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