summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-02-01 12:19:27 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-02-01 12:52:25 -0500
commitfba3bad488a2eec2d76c067edb7a5ff92ef42431 (patch)
treea7cee933e9089e5c187008b396ee7bcbdb57ff80
parentadb12f63e0f837078c6832fa2c90649ddeaab54f (diff)
SUNRPC: Move upcall out of auth->au_ops->crcreate()
This fixes a bug whereby if two processes try to look up the same auth_gss credential, they may end up creating two creds, and triggering two upcalls because the upcall is performed before the credential is added to the credcache. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--include/linux/sunrpc/auth.h1
-rw-r--r--net/sunrpc/auth.c8
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c23
3 files changed, 23 insertions, 9 deletions
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index bfc5fb27953..2647798b72c 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -110,6 +110,7 @@ struct rpc_authops {
struct rpc_credops {
const char * cr_name; /* Name of the auth flavour */
+ int (*cr_init)(struct rpc_auth *, struct rpc_cred *);
void (*crdestroy)(struct rpc_cred *);
int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 1ca89c36da7..8d6f1a176b1 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -232,6 +232,14 @@ retry:
goto retry;
} else
cred = new;
+ } else if ((cred->cr_flags & RPCAUTH_CRED_NEW)
+ && cred->cr_ops->cr_init != NULL
+ && !(flags & RPCAUTH_LOOKUP_NEW)) {
+ int res = cred->cr_ops->cr_init(auth, cred);
+ if (res < 0) {
+ put_rpccred(cred);
+ cred = ERR_PTR(res);
+ }
}
return (struct rpc_cred *) cred;
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 03affcbf629..bb46efd92e5 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -788,15 +788,6 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
cred->gc_base.cr_ops = &gss_credops;
cred->gc_base.cr_flags = RPCAUTH_CRED_NEW;
cred->gc_service = gss_auth->service;
- /* Is the caller prepared to initialise the credential? */
- if (flags & RPCAUTH_LOOKUP_NEW)
- goto out;
- do {
- err = gss_create_upcall(gss_auth, cred);
- } while (err == -EAGAIN);
- if (err < 0)
- goto out_err;
-out:
return &cred->gc_base;
out_err:
@@ -806,6 +797,19 @@ out_err:
}
static int
+gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+ struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+ struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base);
+ int err;
+
+ do {
+ err = gss_create_upcall(gss_auth, gss_cred);
+ } while (err == -EAGAIN);
+ return err;
+}
+
+static int
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);
@@ -1254,6 +1258,7 @@ static struct rpc_authops authgss_ops = {
static struct rpc_credops gss_credops = {
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
+ .cr_init = gss_cred_init,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh,