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