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/time.h> 39 #include <sys/ucred.h> 40 #include <sys/vnode.h> 41 #include <sys/wait.h> 42 43 #include <nfs/nfssvc.h> 44 45 #include <rpc/rpc.h> 46 47 #include <fs/nfs/rpcv2.h> 48 #include <fs/nfs/nfsproto.h> 49 #include <fs/nfs/nfskpiport.h> 50 #include <fs/nfs/nfs.h> 51 52 #include <ctype.h> 53 #include <err.h> 54 #include <grp.h> 55 #include <netdb.h> 56 #include <pwd.h> 57 #include <signal.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <syslog.h> 62 #include <unistd.h> 63 64 /* 65 * This program loads the password and group databases into the kernel 66 * for NFS V4. 67 */ 68 69 static void cleanup_term(int); 70 static void usage(void); 71 static void nfsuserdsrv(struct svc_req *, SVCXPRT *); 72 static bool_t xdr_getid(XDR *, caddr_t); 73 static bool_t xdr_getname(XDR *, caddr_t); 74 static bool_t xdr_retval(XDR *, caddr_t); 75 76 #define MAXNAME 1024 77 #define MAXNFSUSERD 20 78 #define DEFNFSUSERD 4 79 #define MAXUSERMAX 100000 80 #define MINUSERMAX 10 81 #define DEFUSERMAX 200 82 #define DEFUSERTIMEOUT (1 * 60) 83 struct info { 84 long id; 85 long retval; 86 char name[MAXNAME + 1]; 87 }; 88 89 u_char *dnsname = "default.domain"; 90 u_char *defaultuser = "nobody"; 91 uid_t defaultuid = (uid_t)32767; 92 u_char *defaultgroup = "nogroup"; 93 gid_t defaultgid = (gid_t)32767; 94 int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0; 95 int defusertimeout = DEFUSERTIMEOUT; 96 pid_t slaves[MAXNFSUSERD]; 97 98 int 99 main(int argc, char *argv[]) 100 { 101 int i, j; 102 int error, fnd_dup, len, mustfreeai = 0, start_uidpos; 103 struct nfsd_idargs nid; 104 struct passwd *pwd; 105 struct group *grp; 106 int sock, one = 1; 107 SVCXPRT *udptransp; 108 u_short portnum; 109 sigset_t signew; 110 char hostname[MAXHOSTNAMELEN + 1], *cp; 111 struct addrinfo *aip, hints; 112 static uid_t check_dups[MAXUSERMAX]; 113 114 if (modfind("nfscommon") < 0) { 115 /* Not present in kernel, try loading it */ 116 if (kldload("nfscommon") < 0 || 117 modfind("nfscommon") < 0) 118 errx(1, "Experimental nfs subsystem is not available"); 119 } 120 121 /* 122 * First, figure out what our domain name and Kerberos Realm 123 * seem to be. Command line args may override these later. 124 */ 125 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { 126 if ((cp = strchr(hostname, '.')) != NULL && 127 *(cp + 1) != '\0') { 128 dnsname = cp + 1; 129 } else { 130 memset((void *)&hints, 0, sizeof (hints)); 131 hints.ai_flags = AI_CANONNAME; 132 error = getaddrinfo(hostname, NULL, &hints, &aip); 133 if (error == 0) { 134 if (aip->ai_canonname != NULL && 135 (cp = strchr(aip->ai_canonname, '.')) != NULL 136 && *(cp + 1) != '\0') { 137 dnsname = cp + 1; 138 mustfreeai = 1; 139 } else { 140 freeaddrinfo(aip); 141 } 142 } 143 } 144 } 145 nid.nid_usermax = DEFUSERMAX; 146 nid.nid_usertimeout = defusertimeout; 147 148 argc--; 149 argv++; 150 while (argc >= 1) { 151 if (!strcmp(*argv, "-domain")) { 152 if (argc == 1) 153 usage(); 154 argc--; 155 argv++; 156 strncpy(hostname, *argv, MAXHOSTNAMELEN); 157 hostname[MAXHOSTNAMELEN] = '\0'; 158 dnsname = hostname; 159 } else if (!strcmp(*argv, "-verbose")) { 160 verbose = 1; 161 } else if (!strcmp(*argv, "-force")) { 162 forcestart = 1; 163 } else if (!strcmp(*argv, "-usermax")) { 164 if (argc == 1) 165 usage(); 166 argc--; 167 argv++; 168 i = atoi(*argv); 169 if (i < MINUSERMAX || i > MAXUSERMAX) { 170 fprintf(stderr, 171 "usermax %d out of range %d<->%d\n", i, 172 MINUSERMAX, MAXUSERMAX); 173 usage(); 174 } 175 nid.nid_usermax = i; 176 } else if (!strcmp(*argv, "-usertimeout")) { 177 if (argc == 1) 178 usage(); 179 argc--; 180 argv++; 181 i = atoi(*argv); 182 if (i < 0 || i > 100000) { 183 fprintf(stderr, 184 "usertimeout %d out of range 0<->100000\n", 185 i); 186 usage(); 187 } 188 nid.nid_usertimeout = defusertimeout = i * 60; 189 } else if (nfsuserdcnt == -1) { 190 nfsuserdcnt = atoi(*argv); 191 if (nfsuserdcnt < 1) 192 usage(); 193 if (nfsuserdcnt > MAXNFSUSERD) { 194 warnx("nfsuserd count %d; reset to %d", 195 nfsuserdcnt, DEFNFSUSERD); 196 nfsuserdcnt = DEFNFSUSERD; 197 } 198 } else { 199 usage(); 200 } 201 argc--; 202 argv++; 203 } 204 if (nfsuserdcnt < 1) 205 nfsuserdcnt = DEFNFSUSERD; 206 207 /* 208 * Strip off leading and trailing '.'s in domain name and map 209 * alphabetics to lower case. 210 */ 211 while (*dnsname == '.') 212 dnsname++; 213 if (*dnsname == '\0') 214 errx(1, "Domain name all '.'"); 215 len = strlen(dnsname); 216 cp = dnsname + len - 1; 217 while (*cp == '.') { 218 *cp = '\0'; 219 len--; 220 cp--; 221 } 222 for (i = 0; i < len; i++) { 223 if (!isascii(dnsname[i])) 224 errx(1, "Domain name has non-ascii char"); 225 if (isupper(dnsname[i])) 226 dnsname[i] = tolower(dnsname[i]); 227 } 228 229 /* 230 * If the nfsuserd died off ungracefully, this is necessary to 231 * get them to start again. 232 */ 233 if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) 234 errx(1, "Can't do nfssvc() to delete the port"); 235 236 if (verbose) 237 fprintf(stderr, 238 "nfsuserd: domain=%s usermax=%d usertimeout=%d\n", 239 dnsname, nid.nid_usermax, nid.nid_usertimeout); 240 241 for (i = 0; i < nfsuserdcnt; i++) 242 slaves[i] = (pid_t)-1; 243 244 /* 245 * Set up the service port to accept requests via UDP from 246 * localhost (127.0.0.1). 247 */ 248 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 249 err(1, "cannot create udp socket"); 250 251 /* 252 * Not sure what this does, so I'll leave it here for now. 253 */ 254 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 255 256 if ((udptransp = svcudp_create(sock)) == NULL) 257 err(1, "Can't set up socket"); 258 259 /* 260 * By not specifying a protocol, it is linked into the 261 * dispatch queue, but not registered with portmapper, 262 * which is just what I want. 263 */ 264 if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, 265 nfsuserdsrv, 0)) 266 err(1, "Can't register nfsuserd"); 267 268 /* 269 * Tell the kernel what my port# is. 270 */ 271 portnum = htons(udptransp->xp_port); 272 #ifdef DEBUG 273 printf("portnum=0x%x\n", portnum); 274 #else 275 if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) { 276 if (errno == EPERM) { 277 fprintf(stderr, 278 "Can't start nfsuserd when already running"); 279 fprintf(stderr, 280 " If not running, use the -force option.\n"); 281 } else { 282 fprintf(stderr, "Can't do nfssvc() to add port\n"); 283 } 284 exit(1); 285 } 286 #endif 287 288 pwd = getpwnam(defaultuser); 289 if (pwd) 290 nid.nid_uid = pwd->pw_uid; 291 else 292 nid.nid_uid = defaultuid; 293 grp = getgrnam(defaultgroup); 294 if (grp) 295 nid.nid_gid = grp->gr_gid; 296 else 297 nid.nid_gid = defaultgid; 298 nid.nid_name = dnsname; 299 nid.nid_namelen = strlen(nid.nid_name); 300 nid.nid_flag = NFSID_INITIALIZE; 301 #ifdef DEBUG 302 printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, 303 nid.nid_name); 304 #else 305 error = nfssvc(NFSSVC_IDNAME, &nid); 306 if (error) 307 errx(1, "Can't initialize nfs user/groups"); 308 #endif 309 310 i = 0; 311 /* 312 * Loop around adding all groups. 313 */ 314 setgrent(); 315 while (i < nid.nid_usermax && (grp = getgrent())) { 316 nid.nid_gid = grp->gr_gid; 317 nid.nid_name = grp->gr_name; 318 nid.nid_namelen = strlen(grp->gr_name); 319 nid.nid_flag = NFSID_ADDGID; 320 #ifdef DEBUG 321 printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name); 322 #else 323 error = nfssvc(NFSSVC_IDNAME, &nid); 324 if (error) 325 errx(1, "Can't add group %s", grp->gr_name); 326 #endif 327 i++; 328 } 329 330 /* 331 * Loop around adding all users. 332 */ 333 start_uidpos = i; 334 setpwent(); 335 while (i < nid.nid_usermax && (pwd = getpwent())) { 336 fnd_dup = 0; 337 /* 338 * Yes, this is inefficient, but it is only done once when 339 * the daemon is started and will run in a fraction of a second 340 * for nid_usermax at 10000. If nid_usermax is cranked up to 341 * 100000, it will take several seconds, depending on the CPU. 342 */ 343 for (j = 0; j < (i - start_uidpos); j++) 344 if (check_dups[j] == pwd->pw_uid) { 345 /* Found another entry for uid, so skip it */ 346 fnd_dup = 1; 347 break; 348 } 349 if (fnd_dup != 0) 350 continue; 351 check_dups[i - start_uidpos] = pwd->pw_uid; 352 nid.nid_uid = pwd->pw_uid; 353 nid.nid_name = pwd->pw_name; 354 nid.nid_namelen = strlen(pwd->pw_name); 355 nid.nid_flag = NFSID_ADDUID; 356 #ifdef DEBUG 357 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name); 358 #else 359 error = nfssvc(NFSSVC_IDNAME, &nid); 360 if (error) 361 errx(1, "Can't add user %s", pwd->pw_name); 362 #endif 363 i++; 364 } 365 366 /* 367 * I should feel guilty for not calling this for all the above exit() 368 * upon error cases, but I don't. 369 */ 370 if (mustfreeai) 371 freeaddrinfo(aip); 372 373 #ifdef DEBUG 374 exit(0); 375 #endif 376 /* 377 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't 378 * end up bogus. 379 */ 380 sigemptyset(&signew); 381 sigaddset(&signew, SIGUSR1); 382 sigaddset(&signew, SIGCHLD); 383 sigprocmask(SIG_BLOCK, &signew, NULL); 384 385 daemon(0, 0); 386 (void)signal(SIGHUP, SIG_IGN); 387 (void)signal(SIGINT, SIG_IGN); 388 (void)signal(SIGQUIT, SIG_IGN); 389 (void)signal(SIGTERM, SIG_IGN); 390 (void)signal(SIGUSR1, cleanup_term); 391 (void)signal(SIGCHLD, cleanup_term); 392 393 openlog("nfsuserd:", LOG_PID, LOG_DAEMON); 394 395 /* 396 * Fork off the slave daemons that do the work. All the master 397 * does is kill them off and cleanup. 398 */ 399 for (i = 0; i < nfsuserdcnt; i++) { 400 slaves[i] = fork(); 401 if (slaves[i] == 0) { 402 im_a_slave = 1; 403 setproctitle("slave"); 404 sigemptyset(&signew); 405 sigaddset(&signew, SIGUSR1); 406 sigprocmask(SIG_UNBLOCK, &signew, NULL); 407 408 /* 409 * and away we go. 410 */ 411 svc_run(); 412 syslog(LOG_ERR, "nfsuserd died: %m"); 413 exit(1); 414 } else if (slaves[i] < 0) { 415 syslog(LOG_ERR, "fork: %m"); 416 } 417 } 418 419 /* 420 * Just wait for SIGUSR1 or a child to die and then... 421 * As the Governor of California would say, "Terminate them". 422 */ 423 setproctitle("master"); 424 sigemptyset(&signew); 425 while (1) 426 sigsuspend(&signew); 427 } 428 429 /* 430 * The nfsuserd rpc service 431 */ 432 static void 433 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp) 434 { 435 struct passwd *pwd; 436 struct group *grp; 437 int error; 438 u_short sport; 439 struct info info; 440 struct nfsd_idargs nid; 441 u_int32_t saddr; 442 443 /* 444 * Only handle requests from 127.0.0.1 on a reserved port number. 445 * (Since a reserved port # at localhost implies a client with 446 * local root, there won't be a security breach. This is about 447 * the only case I can think of where a reserved port # means 448 * something.) 449 */ 450 sport = ntohs(transp->xp_raddr.sin_port); 451 saddr = ntohl(transp->xp_raddr.sin_addr.s_addr); 452 if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) || 453 saddr != 0x7f000001) { 454 syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport); 455 svcerr_weakauth(transp); 456 return; 457 } 458 switch (rqstp->rq_proc) { 459 case NULLPROC: 460 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 461 syslog(LOG_ERR, "Can't send reply"); 462 return; 463 case RPCNFSUSERD_GETUID: 464 if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 465 (caddr_t)&info)) { 466 svcerr_decode(transp); 467 return; 468 } 469 pwd = getpwuid((uid_t)info.id); 470 info.retval = 0; 471 if (pwd != NULL) { 472 nid.nid_usertimeout = defusertimeout; 473 nid.nid_uid = pwd->pw_uid; 474 nid.nid_name = pwd->pw_name; 475 } else { 476 nid.nid_usertimeout = 5; 477 nid.nid_uid = (uid_t)info.id; 478 nid.nid_name = defaultuser; 479 } 480 nid.nid_namelen = strlen(nid.nid_name); 481 nid.nid_flag = NFSID_ADDUID; 482 error = nfssvc(NFSSVC_IDNAME, &nid); 483 if (error) { 484 info.retval = error; 485 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 486 } else if (verbose) { 487 syslog(LOG_ERR,"Added uid=%d name=%s\n", 488 nid.nid_uid, nid.nid_name); 489 } 490 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 491 (caddr_t)&info)) 492 syslog(LOG_ERR, "Can't send reply"); 493 return; 494 case RPCNFSUSERD_GETGID: 495 if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 496 (caddr_t)&info)) { 497 svcerr_decode(transp); 498 return; 499 } 500 grp = getgrgid((gid_t)info.id); 501 info.retval = 0; 502 if (grp != NULL) { 503 nid.nid_usertimeout = defusertimeout; 504 nid.nid_gid = grp->gr_gid; 505 nid.nid_name = grp->gr_name; 506 } else { 507 nid.nid_usertimeout = 5; 508 nid.nid_gid = (gid_t)info.id; 509 nid.nid_name = defaultgroup; 510 } 511 nid.nid_namelen = strlen(nid.nid_name); 512 nid.nid_flag = NFSID_ADDGID; 513 error = nfssvc(NFSSVC_IDNAME, &nid); 514 if (error) { 515 info.retval = error; 516 syslog(LOG_ERR, "Can't add group %s\n", 517 grp->gr_name); 518 } else if (verbose) { 519 syslog(LOG_ERR,"Added gid=%d name=%s\n", 520 nid.nid_gid, nid.nid_name); 521 } 522 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 523 (caddr_t)&info)) 524 syslog(LOG_ERR, "Can't send reply"); 525 return; 526 case RPCNFSUSERD_GETUSER: 527 if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 528 (caddr_t)&info)) { 529 svcerr_decode(transp); 530 return; 531 } 532 pwd = getpwnam(info.name); 533 info.retval = 0; 534 if (pwd != NULL) { 535 nid.nid_usertimeout = defusertimeout; 536 nid.nid_uid = pwd->pw_uid; 537 nid.nid_name = pwd->pw_name; 538 } else { 539 nid.nid_usertimeout = 5; 540 nid.nid_uid = defaultuid; 541 nid.nid_name = info.name; 542 } 543 nid.nid_namelen = strlen(nid.nid_name); 544 nid.nid_flag = NFSID_ADDUSERNAME; 545 error = nfssvc(NFSSVC_IDNAME, &nid); 546 if (error) { 547 info.retval = error; 548 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 549 } else if (verbose) { 550 syslog(LOG_ERR,"Added uid=%d name=%s\n", 551 nid.nid_uid, nid.nid_name); 552 } 553 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 554 (caddr_t)&info)) 555 syslog(LOG_ERR, "Can't send reply"); 556 return; 557 case RPCNFSUSERD_GETGROUP: 558 if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 559 (caddr_t)&info)) { 560 svcerr_decode(transp); 561 return; 562 } 563 grp = getgrnam(info.name); 564 info.retval = 0; 565 if (grp != NULL) { 566 nid.nid_usertimeout = defusertimeout; 567 nid.nid_gid = grp->gr_gid; 568 nid.nid_name = grp->gr_name; 569 } else { 570 nid.nid_usertimeout = 5; 571 nid.nid_gid = defaultgid; 572 nid.nid_name = info.name; 573 } 574 nid.nid_namelen = strlen(nid.nid_name); 575 nid.nid_flag = NFSID_ADDGROUPNAME; 576 error = nfssvc(NFSSVC_IDNAME, &nid); 577 if (error) { 578 info.retval = error; 579 syslog(LOG_ERR, "Can't add group %s\n", 580 grp->gr_name); 581 } else if (verbose) { 582 syslog(LOG_ERR,"Added gid=%d name=%s\n", 583 nid.nid_gid, nid.nid_name); 584 } 585 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 586 (caddr_t)&info)) 587 syslog(LOG_ERR, "Can't send reply"); 588 return; 589 default: 590 svcerr_noproc(transp); 591 return; 592 }; 593 } 594 595 /* 596 * Xdr routine to get an id number 597 */ 598 static bool_t 599 xdr_getid(XDR *xdrsp, caddr_t cp) 600 { 601 struct info *ifp = (struct info *)cp; 602 603 return (xdr_long(xdrsp, &ifp->id)); 604 } 605 606 /* 607 * Xdr routine to get a user name 608 */ 609 static bool_t 610 xdr_getname(XDR *xdrsp, caddr_t cp) 611 { 612 struct info *ifp = (struct info *)cp; 613 long len; 614 615 if (!xdr_long(xdrsp, &len)) 616 return (0); 617 if (len > MAXNAME) 618 return (0); 619 if (!xdr_opaque(xdrsp, ifp->name, len)) 620 return (0); 621 ifp->name[len] = '\0'; 622 return (1); 623 } 624 625 /* 626 * Xdr routine to return the value. 627 */ 628 static bool_t 629 xdr_retval(XDR *xdrsp, caddr_t cp) 630 { 631 struct info *ifp = (struct info *)cp; 632 long val; 633 634 val = ifp->retval; 635 return (xdr_long(xdrsp, &val)); 636 } 637 638 /* 639 * cleanup_term() called via SIGUSR1. 640 */ 641 static void 642 cleanup_term(int signo __unused) 643 { 644 int i, cnt; 645 646 if (im_a_slave) 647 exit(0); 648 649 /* 650 * Ok, so I'm the master. 651 * As the Governor of California might say, "Terminate them". 652 */ 653 cnt = 0; 654 for (i = 0; i < nfsuserdcnt; i++) { 655 if (slaves[i] != (pid_t)-1) { 656 cnt++; 657 kill(slaves[i], SIGUSR1); 658 } 659 } 660 661 /* 662 * and wait for them to die 663 */ 664 for (i = 0; i < cnt; i++) 665 wait3(NULL, 0, NULL); 666 667 /* 668 * Finally, get rid of the socket 669 */ 670 if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) { 671 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n"); 672 exit(1); 673 } 674 exit(0); 675 } 676 677 static void 678 usage(void) 679 { 680 681 errx(1, 682 "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-domain domain_name] [n]"); 683 } 684