1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27 /*
28 * University Copyright- Copyright (c) 1982, 1986, 1988
29 * The Regents of the University of California
30 * All Rights Reserved
31 *
32 * University Acknowledgment- Portions of this document are derived from
33 * software developed by the University of California, Berkeley, and its
34 * contributors.
35 */
36
37 #pragma ident "%Z%%M% %I% %E% SMI"
38
39 /*
40 * rpcbind.c
41 * Implements the program, version to address mapping for rpc.
42 *
43 */
44
45 #include <dlfcn.h>
46 #include <stdio.h>
47 #include <stdio_ext.h>
48 #include <sys/types.h>
49 #include <unistd.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <rpc/rpc.h>
53 #include <netconfig.h>
54 #include <netdir.h>
55 #include <errno.h>
56 #include <sys/wait.h>
57 #include <signal.h>
58 #include <string.h>
59 #include <stdlib.h>
60 #include <thread.h>
61 #include <synch.h>
62 #include <stdarg.h>
63 #ifdef PORTMAP
64 #include <netinet/in.h>
65 #endif
66 #include <arpa/inet.h>
67 #include <sys/termios.h>
68 #include "rpcbind.h"
69 #include <sys/syslog.h>
70 #include <sys/stat.h>
71 #include <syslog.h>
72 #include <string.h>
73 #include <sys/time.h>
74 #include <sys/resource.h>
75 #include <rpcsvc/daemon_utils.h>
76 #include <priv_utils.h>
77 #include <libscf.h>
78
79 #ifdef PORTMAP
80 extern void pmap_service(struct svc_req *, SVCXPRT *xprt);
81 #endif
82 extern void rpcb_service_3(struct svc_req *, SVCXPRT *xprt);
83 extern void rpcb_service_4(struct svc_req *, SVCXPRT *xprt);
84 extern void read_warmstart(void);
85 extern void write_warmstart(void);
86 extern int Is_ipv6present(void);
87
88 #define MAX_FILEDESC_LIMIT 1023
89
90 static void terminate(int);
91 static void note_refresh(int);
92 static void detachfromtty(void);
93 static void parseargs(int, char *[]);
94 static void rbllist_add(ulong_t, ulong_t, struct netconfig *, struct netbuf *);
95 static int init_transport(struct netconfig *);
96 static int check_netconfig(void);
97
98 static boolean_t check_hostserv(struct netconfig *, const char *, const char *);
99 static int setopt_reuseaddr(int);
100 static int setopt_anon_mlp(int);
101 static int setup_callit(int);
102
103 /* Global variables */
104 #ifdef ND_DEBUG
105 int debugging = 1; /* Tell me what's going on */
106 #else
107 int debugging = 0; /* Tell me what's going on */
108 #endif
109 static int ipv6flag = 0;
110 int doabort = 0; /* When debugging, do an abort on errors */
111 static int listen_backlog = 64;
112 rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */
113 char *loopback_dg; /* Datagram loopback transport, for set and unset */
114 char *loopback_vc; /* COTS loopback transport, for set and unset */
115 char *loopback_vc_ord; /* COTS_ORD loopback transport, for set and unset */
116
117 boolean_t verboselog = B_FALSE;
118 boolean_t wrap_enabled = B_FALSE;
119 boolean_t allow_indirect = B_TRUE;
120 boolean_t local_only = B_FALSE;
121
122 volatile sig_atomic_t sigrefresh;
123
124 /* Local Variable */
125 static int warmstart = 0; /* Grab a old copy of registrations */
126
127 #ifdef PORTMAP
128 PMAPLIST *list_pml; /* A list of version 2 rpcbind services */
129 char *udptrans; /* Name of UDP transport */
130 char *tcptrans; /* Name of TCP transport */
131 char *udp_uaddr; /* Universal UDP address */
132 char *tcp_uaddr; /* Universal TCP address */
133 #endif
134 static char servname[] = "rpcbind";
135 static char superuser[] = "superuser";
136
137 static const char daemon_dir[] = DAEMON_DIR;
138
139 int
main(int argc,char * argv[])140 main(int argc, char *argv[])
141 {
142 struct netconfig *nconf;
143 void *nc_handle; /* Net config handle */
144 struct rlimit rl;
145 int maxrecsz = RPC_MAXDATASIZE;
146 boolean_t can_do_mlp;
147
148 parseargs(argc, argv);
149
150 getrlimit(RLIMIT_NOFILE, &rl);
151
152 if (rl.rlim_cur < MAX_FILEDESC_LIMIT) {
153 if (rl.rlim_max <= MAX_FILEDESC_LIMIT)
154 rl.rlim_cur = rl.rlim_max;
155 else
156 rl.rlim_cur = MAX_FILEDESC_LIMIT;
157 setrlimit(RLIMIT_NOFILE, &rl);
158 }
159 (void) enable_extended_FILE_stdio(-1, -1);
160
161 openlog("rpcbind", LOG_CONS, LOG_DAEMON);
162
163 /*
164 * Create the daemon directory in /var/run
165 */
166 if (mkdir(daemon_dir, DAEMON_DIR_MODE) == 0 || errno == EEXIST) {
167 chmod(daemon_dir, DAEMON_DIR_MODE);
168 chown(daemon_dir, DAEMON_UID, DAEMON_GID);
169 } else {
170 syslog(LOG_ERR, "failed to create \"%s\": %m", daemon_dir);
171 }
172
173 /*
174 * These privileges are required for the t_bind check rpcbind uses
175 * to determine whether a service is still live or not.
176 */
177 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
178 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, DAEMON_UID,
179 DAEMON_GID, PRIV_NET_PRIVADDR, PRIV_SYS_NFS,
180 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
181 fprintf(stderr, "Insufficient privileges\n");
182 exit(1);
183 }
184
185 /*
186 * Enable non-blocking mode and maximum record size checks for
187 * connection oriented transports.
188 */
189 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
190 syslog(LOG_INFO, "unable to set RPC max record size");
191 }
192
193 nc_handle = setnetconfig(); /* open netconfig file */
194 if (nc_handle == NULL) {
195 syslog(LOG_ERR, "could not read /etc/netconfig");
196 exit(1);
197 }
198 loopback_dg = "";
199 loopback_vc = "";
200 loopback_vc_ord = "";
201 #ifdef PORTMAP
202 udptrans = "";
203 tcptrans = "";
204 #endif
205
206 {
207 /*
208 * rpcbind is the first application to encounter the
209 * various netconfig files. check_netconfig() verifies
210 * that they are set up correctly and complains loudly
211 * if not.
212 */
213 int trouble;
214
215 trouble = check_netconfig();
216 if (trouble) {
217 syslog(LOG_ERR,
218 "%s: found %d errors with network configuration files. Exiting.",
219 argv[0], trouble);
220 fprintf(stderr,
221 "%s: found %d errors with network configuration files. Exiting.\n",
222 argv[0], trouble);
223 exit(1);
224 }
225 }
226 ipv6flag = Is_ipv6present();
227 rpcb_check_init();
228 while (nconf = getnetconfig(nc_handle)) {
229 if (nconf->nc_flag & NC_VISIBLE)
230 init_transport(nconf);
231 }
232 endnetconfig(nc_handle);
233
234 if ((loopback_dg[0] == NULL) && (loopback_vc[0] == NULL) &&
235 (loopback_vc_ord[0] == NULL)) {
236 syslog(LOG_ERR, "could not find loopback transports");
237 exit(1);
238 }
239
240 /* catch the usual termination signals for graceful exit */
241 (void) signal(SIGINT, terminate);
242 (void) signal(SIGTERM, terminate);
243 (void) signal(SIGQUIT, terminate);
244 /* ignore others that could get sent */
245 (void) sigset(SIGHUP, note_refresh);
246 (void) signal(SIGUSR1, SIG_IGN);
247 (void) signal(SIGUSR2, SIG_IGN);
248 if (warmstart) {
249 read_warmstart();
250 }
251 if (debugging) {
252 printf("rpcbind debugging enabled.");
253 if (doabort) {
254 printf(" Will abort on errors!\n");
255 } else {
256 printf("\n");
257 }
258 } else {
259 detachfromtty();
260 }
261
262 /* These are basic privileges we do not need */
263 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
264 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
265
266 my_svc_run();
267 syslog(LOG_ERR, "svc_run returned unexpectedly");
268 rpcbind_abort();
269 /* NOTREACHED */
270 }
271
272 /*
273 * Increments a counter each time a problem is found with the network
274 * configuration information.
275 */
276 static int
check_netconfig(void)277 check_netconfig(void)
278 {
279 void *nc;
280 void *dlcookie;
281 int busted = 0;
282 int i;
283 int lo_clts_found = 0, lo_cots_found = 0, lo_cotsord_found = 0;
284 struct netconfig *nconf, *np;
285 struct stat sb;
286
287 nc = setnetconfig();
288 if (nc == NULL) {
289 if (debugging)
290 fprintf(stderr,
291 "setnetconfig() failed: %s\n", nc_sperror());
292 syslog(LOG_ALERT, "setnetconfig() failed: %s", nc_sperror());
293 return (1);
294 }
295 while (np = getnetconfig(nc)) {
296 if ((np->nc_flag & NC_VISIBLE) == 0)
297 continue;
298 if (debugging)
299 fprintf(stderr, "checking netid \"%s\"\n",
300 np->nc_netid);
301 if (strcmp(np->nc_protofmly, NC_LOOPBACK) == 0)
302 switch (np->nc_semantics) {
303 case NC_TPI_CLTS:
304 lo_clts_found = 1;
305 break;
306
307 case NC_TPI_COTS:
308 lo_cots_found = 1;
309 break;
310
311 case NC_TPI_COTS_ORD:
312 lo_cotsord_found = 1;
313 break;
314 }
315 if (stat(np->nc_device, &sb) == -1 && errno == ENOENT) {
316 if (debugging)
317 fprintf(stderr, "\tdevice %s does not exist\n",
318 np->nc_device);
319 syslog(LOG_ERR, "netid %s: device %s does not exist",
320 np->nc_netid, np->nc_device);
321 busted++;
322 } else
323 if (debugging)
324 fprintf(stderr, "\tdevice %s present\n",
325 np->nc_device);
326 for (i = 0; i < np->nc_nlookups; i++) {
327 char *libname = np->nc_lookups[i];
328
329 if ((dlcookie = dlopen(libname, RTLD_LAZY)) == NULL) {
330 char *dlerrstr;
331
332 dlerrstr = dlerror();
333 if (debugging) {
334 fprintf(stderr,
335 "\tnetid %s: dlopen of name-to-address library %s failed\ndlerror: %s",
336 np->nc_netid, libname, dlerrstr ? dlerrstr : "");
337 }
338 syslog(LOG_ERR,
339 "netid %s: dlopen of name-to-address library %s failed",
340 np->nc_netid, libname);
341 if (dlerrstr)
342 syslog(LOG_ERR, "%s", dlerrstr);
343 busted++;
344 } else {
345 if (debugging)
346 fprintf(stderr,
347 "\tdlopen of name-to-address library %s succeeded\n", libname);
348 (void) dlclose(dlcookie);
349 }
350 }
351 nconf = getnetconfigent(np->nc_netid);
352
353 if (!check_hostserv(nconf, HOST_SELF, ""))
354 busted++;
355 if (!check_hostserv(nconf, HOST_SELF_CONNECT, ""))
356 busted++;
357 if (!check_hostserv(nconf, HOST_SELF, "rpcbind"))
358 busted++;
359 if (!check_hostserv(nconf, HOST_SELF_CONNECT, "rpcbind"))
360 busted++;
361
362 freenetconfigent(nconf);
363 }
364 endnetconfig(nc);
365
366 if (lo_clts_found) {
367 if (debugging)
368 fprintf(stderr, "Found CLTS loopback transport\n");
369 } else {
370 syslog(LOG_ALERT, "no CLTS loopback transport found\n");
371 if (debugging)
372 fprintf(stderr, "no CLTS loopback transport found\n");
373 }
374 if (lo_cots_found) {
375 if (debugging)
376 fprintf(stderr, "Found COTS loopback transport\n");
377 } else {
378 syslog(LOG_ALERT, "no COTS loopback transport found\n");
379 if (debugging)
380 fprintf(stderr, "no COTS loopback transport found\n");
381 }
382 if (lo_cotsord_found) {
383 if (debugging)
384 fprintf(stderr, "Found COTS ORD loopback transport\n");
385 } else {
386 syslog(LOG_ALERT, "no COTS ORD loopback transport found\n");
387 if (debugging)
388 fprintf(stderr,
389 "no COTS ORD loopback transport found\n");
390 }
391
392 return (busted);
393 }
394
395 /*
396 * Adds the entry into the rpcbind database.
397 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
398 * Returns 0 if succeeds, else fails
399 */
400 static int
init_transport(struct netconfig * nconf)401 init_transport(struct netconfig *nconf)
402 {
403 int fd;
404 struct t_bind *taddr, *baddr;
405 SVCXPRT *my_xprt;
406 struct nd_addrlist *nas;
407 struct nd_hostserv hs;
408 int status; /* bound checking ? */
409 static int msgprt = 0;
410
411 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
412 (nconf->nc_semantics != NC_TPI_COTS) &&
413 (nconf->nc_semantics != NC_TPI_COTS_ORD))
414 return (1); /* not my type */
415
416 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && !ipv6flag) {
417 if (!msgprt)
418 syslog(LOG_DEBUG,
419 "/etc/netconfig has IPv6 entries but IPv6 is not configured");
420 msgprt++;
421 return (1);
422 }
423 #ifdef ND_DEBUG
424 {
425 int i;
426 char **s;
427
428 (void) fprintf(stderr, "%s: %d lookup routines :\n",
429 nconf->nc_netid, nconf->nc_nlookups);
430 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; i++, s++)
431 fprintf(stderr, "[%d] - %s\n", i, *s);
432 }
433 #endif
434
435 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) {
436 syslog(LOG_ERR, "%s: cannot open connection: %s",
437 nconf->nc_netid, t_errlist[t_errno]);
438 return (1);
439 }
440
441 if (is_system_labeled() &&
442 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
443 strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
444 setopt_anon_mlp(fd) == -1) {
445 syslog(LOG_ERR, "%s: couldn't set SO_ANON_MLP option",
446 nconf->nc_netid);
447 }
448
449 /*
450 * Negotiate for returning the ucred of the caller. This should
451 * done before enabling the endpoint for service via
452 * t_bind() so that requests to rpcbind contain the uid.
453 */
454 svc_fd_negotiate_ucred(fd);
455
456 taddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
457 baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
458 if ((baddr == NULL) || (taddr == NULL)) {
459 syslog(LOG_ERR, "%s: cannot allocate netbuf: %s",
460 nconf->nc_netid, t_errlist[t_errno]);
461 exit(1);
462 }
463
464 /* Get rpcbind's address on this transport */
465 hs.h_host = HOST_SELF;
466 hs.h_serv = servname;
467 if (netdir_getbyname(nconf, &hs, &nas))
468 goto error;
469
470 /* Copy the address */
471 taddr->addr.len = nas->n_addrs->len;
472 memcpy(taddr->addr.buf, nas->n_addrs->buf, (int)nas->n_addrs->len);
473 #ifdef ND_DEBUG
474 {
475 /* for debugging print out our universal address */
476 char *uaddr;
477
478 uaddr = taddr2uaddr(nconf, nas->n_addrs);
479 (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr);
480 (void) free(uaddr);
481 }
482 #endif
483 netdir_free((char *)nas, ND_ADDRLIST);
484
485 if (nconf->nc_semantics == NC_TPI_CLTS)
486 taddr->qlen = 0;
487 else
488 taddr->qlen = listen_backlog;
489
490 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
491 /*
492 * Sm: If we are running then set SO_REUSEADDR option
493 * so that we can bind to our preferred address even if
494 * previous connections are in FIN_WAIT state
495 */
496 #ifdef ND_DEBUG
497 fprintf(stdout, "Setting SO_REUSEADDR.\n");
498 #endif
499 if (setopt_reuseaddr(fd) == -1) {
500 syslog(LOG_ERR, "Couldn't set SO_REUSEADDR option");
501 }
502 }
503
504 if (t_bind(fd, taddr, baddr) != 0) {
505 syslog(LOG_ERR, "%s: cannot bind: %s",
506 nconf->nc_netid, t_errlist[t_errno]);
507 goto error;
508 }
509
510
511 if (memcmp(taddr->addr.buf, baddr->addr.buf, (int)baddr->addr.len)) {
512 syslog(LOG_ERR, "%s: address in use", nconf->nc_netid);
513 goto error;
514 }
515
516 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, baddr, 0, 0);
517 if (my_xprt == (SVCXPRT *)NULL) {
518 syslog(LOG_ERR, "%s: could not create service",
519 nconf->nc_netid);
520 goto error;
521 }
522
523 /* set up multicast address for RPC CALL_IT, IPv6 */
524
525 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
526 (strcmp(nconf->nc_proto, NC_UDP) == 0)) {
527 if (setup_callit(fd) < 0) {
528 syslog(LOG_ERR, "Unable to join IPv6 multicast group \
529 for rpc broadcast %s", RPCB_MULTICAST_ADDR);
530 }
531 }
532
533 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
534 svc_control(my_xprt, SVCSET_KEEPALIVE, (void *) TRUE);
535 }
536
537 #ifdef PORTMAP
538 /*
539 * Register both the versions for tcp/ip and udp/ip
540 */
541 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
542 ((strcmp(nconf->nc_proto, NC_TCP) == 0) ||
543 (strcmp(nconf->nc_proto, NC_UDP) == 0))) {
544 PMAPLIST *pml;
545
546 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
547 pmap_service, NULL)) {
548 syslog(LOG_ERR, "could not register on %s",
549 nconf->nc_netid);
550 goto error;
551 }
552 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
553 if (pml == (PMAPLIST *)NULL) {
554 syslog(LOG_ERR, "no memory!");
555 exit(1);
556 }
557 pml->pml_map.pm_prog = PMAPPROG;
558 pml->pml_map.pm_vers = PMAPVERS;
559 pml->pml_map.pm_port = PMAPPORT;
560 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
561 if (tcptrans[0]) {
562 syslog(LOG_ERR,
563 "cannot have more than one TCP transport");
564 goto error;
565 }
566 tcptrans = strdup(nconf->nc_netid);
567 pml->pml_map.pm_prot = IPPROTO_TCP;
568
569 /* Let's snarf the universal address */
570 /* "h1.h2.h3.h4.p1.p2" */
571 tcp_uaddr = taddr2uaddr(nconf, &baddr->addr);
572 } else {
573 if (udptrans[0]) {
574 syslog(LOG_ERR,
575 "cannot have more than one UDP transport");
576 goto error;
577 }
578 udptrans = strdup(nconf->nc_netid);
579 pml->pml_map.pm_prot = IPPROTO_UDP;
580
581 /* Let's snarf the universal address */
582 /* "h1.h2.h3.h4.p1.p2" */
583 udp_uaddr = taddr2uaddr(nconf, &baddr->addr);
584 }
585 pml->pml_next = list_pml;
586 list_pml = pml;
587
588 /* Add version 3 information */
589 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
590 if (pml == (PMAPLIST *)NULL) {
591 syslog(LOG_ERR, "no memory!");
592 exit(1);
593 }
594 pml->pml_map = list_pml->pml_map;
595 pml->pml_map.pm_vers = RPCBVERS;
596 pml->pml_next = list_pml;
597 list_pml = pml;
598
599 /* Add version 4 information */
600 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
601 if (pml == (PMAPLIST *)NULL) {
602 syslog(LOG_ERR, "no memory!");
603 exit(1);
604 }
605 pml->pml_map = list_pml->pml_map;
606 pml->pml_map.pm_vers = RPCBVERS4;
607 pml->pml_next = list_pml;
608 list_pml = pml;
609
610 /* Also add version 2 stuff to rpcbind list */
611 rbllist_add(PMAPPROG, PMAPVERS, nconf, &baddr->addr);
612 }
613 #endif
614
615 /* version 3 registration */
616 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
617 syslog(LOG_ERR, "could not register %s version 3",
618 nconf->nc_netid);
619 goto error;
620 }
621 rbllist_add(RPCBPROG, RPCBVERS, nconf, &baddr->addr);
622
623 /* version 4 registration */
624 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
625 syslog(LOG_ERR, "could not register %s version 4",
626 nconf->nc_netid);
627 goto error;
628 }
629 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &baddr->addr);
630
631 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
632 if (nconf->nc_semantics == NC_TPI_CLTS)
633 loopback_dg = strdup(nconf->nc_netid);
634 else if (nconf->nc_semantics == NC_TPI_COTS)
635 loopback_vc = strdup(nconf->nc_netid);
636 else if (nconf->nc_semantics == NC_TPI_COTS_ORD)
637 loopback_vc_ord = strdup(nconf->nc_netid);
638 }
639
640 /* decide if bound checking works for this transport */
641 status = add_bndlist(nconf, taddr, baddr);
642 #ifdef BIND_DEBUG
643 if (status < 0) {
644 fprintf(stderr, "Error in finding bind status for %s\n",
645 nconf->nc_netid);
646 } else if (status == 0) {
647 fprintf(stderr, "check binding for %s\n",
648 nconf->nc_netid);
649 } else if (status > 0) {
650 fprintf(stderr, "No check binding for %s\n",
651 nconf->nc_netid);
652 }
653 #endif
654 /*
655 * rmtcall only supported on CLTS transports for now.
656 * only needed when we are allowing indirect calls
657 */
658 if (allow_indirect && nconf->nc_semantics == NC_TPI_CLTS) {
659 status = create_rmtcall_fd(nconf);
660
661 #ifdef BIND_DEBUG
662 if (status < 0) {
663 fprintf(stderr, "Could not create rmtcall fd for %s\n",
664 nconf->nc_netid);
665 } else {
666 fprintf(stderr, "rmtcall fd for %s is %d\n",
667 nconf->nc_netid, status);
668 }
669 #endif
670 }
671 (void) t_free((char *)taddr, T_BIND);
672 (void) t_free((char *)baddr, T_BIND);
673 return (0);
674 error:
675 (void) t_free((char *)taddr, T_BIND);
676 (void) t_free((char *)baddr, T_BIND);
677 (void) t_close(fd);
678 return (1);
679 }
680
681 static void
rbllist_add(ulong_t prog,ulong_t vers,struct netconfig * nconf,struct netbuf * addr)682 rbllist_add(ulong_t prog, ulong_t vers, struct netconfig *nconf,
683 struct netbuf *addr)
684 {
685 rpcblist_ptr rbl;
686
687 rbl = (rpcblist_ptr)malloc((uint_t)sizeof (rpcblist));
688 if (rbl == (rpcblist_ptr)NULL) {
689 syslog(LOG_ERR, "no memory!");
690 exit(1);
691 }
692
693 rbl->rpcb_map.r_prog = prog;
694 rbl->rpcb_map.r_vers = vers;
695 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
696 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
697 rbl->rpcb_map.r_owner = strdup(superuser);
698 rbl->rpcb_next = list_rbl; /* Attach to global list */
699 list_rbl = rbl;
700 }
701
702 /*
703 * Catch the signal and die
704 */
705 /* ARGSUSED */
706 static void
terminate(int sig)707 terminate(int sig)
708 {
709 syslog(LOG_ERR, "rpcbind terminating on signal.");
710 write_warmstart(); /* Dump yourself */
711 exit(2);
712 }
713
714 /* ARGSUSED */
715 static void
note_refresh(int sig)716 note_refresh(int sig)
717 {
718 sigrefresh = 1;
719 }
720
721 void
rpcbind_abort(void)722 rpcbind_abort(void)
723 {
724 write_warmstart(); /* Dump yourself */
725 abort();
726 }
727
728 /*
729 * detach from tty
730 */
731 static void
detachfromtty(void)732 detachfromtty(void)
733 {
734 close(0);
735 close(1);
736 close(2);
737 switch (forkall()) {
738 case (pid_t)-1:
739 perror("fork");
740 break;
741 case 0:
742 break;
743 default:
744 exit(0);
745 }
746 setsid();
747 (void) open("/dev/null", O_RDWR, 0);
748 dup(0);
749 dup(0);
750 }
751
752 /* get command line options */
753 static void
parseargs(int argc,char * argv[])754 parseargs(int argc, char *argv[])
755 {
756 int c;
757 int tmp;
758
759 while ((c = getopt(argc, argv, "dwal:")) != EOF) {
760 switch (c) {
761 case 'd':
762 debugging = 1;
763 break;
764 case 'a':
765 doabort = 1; /* when debugging, do an abort on */
766 break; /* errors; for rpcbind developers */
767 /* only! */
768 case 'w':
769 warmstart = 1;
770 break;
771
772 case 'l':
773 if (sscanf(optarg, "%d", &tmp)) {
774 if (tmp > listen_backlog) {
775 listen_backlog = tmp;
776 }
777 }
778 break;
779 default: /* error */
780 fprintf(stderr,
781 "usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
782 exit(1);
783 }
784 }
785 if (doabort && !debugging) {
786 fprintf(stderr,
787 "-a (abort) specified without -d (debugging) -- ignored.\n");
788 doabort = 0;
789 }
790 }
791
792 static int
setopt_int(int fd,int level,int name,int value)793 setopt_int(int fd, int level, int name, int value)
794 {
795 struct t_optmgmt req, resp;
796 struct {
797 struct opthdr opt;
798 int value;
799 } optdata;
800
801 optdata.opt.level = level;
802 optdata.opt.name = name;
803 optdata.opt.len = sizeof (int);
804
805 optdata.value = value;
806
807 req.flags = T_NEGOTIATE;
808 req.opt.len = sizeof (optdata);
809 req.opt.buf = (char *)&optdata;
810
811 resp.flags = 0;
812 resp.opt.buf = (char *)&optdata;
813 resp.opt.maxlen = sizeof (optdata);
814
815 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
816 t_error("t_optmgmt");
817 return (-1);
818 }
819 return (0);
820 }
821
822 static int
setopt_reuseaddr(int fd)823 setopt_reuseaddr(int fd)
824 {
825 return (setopt_int(fd, SOL_SOCKET, SO_REUSEADDR, 1));
826 }
827
828 static int
setopt_anon_mlp(int fd)829 setopt_anon_mlp(int fd)
830 {
831 return (setopt_int(fd, SOL_SOCKET, SO_ANON_MLP, 1));
832 }
833
834 static int
setup_callit(int fd)835 setup_callit(int fd)
836 {
837 struct ipv6_mreq mreq;
838 struct t_optmgmt req, resp;
839 struct opthdr *opt;
840 char reqbuf[ sizeof (struct ipv6_mreq) + 24];
841 struct ipv6_mreq *pmreq;
842
843 opt = (struct opthdr *)reqbuf;
844
845 opt->level = IPPROTO_IPV6;
846 opt->name = IPV6_ADD_MEMBERSHIP;
847 opt->len = sizeof (struct ipv6_mreq);
848
849 /* multicast address */
850 (void) inet_pton(AF_INET6, RPCB_MULTICAST_ADDR,
851 mreq.ipv6mr_multiaddr.s6_addr);
852 mreq.ipv6mr_interface = 0;
853
854 /* insert it into opt */
855 pmreq = (struct ipv6_mreq *)&reqbuf[sizeof (struct opthdr)];
856 memcpy(pmreq, &mreq, sizeof (struct ipv6_mreq));
857
858 req.flags = T_NEGOTIATE;
859 req.opt.len = sizeof (struct opthdr) + opt->len;
860 req.opt.buf = (char *)opt;
861
862 resp.flags = 0;
863 resp.opt.buf = reqbuf;
864 resp.opt.maxlen = sizeof (reqbuf);
865
866 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
867 t_error("t_optmgmt");
868 return (-1);
869 }
870 return (0);
871 }
872
873 static boolean_t
check_hostserv(struct netconfig * nconf,const char * host,const char * serv)874 check_hostserv(struct netconfig *nconf, const char *host, const char *serv)
875 {
876 struct nd_hostserv nh;
877 struct nd_addrlist *na;
878 const char *hostname = host;
879 const char *servname = serv;
880 int retval;
881
882 if (strcmp(host, HOST_SELF) == 0)
883 hostname = "HOST_SELF";
884 else if (strcmp(host, HOST_SELF_CONNECT) == 0)
885 hostname = "HOST_SELF_CONNECT";
886
887 if (serv[0] == '\0')
888 servname = "<any>";
889
890 nh.h_host = (char *)host;
891 nh.h_serv = (char *)serv;
892
893 retval = netdir_getbyname(nconf, &nh, &na);
894 if (retval != ND_OK || na->n_cnt == 0) {
895 if (retval == ND_OK)
896 netdir_free(na, ND_ADDRLIST);
897
898 syslog(LOG_ALERT, "netid %s: cannot find an address for host "
899 "%s, service \"%s\"", nconf->nc_netid, hostname, servname);
900 if (debugging) {
901 (void) fprintf(stderr, "\tnetdir_getbyname for %s, "
902 "service \"%s\" failed\n", hostname, servname);
903 }
904 return (B_FALSE);
905 }
906 netdir_free(na, ND_ADDRLIST);
907
908 if (debugging) {
909 (void) fprintf(stderr, "\tnetdir_getbyname for %s, service "
910 "service \"%s\" succeeded\n", hostname, servname);
911 }
912 return (B_TRUE);
913 }
914
915 /* Maximum outstanding syslog requests */
916 #define MAXLOG 100
917 /* Maximum length: the messages generated are fairly short; no hostnames. */
918 #define MAXMSG 128
919
920 typedef struct logmsg {
921 struct logmsg *log_next;
922 int log_pri;
923 char log_msg[MAXMSG];
924 } logmsg;
925
926 static logmsg *loghead = NULL;
927 static logmsg **logtailp = &loghead;
928 static mutex_t logmutex = DEFAULTMUTEX;
929 static cond_t logcond = DEFAULTCV;
930 static int logcount = 0;
931
932 /*ARGSUSED*/
933 static void *
logthread(void * arg)934 logthread(void *arg)
935 {
936 while (1) {
937 logmsg *msg;
938 (void) mutex_lock(&logmutex);
939 while ((msg = loghead) == NULL)
940 (void) cond_wait(&logcond, &logmutex);
941
942 loghead = msg->log_next;
943 logcount--;
944 if (loghead == NULL) {
945 logtailp = &loghead;
946 logcount = 0;
947 }
948 (void) mutex_unlock(&logmutex);
949 syslog(msg->log_pri, "%s", msg->log_msg);
950 free(msg);
951 }
952 /* NOTREACHED */
953 }
954
955 static boolean_t
get_smf_prop(const char * var,boolean_t def_val)956 get_smf_prop(const char *var, boolean_t def_val)
957 {
958 scf_simple_prop_t *prop;
959 uint8_t *val;
960 boolean_t res = def_val;
961
962 prop = scf_simple_prop_get(NULL, NULL, "config", var);
963 if (prop) {
964 if ((val = scf_simple_prop_next_boolean(prop)) != NULL)
965 res = (*val == 0) ? B_FALSE : B_TRUE;
966 scf_simple_prop_free(prop);
967 }
968
969 if (prop == NULL || val == NULL) {
970 syslog(LOG_ALERT, "no value for config/%s (%s). "
971 "Using default \"%s\"", var, scf_strerror(scf_error()),
972 def_val ? "true" : "false");
973 }
974
975 return (res);
976 }
977
978 /*
979 * Initialize: read the configuration parameters from SMF.
980 * This function must be idempotent because it can be called from the
981 * main poll() loop in my_svc_run().
982 */
983 void
rpcb_check_init(void)984 rpcb_check_init(void)
985 {
986 thread_t tid;
987 static int thr_running;
988
989 wrap_enabled = get_smf_prop("enable_tcpwrappers", B_FALSE);
990 verboselog = get_smf_prop("verbose_logging", B_FALSE);
991 allow_indirect = get_smf_prop("allow_indirect", B_TRUE);
992 local_only = get_smf_prop("local_only", B_FALSE);
993
994 if (wrap_enabled && !thr_running) {
995 (void) thr_create(NULL, 0, logthread, NULL, THR_DETACHED, &tid);
996 thr_running = 1;
997 }
998 }
999
1000 /*
1001 * qsyslog() - queue a request for syslog(); if syslog blocks, the other
1002 * thread blocks; we make sure we don't run out of memory by allowing
1003 * only a limited number of outstandig syslog() requests.
1004 */
1005 void
qsyslog(int pri,const char * fmt,...)1006 qsyslog(int pri, const char *fmt, ...)
1007 {
1008 logmsg *msg = malloc(sizeof (*msg));
1009 int oldcount;
1010 va_list ap;
1011
1012 if (msg == NULL)
1013 return;
1014
1015 msg->log_pri = pri;
1016
1017 va_start(ap, fmt);
1018 (void) vsnprintf(msg->log_msg, sizeof (msg->log_msg), fmt, ap);
1019 va_end(ap);
1020
1021 msg->log_next = NULL;
1022
1023 (void) mutex_lock(&logmutex);
1024 oldcount = logcount;
1025 if (logcount < MAXLOG) {
1026 logcount++;
1027 *logtailp = msg;
1028 logtailp = &msg->log_next;
1029 } else {
1030 free(msg);
1031 }
1032 (void) mutex_unlock(&logmutex);
1033 if (oldcount == 0)
1034 (void) cond_signal(&logcond);
1035 }
1036