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: stable/10/usr.sbin/nfsuserd/nfsuserd.c 346467 2019-04-21 01:25:27Z rmacklem $"); 30 31#include <sys/param.h> 32#include <sys/errno.h> 33#include <sys/linker.h> 34#include <sys/module.h> 35#include <sys/mount.h> 36#include <sys/socket.h> 37#include <sys/socketvar.h> 38#include <sys/time.h> 39#include <sys/ucred.h> 40#include <sys/vnode.h> 41#include <sys/wait.h> 42 43#include <netinet/in.h> 44 45#include <arpa/inet.h> 46 47#include <nfs/nfssvc.h> 48 49#include <rpc/rpc.h> 50 51#include <fs/nfs/rpcv2.h> 52#include <fs/nfs/nfsproto.h> 53#include <fs/nfs/nfskpiport.h> 54#include <fs/nfs/nfs.h> 55 56#include <ctype.h> 57#include <err.h> 58#include <grp.h> 59#include <netdb.h> 60#include <pwd.h> 61#include <signal.h> 62#include <stdio.h> 63#include <stdlib.h> 64#include <string.h> 65#include <syslog.h> 66#include <unistd.h> 67 68/* 69 * This program loads the password and group databases into the kernel 70 * for NFS V4. 71 */ 72 73static void cleanup_term(int); 74static void usage(void); 75static void nfsuserdsrv(struct svc_req *, SVCXPRT *); 76static bool_t xdr_getid(XDR *, caddr_t); 77static bool_t xdr_getname(XDR *, caddr_t); 78static bool_t xdr_retval(XDR *, caddr_t); 79static int nfsbind_localhost(void); 80 81#define MAXNAME 1024 82#define MAXNFSUSERD 20 83#define DEFNFSUSERD 4 84#define MAXUSERMAX 100000 85#define MINUSERMAX 10 86#define DEFUSERMAX 200 87#define DEFUSERTIMEOUT (1 * 60) 88struct info { 89 long id; 90 long retval; 91 char name[MAXNAME + 1]; 92}; 93 94u_char *dnsname = "default.domain"; 95u_char *defaultuser = "nobody"; 96uid_t defaultuid = 65534; 97u_char *defaultgroup = "nogroup"; 98gid_t defaultgid = 65533; 99int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0; 100int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0; 101pid_t slaves[MAXNFSUSERD]; 102static struct sockaddr_storage fromip; 103#ifdef INET6 104static struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT; 105#endif 106 107int 108main(int argc, char *argv[]) 109{ 110 int i, j; 111 int error, fnd_dup, len, mustfreeai = 0, start_uidpos; 112 struct nfsd_idargs nid; 113 struct passwd *pwd; 114 struct group *grp; 115 int sock, one = 1; 116 SVCXPRT *udptransp; 117 struct nfsuserd_args nargs; 118 sigset_t signew; 119 char hostname[MAXHOSTNAMELEN + 1], *cp; 120 struct addrinfo *aip, hints; 121 static uid_t check_dups[MAXUSERMAX]; 122 gid_t grps[NGROUPS]; 123 int ngroup; 124#ifdef INET 125 struct sockaddr_in *sin; 126#endif 127#ifdef INET6 128 struct sockaddr_in6 *sin6; 129#endif 130 int s; 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 slaves[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 fprintf(stderr, 330 "Can't start nfsuserd when already running"); 331 fprintf(stderr, 332 " If not running, use the -force option.\n"); 333 } else { 334 fprintf(stderr, "Can't do nfssvc() to add port\n"); 335 } 336 exit(1); 337 } 338#endif 339 340 pwd = getpwnam(defaultuser); 341 if (pwd) 342 nid.nid_uid = pwd->pw_uid; 343 else 344 nid.nid_uid = defaultuid; 345 grp = getgrnam(defaultgroup); 346 if (grp) 347 nid.nid_gid = grp->gr_gid; 348 else 349 nid.nid_gid = defaultgid; 350 nid.nid_name = dnsname; 351 nid.nid_namelen = strlen(nid.nid_name); 352 nid.nid_ngroup = 0; 353 nid.nid_grps = NULL; 354 nid.nid_flag = NFSID_INITIALIZE; 355#ifdef DEBUG 356 printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, 357 nid.nid_name); 358#else 359 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 360 if (error) 361 errx(1, "Can't initialize nfs user/groups"); 362#endif 363 364 i = 0; 365 /* 366 * Loop around adding all groups. 367 */ 368 setgrent(); 369 while (i < nid.nid_usermax && (grp = getgrent())) { 370 nid.nid_gid = grp->gr_gid; 371 nid.nid_name = grp->gr_name; 372 nid.nid_namelen = strlen(grp->gr_name); 373 nid.nid_ngroup = 0; 374 nid.nid_grps = NULL; 375 nid.nid_flag = NFSID_ADDGID; 376#ifdef DEBUG 377 printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name); 378#else 379 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 380 if (error) 381 errx(1, "Can't add group %s", grp->gr_name); 382#endif 383 i++; 384 } 385 386 /* 387 * Loop around adding all users. 388 */ 389 start_uidpos = i; 390 setpwent(); 391 while (i < nid.nid_usermax && (pwd = getpwent())) { 392 fnd_dup = 0; 393 /* 394 * Yes, this is inefficient, but it is only done once when 395 * the daemon is started and will run in a fraction of a second 396 * for nid_usermax at 10000. If nid_usermax is cranked up to 397 * 100000, it will take several seconds, depending on the CPU. 398 */ 399 for (j = 0; j < (i - start_uidpos); j++) 400 if (check_dups[j] == pwd->pw_uid) { 401 /* Found another entry for uid, so skip it */ 402 fnd_dup = 1; 403 break; 404 } 405 if (fnd_dup != 0) 406 continue; 407 check_dups[i - start_uidpos] = pwd->pw_uid; 408 nid.nid_uid = pwd->pw_uid; 409 nid.nid_name = pwd->pw_name; 410 nid.nid_namelen = strlen(pwd->pw_name); 411 if (manage_gids != 0) { 412 /* Get the group list for this user. */ 413 ngroup = NGROUPS; 414 if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps, 415 &ngroup) < 0) 416 syslog(LOG_ERR, "Group list too small"); 417 nid.nid_ngroup = ngroup; 418 nid.nid_grps = grps; 419 } else { 420 nid.nid_ngroup = 0; 421 nid.nid_grps = NULL; 422 } 423 nid.nid_flag = NFSID_ADDUID; 424#ifdef DEBUG 425 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name); 426#else 427 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 428 if (error) 429 errx(1, "Can't add user %s", pwd->pw_name); 430#endif 431 i++; 432 } 433 434 /* 435 * I should feel guilty for not calling this for all the above exit() 436 * upon error cases, but I don't. 437 */ 438 if (mustfreeai) 439 freeaddrinfo(aip); 440 441#ifdef DEBUG 442 exit(0); 443#endif 444 /* 445 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't 446 * end up bogus. 447 */ 448 sigemptyset(&signew); 449 sigaddset(&signew, SIGUSR1); 450 sigaddset(&signew, SIGCHLD); 451 sigprocmask(SIG_BLOCK, &signew, NULL); 452 453 daemon(0, 0); 454 (void)signal(SIGHUP, SIG_IGN); 455 (void)signal(SIGINT, SIG_IGN); 456 (void)signal(SIGQUIT, SIG_IGN); 457 (void)signal(SIGTERM, SIG_IGN); 458 (void)signal(SIGUSR1, cleanup_term); 459 (void)signal(SIGCHLD, cleanup_term); 460 461 openlog("nfsuserd:", LOG_PID, LOG_DAEMON); 462 463 /* 464 * Fork off the slave daemons that do the work. All the master 465 * does is kill them off and cleanup. 466 */ 467 for (i = 0; i < nfsuserdcnt; i++) { 468 slaves[i] = fork(); 469 if (slaves[i] == 0) { 470 im_a_slave = 1; 471 setproctitle("slave"); 472 sigemptyset(&signew); 473 sigaddset(&signew, SIGUSR1); 474 sigprocmask(SIG_UNBLOCK, &signew, NULL); 475 476 /* 477 * and away we go. 478 */ 479 svc_run(); 480 syslog(LOG_ERR, "nfsuserd died: %m"); 481 exit(1); 482 } else if (slaves[i] < 0) { 483 syslog(LOG_ERR, "fork: %m"); 484 } 485 } 486 487 /* 488 * Just wait for SIGUSR1 or a child to die and then... 489 * As the Governor of California would say, "Terminate them". 490 */ 491 setproctitle("master"); 492 sigemptyset(&signew); 493 while (1) 494 sigsuspend(&signew); 495} 496 497/* 498 * The nfsuserd rpc service 499 */ 500static void 501nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp) 502{ 503 struct passwd *pwd; 504 struct group *grp; 505 int error; 506#if defined(INET) || defined(INET6) 507 u_short sport; 508 int ret; 509#endif 510 struct info info; 511 struct nfsd_idargs nid; 512 gid_t grps[NGROUPS]; 513 int ngroup; 514#ifdef INET 515 struct sockaddr_in *fromsin, *sin; 516#endif 517#ifdef INET6 518 struct sockaddr_in6 *fromsin6, *sin6; 519 char buf[INET6_ADDRSTRLEN]; 520#endif 521 522 /* 523 * Only handle requests from localhost on a reserved port number. 524 * If the upcall is from a different address, call nfsbind_localhost() 525 * to check for a remapping of localhost, due to jails. 526 * (Since a reserved port # at localhost implies a client with 527 * local root, there won't be a security breach. This is about 528 * the only case I can think of where a reserved port # means 529 * something.) 530 */ 531 if (rqstp->rq_proc != NULLPROC) { 532 switch (fromip.ss_family) { 533#ifdef INET 534 case AF_INET: 535 if (transp->xp_rtaddr.len < sizeof(*sin)) { 536 syslog(LOG_ERR, "xp_rtaddr too small"); 537 svcerr_weakauth(transp); 538 return; 539 } 540 sin = (struct sockaddr_in *)transp->xp_rtaddr.buf; 541 fromsin = (struct sockaddr_in *)&fromip; 542 sport = ntohs(sin->sin_port); 543 if (sport >= IPPORT_RESERVED) { 544 syslog(LOG_ERR, "not a reserved port#"); 545 svcerr_weakauth(transp); 546 return; 547 } 548 ret = 1; 549 if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr) 550 ret = nfsbind_localhost(); 551 if (ret == 0 || sin->sin_addr.s_addr != 552 fromsin->sin_addr.s_addr) { 553 syslog(LOG_ERR, "bad from ip %s", 554 inet_ntoa(sin->sin_addr)); 555 svcerr_weakauth(transp); 556 return; 557 } 558 break; 559#endif /* INET */ 560#ifdef INET6 561 case AF_INET6: 562 if (transp->xp_rtaddr.len < sizeof(*sin6)) { 563 syslog(LOG_ERR, "xp_rtaddr too small"); 564 svcerr_weakauth(transp); 565 return; 566 } 567 sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf; 568 fromsin6 = (struct sockaddr_in6 *)&fromip; 569 sport = ntohs(sin6->sin6_port); 570 if (sport >= IPV6PORT_RESERVED) { 571 syslog(LOG_ERR, "not a reserved port#"); 572 svcerr_weakauth(transp); 573 return; 574 } 575 ret = 1; 576 if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 577 &fromsin6->sin6_addr)) 578 ret = nfsbind_localhost(); 579 if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 580 &fromsin6->sin6_addr)) { 581 if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 582 INET6_ADDRSTRLEN) != NULL) 583 syslog(LOG_ERR, "bad from ip %s", buf); 584 else 585 syslog(LOG_ERR, "bad from ip6 addr"); 586 svcerr_weakauth(transp); 587 return; 588 } 589 break; 590#endif /* INET6 */ 591 } 592 } 593 switch (rqstp->rq_proc) { 594 case NULLPROC: 595 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 596 syslog(LOG_ERR, "Can't send reply"); 597 return; 598 case RPCNFSUSERD_GETUID: 599 if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 600 (caddr_t)&info)) { 601 svcerr_decode(transp); 602 return; 603 } 604 pwd = getpwuid((uid_t)info.id); 605 info.retval = 0; 606 if (pwd != NULL) { 607 nid.nid_usertimeout = defusertimeout; 608 nid.nid_uid = pwd->pw_uid; 609 nid.nid_name = pwd->pw_name; 610 if (manage_gids != 0) { 611 /* Get the group list for this user. */ 612 ngroup = NGROUPS; 613 if (getgrouplist(pwd->pw_name, pwd->pw_gid, 614 grps, &ngroup) < 0) 615 syslog(LOG_ERR, "Group list too small"); 616 nid.nid_ngroup = ngroup; 617 nid.nid_grps = grps; 618 } else { 619 nid.nid_ngroup = 0; 620 nid.nid_grps = NULL; 621 } 622 } else { 623 nid.nid_usertimeout = 5; 624 nid.nid_uid = (uid_t)info.id; 625 nid.nid_name = defaultuser; 626 nid.nid_ngroup = 0; 627 nid.nid_grps = NULL; 628 } 629 nid.nid_namelen = strlen(nid.nid_name); 630 nid.nid_flag = NFSID_ADDUID; 631 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 632 if (error) { 633 info.retval = error; 634 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 635 } else if (verbose) { 636 syslog(LOG_ERR,"Added uid=%d name=%s\n", 637 nid.nid_uid, nid.nid_name); 638 } 639 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 640 (caddr_t)&info)) 641 syslog(LOG_ERR, "Can't send reply"); 642 return; 643 case RPCNFSUSERD_GETGID: 644 if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 645 (caddr_t)&info)) { 646 svcerr_decode(transp); 647 return; 648 } 649 grp = getgrgid((gid_t)info.id); 650 info.retval = 0; 651 if (grp != NULL) { 652 nid.nid_usertimeout = defusertimeout; 653 nid.nid_gid = grp->gr_gid; 654 nid.nid_name = grp->gr_name; 655 } else { 656 nid.nid_usertimeout = 5; 657 nid.nid_gid = (gid_t)info.id; 658 nid.nid_name = defaultgroup; 659 } 660 nid.nid_namelen = strlen(nid.nid_name); 661 nid.nid_ngroup = 0; 662 nid.nid_grps = NULL; 663 nid.nid_flag = NFSID_ADDGID; 664 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 665 if (error) { 666 info.retval = error; 667 syslog(LOG_ERR, "Can't add group %s\n", 668 grp->gr_name); 669 } else if (verbose) { 670 syslog(LOG_ERR,"Added gid=%d name=%s\n", 671 nid.nid_gid, nid.nid_name); 672 } 673 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 674 (caddr_t)&info)) 675 syslog(LOG_ERR, "Can't send reply"); 676 return; 677 case RPCNFSUSERD_GETUSER: 678 if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 679 (caddr_t)&info)) { 680 svcerr_decode(transp); 681 return; 682 } 683 pwd = getpwnam(info.name); 684 info.retval = 0; 685 if (pwd != NULL) { 686 nid.nid_usertimeout = defusertimeout; 687 nid.nid_uid = pwd->pw_uid; 688 nid.nid_name = pwd->pw_name; 689 } else { 690 nid.nid_usertimeout = 5; 691 nid.nid_uid = defaultuid; 692 nid.nid_name = info.name; 693 } 694 nid.nid_namelen = strlen(nid.nid_name); 695 nid.nid_ngroup = 0; 696 nid.nid_grps = NULL; 697 nid.nid_flag = NFSID_ADDUSERNAME; 698 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 699 if (error) { 700 info.retval = error; 701 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 702 } else if (verbose) { 703 syslog(LOG_ERR,"Added uid=%d name=%s\n", 704 nid.nid_uid, nid.nid_name); 705 } 706 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 707 (caddr_t)&info)) 708 syslog(LOG_ERR, "Can't send reply"); 709 return; 710 case RPCNFSUSERD_GETGROUP: 711 if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 712 (caddr_t)&info)) { 713 svcerr_decode(transp); 714 return; 715 } 716 grp = getgrnam(info.name); 717 info.retval = 0; 718 if (grp != NULL) { 719 nid.nid_usertimeout = defusertimeout; 720 nid.nid_gid = grp->gr_gid; 721 nid.nid_name = grp->gr_name; 722 } else { 723 nid.nid_usertimeout = 5; 724 nid.nid_gid = defaultgid; 725 nid.nid_name = info.name; 726 } 727 nid.nid_namelen = strlen(nid.nid_name); 728 nid.nid_ngroup = 0; 729 nid.nid_grps = NULL; 730 nid.nid_flag = NFSID_ADDGROUPNAME; 731 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 732 if (error) { 733 info.retval = error; 734 syslog(LOG_ERR, "Can't add group %s\n", 735 grp->gr_name); 736 } else if (verbose) { 737 syslog(LOG_ERR,"Added gid=%d name=%s\n", 738 nid.nid_gid, nid.nid_name); 739 } 740 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 741 (caddr_t)&info)) 742 syslog(LOG_ERR, "Can't send reply"); 743 return; 744 default: 745 svcerr_noproc(transp); 746 return; 747 }; 748} 749 750/* 751 * Xdr routine to get an id number 752 */ 753static bool_t 754xdr_getid(XDR *xdrsp, caddr_t cp) 755{ 756 struct info *ifp = (struct info *)cp; 757 758 return (xdr_long(xdrsp, &ifp->id)); 759} 760 761/* 762 * Xdr routine to get a user name 763 */ 764static bool_t 765xdr_getname(XDR *xdrsp, caddr_t cp) 766{ 767 struct info *ifp = (struct info *)cp; 768 long len; 769 770 if (!xdr_long(xdrsp, &len)) 771 return (0); 772 if (len > MAXNAME) 773 return (0); 774 if (!xdr_opaque(xdrsp, ifp->name, len)) 775 return (0); 776 ifp->name[len] = '\0'; 777 return (1); 778} 779 780/* 781 * Xdr routine to return the value. 782 */ 783static bool_t 784xdr_retval(XDR *xdrsp, caddr_t cp) 785{ 786 struct info *ifp = (struct info *)cp; 787 long val; 788 789 val = ifp->retval; 790 return (xdr_long(xdrsp, &val)); 791} 792 793/* 794 * cleanup_term() called via SIGUSR1. 795 */ 796static void 797cleanup_term(int signo __unused) 798{ 799 int i, cnt; 800 801 if (im_a_slave) 802 exit(0); 803 804 /* 805 * Ok, so I'm the master. 806 * As the Governor of California might say, "Terminate them". 807 */ 808 cnt = 0; 809 for (i = 0; i < nfsuserdcnt; i++) { 810 if (slaves[i] != (pid_t)-1) { 811 cnt++; 812 kill(slaves[i], SIGUSR1); 813 } 814 } 815 816 /* 817 * and wait for them to die 818 */ 819 for (i = 0; i < cnt; i++) 820 wait3(NULL, 0, NULL); 821 822 /* 823 * Finally, get rid of the socket 824 */ 825 if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) { 826 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n"); 827 exit(1); 828 } 829 exit(0); 830} 831 832/* 833 * Get the IP address that the localhost address maps to. 834 * This is needed when jails map localhost to another IP address. 835 */ 836static int 837nfsbind_localhost(void) 838{ 839#ifdef INET 840 struct sockaddr_in sin; 841#endif 842#ifdef INET6 843 struct sockaddr_in6 sin6; 844#endif 845 socklen_t slen; 846 int ret, s; 847 848 switch (fromip.ss_family) { 849#ifdef INET6 850 case AF_INET6: 851 s = socket(PF_INET6, SOCK_DGRAM, 0); 852 if (s < 0) 853 return (0); 854 memset(&sin6, 0, sizeof(sin6)); 855 sin6.sin6_len = sizeof(sin6); 856 sin6.sin6_family = AF_INET6; 857 sin6.sin6_addr = in6loopback; 858 sin6.sin6_port = 0; 859 ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6)); 860 if (ret < 0) { 861 close(s); 862 return (0); 863 } 864 break; 865#endif /* INET6 */ 866#ifdef INET 867 case AF_INET: 868 s = socket(PF_INET, SOCK_DGRAM, 0); 869 if (s < 0) 870 return (0); 871 memset(&sin, 0, sizeof(sin)); 872 sin.sin_len = sizeof(sin); 873 sin.sin_family = AF_INET; 874 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 875 sin.sin_port = 0; 876 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin)); 877 if (ret < 0) { 878 close(s); 879 return (0); 880 } 881 break; 882#endif /* INET */ 883 } 884 memset(&fromip, 0, sizeof(fromip)); 885 slen = sizeof(fromip); 886 ret = getsockname(s, (struct sockaddr *)&fromip, &slen); 887 close(s); 888 if (ret < 0) 889 return (0); 890 return (1); 891} 892 893static void 894usage(void) 895{ 896 897 errx(1, 898 "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]"); 899} 900