Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 48328
b: refs/heads/master
c: 3fc605a
h: refs/heads/master
v: v3
  • Loading branch information
NeilBrown authored and Linus Torvalds committed Feb 14, 2007
1 parent 28d78b2 commit bbe103d
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: af6a4e280e3ff453653f39190b57b345ff0bec16
refs/heads/master: 3fc605a2aa38899c12180ca311f1eeb61a6d867e
5 changes: 4 additions & 1 deletion trunk/net/sunrpc/sunrpc_syms.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ EXPORT_SYMBOL(nlm_debug);

extern int register_rpc_pipefs(void);
extern void unregister_rpc_pipefs(void);
extern struct cache_detail ip_map_cache;
extern struct cache_detail ip_map_cache, unix_gid_cache;
extern int init_socket_xprt(void);
extern void cleanup_socket_xprt(void);

Expand All @@ -157,6 +157,7 @@ init_sunrpc(void)
rpc_proc_init();
#endif
cache_register(&ip_map_cache);
cache_register(&unix_gid_cache);
init_socket_xprt();
out:
return err;
Expand All @@ -170,6 +171,8 @@ cleanup_sunrpc(void)
rpc_destroy_mempool();
if (cache_unregister(&ip_map_cache))
printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
if (cache_unregister(&unix_gid_cache))
printk(KERN_ERR "sunrpc: failed to unregister unix_gid cache\n");
#ifdef RPC_DEBUG
rpc_unregister_sysctl();
#endif
Expand Down
225 changes: 220 additions & 5 deletions trunk/net/sunrpc/svcauth_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,214 @@ svcauth_unix_info_release(void *info)
cache_put(&ipm->h, &ip_map_cache);
}

/****************************************************************************
* auth.unix.gid cache
* simple cache to map a UID to a list of GIDs
* because AUTH_UNIX aka AUTH_SYS has a max of 16
*/
#define GID_HASHBITS 8
#define GID_HASHMAX (1<<GID_HASHBITS)
#define GID_HASHMASK (GID_HASHMAX - 1)

struct unix_gid {
struct cache_head h;
uid_t uid;
struct group_info *gi;
};
static struct cache_head *gid_table[GID_HASHMAX];

static void unix_gid_put(struct kref *kref)
{
struct cache_head *item = container_of(kref, struct cache_head, ref);
struct unix_gid *ug = container_of(item, struct unix_gid, h);
if (test_bit(CACHE_VALID, &item->flags) &&
!test_bit(CACHE_NEGATIVE, &item->flags))
put_group_info(ug->gi);
kfree(ug);
}

static int unix_gid_match(struct cache_head *corig, struct cache_head *cnew)
{
struct unix_gid *orig = container_of(corig, struct unix_gid, h);
struct unix_gid *new = container_of(cnew, struct unix_gid, h);
return orig->uid == new->uid;
}
static void unix_gid_init(struct cache_head *cnew, struct cache_head *citem)
{
struct unix_gid *new = container_of(cnew, struct unix_gid, h);
struct unix_gid *item = container_of(citem, struct unix_gid, h);
new->uid = item->uid;
}
static void unix_gid_update(struct cache_head *cnew, struct cache_head *citem)
{
struct unix_gid *new = container_of(cnew, struct unix_gid, h);
struct unix_gid *item = container_of(citem, struct unix_gid, h);

get_group_info(item->gi);
new->gi = item->gi;
}
static struct cache_head *unix_gid_alloc(void)
{
struct unix_gid *g = kmalloc(sizeof(*g), GFP_KERNEL);
if (g)
return &g->h;
else
return NULL;
}

static void unix_gid_request(struct cache_detail *cd,
struct cache_head *h,
char **bpp, int *blen)
{
char tuid[20];
struct unix_gid *ug = container_of(h, struct unix_gid, h);

snprintf(tuid, 20, "%u", ug->uid);
qword_add(bpp, blen, tuid);
(*bpp)[-1] = '\n';
}

static struct unix_gid *unix_gid_lookup(uid_t uid);
extern struct cache_detail unix_gid_cache;

