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 #include <sys/param.h> 30 #include <sys/errno.h> 31 #include <sys/linker.h> 32 #include <sys/module.h> 33 #include <sys/mount.h> 34 #include <sys/socket.h> 35 #include <sys/socketvar.h> 36 #include <sys/sysctl.h> 37 #include <sys/time.h> 38 #include <sys/ucred.h> 39 #include <sys/vnode.h> 40 #include <sys/wait.h> 41 42 #include <netinet/in.h> 43 44 #include <arpa/inet.h> 45 46 #include <nfs/nfssvc.h> 47 48 #include <rpc/rpc.h> 49 50 #include <fs/nfs/rpcv2.h> 51 #include <fs/nfs/nfsproto.h> 52 #include <fs/nfs/nfskpiport.h> 53 #include <fs/nfs/nfs.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, "Group list too small"); 427 nid.nid_ngroup = ngroup; 428 nid.nid_grps = grps; 429 } else { 430 nid.nid_ngroup = 0; 431 nid.nid_grps = NULL; 432 } 433 nid.nid_flag = NFSID_ADDUID; 434 #ifdef DEBUG 435 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name); 436 #else 437 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 438 if (error) 439 errx(1, "Can't add user %s", pwd->pw_name); 440 #endif 441 i++; 442 } 443 endpwent(); 444 445 /* 446 * I should feel guilty for not calling this for all the above exit() 447 * upon error cases, but I don't. 448 */ 449 if (mustfreeai) 450 freeaddrinfo(aip); 451 452 #ifdef DEBUG 453 exit(0); 454 #endif 455 /* 456 * Temporarily block SIGUSR1 and SIGCHLD, so servers[] can't 457 * end up bogus. 458 */ 459 sigemptyset(&signew); 460 sigaddset(&signew, SIGUSR1); 461 sigaddset(&signew, SIGCHLD); 462 sigprocmask(SIG_BLOCK, &signew, NULL); 463 464 daemon(0, 0); 465 (void)signal(SIGHUP, SIG_IGN); 466 (void)signal(SIGINT, SIG_IGN); 467 (void)signal(SIGQUIT, SIG_IGN); 468 (void)signal(SIGTERM, SIG_IGN); 469 (void)signal(SIGUSR1, cleanup_term); 470 (void)signal(SIGCHLD, cleanup_term); 471 472 openlog("nfsuserd:", LOG_PID, LOG_DAEMON); 473 474 /* 475 * Fork off the server daemons that do the work. All the master 476 * does is terminate them and cleanup. 477 */ 478 for (i = 0; i < nfsuserdcnt; i++) { 479 servers[i] = fork(); 480 if (servers[i] == 0) { 481 im_a_server = 1; 482 setproctitle("server"); 483 sigemptyset(&signew); 484 sigaddset(&signew, SIGUSR1); 485 sigprocmask(SIG_UNBLOCK, &signew, NULL); 486 487 /* 488 * and away we go. 489 */ 490 svc_run(); 491 syslog(LOG_ERR, "nfsuserd died: %m"); 492 exit(1); 493 } else if (servers[i] < 0) { 494 syslog(LOG_ERR, "fork: %m"); 495 } 496 } 497 498 /* 499 * Just wait for SIGUSR1 or a child to die and then... 500 * As the Governor of California would say, "Terminate them". 501 */ 502 setproctitle("master"); 503 sigemptyset(&signew); 504 while (1) 505 sigsuspend(&signew); 506 } 507 508 /* 509 * The nfsuserd rpc service 510 */ 511 static void 512 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp) 513 { 514 struct passwd *pwd; 515 struct group *grp; 516 int error; 517 #if defined(INET) || defined(INET6) 518 u_short sport; 519 int ret; 520 #endif 521 struct info info; 522 struct nfsd_idargs nid; 523 gid_t grps[NGROUPS]; 524 int ngroup; 525 #ifdef INET 526 struct sockaddr_in *fromsin, *sin; 527 #endif 528 #ifdef INET6 529 struct sockaddr_in6 *fromsin6, *sin6; 530 char buf[INET6_ADDRSTRLEN]; 531 #endif 532 533 /* 534 * Only handle requests from localhost on a reserved port number. 535 * If the upcall is from a different address, call nfsbind_localhost() 536 * to check for a remapping of localhost, due to jails. 537 * (Since a reserved port # at localhost implies a client with 538 * local root, there won't be a security breach. This is about 539 * the only case I can think of where a reserved port # means 540 * something.) 541 */ 542 if (rqstp->rq_proc != NULLPROC) { 543 switch (fromip.ss_family) { 544 #ifdef INET 545 case AF_INET: 546 if (transp->xp_rtaddr.len < sizeof(*sin)) { 547 syslog(LOG_ERR, "xp_rtaddr too small"); 548 svcerr_weakauth(transp); 549 return; 550 } 551 sin = (struct sockaddr_in *)transp->xp_rtaddr.buf; 552 fromsin = (struct sockaddr_in *)&fromip; 553 sport = ntohs(sin->sin_port); 554 if (sport >= IPPORT_RESERVED) { 555 syslog(LOG_ERR, "not a reserved port#"); 556 svcerr_weakauth(transp); 557 return; 558 } 559 ret = 1; 560 if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr) 561 ret = nfsbind_localhost(); 562 if (ret == 0 || sin->sin_addr.s_addr != 563 fromsin->sin_addr.s_addr) { 564 syslog(LOG_ERR, "bad from ip %s", 565 inet_ntoa(sin->sin_addr)); 566 svcerr_weakauth(transp); 567 return; 568 } 569 break; 570 #endif /* INET */ 571 #ifdef INET6 572 case AF_INET6: 573 if (transp->xp_rtaddr.len < sizeof(*sin6)) { 574 syslog(LOG_ERR, "xp_rtaddr too small"); 575 svcerr_weakauth(transp); 576 return; 577 } 578 sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf; 579 fromsin6 = (struct sockaddr_in6 *)&fromip; 580 sport = ntohs(sin6->sin6_port); 581 if (sport >= IPV6PORT_RESERVED) { 582 syslog(LOG_ERR, "not a reserved port#"); 583 svcerr_weakauth(transp); 584 return; 585 } 586 ret = 1; 587 if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 588 &fromsin6->sin6_addr)) 589 ret = nfsbind_localhost(); 590 if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 591 &fromsin6->sin6_addr)) { 592 if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 593 INET6_ADDRSTRLEN) != NULL) 594 syslog(LOG_ERR, "bad from ip %s", buf); 595 else 596 syslog(LOG_ERR, "bad from ip6 addr"); 597 svcerr_weakauth(transp); 598 return; 599 } 600 break; 601 #endif /* INET6 */ 602 } 603 } 604 switch (rqstp->rq_proc) { 605 case NULLPROC: 606 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 607 syslog(LOG_ERR, "Can't send reply"); 608 return; 609 case RPCNFSUSERD_GETUID: 610 if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 611 (caddr_t)&info)) { 612 svcerr_decode(transp); 613 return; 614 } 615 pwd = getpwuid((uid_t)info.id); 616 info.retval = 0; 617 if (pwd != NULL) { 618 nid.nid_usertimeout = defusertimeout; 619 nid.nid_uid = pwd->pw_uid; 620 nid.nid_name = pwd->pw_name; 621 if (manage_gids != 0) { 622 /* Get the group list for this user. */ 623 ngroup = NGROUPS; 624 if (getgrouplist(pwd->pw_name, pwd->pw_gid, 625 grps, &ngroup) < 0) 626 syslog(LOG_ERR, "Group list too small"); 627 nid.nid_ngroup = ngroup; 628 nid.nid_grps = grps; 629 } else { 630 nid.nid_ngroup = 0; 631 nid.nid_grps = NULL; 632 } 633 } else { 634 nid.nid_usertimeout = 5; 635 nid.nid_uid = (uid_t)info.id; 636 nid.nid_name = defaultuser; 637 nid.nid_ngroup = 0; 638 nid.nid_grps = NULL; 639 } 640 nid.nid_namelen = strlen(nid.nid_name); 641 nid.nid_flag = NFSID_ADDUID; 642 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 643 if (error) { 644 info.retval = error; 645 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 646 } else if (verbose) { 647 syslog(LOG_ERR,"Added uid=%d name=%s\n", 648 nid.nid_uid, nid.nid_name); 649 } 650 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 651 (caddr_t)&info)) 652 syslog(LOG_ERR, "Can't send reply"); 653 return; 654 case RPCNFSUSERD_GETGID: 655 if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 656 (caddr_t)&info)) { 657 svcerr_decode(transp); 658 return; 659 } 660 grp = getgrgid((gid_t)info.id); 661 info.retval = 0; 662 if (grp != NULL) { 663 nid.nid_usertimeout = defusertimeout; 664 nid.nid_gid = grp->gr_gid; 665 nid.nid_name = grp->gr_name; 666 } else { 667 nid.nid_usertimeout = 5; 668 nid.nid_gid = (gid_t)info.id; 669 nid.nid_name = defaultgroup; 670 } 671 nid.nid_namelen = strlen(nid.nid_name); 672 nid.nid_ngroup = 0; 673 nid.nid_grps = NULL; 674 nid.nid_flag = NFSID_ADDGID; 675 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 676 if (error) { 677 info.retval = error; 678 syslog(LOG_ERR, "Can't add group %s\n", 679 grp->gr_name); 680 } else if (verbose) { 681 syslog(LOG_ERR,"Added gid=%d name=%s\n", 682 nid.nid_gid, nid.nid_name); 683 } 684 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 685 (caddr_t)&info)) 686 syslog(LOG_ERR, "Can't send reply"); 687 return; 688 case RPCNFSUSERD_GETUSER: 689 if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 690 (caddr_t)&info)) { 691 svcerr_decode(transp); 692 return; 693 } 694 pwd = getpwnam(info.name); 695 info.retval = 0; 696 if (pwd != NULL) { 697 nid.nid_usertimeout = defusertimeout; 698 nid.nid_uid = pwd->pw_uid; 699 nid.nid_name = pwd->pw_name; 700 } else { 701 nid.nid_usertimeout = 5; 702 nid.nid_uid = defaultuid; 703 nid.nid_name = info.name; 704 } 705 nid.nid_namelen = strlen(nid.nid_name); 706 nid.nid_ngroup = 0; 707 nid.nid_grps = NULL; 708 nid.nid_flag = NFSID_ADDUSERNAME; 709 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 710 if (error) { 711 info.retval = error; 712 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 713 } else if (verbose) { 714 syslog(LOG_ERR,"Added uid=%d name=%s\n", 715 nid.nid_uid, nid.nid_name); 716 } 717 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 718 (caddr_t)&info)) 719 syslog(LOG_ERR, "Can't send reply"); 720 return; 721 case RPCNFSUSERD_GETGROUP: 722 if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 723 (caddr_t)&info)) { 724 svcerr_decode(transp); 725 return; 726 } 727 grp = getgrnam(info.name); 728 info.retval = 0; 729 if (grp != NULL) { 730 nid.nid_usertimeout = defusertimeout; 731 nid.nid_gid = grp->gr_gid; 732 nid.nid_name = grp->gr_name; 733 } else { 734 nid.nid_usertimeout = 5; 735 nid.nid_gid = defaultgid; 736 nid.nid_name = info.name; 737 } 738 nid.nid_namelen = strlen(nid.nid_name); 739 nid.nid_ngroup = 0; 740 nid.nid_grps = NULL; 741 nid.nid_flag = NFSID_ADDGROUPNAME; 742 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 743 if (error) { 744 info.retval = error; 745 syslog(LOG_ERR, "Can't add group %s\n", 746 grp->gr_name); 747 } else if (verbose) { 748 syslog(LOG_ERR,"Added gid=%d name=%s\n", 749 nid.nid_gid, nid.nid_name); 750 } 751 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 752 (caddr_t)&info)) 753 syslog(LOG_ERR, "Can't send reply"); 754 return; 755 default: 756 svcerr_noproc(transp); 757 return; 758 }; 759 } 760 761 /* 762 * Xdr routine to get an id number 763 */ 764 static bool_t 765 xdr_getid(XDR *xdrsp, caddr_t cp) 766 { 767 struct info *ifp = (struct info *)cp; 768 769 return (xdr_long(xdrsp, &ifp->id)); 770 } 771 772 /* 773 * Xdr routine to get a user name 774 */ 775 static bool_t 776 xdr_getname(XDR *xdrsp, caddr_t cp) 777 { 778 struct info *ifp = (struct info *)cp; 779 long len; 780 781 if (!xdr_long(xdrsp, &len)) 782 return (0); 783 if (len > MAXNAME) 784 return (0); 785 if (!xdr_opaque(xdrsp, ifp->name, len)) 786 return (0); 787 ifp->name[len] = '\0'; 788 return (1); 789 } 790 791 /* 792 * Xdr routine to return the value. 793 */ 794 static bool_t 795 xdr_retval(XDR *xdrsp, caddr_t cp) 796 { 797 struct info *ifp = (struct info *)cp; 798 long val; 799 800 val = ifp->retval; 801 return (xdr_long(xdrsp, &val)); 802 } 803 804 /* 805 * cleanup_term() called via SIGUSR1. 806 */ 807 static void 808 cleanup_term(int signo __unused) 809 { 810 int i, cnt; 811 812 if (im_a_server) 813 exit(0); 814 815 /* 816 * Ok, so I'm the master. 817 * As the Governor of California might say, "Terminate them". 818 */ 819 cnt = 0; 820 for (i = 0; i < nfsuserdcnt; i++) { 821 if (servers[i] != (pid_t)-1) { 822 cnt++; 823 kill(servers[i], SIGUSR1); 824 } 825 } 826 827 /* 828 * and wait for them to die 829 */ 830 for (i = 0; i < cnt; i++) 831 wait3(NULL, 0, NULL); 832 833 /* 834 * Finally, get rid of the socket 835 */ 836 if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) { 837 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n"); 838 exit(1); 839 } 840 exit(0); 841 } 842 843 /* 844 * Get the IP address that the localhost address maps to. 845 * This is needed when jails map localhost to another IP address. 846 */ 847 static int 848 nfsbind_localhost(void) 849 { 850 #ifdef INET 851 struct sockaddr_in sin; 852 #endif 853 #ifdef INET6 854 struct sockaddr_in6 sin6; 855 #endif 856 socklen_t slen; 857 int ret, s; 858 859 switch (fromip.ss_family) { 860 #ifdef INET6 861 case AF_INET6: 862 s = socket(PF_INET6, SOCK_DGRAM, 0); 863 if (s < 0) 864 return (0); 865 memset(&sin6, 0, sizeof(sin6)); 866 sin6.sin6_len = sizeof(sin6); 867 sin6.sin6_family = AF_INET6; 868 sin6.sin6_addr = in6loopback; 869 sin6.sin6_port = 0; 870 ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6)); 871 if (ret < 0) { 872 close(s); 873 return (0); 874 } 875 break; 876 #endif /* INET6 */ 877 #ifdef INET 878 case AF_INET: 879 s = socket(PF_INET, SOCK_DGRAM, 0); 880 if (s < 0) 881 return (0); 882 memset(&sin, 0, sizeof(sin)); 883 sin.sin_len = sizeof(sin); 884 sin.sin_family = AF_INET; 885 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 886 sin.sin_port = 0; 887 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin)); 888 if (ret < 0) { 889 close(s); 890 return (0); 891 } 892 break; 893 #endif /* INET */ 894 } 895 memset(&fromip, 0, sizeof(fromip)); 896 slen = sizeof(fromip); 897 ret = getsockname(s, (struct sockaddr *)&fromip, &slen); 898 close(s); 899 if (ret < 0) 900 return (0); 901 return (1); 902 } 903 904 static void 905 usage(void) 906 { 907 908 errx(1, 909 "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]"); 910 } 911