Commit 756a93f7 authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] Clean up RPC client credcache lookups [1/6]

Clean up RPC client credcache lookups.

    - Remove the limitation whereby the RPC client may only look up
      credentials for the current task.

The ability to lookup arbitrary credentials is needed in order to allow
a user daemon to set the RPCSEC_GSS private information once it
has finished negotiating the RPCSEC user context with the server.
parent 68fc0a78
...@@ -19,6 +19,14 @@ ...@@ -19,6 +19,14 @@
/* size of the nodename buffer */ /* size of the nodename buffer */
#define UNX_MAXNODENAME 32 #define UNX_MAXNODENAME 32
/* Work around the lack of a VFS credential */
struct auth_cred {
uid_t uid;
gid_t gid;
int ngroups;
gid_t *groups;
};
/* /*
* Client user credentials * Client user credentials
*/ */
...@@ -74,13 +82,13 @@ struct rpc_authops { ...@@ -74,13 +82,13 @@ struct rpc_authops {
struct rpc_auth * (*create)(struct rpc_clnt *); struct rpc_auth * (*create)(struct rpc_clnt *);
void (*destroy)(struct rpc_auth *); void (*destroy)(struct rpc_auth *);
struct rpc_cred * (*crcreate)(int); struct rpc_cred * (*crcreate)(struct auth_cred *, int);
}; };
struct rpc_credops { struct rpc_credops {
void (*crdestroy)(struct rpc_cred *); void (*crdestroy)(struct rpc_cred *);
int (*crmatch)(struct rpc_cred *, int); int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
u32 * (*crmarshal)(struct rpc_task *, u32 *, int); u32 * (*crmarshal)(struct rpc_task *, u32 *, int);
int (*crrefresh)(struct rpc_task *); int (*crrefresh)(struct rpc_task *);
u32 * (*crvalidate)(struct rpc_task *, u32 *); u32 * (*crvalidate)(struct rpc_task *, u32 *);
......
...@@ -174,7 +174,8 @@ rpcauth_gc_credcache(struct rpc_auth *auth, struct list_head *free) ...@@ -174,7 +174,8 @@ rpcauth_gc_credcache(struct rpc_auth *auth, struct list_head *free)
* Look up a process' credentials in the authentication cache * Look up a process' credentials in the authentication cache
*/ */
static struct rpc_cred * static struct rpc_cred *
rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags) rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
int taskflags)
{ {
LIST_HEAD(free); LIST_HEAD(free);
struct list_head *pos, *next; struct list_head *pos, *next;
...@@ -183,7 +184,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags) ...@@ -183,7 +184,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
int nr = 0; int nr = 0;
if (!(taskflags & RPC_TASK_ROOTCREDS)) if (!(taskflags & RPC_TASK_ROOTCREDS))
nr = current->uid & RPC_CREDCACHE_MASK; nr = acred->uid & RPC_CREDCACHE_MASK;
retry: retry:
spin_lock(&rpc_credcache_lock); spin_lock(&rpc_credcache_lock);
if (time_before(auth->au_nextgc, jiffies)) if (time_before(auth->au_nextgc, jiffies))
...@@ -195,7 +196,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags) ...@@ -195,7 +196,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
continue; continue;
if (rpcauth_prune_expired(entry, &free)) if (rpcauth_prune_expired(entry, &free))
continue; continue;
if (entry->cr_ops->crmatch(entry, taskflags)) { if (entry->cr_ops->crmatch(acred, entry, taskflags)) {
list_del(&entry->cr_hash); list_del(&entry->cr_hash);
cred = entry; cred = entry;
break; break;
...@@ -217,7 +218,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags) ...@@ -217,7 +218,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
rpcauth_destroy_credlist(&free); rpcauth_destroy_credlist(&free);
if (!cred) { if (!cred) {
new = auth->au_ops->crcreate(taskflags); new = auth->au_ops->crcreate(acred, taskflags);
if (new) { if (new) {
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
new->cr_magic = RPCAUTH_CRED_MAGIC; new->cr_magic = RPCAUTH_CRED_MAGIC;
...@@ -232,19 +233,31 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags) ...@@ -232,19 +233,31 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
struct rpc_cred * struct rpc_cred *
rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
{ {
struct auth_cred acred = {
.uid = current->fsuid,
.gid = current->fsgid,
.ngroups = current->ngroups,
.groups = current->groups,
};
dprintk("RPC: looking up %s cred\n", dprintk("RPC: looking up %s cred\n",
auth->au_ops->au_name); auth->au_ops->au_name);
return rpcauth_lookup_credcache(auth, taskflags); return rpcauth_lookup_credcache(auth, &acred, taskflags);
} }
struct rpc_cred * struct rpc_cred *
rpcauth_bindcred(struct rpc_task *task) rpcauth_bindcred(struct rpc_task *task)
{ {
struct rpc_auth *auth = task->tk_auth; struct rpc_auth *auth = task->tk_auth;
struct auth_cred acred = {
.uid = current->fsuid,
.gid = current->fsgid,
.ngroups = current->ngroups,
.groups = current->groups,
};
dprintk("RPC: %4d looking up %s cred\n", dprintk("RPC: %4d looking up %s cred\n",
task->tk_pid, task->tk_auth->au_ops->au_name); task->tk_pid, task->tk_auth->au_ops->au_name);
task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, task->tk_flags); task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, &acred, task->tk_flags);
if (task->tk_msg.rpc_cred == 0) if (task->tk_msg.rpc_cred == 0)
task->tk_status = -ENOMEM; task->tk_status = -ENOMEM;
return task->tk_msg.rpc_cred; return task->tk_msg.rpc_cred;
......
...@@ -48,7 +48,7 @@ nul_destroy(struct rpc_auth *auth) ...@@ -48,7 +48,7 @@ nul_destroy(struct rpc_auth *auth)
* Create NULL creds for current process * Create NULL creds for current process
*/ */
static struct rpc_cred * static struct rpc_cred *
nul_create_cred(int flags) nul_create_cred(struct auth_cred *acred, int flags)
{ {
struct rpc_cred *cred; struct rpc_cred *cred;
...@@ -56,7 +56,7 @@ nul_create_cred(int flags) ...@@ -56,7 +56,7 @@ nul_create_cred(int flags)
return NULL; return NULL;
atomic_set(&cred->cr_count, 0); atomic_set(&cred->cr_count, 0);
cred->cr_flags = RPCAUTH_CRED_UPTODATE; cred->cr_flags = RPCAUTH_CRED_UPTODATE;
cred->cr_uid = current->uid; cred->cr_uid = acred->uid;
cred->cr_ops = &null_credops; cred->cr_ops = &null_credops;
return cred; return cred;
...@@ -75,7 +75,7 @@ nul_destroy_cred(struct rpc_cred *cred) ...@@ -75,7 +75,7 @@ nul_destroy_cred(struct rpc_cred *cred)
* Match cred handle against current process * Match cred handle against current process
*/ */
static int static int
nul_match(struct rpc_cred *cred, int taskflags) nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags)
{ {
return 1; return 1;
} }
......
...@@ -14,10 +14,12 @@ ...@@ -14,10 +14,12 @@
#include <linux/sunrpc/auth.h> #include <linux/sunrpc/auth.h>
#define NFS_NGROUPS 16 #define NFS_NGROUPS 16
struct unx_cred { struct unx_cred {
struct rpc_cred uc_base; struct rpc_cred uc_base;
uid_t uc_fsuid; gid_t uc_gid;
gid_t uc_gid, uc_fsgid; uid_t uc_puid; /* process uid */
gid_t uc_pgid; /* process gid */
gid_t uc_gids[NFS_NGROUPS]; gid_t uc_gids[NFS_NGROUPS];
}; };
#define uc_uid uc_base.cr_uid #define uc_uid uc_base.cr_uid
...@@ -62,13 +64,13 @@ unx_destroy(struct rpc_auth *auth) ...@@ -62,13 +64,13 @@ unx_destroy(struct rpc_auth *auth)
} }
static struct rpc_cred * static struct rpc_cred *
unx_create_cred(int flags) unx_create_cred(struct auth_cred *acred, int flags)
{ {
struct unx_cred *cred; struct unx_cred *cred;
int i; int i;
dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", dprintk("RPC: allocating UNIX cred for uid %d gid %d\n",
current->uid, current->gid); acred->uid, acred->gid);
if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL))) if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL)))
return NULL; return NULL;
...@@ -76,20 +78,20 @@ unx_create_cred(int flags) ...@@ -76,20 +78,20 @@ unx_create_cred(int flags)
atomic_set(&cred->uc_count, 0); atomic_set(&cred->uc_count, 0);
cred->uc_flags = RPCAUTH_CRED_UPTODATE; cred->uc_flags = RPCAUTH_CRED_UPTODATE;
if (flags & RPC_TASK_ROOTCREDS) { if (flags & RPC_TASK_ROOTCREDS) {
cred->uc_uid = cred->uc_fsuid = 0; cred->uc_uid = cred->uc_puid = 0;
cred->uc_gid = cred->uc_fsgid = 0; cred->uc_gid = cred->uc_pgid = 0;
cred->uc_gids[0] = NOGROUP; cred->uc_gids[0] = NOGROUP;
} else { } else {
int groups = current->ngroups; int groups = acred->ngroups;
if (groups > NFS_NGROUPS) if (groups > NFS_NGROUPS)
groups = NFS_NGROUPS; groups = NFS_NGROUPS;
cred->uc_uid = current->uid; cred->uc_uid = acred->uid;
cred->uc_gid = current->gid; cred->uc_gid = acred->gid;
cred->uc_fsuid = current->fsuid; cred->uc_puid = current->uid;
cred->uc_fsgid = current->fsgid; cred->uc_pgid = current->gid;
for (i = 0; i < groups; i++) for (i = 0; i < groups; i++)
cred->uc_gids[i] = (gid_t) current->groups[i]; cred->uc_gids[i] = (gid_t) acred->groups[i];
if (i < NFS_NGROUPS) if (i < NFS_NGROUPS)
cred->uc_gids[i] = NOGROUP; cred->uc_gids[i] = NOGROUP;
} }
...@@ -110,7 +112,7 @@ unx_destroy_cred(struct rpc_cred *cred) ...@@ -110,7 +112,7 @@ unx_destroy_cred(struct rpc_cred *cred)
* request root creds (e.g. for NFS swapping). * request root creds (e.g. for NFS swapping).
*/ */
static int static int
unx_match(struct rpc_cred *rcred, int taskflags) unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
{ {
struct unx_cred *cred = (struct unx_cred *) rcred; struct unx_cred *cred = (struct unx_cred *) rcred;
int i; int i;
...@@ -118,22 +120,22 @@ unx_match(struct rpc_cred *rcred, int taskflags) ...@@ -118,22 +120,22 @@ unx_match(struct rpc_cred *rcred, int taskflags)
if (!(taskflags & RPC_TASK_ROOTCREDS)) { if (!(taskflags & RPC_TASK_ROOTCREDS)) {
int groups; int groups;
if (cred->uc_uid != current->uid if (cred->uc_uid != acred->uid
|| cred->uc_gid != current->gid || cred->uc_gid != acred->gid
|| cred->uc_fsuid != current->fsuid || cred->uc_puid != current->uid
|| cred->uc_fsgid != current->fsgid) || cred->uc_pgid != current->gid)
return 0; return 0;
groups = current->ngroups; groups = acred->ngroups;
if (groups > NFS_NGROUPS) if (groups > NFS_NGROUPS)
groups = NFS_NGROUPS; groups = NFS_NGROUPS;
for (i = 0; i < groups ; i++) for (i = 0; i < groups ; i++)
if (cred->uc_gids[i] != (gid_t) current->groups[i]) if (cred->uc_gids[i] != (gid_t) acred->groups[i])
return 0; return 0;
return 1; return 1;
} }
return (cred->uc_uid == 0 && cred->uc_fsuid == 0 return (cred->uc_uid == 0 && cred->uc_puid == 0
&& cred->uc_gid == 0 && cred->uc_fsgid == 0 && cred->uc_gid == 0 && cred->uc_pgid == 0
&& cred->uc_gids[0] == (gid_t) NOGROUP); && cred->uc_gids[0] == (gid_t) NOGROUP);
} }
...@@ -162,12 +164,12 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid) ...@@ -162,12 +164,12 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid)
p += (n + 3) >> 2; p += (n + 3) >> 2;
/* Note: we don't use real uid if it involves raising priviledge */ /* Note: we don't use real uid if it involves raising priviledge */
if (ruid && cred->uc_uid != 0 && cred->uc_gid != 0) { if (ruid && cred->uc_puid != 0 && cred->uc_pgid != 0) {
*p++ = htonl((u32) cred->uc_puid);
*p++ = htonl((u32) cred->uc_pgid);
} else {
*p++ = htonl((u32) cred->uc_uid); *p++ = htonl((u32) cred->uc_uid);
*p++ = htonl((u32) cred->uc_gid); *p++ = htonl((u32) cred->uc_gid);
} else {
*p++ = htonl((u32) cred->uc_fsuid);
*p++ = htonl((u32) cred->uc_fsgid);
} }
hold = p++; hold = p++;
for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++) for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
......
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