Index: enf/src/linux/2.4.17/fs/nfsd/Makefile diff -u enf/src/linux/2.4.17/fs/nfsd/Makefile:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/Makefile:1.2 --- enf/src/linux/2.4.17/fs/nfsd/Makefile:1.1.1.1 Tue Feb 19 06:20:06 2002 +++ enf/src/linux/2.4.17/fs/nfsd/Makefile Tue Feb 19 12:38:00 2002 @@ -11,7 +11,7 @@ obj-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o nfsxdr.o \ - stats.o + stats.o enf.o obj-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o Index: enf/src/linux/2.4.17/fs/nfsd/auth.c diff -u enf/src/linux/2.4.17/fs/nfsd/auth.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/auth.c:1.2 --- enf/src/linux/2.4.17/fs/nfsd/auth.c:1.1.1.1 Tue Feb 19 06:20:16 2002 +++ enf/src/linux/2.4.17/fs/nfsd/auth.c Tue Feb 19 12:38:00 2002 @@ -9,29 +9,51 @@ #include #include #include +#include +#include +#include #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) void nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) { struct svc_cred *cred = &rqstp->rq_cred; - int i; + int i; + uid_t newuid; + gid_t newgid; + + ASSERT(rqstp != NULL); + ASSERT(exp != NULL); if (rqstp->rq_userset) return; - if (exp->ex_flags & NFSEXP_ALLSQUASH) { - cred->cr_uid = exp->ex_anon_uid; - cred->cr_gid = exp->ex_anon_gid; - cred->cr_groups[0] = NOGROUP; - } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) { - if (!cred->cr_uid) + /* if there is not range mapping on this uid + gid + * then preform possible {root,all} squash + */ + newuid = rmap_luid(cred->cr_uid, exp); + newgid = rmap_lgid(cred->cr_gid, exp); + if(newuid == cred->cr_uid && + newgid == cred->cr_gid) { + if (exp->ex_flags & NFSEXP_ALLSQUASH) { cred->cr_uid = exp->ex_anon_uid; - if (!cred->cr_gid) cred->cr_gid = exp->ex_anon_gid; - for (i = 0; i < NGROUPS; i++) - if (!cred->cr_groups[i]) - cred->cr_groups[i] = exp->ex_anon_gid; + cred->cr_groups[0] = NOGROUP; + } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) { + if (!cred->cr_uid) + cred->cr_uid = exp->ex_anon_uid; + if (!cred->cr_gid) + cred->cr_gid = exp->ex_anon_gid; + for (i = 0; i < NGROUPS; i++) + if (!cred->cr_groups[i]) + cred->cr_groups[i] = exp->ex_anon_gid; + } + } else { + /* If there is range mapping to be done, do it. + * Here we are doing remote to local range mapping. + */ + cred->cr_uid = newuid; + cred->cr_gid = newgid; } if (cred->cr_uid != (uid_t) -1) @@ -46,7 +68,7 @@ gid_t group = cred->cr_groups[i]; if (group == (gid_t) NOGROUP) break; - current->groups[i] = group; + current->groups[i] = rmap_lgid(group, exp); } current->ngroups = i; Index: enf/src/linux/2.4.17/fs/nfsd/enf.c diff -u /dev/null enf/src/linux/2.4.17/fs/nfsd/enf.c:1.3 --- /dev/null Tue Mar 19 02:10:52 2002 +++ enf/src/linux/2.4.17/fs/nfsd/enf.c Mon Mar 11 22:20:12 2002 @@ -0,0 +1,766 @@ +/* enf.c + * + * Enhanced NFS Features (ENF) + * + * supported features + * uid/gid range mapping + * file cloaking + * + * Sun Mar 4 07:37:32 2001 + * Joseph Spadavecchia [JES] + * Nenad Dedic + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct list_head g_enfdl; /* global definition lists */ + +int enf_add(struct nfsctl_enf *data) +{ + struct svc_export *exp; + struct list_head *defl, *index; + struct enf_dl *target; + struct enf_rmap *newrmap; + struct enf_clist *newclist; + unsigned char type; + char *sz_id, *sz_client, *sz_path; + int err, i, found, isuid; + + ASSERT(data); + + target = NULL; + type = data->ne_type; + switch(type) { + case ENF_TRMAP: + case ENF_TCLIST: + break; + default: + err = -EINVAL; + goto out_err; + } + + err = 0; + defl = &(g_enfdl); + sz_id = data->ne_id; + sz_client = data->ne_client; + sz_path = data->ne_path; + isuid = data->ne_uid; + + /* Try to lock the export table for update */ + if ((err = exp_writelock()) < 0) { + goto out_err; + } + + if (!(exp = enf_find_exp(sz_client, sz_path))) { + err = -ENOENT; + goto out_unlock; + } + + /* lookup sz_id global entry in def. lists + * sz_id is ONLY needed when adding new range + * mapping or file cloaking informaiton + * it should be the path and hostname (FQDN or not) + * as it apprears in the /etc/exports file + * this allows us to save memory + */ + found = 0; + list_for_each(index, defl) { + target = list_entry(index, struct enf_dl, ed_list); + + if(strncmp(target->ed_id, sz_id, + NFSCLNT_IDMAX + NFS_MAXPATHLEN) == 0) { + found = 1; + break; + } + } + /* if there is not a global entry + * create one + */ + if (!found) { + target = (struct enf_dl*)kmalloc(sizeof(struct enf_dl), + GFP_KERNEL); + if (target == NULL) { + err = -ENOMEM; + goto out_unlock; + } + strncpy(target->ed_id, sz_id, + NFSCLNT_IDMAX + NFS_MAXPATHLEN); + + for(i = 0; i < ENF_MAXTYPE; i++) { + target->ed_refcnt[i] = 0; + INIT_LIST_HEAD(&(target->ed_opaque[i][ENF_TUID])); + INIT_LIST_HEAD(&(target->ed_opaque[i][ENF_TGID])); + } + /* add this def to the global definition lists */ + list_add(&(target->ed_list), defl); + } + + switch(type) { + case ENF_TRMAP: + found = 0; + list_for_each(index, &(target->ed_opaque[type][!isuid])) { + newrmap = list_entry(index, struct enf_rmap, er_list); + + if(isuid && newrmap->u_lo.uid == data->u_lo.uid && + newrmap->u_hi.uid == data->u_hi.uid && + newrmap->u_mapto.uid == data->u_mapto.uid && + newrmap->er_map == data->ne_map) { + found = 1; + break; + } else if(!isuid && newrmap->u_lo.gid == data->u_lo.gid && + newrmap->u_hi.gid == data->u_hi.gid && + newrmap->u_mapto.gid == data->u_mapto.gid && + newrmap->er_map == data->ne_map) { + found = 1; + break; + } + } + + if(found) { + goto out; + } + + if (!(newrmap = + (struct enf_rmap *)kmalloc(sizeof(struct enf_rmap), GFP_KERNEL))) { + err = -ENOMEM; + goto out_unlock; + } + + list_add(&(newrmap->er_list), &(target->ed_opaque[ENF_TRMAP][!isuid])); + + if(isuid) { + newrmap->u_lo.uid = data->u_lo.uid; + newrmap->u_hi.uid = data->u_hi.uid; + newrmap->u_mapto.uid = data->u_mapto.uid; + } else { + newrmap->u_lo.gid = data->u_lo.gid; + newrmap->u_hi.gid = data->u_hi.gid; + newrmap->u_mapto.gid = data->u_mapto.gid; + } + + newrmap->er_map = data->ne_map; + break; + case ENF_TCLIST: + ENF_MASK2MODE(data->ne_mask); + found = 0; + list_for_each(index, &(target->ed_opaque[type][!isuid])) { + newclist = list_entry(index, struct enf_clist, ec_list); + + if(isuid && newclist->u_lo.uid == data->u_lo.uid && + newclist->u_hi.uid == data->u_hi.uid && + newclist->ec_mask == data->ne_mask) { + found = 1; + break; + } else if(!isuid && newclist->u_lo.gid == data->u_lo.gid && + newclist->u_hi.gid == data->u_hi.gid && + newclist->ec_mask == data->ne_mask) { + found = 1; + break; + } + } + + if(found) { + goto out; + } + + if (!(newclist = + (struct enf_clist *)kmalloc(sizeof(struct enf_clist), GFP_KERNEL))) { + err = -ENOMEM; + goto out_unlock; + } + + list_add(&(newclist->ec_list), &(target->ed_opaque[ENF_TCLIST][!isuid])); + + if(isuid) { + newclist->u_lo.uid = data->u_lo.uid; + newclist->u_hi.uid = data->u_hi.uid; + } else { + newclist->u_lo.gid = data->u_lo.gid; + newclist->u_hi.gid = data->u_hi.gid; + } + + newclist->ec_mask = data->ne_mask; + + break; + } + +out: + /* regardless inc the refcnt */ + if (!(exp->ex_opaque[type][ENF_TUID] || exp->ex_opaque[ENF_TRMAP][ENF_TGID])) { + target->ed_refcnt[type]++; + } + + exp->ex_opaque[type][!isuid] = &(target->ed_opaque[type][!isuid]); + +out_unlock: + exp_unlock(); +out_err: + return err; +} + +int enf_delete(struct nfsctl_enf *data) +{ + struct svc_export *exp; + struct svc_client *clp; + struct enf_rmap *targetrmap = NULL; + struct enf_clist *targetclist = NULL; + struct list_head *defl, *index, *index2; + struct enf_dl *target = NULL; + unsigned short isuid; + unsigned char type; + char *sz_client, *sz_path; + int err, i, found; + + ASSERT(data); + + type = data->ne_type; + switch(type) { + case ENF_TRMAP: + case ENF_TCLIST: + break; + default: + err = -EINVAL; + goto out_err; + } + + err = 0; + defl = &(g_enfdl); + sz_client = data->ne_client; + sz_path = data->ne_path; + isuid = data->ne_uid; + + /* Try to lock the export table for update */ + if ((err = exp_writelock()) < 0) { + goto out_err; + } + + if(!(exp = enf_find_exp(sz_client, sz_path))) { + err = -ENOENT; + goto out_unlock; + } + + /* check def. list for exp */ + found = 0; + list_for_each(index, defl) { + target = list_entry(index, struct enf_dl, ed_list); + + if(exp->ex_opaque[type][!isuid] == &(target->ed_opaque[type][!isuid]) || + exp->ex_opaque[type][!isuid] == &(target->ed_opaque[type][!isuid])) { + found = 1; + break; + } + } + + if(!found) { + goto out_unlock; + } + + switch(type) { + case ENF_TRMAP: + found = 0; + list_for_each(index2, &(target->ed_opaque[type][!isuid])) { + targetrmap = list_entry(index2, struct enf_rmap, er_list); + + if(isuid && targetrmap->u_lo.uid == data->u_lo.uid && + targetrmap->u_hi.uid == data->u_hi.uid && + targetrmap->u_mapto.uid == data->u_mapto.uid && + targetrmap->er_map == data->ne_map) { + found = 1; + break; + } else if(!isuid && targetrmap->u_lo.gid == data->u_lo.gid && + targetrmap->u_hi.gid == data->u_hi.gid && + targetrmap->u_mapto.gid == data->u_mapto.gid && + targetrmap->er_map == data->ne_map) { + found = 1; + break; + } + } + + if(!found) { + err = -ENOENT; + goto out_unlock; + } + list_del(index2); + kfree(targetrmap); + break; + case ENF_TCLIST: + found = 0; + list_for_each(index2, &(target->ed_opaque[type][!isuid])) { + targetclist = list_entry(index2, struct enf_clist, ec_list); + ENF_MASK2MODE(data->ne_mask); + if(isuid && targetclist->u_lo.uid == data->u_lo.uid && + targetclist->u_hi.uid == data->u_hi.uid && + targetclist->ec_mask == data->ne_mask) { + found = 1; + break; + } else if(!isuid && targetclist->u_lo.gid == data->u_lo.gid && + targetclist->u_hi.gid == data->u_hi.gid && + targetclist->ec_mask == data->ne_mask) { + found = 1; + break; + } + } + + if(!found) { + err = -ENOENT; + goto out_unlock; + } + list_del(index2); + kfree(targetclist); + break; + } + + if(list_empty(&(target->ed_opaque[type][!isuid]))) { + exp->ex_opaque[type][!isuid] = NULL; + target->ed_refcnt[type]--; + + switch(type) { + case ENF_TRMAP: + if(isuid) { + ENF_HASH_INIT(exp->ex_ruid); + ENF_HASH_INIT(exp->ex_luid); + } else { + ENF_HASH_INIT(exp->ex_rgid); + ENF_HASH_INIT(exp->ex_rgid); + } + break; + case ENF_TCLIST: + if(isuid) { + ENF_HASH_INIT(exp->ex_cuid); + } else { + ENF_HASH_INIT(exp->ex_cgid); + } + break; + } + /* search for other exports pointing to this def. list entry + * and nullify their def. list pointers + adjust refcnt + * on the def. list entry + */ + for (clp = get_clients(); clp; clp = clp->cl_next) { + for (i = 0; i < NFSCLNT_EXPMAX; i++) { + if ((exp = (clp->cl_export)[i])) { + do { + if (exp->ex_opaque[type][!isuid] + == &(target->ed_opaque[type][!isuid])) { + target->ed_refcnt[type]--; + exp->ex_opaque[type][!isuid] = NULL; + switch(type) { + case ENF_TRMAP: + if(isuid) { + ENF_HASH_INIT(exp->ex_ruid); + ENF_HASH_INIT(exp->ex_luid); + } else { + ENF_HASH_INIT(exp->ex_rgid); + ENF_HASH_INIT(exp->ex_rgid); + } + break; + case ENF_TCLIST: + if(isuid) { + ENF_HASH_INIT(exp->ex_cuid); + } else { + ENF_HASH_INIT(exp->ex_cgid); + } + break; + } + } + } while ((exp = exp->ex_next)); + } + } + } + + if (!target->ed_refcnt[ENF_TRMAP] && !target->ed_refcnt[ENF_TCLIST]) { + /* remove definition list entry */ + list_del(&(target->ed_list)); + kfree(target); + } + } +out_unlock: + exp_unlock(); +out_err: + return err; +} + +int enf_flush(struct nfsctl_enf *data) +{ + struct list_head *defl, *index, *index2; + struct enf_rmap *rmap; + struct enf_clist *clist; + struct enf_dl *target; + struct svc_export *exp; + int err, found; + unsigned char type; + char *sz_path, *sz_client; + + ASSERT(data); + + err = 0; + target = NULL; + type = data->ne_type; + switch(type) { + case ENF_TRMAP: + case ENF_TCLIST: + break; + default: + err = -EINVAL; + goto out_err; + } + + defl = &(g_enfdl); + sz_client = data->ne_client; + sz_path = data->ne_path; + + /* Try to lock the export table for update */ + if ((err = exp_writelock()) < 0) { + goto out_err; + } + + /* find the export */ + if (!(exp = enf_find_exp(sz_client, sz_path))) { + err = -ENOENT; + goto out_unlock; + } + + /* find the corresponding definition list entry */ + found = 0; + list_for_each(index, defl) { + target = list_entry(index, struct enf_dl, ed_list); + if(exp->ex_opaque[type][ENF_TUID] == &(target->ed_opaque[type][ENF_TUID]) || + exp->ex_opaque[type][ENF_TGID] == &(target->ed_opaque[type][ENF_TGID])) { + found = 1; + break; + } + } + + if(!found) { + goto out_unlock; + } + + exp->ex_opaque[type][ENF_TUID] = NULL; + exp->ex_opaque[type][ENF_TGID] = NULL; + + switch(type) { + case ENF_TRMAP: + ENF_HASH_INIT(exp->ex_ruid); + ENF_HASH_INIT(exp->ex_rgid); + ENF_HASH_INIT(exp->ex_luid); + ENF_HASH_INIT(exp->ex_lgid); + break; + case ENF_TCLIST: + ENF_HASH_INIT(exp->ex_cuid); + ENF_HASH_INIT(exp->ex_cgid); + break; + } + + target->ed_refcnt[type]--; + if (!(target->ed_refcnt[type])) { + switch(type) { + case ENF_TRMAP: + /* free uid list */ + list_for_each(index2, &(target->ed_opaque[ENF_TRMAP][ENF_TUID])) { + rmap = list_entry(index2, struct enf_rmap, er_list); + list_del(&(rmap->er_list)); + kfree(rmap); + } + + /* free gid list */ + list_for_each(index2, &(target->ed_opaque[ENF_TRMAP][ENF_TGID])) { + rmap = list_entry(index2, struct enf_rmap, er_list); + list_del(&(rmap->er_list)); + kfree(rmap); + } + break; + case ENF_TCLIST: + /* free uid list */ + list_for_each(index2, &(target->ed_opaque[ENF_TCLIST][ENF_TUID])) { + clist = list_entry(index2, struct enf_clist, ec_list); + list_del(&(clist->ec_list)); + kfree(clist); + } + + /* free gid list */ + list_for_each(index2, &(target->ed_opaque[ENF_TCLIST][ENF_TGID])) { + clist = list_entry(index2, struct enf_clist, ec_list); + list_del(&(clist->ec_list)); + kfree(clist); + } + break; + } + + if(!target->ed_refcnt[ENF_TRMAP] && !target->ed_refcnt[ENF_TCLIST]) { + /* remove definition list entry */ + list_del(&(target->ed_list)); + kfree(target); + } + } + +out_unlock: + exp_unlock(); +out_err: + return err; +} + +/** + * Returns the export with client @cl_name and path @path. + * IN: + * @cl_name: client name + * @path: export path + * OUT: + * if found the svc_export else NULL + * + * (This function assumes locking before invocation.) + */ +struct svc_export *enf_find_exp(char *cl_name, char *path) +{ + struct svc_client *clp; + struct svc_export *exp; + int i; + + ASSERT(cl_name); + ASSERT(path); + + /* TODO: what about parents */ + for (clp = get_clients(); clp; clp = clp->cl_next) { + if (strcmp(clp->cl_ident, cl_name) == 0) { + for (i = 0; i < NFSCLNT_EXPMAX; i++) { + if ((exp = (clp->cl_export)[i])) { + do { + if (strcmp(exp->ex_path, path) == 0) { + /* found */ + goto out; + } + } while ((exp = exp->ex_next)); + } + } + } + } + /* haven't found */ + exp = NULL; +out: + return exp; +} + +/** + * Map a local uid to a remote uid. + * (reverse mapping) + * IN: + * @svc_rqst: structure 'rqstp' containing + * _the_ svc_fh in '.rq_resp' + * @id: local uid + * OUT: + * if there exists a reverse range mapping + * for 'id' the remote uid is calculated + * from it and returned + * else then 'id' is returned unchanged + * + * (This function assumes locking before invocation.) + */ +uid_t rmap_ruid(struct svc_rqst *rqstp, uid_t id) +{ + struct svc_export *exp; + struct enf_rmap *map; + struct list_head *index; + uid_t newid, tmpid; + int i_hv; + + ASSERT(rqstp != NULL); + + newid = id; + exp = nfs3svc_rqst2exp(rqstp); + if(!exp) { + printk(KERN_DEBUG "RMAP: null export - (this should never happen)\n"); + /* return old id */ + goto out; + } + + if (!(exp->ex_opaque[ENF_TRMAP][ENF_TUID])) { + goto out; + } + + i_hv = ENF_HASH_FUNCTION(id); + if (exp->ex_ruid[i_hv][ENF_HSRC] != id) { + list_for_each(index, exp->ex_opaque[ENF_TRMAP][ENF_TUID]) { + map = list_entry(index, struct enf_rmap, er_list); + if (map->er_map) { + /* range map -- we do reverse mapping only when + * range mapping is in question + */ + /* for squashing, reverse maps make no sense */ + tmpid = id - map->u_mapto.uid + map->u_lo.uid; + if ((map->u_lo.uid <= tmpid) && (tmpid <= map->u_hi.uid) ) { + newid = tmpid; + exp->ex_ruid[i_hv][ENF_HSRC] = id; + exp->ex_ruid[i_hv][ENF_HDST] = newid; + break; + } + } + } + } else { + newid = exp->ex_ruid[i_hv][ENF_HDST]; + } +out: + return newid; +} + +/* (This function assumes locking before invocation.) */ +gid_t rmap_rgid(struct svc_rqst *rqstp, gid_t id) +{ + struct svc_export *exp; + struct enf_rmap *map; + struct list_head *index; + gid_t newid, tmpid; + int i_hv; + + ASSERT(rqstp != NULL); + + newid = id; + exp = nfs3svc_rqst2exp(rqstp); + if(!exp) { + /* return old id */ + goto out; + } + + if (!(exp->ex_opaque[ENF_TRMAP][ENF_TGID])) { + goto out; + } + + i_hv = ENF_HASH_FUNCTION(id); + + if(exp->ex_rgid[i_hv][ENF_HSRC] != id) { + list_for_each(index, exp->ex_opaque[ENF_TRMAP][ENF_TGID]) { + map = list_entry(index, struct enf_rmap, er_list); + + if (map->er_map) { + /* range map -- we do reverse mapping only when + * range mapping is in question + */ + + /* for squashing, reverse maps make no sense */ + tmpid = id - map->u_mapto.gid + map->u_lo.gid; + if ((map->u_lo.gid <= tmpid) && (tmpid <= map->u_hi.gid)) { + newid = tmpid; + exp->ex_rgid[i_hv][ENF_HSRC] = id; + exp->ex_rgid[i_hv][ENF_HDST] = newid; + break; + } + } + } + } else { + newid = exp->ex_rgid[i_hv][ENF_HDST]; + } +out: + return newid; +} + +/** + * Map a remote uid to a local uid. + * IN: + * @svc_rqst: structure 'rqstp' containing + * _the_ svc_fh in '.rq_resp' + * @ruid: remote uid + * OUT: + * if there exists a range mapping + * for 'ruid' the local uid is calculated + * and returned else then 'ruid' is returned + * + * (This function assumes locking before invocation.) + */ +uid_t rmap_luid(uid_t ruid, struct svc_export *exp) +{ + struct enf_rmap *map = NULL; + struct list_head *index; + uid_t newid; + int i_hv; + + ASSERT(exp != NULL); + + newid = ruid; + /* get credentials */ + if (!(exp->ex_opaque[ENF_TRMAP][ENF_TUID])) { + goto out; + } + + i_hv = ENF_HASH_FUNCTION(ruid); + + if (exp->ex_luid[i_hv][ENF_HSRC] != ruid) { + list_for_each(index, exp->ex_opaque[ENF_TRMAP][ENF_TUID]) { + map = list_entry(index, struct enf_rmap, er_list); + if ((map->u_lo.uid <= ruid) && (ruid <= map->u_hi.uid)) { + /* map this uid */ + if (map->er_map) { + /* range map */ + newid = map->u_mapto.uid - map->u_lo.uid + ruid; + } else { + /* squash */ + newid = map->u_mapto.uid; + } + + exp->ex_luid[i_hv][ENF_HSRC] = ruid; + exp->ex_luid[i_hv][ENF_HDST] = newid; + + break; + } + + } + } else { + newid = exp->ex_luid[i_hv][ENF_HDST]; + } +out: + return newid; +} + +uid_t rmap_lgid(uid_t rgid, struct svc_export *exp) +{ + struct enf_rmap *map; + struct list_head *index; + uid_t newid; + int i_hv; + + ASSERT(exp != NULL); + + newid = rgid; + /* get credentials */ + if (!(exp->ex_opaque[ENF_TRMAP][ENF_TGID])) { + goto out; + } + + i_hv = ENF_HASH_FUNCTION(rgid); + + if (exp->ex_lgid[i_hv][ENF_HSRC] != rgid) { + list_for_each(index, exp->ex_opaque[ENF_TRMAP][ENF_TGID]) { + map = list_entry(index, struct enf_rmap, er_list); + if ((map->u_lo.gid <= rgid) && (rgid <= map->u_hi.gid)) { + /* map this gid */ + if (map->er_map) { + /* range map */ + newid = map->u_mapto.gid - map->u_lo.gid + rgid; + } else { + /* squash */ + newid = map->u_mapto.gid; + } + + exp->ex_lgid[i_hv][ENF_HSRC] = rgid; + exp->ex_lgid[i_hv][ENF_HDST] = newid; + + break; + } + } + } else { + newid = exp->ex_lgid[i_hv][ENF_HDST]; + } +out: + return newid; +} Index: enf/src/linux/2.4.17/fs/nfsd/export.c diff -u enf/src/linux/2.4.17/fs/nfsd/export.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/export.c:1.5 --- enf/src/linux/2.4.17/fs/nfsd/export.c:1.1.1.1 Tue Feb 19 06:20:06 2002 +++ enf/src/linux/2.4.17/fs/nfsd/export.c Mon Mar 11 22:20:12 2002 @@ -1,4 +1,3 @@ -#define MSNFS /* HACK HACK */ /* * linux/fs/nfsd/export.c * @@ -25,6 +24,11 @@ #include #include +#include +#include +#include + + #define NFSDDBG_FACILITY NFSDDBG_EXPORT #define NFSD_PARANOIA 1 @@ -65,6 +69,16 @@ static int hash_count; static DECLARE_WAIT_QUEUE_HEAD( hash_wait ); +/* ENF (Enhanced NFS Featrues) + * global definition list + */ +LIST_HEAD(g_enfdl); + +struct svc_client * +get_clients() +{ + return clients; +} /* * Find a client's export for a device. @@ -184,6 +198,7 @@ exp->ex_flags = nxp->ex_flags; exp->ex_anon_uid = nxp->ex_anon_uid; exp->ex_anon_gid = nxp->ex_anon_gid; + err = 0; goto out_unlock; } @@ -245,6 +260,11 @@ exp->ex_anon_uid = nxp->ex_anon_uid; exp->ex_anon_gid = nxp->ex_anon_gid; + exp->ex_opaque[ENF_TRMAP][ENF_TUID] = NULL; + exp->ex_opaque[ENF_TRMAP][ENF_TGID] = NULL; + exp->ex_opaque[ENF_TCLIST][ENF_TUID] = NULL; + exp->ex_opaque[ENF_TCLIST][ENF_TGID] = NULL; + /* Update parent pointers of all exports */ if (parent) { for (i = 0; i < NFSCLNT_EXPMAX; i++) { @@ -386,7 +406,7 @@ struct svc_fh fh; int err; - err = -EPERM; + err = -EPERM; if (path) { if (path_init(path, LOOKUP_POSITIVE, &nd) && path_walk(path, &nd)) { @@ -552,7 +572,6 @@ { NFSEXP_ALLSQUASH, {"all_squash", ""}}, { NFSEXP_ASYNC, {"async", "sync"}}, { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}}, - { NFSEXP_UIDMAP, {"uidmap", ""}}, { NFSEXP_KERBEROS, { "kerberos", ""}}, { NFSEXP_SUNSECURE, { "sunsecure", ""}}, { NFSEXP_CROSSMNT, {"nohide", ""}}, @@ -620,6 +639,7 @@ { struct svc_clnthash **hp, **head, *tmp; struct svc_client *clp; + svc_export *exp; off_t pos = 0; off_t begin = 0; @@ -656,19 +676,23 @@ htonl(addr.s_addr) >> 8 & 0xff, htonl(addr.s_addr) >> 0 & 0xff); if (tmp->h_client != clp) + { + len += sprintf(buffer+len, ")"); + } break; } } } + exp = exp->ex_next; - buffer[len++]='\n'; + buffer[len++] = '\n'; - pos=begin+len; - if(pos offset + length) goto done; @@ -683,6 +707,48 @@ len -= (offset - begin); if ( len > length ) len = length; + + return len; +} + +int +exp_procfs_debug(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + struct list_head *index, *index2; + struct enf_dl *defl; + int len = 0; + + int ur_cnt = 0; + int gr_cnt = 0; + int uc_cnt = 0; + int gc_cnt = 0; + + list_for_each(index, &(g_enfdl)) { + defl = list_entry(index, struct enf_dl, ed_list); + + list_for_each(index2, &(defl->ed_opaque[ENF_TRMAP][ENF_TUID])) { + ur_cnt++; + } + + list_for_each(index2, &(defl->ed_opaque[ENF_TRMAP][ENF_TGID])) { + gr_cnt++; + } + + list_for_each(index2, &(defl->ed_opaque[ENF_TCLIST][ENF_TUID])) { + uc_cnt++; + } + + list_for_each(index2, &(defl->ed_opaque[ENF_TCLIST][ENF_TGID])) { + gc_cnt++; + } + } + + len += sprintf(buffer + len, "%d uid rmap(s) installed\n", ur_cnt); + len += sprintf(buffer + len, "%d gid rmap(s) installed\n", gr_cnt); + len += sprintf(buffer + len, "%d uid clist(s) installed\n", uc_cnt); + len += sprintf(buffer + len, "%d gid clist(s) installed\n", gc_cnt); + return len; } Index: enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c diff -u enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c:1.3 --- enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c:1.1.1.1 Tue Feb 19 06:20:16 2002 +++ enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c Mon Mar 11 22:20:12 2002 @@ -14,6 +14,8 @@ #include #include #include +#include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -157,12 +159,14 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry) { struct inode *inode = dentry->d_inode; + static unsigned long lasttime; + struct svc_export *expp; *p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]); *p++ = htonl((u32) inode->i_mode); *p++ = htonl((u32) inode->i_nlink); - *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid)); - *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid)); + *p++ = htonl((u32) rmap_ruid(rqstp, inode->i_uid)); + *p++ = htonl((u32) rmap_rgid(rqstp, inode->i_gid)); if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) { p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { @@ -178,7 +182,24 @@ p = xdr_encode_hyper(p, (u64) inode->i_dev); p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, inode->i_atime); - p = encode_time3(p, lease_get_mtime(inode)); + + /* make readdir persist + * THIS IS NECESSARY FOR FILE CLOAKING + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + expp = nfs3svc_rqst2exp(rqstp); + if(expp && (expp->ex_opaque[ENF_TCLIST][ENF_TUID] || expp->ex_opaque[ENF_TCLIST][ENF_TGID]) + && inode->i_mode & S_IFDIR && (expp->ex_flags & NFSEXP_NOCLIENTCACHE)) { + if(CURRENT_TIME <= lasttime) { + lasttime++; + } else { + lasttime = CURRENT_TIME; + } + p = encode_time3(p, lasttime); + } else { + p = encode_time3(p, lease_get_mtime(inode)); + } + p = encode_time3(p, inode->i_ctime); return p; @@ -195,8 +216,8 @@ *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]); *p++ = htonl((u32) fhp->fh_post_mode); *p++ = htonl((u32) fhp->fh_post_nlink); - *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); - *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); + *p++ = htonl((u32) rmap_ruid(rqstp, fhp->fh_post_uid)); + *p++ = htonl((u32) rmap_rgid(rqstp, fhp->fh_post_gid)); if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { @@ -654,8 +675,32 @@ encode_entry(struct readdir_cd *cd, const char *name, int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus) { - u32 *p = cd->buffer; - int buflen, slen, elen; + u32 *p = cd->buffer; + int buflen=0, slen, elen; + struct dentry *dentry; + struct svc_export *exp = NULL; + + /* file cloaking */ + if(cd && cd->dirfh) { + exp = cd->dirfh->fh_export; + + dentry = lookup_one_len(name, cd->dirfh->fh_dentry, namlen); + if(!IS_ERR(dentry) && dentry) { + /* check for file cloaking */ + int iscl = 0; + + if (exp) { + iscl = clist_iscloaked(exp, dentry->d_inode); + } + + dput(dentry); + + if (iscl) { + /* perform file cloaking */ + return 0; + } + } + } if (cd->offset) xdr_encode_hyper(cd->offset, (u64) offset); @@ -664,11 +709,6 @@ * set the last offset entry. */ if (name == 0) return 0; - - /* - dprintk("encode_entry(%.*s @%ld%s)\n", - namlen, name, (long) offset, plus? " plus" : ""); - */ /* truncate filename if too long */ if (namlen > NFS3_MAXNAMLEN) Index: enf/src/linux/2.4.17/fs/nfsd/nfsctl.c diff -u enf/src/linux/2.4.17/fs/nfsd/nfsctl.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/nfsctl.c:1.2 --- enf/src/linux/2.4.17/fs/nfsd/nfsctl.c:1.1.1.1 Tue Feb 19 06:20:22 2002 +++ enf/src/linux/2.4.17/fs/nfsd/nfsctl.c Tue Feb 19 12:38:00 2002 @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -40,20 +41,22 @@ static int nfsctl_getfh(struct nfsctl_fhparm *, __u8 *); static int nfsctl_getfd(struct nfsctl_fdparm *, __u8 *); static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *); -#ifdef notyet -static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); -#endif + +static int nfsctl_enf(struct nfsctl_enf *data); static int initialized; int exp_procfs_exports(char *buffer, char **start, off_t offset, int length, int *eof, void *data); +int exp_procfs_debug(char *buffer, char **start, off_t offset, + int length, int *eof, void *data); void proc_export_init(void) { if (!proc_mkdir("fs/nfs", 0)) return; create_proc_read_entry("fs/nfs/exports", 0, 0, exp_procfs_exports,NULL); + create_proc_read_entry("fs/nfs/debug", 0, 0, exp_procfs_debug, NULL); } @@ -101,13 +104,32 @@ return exp_unexport(data); } -#ifdef notyet static inline int -nfsctl_ugidupdate(nfs_ugidmap *data) +nfsctl_enf(struct nfsctl_enf *data) { - return -EINVAL; + int i_ret; + unsigned short func; + + func = data->ne_func; + + switch(func) { + case ENF_ADD: + i_ret = enf_add(data); + break; + case ENF_DELETE: + i_ret = enf_delete(data); + break; + case ENF_FLUSH: + i_ret = enf_flush(data); + break; + default: + i_ret = -EINVAL; + goto out; + + } +out: + return i_ret; } -#endif static inline int nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res) @@ -208,7 +230,7 @@ /* NFSCTL_DELCLIENT */ { sizeof(struct nfsctl_client), 0}, /* NFSCTL_EXPORT */ { sizeof(struct nfsctl_export), 0}, /* NFSCTL_UNEXPORT */ { sizeof(struct nfsctl_export), 0}, - /* NFSCTL_UGIDUPDATE */ { sizeof(struct nfsctl_uidmap), 0}, + /* NFSCTL_ENF */ { sizeof(struct nfsctl_enf), 0}, /* NFSCTL_GETFH */ { sizeof(struct nfsctl_fhparm), NFS_FHSIZE}, /* NFSCTL_GETFD */ { sizeof(struct nfsctl_fdparm), NFS_FHSIZE}, /* NFSCTL_GETFS */ { sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)}, @@ -272,11 +294,9 @@ case NFSCTL_UNEXPORT: err = nfsctl_unexport(&arg->ca_export); break; -#ifdef notyet - case NFSCTL_UGIDUPDATE: - err = nfsctl_ugidupdate(&arg->ca_umap); + case NFSCTL_ENF: + err = nfsctl_enf(&arg->ca_enf); break; -#endif case NFSCTL_GETFH: err = nfsctl_getfh(&arg->ca_getfh, res->cr_getfh); break; @@ -336,6 +356,7 @@ nfsd_export_shutdown(); nfsd_cache_shutdown(); remove_proc_entry("fs/nfs/exports", NULL); + remove_proc_entry("fs/nfs/debug", NULL); remove_proc_entry("fs/nfs", NULL); nfsd_stat_shutdown(); nfsd_lockd_shutdown(); Index: enf/src/linux/2.4.17/fs/nfsd/nfsfh.c diff -u enf/src/linux/2.4.17/fs/nfsd/nfsfh.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/nfsfh.c:1.2 --- enf/src/linux/2.4.17/fs/nfsd/nfsfh.c:1.1.1.1 Tue Feb 19 06:20:19 2002 +++ enf/src/linux/2.4.17/fs/nfsd/nfsfh.c Tue Feb 19 12:38:00 2002 @@ -28,6 +28,8 @@ static int nfsd_nr_verified; static int nfsd_nr_put; +extern void nfsd_setuser(struct svc_rqst *, struct svc_export *); + struct nfsd_getdents_callback { char *name; /* name that was found. It already points to a buffer NAME_MAX+1 is size */ @@ -533,7 +535,7 @@ u32 error = 0; dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); - + if (!fhp->fh_dentry) { kdev_t xdev; ino_t xino; @@ -544,7 +546,6 @@ if (rqstp->rq_vers == 3) error = nfserr_badhandle; if (fh->fh_version == 1) { - datap = fh->fh_auth; if (--data_left<0) goto out; switch (fh->fh_auth_type) { @@ -599,8 +600,9 @@ * Look up the dentry using the NFS file handle. */ error = nfserr_stale; - if (rqstp->rq_vers == 3) + if (rqstp->rq_vers == 3) { error = nfserr_badhandle; + } if (fh->fh_version == 1) { /* if fileid_type != 0, and super_operations provide fh_to_dentry lookup, @@ -675,7 +677,6 @@ if (!(exp->ex_flags & NFSEXP_NOSUBTREECHECK)) { if (exp->ex_dentry != dentry) { struct dentry *tdentry = dentry; - do { tdentry = tdentry->d_parent; if (exp->ex_dentry == tdentry) Index: enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c diff -u enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c:1.3 --- enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c:1.1.1.1 Tue Feb 19 06:20:27 2002 +++ enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c Mon Mar 11 22:20:12 2002 @@ -14,6 +14,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -135,12 +136,14 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct inode *inode) { int type = (inode->i_mode & S_IFMT); + static unsigned long lasttime; + struct svc_export *expp; *p++ = htonl(nfs_ftypes[type >> 12]); *p++ = htonl((u32) inode->i_mode); *p++ = htonl((u32) inode->i_nlink); - *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid)); - *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid)); + *p++ = htonl((u32) rmap_ruid(rqstp, inode->i_uid)); + *p++ = htonl((u32) rmap_rgid(rqstp, inode->i_gid)); if (S_ISLNK(type) && inode->i_size > NFS_MAXPATHLEN) { *p++ = htonl(NFS_MAXPATHLEN); @@ -157,7 +160,25 @@ *p++ = htonl((u32) inode->i_ino); *p++ = htonl((u32) inode->i_atime); *p++ = 0; - *p++ = htonl((u32) lease_get_mtime(inode)); + + /* make readdir persist (force clients not to cache) + * + * THIS IS NECESSARY FOR FILE CLOAKING + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + expp = nfs3svc_rqst2exp(rqstp); + if(expp && (expp->ex_opaque[ENF_TCLIST][ENF_TUID] || expp->ex_opaque[ENF_TCLIST][ENF_TGID]) + && inode->i_mode & S_IFDIR && (expp->ex_flags & NFSEXP_NOCLIENTCACHE)) { + if(CURRENT_TIME <= lasttime) { + lasttime++; + } else { + lasttime = CURRENT_TIME; + } + *p++ = ((u32) lasttime); + } else { + *p++ = ((u32) lease_get_mtime(inode)); + } + *p++ = 0; *p++ = htonl((u32) inode->i_ctime); *p++ = 0; @@ -393,6 +414,35 @@ { u32 *p = cd->buffer; int buflen, slen; + struct dentry *dentry; + struct svc_export *exp = NULL; + + /* + dprintk("nfsd: entry(%.*s off %ld ino %ld)\n", + namlen, name, offset, ino); + */ + + /* file cloaking */ + if(cd && cd->dirfh) { + exp = cd->dirfh->fh_export; + + dentry = lookup_one_len(name, cd->dirfh->fh_dentry, namlen); + if(!IS_ERR(dentry) && dentry) { + /* check for file cloaking */ + int iscl = 0; + + if (exp) { + iscl = clist_iscloaked(exp, dentry->d_inode); + } + + dput(dentry); + + if (iscl) { + /* perform file cloaking */ + return 0; + } + } + } /* dprintk("nfsd: entry(%.*s off %ld ino %ld)\n", Index: enf/src/linux/2.4.17/fs/nfsd/vfs.c diff -u enf/src/linux/2.4.17/fs/nfsd/vfs.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/vfs.c:1.2 --- enf/src/linux/2.4.17/fs/nfsd/vfs.c:1.1.1.1 Tue Feb 19 06:20:12 2002 +++ enf/src/linux/2.4.17/fs/nfsd/vfs.c Tue Feb 19 12:38:00 2002 @@ -41,8 +41,8 @@ #include #endif /* CONFIG_NFSD_V3 */ #include +#include #include - #include #define NFSDDBG_FACILITY NFSDDBG_FILEOP @@ -179,7 +179,15 @@ err = fh_compose(resfh, exp, dentry, fhp); if (!err && !dentry->d_inode) err = nfserr_noent; + + /* check for file cloaking */ + if(exp && dentry && clist_iscloaked(exp, dentry->d_inode)) { + /* perform file cloaking */ + return nfserr_perm; + } + out: + return err; out_nfserr: @@ -822,7 +830,7 @@ goto out; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); - if (err) + if (err) goto out; dentry = fhp->fh_dentry; @@ -1483,7 +1491,7 @@ if (acc == MAY_NOP) return 0; -#if 0 + dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n", acc, (acc & MAY_READ)? " read" : "", @@ -1499,7 +1507,16 @@ IS_RDONLY(inode)? " ro" : ""); dprintk(" owner %d/%d user %d/%d\n", inode->i_uid, inode->i_gid, current->fsuid, current->fsgid); -#endif + + /* file cloaking effects permissions + * IF inode is cloaked THEN there is no access to it + * ELSE proceede with standard UNIX convention + */ + if(clist_iscloaked(exp, dentry->d_inode)) + { + /* perform cloaking */ + return nfserr_perm; + } /* only care about readonly exports for files and * directories. links don't have meaningful write access, Index: enf/src/linux/2.4.17/include/linux/nfsd/auth.h diff -u enf/src/linux/2.4.17/include/linux/nfsd/auth.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/auth.h:1.2 --- enf/src/linux/2.4.17/include/linux/nfsd/auth.h:1.1.1.1 Tue Feb 19 10:34:22 2002 +++ enf/src/linux/2.4.17/include/linux/nfsd/auth.h Tue Feb 19 12:38:27 2002 @@ -12,34 +12,11 @@ #ifdef __KERNEL__ -#define nfsd_luid(rq, uid) ((u32)(uid)) -#define nfsd_lgid(rq, gid) ((u32)(gid)) -#define nfsd_ruid(rq, uid) ((u32)(uid)) -#define nfsd_rgid(rq, gid) ((u32)(gid)) - /* * Set the current process's fsuid/fsgid etc to those of the NFS * client user */ void nfsd_setuser(struct svc_rqst *, struct svc_export *); - -#if 0 -/* - * These must match the actual size of uid_t and gid_t - */ -#define UGID_BITS (8 * sizeof(uid_t)) -#define UGID_SHIFT 8 -#define UGID_MASK ((1 << UGID_SHIFT) - 1) -#define UGID_NRENTRIES ((1 << (UGID_BITS - UGID_SHIFT)) + 1) -#define UGID_NONE ((unsigned short)-1) - -typedef struct svc_uidmap { - uid_t * um_ruid[UGID_NRENTRIES]; - uid_t * um_luid[UGID_NRENTRIES]; - gid_t * um_rgid[UGID_NRENTRIES]; - gid_t * um_lgid[UGID_NRENTRIES]; -} svc_uidmap; -#endif #endif /* __KERNEL__ */ #endif /* LINUX_NFSD_AUTH_H */ Index: enf/src/linux/2.4.17/include/linux/nfsd/enf.h diff -u /dev/null enf/src/linux/2.4.17/include/linux/nfsd/enf.h:1.2 --- /dev/null Tue Mar 19 02:10:53 2002 +++ enf/src/linux/2.4.17/include/linux/nfsd/enf.h Mon Mar 11 22:25:11 2002 @@ -0,0 +1,269 @@ +/* + * include/linux/nfsd/enf.h + * + * Enhanced NFS Features + * + * supported feature set: + * uid/gid mapping + * file cloaking + * + * Wed Sep 19 16:12:05 2001 + * Joseph Spadavecchia [JES] + * Nenad Dedic + */ + +#ifndef LINUX_NFSD_AUTH_H +#define LINUX_NFSD_AUTH_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include + +#define ENF_TRMAP 0 +#define ENF_TCLIST 1 +#define ENF_MAXTYPE 2 + +#define ENF_TUID 0 +#define ENF_TGID 1 + +#define ENF_HSRC 0 +#define ENF_HDST 1 + +#define ENF_MAXIDLEN NFSCLNT_IDMAX + NFS_MAXPATHLEN + +#define ENF_HASH_FUNCTION(x) ((x) % ENF_HASH_LEN) +#define ENF_HASH_INIT(x) do { \ + int i; \ + for(i = 0; i < ENF_HASH_LEN; i++) \ + x[i][ENF_HSRC] = i + 1; \ + } while(0); \ + +/* align mask bits with inode bits */ +#define ENF_MASK2MODE(mask) mask = (mask & 0x0077) | \ + ((mask << 4) & 0x7000) | \ + ((mask & 0x1000) >> 4); + +uid_t rmap_ruid(struct svc_rqst *, uid_t); +gid_t rmap_rgid(struct svc_rqst *, gid_t); +uid_t rmap_luid(uid_t ruid, struct svc_export *); +gid_t rmap_lgid(gid_t rgid, struct svc_export *); + +struct svc_export* enf_find_exp(char *, char *); + +/* struct for maintaining a global list + * of definition lists + * (can contain either rmaps or clists) + */ +struct enf_dl { + /* identifies a rmap definition entry */ + char ed_id[ENF_MAXIDLEN]; + + /* rmap + cloaking uid and gid information */ + struct list_head ed_opaque[ENF_MAXTYPE][2]; + + int ed_refcnt[ENF_MAXTYPE]; /* number of references to this definition */ + + struct list_head ed_list; +}; + +/* range mapping list element */ +struct enf_rmap { + unsigned char er_map:1; /* 1 for map, 0 for squash */ + + union { + uid_t uid; /* lower bound */ + gid_t gid; + } u_lo; + + union { + uid_t uid; /* lower bound */ + gid_t gid; + } u_hi; + + union { + uid_t uid; /* im_lo will be mapped to im_mapto */ + /* and im_lo + 1 to im_mapto + 1 */ + gid_t gid; + } u_mapto; + + struct list_head er_list; +}; + +/* file cloaking list element */ +struct enf_clist { + umode_t ec_mask; /* 15 14 13 12 11 10 8 7 6 5 4 3 2 1 0 */ + /* u g t show gr gw gx or ow ox */ + + union { + uid_t uid; /* lower bound */ + gid_t gid; + } u_lo; + + union { + uid_t uid; /* lower bound */ + gid_t gid; + } u_hi; + + union { + uid_t uid; /* im_lo will be mapped to im_mapto */ + /* and im_lo + 1 to im_mapto + 1 */ + gid_t gid; + } u_mapto; + + struct list_head ec_list; +}; + +/** + * Determine if a inode should be cloaked for a + * particular client and export. + * IN: + * @expp: pointer to the svc_export of the request + * @inodep: pointer to inode + * OUT: + * returns 1 IF cloaking is to be done + * ELSE returns 0 + * + * (This function assumes invocation under exp locked context.) + */ +static inline int clist_iscloaked(struct svc_export *expp, struct inode *inodep) +{ + char b_and, b_show; + struct enf_clist *tmpp; + struct list_head *index; + uid_t fuid; + gid_t fgid; + umode_t mask; + umode_t mode; + int i_hv; + struct list_head * uidlist, * gidlist; + + b_and = 0; + b_show = 0; + + if(!inodep) { + goto out; + } + + /* IF this current user owns the file + * Then the file is VISIBLE + */ + if(current->fsuid == inodep->i_uid) { + goto out; + } + + uidlist = expp->ex_opaque[ENF_TCLIST][ENF_TUID]; + gidlist = expp->ex_opaque[ENF_TCLIST][ENF_TGID]; + + if(!uidlist && !gidlist) { + goto out; + } + + fuid = inodep->i_uid; + fgid = inodep->i_gid; + mode = inodep->i_mode; + + i_hv = ENF_HASH_FUNCTION(fuid); + + /* IF the client/export has UID file + * cloaking information THEN check + * if this file should be cloaked + */ + if(uidlist) { + /* check the cloaking hash */ + if(expp->ex_cuid[i_hv][ENF_HSRC] != fuid) { + list_for_each(index, uidlist) { + tmpp = list_entry(index, struct enf_clist, ec_list); + + if(fuid >= tmpp->u_lo.uid && fuid <= tmpp->u_hi.uid) { + /* simple hash replacement */ + mask = tmpp->ec_mask; + b_show = ((mask & 0x0100) != 0); + expp->ex_cuid[i_hv][ENF_HSRC] = fuid; + expp->ex_cuid[i_hv][ENF_HDST] = mask; + goto check_cloak; + } + } + } else { + mask = expp->ex_cuid[i_hv][ENF_HDST]; + b_show = ((mask & 0x0100) != 0); + goto check_cloak; + } + + } + + i_hv = ENF_HASH_FUNCTION(fgid); + + /* IF the client/export has GID file + * cloaking information THEN check + * if this file should be CLOAKED + */ + if(gidlist) { + if(expp->ex_cgid[i_hv][ENF_HSRC] != fgid) { + list_for_each(index, gidlist) { + tmpp = list_entry(index, struct enf_clist, ec_list); + + if(fgid >= tmpp->u_lo.gid && fgid <= tmpp->u_hi.gid) { + /* simple hash replacement */ + mask = tmpp->ec_mask; + b_show = ((mask & 0x0100) != 0); + expp->ex_cgid[i_hv][ENF_HSRC] = fgid; + expp->ex_cgid[i_hv][ENF_HDST] = mask; + goto check_cloak; + } + } + } else { + mask = expp->ex_cgid[i_hv][ENF_HDST]; + b_show = ((mask & 0x0100) != 0); + goto check_cloak; + } + } + + /* IF the file is owned by a uid and gid that are + * not cloaked THEN visible + */ + goto out; + +check_cloak: + + /* IF the file is world rwx or ugt + * AND the admin mask allows other or ugt + * THEN the file is visible IF b_show = 1 + * ELSE IF b_show = 0 the file is + * hidden + */ + if(mode & (mask & 0x7007)) { + b_and = 1; + goto out; + } + + /* IF the file has any group bits on + * AND the fcloak mask allows group + * AND the current user is a member of + * the files's group then THEN file + * is visible IF b_show = 1 + * ELSE IF b_show = 0 the file + * is hidden + */ + if((mode & (0x0070 & mask)) && + in_group_p(fgid)) { + b_and = 1; + goto out; + } + + /* IF we arrive here THEN + * IF b_show = 1 + * the file is hidden + * ELSE IF b_show = 0 the + * file is visible + */ + b_and = 0; +out: + return b_and ^ b_show; +} + +#endif /* __KERNEL__ */ +#endif /* LINUX_NFSD_ENF_H */ Index: enf/src/linux/2.4.17/include/linux/nfsd/export.h diff -u enf/src/linux/2.4.17/include/linux/nfsd/export.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/export.h:1.4 --- enf/src/linux/2.4.17/include/linux/nfsd/export.h:1.1.1.1 Tue Feb 19 10:34:20 2002 +++ enf/src/linux/2.4.17/include/linux/nfsd/export.h Mon Mar 11 22:25:11 2002 @@ -32,28 +32,29 @@ #define NFSEXP_ALLSQUASH 0x0008 #define NFSEXP_ASYNC 0x0010 #define NFSEXP_GATHERED_WRITES 0x0020 -#define NFSEXP_UIDMAP 0x0040 +#define NFSEXP_RMAP 0x0040 /* range mapping */ #define NFSEXP_KERBEROS 0x0080 /* not available */ #define NFSEXP_SUNSECURE 0x0100 #define NFSEXP_CROSSMNT 0x0200 #define NFSEXP_NOSUBTREECHECK 0x0400 #define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ #define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect */ -#define NFSEXP_ALLFLAGS 0x1FFF - +#define NFSEXP_NOCLIENTCACHE 0x2000 /* cause NFS server to turn off _client_ caching to assist file cloaking */ +#define NFSEXP_ALLFLAGS 0x2FFF #ifdef __KERNEL__ /* The following are hashtable sizes and must be powers of 2 */ #define NFSCLNT_EXPMAX 16 +#define ENF_HASH_LEN 32 + struct svc_client { struct svc_client * cl_next; char cl_ident[NFSCLNT_IDMAX]; int cl_idlen; int cl_naddr; struct in_addr cl_addr[NFSCLNT_ADDRMAX]; - struct svc_uidmap * cl_umap; struct svc_export * cl_export[NFSCLNT_EXPMAX]; }; @@ -69,6 +70,25 @@ ino_t ex_ino; uid_t ex_anon_uid; gid_t ex_anon_gid; + + /* range mapping hash tables */ + uid_t ex_ruid[ENF_HASH_LEN][2]; + uid_t ex_luid[ENF_HASH_LEN][2]; + gid_t ex_rgid[ENF_HASH_LEN][2]; + gid_t ex_lgid[ENF_HASH_LEN][2]; + + /* file cloaking hash tables */ + uid_t ex_cuid[ENF_HASH_LEN][2]; + gid_t ex_cgid[ENF_HASH_LEN][2]; + + /* ex_opaque: + * ________0________________1________ + * 0| uid rmap list | gid rmap list | + * |----------------|-----------------| + * 1| uid clist list | gid clist list | + * ---------------------------------- + */ + struct list_head *ex_opaque[2][2]; }; #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) @@ -94,7 +114,7 @@ char *path, struct knfsd_fh *, int maxsize); int nfserrno(int errno); void exp_nlmdetach(void); - +struct svc_client * get_clients(void); #endif /* __KERNEL__ */ Index: enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h diff -u enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h:1.2 --- enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h:1.1.1.1 Tue Feb 19 10:34:24 2002 +++ enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h Tue Feb 19 12:38:27 2002 @@ -19,13 +19,36 @@ #include #include #include +#include #include #include #include + /* * nfsd version */ #define NFSD_VERSION "0.5" + + +#if 1 +# define ASSERT(EX) \ +do { \ + if (!(EX)) { \ + printk(KERN_CRIT "ASSERTION FAILED: %s at %s:%d (%s)\n", #EX, \ + __FILE__, __LINE__, __FUNCTION__); \ + (*((char *)0))=0; \ + } \ +} while (0) +#else +# define ASSERT(EX) +#endif + + +#if 1 +# define DBG printk("<1> %s:%d:%s\n",__FILE__,__LINE__,__FUNCTION__) +#else +# define DBG +#endif #ifdef __KERNEL__ /* Index: enf/src/linux/2.4.17/include/linux/nfsd/syscall.h diff -u enf/src/linux/2.4.17/include/linux/nfsd/syscall.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/syscall.h:1.3 --- enf/src/linux/2.4.17/include/linux/nfsd/syscall.h:1.1.1.1 Tue Feb 19 10:34:21 2002 +++ enf/src/linux/2.4.17/include/linux/nfsd/syscall.h Mon Mar 11 22:25:11 2002 @@ -15,6 +15,7 @@ # include # include #endif + #include #include #include @@ -34,7 +35,7 @@ #define NFSCTL_DELCLIENT 2 /* Remove an NFS client. */ #define NFSCTL_EXPORT 3 /* export a file system. */ #define NFSCTL_UNEXPORT 4 /* unexport a file system. */ -#define NFSCTL_UGIDUPDATE 5 /* update a client's uid/gid map. */ +#define NFSCTL_ENF 5 /* update uid/gid range mapping or cloaking info. */ #define NFSCTL_GETFH 6 /* get an fh by ino (used by mountd) */ #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ @@ -66,15 +67,56 @@ __kernel_gid_t ex_anon_gid; }; -/* UGIDUPDATE */ -struct nfsctl_uidmap { - char * ug_ident; - __kernel_uid_t ug_uidbase; - int ug_uidlen; - __kernel_uid_t * ug_udimap; - __kernel_gid_t ug_gidbase; - int ug_gidlen; - __kernel_gid_t * ug_gdimap; +/* ENF arguments */ +struct nfsctl_enf { +/* functions (ne_func) */ +#define ENF_ADD 1 +#define ENF_DELETE 2 +#define ENF_FLUSH 3 + + /* The type of information we are adding + */ + unsigned char ne_type; /* range map (ENF_TRMAP) */ + /* file cloak (ENF_TCLIST) */ + + /* This is only set for enf_add(). It the the key in the global + * def. list that uniquely identifies the /etc/exports entry + * this belongs to. It alows us to save memory by storing + * one copy of a range mapping or cloaking definition for all + * clients connected an export + */ + char ne_id[ENF_MAXIDLEN]; + + /* Used to identify an actual client and export. + * nr_client is always a FQDN, where nr_id may + * have non FQDN client portion + */ + char ne_client[NFSCLNT_IDMAX]; + char ne_path[NFS_MAXPATHLEN]; + + unsigned short ne_func:8, /* function to perform (e.g. ENF_ADD) */ + ne_uid:1, /* 1 for uidmap, 0 for gidmap */ + ne_generic:6; /* 6 bits future features */ + + umode_t ne_mask; /*file-cloaking mask */ + /* 13 12 11 10 8 7 6 5 4 3 2 1 0 */ + /* show u g t gr gw gx or ow ox */ + union { + uid_t uid; + gid_t gid; + } u_lo; + + union { + uid_t uid; + gid_t gid; + } u_hi; + + /* Below only used to add range-mapping information */ + unsigned char ne_map:1; /* 1 for mapping 0 for squashing */ + union { + uid_t uid; + gid_t gid; + } u_mapto; }; /* GETFH */ @@ -108,7 +150,7 @@ struct nfsctl_svc u_svc; struct nfsctl_client u_client; struct nfsctl_export u_export; - struct nfsctl_uidmap u_umap; + struct nfsctl_enf u_enf; struct nfsctl_fhparm u_getfh; struct nfsctl_fdparm u_getfd; struct nfsctl_fsparm u_getfs; @@ -116,7 +158,7 @@ #define ca_svc u.u_svc #define ca_client u.u_client #define ca_export u.u_export -#define ca_umap u.u_umap +#define ca_enf u.u_enf #define ca_getfh u.u_getfh #define ca_getfd u.u_getfd #define ca_getfs u.u_getfs @@ -141,6 +183,9 @@ extern int exp_delclient(struct nfsctl_client *ncp); extern int exp_export(struct nfsctl_export *nxp); extern int exp_unexport(struct nfsctl_export *nxp); +extern int enf_add(struct nfsctl_enf *data); +extern int enf_delete(struct nfsctl_enf *data); +extern int enf_flush(struct nfsctl_enf *data); #endif /* __KERNEL__ */ Index: enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h diff -u enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h:1.2 --- enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h:1.1.1.1 Tue Feb 19 10:34:25 2002 +++ enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h Tue Feb 19 12:38:27 2002 @@ -298,5 +298,45 @@ int namlen, loff_t offset, ino_t ino, unsigned int); +/* [JES] + * Return the svc_export from the @rqstp svc_request struct. + */ +static __inline__ struct svc_export *nfs3svc_rqst2exp(struct svc_rqst *rqstp) +{ + struct svc_export *retp = NULL; + struct svc_fh fh; + struct nfsd3_attrstat response; /* for nfs3 */ + + if(!rqstp) { + goto out; + } + + /* get the export this request is referring to */ + if (rqstp->rq_vers == 2) + { + /* HACK v2! */ + memcpy((void *)(&fh), (void *)(rqstp->rq_resp), sizeof(fh)); + } + else if (rqstp->rq_vers == 3) + { + /* HACK v3! */ + memcpy((void *)(&response), (void *)(rqstp->rq_resp), + sizeof(struct nfsd3_attrstat)); + + memcpy((void *)(&fh), (void*)(&(response.fh)), sizeof(fh)); + } + else + { + printk(KERN_DEBUG "EXP: exp_rqst2exp() -- unsuported NFS version %d\n", + rqstp->rq_vers); + + goto out_unlock; + } +out_unlock: + retp = (fh.fh_export); +out: + return retp; +} + #endif /* _LINUX_NFSD_XDR3_H */