Commit 20065001 authored by Trond Myklebust's avatar Trond Myklebust

RPCSEC_GSS: Split out integrity code in wrap and

    unwrap procedures; otherwise they're going to
    be ridiculously long after we add privacy support.

Patch by Bruce Fields
parent d4e0c4b2
...@@ -812,41 +812,19 @@ gss_validate(struct rpc_task *task, u32 *p) ...@@ -812,41 +812,19 @@ gss_validate(struct rpc_task *task, u32 *p)
return NULL; return NULL;
} }
static int static inline int
gss_wrap_req(struct rpc_task *task, gss_wrap_req_integ(struct gss_cl_ctx *ctx,
kxdrproc_t encode, void *rqstp, u32 *p, void *obj) kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
{ {
struct rpc_rqst *req = (struct rpc_rqst *)rqstp; struct rpc_rqst *req = (struct rpc_rqst *)rqstp;
struct xdr_buf *snd_buf = &req->rq_snd_buf; struct xdr_buf *snd_buf = &req->rq_snd_buf;
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
u32 *integ_len = NULL;
int status = -EIO;
u32 maj_stat = 0;
struct xdr_buf integ_buf; struct xdr_buf integ_buf;
u32 *integ_len = NULL;
struct xdr_netobj mic; struct xdr_netobj mic;
u32 service;
u32 offset, *q; u32 offset, *q;
struct iovec *iov; struct iovec *iov;
u32 maj_stat = 0;
dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid); int status = -EIO;
BUG_ON(!ctx);
if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
/* The spec seems a little ambiguous here, but I think that not
* wrapping context destruction requests makes the most sense.
*/
status = encode(rqstp, p, obj);
goto out;
}
service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
gss_cred->gc_flavor);
switch (service) {
case RPC_GSS_SVC_NONE:
status = encode(rqstp, p, obj);
goto out;
case RPC_GSS_SVC_INTEGRITY:
integ_len = p++; integ_len = p++;
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
...@@ -854,11 +832,11 @@ gss_wrap_req(struct rpc_task *task, ...@@ -854,11 +832,11 @@ gss_wrap_req(struct rpc_task *task,
status = encode(rqstp, p, obj); status = encode(rqstp, p, obj);
if (status) if (status)
goto out; return status;
if (xdr_buf_subsegment(snd_buf, &integ_buf, if (xdr_buf_subsegment(snd_buf, &integ_buf,
offset, snd_buf->len - offset)) offset, snd_buf->len - offset))
goto out; return status;
*integ_len = htonl(integ_buf.len); *integ_len = htonl(integ_buf.len);
/* guess whether we're in the head or the tail: */ /* guess whether we're in the head or the tail: */
...@@ -873,72 +851,112 @@ gss_wrap_req(struct rpc_task *task, ...@@ -873,72 +851,112 @@ gss_wrap_req(struct rpc_task *task,
GSS_C_QOP_DEFAULT, &integ_buf, &mic); GSS_C_QOP_DEFAULT, &integ_buf, &mic);
status = -EIO; /* XXX? */ status = -EIO; /* XXX? */
if (maj_stat) if (maj_stat)
goto out; return status;
q = xdr_encode_opaque(p, NULL, mic.len); q = xdr_encode_opaque(p, NULL, mic.len);
offset = (u8 *)q - (u8 *)p; offset = (u8 *)q - (u8 *)p;
iov->iov_len += offset; iov->iov_len += offset;
snd_buf->len += offset; snd_buf->len += offset;
break; return 0;
}
static int
gss_wrap_req(struct rpc_task *task,
kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
int status = -EIO;
u32 service;
dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid);
if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
/* The spec seems a little ambiguous here, but I think that not
* wrapping context destruction requests makes the most sense.
*/
status = encode(rqstp, p, obj);
goto out;
}
service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
gss_cred->gc_flavor);
switch (service) {
case RPC_GSS_SVC_NONE:
status = encode(rqstp, p, obj);
goto out;
case RPC_GSS_SVC_INTEGRITY:
status = gss_wrap_req_integ(ctx, encode, rqstp, p, obj);
goto out;
case RPC_GSS_SVC_PRIVACY: case RPC_GSS_SVC_PRIVACY:
default: default:
goto out; goto out;
} }
status = 0;
out: out:
gss_put_ctx(ctx); gss_put_ctx(ctx);
dprintk("RPC: %4u gss_wrap_req returning %d\n", task->tk_pid, status); dprintk("RPC: %4u gss_wrap_req returning %d\n", task->tk_pid, status);
return status; return status;
} }
static int static inline int
gss_unwrap_resp(struct rpc_task *task, gss_unwrap_resp_integ(struct gss_cl_ctx *ctx,
kxdrproc_t decode, void *rqstp, u32 *p, void *obj) kxdrproc_t decode, void *rqstp, u32 **p, void *obj)
{ {
struct rpc_rqst *req = (struct rpc_rqst *)rqstp; struct rpc_rqst *req = (struct rpc_rqst *)rqstp;
struct xdr_buf *rcv_buf = &req->rq_rcv_buf; struct xdr_buf *rcv_buf = &req->rq_rcv_buf;
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
struct xdr_buf integ_buf; struct xdr_buf integ_buf;
struct xdr_netobj mic; struct xdr_netobj mic;
int status = -EIO;
u32 maj_stat = 0;
u32 service;
u32 data_offset, mic_offset; u32 data_offset, mic_offset;
u32 integ_len; u32 integ_len;
u32 maj_stat;
int status = -EIO;
BUG_ON(!ctx); integ_len = ntohl(*(*p)++);
if (ctx->gc_proc != RPC_GSS_PROC_DATA)
goto out_decode;
service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
gss_cred->gc_flavor);
switch (service) {
case RPC_GSS_SVC_NONE:
goto out_decode;
case RPC_GSS_SVC_INTEGRITY:
integ_len = ntohl(*p++);
if (integ_len & 3) if (integ_len & 3)
goto out; return status;
data_offset = (u8 *)p - (u8 *)rcv_buf->head[0].iov_base; data_offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base;
mic_offset = integ_len + data_offset; mic_offset = integ_len + data_offset;
if (mic_offset > rcv_buf->len) if (mic_offset > rcv_buf->len)
goto out; return status;
if (ntohl(*p++) != req->rq_seqno) if (ntohl(*(*p)++) != req->rq_seqno)
goto out; return status;
if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset,
mic_offset - data_offset)) mic_offset - data_offset))
goto out; return status;
if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset))
goto out; return status;
maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf,
&mic, NULL); &mic, NULL);
if (maj_stat != GSS_S_COMPLETE) if (maj_stat != GSS_S_COMPLETE)
return status;
return 0;
}
static int
gss_unwrap_resp(struct rpc_task *task,
kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
int status = -EIO;
u32 service;
if (ctx->gc_proc != RPC_GSS_PROC_DATA)
goto out_decode;
service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
gss_cred->gc_flavor);
switch (service) {
case RPC_GSS_SVC_NONE:
goto out_decode;
case RPC_GSS_SVC_INTEGRITY:
status = gss_unwrap_resp_integ(ctx, decode,
rqstp, &p, obj);
if (status)
goto out; goto out;
break; break;
case RPC_GSS_SVC_PRIVACY: case RPC_GSS_SVC_PRIVACY:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment