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$"); 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 43192811Srmacklem#include <nfs/nfssvc.h> 44192811Srmacklem 45192811Srmacklem#include <rpc/rpc.h> 46192811Srmacklem 47192811Srmacklem#include <fs/nfs/rpcv2.h> 48192811Srmacklem#include <fs/nfs/nfsproto.h> 49192811Srmacklem#include <fs/nfs/nfskpiport.h> 50192811Srmacklem#include <fs/nfs/nfs.h> 51192811Srmacklem 52192811Srmacklem#include <ctype.h> 53192811Srmacklem#include <err.h> 54192811Srmacklem#include <grp.h> 55192811Srmacklem#include <netdb.h> 56192811Srmacklem#include <pwd.h> 57192811Srmacklem#include <signal.h> 58192811Srmacklem#include <stdio.h> 59192811Srmacklem#include <stdlib.h> 60192811Srmacklem#include <string.h> 61192811Srmacklem#include <syslog.h> 62192811Srmacklem#include <unistd.h> 63192811Srmacklem 64192811Srmacklem/* 65192811Srmacklem * This program loads the password and group databases into the kernel 66192811Srmacklem * for NFS V4. 67192811Srmacklem */ 68192811Srmacklem 69193070Sdelphijstatic void cleanup_term(int); 70193070Sdelphijstatic void usage(void); 71193070Sdelphijstatic void nfsuserdsrv(struct svc_req *, SVCXPRT *); 72193070Sdelphijstatic bool_t xdr_getid(XDR *, caddr_t); 73193070Sdelphijstatic bool_t xdr_getname(XDR *, caddr_t); 74193070Sdelphijstatic bool_t xdr_retval(XDR *, caddr_t); 75192811Srmacklem 76192811Srmacklem#define MAXNAME 1024 77192811Srmacklem#define MAXNFSUSERD 20 78192811Srmacklem#define DEFNFSUSERD 4 79223382Srmacklem#define MAXUSERMAX 100000 80223382Srmacklem#define MINUSERMAX 10 81192811Srmacklem#define DEFUSERMAX 200 82192811Srmacklem#define DEFUSERTIMEOUT (1 * 60) 83192811Srmacklemstruct info { 84192811Srmacklem long id; 85192811Srmacklem long retval; 86192811Srmacklem char name[MAXNAME + 1]; 87192811Srmacklem}; 88192811Srmacklem 89192811Srmacklemu_char *dnsname = "default.domain"; 90192811Srmacklemu_char *defaultuser = "nobody"; 91192811Srmacklemuid_t defaultuid = (uid_t)32767; 92192811Srmacklemu_char *defaultgroup = "nogroup"; 93192811Srmacklemgid_t defaultgid = (gid_t)32767; 94192811Srmacklemint verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0; 95192811Srmacklemint defusertimeout = DEFUSERTIMEOUT; 96192811Srmacklempid_t slaves[MAXNFSUSERD]; 97192811Srmacklem 98192811Srmacklemint 99193070Sdelphijmain(int argc, char *argv[]) 100192811Srmacklem{ 101223382Srmacklem int i, j; 102223382Srmacklem int error, fnd_dup, len, mustfreeai = 0, start_uidpos; 103192811Srmacklem struct nfsd_idargs nid; 104192811Srmacklem struct passwd *pwd; 105192811Srmacklem struct group *grp; 106192811Srmacklem int sock, one = 1; 107193070Sdelphij SVCXPRT *udptransp; 108192811Srmacklem u_short portnum; 109192811Srmacklem sigset_t signew; 110193070Sdelphij char hostname[MAXHOSTNAMELEN + 1], *cp; 111192811Srmacklem struct addrinfo *aip, hints; 112223382Srmacklem static uid_t check_dups[MAXUSERMAX]; 113192811Srmacklem 114192811Srmacklem if (modfind("nfscommon") < 0) { 115192811Srmacklem /* Not present in kernel, try loading it */ 116192811Srmacklem if (kldload("nfscommon") < 0 || 117192811Srmacklem modfind("nfscommon") < 0) 118192811Srmacklem errx(1, "Experimental nfs subsystem is not available"); 119192811Srmacklem } 120192811Srmacklem 121192811Srmacklem /* 122192811Srmacklem * First, figure out what our domain name and Kerberos Realm 123192811Srmacklem * seem to be. Command line args may override these later. 124192811Srmacklem */ 125192811Srmacklem if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { 126192811Srmacklem if ((cp = strchr(hostname, '.')) != NULL && 127192811Srmacklem *(cp + 1) != '\0') { 128192811Srmacklem dnsname = cp + 1; 129192811Srmacklem } else { 130192811Srmacklem memset((void *)&hints, 0, sizeof (hints)); 131192811Srmacklem hints.ai_flags = AI_CANONNAME; 132192811Srmacklem error = getaddrinfo(hostname, NULL, &hints, &aip); 133192811Srmacklem if (error == 0) { 134192811Srmacklem if (aip->ai_canonname != NULL && 135192811Srmacklem (cp = strchr(aip->ai_canonname, '.')) != NULL 136192811Srmacklem && *(cp + 1) != '\0') { 137192811Srmacklem dnsname = cp + 1; 138192811Srmacklem mustfreeai = 1; 139192811Srmacklem } else { 140192811Srmacklem freeaddrinfo(aip); 141192811Srmacklem } 142192811Srmacklem } 143192811Srmacklem } 144192811Srmacklem } 145192811Srmacklem nid.nid_usermax = DEFUSERMAX; 146192811Srmacklem nid.nid_usertimeout = defusertimeout; 147192811Srmacklem 148192811Srmacklem argc--; 149192811Srmacklem argv++; 150192811Srmacklem while (argc >= 1) { 151192811Srmacklem if (!strcmp(*argv, "-domain")) { 152192811Srmacklem if (argc == 1) 153192811Srmacklem usage(); 154192811Srmacklem argc--; 155192811Srmacklem argv++; 156192811Srmacklem strncpy(hostname, *argv, MAXHOSTNAMELEN); 157192811Srmacklem hostname[MAXHOSTNAMELEN] = '\0'; 158192811Srmacklem dnsname = hostname; 159192811Srmacklem } else if (!strcmp(*argv, "-verbose")) { 160192811Srmacklem verbose = 1; 161192811Srmacklem } else if (!strcmp(*argv, "-force")) { 162192811Srmacklem forcestart = 1; 163192811Srmacklem } else if (!strcmp(*argv, "-usermax")) { 164192811Srmacklem if (argc == 1) 165192811Srmacklem usage(); 166192811Srmacklem argc--; 167192811Srmacklem argv++; 168192811Srmacklem i = atoi(*argv); 169223382Srmacklem if (i < MINUSERMAX || i > MAXUSERMAX) { 170192811Srmacklem fprintf(stderr, 171223382Srmacklem "usermax %d out of range %d<->%d\n", i, 172223382Srmacklem MINUSERMAX, MAXUSERMAX); 173192811Srmacklem usage(); 174192811Srmacklem } 175192811Srmacklem nid.nid_usermax = i; 176192811Srmacklem } else if (!strcmp(*argv, "-usertimeout")) { 177192811Srmacklem if (argc == 1) 178192811Srmacklem usage(); 179192811Srmacklem argc--; 180192811Srmacklem argv++; 181192811Srmacklem i = atoi(*argv); 182192811Srmacklem if (i < 0 || i > 100000) { 183192811Srmacklem fprintf(stderr, 184193070Sdelphij "usertimeout %d out of range 0<->100000\n", 185192811Srmacklem i); 186192811Srmacklem usage(); 187192811Srmacklem } 188192811Srmacklem nid.nid_usertimeout = defusertimeout = i * 60; 189192811Srmacklem } else if (nfsuserdcnt == -1) { 190192811Srmacklem nfsuserdcnt = atoi(*argv); 191192811Srmacklem if (nfsuserdcnt < 1) 192192811Srmacklem usage(); 193192811Srmacklem if (nfsuserdcnt > MAXNFSUSERD) { 194192811Srmacklem warnx("nfsuserd count %d; reset to %d", 195192811Srmacklem nfsuserdcnt, DEFNFSUSERD); 196192811Srmacklem nfsuserdcnt = DEFNFSUSERD; 197192811Srmacklem } 198192811Srmacklem } else { 199192811Srmacklem usage(); 200192811Srmacklem } 201192811Srmacklem argc--; 202192811Srmacklem argv++; 203192811Srmacklem } 204192811Srmacklem if (nfsuserdcnt < 1) 205192811Srmacklem nfsuserdcnt = DEFNFSUSERD; 206192811Srmacklem 207192811Srmacklem /* 208192811Srmacklem * Strip off leading and trailing '.'s in domain name and map 209192811Srmacklem * alphabetics to lower case. 210192811Srmacklem */ 211192811Srmacklem while (*dnsname == '.') 212192811Srmacklem dnsname++; 213192811Srmacklem if (*dnsname == '\0') 214192811Srmacklem errx(1, "Domain name all '.'"); 215192811Srmacklem len = strlen(dnsname); 216192811Srmacklem cp = dnsname + len - 1; 217192811Srmacklem while (*cp == '.') { 218192811Srmacklem *cp = '\0'; 219192811Srmacklem len--; 220192811Srmacklem cp--; 221192811Srmacklem } 222192811Srmacklem for (i = 0; i < len; i++) { 223192811Srmacklem if (!isascii(dnsname[i])) 224192811Srmacklem errx(1, "Domain name has non-ascii char"); 225192811Srmacklem if (isupper(dnsname[i])) 226192811Srmacklem dnsname[i] = tolower(dnsname[i]); 227192811Srmacklem } 228192811Srmacklem 229192811Srmacklem /* 230192811Srmacklem * If the nfsuserd died off ungracefully, this is necessary to 231192811Srmacklem * get them to start again. 232192811Srmacklem */ 233192811Srmacklem if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) 234192811Srmacklem errx(1, "Can't do nfssvc() to delete the port"); 235192811Srmacklem 236192811Srmacklem if (verbose) 237192811Srmacklem fprintf(stderr, 238192811Srmacklem "nfsuserd: domain=%s usermax=%d usertimeout=%d\n", 239192811Srmacklem dnsname, nid.nid_usermax, nid.nid_usertimeout); 240192811Srmacklem 241192811Srmacklem for (i = 0; i < nfsuserdcnt; i++) 242192811Srmacklem slaves[i] = (pid_t)-1; 243192811Srmacklem 244192811Srmacklem /* 245192811Srmacklem * Set up the service port to accept requests via UDP from 246192811Srmacklem * localhost (127.0.0.1). 247192811Srmacklem */ 248192811Srmacklem if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 249192811Srmacklem err(1, "cannot create udp socket"); 250192811Srmacklem 251192811Srmacklem /* 252192811Srmacklem * Not sure what this does, so I'll leave it here for now. 253192811Srmacklem */ 254192811Srmacklem setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 255192811Srmacklem 256192811Srmacklem if ((udptransp = svcudp_create(sock)) == NULL) 257192811Srmacklem err(1, "Can't set up socket"); 258192811Srmacklem 259192811Srmacklem /* 260192811Srmacklem * By not specifying a protocol, it is linked into the 261192811Srmacklem * dispatch queue, but not registered with portmapper, 262192811Srmacklem * which is just what I want. 263192811Srmacklem */ 264192811Srmacklem if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, 265192811Srmacklem nfsuserdsrv, 0)) 266192811Srmacklem err(1, "Can't register nfsuserd"); 267192811Srmacklem 268192811Srmacklem /* 269192811Srmacklem * Tell the kernel what my port# is. 270192811Srmacklem */ 271192811Srmacklem portnum = htons(udptransp->xp_port); 272192811Srmacklem#ifdef DEBUG 273192811Srmacklem printf("portnum=0x%x\n", portnum); 274192811Srmacklem#else 275192811Srmacklem if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) { 276192811Srmacklem if (errno == EPERM) { 277192811Srmacklem fprintf(stderr, 278192811Srmacklem "Can't start nfsuserd when already running"); 279192811Srmacklem fprintf(stderr, 280192811Srmacklem " If not running, use the -force option.\n"); 281192811Srmacklem } else { 282192811Srmacklem fprintf(stderr, "Can't do nfssvc() to add port\n"); 283192811Srmacklem } 284192811Srmacklem exit(1); 285192811Srmacklem } 286192811Srmacklem#endif 287192811Srmacklem 288192811Srmacklem pwd = getpwnam(defaultuser); 289192811Srmacklem if (pwd) 290192811Srmacklem nid.nid_uid = pwd->pw_uid; 291192811Srmacklem else 292192811Srmacklem nid.nid_uid = defaultuid; 293192811Srmacklem grp = getgrnam(defaultgroup); 294192811Srmacklem if (grp) 295192811Srmacklem nid.nid_gid = grp->gr_gid; 296192811Srmacklem else 297192811Srmacklem nid.nid_gid = defaultgid; 298192811Srmacklem nid.nid_name = dnsname; 299192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 300192811Srmacklem nid.nid_flag = NFSID_INITIALIZE; 301192811Srmacklem#ifdef DEBUG 302192811Srmacklem printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, 303192811Srmacklem nid.nid_name); 304192811Srmacklem#else 305192811Srmacklem error = nfssvc(NFSSVC_IDNAME, &nid); 306192811Srmacklem if (error) 307192811Srmacklem errx(1, "Can't initialize nfs user/groups"); 308192811Srmacklem#endif 309192811Srmacklem 310192811Srmacklem i = 0; 311192811Srmacklem /* 312192811Srmacklem * Loop around adding all groups. 313192811Srmacklem */ 314192811Srmacklem setgrent(); 315192811Srmacklem while (i < nid.nid_usermax && (grp = getgrent())) { 316192811Srmacklem nid.nid_gid = grp->gr_gid; 317192811Srmacklem nid.nid_name = grp->gr_name; 318192811Srmacklem nid.nid_namelen = strlen(grp->gr_name); 319192811Srmacklem nid.nid_flag = NFSID_ADDGID; 320192811Srmacklem#ifdef DEBUG 321192811Srmacklem printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name); 322192811Srmacklem#else 323192811Srmacklem error = nfssvc(NFSSVC_IDNAME, &nid); 324192811Srmacklem if (error) 325192811Srmacklem errx(1, "Can't add group %s", grp->gr_name); 326192811Srmacklem#endif 327192811Srmacklem i++; 328192811Srmacklem } 329192811Srmacklem 330192811Srmacklem /* 331192811Srmacklem * Loop around adding all users. 332192811Srmacklem */ 333223382Srmacklem start_uidpos = i; 334192811Srmacklem setpwent(); 335192811Srmacklem while (i < nid.nid_usermax && (pwd = getpwent())) { 336223382Srmacklem fnd_dup = 0; 337223382Srmacklem /* 338223382Srmacklem * Yes, this is inefficient, but it is only done once when 339223382Srmacklem * the daemon is started and will run in a fraction of a second 340223382Srmacklem * for nid_usermax at 10000. If nid_usermax is cranked up to 341223382Srmacklem * 100000, it will take several seconds, depending on the CPU. 342223382Srmacklem */ 343223382Srmacklem for (j = 0; j < (i - start_uidpos); j++) 344223382Srmacklem if (check_dups[j] == pwd->pw_uid) { 345223382Srmacklem /* Found another entry for uid, so skip it */ 346223382Srmacklem fnd_dup = 1; 347223382Srmacklem break; 348223382Srmacklem } 349223382Srmacklem if (fnd_dup != 0) 350223382Srmacklem continue; 351223382Srmacklem check_dups[i - start_uidpos] = pwd->pw_uid; 352192811Srmacklem nid.nid_uid = pwd->pw_uid; 353192811Srmacklem nid.nid_name = pwd->pw_name; 354192811Srmacklem nid.nid_namelen = strlen(pwd->pw_name); 355192811Srmacklem nid.nid_flag = NFSID_ADDUID; 356192811Srmacklem#ifdef DEBUG 357192811Srmacklem printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name); 358192811Srmacklem#else 359192811Srmacklem error = nfssvc(NFSSVC_IDNAME, &nid); 360192811Srmacklem if (error) 361192811Srmacklem errx(1, "Can't add user %s", pwd->pw_name); 362192811Srmacklem#endif 363192811Srmacklem i++; 364192811Srmacklem } 365192811Srmacklem 366192811Srmacklem /* 367192811Srmacklem * I should feel guilty for not calling this for all the above exit() 368192811Srmacklem * upon error cases, but I don't. 369192811Srmacklem */ 370192811Srmacklem if (mustfreeai) 371192811Srmacklem freeaddrinfo(aip); 372192811Srmacklem 373192811Srmacklem#ifdef DEBUG 374192811Srmacklem exit(0); 375192811Srmacklem#endif 376192811Srmacklem /* 377192811Srmacklem * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't 378192811Srmacklem * end up bogus. 379192811Srmacklem */ 380192811Srmacklem sigemptyset(&signew); 381192811Srmacklem sigaddset(&signew, SIGUSR1); 382192811Srmacklem sigaddset(&signew, SIGCHLD); 383192811Srmacklem sigprocmask(SIG_BLOCK, &signew, NULL); 384192811Srmacklem 385192811Srmacklem daemon(0, 0); 386192811Srmacklem (void)signal(SIGHUP, SIG_IGN); 387192811Srmacklem (void)signal(SIGINT, SIG_IGN); 388192811Srmacklem (void)signal(SIGQUIT, SIG_IGN); 389192811Srmacklem (void)signal(SIGTERM, SIG_IGN); 390192811Srmacklem (void)signal(SIGUSR1, cleanup_term); 391192811Srmacklem (void)signal(SIGCHLD, cleanup_term); 392192811Srmacklem 393192811Srmacklem openlog("nfsuserd:", LOG_PID, LOG_DAEMON); 394192811Srmacklem 395192811Srmacklem /* 396192811Srmacklem * Fork off the slave daemons that do the work. All the master 397192811Srmacklem * does is kill them off and cleanup. 398192811Srmacklem */ 399192811Srmacklem for (i = 0; i < nfsuserdcnt; i++) { 400192811Srmacklem slaves[i] = fork(); 401192811Srmacklem if (slaves[i] == 0) { 402192811Srmacklem im_a_slave = 1; 403192811Srmacklem setproctitle("slave"); 404192811Srmacklem sigemptyset(&signew); 405192811Srmacklem sigaddset(&signew, SIGUSR1); 406192811Srmacklem sigprocmask(SIG_UNBLOCK, &signew, NULL); 407192811Srmacklem 408192811Srmacklem /* 409192811Srmacklem * and away we go. 410192811Srmacklem */ 411192811Srmacklem svc_run(); 412192811Srmacklem syslog(LOG_ERR, "nfsuserd died: %m"); 413192811Srmacklem exit(1); 414192811Srmacklem } else if (slaves[i] < 0) { 415192811Srmacklem syslog(LOG_ERR, "fork: %m"); 416192811Srmacklem } 417192811Srmacklem } 418192811Srmacklem 419192811Srmacklem /* 420192811Srmacklem * Just wait for SIGUSR1 or a child to die and then... 421192811Srmacklem * As the Governor of California would say, "Terminate them". 422192811Srmacklem */ 423192811Srmacklem setproctitle("master"); 424192811Srmacklem sigemptyset(&signew); 425192811Srmacklem while (1) 426192811Srmacklem sigsuspend(&signew); 427192811Srmacklem} 428192811Srmacklem 429192811Srmacklem/* 430192811Srmacklem * The nfsuserd rpc service 431192811Srmacklem */ 432193070Sdelphijstatic void 433192811Srmacklemnfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp) 434192811Srmacklem{ 435192811Srmacklem struct passwd *pwd; 436192811Srmacklem struct group *grp; 437192811Srmacklem int error; 438192811Srmacklem u_short sport; 439192811Srmacklem struct info info; 440192811Srmacklem struct nfsd_idargs nid; 441192811Srmacklem u_int32_t saddr; 442192811Srmacklem 443192811Srmacklem /* 444192811Srmacklem * Only handle requests from 127.0.0.1 on a reserved port number. 445192811Srmacklem * (Since a reserved port # at localhost implies a client with 446192811Srmacklem * local root, there won't be a security breach. This is about 447192811Srmacklem * the only case I can think of where a reserved port # means 448192811Srmacklem * something.) 449192811Srmacklem */ 450192811Srmacklem sport = ntohs(transp->xp_raddr.sin_port); 451192811Srmacklem saddr = ntohl(transp->xp_raddr.sin_addr.s_addr); 452192811Srmacklem if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) || 453192811Srmacklem saddr != 0x7f000001) { 454192811Srmacklem syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport); 455192811Srmacklem svcerr_weakauth(transp); 456192811Srmacklem return; 457192811Srmacklem } 458192811Srmacklem switch (rqstp->rq_proc) { 459192811Srmacklem case NULLPROC: 460192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 461192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 462192811Srmacklem return; 463192811Srmacklem case RPCNFSUSERD_GETUID: 464192811Srmacklem if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 465192811Srmacklem (caddr_t)&info)) { 466192811Srmacklem svcerr_decode(transp); 467192811Srmacklem return; 468192811Srmacklem } 469192811Srmacklem pwd = getpwuid((uid_t)info.id); 470192811Srmacklem info.retval = 0; 471192811Srmacklem if (pwd != NULL) { 472192811Srmacklem nid.nid_usertimeout = defusertimeout; 473192811Srmacklem nid.nid_uid = pwd->pw_uid; 474192811Srmacklem nid.nid_name = pwd->pw_name; 475192811Srmacklem } else { 476192811Srmacklem nid.nid_usertimeout = 5; 477192811Srmacklem nid.nid_uid = (uid_t)info.id; 478192811Srmacklem nid.nid_name = defaultuser; 479192811Srmacklem } 480192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 481192811Srmacklem nid.nid_flag = NFSID_ADDUID; 482192811Srmacklem error = nfssvc(NFSSVC_IDNAME, &nid); 483192811Srmacklem if (error) { 484192811Srmacklem info.retval = error; 485192811Srmacklem syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 486192811Srmacklem } else if (verbose) { 487192811Srmacklem syslog(LOG_ERR,"Added uid=%d name=%s\n", 488192811Srmacklem nid.nid_uid, nid.nid_name); 489192811Srmacklem } 490192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 491192811Srmacklem (caddr_t)&info)) 492192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 493192811Srmacklem return; 494192811Srmacklem case RPCNFSUSERD_GETGID: 495192811Srmacklem if (!svc_getargs(transp, (xdrproc_t)xdr_getid, 496192811Srmacklem (caddr_t)&info)) { 497192811Srmacklem svcerr_decode(transp); 498192811Srmacklem return; 499192811Srmacklem } 500192811Srmacklem grp = getgrgid((gid_t)info.id); 501192811Srmacklem info.retval = 0; 502192811Srmacklem if (grp != NULL) { 503192811Srmacklem nid.nid_usertimeout = defusertimeout; 504192811Srmacklem nid.nid_gid = grp->gr_gid; 505192811Srmacklem nid.nid_name = grp->gr_name; 506192811Srmacklem } else { 507192811Srmacklem nid.nid_usertimeout = 5; 508192811Srmacklem nid.nid_gid = (gid_t)info.id; 509192811Srmacklem nid.nid_name = defaultgroup; 510192811Srmacklem } 511192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 512192811Srmacklem nid.nid_flag = NFSID_ADDGID; 513192811Srmacklem error = nfssvc(NFSSVC_IDNAME, &nid); 514192811Srmacklem if (error) { 515192811Srmacklem info.retval = error; 516192811Srmacklem syslog(LOG_ERR, "Can't add group %s\n", 517192811Srmacklem grp->gr_name); 518192811Srmacklem } else if (verbose) { 519192811Srmacklem syslog(LOG_ERR,"Added gid=%d name=%s\n", 520192811Srmacklem nid.nid_gid, nid.nid_name); 521192811Srmacklem } 522192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 523192811Srmacklem (caddr_t)&info)) 524192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 525192811Srmacklem return; 526192811Srmacklem case RPCNFSUSERD_GETUSER: 527192811Srmacklem if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 528192811Srmacklem (caddr_t)&info)) { 529192811Srmacklem svcerr_decode(transp); 530192811Srmacklem return; 531192811Srmacklem } 532192811Srmacklem pwd = getpwnam(info.name); 533192811Srmacklem info.retval = 0; 534192811Srmacklem if (pwd != NULL) { 535192811Srmacklem nid.nid_usertimeout = defusertimeout; 536192811Srmacklem nid.nid_uid = pwd->pw_uid; 537192811Srmacklem nid.nid_name = pwd->pw_name; 538192811Srmacklem } else { 539192811Srmacklem nid.nid_usertimeout = 5; 540192811Srmacklem nid.nid_uid = defaultuid; 541192811Srmacklem nid.nid_name = info.name; 542192811Srmacklem } 543192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 544192811Srmacklem nid.nid_flag = NFSID_ADDUSERNAME; 545192811Srmacklem error = nfssvc(NFSSVC_IDNAME, &nid); 546192811Srmacklem if (error) { 547192811Srmacklem info.retval = error; 548192811Srmacklem syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); 549192811Srmacklem } else if (verbose) { 550192811Srmacklem syslog(LOG_ERR,"Added uid=%d name=%s\n", 551192811Srmacklem nid.nid_uid, nid.nid_name); 552192811Srmacklem } 553192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 554192811Srmacklem (caddr_t)&info)) 555192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 556192811Srmacklem return; 557192811Srmacklem case RPCNFSUSERD_GETGROUP: 558192811Srmacklem if (!svc_getargs(transp, (xdrproc_t)xdr_getname, 559192811Srmacklem (caddr_t)&info)) { 560192811Srmacklem svcerr_decode(transp); 561192811Srmacklem return; 562192811Srmacklem } 563192811Srmacklem grp = getgrnam(info.name); 564192811Srmacklem info.retval = 0; 565192811Srmacklem if (grp != NULL) { 566192811Srmacklem nid.nid_usertimeout = defusertimeout; 567192811Srmacklem nid.nid_gid = grp->gr_gid; 568192811Srmacklem nid.nid_name = grp->gr_name; 569192811Srmacklem } else { 570192811Srmacklem nid.nid_usertimeout = 5; 571192811Srmacklem nid.nid_gid = defaultgid; 572192811Srmacklem nid.nid_name = info.name; 573192811Srmacklem } 574192811Srmacklem nid.nid_namelen = strlen(nid.nid_name); 575192811Srmacklem nid.nid_flag = NFSID_ADDGROUPNAME; 576192811Srmacklem error = nfssvc(NFSSVC_IDNAME, &nid); 577192811Srmacklem if (error) { 578192811Srmacklem info.retval = error; 579192811Srmacklem syslog(LOG_ERR, "Can't add group %s\n", 580192811Srmacklem grp->gr_name); 581192811Srmacklem } else if (verbose) { 582192811Srmacklem syslog(LOG_ERR,"Added gid=%d name=%s\n", 583192811Srmacklem nid.nid_gid, nid.nid_name); 584192811Srmacklem } 585192811Srmacklem if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, 586192811Srmacklem (caddr_t)&info)) 587192811Srmacklem syslog(LOG_ERR, "Can't send reply"); 588192811Srmacklem return; 589192811Srmacklem default: 590192811Srmacklem svcerr_noproc(transp); 591192811Srmacklem return; 592192811Srmacklem }; 593192811Srmacklem} 594192811Srmacklem 595192811Srmacklem/* 596192811Srmacklem * Xdr routine to get an id number 597192811Srmacklem */ 598193070Sdelphijstatic bool_t 599192811Srmacklemxdr_getid(XDR *xdrsp, caddr_t cp) 600192811Srmacklem{ 601192811Srmacklem struct info *ifp = (struct info *)cp; 602192811Srmacklem 603192811Srmacklem return (xdr_long(xdrsp, &ifp->id)); 604192811Srmacklem} 605192811Srmacklem 606192811Srmacklem/* 607192811Srmacklem * Xdr routine to get a user name 608192811Srmacklem */ 609193070Sdelphijstatic bool_t 610192811Srmacklemxdr_getname(XDR *xdrsp, caddr_t cp) 611192811Srmacklem{ 612192811Srmacklem struct info *ifp = (struct info *)cp; 613192811Srmacklem long len; 614192811Srmacklem 615192811Srmacklem if (!xdr_long(xdrsp, &len)) 616192811Srmacklem return (0); 617192811Srmacklem if (len > MAXNAME) 618192811Srmacklem return (0); 619192811Srmacklem if (!xdr_opaque(xdrsp, ifp->name, len)) 620192811Srmacklem return (0); 621192811Srmacklem ifp->name[len] = '\0'; 622192811Srmacklem return (1); 623192811Srmacklem} 624192811Srmacklem 625192811Srmacklem/* 626192811Srmacklem * Xdr routine to return the value. 627192811Srmacklem */ 628193070Sdelphijstatic bool_t 629192811Srmacklemxdr_retval(XDR *xdrsp, caddr_t cp) 630192811Srmacklem{ 631192811Srmacklem struct info *ifp = (struct info *)cp; 632192811Srmacklem long val; 633192811Srmacklem 634192811Srmacklem val = ifp->retval; 635192811Srmacklem return (xdr_long(xdrsp, &val)); 636192811Srmacklem} 637192811Srmacklem 638192811Srmacklem/* 639192811Srmacklem * cleanup_term() called via SIGUSR1. 640192811Srmacklem */ 641193070Sdelphijstatic void 642193070Sdelphijcleanup_term(int signo __unused) 643192811Srmacklem{ 644192811Srmacklem int i, cnt; 645192811Srmacklem 646192811Srmacklem if (im_a_slave) 647192811Srmacklem exit(0); 648192811Srmacklem 649192811Srmacklem /* 650192811Srmacklem * Ok, so I'm the master. 651192811Srmacklem * As the Governor of California might say, "Terminate them". 652192811Srmacklem */ 653192811Srmacklem cnt = 0; 654192811Srmacklem for (i = 0; i < nfsuserdcnt; i++) { 655192811Srmacklem if (slaves[i] != (pid_t)-1) { 656192811Srmacklem cnt++; 657192811Srmacklem kill(slaves[i], SIGUSR1); 658192811Srmacklem } 659192811Srmacklem } 660192811Srmacklem 661192811Srmacklem /* 662192811Srmacklem * and wait for them to die 663192811Srmacklem */ 664192811Srmacklem for (i = 0; i < cnt; i++) 665192811Srmacklem wait3(NULL, 0, NULL); 666192811Srmacklem 667192811Srmacklem /* 668192811Srmacklem * Finally, get rid of the socket 669192811Srmacklem */ 670192811Srmacklem if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) { 671192811Srmacklem syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n"); 672192811Srmacklem exit(1); 673192811Srmacklem } 674192811Srmacklem exit(0); 675192811Srmacklem} 676192811Srmacklem 677193070Sdelphijstatic void 678192811Srmacklemusage(void) 679192811Srmacklem{ 680192811Srmacklem 681192811Srmacklem errx(1, 682192811Srmacklem "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-domain domain_name] [n]"); 683192811Srmacklem} 684