aboutsummaryrefslogtreecommitdiff
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.c107
-rw-r--r--net/sunrpc/auth_gss/gss_generic_token.c4
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c6
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seal.c9
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seqnum.c4
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_unseal.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c8
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_seal.c4
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c9
9 files changed, 93 insertions, 60 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 6dac38792288..cc12d5f5d5da 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -114,27 +114,14 @@ static void
gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
{
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
- struct gss_cl_ctx *old;
- old = gss_cred->gc_ctx;
+ if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+ return;
+ gss_get_ctx(ctx);
rcu_assign_pointer(gss_cred->gc_ctx, ctx);
set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+ smp_mb__before_clear_bit();
clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
- if (old)
- gss_put_ctx(old);
-}
-
-static int
-gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
-{
- struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
- int res = 0;
-
- rcu_read_lock();
- if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx)
- res = 1;
- rcu_read_unlock();
- return res;
}
static const void *
@@ -266,6 +253,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
BUG_ON(!list_empty(&gss_msg->list));
if (gss_msg->ctx != NULL)
gss_put_ctx(gss_msg->ctx);
+ rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
kfree(gss_msg);
}
@@ -339,7 +327,7 @@ gss_upcall_callback(struct rpc_task *task)
spin_lock(&inode->i_lock);
if (gss_msg->ctx)
- gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
+ gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
else
task->tk_status = gss_msg->msg.errno;
gss_cred->gc_upcall = NULL;
@@ -370,9 +358,16 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
static struct gss_upcall_msg *
gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred)
{
+ struct gss_cred *gss_cred = container_of(cred,
+ struct gss_cred, gc_base);
struct gss_upcall_msg *gss_new, *gss_msg;
+ uid_t uid = cred->cr_uid;
- gss_new = gss_alloc_msg(gss_auth, cred->cr_uid);
+ /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */
+ if (gss_cred->gc_machine_cred != 0)
+ uid = 0;
+
+ gss_new = gss_alloc_msg(gss_auth, uid);
if (gss_new == NULL)
return ERR_PTR(-ENOMEM);
gss_msg = gss_add_msg(gss_auth, gss_new);
@@ -408,13 +403,17 @@ gss_refresh_upcall(struct rpc_task *task)
}
spin_lock(&inode->i_lock);
if (gss_cred->gc_upcall != NULL)
- rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL);
- else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
+ rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
+ else if (gss_msg->ctx != NULL) {
+ gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
+ gss_cred->gc_upcall = NULL;
+ rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
+ } else if (gss_msg->msg.errno >= 0) {
task->tk_timeout = 0;
gss_cred->gc_upcall = gss_msg;
/* gss_upcall_callback will release the reference to gss_upcall_msg */
atomic_inc(&gss_msg->count);
- rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL);
+ rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
} else
err = gss_msg->msg.errno;
spin_unlock(&inode->i_lock);
@@ -454,7 +453,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
schedule();
}
if (gss_msg->ctx)
- gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
+ gss_cred_set_ctx(cred, gss_msg->ctx);
else
err = gss_msg->msg.errno;
spin_unlock(&inode->i_lock);
@@ -625,7 +624,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
if (!gss_auth->mech) {
printk(KERN_WARNING "%s: Pseudoflavor %d not found!\n",
- __FUNCTION__, flavor);
+ __func__, flavor);
goto err_free;
}
gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
@@ -709,7 +708,7 @@ gss_destroying_context(struct rpc_cred *cred)
struct rpc_task *task;
if (gss_cred->gc_ctx == NULL ||
- gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY)
+ test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
return 0;
gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY;
@@ -719,7 +718,7 @@ gss_destroying_context(struct rpc_cred *cred)
* by the RPC call or by the put_rpccred() below */
get_rpccred(cred);
- task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC);
+ task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT);
if (!IS_ERR(task))
rpc_put_task(task);
@@ -817,6 +816,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
*/
cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
cred->gc_service = gss_auth->service;
+ cred->gc_machine_cred = acred->machine_cred;
kref_get(&gss_auth->kref);
return &cred->gc_base;
@@ -843,17 +843,16 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
{
struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
- /*
- * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
- * we don't really care if the credential has expired or not,
- * since the caller should be prepared to reinitialise it.
- */
- if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
+ if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
goto out;
/* Don't match with creds that have expired. */
- if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+ if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+ return 0;
+ if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
return 0;
out:
+ if (acred->machine_cred != gss_cred->gc_machine_cred)
+ return 0;
return (rc->cr_uid == acred->uid);
}
@@ -917,16 +916,48 @@ out_put_ctx:
return NULL;
}
+static int gss_renew_cred(struct rpc_task *task)
+{
+ struct rpc_cred *oldcred = task->tk_msg.rpc_cred;
+ struct gss_cred *gss_cred = container_of(oldcred,
+ struct gss_cred,
+ gc_base);
+ struct rpc_auth *auth = oldcred->cr_auth;
+ struct auth_cred acred = {
+ .uid = oldcred->cr_uid,
+ .machine_cred = gss_cred->gc_machine_cred,
+ };
+ struct rpc_cred *new;
+
+ new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
+ if (IS_ERR(new))
+ return PTR_ERR(new);
+ task->tk_msg.rpc_cred = new;
+ put_rpccred(oldcred);
+ return 0;
+}
+
/*
* Refresh credentials. XXX - finish
*/
static int
gss_refresh(struct rpc_task *task)
{
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ int ret = 0;
+
+ if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
+ !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
+ ret = gss_renew_cred(task);
+ if (ret < 0)
+ goto out;
+ cred = task->tk_msg.rpc_cred;
+ }
- if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred))
- return gss_refresh_upcall(task);
- return 0;
+ if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+ ret = gss_refresh_upcall(task);
+out:
+ return ret;
}
/* Dummy refresh routine: used only when destroying the context */
@@ -1286,9 +1317,7 @@ out:
static const struct rpc_authops authgss_ops = {
.owner = THIS_MODULE,
.au_flavor = RPC_AUTH_GSS,
-#ifdef RPC_DEBUG
.au_name = "RPCSEC_GSS",
-#endif
.create = gss_create,
.destroy = gss_destroy,
.lookup_cred = gss_lookup_cred,
@@ -1299,6 +1328,7 @@ static const struct rpc_credops gss_credops = {
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
.cr_init = gss_cred_init,
+ .crbind = rpcauth_generic_bind_cred,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh,
@@ -1310,6 +1340,7 @@ static const struct rpc_credops gss_credops = {
static const struct rpc_credops gss_nullops = {
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
+ .crbind = rpcauth_generic_bind_cred,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh_null,
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c
index ea8c92ecdae5..d83b881685fe 100644
--- a/net/sunrpc/auth_gss/gss_generic_token.c
+++ b/net/sunrpc/auth_gss/gss_generic_token.c
@@ -148,7 +148,7 @@ int
g_token_size(struct xdr_netobj *mech, unsigned int body_size)
{
/* set body_size to sequence contents size */
- body_size += 4 + (int) mech->len; /* NEED overflow check */
+ body_size += 2 + (int) mech->len; /* NEED overflow check */
return(1 + der_length_size(body_size) + body_size);
}
@@ -161,7 +161,7 @@ void
g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
{
*(*buf)++ = 0x60;
- der_write_length(buf, 4 + mech->len + body_size);
+ der_write_length(buf, 2 + mech->len + body_size);
*(*buf)++ = 0x06;
*(*buf)++ = (unsigned char) mech->len;
TWRITE_STR(*buf, mech->data, ((int) mech->len));
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 0dd792338fa9..1d52308ca324 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -66,8 +66,8 @@ krb5_encrypt(
goto out;
if (crypto_blkcipher_ivsize(tfm) > 16) {
- dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
- crypto_blkcipher_ivsize(tfm));
+ dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n",
+ crypto_blkcipher_ivsize(tfm));
goto out;
}
@@ -102,7 +102,7 @@ krb5_decrypt(
goto out;
if (crypto_blkcipher_ivsize(tfm) > 16) {
- dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n",
+ dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n",
crypto_blkcipher_ivsize(tfm));
goto out;
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index dedcbd6108f4..5f1d36dfbcf7 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -87,10 +87,10 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
now = get_seconds();
- token->len = g_token_size(&ctx->mech_used, 22);
+ token->len = g_token_size(&ctx->mech_used, 24);
ptr = token->data;
- g_make_token_header(&ctx->mech_used, 22, &ptr);
+ g_make_token_header(&ctx->mech_used, 24, &ptr);
*ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
*ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
@@ -109,15 +109,14 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
- KRB5_CKSUM_LENGTH);
+ memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
spin_lock(&krb5_seq_lock);
seq_send = ctx->seq_send++;
spin_unlock(&krb5_seq_lock);
if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
- ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))
+ seq_send, krb5_hdr + 16, krb5_hdr + 8))
return GSS_S_FAILURE;
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
index 43f3421f1e6a..f160be6c1a46 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
@@ -43,7 +43,7 @@
s32
krb5_make_seq_num(struct crypto_blkcipher *key,
int direction,
- s32 seqnum,
+ u32 seqnum,
unsigned char *cksum, unsigned char *buf)
{
unsigned char plain[8];
@@ -65,7 +65,7 @@ s32
krb5_get_seq_num(struct crypto_blkcipher *key,
unsigned char *cksum,
unsigned char *buf,
- int *direction, s32 * seqnum)
+ int *direction, u32 *seqnum)
{
s32 code;
unsigned char plain[8];
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index e30a993466bc..d91a5d004803 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -82,7 +82,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
s32 now;
int direction;
- s32 seqnum;
+ u32 seqnum;
unsigned char *ptr = (unsigned char *)read_token->data;
int bodysize;
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 3bdc527ee64a..b00b1b426301 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -137,7 +137,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
BUG_ON((buf->len - offset) % blocksize);
plainlen = blocksize + buf->len - offset;
- headlen = g_token_size(&kctx->mech_used, 22 + plainlen) -
+ headlen = g_token_size(&kctx->mech_used, 24 + plainlen) -
(buf->len - offset);
ptr = buf->head[0].iov_base + offset;
@@ -149,7 +149,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
buf->len += headlen;
BUG_ON((buf->len - offset - headlen) % blocksize);
- g_make_token_header(&kctx->mech_used, 22 + plainlen, &ptr);
+ g_make_token_header(&kctx->mech_used, 24 + plainlen, &ptr);
*ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
@@ -176,9 +176,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16,
- md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
- KRB5_CKSUM_LENGTH);
+ memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
spin_lock(&krb5_seq_lock);
seq_send = kctx->seq_send++;
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
index abf17ce2e3b1..c832712f8d55 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -107,10 +107,10 @@ spkm3_make_token(struct spkm3_ctx *ctx,
tokenlen = 10 + ctxelen + 1 + md5elen + 1;
/* Create token header using generic routines */
- token->len = g_token_size(&ctx->mech_used, tokenlen);
+ token->len = g_token_size(&ctx->mech_used, tokenlen + 2);
ptr = token->data;
- g_make_token_header(&ctx->mech_used, tokenlen, &ptr);
+ g_make_token_header(&ctx->mech_used, tokenlen + 2, &ptr);
spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
} else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 481f984e9a22..5905d56737d6 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1146,7 +1146,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
case RPC_GSS_SVC_INTEGRITY:
if (unwrap_integ_data(&rqstp->rq_arg,
gc->gc_seq, rsci->mechctx))
- goto auth_err;
+ goto garbage_args;
/* placeholders for length and seq. number: */
svc_putnl(resv, 0);
svc_putnl(resv, 0);
@@ -1154,7 +1154,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
case RPC_GSS_SVC_PRIVACY:
if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
gc->gc_seq, rsci->mechctx))
- goto auth_err;
+ goto garbage_args;
/* placeholders for length and seq. number: */
svc_putnl(resv, 0);
svc_putnl(resv, 0);
@@ -1169,6 +1169,11 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
ret = SVC_OK;
goto out;
}
+garbage_args:
+ /* Restore write pointer to its original value: */
+ xdr_ressize_check(rqstp, reject_stat);
+ ret = SVC_GARBAGE;
+ goto out;
auth_err:
/* Restore write pointer to its original value: */
xdr_ressize_check(rqstp, reject_stat);