]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/rpc.lockd/lockd.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.sbin / rpc.lockd / lockd.c
1 /*      $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $        */
2 /*      $FreeBSD$ */
3
4 /*
5  * Copyright (c) 1995
6  *      A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed for the FreeBSD project
19  * 4. Neither the name of the author nor the names of any co-contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  */
36
37 #include <sys/cdefs.h>
38 #ifndef lint
39 __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $");
40 #endif
41
42 /*
43  * main() function for NFS lock daemon.  Most of the code in this
44  * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x.
45  *
46  * The actual program logic is in the file lock_proc.c
47  */
48
49 #include <sys/param.h>
50 #include <sys/linker.h>
51 #include <sys/module.h>
52 #include <sys/socket.h>
53 #include <sys/stat.h>
54
55 #include <netinet/in.h>
56 #include <arpa/inet.h>
57
58 #include <err.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <errno.h>
62 #include <syslog.h>
63 #include <signal.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include <libutil.h>
67 #include <netconfig.h>
68 #include <netdb.h>
69
70 #include <rpc/rpc.h>
71 #include <rpc/rpc_com.h>
72 #include <rpcsvc/sm_inter.h>
73
74 #include "lockd.h"
75 #include <rpcsvc/nlm_prot.h>
76
77 int             debug_level = 0;        /* 0 = no debugging syslog() calls */
78 int             _rpcsvcdirty = 0;
79
80 int grace_expired;
81 int nsm_state;
82 int kernel_lockd;
83 int kernel_lockd_client;
84 pid_t client_pid;
85 struct mon mon_host;
86 char **hosts, *svcport_str = NULL;
87 int nhosts = 0;
88 int xcreated = 0;
89 char **addrs;                   /* actually (netid, uaddr) pairs */
90 int naddrs;                     /* count of how many (netid, uaddr) pairs */
91
92 void    create_service(struct netconfig *nconf);
93 void    lookup_addresses(struct netconfig *nconf);
94 void    init_nsm(void);
95 void    nlm_prog_0(struct svc_req *, SVCXPRT *);
96 void    nlm_prog_1(struct svc_req *, SVCXPRT *);
97 void    nlm_prog_3(struct svc_req *, SVCXPRT *);
98 void    nlm_prog_4(struct svc_req *, SVCXPRT *);
99 void    out_of_mem(void);
100 void    usage(void);
101
102 void sigalarm_handler(void);
103
104 /*
105  * XXX move to some header file.
106  */
107 #define _PATH_RPCLOCKDSOCK      "/var/run/rpclockd.sock"
108
109 int
110 main(int argc, char **argv)
111 {
112         int ch, i, s;
113         void *nc_handle;
114         char *endptr, **hosts_bak;
115         struct sigaction sigalarm;
116         int grace_period = 30;
117         struct netconfig *nconf;
118         int have_v6 = 1;
119         int maxrec = RPC_MAXDATASIZE;
120         in_port_t svcport = 0;
121
122         while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) {
123                 switch (ch) {
124                 case 'd':
125                         debug_level = atoi(optarg);
126                         if (!debug_level) {
127                                 usage();
128                                 /* NOTREACHED */
129                         }
130                         break;
131                 case 'g':
132                         grace_period = atoi(optarg);
133                         if (!grace_period) {
134                                 usage();
135                                 /* NOTREACHED */
136                         }
137                         break;
138                 case 'h':
139                         ++nhosts;
140                         hosts_bak = hosts;
141                         hosts_bak = realloc(hosts, nhosts * sizeof(char *));
142                         if (hosts_bak == NULL) {
143                                 if (hosts != NULL) {
144                                         for (i = 0; i < nhosts; i++) 
145                                                 free(hosts[i]);
146                                         free(hosts);
147                                         out_of_mem();
148                                 }
149                         }
150                         hosts = hosts_bak;
151                         hosts[nhosts - 1] = strdup(optarg);
152                         if (hosts[nhosts - 1] == NULL) {
153                                 for (i = 0; i < (nhosts - 1); i++) 
154                                         free(hosts[i]);
155                                 free(hosts);
156                                 out_of_mem();
157                         }
158                         break;
159                 case 'p':
160                         endptr = NULL;
161                         svcport = (in_port_t)strtoul(optarg, &endptr, 10);
162                         if (endptr == NULL || *endptr != '\0' ||
163                             svcport == 0 || svcport >= IPPORT_MAX)
164                                 usage();
165                         svcport_str = strdup(optarg);
166                         break;
167                 default:
168                 case '?':
169                         usage();
170                         /* NOTREACHED */
171                 }
172         }
173         if (geteuid()) { /* This command allowed only to root */
174                 fprintf(stderr, "Sorry. You are not superuser\n");
175                 exit(1);
176         }
177
178         kernel_lockd = FALSE;
179         kernel_lockd_client = FALSE;
180         if (modfind("nfslockd") < 0) {
181                 if (kldload("nfslockd") < 0) {
182                         fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n");
183                 } else {
184                         kernel_lockd = TRUE;
185                 }
186         } else {
187                 kernel_lockd = TRUE;
188         }
189         if (kernel_lockd) {
190                 if (getosreldate() >= 800040)
191                         kernel_lockd_client = TRUE;
192         }
193
194         (void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
195         (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
196         (void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
197         (void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);
198
199         /*
200          * Check if IPv6 support is present.
201          */
202         s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
203         if (s < 0)
204                 have_v6 = 0;
205         else 
206                 close(s);
207
208         rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
209
210         /*
211          * If no hosts were specified, add a wildcard entry to bind to
212          * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
213          * list.
214          */
215         if (nhosts == 0) {
216                 hosts = malloc(sizeof(char**));
217                 if (hosts == NULL)
218                         out_of_mem();
219
220                 hosts[0] = "*";
221                 nhosts = 1;
222         } else {
223                 hosts_bak = hosts;
224                 if (have_v6) {
225                         hosts_bak = realloc(hosts, (nhosts + 2) *
226                             sizeof(char *));
227                         if (hosts_bak == NULL) {
228                                 for (i = 0; i < nhosts; i++)
229                                         free(hosts[i]);
230                                 free(hosts);
231                                 out_of_mem();
232                         } else
233                                 hosts = hosts_bak;
234
235                         nhosts += 2;
236                         hosts[nhosts - 2] = "::1";
237                 } else {
238                         hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
239                         if (hosts_bak == NULL) {
240                                 for (i = 0; i < nhosts; i++)
241                                         free(hosts[i]);
242
243                                 free(hosts);
244                                 out_of_mem();
245                         } else {
246                                 nhosts += 1;
247                                 hosts = hosts_bak;
248                         }
249                 }
250                 hosts[nhosts - 1] = "127.0.0.1";
251         }
252
253         if (kernel_lockd) {
254                 if (!kernel_lockd_client) {
255                         /*
256                          * For the case where we have a kernel lockd but it
257                          * doesn't provide client locking, we run a cut-down
258                          * RPC service on a local-domain socket. The kernel's
259                          * RPC server will pass what it can't handle (mainly
260                          * client replies) down to us.
261                          */
262                         struct sockaddr_un sun;
263                         int fd, oldmask;
264                         SVCXPRT *xprt;
265
266                         memset(&sun, 0, sizeof sun);
267                         sun.sun_family = AF_LOCAL;
268                         unlink(_PATH_RPCLOCKDSOCK);
269                         strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK);
270                         sun.sun_len = SUN_LEN(&sun);
271                         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
272                         if (!fd) {
273                                 err(1, "Can't create local lockd socket");
274                         }
275                         oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
276                         if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
277                                 err(1, "Can't bind local lockd socket");
278                         }
279                         umask(oldmask);
280                         if (listen(fd, SOMAXCONN) < 0) {
281                                 err(1, "Can't listen on local lockd socket");
282                         }
283                         xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
284                         if (!xprt) {
285                                 err(1, "Can't create transport for local lockd socket");
286                         }
287                         if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) {
288                                 err(1, "Can't register service for local lockd socket");
289                         }
290                 }
291
292                 /*
293                  * We need to look up the addresses so that we can
294                  * hand uaddrs (ascii encoded address+port strings) to
295                  * the kernel.
296                  */
297                 nc_handle = setnetconfig();
298                 while ((nconf = getnetconfig(nc_handle))) {
299                         /* We want to listen only on udp6, tcp6, udp, tcp transports */
300                         if (nconf->nc_flag & NC_VISIBLE) {
301                                 /* Skip if there's no IPv6 support */
302                                 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
303                                         /* DO NOTHING */
304                                 } else {
305                                         lookup_addresses(nconf);
306                                 }
307                         }
308                 }
309                 endnetconfig(nc_handle);
310         } else {
311                 nc_handle = setnetconfig();
312                 while ((nconf = getnetconfig(nc_handle))) {
313                         /* We want to listen only on udp6, tcp6, udp, tcp transports */
314                         if (nconf->nc_flag & NC_VISIBLE) {
315                                 /* Skip if there's no IPv6 support */
316                                 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
317                                         /* DO NOTHING */
318                                 } else {
319                                         create_service(nconf);
320                                 }
321                         }
322                 }
323                 endnetconfig(nc_handle);
324         }
325
326         /*
327          * Note that it is NOT sensible to run this program from inetd - the
328          * protocol assumes that it will run immediately at boot time.
329          */
330         if (daemon(0, debug_level > 0)) {
331                 err(1, "cannot fork");
332                 /* NOTREACHED */
333         }
334
335         openlog("rpc.lockd", 0, LOG_DAEMON);
336         if (debug_level)
337                 syslog(LOG_INFO, "Starting, debug level %d", debug_level);
338         else
339                 syslog(LOG_INFO, "Starting");
340
341         sigalarm.sa_handler = (sig_t) sigalarm_handler;
342         sigemptyset(&sigalarm.sa_mask);
343         sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
344         sigalarm.sa_flags |= SA_RESTART;
345         if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
346                 syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
347                     strerror(errno));
348                 exit(1);
349         }
350
351         if (kernel_lockd) {
352                 if (!kernel_lockd_client) {
353                         init_nsm();
354                         client_pid = client_request();
355
356                         /*
357                          * Create a child process to enter the kernel and then
358                          * wait for RPCs on our local domain socket.
359                          */
360                         if (!fork())
361                                 nlm_syscall(debug_level, grace_period,
362                                     naddrs, addrs);
363                         else
364                                 svc_run();
365                 } else {
366                         /*
367                          * The kernel lockd implementation provides
368                          * both client and server so we don't need to
369                          * do anything else.
370                          */
371                         nlm_syscall(debug_level, grace_period, naddrs, addrs);
372                 }
373         } else {
374                 grace_expired = 0;
375                 alarm(grace_period);
376
377                 init_nsm();
378
379                 client_pid = client_request();
380
381                 svc_run();              /* Should never return */
382         }
383         exit(1);
384 }
385
386 /*
387  * This routine creates and binds sockets on the appropriate
388  * addresses. It gets called one time for each transport and
389  * registrates the service with rpcbind on that trasport.
390  */
391 void
392 create_service(struct netconfig *nconf)
393 {
394         struct addrinfo hints, *res = NULL;
395         struct sockaddr_in *sin;
396         struct sockaddr_in6 *sin6;
397         struct __rpc_sockinfo si;
398         struct netbuf servaddr;
399         SVCXPRT *transp = NULL;
400         int aicode;
401         int fd;
402         int nhostsbak;
403         int r;
404         int registered = 0;
405         u_int32_t host_addr[4];  /* IPv4 or IPv6 */
406
407         if ((nconf->nc_semantics != NC_TPI_CLTS) &&
408             (nconf->nc_semantics != NC_TPI_COTS) &&
409             (nconf->nc_semantics != NC_TPI_COTS_ORD))
410                 return; /* not my type */
411
412         /*
413          * XXX - using RPC library internal functions.
414          */
415         if (!__rpc_nconf2sockinfo(nconf, &si)) {
416                 syslog(LOG_ERR, "cannot get information for %s",
417                     nconf->nc_netid);
418                 return;
419         }
420
421         /* Get rpc.statd's address on this transport */
422         memset(&hints, 0, sizeof hints);
423         hints.ai_flags = AI_PASSIVE;
424         hints.ai_family = si.si_af;
425         hints.ai_socktype = si.si_socktype;
426         hints.ai_protocol = si.si_proto;
427
428         /*
429          * Bind to specific IPs if asked to
430          */
431         nhostsbak = nhosts;
432         while (nhostsbak > 0) {
433                 --nhostsbak;
434
435                 /*      
436                  * XXX - using RPC library internal functions.
437                  */
438                 if ((fd = __rpc_nconf2fd(nconf)) < 0) {
439                         syslog(LOG_ERR, "cannot create socket for %s",
440                             nconf->nc_netid);
441                         continue;
442                 }
443
444                 switch (hints.ai_family) {
445                         case AF_INET:
446                                 if (inet_pton(AF_INET, hosts[nhostsbak],
447                                     host_addr) == 1) {
448                                         hints.ai_flags &= AI_NUMERICHOST;
449                                 } else {
450                                         /*
451                                          * Skip if we have an AF_INET6 address.
452                                          */
453                                         if (inet_pton(AF_INET6, hosts[nhostsbak],
454                                             host_addr) == 1) {
455                                                 close(fd);
456                                                 continue;
457                                         }
458                                 }
459                                 break;
460                         case AF_INET6:
461                                 if (inet_pton(AF_INET6, hosts[nhostsbak],
462                                     host_addr) == 1) {
463                                         hints.ai_flags &= AI_NUMERICHOST;
464                                 } else {
465                                         /*
466                                          * Skip if we have an AF_INET address.
467                                          */
468                                         if (inet_pton(AF_INET, hosts[nhostsbak],
469                                             host_addr) == 1) {
470                                                 close(fd);
471                                                 continue;
472                                         }
473                                 }
474                                 break;
475                         default:
476                                 break;
477                 }
478
479                 /*
480                  * If no hosts were specified, just bind to INADDR_ANY
481                  */
482                 if (strcmp("*", hosts[nhostsbak]) == 0) {
483                         if (svcport_str == NULL) {
484                                 res = malloc(sizeof(struct addrinfo));
485                                 if (res == NULL) 
486                                         out_of_mem();
487                                 res->ai_flags = hints.ai_flags;
488                                 res->ai_family = hints.ai_family;
489                                 res->ai_protocol = hints.ai_protocol;
490                                 switch (res->ai_family) {
491                                         case AF_INET:
492                                                 sin = malloc(sizeof(struct sockaddr_in));
493                                                 if (sin == NULL) 
494                                                         out_of_mem();
495                                                 sin->sin_family = AF_INET;
496                                                 sin->sin_port = htons(0);
497                                                 sin->sin_addr.s_addr = htonl(INADDR_ANY);
498                                                 res->ai_addr = (struct sockaddr*) sin;
499                                                 res->ai_addrlen = (socklen_t)
500                                                     sizeof(res->ai_addr);
501                                                 break;
502                                         case AF_INET6:
503                                                 sin6 = malloc(sizeof(struct sockaddr_in6));
504                                                 if (sin6 == NULL)
505                                                         out_of_mem();
506                                                 sin6->sin6_family = AF_INET6;
507                                                 sin6->sin6_port = htons(0);
508                                                 sin6->sin6_addr = in6addr_any;
509                                                 res->ai_addr = (struct sockaddr*) sin6;
510                                                 res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
511                                                 break;
512                                         default:
513                                                 break;
514                                 }
515                         } else { 
516                                 if ((aicode = getaddrinfo(NULL, svcport_str,
517                                     &hints, &res)) != 0) {
518                                         syslog(LOG_ERR,
519                                             "cannot get local address for %s: %s",
520                                             nconf->nc_netid,
521                                             gai_strerror(aicode));
522                                         continue;
523                                 }
524                         }
525                 } else {
526                         if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
527                             &hints, &res)) != 0) {
528                                 syslog(LOG_ERR,
529                                     "cannot get local address for %s: %s",
530                                     nconf->nc_netid, gai_strerror(aicode));
531                                 continue;
532                         }
533                 }
534
535                 r = bindresvport_sa(fd, res->ai_addr);
536                 if (r != 0) {
537                         syslog(LOG_ERR, "bindresvport_sa: %m");
538                         exit(1);
539                 }
540
541                 if (nconf->nc_semantics != NC_TPI_CLTS)
542                     listen(fd, SOMAXCONN);
543
544                 transp = svc_tli_create(fd, nconf, NULL,
545                     RPC_MAXDATASIZE, RPC_MAXDATASIZE);
546
547                 if (transp != (SVCXPRT *) NULL) {
548                         if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0,
549                             NULL)) 
550                                 syslog(LOG_ERR,
551                                     "can't register %s NLM_PROG, NLM_SM service",
552                                     nconf->nc_netid);
553                         
554                         if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1,
555                             NULL)) 
556                                 syslog(LOG_ERR,
557                                     "can't register %s NLM_PROG, NLM_VERS service",
558                                     nconf->nc_netid);
559                         
560                         if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3,
561                             NULL)) 
562                                 syslog(LOG_ERR,
563                                     "can't register %s NLM_PROG, NLM_VERSX service",
564                                     nconf->nc_netid);
565                         
566                         if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4,
567                             NULL)) 
568                                 syslog(LOG_ERR,
569                                     "can't register %s NLM_PROG, NLM_VERS4 service",
570                                     nconf->nc_netid);
571                         
572                 } else 
573                         syslog(LOG_WARNING, "can't create %s services",
574                             nconf->nc_netid);
575
576                 if (registered == 0) {
577                         registered = 1;
578                         memset(&hints, 0, sizeof hints);
579                         hints.ai_flags = AI_PASSIVE;
580                         hints.ai_family = si.si_af;
581                         hints.ai_socktype = si.si_socktype;
582                         hints.ai_protocol = si.si_proto;
583
584                         if (svcport_str == NULL) {
585                                 svcport_str = malloc(NI_MAXSERV * sizeof(char));
586                                 if (svcport_str == NULL)
587                                         out_of_mem();
588
589                                 if (getnameinfo(res->ai_addr,
590                                     res->ai_addr->sa_len, NULL, NI_MAXHOST,
591                                     svcport_str, NI_MAXSERV * sizeof(char),
592                                     NI_NUMERICHOST | NI_NUMERICSERV))
593                                         errx(1, "Cannot get port number");
594                         }
595
596                         if((aicode = getaddrinfo(NULL, svcport_str, &hints,
597                             &res)) != 0) {
598                                 syslog(LOG_ERR, "cannot get local address: %s",
599                                     gai_strerror(aicode));
600                                 exit(1);
601                         }
602
603                         servaddr.buf = malloc(res->ai_addrlen);
604                         memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
605                         servaddr.len = res->ai_addrlen;
606
607                         rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr);
608                         rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr);
609                         rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr);
610                         rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr);
611
612                         xcreated++;
613                         freeaddrinfo(res);
614                 }
615         } /* end while */
616 }
617
618 /*
619  * Look up addresses for the kernel to create transports for.
620  */
621 void
622 lookup_addresses(struct netconfig *nconf)
623 {
624         struct addrinfo hints, *res = NULL;
625         struct sockaddr_in *sin;
626         struct sockaddr_in6 *sin6;
627         struct __rpc_sockinfo si;
628         struct netbuf servaddr;
629         SVCXPRT *transp = NULL;
630         int aicode;
631         int nhostsbak;
632         int r;
633         int registered = 0;
634         u_int32_t host_addr[4];  /* IPv4 or IPv6 */
635         char *uaddr;
636
637         if ((nconf->nc_semantics != NC_TPI_CLTS) &&
638             (nconf->nc_semantics != NC_TPI_COTS) &&
639             (nconf->nc_semantics != NC_TPI_COTS_ORD))
640                 return; /* not my type */
641
642         /*
643          * XXX - using RPC library internal functions.
644          */
645         if (!__rpc_nconf2sockinfo(nconf, &si)) {
646                 syslog(LOG_ERR, "cannot get information for %s",
647                     nconf->nc_netid);
648                 return;
649         }
650
651         /* Get rpc.statd's address on this transport */
652         memset(&hints, 0, sizeof hints);
653         hints.ai_flags = AI_PASSIVE;
654         hints.ai_family = si.si_af;
655         hints.ai_socktype = si.si_socktype;
656         hints.ai_protocol = si.si_proto;
657
658         /*
659          * Bind to specific IPs if asked to
660          */
661         nhostsbak = nhosts;
662         while (nhostsbak > 0) {
663                 --nhostsbak;
664
665                 switch (hints.ai_family) {
666                         case AF_INET:
667                                 if (inet_pton(AF_INET, hosts[nhostsbak],
668                                     host_addr) == 1) {
669                                         hints.ai_flags &= AI_NUMERICHOST;
670                                 } else {
671                                         /*
672                                          * Skip if we have an AF_INET6 address.
673                                          */
674                                         if (inet_pton(AF_INET6, hosts[nhostsbak],
675                                             host_addr) == 1) {
676                                                 continue;
677                                         }
678                                 }
679                                 break;
680                         case AF_INET6:
681                                 if (inet_pton(AF_INET6, hosts[nhostsbak],
682                                     host_addr) == 1) {
683                                         hints.ai_flags &= AI_NUMERICHOST;
684                                 } else {
685                                         /*
686                                          * Skip if we have an AF_INET address.
687                                          */
688                                         if (inet_pton(AF_INET, hosts[nhostsbak],
689                                             host_addr) == 1) {
690                                                 continue;
691                                         }
692                                 }
693                                 break;
694                         default:
695                                 break;
696                 }
697
698                 /*
699                  * If no hosts were specified, just bind to INADDR_ANY
700                  */
701                 if (strcmp("*", hosts[nhostsbak]) == 0) {
702                         if (svcport_str == NULL) {
703                                 res = malloc(sizeof(struct addrinfo));
704                                 if (res == NULL) 
705                                         out_of_mem();
706                                 res->ai_flags = hints.ai_flags;
707                                 res->ai_family = hints.ai_family;
708                                 res->ai_protocol = hints.ai_protocol;
709                                 switch (res->ai_family) {
710                                         case AF_INET:
711                                                 sin = malloc(sizeof(struct sockaddr_in));
712                                                 if (sin == NULL) 
713                                                         out_of_mem();
714                                                 sin->sin_family = AF_INET;
715                                                 sin->sin_port = htons(0);
716                                                 sin->sin_addr.s_addr = htonl(INADDR_ANY);
717                                                 res->ai_addr = (struct sockaddr*) sin;
718                                                 res->ai_addrlen = (socklen_t)
719                                                     sizeof(res->ai_addr);
720                                                 break;
721                                         case AF_INET6:
722                                                 sin6 = malloc(sizeof(struct sockaddr_in6));
723                                                 if (sin6 == NULL)
724                                                         out_of_mem();
725                                                 sin6->sin6_family = AF_INET6;
726                                                 sin6->sin6_port = htons(0);
727                                                 sin6->sin6_addr = in6addr_any;
728                                                 res->ai_addr = (struct sockaddr*) sin6;
729                                                 res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
730                                                 break;
731                                         default:
732                                                 break;
733                                 }
734                         } else { 
735                                 if ((aicode = getaddrinfo(NULL, svcport_str,
736                                     &hints, &res)) != 0) {
737                                         syslog(LOG_ERR,
738                                             "cannot get local address for %s: %s",
739                                             nconf->nc_netid,
740                                             gai_strerror(aicode));
741                                         continue;
742                                 }
743                         }
744                 } else {
745                         if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
746                             &hints, &res)) != 0) {
747                                 syslog(LOG_ERR,
748                                     "cannot get local address for %s: %s",
749                                     nconf->nc_netid, gai_strerror(aicode));
750                                 continue;
751                         }
752                 }
753
754                 servaddr.len = servaddr.maxlen = res->ai_addr->sa_len;
755                 servaddr.buf = res->ai_addr;
756                 uaddr = taddr2uaddr(nconf, &servaddr);
757
758                 addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
759                 if (!addrs)
760                         out_of_mem();
761                 addrs[2 * naddrs] = strdup(nconf->nc_netid);
762                 addrs[2 * naddrs + 1] = uaddr;
763                 naddrs++;
764         } /* end while */
765 }
766
767 void
768 sigalarm_handler(void)
769 {
770
771         grace_expired = 1;
772 }
773
774 void
775 usage()
776 {
777         errx(1, "usage: rpc.lockd [-d <debuglevel>]"
778             " [-g <grace period>] [-h <bindip>] [-p <port>]");
779 }
780
781 /*
782  * init_nsm --
783  *      Reset the NSM state-of-the-world and acquire its state.
784  */
785 void
786 init_nsm(void)
787 {
788         enum clnt_stat ret;
789         my_id id;
790         sm_stat stat;
791         char name[] = "NFS NLM";
792         char localhost[] = "localhost";
793
794         /*
795          * !!!
796          * The my_id structure isn't used by the SM_UNMON_ALL call, as far
797          * as I know.  Leave it empty for now.
798          */
799         memset(&id, 0, sizeof(id));
800         id.my_name = name;
801
802         /*
803          * !!!
804          * The statd program must already be registered when lockd runs.
805          */
806         do {
807                 ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
808                     (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
809                 if (ret == RPC_PROGUNAVAIL) {
810                         syslog(LOG_WARNING, "%lu %s", SM_PROG,
811                             clnt_sperrno(ret));
812                         sleep(2);
813                         continue;
814                 }
815                 break;
816         } while (0);
817
818         if (ret != 0) {
819                 syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
820                 exit(1);
821         }
822
823         nsm_state = stat.state;
824
825         /* setup constant data for SM_MON calls */
826         mon_host.mon_id.my_id.my_name = localhost;
827         mon_host.mon_id.my_id.my_prog = NLM_PROG;
828         mon_host.mon_id.my_id.my_vers = NLM_SM;
829         mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
830 }
831
832 /*
833  * Out of memory, fatal
834  */
835 void out_of_mem()
836 {
837         syslog(LOG_ERR, "out of memory");
838         exit(2);
839 }