Commit 4d08b43c authored by Trond Myklebust's avatar Trond Myklebust

RPC: Remove dependency of RPCSEC_GSS upcalls on the credential cache

 Ensure that credentials that are referenced by an RPC task, but that
 have been booted out of the credcache may still be refreshed.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 6180efbe
...@@ -77,10 +77,12 @@ struct gss_cl_ctx { ...@@ -77,10 +77,12 @@ struct gss_cl_ctx {
unsigned long gc_expiry; unsigned long gc_expiry;
}; };
struct gss_upcall_msg;
struct gss_cred { struct gss_cred {
struct rpc_cred gc_base; struct rpc_cred gc_base;
enum rpc_gss_svc gc_service; enum rpc_gss_svc gc_service;
struct gss_cl_ctx *gc_ctx; struct gss_cl_ctx *gc_ctx;
struct gss_upcall_msg *gc_upcall;
}; };
#define gc_uid gc_base.cr_uid #define gc_uid gc_base.cr_uid
......
...@@ -289,12 +289,13 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct ...@@ -289,12 +289,13 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
struct gss_upcall_msg { struct gss_upcall_msg {
atomic_t count;
uid_t uid;
struct rpc_pipe_msg msg; struct rpc_pipe_msg msg;
struct list_head list; struct list_head list;
struct gss_auth *auth; struct gss_auth *auth;
struct rpc_wait_queue waitq; struct rpc_wait_queue waitq;
uid_t uid; struct gss_cl_ctx *ctx;
atomic_t count;
}; };
static void static void
...@@ -303,6 +304,8 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) ...@@ -303,6 +304,8 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
if (!atomic_dec_and_test(&gss_msg->count)) if (!atomic_dec_and_test(&gss_msg->count))
return; return;
BUG_ON(!list_empty(&gss_msg->list)); BUG_ON(!list_empty(&gss_msg->list));
if (gss_msg->ctx != NULL)
gss_put_ctx(gss_msg->ctx);
kfree(gss_msg); kfree(gss_msg);
} }
...@@ -344,11 +347,29 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg) ...@@ -344,11 +347,29 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg)
spin_unlock(&gss_auth->lock); spin_unlock(&gss_auth->lock);
} }
static void
gss_upcall_callback(struct rpc_task *task)
{
struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred,
struct gss_cred, gc_base);
struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
BUG_ON(gss_msg == NULL);
if (gss_msg->ctx)
gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
else
task->tk_status = gss_msg->msg.errno;
gss_cred->gc_upcall = NULL;
gss_release_msg(gss_msg);
}
static int static int
gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred) gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred)
{ {
struct gss_auth *gss_auth = container_of(clnt->cl_auth, struct gss_auth *gss_auth = container_of(clnt->cl_auth,
struct gss_auth, rpc_auth); struct gss_auth, rpc_auth);
struct gss_cred *gss_cred = container_of(cred,
struct gss_cred, gc_base);
struct gss_upcall_msg *gss_msg, *gss_new = NULL; struct gss_upcall_msg *gss_msg, *gss_new = NULL;
struct rpc_pipe_msg *msg; struct rpc_pipe_msg *msg;
struct dentry *dentry = gss_auth->dentry; struct dentry *dentry = gss_auth->dentry;
...@@ -387,7 +408,9 @@ gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred) ...@@ -387,7 +408,9 @@ gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred)
if (!gss_cred_is_uptodate_ctx(cred)) { if (!gss_cred_is_uptodate_ctx(cred)) {
/* No, so do upcall and sleep */ /* No, so do upcall and sleep */
task->tk_timeout = 0; task->tk_timeout = 0;
rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL); /* gss_upcall_callback will release the reference to gss_msg */
gss_cred->gc_upcall = gss_msg;
rpc_sleep_on(&gss_msg->waitq, task, gss_upcall_callback, NULL);
spin_unlock(&gss_auth->lock); spin_unlock(&gss_auth->lock);
res = rpc_queue_upcall(dentry->d_inode, msg); res = rpc_queue_upcall(dentry->d_inode, msg);
if (res) if (res)
...@@ -396,23 +419,20 @@ gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred) ...@@ -396,23 +419,20 @@ gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred)
/* Yes, so cancel upcall */ /* Yes, so cancel upcall */
__gss_unhash_msg(gss_msg); __gss_unhash_msg(gss_msg);
spin_unlock(&gss_auth->lock); spin_unlock(&gss_auth->lock);
gss_release_msg(gss_msg);
} }
gss_release_msg(gss_msg);
dprintk("RPC: %4u gss_upcall for uid %u result %d\n", task->tk_pid, dprintk("RPC: %4u gss_upcall for uid %u result %d\n", task->tk_pid,
uid, res); uid, res);
return res; return res;
out_sleep: out_sleep:
task->tk_timeout = 0; task->tk_timeout = 0;
rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL); /* gss_upcall_callback will release the reference to gss_msg */
gss_cred->gc_upcall = gss_msg;
rpc_sleep_on(&gss_msg->waitq, task, gss_upcall_callback, NULL);
spin_unlock(&gss_auth->lock); spin_unlock(&gss_auth->lock);
dprintk("RPC: %4u gss_upcall sleeping\n", task->tk_pid); dprintk("RPC: %4u gss_upcall sleeping\n", task->tk_pid);
if (gss_new) if (gss_new)
kfree(gss_new); kfree(gss_new);
/* Note: we drop the reference here: we are automatically removed
* from the queue when we're woken up, and we should in any case
* have no further responsabilities w.r.t. the upcall.
*/
gss_release_msg(gss_msg);
return 0; return 0;
} }
...@@ -446,7 +466,6 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) ...@@ -446,7 +466,6 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
void *buf; void *buf;
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
struct gss_auth *gss_auth; struct gss_auth *gss_auth;
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;
...@@ -471,11 +490,6 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) ...@@ -471,11 +490,6 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
err = PTR_ERR(p); err = PTR_ERR(p);
goto err; goto err;
} }
acred.uid = uid;
err = -ENOENT;
cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0);
if (!cred)
goto err;
err = -ENOMEM; err = -ENOMEM;
ctx = gss_alloc_context(); ctx = gss_alloc_context();
...@@ -488,17 +502,25 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) ...@@ -488,17 +502,25 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
err = PTR_ERR(p); err = PTR_ERR(p);
if (err != -EACCES) if (err != -EACCES)
goto err_put_ctx; goto err_put_ctx;
} else }
gss_cred_set_ctx(cred, gss_get_ctx(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, uid);
if (gss_msg) { if (gss_msg) {
if (err == 0 && gss_msg->ctx == NULL)
gss_msg->ctx = gss_get_ctx(ctx);
gss_msg->msg.errno = err; gss_msg->msg.errno = err;
__gss_unhash_msg(gss_msg); __gss_unhash_msg(gss_msg);
spin_unlock(&gss_auth->lock); spin_unlock(&gss_auth->lock);
gss_release_msg(gss_msg); gss_release_msg(gss_msg);
} else } else {
struct auth_cred acred = { .uid = uid };
spin_unlock(&gss_auth->lock); spin_unlock(&gss_auth->lock);
err = -ENOENT;
cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0);
if (!cred)
goto err_put_ctx;
gss_cred_set_ctx(cred, gss_get_ctx(ctx));
}
gss_put_ctx(ctx); gss_put_ctx(ctx);
kfree(buf); kfree(buf);
dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen); dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen);
......
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