]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/rpcbind/rpcbind.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / rpcbind / rpcbind.c
1 /*      $NetBSD: rpcbind.c,v 1.3 2002/11/08 00:16:40 fvdl Exp $ */
2 /*      $FreeBSD$ */
3
4 /*
5  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
6  * unrestricted use provided that this legend is included on all tape
7  * media and as a part of the software program in whole or part.  Users
8  * may copy or modify Sun RPC without charge, but are not authorized
9  * to license or distribute it to anyone else except as part of a product or
10  * program developed by the user.
11  * 
12  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
13  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
14  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
15  * 
16  * Sun RPC is provided with no support and without any obligation on the
17  * part of Sun Microsystems, Inc. to assist in its use, correction,
18  * modification or enhancement.
19  * 
20  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
21  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
22  * OR ANY PART THEREOF.
23  * 
24  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
25  * or profits or other special, indirect and consequential damages, even if
26  * Sun has been advised of the possibility of such damages.
27  * 
28  * Sun Microsystems, Inc.
29  * 2550 Garcia Avenue
30  * Mountain View, California  94043
31  */
32 /*
33  * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
34  */
35
36 /* #ident       "@(#)rpcbind.c  1.19    94/04/25 SMI" */
37
38 #if 0
39 #ifndef lint
40 static  char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro";
41 #endif
42 #endif
43
44 /*
45  * rpcbind.c
46  * Implements the program, version to address mapping for rpc.
47  *
48  */
49
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/errno.h>
53 #include <sys/time.h>
54 #include <sys/resource.h>
55 #include <sys/wait.h>
56 #include <sys/signal.h>
57 #include <sys/socket.h>
58 #include <sys/un.h>
59 #include <rpc/rpc.h>
60 #include <rpc/rpc_com.h>
61 #ifdef PORTMAP
62 #include <netinet/in.h>
63 #endif
64 #include <arpa/inet.h>
65 #include <fcntl.h>
66 #include <netdb.h>
67 #include <stdio.h>
68 #include <netconfig.h>
69 #include <stdlib.h>
70 #include <unistd.h>
71 #include <syslog.h>
72 #include <err.h>
73 #include <libutil.h>
74 #include <pwd.h>
75 #include <string.h>
76 #include <errno.h>
77 #include "rpcbind.h"
78
79 /* Global variables */
80 int debugging = 0;      /* Tell me what's going on */
81 int doabort = 0;        /* When debugging, do an abort on errors */
82 rpcblist_ptr list_rbl;  /* A list of version 3/4 rpcbind services */
83
84 /* who to suid to if -s is given */
85 #define RUN_AS  "daemon"
86
87 #define RPCBINDDLOCK "/var/run/rpcbind.lock"
88
89 int runasdaemon = 0;
90 int insecure = 0;
91 int oldstyle_local = 0;
92 int verboselog = 0;
93
94 char **hosts = NULL;
95 struct sockaddr **bound_sa;
96 int ipv6_only = 0;
97 int nhosts = 0;
98 int on = 1;
99 int rpcbindlockfd;
100
101 #ifdef WARMSTART
102 /* Local Variable */
103 static int warmstart = 0;       /* Grab an old copy of registrations. */
104 #endif
105
106 #ifdef PORTMAP
107 struct pmaplist *list_pml;      /* A list of version 2 rpcbind services */
108 char *udptrans;         /* Name of UDP transport */
109 char *tcptrans;         /* Name of TCP transport */
110 char *udp_uaddr;        /* Universal UDP address */
111 char *tcp_uaddr;        /* Universal TCP address */
112 #endif
113 static char servname[] = "rpcbind";
114 static char superuser[] = "superuser";
115
116 int main(int, char *[]);
117
118 static int init_transport(struct netconfig *);
119 static void rbllist_add(rpcprog_t, rpcvers_t, struct netconfig *,
120                              struct netbuf *);
121 static void terminate(int);
122 static void parseargs(int, char *[]);
123 static void update_bound_sa(void);
124
125 int
126 main(int argc, char *argv[])
127 {
128         struct netconfig *nconf;
129         void *nc_handle;        /* Net config handle */
130         struct rlimit rl;
131         int maxrec = RPC_MAXDATASIZE;
132
133         parseargs(argc, argv);
134
135         update_bound_sa();
136
137         /* Check that another rpcbind isn't already running. */
138         if ((rpcbindlockfd = (open(RPCBINDDLOCK,
139             O_RDONLY|O_CREAT, 0444))) == -1)
140                 err(1, "%s", RPCBINDDLOCK);
141
142         if(flock(rpcbindlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
143                 errx(1, "another rpcbind is already running. Aborting");
144
145         getrlimit(RLIMIT_NOFILE, &rl);
146         if (rl.rlim_cur < 128) {
147                 if (rl.rlim_max <= 128)
148                         rl.rlim_cur = rl.rlim_max;
149                 else
150                         rl.rlim_cur = 128;
151                 setrlimit(RLIMIT_NOFILE, &rl);
152         }
153         openlog("rpcbind", LOG_CONS, LOG_DAEMON);
154         if (geteuid()) { /* This command allowed only to root */
155                 fprintf(stderr, "Sorry. You are not superuser\n");
156                 exit(1);
157         }
158         nc_handle = setnetconfig();     /* open netconfig file */
159         if (nc_handle == NULL) {
160                 syslog(LOG_ERR, "could not read /etc/netconfig");
161                 exit(1);
162         }
163 #ifdef PORTMAP
164         udptrans = "";
165         tcptrans = "";
166 #endif
167
168         nconf = getnetconfigent("local");
169         if (nconf == NULL)
170                 nconf = getnetconfigent("unix");
171         if (nconf == NULL) {
172                 syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]);
173                 exit(1);
174         }
175
176         rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
177
178         init_transport(nconf);
179
180         while ((nconf = getnetconfig(nc_handle))) {
181             if (nconf->nc_flag & NC_VISIBLE) {
182                 if (ipv6_only == 1 && strcmp(nconf->nc_protofmly,
183                     "inet") == 0) {
184                     /* DO NOTHING */
185                 } else
186                     init_transport(nconf);
187             }
188         }
189         endnetconfig(nc_handle);
190
191         /* catch the usual termination signals for graceful exit */
192         (void) signal(SIGCHLD, reap);
193         (void) signal(SIGINT, terminate);
194         (void) signal(SIGTERM, terminate);
195         (void) signal(SIGQUIT, terminate);
196         /* ignore others that could get sent */
197         (void) signal(SIGPIPE, SIG_IGN);
198         (void) signal(SIGHUP, SIG_IGN);
199         (void) signal(SIGUSR1, SIG_IGN);
200         (void) signal(SIGUSR2, SIG_IGN);
201 #ifdef WARMSTART
202         if (warmstart) {
203                 read_warmstart();
204         }
205 #endif
206         if (debugging) {
207                 printf("rpcbind debugging enabled.");
208                 if (doabort) {
209                         printf("  Will abort on errors!\n");
210                 } else {
211                         printf("\n");
212                 }
213         } else {
214                 if (daemon(0, 0))
215                         err(1, "fork failed");
216         }
217
218         if (runasdaemon) {
219                 struct passwd *p;
220
221                 if((p = getpwnam(RUN_AS)) == NULL) {
222                         syslog(LOG_ERR, "cannot get uid of daemon: %m");
223                         exit(1);
224                 }
225                 if (setuid(p->pw_uid) == -1) {
226                         syslog(LOG_ERR, "setuid to daemon failed: %m");
227                         exit(1);
228                 }
229         }
230
231         network_init();
232
233         my_svc_run();
234         syslog(LOG_ERR, "svc_run returned unexpectedly");
235         rpcbind_abort();
236         /* NOTREACHED */
237
238         return 0;
239 }
240
241 /*
242  * Adds the entry into the rpcbind database.
243  * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
244  * Returns 0 if succeeds, else fails
245  */
246 static int
247 init_transport(struct netconfig *nconf)
248 {
249         int fd;
250         struct t_bind taddr;
251         struct addrinfo hints, *res = NULL;
252         struct __rpc_sockinfo si;
253         SVCXPRT *my_xprt;
254         int status;     /* bound checking ? */
255         int aicode;
256         int addrlen;
257         int nhostsbak;
258         int bound;
259         struct sockaddr *sa;
260         u_int32_t host_addr[4];  /* IPv4 or IPv6 */
261         struct sockaddr_un sun;
262         mode_t oldmask;
263
264         if ((nconf->nc_semantics != NC_TPI_CLTS) &&
265             (nconf->nc_semantics != NC_TPI_COTS) &&
266             (nconf->nc_semantics != NC_TPI_COTS_ORD))
267             return (1); /* not my type */
268 #ifdef ND_DEBUG
269         if (debugging) {
270             int i;
271             char **s;
272
273             (void)fprintf(stderr, "%s: %ld lookup routines :\n",
274                 nconf->nc_netid, nconf->nc_nlookups);
275             for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
276                 i++, s++)
277                 fprintf(stderr, "[%d] - %s\n", i, *s);
278         }
279 #endif
280
281         /*
282          * XXX - using RPC library internal functions.
283          */
284         if ((strcmp(nconf->nc_netid, "local") == 0) ||
285             (strcmp(nconf->nc_netid, "unix") == 0)) {
286             /* 
287              * For other transports we call this later, for each socket we
288              * like to bind.
289              */
290             if ((fd = __rpc_nconf2fd(nconf)) < 0) {
291                 int non_fatal = 0;
292                 if (errno == EAFNOSUPPORT)
293                     non_fatal = 1;
294                 syslog(non_fatal?LOG_DEBUG:LOG_ERR, "cannot create socket for %s",
295                     nconf->nc_netid);
296                 return (1);
297             }
298         }
299
300         if (!__rpc_nconf2sockinfo(nconf, &si)) {
301             syslog(LOG_ERR, "cannot get information for %s",
302                 nconf->nc_netid);
303             return (1);
304         }
305
306         if ((strcmp(nconf->nc_netid, "local") == 0) ||
307             (strcmp(nconf->nc_netid, "unix") == 0)) {
308             memset(&sun, 0, sizeof sun);
309             sun.sun_family = AF_LOCAL;
310             unlink(_PATH_RPCBINDSOCK);
311             strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
312             sun.sun_len = SUN_LEN(&sun);
313             addrlen = sizeof (struct sockaddr_un);
314             sa = (struct sockaddr *)&sun;
315         } else {
316             /* Get rpcbind's address on this transport */
317
318             memset(&hints, 0, sizeof hints);
319             hints.ai_flags = AI_PASSIVE;
320             hints.ai_family = si.si_af;
321             hints.ai_socktype = si.si_socktype;
322             hints.ai_protocol = si.si_proto;
323         }
324
325         if ((strcmp(nconf->nc_netid, "local") != 0) &&
326             (strcmp(nconf->nc_netid, "unix") != 0)) {
327             /*
328              * If no hosts were specified, just bind to INADDR_ANY.
329              * Otherwise  make sure 127.0.0.1 is added to the list.
330              */
331             nhostsbak = nhosts + 1;
332             hosts = realloc(hosts, nhostsbak * sizeof(char *));
333             if (nhostsbak == 1)
334                 hosts[0] = "*";
335             else {
336                 if (hints.ai_family == AF_INET) {
337                     hosts[nhostsbak - 1] = "127.0.0.1";
338                 } else if (hints.ai_family == AF_INET6) {
339                     hosts[nhostsbak - 1] = "::1";
340                 } else
341                     return 1;
342             }
343
344             /*
345              * Bind to specific IPs if asked to
346              */
347             bound = 0;
348             while (nhostsbak > 0) {
349                 --nhostsbak;
350                 /*
351                  * XXX - using RPC library internal functions.
352                  */
353                 if ((fd = __rpc_nconf2fd(nconf)) < 0) {
354                     int non_fatal = 0;
355                     if (errno == EAFNOSUPPORT &&
356                         nconf->nc_semantics != NC_TPI_CLTS) 
357                         non_fatal = 1;
358                     syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 
359                         "cannot create socket for %s", nconf->nc_netid);
360                     return (1);
361                 }
362                 switch (hints.ai_family) {
363                 case AF_INET:
364                     if (inet_pton(AF_INET, hosts[nhostsbak],
365                         host_addr) == 1) {
366                         hints.ai_flags &= AI_NUMERICHOST;
367                     } else {
368                         /*
369                          * Skip if we have an AF_INET6 address.
370                          */
371                         if (inet_pton(AF_INET6,
372                             hosts[nhostsbak], host_addr) == 1) {
373                             close(fd);
374                             continue;
375                         }
376                     }
377                     break;
378                 case AF_INET6:
379                     if (inet_pton(AF_INET6, hosts[nhostsbak],
380                         host_addr) == 1) {
381                         hints.ai_flags &= AI_NUMERICHOST;
382                     } else {
383                         /*
384                          * Skip if we have an AF_INET address.
385                          */
386                         if (inet_pton(AF_INET, hosts[nhostsbak],
387                             host_addr) == 1) {
388                                 close(fd);
389                                 continue;
390                         }
391                     }
392                     if (setsockopt(fd, IPPROTO_IPV6,
393                         IPV6_V6ONLY, &on, sizeof on) < 0) {
394                         syslog(LOG_ERR,
395                             "can't set v6-only binding for "
396                             "ipv6 socket: %m");
397                         continue;
398                     }
399                     break;
400                 default:
401                     break;
402                 }
403
404                 /*
405                  * If no hosts were specified, just bind to INADDR_ANY
406                  */
407                 if (strcmp("*", hosts[nhostsbak]) == 0)
408                     hosts[nhostsbak] = NULL;
409                 if ((strcmp(nconf->nc_netid, "local") != 0) &&
410                     (strcmp(nconf->nc_netid, "unix") != 0)) {
411                     if ((aicode = getaddrinfo(hosts[nhostsbak],
412                         servname, &hints, &res)) != 0) {
413                         syslog(LOG_ERR,
414                             "cannot get local address for %s: %s",
415                             nconf->nc_netid, gai_strerror(aicode));
416                         continue;
417                     }
418                     addrlen = res->ai_addrlen;
419                     sa = (struct sockaddr *)res->ai_addr;
420                 }
421                 oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
422                 if (bind(fd, sa, addrlen) != 0) {
423                     syslog(LOG_ERR, "cannot bind %s on %s: %m",
424                         (hosts[nhostsbak] == NULL) ? "*" :
425                             hosts[nhostsbak], nconf->nc_netid);
426                     if (res != NULL)
427                         freeaddrinfo(res);
428                     continue;
429                 } else
430                     bound = 1;
431                 (void)umask(oldmask);
432
433                 /* Copy the address */
434                 taddr.addr.len = taddr.addr.maxlen = addrlen;
435                 taddr.addr.buf = malloc(addrlen);
436                 if (taddr.addr.buf == NULL) {
437                     syslog(LOG_ERR,
438                         "cannot allocate memory for %s address",
439                         nconf->nc_netid);
440                     if (res != NULL)
441                         freeaddrinfo(res);
442                     return 1;
443                 }
444                 memcpy(taddr.addr.buf, sa, addrlen);
445 #ifdef ND_DEBUG
446                 if (debugging) {
447                     /*
448                      * for debugging print out our universal
449                      * address
450                      */
451                     char *uaddr;
452                     struct netbuf nb;
453
454                     nb.buf = sa;
455                     nb.len = nb.maxlen = sa->sa_len;
456                     uaddr = taddr2uaddr(nconf, &nb);
457                     (void)fprintf(stderr,
458                         "rpcbind : my address is %s\n", uaddr);
459                     (void)free(uaddr);
460                 }
461 #endif
462
463                 if (nconf->nc_semantics != NC_TPI_CLTS)
464                     listen(fd, SOMAXCONN);
465
466                 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
467                     RPC_MAXDATASIZE, RPC_MAXDATASIZE);
468                 if (my_xprt == (SVCXPRT *)NULL) {
469                     syslog(LOG_ERR, "%s: could not create service",
470                         nconf->nc_netid);
471                     goto error;
472                 }
473             }
474             if (!bound)
475                 return 1;
476         } else {
477             oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
478             if (bind(fd, sa, addrlen) < 0) {
479                 syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
480                 if (res != NULL)
481                     freeaddrinfo(res);
482                 return 1;
483             }
484             (void) umask(oldmask);
485
486             /* Copy the address */
487             taddr.addr.len = taddr.addr.maxlen = addrlen;
488             taddr.addr.buf = malloc(addrlen);
489             if (taddr.addr.buf == NULL) {
490                 syslog(LOG_ERR, "cannot allocate memory for %s address",
491                     nconf->nc_netid);
492                 if (res != NULL)
493                     freeaddrinfo(res);
494                 return 1;
495             }
496             memcpy(taddr.addr.buf, sa, addrlen);
497 #ifdef ND_DEBUG
498             if (debugging) {
499                 /* for debugging print out our universal address */
500                 char *uaddr;
501                 struct netbuf nb;
502
503                 nb.buf = sa;
504                 nb.len = nb.maxlen = sa->sa_len;
505                 uaddr = taddr2uaddr(nconf, &nb);
506                 (void) fprintf(stderr, "rpcbind : my address is %s\n",
507                     uaddr);
508                 (void) free(uaddr);
509             }
510 #endif
511
512             if (nconf->nc_semantics != NC_TPI_CLTS)
513                 listen(fd, SOMAXCONN);
514
515             my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
516                 RPC_MAXDATASIZE, RPC_MAXDATASIZE);
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
524 #ifdef PORTMAP
525         /*
526          * Register both the versions for tcp/ip, udp/ip and local.
527          */
528         if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
529                 (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
530                 strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
531                 (strcmp(nconf->nc_netid, "unix") == 0) ||
532                 (strcmp(nconf->nc_netid, "local") == 0)) {
533                 struct pmaplist *pml;
534
535                 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
536                         pmap_service, 0)) {
537                         syslog(LOG_ERR, "could not register on %s",
538                                         nconf->nc_netid);
539                         goto error;
540                 }
541                 pml = malloc(sizeof (struct pmaplist));
542                 if (pml == NULL) {
543                         syslog(LOG_ERR, "no memory!");
544                         exit(1);
545                 }
546                 pml->pml_map.pm_prog = PMAPPROG;
547                 pml->pml_map.pm_vers = PMAPVERS;
548                 pml->pml_map.pm_port = PMAPPORT;
549                 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
550                         if (tcptrans[0]) {
551                                 syslog(LOG_ERR,
552                                 "cannot have more than one TCP transport");
553                                 goto error;
554                         }
555                         tcptrans = strdup(nconf->nc_netid);
556                         pml->pml_map.pm_prot = IPPROTO_TCP;
557
558                         /* Let's snarf the universal address */
559                         /* "h1.h2.h3.h4.p1.p2" */
560                         tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
561                 } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
562                         if (udptrans[0]) {
563                                 syslog(LOG_ERR,
564                                 "cannot have more than one UDP transport");
565                                 goto error;
566                         }
567                         udptrans = strdup(nconf->nc_netid);
568                         pml->pml_map.pm_prot = IPPROTO_UDP;
569
570                         /* Let's snarf the universal address */
571                         /* "h1.h2.h3.h4.p1.p2" */
572                         udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
573                 } else if (strcmp(nconf->nc_netid, "local") == 0)
574                         pml->pml_map.pm_prot = IPPROTO_ST;
575                 else if (strcmp(nconf->nc_netid, "unix") == 0)
576                         pml->pml_map.pm_prot = IPPROTO_ST;
577                 pml->pml_next = list_pml;
578                 list_pml = pml;
579
580                 /* Add version 3 information */
581                 pml = malloc(sizeof (struct pmaplist));
582                 if (pml == NULL) {
583                         syslog(LOG_ERR, "no memory!");
584                         exit(1);
585                 }
586                 pml->pml_map = list_pml->pml_map;
587                 pml->pml_map.pm_vers = RPCBVERS;
588                 pml->pml_next = list_pml;
589                 list_pml = pml;
590
591                 /* Add version 4 information */
592                 pml = malloc (sizeof (struct pmaplist));
593                 if (pml == NULL) {
594                         syslog(LOG_ERR, "no memory!");
595                         exit(1);
596                 }
597                 pml->pml_map = list_pml->pml_map;
598                 pml->pml_map.pm_vers = RPCBVERS4;
599                 pml->pml_next = list_pml;
600                 list_pml = pml;
601
602                 /* Also add version 2 stuff to rpcbind list */
603                 rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
604         }
605 #endif
606
607         /* version 3 registration */
608         if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
609                 syslog(LOG_ERR, "could not register %s version 3",
610                                 nconf->nc_netid);
611                 goto error;
612         }
613         rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);
614
615         /* version 4 registration */
616         if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
617                 syslog(LOG_ERR, "could not register %s version 4",
618                                 nconf->nc_netid);
619                 goto error;
620         }
621         rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);
622
623         /* decide if bound checking works for this transport */
624         status = add_bndlist(nconf, &taddr.addr);
625 #ifdef BIND_DEBUG
626         if (debugging) {
627                 if (status < 0) {
628                         fprintf(stderr, "Error in finding bind status for %s\n",
629                                 nconf->nc_netid);
630                 } else if (status == 0) {
631                         fprintf(stderr, "check binding for %s\n",
632                                 nconf->nc_netid);
633                 } else if (status > 0) {
634                         fprintf(stderr, "No check binding for %s\n",
635                                 nconf->nc_netid);
636                 }
637         }
638 #endif
639         /*
640          * rmtcall only supported on CLTS transports for now.
641          */
642         if (nconf->nc_semantics == NC_TPI_CLTS) {
643                 status = create_rmtcall_fd(nconf);
644
645 #ifdef BIND_DEBUG
646                 if (debugging) {
647                         if (status < 0) {
648                                 fprintf(stderr,
649                                     "Could not create rmtcall fd for %s\n",
650                                         nconf->nc_netid);
651                         } else {
652                                 fprintf(stderr, "rmtcall fd for %s is %d\n",
653                                         nconf->nc_netid, status);
654                         }
655                 }
656 #endif
657         }
658         return (0);
659 error:
660         close(fd);
661         return (1);
662 }
663
664 /*
665  * Create the list of addresses that we're bound to.  Normally, this
666  * list is empty because we're listening on the wildcard address
667  * (nhost == 0).  If -h is specified on the command line, then
668  * bound_sa will have a list of the addresses that the program binds
669  * to specifically.  This function takes that list and converts them to
670  * struct sockaddr * and stores them in bound_sa.
671  */
672 static void
673 update_bound_sa(void)
674 {
675         struct addrinfo hints, *res = NULL;
676         int i;
677
678         if (nhosts == 0)
679                 return;
680         bound_sa = malloc(sizeof(*bound_sa) * nhosts);
681         memset(&hints, 0, sizeof(hints));
682         hints.ai_family = PF_UNSPEC;
683         for (i = 0; i < nhosts; i++)  {
684                 if (getaddrinfo(hosts[i], NULL, &hints, &res) != 0)
685                         continue;
686                 bound_sa[i] = malloc(res->ai_addrlen);
687                 memcpy(bound_sa[i], res->ai_addr, res->ai_addrlen);
688         }
689 }
690
691 /*
692  * Match the sa against the list of addresses we've bound to.  If
693  * we've not specifically bound to anything, we match everything.
694  * Otherwise, if the IPv4 or IPv6 address matches one of the addresses
695  * in bound_sa, we return true.  If not, we return false.
696  */
697 int
698 listen_addr(const struct sockaddr *sa)
699 {
700         int i;
701
702         /*
703          * If nhosts == 0, then there were no -h options on the
704          * command line, so all addresses are addresses we're
705          * listening to.
706          */
707         if (nhosts == 0)
708                 return 1;
709         for (i = 0; i < nhosts; i++) {
710                 if (bound_sa[i] == NULL ||
711                     sa->sa_family != bound_sa[i]->sa_family)
712                         continue;
713                 switch (sa->sa_family) {
714                 case AF_INET:
715                         if (memcmp(&SA2SINADDR(sa), &SA2SINADDR(bound_sa[i]),
716                             sizeof(struct in_addr)) == 0)
717                                 return (1);
718                         break;
719 #ifdef INET6
720                 case AF_INET6:
721                         if (memcmp(&SA2SIN6ADDR(sa), &SA2SIN6ADDR(bound_sa[i]),
722                             sizeof(struct in6_addr)) == 0)
723                                 return (1);
724                         break;
725 #endif
726                 default:
727                         break;
728                 }
729         }
730         return (0);
731 }
732
733 static void
734 rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
735             struct netbuf *addr)
736 {
737         rpcblist_ptr rbl;
738
739         rbl = malloc(sizeof (rpcblist));
740         if (rbl == NULL) {
741                 syslog(LOG_ERR, "no memory!");
742                 exit(1);
743         }
744
745         rbl->rpcb_map.r_prog = prog;
746         rbl->rpcb_map.r_vers = vers;
747         rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
748         rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
749         rbl->rpcb_map.r_owner = strdup(superuser);
750         rbl->rpcb_next = list_rbl;      /* Attach to global list */
751         list_rbl = rbl;
752 }
753
754 /*
755  * Catch the signal and die
756  */
757 static void
758 terminate(int dummy __unused)
759 {
760         close(rpcbindlockfd);
761 #ifdef WARMSTART
762         syslog(LOG_ERR,
763                 "rpcbind terminating on signal. Restart with \"rpcbind -w\"");
764         write_warmstart();      /* Dump yourself */
765 #endif
766         exit(2);
767 }
768
769 void
770 rpcbind_abort(void)
771 {
772 #ifdef WARMSTART
773         write_warmstart();      /* Dump yourself */
774 #endif
775         abort();
776 }
777
778 /* get command line options */
779 static void
780 parseargs(int argc, char *argv[])
781 {
782         int c;
783
784 #ifdef WARMSTART
785 #define WSOP    "w"
786 #else
787 #define WSOP    ""
788 #endif
789         while ((c = getopt(argc, argv, "6adh:iLls" WSOP)) != -1) {
790                 switch (c) {
791                 case '6':
792                         ipv6_only = 1;
793                         break;
794                 case 'a':
795                         doabort = 1;    /* when debugging, do an abort on */
796                         break;          /* errors; for rpcbind developers */
797                                         /* only! */
798                 case 'd':
799                         debugging = 1;
800                         break;
801                 case 'h':
802                         ++nhosts;
803                         hosts = realloc(hosts, nhosts * sizeof(char *));
804                         if (hosts == NULL)
805                                 errx(1, "Out of memory");
806                         hosts[nhosts - 1] = strdup(optarg);
807                         if (hosts[nhosts - 1] == NULL)
808                                 errx(1, "Out of memory");
809                         break;
810                 case 'i':
811                         insecure = 1;
812                         break;
813                 case 'L':
814                         oldstyle_local = 1;
815                         break;
816                 case 'l':
817                         verboselog = 1;
818                         break;
819                 case 's':
820                         runasdaemon = 1;
821                         break;
822 #ifdef WARMSTART
823                 case 'w':
824                         warmstart = 1;
825                         break;
826 #endif
827                 default:        /* error */
828                         fprintf(stderr,
829                             "usage: rpcbind [-6adiLls%s] [-h bindip]\n",
830                             WSOP);
831                         exit (1);
832                 }
833         }
834         if (doabort && !debugging) {
835             fprintf(stderr,
836                 "-a (abort) specified without -d (debugging) -- ignored.\n");
837             doabort = 0;
838         }
839 #undef WSOP
840 }
841
842 void
843 reap(int dummy __unused)
844 {
845         int save_errno = errno;
846  
847         while (wait3(NULL, WNOHANG, NULL) > 0)
848                 ;       
849         errno = save_errno;
850 }
851
852 void
853 toggle_verboselog(int dummy __unused)
854 {
855         verboselog = !verboselog;
856 }