From: Andy Adamson Date: Tue, 17 Jul 2007 11:04:51 +0000 (-0700) Subject: knfsd: nfsd4: implement secinfo X-Git-Tag: v2.6.23-rc1~638 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dcb488a3b7ac3987e21148f44f641c9b2e734232;p=linux-2.6 knfsd: nfsd4: implement secinfo Implement the secinfo operation. (Thanks to Usha Ketineni wrote an earlier version of this support.) Cc: Usha Ketineni Signed-off-by: Andy Adamson Signed-off-by: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index a106e3be7c..3c627128e2 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -47,6 +47,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_PROC @@ -609,6 +610,30 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; } +static __be32 +nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_secinfo *secinfo) +{ + struct svc_fh resfh; + struct svc_export *exp; + struct dentry *dentry; + __be32 err; + + fh_init(&resfh, NFS4_FHSIZE); + err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, + secinfo->si_name, secinfo->si_namelen, + &exp, &dentry); + if (err) + return err; + if (dentry->d_inode == NULL) { + exp_put(exp); + err = nfserr_noent; + } else + secinfo->si_exp = exp; + dput(dentry); + return err; +} + static __be32 nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) @@ -1008,6 +1033,9 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { [OP_SAVEFH] = { .op_func = (nfsd4op_func)nfsd4_savefh, }, + [OP_SECINFO] = { + .op_func = (nfsd4op_func)nfsd4_secinfo, + }, [OP_SETATTR] = { .op_func = (nfsd4op_func)nfsd4_setattr, }, diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b0bfbda375..864498f8f2 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -56,6 +56,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -818,6 +819,23 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) DECODE_TAIL; } +static __be32 +nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, + struct nfsd4_secinfo *secinfo) +{ + DECODE_HEAD; + + READ_BUF(4); + READ32(secinfo->si_namelen); + READ_BUF(secinfo->si_namelen); + SAVEMEM(secinfo->si_name, secinfo->si_namelen); + status = check_filename(secinfo->si_name, secinfo->si_namelen, + nfserr_noent); + if (status) + return status; + DECODE_TAIL; +} + static __be32 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) { @@ -1131,6 +1149,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) case OP_SAVEFH: op->status = nfs_ok; break; + case OP_SECINFO: + op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo); + break; case OP_SETATTR: op->status = nfsd4_decode_setattr(argp, &op->u.setattr); break; @@ -1847,11 +1868,19 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, if (d_mountpoint(dentry)) { int err; + /* + * Why the heck aren't we just using nfsd_lookup?? + * Different "."/".." handling? Something else? + * At least, add a comment here to explain.... + */ err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); if (err) { nfserr = nfserrno(err); goto out_put; } + nfserr = check_nfsd_access(exp, cd->rd_rqstp); + if (nfserr) + goto out_put; } nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, @@ -2419,6 +2448,49 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ } } +static void +nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr, + struct nfsd4_secinfo *secinfo) +{ + int i = 0; + struct svc_export *exp = secinfo->si_exp; + ENCODE_HEAD; + + if (nfserr) + goto out; + RESERVE_SPACE(4); + WRITE32(exp->ex_nflavors); + ADJUST_ARGS(); + for (i = 0; i < exp->ex_nflavors; i++) { + u32 flav = exp->ex_flavors[i].pseudoflavor; + struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav); + + if (gm) { + RESERVE_SPACE(4); + WRITE32(RPC_AUTH_GSS); + ADJUST_ARGS(); + RESERVE_SPACE(4 + gm->gm_oid.len); + WRITE32(gm->gm_oid.len); + WRITEMEM(gm->gm_oid.data, gm->gm_oid.len); + ADJUST_ARGS(); + RESERVE_SPACE(4); + WRITE32(0); /* qop */ + ADJUST_ARGS(); + RESERVE_SPACE(4); + WRITE32(gss_pseudoflavor_to_service(gm, flav)); + ADJUST_ARGS(); + gss_mech_put(gm); + } else { + RESERVE_SPACE(4); + WRITE32(flav); + ADJUST_ARGS(); + } + } +out: + if (exp) + exp_put(exp); +} + /* * The SETATTR encode routine is special -- it always encodes a bitmap, * regardless of the error status. @@ -2559,6 +2631,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) break; case OP_SAVEFH: break; + case OP_SECINFO: + nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo); + break; case OP_SETATTR: nfsd4_encode_setattr(resp, op->status, &op->u.setattr); break; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 54ef1a18a5..e452256d3f 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -71,6 +71,9 @@ int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, struct svc_export **expp); __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); +__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *, + const char *, int, + struct svc_export **, struct dentry **); __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, struct iattr *, int, time_t); #ifdef CONFIG_NFSD_V4 diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 09799bcee0..1b65326713 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -293,6 +293,12 @@ struct nfsd4_rename { struct nfsd4_change_info rn_tinfo; /* response */ }; +struct nfsd4_secinfo { + u32 si_namelen; /* request */ + char *si_name; /* request */ + struct svc_export *si_exp; /* response */ +}; + struct nfsd4_setattr { stateid_t sa_stateid; /* request */ u32 sa_bmval[2]; /* request */ @@ -365,6 +371,7 @@ struct nfsd4_op { struct nfsd4_remove remove; struct nfsd4_rename rename; clientid_t renew; + struct nfsd4_secinfo secinfo; struct nfsd4_setattr setattr; struct nfsd4_setclientid setclientid; struct nfsd4_setclientid_confirm setclientid_confirm;