From 2864c5d543e6e9084ecdc1a66dab4d64fceed270 Mon Sep 17 00:00:00 2001 From: rmacklem Date: Tue, 26 May 2009 15:19:04 +0000 Subject: Add two new utilities and two new daemons to /usr/src/usr.sbin that are specifically used by the experimental nfsv4 subsystem. nfscbd - The NFSv4 client callback daemon. nfsuserd - The NFSv4 daemon that maps between user and group name and their corresponding uid/gid numbers. nfsdumpstate - A utility that dumps out the NFSv4 Open/Lock state. nfsrevoke - Administratively revokes an NFSv4 client, releasing all NFSv4 Open/Lock state it holds on the server. Approved by: kib (mentor) --- usr.sbin/nfsuserd/Makefile | 6 + usr.sbin/nfsuserd/nfsuserd.8 | 114 ++++++++ usr.sbin/nfsuserd/nfsuserd.c | 665 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 785 insertions(+) create mode 100644 usr.sbin/nfsuserd/Makefile create mode 100644 usr.sbin/nfsuserd/nfsuserd.8 create mode 100644 usr.sbin/nfsuserd/nfsuserd.c (limited to 'usr.sbin/nfsuserd') diff --git a/usr.sbin/nfsuserd/Makefile b/usr.sbin/nfsuserd/Makefile new file mode 100644 index 0000000..377b5af --- /dev/null +++ b/usr.sbin/nfsuserd/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +PROG= nfsuserd +MAN= nfsuserd.8 + +.include diff --git a/usr.sbin/nfsuserd/nfsuserd.8 b/usr.sbin/nfsuserd/nfsuserd.8 new file mode 100644 index 0000000..b98c34a --- /dev/null +++ b/usr.sbin/nfsuserd/nfsuserd.8 @@ -0,0 +1,114 @@ +.\" Copyright (c) 2009 Rick Macklem, University of Guelph +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 25, 2009 +.Dt NFSUSERD 8 +.Os +.Sh NAME +.Nm nfsuserd +.Nd load user and group information into the kernel for +.Tn NFSv4 +services +.Sh SYNOPSIS +.Nm nfsuserd +.Op Fl domain Ar domain_name +.Op Fl usertimeout Ar minutes +.Op Fl usermax Ar max_cache_size +.Op Fl verbose +.Op Fl force +.Op Ar num_servers +.Sh DESCRIPTION +.Nm +loads user and group information into the kernel for NFSv4. +It must be running for NFSv4 to function correctly, either client or server. +.Pp +Upon startup, it loads the machines DNS domain name, plus timeout and +cache size limit into the kernel. It then preloads the cache with group +and user information, up to the cache size limit and forks off N children +(default 4), that service requests from the kernel for cache misses. The +master server is there for the sole purpose of killing off the slaves. +To stop the nfsuserd, send a SIGUSR1 to the master server. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl domain Ar domain_name +This option allows you to override the default DNS domain name, which +is acquired by taking either the suffix on the machine's hostname or, +if that name is not a fully qualified host name, the cannonical name as +reported by +.Xr getaddrinfo 3 . +.It Fl usertimeout Ar minutes +Overrides the default timeout for cache entries, in minutes. If the +timeout is specified as 0, cache entries never time out. The longer the +time out, the better the performance, but the longer it takes for replaced +entries to be seen. If your user/group database management system almost +never re-uses the same names or id numbers, a large timeout is recommended. +The default is 1 minute. +.It Fl usermax Ar max_cache_size +Overrides the default upper bound on the cache size. The larger the cache, +the more kernel memory is used, but the better the performance. If your +system can afford the memory use, make this the sum of the number of +entries in your group and password databases. +The default is 200 entries. +.It Fl verbose +When set, the server logs a bunch of information to syslog. +.It Fl force +This flag option must be set to restart the daemon after it has gone away +abnormally and refuses to start, because it thinks nfsuserd is already +running. +.It Ar num_servers +Specifies how many servers to create (max 20). +The default of 4 may be sufficient. You should run enough servers, so that +.Xr ps 1 +shows almost no running time for one or two of the slaves after the system +has been running for a long period. Running too few will have a major +performance impact, whereas running too many will only tie up some resources, +such as a process table entry and swap space. +.El +.Sh SEE ALSO +.Xr getpwent 3 , +.Xr getgrent 3 , +.Xr nfsv4 4 , +.Xr group 5 , +.Xr passwd 5 , +.Xr nfsd 8 . +.Sh HISTORY +The +.Nm +utility was introduced with the NFSv4 experimental subsystem in 2009. +.Sh BUGS +The +.Nm +use +.Xr getgrent 3 +and +.Xr getpwent 3 +library calls to resolve requests and will hang if the servers handling +those requests fail and the library functions don't return. See +.Xr group 5 +and +.Xr passwd 5 +for more information on how the databases are accessed. diff --git a/usr.sbin/nfsuserd/nfsuserd.c b/usr.sbin/nfsuserd/nfsuserd.c new file mode 100644 index 0000000..7928a75 --- /dev/null +++ b/usr.sbin/nfsuserd/nfsuserd.c @@ -0,0 +1,665 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This program loads the password and group databases into the kernel + * for NFS V4. + */ + +void cleanup_term(int); +void usage(void); +void nfsuserdsrv(struct svc_req *, SVCXPRT *); +bool_t xdr_getid(XDR *, caddr_t); +bool_t xdr_getname(XDR *, caddr_t); +bool_t xdr_retval(XDR *, caddr_t); + +#define MAXNAME 1024 +#define MAXNFSUSERD 20 +#define DEFNFSUSERD 4 +#define DEFUSERMAX 200 +#define DEFUSERTIMEOUT (1 * 60) +struct info { + long id; + long retval; + char name[MAXNAME + 1]; +}; + +u_char *dnsname = "default.domain"; +u_char *defaultuser = "nobody"; +uid_t defaultuid = (uid_t)32767; +u_char *defaultgroup = "nogroup"; +gid_t defaultgid = (gid_t)32767; +int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0; +int defusertimeout = DEFUSERTIMEOUT; +pid_t slaves[MAXNFSUSERD]; + +int +main(int argc, char *argv[], char *envp[]) +{ + int i; + int error, len, mustfreeai = 0; + struct nfsd_idargs nid; + struct passwd *pwd; + struct group *grp; + int sock, one = 1; + SVCXPRT *udptransp, *tcptransp; + struct passwd *pw; + u_short portnum; + sigset_t signew; + char hostname[MAXHOSTNAMELEN + 1], *cp, **aliases; + struct addrinfo *aip, hints; + + if (modfind("nfscommon") < 0) { + /* Not present in kernel, try loading it */ + if (kldload("nfscommon") < 0 || + modfind("nfscommon") < 0) + errx(1, "Experimental nfs subsystem is not available"); + } + + /* + * First, figure out what our domain name and Kerberos Realm + * seem to be. Command line args may override these later. + */ + if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { + if ((cp = strchr(hostname, '.')) != NULL && + *(cp + 1) != '\0') { + dnsname = cp + 1; + } else { + memset((void *)&hints, 0, sizeof (hints)); + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(hostname, NULL, &hints, &aip); + if (error == 0) { + if (aip->ai_canonname != NULL && + (cp = strchr(aip->ai_canonname, '.')) != NULL + && *(cp + 1) != '\0') { + dnsname = cp + 1; + mustfreeai = 1; + } else { + freeaddrinfo(aip); + } + } + } + } + nid.nid_usermax = DEFUSERMAX; + nid.nid_usertimeout = defusertimeout; + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-domain")) { + if (argc == 1) + usage(); + argc--; + argv++; + strncpy(hostname, *argv, MAXHOSTNAMELEN); + hostname[MAXHOSTNAMELEN] = '\0'; + dnsname = hostname; + } else if (!strcmp(*argv, "-verbose")) { + verbose = 1; + } else if (!strcmp(*argv, "-force")) { + forcestart = 1; + } else if (!strcmp(*argv, "-usermax")) { + if (argc == 1) + usage(); + argc--; + argv++; + i = atoi(*argv); + if (i < 10 || i > 100000) { + fprintf(stderr, + "usermax out of range 10<->100000\n", i); + usage(); + } + nid.nid_usermax = i; + } else if (!strcmp(*argv, "-usertimeout")) { + if (argc == 1) + usage(); + argc--; + argv++; + i = atoi(*argv); + if (i < 0 || i > 100000) { + fprintf(stderr, + "usertimeout out of range 0<->100000\n", + i); + usage(); + } + nid.nid_usertimeout = defusertimeout = i * 60; + } else if (nfsuserdcnt == -1) { + nfsuserdcnt = atoi(*argv); + if (nfsuserdcnt < 1) + usage(); + if (nfsuserdcnt > MAXNFSUSERD) { + warnx("nfsuserd count %d; reset to %d", + nfsuserdcnt, DEFNFSUSERD); + nfsuserdcnt = DEFNFSUSERD; + } + } else { + usage(); + } + argc--; + argv++; + } + if (nfsuserdcnt < 1) + nfsuserdcnt = DEFNFSUSERD; + + /* + * Strip off leading and trailing '.'s in domain name and map + * alphabetics to lower case. + */ + while (*dnsname == '.') + dnsname++; + if (*dnsname == '\0') + errx(1, "Domain name all '.'"); + len = strlen(dnsname); + cp = dnsname + len - 1; + while (*cp == '.') { + *cp = '\0'; + len--; + cp--; + } + for (i = 0; i < len; i++) { + if (!isascii(dnsname[i])) + errx(1, "Domain name has non-ascii char"); + if (isupper(dnsname[i])) + dnsname[i] = tolower(dnsname[i]); + } + + /* + * If the nfsuserd died off ungracefully, this is necessary to + * get them to start again. + */ + if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) + errx(1, "Can't do nfssvc() to delete the port"); + + if (verbose) + fprintf(stderr, + "nfsuserd: domain=%s usermax=%d usertimeout=%d\n", + dnsname, nid.nid_usermax, nid.nid_usertimeout); + + for (i = 0; i < nfsuserdcnt; i++) + slaves[i] = (pid_t)-1; + + /* + * Set up the service port to accept requests via UDP from + * localhost (127.0.0.1). + */ + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + err(1, "cannot create udp socket"); + + /* + * Not sure what this does, so I'll leave it here for now. + */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + + if ((udptransp = svcudp_create(sock)) == NULL) + err(1, "Can't set up socket"); + + /* + * By not specifying a protocol, it is linked into the + * dispatch queue, but not registered with portmapper, + * which is just what I want. + */ + if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, + nfsuserdsrv, 0)) + err(1, "Can't register nfsuserd"); + + /* + * Tell the kernel what my port# is. + */ + portnum = htons(udptransp->xp_port); +#ifdef DEBUG + printf("portnum=0x%x\n", portnum); +#else + if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) { + if (errno == EPERM) { + fprintf(stderr, + "Can't start nfsuserd when already running"); + fprintf(stderr, + " If not running, use the -force option.\n"); + } else { + fprintf(stderr, "Can't do nfssvc() to add port\n"); + } + exit(1); + } +#endif + + pwd = getpwnam(defaultuser); + if (pwd) + nid.nid_uid = pwd->pw_uid; + else + nid.nid_uid = defaultuid; + grp = getgrnam(defaultgroup); + if (grp) + nid.nid_gid = grp->gr_gid; + else + nid.nid_gid = defaultgid; + nid.nid_name = dnsname; + nid.nid_namelen = strlen(nid.nid_name); + nid.nid_flag = NFSID_INITIALIZE; +#ifdef DEBUG + printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, + nid.nid_name); +#else + error = nfssvc(NFSSVC_IDNAME, &nid); + if (error) + errx(1, "Can't initialize nfs user/groups"); +#endif + + i = 0; + /* + * Loop around adding all groups. + */ + setgrent(); + while (i < nid.nid_usermax && (grp = getgrent())) { + nid.nid_gid = grp->gr_gid; + nid.nid_name = grp->gr_name; + nid.nid_namelen = strlen(grp->gr_name); + nid.nid_flag = NFSID_ADDGID; +#ifdef DEBUG + printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name); +#else + error = nfssvc(NFSSVC_IDNAME, &nid); + if (error) + errx(1, "Can't add group %s", grp->gr_name); +#endif + i++; + } + + /* + * Loop around adding all users. + */ + setpwent(); + while (i < nid.nid_usermax && (pwd = getpwent())) { + nid.nid_uid = pwd->pw_uid; + nid.nid_name = pwd->pw_name; + nid.nid_namelen = strlen(pwd->pw_name); + nid.nid_flag = NFSID_ADDUID; +#ifdef DEBUG + printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name); +#else + error = nfssvc(NFSSVC_IDNAME, &nid); + if (error) + errx(1, "Can't add user %s", pwd->pw_name); +#endif + i++; + } + + /* + * I should feel guilty for not calling this for all the above exit() + * upon error cases, but I don't. + */ + if (mustfreeai) + freeaddrinfo(aip); + +#ifdef DEBUG + exit(0); +#endif + /* + * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't + * end up bogus. + */ + sigemptyset(&signew); + sigaddset(&signew, SIGUSR1); + sigaddset(&signew, SIGCHLD); + sigprocmask(SIG_BLOCK, &signew, NULL); + + daemon(0, 0); + (void)signal(SIGHUP, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGTERM, SIG_IGN); + (void)signal(SIGUSR1, cleanup_term); + (void)signal(SIGCHLD, cleanup_term); + + openlog("nfsuserd:", LOG_PID, LOG_DAEMON); + + /* + * Fork off the slave daemons that do the work. All the master + * does is kill them off and cleanup. + */ + for (i = 0; i < nfsuserdcnt; i++) { + slaves[i] = fork(); + if (slaves[i] == 0) { + im_a_slave = 1; + setproctitle("slave"); + sigemptyset(&signew); + sigaddset(&signew, SIGUSR1); + sigprocmask(SIG_UNBLOCK, &signew, NULL); + + /* + * and away we go. + */ + svc_run(); + syslog(LOG_ERR, "nfsuserd died: %m"); + exit(1); + } else if (slaves[i] < 0) { + syslog(LOG_ERR, "fork: %m"); + } + } + + /* + * Just wait for SIGUSR1 or a child to die and then... + * As the Governor of California would say, "Terminate them". + */ + setproctitle("master"); + sigemptyset(&signew); + while (1) + sigsuspend(&signew); +} + +/* + * The nfsuserd rpc service + */ +void +nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp) +{ + int i; + char *cp; + struct passwd *pwd; + struct group *grp; + int error; + u_short sport; + struct info info; + struct nfsd_idargs nid; + u_int32_t saddr; + + /* + * Only handle requests from 127.0.0.1 on a reserved port number. + * (Since a reserved port # at localhost implies a client with + * local root, there won't be a security breach. This is about + * the only case I can think of where a reserved port # means + * something.) + */ + sport = ntohs(transp->xp_raddr.sin_port); + saddr = ntohl(transp->xp_raddr.sin_addr.s_addr); + if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) || + saddr != 0x7f000001) { + syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport); + svcerr_weakauth(transp); + return; + } + switch (rqstp->rq_proc) { + case NULLPROC: + if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) + syslog(LOG_ERR, "Can't send reply"); + return; + case RPCNFSUSERD_GETUID: + if (!svc_getargs(transp, (xdrproc_t)xdr_getid, + (caddr_t)&info)) { + svcerr_decode(transp); + return; + } + pwd = getpwuid((uid_t)info.id); + info.retval = 0; + if (pwd != NULL) { + nid.nid_usertimeout = defusertimeout; + nid.nid_uid = pwd->pw_uid; + nid.nid_name = pwd->pw_name; + } else { + nid.nid_usertimeout = 5; + nid.nid_uid = (uid_t)info.id; + nid.nid_name = defaultuser; + } + nid.nid_namelen = strlen(nid.nid_name); + nid.nid_flag = NFSID_ADDUID; + error = nfssvc(NFSSVC_IDNAME, &nid); + if (error) { + info.retval = error; + syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); + } else if (verbose) { + syslog(LOG_ERR,"Added uid=%d name=%s\n", + nid.nid_uid, nid.nid_name); + } + if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, + (caddr_t)&info)) + syslog(LOG_ERR, "Can't send reply"); + return; + case RPCNFSUSERD_GETGID: + if (!svc_getargs(transp, (xdrproc_t)xdr_getid, + (caddr_t)&info)) { + svcerr_decode(transp); + return; + } + grp = getgrgid((gid_t)info.id); + info.retval = 0; + if (grp != NULL) { + nid.nid_usertimeout = defusertimeout; + nid.nid_gid = grp->gr_gid; + nid.nid_name = grp->gr_name; + } else { + nid.nid_usertimeout = 5; + nid.nid_gid = (gid_t)info.id; + nid.nid_name = defaultgroup; + } + nid.nid_namelen = strlen(nid.nid_name); + nid.nid_flag = NFSID_ADDGID; + error = nfssvc(NFSSVC_IDNAME, &nid); + if (error) { + info.retval = error; + syslog(LOG_ERR, "Can't add group %s\n", + grp->gr_name); + } else if (verbose) { + syslog(LOG_ERR,"Added gid=%d name=%s\n", + nid.nid_gid, nid.nid_name); + } + if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, + (caddr_t)&info)) + syslog(LOG_ERR, "Can't send reply"); + return; + case RPCNFSUSERD_GETUSER: + if (!svc_getargs(transp, (xdrproc_t)xdr_getname, + (caddr_t)&info)) { + svcerr_decode(transp); + return; + } + pwd = getpwnam(info.name); + info.retval = 0; + if (pwd != NULL) { + nid.nid_usertimeout = defusertimeout; + nid.nid_uid = pwd->pw_uid; + nid.nid_name = pwd->pw_name; + } else { + nid.nid_usertimeout = 5; + nid.nid_uid = defaultuid; + nid.nid_name = info.name; + } + nid.nid_namelen = strlen(nid.nid_name); + nid.nid_flag = NFSID_ADDUSERNAME; + error = nfssvc(NFSSVC_IDNAME, &nid); + if (error) { + info.retval = error; + syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name); + } else if (verbose) { + syslog(LOG_ERR,"Added uid=%d name=%s\n", + nid.nid_uid, nid.nid_name); + } + if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, + (caddr_t)&info)) + syslog(LOG_ERR, "Can't send reply"); + return; + case RPCNFSUSERD_GETGROUP: + if (!svc_getargs(transp, (xdrproc_t)xdr_getname, + (caddr_t)&info)) { + svcerr_decode(transp); + return; + } + grp = getgrnam(info.name); + info.retval = 0; + if (grp != NULL) { + nid.nid_usertimeout = defusertimeout; + nid.nid_gid = grp->gr_gid; + nid.nid_name = grp->gr_name; + } else { + nid.nid_usertimeout = 5; + nid.nid_gid = defaultgid; + nid.nid_name = info.name; + } + nid.nid_namelen = strlen(nid.nid_name); + nid.nid_flag = NFSID_ADDGROUPNAME; + error = nfssvc(NFSSVC_IDNAME, &nid); + if (error) { + info.retval = error; + syslog(LOG_ERR, "Can't add group %s\n", + grp->gr_name); + } else if (verbose) { + syslog(LOG_ERR,"Added gid=%d name=%s\n", + nid.nid_gid, nid.nid_name); + } + if (!svc_sendreply(transp, (xdrproc_t)xdr_retval, + (caddr_t)&info)) + syslog(LOG_ERR, "Can't send reply"); + return; + default: + svcerr_noproc(transp); + return; + }; +} + +/* + * Xdr routine to get an id number + */ +bool_t +xdr_getid(XDR *xdrsp, caddr_t cp) +{ + struct info *ifp = (struct info *)cp; + + return (xdr_long(xdrsp, &ifp->id)); +} + +/* + * Xdr routine to get a user name + */ +bool_t +xdr_getname(XDR *xdrsp, caddr_t cp) +{ + struct info *ifp = (struct info *)cp; + long len; + + if (!xdr_long(xdrsp, &len)) + return (0); + if (len > MAXNAME) + return (0); + if (!xdr_opaque(xdrsp, ifp->name, len)) + return (0); + ifp->name[len] = '\0'; + return (1); +} + +/* + * Xdr routine to return the value. + */ +bool_t +xdr_retval(XDR *xdrsp, caddr_t cp) +{ + struct info *ifp = (struct info *)cp; + long val; + + val = ifp->retval; + return (xdr_long(xdrsp, &val)); +} + +/* + * cleanup_term() called via SIGUSR1. + */ +void +cleanup_term(int signo) +{ + int i, cnt; + + if (im_a_slave) + exit(0); + + /* + * Ok, so I'm the master. + * As the Governor of California might say, "Terminate them". + */ + cnt = 0; + for (i = 0; i < nfsuserdcnt; i++) { + if (slaves[i] != (pid_t)-1) { + cnt++; + kill(slaves[i], SIGUSR1); + } + } + + /* + * and wait for them to die + */ + for (i = 0; i < cnt; i++) + wait3(NULL, 0, NULL); + + /* + * Finally, get rid of the socket + */ + if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) { + syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n"); + exit(1); + } + exit(0); +} + +void +usage(void) +{ + + errx(1, + "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-domain domain_name] [n]"); +} -- cgit v1.1