diff --git a/support/export/xtab.c b/support/export/xtab.c index 3b1dcce..2a43193 100644 --- a/support/export/xtab.c +++ b/support/export/xtab.c @@ -19,7 +19,9 @@ #include "exportfs.h" #include "xio.h" #include "xlog.h" +#include "v4root.h" +int v4root_needed; static void cond_rename(char *newfile, char *oldfile); static int @@ -36,6 +38,8 @@ xtab_read(char *xtab, char *lockfn, int is_export) if ((lockid = xflock(lockfn, "r")) < 0) return 0; setexportent(xtab, "r"); + if (is_export == 1) + v4root_needed = 1; while ((xp = getexportent(is_export==0, 0)) != NULL) { if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) && !(exp = export_create(xp, is_export!=1))) { @@ -48,6 +52,8 @@ xtab_read(char *xtab, char *lockfn, int is_export) case 1: exp->m_xtabent = 1; exp->m_mayexport = 1; + if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0) + v4root_needed = 0; break; case 2: exp->m_exported = -1;/* may be exported */ diff --git a/support/include/nfs/export.h b/support/include/nfs/export.h index f7a99ba..76953ac 100644 --- a/support/include/nfs/export.h +++ b/support/include/nfs/export.h @@ -24,6 +24,7 @@ #define NFSEXP_FSID 0x2000 #define NFSEXP_CROSSMOUNT 0x4000 #define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ -#define NFSEXP_ALLFLAGS 0xFFFF +#define NFSEXP_V4ROOT 0x10000 +#define NFSEXP_ALLFLAGS 0x1FFFF #endif /* _NSF_EXPORT_H */ diff --git a/support/include/pseudoflavors.h b/support/include/pseudoflavors.h index c21087b..c7ba8a2 100644 --- a/support/include/pseudoflavors.h +++ b/support/include/pseudoflavors.h @@ -15,3 +15,4 @@ struct flav_info { extern struct flav_info flav_map[]; extern const int flav_map_size; +extern unsigned int flavors_setall(struct exportent *ep); 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 1aaebf4..fe9ed3a 100644 --- a/support/nfs/exports.c +++ b/support/nfs/exports.c @@ -39,16 +39,18 @@ struct flav_info flav_map[] = { { "krb5", RPC_AUTH_GSS_KRB5 }, { "krb5i", RPC_AUTH_GSS_KRB5I }, { "krb5p", RPC_AUTH_GSS_KRB5P }, + { "unix", AUTH_UNIX }, + { "sys", AUTH_SYS }, + { "null", AUTH_NULL }, + { "none", AUTH_NONE }, +#ifdef NOLONGERSUPPORTED { "lipkey", RPC_AUTH_GSS_LKEY }, { "lipkey-i", RPC_AUTH_GSS_LKEYI }, { "lipkey-p", RPC_AUTH_GSS_LKEYP }, { "spkm3", RPC_AUTH_GSS_SPKM }, { "spkm3i", RPC_AUTH_GSS_SPKMI }, { "spkm3p", RPC_AUTH_GSS_SPKMP }, - { "unix", AUTH_UNIX }, - { "sys", AUTH_SYS }, - { "null", AUTH_NULL }, - { "none", AUTH_NONE }, +#endif }; const int flav_map_size = sizeof(flav_map)/sizeof(flav_map[0]); @@ -436,6 +438,20 @@ static unsigned int parse_flavors(char *str, struct exportent *ep) } return out; } +unsigned int flavors_setall(struct exportent *ep) +{ + struct flav_info *flav; + unsigned int out=0; + int bit; + + for (flav = flav_map; flav < flav_map + flav_map_size; flav++) { + bit = secinfo_addflavor(flav, ep); + if (bit < 0) + return 0; + out |= 1<m_next) { + /* Don't show pseudo exports */ + if (exp->m_export.e_flags & NFSEXP_V4ROOT) + continue; + for (e = elist; e != NULL; e = e->ex_next) { if (!strcmp(exp->m_export.e_path, e->ex_dir)) break; diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c new file mode 100644 index 0000000..b1e483a --- /dev/null +++ b/utils/mountd/v4root.c @@ -0,0 +1,218 @@ +/* + * 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 "pseudoflavors.h" +#include "v4root.h" + +#ifndef _PATH_PSEUDO_ROOT +#define _PATH_PSEUDO_ROOT "/" +#endif + +#ifndef _PSEUDO_ROOT_FSID +#define _PSEUDO_ROOT_FSID 0 +#endif + +void v4root_set(void); +void v4root_unset(void); +static int v4root_support(void); + +static struct exportent *v4root_create(char *, nfs_export *); + +int v4root_needed; +static nfs_export pseudo_root = { + .m_next = NULL, + .m_client = NULL, + .m_export = { + .e_hostname = "*", + .e_path = _PATH_PSEUDO_ROOT, + .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH + | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID + | NFSEXP_CROSSMOUNT | 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, + .e_secinfo[0].flav = NULL, + }, + .m_exported = 0, + .m_xtabent = 1, + .m_mayexport = 1, + .m_changed = 0, + .m_warned = 0, +}; + +/* + * 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, curexp); + eep.e_hostname = strdup(curexp->e_hostname); + strncpy(eep.e_path, path, sizeof(eep.e_path)); + exp = export_create(&eep, 0); + if (exp == NULL) + return NULL; + + exp->m_export.e_flags |= NFSEXP_V4ROOT; + if (strcmp(path, _PATH_PSEUDO_ROOT) != 0) + exp->m_export.e_flags &= ~NFSEXP_FSID; + + 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() +{ + static int kernel_support = -1; + char *ptr, version[64]; + int major, minor; + FILE *fp; + + if (kernel_support != -1) + return kernel_support; + + kernel_support = 0; + fp = fopen("/proc/fs/nfsd/exports", "r"); + if (fp == NULL) + goto out; + + ptr = fgets(version, 64, fp); + fclose(fp); + if (ptr == NULL) + goto out; + + while(*ptr && isdigit(*ptr) == 0) + ptr++; + if (*ptr == '\0') + goto out; + + major = minor = 0; + sscanf(ptr, " %d.%d",&major, &minor); + if (major >= 1 && minor >= 2) + kernel_support = 1; +out: + if (!kernel_support) { + 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."); + } + + return kernel_support; +} + +/* + * 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; + struct exportent *proot; + int i, insecure = 0, secflavors = 0; + char *path, *ptr; + char *hostname; + + if (!v4root_needed) + return; + + if (!v4root_support()) + return; + + proot = v4root_create(_PATH_PSEUDO_ROOT, &pseudo_root); + if (proot == NULL) { + xlog(L_WARNING, "v4root_set: Unable to create " + "pseudo export for '%s'", _PATH_PSEUDO_ROOT); + 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); + ptr = path + 1; + while ((ptr = strchr(ptr, '/')) != NULL) { + *ptr = '\0'; + if (export_lookup(hostname, path, 0) == NULL) + if (v4root_create(path, exp) == NULL) { + xlog(L_WARNING, "v4root_set: Unable to create " + "pseudo export for '%s'", path); + break; + } + *ptr = '/'; + ptr++; + } + /* Make note of insecure exports */ + if (!insecure) + insecure = (exp->m_export.e_flags & NFSEXP_INSECURE_PORT); + + /* Make note of security flavors being set */ + if (!secflavors) + secflavors = (exp->m_export.e_secinfo[0].flav != NULL); + + free(path); + } + } + + /* + * If there are any insecure exports, the pseudo root + * also has to be insecure + */ + if (insecure) { + proot->e_flags |= NFSEXP_INSECURE_PORT; + } + + /* + * Make sure the pseudo root is accessible from all + * security flavors when it needs to be. + */ + if (secflavors && !flavors_setall(proot)) { + xlog(L_WARNING, "v4root_set: Unable to set security " + "flavors on pseudo root"); + } + +} +