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)
This commit is contained in:
parent
4147dd02cd
commit
03914b0bb2
@ -110,7 +110,11 @@ SUBDIR= ${_ac} \
|
||||
${_ndiscvt} \
|
||||
${_ndp} \
|
||||
newsyslog \
|
||||
nfscbd \
|
||||
nfsd \
|
||||
nfsdumpstate \
|
||||
nfsrevoke \
|
||||
nfsuserd \
|
||||
${_ngctl} \
|
||||
${_nghook} \
|
||||
nologin \
|
||||
|
6
usr.sbin/nfscbd/Makefile
Normal file
6
usr.sbin/nfscbd/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= nfscbd
|
||||
MAN= nfscbd.8
|
||||
|
||||
.include <bsd.prog.mk>
|
87
usr.sbin/nfscbd/nfscbd.8
Normal file
87
usr.sbin/nfscbd/nfscbd.8
Normal file
@ -0,0 +1,87 @@
|
||||
.\" 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 NFSCBD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm nfscbd
|
||||
.Tn NFSv4
|
||||
client side callback daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm nfscbd
|
||||
.Op Fl p Ar port_number
|
||||
.Op Fl P Ar client_principal
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
runs on a client using
|
||||
.Tn NFSv4
|
||||
to handle callback requests from the NFSv4 server.
|
||||
If no
|
||||
.Nm
|
||||
is running, NFSv4 mounts will still work, but the server will never issue
|
||||
Open Delegations to the client.
|
||||
.Pp
|
||||
One callback server and one master server
|
||||
are always started.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl p Ar port_number
|
||||
Specifies what port# the callback server should use.
|
||||
.It Fl P Ar client_principal
|
||||
Specifies the host based principal name to be used as the target for
|
||||
callbacks over RPCSEC_GSS. For KerberosV, it must be in the client's
|
||||
default keytab file.
|
||||
This client_principal should be the same one specified by the
|
||||
.Cm gssname
|
||||
argument being used by nfsv4 mounts.
|
||||
If you do not specify this argument, callbacks will still work over AUTH_SYS,
|
||||
which is what many extant servers use even for RPCSEC_GSS mounts, as of 2009.
|
||||
.El
|
||||
.Pp
|
||||
For example,
|
||||
.Dq Li "nfscbd -p 7654 -P root"
|
||||
starts the daemon to handle callbacks on port# 7654 and is using the host based
|
||||
principal root@<client-host>.<dns-domain> as the callback target.
|
||||
.Pp
|
||||
.Nm
|
||||
listens for service requests at the port
|
||||
defined by NFSV4_CBPORT in /usr/include/fs/nfs/nfs.h, unless
|
||||
.Fl p
|
||||
has been specified.
|
||||
For more information on what callbacks and Open Delegations do, see
|
||||
.%T "Network File System (NFS) Version 4 Protocol" ,
|
||||
RFC3530 .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility exits 0 on success or >0 if an error occurred.
|
||||
.Sh SEE ALSO
|
||||
.Xr nfsv4 4 ,
|
||||
.Xr mount_nfs 8
|
||||
.Sh HISTORY
|
||||
First introduced with the experimental nfs client for NFSv4 support in 2009.
|
380
usr.sbin/nfscbd/nfscbd.c
Normal file
380
usr.sbin/nfscbd/nfscbd.c
Normal file
@ -0,0 +1,380 @@
|
||||
/*-
|
||||
* 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <nfs/nfssvc.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
|
||||
#include <fs/nfs/nfsproto.h>
|
||||
#include <fs/nfs/nfskpiport.h>
|
||||
#include <fs/nfs/nfs.h>
|
||||
#include <fs/nfs/rpcv2.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Global defs */
|
||||
#ifdef DEBUG
|
||||
#define syslog(e, s) fprintf(stderr,(s))
|
||||
int debug = 1;
|
||||
#else
|
||||
int debug = 0;
|
||||
#endif
|
||||
|
||||
pid_t children;
|
||||
|
||||
void nonfs(int);
|
||||
void reapchild(int);
|
||||
void usage(void);
|
||||
void cleanup(int);
|
||||
void child_cleanup(int);
|
||||
void nfscbd_exit(int);
|
||||
void killchildren(void);
|
||||
|
||||
/*
|
||||
* Nfs callback server daemon.
|
||||
*
|
||||
* 1 - do file descriptor and signal cleanup
|
||||
* 2 - fork the nfscbd(s)
|
||||
* 4 - create callback server socket(s)
|
||||
* 5 - set up server socket for rpc
|
||||
*
|
||||
* For connectionless protocols, just pass the socket into the kernel via.
|
||||
* nfssvc().
|
||||
* For connection based sockets, loop doing accepts. When you get a new
|
||||
* socket from accept, pass the msgsock into the kernel via. nfssvc().
|
||||
*/
|
||||
int
|
||||
main(int argc, char *argv[], char **envp)
|
||||
{
|
||||
struct group *grp;
|
||||
struct nfscbd_args nfscbdargs;
|
||||
struct nfsd_nfscbd_args nfscbdargs2;
|
||||
struct passwd *pwd;
|
||||
struct ucred *cr;
|
||||
struct sockaddr_in inetaddr, inetpeer;
|
||||
struct timeval ktv;
|
||||
fd_set ready, sockbits;
|
||||
int ch, connect_type_cnt, i, len, maxsock, msgsock, error;
|
||||
int nfssvc_flag, on, sock, tcpsock, ret, mustfreeai = 0;
|
||||
char *cp, **cpp, princname[128];
|
||||
char myname[MAXHOSTNAMELEN], *myfqdnname = NULL;
|
||||
struct addrinfo *aip, hints;
|
||||
pid_t pid;
|
||||
sigset_t signew;
|
||||
short myport = NFSV4_CBPORT;
|
||||
|
||||
if (modfind("nfscl") < 0) {
|
||||
/* Not present in kernel, try loading it */
|
||||
if (kldload("nfscl") < 0 ||
|
||||
modfind("nfscl") < 0)
|
||||
errx(1, "nfscl is not available");
|
||||
}
|
||||
/*
|
||||
* First, get our fully qualified host name, if possible.
|
||||
*/
|
||||
if (gethostname(myname, MAXHOSTNAMELEN) >= 0) {
|
||||
cp = strchr(myname, '.');
|
||||
if (cp != NULL && *(cp + 1) != '\0') {
|
||||
cp = myname;
|
||||
} else {
|
||||
/*
|
||||
* No domain on myname, so try looking it up.
|
||||
*/
|
||||
cp = NULL;
|
||||
memset((void *)&hints, 0, sizeof (hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
error = getaddrinfo(myname, NULL, &hints, &aip);
|
||||
if (error == 0) {
|
||||
if (aip->ai_canonname != NULL &&
|
||||
(cp = strchr(aip->ai_canonname, '.')) != NULL
|
||||
&& *(cp + 1) != '\0') {
|
||||
cp = aip->ai_canonname;
|
||||
mustfreeai = 1;
|
||||
} else {
|
||||
freeaddrinfo(aip);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cp == NULL)
|
||||
warnx("Can't get fully qualified host name");
|
||||
myfqdnname = cp;
|
||||
}
|
||||
|
||||
princname[0] = '\0';
|
||||
#define GETOPT "p:P:"
|
||||
#define USAGE "[ -p port_num ] [ -P client_principal ]"
|
||||
while ((ch = getopt(argc, argv, GETOPT)) != -1)
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
myport = atoi(optarg);
|
||||
if (myport < 1) {
|
||||
warnx("port# non-positive, reset to %d",
|
||||
NFSV4_CBPORT);
|
||||
myport = NFSV4_CBPORT;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
cp = optarg;
|
||||
if (cp != NULL && strlen(cp) > 0 &&
|
||||
strlen(cp) < sizeof (princname)) {
|
||||
if (strchr(cp, '@') == NULL &&
|
||||
myfqdnname != NULL)
|
||||
snprintf(princname, sizeof (princname),
|
||||
"%s@%s", cp, myfqdnname);
|
||||
else
|
||||
strlcpy(princname, cp,
|
||||
sizeof (princname));
|
||||
} else {
|
||||
warnx("client princ invalid. ignored\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case '?':
|
||||
usage();
|
||||
};
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc > 0)
|
||||
usage();
|
||||
|
||||
if (mustfreeai)
|
||||
freeaddrinfo(aip);
|
||||
nfscbdargs2.principal = (const char *)princname;
|
||||
if (debug == 0) {
|
||||
daemon(0, 0);
|
||||
(void)signal(SIGTERM, SIG_IGN);
|
||||
(void)signal(SIGHUP, SIG_IGN);
|
||||
(void)signal(SIGINT, SIG_IGN);
|
||||
(void)signal(SIGQUIT, SIG_IGN);
|
||||
}
|
||||
(void)signal(SIGSYS, nonfs);
|
||||
(void)signal(SIGCHLD, reapchild);
|
||||
|
||||
openlog("nfscbd:", LOG_PID, LOG_DAEMON);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
syslog(LOG_ERR, "fork: %m");
|
||||
nfscbd_exit(1);
|
||||
} else if (pid > 0) {
|
||||
children = pid;
|
||||
} else {
|
||||
(void)signal(SIGUSR1, child_cleanup);
|
||||
setproctitle("server");
|
||||
nfssvc_flag = NFSSVC_NFSCBD;
|
||||
if (nfssvc(nfssvc_flag, &nfscbdargs2) < 0) {
|
||||
syslog(LOG_ERR, "nfssvc: %m");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
(void)signal(SIGUSR1, cleanup);
|
||||
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
syslog(LOG_ERR, "can't create udp socket");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
memset(&inetaddr, 0, sizeof inetaddr);
|
||||
inetaddr.sin_family = AF_INET;
|
||||
inetaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
inetaddr.sin_port = htons(myport);
|
||||
inetaddr.sin_len = sizeof(inetaddr);
|
||||
ret = bind(sock, (struct sockaddr *)&inetaddr, sizeof(inetaddr));
|
||||
/* If bind() fails, this is a restart, so just skip UDP. */
|
||||
if (ret == 0) {
|
||||
len = sizeof(inetaddr);
|
||||
if (getsockname(sock, (struct sockaddr *)&inetaddr, &len) < 0){
|
||||
syslog(LOG_ERR, "can't get bound addr");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
nfscbdargs.port = ntohs(inetaddr.sin_port);
|
||||
if (nfscbdargs.port != myport) {
|
||||
syslog(LOG_ERR, "BAD PORT#");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
nfscbdargs.sock = sock;
|
||||
nfscbdargs.name = NULL;
|
||||
nfscbdargs.namelen = 0;
|
||||
if (nfssvc(NFSSVC_CBADDSOCK, &nfscbdargs) < 0) {
|
||||
syslog(LOG_ERR, "can't Add UDP socket");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
}
|
||||
(void)close(sock);
|
||||
|
||||
/* Now set up the master server socket waiting for tcp connections. */
|
||||
on = 1;
|
||||
FD_ZERO(&sockbits);
|
||||
connect_type_cnt = 0;
|
||||
if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
syslog(LOG_ERR, "can't create tcp socket");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
if (setsockopt(tcpsock,
|
||||
SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
|
||||
syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
|
||||
/* sin_port is already set */
|
||||
inetaddr.sin_family = AF_INET;
|
||||
inetaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
inetaddr.sin_port = htons(myport);
|
||||
inetaddr.sin_len = sizeof(inetaddr);
|
||||
if (bind(tcpsock,
|
||||
(struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
|
||||
syslog(LOG_ERR, "can't bind tcp addr");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
if (listen(tcpsock, 5) < 0) {
|
||||
syslog(LOG_ERR, "listen failed");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
FD_SET(tcpsock, &sockbits);
|
||||
maxsock = tcpsock;
|
||||
connect_type_cnt++;
|
||||
|
||||
setproctitle("master");
|
||||
|
||||
/*
|
||||
* Loop forever accepting connections and passing the sockets
|
||||
* into the kernel for the mounts.
|
||||
*/
|
||||
for (;;) {
|
||||
ready = sockbits;
|
||||
if (connect_type_cnt > 1) {
|
||||
if (select(maxsock + 1,
|
||||
&ready, NULL, NULL, NULL) < 1) {
|
||||
syslog(LOG_ERR, "select failed: %m");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(tcpsock, &ready)) {
|
||||
len = sizeof(inetpeer);
|
||||
if ((msgsock = accept(tcpsock,
|
||||
(struct sockaddr *)&inetpeer, &len)) < 0) {
|
||||
syslog(LOG_ERR, "accept failed: %m");
|
||||
nfscbd_exit(1);
|
||||
}
|
||||
memset(inetpeer.sin_zero, 0,
|
||||
sizeof (inetpeer.sin_zero));
|
||||
if (setsockopt(msgsock, SOL_SOCKET,
|
||||
SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
|
||||
syslog(LOG_ERR,
|
||||
"setsockopt SO_KEEPALIVE: %m");
|
||||
nfscbdargs.sock = msgsock;
|
||||
nfscbdargs.name = (caddr_t)&inetpeer;
|
||||
nfscbdargs.namelen = sizeof(inetpeer);
|
||||
nfssvc(NFSSVC_CBADDSOCK, &nfscbdargs);
|
||||
(void)close(msgsock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
errx(1, "usage: nfscbd %s", USAGE);
|
||||
}
|
||||
|
||||
void
|
||||
nonfs(int signo)
|
||||
{
|
||||
syslog(LOG_ERR, "missing system call: NFS not available");
|
||||
}
|
||||
|
||||
void
|
||||
reapchild(int signo)
|
||||
{
|
||||
pid_t pid;
|
||||
int i;
|
||||
|
||||
while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) {
|
||||
if (pid == children)
|
||||
children = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
killchildren(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (children > 0)
|
||||
kill(children, SIGKILL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup master after SIGUSR1.
|
||||
*/
|
||||
void
|
||||
cleanup(int signo)
|
||||
{
|
||||
nfscbd_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup child after SIGUSR1.
|
||||
*/
|
||||
void
|
||||
child_cleanup(int signo)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
nfscbd_exit(int status)
|
||||
{
|
||||
killchildren();
|
||||
exit(status);
|
||||
}
|
6
usr.sbin/nfsdumpstate/Makefile
Normal file
6
usr.sbin/nfsdumpstate/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= nfsdumpstate
|
||||
MAN= nfsdumpstate.8
|
||||
|
||||
.include <bsd.prog.mk>
|
71
usr.sbin/nfsdumpstate/nfsdumpstate.8
Normal file
71
usr.sbin/nfsdumpstate/nfsdumpstate.8
Normal file
@ -0,0 +1,71 @@
|
||||
.\" 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 NFSDUMPSTATE 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm nfsdumpstate
|
||||
.Nd display
|
||||
.Tn NFSv4
|
||||
open/lock state
|
||||
.Sh SYNOPSIS
|
||||
.Nm nfsdumpstate
|
||||
.Op Fl o
|
||||
.Op Fl l Ar filename
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
displays open/lock state for the
|
||||
.Tn NFSv4
|
||||
client and server in the experimental nfs subsystem.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl o
|
||||
Displays a summary of Clients for NFSv4. Each line lists a Client with
|
||||
the ClientID being the last field of the line.
|
||||
.sp
|
||||
.nf
|
||||
The following are the client flag values displayed:
|
||||
NC - Needs Confirmation
|
||||
CB - Callbacks are enabled
|
||||
GSS - Using RPCSEC_GSS
|
||||
REV - Administratively Revoked, via nfsrevoke(8)
|
||||
.fi
|
||||
.sp
|
||||
.It Fl l Ar filename
|
||||
Displays a list of all NFSv4 Opens and Locks on the file specified by
|
||||
the
|
||||
.Ar filename .
|
||||
The ClientID is the last field of each line.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr nfsv4 4 ,
|
||||
.Xr nfsrevoke 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility was introduced with the NFSv4 experimental subsystem in 2009.
|
280
usr.sbin/nfsdumpstate/nfsdumpstate.c
Normal file
280
usr.sbin/nfsdumpstate/nfsdumpstate.c
Normal file
@ -0,0 +1,280 @@
|
||||
/*-
|
||||
* 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <nfs/nfssvc.h>
|
||||
|
||||
#include <fs/nfs/rpcv2.h>
|
||||
#include <fs/nfs/nfsproto.h>
|
||||
#include <fs/nfs/nfskpiport.h>
|
||||
#include <fs/nfs/nfs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DUMPSIZE 10000
|
||||
|
||||
static void dump_lockstate(char *);
|
||||
static void dump_openstate(void);
|
||||
static void usage(void);
|
||||
static char *open_flags(uint32_t);
|
||||
static char *deleg_flags(uint32_t);
|
||||
static char *lock_flags(uint32_t);
|
||||
static char *client_flags(uint32_t);
|
||||
|
||||
static struct nfsd_dumpclients dp[DUMPSIZE];
|
||||
static struct nfsd_dumplocks lp[DUMPSIZE];
|
||||
static char flag_string[20];
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ch, openstate;
|
||||
char *lockfile;
|
||||
|
||||
if (modfind("nfsd") < 0)
|
||||
errx(1, "nfsd not loaded - self terminating");
|
||||
openstate = 0;
|
||||
lockfile = NULL;
|
||||
while ((ch = getopt(argc, argv, "ol")) != -1)
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
openstate = 1;
|
||||
break;
|
||||
case 'l':
|
||||
lockfile = optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (openstate == 0 && lockfile == NULL)
|
||||
openstate = 1;
|
||||
else if (openstate != 0 && lockfile != NULL)
|
||||
errx(1, "-o and -l cannot both be specified");
|
||||
|
||||
/*
|
||||
* For -o, dump all open/lock state.
|
||||
* For -l, dump lock state for that file.
|
||||
*/
|
||||
if (openstate != 0)
|
||||
dump_openstate();
|
||||
else
|
||||
dump_lockstate(lockfile);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
errx(1, "usage: nfsdumpstate [-o] [-l]");
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump all open/lock state.
|
||||
*/
|
||||
static void
|
||||
dump_openstate(void)
|
||||
{
|
||||
struct nfsd_dumplist dumplist;
|
||||
int cnt, i;
|
||||
|
||||
dumplist.ndl_size = DUMPSIZE;
|
||||
dumplist.ndl_list = (void *)dp;
|
||||
if (nfssvc(NFSSVC_DUMPCLIENTS, &dumplist) < 0)
|
||||
errx(1, "Can't perform dump clients syscall");
|
||||
|
||||
printf("%-13s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %-15s %s\n",
|
||||
"Flags", "OpenOwner", "Open", "LockOwner",
|
||||
"Lock", "Deleg", "OldDeleg", "Clientaddr", "ClientID");
|
||||
/*
|
||||
* Loop through results, printing them out.
|
||||
*/
|
||||
cnt = 0;
|
||||
while (dp[cnt].ndcl_clid.nclid_idlen > 0 && cnt < DUMPSIZE) {
|
||||
printf("%-13s ", client_flags(dp[cnt].ndcl_flags));
|
||||
printf("%9d %9d %9d %9d %9d %9d ",
|
||||
dp[cnt].ndcl_nopenowners,
|
||||
dp[cnt].ndcl_nopens,
|
||||
dp[cnt].ndcl_nlockowners,
|
||||
dp[cnt].ndcl_nlocks,
|
||||
dp[cnt].ndcl_ndelegs,
|
||||
dp[cnt].ndcl_nolddelegs);
|
||||
if (dp[cnt].ndcl_addrfam == AF_INET)
|
||||
printf("%-15s ",
|
||||
inet_ntoa(dp[cnt].ndcl_cbaddr.sin_addr));
|
||||
for (i = 0; i < dp[cnt].ndcl_clid.nclid_idlen; i++)
|
||||
printf("%02x", dp[cnt].ndcl_clid.nclid_id[i]);
|
||||
printf("\n");
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump the lock state for a file.
|
||||
*/
|
||||
static void
|
||||
dump_lockstate(char *fname)
|
||||
{
|
||||
struct nfsd_dumplocklist dumplocklist;
|
||||
int cnt, i;
|
||||
|
||||
dumplocklist.ndllck_size = DUMPSIZE;
|
||||
dumplocklist.ndllck_list = (void *)lp;
|
||||
dumplocklist.ndllck_fname = fname;
|
||||
if (nfssvc(NFSSVC_DUMPLOCKS, &dumplocklist) < 0)
|
||||
errx(1, "Can't dump locks for %s\n", fname);
|
||||
|
||||
printf("%-11s %-36s %-15s %s\n",
|
||||
"Open/Lock",
|
||||
" Stateid or Lock Range",
|
||||
"Clientaddr",
|
||||
"Owner and ClientID");
|
||||
/*
|
||||
* Loop through results, printing them out.
|
||||
*/
|
||||
cnt = 0;
|
||||
while (lp[cnt].ndlck_clid.nclid_idlen > 0 && cnt < DUMPSIZE) {
|
||||
if (lp[cnt].ndlck_flags & NFSLCK_OPEN)
|
||||
printf("%-11s %9d %08x %08x %08x ",
|
||||
open_flags(lp[cnt].ndlck_flags),
|
||||
lp[cnt].ndlck_stateid.seqid,
|
||||
lp[cnt].ndlck_stateid.other[0],
|
||||
lp[cnt].ndlck_stateid.other[1],
|
||||
lp[cnt].ndlck_stateid.other[2]);
|
||||
else if (lp[cnt].ndlck_flags & (NFSLCK_DELEGREAD |
|
||||
NFSLCK_DELEGWRITE))
|
||||
printf("%-11s %9d %08x %08x %08x ",
|
||||
deleg_flags(lp[cnt].ndlck_flags),
|
||||
lp[cnt].ndlck_stateid.seqid,
|
||||
lp[cnt].ndlck_stateid.other[0],
|
||||
lp[cnt].ndlck_stateid.other[1],
|
||||
lp[cnt].ndlck_stateid.other[2]);
|
||||
else
|
||||
printf("%-11s %17lld %17lld ",
|
||||
lock_flags(lp[cnt].ndlck_flags),
|
||||
lp[cnt].ndlck_first,
|
||||
lp[cnt].ndlck_end);
|
||||
if (lp[cnt].ndlck_addrfam == AF_INET)
|
||||
printf("%-15s ",
|
||||
inet_ntoa(lp[cnt].ndlck_cbaddr.sin_addr));
|
||||
else
|
||||
printf("%-15s ", " ");
|
||||
for (i = 0; i < lp[cnt].ndlck_owner.nclid_idlen; i++)
|
||||
printf("%02x", lp[cnt].ndlck_owner.nclid_id[i]);
|
||||
printf(" ");
|
||||
for (i = 0; i < lp[cnt].ndlck_clid.nclid_idlen; i++)
|
||||
printf("%02x", lp[cnt].ndlck_clid.nclid_id[i]);
|
||||
printf("\n");
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the Open/Lock flag bits and create a string to be printed.
|
||||
*/
|
||||
static char *
|
||||
open_flags(uint32_t flags)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
strlcpy(flag_string, "Open ", sizeof (flag_string));
|
||||
i = 5;
|
||||
if (flags & NFSLCK_READACCESS)
|
||||
flag_string[i++] = 'R';
|
||||
if (flags & NFSLCK_WRITEACCESS)
|
||||
flag_string[i++] = 'W';
|
||||
flag_string[i++] = ' ';
|
||||
flag_string[i++] = 'D';
|
||||
flag_string[i] = 'N';
|
||||
j = i;
|
||||
if (flags & NFSLCK_READDENY)
|
||||
flag_string[i++] = 'R';
|
||||
if (flags & NFSLCK_WRITEDENY)
|
||||
flag_string[i++] = 'W';
|
||||
if (i == j)
|
||||
i++;
|
||||
flag_string[i] = '\0';
|
||||
return (flag_string);
|
||||
}
|
||||
|
||||
static char *
|
||||
deleg_flags(uint32_t flags)
|
||||
{
|
||||
|
||||
if (flags & NFSLCK_DELEGREAD)
|
||||
strlcpy(flag_string, "Deleg R", sizeof (flag_string));
|
||||
else
|
||||
strlcpy(flag_string, "Deleg W", sizeof (flag_string));
|
||||
return (flag_string);
|
||||
}
|
||||
|
||||
static char *
|
||||
lock_flags(uint32_t flags)
|
||||
{
|
||||
|
||||
if (flags & NFSLCK_READ)
|
||||
strlcpy(flag_string, "Lock R", sizeof (flag_string));
|
||||
else
|
||||
strlcpy(flag_string, "Lock W", sizeof (flag_string));
|
||||
return (flag_string);
|
||||
}
|
||||
|
||||
static char *
|
||||
client_flags(uint32_t flags)
|
||||
{
|
||||
|
||||
flag_string[0] = '\0';
|
||||
if (flags & LCL_NEEDSCONFIRM)
|
||||
strlcat(flag_string, "NC ", sizeof (flag_string));
|
||||
if (flags & LCL_CALLBACKSON)
|
||||
strlcat(flag_string, "CB ", sizeof (flag_string));
|
||||
if (flags & LCL_GSS)
|
||||
strlcat(flag_string, "GSS ", sizeof (flag_string));
|
||||
if (flags & LCL_ADMINREVOKED)
|
||||
strlcat(flag_string, "REV", sizeof (flag_string));
|
||||
return (flag_string);
|
||||
}
|
6
usr.sbin/nfsrevoke/Makefile
Normal file
6
usr.sbin/nfsrevoke/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= nfsrevoke
|
||||
MAN= nfsrevoke.8
|
||||
|
||||
.include <bsd.prog.mk>
|
64
usr.sbin/nfsrevoke/nfsrevoke.8
Normal file
64
usr.sbin/nfsrevoke/nfsrevoke.8
Normal file
@ -0,0 +1,64 @@
|
||||
.\" 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 NFSREVOKE 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm nfsrevoke
|
||||
.Nd revoke
|
||||
.Tn NFS
|
||||
V4 client
|
||||
.Sh SYNOPSIS
|
||||
.Nm nfsrevoke
|
||||
.Ar ClientId
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
This command is used by a system administrator to revoke a client's access
|
||||
to the NFS Version 4 server. All Open/Lock state held by the client will
|
||||
be released.
|
||||
After revocation, the client will no longer be able to use state on the server
|
||||
until it does a fresh SetClientID/SetClientIDConfirm operations sequence.
|
||||
THIS SHOULD BE DONE AS A LAST RESORT ONLY, when clients are holding state
|
||||
that must be released on the server.
|
||||
.Pp
|
||||
The
|
||||
.Ar ClientId
|
||||
argument is a hexadecimal string, which is the last field
|
||||
of the
|
||||
.Xr nfsdumpstate 8
|
||||
command's
|
||||
.Fl o
|
||||
and
|
||||
.Fl l
|
||||
options output.
|
||||
.Sh SEE ALSO
|
||||
.Xr nfsv4 4 ,
|
||||
.Xr nfsdumpstate 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command was introduced as a part of the experimental nfs server subsystem.
|
124
usr.sbin/nfsrevoke/nfsrevoke.c
Normal file
124
usr.sbin/nfsrevoke/nfsrevoke.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*-
|
||||
* 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <nfs/nfssvc.h>
|
||||
|
||||
#include <fs/nfs/rpcv2.h>
|
||||
#include <fs/nfs/nfsproto.h>
|
||||
#include <fs/nfs/nfskpiport.h>
|
||||
#include <fs/nfs/nfs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void usage(void);
|
||||
extern int errno;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *cp;
|
||||
u_char val;
|
||||
int cnt, even;
|
||||
struct nfsd_clid revoke;
|
||||
|
||||
if (modfind("nfsd") < 0)
|
||||
errx(1, "nfsd not loaded - self terminating");
|
||||
if (argc != 2)
|
||||
usage();
|
||||
cnt = 0;
|
||||
cp = argv[1];
|
||||
if (strlen(cp) % 2)
|
||||
even = 0;
|
||||
else
|
||||
even = 1;
|
||||
val = 0;
|
||||
while (*cp) {
|
||||
if (*cp >= '0' & *cp <= '9')
|
||||
val += (u_char)(*cp - '0');
|
||||
else if (*cp >= 'A' && *cp <= 'F')
|
||||
val += ((u_char)(*cp - 'A')) + 0xa;
|
||||
else if (*cp >= 'a' && *cp <= 'f')
|
||||
val += ((u_char)(*cp - 'a')) + 0xa;
|
||||
else
|
||||
errx(1, "Non hexadecimal digit in %s", argv[1]);
|
||||
if (even) {
|
||||
val <<= 4;
|
||||
even = 0;
|
||||
} else {
|
||||
revoke.nclid_id[cnt++] = val;
|
||||
if (cnt > NFSV4_OPAQUELIMIT)
|
||||
errx(1, "Clientid %s, loo long", argv[1]);
|
||||
val = 0;
|
||||
even = 1;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the revocation system call.
|
||||
*/
|
||||
revoke.nclid_idlen = cnt;
|
||||
#ifdef DEBUG
|
||||
printf("Idlen=%d\n", revoke.nclid_idlen);
|
||||
for (cnt = 0; cnt < revoke.nclid_idlen; cnt++)
|
||||
printf("%02x", revoke.nclid_id[cnt]);
|
||||
printf("\n");
|
||||
#else
|
||||
if (nfssvc(NFSSVC_ADMINREVOKE, &revoke) < 0)
|
||||
err(1, "Admin revoke failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
errx(1, "Usage: nfsrevoke <ClientID>");
|
||||
}
|
6
usr.sbin/nfsuserd/Makefile
Normal file
6
usr.sbin/nfsuserd/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= nfsuserd
|
||||
MAN= nfsuserd.8
|
||||
|
||||
.include <bsd.prog.mk>
|
114
usr.sbin/nfsuserd/nfsuserd.8
Normal file
114
usr.sbin/nfsuserd/nfsuserd.8
Normal file
@ -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.
|
665
usr.sbin/nfsuserd/nfsuserd.c
Normal file
665
usr.sbin/nfsuserd/nfsuserd.c
Normal file
@ -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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <nfs/nfssvc.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
|
||||
#include <fs/nfs/rpcv2.h>
|
||||
#include <fs/nfs/nfsproto.h>
|
||||
#include <fs/nfs/nfskpiport.h>
|
||||
#include <fs/nfs/nfs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <grp.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* 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]");
|
||||
}
|
Loading…
Reference in New Issue
Block a user