11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/net/sunrpc/auth.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Generic RPC client authentication API. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/types.h> 101da177e4SLinus Torvalds #include <linux/sched.h> 111da177e4SLinus Torvalds #include <linux/module.h> 121da177e4SLinus Torvalds #include <linux/slab.h> 131da177e4SLinus Torvalds #include <linux/errno.h> 141da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 151da177e4SLinus Torvalds #include <linux/spinlock.h> 16d8558f99SJ. Bruce Fields #include <linux/smp_lock.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #ifdef RPC_DEBUG 191da177e4SLinus Torvalds # define RPCDBG_FACILITY RPCDBG_AUTH 201da177e4SLinus Torvalds #endif 211da177e4SLinus Torvalds 22fc1b356fSTrond Myklebust static DEFINE_SPINLOCK(rpc_authflavor_lock); 23f1c0a861STrond Myklebust static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { 241da177e4SLinus Torvalds &authnull_ops, /* AUTH_NULL */ 251da177e4SLinus Torvalds &authunix_ops, /* AUTH_UNIX */ 261da177e4SLinus Torvalds NULL, /* others can be loadable modules */ 271da177e4SLinus Torvalds }; 281da177e4SLinus Torvalds 29e092bdcdSTrond Myklebust static LIST_HEAD(cred_unused); 30f5c2187cSTrond Myklebust static unsigned long number_cred_unused; 31e092bdcdSTrond Myklebust 321da177e4SLinus Torvalds static u32 331da177e4SLinus Torvalds pseudoflavor_to_flavor(u32 flavor) { 341da177e4SLinus Torvalds if (flavor >= RPC_AUTH_MAXFLAVOR) 351da177e4SLinus Torvalds return RPC_AUTH_GSS; 361da177e4SLinus Torvalds return flavor; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds int 40f1c0a861STrond Myklebust rpcauth_register(const struct rpc_authops *ops) 411da177e4SLinus Torvalds { 421da177e4SLinus Torvalds rpc_authflavor_t flavor; 43fc1b356fSTrond Myklebust int ret = -EPERM; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) 461da177e4SLinus Torvalds return -EINVAL; 47fc1b356fSTrond Myklebust spin_lock(&rpc_authflavor_lock); 48fc1b356fSTrond Myklebust if (auth_flavors[flavor] == NULL) { 491da177e4SLinus Torvalds auth_flavors[flavor] = ops; 50fc1b356fSTrond Myklebust ret = 0; 51fc1b356fSTrond Myklebust } 52fc1b356fSTrond Myklebust spin_unlock(&rpc_authflavor_lock); 53fc1b356fSTrond Myklebust return ret; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds int 57f1c0a861STrond Myklebust rpcauth_unregister(const struct rpc_authops *ops) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds rpc_authflavor_t flavor; 60fc1b356fSTrond Myklebust int ret = -EPERM; 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) 631da177e4SLinus Torvalds return -EINVAL; 64fc1b356fSTrond Myklebust spin_lock(&rpc_authflavor_lock); 65fc1b356fSTrond Myklebust if (auth_flavors[flavor] == ops) { 661da177e4SLinus Torvalds auth_flavors[flavor] = NULL; 67fc1b356fSTrond Myklebust ret = 0; 68fc1b356fSTrond Myklebust } 69fc1b356fSTrond Myklebust spin_unlock(&rpc_authflavor_lock); 70fc1b356fSTrond Myklebust return ret; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds struct rpc_auth * 741da177e4SLinus Torvalds rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds struct rpc_auth *auth; 77f1c0a861STrond Myklebust const struct rpc_authops *ops; 781da177e4SLinus Torvalds u32 flavor = pseudoflavor_to_flavor(pseudoflavor); 791da177e4SLinus Torvalds 80f344f6dfSOlaf Kirch auth = ERR_PTR(-EINVAL); 81f344f6dfSOlaf Kirch if (flavor >= RPC_AUTH_MAXFLAVOR) 82f344f6dfSOlaf Kirch goto out; 83f344f6dfSOlaf Kirch 84f344f6dfSOlaf Kirch #ifdef CONFIG_KMOD 85f344f6dfSOlaf Kirch if ((ops = auth_flavors[flavor]) == NULL) 86f344f6dfSOlaf Kirch request_module("rpc-auth-%u", flavor); 87f344f6dfSOlaf Kirch #endif 88fc1b356fSTrond Myklebust spin_lock(&rpc_authflavor_lock); 89fc1b356fSTrond Myklebust ops = auth_flavors[flavor]; 90fc1b356fSTrond Myklebust if (ops == NULL || !try_module_get(ops->owner)) { 91fc1b356fSTrond Myklebust spin_unlock(&rpc_authflavor_lock); 92f344f6dfSOlaf Kirch goto out; 93fc1b356fSTrond Myklebust } 94fc1b356fSTrond Myklebust spin_unlock(&rpc_authflavor_lock); 951da177e4SLinus Torvalds auth = ops->create(clnt, pseudoflavor); 96fc1b356fSTrond Myklebust module_put(ops->owner); 976a19275aSJ. Bruce Fields if (IS_ERR(auth)) 986a19275aSJ. Bruce Fields return auth; 991da177e4SLinus Torvalds if (clnt->cl_auth) 100de7a8ce3STrond Myklebust rpcauth_release(clnt->cl_auth); 1011da177e4SLinus Torvalds clnt->cl_auth = auth; 102f344f6dfSOlaf Kirch 103f344f6dfSOlaf Kirch out: 1041da177e4SLinus Torvalds return auth; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds void 108de7a8ce3STrond Myklebust rpcauth_release(struct rpc_auth *auth) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds if (!atomic_dec_and_test(&auth->au_count)) 1111da177e4SLinus Torvalds return; 1121da177e4SLinus Torvalds auth->au_ops->destroy(auth); 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds static DEFINE_SPINLOCK(rpc_credcache_lock); 1161da177e4SLinus Torvalds 11731be5bf1STrond Myklebust static void 11831be5bf1STrond Myklebust rpcauth_unhash_cred_locked(struct rpc_cred *cred) 11931be5bf1STrond Myklebust { 12031be5bf1STrond Myklebust hlist_del_rcu(&cred->cr_hash); 12131be5bf1STrond Myklebust smp_mb__before_clear_bit(); 12231be5bf1STrond Myklebust clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); 12331be5bf1STrond Myklebust } 12431be5bf1STrond Myklebust 1259499b434STrond Myklebust static void 1269499b434STrond Myklebust rpcauth_unhash_cred(struct rpc_cred *cred) 1279499b434STrond Myklebust { 1289499b434STrond Myklebust spinlock_t *cache_lock; 1299499b434STrond Myklebust 1309499b434STrond Myklebust cache_lock = &cred->cr_auth->au_credcache->lock; 1319499b434STrond Myklebust spin_lock(cache_lock); 1329499b434STrond Myklebust if (atomic_read(&cred->cr_count) == 0) 1339499b434STrond Myklebust rpcauth_unhash_cred_locked(cred); 1349499b434STrond Myklebust spin_unlock(cache_lock); 1359499b434STrond Myklebust } 1369499b434STrond Myklebust 1371da177e4SLinus Torvalds /* 1381da177e4SLinus Torvalds * Initialize RPC credential cache 1391da177e4SLinus Torvalds */ 1401da177e4SLinus Torvalds int 141f5c2187cSTrond Myklebust rpcauth_init_credcache(struct rpc_auth *auth) 1421da177e4SLinus Torvalds { 1431da177e4SLinus Torvalds struct rpc_cred_cache *new; 1441da177e4SLinus Torvalds int i; 1451da177e4SLinus Torvalds 1468b3a7005SKris Katterjohn new = kmalloc(sizeof(*new), GFP_KERNEL); 1471da177e4SLinus Torvalds if (!new) 1481da177e4SLinus Torvalds return -ENOMEM; 1491da177e4SLinus Torvalds for (i = 0; i < RPC_CREDCACHE_NR; i++) 1501da177e4SLinus Torvalds INIT_HLIST_HEAD(&new->hashtable[i]); 1519499b434STrond Myklebust spin_lock_init(&new->lock); 1521da177e4SLinus Torvalds auth->au_credcache = new; 1531da177e4SLinus Torvalds return 0; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds /* 1571da177e4SLinus Torvalds * Destroy a list of credentials 1581da177e4SLinus Torvalds */ 1591da177e4SLinus Torvalds static inline 160e092bdcdSTrond Myklebust void rpcauth_destroy_credlist(struct list_head *head) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds struct rpc_cred *cred; 1631da177e4SLinus Torvalds 164e092bdcdSTrond Myklebust while (!list_empty(head)) { 165e092bdcdSTrond Myklebust cred = list_entry(head->next, struct rpc_cred, cr_lru); 166e092bdcdSTrond Myklebust list_del_init(&cred->cr_lru); 1671da177e4SLinus Torvalds put_rpccred(cred); 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds /* 1721da177e4SLinus Torvalds * Clear the RPC credential cache, and delete those credentials 1731da177e4SLinus Torvalds * that are not referenced. 1741da177e4SLinus Torvalds */ 1751da177e4SLinus Torvalds void 1763ab9bb72STrond Myklebust rpcauth_clear_credcache(struct rpc_cred_cache *cache) 1771da177e4SLinus Torvalds { 178e092bdcdSTrond Myklebust LIST_HEAD(free); 179e092bdcdSTrond Myklebust struct hlist_head *head; 1801da177e4SLinus Torvalds struct rpc_cred *cred; 1811da177e4SLinus Torvalds int i; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds spin_lock(&rpc_credcache_lock); 1849499b434STrond Myklebust spin_lock(&cache->lock); 1851da177e4SLinus Torvalds for (i = 0; i < RPC_CREDCACHE_NR; i++) { 186e092bdcdSTrond Myklebust head = &cache->hashtable[i]; 187e092bdcdSTrond Myklebust while (!hlist_empty(head)) { 188e092bdcdSTrond Myklebust cred = hlist_entry(head->first, struct rpc_cred, cr_hash); 189e092bdcdSTrond Myklebust get_rpccred(cred); 190f5c2187cSTrond Myklebust if (!list_empty(&cred->cr_lru)) { 191f5c2187cSTrond Myklebust list_del(&cred->cr_lru); 192f5c2187cSTrond Myklebust number_cred_unused--; 193f5c2187cSTrond Myklebust } 194f5c2187cSTrond Myklebust list_add_tail(&cred->cr_lru, &free); 19531be5bf1STrond Myklebust rpcauth_unhash_cred_locked(cred); 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds } 1989499b434STrond Myklebust spin_unlock(&cache->lock); 1991da177e4SLinus Torvalds spin_unlock(&rpc_credcache_lock); 2001da177e4SLinus Torvalds rpcauth_destroy_credlist(&free); 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2033ab9bb72STrond Myklebust /* 2043ab9bb72STrond Myklebust * Destroy the RPC credential cache 2053ab9bb72STrond Myklebust */ 2063ab9bb72STrond Myklebust void 2073ab9bb72STrond Myklebust rpcauth_destroy_credcache(struct rpc_auth *auth) 2083ab9bb72STrond Myklebust { 2093ab9bb72STrond Myklebust struct rpc_cred_cache *cache = auth->au_credcache; 2103ab9bb72STrond Myklebust 2113ab9bb72STrond Myklebust if (cache) { 2123ab9bb72STrond Myklebust auth->au_credcache = NULL; 2133ab9bb72STrond Myklebust rpcauth_clear_credcache(cache); 2143ab9bb72STrond Myklebust kfree(cache); 2153ab9bb72STrond Myklebust } 2163ab9bb72STrond Myklebust } 2173ab9bb72STrond Myklebust 2181da177e4SLinus Torvalds /* 2191da177e4SLinus Torvalds * Remove stale credentials. Avoid sleeping inside the loop. 2201da177e4SLinus Torvalds */ 221f5c2187cSTrond Myklebust static int 222f5c2187cSTrond Myklebust rpcauth_prune_expired(struct list_head *free, int nr_to_scan) 2231da177e4SLinus Torvalds { 2249499b434STrond Myklebust spinlock_t *cache_lock; 2251da177e4SLinus Torvalds struct rpc_cred *cred; 2261da177e4SLinus Torvalds 227e092bdcdSTrond Myklebust while (!list_empty(&cred_unused)) { 228e092bdcdSTrond Myklebust cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru); 229e092bdcdSTrond Myklebust list_del_init(&cred->cr_lru); 230f5c2187cSTrond Myklebust number_cred_unused--; 231e092bdcdSTrond Myklebust if (atomic_read(&cred->cr_count) != 0) 232e092bdcdSTrond Myklebust continue; 2339499b434STrond Myklebust cache_lock = &cred->cr_auth->au_credcache->lock; 2349499b434STrond Myklebust spin_lock(cache_lock); 2359499b434STrond Myklebust if (atomic_read(&cred->cr_count) == 0) { 236e092bdcdSTrond Myklebust get_rpccred(cred); 237e092bdcdSTrond Myklebust list_add_tail(&cred->cr_lru, free); 23831be5bf1STrond Myklebust rpcauth_unhash_cred_locked(cred); 239f5c2187cSTrond Myklebust nr_to_scan--; 2401da177e4SLinus Torvalds } 2419499b434STrond Myklebust spin_unlock(cache_lock); 242f5c2187cSTrond Myklebust if (nr_to_scan == 0) 243f5c2187cSTrond Myklebust break; 2449499b434STrond Myklebust } 245f5c2187cSTrond Myklebust return nr_to_scan; 2461da177e4SLinus Torvalds } 247e092bdcdSTrond Myklebust 248e092bdcdSTrond Myklebust /* 249f5c2187cSTrond Myklebust * Run memory cache shrinker. 250e092bdcdSTrond Myklebust */ 251f5c2187cSTrond Myklebust static int 252f5c2187cSTrond Myklebust rpcauth_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) 253e092bdcdSTrond Myklebust { 254f5c2187cSTrond Myklebust LIST_HEAD(free); 255f5c2187cSTrond Myklebust int res; 256f5c2187cSTrond Myklebust 257f5c2187cSTrond Myklebust if (list_empty(&cred_unused)) 258f5c2187cSTrond Myklebust return 0; 25931be5bf1STrond Myklebust spin_lock(&rpc_credcache_lock); 260f5c2187cSTrond Myklebust nr_to_scan = rpcauth_prune_expired(&free, nr_to_scan); 261f5c2187cSTrond Myklebust res = (number_cred_unused / 100) * sysctl_vfs_cache_pressure; 26231be5bf1STrond Myklebust spin_unlock(&rpc_credcache_lock); 263f5c2187cSTrond Myklebust rpcauth_destroy_credlist(&free); 264f5c2187cSTrond Myklebust return res; 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds /* 2681da177e4SLinus Torvalds * Look up a process' credentials in the authentication cache 2691da177e4SLinus Torvalds */ 2701da177e4SLinus Torvalds struct rpc_cred * 2711da177e4SLinus Torvalds rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, 2728a317760STrond Myklebust int flags) 2731da177e4SLinus Torvalds { 274e092bdcdSTrond Myklebust LIST_HEAD(free); 2751da177e4SLinus Torvalds struct rpc_cred_cache *cache = auth->au_credcache; 276e092bdcdSTrond Myklebust struct hlist_node *pos; 27731be5bf1STrond Myklebust struct rpc_cred *cred = NULL, 27831be5bf1STrond Myklebust *entry, *new; 2791da177e4SLinus Torvalds int nr = 0; 2801da177e4SLinus Torvalds 2818a317760STrond Myklebust if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) 2821da177e4SLinus Torvalds nr = acred->uid & RPC_CREDCACHE_MASK; 28331be5bf1STrond Myklebust 28431be5bf1STrond Myklebust rcu_read_lock(); 28531be5bf1STrond Myklebust hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { 28631be5bf1STrond Myklebust if (!entry->cr_ops->crmatch(acred, entry, flags)) 28731be5bf1STrond Myklebust continue; 2889499b434STrond Myklebust spin_lock(&cache->lock); 28931be5bf1STrond Myklebust if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { 2909499b434STrond Myklebust spin_unlock(&cache->lock); 29131be5bf1STrond Myklebust continue; 29231be5bf1STrond Myklebust } 29331be5bf1STrond Myklebust cred = get_rpccred(entry); 2949499b434STrond Myklebust spin_unlock(&cache->lock); 29531be5bf1STrond Myklebust break; 29631be5bf1STrond Myklebust } 29731be5bf1STrond Myklebust rcu_read_unlock(); 29831be5bf1STrond Myklebust 2999499b434STrond Myklebust if (cred != NULL) 30031be5bf1STrond Myklebust goto found; 30131be5bf1STrond Myklebust 30231be5bf1STrond Myklebust new = auth->au_ops->crcreate(auth, acred, flags); 30331be5bf1STrond Myklebust if (IS_ERR(new)) { 30431be5bf1STrond Myklebust cred = new; 30531be5bf1STrond Myklebust goto out; 30631be5bf1STrond Myklebust } 30731be5bf1STrond Myklebust 3089499b434STrond Myklebust spin_lock(&cache->lock); 309e092bdcdSTrond Myklebust hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { 310e092bdcdSTrond Myklebust if (!entry->cr_ops->crmatch(acred, entry, flags)) 311e092bdcdSTrond Myklebust continue; 312e092bdcdSTrond Myklebust cred = get_rpccred(entry); 3131da177e4SLinus Torvalds break; 3141da177e4SLinus Torvalds } 31531be5bf1STrond Myklebust if (cred == NULL) { 31631be5bf1STrond Myklebust cred = new; 31731be5bf1STrond Myklebust set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); 31831be5bf1STrond Myklebust hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]); 31931be5bf1STrond Myklebust } else 320e092bdcdSTrond Myklebust list_add_tail(&new->cr_lru, &free); 3219499b434STrond Myklebust spin_unlock(&cache->lock); 32231be5bf1STrond Myklebust found: 32331be5bf1STrond Myklebust if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) 324fba3bad4STrond Myklebust && cred->cr_ops->cr_init != NULL 325fba3bad4STrond Myklebust && !(flags & RPCAUTH_LOOKUP_NEW)) { 326fba3bad4STrond Myklebust int res = cred->cr_ops->cr_init(auth, cred); 327fba3bad4STrond Myklebust if (res < 0) { 328fba3bad4STrond Myklebust put_rpccred(cred); 329fba3bad4STrond Myklebust cred = ERR_PTR(res); 330fba3bad4STrond Myklebust } 3311da177e4SLinus Torvalds } 33231be5bf1STrond Myklebust rpcauth_destroy_credlist(&free); 33331be5bf1STrond Myklebust out: 33431be5bf1STrond Myklebust return cred; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds struct rpc_cred * 3388a317760STrond Myklebust rpcauth_lookupcred(struct rpc_auth *auth, int flags) 3391da177e4SLinus Torvalds { 3401da177e4SLinus Torvalds struct auth_cred acred = { 3411da177e4SLinus Torvalds .uid = current->fsuid, 3421da177e4SLinus Torvalds .gid = current->fsgid, 3431da177e4SLinus Torvalds .group_info = current->group_info, 3441da177e4SLinus Torvalds }; 3451da177e4SLinus Torvalds struct rpc_cred *ret; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds dprintk("RPC: looking up %s cred\n", 3481da177e4SLinus Torvalds auth->au_ops->au_name); 3491da177e4SLinus Torvalds get_group_info(acred.group_info); 3508a317760STrond Myklebust ret = auth->au_ops->lookup_cred(auth, &acred, flags); 3511da177e4SLinus Torvalds put_group_info(acred.group_info); 3521da177e4SLinus Torvalds return ret; 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 3555fe4755eSTrond Myklebust void 3565fe4755eSTrond Myklebust rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, 3575fe4755eSTrond Myklebust struct rpc_auth *auth, const struct rpc_credops *ops) 3585fe4755eSTrond Myklebust { 3595fe4755eSTrond Myklebust INIT_HLIST_NODE(&cred->cr_hash); 360e092bdcdSTrond Myklebust INIT_LIST_HEAD(&cred->cr_lru); 3615fe4755eSTrond Myklebust atomic_set(&cred->cr_count, 1); 3625fe4755eSTrond Myklebust cred->cr_auth = auth; 3635fe4755eSTrond Myklebust cred->cr_ops = ops; 3645fe4755eSTrond Myklebust cred->cr_expire = jiffies; 3655fe4755eSTrond Myklebust #ifdef RPC_DEBUG 3665fe4755eSTrond Myklebust cred->cr_magic = RPCAUTH_CRED_MAGIC; 3675fe4755eSTrond Myklebust #endif 3685fe4755eSTrond Myklebust cred->cr_uid = acred->uid; 3695fe4755eSTrond Myklebust } 3705fe4755eSTrond Myklebust EXPORT_SYMBOL(rpcauth_init_cred); 3715fe4755eSTrond Myklebust 3721da177e4SLinus Torvalds struct rpc_cred * 3731da177e4SLinus Torvalds rpcauth_bindcred(struct rpc_task *task) 3741da177e4SLinus Torvalds { 3751be27f36STrond Myklebust struct rpc_auth *auth = task->tk_client->cl_auth; 3761da177e4SLinus Torvalds struct auth_cred acred = { 3771da177e4SLinus Torvalds .uid = current->fsuid, 3781da177e4SLinus Torvalds .gid = current->fsgid, 3791da177e4SLinus Torvalds .group_info = current->group_info, 3801da177e4SLinus Torvalds }; 3811da177e4SLinus Torvalds struct rpc_cred *ret; 3828a317760STrond Myklebust int flags = 0; 3831da177e4SLinus Torvalds 38446121cf7SChuck Lever dprintk("RPC: %5u looking up %s cred\n", 3851be27f36STrond Myklebust task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); 3861da177e4SLinus Torvalds get_group_info(acred.group_info); 3878a317760STrond Myklebust if (task->tk_flags & RPC_TASK_ROOTCREDS) 3888a317760STrond Myklebust flags |= RPCAUTH_LOOKUP_ROOTCREDS; 3898a317760STrond Myklebust ret = auth->au_ops->lookup_cred(auth, &acred, flags); 3901da177e4SLinus Torvalds if (!IS_ERR(ret)) 3911da177e4SLinus Torvalds task->tk_msg.rpc_cred = ret; 3921da177e4SLinus Torvalds else 3931da177e4SLinus Torvalds task->tk_status = PTR_ERR(ret); 3941da177e4SLinus Torvalds put_group_info(acred.group_info); 3951da177e4SLinus Torvalds return ret; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds void 3991da177e4SLinus Torvalds rpcauth_holdcred(struct rpc_task *task) 4001da177e4SLinus Torvalds { 4011be27f36STrond Myklebust struct rpc_cred *cred = task->tk_msg.rpc_cred; 4021be27f36STrond Myklebust if (cred != NULL) { 4031be27f36STrond Myklebust get_rpccred(cred); 4041be27f36STrond Myklebust dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, 4051be27f36STrond Myklebust cred->cr_auth->au_ops->au_name, cred); 4061be27f36STrond Myklebust } 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds void 4101da177e4SLinus Torvalds put_rpccred(struct rpc_cred *cred) 4111da177e4SLinus Torvalds { 412e092bdcdSTrond Myklebust /* Fast path for unhashed credentials */ 41331be5bf1STrond Myklebust if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) 414e092bdcdSTrond Myklebust goto need_lock; 415e092bdcdSTrond Myklebust 4161da177e4SLinus Torvalds if (!atomic_dec_and_test(&cred->cr_count)) 4171da177e4SLinus Torvalds return; 418e092bdcdSTrond Myklebust goto out_destroy; 419e092bdcdSTrond Myklebust need_lock: 420e092bdcdSTrond Myklebust if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) 421e092bdcdSTrond Myklebust return; 422f5c2187cSTrond Myklebust if (!list_empty(&cred->cr_lru)) { 423f5c2187cSTrond Myklebust number_cred_unused--; 424e092bdcdSTrond Myklebust list_del_init(&cred->cr_lru); 425f5c2187cSTrond Myklebust } 426e092bdcdSTrond Myklebust if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) 4279499b434STrond Myklebust rpcauth_unhash_cred(cred); 42831be5bf1STrond Myklebust else if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) { 429e092bdcdSTrond Myklebust cred->cr_expire = jiffies; 430e092bdcdSTrond Myklebust list_add_tail(&cred->cr_lru, &cred_unused); 431f5c2187cSTrond Myklebust number_cred_unused++; 432e092bdcdSTrond Myklebust spin_unlock(&rpc_credcache_lock); 433e092bdcdSTrond Myklebust return; 434e092bdcdSTrond Myklebust } 435e092bdcdSTrond Myklebust spin_unlock(&rpc_credcache_lock); 436e092bdcdSTrond Myklebust out_destroy: 4371da177e4SLinus Torvalds cred->cr_ops->crdestroy(cred); 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds void 4411da177e4SLinus Torvalds rpcauth_unbindcred(struct rpc_task *task) 4421da177e4SLinus Torvalds { 4431da177e4SLinus Torvalds struct rpc_cred *cred = task->tk_msg.rpc_cred; 4441da177e4SLinus Torvalds 44546121cf7SChuck Lever dprintk("RPC: %5u releasing %s cred %p\n", 4461be27f36STrond Myklebust task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds put_rpccred(cred); 4491da177e4SLinus Torvalds task->tk_msg.rpc_cred = NULL; 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds 452d8ed029dSAlexey Dobriyan __be32 * 453d8ed029dSAlexey Dobriyan rpcauth_marshcred(struct rpc_task *task, __be32 *p) 4541da177e4SLinus Torvalds { 4551da177e4SLinus Torvalds struct rpc_cred *cred = task->tk_msg.rpc_cred; 4561da177e4SLinus Torvalds 45746121cf7SChuck Lever dprintk("RPC: %5u marshaling %s cred %p\n", 4581be27f36STrond Myklebust task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 4590bbacc40SChuck Lever 4601da177e4SLinus Torvalds return cred->cr_ops->crmarshal(task, p); 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds 463d8ed029dSAlexey Dobriyan __be32 * 464d8ed029dSAlexey Dobriyan rpcauth_checkverf(struct rpc_task *task, __be32 *p) 4651da177e4SLinus Torvalds { 4661da177e4SLinus Torvalds struct rpc_cred *cred = task->tk_msg.rpc_cred; 4671da177e4SLinus Torvalds 46846121cf7SChuck Lever dprintk("RPC: %5u validating %s cred %p\n", 4691be27f36STrond Myklebust task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 4700bbacc40SChuck Lever 4711da177e4SLinus Torvalds return cred->cr_ops->crvalidate(task, p); 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds int 4751da177e4SLinus Torvalds rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, 476d8ed029dSAlexey Dobriyan __be32 *data, void *obj) 4771da177e4SLinus Torvalds { 4781da177e4SLinus Torvalds struct rpc_cred *cred = task->tk_msg.rpc_cred; 479d8558f99SJ. Bruce Fields int ret; 4801da177e4SLinus Torvalds 48146121cf7SChuck Lever dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", 4821da177e4SLinus Torvalds task->tk_pid, cred->cr_ops->cr_name, cred); 4831da177e4SLinus Torvalds if (cred->cr_ops->crwrap_req) 4841da177e4SLinus Torvalds return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); 4851da177e4SLinus Torvalds /* By default, we encode the arguments normally. */ 486d8558f99SJ. Bruce Fields lock_kernel(); 487d8558f99SJ. Bruce Fields ret = encode(rqstp, data, obj); 488d8558f99SJ. Bruce Fields unlock_kernel(); 489d8558f99SJ. Bruce Fields return ret; 4901da177e4SLinus Torvalds } 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds int 4931da177e4SLinus Torvalds rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, 494d8ed029dSAlexey Dobriyan __be32 *data, void *obj) 4951da177e4SLinus Torvalds { 4961da177e4SLinus Torvalds struct rpc_cred *cred = task->tk_msg.rpc_cred; 497d8558f99SJ. Bruce Fields int ret; 4981da177e4SLinus Torvalds 49946121cf7SChuck Lever dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", 5001da177e4SLinus Torvalds task->tk_pid, cred->cr_ops->cr_name, cred); 5011da177e4SLinus Torvalds if (cred->cr_ops->crunwrap_resp) 5021da177e4SLinus Torvalds return cred->cr_ops->crunwrap_resp(task, decode, rqstp, 5031da177e4SLinus Torvalds data, obj); 5041da177e4SLinus Torvalds /* By default, we decode the arguments normally. */ 505d8558f99SJ. Bruce Fields lock_kernel(); 506d8558f99SJ. Bruce Fields ret = decode(rqstp, data, obj); 507d8558f99SJ. Bruce Fields unlock_kernel(); 508d8558f99SJ. Bruce Fields return ret; 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds int 5121da177e4SLinus Torvalds rpcauth_refreshcred(struct rpc_task *task) 5131da177e4SLinus Torvalds { 5141da177e4SLinus Torvalds struct rpc_cred *cred = task->tk_msg.rpc_cred; 5151da177e4SLinus Torvalds int err; 5161da177e4SLinus Torvalds 51746121cf7SChuck Lever dprintk("RPC: %5u refreshing %s cred %p\n", 5181be27f36STrond Myklebust task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 5190bbacc40SChuck Lever 5201da177e4SLinus Torvalds err = cred->cr_ops->crrefresh(task); 5211da177e4SLinus Torvalds if (err < 0) 5221da177e4SLinus Torvalds task->tk_status = err; 5231da177e4SLinus Torvalds return err; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds void 5271da177e4SLinus Torvalds rpcauth_invalcred(struct rpc_task *task) 5281da177e4SLinus Torvalds { 529fc432dd9STrond Myklebust struct rpc_cred *cred = task->tk_msg.rpc_cred; 530fc432dd9STrond Myklebust 53146121cf7SChuck Lever dprintk("RPC: %5u invalidating %s cred %p\n", 5321be27f36STrond Myklebust task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 533fc432dd9STrond Myklebust if (cred) 534fc432dd9STrond Myklebust clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds int 5381da177e4SLinus Torvalds rpcauth_uptodatecred(struct rpc_task *task) 5391da177e4SLinus Torvalds { 540fc432dd9STrond Myklebust struct rpc_cred *cred = task->tk_msg.rpc_cred; 541fc432dd9STrond Myklebust 542fc432dd9STrond Myklebust return cred == NULL || 543fc432dd9STrond Myklebust test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; 5441da177e4SLinus Torvalds } 545f5c2187cSTrond Myklebust 5468e1f936bSRusty Russell static struct shrinker rpc_cred_shrinker = { 5478e1f936bSRusty Russell .shrink = rpcauth_cache_shrinker, 5488e1f936bSRusty Russell .seeks = DEFAULT_SEEKS, 5498e1f936bSRusty Russell }; 550f5c2187cSTrond Myklebust 551f5c2187cSTrond Myklebust void __init rpcauth_init_module(void) 552f5c2187cSTrond Myklebust { 553f5c2187cSTrond Myklebust rpc_init_authunix(); 5548e1f936bSRusty Russell register_shrinker(&rpc_cred_shrinker); 555f5c2187cSTrond Myklebust } 556f5c2187cSTrond Myklebust 557f5c2187cSTrond Myklebust void __exit rpcauth_remove_module(void) 558f5c2187cSTrond Myklebust { 5598e1f936bSRusty Russell unregister_shrinker(&rpc_cred_shrinker); 560f5c2187cSTrond Myklebust } 561