Commit 315a0e34 authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Linus Torvalds

allow gssd to communicate failure to initialize contexts back to the kernel, so

the kernel can return -EACCES when a user lacks credentials, instead of just
hanging until they kinit.
parent 4f1cab9b
...@@ -127,6 +127,7 @@ u32 * rpcauth_checkverf(struct rpc_task *, u32 *); ...@@ -127,6 +127,7 @@ u32 * rpcauth_checkverf(struct rpc_task *, u32 *);
int rpcauth_refreshcred(struct rpc_task *); int rpcauth_refreshcred(struct rpc_task *);
void rpcauth_invalcred(struct rpc_task *); void rpcauth_invalcred(struct rpc_task *);
int rpcauth_uptodatecred(struct rpc_task *); int rpcauth_uptodatecred(struct rpc_task *);
int rpcauth_deadcred(struct rpc_task *);
void rpcauth_init_credcache(struct rpc_auth *); void rpcauth_init_credcache(struct rpc_auth *);
void rpcauth_free_credcache(struct rpc_auth *); void rpcauth_free_credcache(struct rpc_auth *);
......
...@@ -369,3 +369,9 @@ rpcauth_uptodatecred(struct rpc_task *task) ...@@ -369,3 +369,9 @@ rpcauth_uptodatecred(struct rpc_task *task)
(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE); (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
} }
int
rpcauth_deadcred(struct rpc_task *task)
{
return !(task->tk_msg.rpc_cred) ||
(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_DEAD);
}
...@@ -221,7 +221,7 @@ gss_cred_get_ctx(struct rpc_cred *cred) ...@@ -221,7 +221,7 @@ gss_cred_get_ctx(struct rpc_cred *cred)
static int static int
gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf, gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf,
struct gss_cl_ctx **gc, uid_t *uid) struct gss_cl_ctx **gc, uid_t *uid, int *gss_err)
{ {
char *end = buf->data + buf->len; char *end = buf->data + buf->len;
char *p = buf->data; char *p = buf->data;
...@@ -244,8 +244,17 @@ gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf, ...@@ -244,8 +244,17 @@ gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf,
/* FIXME: discarded timeout for now */ /* FIXME: discarded timeout for now */
if (simple_get_bytes(&p, end, &timeout, sizeof(timeout))) if (simple_get_bytes(&p, end, &timeout, sizeof(timeout)))
goto err_free_ctx; goto err_free_ctx;
*gss_err = 0;
if (simple_get_bytes(&p, end, &ctx->gc_win, sizeof(ctx->gc_win))) if (simple_get_bytes(&p, end, &ctx->gc_win, sizeof(ctx->gc_win)))
goto err_free_ctx; goto err_free_ctx;
/* gssd signals an error by passing ctx->gc_win = 0: */
if (!ctx->gc_win) {
/* in which case the next int is an error code: */
if (simple_get_bytes(&p, end, gss_err, sizeof(*gss_err)))
goto err_free_ctx;
err = 0;
goto err_free_ctx;
}
if (simple_get_netobj(&p, end, &tmp_buf)) if (simple_get_netobj(&p, end, &tmp_buf))
goto err_free_ctx; goto err_free_ctx;
if (dup_netobj(&tmp_buf, &ctx->gc_wire_ctx)) { if (dup_netobj(&tmp_buf, &ctx->gc_wire_ctx)) {
...@@ -395,9 +404,10 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen) ...@@ -395,9 +404,10 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
struct auth_cred acred = { 0 }; struct auth_cred acred = { 0 };
struct rpc_cred *cred; struct rpc_cred *cred;
struct gss_upcall_msg *gss_msg; struct gss_upcall_msg *gss_msg;
struct gss_cl_ctx *ctx; struct gss_cl_ctx *ctx = NULL;
ssize_t left; ssize_t left;
int err; int err;
int gss_err;
if (mlen > sizeof(buf)) if (mlen > sizeof(buf))
return -ENOSPC; return -ENOSPC;
...@@ -409,12 +419,15 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen) ...@@ -409,12 +419,15 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
auth = clnt->cl_auth; auth = clnt->cl_auth;
gss_auth = container_of(auth, struct gss_auth, rpc_auth); gss_auth = container_of(auth, struct gss_auth, rpc_auth);
mech = gss_auth->mech; mech = gss_auth->mech;
err = gss_parse_init_downcall(mech, &obj, &ctx, &acred.uid); err = gss_parse_init_downcall(mech, &obj, &ctx, &acred.uid, &gss_err);
if (err) if (err)
goto err; goto err;
cred = rpcauth_lookup_credcache(auth, &acred, 0); cred = rpcauth_lookup_credcache(auth, &acred, 0);
if (!cred) if (!cred)
goto err_release_ctx; goto err;
if (gss_err)
cred->cr_flags |= RPCAUTH_CRED_DEAD;
else
gss_cred_set_ctx(cred, ctx); gss_cred_set_ctx(cred, ctx);
spin_lock(&gss_auth->lock); spin_lock(&gss_auth->lock);
gss_msg = gss_find_upcall(gss_auth, acred.uid); gss_msg = gss_find_upcall(gss_auth, acred.uid);
...@@ -423,9 +436,9 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen) ...@@ -423,9 +436,9 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
spin_unlock(&gss_auth->lock); spin_unlock(&gss_auth->lock);
rpc_release_client(clnt); rpc_release_client(clnt);
return mlen; return mlen;
err_release_ctx:
gss_destroy_ctx(ctx);
err: err:
if (ctx)
gss_destroy_ctx(ctx);
rpc_release_client(clnt); rpc_release_client(clnt);
dprintk("RPC: gss_pipe_downcall returning %d\n", err); dprintk("RPC: gss_pipe_downcall returning %d\n", err);
return err; return err;
......
...@@ -850,17 +850,16 @@ call_refreshresult(struct rpc_task *task) ...@@ -850,17 +850,16 @@ call_refreshresult(struct rpc_task *task)
task->tk_status = 0; task->tk_status = 0;
task->tk_action = call_reserve; task->tk_action = call_reserve;
if (status >= 0) if (status >= 0 && rpcauth_uptodatecred(task))
return; return;
switch (status) { if (rpcauth_deadcred(task)) {
case -EPIPE:
rpc_delay(task, 3*HZ);
case -ETIMEDOUT:
task->tk_action = call_refresh;
break;
default:
rpc_exit(task, -EACCES); rpc_exit(task, -EACCES);
return;
} }
task->tk_action = call_refresh;
if (status != -ETIMEDOUT)
rpc_delay(task, 3*HZ);
return;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment