]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/nfsuserd/nfsuserd.c
MFC: r345994
[FreeBSD/stable/10.git] / usr.sbin / nfsuserd / nfsuserd.c
1 /*-
2  * Copyright (c) 2009 Rick Macklem, University of Guelph
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/errno.h>
33 #include <sys/linker.h>
34 #include <sys/module.h>
35 #include <sys/mount.h>
36 #include <sys/socket.h>
37 #include <sys/socketvar.h>
38 #include <sys/time.h>
39 #include <sys/ucred.h>
40 #include <sys/vnode.h>
41 #include <sys/wait.h>
42
43 #include <netinet/in.h>
44
45 #include <arpa/inet.h>
46
47 #include <nfs/nfssvc.h>
48
49 #include <rpc/rpc.h>
50
51 #include <fs/nfs/rpcv2.h>
52 #include <fs/nfs/nfsproto.h>
53 #include <fs/nfs/nfskpiport.h>
54 #include <fs/nfs/nfs.h>
55
56 #include <ctype.h>
57 #include <err.h>
58 #include <grp.h>
59 #include <netdb.h>
60 #include <pwd.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <syslog.h>
66 #include <unistd.h>
67
68 /*
69  * This program loads the password and group databases into the kernel
70  * for NFS V4.
71  */
72
73 static void     cleanup_term(int);
74 static void     usage(void);
75 static void     nfsuserdsrv(struct svc_req *, SVCXPRT *);
76 static bool_t   xdr_getid(XDR *, caddr_t);
77 static bool_t   xdr_getname(XDR *, caddr_t);
78 static bool_t   xdr_retval(XDR *, caddr_t);
79 static int      nfsbind_localhost(void);
80
81 #define MAXNAME         1024
82 #define MAXNFSUSERD     20
83 #define DEFNFSUSERD     4
84 #define MAXUSERMAX      100000
85 #define MINUSERMAX      10
86 #define DEFUSERMAX      200
87 #define DEFUSERTIMEOUT  (1 * 60)
88 struct info {
89         long    id;
90         long    retval;
91         char    name[MAXNAME + 1];
92 };
93
94 u_char *dnsname = "default.domain";
95 u_char *defaultuser = "nobody";
96 uid_t defaultuid = 65534;
97 u_char *defaultgroup = "nogroup";
98 gid_t defaultgid = 65533;
99 int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
100 int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
101 pid_t slaves[MAXNFSUSERD];
102 static struct sockaddr_storage fromip;
103 #ifdef INET6
104 static struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
105 #endif
106
107 int
108 main(int argc, char *argv[])
109 {
110         int i, j;
111         int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
112         struct nfsd_idargs nid;
113         struct passwd *pwd;
114         struct group *grp;
115         int sock, one = 1;
116         SVCXPRT *udptransp;
117         struct nfsuserd_args nargs;
118         sigset_t signew;
119         char hostname[MAXHOSTNAMELEN + 1], *cp;
120         struct addrinfo *aip, hints;
121         static uid_t check_dups[MAXUSERMAX];
122         gid_t grps[NGROUPS];
123         int ngroup;
124 #ifdef INET
125         struct sockaddr_in *sin;
126 #endif
127 #ifdef INET6
128         struct sockaddr_in6 *sin6;
129 #endif
130         int s;
131
132         if (modfind("nfscommon") < 0) {
133                 /* Not present in kernel, try loading it */
134                 if (kldload("nfscommon") < 0 ||
135                     modfind("nfscommon") < 0)
136                         errx(1, "Experimental nfs subsystem is not available");
137         }
138
139         /*
140          * First, figure out what our domain name and Kerberos Realm
141          * seem to be. Command line args may override these later.
142          */
143         if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
144                 if ((cp = strchr(hostname, '.')) != NULL &&
145                     *(cp + 1) != '\0') {
146                         dnsname = cp + 1;
147                 } else {
148                         memset((void *)&hints, 0, sizeof (hints));
149                         hints.ai_flags = AI_CANONNAME;
150                         error = getaddrinfo(hostname, NULL, &hints, &aip);
151                         if (error == 0) {
152                             if (aip->ai_canonname != NULL &&
153                                 (cp = strchr(aip->ai_canonname, '.')) != NULL
154                                 && *(cp + 1) != '\0') {
155                                         dnsname = cp + 1;
156                                         mustfreeai = 1;
157                                 } else {
158                                         freeaddrinfo(aip);
159                                 }
160                         }
161                 }
162         }
163
164         /*
165          * See if this server handles IPv4 or IPv6 and set up the default
166          * localhost address.
167          */
168         s = -1;
169 #ifdef INET6
170         s = socket(PF_INET6, SOCK_DGRAM, 0);
171         if (s >= 0) {
172                 fromip.ss_family = AF_INET6;
173                 fromip.ss_len = sizeof(struct sockaddr_in6);
174                 sin6 = (struct sockaddr_in6 *)&fromip;
175                 sin6->sin6_addr = in6loopback;
176                 close(s);
177         }
178 #endif  /* INET6 */
179 #ifdef INET
180         if (s < 0) {
181                 s = socket(PF_INET, SOCK_DGRAM, 0);
182                 if (s >= 0) {
183                         fromip.ss_family = AF_INET;
184                         fromip.ss_len = sizeof(struct sockaddr_in);
185                         sin = (struct sockaddr_in *)&fromip;
186                         sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
187                         close(s);
188                 }
189         }
190 #endif  /* INET */
191         if (s < 0)
192                 err(1, "Can't create a inet/inet6 socket");
193
194         nid.nid_usermax = DEFUSERMAX;
195         nid.nid_usertimeout = defusertimeout;
196
197         argc--;
198         argv++;
199         while (argc >= 1) {
200                 if (!strcmp(*argv, "-domain")) {
201                         if (argc == 1)
202                                 usage();
203                         argc--;
204                         argv++;
205                         strncpy(hostname, *argv, MAXHOSTNAMELEN);
206                         hostname[MAXHOSTNAMELEN] = '\0';
207                         dnsname = hostname;
208                 } else if (!strcmp(*argv, "-verbose")) {
209                         verbose = 1;
210                 } else if (!strcmp(*argv, "-force")) {
211                         forcestart = 1;
212                 } else if (!strcmp(*argv, "-manage-gids")) {
213                         manage_gids = 1;
214                 } else if (!strcmp(*argv, "-usermax")) {
215                         if (argc == 1)
216                                 usage();
217                         argc--;
218                         argv++;
219                         i = atoi(*argv);
220                         if (i < MINUSERMAX || i > MAXUSERMAX) {
221                                 fprintf(stderr,
222                                     "usermax %d out of range %d<->%d\n", i,
223                                     MINUSERMAX, MAXUSERMAX);
224                                 usage();
225                         }
226                         nid.nid_usermax = i;
227                 } else if (!strcmp(*argv, "-usertimeout")) {
228                         if (argc == 1)
229                                 usage();
230                         argc--;
231                         argv++;
232                         i = atoi(*argv);
233                         if (i < 0 || i > 100000) {
234                                 fprintf(stderr,
235                                     "usertimeout %d out of range 0<->100000\n",
236                                     i);
237                                 usage();
238                         }
239                         nid.nid_usertimeout = defusertimeout = i * 60;
240                 } else if (nfsuserdcnt == -1) {
241                         nfsuserdcnt = atoi(*argv);
242                         if (nfsuserdcnt < 1)
243                                 usage();
244                         if (nfsuserdcnt > MAXNFSUSERD) {
245                                 warnx("nfsuserd count %d; reset to %d",
246                                     nfsuserdcnt, DEFNFSUSERD);
247                                 nfsuserdcnt = DEFNFSUSERD;
248                         }
249                 } else {
250                         usage();
251                 }
252                 argc--;
253                 argv++;
254         }
255         if (nfsuserdcnt < 1)
256                 nfsuserdcnt = DEFNFSUSERD;
257
258         /*
259          * Strip off leading and trailing '.'s in domain name and map
260          * alphabetics to lower case.
261          */
262         while (*dnsname == '.')
263                 dnsname++;
264         if (*dnsname == '\0')
265                 errx(1, "Domain name all '.'");
266         len = strlen(dnsname);
267         cp = dnsname + len - 1;
268         while (*cp == '.') {
269                 *cp = '\0';
270                 len--;
271                 cp--;
272         }
273         for (i = 0; i < len; i++) {
274                 if (!isascii(dnsname[i]))
275                         errx(1, "Domain name has non-ascii char");
276                 if (isupper(dnsname[i]))
277                         dnsname[i] = tolower(dnsname[i]);
278         }
279
280         /*
281          * If the nfsuserd died off ungracefully, this is necessary to
282          * get them to start again.
283          */
284         if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
285                 errx(1, "Can't do nfssvc() to delete the port");
286
287         if (verbose)
288                 fprintf(stderr,
289                     "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
290                     dnsname, nid.nid_usermax, nid.nid_usertimeout);
291
292         for (i = 0; i < nfsuserdcnt; i++)
293                 slaves[i] = (pid_t)-1;
294
295         nargs.nuserd_family = fromip.ss_family;
296         /*
297          * Set up the service port to accept requests via UDP from
298          * localhost (INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT).
299          */
300         if ((sock = socket(nargs.nuserd_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
301                 err(1, "cannot create udp socket");
302
303         /*
304          * Not sure what this does, so I'll leave it here for now.
305          */
306         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
307         
308         if ((udptransp = svcudp_create(sock)) == NULL)
309                 err(1, "Can't set up socket");
310
311         /*
312          * By not specifying a protocol, it is linked into the
313          * dispatch queue, but not registered with portmapper,
314          * which is just what I want.
315          */
316         if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
317             nfsuserdsrv, 0))
318                 err(1, "Can't register nfsuserd");
319
320         /*
321          * Tell the kernel what my port# is.
322          */
323         nargs.nuserd_port = htons(udptransp->xp_port);
324 #ifdef DEBUG
325         printf("portnum=0x%x\n", nargs.nuserd_port);
326 #else
327         if (nfssvc(NFSSVC_NFSUSERDPORT | NFSSVC_NEWSTRUCT, &nargs) < 0) {
328                 if (errno == EPERM) {
329                         fprintf(stderr,
330                             "Can't start nfsuserd when already running");
331                         fprintf(stderr,
332                             " If not running, use the -force option.\n");
333                 } else {
334                         fprintf(stderr, "Can't do nfssvc() to add port\n");
335                 }
336                 exit(1);
337         }
338 #endif
339
340         pwd = getpwnam(defaultuser);
341         if (pwd)
342                 nid.nid_uid = pwd->pw_uid;
343         else
344                 nid.nid_uid = defaultuid;
345         grp = getgrnam(defaultgroup);
346         if (grp)
347                 nid.nid_gid = grp->gr_gid;
348         else
349                 nid.nid_gid = defaultgid;
350         nid.nid_name = dnsname;
351         nid.nid_namelen = strlen(nid.nid_name);
352         nid.nid_ngroup = 0;
353         nid.nid_grps = NULL;
354         nid.nid_flag = NFSID_INITIALIZE;
355 #ifdef DEBUG
356         printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, 
357             nid.nid_name);
358 #else
359         error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
360         if (error)
361                 errx(1, "Can't initialize nfs user/groups");
362 #endif
363
364         i = 0;
365         /*
366          * Loop around adding all groups.
367          */
368         setgrent();
369         while (i < nid.nid_usermax && (grp = getgrent())) {
370                 nid.nid_gid = grp->gr_gid;
371                 nid.nid_name = grp->gr_name;
372                 nid.nid_namelen = strlen(grp->gr_name);
373                 nid.nid_ngroup = 0;
374                 nid.nid_grps = NULL;
375                 nid.nid_flag = NFSID_ADDGID;
376 #ifdef DEBUG
377                 printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
378 #else
379                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
380                 if (error)
381                         errx(1, "Can't add group %s", grp->gr_name);
382 #endif
383                 i++;
384         }
385
386         /*
387          * Loop around adding all users.
388          */
389         start_uidpos = i;
390         setpwent();
391         while (i < nid.nid_usermax && (pwd = getpwent())) {
392                 fnd_dup = 0;
393                 /*
394                  * Yes, this is inefficient, but it is only done once when
395                  * the daemon is started and will run in a fraction of a second
396                  * for nid_usermax at 10000. If nid_usermax is cranked up to
397                  * 100000, it will take several seconds, depending on the CPU.
398                  */
399                 for (j = 0; j < (i - start_uidpos); j++)
400                         if (check_dups[j] == pwd->pw_uid) {
401                                 /* Found another entry for uid, so skip it */
402                                 fnd_dup = 1;
403                                 break;
404                         }
405                 if (fnd_dup != 0)
406                         continue;
407                 check_dups[i - start_uidpos] = pwd->pw_uid;
408                 nid.nid_uid = pwd->pw_uid;
409                 nid.nid_name = pwd->pw_name;
410                 nid.nid_namelen = strlen(pwd->pw_name);
411                 if (manage_gids != 0) {
412                         /* Get the group list for this user. */
413                         ngroup = NGROUPS;
414                         if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
415                             &ngroup) < 0)
416                                 syslog(LOG_ERR, "Group list too small");
417                         nid.nid_ngroup = ngroup;
418                         nid.nid_grps = grps;
419                 } else {
420                         nid.nid_ngroup = 0;
421                         nid.nid_grps = NULL;
422                 }
423                 nid.nid_flag = NFSID_ADDUID;
424 #ifdef DEBUG
425                 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
426 #else
427                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
428                 if (error)
429                         errx(1, "Can't add user %s", pwd->pw_name);
430 #endif
431                 i++;
432         }
433
434         /*
435          * I should feel guilty for not calling this for all the above exit()
436          * upon error cases, but I don't.
437          */
438         if (mustfreeai)
439                 freeaddrinfo(aip);
440
441 #ifdef DEBUG
442         exit(0);
443 #endif
444         /*
445          * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
446          * end up bogus.
447          */
448         sigemptyset(&signew);
449         sigaddset(&signew, SIGUSR1);
450         sigaddset(&signew, SIGCHLD);
451         sigprocmask(SIG_BLOCK, &signew, NULL);
452
453         daemon(0, 0);
454         (void)signal(SIGHUP, SIG_IGN);
455         (void)signal(SIGINT, SIG_IGN);
456         (void)signal(SIGQUIT, SIG_IGN);
457         (void)signal(SIGTERM, SIG_IGN);
458         (void)signal(SIGUSR1, cleanup_term);
459         (void)signal(SIGCHLD, cleanup_term);
460
461         openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
462
463         /*
464          * Fork off the slave daemons that do the work. All the master
465          * does is kill them off and cleanup.
466          */
467         for (i = 0; i < nfsuserdcnt; i++) {
468                 slaves[i] = fork();
469                 if (slaves[i] == 0) {
470                         im_a_slave = 1;
471                         setproctitle("slave");
472                         sigemptyset(&signew);
473                         sigaddset(&signew, SIGUSR1);
474                         sigprocmask(SIG_UNBLOCK, &signew, NULL);
475
476                         /*
477                          * and away we go.
478                          */
479                         svc_run();
480                         syslog(LOG_ERR, "nfsuserd died: %m");
481                         exit(1);
482                 } else if (slaves[i] < 0) {
483                         syslog(LOG_ERR, "fork: %m");
484                 }
485         }
486
487         /*
488          * Just wait for SIGUSR1 or a child to die and then...
489          * As the Governor of California would say, "Terminate them".
490          */
491         setproctitle("master");
492         sigemptyset(&signew);
493         while (1)
494                 sigsuspend(&signew);
495 }
496
497 /*
498  * The nfsuserd rpc service
499  */
500 static void
501 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
502 {
503         struct passwd *pwd;
504         struct group *grp;
505         int error;
506 #if defined(INET) || defined(INET6)
507         u_short sport;
508         int ret;
509 #endif
510         struct info info;
511         struct nfsd_idargs nid;
512         gid_t grps[NGROUPS];
513         int ngroup;
514 #ifdef INET
515         struct sockaddr_in *fromsin, *sin;
516 #endif
517 #ifdef INET6
518         struct sockaddr_in6 *fromsin6, *sin6;
519         char buf[INET6_ADDRSTRLEN];
520 #endif
521
522         /*
523          * Only handle requests from localhost on a reserved port number.
524          * If the upcall is from a different address, call nfsbind_localhost()
525          * to check for a remapping of localhost, due to jails.
526          * (Since a reserved port # at localhost implies a client with
527          *  local root, there won't be a security breach. This is about
528          *  the only case I can think of where a reserved port # means
529          *  something.)
530          */
531         if (rqstp->rq_proc != NULLPROC) {
532                 switch (fromip.ss_family) {
533 #ifdef INET
534                 case AF_INET:
535                         if (transp->xp_rtaddr.len < sizeof(*sin)) {
536                                 syslog(LOG_ERR, "xp_rtaddr too small");
537                                 svcerr_weakauth(transp);
538                                 return;
539                         }
540                         sin = (struct sockaddr_in *)transp->xp_rtaddr.buf;
541                         fromsin = (struct sockaddr_in *)&fromip;
542                         sport = ntohs(sin->sin_port);
543                         if (sport >= IPPORT_RESERVED) {
544                                 syslog(LOG_ERR, "not a reserved port#");
545                                 svcerr_weakauth(transp);
546                                 return;
547                         }
548                         ret = 1;
549                         if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr)
550                                 ret = nfsbind_localhost();
551                         if (ret == 0 || sin->sin_addr.s_addr !=
552                             fromsin->sin_addr.s_addr) {
553                                 syslog(LOG_ERR, "bad from ip %s",
554                                     inet_ntoa(sin->sin_addr));
555                                 svcerr_weakauth(transp);
556                                 return;
557                         }
558                         break;
559 #endif  /* INET */
560 #ifdef INET6
561                 case AF_INET6:
562                         if (transp->xp_rtaddr.len < sizeof(*sin6)) {
563                                 syslog(LOG_ERR, "xp_rtaddr too small");
564                                 svcerr_weakauth(transp);
565                                 return;
566                         }
567                         sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
568                         fromsin6 = (struct sockaddr_in6 *)&fromip;
569                         sport = ntohs(sin6->sin6_port);
570                         if (sport >= IPV6PORT_RESERVED) {
571                                 syslog(LOG_ERR, "not a reserved port#");
572                                 svcerr_weakauth(transp);
573                                 return;
574                         }
575                         ret = 1;
576                         if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
577                             &fromsin6->sin6_addr))
578                                 ret = nfsbind_localhost();
579                         if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
580                             &fromsin6->sin6_addr)) {
581                                 if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
582                                     INET6_ADDRSTRLEN) != NULL)
583                                         syslog(LOG_ERR, "bad from ip %s", buf);
584                                 else
585                                         syslog(LOG_ERR, "bad from ip6 addr");
586                                 svcerr_weakauth(transp);
587                                 return;
588                         }
589                         break;
590 #endif  /* INET6 */
591                 }
592         }
593         switch (rqstp->rq_proc) {
594         case NULLPROC:
595                 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
596                         syslog(LOG_ERR, "Can't send reply");
597                 return;
598         case RPCNFSUSERD_GETUID:
599                 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
600                     (caddr_t)&info)) {
601                         svcerr_decode(transp);
602                         return;
603                 }
604                 pwd = getpwuid((uid_t)info.id);
605                 info.retval = 0;
606                 if (pwd != NULL) {
607                         nid.nid_usertimeout = defusertimeout;
608                         nid.nid_uid = pwd->pw_uid;
609                         nid.nid_name = pwd->pw_name;
610                         if (manage_gids != 0) {
611                                 /* Get the group list for this user. */
612                                 ngroup = NGROUPS;
613                                 if (getgrouplist(pwd->pw_name, pwd->pw_gid,
614                                     grps, &ngroup) < 0)
615                                         syslog(LOG_ERR, "Group list too small");
616                                 nid.nid_ngroup = ngroup;
617                                 nid.nid_grps = grps;
618                         } else {
619                                 nid.nid_ngroup = 0;
620                                 nid.nid_grps = NULL;
621                         }
622                 } else {
623                         nid.nid_usertimeout = 5;
624                         nid.nid_uid = (uid_t)info.id;
625                         nid.nid_name = defaultuser;
626                         nid.nid_ngroup = 0;
627                         nid.nid_grps = NULL;
628                 }
629                 nid.nid_namelen = strlen(nid.nid_name);
630                 nid.nid_flag = NFSID_ADDUID;
631                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
632                 if (error) {
633                         info.retval = error;
634                         syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
635                 } else if (verbose) {
636                         syslog(LOG_ERR,"Added uid=%d name=%s\n",
637                             nid.nid_uid, nid.nid_name);
638                 }
639                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
640                     (caddr_t)&info))
641                         syslog(LOG_ERR, "Can't send reply");
642                 return;
643         case RPCNFSUSERD_GETGID:
644                 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
645                     (caddr_t)&info)) {
646                         svcerr_decode(transp);
647                         return;
648                 }
649                 grp = getgrgid((gid_t)info.id);
650                 info.retval = 0;
651                 if (grp != NULL) {
652                         nid.nid_usertimeout = defusertimeout;
653                         nid.nid_gid = grp->gr_gid;
654                         nid.nid_name = grp->gr_name;
655                 } else {
656                         nid.nid_usertimeout = 5;
657                         nid.nid_gid = (gid_t)info.id;
658                         nid.nid_name = defaultgroup;
659                 }
660                 nid.nid_namelen = strlen(nid.nid_name);
661                 nid.nid_ngroup = 0;
662                 nid.nid_grps = NULL;
663                 nid.nid_flag = NFSID_ADDGID;
664                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
665                 if (error) {
666                         info.retval = error;
667                         syslog(LOG_ERR, "Can't add group %s\n",
668                             grp->gr_name);
669                 } else if (verbose) {
670                         syslog(LOG_ERR,"Added gid=%d name=%s\n",
671                             nid.nid_gid, nid.nid_name);
672                 }
673                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
674                     (caddr_t)&info))
675                         syslog(LOG_ERR, "Can't send reply");
676                 return;
677         case RPCNFSUSERD_GETUSER:
678                 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
679                     (caddr_t)&info)) {
680                         svcerr_decode(transp);
681                         return;
682                 }
683                 pwd = getpwnam(info.name);
684                 info.retval = 0;
685                 if (pwd != NULL) {
686                         nid.nid_usertimeout = defusertimeout;
687                         nid.nid_uid = pwd->pw_uid;
688                         nid.nid_name = pwd->pw_name;
689                 } else {
690                         nid.nid_usertimeout = 5;
691                         nid.nid_uid = defaultuid;
692                         nid.nid_name = info.name;
693                 }
694                 nid.nid_namelen = strlen(nid.nid_name);
695                 nid.nid_ngroup = 0;
696                 nid.nid_grps = NULL;
697                 nid.nid_flag = NFSID_ADDUSERNAME;
698                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
699                 if (error) {
700                         info.retval = error;
701                         syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
702                 } else if (verbose) {
703                         syslog(LOG_ERR,"Added uid=%d name=%s\n",
704                             nid.nid_uid, nid.nid_name);
705                 }
706                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
707                     (caddr_t)&info))
708                         syslog(LOG_ERR, "Can't send reply");
709                 return;
710         case RPCNFSUSERD_GETGROUP:
711                 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
712                     (caddr_t)&info)) {
713                         svcerr_decode(transp);
714                         return;
715                 }
716                 grp = getgrnam(info.name);
717                 info.retval = 0;
718                 if (grp != NULL) {
719                         nid.nid_usertimeout = defusertimeout;
720                         nid.nid_gid = grp->gr_gid;
721                         nid.nid_name = grp->gr_name;
722                 } else {
723                         nid.nid_usertimeout = 5;
724                         nid.nid_gid = defaultgid;
725                         nid.nid_name = info.name;
726                 }
727                 nid.nid_namelen = strlen(nid.nid_name);
728                 nid.nid_ngroup = 0;
729                 nid.nid_grps = NULL;
730                 nid.nid_flag = NFSID_ADDGROUPNAME;
731                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
732                 if (error) {
733                         info.retval = error;
734                         syslog(LOG_ERR, "Can't add group %s\n",
735                             grp->gr_name);
736                 } else if (verbose) {
737                         syslog(LOG_ERR,"Added gid=%d name=%s\n",
738                             nid.nid_gid, nid.nid_name);
739                 }
740                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
741                     (caddr_t)&info))
742                         syslog(LOG_ERR, "Can't send reply");
743                 return;
744         default:
745                 svcerr_noproc(transp);
746                 return;
747         };
748 }
749
750 /*
751  * Xdr routine to get an id number
752  */
753 static bool_t
754 xdr_getid(XDR *xdrsp, caddr_t cp)
755 {
756         struct info *ifp = (struct info *)cp;
757
758         return (xdr_long(xdrsp, &ifp->id));
759 }
760
761 /*
762  * Xdr routine to get a user name
763  */
764 static bool_t
765 xdr_getname(XDR *xdrsp, caddr_t cp)
766 {
767         struct info *ifp = (struct info *)cp;
768         long len;
769
770         if (!xdr_long(xdrsp, &len))
771                 return (0);
772         if (len > MAXNAME)
773                 return (0);
774         if (!xdr_opaque(xdrsp, ifp->name, len))
775                 return (0);
776         ifp->name[len] = '\0';
777         return (1);
778 }
779
780 /*
781  * Xdr routine to return the value.
782  */
783 static bool_t
784 xdr_retval(XDR *xdrsp, caddr_t cp)
785 {
786         struct info *ifp = (struct info *)cp;
787         long val;
788
789         val = ifp->retval;
790         return (xdr_long(xdrsp, &val));
791 }
792
793 /*
794  * cleanup_term() called via SIGUSR1.
795  */
796 static void
797 cleanup_term(int signo __unused)
798 {
799         int i, cnt;
800
801         if (im_a_slave)
802                 exit(0);
803
804         /*
805          * Ok, so I'm the master.
806          * As the Governor of California might say, "Terminate them".
807          */
808         cnt = 0;
809         for (i = 0; i < nfsuserdcnt; i++) {
810                 if (slaves[i] != (pid_t)-1) {
811                         cnt++;
812                         kill(slaves[i], SIGUSR1);
813                 }
814         }
815
816         /*
817          * and wait for them to die
818          */
819         for (i = 0; i < cnt; i++)
820                 wait3(NULL, 0, NULL);
821
822         /*
823          * Finally, get rid of the socket
824          */
825         if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
826                 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
827                 exit(1);
828         }
829         exit(0);
830 }
831
832 /*
833  * Get the IP address that the localhost address maps to.
834  * This is needed when jails map localhost to another IP address.
835  */
836 static int
837 nfsbind_localhost(void)
838 {
839 #ifdef INET
840         struct sockaddr_in sin;
841 #endif
842 #ifdef INET6
843         struct sockaddr_in6 sin6;
844 #endif
845         socklen_t slen;
846         int ret, s;
847
848         switch (fromip.ss_family) {
849 #ifdef INET6
850         case AF_INET6:
851                 s = socket(PF_INET6, SOCK_DGRAM, 0);
852                 if (s < 0)
853                         return (0);
854                 memset(&sin6, 0, sizeof(sin6));
855                 sin6.sin6_len = sizeof(sin6);
856                 sin6.sin6_family = AF_INET6;
857                 sin6.sin6_addr = in6loopback;
858                 sin6.sin6_port = 0;
859                 ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6));
860                 if (ret < 0) {
861                         close(s);
862                         return (0);
863                 }
864                 break;
865 #endif  /* INET6 */
866 #ifdef INET
867         case AF_INET:
868                 s = socket(PF_INET, SOCK_DGRAM, 0);
869                 if (s < 0)
870                         return (0);
871                 memset(&sin, 0, sizeof(sin));
872                 sin.sin_len = sizeof(sin);
873                 sin.sin_family = AF_INET;
874                 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
875                 sin.sin_port = 0;
876                 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
877                 if (ret < 0) {
878                         close(s);
879                         return (0);
880                 }
881                 break;
882 #endif  /* INET */
883         }
884         memset(&fromip, 0, sizeof(fromip));
885         slen = sizeof(fromip);
886         ret = getsockname(s, (struct sockaddr *)&fromip, &slen);
887         close(s);
888         if (ret < 0)
889                 return (0);
890         return (1);
891 }
892
893 static void
894 usage(void)
895 {
896
897         errx(1,
898             "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
899 }