client-side only integrity include/linux/sunrpc/auth.h | 6 include/linux/sunrpc/gss_api.h | 9 - include/linux/sunrpc/gss_krb5.h | 6 include/linux/sunrpc/xdr.h | 4 net/sunrpc/auth.c | 29 ++++ net/sunrpc/auth_gss/auth_gss.c | 237 +++++++++++++++++++++++++++------- net/sunrpc/auth_gss/gss_krb5_crypto.c | 47 +++++- net/sunrpc/auth_gss/gss_krb5_mech.c | 7 - net/sunrpc/auth_gss/gss_krb5_seal.c | 23 --- net/sunrpc/auth_gss/gss_krb5_unseal.c | 58 +------- net/sunrpc/auth_gss/gss_mech_switch.c | 4 net/sunrpc/clnt.c | 6 net/sunrpc/sunrpc_syms.c | 3 net/sunrpc/xdr.c | 121 +++++++++++++++++ 14 files changed, 425 insertions(+), 135 deletions(-) diff -puN include/linux/sunrpc/auth.h~rpc_integ include/linux/sunrpc/auth.h --- linux-2.5.69/include/linux/sunrpc/auth.h~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/include/linux/sunrpc/auth.h 2003-05-07 21:29:02.000000000 -0400 @@ -102,6 +102,10 @@ struct rpc_credops { u32 * (*crmarshal)(struct rpc_task *, u32 *, int); int (*crrefresh)(struct rpc_task *); u32 * (*crvalidate)(struct rpc_task *, u32 *); + int (*crwrap_req)(struct rpc_task *, kxdrproc_t, + void *, u32 *, void *); + int (*crunwrap_resp)(struct rpc_task *, kxdrproc_t, + void *, u32 *, void *); }; extern struct rpc_authops authunix_ops; @@ -124,6 +128,8 @@ void put_rpccred(struct rpc_cred *); void rpcauth_unbindcred(struct rpc_task *); u32 * rpcauth_marshcred(struct rpc_task *, u32 *); u32 * rpcauth_checkverf(struct rpc_task *, u32 *); +int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *data, void *obj); +int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *data, void *obj); int rpcauth_refreshcred(struct rpc_task *); void rpcauth_invalcred(struct rpc_task *); int rpcauth_uptodatecred(struct rpc_task *); diff -puN include/linux/sunrpc/gss_api.h~rpc_integ include/linux/sunrpc/gss_api.h --- linux-2.5.69/include/linux/sunrpc/gss_api.h~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/include/linux/sunrpc/gss_api.h 2003-05-07 21:29:02.000000000 -0400 @@ -16,6 +16,7 @@ #ifdef __KERNEL__ #include +#include /* The mechanism-independent gss-api context: */ struct gss_ctx { @@ -39,11 +40,11 @@ u32 gss_import_sec_context( u32 gss_get_mic( struct gss_ctx *ctx_id, u32 qop, - struct xdr_netobj *message, + struct xdr_buf *message, struct xdr_netobj *mic_token); u32 gss_verify_mic( struct gss_ctx *ctx_id, - struct xdr_netobj *message, + struct xdr_buf *message, struct xdr_netobj *mic_token, u32 *qstate); u32 gss_delete_sec_context( @@ -95,11 +96,11 @@ struct gss_api_ops { u32 (*gss_get_mic)( struct gss_ctx *ctx_id, u32 qop, - struct xdr_netobj *message, + struct xdr_buf *message, struct xdr_netobj *mic_token); u32 (*gss_verify_mic)( struct gss_ctx *ctx_id, - struct xdr_netobj *message, + struct xdr_buf *message, struct xdr_netobj *mic_token, u32 *qstate); void (*gss_delete_sec_context)( diff -puN include/linux/sunrpc/gss_krb5.h~rpc_integ include/linux/sunrpc/gss_krb5.h --- linux-2.5.69/include/linux/sunrpc/gss_krb5.h~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/include/linux/sunrpc/gss_krb5.h 2003-05-07 21:29:02.000000000 -0400 @@ -120,18 +120,18 @@ enum seal_alg { #define ENCTYPE_UNKNOWN 0x01ff s32 -krb5_make_checksum(s32 cksumtype, char *header, char *body, int body_len, +krb5_make_checksum(s32 cksumtype, char *header, struct xdr_buf *body, struct xdr_netobj *cksum); u32 krb5_make_token(struct krb5_ctx *context_handle, int qop_req, - struct xdr_netobj *input_message_buffer, + struct xdr_buf *input_message_buffer, struct xdr_netobj *output_message_buffer, int toktype); u32 krb5_read_token(struct krb5_ctx *context_handle, struct xdr_netobj *input_token_buffer, - struct xdr_netobj *message_buffer, + struct xdr_buf *message_buffer, int *qop_state, int toktype); u32 diff -puN net/sunrpc/auth.c~rpc_integ net/sunrpc/auth.c --- linux-2.5.69/net/sunrpc/auth.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/auth.c 2003-05-07 21:30:40.000000000 -0400 @@ -340,6 +340,35 @@ rpcauth_checkverf(struct rpc_task *task, } int +rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, + u32 *data, void *obj) +{ + struct rpc_cred *cred = task->tk_msg.rpc_cred; + + dprintk("RPC: %4d using %s cred %p to wrap rpc data\n", + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); + if (cred->cr_ops->crwrap_req) + return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); + /* By default, we encode the arguments normally. */ + return encode(rqstp, data, obj); +} + +int +rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, + u32 *data, void *obj) +{ + struct rpc_cred *cred = task->tk_msg.rpc_cred; + + dprintk("RPC: %4d using %s cred %p to unwrap rpc data\n", + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); + if (cred->cr_ops->crunwrap_resp) + return cred->cr_ops->crunwrap_resp(task, decode, rqstp, + data, obj); + /* By default, we decode the arguments normally. */ + return decode(rqstp, data, obj); +} + +int rpcauth_refreshcred(struct rpc_task *task) { struct rpc_auth *auth = task->tk_auth; diff -puN net/sunrpc/auth_gss/auth_gss.c~rpc_integ net/sunrpc/auth_gss/auth_gss.c --- linux-2.5.69/net/sunrpc/auth_gss/auth_gss.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/auth_gss/auth_gss.c 2003-05-07 21:34:31.000000000 -0400 @@ -50,6 +50,7 @@ #include #include #include +#include #include static struct rpc_authops authgss_ops; @@ -64,7 +65,9 @@ static struct rpc_credops gss_credops; #define GSS_CRED_EXPIRE (60 * HZ) /* XXX: reasonable? */ #define GSS_CRED_SLACK 1024 /* XXX: unused */ -#define GSS_VERF_SLACK 48 /* length of a krb5 verifier.*/ +/* length of a krb5 verifier (48), plus data added before arguments when + * using integrity (two 4-byte integers): */ +#define GSS_VERF_SLACK 56 /* XXX this define must match the gssd define * as it is passed to gssd to signal the use of @@ -602,21 +605,14 @@ gss_marshal(struct rpc_task *task, u32 * struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); u32 *cred_len; struct rpc_rqst *req = task->tk_rqstp; - struct rpc_clnt *clnt = task->tk_client; - struct rpc_xprt *xprt = clnt->cl_xprt; - u32 *verfbase = req->rq_svec[0].iov_base; u32 maj_stat = 0; - struct xdr_netobj bufin,bufout; + struct xdr_netobj mic; + struct iovec iov; + struct xdr_buf verf_buf; u32 service; dprintk("RPC: gss_marshal\n"); - /* We compute the checksum for the verifier over the xdr-encoded bytes - * starting with the xid (which verfbase points to) and ending at - * the end of the credential. */ - if (xprt->stream) - verfbase++; /* See clnt.c:call_header() */ - *p++ = htonl(RPC_AUTH_GSS); cred_len = p++; @@ -637,22 +633,25 @@ gss_marshal(struct rpc_task *task, u32 * p = xdr_encode_netobj(p, &ctx->gc_wire_ctx); *cred_len = htonl((p - (cred_len + 1)) << 2); - /* Marshal verifier. */ - bufin.data = (u8 *)verfbase; - bufin.len = (p - verfbase) << 2; + /* We compute the checksum for the verifier over the xdr-encoded bytes + * starting with the xid and ending at the end of the credential: */ + iov.iov_base = req->rq_snd_buf.head[0].iov_base; + if (task->tk_client->cl_xprt->stream) + iov.iov_base += 4; /* See clnt.c:call_header() */ + iov.iov_len = (u8 *)p - (u8 *)iov.iov_base; + xdr_buf_from_iov(&iov, &verf_buf); - /* set verifier flavor*/ *p++ = htonl(RPC_AUTH_GSS); maj_stat = gss_get_mic(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, - &bufin, &bufout); - if(maj_stat != 0){ - printk("gss_marshal: gss_get_mic FAILED (%d)\n", - maj_stat); + &verf_buf, &mic); + if(maj_stat) { + printk("gss_marshal: gss_get_mic failed (%d)\n", maj_stat); goto out_put_ctx; } - p = xdr_encode_netobj(p, &bufout); + p = xdr_encode_netobj(p, &mic); + kfree(mic.data); return p; out_put_ctx: gss_put_ctx(ctx); @@ -686,36 +685,189 @@ static u32 * gss_validate(struct rpc_task *task, u32 *p) { 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 seq, qop_state; - struct xdr_netobj bufin; - struct xdr_netobj bufout; + struct iovec iov; + struct xdr_buf verf_buf; + struct xdr_netobj mic; u32 flav,len; + u32 service; dprintk("RPC: gss_validate\n"); flav = ntohl(*p++); - if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE) { - printk("RPC: giant verf size: %ld\n", (unsigned long) len); - return NULL; - } - dprintk("RPC: gss_validate: verifier flavor %d, len %d\n", flav, len); - - if (flav != RPC_AUTH_GSS) { - printk("RPC: bad verf flavor: %ld\n", (unsigned long)flav); - return NULL; - } + if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE) + goto out; + + if (flav != RPC_AUTH_GSS) + goto out; + seq = htonl(task->tk_gss_seqno); - bufin.data = (u8 *) &seq; - bufin.len = sizeof(seq); - bufout.data = (u8 *) p; - bufout.len = len; - - if (gss_verify_mic(ctx->gc_gss_ctx, &bufin, &bufout, &qop_state) != 0) - return NULL; - task->tk_auth->au_rslack = XDR_QUADLEN(len) + 2; - dprintk("RPC: GSS gss_validate: gss_verify_mic succeeded.\n"); + iov.iov_base = &seq; + iov.iov_len = sizeof(seq); + xdr_buf_from_iov(&iov, &verf_buf); + mic.data = (u8 *)p; + mic.len = len; + + if (gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic, &qop_state)) + goto out; + service = gss_pseudoflavor_to_service(gss_cred->gc_flavor); + switch (service) { + case RPC_GSS_SVC_NONE: + /* verifier data, flavor, length: */ + task->tk_auth->au_rslack = XDR_QUADLEN(len) + 2; + break; + case RPC_GSS_SVC_INTEGRITY: + /* verifier data, flavor, length, length, sequence number: */ + task->tk_auth->au_rslack = XDR_QUADLEN(len) + 4; + break; + default: + goto out; + } + return p + XDR_QUADLEN(len); +out: + dprintk("RPC: gss_validate failed.\n"); + return NULL; +} + +static int +gss_wrap_req(struct rpc_task *task, + kxdrproc_t encode, void *rqstp, u32 *p, void *obj) +{ + struct rpc_rqst *req = (struct rpc_rqst *)rqstp; + 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_netobj mic; + u32 service; + u32 offset, *q; + struct iovec *iov; + + dprintk("RPC: gss_wrap_body\n"); + 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(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++; + offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; + *p++ = htonl(task->tk_gss_seqno); + + status = encode(rqstp, p, obj); + if (status) + goto out; + + if (xdr_buf_subsegment(snd_buf, &integ_buf, + offset, snd_buf->len - offset)) + goto out; + *integ_len = htonl(integ_buf.len); + + maj_stat = gss_get_mic(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, + &integ_buf, &mic); + status = -EIO; /* XXX? */ + if (maj_stat != 0) + goto out; + + /* guess whether we're in the head or the tail: */ + if (snd_buf->page_len || snd_buf->tail[0].iov_len) + iov = snd_buf->tail; + else + iov = snd_buf->head; + p = iov->iov_base + iov->iov_len; + q = xdr_encode_netobj(p, &mic); + kfree(mic.data); + offset = (u8 *)q - (u8 *)p; + iov->iov_len += offset; + snd_buf->len += offset; + break; + case RPC_GSS_SVC_PRIVACY: + default: + goto out; + } + status = 0; +out: + dprintk("RPC: gss_wrap_req returning %d\n", status); + return status; +} + +static int +gss_unwrap_resp(struct rpc_task *task, + kxdrproc_t decode, void *rqstp, u32 *p, void *obj) +{ + struct rpc_rqst *req = (struct rpc_rqst *)rqstp; + 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_netobj mic; + int status = -EIO; + u32 maj_stat = 0; + u32 service; + u32 data_offset, mic_offset; + u32 integ_len; + + BUG_ON(!ctx); + + if (ctx->gc_proc != RPC_GSS_PROC_DATA) + goto out_decode; + service = gss_pseudoflavor_to_service(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) + goto out; + data_offset = (u8 *)p - (u8 *)rcv_buf->head[0].iov_base; + mic_offset = integ_len + data_offset; + if (mic_offset > rcv_buf->len) + goto out; + if (ntohl(*p++) != task->tk_gss_seqno) + goto out; + + if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, + mic_offset - data_offset)) + goto out; + + if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) + goto out; + + maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, + &mic, NULL); + kfree(mic.data); + if (maj_stat != GSS_S_COMPLETE) + goto out; + break; + case RPC_GSS_SVC_PRIVACY: + default: + goto out; + } +out_decode: + status = decode(rqstp, p, obj); +out: + dprintk("RPC: gss_unwrap_resp returning %d\n", status); + return status; } static struct rpc_authops authgss_ops = { @@ -735,6 +887,8 @@ static struct rpc_credops gss_credops = .crmarshal = gss_marshal, .crrefresh = gss_refresh, .crvalidate = gss_validate, + .crwrap_req = gss_wrap_req, + .crunwrap_resp = gss_unwrap_resp, }; static struct rpc_pipe_ops gss_upcall_ops = { @@ -762,4 +916,3 @@ static void __exit exit_rpcsec_gss(void) MODULE_LICENSE("GPL"); module_init(init_rpcsec_gss) -module_exit(exit_rpcsec_gss) diff -puN net/sunrpc/auth_gss/gss_krb5_crypto.c~rpc_integ net/sunrpc/auth_gss/gss_krb5_crypto.c --- linux-2.5.69/net/sunrpc/auth_gss/gss_krb5_crypto.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/auth_gss/gss_krb5_crypto.c 2003-05-07 21:30:45.000000000 -0400 @@ -40,6 +40,7 @@ #include #include #include +#include #include #ifdef RPC_DEBUG @@ -59,7 +60,7 @@ krb5_encrypt( u8 local_iv[16] = {0}; struct crypto_tfm *tfm = atfm->tfm; - dprintk("RPC: gss_k5encrypt: TOP in %p out %p\nin data:\n", out, in); + dprintk("RPC: krb5_encrypt: input data:\n"); print_hexl((u32 *)in, length, 0); if (length % crypto_tfm_alg_blocksize(tfm) != 0) @@ -84,8 +85,10 @@ krb5_encrypt( ret = crypto_cipher_encrypt(tfm, sg, sg, length); spin_unlock_bh(&atfm->lock); + dprintk("RPC: krb5_encrypt: output data:\n"); + print_hexl((u32 *)out, length, 0); out: - dprintk("gss_k5encrypt returns %d\n",ret); + dprintk("krb5_encrypt returns %d\n",ret); return(ret); } @@ -102,8 +105,8 @@ krb5_decrypt( u8 local_iv[16] = {0}; struct crypto_tfm *tfm = atfm->tfm; - dprintk("RPC: gss_k5decrypt: TOP in %p out %p\nin data:\n", in, out); - print_hexl((u32 *)in,length,0); + dprintk("RPC: krb5_decrypt: input data:\n"); + print_hexl((u32 *)in, length, 0); if (length % crypto_tfm_alg_blocksize(tfm) != 0) goto out; @@ -126,6 +129,8 @@ krb5_decrypt( ret = crypto_cipher_decrypt(tfm, sg, sg, length); spin_unlock_bh(&atfm->lock); + dprintk("RPC: krb5_decrypt: output_data:\n"); + print_hexl((u32 *)out, length, 0); out: dprintk("gss_k5decrypt returns %d\n",ret); return(ret); @@ -141,13 +146,15 @@ buf_to_sg(struct scatterlist *sg, char * /* checksum the plaintext data and the first 8 bytes of the krb5 token header, * as specified by the rfc: */ s32 -krb5_make_checksum(s32 cksumtype, char *header, char *body, int body_len, +krb5_make_checksum(s32 cksumtype, char *header, struct xdr_buf *body, struct xdr_netobj *cksum) { char *cksumname; struct crypto_tfm *tfm = NULL; /* XXX add to ctx? */ - struct scatterlist sg[2]; + struct scatterlist sg[1]; u32 code = GSS_S_FAILURE; + int len, thislen, offset; + int i; switch (cksumtype) { case CKSUMTYPE_RSA_MD5: @@ -164,10 +171,32 @@ krb5_make_checksum(s32 cksumtype, char * if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL) goto out; - buf_to_sg(&sg[0], header, 8); - buf_to_sg(&sg[1], body, body_len); crypto_digest_init(tfm); - crypto_digest_update(tfm, sg, 2); + buf_to_sg(sg, header, 8); + crypto_digest_update(tfm, sg, 1); + buf_to_sg(sg, body->head[0].iov_base, body->head[0].iov_len); + crypto_digest_update(tfm, sg, 1); + + len = body->page_len; + offset = body->page_base; + i = 0; + while (len) { + sg->page = body->pages[i]; + sg->offset = offset; + offset = 0; + if (PAGE_SIZE > len) + thislen = len; + else + thislen = PAGE_SIZE; + sg->length = thislen; + kmap(sg->page); /* XXX kmap_atomic? */ + crypto_digest_update(tfm, sg, 1); + kunmap(sg->page); + len -= thislen; + i++; + } + buf_to_sg(sg, body->tail[0].iov_base, body->tail[0].iov_len); + crypto_digest_update(tfm, sg, 1); crypto_digest_final(tfm, cksum->data); code = 0; out: diff -puN net/sunrpc/auth_gss/gss_krb5_mech.c~rpc_integ net/sunrpc/auth_gss/gss_krb5_mech.c --- linux-2.5.69/net/sunrpc/auth_gss/gss_krb5_mech.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/auth_gss/gss_krb5_mech.c 2003-05-07 21:31:29.000000000 -0400 @@ -184,7 +184,7 @@ gss_delete_sec_context_kerberos(void *in static u32 gss_verify_mic_kerberos(struct gss_ctx *ctx, - struct xdr_netobj *message, + struct xdr_buf *message, struct xdr_netobj *mic_token, u32 *qstate) { u32 maj_stat = 0; @@ -203,13 +203,11 @@ gss_verify_mic_kerberos(struct gss_ctx static u32 gss_get_mic_kerberos(struct gss_ctx *ctx, u32 qop, - struct xdr_netobj *message, + struct xdr_buf *message, struct xdr_netobj *mic_token) { u32 err = 0; struct krb5_ctx *kctx = ctx->internal_ctx_id; - if (!message->data) return GSS_S_FAILURE; - err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG); dprintk("RPC: gss_get_mic_kerberos returning %d\n",err); @@ -234,6 +232,7 @@ static int __init init_kerberos_module(v printk("Failed to register kerberos gss mechanism!\n"); gm = gss_mech_get_by_OID(&gss_mech_krb5_oid); gss_register_triple(RPC_AUTH_GSS_KRB5 , gm, 0, RPC_GSS_SVC_NONE); + gss_register_triple(RPC_AUTH_GSS_KRB5I, gm, 0, RPC_GSS_SVC_INTEGRITY); gss_mech_put(gm); return 0; } diff -puN net/sunrpc/auth_gss/gss_krb5_seal.c~rpc_integ net/sunrpc/auth_gss/gss_krb5_seal.c --- linux-2.5.69/net/sunrpc/auth_gss/gss_krb5_seal.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/auth_gss/gss_krb5_seal.c 2003-05-07 21:30:45.000000000 -0400 @@ -80,7 +80,7 @@ gss_krb5_padding(int blocksize, int leng u32 krb5_make_token(struct krb5_ctx *ctx, int qop_req, - struct xdr_netobj * text, struct xdr_netobj * token, + struct xdr_buf *text, struct xdr_netobj *token, int toktype) { s32 checksum_type; @@ -138,24 +138,11 @@ krb5_make_token(struct krb5_ctx *ctx, in *(u16 *)(krb5_hdr + 4) = htons(ctx->sealalg); if (toktype == KG_TOK_WRAP_MSG) { - unsigned char pad = gss_krb5_padding(blocksize, text->len); - - get_random_bytes(msg_start, blocksize); /* "confounder" */ - memcpy(msg_start + blocksize, text->data, text->len); - - memset(msg_start + blocksize + text->len, pad, pad); - - if (krb5_make_checksum(checksum_type, krb5_hdr, msg_start, - tmsglen, &md5cksum)) - goto out_err; - - if (krb5_encrypt(&ctx->enc, NULL, msg_start, msg_start, - tmsglen)) - goto out_err; - + /* XXX removing support for now */ + goto out_err; } else { /* Sign only. */ - if (krb5_make_checksum(checksum_type, krb5_hdr, text->data, - text->len, &md5cksum)) + if (krb5_make_checksum(checksum_type, krb5_hdr, text, + &md5cksum)) goto out_err; } diff -puN net/sunrpc/auth_gss/gss_krb5_unseal.c~rpc_integ net/sunrpc/auth_gss/gss_krb5_unseal.c --- linux-2.5.69/net/sunrpc/auth_gss/gss_krb5_unseal.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/auth_gss/gss_krb5_unseal.c 2003-05-07 21:30:45.000000000 -0400 @@ -75,20 +75,19 @@ * to return the decrypted data. */ +/* XXX will need to change prototype and/or just split into a separate function + * when we add privacy (because read_token will be in pages too). */ u32 krb5_read_token(struct krb5_ctx *ctx, struct xdr_netobj *read_token, - struct xdr_netobj *message_buffer, + struct xdr_buf *message_buffer, int *qop_state, int toktype) { int signalg; int sealalg; - struct xdr_netobj token = {.len = 0, .data = NULL}; s32 checksum_type; struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; s32 now; - unsigned char *plain = NULL; - int plainlen = 0; int direction; s32 seqnum; unsigned char *ptr = (unsigned char *)read_token->data; @@ -100,10 +99,11 @@ krb5_read_token(struct krb5_ctx *ctx, if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr, toktype, read_token->len)) goto out; + /* XXX sanity-check bodysize?? */ if (toktype == KG_TOK_WRAP_MSG) { - message_buffer->len = 0; - message_buffer->data = NULL; + /* XXX gone */ + goto out; } /* get the sign and seal algorithms */ @@ -135,43 +135,6 @@ krb5_read_token(struct krb5_ctx *ctx, signalg != SGN_ALG_HMAC_SHA1_DES3_KD)) goto out; - if (toktype == KG_TOK_WRAP_MSG) { - int conflen = crypto_tfm_alg_blocksize(ctx->enc.tfm); - int padlen; - - plainlen = bodysize - (14 + KRB5_CKSUM_LENGTH); - plain = ptr + 14 + KRB5_CKSUM_LENGTH; - - ret = krb5_decrypt(&ctx->enc, NULL, plain, plain, plainlen); - if (ret) - goto out; - - ret = GSS_S_FAILURE; - padlen = plain[plainlen -1]; - if ((padlen < 1) || (padlen > 8)) - goto out; - token.len = plainlen - conflen - padlen; - - if (token.len) { - token.data = kmalloc(token.len, GFP_KERNEL); - if (token.data == NULL) - goto out; - memcpy(token.data, plain + conflen, token.len); - } - - } else if (toktype == KG_TOK_MIC_MSG) { - token = *message_buffer; - plain = token.data; - plainlen = token.len; - } else { - printk("RPC: bad toktype in krb5_read_token"); - ret = GSS_S_FAILURE; - goto out; - } - - dprintk("RPC krb5_read_token: token.len %d plainlen %d\n", token.len, - plainlen); - /* compute the checksum of the message */ /* initialize the the cksum */ @@ -186,8 +149,8 @@ krb5_read_token(struct krb5_ctx *ctx, switch (signalg) { case SGN_ALG_DES_MAC_MD5: - ret = krb5_make_checksum(checksum_type, ptr - 2, plain, - plainlen, &md5cksum); + ret = krb5_make_checksum(checksum_type, ptr - 2, + message_buffer, &md5cksum); if (ret) goto out; @@ -208,9 +171,6 @@ krb5_read_token(struct krb5_ctx *ctx, /* it got through unscathed. Make sure the context is unexpired */ - if (toktype == KG_TOK_WRAP_MSG) - *message_buffer = token; - if (qop_state) *qop_state = GSS_C_QOP_DEFAULT; @@ -234,7 +194,5 @@ krb5_read_token(struct krb5_ctx *ctx, ret = GSS_S_COMPLETE; out: if (md5cksum.data) kfree(md5cksum.data); - if ((toktype == KG_TOK_WRAP_MSG) && ret && token.data) - kfree(token.data); return ret; } diff -puN net/sunrpc/auth_gss/gss_mech_switch.c~rpc_integ net/sunrpc/auth_gss/gss_mech_switch.c --- linux-2.5.69/net/sunrpc/auth_gss/gss_mech_switch.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/auth_gss/gss_mech_switch.c 2003-05-07 21:30:45.000000000 -0400 @@ -195,7 +195,7 @@ gss_import_sec_context(struct xdr_netobj u32 gss_get_mic(struct gss_ctx *context_handle, u32 qop, - struct xdr_netobj *message, + struct xdr_buf *message, struct xdr_netobj *mic_token) { return context_handle->mech_type->gm_ops @@ -209,7 +209,7 @@ gss_get_mic(struct gss_ctx *context_hand u32 gss_verify_mic(struct gss_ctx *context_handle, - struct xdr_netobj *message, + struct xdr_buf *message, struct xdr_netobj *mic_token, u32 *qstate) { diff -puN -L net/sunrpc/auth_gss/svcauth_gss.c /dev/null /dev/null diff -puN net/sunrpc/clnt.c~rpc_integ net/sunrpc/clnt.c --- linux-2.5.69/net/sunrpc/clnt.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/clnt.c 2003-05-07 21:31:29.000000000 -0400 @@ -567,7 +567,8 @@ call_encode(struct rpc_task *task) rpc_exit(task, -EIO); return; } - if (encode && (status = encode(req, p, task->tk_msg.rpc_argp)) < 0) { + if (encode && (status = rpcauth_wrap_req(task, encode, req, p, + task->tk_msg.rpc_argp)) < 0) { printk(KERN_WARNING "%s: can't encode arguments: %d\n", clnt->cl_protname, -status); rpc_exit(task, status); @@ -810,7 +811,8 @@ call_decode(struct rpc_task *task) task->tk_action = NULL; if (decode) - task->tk_status = decode(req, p, task->tk_msg.rpc_resp); + task->tk_status = rpcauth_unwrap_resp(task, decode, req, p, + task->tk_msg.rpc_resp); dprintk("RPC: %4d call_decode result %d\n", task->tk_pid, task->tk_status); } diff -puN net/sunrpc/sunrpc_syms.c~rpc_integ net/sunrpc/sunrpc_syms.c --- linux-2.5.69/net/sunrpc/sunrpc_syms.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/sunrpc_syms.c 2003-05-07 21:31:29.000000000 -0400 @@ -127,6 +127,9 @@ EXPORT_SYMBOL(xdr_inline_pages); EXPORT_SYMBOL(xdr_shift_buf); EXPORT_SYMBOL(xdr_write_pages); EXPORT_SYMBOL(xdr_read_pages); +EXPORT_SYMBOL(xdr_buf_from_iov); +EXPORT_SYMBOL(xdr_buf_subsegment); +EXPORT_SYMBOL(xdr_buf_read_netobj); /* Debugging symbols */ #ifdef RPC_DEBUG diff -puN net/sunrpc/xdr.c~rpc_integ net/sunrpc/xdr.c --- linux-2.5.69/net/sunrpc/xdr.c~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/net/sunrpc/xdr.c 2003-05-07 21:30:40.000000000 -0400 @@ -431,7 +431,7 @@ _copy_to_pages(struct page **pages, size * Copies data into an arbitrary memory location from an array of pages * The copy is assumed to be non-overlapping. */ -static void +void _copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len) { struct page **pgfrom; @@ -623,3 +623,122 @@ xdr_read_pages(struct xdr_stream *xdr, u xdr->p = (uint32_t *)iov->iov_base; xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); } + +static struct iovec empty_iov = {.iov_base = NULL, .iov_len = 0}; + +void +xdr_buf_from_iov(struct iovec *iov, struct xdr_buf *buf) +{ + buf->head[0] = *iov; + buf->tail[0] = empty_iov; + buf->page_len = 0; + buf->len = iov->iov_len; +} + +/* Sets subiov to the intersection of iov with the buffer of length len + * starting base bytes after iov. Indicates empty intersection by setting + * length of subiov to zero. Decrements len by length of subiov, sets base + * to zero (or decrements it by length of iov if subiov is empty). */ +static void +iov_subsegment(struct iovec *iov, struct iovec *subiov, int *base, int *len) +{ + if (*base > iov->iov_len) { + subiov->iov_base = NULL; + subiov->iov_len = 0; + *base -= iov->iov_len; + } else { + subiov->iov_base = iov->iov_base + *base; + subiov->iov_len = min(*len, (int)iov->iov_len - *base); + *base = 0; + } + *len -= subiov->iov_len; +} + +/* Sets subbuf to the portion of buf of length len beginning base bytes + * from the start of buf. Returns -1 if base of length are out of bounds. */ +int +xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, + int base, int len) +{ + int i; + + subbuf->len = len; + iov_subsegment(buf->head, subbuf->head, &base, &len); + + if (base < buf->page_len) { + i = (base + buf->page_base) >> PAGE_CACHE_SHIFT; + subbuf->pages = &buf->pages[i]; + subbuf->page_base = (base + buf->page_base) & ~PAGE_CACHE_MASK; + subbuf->page_len = min((int)buf->page_len - base, len); + len -= subbuf->page_len; + base = 0; + } else { + base -= buf->page_len; + subbuf->page_len = 0; + } + + iov_subsegment(buf->tail, subbuf->tail, &base, &len); + if (base || len) + return -1; + return 0; +} + +/* obj is assumed to point to allocated memory of size at least len: */ +static int +read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len) +{ + struct xdr_buf subbuf; + int this_len; + int status; + + status = xdr_buf_subsegment(buf, &subbuf, base, len); + if (status) + goto out; + this_len = min(len, (int)subbuf.head[0].iov_len); + memcpy(obj, subbuf.head[0].iov_base, this_len); + len -= this_len; + obj += this_len; + this_len = min(len, (int)subbuf.page_len); + if (this_len) + _copy_from_pages(obj, subbuf.pages, subbuf.page_base, this_len); + len -= this_len; + obj += this_len; + this_len = min(len, (int)subbuf.tail[0].iov_len); + memcpy(obj, subbuf.tail[0].iov_base, this_len); +out: + return status; +} + +static int +read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) +{ + u32 raw; + int status; + + status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj)); + if (status) + return status; + *obj = ntohl(raw); + return 0; +} + +int +xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int base) +{ + int status; + + obj->data = NULL; + status = read_u32_from_xdr_buf(buf, base, &obj->len); + if (status) + goto out; + if (obj->len > buf->len - base) + goto out; + obj->data = kmalloc(obj->len, GFP_KERNEL); + if (!obj->data) + goto out; + status = read_bytes_from_xdr_buf(buf, base + 4, obj->data, obj->len); +out: + if (status) + kfree(obj->data); + return status; +} diff -puN include/linux/sunrpc/xdr.h~rpc_integ include/linux/sunrpc/xdr.h --- linux-2.5.69/include/linux/sunrpc/xdr.h~rpc_integ 2003-05-07 20:51:50.000000000 -0400 +++ linux-2.5.69-bfields/include/linux/sunrpc/xdr.h 2003-05-07 21:30:57.000000000 -0400 @@ -141,6 +141,10 @@ void xdr_shift_iovec(struct iovec *, int extern int xdr_kmap(struct iovec *, struct xdr_buf *, size_t); extern void xdr_kunmap(struct xdr_buf *, size_t); extern void xdr_shift_buf(struct xdr_buf *, size_t); +extern void _copy_from_pages(char *, struct page **, size_t, size_t); +extern void xdr_buf_from_iov(struct iovec *, struct xdr_buf *); +extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int); +extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int); /* * Helper structure for copying from an sk_buff. _