]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/nfsuserd/nfsuserd.c
Move SYSCTL_ADD_PROC() to unlocked context in if_ure to avoid lock order reversal.
[FreeBSD/FreeBSD.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         endgrent();
386
387         /*
388          * Loop around adding all users.
389          */
390         start_uidpos = i;
391         setpwent();
392         while (i < nid.nid_usermax && (pwd = getpwent())) {
393                 fnd_dup = 0;
394                 /*
395                  * Yes, this is inefficient, but it is only done once when
396                  * the daemon is started and will run in a fraction of a second
397                  * for nid_usermax at 10000. If nid_usermax is cranked up to
398                  * 100000, it will take several seconds, depending on the CPU.
399                  */
400                 for (j = 0; j < (i - start_uidpos); j++)
401                         if (check_dups[j] == pwd->pw_uid) {
402                                 /* Found another entry for uid, so skip it */
403                                 fnd_dup = 1;
404                                 break;
405                         }
406                 if (fnd_dup != 0)
407                         continue;
408                 check_dups[i - start_uidpos] = pwd->pw_uid;
409                 nid.nid_uid = pwd->pw_uid;
410                 nid.nid_name = pwd->pw_name;
411                 nid.nid_namelen = strlen(pwd->pw_name);
412                 if (manage_gids != 0) {
413                         /* Get the group list for this user. */
414                         ngroup = NGROUPS;
415                         if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
416                             &ngroup) < 0)
417                                 syslog(LOG_ERR, "Group list too small");
418                         nid.nid_ngroup = ngroup;
419                         nid.nid_grps = grps;
420                 } else {
421                         nid.nid_ngroup = 0;
422                         nid.nid_grps = NULL;
423                 }
424                 nid.nid_flag = NFSID_ADDUID;
425 #ifdef DEBUG
426                 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
427 #else
428                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
429                 if (error)
430                         errx(1, "Can't add user %s", pwd->pw_name);
431 #endif
432                 i++;
433         }
434         endpwent();
435
436         /*
437          * I should feel guilty for not calling this for all the above exit()
438          * upon error cases, but I don't.
439          */
440         if (mustfreeai)
441                 freeaddrinfo(aip);
442
443 #ifdef DEBUG
444         exit(0);
445 #endif
446         /*
447          * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
448          * end up bogus.
449          */
450         sigemptyset(&signew);
451         sigaddset(&signew, SIGUSR1);
452         sigaddset(&signew, SIGCHLD);
453         sigprocmask(SIG_BLOCK, &signew, NULL);
454
455         daemon(0, 0);
456         (void)signal(SIGHUP, SIG_IGN);
457         (void)signal(SIGINT, SIG_IGN);
458         (void)signal(SIGQUIT, SIG_IGN);
459         (void)signal(SIGTERM, SIG_IGN);
460         (void)signal(SIGUSR1, cleanup_term);
461         (void)signal(SIGCHLD, cleanup_term);
462
463         openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
464
465         /*
466          * Fork off the slave daemons that do the work. All the master
467          * does is kill them off and cleanup.
468          */
469         for (i = 0; i < nfsuserdcnt; i++) {
470                 slaves[i] = fork();
471                 if (slaves[i] == 0) {
472                         im_a_slave = 1;
473                         setproctitle("slave");
474                         sigemptyset(&signew);
475                         sigaddset(&signew, SIGUSR1);
476                         sigprocmask(SIG_UNBLOCK, &signew, NULL);
477
478                         /*
479                          * and away we go.
480                          */
481                         svc_run();
482                         syslog(LOG_ERR, "nfsuserd died: %m");
483                         exit(1);
484                 } else if (slaves[i] < 0) {
485                         syslog(LOG_ERR, "fork: %m");
486                 }
487         }
488
489         /*
490          * Just wait for SIGUSR1 or a child to die and then...
491          * As the Governor of California would say, "Terminate them".
492          */
493         setproctitle("master");
494         sigemptyset(&signew);
495         while (1)
496                 sigsuspend(&signew);
497 }
498
499 /*
500  * The nfsuserd rpc service
501  */
502 static void
503 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
504 {
505         struct passwd *pwd;
506         struct group *grp;
507         int error;
508 #if defined(INET) || defined(INET6)
509         u_short sport;
510         int ret;
511 #endif
512         struct info info;
513         struct nfsd_idargs nid;
514         gid_t grps[NGROUPS];
515         int ngroup;
516 #ifdef INET
517         struct sockaddr_in *fromsin, *sin;
518 #endif
519 #ifdef INET6
520         struct sockaddr_in6 *fromsin6, *sin6;
521         char buf[INET6_ADDRSTRLEN];
522 #endif
523
524         /*
525          * Only handle requests from localhost on a reserved port number.
526          * If the upcall is from a different address, call nfsbind_localhost()
527          * to check for a remapping of localhost, due to jails.
528          * (Since a reserved port # at localhost implies a client with
529          *  local root, there won't be a security breach. This is about
530          *  the only case I can think of where a reserved port # means
531          *  something.)
532          */
533         if (rqstp->rq_proc != NULLPROC) {
534                 switch (fromip.ss_family) {
535 #ifdef INET
536                 case AF_INET:
537                         if (transp->xp_rtaddr.len < sizeof(*sin)) {
538                                 syslog(LOG_ERR, "xp_rtaddr too small");
539                                 svcerr_weakauth(transp);
540                                 return;
541                         }
542                         sin = (struct sockaddr_in *)transp->xp_rtaddr.buf;
543                         fromsin = (struct sockaddr_in *)&fromip;
544                         sport = ntohs(sin->sin_port);
545                         if (sport >= IPPORT_RESERVED) {
546                                 syslog(LOG_ERR, "not a reserved port#");
547                                 svcerr_weakauth(transp);
548                                 return;
549                         }
550                         ret = 1;
551                         if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr)
552                                 ret = nfsbind_localhost();
553                         if (ret == 0 || sin->sin_addr.s_addr !=
554                             fromsin->sin_addr.s_addr) {
555                                 syslog(LOG_ERR, "bad from ip %s",
556                                     inet_ntoa(sin->sin_addr));
557                                 svcerr_weakauth(transp);
558                                 return;
559                         }
560                         break;
561 #endif  /* INET */
562 #ifdef INET6
563                 case AF_INET6:
564                         if (transp->xp_rtaddr.len < sizeof(*sin6)) {
565                                 syslog(LOG_ERR, "xp_rtaddr too small");
566                                 svcerr_weakauth(transp);
567                                 return;
568                         }
569                         sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
570                         fromsin6 = (struct sockaddr_in6 *)&fromip;
571                         sport = ntohs(sin6->sin6_port);
572                         if (sport >= IPV6PORT_RESERVED) {
573                                 syslog(LOG_ERR, "not a reserved port#");
574                                 svcerr_weakauth(transp);
575                                 return;
576                         }
577                         ret = 1;
578                         if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
579                             &fromsin6->sin6_addr))
580                                 ret = nfsbind_localhost();
581                         if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
582                             &fromsin6->sin6_addr)) {
583                                 if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
584                                     INET6_ADDRSTRLEN) != NULL)
585                                         syslog(LOG_ERR, "bad from ip %s", buf);
586                                 else
587                                         syslog(LOG_ERR, "bad from ip6 addr");
588                                 svcerr_weakauth(transp);
589                                 return;
590                         }
591                         break;
592 #endif  /* INET6 */
593                 }
594         }
595         switch (rqstp->rq_proc) {
596         case NULLPROC:
597                 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
598                         syslog(LOG_ERR, "Can't send reply");
599                 return;
600         case RPCNFSUSERD_GETUID:
601                 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
602                     (caddr_t)&info)) {
603                         svcerr_decode(transp);
604                         return;
605                 }
606                 pwd = getpwuid((uid_t)info.id);
607                 info.retval = 0;
608                 if (pwd != NULL) {
609                         nid.nid_usertimeout = defusertimeout;
610                         nid.nid_uid = pwd->pw_uid;
611                         nid.nid_name = pwd->pw_name;
612                         if (manage_gids != 0) {
613                                 /* Get the group list for this user. */
614                                 ngroup = NGROUPS;
615                                 if (getgrouplist(pwd->pw_name, pwd->pw_gid,
616                                     grps, &ngroup) < 0)
617                                         syslog(LOG_ERR, "Group list too small");
618                                 nid.nid_ngroup = ngroup;
619                                 nid.nid_grps = grps;
620                         } else {
621                                 nid.nid_ngroup = 0;
622                                 nid.nid_grps = NULL;
623                         }
624                 } else {
625                         nid.nid_usertimeout = 5;
626                         nid.nid_uid = (uid_t)info.id;
627                         nid.nid_name = defaultuser;
628                         nid.nid_ngroup = 0;
629                         nid.nid_grps = NULL;
630                 }
631                 nid.nid_namelen = strlen(nid.nid_name);
632                 nid.nid_flag = NFSID_ADDUID;
633                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
634                 if (error) {
635                         info.retval = error;
636                         syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
637                 } else if (verbose) {
638                         syslog(LOG_ERR,"Added uid=%d name=%s\n",
639                             nid.nid_uid, nid.nid_name);
640                 }
641                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
642                     (caddr_t)&info))
643                         syslog(LOG_ERR, "Can't send reply");
644                 return;
645         case RPCNFSUSERD_GETGID:
646                 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
647                     (caddr_t)&info)) {
648                         svcerr_decode(transp);
649                         return;
650                 }
651                 grp = getgrgid((gid_t)info.id);
652                 info.retval = 0;
653                 if (grp != NULL) {
654                         nid.nid_usertimeout = defusertimeout;
655                         nid.nid_gid = grp->gr_gid;
656                         nid.nid_name = grp->gr_name;
657                 } else {
658                         nid.nid_usertimeout = 5;
659                         nid.nid_gid = (gid_t)info.id;
660                         nid.nid_name = defaultgroup;
661                 }
662                 nid.nid_namelen = strlen(nid.nid_name);
663                 nid.nid_ngroup = 0;
664                 nid.nid_grps = NULL;
665                 nid.nid_flag = NFSID_ADDGID;
666                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
667                 if (error) {
668                         info.retval = error;
669                         syslog(LOG_ERR, "Can't add group %s\n",
670                             grp->gr_name);
671                 } else if (verbose) {
672                         syslog(LOG_ERR,"Added gid=%d name=%s\n",
673                             nid.nid_gid, nid.nid_name);
674                 }
675                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
676                     (caddr_t)&info))
677                         syslog(LOG_ERR, "Can't send reply");
678                 return;
679         case RPCNFSUSERD_GETUSER:
680                 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
681                     (caddr_t)&info)) {
682                         svcerr_decode(transp);
683                         return;
684                 }
685                 pwd = getpwnam(info.name);
686                 info.retval = 0;
687                 if (pwd != NULL) {
688                         nid.nid_usertimeout = defusertimeout;
689                         nid.nid_uid = pwd->pw_uid;
690                         nid.nid_name = pwd->pw_name;
691                 } else {
692                         nid.nid_usertimeout = 5;
693                         nid.nid_uid = defaultuid;
694                         nid.nid_name = info.name;
695                 }
696                 nid.nid_namelen = strlen(nid.nid_name);
697                 nid.nid_ngroup = 0;
698                 nid.nid_grps = NULL;
699                 nid.nid_flag = NFSID_ADDUSERNAME;
700                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
701                 if (error) {
702                         info.retval = error;
703                         syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
704                 } else if (verbose) {
705                         syslog(LOG_ERR,"Added uid=%d name=%s\n",
706                             nid.nid_uid, nid.nid_name);
707                 }
708                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
709                     (caddr_t)&info))
710                         syslog(LOG_ERR, "Can't send reply");
711                 return;
712         case RPCNFSUSERD_GETGROUP:
713                 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
714                     (caddr_t)&info)) {
715                         svcerr_decode(transp);
716                         return;
717                 }
718                 grp = getgrnam(info.name);
719                 info.retval = 0;
720                 if (grp != NULL) {
721                         nid.nid_usertimeout = defusertimeout;
722                         nid.nid_gid = grp->gr_gid;
723                         nid.nid_name = grp->gr_name;
724                 } else {
725                         nid.nid_usertimeout = 5;
726                         nid.nid_gid = defaultgid;
727                         nid.nid_name = info.name;
728                 }
729                 nid.nid_namelen = strlen(nid.nid_name);
730                 nid.nid_ngroup = 0;
731                 nid.nid_grps = NULL;
732                 nid.nid_flag = NFSID_ADDGROUPNAME;
733                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
734                 if (error) {
735                         info.retval = error;
736                         syslog(LOG_ERR, "Can't add group %s\n",
737                             grp->gr_name);
738                 } else if (verbose) {
739                         syslog(LOG_ERR,"Added gid=%d name=%s\n",
740                             nid.nid_gid, nid.nid_name);
741                 }
742                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
743                     (caddr_t)&info))
744                         syslog(LOG_ERR, "Can't send reply");
745                 return;
746         default:
747                 svcerr_noproc(transp);
748                 return;
749         };
750 }
751
752 /*
753  * Xdr routine to get an id number
754  */
755 static bool_t
756 xdr_getid(XDR *xdrsp, caddr_t cp)
757 {
758         struct info *ifp = (struct info *)cp;
759
760         return (xdr_long(xdrsp, &ifp->id));
761 }
762
763 /*
764  * Xdr routine to get a user name
765  */
766 static bool_t
767 xdr_getname(XDR *xdrsp, caddr_t cp)
768 {
769         struct info *ifp = (struct info *)cp;
770         long len;
771
772         if (!xdr_long(xdrsp, &len))
773                 return (0);
774         if (len > MAXNAME)
775                 return (0);
776         if (!xdr_opaque(xdrsp, ifp->name, len))
777                 return (0);
778         ifp->name[len] = '\0';
779         return (1);
780 }
781
782 /*
783  * Xdr routine to return the value.
784  */
785 static bool_t
786 xdr_retval(XDR *xdrsp, caddr_t cp)
787 {
788         struct info *ifp = (struct info *)cp;
789         long val;
790
791         val = ifp->retval;
792         return (xdr_long(xdrsp, &val));
793 }
794
795 /*
796  * cleanup_term() called via SIGUSR1.
797  */
798 static void
799 cleanup_term(int signo __unused)
800 {
801         int i, cnt;
802
803         if (im_a_slave)
804                 exit(0);
805
806         /*
807          * Ok, so I'm the master.
808          * As the Governor of California might say, "Terminate them".
809          */
810         cnt = 0;
811         for (i = 0; i < nfsuserdcnt; i++) {
812                 if (slaves[i] != (pid_t)-1) {
813                         cnt++;
814                         kill(slaves[i], SIGUSR1);
815                 }
816         }
817
818         /*
819          * and wait for them to die
820          */
821         for (i = 0; i < cnt; i++)
822                 wait3(NULL, 0, NULL);
823
824         /*
825          * Finally, get rid of the socket
826          */
827         if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
828                 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
829                 exit(1);
830         }
831         exit(0);
832 }
833
834 /*
835  * Get the IP address that the localhost address maps to.
836  * This is needed when jails map localhost to another IP address.
837  */
838 static int
839 nfsbind_localhost(void)
840 {
841 #ifdef INET
842         struct sockaddr_in sin;
843 #endif
844 #ifdef INET6
845         struct sockaddr_in6 sin6;
846 #endif
847         socklen_t slen;
848         int ret, s;
849
850         switch (fromip.ss_family) {
851 #ifdef INET6
852         case AF_INET6:
853                 s = socket(PF_INET6, SOCK_DGRAM, 0);
854                 if (s < 0)
855                         return (0);
856                 memset(&sin6, 0, sizeof(sin6));
857                 sin6.sin6_len = sizeof(sin6);
858                 sin6.sin6_family = AF_INET6;
859                 sin6.sin6_addr = in6loopback;
860                 sin6.sin6_port = 0;
861                 ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6));
862                 if (ret < 0) {
863                         close(s);
864                         return (0);
865                 }
866                 break;
867 #endif  /* INET6 */
868 #ifdef INET
869         case AF_INET:
870                 s = socket(PF_INET, SOCK_DGRAM, 0);
871                 if (s < 0)
872                         return (0);
873                 memset(&sin, 0, sizeof(sin));
874                 sin.sin_len = sizeof(sin);
875                 sin.sin_family = AF_INET;
876                 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
877                 sin.sin_port = 0;
878                 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
879                 if (ret < 0) {
880                         close(s);
881                         return (0);
882                 }
883                 break;
884 #endif  /* INET */
885         }
886         memset(&fromip, 0, sizeof(fromip));
887         slen = sizeof(fromip);
888         ret = getsockname(s, (struct sockaddr *)&fromip, &slen);
889         close(s);
890         if (ret < 0)
891                 return (0);
892         return (1);
893 }
894
895 static void
896 usage(void)
897 {
898
899         errx(1,
900             "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
901 }