rpcbind.c revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Implements the program, version to address mapping for rpc.
*
*/
#include <dlfcn.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netconfig.h>
#include <netdir.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <thread.h>
#include <synch.h>
#include <deflt.h>
#include <stdarg.h>
#ifdef PORTMAP
#endif
#include "rpcbind.h"
#include <syslog.h>
#include <string.h>
#include <sys/resource.h>
#include <rpcsvc/daemon_utils.h>
#include <priv_utils.h>
#include <libscf.h>
#ifdef PORTMAP
#endif
extern void read_warmstart(void);
extern void write_warmstart(void);
extern int Is_ipv6present(void);
#define MAX_FILEDESC_LIMIT 1023
static void terminate(int);
static void detachfromtty(void);
static void parseargs(int, char *[]);
static int init_transport(struct netconfig *);
static int check_netconfig(void);
static void rpcb_check_init(void);
static int setopt_reuseaddr(int);
static int setopt_anon_mlp(int);
static int setup_callit(int);
/* Global variables */
#ifdef ND_DEBUG
#else
int debugging = 0; /* Tell me what's going on */
#endif
static int ipv6flag = 0;
int doabort = 0; /* When debugging, do an abort on errors */
static int listen_backlog = 64;
char *loopback_dg; /* Datagram loopback transport, for set and unset */
char *loopback_vc; /* COTS loopback transport, for set and unset */
char *loopback_vc_ord; /* COTS_ORD loopback transport, for set and unset */
/* Local Variable */
static int warmstart = 0; /* Grab a old copy of registrations */
#ifdef PORTMAP
char *udptrans; /* Name of UDP transport */
char *tcptrans; /* Name of TCP transport */
char *udp_uaddr; /* Universal UDP address */
char *tcp_uaddr; /* Universal TCP address */
#endif
static char servname[] = "rpcbind";
static char superuser[] = "superuser";
static const char daemon_dir[] = DAEMON_DIR;
int
{
void *nc_handle; /* Net config handle */
int maxrecsz = RPC_MAXDATASIZE;
else
}
/*
*/
} else {
}
/*
* These privileges are required for the t_bind check rpcbind uses
* to determine whether a service is still live or not.
*/
exit(1);
}
/*
* Enable non-blocking mode and maximum record size checks for
* connection oriented transports.
*/
}
exit(1);
}
loopback_dg = "";
loopback_vc = "";
loopback_vc_ord = "";
#ifdef PORTMAP
udptrans = "";
tcptrans = "";
#endif
{
/*
* rpcbind is the first application to encounter the
* various netconfig files. check_netconfig() verifies
* that they are set up correctly and complains loudly
* if not.
*/
int trouble;
trouble = check_netconfig();
if (trouble) {
"%s: found %d errors with network configuration files. Exiting.",
"%s: found %d errors with network configuration files. Exiting.\n",
exit(1);
}
}
ipv6flag = Is_ipv6present();
}
(loopback_vc_ord[0] == NULL)) {
exit(1);
}
/* catch the usual termination signals for graceful exit */
/* ignore others that could get sent */
if (warmstart) {
}
if (debugging) {
printf("rpcbind debugging enabled.");
if (doabort) {
printf(" Will abort on errors!\n");
} else {
printf("\n");
}
} else {
}
/* These are basic privileges we do not need */
my_svc_run();
/* NOTREACHED */
}
/*
* Increments a counter each time a problem is found with the network
* configuration information.
*/
static int
check_netconfig(void)
{
void *nc;
void *dlcookie;
int busted = 0;
int i;
nc = setnetconfig();
if (debugging)
"setnetconfig() failed: %s\n", nc_sperror());
return (1);
}
continue;
if (debugging)
switch (np->nc_semantics) {
case NC_TPI_CLTS:
lo_clts_found = 1;
break;
case NC_TPI_COTS:
lo_cots_found = 1;
break;
case NC_TPI_COTS_ORD:
lo_cotsord_found = 1;
break;
}
if (debugging)
busted++;
} else
if (debugging)
for (i = 0; i < np->nc_nlookups; i++) {
char *dlerrstr;
if (debugging) {
"\tnetid %s: dlopen of name-to-address library %s failed\ndlerror: %s",
}
"netid %s: dlopen of name-to-address library %s failed",
if (dlerrstr)
busted++;
} else {
if (debugging)
"\tdlopen of name-to-address library %s succeeded\n", libname);
}
}
busted++;
busted++;
busted++;
busted++;
}
if (lo_clts_found) {
if (debugging)
} else {
if (debugging)
}
if (lo_cots_found) {
if (debugging)
} else {
if (debugging)
}
if (lo_cotsord_found) {
if (debugging)
} else {
if (debugging)
"no COTS ORD loopback transport found\n");
}
return (busted);
}
/*
* Adds the entry into the rpcbind database.
* If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
* Returns 0 if succeeds, else fails
*/
static int
{
int fd;
struct nd_addrlist *nas;
struct nd_hostserv hs;
int status; /* bound checking ? */
static int msgprt = 0;
return (1); /* not my type */
if (!msgprt)
msgprt++;
return (1);
}
#ifdef ND_DEBUG
{
int i;
char **s;
}
#endif
return (1);
}
if (is_system_labeled() &&
}
/*
* Negotiate for returning the ucred of the caller. This should
* done before enabling the endpoint for service via
* t_bind() so that requests to rpcbind contain the uid.
*/
exit(1);
}
/* Get rpcbind's address on this transport */
goto error;
/* Copy the address */
#ifdef ND_DEBUG
{
/* for debugging print out our universal address */
char *uaddr;
}
#endif
else
/*
* Sm: If we are running then set SO_REUSEADDR option
* so that we can bind to our preferred address even if
* previous connections are in FIN_WAIT state
*/
#ifdef ND_DEBUG
#endif
}
}
goto error;
}
goto error;
}
goto error;
}
/* set up multicast address for RPC CALL_IT, IPv6 */
if (setup_callit(fd) < 0) {
for rpc broadcast %s", RPCB_MULTICAST_ADDR);
}
}
}
#ifdef PORTMAP
/*
*/
pmap_service, NULL)) {
goto error;
}
exit(1);
}
if (tcptrans[0]) {
"cannot have more than one TCP transport");
goto error;
}
/* Let's snarf the universal address */
/* "h1.h2.h3.h4.p1.p2" */
} else {
if (udptrans[0]) {
"cannot have more than one UDP transport");
goto error;
}
/* Let's snarf the universal address */
/* "h1.h2.h3.h4.p1.p2" */
}
/* Add version 3 information */
exit(1);
}
/* Add version 4 information */
exit(1);
}
/* Also add version 2 stuff to rpcbind list */
}
#endif
/* version 3 registration */
goto error;
}
/* version 4 registration */
goto error;
}
}
/* decide if bound checking works for this transport */
#ifdef BIND_DEBUG
if (status < 0) {
} else if (status == 0) {
} else if (status > 0) {
}
#endif
/*
* rmtcall only supported on CLTS transports for now.
* only needed when we are allowing indirect calls
*/
#ifdef BIND_DEBUG
if (status < 0) {
} else {
}
#endif
}
return (0);
return (1);
}
static void
{
exit(1);
}
}
/*
* Catch the signal and die
*/
/* ARGSUSED */
static void
{
write_warmstart(); /* Dump yourself */
exit(2);
}
void
rpcbind_abort(void)
{
write_warmstart(); /* Dump yourself */
abort();
}
/*
* detach from tty
*/
static void
detachfromtty(void)
{
close(0);
close(1);
close(2);
switch (forkall()) {
case (pid_t)-1:
perror("fork");
break;
case 0:
break;
default:
exit(0);
}
setsid();
dup(0);
dup(0);
}
/* get command line options */
static void
{
int c;
int tmp;
switch (c) {
case 'd':
debugging = 1;
break;
case 'a':
break; /* errors; for rpcbind developers */
/* only! */
case 'w':
warmstart = 1;
break;
case 'l':
if (tmp > listen_backlog) {
}
}
break;
default: /* error */
"usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
exit(1);
}
}
"-a (abort) specified without -d (debugging) -- ignored.\n");
doabort = 0;
}
}
static int
{
struct {
int value;
} optdata;
t_error("t_optmgmt");
return (-1);
}
return (0);
}
static int
setopt_reuseaddr(int fd)
{
}
static int
setopt_anon_mlp(int fd)
{
}
static int
setup_callit(int fd)
{
/* multicast address */
mreq.ipv6mr_interface = 0;
/* insert it into opt */
t_error("t_optmgmt");
return (-1);
}
return (0);
}
static boolean_t
{
struct nd_hostserv nh;
struct nd_addrlist *na;
int retval;
hostname = "HOST_SELF";
hostname = "HOST_SELF_CONNECT";
if (serv[0] == '\0')
servname = "<any>";
if (debugging) {
}
return (B_FALSE);
}
if (debugging) {
}
return (B_TRUE);
}
#define DEFRPCBIND "/etc/default/rpcbind"
/* Maximum outstanding syslog requests */
#define MAXLOG 100
/* Maximum length: the messages generated are fairly short; no hostnames. */
#define MAXMSG 128
typedef struct logmsg {
int log_pri;
} logmsg;
static int logcount = 0;
/*ARGSUSED*/
static void *
{
while (1) {
(void) mutex_lock(&logmutex);
logcount--;
logcount = 0;
}
(void) mutex_unlock(&logmutex);
}
/* NOTREACHED */
}
/*
* Initialize: read the configuration parameters from the default file.
*/
static void
rpcb_check_init(void)
{
uint8_t *bool;
"enable_tcpwrappers")) != NULL) {
} else {
scf_strerror(scf_error()));
}
} else {
scf_strerror(scf_error()));
}
"verbose_logging")) != NULL) {
} else {
scf_strerror(scf_error()));
}
} else {
scf_strerror(scf_error()));
}
"allow_indirect")) != NULL) {
} else {
scf_strerror(scf_error()));
}
} else {
scf_strerror(scf_error()));
}
if (wrap_enabled)
}
/*
* qsyslog() - queue a request for syslog(); if syslog blocks, the other
* thread blocks; we make sure we don't run out of memory by allowing
* only a limited number of outstandig syslog() requests.
*/
void
{
int oldcount;
return;
(void) mutex_lock(&logmutex);
logcount++;
} else {
}
(void) mutex_unlock(&logmutex);
if (oldcount == 0)
(void) cond_signal(&logcond);
}