1192811Srmacklem/*- 2192811Srmacklem * Copyright (c) 2009 Rick Macklem, University of Guelph 3192811Srmacklem * All rights reserved. 4192811Srmacklem * 5192811Srmacklem * Redistribution and use in source and binary forms, with or without 6192811Srmacklem * modification, are permitted provided that the following conditions 7192811Srmacklem * are met: 8192811Srmacklem * 1. Redistributions of source code must retain the above copyright 9192811Srmacklem * notice, this list of conditions and the following disclaimer. 10192811Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 11192811Srmacklem * notice, this list of conditions and the following disclaimer in the 12192811Srmacklem * documentation and/or other materials provided with the distribution. 13192811Srmacklem * 14192811Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15192811Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16192811Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17192811Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18192811Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19192811Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20192811Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21192811Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22192811Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23192811Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24192811Srmacklem * SUCH DAMAGE. 25192811Srmacklem * 26192811Srmacklem */ 27192811Srmacklem 28192811Srmacklem#include <sys/cdefs.h> 29192811Srmacklem__FBSDID("$FreeBSD: stable/10/usr.sbin/nfsuserd/nfsuserd.c 346467 2019-04-21 01:25:27Z rmacklem $"); 30192811Srmacklem 31192811Srmacklem#include <sys/param.h> 32192811Srmacklem#include <sys/errno.h> 33192811Srmacklem#include <sys/linker.h> 34192811Srmacklem#include <sys/module.h> 35192811Srmacklem#include <sys/mount.h> 36192811Srmacklem#include <sys/socket.h> 37192811Srmacklem#include <sys/socketvar.h> 38192811Srmacklem#include <sys/time.h> 39192811Srmacklem#include <sys/ucred.h> 40192811Srmacklem#include <sys/vnode.h> 41192811Srmacklem#include <sys/wait.h> 42192811Srmacklem 43346467Srmacklem#include <netinet/in.h> 44346467Srmacklem 45346467Srmacklem#include <arpa/inet.h> 46346467Srmacklem 47192811Srmacklem#include <nfs/nfssvc.h> 48192811Srmacklem 49192811Srmacklem#include <rpc/rpc.h> 50192811Srmacklem 51192811Srmacklem#include <fs/nfs/rpcv2.h> 52192811Srmacklem#include <fs/nfs/nfsproto.h> 53192811Srmacklem#include <fs/nfs/nfskpiport.h> 54192811Srmacklem#include <fs/nfs/nfs.h> 55192811Srmacklem 56192811Srmacklem#include <ctype.h> 57192811Srmacklem#include <err.h> 58192811Srmacklem#include <grp.h> 59192811Srmacklem#include <netdb.h> 60192811Srmacklem#include <pwd.h> 61192811Srmacklem#include <signal.h> 62192811Srmacklem#include <stdio.h> 63192811Srmacklem#include <stdlib.h> 64192811Srmacklem#include <string.h> 65192811Srmacklem#include <syslog.h> 66192811Srmacklem#include <unistd.h> 67192811Srmacklem 68192811Srmacklem/* 69192811Srmacklem * This program loads the password and group databases into the kernel 70192811Srmacklem * for NFS V4. 71192811Srmacklem */ 72192811Srmacklem 73193070Sdelphijstatic void cleanup_term(int); 74193070Sdelphijstatic void usage(void); 75193070Sdelphijstatic void nfsuserdsrv(struct svc_req *, SVCXPRT *); 76193070Sdelphijstatic bool_t xdr_getid(XDR *, caddr_t); 77193070Sdelphijstatic bool_t xdr_getname(XDR *, caddr_t); 78193070Sdelphijstatic bool_t xdr_retval(XDR *, caddr_t); 79346467Srmacklemstatic int nfsbind_localhost(void); 80192811Srmacklem 81192811Srmacklem#define MAXNAME 1024 82192811Srmacklem#define MAXNFSUSERD 20 83192811Srmacklem#define DEFNFSUSERD 4 84223382Srmacklem#define MAXUSERMAX 100000 85223382Srmacklem#define MINUSERMAX 10 86192811Srmacklem#define DEFUSERMAX 200 87192811Srmacklem#define DEFUSERTIMEOUT (1 * 60) 88192811Srmacklemstruct info { 89192811Srmacklem long id; 90192811Srmacklem long retval; 91192811Srmacklem char name[MAXNAME + 1]; 92192811Srmacklem}; 93192811Srmacklem 94192811Srmacklemu_char *dnsname = "default.domain"; 95192811Srmacklemu_char *defaultuser = "nobody"; 96317920Srmacklemuid_t defaultuid = 65534; 97192811Srmacklemu_char *defaultgroup = "nogroup"; 98317920Srmacklemgid_t defaultgid = 65533; 99192811Srmacklemint verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0; 100292231Srmacklemint defusertimeout = DEFUSERTIMEOUT, manage_gids = 0; 101192811Srmacklempid_t slaves[MAXNFSUSERD]; 102346467Srmacklemstatic struct sockaddr_storage fromip; 103346467Srmacklem#ifdef INET6 104346467Srmacklemstatic struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT; 105346467Srmacklem#endif 106192811Srmacklem 107192811Srmacklemint 108193070Sdelphijmain(int argc, char *argv[]) 109192811Srmacklem{ 110223382Srmacklem int i, j; 111223382Srmacklem int error, fnd_dup, len, mustfreeai = 0, start_uidpos; 112192811Srmacklem struct nfsd_idargs nid; 113192811Srmacklem struct passwd *pwd; 114192811Srmacklem struct group *grp; 115192811Srmacklem int sock, one = 1; 116193070Sdelphij SVCXPRT *udptransp; 117346467Srmacklem struct nfsuserd_args nargs; 118192811Srmacklem sigset_t signew; 119193070Sdelphij char hostname[MAXHOSTNAMELEN + 1], *cp; 120192811Srmacklem struct addrinfo *aip, hints; 121223382Srmacklem static uid_t check_dups[MAXUSERMAX]; 122292231Srmacklem gid_t grps[NGROUPS]; 123292231Srmacklem int ngroup; 124346467Srmacklem#ifdef INET 125346467Srmacklem struct sockaddr_in *sin; 126346467Srmacklem#endif 127346467Srmacklem#ifdef INET6 128346467Srmacklem struct sockaddr_in6 *sin6; 129346467Srmacklem#endif 130346467Srmacklem int s; 131192811Srmacklem 132192811Srmacklem if (modfind("nfscommon") < 0) { 133192811Srmacklem /* Not present in kernel, try loading it */ 134192811Srmacklem if (kldload("nfscommon") < 0 || 135192811Srmacklem modfind("nfscommon") < 0) 136192811Srmacklem errx(1, "Experimental nfs subsystem is not available"); 137192811Srmacklem } 138192811Srmacklem 139192811Srmacklem /* 140192811Srmacklem * First, figure out what our domain name and Kerberos Realm 141192811Srmacklem * seem to be. Command line args may override these later. 142192811Srmacklem */ 143192811Srmacklem if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { 144192811Srmacklem if ((cp = strchr(hostname, '.')) != NULL && 145192811Srmacklem *(cp + 1) != '\0') { 146192811Srmacklem dnsname = cp + 1; 147192811Srmacklem } else { 148192811Srmacklem memset((void *)&hints, 0, sizeof (hints)); 149192811Srmacklem hints.ai_flags = AI_CANONNAME; 150192811Srmacklem error = getaddrinfo(hostname, NULL, &hints, &aip); 151192811Srmacklem if (error == 0) { 152192811Srmacklem if (aip->ai_canonname != NULL && 153192811Srmacklem (cp = strchr(aip->ai_canonname, '.')) != NULL 154192811Srmacklem && *(cp + 1) != '\0') { 155192811Srmacklem dnsname = cp + 1; 156192811Srmacklem mustfreeai = 1; 157192811Srmacklem } else { 158192811Srmacklem freeaddrinfo(aip); 159192811Srmacklem } 160192811Srmacklem } 161192811Srmacklem } 162192811Srmacklem } 163346467Srmacklem 164346467Srmacklem /* 165346467Srmacklem * See if this server handles IPv4 or IPv6 and set up the default 166346467Srmacklem * localhost address. 167346467Srmacklem */ 168346467Srmacklem s = -1; 169346467Srmacklem#ifdef INET6 170346467Srmacklem s = socket(PF_INET6, SOCK_DGRAM, 0); 171346467Srmacklem if (s >= 0) { 172346467Srmacklem fromip.ss_family = AF_INET6; 173346467Srmacklem fromip.ss_len = sizeof(struct sockaddr_in6); 174346467Srmacklem sin6 = (struct sockaddr_in6 *)&fromip; 175346467Srmacklem sin6->sin6_addr = in6loopback; 176346467Srmacklem close(s); 177346467Srmacklem } 178346467Srmacklem#endif /* INET6 */ 179346467Srmacklem#ifdef INET 180346467Srmacklem if (s < 0) { 181346467Srmacklem s = socket(PF_INET, SOCK_DGRAM, 0); 182346467Srmacklem if (s >= 0) { 183346467Srmacklem fromip.ss_family = AF_INET; 184346467Srmacklem fromip.ss_len = sizeof(struct sockaddr_in); 185346467Srmacklem sin = (struct sockaddr_in *)&fromip; 186346467Srmacklem sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 187346467Srmacklem close(s); 188346467Srmacklem } 189346467Srmacklem } 190346467Srmacklem#endif /* INET */ 191346467Srmacklem if (s < 0) 192346467Srmacklem err(1, "Can't create a inet/inet6 socket"); 193346467Srmacklem 194192811Srmacklem nid.nid_usermax = DEFUSERMAX; 195192811Srmacklem nid.nid_usertimeout = defusertimeout; 196192811Srmacklem 197192811Srmacklem argc--; 198192811Srmacklem argv++; 199192811Srmacklem while (argc >= 1) { 200192811Srmacklem if (!strcmp(*argv, "-domain")) { 201192811Srmacklem if (argc == 1) 202192811Srmacklem usage(); 203192811Srmacklem argc--; 204192811Srmacklem argv++; 205192811Srmacklem strncpy(hostname, *argv, MAXHOSTNAMELEN); 206192811Srmacklem hostname[MAXHOSTNAMELEN] = '\0'; 207192811Srmacklem dnsname = hostname; 208192811Srmacklem } else if (!strcmp(*argv, "-verbose")) { 209192811Srmacklem verbose = 1; 210192811Srmacklem } else if (!strcmp(*argv, "-force")) { 211192811Srmacklem forcestart = 1; 212292231Srmacklem } else if (!strcmp(*argv, "-manage-gids")) { 213292231Srmacklem manage_gids = 1; 214192811Srmacklem } else if (!strcmp(*argv, "-usermax")) { 215192811Srmacklem if (argc == 1) 216192811Srmacklem usage(); 217192811Srmacklem argc--; 218192811Srmacklem argv++; 219192811Srmacklem i = atoi(*argv); 220223382Srmacklem if (i < MINUSERMAX || i > MAXUSERMAX) { 221192811Srmacklem fprintf(stderr, 222223382Srmacklem "usermax %d out of range %d<->%d\n", i, 223223382Srmacklem MINUSERMAX, MAXUSERMAX); 224192811Srmacklem usage(); 225192811Srmacklem } 226192811Srmacklem nid.nid_usermax = i; 227192811Srmacklem } else if (!strcmp(*argv, "-usertimeout")) { 228192811Srmacklem if (argc == 1) 229192811Srmacklem usage(); 230192811Srmacklem argc--; 231192811Srmacklem argv++; 232192811Srmacklem i = atoi(*argv); 233192811Srmacklem if (i < 0 || i > 100000) { 234192811Srmacklem fprintf(stderr, 235193070Sdelphij "usertimeout %d out of range 0<->100000\n", 236192811Srmacklem i); 237192811Srmacklem usage(); 238192811Srmacklem } 239192811Srmacklem nid.nid_usertimeout = defusertimeout = i * 60; 240192811Srmacklem } else if (nfsuserdcnt == -1) { 241192811Srmacklem nfsuserdcnt = atoi(*argv); 242192811Srmacklem if (nfsuserdcnt < 1) 243192811Srmacklem usage(); 244192811Srmacklem if (nfsuserdcnt > MAXNFSUSERD) { 245192811Srmacklem warnx("nfsuserd count %d; reset to %d", 246192811Srmacklem nfsuserdcnt, DEFNFSUSERD); 247192811Srmacklem nfsuserdcnt = DEFNFSUSERD; 248192811Srmacklem } 249192811Srmacklem } else { 250192811Srmacklem usage(); 251192811Srmacklem } 252192811Srmacklem argc--; 253192811Srmacklem argv++; 254192811Srmacklem } 255192811Srmacklem if (nfsuserdcnt < 1) 256192811Srmacklem nfsuserdcnt = DEFNFSUSERD; 257192811Srmacklem 258192811Srmacklem /* 259192811Srmacklem * Strip off leading and trailing '.'s in domain name and map 260192811Srmacklem * alphabetics to lower case. 261192811Srmacklem */ 262192811Srmacklem while (*dnsname == '.') 263192811Srmacklem dnsname++; 264192811Srmacklem if (*dnsname == '\0') 265192811Srmacklem errx(1, "Domain name all '.'"); 266192811Srmacklem len = strlen(dnsname); 267192811Srmacklem cp = dnsname + len - 1; 268192811Srmacklem while (*cp == '.') { 269192811Srmacklem *cp = '\0'; 270192811Srmacklem len--; 271192811Srmacklem cp--; 272192811Srmacklem } 273192811Srmacklem for (i = 0; i < len; i++) { 274192811Srmacklem if (!isascii(dnsname[i])) 275192811Srmacklem errx(1, "Domain name has non-ascii char"); 276192811Srmacklem if (isupper(dnsname[i])) 277192811Srmacklem dnsname[i] = tolower(dnsname[i]); 278192811Srmacklem } 279192811Srmacklem 280192811Srmacklem /* 281192811Srmacklem * If the nfsuserd died off ungracefully, this is necessary to 282192811Srmacklem * get them to start again. 283192811Srmacklem */ 284192811Srmacklem if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) 285192811Srmacklem errx(1, "Can't do nfssvc() to delete the port"); 286192811Srmacklem 287192811Srmacklem if (verbose) 288192811Srmacklem fprintf(stderr, 289192811Srmacklem "nfsuserd: domain=%s usermax=%d usertimeout=%d\n", 290192811Srmacklem dnsname, nid.nid_usermax, nid.nid_usertimeout); 291192811Srmacklem 292192811Srmacklem for (i = 0; i < nfsuserdcnt; i++) 293192811Srmacklem slaves[i] = (pid_t)-1; 294192811Srmacklem 295346467Srmacklem nargs.nuserd_family = fromip.ss_family; 296192811Srmacklem /* 297192811Srmacklem * Set up the service port to accept requests via UDP from 298346467Srmacklem * localhost (INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT). 299192811Srmacklem */ 300346467Srmacklem if ((sock = socket(nargs.nuserd_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) 301192811Srmacklem err(1, "cannot create udp socket"); 302192811Srmacklem 303192811Srmacklem /* 304192811Srmacklem * Not sure what this does, so I'll leave it here for now. 305192811Srmacklem */ 306192811Srmacklem setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 307192811Srmacklem 308192811Srmacklem if ((udptransp = svcudp_create(sock)) == NULL) 309192811Srmacklem err(1, "Can't set up socket"); 310192811Srmacklem 311192811Srmacklem /* 312192811Srmacklem * By not specifying a protocol, it is linked into the 313192811Srmacklem * dispatch queue, but not registered with portmapper, 314192811Srmacklem * which is just what I want. 315192811Srmacklem */ 316192811Srmacklem if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, 317192811Srmacklem nfsuserdsrv, 0)) 318192811Srmacklem err(1, "Can't register nfsuserd"); 319192811Srmacklem 320192811Srmacklem /* 321192811Srmacklem * Tell the kernel what my port# is. 322192811Srmacklem */ 323346467Srmacklem nargs.nuserd_port = htons(udptransp->xp_port); 324192811Srmacklem#ifdef DEBUG 325346467Srmacklem printf("portnum=0x%x\n", nargs.nuserd_port); 326192811Srmacklem#else 327346467Srmacklem if (nfssvc(NFSSVC_NFSUSERDPORT | NFSSVC_NEWSTRUCT, &nargs) < 0) { 328192811Srmacklem if (errno == EPERM) { 329192811Srmacklem fprintf(stderr, 330192811Srmacklem "Can't start nfsuserd when already running"); 331192811Srmacklem fprintf(stderr, 332192811Srmacklem " If not running, use the -force option.\n"); 333192811Srmacklem } else { 334192811Srmacklem fprintf(stderr, "Can't do nfssvc() to add port\n"); 335192811Srmacklem } 336192811Srmacklem exit(1); 337192811Srmacklem } 338192811Srmacklem#endif 339192811Srmacklem 340192811Srmacklem pwd = getpwnam(defaultuser); 341192811Srmacklem if (pwd) 342192811Srmacklem nid.nid_uid = pwd->pw_uid; 343192811Srmacklem else 344192811Srmacklem nid.nid_uid = defaultuid; 345192811Srmacklem grp = getgrnam(defaultgroup); 346192811Srmacklem if (grp) 347192811Srmacklem nid.nid_gid = grp->gr_gid; 348192811Srmacklem else 349192811Srmacklem nid.nid_gid = defaultgid; 350192811Srmacklem nid.nid_name = dnsname; 351192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 352292231Srmacklem nid.nid_ngroup = 0; 353292231Srmacklem nid.nid_grps = NULL; 354192811Srmacklem nid.nid_flag = NFSID_INITIALIZE; 355192811Srmacklem#ifdef DEBUG 356192811Srmacklem printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, 357192811Srmacklem nid.nid_name); 358192811Srmacklem#else 359292231Srmacklem error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 360192811Srmacklem if (error) 361192811Srmacklem errx(1, "Can't initialize nfs user/groups"); 362192811Srmacklem#endif 363192811Srmacklem 364192811Srmacklem i = 0; 365192811Srmacklem /* 366192811Srmacklem * Loop around adding all groups. 367192811Srmacklem */ 368192811Srmacklem setgrent(); 369192811Srmacklem while (i < nid.nid_usermax && (grp = getgrent())) { 370192811Srmacklem nid.nid_gid = grp->gr_gid; 371192811Srmacklem nid.nid_name = grp->gr_name; 372192811Srmacklem nid.nid_namelen = strlen(grp->gr_name); 373292231Srmacklem nid.nid_ngroup = 0; 374292231Srmacklem nid.nid_grps = NULL; 375192811Srmacklem nid.nid_flag = NFSID_ADDGID; 376192811Srmacklem#ifdef DEBUG 377192811Srmacklem printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name); 378192811Srmacklem#else 379292231Srmacklem error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 380192811Srmacklem if (error) 381192811Srmacklem errx(1, "Can't add group %s", grp->gr_name); 382192811Srmacklem#endif 383192811Srmacklem i++; 384192811Srmacklem } 385192811Srmacklem 386192811Srmacklem /* 387192811Srmacklem * Loop around adding all users. 388192811Srmacklem */ 389223382Srmacklem start_uidpos = i; 390192811Srmacklem setpwent(); 391192811Srmacklem while (i < nid.nid_usermax && (pwd = getpwent())) { 392223382Srmacklem fnd_dup = 0; 393223382Srmacklem /* 394223382Srmacklem * Yes, this is inefficient, but it is only done once when 395223382Srmacklem * the daemon is started and will run in a fraction of a second 396223382Srmacklem * for nid_usermax at 10000. If nid_usermax is cranked up to 397223382Srmacklem * 100000, it will take several seconds, depending on the CPU. 398223382Srmacklem */ 399223382Srmacklem for (j = 0; j < (i - start_uidpos); j++) 400223382Srmacklem if (check_dups[j] == pwd->pw_uid) { 401223382Srmacklem /* Found another entry for uid, so skip it */ 402223382Srmacklem fnd_dup = 1; 403223382Srmacklem break; 404223382Srmacklem } 405223382Srmacklem if (fnd_dup != 0) 406223382Srmacklem continue; 407223382Srmacklem check_dups[i - start_uidpos] = pwd->pw_uid; 408192811Srmacklem nid.nid_uid = pwd->pw_uid; 409192811Srmacklem nid.nid_name = pwd->pw_name; 410192811Srmacklem nid.nid_namelen = strlen(pwd->pw_name); 411292231Srmacklem if (manage_gids != 0) { 412292231Srmacklem /* Get the group list for this user. */ 413292231Srmacklem ngroup = NGROUPS; 414292231Srmacklem if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps, 415292231Srmacklem &ngroup) < 0) 416292231Srmacklem syslog(LOG_ERR, "Group list too small"); 417292231Srmacklem nid.nid_ngroup = ngroup; 418292231Srmacklem nid.nid_grps = grps; 419292231Srmacklem } else { 420292231Srmacklem nid.nid_ngroup = 0; 421292231Srmacklem nid.nid_grps = NULL; 422292231Srmacklem } 423192811Srmacklem nid.nid_flag = NFSID_ADDUID; 424192811Srmacklem#ifdef DEBUG 425192811Srmacklem printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name); 426192811Srmacklem#else 427292231Srmacklem error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 428192811Srmacklem if (error) 429192811Srmacklem errx(1, "Can't add user %s", pwd->pw_name); 430192811Srmacklem#endif 431192811Srmacklem i++; 432192811Srmacklem } 433192811Srmacklem 434192811Srmacklem /* 435192811Srmacklem * I should feel guilty for not calling this for all the above exit() 436192811Srmacklem * upon error cases, but I don't. 437192811Srmacklem */ 438192811Srmacklem if (mustfreeai) 439192811Srmacklem freeaddrinfo(aip); 440192811Srmacklem 441192811Srmacklem#ifdef DEBUG 442192811Srmacklem exit(0); 443192811Srmacklem#endif 444192811Srmacklem /* 445192811Srmacklem * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't 446192811Srmacklem * end up bogus. 447192811Srmacklem */ 448192811Srmacklem sigemptyset(&signew); 449192811Srmacklem sigaddset(&signew, SIGUSR1); 450192811Srmacklem sigaddset(&signew, SIGCHLD); 451192811Srmacklem sigprocmask(SIG_BLOCK, &signew, NULL); 452192811Srmacklem 453192811Srmacklem daemon(0, 0); 454192811Srmacklem (void)signal(SIGHUP, SIG_IGN); 455192811Srmacklem (void)signal(SIGINT, SIG_IGN); 456192811Srmacklem (void)signal(SIGQUIT, SIG_IGN); 457192811Srmacklem (void)signal(SIGTERM, SIG_IGN); 458192811Srmacklem (void)signal(SIGUSR1, cleanup_term); 459192811Srmacklem (void)signal(SIGCHLD, cleanup_term); 460192811Srmacklem 461192811Srmacklem openlog("nfsuserd:", LOG_PID, LOG_DAEMON); 462192811Srmacklem 463192811Srmacklem /* 464192811Srmacklem * Fork off the slave daemons that do the work. All the master 465192811Srmacklem * does is kill them off and cleanup. 466192811Srmacklem */ 467192811Srmacklem for (i = 0; i < nfsuserdcnt; i++) { 468192811Srmacklem slaves[i] = fork(); 469192811Srmacklem if (slaves[i] == 0) { 470192811Srmacklem im_a_slave = 1; 471192811Srmacklem setproctitle("slave"); 472192811Srmacklem sigemptyset(&signew); 473192811Srmacklem sigaddset(&signew, SIGUSR1); 474192811Srmacklem sigprocmask(SIG_UNBLOCK, &signew, NULL); 475192811Srmacklem 476192811Srmacklem /* 477192811Srmacklem * and away we go. 478192811Srmacklem */ 479192811Srmacklem svc_run(); 480192811Srmacklem syslog(LOG_ERR, "nfsuserd died: %m"); 481192811Srmacklem exit(1); 482192811Srmacklem } else if (slaves[i] < 0) { 483192811Srmacklem syslog(LOG_ERR, "fork: %m"); 484192811Srmacklem } 485192811Srmacklem } 486192811Srmacklem 487192811Srmacklem /* 488192811Srmacklem * Just wait for SIGUSR1 or a child to die and then... 489192811Srmacklem * As the Governor of California would say, "Terminate them". 490192811Srmacklem */ 491192811Srmacklem setproctitle("master"); 492192811Srmacklem sigemptyset(&signew); 493192811Srmacklem while (1) 494192811Srmacklem sigsuspend(&signew); 495192811Srmacklem} 496192811Srmacklem 497192811Srmacklem/* 498192811Srmacklem * The nfsuserd rpc service 499192811Srmacklem */ 500193070Sdelphijstatic void 501192811Srmacklemnfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp) 502192811Srmacklem{ 503192811Srmacklem struct passwd *pwd; 504192811Srmacklem struct group *grp; 505192811Srmacklem int error; 506346467Srmacklem#if defined(INET) || defined(INET6) 507192811Srmacklem u_short sport; 508346467Srmacklem int ret; 509346467Srmacklem#endif 510192811Srmacklem struct info info; 511192811Srmacklem struct nfsd_idargs nid; 512292231Srmacklem gid_t grps[NGROUPS]; 513292231Srmacklem int ngroup; 514346467Srmacklem#ifdef INET 515346467Srmacklem struct sockaddr_in *fromsin, *sin; 516346467Srmacklem#endif 517346467Srmacklem#ifdef INET6 518346467Srmacklem struct sockaddr_in6 *fromsin6, *sin6; 519346467Srmacklem char buf[INET6_ADDRSTRLEN]; 520346467Srmacklem#endif 521192811Srmacklem 522192811Srmacklem /* 523346467Srmacklem * Only handle requests from localhost on a reserved port number. 524346467Srmacklem * If the upcall is from a different address, call nfsbind_localhost() 525346467Srmacklem * to check for a remapping of localhost, due to jails. 526192811Srmacklem * (Since a reserved port # at localhost implies a client with 527192811Srmacklem * local root, there won't be a security breach. This is about 528192811Srmacklem * the only case I can think of where a reserved port # means 529192811Srmacklem * something.) 530192811Srmacklem */ 531346467Srmacklem if (rqstp->rq_proc != NULLPROC) { 532346467Srmacklem switch (fromip.ss_family) { 533346467Srmacklem#ifdef INET 534346467Srmacklem case AF_INET: 535346467Srmacklem if (transp->xp_rtaddr.len < sizeof(*sin)) { 536346467Srmacklem syslog(LOG_ERR, "xp_rtaddr too small"); 537346467Srmacklem svcerr_weakauth(transp); 538346467Srmacklem return; 539346467Srmacklem } 540346467Srmacklem sin = (struct sockaddr_in *)transp->xp_rtaddr.buf; 541346467Srmacklem fromsin = (struct sockaddr_in *)&fromip; 542346467Srmacklem sport = ntohs(sin->sin_port); 543346467Srmacklem if (sport >= IPPORT_RESERVED) { 544346467Srmacklem syslog(LOG_ERR, "not a reserved port#"); 545346467Srmacklem svcerr_weakauth(transp); 546346467Srmacklem return; 547346467Srmacklem } 548346467Srmacklem ret = 1; 549346467Srmacklem if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr) 550346467Srmacklem ret = nfsbind_localhost(); 551346467Srmacklem if (ret == 0 || sin->sin_addr.s_addr != 552346467Srmacklem fromsin->sin_addr.s_addr) { 553346467Srmacklem syslog(LOG_ERR, "bad from ip %s", 554346467Srmacklem inet_ntoa(sin->sin_addr)); 555346467Srmacklem svcerr_weakauth(transp); 556346467Srmacklem return; 557346467Srmacklem } 558346467Srmacklem break; 559346467Srmacklem#endif /* INET */ 560346467Srmacklem#ifdef INET6 561346467Srmacklem case AF_INET6: 562346467Srmacklem if (transp->xp_rtaddr.len < sizeof(*sin6)) { 563346467Srmacklem syslog(LOG_ERR, "xp_rtaddr too small"); 564346467Srmacklem svcerr_weakauth(transp); 565346467Srmacklem return; 566346467Srmacklem } 567346467Srmacklem sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf; 568346467Srmacklem fromsin6 = (struct sockaddr_in6 *)&fromip; 569346467Srmacklem sport = ntohs(sin6->sin6_port); 570346467Srmacklem if (sport >= IPV6PORT_RESERVED) { 571346467Srmacklem syslog(LOG_ERR, "not a reserved port#"); 572346467Srmacklem svcerr_weakauth(transp); 573346467Srmacklem return; 574346467Srmacklem } 575346467Srmacklem ret = 1; 576346467Srmacklem if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 577346467Srmacklem &fromsin6->sin6_addr)) 578346467Srmacklem ret = nfsbind_localhost(); 579346467Srmacklem if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 580346467Srmacklem &fromsin6->sin6_addr)) { 581346467Srmacklem if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 582346467Srmacklem INET6_ADDRSTRLEN) != NULL) 583346467Srmacklem syslog(LOG_ERR, "bad from ip %s", buf); 584346467Srmacklem else 585346467Srmacklem syslog(LOG_ERR, "bad from ip6 addr"); 586346467Srmacklem svcerr_weakauth(transp); 587346467Srmacklem return; 588346467Srmacklem } 589346467Srmacklem break; 590346467Srmacklem#endif /* INET6 */ 591346467Srmacklem } 592192811Srmacklem } 593192811Srmacklem switch (rqstp->rq_proc) { 594192811Srmacklem case NULLPROC: 595192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 596192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 597192811Srmacklem return; 598192811Srmacklem case RPCNFSUSERD_GETUID: 599192811Srmacklem if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 600192811Srmacklem (caddr_t)&info)) { 601192811Srmacklem svcerr_decode(transp); 602192811Srmacklem return; 603192811Srmacklem } 604192811Srmacklem pwd = getpwuid((uid_t)info.id); 605192811Srmacklem info.retval = 0; 606192811Srmacklem if (pwd != NULL) { 607192811Srmacklem nid.nid_usertimeout = defusertimeout; 608192811Srmacklem nid.nid_uid = pwd->pw_uid; 609192811Srmacklem nid.nid_name = pwd->pw_name; 610292231Srmacklem if (manage_gids != 0) { 611292231Srmacklem /* Get the group list for this user. */ 612292231Srmacklem ngroup = NGROUPS; 613292231Srmacklem if (getgrouplist(pwd->pw_name, pwd->pw_gid, 614292231Srmacklem grps, &ngroup) < 0) 615292231Srmacklem syslog(LOG_ERR, "Group list too small"); 616292231Srmacklem nid.nid_ngroup = ngroup; 617292231Srmacklem nid.nid_grps = grps; 618292231Srmacklem } else { 619292231Srmacklem nid.nid_ngroup = 0; 620292231Srmacklem nid.nid_grps = NULL; 621292231Srmacklem } 622192811Srmacklem } else { 623192811Srmacklem nid.nid_usertimeout = 5; 624192811Srmacklem nid.nid_uid = (uid_t)info.id; 625192811Srmacklem nid.nid_name = defaultuser; 626292231Srmacklem nid.nid_ngroup = 0; 627292231Srmacklem nid.nid_grps = NULL; 628192811Srmacklem } 629192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 630192811Srmacklem nid.nid_flag = NFSID_ADDUID; 631292231Srmacklem error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 632192811Srmacklem if (error) { 633192811Srmacklem info.retval = error; 634192811Srmacklem syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 635192811Srmacklem } else if (verbose) { 636192811Srmacklem syslog(LOG_ERR,"Added uid=%d name=%s\n", 637192811Srmacklem nid.nid_uid, nid.nid_name); 638192811Srmacklem } 639192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 640192811Srmacklem (caddr_t)&info)) 641192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 642192811Srmacklem return; 643192811Srmacklem case RPCNFSUSERD_GETGID: 644192811Srmacklem if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 645192811Srmacklem (caddr_t)&info)) { 646192811Srmacklem svcerr_decode(transp); 647192811Srmacklem return; 648192811Srmacklem } 649192811Srmacklem grp = getgrgid((gid_t)info.id); 650192811Srmacklem info.retval = 0; 651192811Srmacklem if (grp != NULL) { 652192811Srmacklem nid.nid_usertimeout = defusertimeout; 653192811Srmacklem nid.nid_gid = grp->gr_gid; 654192811Srmacklem nid.nid_name = grp->gr_name; 655192811Srmacklem } else { 656192811Srmacklem nid.nid_usertimeout = 5; 657192811Srmacklem nid.nid_gid = (gid_t)info.id; 658192811Srmacklem nid.nid_name = defaultgroup; 659192811Srmacklem } 660192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 661292231Srmacklem nid.nid_ngroup = 0; 662292231Srmacklem nid.nid_grps = NULL; 663192811Srmacklem nid.nid_flag = NFSID_ADDGID; 664292231Srmacklem error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 665192811Srmacklem if (error) { 666192811Srmacklem info.retval = error; 667192811Srmacklem syslog(LOG_ERR, "Can't add group %s\n", 668192811Srmacklem grp->gr_name); 669192811Srmacklem } else if (verbose) { 670192811Srmacklem syslog(LOG_ERR,"Added gid=%d name=%s\n", 671192811Srmacklem nid.nid_gid, nid.nid_name); 672192811Srmacklem } 673192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 674192811Srmacklem (caddr_t)&info)) 675192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 676192811Srmacklem return; 677192811Srmacklem case RPCNFSUSERD_GETUSER: 678192811Srmacklem if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 679192811Srmacklem (caddr_t)&info)) { 680192811Srmacklem svcerr_decode(transp); 681192811Srmacklem return; 682192811Srmacklem } 683192811Srmacklem pwd = getpwnam(info.name); 684192811Srmacklem info.retval = 0; 685192811Srmacklem if (pwd != NULL) { 686192811Srmacklem nid.nid_usertimeout = defusertimeout; 687192811Srmacklem nid.nid_uid = pwd->pw_uid; 688192811Srmacklem nid.nid_name = pwd->pw_name; 689192811Srmacklem } else { 690192811Srmacklem nid.nid_usertimeout = 5; 691192811Srmacklem nid.nid_uid = defaultuid; 692192811Srmacklem nid.nid_name = info.name; 693192811Srmacklem } 694192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 695292231Srmacklem nid.nid_ngroup = 0; 696292231Srmacklem nid.nid_grps = NULL; 697192811Srmacklem nid.nid_flag = NFSID_ADDUSERNAME; 698292231Srmacklem error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 699192811Srmacklem if (error) { 700192811Srmacklem info.retval = error; 701192811Srmacklem syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 702192811Srmacklem } else if (verbose) { 703192811Srmacklem syslog(LOG_ERR,"Added uid=%d name=%s\n", 704192811Srmacklem nid.nid_uid, nid.nid_name); 705192811Srmacklem } 706192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 707192811Srmacklem (caddr_t)&info)) 708192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 709192811Srmacklem return; 710192811Srmacklem case RPCNFSUSERD_GETGROUP: 711192811Srmacklem if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 712192811Srmacklem (caddr_t)&info)) { 713192811Srmacklem svcerr_decode(transp); 714192811Srmacklem return; 715192811Srmacklem } 716192811Srmacklem grp = getgrnam(info.name); 717192811Srmacklem info.retval = 0; 718192811Srmacklem if (grp != NULL) { 719192811Srmacklem nid.nid_usertimeout = defusertimeout; 720192811Srmacklem nid.nid_gid = grp->gr_gid; 721192811Srmacklem nid.nid_name = grp->gr_name; 722192811Srmacklem } else { 723192811Srmacklem nid.nid_usertimeout = 5; 724192811Srmacklem nid.nid_gid = defaultgid; 725192811Srmacklem nid.nid_name = info.name; 726192811Srmacklem } 727192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 728292231Srmacklem nid.nid_ngroup = 0; 729292231Srmacklem nid.nid_grps = NULL; 730192811Srmacklem nid.nid_flag = NFSID_ADDGROUPNAME; 731292231Srmacklem error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid); 732192811Srmacklem if (error) { 733192811Srmacklem info.retval = error; 734192811Srmacklem syslog(LOG_ERR, "Can't add group %s\n", 735192811Srmacklem grp->gr_name); 736192811Srmacklem } else if (verbose) { 737192811Srmacklem syslog(LOG_ERR,"Added gid=%d name=%s\n", 738192811Srmacklem nid.nid_gid, nid.nid_name); 739192811Srmacklem } 740192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 741192811Srmacklem (caddr_t)&info)) 742192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 743192811Srmacklem return; 744192811Srmacklem default: 745192811Srmacklem svcerr_noproc(transp); 746192811Srmacklem return; 747192811Srmacklem }; 748192811Srmacklem} 749192811Srmacklem 750192811Srmacklem/* 751192811Srmacklem * Xdr routine to get an id number 752192811Srmacklem */ 753193070Sdelphijstatic bool_t 754192811Srmacklemxdr_getid(XDR *xdrsp, caddr_t cp) 755192811Srmacklem{ 756192811Srmacklem struct info *ifp = (struct info *)cp; 757192811Srmacklem 758192811Srmacklem return (xdr_long(xdrsp, &ifp->id)); 759192811Srmacklem} 760192811Srmacklem 761192811Srmacklem/* 762192811Srmacklem * Xdr routine to get a user name 763192811Srmacklem */ 764193070Sdelphijstatic bool_t 765192811Srmacklemxdr_getname(XDR *xdrsp, caddr_t cp) 766192811Srmacklem{ 767192811Srmacklem struct info *ifp = (struct info *)cp; 768192811Srmacklem long len; 769192811Srmacklem 770192811Srmacklem if (!xdr_long(xdrsp, &len)) 771192811Srmacklem return (0); 772192811Srmacklem if (len > MAXNAME) 773192811Srmacklem return (0); 774192811Srmacklem if (!xdr_opaque(xdrsp, ifp->name, len)) 775192811Srmacklem return (0); 776192811Srmacklem ifp->name[len] = '\0'; 777192811Srmacklem return (1); 778192811Srmacklem} 779192811Srmacklem 780192811Srmacklem/* 781192811Srmacklem * Xdr routine to return the value. 782192811Srmacklem */ 783193070Sdelphijstatic bool_t 784192811Srmacklemxdr_retval(XDR *xdrsp, caddr_t cp) 785192811Srmacklem{ 786192811Srmacklem struct info *ifp = (struct info *)cp; 787192811Srmacklem long val; 788192811Srmacklem 789192811Srmacklem val = ifp->retval; 790192811Srmacklem return (xdr_long(xdrsp, &val)); 791192811Srmacklem} 792192811Srmacklem 793192811Srmacklem/* 794192811Srmacklem * cleanup_term() called via SIGUSR1. 795192811Srmacklem */ 796193070Sdelphijstatic void 797193070Sdelphijcleanup_term(int signo __unused) 798192811Srmacklem{ 799192811Srmacklem int i, cnt; 800192811Srmacklem 801192811Srmacklem if (im_a_slave) 802192811Srmacklem exit(0); 803192811Srmacklem 804192811Srmacklem /* 805192811Srmacklem * Ok, so I'm the master. 806192811Srmacklem * As the Governor of California might say, "Terminate them". 807192811Srmacklem */ 808192811Srmacklem cnt = 0; 809192811Srmacklem for (i = 0; i < nfsuserdcnt; i++) { 810192811Srmacklem if (slaves[i] != (pid_t)-1) { 811192811Srmacklem cnt++; 812192811Srmacklem kill(slaves[i], SIGUSR1); 813192811Srmacklem } 814192811Srmacklem } 815192811Srmacklem 816192811Srmacklem /* 817192811Srmacklem * and wait for them to die 818192811Srmacklem */ 819192811Srmacklem for (i = 0; i < cnt; i++) 820192811Srmacklem wait3(NULL, 0, NULL); 821192811Srmacklem 822192811Srmacklem /* 823192811Srmacklem * Finally, get rid of the socket 824192811Srmacklem */ 825192811Srmacklem if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) { 826192811Srmacklem syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n"); 827192811Srmacklem exit(1); 828192811Srmacklem } 829192811Srmacklem exit(0); 830192811Srmacklem} 831192811Srmacklem 832346467Srmacklem/* 833346467Srmacklem * Get the IP address that the localhost address maps to. 834346467Srmacklem * This is needed when jails map localhost to another IP address. 835346467Srmacklem */ 836346467Srmacklemstatic int 837346467Srmacklemnfsbind_localhost(void) 838346467Srmacklem{ 839346467Srmacklem#ifdef INET 840346467Srmacklem struct sockaddr_in sin; 841346467Srmacklem#endif 842346467Srmacklem#ifdef INET6 843346467Srmacklem struct sockaddr_in6 sin6; 844346467Srmacklem#endif 845346467Srmacklem socklen_t slen; 846346467Srmacklem int ret, s; 847346467Srmacklem 848346467Srmacklem switch (fromip.ss_family) { 849346467Srmacklem#ifdef INET6 850346467Srmacklem case AF_INET6: 851346467Srmacklem s = socket(PF_INET6, SOCK_DGRAM, 0); 852346467Srmacklem if (s < 0) 853346467Srmacklem return (0); 854346467Srmacklem memset(&sin6, 0, sizeof(sin6)); 855346467Srmacklem sin6.sin6_len = sizeof(sin6); 856346467Srmacklem sin6.sin6_family = AF_INET6; 857346467Srmacklem sin6.sin6_addr = in6loopback; 858346467Srmacklem sin6.sin6_port = 0; 859346467Srmacklem ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6)); 860346467Srmacklem if (ret < 0) { 861346467Srmacklem close(s); 862346467Srmacklem return (0); 863346467Srmacklem } 864346467Srmacklem break; 865346467Srmacklem#endif /* INET6 */ 866346467Srmacklem#ifdef INET 867346467Srmacklem case AF_INET: 868346467Srmacklem s = socket(PF_INET, SOCK_DGRAM, 0); 869346467Srmacklem if (s < 0) 870346467Srmacklem return (0); 871346467Srmacklem memset(&sin, 0, sizeof(sin)); 872346467Srmacklem sin.sin_len = sizeof(sin); 873346467Srmacklem sin.sin_family = AF_INET; 874346467Srmacklem sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 875346467Srmacklem sin.sin_port = 0; 876346467Srmacklem ret = bind(s, (struct sockaddr *)&sin, sizeof(sin)); 877346467Srmacklem if (ret < 0) { 878346467Srmacklem close(s); 879346467Srmacklem return (0); 880346467Srmacklem } 881346467Srmacklem break; 882346467Srmacklem#endif /* INET */ 883346467Srmacklem } 884346467Srmacklem memset(&fromip, 0, sizeof(fromip)); 885346467Srmacklem slen = sizeof(fromip); 886346467Srmacklem ret = getsockname(s, (struct sockaddr *)&fromip, &slen); 887346467Srmacklem close(s); 888346467Srmacklem if (ret < 0) 889346467Srmacklem return (0); 890346467Srmacklem return (1); 891346467Srmacklem} 892346467Srmacklem 893193070Sdelphijstatic void 894192811Srmacklemusage(void) 895192811Srmacklem{ 896192811Srmacklem 897192811Srmacklem errx(1, 898292231Srmacklem "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]"); 899192811Srmacklem} 900