summaryrefslogtreecommitdiff
path: root/net/sunrpc/auth_gss
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/auth_gss')
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c52
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c95
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c29
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seal.c4
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seqnum.c4
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c8
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c9
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_mech.c34
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_token.c3
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c337
10 files changed, 367 insertions, 208 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 519ebc17c028..a6ed2d22a6e6 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -88,7 +88,6 @@ struct gss_auth {
struct list_head upcalls;
struct rpc_clnt *client;
struct dentry *dentry;
- char path[48];
spinlock_t lock;
};
@@ -225,9 +224,8 @@ gss_alloc_context(void)
{
struct gss_cl_ctx *ctx;
- ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) {
- memset(ctx, 0, sizeof(*ctx));
ctx->gc_proc = RPC_GSS_PROC_DATA;
ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */
spin_lock_init(&ctx->gc_seq_lock);
@@ -391,9 +389,8 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
{
struct gss_upcall_msg *gss_msg;
- gss_msg = kmalloc(sizeof(*gss_msg), GFP_KERNEL);
+ gss_msg = kzalloc(sizeof(*gss_msg), GFP_KERNEL);
if (gss_msg != NULL) {
- memset(gss_msg, 0, sizeof(*gss_msg));
INIT_LIST_HEAD(&gss_msg->list);
rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
init_waitqueue_head(&gss_msg->waitqueue);
@@ -692,10 +689,8 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
if (err)
goto err_put_mech;
- snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s",
- clnt->cl_pathname,
- gss_auth->mech->gm_name);
- gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
+ gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name,
+ clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
if (IS_ERR(gss_auth->dentry)) {
err = PTR_ERR(gss_auth->dentry);
goto err_put_mech;
@@ -720,8 +715,7 @@ gss_destroy(struct rpc_auth *auth)
auth, auth->au_flavor);
gss_auth = container_of(auth, struct gss_auth, rpc_auth);
- rpc_unlink(gss_auth->path);
- dput(gss_auth->dentry);
+ rpc_unlink(gss_auth->dentry);
gss_auth->dentry = NULL;
gss_mech_put(gss_auth->mech);
@@ -776,10 +770,9 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
dprintk("RPC: gss_create_cred for uid %d, flavor %d\n",
acred->uid, auth->au_flavor);
- if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL)))
+ if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL)))
goto out_err;
- memset(cred, 0, sizeof(*cred));
atomic_set(&cred->gc_count, 1);
cred->gc_uid = acred->uid;
/*
@@ -833,14 +826,14 @@ out:
* Marshal credentials.
* Maybe we should keep a cached credential for performance reasons.
*/
-static u32 *
-gss_marshal(struct rpc_task *task, u32 *p)
+static __be32 *
+gss_marshal(struct rpc_task *task, __be32 *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 *cred_len;
+ __be32 *cred_len;
struct rpc_rqst *req = task->tk_rqstp;
u32 maj_stat = 0;
struct xdr_netobj mic;
@@ -901,12 +894,12 @@ gss_refresh(struct rpc_task *task)
return 0;
}
-static u32 *
-gss_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+gss_validate(struct rpc_task *task, __be32 *p)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
- u32 seq;
+ __be32 seq;
struct kvec iov;
struct xdr_buf verf_buf;
struct xdr_netobj mic;
@@ -947,13 +940,14 @@ out_bad:
static inline int
gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
- kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
+ kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
{
struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
struct xdr_buf integ_buf;
- u32 *integ_len = NULL;
+ __be32 *integ_len = NULL;
struct xdr_netobj mic;
- u32 offset, *q;
+ u32 offset;
+ __be32 *q;
struct kvec *iov;
u32 maj_stat = 0;
int status = -EIO;
@@ -1039,13 +1033,13 @@ out:
static inline int
gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
- kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
+ kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
{
struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
u32 offset;
u32 maj_stat;
int status;
- u32 *opaque_len;
+ __be32 *opaque_len;
struct page **inpages;
int first;
int pad;
@@ -1102,7 +1096,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
static int
gss_wrap_req(struct rpc_task *task,
- kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
+ kxdrproc_t encode, void *rqstp, __be32 *p, void *obj)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
@@ -1139,7 +1133,7 @@ out:
static inline int
gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
- struct rpc_rqst *rqstp, u32 **p)
+ struct rpc_rqst *rqstp, __be32 **p)
{
struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
struct xdr_buf integ_buf;
@@ -1176,7 +1170,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
static inline int
gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
- struct rpc_rqst *rqstp, u32 **p)
+ struct rpc_rqst *rqstp, __be32 **p)
{
struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
u32 offset;
@@ -1205,13 +1199,13 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
static int
gss_unwrap_resp(struct rpc_task *task,
- kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
+ kxdrproc_t decode, void *rqstp, __be32 *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);
- u32 *savedp = p;
+ __be32 *savedp = p;
struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
int savedlen = head->iov_len;
int status = -EIO;
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 76b969e6904f..e11a40b25cce 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -34,6 +34,7 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#include <linux/err.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -49,7 +50,7 @@
u32
krb5_encrypt(
- struct crypto_tfm *tfm,
+ struct crypto_blkcipher *tfm,
void * iv,
void * in,
void * out,
@@ -58,26 +59,27 @@ krb5_encrypt(
u32 ret = -EINVAL;
struct scatterlist sg[1];
u8 local_iv[16] = {0};
+ struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv };
dprintk("RPC: krb5_encrypt: input data:\n");
print_hexl((u32 *)in, length, 0);
- if (length % crypto_tfm_alg_blocksize(tfm) != 0)
+ if (length % crypto_blkcipher_blocksize(tfm) != 0)
goto out;
- if (crypto_tfm_alg_ivsize(tfm) > 16) {
+ if (crypto_blkcipher_ivsize(tfm) > 16) {
dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
- crypto_tfm_alg_ivsize(tfm));
+ crypto_blkcipher_ivsize(tfm));
goto out;
}
if (iv)
- memcpy(local_iv, iv, crypto_tfm_alg_ivsize(tfm));
+ memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
memcpy(out, in, length);
sg_set_buf(sg, out, length);
- ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv);
+ ret = crypto_blkcipher_encrypt_iv(&desc, sg, sg, length);
dprintk("RPC: krb5_encrypt: output data:\n");
print_hexl((u32 *)out, length, 0);
@@ -90,7 +92,7 @@ EXPORT_SYMBOL(krb5_encrypt);
u32
krb5_decrypt(
- struct crypto_tfm *tfm,
+ struct crypto_blkcipher *tfm,
void * iv,
void * in,
void * out,
@@ -99,25 +101,26 @@ krb5_decrypt(
u32 ret = -EINVAL;
struct scatterlist sg[1];
u8 local_iv[16] = {0};
+ struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv };
dprintk("RPC: krb5_decrypt: input data:\n");
print_hexl((u32 *)in, length, 0);
- if (length % crypto_tfm_alg_blocksize(tfm) != 0)
+ if (length % crypto_blkcipher_blocksize(tfm) != 0)
goto out;
- if (crypto_tfm_alg_ivsize(tfm) > 16) {
+ if (crypto_blkcipher_ivsize(tfm) > 16) {
dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n",
- crypto_tfm_alg_ivsize(tfm));
+ crypto_blkcipher_ivsize(tfm));
goto out;
}
if (iv)
- memcpy(local_iv,iv, crypto_tfm_alg_ivsize(tfm));
+ memcpy(local_iv,iv, crypto_blkcipher_ivsize(tfm));
memcpy(out, in, length);
sg_set_buf(sg, out, length);
- ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv);
+ ret = crypto_blkcipher_decrypt_iv(&desc, sg, sg, length);
dprintk("RPC: krb5_decrypt: output_data:\n");
print_hexl((u32 *)out, length, 0);
@@ -197,11 +200,9 @@ out:
static int
checksummer(struct scatterlist *sg, void *data)
{
- struct crypto_tfm *tfm = (struct crypto_tfm *)data;
+ struct hash_desc *desc = data;
- crypto_digest_update(tfm, sg, 1);
-
- return 0;
+ return crypto_hash_update(desc, sg, sg->length);
}
/* checksum the plaintext data and hdrlen bytes of the token header */
@@ -210,8 +211,9 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
int body_offset, struct xdr_netobj *cksum)
{
char *cksumname;
- struct crypto_tfm *tfm = NULL; /* XXX add to ctx? */
+ struct hash_desc desc; /* XXX add to ctx? */
struct scatterlist sg[1];
+ int err;
switch (cksumtype) {
case CKSUMTYPE_RSA_MD5:
@@ -222,25 +224,35 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
" unsupported checksum %d", cksumtype);
return GSS_S_FAILURE;
}
- if (!(tfm = crypto_alloc_tfm(cksumname, CRYPTO_TFM_REQ_MAY_SLEEP)))
+ desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(desc.tfm))
return GSS_S_FAILURE;
- cksum->len = crypto_tfm_alg_digestsize(tfm);
+ cksum->len = crypto_hash_digestsize(desc.tfm);
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- crypto_digest_init(tfm);
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out;
sg_set_buf(sg, header, hdrlen);
- crypto_digest_update(tfm, sg, 1);
- process_xdr_buf(body, body_offset, body->len - body_offset,
- checksummer, tfm);
- crypto_digest_final(tfm, cksum->data);
- crypto_free_tfm(tfm);
- return 0;
+ err = crypto_hash_update(&desc, sg, hdrlen);
+ if (err)
+ goto out;
+ err = process_xdr_buf(body, body_offset, body->len - body_offset,
+ checksummer, &desc);
+ if (err)
+ goto out;
+ err = crypto_hash_final(&desc, cksum->data);
+
+out:
+ crypto_free_hash(desc.tfm);
+ return err ? GSS_S_FAILURE : 0;
}
EXPORT_SYMBOL(make_checksum);
struct encryptor_desc {
u8 iv[8]; /* XXX hard-coded blocksize */
- struct crypto_tfm *tfm;
+ struct blkcipher_desc desc;
int pos;
struct xdr_buf *outbuf;
struct page **pages;
@@ -285,8 +297,8 @@ encryptor(struct scatterlist *sg, void *data)
if (thislen == 0)
return 0;
- ret = crypto_cipher_encrypt_iv(desc->tfm, desc->outfrags, desc->infrags,
- thislen, desc->iv);
+ ret = crypto_blkcipher_encrypt_iv(&desc->desc, desc->outfrags,
+ desc->infrags, thislen);
if (ret)
return ret;
if (fraglen) {
@@ -305,16 +317,18 @@ encryptor(struct scatterlist *sg, void *data)
}
int
-gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset,
- struct page **pages)
+gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
+ int offset, struct page **pages)
{
int ret;
struct encryptor_desc desc;
- BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0);
+ BUG_ON((buf->len - offset) % crypto_blkcipher_blocksize(tfm) != 0);
memset(desc.iv, 0, sizeof(desc.iv));
- desc.tfm = tfm;
+ desc.desc.tfm = tfm;
+ desc.desc.info = desc.iv;
+ desc.desc.flags = 0;
desc.pos = offset;
desc.outbuf = buf;
desc.pages = pages;
@@ -329,7 +343,7 @@ EXPORT_SYMBOL(gss_encrypt_xdr_buf);
struct decryptor_desc {
u8 iv[8]; /* XXX hard-coded blocksize */
- struct crypto_tfm *tfm;
+ struct blkcipher_desc desc;
struct scatterlist frags[4];
int fragno;
int fraglen;
@@ -355,8 +369,8 @@ decryptor(struct scatterlist *sg, void *data)
if (thislen == 0)
return 0;
- ret = crypto_cipher_decrypt_iv(desc->tfm, desc->frags, desc->frags,
- thislen, desc->iv);
+ ret = crypto_blkcipher_decrypt_iv(&desc->desc, desc->frags,
+ desc->frags, thislen);
if (ret)
return ret;
if (fraglen) {
@@ -373,15 +387,18 @@ decryptor(struct scatterlist *sg, void *data)
}
int
-gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset)
+gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
+ int offset)
{
struct decryptor_desc desc;
/* XXXJBF: */
- BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0);
+ BUG_ON((buf->len - offset) % crypto_blkcipher_blocksize(tfm) != 0);
memset(desc.iv, 0, sizeof(desc.iv));
- desc.tfm = tfm;
+ desc.desc.tfm = tfm;
+ desc.desc.info = desc.iv;
+ desc.desc.flags = 0;
desc.fragno = 0;
desc.fraglen = 0;
return process_xdr_buf(buf, offset, buf->len - offset, decryptor, &desc);
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 129e2bd36aff..325e72e4fd31 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -34,6 +34,7 @@
*
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -78,10 +79,10 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
}
static inline const void *
-get_key(const void *p, const void *end, struct crypto_tfm **res)
+get_key(const void *p, const void *end, struct crypto_blkcipher **res)
{
struct xdr_netobj key;
- int alg, alg_mode;
+ int alg;
char *alg_name;
p = simple_get_bytes(p, end, &alg, sizeof(alg));
@@ -93,18 +94,19 @@ get_key(const void *p, const void *end, struct crypto_tfm **res)
switch (alg) {
case ENCTYPE_DES_CBC_RAW:
- alg_name = "des";
- alg_mode = CRYPTO_TFM_MODE_CBC;
+ alg_name = "cbc(des)";
break;
default:
printk("gss_kerberos_mech: unsupported algorithm %d\n", alg);
goto out_err_free_key;
}
- if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) {
+ *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(*res)) {
printk("gss_kerberos_mech: unable to initialize crypto algorithm %s\n", alg_name);
+ *res = NULL;
goto out_err_free_key;
}
- if (crypto_cipher_setkey(*res, key.data, key.len)) {
+ if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
printk("gss_kerberos_mech: error setting key for crypto algorithm %s\n", alg_name);
goto out_err_free_tfm;
}
@@ -113,7 +115,7 @@ get_key(const void *p, const void *end, struct crypto_tfm **res)
return p;
out_err_free_tfm:
- crypto_free_tfm(*res);
+ crypto_free_blkcipher(*res);
out_err_free_key:
kfree(key.data);
p = ERR_PTR(-EINVAL);
@@ -129,9 +131,8 @@ gss_import_sec_context_kerberos(const void *p,
const void *end = (const void *)((const char *)p + len);
struct krb5_ctx *ctx;
- if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
+ if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL)))
goto out_err;
- memset(ctx, 0, sizeof(*ctx));
p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
if (IS_ERR(p))
@@ -169,13 +170,13 @@ gss_import_sec_context_kerberos(const void *p,
}
ctx_id->internal_ctx_id = ctx;
- dprintk("RPC: Succesfully imported new context.\n");
+ dprintk("RPC: Successfully imported new context.\n");
return 0;
out_err_free_key2:
- crypto_free_tfm(ctx->seq);
+ crypto_free_blkcipher(ctx->seq);
out_err_free_key1:
- crypto_free_tfm(ctx->enc);
+ crypto_free_blkcipher(ctx->enc);
out_err_free_mech:
kfree(ctx->mech_used.data);
out_err_free_ctx:
@@ -188,8 +189,8 @@ static void
gss_delete_sec_context_kerberos(void *internal_ctx) {
struct krb5_ctx *kctx = internal_ctx;
- crypto_free_tfm(kctx->seq);
- crypto_free_tfm(kctx->enc);
+ crypto_free_blkcipher(kctx->seq);
+ crypto_free_blkcipher(kctx->enc);
kfree(kctx->mech_used.data);
kfree(kctx);
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index f43311221a72..08601ee4cd73 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -70,7 +70,7 @@
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
-spinlock_t krb5_seq_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(krb5_seq_lock);
u32
gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
@@ -115,7 +115,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
krb5_hdr = ptr - 2;
msg_start = krb5_hdr + 24;
- *(u16 *)(krb5_hdr + 2) = htons(ctx->signalg);
+ *(__be16 *)(krb5_hdr + 2) = htons(ctx->signalg);
memset(krb5_hdr + 4, 0xff, 4);
if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum))
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
index c53ead39118d..c604baf3a5f6 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
@@ -41,7 +41,7 @@
#endif
s32
-krb5_make_seq_num(struct crypto_tfm *key,
+krb5_make_seq_num(struct crypto_blkcipher *key,
int direction,
s32 seqnum,
unsigned char *cksum, unsigned char *buf)
@@ -62,7 +62,7 @@ krb5_make_seq_num(struct crypto_tfm *key,
}
s32
-krb5_get_seq_num(struct crypto_tfm *key,
+krb5_get_seq_num(struct crypto_blkcipher *key,
unsigned char *cksum,
unsigned char *buf,
int *direction, s32 * seqnum)
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 89d1f3e14128..cc45c1605f80 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -149,7 +149,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
goto out_err;
}
- blocksize = crypto_tfm_alg_blocksize(kctx->enc);
+ blocksize = crypto_blkcipher_blocksize(kctx->enc);
gss_krb5_add_padding(buf, offset, blocksize);
BUG_ON((buf->len - offset) % blocksize);
plainlen = blocksize + buf->len - offset;
@@ -177,9 +177,9 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
msg_start = krb5_hdr + 24;
/* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize);
- *(u16 *)(krb5_hdr + 2) = htons(kctx->signalg);
+ *(__be16 *)(krb5_hdr + 2) = htons(kctx->signalg);
memset(krb5_hdr + 4, 0xff, 4);
- *(u16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
+ *(__be16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
make_confounder(msg_start, blocksize);
@@ -346,7 +346,7 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf)
/* Copy the data back to the right position. XXX: Would probably be
* better to copy and encrypt at the same time. */
- blocksize = crypto_tfm_alg_blocksize(kctx->enc);
+ blocksize = crypto_blkcipher_blocksize(kctx->enc);
data_start = ptr + 22 + blocksize;
orig_start = buf->head[0].iov_base + offset;
data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start;
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index f8bac6ccd524..3db745379d06 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -224,7 +224,8 @@ EXPORT_SYMBOL(gss_service_to_auth_domain_name);
void
gss_mech_put(struct gss_api_mech * gm)
{
- module_put(gm->gm_owner);
+ if (gm)
+ module_put(gm->gm_owner);
}
EXPORT_SYMBOL(gss_mech_put);
@@ -236,9 +237,8 @@ gss_import_sec_context(const void *input_token, size_t bufsize,
struct gss_api_mech *mech,
struct gss_ctx **ctx_id)
{
- if (!(*ctx_id = kmalloc(sizeof(**ctx_id), GFP_KERNEL)))
+ if (!(*ctx_id = kzalloc(sizeof(**ctx_id), GFP_KERNEL)))
return GSS_S_FAILURE;
- memset(*ctx_id, 0, sizeof(**ctx_id));
(*ctx_id)->mech_type = gss_mech_get(mech);
return mech->gm_ops
@@ -307,8 +307,7 @@ gss_delete_sec_context(struct gss_ctx **context_handle)
(*context_handle)->mech_type->gm_ops
->gss_delete_sec_context((*context_handle)
->internal_ctx_id);
- if ((*context_handle)->mech_type)
- gss_mech_put((*context_handle)->mech_type);
+ gss_mech_put((*context_handle)->mech_type);
kfree(*context_handle);
*context_handle=NULL;
return GSS_S_COMPLETE;
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index 5bf11ccba7cd..bdedf456bc17 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -34,6 +34,7 @@
*
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -83,10 +84,11 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
}
static inline const void *
-get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg)
+get_key(const void *p, const void *end, struct crypto_blkcipher **res,
+ int *resalg)
{
struct xdr_netobj key = { 0 };
- int alg_mode,setkey = 0;
+ int setkey = 0;
char *alg_name;
p = simple_get_bytes(p, end, resalg, sizeof(*resalg));
@@ -98,14 +100,12 @@ get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg)
switch (*resalg) {
case NID_des_cbc:
- alg_name = "des";
- alg_mode = CRYPTO_TFM_MODE_CBC;
+ alg_name = "cbc(des)";
setkey = 1;
break;
case NID_cast5_cbc:
/* XXXX here in name only, not used */
- alg_name = "cast5";
- alg_mode = CRYPTO_TFM_MODE_CBC;
+ alg_name = "cbc(cast5)";
setkey = 0; /* XXX will need to set to 1 */
break;
case NID_md5:
@@ -113,19 +113,20 @@ get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg)
dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n");
}
alg_name = "md5";
- alg_mode = 0;
setkey = 0;
break;
default:
dprintk("gss_spkm3_mech: unsupported algorithm %d\n", *resalg);
goto out_err_free_key;
}
- if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) {
+ *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(*res)) {
printk("gss_spkm3_mech: unable to initialize crypto algorthm %s\n", alg_name);
+ *res = NULL;
goto out_err_free_key;
}
if (setkey) {
- if (crypto_cipher_setkey(*res, key.data, key.len)) {
+ if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
printk("gss_spkm3_mech: error setting key for crypto algorthm %s\n", alg_name);
goto out_err_free_tfm;
}
@@ -136,7 +137,7 @@ get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg)
return p;
out_err_free_tfm:
- crypto_free_tfm(*res);
+ crypto_free_blkcipher(*res);
out_err_free_key:
if(key.len > 0)
kfree(key.data);
@@ -152,9 +153,8 @@ gss_import_sec_context_spkm3(const void *p, size_t len,
const void *end = (const void *)((const char *)p + len);
struct spkm3_ctx *ctx;
- if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
+ if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL)))
goto out_err;
- memset(ctx, 0, sizeof(*ctx));
p = simple_get_netobj(p, end, &ctx->ctx_id);
if (IS_ERR(p))
@@ -201,13 +201,13 @@ gss_import_sec_context_spkm3(const void *p, size_t len,
ctx_id->internal_ctx_id = ctx;
- dprintk("Succesfully imported new spkm context.\n");
+ dprintk("Successfully imported new spkm context.\n");
return 0;
out_err_free_key2:
- crypto_free_tfm(ctx->derived_integ_key);
+ crypto_free_blkcipher(ctx->derived_integ_key);
out_err_free_key1:
- crypto_free_tfm(ctx->derived_conf_key);
+ crypto_free_blkcipher(ctx->derived_conf_key);
out_err_free_s_key:
kfree(ctx->share_key.data);
out_err_free_mech:
@@ -224,8 +224,8 @@ static void
gss_delete_sec_context_spkm3(void *internal_ctx) {
struct spkm3_ctx *sctx = internal_ctx;
- crypto_free_tfm(sctx->derived_integ_key);
- crypto_free_tfm(sctx->derived_conf_key);
+ crypto_free_blkcipher(sctx->derived_integ_key);
+ crypto_free_blkcipher(sctx->derived_conf_key);
kfree(sctx->share_key.data);
kfree(sctx->mech_used.data);
kfree(sctx);
diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c
index af0d7ce74686..854a983ccf26 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_token.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_token.c
@@ -90,10 +90,9 @@ asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
int
decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
{
- if (!(out->data = kmalloc(explen,GFP_KERNEL)))
+ if (!(out->data = kzalloc(explen,GFP_KERNEL)))
return 0;
out->len = explen;
- memset(out->data, 0, explen);
memcpy(out->data, in, enclen);
return 1;
}
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index d51e316c5821..638c0b576203 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -425,6 +425,7 @@ static int rsc_parse(struct cache_detail *cd,
struct rsc rsci, *rscp = NULL;
time_t expiry;
int status = -EINVAL;
+ struct gss_api_mech *gm = NULL;
memset(&rsci, 0, sizeof(rsci));
/* context handle */
@@ -453,7 +454,6 @@ static int rsc_parse(struct cache_detail *cd,
set_bit(CACHE_NEGATIVE, &rsci.h.flags);
else {
int N, i;
- struct gss_api_mech *gm;
/* gid */
if (get_int(&mesg, &rsci.cred.cr_gid))
@@ -488,21 +488,17 @@ static int rsc_parse(struct cache_detail *cd,
status = -EINVAL;
/* mech-specific data: */
len = qword_get(&mesg, buf, mlen);
- if (len < 0) {
- gss_mech_put(gm);
+ if (len < 0)
goto out;
- }
status = gss_import_sec_context(buf, len, gm, &rsci.mechctx);
- if (status) {
- gss_mech_put(gm);
+ if (status)
goto out;
- }
- gss_mech_put(gm);
}
rsci.h.expiry_time = expiry;
rscp = rsc_update(&rsci, rscp);
status = 0;
out:
+ gss_mech_put(gm);
rsc_free(&rsci);
if (rscp)
cache_put(&rscp->h, &rsc_cache);
@@ -611,7 +607,7 @@ svc_safe_getnetobj(struct kvec *argv, struct xdr_netobj *o)
if (argv->iov_len < 4)
return -1;
- o->len = ntohl(svc_getu32(argv));
+ o->len = svc_getnl(argv);
l = round_up_to_quad(o->len);
if (argv->iov_len < l)
return -1;
@@ -624,17 +620,17 @@ svc_safe_getnetobj(struct kvec *argv, struct xdr_netobj *o)
static inline int
svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
{
- u32 *p;
+ u8 *p;
if (resv->iov_len + 4 > PAGE_SIZE)
return -1;
- svc_putu32(resv, htonl(o->len));
+ svc_putnl(resv, o->len);
p = resv->iov_base + resv->iov_len;
resv->iov_len += round_up_to_quad(o->len);
if (resv->iov_len > PAGE_SIZE)
return -1;
memcpy(p, o->data, o->len);
- memset((u8 *)p + o->len, 0, round_up_to_quad(o->len) - o->len);
+ memset(p + o->len, 0, round_up_to_quad(o->len) - o->len);
return 0;
}
@@ -644,7 +640,7 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
*/
static int
gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
- u32 *rpcstart, struct rpc_gss_wire_cred *gc, u32 *authp)
+ __be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp)
{
struct gss_ctx *ctx_id = rsci->mechctx;
struct xdr_buf rpchdr;
@@ -661,7 +657,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
*authp = rpc_autherr_badverf;
if (argv->iov_len < 4)
return SVC_DENIED;
- flavor = ntohl(svc_getu32(argv));
+ flavor = svc_getnl(argv);
if (flavor != RPC_AUTH_GSS)
return SVC_DENIED;
if (svc_safe_getnetobj(argv, &checksum))
@@ -691,9 +687,9 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
static int
gss_write_null_verf(struct svc_rqst *rqstp)
{
- u32 *p;
+ __be32 *p;
- svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_NULL));
+ svc_putnl(rqstp->rq_res.head, RPC_AUTH_NULL);
p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
/* don't really need to check if head->iov_len > PAGE_SIZE ... */
*p++ = 0;
@@ -705,14 +701,14 @@ gss_write_null_verf(struct svc_rqst *rqstp)
static int
gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
{
- u32 xdr_seq;
+ __be32 xdr_seq;
u32 maj_stat;
struct xdr_buf verf_data;
struct xdr_netobj mic;
- u32 *p;
+ __be32 *p;
struct kvec iov;
- svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_GSS));
+ svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS);
xdr_seq = htonl(seq);
iov.iov_base = &xdr_seq;
@@ -786,7 +782,7 @@ EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor);
static inline int
read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
{
- u32 raw;
+ __be32 raw;
int status;
status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
@@ -809,7 +805,7 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
struct xdr_netobj mic;
struct xdr_buf integ_buf;
- integ_len = ntohl(svc_getu32(&buf->head[0]));
+ integ_len = svc_getnl(&buf->head[0]);
if (integ_len & 3)
goto out;
if (integ_len > buf->len)
@@ -829,19 +825,87 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
if (maj_stat != GSS_S_COMPLETE)
goto out;
- if (ntohl(svc_getu32(&buf->head[0])) != seq)
+ if (svc_getnl(&buf->head[0]) != seq)
goto out;
stat = 0;
out:
return stat;
}
+static inline int
+total_buf_len(struct xdr_buf *buf)
+{
+ return buf->head[0].iov_len + buf->page_len + buf->tail[0].iov_len;
+}
+
+static void
+fix_priv_head(struct xdr_buf *buf, int pad)
+{
+ if (buf->page_len == 0) {
+ /* We need to adjust head and buf->len in tandem in this
+ * case to make svc_defer() work--it finds the original
+ * buffer start using buf->len - buf->head[0].iov_len. */
+ buf->head[0].iov_len -= pad;
+ }
+}
+
+static int
+unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
+{
+ u32 priv_len, maj_stat;
+ int pad, saved_len, remaining_len, offset;
+
+ rqstp->rq_sendfile_ok = 0;
+
+ priv_len = svc_getnl(&buf->head[0]);
+ if (rqstp->rq_deferred) {
+ /* Already decrypted last time through! The sequence number
+ * check at out_seq is unnecessary but harmless: */
+ goto out_seq;
+ }
+ /* buf->len is the number of bytes from the original start of the
+ * request to the end, where head[0].iov_len is just the bytes
+ * not yet read from the head, so these two values are different: */
+ remaining_len = total_buf_len(buf);
+ if (priv_len > remaining_len)
+ return -EINVAL;
+ pad = remaining_len - priv_len;
+ buf->len -= pad;
+ fix_priv_head(buf, pad);
+
+ /* Maybe it would be better to give gss_unwrap a length parameter: */
+ saved_len = buf->len;
+ buf->len = priv_len;
+ maj_stat = gss_unwrap(ctx, 0, buf);
+ pad = priv_len - buf->len;
+ buf->len = saved_len;
+ buf->len -= pad;
+ /* The upper layers assume the buffer is aligned on 4-byte boundaries.
+ * In the krb5p case, at least, the data ends up offset, so we need to
+ * move it around. */
+ /* XXX: This is very inefficient. It would be better to either do
+ * this while we encrypt, or maybe in the receive code, if we can peak
+ * ahead and work out the service and mechanism there. */
+ offset = buf->head[0].iov_len % 4;
+ if (offset) {
+ buf->buflen = RPCSVC_MAXPAYLOAD;
+ xdr_shift_buf(buf, offset);
+ fix_priv_head(buf, pad);
+ }
+ if (maj_stat != GSS_S_COMPLETE)
+ return -EINVAL;
+out_seq:
+ if (svc_getnl(&buf->head[0]) != seq)
+ return -EINVAL;
+ return 0;
+}
+
struct gss_svc_data {
/* decoded gss client cred: */
struct rpc_gss_wire_cred clcred;
/* pointer to the beginning of the procedure-specific results,
* which may be encrypted/checksummed in svcauth_gss_release: */
- u32 *body_start;
+ __be32 *body_start;
struct rsc *rsci;
};
@@ -882,7 +946,7 @@ gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
* response here and return SVC_COMPLETE.
*/
static int
-svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
+svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
{
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
@@ -892,8 +956,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
struct rpc_gss_wire_cred *gc;
struct rsc *rsci = NULL;
struct rsi *rsip, rsikey;
- u32 *rpcstart;
- u32 *reject_stat = resv->iov_base + resv->iov_len;
+ __be32 *rpcstart;
+ __be32 *reject_stat = resv->iov_base + resv->iov_len;
int ret;
dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",argv->iov_len);
@@ -921,12 +985,12 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
if (argv->iov_len < 5 * 4)
goto auth_err;
- crlen = ntohl(svc_getu32(argv));
- if (ntohl(svc_getu32(argv)) != RPC_GSS_VERSION)
+ crlen = svc_getnl(argv);
+ if (svc_getnl(argv) != RPC_GSS_VERSION)
goto auth_err;
- gc->gc_proc = ntohl(svc_getu32(argv));
- gc->gc_seq = ntohl(svc_getu32(argv));
- gc->gc_svc = ntohl(svc_getu32(argv));
+ gc->gc_proc = svc_getnl(argv);
+ gc->gc_seq = svc_getnl(argv);
+ gc->gc_svc = svc_getnl(argv);
if (svc_safe_getnetobj(argv, &gc->gc_ctx))
goto auth_err;
if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
@@ -952,9 +1016,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
case RPC_GSS_PROC_CONTINUE_INIT:
if (argv->iov_len < 2 * 4)
goto auth_err;
- if (ntohl(svc_getu32(argv)) != RPC_AUTH_NULL)
+ if (svc_getnl(argv) != RPC_AUTH_NULL)
goto auth_err;
- if (ntohl(svc_getu32(argv)) != 0)
+ if (svc_getnl(argv) != 0)
goto auth_err;
break;
case RPC_GSS_PROC_DATA:
@@ -1012,14 +1076,14 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
goto drop;
if (resv->iov_len + 4 > PAGE_SIZE)
goto drop;
- svc_putu32(resv, rpc_success);
+ svc_putnl(resv, RPC_SUCCESS);
if (svc_safe_putnetobj(resv, &rsip->out_handle))
goto drop;
if (resv->iov_len + 3 * 4 > PAGE_SIZE)
goto drop;
- svc_putu32(resv, htonl(rsip->major_status));
- svc_putu32(resv, htonl(rsip->minor_status));
- svc_putu32(resv, htonl(GSS_SEQ_WIN));
+ svc_putnl(resv, rsip->major_status);
+ svc_putnl(resv, rsip->minor_status);
+ svc_putnl(resv, GSS_SEQ_WIN);
if (svc_safe_putnetobj(resv, &rsip->out_token))
goto drop;
rqstp->rq_client = NULL;
@@ -1029,7 +1093,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
set_bit(CACHE_NEGATIVE, &rsci->h.flags);
if (resv->iov_len + 4 > PAGE_SIZE)
goto drop;
- svc_putu32(resv, rpc_success);
+ svc_putnl(resv, RPC_SUCCESS);
goto complete;
case RPC_GSS_PROC_DATA:
*authp = rpcsec_gsserr_ctxproblem;
@@ -1047,11 +1111,18 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
goto auth_err;
/* placeholders for length and seq. number: */
svcdata->body_start = resv->iov_base + resv->iov_len;
- svc_putu32(resv, 0);
- svc_putu32(resv, 0);
+ svc_putnl(resv, 0);
+ svc_putnl(resv, 0);
break;
case RPC_GSS_SVC_PRIVACY:
- /* currently unsupported */
+ if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
+ gc->gc_seq, rsci->mechctx))
+ goto auth_err;
+ /* placeholders for length and seq. number: */
+ svcdata->body_start = resv->iov_base + resv->iov_len;
+ svc_putnl(resv, 0);
+ svc_putnl(resv, 0);
+ break;
default:
goto auth_err;
}
@@ -1076,8 +1147,8 @@ out:
return ret;
}
-static int
-svcauth_gss_release(struct svc_rqst *rqstp)
+static inline int
+svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
{
struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
struct rpc_gss_wire_cred *gc = &gsd->clcred;
@@ -1085,73 +1156,151 @@ svcauth_gss_release(struct svc_rqst *rqstp)
struct xdr_buf integ_buf;
struct xdr_netobj mic;
struct kvec *resv;
- u32 *p;
+ __be32 *p;
int integ_offset, integ_len;
int stat = -EINVAL;
+ p = gsd->body_start;
+ gsd->body_start = NULL;
+ /* move accept_stat to right place: */
+ memcpy(p, p + 2, 4);
+ /* Don't wrap in failure case: */
+ /* Counting on not getting here if call was not even accepted! */
+ if (*p != rpc_success) {
+ resbuf->head[0].iov_len -= 2 * 4;
+ goto out;
+ }
+ p++;
+ integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
+ integ_len = resbuf->len - integ_offset;
+ BUG_ON(integ_len % 4);
+ *p++ = htonl(integ_len);
+ *p++ = htonl(gc->gc_seq);
+ if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
+ integ_len))
+ BUG();
+ if (resbuf->page_len == 0
+ && resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
+ < PAGE_SIZE) {
+ BUG_ON(resbuf->tail[0].iov_len);
+ /* Use head for everything */
+ resv = &resbuf->head[0];
+ } else if (resbuf->tail[0].iov_base == NULL) {
+ if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
+ goto out_err;
+ resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ + resbuf->head[0].iov_len;
+ resbuf->tail[0].iov_len = 0;
+ rqstp->rq_restailpage = 0;
+ resv = &resbuf->tail[0];
+ } else {
+ resv = &resbuf->tail[0];
+ }
+ mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
+ if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))
+ goto out_err;
+ svc_putnl(resv, mic.len);
+ memset(mic.data + mic.len, 0,
+ round_up_to_quad(mic.len) - mic.len);
+ resv->iov_len += XDR_QUADLEN(mic.len) << 2;
+ /* not strictly required: */
+ resbuf->len += XDR_QUADLEN(mic.len) << 2;
+ BUG_ON(resv->iov_len > PAGE_SIZE);
+out:
+ stat = 0;
+out_err:
+ return stat;
+}
+
+static inline int
+svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
+{
+ struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
+ struct rpc_gss_wire_cred *gc = &gsd->clcred;
+ struct xdr_buf *resbuf = &rqstp->rq_res;
+ struct page **inpages = NULL;
+ __be32 *p, *len;
+ int offset;
+ int pad;
+
+ p = gsd->body_start;
+ gsd->body_start = NULL;
+ /* move accept_stat to right place: */
+ memcpy(p, p + 2, 4);
+ /* Don't wrap in failure case: */
+ /* Counting on not getting here if call was not even accepted! */
+ if (*p != rpc_success) {
+ resbuf->head[0].iov_len -= 2 * 4;
+ return 0;
+ }
+ p++;
+ len = p++;
+ offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
+ *p++ = htonl(gc->gc_seq);
+ inpages = resbuf->pages;
+ /* XXX: Would be better to write some xdr helper functions for
+ * nfs{2,3,4}xdr.c that place the data right, instead of copying: */
+ if (resbuf->tail[0].iov_base && rqstp->rq_restailpage == 0) {
+ BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
+ + PAGE_SIZE);
+ BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);
+ if (resbuf->tail[0].iov_len + resbuf->head[0].iov_len
+ + 2 * RPC_MAX_AUTH_SIZE > PAGE_SIZE)
+ return -ENOMEM;
+ memmove(resbuf->tail[0].iov_base + RPC_MAX_AUTH_SIZE,
+ resbuf->tail[0].iov_base,
+ resbuf->tail[0].iov_len);
+ resbuf->tail[0].iov_base += RPC_MAX_AUTH_SIZE;
+ }
+ if (resbuf->tail[0].iov_base == NULL) {
+ if (resbuf->head[0].iov_len + 2*RPC_MAX_AUTH_SIZE > PAGE_SIZE)
+ return -ENOMEM;
+ resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ + resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
+ resbuf->tail[0].iov_len = 0;
+ rqstp->rq_restailpage = 0;
+ }
+ if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
+ return -ENOMEM;
+ *len = htonl(resbuf->len - offset);
+ pad = 3 - ((resbuf->len - offset - 1)&3);
+ p = (__be32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);
+ memset(p, 0, pad);
+ resbuf->tail[0].iov_len += pad;
+ resbuf->len += pad;
+ return 0;
+}
+
+static int
+svcauth_gss_release(struct svc_rqst *rqstp)
+{
+ struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
+ struct rpc_gss_wire_cred *gc = &gsd->clcred;
+ struct xdr_buf *resbuf = &rqstp->rq_res;
+ int stat = -EINVAL;
+
if (gc->gc_proc != RPC_GSS_PROC_DATA)
goto out;
/* Release can be called twice, but we only wrap once. */
if (gsd->body_start == NULL)
goto out;
/* normally not set till svc_send, but we need it here: */
- resbuf->len = resbuf->head[0].iov_len
- + resbuf->page_len + resbuf->tail[0].iov_len;
+ /* XXX: what for? Do we mess it up the moment we call svc_putu32
+ * or whatever? */
+ resbuf->len = total_buf_len(resbuf);
switch (gc->gc_svc) {
case RPC_GSS_SVC_NONE:
break;
case RPC_GSS_SVC_INTEGRITY:
- p = gsd->body_start;
- gsd->body_start = NULL;
- /* move accept_stat to right place: */
- memcpy(p, p + 2, 4);
- /* don't wrap in failure case: */
- /* Note: counting on not getting here if call was not even
- * accepted! */
- if (*p != rpc_success) {
- resbuf->head[0].iov_len -= 2 * 4;
- goto out;
- }
- p++;
- integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
- integ_len = resbuf->len - integ_offset;
- BUG_ON(integ_len % 4);
- *p++ = htonl(integ_len);
- *p++ = htonl(gc->gc_seq);
- if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
- integ_len))
- BUG();
- if (resbuf->page_len == 0
- && resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
- < PAGE_SIZE) {
- BUG_ON(resbuf->tail[0].iov_len);
- /* Use head for everything */
- resv = &resbuf->head[0];
- } else if (resbuf->tail[0].iov_base == NULL) {
- if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
- > PAGE_SIZE)
- goto out_err;
- resbuf->tail[0].iov_base =
- resbuf->head[0].iov_base
- + resbuf->head[0].iov_len;
- resbuf->tail[0].iov_len = 0;
- rqstp->rq_restailpage = 0;
- resv = &resbuf->tail[0];
- } else {
- resv = &resbuf->tail[0];
- }
- mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
- if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))
+ stat = svcauth_gss_wrap_resp_integ(rqstp);
+ if (stat)
goto out_err;
- svc_putu32(resv, htonl(mic.len));
- memset(mic.data + mic.len, 0,
- round_up_to_quad(mic.len) - mic.len);
- resv->iov_len += XDR_QUADLEN(mic.len) << 2;
- /* not strictly required: */
- resbuf->len += XDR_QUADLEN(mic.len) << 2;
- BUG_ON(resv->iov_len > PAGE_SIZE);
break;
case RPC_GSS_SVC_PRIVACY:
+ stat = svcauth_gss_wrap_resp_priv(rqstp);
+ if (stat)
+ goto out_err;
+ break;
default:
goto out_err;
}