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