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