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