1319 lines
36 KiB
Diff
1319 lines
36 KiB
Diff
|
diff --git a/nfs.conf b/nfs.conf
|
||
|
index bebb2e3d..31994f61 100644
|
||
|
--- a/nfs.conf
|
||
|
+++ b/nfs.conf
|
||
|
@@ -24,6 +24,7 @@
|
||
|
# keytab-file=/etc/krb5.keytab
|
||
|
# cred-cache-directory=
|
||
|
# preferred-realm=
|
||
|
+# set-home=1
|
||
|
#
|
||
|
[lockd]
|
||
|
# port=0
|
||
|
@@ -31,8 +32,11 @@
|
||
|
#
|
||
|
[exportd]
|
||
|
# debug="all|auth|call|general|parse"
|
||
|
+# manage-gids=n
|
||
|
# state-directory-path=/var/lib/nfs
|
||
|
# threads=1
|
||
|
+# cache-use-ipaddr=n
|
||
|
+# ttl=1800
|
||
|
[mountd]
|
||
|
# debug="all|auth|call|general|parse"
|
||
|
# manage-gids=n
|
||
|
@@ -42,6 +46,8 @@
|
||
|
# reverse-lookup=n
|
||
|
# state-directory-path=/var/lib/nfs
|
||
|
# ha-callout=
|
||
|
+# cache-use-ipaddr=n
|
||
|
+# ttl=1800
|
||
|
#
|
||
|
[nfsdcld]
|
||
|
# debug=0
|
||
|
@@ -66,9 +72,9 @@
|
||
|
# vers4.0=y
|
||
|
# vers4.1=y
|
||
|
# vers4.2=y
|
||
|
-# rdma=n
|
||
|
-# rdma-port=20049
|
||
|
-#
|
||
|
+rdma=y
|
||
|
+rdma-port=20049
|
||
|
+
|
||
|
[statd]
|
||
|
# debug=0
|
||
|
# port=0
|
||
|
diff --git a/support/export/Makefile.am b/support/export/Makefile.am
|
||
|
index a9e710c0..eec737f6 100644
|
||
|
--- a/support/export/Makefile.am
|
||
|
+++ b/support/export/Makefile.am
|
||
|
@@ -12,7 +12,8 @@ EXTRA_DIST = mount.x
|
||
|
noinst_LIBRARIES = libexport.a
|
||
|
libexport_a_SOURCES = client.c export.c hostname.c \
|
||
|
xtab.c mount_clnt.c mount_xdr.c \
|
||
|
- cache.c auth.c v4root.c fsloc.c
|
||
|
+ cache.c auth.c v4root.c fsloc.c \
|
||
|
+ v4clients.c
|
||
|
BUILT_SOURCES = $(GENFILES)
|
||
|
|
||
|
noinst_HEADERS = mount.h
|
||
|
diff --git a/support/export/auth.c b/support/export/auth.c
|
||
|
index 0bfa77d1..cea37630 100644
|
||
|
--- a/support/export/auth.c
|
||
|
+++ b/support/export/auth.c
|
||
|
@@ -66,6 +66,10 @@ check_useipaddr(void)
|
||
|
int old_use_ipaddr = use_ipaddr;
|
||
|
unsigned int len = 0;
|
||
|
|
||
|
+ if (use_ipaddr > 1)
|
||
|
+ /* fixed - don't check */
|
||
|
+ return;
|
||
|
+
|
||
|
/* add length of m_hostname + 1 for the comma */
|
||
|
for (clp = clientlist[MCL_NETGROUP]; clp; clp = clp->m_next)
|
||
|
len += (strlen(clp->m_hostname) + 1);
|
||
|
diff --git a/support/export/cache.c b/support/export/cache.c
|
||
|
index f1569afb..3e4f53c0 100644
|
||
|
--- a/support/export/cache.c
|
||
|
+++ b/support/export/cache.c
|
||
|
@@ -42,13 +42,6 @@
|
||
|
#include "blkid/blkid.h"
|
||
|
#endif
|
||
|
|
||
|
-/*
|
||
|
- * Invoked by RPC service loop
|
||
|
- */
|
||
|
-void cache_set_fds(fd_set *fdset);
|
||
|
-int cache_process_req(fd_set *readfds);
|
||
|
-void cache_process_loop(void);
|
||
|
-
|
||
|
enum nfsd_fsid {
|
||
|
FSID_DEV = 0,
|
||
|
FSID_NUM,
|
||
|
@@ -96,7 +89,6 @@ static bool path_lookup_error(int err)
|
||
|
* Record is terminated with newline.
|
||
|
*
|
||
|
*/
|
||
|
-static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path);
|
||
|
|
||
|
#define INITIAL_MANAGED_GROUPS 100
|
||
|
|
||
|
@@ -114,6 +106,7 @@ static void auth_unix_ip(int f)
|
||
|
char class[20];
|
||
|
char ipaddr[INET6_ADDRSTRLEN + 1];
|
||
|
char *client = NULL;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
struct addrinfo *tmp = NULL;
|
||
|
char buf[RPC_CHAN_BUF_SIZE], *bp;
|
||
|
int blen;
|
||
|
@@ -139,21 +132,26 @@ static void auth_unix_ip(int f)
|
||
|
|
||
|
auth_reload();
|
||
|
|
||
|
- /* addr is a valid, interesting address, find the domain name... */
|
||
|
- if (!use_ipaddr) {
|
||
|
- struct addrinfo *ai = NULL;
|
||
|
-
|
||
|
- ai = client_resolve(tmp->ai_addr);
|
||
|
- if (ai) {
|
||
|
- client = client_compose(ai);
|
||
|
- nfs_freeaddrinfo(ai);
|
||
|
- }
|
||
|
+ /* addr is a valid address, find the domain name... */
|
||
|
+ ai = client_resolve(tmp->ai_addr);
|
||
|
+ if (ai) {
|
||
|
+ client = client_compose(ai);
|
||
|
+ nfs_freeaddrinfo(ai);
|
||
|
}
|
||
|
+ if (!client)
|
||
|
+ xlog(D_AUTH, "failed authentication for IP %s", ipaddr);
|
||
|
+ else if (!use_ipaddr)
|
||
|
+ xlog(D_AUTH, "successful authentication for IP %s as %s",
|
||
|
+ ipaddr, *client ? client : "DEFAULT");
|
||
|
+ else
|
||
|
+ xlog(D_AUTH, "successful authentication for IP %s",
|
||
|
+ ipaddr);
|
||
|
+
|
||
|
bp = buf; blen = sizeof(buf);
|
||
|
qword_add(&bp, &blen, "nfsd");
|
||
|
qword_add(&bp, &blen, ipaddr);
|
||
|
- qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL);
|
||
|
- if (use_ipaddr) {
|
||
|
+ qword_adduint(&bp, &blen, time(0) + default_ttl);
|
||
|
+ if (use_ipaddr && client) {
|
||
|
memmove(ipaddr + 1, ipaddr, strlen(ipaddr) + 1);
|
||
|
ipaddr[0] = '$';
|
||
|
qword_add(&bp, &blen, ipaddr);
|
||
|
@@ -225,7 +223,7 @@ static void auth_unix_gid(int f)
|
||
|
|
||
|
bp = buf; blen = sizeof(buf);
|
||
|
qword_adduint(&bp, &blen, uid);
|
||
|
- qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL);
|
||
|
+ qword_adduint(&bp, &blen, time(0) + default_ttl);
|
||
|
if (rv >= 0) {
|
||
|
qword_adduint(&bp, &blen, ngroups);
|
||
|
for (i=0; i<ngroups; i++)
|
||
|
@@ -873,18 +871,13 @@ static void nfsd_fh(int f)
|
||
|
!is_mountpoint(found->e_mountpoint[0]?
|
||
|
found->e_mountpoint:
|
||
|
found->e_path)) {
|
||
|
- /* Cannot export this yet
|
||
|
+ /* Cannot export this yet
|
||
|
* should log a warning, but need to rate limit
|
||
|
xlog(L_WARNING, "%s not exported as %d not a mountpoint",
|
||
|
found->e_path, found->e_mountpoint);
|
||
|
*/
|
||
|
/* FIXME we need to make sure we re-visit this later */
|
||
|
goto out;
|
||
|
- } else if (cache_export_ent(buf, sizeof(buf), dom, found, found_path) < 0) {
|
||
|
- if (!path_lookup_error(errno))
|
||
|
- goto out;
|
||
|
- /* The kernel is saying the path is unexportable */
|
||
|
- found = NULL;
|
||
|
}
|
||
|
|
||
|
bp = buf; blen = sizeof(buf);
|
||
|
@@ -905,6 +898,8 @@ static void nfsd_fh(int f)
|
||
|
qword_addeol(&bp, &blen);
|
||
|
if (blen <= 0 || cache_write(f, buf, bp - buf) != bp - buf)
|
||
|
xlog(L_ERROR, "nfsd_fh: error writing reply");
|
||
|
+ if (!found)
|
||
|
+ xlog(D_AUTH, "denied access to %s", *dom == '$' ? dom+1 : dom);
|
||
|
out:
|
||
|
if (found_path)
|
||
|
free(found_path);
|
||
|
@@ -966,7 +961,7 @@ static int dump_to_cache(int f, char *buf, int blen, char *domain,
|
||
|
ssize_t err;
|
||
|
|
||
|
if (ttl <= 1)
|
||
|
- ttl = DEFAULT_TTL;
|
||
|
+ ttl = default_ttl;
|
||
|
|
||
|
qword_add(&bp, &blen, domain);
|
||
|
qword_add(&bp, &blen, path);
|
||
|
@@ -996,8 +991,13 @@ static int dump_to_cache(int f, char *buf, int blen, char *domain,
|
||
|
qword_add(&bp, &blen, "uuid");
|
||
|
qword_addhex(&bp, &blen, u, 16);
|
||
|
}
|
||
|
- } else
|
||
|
+ xlog(D_AUTH, "granted access to %s for %s",
|
||
|
+ path, *domain == '$' ? domain+1 : domain);
|
||
|
+ } else {
|
||
|
qword_adduint(&bp, &blen, now + ttl);
|
||
|
+ xlog(D_AUTH, "denied access to %s for %s",
|
||
|
+ path, *domain == '$' ? domain+1 : domain);
|
||
|
+ }
|
||
|
qword_addeol(&bp, &blen);
|
||
|
if (blen <= 0) {
|
||
|
errno = ENOBUFS;
|
||
|
@@ -1530,6 +1530,7 @@ void cache_process_loop(void)
|
||
|
for (;;) {
|
||
|
|
||
|
cache_set_fds(&readfds);
|
||
|
+ v4clients_set_fds(&readfds);
|
||
|
|
||
|
selret = select(FD_SETSIZE, &readfds,
|
||
|
(void *) 0, (void *) 0, (struct timeval *) 0);
|
||
|
@@ -1545,6 +1546,7 @@ void cache_process_loop(void)
|
||
|
|
||
|
default:
|
||
|
cache_process_req(&readfds);
|
||
|
+ v4clients_process(&readfds);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
diff --git a/support/export/export.h b/support/export/export.h
|
||
|
index 4296db1a..8d5a0d30 100644
|
||
|
--- a/support/export/export.h
|
||
|
+++ b/support/export/export.h
|
||
|
@@ -3,13 +3,14 @@
|
||
|
*
|
||
|
* support/export/export.h
|
||
|
*
|
||
|
- * Declarations for export support
|
||
|
+ * Declarations for export support
|
||
|
*/
|
||
|
|
||
|
#ifndef EXPORT_H
|
||
|
#define EXPORT_H
|
||
|
|
||
|
#include "nfslib.h"
|
||
|
+#include "exportfs.h"
|
||
|
|
||
|
unsigned int auth_reload(void);
|
||
|
nfs_export * auth_authenticate(const char *what,
|
||
|
@@ -17,8 +18,14 @@ nfs_export * auth_authenticate(const char *what,
|
||
|
const char *path);
|
||
|
|
||
|
void cache_open(void);
|
||
|
+void cache_set_fds(fd_set *fdset);
|
||
|
+int cache_process_req(fd_set *readfds);
|
||
|
void cache_process_loop(void);
|
||
|
|
||
|
+void v4clients_init(void);
|
||
|
+void v4clients_set_fds(fd_set *fdset);
|
||
|
+int v4clients_process(fd_set *fdset);
|
||
|
+
|
||
|
struct nfs_fh_len *
|
||
|
cache_get_filehandle(nfs_export *exp, int len, char *p);
|
||
|
int cache_export(nfs_export *exp, char *path);
|
||
|
diff --git a/support/export/v4clients.c b/support/export/v4clients.c
|
||
|
new file mode 100644
|
||
|
index 00000000..dd985463
|
||
|
--- /dev/null
|
||
|
+++ b/support/export/v4clients.c
|
||
|
@@ -0,0 +1,227 @@
|
||
|
+/*
|
||
|
+ * support/export/v4clients.c
|
||
|
+ *
|
||
|
+ * Montior clients appearing in, and disappearing from, /proc/fs/nfsd/clients
|
||
|
+ * and log relevant information.
|
||
|
+ */
|
||
|
+
|
||
|
+#include <unistd.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <sys/inotify.h>
|
||
|
+#include <errno.h>
|
||
|
+#include "export.h"
|
||
|
+
|
||
|
+/* search.h declares 'struct entry' and nfs_prot.h
|
||
|
+ * does too. Easiest fix is to trick search.h into
|
||
|
+ * calling its struct "struct Entry".
|
||
|
+ */
|
||
|
+#define entry Entry
|
||
|
+#include <search.h>
|
||
|
+#undef entry
|
||
|
+
|
||
|
+static int clients_fd = -1;
|
||
|
+
|
||
|
+void v4clients_init(void)
|
||
|
+{
|
||
|
+ if (clients_fd >= 0)
|
||
|
+ return;
|
||
|
+ clients_fd = inotify_init1(IN_NONBLOCK);
|
||
|
+ if (clients_fd < 0) {
|
||
|
+ xlog_err("Unable to initialise v4clients watcher: %s\n",
|
||
|
+ strerror(errno));
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ if (inotify_add_watch(clients_fd, "/proc/fs/nfsd/clients",
|
||
|
+ IN_CREATE | IN_DELETE) < 0) {
|
||
|
+ xlog_err("Unable to watch /proc/fs/nfsd/clients: %s\n",
|
||
|
+ strerror(errno));
|
||
|
+ close(clients_fd);
|
||
|
+ clients_fd = -1;
|
||
|
+ return;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+void v4clients_set_fds(fd_set *fdset)
|
||
|
+{
|
||
|
+ if (clients_fd >= 0)
|
||
|
+ FD_SET(clients_fd, fdset);
|
||
|
+}
|
||
|
+
|
||
|
+static void *tree_root;
|
||
|
+static int have_unconfirmed;
|
||
|
+
|
||
|
+struct ent {
|
||
|
+ unsigned long num;
|
||
|
+ char *clientid;
|
||
|
+ char *addr;
|
||
|
+ int vers;
|
||
|
+ int unconfirmed;
|
||
|
+ int wid;
|
||
|
+};
|
||
|
+
|
||
|
+static int ent_cmp(const void *av, const void *bv)
|
||
|
+{
|
||
|
+ const struct ent *a = av;
|
||
|
+ const struct ent *b = bv;
|
||
|
+
|
||
|
+ if (a->num < b->num)
|
||
|
+ return -1;
|
||
|
+ if (a->num > b->num)
|
||
|
+ return 1;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static void free_ent(struct ent *ent)
|
||
|
+{
|
||
|
+ free(ent->clientid);
|
||
|
+ free(ent->addr);
|
||
|
+ free(ent);
|
||
|
+}
|
||
|
+
|
||
|
+static char *dup_line(char *line)
|
||
|
+{
|
||
|
+ char *ret;
|
||
|
+ char *e = strchr(line, '\n');
|
||
|
+ if (!e)
|
||
|
+ e = line + strlen(line);
|
||
|
+ ret = malloc(e - line + 1);
|
||
|
+ if (ret) {
|
||
|
+ memcpy(ret, line, e - line);
|
||
|
+ ret[e-line] = 0;
|
||
|
+ }
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static void read_info(struct ent *key)
|
||
|
+{
|
||
|
+ char buf[2048];
|
||
|
+ char *path;
|
||
|
+ int was_unconfirmed = key->unconfirmed;
|
||
|
+ FILE *f;
|
||
|
+
|
||
|
+ if (asprintf(&path, "/proc/fs/nfsd/clients/%lu/info", key->num) < 0)
|
||
|
+ return;
|
||
|
+
|
||
|
+ f = fopen(path, "r");
|
||
|
+ if (!f) {
|
||
|
+ free(path);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ if (key->wid < 0)
|
||
|
+ key->wid = inotify_add_watch(clients_fd, path, IN_MODIFY);
|
||
|
+
|
||
|
+ while (fgets(buf, sizeof(buf), f)) {
|
||
|
+ if (strncmp(buf, "clientid: ", 10) == 0) {
|
||
|
+ free(key->clientid);
|
||
|
+ key->clientid = dup_line(buf+10);
|
||
|
+ }
|
||
|
+ if (strncmp(buf, "address: ", 9) == 0) {
|
||
|
+ free(key->addr);
|
||
|
+ key->addr = dup_line(buf+9);
|
||
|
+ }
|
||
|
+ if (strncmp(buf, "minor version: ", 15) == 0)
|
||
|
+ key->vers = atoi(buf+15);
|
||
|
+ if (strncmp(buf, "status: ", 8) == 0 &&
|
||
|
+ strstr(buf, " unconfirmed") != NULL) {
|
||
|
+ key->unconfirmed = 1;
|
||
|
+ have_unconfirmed = 1;
|
||
|
+ }
|
||
|
+ if (strncmp(buf, "status: ", 8) == 0 &&
|
||
|
+ strstr(buf, " confirmed") != NULL)
|
||
|
+ key->unconfirmed = 0;
|
||
|
+ }
|
||
|
+ fclose(f);
|
||
|
+ free(path);
|
||
|
+
|
||
|
+ if (was_unconfirmed && !key->unconfirmed)
|
||
|
+ xlog(L_NOTICE, "v4.%d client attached: %s from %s",
|
||
|
+ key->vers, key->clientid ?: "-none-",
|
||
|
+ key->addr ?: "-none-");
|
||
|
+ if (!key->unconfirmed && key->wid >= 0) {
|
||
|
+ inotify_rm_watch(clients_fd, key->wid);
|
||
|
+ key->wid = -1;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void add_id(int id)
|
||
|
+{
|
||
|
+ struct ent **ent;
|
||
|
+ struct ent *key;
|
||
|
+
|
||
|
+ key = calloc(1, sizeof(*key));
|
||
|
+ if (!key) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ key->num = id;
|
||
|
+ key->wid = -1;
|
||
|
+
|
||
|
+ ent = tsearch(key, &tree_root, ent_cmp);
|
||
|
+
|
||
|
+ if (!ent || *ent != key)
|
||
|
+ /* Already existed, or insertion failed */
|
||
|
+ free_ent(key);
|
||
|
+ else
|
||
|
+ read_info(key);
|
||
|
+}
|
||
|
+
|
||
|
+static void del_id(unsigned long id)
|
||
|
+{
|
||
|
+ struct ent key = {.num = id};
|
||
|
+ struct ent **e, *ent;
|
||
|
+
|
||
|
+ e = tfind(&key, &tree_root, ent_cmp);
|
||
|
+ if (!e || !*e)
|
||
|
+ return;
|
||
|
+ ent = *e;
|
||
|
+ tdelete(ent, &tree_root, ent_cmp);
|
||
|
+ if (!ent->unconfirmed)
|
||
|
+ xlog(L_NOTICE, "v4.%d client detached: %s from %s",
|
||
|
+ ent->vers, ent->clientid, ent->addr);
|
||
|
+ if (ent->wid >= 0)
|
||
|
+ inotify_rm_watch(clients_fd, ent->wid);
|
||
|
+ free_ent(ent);
|
||
|
+}
|
||
|
+
|
||
|
+static void check_id(unsigned long id)
|
||
|
+{
|
||
|
+ struct ent key = {.num = id};
|
||
|
+ struct ent **e, *ent;
|
||
|
+
|
||
|
+ e = tfind(&key, &tree_root, ent_cmp);
|
||
|
+ if (!e || !*e)
|
||
|
+ return;
|
||
|
+ ent = *e;
|
||
|
+ if (ent->unconfirmed)
|
||
|
+ read_info(ent);
|
||
|
+}
|
||
|
+
|
||
|
+int v4clients_process(fd_set *fdset)
|
||
|
+{
|
||
|
+ char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
|
||
|
+ const struct inotify_event *ev;
|
||
|
+ ssize_t len;
|
||
|
+ char *ptr;
|
||
|
+
|
||
|
+ if (clients_fd < 0 ||
|
||
|
+ !FD_ISSET(clients_fd, fdset))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ while ((len = read(clients_fd, buf, sizeof(buf))) > 0) {
|
||
|
+ for (ptr = buf; ptr < buf + len;
|
||
|
+ ptr += sizeof(struct inotify_event) + ev->len) {
|
||
|
+ int id;
|
||
|
+ ev = (const struct inotify_event *)ptr;
|
||
|
+
|
||
|
+ id = atoi(ev->name);
|
||
|
+ if (id <= 0)
|
||
|
+ continue;
|
||
|
+ if (ev->mask & IN_CREATE)
|
||
|
+ add_id(id);
|
||
|
+ if (ev->mask & IN_DELETE)
|
||
|
+ del_id(id);
|
||
|
+ if (ev->mask & IN_MODIFY)
|
||
|
+ check_id(id);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return 1;
|
||
|
+}
|
||
|
diff --git a/support/export/v4root.c b/support/export/v4root.c
|
||
|
index 6f640aa9..3654bd7c 100644
|
||
|
--- a/support/export/v4root.c
|
||
|
+++ b/support/export/v4root.c
|
||
|
@@ -45,7 +45,7 @@ static nfs_export pseudo_root = {
|
||
|
.e_nsqgids = 0,
|
||
|
.e_fsid = 0,
|
||
|
.e_mountpoint = NULL,
|
||
|
- .e_ttl = DEFAULT_TTL,
|
||
|
+ .e_ttl = 0,
|
||
|
},
|
||
|
.m_exported = 0,
|
||
|
.m_xtabent = 1,
|
||
|
@@ -84,6 +84,7 @@ v4root_create(char *path, nfs_export *export)
|
||
|
struct exportent *curexp = &export->m_export;
|
||
|
|
||
|
dupexportent(&eep, &pseudo_root.m_export);
|
||
|
+ eep.e_ttl = default_ttl;
|
||
|
eep.e_hostname = curexp->e_hostname;
|
||
|
strncpy(eep.e_path, path, sizeof(eep.e_path)-1);
|
||
|
if (strcmp(path, "/") != 0)
|
||
|
diff --git a/support/include/exportfs.h b/support/include/exportfs.h
|
||
|
index daa7e2a0..81d13721 100644
|
||
|
--- a/support/include/exportfs.h
|
||
|
+++ b/support/include/exportfs.h
|
||
|
@@ -105,7 +105,8 @@ typedef struct mexport {
|
||
|
} nfs_export;
|
||
|
|
||
|
#define HASH_TABLE_SIZE 1021
|
||
|
-#define DEFAULT_TTL (30 * 60)
|
||
|
+
|
||
|
+extern int default_ttl;
|
||
|
|
||
|
typedef struct _exp_hash_entry {
|
||
|
nfs_export * p_first;
|
||
|
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
|
||
|
index 037febd0..2c8f0752 100644
|
||
|
--- a/support/nfs/exports.c
|
||
|
+++ b/support/nfs/exports.c
|
||
|
@@ -47,6 +47,8 @@ struct flav_info flav_map[] = {
|
||
|
|
||
|
const int flav_map_size = sizeof(flav_map)/sizeof(flav_map[0]);
|
||
|
|
||
|
+int default_ttl = 30 * 60;
|
||
|
+
|
||
|
static char *efname = NULL;
|
||
|
static XFILE *efp = NULL;
|
||
|
static int first;
|
||
|
@@ -100,7 +102,7 @@ static void init_exportent (struct exportent *ee, int fromkernel)
|
||
|
ee->e_nsquids = 0;
|
||
|
ee->e_nsqgids = 0;
|
||
|
ee->e_uuid = NULL;
|
||
|
- ee->e_ttl = DEFAULT_TTL;
|
||
|
+ ee->e_ttl = default_ttl;
|
||
|
}
|
||
|
|
||
|
struct exportent *
|
||
|
diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man
|
||
|
index d2187f8a..4436a38a 100644
|
||
|
--- a/systemd/nfs.conf.man
|
||
|
+++ b/systemd/nfs.conf.man
|
||
|
@@ -132,12 +132,22 @@ but on the server, this will resolve to the path
|
||
|
.B exportd
|
||
|
Recognized values:
|
||
|
.BR threads ,
|
||
|
+.BR cache-use-upaddr ,
|
||
|
+.BR ttl ,
|
||
|
.BR state-directory-path
|
||
|
|
||
|
See
|
||
|
.BR exportd (8)
|
||
|
for details.
|
||
|
|
||
|
+Note that setting
|
||
|
+.B "\[dq]debug = auth\[dq]"
|
||
|
+for
|
||
|
+.B exportd
|
||
|
+is equivalent to providing the
|
||
|
+.B \-\-log\-auth
|
||
|
+option.
|
||
|
+
|
||
|
.TP
|
||
|
.B nfsdcltrack
|
||
|
Recognized values:
|
||
|
@@ -188,6 +198,8 @@ Recognized values:
|
||
|
.BR port ,
|
||
|
.BR threads ,
|
||
|
.BR reverse-lookup ,
|
||
|
+.BR cache-use-upaddr ,
|
||
|
+.BR ttl ,
|
||
|
.BR state-directory-path ,
|
||
|
.BR ha-callout .
|
||
|
|
||
|
@@ -197,6 +209,14 @@ section, are used to configure mountd. See
|
||
|
.BR rpc.mountd (8)
|
||
|
for details.
|
||
|
|
||
|
+Note that setting
|
||
|
+.B "\[dq]debug = auth\[dq]"
|
||
|
+for
|
||
|
+.B mountd
|
||
|
+is equivalent to providing the
|
||
|
+.B \-\-log\-auth
|
||
|
+option.
|
||
|
+
|
||
|
The
|
||
|
.B state-directory-path
|
||
|
value in the
|
||
|
@@ -253,7 +273,8 @@ Recognized values:
|
||
|
.BR rpc-timeout ,
|
||
|
.BR keytab-file ,
|
||
|
.BR cred-cache-directory ,
|
||
|
-.BR preferred-realm .
|
||
|
+.BR preferred-realm ,
|
||
|
+.BR set-home .
|
||
|
|
||
|
See
|
||
|
.BR rpc.gssd (8)
|
||
|
diff --git a/tools/nfsdclnts/nfsdclnts.py b/tools/nfsdclnts/nfsdclnts.py
|
||
|
index 5e7e03c2..b7280f2c 100755
|
||
|
--- a/tools/nfsdclnts/nfsdclnts.py
|
||
|
+++ b/tools/nfsdclnts/nfsdclnts.py
|
||
|
@@ -223,6 +223,7 @@ def nfsd4_show():
|
||
|
|
||
|
global verbose
|
||
|
verbose = False
|
||
|
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
||
|
if args.verbose:
|
||
|
verbose = True
|
||
|
|
||
|
diff --git a/utils/exportd/exportd.c b/utils/exportd/exportd.c
|
||
|
index 7130bcbf..f36f51d2 100644
|
||
|
--- a/utils/exportd/exportd.c
|
||
|
+++ b/utils/exportd/exportd.c
|
||
|
@@ -42,9 +42,14 @@ static struct option longopts[] =
|
||
|
{ "foreground", 0, 0, 'F' },
|
||
|
{ "debug", 1, 0, 'd' },
|
||
|
{ "help", 0, 0, 'h' },
|
||
|
+ { "manage-gids", 0, 0, 'g' },
|
||
|
{ "num-threads", 1, 0, 't' },
|
||
|
+ { "log-auth", 0, 0, 'l' },
|
||
|
+ { "cache-use-ipaddr", 0, 0, 'i' },
|
||
|
+ { "ttl", 0, 0, 'T' },
|
||
|
{ NULL, 0, 0, 0 }
|
||
|
};
|
||
|
+static char shortopts[] = "d:fghs:t:liT:";
|
||
|
|
||
|
/*
|
||
|
* Signal handlers.
|
||
|
@@ -174,33 +179,43 @@ usage(const char *prog, int n)
|
||
|
{
|
||
|
fprintf(stderr,
|
||
|
"Usage: %s [-f|--foreground] [-h|--help] [-d kind|--debug kind]\n"
|
||
|
+" [-g|--manage-gids] [-l|--log-auth] [-i|--cache-use-ipaddr] [-T|--ttl ttl]\n"
|
||
|
" [-s|--state-directory-path path]\n"
|
||
|
" [-t num|--num-threads=num]\n", prog);
|
||
|
exit(n);
|
||
|
}
|
||
|
|
||
|
-inline static void
|
||
|
+inline static void
|
||
|
read_exportd_conf(char *progname, char **argv)
|
||
|
{
|
||
|
char *s;
|
||
|
+ int ttl;
|
||
|
|
||
|
conf_init_file(NFS_CONFFILE);
|
||
|
|
||
|
xlog_set_debug(progname);
|
||
|
|
||
|
+ manage_gids = conf_get_bool("exportd", "manage-gids", manage_gids);
|
||
|
num_threads = conf_get_num("exportd", "threads", num_threads);
|
||
|
+ if (conf_get_bool("mountd", "cache-use-ipaddr", 0))
|
||
|
+ use_ipaddr = 2;
|
||
|
|
||
|
s = conf_get_str("exportd", "state-directory-path");
|
||
|
if (s && !state_setup_basedir(argv[0], s))
|
||
|
exit(1);
|
||
|
+
|
||
|
+ ttl = conf_get_num("mountd", "ttl", default_ttl);
|
||
|
+ if (ttl > 0)
|
||
|
+ default_ttl = ttl;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
char *progname;
|
||
|
- int foreground = 0;
|
||
|
- int c;
|
||
|
+ int foreground = 0;
|
||
|
+ int c;
|
||
|
+ int ttl;
|
||
|
|
||
|
/* Set the basename */
|
||
|
if ((progname = strrchr(argv[0], '/')) != NULL)
|
||
|
@@ -214,17 +229,35 @@ main(int argc, char **argv)
|
||
|
/* Read in config setting */
|
||
|
read_exportd_conf(progname, argv);
|
||
|
|
||
|
- while ((c = getopt_long(argc, argv, "d:fhs:t:", longopts, NULL)) != EOF) {
|
||
|
+ while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF) {
|
||
|
switch (c) {
|
||
|
case 'd':
|
||
|
xlog_sconfig(optarg, 1);
|
||
|
break;
|
||
|
+ case 'l':
|
||
|
+ xlog_sconfig("auth", 1);
|
||
|
+ break;
|
||
|
case 'f':
|
||
|
foreground++;
|
||
|
break;
|
||
|
+ case 'g':
|
||
|
+ manage_gids = 1;
|
||
|
+ break;
|
||
|
case 'h':
|
||
|
usage(progname, 0);
|
||
|
break;
|
||
|
+ case 'i':
|
||
|
+ use_ipaddr = 2;
|
||
|
+ break;
|
||
|
+ case 'T':
|
||
|
+ ttl = atoi(optarg);
|
||
|
+ if (ttl <= 0) {
|
||
|
+ fprintf(stderr, "%s: bad ttl number of seconds: %s\n",
|
||
|
+ argv[0], optarg);
|
||
|
+ usage(argv[0], 1);
|
||
|
+ }
|
||
|
+ default_ttl = ttl;
|
||
|
+ break;
|
||
|
case 's':
|
||
|
if (!state_setup_basedir(argv[0], optarg))
|
||
|
exit(1);
|
||
|
@@ -241,8 +274,8 @@ main(int argc, char **argv)
|
||
|
|
||
|
if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab))
|
||
|
return 1;
|
||
|
-
|
||
|
- if (!foreground)
|
||
|
+
|
||
|
+ if (!foreground)
|
||
|
xlog_stderr(0);
|
||
|
|
||
|
daemon_init(foreground);
|
||
|
@@ -264,6 +297,7 @@ main(int argc, char **argv)
|
||
|
|
||
|
/* Open files now to avoid sharing descriptors among forked processes */
|
||
|
cache_open();
|
||
|
+ v4clients_init();
|
||
|
|
||
|
/* Process incoming upcalls */
|
||
|
cache_process_loop();
|
||
|
diff --git a/utils/exportd/exportd.man b/utils/exportd/exportd.man
|
||
|
index 1d65b5e0..b238ff05 100644
|
||
|
--- a/utils/exportd/exportd.man
|
||
|
+++ b/utils/exportd/exportd.man
|
||
|
@@ -10,35 +10,74 @@ nfsv4.exportd \- NFSv4 Server Mount Daemon
|
||
|
.SH DESCRIPTION
|
||
|
The
|
||
|
.B nfsv4.exportd
|
||
|
-is used to manage NFSv4 exports. The NFSv4 server
|
||
|
-receives a mount request from a client and pass it up to
|
||
|
-.B nfsv4.exportd.
|
||
|
-.B nfsv4.exportd
|
||
|
-then uses the exports(5) export
|
||
|
-table to verify the validity of the mount request.
|
||
|
-.PP
|
||
|
-An NFS server maintains a table of local physical file systems
|
||
|
-that are accessible to NFS clients.
|
||
|
-Each file system in this table is referred to as an
|
||
|
-.IR "exported file system" ,
|
||
|
-or
|
||
|
-.IR export ,
|
||
|
-for short.
|
||
|
-.PP
|
||
|
-Each file system in the export table has an access control list.
|
||
|
+is used to manage NFSv4 exports.
|
||
|
+The NFS server
|
||
|
+.RI ( nfsd )
|
||
|
+maintains a cache of authentication and authorization information which
|
||
|
+is used to identify the source of each requent, and then what access
|
||
|
+permissions that source has to any local filesystem. When required
|
||
|
+information is not found in the cache, the server sends a request to
|
||
|
.B nfsv4.exportd
|
||
|
-uses these access control lists to determine
|
||
|
-whether an NFS client is permitted to access a given file system.
|
||
|
-For details on how to manage your NFS server's export table, see the
|
||
|
-.BR exports (5)
|
||
|
-and
|
||
|
-.BR exportfs (8)
|
||
|
-man pages.
|
||
|
+to fill in the missing information.
|
||
|
+.B nfsv4.exportd
|
||
|
+uses a table of information stored in
|
||
|
+.B /var/lib/nfs/etab
|
||
|
+and maintained by
|
||
|
+.BR exportfs (8),
|
||
|
+possibly based on the contents of
|
||
|
+.BR exports (5),
|
||
|
+to respond to each request.
|
||
|
.SH OPTIONS
|
||
|
.TP
|
||
|
.B \-d kind " or " \-\-debug kind
|
||
|
Turn on debugging. Valid kinds are: all, auth, call, general and parse.
|
||
|
.TP
|
||
|
+.BR \-l " or " \-\-log\-auth
|
||
|
+Enable logging of responses to authentication and access requests from
|
||
|
+nfsd. Each response is then cached by the kernel for 30 minutes (or as set by
|
||
|
+.B \-\-ttl
|
||
|
+below), and will be refreshed after 15 minutes (half the ttl time) if
|
||
|
+the relevant client remains active.
|
||
|
+Note that
|
||
|
+.B -l
|
||
|
+is equivalent to
|
||
|
+.B "-d auth"
|
||
|
+and so can be enabled in
|
||
|
+.B /etc/nfs.conf
|
||
|
+with
|
||
|
+.B "\[dq]debug = auth\[dq]"
|
||
|
+in the
|
||
|
+.B "[exportd]"
|
||
|
+section.
|
||
|
+.TP
|
||
|
+.BR \-i " or " \-\-cache\-use\-ipaddr
|
||
|
+Normally each client IP address is matched against each host identifier
|
||
|
+(name, wildcard, netgroup etc) found in
|
||
|
+.B /etc/exports
|
||
|
+and a combined identity is formed from all matching identifiers.
|
||
|
+Often many clients will map to the same combined identity so performing
|
||
|
+this mapping reduces the number of distinct access details that the
|
||
|
+kernel needs to store.
|
||
|
+Specifying the
|
||
|
+.B \-i
|
||
|
+option suppresses this mapping so that access to each filesystem is
|
||
|
+requested and cached separately for each client IP address. Doing this
|
||
|
+can increase the burden of updating the cache slightly, but can make the
|
||
|
+log messages produced by the
|
||
|
+.B -l
|
||
|
+option easier to read.
|
||
|
+.TP
|
||
|
+.B \-T " or " \-\-ttl
|
||
|
+Provide a time-to-live (TTL) for cached information given to the kernel.
|
||
|
+The kernel will normally request an update if the information is needed
|
||
|
+after half of this time has expired. Increasing the provided number,
|
||
|
+which is in seconds, reduces the rate of cache update requests, and this
|
||
|
+is particularly noticeable when these requests are logged with
|
||
|
+.BR \-l .
|
||
|
+However increasing also means that changes to hostname to address
|
||
|
+mappings can take longer to be noticed.
|
||
|
+The default TTL is 1800 (30 minutes).
|
||
|
+.TP
|
||
|
.B \-F " or " \-\-foreground
|
||
|
Run in foreground (do not daemonize)
|
||
|
.TP
|
||
|
@@ -46,11 +85,27 @@ Run in foreground (do not daemonize)
|
||
|
Display usage message.
|
||
|
.TP
|
||
|
.BR "\-t N" " or " "\-\-num\-threads=N " or " \-\-num\-threads N "
|
||
|
-This option specifies the number of worker threads that rpc.mountd
|
||
|
+This option specifies the number of worker threads that
|
||
|
+.B nfsv4.exports
|
||
|
spawns. The default is 1 thread, which is probably enough. More
|
||
|
threads are usually only needed for NFS servers which need to handle
|
||
|
mount storms of hundreds of NFS mounts in a few seconds, or when
|
||
|
your DNS server is slow or unreliable.
|
||
|
+.TP
|
||
|
+.BR \-g " or " \-\-manage-gids
|
||
|
+Accept requests from the kernel to map user id numbers into lists of
|
||
|
+group id numbers for use in access control. An NFS request will
|
||
|
+normally (except when using Kerberos or other cryptographic
|
||
|
+authentication) contain a user-id and a list of group-ids. Due to a
|
||
|
+limitation in the NFS protocol, at most 16 groups ids can be listed.
|
||
|
+If you use the
|
||
|
+.B \-g
|
||
|
+flag, then the list of group ids received from the client will be
|
||
|
+replaced by a list of group ids determined by an appropriate lookup on
|
||
|
+the server. Note that the 'primary' group id is not affected so a
|
||
|
+.B newgroup
|
||
|
+command on the client will still be effective. This function requires
|
||
|
+a Linux Kernel with version at least 2.6.21.
|
||
|
.SH CONFIGURATION FILE
|
||
|
Many of the options that can be set on the command line can also be
|
||
|
controlled through values set in the
|
||
|
@@ -63,6 +118,9 @@ configuration file.
|
||
|
Values recognized in the
|
||
|
.B [exportd]
|
||
|
section include
|
||
|
+.B cache\-use\-ipaddr ,
|
||
|
+.BR ttl ,
|
||
|
+.BR manage-gids ", and"
|
||
|
.B debug
|
||
|
which each have the same effect as the option with the same name.
|
||
|
.SH FILES
|
||
|
@@ -78,4 +136,6 @@ listing exports, export options, and access control lists
|
||
|
.BR nfs.conf (5),
|
||
|
.BR firwall-cmd (1),
|
||
|
.sp
|
||
|
-RFC 3530 - "Network File System (NFS) version 4 Protocol"
|
||
|
+RFC 7530 - "Network File System (NFS) Version 4 Protocol"
|
||
|
+.br
|
||
|
+RFC 8881 - "Network File System (NFS) Version 4 Minor Version 1 Protocol"
|
||
|
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
|
||
|
index 262dd19a..25d757d8 100644
|
||
|
--- a/utils/exportfs/exportfs.c
|
||
|
+++ b/utils/exportfs/exportfs.c
|
||
|
@@ -383,7 +383,7 @@ unexportfs_parsed(char *hname, char *path, int verbose)
|
||
|
* so need to deal with it.
|
||
|
*/
|
||
|
size_t nlen = strlen(path);
|
||
|
- while (path[nlen - 1] == '/')
|
||
|
+ while ((nlen > 1) && (path[nlen - 1] == '/'))
|
||
|
nlen--;
|
||
|
|
||
|
for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
|
||
|
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
|
||
|
index 85bc4b07..1541d371 100644
|
||
|
--- a/utils/gssd/gssd.c
|
||
|
+++ b/utils/gssd/gssd.c
|
||
|
@@ -87,6 +87,8 @@ unsigned int context_timeout = 0;
|
||
|
unsigned int rpc_timeout = 5;
|
||
|
char *preferred_realm = NULL;
|
||
|
char *ccachedir = NULL;
|
||
|
+/* set $HOME to "/" by default */
|
||
|
+static bool set_home = true;
|
||
|
/* Avoid DNS reverse lookups on server names */
|
||
|
static bool avoid_dns = true;
|
||
|
static bool use_gssproxy = false;
|
||
|
@@ -900,7 +902,7 @@ sig_die(int signal)
|
||
|
static void
|
||
|
usage(char *progname)
|
||
|
{
|
||
|
- fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm] [-D]\n",
|
||
|
+ fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm] [-D] [-H]\n",
|
||
|
progname);
|
||
|
exit(1);
|
||
|
}
|
||
|
@@ -941,6 +943,7 @@ read_gss_conf(void)
|
||
|
preferred_realm = s;
|
||
|
|
||
|
use_gssproxy = conf_get_bool("gssd", "use-gss-proxy", use_gssproxy);
|
||
|
+ set_home = conf_get_bool("gssd", "set-home", set_home);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
@@ -961,7 +964,7 @@ main(int argc, char *argv[])
|
||
|
verbosity = conf_get_num("gssd", "verbosity", verbosity);
|
||
|
rpc_verbosity = conf_get_num("gssd", "rpc-verbosity", rpc_verbosity);
|
||
|
|
||
|
- while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) {
|
||
|
+ while ((opt = getopt(argc, argv, "HDfvrlmnMp:k:d:t:T:R:")) != -1) {
|
||
|
switch (opt) {
|
||
|
case 'f':
|
||
|
fg = 1;
|
||
|
@@ -1009,6 +1012,9 @@ main(int argc, char *argv[])
|
||
|
case 'D':
|
||
|
avoid_dns = false;
|
||
|
break;
|
||
|
+ case 'H':
|
||
|
+ set_home = false;
|
||
|
+ break;
|
||
|
default:
|
||
|
usage(argv[0]);
|
||
|
break;
|
||
|
@@ -1018,13 +1024,19 @@ main(int argc, char *argv[])
|
||
|
/*
|
||
|
* Some krb5 routines try to scrape info out of files in the user's
|
||
|
* home directory. This can easily deadlock when that homedir is on a
|
||
|
- * kerberized NFS mount. By setting $HOME unconditionally to "/", we
|
||
|
- * prevent this behavior in routines that use $HOME in preference to
|
||
|
- * the results of getpw*.
|
||
|
+ * kerberized NFS mount. By setting $HOME to "/" by default, we prevent
|
||
|
+ * this behavior in routines that use $HOME in preference to the results
|
||
|
+ * of getpw*.
|
||
|
+ *
|
||
|
+ * Some users do not use Kerberized home dirs and need $HOME to remain
|
||
|
+ * unchanged. Those users can leave $HOME unchanged by setting set_home
|
||
|
+ * to false.
|
||
|
*/
|
||
|
- if (setenv("HOME", "/", 1)) {
|
||
|
- printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno));
|
||
|
- exit(1);
|
||
|
+ if (set_home) {
|
||
|
+ if (setenv("HOME", "/", 1)) {
|
||
|
+ printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno));
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
if (use_gssproxy) {
|
||
|
diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man
|
||
|
index 26095a89..9ae6def9 100644
|
||
|
--- a/utils/gssd/gssd.man
|
||
|
+++ b/utils/gssd/gssd.man
|
||
|
@@ -8,7 +8,7 @@
|
||
|
rpc.gssd \- RPCSEC_GSS daemon
|
||
|
.SH SYNOPSIS
|
||
|
.B rpc.gssd
|
||
|
-.RB [ \-DfMnlvr ]
|
||
|
+.RB [ \-DfMnlvrH ]
|
||
|
.RB [ \-k
|
||
|
.IR keytab ]
|
||
|
.RB [ \-p
|
||
|
@@ -282,6 +282,16 @@ The default timeout is set to 5 seconds.
|
||
|
If you get messages like "WARNING: can't create tcp rpc_clnt to server
|
||
|
%servername% for user with uid %uid%: RPC: Remote system error -
|
||
|
Connection timed out", you should consider an increase of this timeout.
|
||
|
+.TP
|
||
|
+.B -H
|
||
|
+Avoids setting $HOME to "/". This allows rpc.gssd to read per user k5identity
|
||
|
+files versus trying to read /.k5identity for each user.
|
||
|
+
|
||
|
+If
|
||
|
+.B \-H
|
||
|
+is not set, rpc.gssd will use the first match found in
|
||
|
+/var/kerberos/krb5/user/$EUID/client.keytab and will not use a principal based on
|
||
|
+host and/or service parameters listed in $HOME/.k5identity.
|
||
|
.SH CONFIGURATION FILE
|
||
|
Many of the options that can be set on the command line can also be
|
||
|
controlled through values set in the
|
||
|
@@ -339,6 +349,13 @@ Equivalent to
|
||
|
.B preferred-realm
|
||
|
Equivalent to
|
||
|
.BR -R .
|
||
|
+.TP
|
||
|
+.B set-home
|
||
|
+Setting to
|
||
|
+.B false
|
||
|
+is equivalent to providing the
|
||
|
+.B -H
|
||
|
+flag.
|
||
|
.P
|
||
|
In addtion, the following value is recognized from the
|
||
|
.B [general]
|
||
|
diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
|
||
|
index 612063ba..39e85fd5 100644
|
||
|
--- a/utils/mountd/mountd.c
|
||
|
+++ b/utils/mountd/mountd.c
|
||
|
@@ -31,6 +31,7 @@
|
||
|
#include "pseudoflavors.h"
|
||
|
#include "nfsd_path.h"
|
||
|
#include "nfslib.h"
|
||
|
+#include "export.h"
|
||
|
|
||
|
extern void my_svc_run(void);
|
||
|
|
||
|
@@ -74,8 +75,12 @@ static struct option longopts[] =
|
||
|
{ "reverse-lookup", 0, 0, 'r' },
|
||
|
{ "manage-gids", 0, 0, 'g' },
|
||
|
{ "no-udp", 0, 0, 'u' },
|
||
|
+ { "log-auth", 0, 0, 'l'},
|
||
|
+ { "cache-use-ipaddr", 0, 0, 'i'},
|
||
|
+ { "ttl", 1, 0, 'T'},
|
||
|
{ NULL, 0, 0, 0 }
|
||
|
};
|
||
|
+static char shortopts[] = "o:nFd:p:P:hH:N:V:vurs:t:gliT:";
|
||
|
|
||
|
#define NFSVERSBIT(vers) (0x1 << (vers - 1))
|
||
|
#define NFSVERSBIT_ALL (NFSVERSBIT(2) | NFSVERSBIT(3) | NFSVERSBIT(4))
|
||
|
@@ -669,6 +674,7 @@ inline static void
|
||
|
read_mountd_conf(char **argv)
|
||
|
{
|
||
|
char *s;
|
||
|
+ int ttl;
|
||
|
|
||
|
conf_init_file(NFS_CONFFILE);
|
||
|
|
||
|
@@ -679,6 +685,8 @@ read_mountd_conf(char **argv)
|
||
|
num_threads = conf_get_num("mountd", "threads", num_threads);
|
||
|
reverse_resolve = conf_get_bool("mountd", "reverse-lookup", reverse_resolve);
|
||
|
ha_callout_prog = conf_get_str("mountd", "ha-callout");
|
||
|
+ if (conf_get_bool("mountd", "cache-use-ipaddr", 0))
|
||
|
+ use_ipaddr = 2;
|
||
|
|
||
|
s = conf_get_str("mountd", "state-directory-path");
|
||
|
if (s && !state_setup_basedir(argv[0], s))
|
||
|
@@ -701,6 +709,10 @@ read_mountd_conf(char **argv)
|
||
|
else
|
||
|
NFSCTL_VERUNSET(nfs_version, vers);
|
||
|
}
|
||
|
+
|
||
|
+ ttl = conf_get_num("mountd", "ttl", default_ttl);
|
||
|
+ if (ttl > 0)
|
||
|
+ default_ttl = ttl;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
@@ -710,6 +722,7 @@ main(int argc, char **argv)
|
||
|
unsigned int listeners = 0;
|
||
|
int foreground = 0;
|
||
|
int c;
|
||
|
+ int ttl;
|
||
|
struct sigaction sa;
|
||
|
struct rlimit rlim;
|
||
|
|
||
|
@@ -727,7 +740,7 @@ main(int argc, char **argv)
|
||
|
|
||
|
/* Parse the command line options and arguments. */
|
||
|
opterr = 0;
|
||
|
- while ((c = getopt_long(argc, argv, "o:nFd:p:P:hH:N:V:vurs:t:g", longopts, NULL)) != EOF)
|
||
|
+ while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF)
|
||
|
switch (c) {
|
||
|
case 'g':
|
||
|
manage_gids = 1;
|
||
|
@@ -798,6 +811,21 @@ main(int argc, char **argv)
|
||
|
case 'u':
|
||
|
NFSCTL_UDPUNSET(_rpcprotobits);
|
||
|
break;
|
||
|
+ case 'l':
|
||
|
+ xlog_sconfig("auth", 1);
|
||
|
+ break;
|
||
|
+ case 'i':
|
||
|
+ use_ipaddr = 2;
|
||
|
+ break;
|
||
|
+ case 'T':
|
||
|
+ ttl = atoi(optarg);
|
||
|
+ if (ttl <= 0) {
|
||
|
+ fprintf(stderr, "%s: bad ttl number of seconds: %s\n",
|
||
|
+ argv[0], optarg);
|
||
|
+ usage(argv[0], 1);
|
||
|
+ }
|
||
|
+ default_ttl = ttl;
|
||
|
+ break;
|
||
|
case 0:
|
||
|
break;
|
||
|
case '?':
|
||
|
@@ -897,6 +925,7 @@ main(int argc, char **argv)
|
||
|
nfsd_path_init();
|
||
|
/* Open files now to avoid sharing descriptors among forked processes */
|
||
|
cache_open();
|
||
|
+ v4clients_init();
|
||
|
|
||
|
xlog(L_NOTICE, "Version " VERSION " starting");
|
||
|
my_svc_run();
|
||
|
@@ -913,6 +942,7 @@ usage(const char *prog, int n)
|
||
|
{
|
||
|
fprintf(stderr,
|
||
|
"Usage: %s [-F|--foreground] [-h|--help] [-v|--version] [-d kind|--debug kind]\n"
|
||
|
+" [-l|--log-auth] [-i|--cache-use-ipaddr] [-T|--ttl ttl]\n"
|
||
|
" [-o num|--descriptors num]\n"
|
||
|
" [-p|--port port] [-V version|--nfs-version version]\n"
|
||
|
" [-N version|--no-nfs-version version] [-n|--no-tcp]\n"
|
||
|
diff --git a/utils/mountd/mountd.h b/utils/mountd/mountd.h
|
||
|
index f058f01d..d3077531 100644
|
||
|
--- a/utils/mountd/mountd.h
|
||
|
+++ b/utils/mountd/mountd.h
|
||
|
@@ -60,9 +60,4 @@ bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai);
|
||
|
bool namelist_client_matches(nfs_export *exp, char *dom);
|
||
|
bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai);
|
||
|
|
||
|
-static inline bool is_ipaddr_client(char *dom)
|
||
|
-{
|
||
|
- return dom[0] == '$';
|
||
|
-}
|
||
|
-
|
||
|
#endif /* MOUNTD_H */
|
||
|
diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man
|
||
|
index 9978afcd..1155cf94 100644
|
||
|
--- a/utils/mountd/mountd.man
|
||
|
+++ b/utils/mountd/mountd.man
|
||
|
@@ -13,24 +13,24 @@ The
|
||
|
.B rpc.mountd
|
||
|
daemon implements the server side of the NFS MOUNT protocol,
|
||
|
an NFS side protocol used by NFS version 2 [RFC1094] and NFS version 3 [RFC1813].
|
||
|
+It also responds to requests from the Linux kernel to authenticate
|
||
|
+clients and provides details of access permissions.
|
||
|
.PP
|
||
|
-An NFS server maintains a table of local physical file systems
|
||
|
-that are accessible to NFS clients.
|
||
|
-Each file system in this table is referred to as an
|
||
|
-.IR "exported file system" ,
|
||
|
-or
|
||
|
-.IR export ,
|
||
|
-for short.
|
||
|
-.PP
|
||
|
-Each file system in the export table has an access control list.
|
||
|
-.B rpc.mountd
|
||
|
-uses these access control lists to determine
|
||
|
-whether an NFS client is permitted to access a given file system.
|
||
|
-For details on how to manage your NFS server's export table, see the
|
||
|
-.BR exports (5)
|
||
|
-and
|
||
|
-.BR exportfs (8)
|
||
|
-man pages.
|
||
|
+The NFS server
|
||
|
+.RI ( nfsd )
|
||
|
+maintains a cache of authentication and authorization information which
|
||
|
+is used to identify the source of each requent, and then what access
|
||
|
+permissions that source has to any local filesystem. When required
|
||
|
+information is not found in the cache, the server sends a request to
|
||
|
+.B mountd
|
||
|
+to fill in the missing information. Mountd uses a table of information
|
||
|
+stored in
|
||
|
+.B /var/lib/nfs/etab
|
||
|
+and maintained by
|
||
|
+.BR exportfs (8),
|
||
|
+possibly based on the contents of
|
||
|
+.BR exports (5),
|
||
|
+to respond to each request.
|
||
|
.SS Mounting exported NFS File Systems
|
||
|
The NFS MOUNT protocol has several procedures.
|
||
|
The most important of these are
|
||
|
@@ -78,11 +78,69 @@ A client may continue accessing an export even after invoking UMNT.
|
||
|
If the client reboots without sending a UMNT request, stale entries
|
||
|
remain for that client in
|
||
|
.IR /var/lib/nfs/rmtab .
|
||
|
+.SS Mounting File Systems with NFSv4
|
||
|
+Version 4 (and later) of NFS does not use a separate NFS MOUNT
|
||
|
+protocol. Instead mounting is performed using regular NFS requests
|
||
|
+handled by the NFS server in the Linux kernel
|
||
|
+.RI ( nfsd ).
|
||
|
+Consequently
|
||
|
+.I /var/lib/nfs/rmtab
|
||
|
+is not updated to reflect any NFSv4 activity.
|
||
|
.SH OPTIONS
|
||
|
.TP
|
||
|
.B \-d kind " or " \-\-debug kind
|
||
|
Turn on debugging. Valid kinds are: all, auth, call, general and parse.
|
||
|
.TP
|
||
|
+.BR \-l " or " \-\-log\-auth
|
||
|
+Enable logging of responses to authentication and access requests from
|
||
|
+nfsd. Each response is then cached by the kernel for 30 minutes (or as set by
|
||
|
+.B \-\-ttl
|
||
|
+below), and will be refreshed after 15 minutes (half the ttl time) if
|
||
|
+the relevant client remains active.
|
||
|
+Note that
|
||
|
+.B -l
|
||
|
+is equivalent to
|
||
|
+.B "-d auth"
|
||
|
+and so can be enabled in
|
||
|
+.B /etc/nfs.conf
|
||
|
+with
|
||
|
+.B "\[dq]debug = auth\[dq]"
|
||
|
+in the
|
||
|
+.B "[mountd]"
|
||
|
+section.
|
||
|
+.IP
|
||
|
+.B rpc.mountd
|
||
|
+will always log authentication responses to MOUNT requests when NFSv3 is
|
||
|
+used, but to get similar logs for NFSv4, this option is required.
|
||
|
+.TP
|
||
|
+.BR \-i " or " \-\-cache\-use\-ipaddr
|
||
|
+Normally each client IP address is matched against each host identifier
|
||
|
+(name, wildcard, netgroup etc) found in
|
||
|
+.B /etc/exports
|
||
|
+and a combined identity is formed from all matching identifiers.
|
||
|
+Often many clients will map to the same combined identity so performing
|
||
|
+this mapping reduces the number of distinct access details that the
|
||
|
+kernel needs to store.
|
||
|
+Specifying the
|
||
|
+.B \-i
|
||
|
+option suppresses this mapping so that access to each filesystem is
|
||
|
+requested and cached separately for each client IP address. Doing this
|
||
|
+can increase the burden of updating the cache slightly, but can make the
|
||
|
+log messages produced by the
|
||
|
+.B -l
|
||
|
+option easier to read.
|
||
|
+.TP
|
||
|
+.B \-T " or " \-\-ttl
|
||
|
+Provide a time-to-live (TTL) for cached information given to the kernel.
|
||
|
+The kernel will normally request an update if the information is needed
|
||
|
+after half of this time has expired. Increasing the provided number,
|
||
|
+which is in seconds, reduces the rate of cache update requests, and this
|
||
|
+is particularly noticeable when these requests are logged with
|
||
|
+.BR \-l .
|
||
|
+However increasing also means that changes to hostname to address
|
||
|
+mappings can take longer to be noticed.
|
||
|
+The default TTL is 1800 (30 minutes).
|
||
|
+.TP
|
||
|
.B \-F " or " \-\-foreground
|
||
|
Run in foreground (do not daemonize)
|
||
|
.TP
|
||
|
@@ -213,9 +271,11 @@ Values recognized in the
|
||
|
.B [mountd]
|
||
|
section include
|
||
|
.BR manage-gids ,
|
||
|
+.BR cache\-use\-ipaddr ,
|
||
|
.BR descriptors ,
|
||
|
.BR port ,
|
||
|
.BR threads ,
|
||
|
+.BR ttl ,
|
||
|
.BR reverse-lookup ", and"
|
||
|
.BR state-directory-path ,
|
||
|
.B ha-callout
|
||
|
@@ -295,5 +355,9 @@ table of clients accessing server's exports
|
||
|
RFC 1094 - "NFS: Network File System Protocol Specification"
|
||
|
.br
|
||
|
RFC 1813 - "NFS Version 3 Protocol Specification"
|
||
|
+.br
|
||
|
+RFC 7530 - "Network File System (NFS) Version 4 Protocol"
|
||
|
+.br
|
||
|
+RFC 8881 - "Network File System (NFS) Version 4 Minor Version 1 Protocol"
|
||
|
.SH AUTHOR
|
||
|
Olaf Kirch, H. J. Lu, G. Allan Morris III, and a host of others.
|
||
|
diff --git a/utils/mountd/svc_run.c b/utils/mountd/svc_run.c
|
||
|
index 41b96d7f..167b9757 100644
|
||
|
--- a/utils/mountd/svc_run.c
|
||
|
+++ b/utils/mountd/svc_run.c
|
||
|
@@ -56,10 +56,9 @@
|
||
|
#ifdef HAVE_LIBTIRPC
|
||
|
#include <rpc/rpc_com.h>
|
||
|
#endif
|
||
|
+#include "export.h"
|
||
|
|
||
|
void my_svc_run(void);
|
||
|
-void cache_set_fds(fd_set *fdset);
|
||
|
-int cache_process_req(fd_set *readfds);
|
||
|
|
||
|
#if defined(__GLIBC__) && LONG_MAX != INT_MAX
|
||
|
/* bug in glibc 2.3.6 and earlier, we need
|
||
|
@@ -101,6 +100,7 @@ my_svc_run(void)
|
||
|
|
||
|
readfds = svc_fdset;
|
||
|
cache_set_fds(&readfds);
|
||
|
+ v4clients_set_fds(&readfds);
|
||
|
|
||
|
selret = select(FD_SETSIZE, &readfds,
|
||
|
(void *) 0, (void *) 0, (struct timeval *) 0);
|
||
|
@@ -116,6 +116,7 @@ my_svc_run(void)
|
||
|
|
||
|
default:
|
||
|
selret -= cache_process_req(&readfds);
|
||
|
+ selret -= v4clients_process(&readfds);
|
||
|
if (selret)
|
||
|
svc_getreqset(&readfds);
|
||
|
}
|