--- nfs-utils-1.0.9/utils/mount/nfs4mount.c.orig 2008-01-18 14:06:52.000000000 -0500 +++ nfs-utils-1.0.9/utils/mount/nfs4mount.c 2008-01-18 14:07:46.000000000 -0500 @@ -36,6 +36,7 @@ #define nfsstat nfs_stat #endif +#include "pseudoflavors.h" #include "nls.h" #include "conn.h" #include "xcommon.h" @@ -71,26 +72,6 @@ char *GSSDLCK = DEFAULT_DIR "/rpcgssd"; #define NFS_PORT 2049 #endif -struct { - char *flavour; - int fnum; -} flav_map[] = { - { "krb5", RPC_AUTH_GSS_KRB5 }, - { "krb5i", RPC_AUTH_GSS_KRB5I }, - { "krb5p", RPC_AUTH_GSS_KRB5P }, - { "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 }, -}; - -#define FMAPSIZE (sizeof(flav_map)/sizeof(flav_map[0])) #define MAX_USER_FLAVOUR 16 static int parse_sec(char *sec, int *pseudoflavour) @@ -104,13 +85,13 @@ static int parse_sec(char *sec, int *pse "exceeded\n")); return 0; } - for (i = 0; i < FMAPSIZE; i++) { + for (i = 0; i < flav_map_size; i++) { if (strcmp(sec, flav_map[i].flavour) == 0) { pseudoflavour[num_flavour++] = flav_map[i].fnum; break; } } - if (i == FMAPSIZE) { + if (i == flav_map_size) { fprintf(stderr, _("mount: unknown security type %s\n"), sec); return 0; @@ -409,7 +390,7 @@ int nfs4mount(const char *spec, const ch printf("sec = "); for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) { - for (i = 0; i < FMAPSIZE; i++) { + for (i = 0; i < flav_map_size; i++) { if (flav_map[i].fnum == pseudoflavour[pf_cnt]) { printf("%s", flav_map[i].flavour); break; --- nfs-utils-1.0.9/utils/mount/nfs4_mount.h.orig 2008-01-18 14:06:52.000000000 -0500 +++ nfs-utils-1.0.9/utils/mount/nfs4_mount.h 2008-01-18 14:07:46.000000000 -0500 @@ -70,18 +70,6 @@ struct nfs4_mount_data { #define NFS4_MOUNT_FLAGMASK 0xFFFFF -/* pseudoflavors: */ - -#define RPC_AUTH_GSS_KRB5 390003 -#define RPC_AUTH_GSS_KRB5I 390004 -#define RPC_AUTH_GSS_KRB5P 390005 -#define RPC_AUTH_GSS_LKEY 390006 -#define RPC_AUTH_GSS_LKEYI 390007 -#define RPC_AUTH_GSS_LKEYP 390008 -#define RPC_AUTH_GSS_SPKM 390009 -#define RPC_AUTH_GSS_SPKMI 390010 -#define RPC_AUTH_GSS_SPKMP 390011 - int nfs4mount(const char *, const char *, int *, char **, char **, int); --- nfs-utils-1.0.9/utils/mountd/cache.c.orig 2008-01-18 14:06:52.000000000 -0500 +++ nfs-utils-1.0.9/utils/mountd/cache.c 2008-01-18 14:07:46.000000000 -0500 @@ -27,6 +27,7 @@ #include "mountd.h" #include "xmalloc.h" #include "fsloc.h" +#include "pseudoflavors.h" /* * Support routines for text-based upcalls. @@ -284,6 +285,25 @@ static void write_fsloc(FILE *f, struct release_replicas(servers); } +static void write_secinfo(FILE *f, struct exportent *ep) +{ + struct sec_entry *p; + + for (p = ep->e_secinfo; p->flav; p++) + ; /* Do nothing */ + if (p == ep->e_secinfo) { + /* There was no sec= option */ + return; + } + qword_print(f, "secinfo"); + qword_printint(f, p - ep->e_secinfo); + for (p = ep->e_secinfo; p->flav; p++) { + qword_printint(f, p->flav->fnum); + qword_printint(f, p->flags); + } + +} + void nfsd_export(FILE *f) { /* requests are: @@ -354,6 +374,7 @@ void nfsd_export(FILE *f) qword_printint(f, found->m_export.e_anongid); qword_printint(f, found->m_export.e_fsid); write_fsloc(f, &found->m_export, path); + write_secinfo(f, &found->m_export); } qword_eol(f); out: --- nfs-utils-1.0.9/utils/exportfs/exports.man.orig 2008-01-18 14:06:52.000000000 -0500 +++ nfs-utils-1.0.9/utils/exportfs/exports.man 2008-01-18 14:38:40.000000000 -0500 @@ -78,11 +78,6 @@ may work by accident when reverse DNS lo '''.B \-\-public\-root '''option. Multiple specifications of a public root will be ignored. .PP -.SS RPCSEC_GSS security -To restrict access to an export using rpcsec_gss security, use the special -string "gss/krb5" as the client. It is not possible to simultaneously require -rpcsec_gss and to make requirements on the IP address of the client. -.PP .SS General Options .IR exportfs understands the following export options: @@ -309,7 +304,32 @@ generally using mount --bind, although i '''If the client asks for alternative locations for the export point, it '''will be given this list of alternatives. (Note that actual replication '''of the filesystem must be handled elsewhere.) - +.TP +.IR sec= flavor[:flavor] +The sec option, followed by a colon-delimited list of security flavors, +restricts the export to clients using those flavors. Available security +flavors include: +.IP "" 8 +.PD 0 +none (no cryptographic security) +.IP +sys (no cryptographic security) +.IP +krb5 (authentication only) +.IP +krb5i (integrity protection) +.IP +krb5p (privacy protection) +.PD +.IP +For the purposes of security flavor negotiation, order +counts: preferred flavors should be listed first. The order of the sec= +option with respect to the other options does not matter, unless you +want some options to be enforced differently depending on flavor. +In that case you may include multiple sec= options, and following options +will be enforced only for access using flavors listed in the immediately +preceding sec= option. The only options that are permitted to vary in +this way are ro, rw, no_root_squash, root_squash, and all_squash. .SS User ID Mapping .PP .I nfsd --- nfs-utils-1.0.9/utils/exportfs/exportfs.c.orig 2008-01-18 14:06:52.000000000 -0500 +++ nfs-utils-1.0.9/utils/exportfs/exportfs.c 2008-01-18 14:07:46.000000000 -0500 @@ -429,6 +429,7 @@ dump(int verbose) c = dumpopt(c, "fsloc=stub"); break; } + secinfo_show(stdout, ep); printf("%c\n", (c != '(')? ')' : ' '); } } --- nfs-utils-1.0.9/support/include/nfslib.h.orig 2008-01-18 14:06:52.000000000 -0500 +++ nfs-utils-1.0.9/support/include/nfslib.h 2008-01-18 14:07:46.000000000 -0500 @@ -57,6 +57,14 @@ enum cle_maptypes { CLE_MAP_UGIDD, }; +/* Maximum number of security flavors on an export: */ +#define SECFLAVOR_COUNT 8 + +struct sec_entry { + struct flav_info *flav; + int flags; +}; + /* * Data related to a single exports entry as returned by getexportent. * FIXME: export options should probably be parsed at a later time to @@ -82,6 +90,7 @@ struct exportent { char * e_mountpoint; int e_fslocmethod; char * e_fslocdata; + struct sec_entry e_secinfo[SECFLAVOR_COUNT+1]; }; struct rmtabent { @@ -95,6 +104,7 @@ struct rmtabent { */ void setexportent(char *fname, char *type); struct exportent * getexportent(int); +void secinfo_show(FILE *fp, struct exportent *ep); void putexportent(struct exportent *xep); void endexportent(void); struct exportent * mkexportent(char *hname, char *path, char *opts); --- /dev/null 2008-01-17 10:24:21.891975071 -0500 +++ nfs-utils-1.0.9/support/include/pseudoflavors.h 2008-01-18 14:07:46.000000000 -0500 @@ -0,0 +1,17 @@ +#define RPC_AUTH_GSS_KRB5 390003 +#define RPC_AUTH_GSS_KRB5I 390004 +#define RPC_AUTH_GSS_KRB5P 390005 +#define RPC_AUTH_GSS_LKEY 390006 +#define RPC_AUTH_GSS_LKEYI 390007 +#define RPC_AUTH_GSS_LKEYP 390008 +#define RPC_AUTH_GSS_SPKM 390009 +#define RPC_AUTH_GSS_SPKMI 390010 +#define RPC_AUTH_GSS_SPKMP 390011 + +struct flav_info { + char *flavour; + int fnum; +}; + +extern struct flav_info flav_map[]; +extern const int flav_map_size; --- nfs-utils-1.0.9/support/nfs/exports.c.orig 2008-01-18 14:06:52.000000000 -0500 +++ nfs-utils-1.0.9/support/nfs/exports.c 2008-01-18 14:07:46.000000000 -0500 @@ -30,11 +30,30 @@ #include "xmalloc.h" #include "xlog.h" #include "xio.h" +#include "pseudoflavors.h" #define EXPORT_DEFAULT_FLAGS \ (NFSEXP_READONLY|NFSEXP_ROOTSQUASH|NFSEXP_GATHERED_WRITES|\ NFSEXP_NOSUBTREECHECK) +struct flav_info flav_map[] = { + { "krb5", RPC_AUTH_GSS_KRB5 }, + { "krb5i", RPC_AUTH_GSS_KRB5I }, + { "krb5p", RPC_AUTH_GSS_KRB5P }, + { "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 }, +}; + +const int flav_map_size = sizeof(flav_map)/sizeof(flav_map[0]); + int export_errno; static char *efname = NULL; @@ -97,6 +116,7 @@ getexportent(int fromkernel) ee.e_mountpoint = NULL; ee.e_fslocmethod = FSLOC_NONE; ee.e_fslocdata = NULL; + ee.e_secinfo[0].flav = NULL; ee.e_nsquids = 0; ee.e_nsqgids = 0; @@ -153,6 +173,27 @@ getexportent(int fromkernel) return ⅇ } +void secinfo_show(FILE *fp, struct exportent *ep) +{ + struct sec_entry *p1, *p2; + int flags; + + for (p1=ep->e_secinfo; p1->flav; p1=p2) { + + fprintf(fp, ",sec=%s", p1->flav->flavour); + for (p2=p1+1; (p2->flav != NULL) && (p1->flags == p2->flags); + p2++) { + fprintf(fp, ":%s", p2->flav->flavour); + } + flags = p1->flags; + fprintf(fp, ",%s", (flags & NFSEXP_READONLY) ? "ro" : "rw"); + fprintf(fp, ",%sroot_squash", (flags & NFSEXP_ROOTSQUASH)? + "" : "no_"); + fprintf(fp, ",%sall_squash", (flags & NFSEXP_ALLSQUASH)? + "" : "no_"); + } +} + void putexportent(struct exportent *ep) { @@ -244,7 +285,9 @@ putexportent(struct exportent *ep) else fprintf(fp, "%d,", id[i]); } - fprintf(fp, "anonuid=%d,anongid=%d)\n", ep->e_anonuid, ep->e_anongid); + fprintf(fp, "anonuid=%d,anongid=%d", ep->e_anonuid, ep->e_anongid); + secinfo_show(fp, ep); + fprintf(fp, ")\n"); } void @@ -292,6 +335,9 @@ mkexportent(char *hname, char *path, cha ee.e_squids = NULL; ee.e_sqgids = NULL; ee.e_mountpoint = NULL; + ee.e_fslocmethod = FSLOC_NONE; + ee.e_fslocdata = NULL; + ee.e_secinfo[0].flav = NULL; ee.e_nsquids = 0; ee.e_nsqgids = 0; @@ -320,13 +366,106 @@ updateexportent(struct exportent *eep, c } /* + * Append the given flavor to the exportent's e_secinfo array, or + * 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) +{ + struct sec_entry *p; + + for (p=ep->e_secinfo; p->flav; p++) { + if (p->flav == flav) + return p - ep->e_secinfo; + } + if (p - ep->e_secinfo >= SECFLAVOR_COUNT) { + xlog(L_ERROR, "more than %d security flavors on an export\n", + SECFLAVOR_COUNT); + return -1; + } + p->flav = flav; + p->flags = ep->e_flags; + (p+1)->flav = NULL; + return p - ep->e_secinfo; +} + +static struct flav_info *find_flavor(char *name) +{ + struct flav_info *flav; + for (flav = flav_map; flav < flav_map + flav_map_size; flav++) + if (strcmp(flav->flavour, name) == 0) + return flav; + return NULL; +} + +/* @str is a colon seperated list of security flavors. Their order + * is recorded in @ep, and a bitmap corresponding to the list is returned. + * A zero return indicates an error. + */ +static unsigned int parse_flavors(char *str, struct exportent *ep) +{ + unsigned int out=0; + char *flavor; + int bit; + + while ( (flavor=strsep(&str, ":")) ) { + struct flav_info *flav = find_flavor(flavor); + if (flav == NULL) { + xlog(L_ERROR, "unknown flavor %s\n", flavor); + return 0; + } + bit = secinfo_addflavor(flav, ep); + if (bit < 0) + return 0; + out |= 1<<bit; + } + return out; +} + +/* Sets the bits in @mask for the appropriate security flavor flags. */ +static void setflags(int mask, unsigned int active, struct exportent *ep) +{ + int bit=0; + + ep->e_flags |= mask; + + while (active) { + if (active & 1) + ep->e_secinfo[bit].flags |= mask; + bit++; + active >>= 1; + } +} + +/* Clears the bits in @mask for the appropriate security flavor flags. */ +static void clearflags(int mask, unsigned int active, struct exportent *ep) +{ + int bit=0; + + ep->e_flags &= ~mask; + + while (active) { + if (active & 1) + ep->e_secinfo[bit].flags &= ~mask; + bit++; + active >>= 1; + } +} + +/* options that can vary per flavor: */ +#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ + | NFSEXP_ALLSQUASH) + +/* * Parse option string pointed to by cp and set mount options accordingly. */ static int parseopts(char *cp, struct exportent *ep) { + struct sec_entry *p; char *flname = efname?efname:"command line"; int flline = efp?efp->x_line:0; + unsigned int active = 0; squids = ep->e_squids; nsquids = ep->e_nsquids; sqgids = ep->e_sqgids; nsqgids = ep->e_nsqgids; @@ -349,9 +488,9 @@ parseopts(char *cp, struct exportent *ep /* process keyword */ if (strcmp(opt, "ro") == 0) - ep->e_flags |= NFSEXP_READONLY; + setflags(NFSEXP_READONLY, active, ep); else if (strcmp(opt, "rw") == 0) - ep->e_flags &= ~NFSEXP_READONLY; + clearflags(NFSEXP_READONLY, active, ep); else if (!strcmp(opt, "secure")) ep->e_flags &= ~NFSEXP_INSECURE_PORT; else if (!strcmp(opt, "insecure")) @@ -373,13 +512,13 @@ parseopts(char *cp, struct exportent *ep else if (!strcmp(opt, "no_wdelay")) ep->e_flags &= ~NFSEXP_GATHERED_WRITES; else if (strcmp(opt, "root_squash") == 0) - ep->e_flags |= NFSEXP_ROOTSQUASH; + setflags(NFSEXP_ROOTSQUASH, active, ep); else if (!strcmp(opt, "no_root_squash")) - ep->e_flags &= ~NFSEXP_ROOTSQUASH; + clearflags(NFSEXP_ROOTSQUASH, active, ep); else if (strcmp(opt, "all_squash") == 0) - ep->e_flags |= NFSEXP_ALLSQUASH; + setflags(NFSEXP_ALLSQUASH, active, ep); else if (strcmp(opt, "no_all_squash") == 0) - ep->e_flags &= ~NFSEXP_ALLSQUASH; + clearflags(NFSEXP_ALLSQUASH, active, ep); else if (strcmp(opt, "subtree_check") == 0) ep->e_flags &= ~NFSEXP_NOSUBTREECHECK; else if (strcmp(opt, "no_subtree_check") == 0) @@ -461,6 +600,10 @@ bad_option: } else if (strncmp(opt, "replicas=", 9) == 0) { ep->e_fslocmethod = FSLOC_REPLICA; ep->e_fslocdata = strdup(opt+9); + } else if (strncmp(opt, "sec=", 4) == 0) { + active = parse_flavors(opt+4, ep); + if (!active) + goto bad_option; } else { xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n", flname, flline, opt); @@ -478,6 +621,8 @@ bad_option: if (ep->e_fslocdata) ep->e_flags |= NFSEXP_NOHIDE; + for (p = ep->e_secinfo; p->flav; p++) + p->flags |= ep->e_flags & ~NFSEXP_SECINFO_FLAGS; ep->e_squids = squids; ep->e_sqgids = sqgids; ep->e_nsquids = nsquids;