5680 Build warnings in cmd/power, cmd/rpcbind
[unleashed.git] / usr / src / cmd / rpcbind / rpcbind.c
blob694e4f942fa24bc587d02341056db7699045f5f1
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 setopt_anon_mlp(int);
147 static int setup_callit(int);
149 static void rpcb_check_init(void);
151 /* Global variables */
152 int debugging = 0; /* Tell me what's going on */
153 static int ipv6flag = 0;
154 int doabort = 0; /* When debugging, do an abort on errors */
155 static int listen_backlog;
156 static const int reserved_threads = 8;
159 * list_rbl_lock protects list_rbl
160 * lock order: list_rbl_lock, list_pml_lock
162 rwlock_t list_rbl_lock = DEFAULTRWLOCK;
163 rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */
165 char *loopback_dg; /* Datagram loopback transport, for set and unset */
166 char *loopback_vc; /* COTS loopback transport, for set and unset */
167 char *loopback_vc_ord; /* COTS_ORD loopback transport, for set and unset */
169 volatile boolean_t verboselog = B_FALSE;
170 volatile boolean_t wrap_enabled = B_FALSE;
171 volatile boolean_t allow_indirect = B_TRUE;
172 volatile boolean_t local_only = B_TRUE;
174 /* Local Variable */
175 static int warmstart = 0; /* Grab a old copy of registrations */
177 #ifdef PORTMAP
179 * list_pml_lock protects list_pml
180 * lock order: list_rbl_lock, list_pml_lock
182 rwlock_t list_pml_lock = DEFAULTRWLOCK;
183 PMAPLIST *list_pml; /* A list of version 2 rpcbind services */
185 char *udptrans; /* Name of UDP transport */
186 char *tcptrans; /* Name of TCP transport */
187 char *udp_uaddr; /* Universal UDP address */
188 char *tcp_uaddr; /* Universal TCP address */
189 #endif
190 static char servname[] = "rpcbind";
191 static char superuser[] = "superuser";
193 static const char daemon_dir[] = DAEMON_DIR;
195 static void
196 block_signals(void)
198 (void) sigemptyset(&sigwaitset);
199 (void) sigaddset(&sigwaitset, SIGINT);
200 (void) sigaddset(&sigwaitset, SIGTERM);
201 (void) sigaddset(&sigwaitset, SIGQUIT);
202 (void) sigaddset(&sigwaitset, SIGHUP);
203 (void) sigprocmask(SIG_BLOCK, &sigwaitset, NULL);
205 /* ignore other signals that could get sent */
206 (void) signal(SIGUSR1, SIG_IGN);
207 (void) signal(SIGUSR2, SIG_IGN);
211 main(int argc, char *argv[])
213 struct netconfig *nconf;
214 void *nc_handle; /* Net config handle */
215 struct rlimit rl;
216 int rpc_svc_fdunlim = 1;
217 int rpc_svc_mode = RPC_SVC_MT_AUTO;
218 int maxrecsz = RPC_MAXDATASIZE;
219 boolean_t can_do_mlp;
221 block_signals();
223 parseargs(argc, argv);
225 if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
226 syslog(LOG_ERR, "getrlimit failed");
227 } else {
228 rl.rlim_cur = rl.rlim_max;
229 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
230 syslog(LOG_ERR, "setrlimit failed");
232 (void) enable_extended_FILE_stdio(-1, -1);
234 openlog("rpcbind", LOG_CONS, LOG_DAEMON);
237 * Create the daemon directory in /var/run
239 if (mkdir(daemon_dir, DAEMON_DIR_MODE) == 0 || errno == EEXIST) {
240 chmod(daemon_dir, DAEMON_DIR_MODE);
241 chown(daemon_dir, DAEMON_UID, DAEMON_GID);
242 } else {
243 syslog(LOG_ERR, "failed to create \"%s\": %m", daemon_dir);
247 * These privileges are required for the t_bind check rpcbind uses
248 * to determine whether a service is still live or not.
250 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
251 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, DAEMON_UID,
252 DAEMON_GID, PRIV_NET_PRIVADDR, PRIV_SYS_NFS,
253 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
254 fprintf(stderr, "Insufficient privileges\n");
255 exit(1);
258 myzone = getzoneid();
261 * Set number of file descriptors to unlimited
263 if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
264 syslog(LOG_INFO, "unable to set number of FD to unlimited");
268 * Tell RPC that we want automatic thread mode.
269 * A new thread will be spawned for each request.
271 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
272 syslog(LOG_ERR, "unable to set automatic MT mode");
273 exit(1);
277 * Enable non-blocking mode and maximum record size checks for
278 * connection oriented transports.
280 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
281 syslog(LOG_INFO, "unable to set RPC max record size");
286 * rpcbind is the first application to encounter the
287 * various netconfig files. check_netconfig() verifies
288 * that they are set up correctly and complains loudly
289 * if not.
291 int trouble;
293 trouble = check_netconfig();
294 if (trouble) {
295 syslog(LOG_ERR, "%s: found %d errors with network "
296 "configuration files. Exiting.", argv[0], trouble);
297 fprintf(stderr, "%s: found %d errors with network "
298 "configuration files. Exiting.\n",
299 argv[0], trouble);
300 exit(1);
304 loopback_dg = "";
305 loopback_vc = "";
306 loopback_vc_ord = "";
307 #ifdef PORTMAP
308 udptrans = "";
309 tcptrans = "";
310 #endif
312 ipv6flag = Is_ipv6present();
313 rpcb_check_init();
315 nc_handle = setnetconfig(); /* open netconfig file */
316 if (nc_handle == NULL) {
317 syslog(LOG_ERR, "could not read /etc/netconfig");
318 exit(1);
320 while ((nconf = getnetconfig(nc_handle)) != NULL) {
321 if (nconf->nc_flag & NC_VISIBLE)
322 init_transport(nconf);
324 endnetconfig(nc_handle);
326 if ((loopback_dg[0] == NULL) && (loopback_vc[0] == NULL) &&
327 (loopback_vc_ord[0] == NULL)) {
328 syslog(LOG_ERR, "could not find loopback transports");
329 exit(1);
332 if (warmstart) {
333 read_warmstart();
336 /* Create terminate signal handler for graceful exit */
337 if (thr_create(NULL, 0, (void *(*)(void *))terminate, NULL, 0, NULL)) {
338 syslog(LOG_ERR, "Failed to create terminate thread");
339 exit(1);
342 if (debugging) {
343 printf("rpcbind debugging enabled.");
344 if (doabort) {
345 printf(" Will abort on errors!\n");
346 } else {
347 printf("\n");
349 } else {
350 detachfromtty();
353 /* These are basic privileges we do not need */
354 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
355 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
357 svc_run();
358 syslog(LOG_ERR, "svc_run returned unexpectedly");
359 rpcbind_abort();
360 /* NOTREACHED */
364 * Increments a counter each time a problem is found with the network
365 * configuration information.
367 static int
368 check_netconfig(void)
370 void *nc;
371 void *dlcookie;
372 int busted = 0;
373 int i;
374 int lo_clts_found = 0, lo_cots_found = 0, lo_cotsord_found = 0;
375 struct netconfig *nconf, *np;
376 struct stat sb;
378 nc = setnetconfig();
379 if (nc == NULL) {
380 if (debugging)
381 fprintf(stderr,
382 "setnetconfig() failed: %s\n", nc_sperror());
383 syslog(LOG_ALERT, "setnetconfig() failed: %s", nc_sperror());
384 return (1);
386 while ((np = getnetconfig(nc)) != NULL) {
387 if ((np->nc_flag & NC_VISIBLE) == 0)
388 continue;
389 if (debugging)
390 fprintf(stderr, "checking netid \"%s\"\n",
391 np->nc_netid);
392 if (strcmp(np->nc_protofmly, NC_LOOPBACK) == 0)
393 switch (np->nc_semantics) {
394 case NC_TPI_CLTS:
395 lo_clts_found = 1;
396 break;
398 case NC_TPI_COTS:
399 lo_cots_found = 1;
400 break;
402 case NC_TPI_COTS_ORD:
403 lo_cotsord_found = 1;
404 break;
406 if (stat(np->nc_device, &sb) == -1 && errno == ENOENT) {
407 if (debugging)
408 fprintf(stderr, "\tdevice %s does not exist\n",
409 np->nc_device);
410 syslog(LOG_ERR, "netid %s: device %s does not exist",
411 np->nc_netid, np->nc_device);
412 busted++;
413 } else
414 if (debugging)
415 fprintf(stderr, "\tdevice %s present\n",
416 np->nc_device);
417 for (i = 0; i < np->nc_nlookups; i++) {
418 char *libname = np->nc_lookups[i];
420 if ((dlcookie = dlopen(libname, RTLD_LAZY)) == NULL) {
421 char *dlerrstr;
423 dlerrstr = dlerror();
424 if (debugging) {
425 fprintf(stderr, "\tnetid %s: dlopen of "
426 "name-to-address library %s "
427 "failed\ndlerror: %s",
428 np->nc_netid, libname,
429 dlerrstr ? dlerrstr : "");
431 syslog(LOG_ERR, "netid %s: dlopen of "
432 "name-to-address library %s failed",
433 np->nc_netid, libname);
434 if (dlerrstr)
435 syslog(LOG_ERR, "%s", dlerrstr);
436 busted++;
437 } else {
438 if (debugging)
439 fprintf(stderr, "\tdlopen of "
440 "name-to-address library %s "
441 "succeeded\n", libname);
442 (void) dlclose(dlcookie);
445 nconf = getnetconfigent(np->nc_netid);
447 if (!check_hostserv(nconf, HOST_SELF, ""))
448 busted++;
449 if (!check_hostserv(nconf, HOST_SELF_CONNECT, ""))
450 busted++;
451 if (!check_hostserv(nconf, HOST_SELF, "rpcbind"))
452 busted++;
453 if (!check_hostserv(nconf, HOST_SELF_CONNECT, "rpcbind"))
454 busted++;
456 freenetconfigent(nconf);
458 endnetconfig(nc);
460 if (lo_clts_found) {
461 if (debugging)
462 fprintf(stderr, "Found CLTS loopback transport\n");
463 } else {
464 syslog(LOG_ALERT, "no CLTS loopback transport found\n");
465 if (debugging)
466 fprintf(stderr, "no CLTS loopback transport found\n");
468 if (lo_cots_found) {
469 if (debugging)
470 fprintf(stderr, "Found COTS loopback transport\n");
471 } else {
472 syslog(LOG_ALERT, "no COTS loopback transport found\n");
473 if (debugging)
474 fprintf(stderr, "no COTS loopback transport found\n");
476 if (lo_cotsord_found) {
477 if (debugging)
478 fprintf(stderr, "Found COTS ORD loopback transport\n");
479 } else {
480 syslog(LOG_ALERT, "no COTS ORD loopback transport found\n");
481 if (debugging)
482 fprintf(stderr,
483 "no COTS ORD loopback transport found\n");
486 return (busted);
490 * Adds the entry into the rpcbind database.
491 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
492 * Returns 0 if succeeds, else fails
494 static int
495 init_transport(struct netconfig *nconf)
497 int fd;
498 struct t_bind *taddr, *baddr;
499 SVCXPRT *my_xprt;
500 struct nd_addrlist *nas;
501 struct nd_hostserv hs;
502 static int msgprt = 0;
504 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
505 (nconf->nc_semantics != NC_TPI_COTS) &&
506 (nconf->nc_semantics != NC_TPI_COTS_ORD))
507 return (1); /* not my type */
509 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && !ipv6flag) {
510 if (!msgprt)
511 syslog(LOG_DEBUG, "/etc/netconfig has IPv6 entries but "
512 "IPv6 is not configured");
513 msgprt++;
514 return (1);
517 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) {
518 syslog(LOG_ERR, "%s: cannot open connection: %s",
519 nconf->nc_netid, t_errlist[t_errno]);
520 return (1);
523 if (is_system_labeled() &&
524 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
525 strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
526 setopt_anon_mlp(fd) == -1) {
527 syslog(LOG_ERR, "%s: couldn't set SO_ANON_MLP option",
528 nconf->nc_netid);
532 * Negotiate for returning the ucred of the caller. This should
533 * done before enabling the endpoint for service via
534 * t_bind() so that requests to rpcbind contain the uid.
536 svc_fd_negotiate_ucred(fd);
538 taddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
539 baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
540 if ((baddr == NULL) || (taddr == NULL)) {
541 syslog(LOG_ERR, "%s: cannot allocate netbuf: %s",
542 nconf->nc_netid, t_errlist[t_errno]);
543 exit(1);
546 /* Get rpcbind's address on this transport */
547 hs.h_host = HOST_SELF;
548 hs.h_serv = servname;
549 if (netdir_getbyname(nconf, &hs, &nas))
550 goto error;
552 /* Copy the address */
553 taddr->addr.len = nas->n_addrs->len;
554 memcpy(taddr->addr.buf, nas->n_addrs->buf, (int)nas->n_addrs->len);
555 netdir_free((char *)nas, ND_ADDRLIST);
557 if (nconf->nc_semantics == NC_TPI_CLTS)
558 taddr->qlen = 0;
559 else
560 taddr->qlen = listen_backlog;
562 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
564 * Sm: If we are running then set SO_REUSEADDR option
565 * so that we can bind to our preferred address even if
566 * previous connections are in FIN_WAIT state
568 if (setopt_reuseaddr(fd) == -1) {
569 syslog(LOG_ERR, "Couldn't set SO_REUSEADDR option");
573 if (t_bind(fd, taddr, baddr) != 0) {
574 syslog(LOG_ERR, "%s: cannot bind: %s",
575 nconf->nc_netid, t_errlist[t_errno]);
576 goto error;
579 if (nconf->nc_semantics != NC_TPI_CLTS && taddr->qlen != baddr->qlen)
580 syslog(LOG_NOTICE, "%s: unable to set listen backlog to %d "
581 "(negotiated: %d)", nconf->nc_netid, taddr->qlen,
582 baddr->qlen);
584 if (memcmp(taddr->addr.buf, baddr->addr.buf, (int)baddr->addr.len)) {
585 syslog(LOG_ERR, "%s: address in use", nconf->nc_netid);
586 goto error;
589 my_xprt = svc_tli_create(fd, nconf, baddr, 0, 0);
590 if (my_xprt == NULL) {
591 syslog(LOG_ERR, "%s: could not create service",
592 nconf->nc_netid);
593 goto error;
596 /* set up multicast address for RPC CALL_IT, IPv6 */
598 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
599 (strcmp(nconf->nc_proto, NC_UDP) == 0)) {
600 if (setup_callit(fd) < 0) {
601 syslog(LOG_ERR, "Unable to join IPv6 multicast group "
602 "for rpc broadcast %s", RPCB_MULTICAST_ADDR);
606 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
607 svc_control(my_xprt, SVCSET_KEEPALIVE, (void *) TRUE);
610 #ifdef PORTMAP
612 * Register both the versions for tcp/ip and udp/ip
614 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
615 ((strcmp(nconf->nc_proto, NC_TCP) == 0) ||
616 (strcmp(nconf->nc_proto, NC_UDP) == 0))) {
617 PMAPLIST *pml;
619 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
620 pmap_service, NULL)) {
621 syslog(LOG_ERR, "could not register on %s",
622 nconf->nc_netid);
623 goto error;
625 pml = malloc(sizeof (PMAPLIST));
626 if (pml == NULL) {
627 syslog(LOG_ERR, "no memory!");
628 exit(1);
630 pml->pml_map.pm_prog = PMAPPROG;
631 pml->pml_map.pm_vers = PMAPVERS;
632 pml->pml_map.pm_port = PMAPPORT;
633 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
634 if (tcptrans[0]) {
635 syslog(LOG_ERR,
636 "cannot have more than one TCP transport");
637 goto error;
639 tcptrans = strdup(nconf->nc_netid);
640 pml->pml_map.pm_prot = IPPROTO_TCP;
642 /* Let's snarf the universal address */
643 /* "h1.h2.h3.h4.p1.p2" */
644 tcp_uaddr = taddr2uaddr(nconf, &baddr->addr);
645 } else {
646 if (udptrans[0]) {
647 syslog(LOG_ERR,
648 "cannot have more than one UDP transport");
649 goto error;
651 udptrans = strdup(nconf->nc_netid);
652 pml->pml_map.pm_prot = IPPROTO_UDP;
654 /* Let's snarf the universal address */
655 /* "h1.h2.h3.h4.p1.p2" */
656 udp_uaddr = taddr2uaddr(nconf, &baddr->addr);
658 pml->pml_next = list_pml;
659 list_pml = pml;
661 /* Add version 3 information */
662 pml = malloc(sizeof (PMAPLIST));
663 if (pml == NULL) {
664 syslog(LOG_ERR, "no memory!");
665 exit(1);
667 pml->pml_map = list_pml->pml_map;
668 pml->pml_map.pm_vers = RPCBVERS;
669 pml->pml_next = list_pml;
670 list_pml = pml;
672 /* Add version 4 information */
673 pml = malloc(sizeof (PMAPLIST));
674 if (pml == NULL) {
675 syslog(LOG_ERR, "no memory!");
676 exit(1);
678 pml->pml_map = list_pml->pml_map;
679 pml->pml_map.pm_vers = RPCBVERS4;
680 pml->pml_next = list_pml;
681 list_pml = pml;
683 /* Also add version 2 stuff to rpcbind list */
684 rbllist_add(PMAPPROG, PMAPVERS, nconf, &baddr->addr);
686 #endif
688 /* version 3 registration */
689 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
690 syslog(LOG_ERR, "could not register %s version 3",
691 nconf->nc_netid);
692 goto error;
694 rbllist_add(RPCBPROG, RPCBVERS, nconf, &baddr->addr);
696 /* version 4 registration */
697 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
698 syslog(LOG_ERR, "could not register %s version 4",
699 nconf->nc_netid);
700 goto error;
702 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &baddr->addr);
704 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
705 if (nconf->nc_semantics == NC_TPI_CLTS)
706 loopback_dg = strdup(nconf->nc_netid);
707 else if (nconf->nc_semantics == NC_TPI_COTS)
708 loopback_vc = strdup(nconf->nc_netid);
709 else if (nconf->nc_semantics == NC_TPI_COTS_ORD)
710 loopback_vc_ord = strdup(nconf->nc_netid);
713 /* decide if bound checking works for this transport */
714 (void) add_bndlist(nconf, taddr, baddr);
717 * rmtcall only supported on CLTS transports for now.
719 if (nconf->nc_semantics == NC_TPI_CLTS)
720 (void) create_rmtcall_fd(nconf);
722 (void) t_free((char *)taddr, T_BIND);
723 (void) t_free((char *)baddr, T_BIND);
724 return (0);
725 error:
726 (void) t_free((char *)taddr, T_BIND);
727 (void) t_free((char *)baddr, T_BIND);
728 (void) t_close(fd);
729 return (1);
732 static void
733 rbllist_add(ulong_t prog, ulong_t vers, struct netconfig *nconf,
734 struct netbuf *addr)
736 rpcblist_ptr rbl;
738 rbl = malloc(sizeof (rpcblist));
739 if (rbl == NULL) {
740 syslog(LOG_ERR, "no memory!");
741 exit(1);
744 rbl->rpcb_map.r_prog = prog;
745 rbl->rpcb_map.r_vers = vers;
746 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
747 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
748 if (rbl->rpcb_map.r_addr == NULL)
749 rbl->rpcb_map.r_addr = strdup("");
750 rbl->rpcb_map.r_owner = strdup(superuser);
752 if (rbl->rpcb_map.r_netid == NULL || rbl->rpcb_map.r_addr == NULL ||
753 rbl->rpcb_map.r_owner == NULL) {
754 syslog(LOG_ERR, "no memory!");
755 exit(1);
758 rbl->rpcb_next = list_rbl; /* Attach to global list */
759 list_rbl = rbl;
763 * Catch the signal and die, if not SIGHUP
765 static void
766 terminate(void)
768 int sig;
770 for (;;) {
771 sig = sigwait(&sigwaitset);
772 if (sig == SIGHUP) {
773 rpcb_check_init();
774 continue;
776 if (sig != -1 || errno != EINTR)
777 break;
780 syslog(LOG_ERR, "rpcbind terminating on signal %d.", sig);
782 rw_wrlock(&list_rbl_lock);
783 #ifdef PORTMAP
784 rw_wrlock(&list_pml_lock);
785 #endif
786 write_warmstart(); /* Dump yourself */
788 exit(2);
791 void
792 rpcbind_abort(void)
795 * We need to hold write locks to make sure
796 * write_warmstart() is executed exactly once
798 rw_wrlock(&list_rbl_lock);
799 #ifdef PORTMAP
800 rw_wrlock(&list_pml_lock);
801 #endif
802 write_warmstart(); /* Dump yourself */
804 abort();
808 * detach from tty
810 static void
811 detachfromtty(void)
813 close(0);
814 close(1);
815 close(2);
816 switch (forkall()) {
817 case (pid_t)-1:
818 perror("fork");
819 break;
820 case 0:
821 break;
822 default:
823 exit(0);
825 setsid();
826 (void) open("/dev/null", O_RDWR, 0);
827 dup(0);
828 dup(0);
831 static int
832 convert_int(int *val, char *str)
834 long lval;
836 if (str == NULL || !isdigit(*str))
837 return (-1);
839 lval = strtol(str, &str, 10);
840 if (*str != '\0' || lval > INT_MAX)
841 return (-2);
843 *val = (int)lval;
844 return (0);
847 static int get_smf_iprop(const char *, int, int, int);
849 /* get command line options */
850 static void
851 parseargs(int argc, char *argv[])
853 int c;
854 int tmp;
856 listen_backlog = get_smf_iprop("listen_backlog", 64, 1, INT_MAX);
858 while ((c = getopt(argc, argv, "dwal:")) != EOF) {
859 switch (c) {
860 case 'd':
861 debugging = 1;
862 break;
863 case 'a':
864 doabort = 1; /* when debugging, do an abort on */
865 break; /* errors; for rpcbind developers */
866 /* only! */
867 case 'w':
868 warmstart = 1;
869 break;
871 case 'l':
872 if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
873 (void) fprintf(stderr, "%s: invalid "
874 "listen_backlog option, using defaults\n",
875 argv[0]);
876 break;
878 listen_backlog = tmp;
879 break;
880 default: /* error */
881 fprintf(stderr,
882 "usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
883 exit(1);
886 if (doabort && !debugging) {
887 fprintf(stderr,
888 "-a (abort) specified without -d "
889 "(debugging) -- ignored.\n");
890 doabort = 0;
894 static int
895 setopt_int(int fd, int level, int name, int value)
897 struct t_optmgmt req, resp;
898 struct {
899 struct opthdr opt;
900 int value;
901 } optdata;
903 optdata.opt.level = level;
904 optdata.opt.name = name;
905 optdata.opt.len = sizeof (int);
907 optdata.value = value;
909 req.flags = T_NEGOTIATE;
910 req.opt.len = sizeof (optdata);
911 req.opt.buf = (char *)&optdata;
913 resp.flags = 0;
914 resp.opt.buf = (char *)&optdata;
915 resp.opt.maxlen = sizeof (optdata);
917 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
918 t_error("t_optmgmt");
919 return (-1);
921 return (0);
924 static int
925 setopt_reuseaddr(int fd)
927 return (setopt_int(fd, SOL_SOCKET, SO_REUSEADDR, 1));
930 static int
931 setopt_anon_mlp(int fd)
933 return (setopt_int(fd, SOL_SOCKET, SO_ANON_MLP, 1));
936 static int
937 setup_callit(int fd)
939 struct ipv6_mreq mreq;
940 struct t_optmgmt req, resp;
941 struct opthdr *opt;
942 char reqbuf[ sizeof (struct ipv6_mreq) + 24];
943 struct ipv6_mreq *pmreq;
945 opt = (struct opthdr *)reqbuf;
947 opt->level = IPPROTO_IPV6;
948 opt->name = IPV6_ADD_MEMBERSHIP;
949 opt->len = sizeof (struct ipv6_mreq);
951 /* multicast address */
952 (void) inet_pton(AF_INET6, RPCB_MULTICAST_ADDR,
953 mreq.ipv6mr_multiaddr.s6_addr);
954 mreq.ipv6mr_interface = 0;
956 /* insert it into opt */
957 pmreq = (struct ipv6_mreq *)&reqbuf[sizeof (struct opthdr)];
958 memcpy(pmreq, &mreq, sizeof (struct ipv6_mreq));
960 req.flags = T_NEGOTIATE;
961 req.opt.len = sizeof (struct opthdr) + opt->len;
962 req.opt.buf = (char *)opt;
964 resp.flags = 0;
965 resp.opt.buf = reqbuf;
966 resp.opt.maxlen = sizeof (reqbuf);
968 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
969 t_error("t_optmgmt");
970 return (-1);
972 return (0);
975 static boolean_t
976 check_hostserv(struct netconfig *nconf, const char *host, const char *serv)
978 struct nd_hostserv nh;
979 struct nd_addrlist *na;
980 const char *hostname = host;
981 const char *servname = serv;
982 int retval;
984 if (strcmp(host, HOST_SELF) == 0)
985 hostname = "HOST_SELF";
986 else if (strcmp(host, HOST_SELF_CONNECT) == 0)
987 hostname = "HOST_SELF_CONNECT";
989 if (serv[0] == '\0')
990 servname = "<any>";
992 nh.h_host = (char *)host;
993 nh.h_serv = (char *)serv;
995 retval = netdir_getbyname(nconf, &nh, &na);
996 if (retval != ND_OK || na->n_cnt == 0) {
997 if (retval == ND_OK)
998 netdir_free(na, ND_ADDRLIST);
1000 syslog(LOG_ALERT, "netid %s: cannot find an address for host "
1001 "%s, service \"%s\"", nconf->nc_netid, hostname, servname);
1002 if (debugging) {
1003 (void) fprintf(stderr, "\tnetdir_getbyname for %s, "
1004 "service \"%s\" failed\n", hostname, servname);
1006 return (B_FALSE);
1008 netdir_free(na, ND_ADDRLIST);
1010 if (debugging) {
1011 (void) fprintf(stderr, "\tnetdir_getbyname for %s, service "
1012 "service \"%s\" succeeded\n", hostname, servname);
1014 return (B_TRUE);
1017 /* Maximum outstanding syslog requests */
1018 #define MAXLOG 100
1019 /* Maximum length: the messages generated are fairly short; no hostnames. */
1020 #define MAXMSG 128
1022 typedef struct logmsg {
1023 struct logmsg *log_next;
1024 int log_pri;
1025 char log_msg[MAXMSG];
1026 } logmsg;
1028 static logmsg *loghead = NULL;
1029 static logmsg **logtailp = &loghead;
1030 static mutex_t logmutex = DEFAULTMUTEX;
1031 static cond_t logcond = DEFAULTCV;
1032 static int logcount = 0;
1034 /* ARGSUSED */
1035 static void * __NORETURN
1036 logthread(void *arg)
1038 for (;;) {
1039 logmsg *msg;
1040 (void) mutex_lock(&logmutex);
1041 while ((msg = loghead) == NULL)
1042 (void) cond_wait(&logcond, &logmutex);
1044 loghead = msg->log_next;
1045 logcount--;
1046 if (loghead == NULL) {
1047 logtailp = &loghead;
1048 logcount = 0;
1050 (void) mutex_unlock(&logmutex);
1051 syslog(msg->log_pri, "%s", msg->log_msg);
1052 free(msg);
1054 /* NOTREACHED */
1057 static boolean_t
1058 get_smf_prop(const char *var, boolean_t def_val)
1060 scf_simple_prop_t *prop;
1061 uint8_t *val = NULL;
1062 boolean_t res = def_val;
1064 prop = scf_simple_prop_get(NULL, NULL, "config", var);
1065 if (prop != NULL) {
1066 if ((val = scf_simple_prop_next_boolean(prop)) != NULL)
1067 res = (*val == 0) ? B_FALSE : B_TRUE;
1068 scf_simple_prop_free(prop);
1071 if (prop == NULL || val == NULL) {
1072 syslog(LOG_ALERT, "no value for config/%s (%s). "
1073 "Using default \"%s\"", var, scf_strerror(scf_error()),
1074 def_val ? "true" : "false");
1077 return (res);
1080 static int
1081 get_smf_iprop(const char *var, int def_val, int min, int max)
1083 scf_simple_prop_t *prop;
1084 int64_t *val = NULL;
1085 int res = def_val;
1087 prop = scf_simple_prop_get(NULL, NULL, "config", var);
1088 if (prop != NULL) {
1089 if ((val = scf_simple_prop_next_integer(prop)) != NULL) {
1090 if (*val < min || *val > max)
1091 syslog(LOG_ALERT, "value for config/%s out of "
1092 "range. Using default %d", var, def_val);
1093 else
1094 res = (int)*val;
1096 scf_simple_prop_free(prop);
1099 if (prop == NULL || val == NULL) {
1100 syslog(LOG_ALERT, "no value for config/%s (%s). "
1101 "Using default %d", var, scf_strerror(scf_error()),
1102 def_val);
1105 return (res);
1109 * Initialize: read the configuration parameters from SMF.
1110 * This function must be idempotent because it can be called from the
1111 * signal handler.
1113 static void
1114 rpcb_check_init(void)
1116 thread_t tid;
1117 int max_threads;
1118 static int thr_running;
1120 wrap_enabled = get_smf_prop("enable_tcpwrappers", B_FALSE);
1121 verboselog = get_smf_prop("verbose_logging", B_FALSE);
1122 allow_indirect = get_smf_prop("allow_indirect", B_TRUE);
1123 local_only = get_smf_prop("local_only", B_TRUE);
1125 if (wrap_enabled && !thr_running) {
1126 (void) thr_create(NULL, 0, logthread, NULL, THR_DETACHED, &tid);
1127 thr_running = 1;
1131 * Set the maximum number of threads.
1133 max_threads = get_smf_iprop("max_threads", 72, 1, INT_MAX);
1134 if (!rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
1135 int tmp;
1138 * The following rpc_control() call cannot fail
1140 if (!rpc_control(RPC_SVC_THRMAX_GET, &tmp))
1141 assert(0);
1143 if (tmp != max_threads) {
1144 syslog(LOG_ERR, "setting max_threads to %d failed, "
1145 "using %d worker threads", max_threads, tmp);
1146 max_threads = tmp;
1151 * Set rpcb_rmtcalls_max.
1153 if (max_threads < reserved_threads)
1154 set_rpcb_rmtcalls_max(0);
1155 else
1156 set_rpcb_rmtcalls_max(max_threads - reserved_threads);
1160 * qsyslog() - queue a request for syslog(); if syslog blocks, the other
1161 * thread blocks; we make sure we don't run out of memory by allowing
1162 * only a limited number of outstandig syslog() requests.
1164 void
1165 qsyslog(int pri, const char *fmt, ...)
1167 logmsg *msg = malloc(sizeof (*msg));
1168 va_list ap;
1170 if (msg == NULL)
1171 return;
1173 msg->log_pri = pri;
1175 va_start(ap, fmt);
1176 (void) vsnprintf(msg->log_msg, sizeof (msg->log_msg), fmt, ap);
1177 va_end(ap);
1179 msg->log_next = NULL;
1181 (void) mutex_lock(&logmutex);
1182 if (logcount < MAXLOG) {
1183 if (logcount == 0)
1184 (void) cond_signal(&logcond);
1185 logcount++;
1186 *logtailp = msg;
1187 logtailp = &msg->log_next;
1188 (void) mutex_unlock(&logmutex);
1189 } else {
1190 (void) mutex_unlock(&logmutex);
1191 free(msg);