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