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