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