static int unix_gid_parse(struct cache_detail *cd,
char *mesg, int mlen)
{
/* uid expiry Ngid gid0 gid1 ... gidN-1 */
int uid;
int gids;
int rv;
int i;
int err;
time_t expiry;
struct unix_gid ug, *ugp;

if (mlen <= 0 || mesg[mlen-1] != '\n')
return -EINVAL;
mesg[mlen-1] = 0;

rv = get_int(&mesg, &uid);
if (rv)
return -EINVAL;
ug.uid = uid;

expiry = get_expiry(&mesg);
if (expiry == 0)
return -EINVAL;

rv = get_int(&mesg, &gids);
if (rv || gids < 0 || gids > 8192)
return -EINVAL;

ug.gi = groups_alloc(gids);
if (!ug.gi)
return -ENOMEM;

for (i = 0 ; i < gids ; i++) {
int gid;
rv = get_int(&mesg, &gid);
err = -EINVAL;
if (rv)
goto out;
GROUP_AT(ug.gi, i) = gid;
}

ugp = unix_gid_lookup(uid);
if (ugp) {
struct cache_head *ch;
ug.h.flags = 0;
ug.h.expiry_time = expiry;
ch = sunrpc_cache_update(&unix_gid_cache,
&ug.h, &ugp->h,
hash_long(uid, GID_HASHBITS));
if (!ch)
err = -ENOMEM;
else {
err = 0;
cache_put(ch, &unix_gid_cache);
}
} else
err = -ENOMEM;
out:
if (ug.gi)
put_group_info(ug.gi);
return err;
}

static int unix_gid_show(struct seq_file *m,
struct cache_detail *cd,
struct cache_head *h)
{
struct unix_gid *ug;
int i;
int glen;

if (h == NULL) {
seq_puts(m, "#uid cnt: gids...\n");
return 0;
}
ug = container_of(h, struct unix_gid, h);
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
glen = ug->gi->ngroups;
else
glen = 0;

seq_printf(m, "%d %d:", ug->uid, glen);
for (i = 0; i < glen; i++)
seq_printf(m, " %d", GROUP_AT(ug->gi, i));
seq_printf(m, "\n");
return 0;
}

struct cache_detail unix_gid_cache = {
.owner = THIS_MODULE,
.hash_size = GID_HASHMAX,
.hash_table = gid_table,
.name = "auth.unix.gid",
.cache_put = unix_gid_put,
.cache_request = unix_gid_request,
.cache_parse = unix_gid_parse,
.cache_show = unix_gid_show,
.match = unix_gid_match,
.init = unix_gid_init,
.update = unix_gid_update,
.alloc = unix_gid_alloc,
};

static struct unix_gid *unix_gid_lookup(uid_t uid)
{
struct unix_gid ug;
struct cache_head *ch;

ug.uid = uid;
ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h,
hash_long(uid, GID_HASHBITS));
if (ch)
return container_of(ch, struct unix_gid, h);
else
return NULL;
}

static int unix_gid_find(uid_t uid, struct group_info **gip,
struct svc_rqst *rqstp)
{
struct unix_gid *ug = unix_gid_lookup(uid);
if (!ug)
return -EAGAIN;
switch (cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle)) {
case -ENOENT:
*gip = NULL;
return 0;
case 0:
*gip = ug->gi;
get_group_info(*gip);
return 0;
default:
return -EAGAIN;
}
}

static int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
Expand Down Expand Up @@ -543,12 +751,19 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
slen = svc_getnl(argv); /* gids length */
if (slen > 16 || (len -= (slen + 2)*4) < 0)
goto badcred;
cred->cr_group_info = groups_alloc(slen);
if (cred->cr_group_info == NULL)
if (unix_gid_find(cred->cr_uid, &cred->cr_group_info, rqstp)
== -EAGAIN)
return SVC_DROP;
for (i = 0; i < slen; i++)
GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);

if (cred->cr_group_info == NULL) {
cred->cr_group_info = groups_alloc(slen);
if (cred->cr_group_info == NULL)
return SVC_DROP;
for (i = 0; i < slen; i++)
GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
} else {
for (i = 0; i < slen ; i++)
svc_getnl(argv);
}
if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
*authp = rpc_autherr_badverf;
return SVC_DENIED;
Expand Down

0 comments on commit bbe103d

Please sign in to comment.