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 } 728