]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - usr.sbin/nfsuserd/nfsuserd.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.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 = (uid_t)32767;
92 u_char *defaultgroup = "nogroup";
93 gid_t defaultgid = (gid_t)32767;
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
338         /*
339          * Loop around adding all users.
340          */
341         start_uidpos = i;
342         setpwent();
343         while (i < nid.nid_usermax && (pwd = getpwent())) {
344                 fnd_dup = 0;
345                 /*
346                  * Yes, this is inefficient, but it is only done once when
347                  * the daemon is started and will run in a fraction of a second
348                  * for nid_usermax at 10000. If nid_usermax is cranked up to
349                  * 100000, it will take several seconds, depending on the CPU.
350                  */
351                 for (j = 0; j < (i - start_uidpos); j++)
352                         if (check_dups[j] == pwd->pw_uid) {
353                                 /* Found another entry for uid, so skip it */
354                                 fnd_dup = 1;
355                                 break;
356                         }
357                 if (fnd_dup != 0)
358                         continue;
359                 check_dups[i - start_uidpos] = pwd->pw_uid;
360                 nid.nid_uid = pwd->pw_uid;
361                 nid.nid_name = pwd->pw_name;
362                 nid.nid_namelen = strlen(pwd->pw_name);
363                 if (manage_gids != 0) {
364                         /* Get the group list for this user. */
365                         ngroup = NGROUPS;
366                         if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
367                             &ngroup) < 0)
368                                 syslog(LOG_ERR, "Group list too small");
369                         nid.nid_ngroup = ngroup;
370                         nid.nid_grps = grps;
371                 } else {
372                         nid.nid_ngroup = 0;
373                         nid.nid_grps = NULL;
374                 }
375                 nid.nid_flag = NFSID_ADDUID;
376 #ifdef DEBUG
377                 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
378 #else
379                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
380                 if (error)
381                         errx(1, "Can't add user %s", pwd->pw_name);
382 #endif
383                 i++;
384         }
385
386         /*
387          * I should feel guilty for not calling this for all the above exit()
388          * upon error cases, but I don't.
389          */
390         if (mustfreeai)
391                 freeaddrinfo(aip);
392
393 #ifdef DEBUG
394         exit(0);
395 #endif
396         /*
397          * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
398          * end up bogus.
399          */
400         sigemptyset(&signew);
401         sigaddset(&signew, SIGUSR1);
402         sigaddset(&signew, SIGCHLD);
403         sigprocmask(SIG_BLOCK, &signew, NULL);
404
405         daemon(0, 0);
406         (void)signal(SIGHUP, SIG_IGN);
407         (void)signal(SIGINT, SIG_IGN);
408         (void)signal(SIGQUIT, SIG_IGN);
409         (void)signal(SIGTERM, SIG_IGN);
410         (void)signal(SIGUSR1, cleanup_term);
411         (void)signal(SIGCHLD, cleanup_term);
412
413         openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
414
415         /*
416          * Fork off the slave daemons that do the work. All the master
417          * does is kill them off and cleanup.
418          */
419         for (i = 0; i < nfsuserdcnt; i++) {
420                 slaves[i] = fork();
421                 if (slaves[i] == 0) {
422                         im_a_slave = 1;
423                         setproctitle("slave");
424                         sigemptyset(&signew);
425                         sigaddset(&signew, SIGUSR1);
426                         sigprocmask(SIG_UNBLOCK, &signew, NULL);
427
428                         /*
429                          * and away we go.
430                          */
431                         svc_run();
432                         syslog(LOG_ERR, "nfsuserd died: %m");
433                         exit(1);
434                 } else if (slaves[i] < 0) {
435                         syslog(LOG_ERR, "fork: %m");
436                 }
437         }
438
439         /*
440          * Just wait for SIGUSR1 or a child to die and then...
441          * As the Governor of California would say, "Terminate them".
442          */
443         setproctitle("master");
444         sigemptyset(&signew);
445         while (1)
446                 sigsuspend(&signew);
447 }
448
449 /*
450  * The nfsuserd rpc service
451  */
452 static void
453 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
454 {
455         struct passwd *pwd;
456         struct group *grp;
457         int error;
458         u_short sport;
459         struct info info;
460         struct nfsd_idargs nid;
461         u_int32_t saddr;
462         gid_t grps[NGROUPS];
463         int ngroup;
464
465         /*
466          * Only handle requests from 127.0.0.1 on a reserved port number.
467          * (Since a reserved port # at localhost implies a client with
468          *  local root, there won't be a security breach. This is about
469          *  the only case I can think of where a reserved port # means
470          *  something.)
471          */
472         sport = ntohs(transp->xp_raddr.sin_port);
473         saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
474         if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
475             saddr != 0x7f000001) {
476                 syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
477                 svcerr_weakauth(transp);
478                 return;
479         }
480         switch (rqstp->rq_proc) {
481         case NULLPROC:
482                 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
483                         syslog(LOG_ERR, "Can't send reply");
484                 return;
485         case RPCNFSUSERD_GETUID:
486                 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
487                     (caddr_t)&info)) {
488                         svcerr_decode(transp);
489                         return;
490                 }
491                 pwd = getpwuid((uid_t)info.id);
492                 info.retval = 0;
493                 if (pwd != NULL) {
494                         nid.nid_usertimeout = defusertimeout;
495                         nid.nid_uid = pwd->pw_uid;
496                         nid.nid_name = pwd->pw_name;
497                         if (manage_gids != 0) {
498                                 /* Get the group list for this user. */
499                                 ngroup = NGROUPS;
500                                 if (getgrouplist(pwd->pw_name, pwd->pw_gid,
501                                     grps, &ngroup) < 0)
502                                         syslog(LOG_ERR, "Group list too small");
503                                 nid.nid_ngroup = ngroup;
504                                 nid.nid_grps = grps;
505                         } else {
506                                 nid.nid_ngroup = 0;
507                                 nid.nid_grps = NULL;
508                         }
509                 } else {
510                         nid.nid_usertimeout = 5;
511                         nid.nid_uid = (uid_t)info.id;
512                         nid.nid_name = defaultuser;
513                         nid.nid_ngroup = 0;
514                         nid.nid_grps = NULL;
515                 }
516                 nid.nid_namelen = strlen(nid.nid_name);
517                 nid.nid_flag = NFSID_ADDUID;
518                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
519                 if (error) {
520                         info.retval = error;
521                         syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
522                 } else if (verbose) {
523                         syslog(LOG_ERR,"Added uid=%d name=%s\n",
524                             nid.nid_uid, nid.nid_name);
525                 }
526                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
527                     (caddr_t)&info))
528                         syslog(LOG_ERR, "Can't send reply");
529                 return;
530         case RPCNFSUSERD_GETGID:
531                 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
532                     (caddr_t)&info)) {
533                         svcerr_decode(transp);
534                         return;
535                 }
536                 grp = getgrgid((gid_t)info.id);
537                 info.retval = 0;
538                 if (grp != NULL) {
539                         nid.nid_usertimeout = defusertimeout;
540                         nid.nid_gid = grp->gr_gid;
541                         nid.nid_name = grp->gr_name;
542                 } else {
543                         nid.nid_usertimeout = 5;
544                         nid.nid_gid = (gid_t)info.id;
545                         nid.nid_name = defaultgroup;
546                 }
547                 nid.nid_namelen = strlen(nid.nid_name);
548                 nid.nid_ngroup = 0;
549                 nid.nid_grps = NULL;
550                 nid.nid_flag = NFSID_ADDGID;
551                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
552                 if (error) {
553                         info.retval = error;
554                         syslog(LOG_ERR, "Can't add group %s\n",
555                             grp->gr_name);
556                 } else if (verbose) {
557                         syslog(LOG_ERR,"Added gid=%d name=%s\n",
558                             nid.nid_gid, nid.nid_name);
559                 }
560                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
561                     (caddr_t)&info))
562                         syslog(LOG_ERR, "Can't send reply");
563                 return;
564         case RPCNFSUSERD_GETUSER:
565                 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
566                     (caddr_t)&info)) {
567                         svcerr_decode(transp);
568                         return;
569                 }
570                 pwd = getpwnam(info.name);
571                 info.retval = 0;
572                 if (pwd != NULL) {
573                         nid.nid_usertimeout = defusertimeout;
574                         nid.nid_uid = pwd->pw_uid;
575                         nid.nid_name = pwd->pw_name;
576                 } else {
577                         nid.nid_usertimeout = 5;
578                         nid.nid_uid = defaultuid;
579                         nid.nid_name = info.name;
580                 }
581                 nid.nid_namelen = strlen(nid.nid_name);
582                 nid.nid_ngroup = 0;
583                 nid.nid_grps = NULL;
584                 nid.nid_flag = NFSID_ADDUSERNAME;
585                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
586                 if (error) {
587                         info.retval = error;
588                         syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
589                 } else if (verbose) {
590                         syslog(LOG_ERR,"Added uid=%d name=%s\n",
591                             nid.nid_uid, nid.nid_name);
592                 }
593                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
594                     (caddr_t)&info))
595                         syslog(LOG_ERR, "Can't send reply");
596                 return;
597         case RPCNFSUSERD_GETGROUP:
598                 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
599                     (caddr_t)&info)) {
600                         svcerr_decode(transp);
601                         return;
602                 }
603                 grp = getgrnam(info.name);
604                 info.retval = 0;
605                 if (grp != NULL) {
606                         nid.nid_usertimeout = defusertimeout;
607                         nid.nid_gid = grp->gr_gid;
608                         nid.nid_name = grp->gr_name;
609                 } else {
610                         nid.nid_usertimeout = 5;
611                         nid.nid_gid = defaultgid;
612                         nid.nid_name = info.name;
613                 }
614                 nid.nid_namelen = strlen(nid.nid_name);
615                 nid.nid_ngroup = 0;
616                 nid.nid_grps = NULL;
617                 nid.nid_flag = NFSID_ADDGROUPNAME;
618                 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
619                 if (error) {
620                         info.retval = error;
621                         syslog(LOG_ERR, "Can't add group %s\n",
622                             grp->gr_name);
623                 } else if (verbose) {
624                         syslog(LOG_ERR,"Added gid=%d name=%s\n",
625                             nid.nid_gid, nid.nid_name);
626                 }
627                 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
628                     (caddr_t)&info))
629                         syslog(LOG_ERR, "Can't send reply");
630                 return;
631         default:
632                 svcerr_noproc(transp);
633                 return;
634         };
635 }
636
637 /*
638  * Xdr routine to get an id number
639  */
640 static bool_t
641 xdr_getid(XDR *xdrsp, caddr_t cp)
642 {
643         struct info *ifp = (struct info *)cp;
644
645         return (xdr_long(xdrsp, &ifp->id));
646 }
647
648 /*
649  * Xdr routine to get a user name
650  */
651 static bool_t
652 xdr_getname(XDR *xdrsp, caddr_t cp)
653 {
654         struct info *ifp = (struct info *)cp;
655         long len;
656
657         if (!xdr_long(xdrsp, &len))
658                 return (0);
659         if (len > MAXNAME)
660                 return (0);
661         if (!xdr_opaque(xdrsp, ifp->name, len))
662                 return (0);
663         ifp->name[len] = '\0';
664         return (1);
665 }
666
667 /*
668  * Xdr routine to return the value.
669  */
670 static bool_t
671 xdr_retval(XDR *xdrsp, caddr_t cp)
672 {
673         struct info *ifp = (struct info *)cp;
674         long val;
675
676         val = ifp->retval;
677         return (xdr_long(xdrsp, &val));
678 }
679
680 /*
681  * cleanup_term() called via SIGUSR1.
682  */
683 static void
684 cleanup_term(int signo __unused)
685 {
686         int i, cnt;
687
688         if (im_a_slave)
689                 exit(0);
690
691         /*
692          * Ok, so I'm the master.
693          * As the Governor of California might say, "Terminate them".
694          */
695         cnt = 0;
696         for (i = 0; i < nfsuserdcnt; i++) {
697                 if (slaves[i] != (pid_t)-1) {
698                         cnt++;
699                         kill(slaves[i], SIGUSR1);
700                 }
701         }
702
703         /*
704          * and wait for them to die
705          */
706         for (i = 0; i < cnt; i++)
707                 wait3(NULL, 0, NULL);
708
709         /*
710          * Finally, get rid of the socket
711          */
712         if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
713                 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
714                 exit(1);
715         }
716         exit(0);
717 }
718
719 static void
720 usage(void)
721 {
722
723         errx(1,
724             "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
725 }