From 3b777b084a438f55482c8bf7508903ff4c30e1db Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Tue, 1 Dec 2009 07:16:13 -0500 Subject: [PATCH] exports: NFSv4 pseudoroot support routines 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 Signed-off-by: J. Bruce Fields --- support/include/exportfs.h | 2 + support/include/v4root.h | 15 ++++ support/nfs/exports.c | 2 +- utils/mountd/Makefile.am | 2 +- utils/mountd/v4root.c | 180 +++++++++++++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 support/include/v4root.h create mode 100644 utils/mountd/v4root.c diff --git a/support/include/exportfs.h b/support/include/exportfs.h index ce7eac0..470b2ec 100644 --- a/support/include/exportfs.h +++ b/support/include/exportfs.h @@ -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 index 0000000..706c15c --- /dev/null +++ b/support/include/v4root.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2009 Red Hat + * 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 */ diff --git a/support/nfs/exports.c b/support/nfs/exports.c index ef31a85..50e83a8 100644 --- a/support/nfs/exports.c +++ b/support/nfs/exports.c @@ -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; diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am index 1e76cf8..eba81fc 100644 --- a/utils/mountd/Makefile.am +++ b/utils/mountd/Makefile.am @@ -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 index 0000000..d890181 --- /dev/null +++ b/utils/mountd/v4root.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2009 Red Hat + * + * support/export/v4root.c + * + * Routines used to support NFSv4 pseudo roots + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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); + } + } +} -- 2.39.2