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