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