nfs4_set_secinfo() queries a struct svc_export->ex_flavors list and stuffs an nfsd4_secinfo struct with an ordered list of supported pseudoflavors. OP_SECINFO processin calls nfsd_lookup using the curent directory filehandle and name. This is the only nfsd_lookup call that passes a non-NULL secinfo parameter. nfs4_set_secinfo() is either called by nfsd_cross_mnt() when the given name is in a different export than the current file handle, or by nfsd4_secinfo when the given name is in the same export as the current file handle. Signed-off-by: Andy Adamson --- --- linux-2.6.18-rc5-andros/fs/nfsd/nfs4proc.c | 79 +++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff -puN fs/nfsd/nfs4proc.c~nfsd-secinfo-proc fs/nfsd/nfs4proc.c --- linux-2.6.18-rc5/fs/nfsd/nfs4proc.c~nfsd-secinfo-proc 2006-10-11 17:36:49.000000000 -0400 +++ linux-2.6.18-rc5-andros/fs/nfsd/nfs4proc.c 2006-10-11 17:36:49.000000000 -0400 @@ -54,6 +54,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_PROC @@ -67,9 +68,13 @@ fh_dup2(struct svc_fh *dst, struct svc_f *dst = *src; } +/* forward declaration */ +void nfs4_set_secinfo(struct svc_export *exp, void *secinfo); + int nfs4_set_secinfo_xmnt(struct svc_export *exp, void *secinfo) { + nfs4_set_secinfo(exp, (struct nfsd4_secinfo *)secinfo); return nfserr_wrongsec; } @@ -593,6 +598,77 @@ nfsd4_rename(struct svc_rqst *rqstp, str return status; } +void +nfs4_set_secinfo(struct svc_export *exp, void *secinfo) +{ + struct nfsd4_secinfo *si = (struct nfsd4_secinfo *)secinfo; + struct gss_api_mech *mech; + int i, order; + + if (!si) + return; + si->nmech = 0; + for (i = 0; i < MAX_SECINFO_LIST; i++) { + int flav = exp->ex_flavors[i].pseudoflavor; + + if (flav == -1) + continue; + + /* Order of pseudoflavor(s) in /etc/export file */ + order = exp->ex_flavors[i].order; + + /* AUTH_SYS and AUTH_NULL return only flavor */ + if (flav == 1 ||flav == 0) { + si->mechs[order].flavor = flav; + si->nmech++; + continue; + } + mech = gss_mech_get_by_pseudoflavor(flav); + if (!mech) { + printk(KERN_WARNING "%s: export pseudoflavor %d not found!", + __FUNCTION__, flav); + continue; + } + si->mechs[order].st.oid = mech->gm_oid; + /* Currently qop is set to 0, can be replaced later with a value + * of pos->gm_pfs[i].qop when qop is being used.*/ + si->mechs[order].st.qop = 0; + si->mechs[order].st.service = gss_pseudoflavor_to_service(mech,flav); + si->mechs[order].flavor = 6; + si->nmech++; + } +} + +static inline int +nfsd4_secinfo(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_secinfo *secinfo) +{ + struct svc_fh resfh; + int status; + + /* XXX also check UTF-8 compliance */ + if (secinfo->len == 0) { + status = nfserr_inval; + goto out; + } + + fh_init(&resfh, NFS4_FHSIZE); + status = __nfsd_lookup(rqstp, current_fh, secinfo->name, secinfo->len, + &resfh, secinfo); + if (status == nfserr_wrongsec) { + /* attempt to cross mountpoint with wrong security. + * nfs4_set_secinfo_xmnt called by nfs4_cross_mnt + * which calls nfs4_set_secinfo(); succeed the secinfo call. + */ + status = 0; + goto out; + } + if (status) + goto out; + nfs4_set_secinfo(current_fh->fh_export, secinfo); +out: + return status; +} + static inline int nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr) { @@ -915,6 +991,9 @@ nfsd4_proc_compound(struct svc_rqst *rqs case OP_SAVEFH: op->status = nfsd4_savefh(current_fh, save_fh); break; + case OP_SECINFO: + op->status = nfsd4_secinfo(rqstp, current_fh, &op->u.secinfo); + break; case OP_SETATTR: op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr); break; _