diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /net/sunrpc/auth.c | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'net/sunrpc/auth.c')
-rw-r--r-- | net/sunrpc/auth.c | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c new file mode 100644 index 000000000..2ac1f7b7f --- /dev/null +++ b/net/sunrpc/auth.c @@ -0,0 +1,295 @@ +/* + * linux/fs/nfs/rpcauth.c + * + * Generic RPC authentication API. + * + * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/errno.h> +#include <linux/socket.h> +#include <linux/sunrpc/clnt.h> + +#ifdef RPC_DEBUG +# define RPCDBG_FACILITY RPCDBG_AUTH +#endif + +#define RPC_MAXFLAVOR 8 + +static struct rpc_authops * auth_flavors[RPC_MAXFLAVOR] = { + &authnull_ops, /* AUTH_NULL */ + &authunix_ops, /* AUTH_UNIX */ + NULL, /* others can be loadable modules */ +}; + +int +rpcauth_register(struct rpc_authops *ops) +{ + unsigned int flavor; + + if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR) + return -EINVAL; + if (auth_flavors[flavor] != NULL) + return -EPERM; /* what else? */ + auth_flavors[flavor] = ops; + return 0; +} + +int +rpcauth_unregister(struct rpc_authops *ops) +{ + unsigned int flavor; + + if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR) + return -EINVAL; + if (auth_flavors[flavor] != ops) + return -EPERM; /* what else? */ + auth_flavors[flavor] = NULL; + return 0; +} + +struct rpc_auth * +rpcauth_create(unsigned int flavor, struct rpc_clnt *clnt) +{ + struct rpc_authops *ops; + + if (flavor >= RPC_MAXFLAVOR || !(ops = auth_flavors[flavor])) + return NULL; + clnt->cl_auth = ops->create(clnt); + return clnt->cl_auth; +} + +void +rpcauth_destroy(struct rpc_auth *auth) +{ + auth->au_ops->destroy(auth); +} + +/* + * Initialize RPC credential cache + */ +void +rpcauth_init_credcache(struct rpc_auth *auth) +{ + memset(auth->au_credcache, 0, sizeof(auth->au_credcache)); + auth->au_nextgc = jiffies + (auth->au_expire >> 1); +} + +/* + * Clear the RPC credential cache + */ +void +rpcauth_free_credcache(struct rpc_auth *auth) +{ + struct rpc_cred **q, *cred; + void (*destroy)(struct rpc_cred *); + int i; + + if (!(destroy = auth->au_ops->crdestroy)) + destroy = (void (*)(struct rpc_cred *)) rpc_free; + + for (i = 0; i < RPC_CREDCACHE_NR; i++) { + q = &auth->au_credcache[i]; + while ((cred = *q) != NULL) { + *q = cred->cr_next; + destroy(cred); + } + } +} + +/* + * Remove stale credentials. Avoid sleeping inside the loop. + */ +static void +rpcauth_gc_credcache(struct rpc_auth *auth) +{ + struct rpc_cred **q, *cred, *free = NULL; + int i, safe = 0; + + dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); + for (i = 0; i < RPC_CREDCACHE_NR; i++) { + q = &auth->au_credcache[i]; + while ((cred = *q) != NULL) { + if (++safe > 500) { + printk("RPC: rpcauth_gc_credcache looping!\n"); + break; + } + if (!cred->cr_count && cred->cr_expire < jiffies) { + *q = cred->cr_next; + cred->cr_next = free; + free = cred; + continue; + } + q = &cred->cr_next; + } + } + while ((cred = free) != NULL) { + free = cred->cr_next; + rpc_free(cred); + } + auth->au_nextgc = jiffies + auth->au_expire; +} + +/* + * Insert credential into cache + */ +inline void +rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred) +{ + int nr; + + nr = (cred->cr_uid % RPC_CREDCACHE_NR); + cred->cr_next = auth->au_credcache[nr]; + auth->au_credcache[nr] = cred; + cred->cr_expire = jiffies + auth->au_expire; + cred->cr_count++; +} + +/* + * Look up a process' credentials in the authentication cache + */ +static struct rpc_cred * +rpcauth_lookup_credcache(struct rpc_task *task) +{ + struct rpc_auth *auth = task->tk_auth; + struct rpc_cred **q, *cred = NULL; + int nr; + + nr = RPC_DO_ROOTOVERRIDE(task)? 0 : (current->uid % RPC_CREDCACHE_NR); + + if (auth->au_nextgc < jiffies) + rpcauth_gc_credcache(auth); + + q = &auth->au_credcache[nr]; + while ((cred = *q) != NULL) { + if (auth->au_ops->crmatch(task, cred)) { + *q = cred->cr_next; + break; + } + q = &cred->cr_next; + } + + if (!cred) + cred = auth->au_ops->crcreate(task); + + rpcauth_insert_credcache(auth, cred); + + return (struct rpc_cred *) cred; +} + +/* + * Remove cred handle from cache + */ +static inline void +rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred) +{ + struct rpc_cred **q, *cr; + int nr; + + nr = (cred->cr_uid % RPC_CREDCACHE_NR); + q = &auth->au_credcache[nr]; + while ((cr = *q) != NULL) { + if (cred == cr) { + *q = cred->cr_next; + return; + } + q = &cred->cr_next; + } +} + +struct rpc_cred * +rpcauth_lookupcred(struct rpc_task *task) +{ + dprintk("RPC: %4d looking up %s cred\n", + task->tk_pid, task->tk_auth->au_ops->au_name); + return task->tk_cred = rpcauth_lookup_credcache(task); +} + +int +rpcauth_matchcred(struct rpc_task *task, struct rpc_cred *cred) +{ + struct rpc_auth *auth = task->tk_auth; + + dprintk("RPC: %4d matching %s cred %p\n", + task->tk_pid, auth->au_ops->au_name, task->tk_cred); + return auth->au_ops->crmatch(task, cred); +} + +void +rpcauth_holdcred(struct rpc_task *task) +{ + dprintk("RPC: %4d holding %s cred %p\n", + task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred); + if (task->tk_cred) + task->tk_cred->cr_count++; +} + +void +rpcauth_releasecred(struct rpc_task *task) +{ + struct rpc_auth *auth = task->tk_auth; + struct rpc_cred *cred; + + dprintk("RPC: %4d releasing %s cred %p\n", + task->tk_pid, auth->au_ops->au_name, task->tk_cred); + if ((cred = task->tk_cred) != NULL) { + cred->cr_count--; + if (cred->cr_flags & RPCAUTH_CRED_DEAD) { + rpcauth_remove_credcache(auth, cred); + if (!cred->cr_count) + auth->au_ops->crdestroy(cred); + } + task->tk_cred = NULL; + } +} + +u32 * +rpcauth_marshcred(struct rpc_task *task, u32 *p) +{ + struct rpc_auth *auth = task->tk_auth; + + dprintk("RPC: %4d marshaling %s cred %p\n", + task->tk_pid, auth->au_ops->au_name, task->tk_cred); + return auth->au_ops->crmarshal(task, p, + task->tk_flags & RPC_CALL_REALUID); +} + +u32 * +rpcauth_checkverf(struct rpc_task *task, u32 *p) +{ + struct rpc_auth *auth = task->tk_auth; + + dprintk("RPC: %4d validating %s cred %p\n", + task->tk_pid, auth->au_ops->au_name, task->tk_cred); + return auth->au_ops->crvalidate(task, p); +} + +int +rpcauth_refreshcred(struct rpc_task *task) +{ + struct rpc_auth *auth = task->tk_auth; + + dprintk("RPC: %4d refreshing %s cred %p\n", + task->tk_pid, auth->au_ops->au_name, task->tk_cred); + task->tk_status = auth->au_ops->crrefresh(task); + return task->tk_status; +} + +void +rpcauth_invalcred(struct rpc_task *task) +{ + dprintk("RPC: %4d invalidating %s cred %p\n", + task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred); + if (task->tk_cred) + task->tk_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; +} + +int +rpcauth_uptodatecred(struct rpc_task *task) +{ + return !(task->tk_cred) || + (task->tk_cred->cr_flags & RPCAUTH_CRED_UPTODATE); +} |