]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/rpc.lockd/lockd.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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                 int osrel = getosreldate();
191                 if (osrel >= 800040 || (osrel < 800000 && osrel >= 700110))
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         SVCXPRT *transp = NULL;
631         int aicode;
632         int nhostsbak;
633         int r;
634         int registered = 0;
635         u_int32_t host_addr[4];  /* IPv4 or IPv6 */
636         char *uaddr;
637
638         if ((nconf->nc_semantics != NC_TPI_CLTS) &&
639             (nconf->nc_semantics != NC_TPI_COTS) &&
640             (nconf->nc_semantics != NC_TPI_COTS_ORD))
641                 return; /* not my type */
642
643         /*
644          * XXX - using RPC library internal functions.
645          */
646         if (!__rpc_nconf2sockinfo(nconf, &si)) {
647                 syslog(LOG_ERR, "cannot get information for %s",
648                     nconf->nc_netid);
649                 return;
650         }
651
652         /* Get rpc.statd's address on this transport */
653         memset(&hints, 0, sizeof hints);
654         hints.ai_flags = AI_PASSIVE;
655         hints.ai_family = si.si_af;
656         hints.ai_socktype = si.si_socktype;
657         hints.ai_protocol = si.si_proto;
658
659         /*
660          * Bind to specific IPs if asked to
661          */
662         nhostsbak = nhosts;
663         while (nhostsbak > 0) {
664                 --nhostsbak;
665
666                 switch (hints.ai_family) {
667                         case AF_INET:
668                                 if (inet_pton(AF_INET, hosts[nhostsbak],
669                                     host_addr) == 1) {
670                                         hints.ai_flags &= AI_NUMERICHOST;
671                                 } else {
672                                         /*
673                                          * Skip if we have an AF_INET6 address.
674                                          */
675                                         if (inet_pton(AF_INET6, hosts[nhostsbak],
676                                             host_addr) == 1) {
677                                                 continue;
678                                         }
679                                 }
680                                 break;
681                         case AF_INET6:
682                                 if (inet_pton(AF_INET6, hosts[nhostsbak],
683                                     host_addr) == 1) {
684                                         hints.ai_flags &= AI_NUMERICHOST;
685                                 } else {
686                                         /*
687                                          * Skip if we have an AF_INET address.
688                                          */
689                                         if (inet_pton(AF_INET, hosts[nhostsbak],
690                                             host_addr) == 1) {
691                                                 continue;
692                                         }
693                                 }
694                                 break;
695                         default:
696                                 break;
697                 }
698
699                 /*
700                  * If no hosts were specified, just bind to INADDR_ANY
701                  */
702                 if (strcmp("*", hosts[nhostsbak]) == 0) {
703                         if (svcport_str == NULL) {
704                                 res = malloc(sizeof(struct addrinfo));
705                                 if (res == NULL) 
706                                         out_of_mem();
707                                 res->ai_flags = hints.ai_flags;
708                                 res->ai_family = hints.ai_family;
709                                 res->ai_protocol = hints.ai_protocol;
710                                 switch (res->ai_family) {
711                                         case AF_INET:
712                                                 sin = malloc(sizeof(struct sockaddr_in));
713                                                 if (sin == NULL) 
714                                                         out_of_mem();
715                                                 sin->sin_family = AF_INET;
716                                                 sin->sin_port = htons(0);
717                                                 sin->sin_addr.s_addr = htonl(INADDR_ANY);
718                                                 res->ai_addr = (struct sockaddr*) sin;
719                                                 res->ai_addrlen = (socklen_t)
720                                                     sizeof(res->ai_addr);
721                                                 break;
722                                         case AF_INET6:
723                                                 sin6 = malloc(sizeof(struct sockaddr_in6));
724                                                 if (sin6 == NULL)
725                                                         out_of_mem();
726                                                 sin6->sin6_family = AF_INET6;
727                                                 sin6->sin6_port = htons(0);
728                                                 sin6->sin6_addr = in6addr_any;
729                                                 res->ai_addr = (struct sockaddr*) sin6;
730                                                 res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
731                                                 break;
732                                         default:
733                                                 break;
734                                 }
735                         } else { 
736                                 if ((aicode = getaddrinfo(NULL, svcport_str,
737                                     &hints, &res)) != 0) {
738                                         syslog(LOG_ERR,
739                                             "cannot get local address for %s: %s",
740                                             nconf->nc_netid,
741                                             gai_strerror(aicode));
742                                         continue;
743                                 }
744                         }
745                 } else {
746                         if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
747                             &hints, &res)) != 0) {
748                                 syslog(LOG_ERR,
749                                     "cannot get local address for %s: %s",
750                                     nconf->nc_netid, gai_strerror(aicode));
751                                 continue;
752                         }
753                 }
754
755                 servaddr.len = servaddr.maxlen = res->ai_addr->sa_len;
756                 servaddr.buf = res->ai_addr;
757                 uaddr = taddr2uaddr(nconf, &servaddr);
758
759                 addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
760                 if (!addrs)
761                         out_of_mem();
762                 addrs[2 * naddrs] = strdup(nconf->nc_netid);
763                 addrs[2 * naddrs + 1] = uaddr;
764                 naddrs++;
765         } /* end while */
766 }
767
768 void
769 sigalarm_handler(void)
770 {
771
772         grace_expired = 1;
773 }
774
775 void
776 usage()
777 {
778         errx(1, "usage: rpc.lockd [-d <debuglevel>]"
779             " [-g <grace period>] [-h <bindip>] [-p <port>]");
780 }
781
782 /*
783  * init_nsm --
784  *      Reset the NSM state-of-the-world and acquire its state.
785  */
786 void
787 init_nsm(void)
788 {
789         enum clnt_stat ret;
790         my_id id;
791         sm_stat stat;
792         char name[] = "NFS NLM";
793         char localhost[] = "localhost";
794
795         /*
796          * !!!
797          * The my_id structure isn't used by the SM_UNMON_ALL call, as far
798          * as I know.  Leave it empty for now.
799          */
800         memset(&id, 0, sizeof(id));
801         id.my_name = name;
802
803         /*
804          * !!!
805          * The statd program must already be registered when lockd runs.
806          */
807         do {
808                 ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
809                     (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
810                 if (ret == RPC_PROGUNAVAIL) {
811                         syslog(LOG_WARNING, "%lu %s", SM_PROG,
812                             clnt_sperrno(ret));
813                         sleep(2);
814                         continue;
815                 }
816                 break;
817         } while (0);
818
819         if (ret != 0) {
820                 syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
821                 exit(1);
822         }
823
824         nsm_state = stat.state;
825
826         /* setup constant data for SM_MON calls */
827         mon_host.mon_id.my_id.my_name = localhost;
828         mon_host.mon_id.my_id.my_prog = NLM_PROG;
829         mon_host.mon_id.my_id.my_vers = NLM_SM;
830         mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
831 }
832
833 /*
834  * Out of memory, fatal
835  */
836 void out_of_mem()
837 {
838         syslog(LOG_ERR, "out of memory");
839         exit(2);
840 }