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