dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / rpcbind / rpcbind.c
blobfd1a56d3a33ddb6c8054d3bf74452e440f347891
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
41 * This is an implementation of RCPBIND according the RFC 1833: Binding
42 * Protocols for ONC RPC Version 2. The RFC specifies three versions of the
43 * binding protocol:
45 * 1) RPCBIND Version 3 (Section 2.2.1 of the RFC)
46 * 2) RPCBIND, Version 4 (Section 2.2.2 of the RFC)
47 * 3) Port Mapper Program Protocol (Section 3 of the RFC)
49 * Where the "Port Mapper Program Protocol" is refered as Version 2 of the
50 * binding protocol. The implementation of the Version 2 of the binding
51 * protocol is compiled in only in a case the PORTMAP macro is defined (by
52 * default it is defined).
54 * The implementation is based on top of the networking services library -
55 * libnsl(3lib) and uses Automatic MT mode (see rcp_control(3nsl) and
56 * svc_run(3nsl) for more details).
58 * Usually, when a thread handles an RPCBIND procedure (one that arrived from a
59 * client), it obtains the data for the response internally, and immediately
60 * sends the response back to the client. The only exception to this rule are
61 * remote (aka indirect) RPC calls, for example RPCBPROC_INDIRECT. Such
62 * procedures are designed to forward the RPC request from the client to some
63 * other RPC service specified by the client, wait for the result, and forward
64 * the result back to the client. This is implemented in rpcbproc_callit_com().
66 * The response from the other (remote) RPC service is handled in
67 * handle_reply(), where the thread waiting in rpcbproc_callit_com() is woken
68 * up to finish the handling and to send (forward) the response back to the
69 * client.
71 * The thread implementing the indirect RPC call might be blocked in the
72 * rpcbproc_callit_com() waiting for the response from the other RPC service
73 * for very long time. During this time the thread is unable to handle other
74 * RPCBIND requests. To avoid a case when all threads are waiting in
75 * rpcbproc_callit_com() and there is no free thread able to handle other
76 * RPCBIND requests, the implementation has reserved eight threads to never be
77 * used for the remote RPC calls. The number of active remote RPC calls is in
78 * rpcb_rmtcalls, the upper limit of such calls is in rpcb_rmtcalls_max.
80 * In addition to the worker threads described above, there are two other
81 * threads. The logthread() thread is responsible for asynchronous logging to
82 * syslog. The terminate() thread is signal handler responsible for reload of
83 * the rpcbind configuration (on SIGHUP), or for gracefully shutting down
84 * rpcbind (otherwise).
86 * There are two global lists used for holding the information about the
87 * registered services: list_rbl is for Version 3 and 4 of the binding
88 * protocol, and list_pml is for Version 2. To protect these lists, two global
89 * readers/writer locks are defined and heavily used across the rpcbind
90 * implementation: list_rbl_lock protecting list_rbl, and list_pml_lock,
91 * protecting list_pml.
93 * The defined locking order is: list_rbl_lock first, list_pml_lock second.
96 #include <dlfcn.h>
97 #include <stdio.h>
98 #include <stdio_ext.h>
99 #include <sys/types.h>
100 #include <unistd.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <rpc/rpc.h>
104 #include <netconfig.h>
105 #include <netdir.h>
106 #include <errno.h>
107 #include <sys/wait.h>
108 #include <signal.h>
109 #include <string.h>
110 #include <stdlib.h>
111 #include <thread.h>
112 #include <synch.h>
113 #include <stdarg.h>
114 #ifdef PORTMAP
115 #include <netinet/in.h>
116 #endif
117 #include <arpa/inet.h>
118 #include <sys/termios.h>
119 #include "rpcbind.h"
120 #include <sys/syslog.h>
121 #include <sys/stat.h>
122 #include <syslog.h>
123 #include <string.h>
124 #include <sys/time.h>
125 #include <sys/resource.h>
126 #include <rpcsvc/daemon_utils.h>
127 #include <priv_utils.h>
128 #include <libscf.h>
129 #include <sys/ccompile.h>
130 #include <zone.h>
131 #include <ctype.h>
132 #include <limits.h>
133 #include <assert.h>
135 static sigset_t sigwaitset;
137 static void terminate(void);
138 static void detachfromtty(void);
139 static void parseargs(int, char *[]);
140 static void rbllist_add(ulong_t, ulong_t, struct netconfig *, struct netbuf *);
141 static int init_transport(struct netconfig *);
142 static int check_netconfig(void);
144 static boolean_t check_hostserv(struct netconfig *, const char *, const char *);
145 static int setopt_reuseaddr(int);
146 static int setup_callit(int);
148 static void rpcb_check_init(void);
150 /* Global variables */
151 int debugging = 0; /* Tell me what's going on */
152 static int ipv6flag = 0;
153 int doabort = 0; /* When debugging, do an abort on errors */
154 static int listen_backlog;
155 static const int reserved_threads = 8;
158 * list_rbl_lock protects list_rbl
159 * lock order: list_rbl_lock, list_pml_lock
161 rwlock_t list_rbl_lock = DEFAULTRWLOCK;
162 rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */
164 char *loopback_dg; /* Datagram loopback transport, for set and unset */
165 char *loopback_vc; /* COTS loopback transport, for set and unset */
166 char *loopback_vc_ord; /* COTS_ORD loopback transport, for set and unset */
168 volatile boolean_t verboselog = B_FALSE;
169 volatile boolean_t wrap_enabled = B_FALSE;
170 volatile boolean_t allow_indirect = B_TRUE;
171 volatile boolean_t local_only = B_TRUE;
173 /* Local Variable */
174 static int warmstart = 0; /* Grab a old copy of registrations */
176 #ifdef PORTMAP
178 * list_pml_lock protects list_pml
179 * lock order: list_rbl_lock, list_pml_lock
181 rwlock_t list_pml_lock = DEFAULTRWLOCK;
182 PMAPLIST *list_pml; /* A list of version 2 rpcbind services */
184 char *udptrans; /* Name of UDP transport */
185 char *tcptrans; /* Name of TCP transport */
186 char *udp_uaddr; /* Universal UDP address */
187 char *tcp_uaddr; /* Universal TCP address */
188 #endif
189 static char servname[] = "rpcbind";
190 static char superuser[] = "superuser";
192 static const char daemon_dir[] = DAEMON_DIR;
194 static void
195 block_signals(void)
197 (void) sigemptyset(&sigwaitset);
198 (void) sigaddset(&sigwaitset, SIGINT);
199 (void) sigaddset(&sigwaitset, SIGTERM);
200 (void) sigaddset(&sigwaitset, SIGQUIT);
201 (void) sigaddset(&sigwaitset, SIGHUP);
202 (void) sigprocmask(SIG_BLOCK, &sigwaitset, NULL);
204 /* ignore other signals that could get sent */
205 (void) signal(SIGUSR1, SIG_IGN);
206 (void) signal(SIGUSR2, SIG_IGN);
210 main(int argc, char *argv[])
212 struct netconfig *nconf;
213 void *nc_handle; /* Net config handle */
214 struct rlimit rl;
215 int rpc_svc_fdunlim = 1;
216 int rpc_svc_mode = RPC_SVC_MT_AUTO;
217 int maxrecsz = RPC_MAXDATASIZE;
219 block_signals();
221 parseargs(argc, argv);
223 if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
224 syslog(LOG_ERR, "getrlimit failed");
225 } else {
226 rl.rlim_cur = rl.rlim_max;
227 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
228 syslog(LOG_ERR, "setrlimit failed");
230 (void) enable_extended_FILE_stdio(-1, -1);
232 openlog("rpcbind", LOG_CONS, LOG_DAEMON);
235 * Create the daemon directory in /var/run
237 if (mkdir(daemon_dir, DAEMON_DIR_MODE) == 0 || errno == EEXIST) {
238 chmod(daemon_dir, DAEMON_DIR_MODE);
239 chown(daemon_dir, DAEMON_UID, DAEMON_GID);
240 } else {
241 syslog(LOG_ERR, "failed to create \"%s\": %m", daemon_dir);
245 * These privileges are required for the t_bind check rpcbind uses
246 * to determine whether a service is still live or not.
248 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, DAEMON_UID,
249 DAEMON_GID, PRIV_NET_PRIVADDR, PRIV_SYS_NFS, NULL) == -1) {
250 fprintf(stderr, "Insufficient privileges\n");
251 exit(1);
254 myzone = getzoneid();
257 * Set number of file descriptors to unlimited
259 if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
260 syslog(LOG_INFO, "unable to set number of FD to unlimited");
264 * Tell RPC that we want automatic thread mode.
265 * A new thread will be spawned for each request.
267 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
268 syslog(LOG_ERR, "unable to set automatic MT mode");
269 exit(1);
273 * Enable non-blocking mode and maximum record size checks for
274 * connection oriented transports.
276 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
277 syslog(LOG_INFO, "unable to set RPC max record size");
282 * rpcbind is the first application to encounter the
283 * various netconfig files. check_netconfig() verifies
284 * that they are set up correctly and complains loudly
285 * if not.
287 int trouble;
289 trouble = check_netconfig();
290 if (trouble) {
291 syslog(LOG_ERR, "%s: found %d errors with network "
292 "configuration files. Exiting.", argv[0], trouble);
293 fprintf(stderr, "%s: found %d errors with network "
294 "configuration files. Exiting.\n",
295 argv[0], trouble);
296 exit(1);
300 loopback_dg = "";
301 loopback_vc = "";
302 loopback_vc_ord = "";
303 #ifdef PORTMAP
304 udptrans = "";
305 tcptrans = "";
306 #endif
308 ipv6flag = Is_ipv6present();
309 rpcb_check_init();
311 nc_handle = setnetconfig(); /* open netconfig file */
312 if (nc_handle == NULL) {
313 syslog(LOG_ERR, "could not read /etc/netconfig");
314 exit(1);
316 while ((nconf = getnetconfig(nc_handle)) != NULL) {
317 if (nconf->nc_flag & NC_VISIBLE)
318 init_transport(nconf);
320 endnetconfig(nc_handle);
322 if ((loopback_dg[0] == '\0') && (loopback_vc[0] == '\0') &&
323 (loopback_vc_ord[0] == '\0')) {
324 syslog(LOG_ERR, "could not find loopback transports");
325 exit(1);
328 if (warmstart) {
329 read_warmstart();
332 /* Create terminate signal handler for graceful exit */
333 if (thr_create(NULL, 0, (void *(*)(void *))terminate, NULL, 0, NULL)) {
334 syslog(LOG_ERR, "Failed to create terminate thread");
335 exit(1);
338 if (debugging) {
339 printf("rpcbind debugging enabled.");
340 if (doabort) {
341 printf(" Will abort on errors!\n");
342 } else {
343 printf("\n");
345 } else {
346 detachfromtty();
349 /* These are basic privileges we do not need */
350 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
351 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL);
353 svc_run();
354 syslog(LOG_ERR, "svc_run returned unexpectedly");
355 rpcbind_abort();
356 /* NOTREACHED */
360 * Increments a counter each time a problem is found with the network
361 * configuration information.
363 static int
364 check_netconfig(void)
366 void *nc;
367 void *dlcookie;
368 int busted = 0;
369 int i;
370 int lo_clts_found = 0, lo_cots_found = 0, lo_cotsord_found = 0;
371 struct netconfig *nconf, *np;
372 struct stat sb;
374 nc = setnetconfig();
375 if (nc == NULL) {
376 if (debugging)
377 fprintf(stderr,
378 "setnetconfig() failed: %s\n", nc_sperror());
379 syslog(LOG_ALERT, "setnetconfig() failed: %s", nc_sperror());
380 return (1);
382 while ((np = getnetconfig(nc)) != NULL) {
383 if ((np->nc_flag & NC_VISIBLE) == 0)
384 continue;
385 if (debugging)
386 fprintf(stderr, "checking netid \"%s\"\n",
387 np->nc_netid);
388 if (strcmp(np->nc_protofmly, NC_LOOPBACK) == 0)
389 switch (np->nc_semantics) {
390 case NC_TPI_CLTS:
391 lo_clts_found = 1;
392 break;
394 case NC_TPI_COTS:
395 lo_cots_found = 1;
396 break;
398 case NC_TPI_COTS_ORD:
399 lo_cotsord_found = 1;
400 break;
402 if (stat(np->nc_device, &sb) == -1 && errno == ENOENT) {
403 if (debugging)
404 fprintf(stderr, "\tdevice %s does not exist\n",
405 np->nc_device);
406 syslog(LOG_ERR, "netid %s: device %s does not exist",
407 np->nc_netid, np->nc_device);
408 busted++;
409 } else
410 if (debugging)
411 fprintf(stderr, "\tdevice %s present\n",
412 np->nc_device);
413 for (i = 0; i < np->nc_nlookups; i++) {
414 char *libname = np->nc_lookups[i];
416 if ((dlcookie = dlopen(libname, RTLD_LAZY)) == NULL) {
417 char *dlerrstr;
419 dlerrstr = dlerror();
420 if (debugging) {
421 fprintf(stderr, "\tnetid %s: dlopen of "
422 "name-to-address library %s "
423 "failed\ndlerror: %s",
424 np->nc_netid, libname,
425 dlerrstr ? dlerrstr : "");
427 syslog(LOG_ERR, "netid %s: dlopen of "
428 "name-to-address library %s failed",
429 np->nc_netid, libname);
430 if (dlerrstr)
431 syslog(LOG_ERR, "%s", dlerrstr);
432 busted++;
433 } else {
434 if (debugging)
435 fprintf(stderr, "\tdlopen of "
436 "name-to-address library %s "
437 "succeeded\n", libname);
438 (void) dlclose(dlcookie);
441 nconf = getnetconfigent(np->nc_netid);
443 if (!check_hostserv(nconf, HOST_SELF, ""))
444 busted++;
445 if (!check_hostserv(nconf, HOST_SELF_CONNECT, ""))
446 busted++;
447 if (!check_hostserv(nconf, HOST_SELF, "rpcbind"))
448 busted++;
449 if (!check_hostserv(nconf, HOST_SELF_CONNECT, "rpcbind"))
450 busted++;
452 freenetconfigent(nconf);
454 endnetconfig(nc);
456 if (lo_clts_found) {
457 if (debugging)
458 fprintf(stderr, "Found CLTS loopback transport\n");
459 } else {
460 syslog(LOG_ALERT, "no CLTS loopback transport found\n");
461 if (debugging)
462 fprintf(stderr, "no CLTS loopback transport found\n");
464 if (lo_cots_found) {
465 if (debugging)
466 fprintf(stderr, "Found COTS loopback transport\n");
467 } else {
468 syslog(LOG_ALERT, "no COTS loopback transport found\n");
469 if (debugging)
470 fprintf(stderr, "no COTS loopback transport found\n");
472 if (lo_cotsord_found) {
473 if (debugging)
474 fprintf(stderr, "Found COTS ORD loopback transport\n");
475 } else {
476 syslog(LOG_ALERT, "no COTS ORD loopback transport found\n");
477 if (debugging)
478 fprintf(stderr,
479 "no COTS ORD loopback transport found\n");
482 return (busted);
486 * Adds the entry into the rpcbind database.
487 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
488 * Returns 0 if succeeds, else fails
490 static int
491 init_transport(struct netconfig *nconf)
493 int fd;
494 struct t_bind *taddr, *baddr;
495 SVCXPRT *my_xprt;
496 struct nd_addrlist *nas;
497 struct nd_hostserv hs;
498 static int msgprt = 0;
500 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
501 (nconf->nc_semantics != NC_TPI_COTS) &&
502 (nconf->nc_semantics != NC_TPI_COTS_ORD))
503 return (1); /* not my type */
505 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && !ipv6flag) {
506 if (!msgprt)
507 syslog(LOG_DEBUG, "/etc/netconfig has IPv6 entries but "
508 "IPv6 is not configured");
509 msgprt++;
510 return (1);
513 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) {
514 syslog(LOG_ERR, "%s: cannot open connection: %s",
515 nconf->nc_netid, t_errlist[t_errno]);
516 return (1);
520 * Negotiate for returning the ucred of the caller. This should
521 * done before enabling the endpoint for service via
522 * t_bind() so that requests to rpcbind contain the uid.
524 svc_fd_negotiate_ucred(fd);
526 taddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
527 baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
528 if ((baddr == NULL) || (taddr == NULL)) {
529 syslog(LOG_ERR, "%s: cannot allocate netbuf: %s",
530 nconf->nc_netid, t_errlist[t_errno]);
531 exit(1);
534 /* Get rpcbind's address on this transport */
535 hs.h_host = HOST_SELF;
536 hs.h_serv = servname;
537 if (netdir_getbyname(nconf, &hs, &nas))
538 goto error;
540 /* Copy the address */
541 taddr->addr.len = nas->n_addrs->len;
542 memcpy(taddr->addr.buf, nas->n_addrs->buf, (int)nas->n_addrs->len);
543 netdir_free((char *)nas, ND_ADDRLIST);
545 if (nconf->nc_semantics == NC_TPI_CLTS)
546 taddr->qlen = 0;
547 else
548 taddr->qlen = listen_backlog;
550 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
552 * Sm: If we are running then set SO_REUSEADDR option
553 * so that we can bind to our preferred address even if
554 * previous connections are in FIN_WAIT state
556 if (setopt_reuseaddr(fd) == -1) {
557 syslog(LOG_ERR, "Couldn't set SO_REUSEADDR option");
561 if (t_bind(fd, taddr, baddr) != 0) {
562 syslog(LOG_ERR, "%s: cannot bind: %s",
563 nconf->nc_netid, t_errlist[t_errno]);
564 goto error;
567 if (nconf->nc_semantics != NC_TPI_CLTS && taddr->qlen != baddr->qlen)
568 syslog(LOG_NOTICE, "%s: unable to set listen backlog to %d "
569 "(negotiated: %d)", nconf->nc_netid, taddr->qlen,
570 baddr->qlen);
572 if (memcmp(taddr->addr.buf, baddr->addr.buf, (int)baddr->addr.len)) {
573 syslog(LOG_ERR, "%s: address in use", nconf->nc_netid);
574 goto error;
577 my_xprt = svc_tli_create(fd, nconf, baddr, 0, 0);
578 if (my_xprt == NULL) {
579 syslog(LOG_ERR, "%s: could not create service",
580 nconf->nc_netid);
581 goto error;
584 /* set up multicast address for RPC CALL_IT, IPv6 */
586 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
587 (strcmp(nconf->nc_proto, NC_UDP) == 0)) {
588 if (setup_callit(fd) < 0) {
589 syslog(LOG_ERR, "Unable to join IPv6 multicast group "
590 "for rpc broadcast %s", RPCB_MULTICAST_ADDR);
594 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
595 svc_control(my_xprt, SVCSET_KEEPALIVE, (void *) TRUE);
598 #ifdef PORTMAP
600 * Register both the versions for tcp/ip and udp/ip
602 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
603 ((strcmp(nconf->nc_proto, NC_TCP) == 0) ||
604 (strcmp(nconf->nc_proto, NC_UDP) == 0))) {
605 PMAPLIST *pml;
607 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
608 pmap_service, 0)) {
609 syslog(LOG_ERR, "could not register on %s",
610 nconf->nc_netid);
611 goto error;
613 pml = malloc(sizeof (PMAPLIST));
614 if (pml == NULL) {
615 syslog(LOG_ERR, "no memory!");
616 exit(1);
618 pml->pml_map.pm_prog = PMAPPROG;
619 pml->pml_map.pm_vers = PMAPVERS;
620 pml->pml_map.pm_port = PMAPPORT;
621 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
622 if (tcptrans[0]) {
623 syslog(LOG_ERR,
624 "cannot have more than one TCP transport");
625 goto error;
627 tcptrans = strdup(nconf->nc_netid);
628 pml->pml_map.pm_prot = IPPROTO_TCP;
630 /* Let's snarf the universal address */
631 /* "h1.h2.h3.h4.p1.p2" */
632 tcp_uaddr = taddr2uaddr(nconf, &baddr->addr);
633 } else {
634 if (udptrans[0]) {
635 syslog(LOG_ERR,
636 "cannot have more than one UDP transport");
637 goto error;
639 udptrans = strdup(nconf->nc_netid);
640 pml->pml_map.pm_prot = IPPROTO_UDP;
642 /* Let's snarf the universal address */
643 /* "h1.h2.h3.h4.p1.p2" */
644 udp_uaddr = taddr2uaddr(nconf, &baddr->addr);
646 pml->pml_next = list_pml;
647 list_pml = pml;
649 /* Add version 3 information */
650 pml = malloc(sizeof (PMAPLIST));
651 if (pml == NULL) {
652 syslog(LOG_ERR, "no memory!");
653 exit(1);
655 pml->pml_map = list_pml->pml_map;
656 pml->pml_map.pm_vers = RPCBVERS;
657 pml->pml_next = list_pml;
658 list_pml = pml;
660 /* Add version 4 information */
661 pml = malloc(sizeof (PMAPLIST));
662 if (pml == NULL) {
663 syslog(LOG_ERR, "no memory!");
664 exit(1);
666 pml->pml_map = list_pml->pml_map;
667 pml->pml_map.pm_vers = RPCBVERS4;
668 pml->pml_next = list_pml;
669 list_pml = pml;
671 /* Also add version 2 stuff to rpcbind list */
672 rbllist_add(PMAPPROG, PMAPVERS, nconf, &baddr->addr);
674 #endif
676 /* version 3 registration */
677 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
678 syslog(LOG_ERR, "could not register %s version 3",
679 nconf->nc_netid);
680 goto error;
682 rbllist_add(RPCBPROG, RPCBVERS, nconf, &baddr->addr);
684 /* version 4 registration */
685 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
686 syslog(LOG_ERR, "could not register %s version 4",
687 nconf->nc_netid);
688 goto error;
690 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &baddr->addr);
692 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
693 if (nconf->nc_semantics == NC_TPI_CLTS)
694 loopback_dg = strdup(nconf->nc_netid);
695 else if (nconf->nc_semantics == NC_TPI_COTS)
696 loopback_vc = strdup(nconf->nc_netid);
697 else if (nconf->nc_semantics == NC_TPI_COTS_ORD)
698 loopback_vc_ord = strdup(nconf->nc_netid);
701 /* decide if bound checking works for this transport */
702 (void) add_bndlist(nconf, taddr, baddr);
705 * rmtcall only supported on CLTS transports for now.
707 if (nconf->nc_semantics == NC_TPI_CLTS)
708 (void) create_rmtcall_fd(nconf);
710 (void) t_free((char *)taddr, T_BIND);
711 (void) t_free((char *)baddr, T_BIND);
712 return (0);
713 error:
714 (void) t_free((char *)taddr, T_BIND);
715 (void) t_free((char *)baddr, T_BIND);
716 (void) t_close(fd);
717 return (1);
720 static void
721 rbllist_add(ulong_t prog, ulong_t vers, struct netconfig *nconf,
722 struct netbuf *addr)
724 rpcblist_ptr rbl;
726 rbl = malloc(sizeof (rpcblist));
727 if (rbl == NULL) {
728 syslog(LOG_ERR, "no memory!");
729 exit(1);
732 rbl->rpcb_map.r_prog = prog;
733 rbl->rpcb_map.r_vers = vers;
734 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
735 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
736 if (rbl->rpcb_map.r_addr == NULL)
737 rbl->rpcb_map.r_addr = strdup("");
738 rbl->rpcb_map.r_owner = strdup(superuser);
740 if (rbl->rpcb_map.r_netid == NULL || rbl->rpcb_map.r_addr == NULL ||
741 rbl->rpcb_map.r_owner == NULL) {
742 syslog(LOG_ERR, "no memory!");
743 exit(1);
746 rbl->rpcb_next = list_rbl; /* Attach to global list */
747 list_rbl = rbl;
751 * Catch the signal and die, if not SIGHUP
753 static void
754 terminate(void)
756 int sig;
758 for (;;) {
759 sig = sigwait(&sigwaitset);
760 if (sig == SIGHUP) {
761 rpcb_check_init();
762 continue;
764 if (sig != -1 || errno != EINTR)
765 break;
768 syslog(LOG_ERR, "rpcbind terminating on signal %d.", sig);
770 rw_wrlock(&list_rbl_lock);
771 #ifdef PORTMAP
772 rw_wrlock(&list_pml_lock);
773 #endif
774 write_warmstart(); /* Dump yourself */
776 exit(2);
779 void
780 rpcbind_abort(void)
783 * We need to hold write locks to make sure
784 * write_warmstart() is executed exactly once
786 rw_wrlock(&list_rbl_lock);
787 #ifdef PORTMAP
788 rw_wrlock(&list_pml_lock);
789 #endif
790 write_warmstart(); /* Dump yourself */
792 abort();
796 * detach from tty
798 static void
799 detachfromtty(void)
801 close(0);
802 close(1);
803 close(2);
804 switch (forkall()) {
805 case (pid_t)-1:
806 perror("fork");
807 break;
808 case 0:
809 break;
810 default:
811 exit(0);
813 setsid();
814 (void) open("/dev/null", O_RDWR, 0);
815 dup(0);
816 dup(0);
819 static int
820 convert_int(int *val, char *str)
822 long lval;
824 if (str == NULL || !isdigit(*str))
825 return (-1);
827 lval = strtol(str, &str, 10);
828 if (*str != '\0' || lval > INT_MAX)
829 return (-2);
831 *val = (int)lval;
832 return (0);
835 static int get_smf_iprop(const char *, int, int, int);
837 /* get command line options */
838 static void
839 parseargs(int argc, char *argv[])
841 int c;
842 int tmp;
844 listen_backlog = get_smf_iprop("listen_backlog", 64, 1, INT_MAX);
846 while ((c = getopt(argc, argv, "dwal:")) != EOF) {
847 switch (c) {
848 case 'd':
849 debugging = 1;
850 break;
851 case 'a':
852 doabort = 1; /* when debugging, do an abort on */
853 break; /* errors; for rpcbind developers */
854 /* only! */
855 case 'w':
856 warmstart = 1;
857 break;
859 case 'l':
860 if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
861 (void) fprintf(stderr, "%s: invalid "
862 "listen_backlog option, using defaults\n",
863 argv[0]);
864 break;
866 listen_backlog = tmp;
867 break;
868 default: /* error */
869 fprintf(stderr,
870 "usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
871 exit(1);
874 if (doabort && !debugging) {
875 fprintf(stderr,
876 "-a (abort) specified without -d "
877 "(debugging) -- ignored.\n");
878 doabort = 0;
882 static int
883 setopt_int(int fd, int level, int name, int value)
885 struct t_optmgmt req, resp;
886 struct {
887 struct opthdr opt;
888 int value;
889 } optdata;
891 optdata.opt.level = level;
892 optdata.opt.name = name;
893 optdata.opt.len = sizeof (int);
895 optdata.value = value;
897 req.flags = T_NEGOTIATE;
898 req.opt.len = sizeof (optdata);
899 req.opt.buf = (char *)&optdata;
901 resp.flags = 0;
902 resp.opt.buf = (char *)&optdata;
903 resp.opt.maxlen = sizeof (optdata);
905 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
906 t_error("t_optmgmt");
907 return (-1);
909 return (0);
912 static int
913 setopt_reuseaddr(int fd)
915 return (setopt_int(fd, SOL_SOCKET, SO_REUSEADDR, 1));
918 static int
919 setup_callit(int fd)
921 struct ipv6_mreq mreq;
922 struct t_optmgmt req, resp;
923 struct opthdr *opt;
924 char reqbuf[ sizeof (struct ipv6_mreq) + 24];
925 struct ipv6_mreq *pmreq;
927 opt = (struct opthdr *)reqbuf;
929 opt->level = IPPROTO_IPV6;
930 opt->name = IPV6_ADD_MEMBERSHIP;
931 opt->len = sizeof (struct ipv6_mreq);
933 /* multicast address */
934 (void) inet_pton(AF_INET6, RPCB_MULTICAST_ADDR,
935 mreq.ipv6mr_multiaddr.s6_addr);
936 mreq.ipv6mr_interface = 0;
938 /* insert it into opt */
939 pmreq = (struct ipv6_mreq *)&reqbuf[sizeof (struct opthdr)];
940 memcpy(pmreq, &mreq, sizeof (struct ipv6_mreq));
942 req.flags = T_NEGOTIATE;
943 req.opt.len = sizeof (struct opthdr) + opt->len;
944 req.opt.buf = (char *)opt;
946 resp.flags = 0;
947 resp.opt.buf = reqbuf;
948 resp.opt.maxlen = sizeof (reqbuf);
950 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
951 t_error("t_optmgmt");
952 return (-1);
954 return (0);
957 static boolean_t
958 check_hostserv(struct netconfig *nconf, const char *host, const char *serv)
960 struct nd_hostserv nh;
961 struct nd_addrlist *na;
962 const char *hostname = host;
963 const char *servname = serv;
964 int retval;
966 if (strcmp(host, HOST_SELF) == 0)
967 hostname = "HOST_SELF";
968 else if (strcmp(host, HOST_SELF_CONNECT) == 0)
969 hostname = "HOST_SELF_CONNECT";
971 if (serv[0] == '\0')
972 servname = "<any>";
974 nh.h_host = (char *)host;
975 nh.h_serv = (char *)serv;
977 retval = netdir_getbyname(nconf, &nh, &na);
978 if (retval != ND_OK || na->n_cnt == 0) {
979 if (retval == ND_OK)
980 netdir_free(na, ND_ADDRLIST);
982 syslog(LOG_ALERT, "netid %s: cannot find an address for host "
983 "%s, service \"%s\"", nconf->nc_netid, hostname, servname);
984 if (debugging) {
985 (void) fprintf(stderr, "\tnetdir_getbyname for %s, "
986 "service \"%s\" failed\n", hostname, servname);
988 return (B_FALSE);
990 netdir_free(na, ND_ADDRLIST);
992 if (debugging) {
993 (void) fprintf(stderr, "\tnetdir_getbyname for %s, service "
994 "service \"%s\" succeeded\n", hostname, servname);
996 return (B_TRUE);
999 /* Maximum outstanding syslog requests */
1000 #define MAXLOG 100
1001 /* Maximum length: the messages generated are fairly short; no hostnames. */
1002 #define MAXMSG 128
1004 typedef struct logmsg {
1005 struct logmsg *log_next;
1006 int log_pri;
1007 char log_msg[MAXMSG];
1008 } logmsg;
1010 static logmsg *loghead = NULL;
1011 static logmsg **logtailp = &loghead;
1012 static mutex_t logmutex = DEFAULTMUTEX;
1013 static cond_t logcond = DEFAULTCV;
1014 static int logcount = 0;
1016 /* ARGSUSED */
1017 static void * __NORETURN
1018 logthread(void *arg)
1020 for (;;) {
1021 logmsg *msg;
1022 (void) mutex_lock(&logmutex);
1023 while ((msg = loghead) == NULL)
1024 (void) cond_wait(&logcond, &logmutex);
1026 loghead = msg->log_next;
1027 logcount--;
1028 if (loghead == NULL) {
1029 logtailp = &loghead;
1030 logcount = 0;
1032 (void) mutex_unlock(&logmutex);
1033 syslog(msg->log_pri, "%s", msg->log_msg);
1034 free(msg);
1036 /* NOTREACHED */
1039 static boolean_t
1040 get_smf_prop(const char *var, boolean_t def_val)
1042 scf_simple_prop_t *prop;
1043 uint8_t *val = NULL;
1044 boolean_t res = def_val;
1046 prop = scf_simple_prop_get(NULL, NULL, "config", var);
1047 if (prop != NULL) {
1048 if ((val = scf_simple_prop_next_boolean(prop)) != NULL)
1049 res = (*val == 0) ? B_FALSE : B_TRUE;
1050 scf_simple_prop_free(prop);
1053 if (prop == NULL || val == NULL) {
1054 syslog(LOG_ALERT, "no value for config/%s (%s). "
1055 "Using default \"%s\"", var, scf_strerror(scf_error()),
1056 def_val ? "true" : "false");
1059 return (res);
1062 static int
1063 get_smf_iprop(const char *var, int def_val, int min, int max)
1065 scf_simple_prop_t *prop;
1066 int64_t *val = NULL;
1067 int res = def_val;
1069 prop = scf_simple_prop_get(NULL, NULL, "config", var);
1070 if (prop != NULL) {
1071 if ((val = scf_simple_prop_next_integer(prop)) != NULL) {
1072 if (*val < min || *val > max)
1073 syslog(LOG_ALERT, "value for config/%s out of "
1074 "range. Using default %d", var, def_val);
1075 else
1076 res = (int)*val;
1078 scf_simple_prop_free(prop);
1081 if (prop == NULL || val == NULL) {
1082 syslog(LOG_ALERT, "no value for config/%s (%s). "
1083 "Using default %d", var, scf_strerror(scf_error()),
1084 def_val);
1087 return (res);
1091 * Initialize: read the configuration parameters from SMF.
1092 * This function must be idempotent because it can be called from the
1093 * signal handler.
1095 static void
1096 rpcb_check_init(void)
1098 thread_t tid;
1099 int max_threads;
1100 static int thr_running;
1102 wrap_enabled = get_smf_prop("enable_tcpwrappers", B_FALSE);
1103 verboselog = get_smf_prop("verbose_logging", B_FALSE);
1104 allow_indirect = get_smf_prop("allow_indirect", B_TRUE);
1105 local_only = get_smf_prop("local_only", B_TRUE);
1107 if (wrap_enabled && !thr_running) {
1108 (void) thr_create(NULL, 0, logthread, NULL, THR_DETACHED, &tid);
1109 thr_running = 1;
1113 * Set the maximum number of threads.
1115 max_threads = get_smf_iprop("max_threads", 72, 1, INT_MAX);
1116 if (!rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
1117 int tmp;
1120 * The following rpc_control() call cannot fail
1122 if (!rpc_control(RPC_SVC_THRMAX_GET, &tmp))
1123 assert(0);
1125 if (tmp != max_threads) {
1126 syslog(LOG_ERR, "setting max_threads to %d failed, "
1127 "using %d worker threads", max_threads, tmp);
1128 max_threads = tmp;
1133 * Set rpcb_rmtcalls_max.
1135 if (max_threads < reserved_threads)
1136 set_rpcb_rmtcalls_max(0);
1137 else
1138 set_rpcb_rmtcalls_max(max_threads - reserved_threads);
1142 * qsyslog() - queue a request for syslog(); if syslog blocks, the other
1143 * thread blocks; we make sure we don't run out of memory by allowing
1144 * only a limited number of outstandig syslog() requests.
1146 void
1147 qsyslog(int pri, const char *fmt, ...)
1149 logmsg *msg = malloc(sizeof (*msg));
1150 va_list ap;
1152 if (msg == NULL)
1153 return;
1155 msg->log_pri = pri;
1157 va_start(ap, fmt);
1158 (void) vsnprintf(msg->log_msg, sizeof (msg->log_msg), fmt, ap);
1159 va_end(ap);
1161 msg->log_next = NULL;
1163 (void) mutex_lock(&logmutex);
1164 if (logcount < MAXLOG) {
1165 if (logcount == 0)
1166 (void) cond_signal(&logcond);
1167 logcount++;
1168 *logtailp = msg;
1169 logtailp = &msg->log_next;
1170 (void) mutex_unlock(&logmutex);
1171 } else {
1172 (void) mutex_unlock(&logmutex);
1173 free(msg);