exports: NFSv4 pseudoroot support routines
authorSteve Dickson <steved@redhat.com>
Tue, 1 Dec 2009 12:16:13 +0000 (07:16 -0500)
committerSteve Dickson <steved@redhat.com>
Wed, 13 Jan 2010 20:39:14 +0000 (15:39 -0500)
Create v4root exports for each directory that is a parent of an explicit
export.  Give each the minimal security required to traverse to any of
its children.

Signed-off-by: Steve Dickson <steved@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
support/include/exportfs.h
support/include/v4root.h [new file with mode: 0644]
support/nfs/exports.c
utils/mountd/Makefile.am
utils/mountd/v4root.c [new file with mode: 0644]

index ce7eac0..470b2ec 100644 (file)
@@ -99,6 +99,8 @@ int                           xtab_mount_write(void);
 int                            xtab_export_write(void);
 void                           xtab_append(nfs_export *);
 
+int                            secinfo_addflavor(struct flav_info *, struct exportent *);
+
 int                            rmtab_read(void);
 
 struct nfskey *                        key_lookup(char *hname);
diff --git a/support/include/v4root.h b/support/include/v4root.h
new file mode 100644 (file)
index 0000000..706c15c
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2009 Red Hat <nfs@redhat.com>
+ * support/include/v4root.h
+ *
+ * Support routines for dynamic pseudo roots.
+ *
+ */
+
+#ifndef V4ROOT_H
+#define V4ROOT_H
+
+extern int v4root_needed;
+extern void v4root_set(void);
+
+#endif /* V4ROOT_H */
index ef31a85..50e83a8 100644 (file)
@@ -385,7 +385,7 @@ static int valid_uuid(char *uuid)
  * do nothing if it's already there.  Returns the index of flavor
  * in the resulting array in any case.
  */
-static int secinfo_addflavor(struct flav_info *flav, struct exportent *ep)
+int secinfo_addflavor(struct flav_info *flav, struct exportent *ep)
 {
        struct sec_entry *p;
 
index 1e76cf8..eba81fc 100644 (file)
@@ -8,7 +8,7 @@ KPREFIX         = @kprefix@
 sbin_PROGRAMS  = mountd
 
 mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
-                svc_run.c fsloc.c mountd.h
+                svc_run.c fsloc.c v4root.c mountd.h
 mountd_LDADD = ../../support/export/libexport.a \
               ../../support/nfs/libnfs.a \
               ../../support/misc/libmisc.a \
diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c
new file mode 100644 (file)
index 0000000..d890181
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2009 Red Hat <nfs@redhat.com>
+ *
+ * support/export/v4root.c
+ *
+ * Routines used to support NFSv4 pseudo roots
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "xlog.h"
+#include "exportfs.h"
+#include "nfslib.h"
+#include "misc.h"
+#include "v4root.h"
+
+int v4root_needed;
+
+static nfs_export pseudo_root = {
+       .m_next = NULL,
+       .m_client = NULL,
+       .m_export = {
+               .e_hostname = "*",
+               .e_path = "/",
+               .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH
+                               | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
+                               | NFSEXP_V4ROOT,
+               .e_anonuid = 65534,
+               .e_anongid = 65534,
+               .e_squids = NULL,
+               .e_nsquids = 0,
+               .e_sqgids = NULL,
+               .e_nsqgids = 0,
+               .e_fsid = 0,
+               .e_mountpoint = NULL,
+       },
+       .m_exported = 0,
+       .m_xtabent = 1,
+       .m_mayexport = 1,
+       .m_changed = 0,
+       .m_warned = 0,
+};
+
+void set_pseudofs_security(struct exportent *pseudo, struct exportent *source)
+{
+       struct sec_entry *se;
+       int i;
+
+       if (source->e_flags & NFSEXP_INSECURE_PORT)
+               pseudo->e_flags |= NFSEXP_INSECURE_PORT;
+       for (se = source->e_secinfo; se->flav; se++) {
+               struct sec_entry *new;
+
+               i = secinfo_addflavor(se->flav, pseudo);
+               new = &pseudo->e_secinfo[i];
+
+               if (se->flags & NFSEXP_INSECURE_PORT)
+                       new->flags |= NFSEXP_INSECURE_PORT;
+       }
+}
+
+/*
+ * Create a pseudo export
+ */
+static struct exportent *
+v4root_create(char *path, nfs_export *export)
+{
+       nfs_export *exp;
+       struct exportent eep;
+       struct exportent *curexp = &export->m_export;
+
+       dupexportent(&eep, &pseudo_root.m_export);
+       eep.e_hostname = strdup(curexp->e_hostname);
+       strncpy(eep.e_path, path, sizeof(eep.e_path));
+       if (strcmp(path, "/") != 0)
+               eep.e_flags &= ~NFSEXP_FSID;
+       set_pseudofs_security(&eep, curexp);
+       exp = export_create(&eep, 0);
+       if (exp == NULL)
+               return NULL;
+       xlog(D_CALL, "v4root_create: path '%s'", exp->m_export.e_path);
+       return &exp->m_export;
+}
+
+/*
+ * Make sure the kernel has pseudo root support.
+ */
+static int
+v4root_support(void)
+{
+       struct export_features *ef;
+       static int warned = 0;
+
+       ef = get_export_features();
+
+       if (ef->flags & NFSEXP_V4ROOT)
+               return 1;
+       if (!warned) {
+               xlog(L_WARNING, "Kernel does not have pseudo root support.");
+               xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0");
+               xlog(L_WARNING, "is specfied in /etc/exports file.");
+               warned++;
+       }
+       return 0;
+}
+
+int pseudofs_update(char *hostname, char *path, nfs_export *source)
+{
+       nfs_export *exp;
+
+       exp = export_lookup(hostname, path, 0);
+       if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT))
+               return 0;
+       if (!exp) {
+               if (v4root_create(path, source) == NULL) {
+                       xlog(L_WARNING, "v4root_set: Unable to create "
+                                       "pseudo export for '%s'", path);
+                       return -ENOMEM;
+               }
+               return 0;
+       }
+       /* Update an existing V4ROOT export: */
+       set_pseudofs_security(&exp->m_export, &source->m_export);
+       return 0;
+}
+
+/*
+ * Create pseudo exports by running through the real export
+ * looking at the components of the path that make up the export.
+ * Those path components, if not exported, will become pseudo
+ * exports allowing them to be found when the kernel does an upcall
+ * looking for components of the v4 mount.
+ */
+void
+v4root_set()
+{
+       nfs_export      *exp, *nxt;
+       int     i;
+       char *path, *ptr;
+       char *hostname;
+
+       if (!v4root_needed)
+               return;
+       if (!v4root_support())
+               return;
+
+       for (i = 0; i < MCL_MAXTYPES; i++) {
+               for (exp = exportlist[i].p_head; exp; exp = nxt) {
+                       nxt = exp->m_next;
+                       hostname = exp->m_export.e_hostname;
+
+                       path = strdup(exp->m_export.e_path);
+                       for (ptr = path + 1; ptr; ptr = strchr(ptr, '/')) {
+                               int ret;
+                               char saved;
+
+                               saved = *ptr;
+                               *ptr = '\0';
+                               ret = pseudofs_update(hostname, path, exp);
+                               /* XXX: error handling */
+                               *ptr = saved;
+                               ptr++;
+                       }
+                       free(path);
+               }
+       }
+}