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