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;
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 *);
#ifdef __KERNEL__
#include <linux/sunrpc/xdr.h>
+#include <linux/uio.h>
/* The mechanism-independent gss-api context: */
struct gss_ctx {
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(
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)(
#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
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.
return cred->cr_ops->crvalidate(task, p);
}
+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)
{
#include <linux/sunrpc/gss_err.h>
#include <linux/workqueue.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
+#include <linux/sunrpc/gss_api.h>
#include <asm/uaccess.h>
static struct rpc_authops authgss_ops;
#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
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++;
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)
+ /* See clnt.c:call_header() */
+ iov.iov_base += 4;
+ iov.iov_len = (u8 *)p - (u8 *)iov.iov_base;
+ xdr_buf_from_iov(&iov, &verf_buf);
/* set verifier flavor*/
*p++ = htonl(RPC_AUTH_GSS);
- bufout.data = (u8 *)(p + 1);
+ mic.data = (u8 *)(p + 1);
maj_stat = gss_get_mic(ctx->gc_gss_ctx,
GSS_C_QOP_DEFAULT,
- &bufin, &bufout);
+ &verf_buf, &mic);
if(maj_stat != 0){
- printk("gss_marshal: gss_get_mic FAILED (%d)\n",
- maj_stat);
+ printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat);
goto out_put_ctx;
}
- *p++ = htonl(bufout.len);
- p += XDR_QUADLEN(bufout.len);
+ *p++ = htonl(mic.len);
+ p += XDR_QUADLEN(mic.len);
gss_put_ctx(ctx);
return p;
out_put_ctx:
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);
+ if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
goto out_bad;
- }
- 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);
+ if (flav != RPC_AUTH_GSS)
goto out_bad;
- }
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)
- goto out_bad;
- 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_bad;
+ 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_bad;
+ }
gss_put_ctx(ctx);
return p + XDR_QUADLEN(len);
out_bad:
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);
+
+ /* 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;
+ mic.data = (u8 *)(p + 1);
+
+ maj_stat = gss_get_mic(ctx->gc_gss_ctx,
+ GSS_C_QOP_DEFAULT, &integ_buf, &mic);
+ status = -EIO; /* XXX? */
+ if (maj_stat)
+ goto out;
+ q = p;
+ *q++ = htonl(mic.len);
+ q += XDR_QUADLEN(mic.len);
+
+ 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:
+ gss_put_ctx(ctx);
+ 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);
+ 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:
+ gss_put_ctx(ctx);
+ dprintk("RPC: gss_unwrap_resp returning %d\n", status);
+ return status;
+}
+
static struct rpc_authops authgss_ops = {
.owner = THIS_MODULE,
.au_flavor = RPC_AUTH_GSS,
.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 = {
#include <linux/slab.h>
#include <asm/scatterlist.h>
#include <linux/crypto.h>
+#include <linux/highmem.h>
#include <linux/sunrpc/gss_krb5.h>
#ifdef RPC_DEBUG
struct scatterlist sg[1];
u8 local_iv[16] = {0};
- 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)
ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv);
+ 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);
}
struct scatterlist sg[1];
u8 local_iv[16] = {0};
- 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;
ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv);
+ dprintk("RPC: krb5_decrypt: output_data:\n");
+ print_hexl((u32 *)out, length, 0);
out:
dprintk("gss_k5decrypt returns %d\n",ret);
return(ret);
/* 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:
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);
+ if (body->head[0].iov_len) {
+ 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++;
+ }
+ if (body->tail[0].iov_len) {
+ 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:
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;
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);
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;
}
static void __exit cleanup_kerberos_module(void)
{
+ gss_unregister_triple(RPC_AUTH_GSS_KRB5I);
gss_unregister_triple(RPC_AUTH_GSS_KRB5);
}
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;
*(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;
}
* 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;
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 */
signalg != SGN_ALG_HMAC_SHA1_DES3_KD))
goto out;
- if (toktype == KG_TOK_WRAP_MSG) {
- int conflen = crypto_tfm_alg_blocksize(ctx->enc);
- 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 */
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;
/* 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;
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;
}
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
u32
gss_verify_mic(struct gss_ctx *context_handle,
- struct xdr_netobj *message,
+ struct xdr_buf *message,
struct xdr_netobj *mic_token,
u32 *qstate)
{
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);
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);
return;
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
* 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;
xdr->p = (uint32_t *)((char *)iov->iov_base + padding);
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;
+}
+
+/* If the netobj starting offset bytes from the start of xdr_buf is contained
+ * entirely in the head or the tail, set object to point to it; otherwise
+ * try to find space for it at the end of the tail, copy it there, and
+ * set obj to point to it. */
+int
+xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset)
+{
+ u32 tail_offset = buf->head[0].iov_len + buf->page_len;
+ u32 obj_end_offset;
+
+ if (read_u32_from_xdr_buf(buf, offset, &obj->len))
+ goto out;
+ obj_end_offset = offset + 4 + obj->len;
+
+ if (obj_end_offset <= buf->head[0].iov_len) {
+ /* The obj is contained entirely in the head: */
+ obj->data = buf->head[0].iov_base + offset + 4;
+ } else if (offset + 4 >= tail_offset) {
+ if (obj_end_offset - tail_offset
+ > buf->tail[0].iov_len)
+ goto out;
+ /* The obj is contained entirely in the tail: */
+ obj->data = buf->tail[0].iov_base
+ + offset - tail_offset + 4;
+ } else {
+ /* use end of tail as storage for obj:
+ * (We don't copy to the beginning because then we'd have
+ * to worry about doing a potentially overlapping copy.
+ * This assumes the object is at most half the length of the
+ * tail.) */
+ if (obj->len > buf->tail[0].iov_len)
+ goto out;
+ obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len -
+ obj->len;
+ if (read_bytes_from_xdr_buf(buf, offset + 4,
+ obj->data, obj->len))
+ goto out;
+
+ }
+ return 0;
+out:
+ return -1;
+}