From: Andy Adamson Date: Fri, 18 May 2007 16:52:40 -0400 NFSv4: Add the NFS SECINFO xdr encode/decode routines Encode and decode routines for OP_SECINFO. Decode routine saves an orderd list of up to NFS4_SECINFO_MAXFLAVORS server supplied pseudoflavors supported on the client. Signed-off-by: Andy Adamson Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/nfs4.h | 1 include/linux/nfs_xdr.h | 11 ++++ 3 files changed, 131 insertions(+), 0 deletions(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 8003c91..e561cc8 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,8 @@ static int nfs4_stat_to_errno(int); 3 + 3 + 3 + 2 * nfs4_name_maxsz)) #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ nfs4_fattr_value_maxsz) +#define gss_oid_maxsz (GSS_OID_MAX_LEN >> 2) +#define nfs4_flav_info_maxsz (1 + gss_oid_maxsz + 1 + 1) #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) #define encode_savefh_maxsz (op_encode_hdr_maxsz) #define decode_savefh_maxsz (op_decode_hdr_maxsz) @@ -137,6 +140,10 @@ static int nfs4_stat_to_errno(int); #define decode_create_maxsz (op_decode_hdr_maxsz + 8) #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) +#define encode_secinfo_maxsz (op_encode_hdr_maxsz + 1 + nfs4_name_maxsz) +#define decode_secinfo_maxsz (op_decode_hdr_maxsz + 1 + \ + (1 + nfs4_flav_info_maxsz) * \ + NFS4_SECINFO_MAXFLAVORS) #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ @@ -423,6 +430,12 @@ static int nfs4_stat_to_errno(int); decode_putfh_maxsz + \ op_decode_hdr_maxsz + \ nfs4_fattr_bitmap_maxsz) +#define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_secinfo_maxsz) +#define NFS4_dec_secinfo_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_secinfo_maxsz) static struct { unsigned int mode; @@ -1215,6 +1228,18 @@ encode_savefh(struct xdr_stream *xdr) return 0; } +static int encode_secinfo(struct xdr_stream *xdr, const struct qstr *name) +{ + uint32_t *p; + + RESERVE_SPACE(8 + name->len); + WRITE32(OP_SECINFO); + WRITE32(name->len); + WRITEMEM(name->name, name->len); + +return 0; +} + static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server) { int status; @@ -1763,6 +1788,25 @@ out: } /* + * Encode SECINFO request + */ +static int nfs4_xdr_enc_secinfo(struct rpc_rqst *req, uint32_t *p, const struct nfs4_secinfo_arg *args) +{ + int status; + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->dir_fh); + if (!status) + status = encode_secinfo(&xdr, args->name); + return status; +} + +/* * Encode an SETATTR request */ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args) @@ -3558,6 +3602,62 @@ decode_savefh(struct xdr_stream *xdr) return decode_op_hdr(xdr, OP_SAVEFH); } +/* + * Save up to NFS4_SECINFO_MAXFLAVORS supported pseudoflavors. + */ +static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) +{ + uint32_t *p; + uint32_t qop; + uint32_t service; + int status; + int i, nflavors; + rpc_authflavor_t flavor; + int oidlen; + char oiddata[GSS_OID_MAX_LEN]; + + status = decode_op_hdr(xdr, OP_SECINFO); + if (status) + return status; + + READ_BUF(4); + READ32(nflavors); + res->fl_num = 0; + for (i = 0; i < nflavors ; i++) { + READ_BUF(4); + READ32(flavor); + switch (flavor) { + case RPC_AUTH_GSS: + READ_BUF(4); + READ32(oidlen); + READ_BUF(oidlen + 8); + + if (oidlen > GSS_OID_MAX_LEN || + res->fl_num > NFS4_SECINFO_MAXFLAVORS) + break; + + COPYMEM(oiddata, oidlen); + READ32(qop); + READ32(service); + flavor = gss_triple_to_pseudoflavor(oidlen, + oiddata, qop, service); + if (flavor == RPC_AUTH_MAXFLAVOR) + /* unsupported pseudoflavor */ + break; + res->flavors[i] = flavor; + res->fl_num++; + break; + case RPC_AUTH_UNIX: + case RPC_AUTH_NULL: + if (res->fl_num > NFS4_SECINFO_MAXFLAVORS) + break; + res->flavors[i] = flavor; + res->fl_num++; + } + } + return 0; +} + static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) { __be32 *p; @@ -4046,6 +4146,24 @@ out: } /* + * Decode SECINFO response + */ +static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_secinfo_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (!status) + status = decode_putfh(&xdr); + if (!status) + status = decode_secinfo(&xdr, res); + return status; +} + +/* * Decode SETATTR response */ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res) @@ -4595,6 +4713,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(GETACL, enc_getacl, dec_getacl), PROC(SETACL, enc_setacl, dec_setacl), PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), + PROC(SECINFO, enc_secinfo, dec_secinfo), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 7e7f33a..16116b8 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -391,6 +391,7 @@ enum { NFSPROC4_CLNT_GETACL, NFSPROC4_CLNT_SETACL, NFSPROC4_CLNT_FS_LOCATIONS, + NFSPROC4_CLNT_SECINFO, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 10c26ed..c1ec5ec 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -320,6 +320,17 @@ struct nfs_renameargs { unsigned int tolen; }; +struct nfs4_secinfo_arg { + const struct nfs_fh * dir_fh; + const struct qstr * name; +}; + +#define NFS4_SECINFO_MAXFLAVORS 12 +struct nfs4_secinfo_res { + unsigned int fl_num; + rpc_authflavor_t flavors[NFS4_SECINFO_MAXFLAVORS]; +}; + struct nfs_setattrargs { struct nfs_fh * fh; nfs4_stateid stateid;