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 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
;
175 static int warmstart
= 0; /* Grab a old copy of registrations */
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 */
190 static char servname
[] = "rpcbind";
191 static char superuser
[] = "superuser";
193 static const char daemon_dir
[] = DAEMON_DIR
;
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 */
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
;
223 parseargs(argc
, argv
);
225 if (getrlimit(RLIMIT_NOFILE
, &rl
) != 0) {
226 syslog(LOG_ERR
, "getrlimit failed");
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
);
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");
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");
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
293 trouble
= check_netconfig();
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",
306 loopback_vc_ord
= "";
312 ipv6flag
= Is_ipv6present();
315 nc_handle
= setnetconfig(); /* open netconfig file */
316 if (nc_handle
== NULL
) {
317 syslog(LOG_ERR
, "could not read /etc/netconfig");
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");
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");
343 printf("rpcbind debugging enabled.");
345 printf(" Will abort on errors!\n");
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
);
358 syslog(LOG_ERR
, "svc_run returned unexpectedly");
364 * Increments a counter each time a problem is found with the network
365 * configuration information.
368 check_netconfig(void)
374 int lo_clts_found
= 0, lo_cots_found
= 0, lo_cotsord_found
= 0;
375 struct netconfig
*nconf
, *np
;
382 "setnetconfig() failed: %s\n", nc_sperror());
383 syslog(LOG_ALERT
, "setnetconfig() failed: %s", nc_sperror());
386 while ((np
= getnetconfig(nc
)) != NULL
) {
387 if ((np
->nc_flag
& NC_VISIBLE
) == 0)
390 fprintf(stderr
, "checking netid \"%s\"\n",
392 if (strcmp(np
->nc_protofmly
, NC_LOOPBACK
) == 0)
393 switch (np
->nc_semantics
) {
402 case NC_TPI_COTS_ORD
:
403 lo_cotsord_found
= 1;
406 if (stat(np
->nc_device
, &sb
) == -1 && errno
== ENOENT
) {
408 fprintf(stderr
, "\tdevice %s does not exist\n",
410 syslog(LOG_ERR
, "netid %s: device %s does not exist",
411 np
->nc_netid
, np
->nc_device
);
415 fprintf(stderr
, "\tdevice %s present\n",
417 for (i
= 0; i
< np
->nc_nlookups
; i
++) {
418 char *libname
= np
->nc_lookups
[i
];
420 if ((dlcookie
= dlopen(libname
, RTLD_LAZY
)) == NULL
) {
423 dlerrstr
= dlerror();
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
);
435 syslog(LOG_ERR
, "%s", dlerrstr
);
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
, ""))
449 if (!check_hostserv(nconf
, HOST_SELF_CONNECT
, ""))
451 if (!check_hostserv(nconf
, HOST_SELF
, "rpcbind"))
453 if (!check_hostserv(nconf
, HOST_SELF_CONNECT
, "rpcbind"))
456 freenetconfigent(nconf
);
462 fprintf(stderr
, "Found CLTS loopback transport\n");
464 syslog(LOG_ALERT
, "no CLTS loopback transport found\n");
466 fprintf(stderr
, "no CLTS loopback transport found\n");
470 fprintf(stderr
, "Found COTS loopback transport\n");
472 syslog(LOG_ALERT
, "no COTS loopback transport found\n");
474 fprintf(stderr
, "no COTS loopback transport found\n");
476 if (lo_cotsord_found
) {
478 fprintf(stderr
, "Found COTS ORD loopback transport\n");
480 syslog(LOG_ALERT
, "no COTS ORD loopback transport found\n");
483 "no COTS ORD loopback transport found\n");
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
495 init_transport(struct netconfig
*nconf
)
498 struct t_bind
*taddr
, *baddr
;
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
) {
511 syslog(LOG_DEBUG
, "/etc/netconfig has IPv6 entries but "
512 "IPv6 is not configured");
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
]);
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",
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
]);
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
))
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
)
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
]);
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
,
584 if (memcmp(taddr
->addr
.buf
, baddr
->addr
.buf
, (int)baddr
->addr
.len
)) {
585 syslog(LOG_ERR
, "%s: address in use", nconf
->nc_netid
);
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",
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
);
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))) {
619 if (!svc_register(my_xprt
, PMAPPROG
, PMAPVERS
,
620 pmap_service
, NULL
)) {
621 syslog(LOG_ERR
, "could not register on %s",
625 pml
= malloc(sizeof (PMAPLIST
));
627 syslog(LOG_ERR
, "no memory!");
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) {
636 "cannot have more than one TCP transport");
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
);
648 "cannot have more than one UDP transport");
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
;
661 /* Add version 3 information */
662 pml
= malloc(sizeof (PMAPLIST
));
664 syslog(LOG_ERR
, "no memory!");
667 pml
->pml_map
= list_pml
->pml_map
;
668 pml
->pml_map
.pm_vers
= RPCBVERS
;
669 pml
->pml_next
= list_pml
;
672 /* Add version 4 information */
673 pml
= malloc(sizeof (PMAPLIST
));
675 syslog(LOG_ERR
, "no memory!");
678 pml
->pml_map
= list_pml
->pml_map
;
679 pml
->pml_map
.pm_vers
= RPCBVERS4
;
680 pml
->pml_next
= list_pml
;
683 /* Also add version 2 stuff to rpcbind list */
684 rbllist_add(PMAPPROG
, PMAPVERS
, nconf
, &baddr
->addr
);
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",
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",
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
);
726 (void) t_free((char *)taddr
, T_BIND
);
727 (void) t_free((char *)baddr
, T_BIND
);
733 rbllist_add(ulong_t prog
, ulong_t vers
, struct netconfig
*nconf
,
738 rbl
= malloc(sizeof (rpcblist
));
740 syslog(LOG_ERR
, "no memory!");
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!");
758 rbl
->rpcb_next
= list_rbl
; /* Attach to global list */
763 * Catch the signal and die, if not SIGHUP
771 sig
= sigwait(&sigwaitset
);
776 if (sig
!= -1 || errno
!= EINTR
)
780 syslog(LOG_ERR
, "rpcbind terminating on signal %d.", sig
);
782 rw_wrlock(&list_rbl_lock
);
784 rw_wrlock(&list_pml_lock
);
786 write_warmstart(); /* Dump yourself */
795 * We need to hold write locks to make sure
796 * write_warmstart() is executed exactly once
798 rw_wrlock(&list_rbl_lock
);
800 rw_wrlock(&list_pml_lock
);
802 write_warmstart(); /* Dump yourself */
826 (void) open("/dev/null", O_RDWR
, 0);
832 convert_int(int *val
, char *str
)
836 if (str
== NULL
|| !isdigit(*str
))
839 lval
= strtol(str
, &str
, 10);
840 if (*str
!= '\0' || lval
> INT_MAX
)
847 static int get_smf_iprop(const char *, int, int, int);
849 /* get command line options */
851 parseargs(int argc
, char *argv
[])
856 listen_backlog
= get_smf_iprop("listen_backlog", 64, 1, INT_MAX
);
858 while ((c
= getopt(argc
, argv
, "dwal:")) != EOF
) {
864 doabort
= 1; /* when debugging, do an abort on */
865 break; /* errors; for rpcbind developers */
872 if (convert_int(&tmp
, optarg
) != 0 || tmp
< 1) {
873 (void) fprintf(stderr
, "%s: invalid "
874 "listen_backlog option, using defaults\n",
878 listen_backlog
= tmp
;
882 "usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
886 if (doabort
&& !debugging
) {
888 "-a (abort) specified without -d "
889 "(debugging) -- ignored.\n");
895 setopt_int(int fd
, int level
, int name
, int value
)
897 struct t_optmgmt req
, resp
;
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
;
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");
925 setopt_reuseaddr(int fd
)
927 return (setopt_int(fd
, SOL_SOCKET
, SO_REUSEADDR
, 1));
931 setopt_anon_mlp(int fd
)
933 return (setopt_int(fd
, SOL_SOCKET
, SO_ANON_MLP
, 1));
939 struct ipv6_mreq mreq
;
940 struct t_optmgmt req
, resp
;
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
;
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");
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
;
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";
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) {
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
);
1003 (void) fprintf(stderr
, "\tnetdir_getbyname for %s, "
1004 "service \"%s\" failed\n", hostname
, servname
);
1008 netdir_free(na
, ND_ADDRLIST
);
1011 (void) fprintf(stderr
, "\tnetdir_getbyname for %s, service "
1012 "service \"%s\" succeeded\n", hostname
, servname
);
1017 /* Maximum outstanding syslog requests */
1019 /* Maximum length: the messages generated are fairly short; no hostnames. */
1022 typedef struct logmsg
{
1023 struct logmsg
*log_next
;
1025 char log_msg
[MAXMSG
];
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;
1035 static void * __NORETURN
1036 logthread(void *arg
)
1040 (void) mutex_lock(&logmutex
);
1041 while ((msg
= loghead
) == NULL
)
1042 (void) cond_wait(&logcond
, &logmutex
);
1044 loghead
= msg
->log_next
;
1046 if (loghead
== NULL
) {
1047 logtailp
= &loghead
;
1050 (void) mutex_unlock(&logmutex
);
1051 syslog(msg
->log_pri
, "%s", msg
->log_msg
);
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
);
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");
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
;
1087 prop
= scf_simple_prop_get(NULL
, NULL
, "config", var
);
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
);
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()),
1109 * Initialize: read the configuration parameters from SMF.
1110 * This function must be idempotent because it can be called from the
1114 rpcb_check_init(void)
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
);
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
)) {
1138 * The following rpc_control() call cannot fail
1140 if (!rpc_control(RPC_SVC_THRMAX_GET
, &tmp
))
1143 if (tmp
!= max_threads
) {
1144 syslog(LOG_ERR
, "setting max_threads to %d failed, "
1145 "using %d worker threads", max_threads
, tmp
);
1151 * Set rpcb_rmtcalls_max.
1153 if (max_threads
< reserved_threads
)
1154 set_rpcb_rmtcalls_max(0);
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.
1165 qsyslog(int pri
, const char *fmt
, ...)
1167 logmsg
*msg
= malloc(sizeof (*msg
));
1176 (void) vsnprintf(msg
->log_msg
, sizeof (msg
->log_msg
), fmt
, ap
);
1179 msg
->log_next
= NULL
;
1181 (void) mutex_lock(&logmutex
);
1182 if (logcount
< MAXLOG
) {
1184 (void) cond_signal(&logcond
);
1187 logtailp
= &msg
->log_next
;
1188 (void) mutex_unlock(&logmutex
);
1190 (void) mutex_unlock(&logmutex
);