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]
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
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
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
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
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.
98 #include <stdio_ext.h>
99 #include <sys/types.h>
104 #include <netconfig.h>
107 #include <sys/wait.h>
115 #include <netinet/in.h>
117 #include <arpa/inet.h>
118 #include <sys/termios.h>
120 #include <sys/syslog.h>
121 #include <sys/stat.h>
124 #include <sys/time.h>
125 #include <sys/resource.h>
126 #include <rpcsvc/daemon_utils.h>
127 #include <priv_utils.h>
129 #include <sys/ccompile.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
;
174 static int warmstart
= 0; /* Grab a old copy of registrations */
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 */
189 static char servname
[] = "rpcbind";
190 static char superuser
[] = "superuser";
192 static const char daemon_dir
[] = DAEMON_DIR
;
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 */
215 int rpc_svc_fdunlim
= 1;
216 int rpc_svc_mode
= RPC_SVC_MT_AUTO
;
217 int maxrecsz
= RPC_MAXDATASIZE
;
221 parseargs(argc
, argv
);
223 if (getrlimit(RLIMIT_NOFILE
, &rl
) != 0) {
224 syslog(LOG_ERR
, "getrlimit failed");
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
);
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");
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");
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
289 trouble
= check_netconfig();
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",
302 loopback_vc_ord
= "";
308 ipv6flag
= Is_ipv6present();
311 nc_handle
= setnetconfig(); /* open netconfig file */
312 if (nc_handle
== NULL
) {
313 syslog(LOG_ERR
, "could not read /etc/netconfig");
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");
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");
339 printf("rpcbind debugging enabled.");
341 printf(" Will abort on errors!\n");
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
);
354 syslog(LOG_ERR
, "svc_run returned unexpectedly");
360 * Increments a counter each time a problem is found with the network
361 * configuration information.
364 check_netconfig(void)
370 int lo_clts_found
= 0, lo_cots_found
= 0, lo_cotsord_found
= 0;
371 struct netconfig
*nconf
, *np
;
378 "setnetconfig() failed: %s\n", nc_sperror());
379 syslog(LOG_ALERT
, "setnetconfig() failed: %s", nc_sperror());
382 while ((np
= getnetconfig(nc
)) != NULL
) {
383 if ((np
->nc_flag
& NC_VISIBLE
) == 0)
386 fprintf(stderr
, "checking netid \"%s\"\n",
388 if (strcmp(np
->nc_protofmly
, NC_LOOPBACK
) == 0)
389 switch (np
->nc_semantics
) {
398 case NC_TPI_COTS_ORD
:
399 lo_cotsord_found
= 1;
402 if (stat(np
->nc_device
, &sb
) == -1 && errno
== ENOENT
) {
404 fprintf(stderr
, "\tdevice %s does not exist\n",
406 syslog(LOG_ERR
, "netid %s: device %s does not exist",
407 np
->nc_netid
, np
->nc_device
);
411 fprintf(stderr
, "\tdevice %s present\n",
413 for (i
= 0; i
< np
->nc_nlookups
; i
++) {
414 char *libname
= np
->nc_lookups
[i
];
416 if ((dlcookie
= dlopen(libname
, RTLD_LAZY
)) == NULL
) {
419 dlerrstr
= dlerror();
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
);
431 syslog(LOG_ERR
, "%s", dlerrstr
);
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
, ""))
445 if (!check_hostserv(nconf
, HOST_SELF_CONNECT
, ""))
447 if (!check_hostserv(nconf
, HOST_SELF
, "rpcbind"))
449 if (!check_hostserv(nconf
, HOST_SELF_CONNECT
, "rpcbind"))
452 freenetconfigent(nconf
);
458 fprintf(stderr
, "Found CLTS loopback transport\n");
460 syslog(LOG_ALERT
, "no CLTS loopback transport found\n");
462 fprintf(stderr
, "no CLTS loopback transport found\n");
466 fprintf(stderr
, "Found COTS loopback transport\n");
468 syslog(LOG_ALERT
, "no COTS loopback transport found\n");
470 fprintf(stderr
, "no COTS loopback transport found\n");
472 if (lo_cotsord_found
) {
474 fprintf(stderr
, "Found COTS ORD loopback transport\n");
476 syslog(LOG_ALERT
, "no COTS ORD loopback transport found\n");
479 "no COTS ORD loopback transport found\n");
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
491 init_transport(struct netconfig
*nconf
)
494 struct t_bind
*taddr
, *baddr
;
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
) {
507 syslog(LOG_DEBUG
, "/etc/netconfig has IPv6 entries but "
508 "IPv6 is not configured");
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
]);
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
]);
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
))
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
)
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
]);
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
,
572 if (memcmp(taddr
->addr
.buf
, baddr
->addr
.buf
, (int)baddr
->addr
.len
)) {
573 syslog(LOG_ERR
, "%s: address in use", nconf
->nc_netid
);
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",
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
);
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))) {
607 if (!svc_register(my_xprt
, PMAPPROG
, PMAPVERS
,
609 syslog(LOG_ERR
, "could not register on %s",
613 pml
= malloc(sizeof (PMAPLIST
));
615 syslog(LOG_ERR
, "no memory!");
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) {
624 "cannot have more than one TCP transport");
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
);
636 "cannot have more than one UDP transport");
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
;
649 /* Add version 3 information */
650 pml
= malloc(sizeof (PMAPLIST
));
652 syslog(LOG_ERR
, "no memory!");
655 pml
->pml_map
= list_pml
->pml_map
;
656 pml
->pml_map
.pm_vers
= RPCBVERS
;
657 pml
->pml_next
= list_pml
;
660 /* Add version 4 information */
661 pml
= malloc(sizeof (PMAPLIST
));
663 syslog(LOG_ERR
, "no memory!");
666 pml
->pml_map
= list_pml
->pml_map
;
667 pml
->pml_map
.pm_vers
= RPCBVERS4
;
668 pml
->pml_next
= list_pml
;
671 /* Also add version 2 stuff to rpcbind list */
672 rbllist_add(PMAPPROG
, PMAPVERS
, nconf
, &baddr
->addr
);
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",
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",
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
);
714 (void) t_free((char *)taddr
, T_BIND
);
715 (void) t_free((char *)baddr
, T_BIND
);
721 rbllist_add(ulong_t prog
, ulong_t vers
, struct netconfig
*nconf
,
726 rbl
= malloc(sizeof (rpcblist
));
728 syslog(LOG_ERR
, "no memory!");
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!");
746 rbl
->rpcb_next
= list_rbl
; /* Attach to global list */
751 * Catch the signal and die, if not SIGHUP
759 sig
= sigwait(&sigwaitset
);
764 if (sig
!= -1 || errno
!= EINTR
)
768 syslog(LOG_ERR
, "rpcbind terminating on signal %d.", sig
);
770 rw_wrlock(&list_rbl_lock
);
772 rw_wrlock(&list_pml_lock
);
774 write_warmstart(); /* Dump yourself */
783 * We need to hold write locks to make sure
784 * write_warmstart() is executed exactly once
786 rw_wrlock(&list_rbl_lock
);
788 rw_wrlock(&list_pml_lock
);
790 write_warmstart(); /* Dump yourself */
814 (void) open("/dev/null", O_RDWR
, 0);
820 convert_int(int *val
, char *str
)
824 if (str
== NULL
|| !isdigit(*str
))
827 lval
= strtol(str
, &str
, 10);
828 if (*str
!= '\0' || lval
> INT_MAX
)
835 static int get_smf_iprop(const char *, int, int, int);
837 /* get command line options */
839 parseargs(int argc
, char *argv
[])
844 listen_backlog
= get_smf_iprop("listen_backlog", 64, 1, INT_MAX
);
846 while ((c
= getopt(argc
, argv
, "dwal:")) != EOF
) {
852 doabort
= 1; /* when debugging, do an abort on */
853 break; /* errors; for rpcbind developers */
860 if (convert_int(&tmp
, optarg
) != 0 || tmp
< 1) {
861 (void) fprintf(stderr
, "%s: invalid "
862 "listen_backlog option, using defaults\n",
866 listen_backlog
= tmp
;
870 "usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
874 if (doabort
&& !debugging
) {
876 "-a (abort) specified without -d "
877 "(debugging) -- ignored.\n");
883 setopt_int(int fd
, int level
, int name
, int value
)
885 struct t_optmgmt req
, resp
;
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
;
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");
913 setopt_reuseaddr(int fd
)
915 return (setopt_int(fd
, SOL_SOCKET
, SO_REUSEADDR
, 1));
921 struct ipv6_mreq mreq
;
922 struct t_optmgmt req
, resp
;
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
;
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");
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
;
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";
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) {
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
);
985 (void) fprintf(stderr
, "\tnetdir_getbyname for %s, "
986 "service \"%s\" failed\n", hostname
, servname
);
990 netdir_free(na
, ND_ADDRLIST
);
993 (void) fprintf(stderr
, "\tnetdir_getbyname for %s, service "
994 "service \"%s\" succeeded\n", hostname
, servname
);
999 /* Maximum outstanding syslog requests */
1001 /* Maximum length: the messages generated are fairly short; no hostnames. */
1004 typedef struct logmsg
{
1005 struct logmsg
*log_next
;
1007 char log_msg
[MAXMSG
];
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;
1017 static void * __NORETURN
1018 logthread(void *arg
)
1022 (void) mutex_lock(&logmutex
);
1023 while ((msg
= loghead
) == NULL
)
1024 (void) cond_wait(&logcond
, &logmutex
);
1026 loghead
= msg
->log_next
;
1028 if (loghead
== NULL
) {
1029 logtailp
= &loghead
;
1032 (void) mutex_unlock(&logmutex
);
1033 syslog(msg
->log_pri
, "%s", msg
->log_msg
);
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
);
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");
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
;
1069 prop
= scf_simple_prop_get(NULL
, NULL
, "config", var
);
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
);
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()),
1091 * Initialize: read the configuration parameters from SMF.
1092 * This function must be idempotent because it can be called from the
1096 rpcb_check_init(void)
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
);
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
)) {
1120 * The following rpc_control() call cannot fail
1122 if (!rpc_control(RPC_SVC_THRMAX_GET
, &tmp
))
1125 if (tmp
!= max_threads
) {
1126 syslog(LOG_ERR
, "setting max_threads to %d failed, "
1127 "using %d worker threads", max_threads
, tmp
);
1133 * Set rpcb_rmtcalls_max.
1135 if (max_threads
< reserved_threads
)
1136 set_rpcb_rmtcalls_max(0);
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.
1147 qsyslog(int pri
, const char *fmt
, ...)
1149 logmsg
*msg
= malloc(sizeof (*msg
));
1158 (void) vsnprintf(msg
->log_msg
, sizeof (msg
->log_msg
), fmt
, ap
);
1161 msg
->log_next
= NULL
;
1163 (void) mutex_lock(&logmutex
);
1164 if (logcount
< MAXLOG
) {
1166 (void) cond_signal(&logcond
);
1169 logtailp
= &msg
->log_next
;
1170 (void) mutex_unlock(&logmutex
);
1172 (void) mutex_unlock(&logmutex
);