summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2001-03-19 12:50:13 +0000
committeralfred <alfred@FreeBSD.org>2001-03-19 12:50:13 +0000
commitf67e4a8fc7fc95c74bd6c09d3453200de47faea5 (patch)
tree98b613188d263fdcef5f2d020e5e8c374db1f5b6 /sbin
parent6f24d923a7fa9d1679753d77cc982ec72c22a197 (diff)
downloadFreeBSD-src-f67e4a8fc7fc95c74bd6c09d3453200de47faea5.zip
FreeBSD-src-f67e4a8fc7fc95c74bd6c09d3453200de47faea5.tar.gz
Bring in a hybrid of SunSoft's transport-independent RPC (TI-RPC) and
associated changes that had to happen to make this possible as well as bugs fixed along the way. Bring in required TLI library routines to support this. Since we don't support TLI we've essentially copied what NetBSD has done, adding a thin layer to emulate direct the TLI calls into BSD socket calls. This is mostly from Sun's tirpc release that was made in 1994, however some fixes were backported from the 1999 release (supposedly only made available after this porting effort was underway). The submitter has agreed to continue on and bring us up to the 1999 release. Several key features are introduced with this update: Client calls are thread safe. (1999 code has server side thread safe) Updated, a more modern interface. Many userland updates were done to bring the code up to par with the recent RPC API. There is an update to the pthreads library, a function pthread_main_np() was added to emulate a function of Sun's threads library. While we're at it, bring in NetBSD's lockd, it's been far too long of a wait. New rpcbind(8) replaces portmap(8) (supporting communication over an authenticated Unix-domain socket, and by default only allowing set and unset requests over that channel). It's much more secure than the old portmapper. Umount(8), mountd(8), mount_nfs(8), nfsd(8) have also been upgraded to support TI-RPC and to support IPV6. Umount(8) is also fixed to unmount pathnames longer than 80 chars, which are currently truncated by the Kernel statfs structure. Submitted by: Martin Blapp <mb@imp.ch> Manpage review: ru Secure RPC implemented by: wpaul
Diffstat (limited to 'sbin')
-rw-r--r--sbin/mount_nfs/mount_nfs.c296
-rw-r--r--sbin/mountd/mountd.c876
-rw-r--r--sbin/nfsd/nfsd.824
-rw-r--r--sbin/nfsd/nfsd.c823
-rw-r--r--sbin/umount/umount.c195
5 files changed, 1450 insertions, 764 deletions
diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c
index 41873ca..c1d7466 100644
--- a/sbin/mount_nfs/mount_nfs.c
+++ b/sbin/mount_nfs/mount_nfs.c
@@ -50,6 +50,7 @@ static const char rcsid[] =
#include <sys/param.h>
#include <sys/mount.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syslog.h>
@@ -72,6 +73,7 @@ static const char rcsid[] =
#include <ctype.h>
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
@@ -193,7 +195,7 @@ NFSKERBKEYSCHED_T kerb_keysched;
#endif
int getnfsargs __P((char *, struct nfs_args *));
-void set_rpc_maxgrouplist __P((int));
+/* void set_rpc_maxgrouplist __P((int)); */
void usage __P((void)) __dead2;
int xdr_dir __P((XDR *, char *));
int xdr_fh __P((XDR *, struct nfhret *));
@@ -299,16 +301,16 @@ main(argc, argv)
case 'd':
nfsargsp->flags |= NFSMNT_DUMBTIMR;
break;
+#if 0 /* XXXX */
case 'g':
num = strtol(optarg, &p, 10);
if (*p || num <= 0)
errx(1, "illegal -g value -- %s", optarg);
-#ifdef __FreeBSD__
set_rpc_maxgrouplist(num);
-#endif
nfsargsp->maxgrouplist = num;
nfsargsp->flags |= NFSMNT_MAXGRPS;
break;
+#endif
case 'I':
num = strtol(optarg, &p, 10);
if (*p || num <= 0)
@@ -456,7 +458,6 @@ main(argc, argv)
/* resolve the mountpoint with realpath(3) */
(void)checkpath(name, mntpath);
-#ifdef __FreeBSD__
error = getvfsbyname("nfs", &vfc);
if (error && vfsisloadable("nfs")) {
if(vfsload("nfs"))
@@ -469,10 +470,6 @@ main(argc, argv)
if (mount(vfc.vfc_name, mntpath, mntflags, nfsargsp))
err(1, "%s", mntpath);
-#else
- if (mount("nfs", mntpath, mntflags, nfsargsp))
- err(1, "%s", mntpath);
-#endif
if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
if ((opflags & ISBGRND) == 0) {
if ((i = fork())) {
@@ -577,75 +574,32 @@ main(argc, argv)
exit(0);
}
-/*
- * Return RPC_SUCCESS if server responds.
- */
-enum clnt_stat
-pingnfsserver(addr, version, sotype)
- struct sockaddr_in *addr;
- int version;
- int sotype;
-{
- struct sockaddr_in sin;
- int tport;
- CLIENT *clp;
- int so = RPC_ANYSOCK;
- enum clnt_stat stat;
- struct timeval pertry, try;
-
- sin = *addr;
-
- if ((tport = port_no ? port_no :
- pmap_getport(&sin, RPCPROG_NFS, version, nfsproto)) == 0) {
- return rpc_createerr.cf_stat;
- }
-
- sin.sin_port = htons(tport);
-
- pertry.tv_sec = 10;
- pertry.tv_usec = 0;
- if (sotype == SOCK_STREAM)
- clp = clnttcp_create(&sin, RPCPROG_NFS, version,
- &so, 0, 0);
- else
- clp = clntudp_create(&sin, RPCPROG_NFS, version,
- pertry, &so);
- if (clp == NULL)
- return rpc_createerr.cf_stat;
-
- try.tv_sec = 10;
- try.tv_usec = 0;
- stat = clnt_call(clp, NFSPROC_NULL,
- xdr_void, NULL, xdr_void, NULL, try);
-
- clnt_destroy(clp);
-
- return stat;
-}
-
int
getnfsargs(spec, nfsargsp)
char *spec;
struct nfs_args *nfsargsp;
{
- register CLIENT *clp;
- struct hostent *hp;
- static struct sockaddr_in saddr;
+ CLIENT *clp;
+ struct addrinfo hints, *ai_nfs, *ai;
+ int ecode;
+ char host[NI_MAXHOST], serv[NI_MAXSERV];
+ static struct netbuf nfs_nb;
+ static struct sockaddr_storage nfs_ss;
+ struct netconfig *nconf;
+ char *netid;
struct timeval pertry, try;
enum clnt_stat clnt_stat;
- int so = RPC_ANYSOCK, i, nfsvers, mntvers, orgcnt, speclen;
+ int so, i, nfsvers, mntvers, orgcnt, speclen;
char *hostp, *delimp;
#ifdef NFSKERB
char *cp;
#endif
- u_short tport;
size_t len;
static struct nfhret nfhret;
static char nam[MNAMELEN + 1];
- tport = 0;
-
- if ((delimp = strchr(spec, ':')) != NULL) {
+ so = i = 0;
+ if ((delimp = strrchr(spec, ':')) != NULL) {
hostp = spec;
spec = delimp + 1;
} else if ((delimp = strrchr(spec, '@')) != NULL) {
@@ -684,27 +638,29 @@ getnfsargs(spec, nfsargsp)
* Handle an internet host address and reverse resolve it if
* doing Kerberos.
*/
- if (isdigit(*hostp)) {
- if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
- warnx("bad net address %s", hostp);
- return (0);
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_socktype = nfsargsp->sotype;
+ if (getaddrinfo(hostp, "nfs", &hints, &ai_nfs) == 0) {
+ if ((nfsargsp->flags & NFSMNT_KERB)) {
+ hints.ai_flags = 0;
+ if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
+ sizeof host, serv, sizeof serv, 0) != 0) {
+ warnx("can't reverse resolve net address");
+ return (0);
+ }
+ hostp = host;
}
- } else if ((hp = gethostbyname(hostp)) != NULL)
- memmove(&saddr.sin_addr, hp->h_addr,
- MIN(hp->h_length, sizeof(saddr.sin_addr)));
- else {
- warnx("can't get net id for host");
- return (0);
- }
-#ifdef NFSKERB
- if ((nfsargsp->flags & NFSMNT_KERB)) {
- if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
- sizeof (u_long), AF_INET)) == (struct hostent *)0) {
- warnx("can't reverse resolve net address");
+ } else {
+ hints.ai_flags = 0;
+ if ((ecode = getaddrinfo(hostp, "nfs", &hints, &ai_nfs)) != 0) {
+ warnx("can't get net id for host/nfs: %s",
+ gai_strerror(ecode));
return (0);
}
- memmove(&saddr.sin_addr, hp->h_addr,
- MIN(hp->h_length, sizeof(saddr.sin_addr)));
+ }
+#ifdef NFSKERB
+ if (nfsargsp->flags & NFSMNT_KERB) {
strncpy(inst, hp->h_name, INST_SZ);
inst[INST_SZ - 1] = '\0';
if (cp = strchr(inst, '.'))
@@ -713,7 +669,7 @@ getnfsargs(spec, nfsargsp)
#endif /* NFSKERB */
orgcnt = retrycnt;
-tryagain:
+
if (mountmode == ANY || mountmode == V3) {
nfsvers = 3;
mntvers = 3;
@@ -724,103 +680,125 @@ tryagain:
nfsargsp->flags &= ~NFSMNT_NFSV3;
}
nfhret.stat = EACCES; /* Mark not yet successful */
- while (retrycnt > 0) {
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(PMAPPORT);
- if ((tport = port_no ? port_no :
- pmap_getport(&saddr, RPCPROG_NFS,
- nfsvers, nfsproto)) == 0) {
- if ((opflags & ISBGRND) == 0)
- clnt_pcreateerror("NFS Portmap");
+ ai = ai_nfs;
+ while (ai != NULL) {
+ /*
+ * XXX. Nead a generic (family, type, proto) -> nconf interface.
+ * __rpc_*2nconf exist, maybe they should be exported.
+ */
+ if (nfsargsp->sotype == SOCK_STREAM) {
+ if (ai->ai_family == AF_INET6)
+ netid = "tcp6";
+ else
+ netid = "tcp";
} else {
- /*
- * First ping the nfs server to see if it supports
- * the version of the protocol we want to use.
- */
- clnt_stat = pingnfsserver(&saddr, nfsvers,
- nfsargsp->sotype);
- if (clnt_stat == RPC_PROGVERSMISMATCH) {
- if (mountmode == ANY) {
- mountmode = V2;
- goto tryagain;
- } else {
- errx(1, "can't contact NFS server");
- }
- }
- saddr.sin_port = 0;
- pertry.tv_sec = 10;
- pertry.tv_usec = 0;
- if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM)
- clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers,
- &so, 0, 0);
+ if (ai->ai_family == AF_INET6)
+ netid = "udp6";
else
- clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers,
- pertry, &so);
- if (clp == NULL) {
+ netid = "udp";
+ }
+
+ nconf = getnetconfigent(netid);
+
+tryagain:
+ retrycnt = orgcnt;
+
+ while (retrycnt > 0) {
+ nfs_nb.buf = &nfs_ss;
+ nfs_nb.maxlen = sizeof nfs_ss;
+ if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf,
+ &nfs_nb, hostp)){
+ if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) {
+ nfhret.stat = rpc_createerr.cf_error.re_errno;
+ break;
+ }
+ if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO) {
+ nfhret.stat = EPROTONOSUPPORT;
+ break;
+ }
if ((opflags & ISBGRND) == 0)
- clnt_pcreateerror("Cannot MNT RPC");
+ clnt_pcreateerror(
+ "mount_nfs: rpcbind on server");
} else {
- clp->cl_auth = authunix_create_default();
- try.tv_sec = 10;
- try.tv_usec = 0;
- if (nfsargsp->flags & NFSMNT_KERB)
- nfhret.auth = RPCAUTH_KERB4;
- else
- nfhret.auth = RPCAUTH_UNIX;
- nfhret.vers = mntvers;
- clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
- xdr_dir, spec, xdr_fh, &nfhret, try);
- if (clnt_stat != RPC_SUCCESS) {
- if (clnt_stat == RPC_PROGVERSMISMATCH) {
- if (mountmode == ANY) {
- mountmode = V2;
- goto tryagain;
- } else {
- errx(1, "%s",
- clnt_sperror(clp, "MNT RPC"));
- }
- }
+ pertry.tv_sec = 10;
+ pertry.tv_usec = 0;
+ /*
+ * XXX relies on clnt_tcp_create to bind
+ * to a reserved socket.
+ */
+ clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers,
+ mnttcp_ok ? nconf : getnetconfigent("udp"));
+ if (clp == NULL) {
if ((opflags & ISBGRND) == 0)
- warnx("%s", clnt_sperror(clp,
- "bad MNT RPC"));
+ clnt_pcreateerror("Cannot MNT RPC");
} else {
- retrycnt = 0;
+ CLNT_CONTROL(clp, CLSET_RETRY_TIMEOUT,
+ (char *)&pertry);
+ clp->cl_auth = authsys_create_default();
+ try.tv_sec = 10;
+ try.tv_usec = 0;
+ if (nfsargsp->flags & NFSMNT_KERB)
+ nfhret.auth = RPCAUTH_KERB4;
+ else
+ nfhret.auth = RPCAUTH_UNIX;
+ nfhret.vers = mntvers;
+ clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
+ xdr_dir, spec, xdr_fh, &nfhret, try);
+ if (clnt_stat != RPC_SUCCESS) {
+ if (clnt_stat == RPC_PROGVERSMISMATCH) {
+ if (mountmode == ANY) {
+ mountmode = V2;
+ goto tryagain;
+ } else {
+ errx(1, "%s",
+ clnt_sperror(clp, "MNT RPC"));
+ }
+ }
+ if ((opflags & ISBGRND) == 0)
+ warnx("%s", clnt_sperror(clp,
+ "bad MNT RPC"));
+ } else {
+ retrycnt = 0;
+ }
+ auth_destroy(clp->cl_auth);
+ clnt_destroy(clp);
+ so = RPC_ANYSOCK;
}
- auth_destroy(clp->cl_auth);
- clnt_destroy(clp);
- so = RPC_ANYSOCK;
}
- }
- if (--retrycnt > 0) {
- if (opflags & BGRND) {
- warnx("Cannot immediately mount %s:%s, "
- "backgrounding", hostp, spec);
- opflags &= ~BGRND;
- if ((i = fork())) {
- if (i == -1)
- err(1, "nqnfs 2");
- exit(0);
+ if (--retrycnt > 0) {
+ if (opflags & BGRND) {
+ warnx("Cannot immediately mount %s:%s, "
+ "backgrounding", hostp, spec);
+ opflags &= ~BGRND;
+ if ((i = fork())) {
+ if (i == -1)
+ err(1, "nqnfs 2");
+ exit(0);
+ }
+ (void) setsid();
+ (void) close(STDIN_FILENO);
+ (void) close(STDOUT_FILENO);
+ (void) close(STDERR_FILENO);
+ (void) chdir("/");
+ opflags |= ISBGRND;
}
- (void) setsid();
- (void) close(STDIN_FILENO);
- (void) close(STDOUT_FILENO);
- (void) close(STDERR_FILENO);
- (void) chdir("/");
- opflags |= ISBGRND;
+ sleep(60);
}
- sleep(60);
}
+ if (nfhret.stat == 0)
+ break;
+ ai = ai->ai_next;
}
+ freeaddrinfo(ai_nfs);
if (nfhret.stat) {
if (opflags & ISBGRND)
exit(1);
warnx("can't access %s: %s", spec, strerror(nfhret.stat));
return (0);
}
- saddr.sin_port = htons(tport);
{
- nfsargsp->addr = (struct sockaddr *) &saddr;
- nfsargsp->addrlen = sizeof (saddr);
+ nfsargsp->addr = (struct sockaddr *) nfs_nb.buf;
+ nfsargsp->addrlen = nfs_nb.len;
}
nfsargsp->fh = nfhret.nfh;
nfsargsp->fhsize = nfhret.fhsize;
diff --git a/sbin/mountd/mountd.c b/sbin/mountd/mountd.c
index 2f46a9f..b527765 100644
--- a/sbin/mountd/mountd.c
+++ b/sbin/mountd/mountd.c
@@ -50,12 +50,15 @@ static const char rcsid[] =
#include <sys/param.h>
#include <sys/mount.h>
+#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/syslog.h>
#include <sys/sysctl.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#include <rpcsvc/mount.h>
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
@@ -83,6 +86,10 @@ static const char rcsid[] =
#include <stdarg.h>
#endif
+#ifndef MOUNTDLOCK
+#define MOUNTDLOCK "/var/run/mountd.lock"
+#endif
+
/*
* Structures for keeping the mount list and export list
*/
@@ -117,13 +124,13 @@ struct exportlist {
#define EX_LINKED 0x1
struct netmsk {
- u_int32_t nt_net;
+ struct sockaddr_storage nt_net;
u_int32_t nt_mask;
char *nt_name;
};
union grouptypes {
- struct hostent *gt_hostent;
+ struct addrinfo *gt_addrinfo;
struct netmsk gt_net;
};
@@ -157,8 +164,8 @@ void add_dlist __P((struct dirlist **, struct dirlist *,
void add_mlist __P((char *, char *));
int check_dirpath __P((char *));
int check_options __P((struct dirlist *));
-int chk_host __P((struct dirlist *, u_int32_t, int *, int *));
-void del_mlist __P((char *, char *));
+int chk_host __P((struct dirlist *, struct sockaddr *, int *, int *));
+int del_mlist __P((char *, char *, struct sockaddr *));
struct dirlist *dirp_search __P((struct dirlist *, char *));
int do_mount __P((struct exportlist *, struct grouplist *, int,
struct xucred *, char *, int, struct statfs *));
@@ -186,18 +193,25 @@ void nextfield __P((char **, char **));
void out_of_mem __P((void));
void parsecred __P((char *, struct xucred *));
int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
-int scan_tree __P((struct dirlist *, u_int32_t));
+int scan_tree __P((struct dirlist *, struct sockaddr *));
static void usage __P((void));
int xdr_dir __P((XDR *, char *));
int xdr_explist __P((XDR *, caddr_t));
int xdr_fhs __P((XDR *, caddr_t));
int xdr_mlist __P((XDR *, caddr_t));
+void terminate __P((int));
/* C library */
int getnetgrent();
void endnetgrent();
void setnetgrent();
+static int bitcmp __P((void *, void *, int));
+static int netpartcmp __P((struct sockaddr *, struct sockaddr *, int));
+static int sacmp __P((struct sockaddr *, struct sockaddr *));
+static int allones __P((struct sockaddr_storage *, int));
+static int countones __P((struct sockaddr *));
+
struct exportlist *exphead;
struct mountlist *mlhead;
struct grouplist *grphead;
@@ -213,7 +227,16 @@ int force_v2 = 0;
int resvport_only = 1;
int dir_only = 1;
int log = 0;
+
int opt_flags;
+static int have_v6 = 1;
+#ifdef NI_WITHSCOPEID
+static const int ninumeric = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+static const int ninumeric = NI_NUMERICHOST;
+#endif
+
+int mountdlockfd;
/* Bits for above */
#define OP_MAPROOT 0x01
#define OP_MAPALL 0x02
@@ -221,6 +244,7 @@ int opt_flags;
#define OP_MASK 0x08
#define OP_NET 0x10
#define OP_ALLDIRS 0x40
+#define OP_MASKLEN 0x200
#ifdef DEBUG
int debug = 1;
@@ -242,10 +266,26 @@ main(argc, argv)
int argc;
char **argv;
{
- SVCXPRT *udptransp, *tcptransp;
+ SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp;
+ struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf;
+ int udpsock, tcpsock, udp6sock, tcp6sock;
+ int xcreated = 0, s;
+ int one = 1;
int c, error, mib[3];
struct vfsconf vfc;
+ /* Check that another mountd isn't already running. */
+
+ if ((mountdlockfd = (open(MOUNTDLOCK, O_RDONLY|O_CREAT, 0444))) == -1)
+ err(1, "%s", MOUNTDLOCK);
+
+ if(flock(mountdlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
+ errx(1, "another rpc.mountd is already running. Aborting");
+ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0)
+ have_v6 = 0;
+ else
+ close(s);
error = getvfsbyname("nfs", &vfc);
if (error && vfsisloadable("nfs")) {
if(vfsload("nfs"))
@@ -301,12 +341,38 @@ main(argc, argv)
signal(SIGQUIT, SIG_IGN);
}
signal(SIGHUP, (void (*) __P((int))) get_exportlist);
+ signal(SIGTERM, terminate);
{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
if (pidfile != NULL) {
fprintf(pidfile, "%d\n", getpid());
fclose(pidfile);
}
}
+ rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL);
+ rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
+ udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ /*
+ * We're doing host-based access checks here, so don't allow
+ * v4-in-v6 to confuse things. The kernel will disable it
+ * by default on NFS sockets too.
+ */
+ if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6,
+ IPV6_BINDV6ONLY, &one, sizeof one) < 0){
+ syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket");
+ exit(1);
+ }
+ if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6,
+ IPV6_BINDV6ONLY, &one, sizeof one) < 0){
+ syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket");
+ exit(1);
+ }
+ udpconf = getnetconfigent("udp");
+ tcpconf = getnetconfigent("tcp");
+ udp6conf = getnetconfigent("udp6");
+ tcp6conf = getnetconfigent("tcp6");
if (!resvport_only) {
mib[0] = CTL_VFS;
mib[1] = vfc.vfc_typenum;
@@ -322,17 +388,90 @@ main(argc, argv)
syslog(LOG_ERR, "can't create socket");
exit(1);
}
- pmap_unset(RPCPROG_MNT, 1);
- pmap_unset(RPCPROG_MNT, 3);
- if (!force_v2)
- if (!svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) ||
- !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) {
- syslog(LOG_ERR, "can't register mount");
- exit(1);
- }
- if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) ||
- !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP)) {
- syslog(LOG_ERR, "can't register mount");
+ if (udpsock != -1 && udpconf != NULL) {
+ bindresvport(udpsock, NULL);
+ udptransp = svc_dg_create(udpsock, 0, 0);
+ if (udptransp != NULL) {
+ if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1,
+ mntsrv, udpconf))
+ syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service");
+ else
+ xcreated++;
+ if (!force_v2) {
+ if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3,
+ mntsrv, udpconf))
+ syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service");
+ else
+ xcreated++;
+ }
+ } else
+ syslog(LOG_WARNING, "can't create UDP services");
+
+ }
+ if (tcpsock != -1 && tcpconf != NULL) {
+ bindresvport(tcpsock, NULL);
+ listen(tcpsock, SOMAXCONN);
+ tcptransp = svc_vc_create(tcpsock, 0, 0);
+ if (tcptransp != NULL) {
+ if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1,
+ mntsrv, tcpconf))
+ syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service");
+ else
+ xcreated++;
+ if (!force_v2) {
+ if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3,
+ mntsrv, tcpconf))
+ syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service");
+ else
+ xcreated++;
+ }
+ } else
+ syslog(LOG_WARNING, "can't create TCP service");
+
+ }
+ if (udp6sock != -1 && udp6conf != NULL) {
+ bindresvport(udp6sock, NULL);
+ udp6transp = svc_dg_create(udp6sock, 0, 0);
+ if (udp6transp != NULL) {
+ if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1,
+ mntsrv, udp6conf))
+ syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service");
+ else
+ xcreated++;
+ if (!force_v2) {
+ if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3,
+ mntsrv, udp6conf))
+ syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service");
+ else
+ xcreated++;
+ }
+ } else
+ syslog(LOG_WARNING, "can't create UDP6 service");
+
+ }
+ if (tcp6sock != -1 && tcp6conf != NULL) {
+ bindresvport(tcp6sock, NULL);
+ listen(tcp6sock, SOMAXCONN);
+ tcp6transp = svc_vc_create(tcp6sock, 0, 0);
+ if (tcp6transp != NULL) {
+ if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1,
+ mntsrv, tcp6conf))
+ syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service");
+ else
+ xcreated++;
+ if (!force_v2) {
+ if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3,
+ mntsrv, tcp6conf))
+ syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service");
+ else
+ xcreated++;
+ }
+ } else
+ syslog(LOG_WARNING, "can't create TCP6 service");
+
+ }
+ if (xcreated == 0) {
+ syslog(LOG_ERR, "could not create any services");
exit(1);
}
svc_run();
@@ -361,20 +500,38 @@ mntsrv(rqstp, transp)
struct fhreturn fhr;
struct stat stb;
struct statfs fsb;
- struct hostent *hp;
- struct in_addr saddrin;
- u_int32_t saddr;
+ struct addrinfo *ai;
+ char host[NI_MAXHOST], numerichost[NI_MAXHOST];
+ int lookup_failed = 1;
+ struct sockaddr *saddr;
u_short sport;
char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
int bad = 0, defset, hostset;
sigset_t sighup_mask;
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin;
sigemptyset(&sighup_mask);
sigaddset(&sighup_mask, SIGHUP);
- saddr = transp->xp_raddr.sin_addr.s_addr;
- saddrin = transp->xp_raddr.sin_addr;
- sport = ntohs(transp->xp_raddr.sin_port);
- hp = (struct hostent *)NULL;
+ saddr = svc_getrpccaller(transp)->buf;
+ switch (saddr->sa_family) {
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)saddr;
+ sport = ntohs(sin6->sin6_port);
+ break;
+ case AF_INET:
+ sin = (struct sockaddr_in *)saddr;
+ sport = ntohs(sin->sin_port);
+ break;
+ default:
+ syslog(LOG_ERR, "request from unknown address family");
+ return;
+ }
+ lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host,
+ NULL, 0, 0);
+ getnameinfo(saddr, saddr->sa_len, numerichost,
+ sizeof numerichost, NULL, 0, NI_NUMERICHOST);
+ ai = NULL;
switch (rqstp->rq_proc) {
case NULLPROC:
if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
@@ -384,13 +541,13 @@ mntsrv(rqstp, transp)
if (sport >= IPPORT_RESERVED && resvport_only) {
syslog(LOG_NOTICE,
"mount request from %s from unprivileged port",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_weakauth(transp);
return;
}
if (!svc_getargs(transp, xdr_dir, rpcpath)) {
syslog(LOG_NOTICE, "undecodable mount request from %s",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_decode(transp);
return;
}
@@ -403,12 +560,12 @@ mntsrv(rqstp, transp)
if (realpath(rpcpath, dirpath) == NULL ||
stat(dirpath, &stb) < 0 ||
(!S_ISDIR(stb.st_mode) &&
- (dir_only || !S_ISREG(stb.st_mode))) ||
+ (dir_only || !S_ISREG(stb.st_mode))) ||
statfs(dirpath, &fsb) < 0) {
chdir("/"); /* Just in case realpath doesn't */
syslog(LOG_NOTICE,
"mount request from %s for non existent path %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
if (debug)
warnx("stat failed on %s", dirpath);
bad = ENOENT; /* We will send error reply later */
@@ -420,9 +577,9 @@ mntsrv(rqstp, transp)
hostset = defset = 0;
if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
((dp = dirp_search(ep->ex_dirl, dirpath)) &&
- chk_host(dp, saddr, &defset, &hostset)) ||
- (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
- scan_tree(ep->ex_dirl, saddr) == 0))) {
+ chk_host(dp, saddr, &defset, &hostset)) ||
+ (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
+ scan_tree(ep->ex_dirl, saddr) == 0))) {
if (bad) {
if (!svc_sendreply(transp, xdr_long,
(caddr_t)&bad))
@@ -448,25 +605,21 @@ mntsrv(rqstp, transp)
}
if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
syslog(LOG_ERR, "can't send reply");
- if (hp == NULL)
- hp = gethostbyaddr((caddr_t)&saddr,
- sizeof(saddr), AF_INET);
- if (hp)
- add_mlist(hp->h_name, dirpath);
+ if (!lookup_failed)
+ add_mlist(host, dirpath);
else
- add_mlist(inet_ntoa(saddrin),
- dirpath);
+ add_mlist(numerichost, dirpath);
if (debug)
warnx("mount successful");
if (log)
syslog(LOG_NOTICE,
"mount request succeeded from %s for %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
} else {
bad = EACCES;
syslog(LOG_NOTICE,
"mount request denied from %s for %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
}
if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad))
@@ -479,56 +632,54 @@ mntsrv(rqstp, transp)
else if (log)
syslog(LOG_NOTICE,
"dump request succeeded from %s",
- inet_ntoa(saddrin));
+ numerichost);
return;
case RPCMNT_UMOUNT:
if (sport >= IPPORT_RESERVED && resvport_only) {
syslog(LOG_NOTICE,
"umount request from %s from unprivileged port",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_weakauth(transp);
return;
}
if (!svc_getargs(transp, xdr_dir, rpcpath)) {
syslog(LOG_NOTICE, "undecodable umount request from %s",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_decode(transp);
return;
}
if (realpath(rpcpath, dirpath) == NULL) {
syslog(LOG_NOTICE, "umount request from %s "
"for non existent path %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
}
if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
syslog(LOG_ERR, "can't send reply");
- hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
- if (hp)
- del_mlist(hp->h_name, dirpath);
- del_mlist(inet_ntoa(saddrin), dirpath);
+ if (!lookup_failed)
+ del_mlist(host, dirpath, saddr);
+ del_mlist(numerichost, dirpath, saddr);
if (log)
syslog(LOG_NOTICE,
"umount request succeeded from %s for %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
return;
case RPCMNT_UMNTALL:
if (sport >= IPPORT_RESERVED && resvport_only) {
syslog(LOG_NOTICE,
"umountall request from %s from unprivileged port",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_weakauth(transp);
return;
}
if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
syslog(LOG_ERR, "can't send reply");
- hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
- if (hp)
- del_mlist(hp->h_name, (char *)NULL);
- del_mlist(inet_ntoa(saddrin), (char *)NULL);
+ if (!lookup_failed)
+ del_mlist(host, NULL, saddr);
+ del_mlist(numerichost, NULL, saddr);
if (log)
syslog(LOG_NOTICE,
"umountall request succeeded from %s",
- inet_ntoa(saddrin));
+ numerichost);
return;
case RPCMNT_EXPORT:
if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
@@ -536,7 +687,7 @@ mntsrv(rqstp, transp)
if (log)
syslog(LOG_NOTICE,
"export request succeeded from %s",
- inet_ntoa(saddrin));
+ numerichost);
return;
default:
svcerr_noproc(transp);
@@ -690,7 +841,7 @@ put_exlist(dp, xdrsp, adp, putdefp)
if (grp->gr_type == GT_HOST) {
if (!xdr_bool(xdrsp, &true))
return (1);
- strp = grp->gr_ptr.gt_hostent->h_name;
+ strp = grp->gr_ptr.gt_addrinfo->ai_canonname;
if (!xdr_string(xdrsp, &strp,
RPCMNT_NAMELEN))
return (1);
@@ -732,7 +883,7 @@ get_exportlist()
struct exportlist **epp;
struct dirlist *dirhead;
struct statfs fsb, *fsp;
- struct hostent *hpe;
+ struct addrinfo *ai;
struct xucred anon;
char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
@@ -786,7 +937,7 @@ get_exportlist()
fsp->f_flags | MNT_UPDATE,
(caddr_t)&targs) < 0)
syslog(LOG_ERR, "can't delete exports for %s",
- fsp->f_mntonname);
+ fsp->f_mntonname);
}
fsp++;
}
@@ -874,9 +1025,9 @@ get_exportlist()
else
out_of_mem();
if (debug)
- warnx("making new ep fs=0x%x,0x%x",
- fsb.f_fsid.val[0],
- fsb.f_fsid.val[1]);
+ warnx("making new ep fs=0x%x,0x%x",
+ fsb.f_fsid.val[0],
+ fsb.f_fsid.val[1]);
} else if (debug)
warnx("found ep fs=0x%x,0x%x",
fsb.f_fsid.val[0],
@@ -944,14 +1095,17 @@ get_exportlist()
if (debug)
warnx("adding a default entry");
/* add a default group and make the grp list NULL */
- hpe = (struct hostent *)malloc(sizeof(struct hostent));
- if (hpe == (struct hostent *)NULL)
- out_of_mem();
- hpe->h_name = strdup("Default");
- hpe->h_addrtype = AF_INET;
- hpe->h_length = sizeof (u_int32_t);
- hpe->h_addr_list = (char **)NULL;
- grp->gr_ptr.gt_hostent = hpe;
+ ai = malloc(sizeof(struct addrinfo));
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET; /* XXXX */
+ ai->ai_socktype = SOCK_DGRAM;
+ /* setting the length to 0 will match anything */
+ ai->ai_addrlen = 0;
+ ai->ai_flags = AI_CANONNAME;
+ ai->ai_canonname = strdup("Default");
+ ai->ai_addr = NULL;
+ ai->ai_next = NULL;
+ grp->gr_ptr.gt_addrinfo = ai;
/*
* Don't allow a network export coincide with a list of
@@ -961,13 +1115,13 @@ get_exportlist()
getexp_err(ep, tgrp);
goto nextline;
- /*
- * If an export list was specified on this line, make sure
+ /*
+ * If an export list was specified on this line, make sure
* that we have at least one valid entry, otherwise skip it.
*/
} else {
grp = tgrp;
- while (grp && grp->gr_type == GT_IGNORE)
+ while (grp && grp->gr_type == GT_IGNORE)
grp = grp->gr_next;
if (! grp) {
getexp_err(ep, tgrp);
@@ -1219,19 +1373,27 @@ add_dlist(dpp, newdp, grp, flags)
/*
* Search for a dirpath on the export point.
*/
+void *
+test()
+{
+}
+
+/*
+ * Search for a dirpath on the export point.
+ */
struct dirlist *
-dirp_search(dp, dirpath)
+dirp_search(dp, dirp)
struct dirlist *dp;
- char *dirpath;
+ char *dirp;
{
int cmp;
if (dp) {
- cmp = strcmp(dp->dp_dirp, dirpath);
+ cmp = strcmp(dp->dp_dirp, dirp);
if (cmp > 0)
- return (dirp_search(dp->dp_left, dirpath));
+ return (dirp_search(dp->dp_left, dirp));
else if (cmp < 0)
- return (dirp_search(dp->dp_right, dirpath));
+ return (dirp_search(dp->dp_right, dirp));
else
return (dp);
}
@@ -1239,18 +1401,59 @@ dirp_search(dp, dirpath)
}
/*
+ * Some helper functions for netmasks. They all assume masks in network
+ * order (big endian).
+ */
+static int
+bitcmp(void *dst, void *src, int bitlen)
+{
+ int i;
+ u_int8_t *p1 = dst, *p2 = src;
+ u_int8_t bitmask;
+ int bytelen, bitsleft;
+
+ bytelen = bitlen / 8;
+ bitsleft = bitlen % 8;
+
+ if (debug) {
+ printf("comparing:\n");
+ for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++)
+ printf("%02x", p1[i]);
+ printf("\n");
+ for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++)
+ printf("%02x", p2[i]);
+ printf("\n");
+ }
+
+ for (i = 0; i < bytelen; i++) {
+ if (*p1 != *p2)
+ return 1;
+ p1++;
+ p2++;
+ }
+
+ for (i = 0; i < bitsleft; i++) {
+ bitmask = 1 << (7 - i);
+ if ((*p1 & bitmask) != (*p2 & bitmask))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
* Scan for a host match in a directory tree.
*/
int
chk_host(dp, saddr, defsetp, hostsetp)
struct dirlist *dp;
- u_int32_t saddr;
+ struct sockaddr *saddr;
int *defsetp;
int *hostsetp;
{
struct hostlist *hp;
struct grouplist *grp;
- u_int32_t **addrp;
+ struct addrinfo *ai;
if (dp) {
if (dp->dp_flag & DP_DEFSET)
@@ -1260,22 +1463,22 @@ chk_host(dp, saddr, defsetp, hostsetp)
grp = hp->ht_grp;
switch (grp->gr_type) {
case GT_HOST:
- addrp = (u_int32_t **)
- grp->gr_ptr.gt_hostent->h_addr_list;
- while (*addrp) {
- if (**addrp == saddr) {
- *hostsetp = (hp->ht_flag | DP_HOSTSET);
- return (1);
+ ai = grp->gr_ptr.gt_addrinfo;
+ for (; ai; ai = ai->ai_next) {
+ if (!sacmp(ai->ai_addr, saddr)) {
+ *hostsetp =
+ (hp->ht_flag | DP_HOSTSET);
+ return (1);
+ }
}
- addrp++;
- }
break;
case GT_NET:
- if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
- grp->gr_ptr.gt_net.nt_net) {
- *hostsetp = (hp->ht_flag | DP_HOSTSET);
- return (1);
- }
+ if (!netpartcmp(saddr,
+ (struct sockaddr *) &grp->gr_ptr.gt_net.nt_net,
+ grp->gr_ptr.gt_net.nt_mask)) {
+ *hostsetp = (hp->ht_flag | DP_HOSTSET);
+ return (1);
+ }
break;
};
hp = hp->ht_next;
@@ -1290,7 +1493,7 @@ chk_host(dp, saddr, defsetp, hostsetp)
int
scan_tree(dp, saddr)
struct dirlist *dp;
- u_int32_t saddr;
+ struct sockaddr *saddr;
{
int defset, hostset;
@@ -1392,6 +1595,11 @@ do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
opt_flags |= OP_MASK;
} else if (cpoptarg && (!strcmp(cpopt, "network") ||
!strcmp(cpopt, "n"))) {
+ if (strchr(cpoptarg, '/') != NULL) {
+ if (debug)
+ fprintf(stderr, "setting OP_MASKLEN\n");
+ opt_flags |= OP_MASKLEN;
+ }
if (grp->gr_type != GT_NULL) {
syslog(LOG_ERR, "network/host conflict");
return (1);
@@ -1442,84 +1650,40 @@ get_host(cp, grp, tgrp)
struct grouplist *tgrp;
{
struct grouplist *checkgrp;
- struct hostent *hp, *nhp;
- char **addrp, **naddrp;
- struct hostent t_host;
+ struct addrinfo *ai, hints;
+ int ecode;
+ char host[NI_MAXHOST];
int i;
- u_int32_t saddr;
char *aptr[2];
- if (grp->gr_type != GT_NULL)
+ if (grp->gr_type != GT_NULL) {
+ syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp);
return (1);
- if ((hp = gethostbyname(cp)) == NULL) {
- if (isdigit(*cp)) {
- saddr = inet_addr(cp);
- if (saddr == -1) {
- syslog(LOG_ERR, "inet_addr failed for %s", cp);
- return (1);
- }
- if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
- AF_INET)) == NULL) {
- hp = &t_host;
- hp->h_name = cp;
- hp->h_addrtype = AF_INET;
- hp->h_length = sizeof (u_int32_t);
- hp->h_addr_list = aptr;
- aptr[0] = (char *)&saddr;
- aptr[1] = (char *)NULL;
- }
- } else {
- syslog(LOG_ERR, "gethostbyname failed for %s", cp);
- return (1);
- }
}
- /*
- * Sanity check: make sure we don't already have an entry
- * for this host in the grouplist.
- */
- checkgrp = tgrp;
- while (checkgrp != NULL) {
- if (checkgrp->gr_type == GT_HOST &&
- checkgrp->gr_ptr.gt_hostent != NULL &&
- (!strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)
- || *(u_int32_t *)checkgrp->gr_ptr.gt_hostent->h_addr ==
- *(u_int32_t *)hp->h_addr)) {
- grp->gr_type = GT_IGNORE;
- return(0);
- }
- checkgrp = checkgrp->gr_next;
- }
-
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(cp, NULL, &hints, &ai);
+ if (ecode != 0) {
+ syslog(LOG_ERR,"can't get address info for "
+ "host %s", cp);
+ return 1;
+ }
grp->gr_type = GT_HOST;
- nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
- malloc(sizeof(struct hostent));
- if (nhp == (struct hostent *)NULL)
- out_of_mem();
- memmove(nhp, hp, sizeof(struct hostent));
- i = strlen(hp->h_name)+1;
- nhp->h_name = (char *)malloc(i);
- if (nhp->h_name == (char *)NULL)
- out_of_mem();
- memmove(nhp->h_name, hp->h_name, i);
- addrp = hp->h_addr_list;
- i = 1;
- while (*addrp++)
- i++;
- naddrp = nhp->h_addr_list = (char **)malloc(i*sizeof(char *));
- if (naddrp == (char **)NULL)
- out_of_mem();
- addrp = hp->h_addr_list;
- while (*addrp) {
- *naddrp = (char *)malloc(hp->h_length);
- if (*naddrp == (char *)NULL)
- out_of_mem();
- memmove(*naddrp, *addrp, hp->h_length);
- addrp++;
- naddrp++;
- }
- *naddrp = (char *)NULL;
- if (debug)
- warnx("got host %s", hp->h_name);
+ grp->gr_ptr.gt_addrinfo = ai;
+ while (ai != NULL) {
+ if (ai->ai_canonname == NULL) {
+ if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
+ sizeof host, NULL, 0, ninumeric) != 0)
+ strlcpy(host, "?", sizeof(host));
+ ai->ai_canonname = strdup(host);
+ ai->ai_flags |= AI_CANONNAME;
+ } else
+ ai->ai_flags &= ~AI_CANONNAME;
+ if (debug)
+ (void)fprintf(stderr, "got host %s\n", ai->ai_canonname);
+ ai = ai->ai_next;
+ }
return (0);
}
@@ -1597,68 +1761,64 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
int dirplen;
struct statfs *fsb;
{
- char *cp = (char *)NULL;
- u_int32_t **addrp;
+ struct sockaddr *addrp;
+ struct sockaddr_storage ss;
+ struct addrinfo *ai;
+ int addrlen;
+ char *cp = NULL;
int done;
char savedc = '\0';
- struct sockaddr_in sin, imask;
union {
struct ufs_args ua;
struct iso_args ia;
struct mfs_args ma;
#ifdef __NetBSD__
struct msdosfs_args da;
+ struct adosfs_args aa;
#endif
struct ntfs_args na;
} args;
- u_int32_t net;
args.ua.fspec = 0;
args.ua.export.ex_flags = exflags;
args.ua.export.ex_anon = *anoncrp;
args.ua.export.ex_indexfile = ep->ex_indexfile;
- memset(&sin, 0, sizeof(sin));
- memset(&imask, 0, sizeof(imask));
- sin.sin_family = AF_INET;
- sin.sin_len = sizeof(sin);
- imask.sin_family = AF_INET;
- imask.sin_len = sizeof(sin);
- if (grp->gr_type == GT_HOST)
- addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list;
- else
- addrp = (u_int32_t **)NULL;
+ if (grp->gr_type == GT_HOST) {
+ ai = grp->gr_ptr.gt_addrinfo;
+ addrp = ai->ai_addr;
+ addrlen = ai->ai_addrlen;
+ } else
+ addrp = NULL;
done = FALSE;
while (!done) {
switch (grp->gr_type) {
case GT_HOST:
- if (addrp) {
- sin.sin_addr.s_addr = **addrp;
- args.ua.export.ex_addrlen = sizeof(sin);
- } else
- args.ua.export.ex_addrlen = 0;
- args.ua.export.ex_addr = (struct sockaddr *)&sin;
+ if (addrp != NULL && addrp->sa_family == AF_INET6 &&
+ have_v6 == 0)
+ goto skip;
+ args.ua.export.ex_addr = addrp;
+ args.ua.export.ex_addrlen = addrlen;
args.ua.export.ex_masklen = 0;
break;
case GT_NET:
- if (grp->gr_ptr.gt_net.nt_mask)
- imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
- else {
- net = ntohl(grp->gr_ptr.gt_net.nt_net);
- if (IN_CLASSA(net))
- imask.sin_addr.s_addr = inet_addr("255.0.0.0");
- else if (IN_CLASSB(net))
- imask.sin_addr.s_addr =
- inet_addr("255.255.0.0");
- else
- imask.sin_addr.s_addr =
- inet_addr("255.255.255.0");
- grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
+ args.ua.export.ex_addr = (struct sockaddr *)
+ &grp->gr_ptr.gt_net.nt_net;
+ if (args.ua.export.ex_addr->sa_family == AF_INET6 &&
+ have_v6 == 0)
+ goto skip;
+ args.ua.export.ex_addrlen =
+ args.ua.export.ex_addr->sa_len;
+ memset(&ss, 0, sizeof ss);
+ ss.ss_family = args.ua.export.ex_addr->sa_family;
+ ss.ss_len = args.ua.export.ex_addr->sa_len;
+ if (allones(&ss, grp->gr_ptr.gt_net.nt_mask) != 0) {
+ syslog(LOG_ERR, "Bad network flag");
+ if (cp)
+ *cp = savedc;
+ return (1);
}
- sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
- args.ua.export.ex_addr = (struct sockaddr *)&sin;
- args.ua.export.ex_addrlen = sizeof (sin);
- args.ua.export.ex_mask = (struct sockaddr *)&imask;
- args.ua.export.ex_masklen = sizeof (imask);
+ args.ua.export.ex_mask = (struct sockaddr *)&ss;
+ args.ua.export.ex_masklen = ss.ss_len;
break;
case GT_IGNORE:
return(0);
@@ -1678,7 +1838,7 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
* exportable file systems and not just "ufs".
*/
while (mount(fsb->f_fstypename, dirp,
- fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
+ fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
if (cp)
*cp-- = savedc;
else
@@ -1707,10 +1867,15 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
savedc = *cp;
*cp = '\0';
}
+skip:
if (addrp) {
- ++addrp;
- if (*addrp == (u_int32_t *)NULL)
+ ai = ai->ai_next;
+ if (ai == NULL)
done = TRUE;
+ else {
+ addrp = ai->ai_addr;
+ addrlen = ai->ai_addrlen;
+ }
} else
done = TRUE;
}
@@ -1729,47 +1894,105 @@ get_net(cp, net, maskflg)
int maskflg;
{
struct netent *np;
- long netaddr;
- struct in_addr inetaddr, inetaddr2;
- char *name;
+ char *name, *p, *prefp;
+ struct sockaddr_in sin, *sinp;
+ struct sockaddr *sa;
+ struct addrinfo hints, *ai = NULL;
+ char netname[NI_MAXHOST];
+ long preflen;
+ int ecode;
+
+ if ((opt_flags & OP_MASKLEN) && !maskflg) {
+ p = strchr(cp, '/');
+ *p = '\0';
+ prefp = p + 1;
+ }
- if (isdigit(*cp) && ((netaddr = inet_network(cp)) != -1)) {
- inetaddr = inet_makeaddr(netaddr, 0);
- /*
- * Due to arbitrary subnet masks, you don't know how many
- * bits to shift the address to make it into a network,
- * however you do know how to make a network address into
- * a host with host == 0 and then compare them.
- * (What a pest)
- */
- if (!maskflg) {
- setnetent(0);
- while ((np = getnetent())) {
- inetaddr2 = inet_makeaddr(np->n_net, 0);
- if (inetaddr2.s_addr == inetaddr.s_addr)
- break;
- }
- endnetent();
- }
- } else if ((np = getnetbyname(cp)) != NULL) {
- inetaddr = inet_makeaddr(np->n_net, 0);
+ if ((np = getnetbyname(cp)) != NULL) {
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof sin;
+ sin.sin_addr = inet_makeaddr(np->n_net, 0);
+ sa = (struct sockaddr *)&sin;
+ } else if (isdigit(*cp)) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(cp, NULL, &hints, &ai) != 0) {
+ /*
+ * If getaddrinfo() failed, try the inet4 network
+ * notation with less than 3 dots.
+ */
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof sin;
+ sin.sin_addr = inet_makeaddr(inet_network(cp),0);
+ if (debug)
+ fprintf(stderr, "get_net: v4 addr %x\n",
+ sin.sin_addr.s_addr);
+ sa = (struct sockaddr *)&sin;
+ } else
+ sa = ai->ai_addr;
+ } else if (isxdigit(*cp) || *cp == ':') {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
+ sa = ai->ai_addr;
+ else
+ goto fail;
} else
- return (1);
+ goto fail;
+
+ ecode = getnameinfo(sa, sa->sa_len, netname, sizeof netname,
+ NULL, 0, ninumeric);
+ if (ecode != 0)
+ goto fail;
if (maskflg)
- net->nt_mask = inetaddr.s_addr;
+ net->nt_mask = countones(sa);
else {
+ if (opt_flags & OP_MASKLEN) {
+ preflen = strtol(prefp, NULL, 10);
+ if (preflen == LONG_MIN && errno == ERANGE)
+ goto fail;
+ net->nt_mask = (int)preflen;
+ *p = '/';
+ }
+
if (np)
name = np->n_name;
+ else {
+ if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
+ NULL, 0, ninumeric) != 0)
+ strlcpy(netname, "?", sizeof(netname));
+ name = netname;
+ }
+ net->nt_name = strdup(name);
+ memcpy(&net->nt_net, sa, sa->sa_len);
+ }
+
+ if (!maskflg && sa->sa_family == AF_INET &&
+ !(opt_flags & (OP_MASK|OP_MASKLEN))) {
+ sinp = (struct sockaddr_in *)sa;
+ if (IN_CLASSA(sinp->sin_addr.s_addr))
+ net->nt_mask = 8;
+ else if (IN_CLASSB(sinp->sin_addr.s_addr))
+ net->nt_mask = 16;
+ else if (IN_CLASSC(sinp->sin_addr.s_addr))
+ net->nt_mask = 24;
+ else if (IN_CLASSD(sinp->sin_addr.s_addr))
+ net->nt_mask = 28;
else
- name = inet_ntoa(inetaddr);
- net->nt_name = (char *)malloc(strlen(name) + 1);
- if (net->nt_name == (char *)NULL)
- out_of_mem();
- strcpy(net->nt_name, name);
- net->nt_net = inetaddr.s_addr;
+ net->nt_mask = 32; /* XXX */
}
- return (0);
+
+ if (ai)
+ freeaddrinfo(ai);
+ return 0;
+
+fail:
+ if (ai)
+ freeaddrinfo(ai);
+ return 1;
}
/*
@@ -1958,15 +2181,28 @@ get_mountlist()
fclose(mlfile);
}
-void
-del_mlist(hostp, dirp)
+int
+del_mlist(hostp, dirp, saddr)
char *hostp, *dirp;
+ struct sockaddr *saddr;
{
struct mountlist *mlp, **mlpp;
struct mountlist *mlp2;
+ u_short sport;
FILE *mlfile;
int fnd = 0;
-
+ char host[NI_MAXHOST];
+
+ switch (saddr->sa_family) {
+ case AF_INET6:
+ sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port);
+ break;
+ case AF_INET:
+ sport = ntohs(((struct sockaddr_in *)saddr)->sin_port);
+ break;
+ default:
+ return -1;
+ }
mlpp = &mlhead;
mlp = mlhead;
while (mlp) {
@@ -2034,17 +2270,11 @@ void
free_grp(grp)
struct grouplist *grp;
{
- char **addrp;
+ struct addrinfo *ai;
if (grp->gr_type == GT_HOST) {
- if (grp->gr_ptr.gt_hostent->h_name) {
- addrp = grp->gr_ptr.gt_hostent->h_addr_list;
- while (addrp && *addrp)
- free(*addrp++);
- free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
- free(grp->gr_ptr.gt_hostent->h_name);
- }
- free((caddr_t)grp->gr_ptr.gt_hostent);
+ if (grp->gr_ptr.gt_addrinfo != NULL)
+ freeaddrinfo(grp->gr_ptr.gt_addrinfo);
} else if (grp->gr_type == GT_NET) {
if (grp->gr_ptr.gt_net.nt_name)
free(grp->gr_ptr.gt_net.nt_name);
@@ -2093,7 +2323,6 @@ check_options(dp)
/*
* Check an absolute directory path for any symbolic links. Return true
- * if no symbolic links are found.
*/
int
check_dirpath(dirp)
@@ -2134,3 +2363,146 @@ get_num(cp)
}
return (res);
}
+
+static int
+netpartcmp(struct sockaddr *s1, struct sockaddr *s2, int bitlen)
+{
+ void *src, *dst;
+
+ if (s1->sa_family != s2->sa_family)
+ return 1;
+
+ switch (s1->sa_family) {
+ case AF_INET:
+ src = &((struct sockaddr_in *)s1)->sin_addr;
+ dst = &((struct sockaddr_in *)s2)->sin_addr;
+ if (bitlen > sizeof(((struct sockaddr_in *)s1)->sin_addr) * 8)
+ return 1;
+ break;
+ case AF_INET6:
+ src = &((struct sockaddr_in6 *)s1)->sin6_addr;
+ dst = &((struct sockaddr_in6 *)s2)->sin6_addr;
+ if (((struct sockaddr_in6 *)s1)->sin6_scope_id !=
+ ((struct sockaddr_in6 *)s2)->sin6_scope_id)
+ return 1;
+ if (bitlen > sizeof(((struct sockaddr_in6 *)s1)->sin6_addr) * 8)
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+
+ return bitcmp(src, dst, bitlen);
+}
+
+static int
+allones(struct sockaddr_storage *ssp, int bitlen)
+{
+ u_int8_t *p;
+ int bytelen, bitsleft, i;
+ int zerolen;
+
+ switch (ssp->ss_family) {
+ case AF_INET:
+ p = (u_int8_t *)&((struct sockaddr_in *)ssp)->sin_addr;
+ zerolen = sizeof (((struct sockaddr_in *)ssp)->sin_addr);
+ break;
+ case AF_INET6:
+ p = (u_int8_t *)&((struct sockaddr_in6 *)ssp)->sin6_addr;
+ zerolen = sizeof (((struct sockaddr_in6 *)ssp)->sin6_addr);
+ break;
+ default:
+ return -1;
+ }
+
+ memset(p, 0, zerolen);
+
+ bytelen = bitlen / 8;
+ bitsleft = bitlen % 8;
+
+ if (bytelen > zerolen)
+ return -1;
+
+ for (i = 0; i < bytelen; i++)
+ *p++ = 0xff;
+
+ for (i = 0; i < bitsleft; i++)
+ *p |= 1 << (7 - i);
+
+ return 0;
+}
+
+static int
+countones(struct sockaddr *sa)
+{
+ void *mask;
+ int i, bits = 0, bytelen;
+ u_int8_t *p;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ mask = (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr;
+ bytelen = 4;
+ break;
+ case AF_INET6:
+ mask = (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr;
+ bytelen = 16;
+ break;
+ default:
+ return 0;
+ }
+
+ p = mask;
+
+ for (i = 0; i < bytelen; i++, p++) {
+ if (*p != 0xff) {
+ for (bits = 0; bits < 8; bits++) {
+ if (!(*p & (1 << (7 - bits))))
+ break;
+ }
+ break;
+ }
+ }
+
+ return (i * 8 + bits);
+}
+
+static int
+sacmp(struct sockaddr *sa1, struct sockaddr *sa2)
+{
+ void *p1, *p2;
+ int len;
+
+ if (sa1->sa_family != sa2->sa_family)
+ return 1;
+
+ switch (sa1->sa_family) {
+ case AF_INET:
+ p1 = &((struct sockaddr_in *)sa1)->sin_addr;
+ p2 = &((struct sockaddr_in *)sa2)->sin_addr;
+ len = 4;
+ break;
+ case AF_INET6:
+ p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
+ p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
+ len = 16;
+ if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
+ ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+
+ return memcmp(p1, p2, len);
+}
+
+void terminate(sig)
+int sig;
+{
+ close(mountdlockfd);
+ unlink(MOUNTDLOCK);
+ pmap_unset(RPCPROG_MNT, 1);
+ pmap_unset(RPCPROG_MNT, 3);
+ exit (0);
+}
diff --git a/sbin/nfsd/nfsd.8 b/sbin/nfsd/nfsd.8
index fb44149..0031ea1 100644
--- a/sbin/nfsd/nfsd.8
+++ b/sbin/nfsd/nfsd.8
@@ -42,7 +42,7 @@
server
.Sh SYNOPSIS
.Nm
-.Op Fl arut
+.Op Fl ardut
.Op Fl n Ar num_servers
.Op Fl h Ar bindip
.Sh DESCRIPTION
@@ -64,13 +64,19 @@ The following options are available:
Register the
.Tn NFS
service with
-.Xr portmap 8
+.Xr rpcbind 8
without creating any servers.
This option can be used along with the
.Fl u
or
.Fl t
-options to re-register NFS if the portmap server is restarted.
+options to re-register NFS if the rpcbind server is restarted.
+.It Fl d
+Unregister the
+.Tn NFS
+service with
+.Xr rpcbind 8
+without creating any servers.
.It Fl n
Specifies how many servers to create.
.It Fl h Ar bindip
@@ -147,6 +153,16 @@ that the NFS sockets can only be accessed by the inside interface.
would then be used to block nfs-related packets that come in on the outside
interface.
.Pp
+.Nm
+has to be terminated with SIGUSR1 and cannot be killed with SIGTERM oder SIGQUIT.
+.Nm
+needs to ignore these signals in order to stay alive as long
+as possible during a shutdown, otherwise loopback mounts will
+not be able to unmount. If you have to kill
+.Nm
+just do a
+.Dq Li "kill -USR1 <PID of master nfsd>"
+.Pp
The
.Nm
utility exits 0 on success, and >0 if an error occurs.
@@ -156,7 +172,7 @@ utility exits 0 on success, and >0 if an error occurs.
.Xr kldload 8 ,
.Xr mountd 8 ,
.Xr nfsiod 8 ,
-.Xr portmap 8 ,
+.Xr rpcbind 8 ,
.Xr ipfw 8
.Sh HISTORY
The
diff --git a/sbin/nfsd/nfsd.c b/sbin/nfsd/nfsd.c
index 2d923a4..959f0fb 100644
--- a/sbin/nfsd/nfsd.c
+++ b/sbin/nfsd/nfsd.c
@@ -58,9 +58,6 @@ static const char rcsid[] =
#include <netdb.h>
#include <arpa/inet.h>
-#ifdef ISO
-#include <netiso/iso.h>
-#endif
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
@@ -76,6 +73,7 @@ static const char rcsid[] =
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
+#include <netdb.h>
/* Global defs */
#ifdef DEBUG
@@ -103,15 +101,23 @@ struct timeval ktv;
NFSKERBKEYSCHED_T kerb_keysched;
#endif
-void nonfs __P((int));
-void reapchild __P((int));
-void setbindhost __P((struct sockaddr_in *ia, const char *bindhost));
+#define MAXNFSDCNT 20
+#define DEFNFSDCNT 4
+pid_t children[MAXNFSDCNT]; /* PIDs of children */
+int nfsdcnt; /* number of children */
+
+void cleanup(int);
+void killchildren(void);
+void nonfs (int);
+void reapchild (int);
+int setbindhost (struct addrinfo **ia, const char *bindhost, struct addrinfo hints);
#ifdef OLD_SETPROCTITLE
#ifdef __FreeBSD__
-void setproctitle __P((char *));
+void setproctitle (char *);
#endif
#endif
-void usage __P((void));
+void unregistration (void);
+void usage (void);
/*
* Nfs server daemon mostly just a user context for nfssvc()
@@ -119,7 +125,7 @@ void usage __P((void));
* 1 - do file descriptor and signal cleanup
* 2 - fork the nfsd(s)
* 3 - create server socket(s)
- * 4 - register socket with portmap
+ * 4 - register socket with rpcbind
*
* For connectionless protocols, just pass the socket into the kernel via.
* nfssvc().
@@ -127,7 +133,8 @@ void usage __P((void));
* socket from accept, pass the msgsock into the kernel via. nfssvc().
* The arguments are:
* -c - support iso cltp clients
- * -r - reregister with portmapper
+ * -r - reregister with rpcbind
+ * -d - unregister with rpcbind
* -t - support tcp nfs clients
* -u - support udp nfs clients
* followed by "n" which is the number of nfsds' to fork off
@@ -138,20 +145,20 @@ main(argc, argv, envp)
char *argv[], *envp[];
{
struct nfsd_args nfsdargs;
- struct sockaddr_in inetaddr, inetpeer;
-#ifdef ISO
- struct sockaddr_iso isoaddr, isopeer;
- char *cp;
-#endif
+ struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
+ struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
+ struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
+ struct sockaddr_in inetpeer;
+ struct sockaddr_in6 inet6peer;
fd_set ready, sockbits;
+ fd_set v4bits, v6bits;
int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
- int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
- int tp4cnt, tp4flag, tpipcnt, tpipflag, udpflag;
- int bindhostc = 0, bindanyflag;
+ int nfssvc_flag, on = 1, unregister, reregister, sock;
+ int tcp6sock, ip6flag, tcpflag, tcpsock;
+ int udpflag, ecode, s;
+ int bindhostc = 0, bindanyflag, rpcbreg, rpcbregcnt;
char **bindhost = NULL;
-#ifdef notyet
- int tp4sock, tpipsock;
-#endif
+ pid_t pid;
#ifdef NFSKERB
struct group *grp;
struct passwd *pwd;
@@ -184,18 +191,11 @@ main(argc, argv, envp)
LastArg = envp[-1] + strlen(envp[-1]);
#endif
-#define MAXNFSDCNT 20
-#define DEFNFSDCNT 4
nfsdcnt = DEFNFSDCNT;
- cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
- bindanyflag = tpipflag = udpflag = 0;
-#ifdef ISO
-#define GETOPT "ach:n:rtu"
-#define USAGE "[-acrtu] [-n num_servers] [-h bindip]"
-#else
-#define GETOPT "ah:n:rtu"
-#define USAGE "[-artu] [-n num_servers] [-h bindip]"
-#endif
+ cltpflag = unregister = reregister = tcpflag = 0;
+ bindanyflag = udpflag = ip6flag = 0;
+#define GETOPT "ah:n:rdtu"
+#define USAGE "[-ardtu] [-n num_servers] [-h bindip]"
while ((ch = getopt(argc, argv, GETOPT)) != -1)
switch (ch) {
case 'a':
@@ -221,25 +221,15 @@ main(argc, argv, envp)
case 'r':
reregister = 1;
break;
+ case 'd':
+ unregister = 1;
+ break;
case 't':
tcpflag = 1;
break;
case 'u':
udpflag = 1;
break;
-#ifdef ISO
- case 'c':
- cltpflag = 1;
- break;
-#ifdef notyet
- case 'i':
- tp4cnt = 1;
- break;
- case 'p':
- tpipcnt = 1;
- break;
-#endif /* notyet */
-#endif /* ISO */
default:
case '?':
usage();
@@ -263,6 +253,13 @@ main(argc, argv, envp)
nfsdcnt = DEFNFSDCNT;
}
}
+ ip6flag = 1;
+ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0 && (errno == EPROTONOSUPPORT ||
+ errno == EPFNOSUPPORT || errno == EAFNOSUPPORT))
+ ip6flag = 0;
+ else
+ close(s);
if (bindhostc == 0 || bindanyflag) {
bindhostc++;
@@ -278,33 +275,126 @@ main(argc, argv, envp)
daemon(0, 0);
(void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
- (void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGSYS, nonfs);
+ (void)signal(SIGUSR1, cleanup);
+ /*
+ * nfsd sits in the kernel most of the time. It needs
+ * to ignore SIGTERM/SIGQUIT in order to stay alive as long
+ * as possible during a shutdown, otherwise loopback
+ * mounts will not be able to unmount.
+ */
(void)signal(SIGTERM, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
}
(void)signal(SIGCHLD, reapchild);
-
+ if (unregister) {
+ unregistration();
+ exit (0);
+ }
if (reregister) {
- if (udpflag &&
- (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
- !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)))
- err(1, "can't register with portmap for UDP");
- if (tcpflag &&
- (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
- !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)))
- err(1, "can't register with portmap for TCP");
- exit(0);
+ if (udpflag) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo udp: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_udp = getnetconfigent("udp");
+ if (nconf_udp == NULL)
+ err(1, "getnetconfigent udp failed");
+ nb_udp.buf = ai_udp->ai_addr;
+ nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
+ err(1, "rpcb_set udp failed");
+ freeaddrinfo(ai_udp);
+ }
+ if (udpflag && ip6flag) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo udp6: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_udp6 = getnetconfigent("udp6");
+ if (nconf_udp6 == NULL)
+ err(1, "getnetconfigent udp6 failed");
+ nb_udp6.buf = ai_udp6->ai_addr;
+ nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
+ err(1, "rpcb_set udp6 failed");
+ freeaddrinfo(ai_udp6);
+ }
+ if (tcpflag) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo tcp: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_tcp = getnetconfigent("tcp");
+ if (nconf_tcp == NULL)
+ err(1, "getnetconfigent tcp failed");
+ nb_tcp.buf = ai_tcp->ai_addr;
+ nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)))
+ err(1, "rpcb_set tcp failed");
+ freeaddrinfo(ai_tcp);
+ }
+ if (tcpflag && ip6flag) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo tcp6: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_tcp6 = getnetconfigent("tcp6");
+ if (nconf_tcp6 == NULL)
+ err(1, "getnetconfigent tcp6 failed");
+ nb_tcp6.buf = ai_tcp6->ai_addr;
+ nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
+ err(1, "rpcb_set tcp6 failed");
+ freeaddrinfo(ai_tcp6);
+ }
+ exit (0);
}
+
openlog("nfsd:", LOG_PID, LOG_DAEMON);
for (i = 0; i < nfsdcnt; i++) {
- switch (fork()) {
+ switch ((pid = fork())) {
case -1:
syslog(LOG_ERR, "fork: %m");
+ killchildren();
exit (1);
case 0:
break;
default:
+ children[i] = pid;
continue;
}
@@ -399,182 +489,295 @@ main(argc, argv, envp)
exit(0);
}
- /* If we are serving udp, set up the socket. */
- for (i = 0; udpflag && i < bindhostc; i++) {
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "can't create udp socket");
- exit(1);
- }
- setbindhost(&inetaddr, bindhost[i]);
- if (bind(sock,
- (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
- syslog(LOG_ERR, "can't bind udp addr %s: %m", bindhost[i]);
- exit(1);
- }
- if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
- !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register with udp portmap");
- exit(1);
+ if (atexit(killchildren) == -1) {
+ syslog(LOG_ERR, "atexit: %s", strerror(errno));
+ exit(1);
+ }
+ FD_ZERO(&v4bits);
+ FD_ZERO(&v6bits);
+
+ rpcbregcnt = 0;
+ /* Set up the socket for udp and rpcb register it. */
+ if (udpflag) {
+ rpcbreg = 0;
+ for (i = 0; i < bindhostc; i++) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
+ rpcbreg = 1;
+ rpcbregcnt++;
+ if ((sock = socket(ai_udp->ai_family,
+ ai_udp->ai_socktype,
+ ai_udp->ai_protocol)) < 0) {
+ syslog(LOG_ERR,
+ "can't create udp socket");
+ exit(1);
+ }
+ if (bind(sock, ai_udp->ai_addr,
+ ai_udp->ai_addrlen) < 0) {
+ syslog(LOG_ERR,
+ "can't bind udp addr %s: %m",
+ bindhost[i]);
+ exit(1);
+ }
+ freeaddrinfo(ai_udp);
+ nfsdargs.sock = sock;
+ nfsdargs.name = NULL;
+ nfsdargs.namelen = 0;
+ if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
+ syslog(LOG_ERR, "can't Add UDP socket");
+ exit(1);
+ }
+ (void)close(sock);
+ }
}
- nfsdargs.sock = sock;
- nfsdargs.name = NULL;
- nfsdargs.namelen = 0;
- if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
- syslog(LOG_ERR, "can't Add UDP socket");
- exit(1);
+ if (rpcbreg == 1) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo udp: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_udp = getnetconfigent("udp");
+ if (nconf_udp == NULL)
+ err(1, "getnetconfigent udp failed");
+ nb_udp.buf = ai_udp->ai_addr;
+ nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
+ err(1, "rpcb_set udp failed");
+ freeaddrinfo(ai_udp);
}
- (void)close(sock);
}
-#ifdef ISO
- /* If we are serving cltp, set up the socket. */
- if (cltpflag) {
- if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "can't create cltp socket");
- exit(1);
- }
- memset(&isoaddr, 0, sizeof(isoaddr));
- isoaddr.siso_family = AF_ISO;
- isoaddr.siso_tlen = 2;
- cp = TSEL(&isoaddr);
- *cp++ = (NFS_PORT >> 8);
- *cp = (NFS_PORT & 0xff);
- isoaddr.siso_len = sizeof(isoaddr);
- if (bind(sock,
- (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
- syslog(LOG_ERR, "can't bind cltp addr");
- exit(1);
- }
-#ifdef notyet
- /*
- * XXX
- * Someday this should probably use "rpcbind", the son of
- * portmap.
- */
- if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register with udp portmap");
- exit(1);
+ /* Set up the socket for udp6 and rpcb register it. */
+ if (udpflag && ip6flag) {
+ rpcbreg = 0;
+ for (i = 0; i < bindhostc; i++) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
+ rpcbreg = 1;
+ rpcbregcnt++;
+ if ((sock = socket(ai_udp6->ai_family,
+ ai_udp6->ai_socktype,
+ ai_udp6->ai_protocol)) < 0) {
+ syslog(LOG_ERR,
+ "can't create udp6 socket");
+ exit(1);
+ }
+ if (setsockopt(sock, IPPROTO_IPV6,
+ IPV6_BINDV6ONLY,
+ &on, sizeof on) < 0) {
+ syslog(LOG_ERR,
+ "can't set v6-only binding for "
+ "udp6 socket: %m");
+ exit(1);
+ }
+ if (bind(sock, ai_udp6->ai_addr,
+ ai_udp6->ai_addrlen) < 0) {
+ syslog(LOG_ERR,
+ "can't bind udp6 addr %s: %m",
+ bindhost[i]);
+ exit(1);
+ }
+ freeaddrinfo(ai_udp6);
+ nfsdargs.sock = sock;
+ nfsdargs.name = NULL;
+ nfsdargs.namelen = 0;
+ if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
+ syslog(LOG_ERR,
+ "can't add UDP6 socket");
+ exit(1);
+ }
+ (void)close(sock);
+ }
}
-#endif /* notyet */
- nfsdargs.sock = sock;
- nfsdargs.name = NULL;
- nfsdargs.namelen = 0;
- if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
- syslog(LOG_ERR, "can't add UDP socket");
- exit(1);
+ if (rpcbreg == 1) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo udp6: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_udp6 = getnetconfigent("udp6");
+ if (nconf_udp6 == NULL)
+ err(1, "getnetconfigent udp6 failed");
+ nb_udp6.buf = ai_udp6->ai_addr;
+ nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
+ err(1, "rpcb_set udp6 failed");
+ freeaddrinfo(ai_udp6);
}
- close(sock);
}
-#endif /* ISO */
-
- /* Now set up the master server socket waiting for tcp connections. */
- on = 1;
- FD_ZERO(&sockbits);
- connect_type_cnt = 0;
- for (i = 0; tcpflag && i < bindhostc; i++) {
- if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- syslog(LOG_ERR, "can't create tcp socket");
- exit(1);
- }
- if (setsockopt(tcpsock,
- SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
- setbindhost(&inetaddr, bindhost[i]);
- if (bind(tcpsock,
- (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
- syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]);
- exit(1);
- }
- if (listen(tcpsock, 5) < 0) {
- syslog(LOG_ERR, "listen failed");
- exit(1);
+
+ /* Set up the socket for tcp and rpcb register it. */
+ if (tcpflag) {
+ rpcbreg = 0;
+ for (i = 0; i < bindhostc; i++) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
+ rpcbreg = 1;
+ rpcbregcnt++;
+ if ((tcpsock = socket(AF_INET, SOCK_STREAM,
+ 0)) < 0) {
+ syslog(LOG_ERR,
+ "can't create tpc socket");
+ exit(1);
+ }
+ if (setsockopt(tcpsock, SOL_SOCKET,
+ SO_REUSEADDR,
+ (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_REUSEADDR: %m");
+ if (bind(tcpsock, ai_tcp->ai_addr,
+ ai_tcp->ai_addrlen) < 0) {
+ syslog(LOG_ERR,
+ "can't bind tcp addr %s: %m",
+ bindhost[i]);
+ exit(1);
+ }
+ if (listen(tcpsock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ freeaddrinfo(ai_tcp);
+ FD_SET(tcpsock, &sockbits);
+ FD_SET(tcpsock, &v4bits);
+ maxsock = tcpsock;
+ connect_type_cnt++;
+ }
}
- if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
- !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register tcp with portmap");
- exit(1);
+ if (rpcbreg == 1) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(NULL, "nfs", &hints,
+ &ai_tcp);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo tcp: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_tcp = getnetconfigent("tcp");
+ if (nconf_tcp == NULL)
+ err(1, "getnetconfigent tcp failed");
+ nb_tcp.buf = ai_tcp->ai_addr;
+ nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp,
+ &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3,
+ nconf_tcp, &nb_tcp)))
+ err(1, "rpcb_set tcp failed");
+ freeaddrinfo(ai_tcp);
}
- FD_SET(tcpsock, &sockbits);
- maxsock = tcpsock;
- connect_type_cnt++;
}
-#ifdef notyet
- /* Now set up the master server socket waiting for tp4 connections. */
- if (tp4flag) {
- if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
- syslog(LOG_ERR, "can't create tp4 socket");
- exit(1);
- }
- if (setsockopt(tp4sock,
- SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
- memset(&isoaddr, 0, sizeof(isoaddr));
- isoaddr.siso_family = AF_ISO;
- isoaddr.siso_tlen = 2;
- cp = TSEL(&isoaddr);
- *cp++ = (NFS_PORT >> 8);
- *cp = (NFS_PORT & 0xff);
- isoaddr.siso_len = sizeof(isoaddr);
- if (bind(tp4sock,
- (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
- syslog(LOG_ERR, "can't bind tp4 addr");
- exit(1);
- }
- if (listen(tp4sock, 5) < 0) {
- syslog(LOG_ERR, "listen failed");
- exit(1);
+ /* Set up the socket for tcp6 and rpcb register it. */
+ if (tcpflag && ip6flag) {
+ rpcbreg = 0;
+ for (i = 0; i < bindhostc; i++) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
+ rpcbreg = 1;
+ rpcbregcnt++;
+ if ((tcp6sock = socket(ai_tcp6->ai_family,
+ ai_tcp6->ai_socktype,
+ ai_tcp6->ai_protocol)) < 0) {
+ syslog(LOG_ERR,
+ "can't create tcp6 socket");
+ exit(1);
+ }
+ if (setsockopt(tcp6sock, SOL_SOCKET,
+ SO_REUSEADDR,
+ (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_REUSEADDR: %m");
+ if (setsockopt(tcp6sock, IPPROTO_IPV6,
+ IPV6_BINDV6ONLY, &on, sizeof on) < 0) {
+ syslog(LOG_ERR,
+ "can't set v6-only binding for tcp6 "
+ "socket: %m");
+ exit(1);
+ }
+ if (bind(tcp6sock, ai_tcp6->ai_addr,
+ ai_tcp6->ai_addrlen) < 0) {
+ syslog(LOG_ERR,
+ "can't bind tcp6 addr %s: %m",
+ bindhost[i]);
+ exit(1);
+ }
+ if (listen(tcp6sock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ freeaddrinfo(ai_tcp6);
+ FD_SET(tcp6sock, &sockbits);
+ FD_SET(tcp6sock, &v6bits);
+ if (maxsock < tcp6sock)
+ maxsock = tcp6sock;
+ connect_type_cnt++;
+ }
}
- /*
- * XXX
- * Someday this should probably use "rpcbind", the son of
- * portmap.
- */
- if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register tcp with portmap");
- exit(1);
+ if (rpcbreg == 1) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo tcp6: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_tcp6 = getnetconfigent("tcp6");
+ if (nconf_tcp6 == NULL)
+ err(1, "getnetconfigent tcp6 failed");
+ nb_tcp6.buf = ai_tcp6->ai_addr;
+ nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
+ err(1, "rpcb_set tcp6 failed");
+ freeaddrinfo(ai_tcp6);
}
- FD_SET(tp4sock, &sockbits);
- maxsock = tp4sock;
- connect_type_cnt++;
}
- /* Now set up the master server socket waiting for tpip connections. */
- for (i = 0; tpipflag && i < bindhostc; i++) {
- if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
- syslog(LOG_ERR, "can't create tpip socket");
- exit(1);
- }
- if (setsockopt(tpipsock,
- SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
- setbindhost(&inetaddr, bindhost[i]);
- if (bind(tpipsock,
- (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
- syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]);
- exit(1);
- }
- if (listen(tpipsock, 5) < 0) {
- syslog(LOG_ERR, "listen failed");
- exit(1);
- }
- /*
- * XXX
- * Someday this should probably use "rpcbind", the son of
- * portmap.
- */
- if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register tcp with portmap");
- exit(1);
- }
- FD_SET(tpipsock, &sockbits);
- maxsock = tpipsock;
- connect_type_cnt++;
+ if (rpcbregcnt == 0) {
+ syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
+ exit(1);
}
-#endif /* notyet */
- if (connect_type_cnt == 0)
- exit(0);
+ if ((tcpflag) && (connect_type_cnt == 0)) {
+ syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
+ exit(1);
+ }
setproctitle("master");
@@ -591,82 +794,94 @@ main(argc, argv, envp)
exit(1);
}
}
- if (tcpflag && FD_ISSET(tcpsock, &ready)) {
- len = sizeof(inetpeer);
- if ((msgsock = accept(tcpsock,
- (struct sockaddr *)&inetpeer, &len)) < 0) {
- syslog(LOG_ERR, "accept failed: %m");
- 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");
- nfsdargs.sock = msgsock;
- nfsdargs.name = (caddr_t)&inetpeer;
- nfsdargs.namelen = sizeof(inetpeer);
- nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
- (void)close(msgsock);
- }
-#ifdef notyet
- if (tp4flag && FD_ISSET(tp4sock, &ready)) {
- len = sizeof(isopeer);
- if ((msgsock = accept(tp4sock,
- (struct sockaddr *)&isopeer, &len)) < 0) {
- syslog(LOG_ERR, "accept failed: %m");
- exit(1);
- }
- if (setsockopt(msgsock, SOL_SOCKET,
- SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR,
- "setsockopt SO_KEEPALIVE: %m");
- nfsdargs.sock = msgsock;
- nfsdargs.name = (caddr_t)&isopeer;
- nfsdargs.namelen = len;
- nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
- (void)close(msgsock);
- }
- if (tpipflag && FD_ISSET(tpipsock, &ready)) {
- len = sizeof(inetpeer);
- if ((msgsock = accept(tpipsock,
- (struct sockaddr *)&inetpeer, &len)) < 0) {
- syslog(LOG_ERR, "accept failed: %m");
- exit(1);
+ for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
+ if (FD_ISSET(tcpsock, &ready)) {
+ if (FD_ISSET(tcpsock, &v4bits)) {
+ len = sizeof(inetpeer);
+ if ((msgsock = accept(tcpsock,
+ (struct sockaddr *)&inetpeer, &len)) < 0) {
+ syslog(LOG_ERR, "accept failed: %m");
+ 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");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inetpeer;
+ nfsdargs.namelen = sizeof(inetpeer);
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ } else if (FD_ISSET(tcpsock, &v6bits)) {
+ len = sizeof(inet6peer);
+ if ((msgsock = accept(tcpsock,
+ (struct sockaddr *)&inet6peer,
+ &len)) < 0) {
+ syslog(LOG_ERR,
+ "accept failed: %m");
+ exit(1);
+ }
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on,
+ sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt "
+ "SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inet6peer;
+ nfsdargs.namelen = sizeof(inet6peer);
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ }
}
- if (setsockopt(msgsock, SOL_SOCKET,
- SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
- nfsdargs.sock = msgsock;
- nfsdargs.name = (caddr_t)&inetpeer;
- nfsdargs.namelen = len;
- nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
- (void)close(msgsock);
}
-#endif /* notyet */
}
}
-void
-setbindhost(struct sockaddr_in *ia, const char *bindhost)
+int
+setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
{
- ia->sin_family = AF_INET;
- ia->sin_port = htons(NFS_PORT);
- ia->sin_len = sizeof(*ia);
- if (bindhost == NULL || strcmp(bindhost,"*") == 0) {
- ia->sin_addr.s_addr = INADDR_ANY;
- } else {
- if (inet_aton(bindhost, &ia->sin_addr) == 0) {
- struct hostent *he;
-
- he = gethostbyname2(bindhost, ia->sin_family);
- if (he == NULL) {
- syslog(LOG_ERR, "gethostbyname of %s failed", bindhost);
- exit(1);
+ int ecode;
+ u_int32_t host_addr[4]; /* IPv4 or IPv6 */
+ const char *hostptr;
+
+ if (bindhost == NULL || strcmp("*", bindhost) == 0)
+ hostptr = NULL;
+ else
+ hostptr = bindhost;
+
+ if (hostptr != NULL) {
+ switch (hints.ai_family) {
+ case AF_INET:
+ if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
+ hints.ai_flags = AI_NUMERICHOST;
+ } else {
+ if (inet_pton(AF_INET6, hostptr,
+ host_addr) == 1)
+ return (1);
+ }
+ break;
+ case AF_INET6:
+ if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
+ hints.ai_flags = AI_NUMERICHOST;
+ } else {
+ if (inet_pton(AF_INET, hostptr,
+ host_addr) == 1)
+ return (1);
}
- bcopy(he->h_addr, &ia->sin_addr, he->h_length);
+ break;
+ default:
}
}
+
+ ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
+ gai_strerror(ecode));
+ return (1);
+ }
+ return (0);
}
void
@@ -691,6 +906,48 @@ reapchild(signo)
while (wait3(NULL, WNOHANG, NULL) > 0);
}
+void
+unregistration()
+{
+ if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) ||
+ (!rpcb_unset(RPCPROG_NFS, 3, NULL)))
+ syslog(LOG_ERR, "rpcb_unset failed");
+}
+
+void
+killchildren()
+{
+ int i;
+ sigset_t sigs;
+
+ sigemptyset(&sigs);
+ /*
+ * Block SIGCHLD to avoid killing a reaped process (although it is
+ * unlikely, the pid might have been reused).
+ */
+ sigaddset(&sigs, SIGCHLD);
+ if (sigprocmask(SIG_BLOCK, &sigs, NULL) == -1) {
+ syslog(LOG_ERR, "sigprocmask: %s",
+ strerror(errno));
+ return;
+ }
+ for (i = 0; i < nfsdcnt; i++) {
+ if (children[i] > 0)
+ kill(children[i], SIGKILL);
+ }
+ if (sigprocmask(SIG_UNBLOCK, &sigs, NULL) == -1) {
+ syslog(LOG_ERR, "sigprocmask: %s", strerror(errno));
+ }
+ unregistration();
+}
+
+void
+cleanup(signo)
+{
+ killchildren();
+ exit (0);
+}
+
#ifdef OLD_SETPROCTITLE
#ifdef __FreeBSD__
void
diff --git a/sbin/umount/umount.c b/sbin/umount/umount.c
index e9ef990..2a3a337 100644
--- a/sbin/umount/umount.c
+++ b/sbin/umount/umount.c
@@ -47,6 +47,7 @@ static const char rcsid[] =
#include <sys/param.h>
#include <sys/mount.h>
+#include <sys/socket.h>
#include <netdb.h>
#include <rpc/rpc.h>
@@ -68,6 +69,7 @@ typedef enum { MNTON, MNTFROM, NOTHING } mntwhat;
typedef enum { MARK, UNMARK, NAME, COUNT, FREE } dowhat;
struct mtablist *mtabhead;
+struct addrinfo *nfshost_ai = NULL;
int fflag, vflag;
char *nfshost;
@@ -78,19 +80,22 @@ char *getmntname (const char *, const char *,
char *getrealname(char *, char *resolved_path);
char **makevfslist (const char *);
size_t mntinfo (struct statfs **);
-int namematch (struct hostent *);
+int namematch (struct addrinfo *);
+int sacmp (struct sockaddr *, struct sockaddr *);
int umountall (char **);
-int umountfs (char *, char **);
+int checkname (char *, char **);
+int umountfs (char *, char *, char *);
void usage (void);
int xdr_dir (XDR *, char *);
int
main(int argc, char *argv[])
{
- int all, errs, ch, mntsize;
+ int all, errs, ch, mntsize, error;
char **typelist = NULL, *mntonname, *mntfromname;
char *type, *mntfromnamerev, *mntonnamerev;
struct statfs *mntbuf;
+ struct addrinfo hints;
/* Start disks transferring immediately. */
sync();
@@ -133,6 +138,15 @@ main(int argc, char *argv[])
if ((nfshost != NULL) && (typelist == NULL))
typelist = makevfslist("nfs");
+ if (nfshost != NULL) {
+ memset(&hints, 0, sizeof hints);
+ error = getaddrinfo(nfshost, NULL, &hints, &nfshost_ai);
+ if (error) {
+ fprintf(stderr, "ndp: %s: %s\n", nfshost,
+ gai_strerror(error));
+ }
+ }
+
switch (all) {
case 2:
if ((mntsize = mntinfo(&mntbuf)) <= 0)
@@ -165,7 +179,7 @@ main(int argc, char *argv[])
"is mounted there, umount it first",
mntonname, mntfromnamerev);
- if (umountfs(mntbuf[mntsize].f_mntonname,
+ if (checkname(mntbuf[mntsize].f_mntonname,
typelist) != 0)
errs = 1;
}
@@ -178,7 +192,7 @@ main(int argc, char *argv[])
break;
case 0:
for (errs = 0; *argv != NULL; ++argv)
- if (umountfs(*argv, typelist) != 0)
+ if (checkname(*argv, typelist) != 0)
errs = 1;
break;
}
@@ -228,33 +242,29 @@ umountall(char **typelist)
err(1, "malloc failed");
(void)strcpy(cp, fs->fs_file);
rval = umountall(typelist);
- rval = umountfs(cp, typelist) || rval;
+ rval = checkname(cp, typelist) || rval;
free(cp);
return (rval);
} while ((fs = getfsent()) != NULL);
return (0);
}
+/*
+ * Do magic checks on mountpoint and device or hand over
+ * it to unmount(2) if everything fails.
+ */
int
-umountfs(char *name, char **typelist)
+checkname(char *name, char **typelist)
{
- enum clnt_stat clnt_stat;
- struct hostent *hp;
- struct mtablist *mtab;
- struct sockaddr_in saddr;
- struct timeval pertry, try;
- CLIENT *clp;
size_t len;
- int so, speclen, do_rpc;
+ int speclen;
char *mntonname, *mntfromname;
char *mntfromnamerev;
- char *nfsdirname, *orignfsdirname;
char *resolved, realname[MAXPATHLEN];
- char *type, *delimp, *hostp, *origname;
+ char *type, *hostp, *delimp, *origname;
len = 0;
- mtab = NULL;
- mntfromname = mntonname = delimp = hostp = orignfsdirname = NULL;
+ mntfromname = mntonname = delimp = hostp = NULL;
/*
* 1. Check if the name exists in the mounttable.
@@ -323,14 +333,29 @@ umountfs(char *name, char **typelist)
resolved = realname;
}
/*
- * All tests failed, return to main()
+ * 5. All tests failed, just hand over the
+ * mountpoint to the kernel, maybe the statfs
+ * structure has been truncated or is not
+ * useful anymore because of a chroot(2).
+ * Please note that nfs will not be able to
+ * notify the nfs-server about unmounting.
+ * These things can change in future when the
+ * fstat structure get's more reliable,
+ * but at the moment we cannot thrust it.
*/
if (mntfromname == NULL && mntonname == NULL) {
(void)strcpy(name, origname);
- warnx("%s: not currently mounted",
- origname);
- free(origname);
- return (1);
+ if (umountfs(NULL, origname,
+ "none") == 0) {;
+ warnx("%s not found in "
+ "mount table, "
+ "unmounted it anyway",
+ origname);
+ free(origname);
+ return (0);
+ } else
+ free(origname);
+ return (1);
}
}
}
@@ -341,21 +366,6 @@ umountfs(char *name, char **typelist)
if (checkvfsname(type, typelist))
return (1);
- hp = NULL;
- nfsdirname = NULL;
- if (!strcmp(type, "nfs")) {
- if ((nfsdirname = strdup(mntfromname)) == NULL)
- err(1, "strdup");
- orignfsdirname = nfsdirname;
- if ((delimp = strchr(nfsdirname, ':')) != NULL) {
- *delimp = '\0';
- hostp = nfsdirname;
- if ((hp = gethostbyname(hostp)) == NULL) {
- warnx("can't get net id for host");
- }
- nfsdirname = delimp + 1;
- }
- }
/*
* Check if the reverse entrys of the mounttable are really the
* same as the normal ones.
@@ -383,6 +393,43 @@ umountfs(char *name, char **typelist)
return (1);
}
free(mntfromnamerev);
+ umountfs(mntfromname, mntonname, type);
+}
+
+/*
+ * NFS stuff and unmount(2) call
+ */
+int
+umountfs(char *mntfromname, char *mntonname, char *type)
+{
+ enum clnt_stat clnt_stat;
+ struct timeval try;
+ struct mtablist *mtab;
+ struct addrinfo *ai, hints;
+ int do_rpc;
+ CLIENT *clp;
+ char *nfsdirname, *orignfsdirname;
+ char *hostp, *delimp;
+
+ mtab = NULL;
+ ai = NULL;
+ nfsdirname = delimp = orignfsdirname = NULL;
+ memset(&hints, 0, sizeof hints);
+
+ if (!strcmp(type, "nfs")) {
+ if ((nfsdirname = strdup(mntfromname)) == NULL)
+ err(1, "strdup");
+ orignfsdirname = nfsdirname;
+ if ((delimp = strrchr(nfsdirname, ':')) != NULL) {
+ *delimp = '\0';
+ hostp = nfsdirname;
+ getaddrinfo(hostp, NULL, &hints, &ai);
+ if (ai == NULL) {
+ warnx("can't get net id for host");
+ }
+ nfsdirname = delimp + 1;
+ }
+ }
/*
* Check if we have to start the rpc-call later.
* If there are still identical nfs-names mounted,
@@ -395,7 +442,8 @@ umountfs(char *name, char **typelist)
do_rpc = 1;
else
do_rpc = 0;
- if (!namematch(hp))
+
+ if (!namematch(ai))
return (1);
if (unmount(mntonname, fflag) != 0 ) {
warn("unmount of %s failed", mntonname);
@@ -407,21 +455,13 @@ umountfs(char *name, char **typelist)
* Report to mountd-server which nfsname
* has been unmounted.
*/
- if (hp != NULL && !(fflag & MNT_FORCE) && do_rpc) {
- memset(&saddr, 0, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_port = 0;
- memmove(&saddr.sin_addr, hp->h_addr,
- MIN(hp->h_length, sizeof(saddr.sin_addr)));
- pertry.tv_sec = 3;
- pertry.tv_usec = 0;
- so = RPC_ANYSOCK;
- if ((clp = clntudp_create(&saddr,
- RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
+ if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) {
+ clp = clnt_create(hostp, RPCPROG_MNT, RPCMNT_VER1, "udp");
+ if (clp == NULL) {
clnt_pcreateerror("Cannot MNT PRC");
return (1);
}
- clp->cl_auth = authunix_create_default();
+ clp->cl_auth = authsys_create_default();
try.tv_sec = 20;
try.tv_usec = 0;
clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir,
@@ -554,30 +594,53 @@ getmntname(const char *fromname, const char *onname,
}
int
-namematch(struct hostent *hp)
+sacmp(struct sockaddr *sa1, struct sockaddr *sa2)
{
- char *cp, **np;
+ void *p1, *p2;
+ int len;
- if ((hp == NULL) || (nfshost == NULL))
+ if (sa1->sa_family != sa2->sa_family)
return (1);
- if (strcasecmp(nfshost, hp->h_name) == 0)
- return (1);
-
- if ((cp = strchr(hp->h_name, '.')) != NULL) {
- *cp = '\0';
- if (strcasecmp(nfshost, hp->h_name) == 0)
+ switch (sa1->sa_family) {
+ case AF_INET:
+ p1 = &((struct sockaddr_in *)sa1)->sin_addr;
+ p2 = &((struct sockaddr_in *)sa2)->sin_addr;
+ len = 4;
+ break;
+ case AF_INET6:
+ p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
+ p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
+ len = 16;
+ if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
+ ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
return (1);
+ break;
+ default:
+ return (1);
}
- for (np = hp->h_aliases; *np; np++) {
- if (strcasecmp(nfshost, *np) == 0)
- return (1);
- if ((cp = strchr(*np, '.')) != NULL) {
- *cp = '\0';
- if (strcasecmp(nfshost, *np) == 0)
+
+ return memcmp(p1, p2, len);
+}
+
+int
+namematch(struct addrinfo *ai)
+{
+ struct addrinfo *aip;
+
+ if (nfshost == NULL || nfshost_ai == NULL)
+ return (1);
+
+ while (ai != NULL) {
+ aip = nfshost_ai;
+ while (aip != NULL) {
+ if (sacmp(ai->ai_addr, aip->ai_addr) == 0)
return (1);
+ aip = aip->ai_next;
}
+ ai = ai->ai_next;
}
+
return (0);
}
OpenPOWER on IntegriCloud