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