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