Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
auth.c
Go to the documentation of this file.
1 /*
2  * linux/net/sunrpc/auth.c
3  *
4  * Generic RPC client authentication API.
5  *
6  * Copyright (C) 1996, Olaf Kirch <[email protected]>
7  */
8 
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/errno.h>
14 #include <linux/hash.h>
15 #include <linux/sunrpc/clnt.h>
16 #include <linux/sunrpc/gss_api.h>
17 #include <linux/spinlock.h>
18 
19 #ifdef RPC_DEBUG
20 # define RPCDBG_FACILITY RPCDBG_AUTH
21 #endif
22 
23 #define RPC_CREDCACHE_DEFAULT_HASHBITS (4)
26  unsigned int hashbits;
28 };
29 
30 static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS;
31 
32 static DEFINE_SPINLOCK(rpc_authflavor_lock);
33 static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
34  &authnull_ops, /* AUTH_NULL */
35  &authunix_ops, /* AUTH_UNIX */
36  NULL, /* others can be loadable modules */
37 };
38 
39 static LIST_HEAD(cred_unused);
40 static unsigned long number_cred_unused;
41 
42 #define MAX_HASHTABLE_BITS (14)
43 static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp)
44 {
45  unsigned long num;
46  unsigned int nbits;
47  int ret;
48 
49  if (!val)
50  goto out_inval;
51  ret = strict_strtoul(val, 0, &num);
52  if (ret == -EINVAL)
53  goto out_inval;
54  nbits = fls(num);
55  if (num > (1U << nbits))
56  nbits++;
57  if (nbits > MAX_HASHTABLE_BITS || nbits < 2)
58  goto out_inval;
59  *(unsigned int *)kp->arg = nbits;
60  return 0;
61 out_inval:
62  return -EINVAL;
63 }
64 
65 static int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp)
66 {
67  unsigned int nbits;
68 
69  nbits = *(unsigned int *)kp->arg;
70  return sprintf(buffer, "%u", 1U << nbits);
71 }
72 
73 #define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);
74 
75 static struct kernel_param_ops param_ops_hashtbl_sz = {
76  .set = param_set_hashtbl_sz,
77  .get = param_get_hashtbl_sz,
78 };
79 
80 module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644);
81 MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
82 
83 static u32
84 pseudoflavor_to_flavor(u32 flavor) {
85  if (flavor >= RPC_AUTH_MAXFLAVOR)
86  return RPC_AUTH_GSS;
87  return flavor;
88 }
89 
90 int
91 rpcauth_register(const struct rpc_authops *ops)
92 {
93  rpc_authflavor_t flavor;
94  int ret = -EPERM;
95 
96  if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
97  return -EINVAL;
98  spin_lock(&rpc_authflavor_lock);
99  if (auth_flavors[flavor] == NULL) {
100  auth_flavors[flavor] = ops;
101  ret = 0;
102  }
103  spin_unlock(&rpc_authflavor_lock);
104  return ret;
105 }
107 
108 int
109 rpcauth_unregister(const struct rpc_authops *ops)
110 {
111  rpc_authflavor_t flavor;
112  int ret = -EPERM;
113 
114  if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
115  return -EINVAL;
116  spin_lock(&rpc_authflavor_lock);
117  if (auth_flavors[flavor] == ops) {
118  auth_flavors[flavor] = NULL;
119  ret = 0;
120  }
121  spin_unlock(&rpc_authflavor_lock);
122  return ret;
123 }
125 
136 int
137 rpcauth_list_flavors(rpc_authflavor_t *array, int size)
138 {
139  rpc_authflavor_t flavor;
140  int result = 0;
141 
142  spin_lock(&rpc_authflavor_lock);
143  for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) {
144  const struct rpc_authops *ops = auth_flavors[flavor];
145  rpc_authflavor_t pseudos[4];
146  int i, len;
147 
148  if (result >= size) {
149  result = -ENOMEM;
150  break;
151  }
152 
153  if (ops == NULL)
154  continue;
155  if (ops->list_pseudoflavors == NULL) {
156  array[result++] = ops->au_flavor;
157  continue;
158  }
159  len = ops->list_pseudoflavors(pseudos, ARRAY_SIZE(pseudos));
160  if (len < 0) {
161  result = len;
162  break;
163  }
164  for (i = 0; i < len; i++) {
165  if (result >= size) {
166  result = -ENOMEM;
167  break;
168  }
169  array[result++] = pseudos[i];
170  }
171  }
172  spin_unlock(&rpc_authflavor_lock);
173 
174  dprintk("RPC: %s returns %d\n", __func__, result);
175  return result;
176 }
178 
179 struct rpc_auth *
180 rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
181 {
182  struct rpc_auth *auth;
183  const struct rpc_authops *ops;
184  u32 flavor = pseudoflavor_to_flavor(pseudoflavor);
185 
186  auth = ERR_PTR(-EINVAL);
187  if (flavor >= RPC_AUTH_MAXFLAVOR)
188  goto out;
189 
190  if ((ops = auth_flavors[flavor]) == NULL)
191  request_module("rpc-auth-%u", flavor);
192  spin_lock(&rpc_authflavor_lock);
193  ops = auth_flavors[flavor];
194  if (ops == NULL || !try_module_get(ops->owner)) {
195  spin_unlock(&rpc_authflavor_lock);
196  goto out;
197  }
198  spin_unlock(&rpc_authflavor_lock);
199  auth = ops->create(clnt, pseudoflavor);
200  module_put(ops->owner);
201  if (IS_ERR(auth))
202  return auth;
203  if (clnt->cl_auth)
204  rpcauth_release(clnt->cl_auth);
205  clnt->cl_auth = auth;
206 
207 out:
208  return auth;
209 }
211 
212 void
213 rpcauth_release(struct rpc_auth *auth)
214 {
215  if (!atomic_dec_and_test(&auth->au_count))
216  return;
217  auth->au_ops->destroy(auth);
218 }
219 
220 static DEFINE_SPINLOCK(rpc_credcache_lock);
221 
222 static void
223 rpcauth_unhash_cred_locked(struct rpc_cred *cred)
224 {
225  hlist_del_rcu(&cred->cr_hash);
227  clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
228 }
229 
230 static int
231 rpcauth_unhash_cred(struct rpc_cred *cred)
232 {
233  spinlock_t *cache_lock;
234  int ret;
235 
236  cache_lock = &cred->cr_auth->au_credcache->lock;
237  spin_lock(cache_lock);
238  ret = atomic_read(&cred->cr_count) == 0;
239  if (ret)
240  rpcauth_unhash_cred_locked(cred);
241  spin_unlock(cache_lock);
242  return ret;
243 }
244 
245 /*
246  * Initialize RPC credential cache
247  */
248 int
249 rpcauth_init_credcache(struct rpc_auth *auth)
250 {
251  struct rpc_cred_cache *new;
252  unsigned int hashsize;
253 
254  new = kmalloc(sizeof(*new), GFP_KERNEL);
255  if (!new)
256  goto out_nocache;
257  new->hashbits = auth_hashbits;
258  hashsize = 1U << new->hashbits;
259  new->hashtable = kcalloc(hashsize, sizeof(new->hashtable[0]), GFP_KERNEL);
260  if (!new->hashtable)
261  goto out_nohashtbl;
262  spin_lock_init(&new->lock);
263  auth->au_credcache = new;
264  return 0;
265 out_nohashtbl:
266  kfree(new);
267 out_nocache:
268  return -ENOMEM;
269 }
271 
272 /*
273  * Destroy a list of credentials
274  */
275 static inline
276 void rpcauth_destroy_credlist(struct list_head *head)
277 {
278  struct rpc_cred *cred;
279 
280  while (!list_empty(head)) {
281  cred = list_entry(head->next, struct rpc_cred, cr_lru);
282  list_del_init(&cred->cr_lru);
283  put_rpccred(cred);
284  }
285 }
286 
287 /*
288  * Clear the RPC credential cache, and delete those credentials
289  * that are not referenced.
290  */
291 void
293 {
294  LIST_HEAD(free);
295  struct hlist_head *head;
296  struct rpc_cred *cred;
297  unsigned int hashsize = 1U << cache->hashbits;
298  int i;
299 
300  spin_lock(&rpc_credcache_lock);
301  spin_lock(&cache->lock);
302  for (i = 0; i < hashsize; i++) {
303  head = &cache->hashtable[i];
304  while (!hlist_empty(head)) {
305  cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
306  get_rpccred(cred);
307  if (!list_empty(&cred->cr_lru)) {
308  list_del(&cred->cr_lru);
309  number_cred_unused--;
310  }
311  list_add_tail(&cred->cr_lru, &free);
312  rpcauth_unhash_cred_locked(cred);
313  }
314  }
315  spin_unlock(&cache->lock);
316  spin_unlock(&rpc_credcache_lock);
317  rpcauth_destroy_credlist(&free);
318 }
319 
320 /*
321  * Destroy the RPC credential cache
322  */
323 void
325 {
326  struct rpc_cred_cache *cache = auth->au_credcache;
327 
328  if (cache) {
329  auth->au_credcache = NULL;
331  kfree(cache->hashtable);
332  kfree(cache);
333  }
334 }
336 
337 
338 #define RPC_AUTH_EXPIRY_MORATORIUM (60 * HZ)
339 
340 /*
341  * Remove stale credentials. Avoid sleeping inside the loop.
342  */
343 static int
344 rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
345 {
346  spinlock_t *cache_lock;
347  struct rpc_cred *cred, *next;
348  unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM;
349 
350  list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) {
351 
352  if (nr_to_scan-- == 0)
353  break;
354  /*
355  * Enforce a 60 second garbage collection moratorium
356  * Note that the cred_unused list must be time-ordered.
357  */
358  if (time_in_range(cred->cr_expire, expired, jiffies) &&
359  test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
360  return 0;
361 
362  list_del_init(&cred->cr_lru);
363  number_cred_unused--;
364  if (atomic_read(&cred->cr_count) != 0)
365  continue;
366 
367  cache_lock = &cred->cr_auth->au_credcache->lock;
368  spin_lock(cache_lock);
369  if (atomic_read(&cred->cr_count) == 0) {
370  get_rpccred(cred);
371  list_add_tail(&cred->cr_lru, free);
372  rpcauth_unhash_cred_locked(cred);
373  }
374  spin_unlock(cache_lock);
375  }
376  return (number_cred_unused / 100) * sysctl_vfs_cache_pressure;
377 }
378 
379 /*
380  * Run memory cache shrinker.
381  */
382 static int
383 rpcauth_cache_shrinker(struct shrinker *shrink, struct shrink_control *sc)
384 {
385  LIST_HEAD(free);
386  int res;
387  int nr_to_scan = sc->nr_to_scan;
388  gfp_t gfp_mask = sc->gfp_mask;
389 
390  if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
391  return (nr_to_scan == 0) ? 0 : -1;
392  if (list_empty(&cred_unused))
393  return 0;
394  spin_lock(&rpc_credcache_lock);
395  res = rpcauth_prune_expired(&free, nr_to_scan);
396  spin_unlock(&rpc_credcache_lock);
397  rpcauth_destroy_credlist(&free);
398  return res;
399 }
400 
401 /*
402  * Look up a process' credentials in the authentication cache
403  */
404 struct rpc_cred *
405 rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
406  int flags)
407 {
408  LIST_HEAD(free);
409  struct rpc_cred_cache *cache = auth->au_credcache;
410  struct hlist_node *pos;
411  struct rpc_cred *cred = NULL,
412  *entry, *new;
413  unsigned int nr;
414 
415  nr = hash_long(acred->uid, cache->hashbits);
416 
417  rcu_read_lock();
418  hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) {
419  if (!entry->cr_ops->crmatch(acred, entry, flags))
420  continue;
421  spin_lock(&cache->lock);
422  if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) {
423  spin_unlock(&cache->lock);
424  continue;
425  }
426  cred = get_rpccred(entry);
427  spin_unlock(&cache->lock);
428  break;
429  }
430  rcu_read_unlock();
431 
432  if (cred != NULL)
433  goto found;
434 
435  new = auth->au_ops->crcreate(auth, acred, flags);
436  if (IS_ERR(new)) {
437  cred = new;
438  goto out;
439  }
440 
441  spin_lock(&cache->lock);
442  hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) {
443  if (!entry->cr_ops->crmatch(acred, entry, flags))
444  continue;
445  cred = get_rpccred(entry);
446  break;
447  }
448  if (cred == NULL) {
449  cred = new;
450  set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
451  hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]);
452  } else
453  list_add_tail(&new->cr_lru, &free);
454  spin_unlock(&cache->lock);
455 found:
456  if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
457  cred->cr_ops->cr_init != NULL &&
458  !(flags & RPCAUTH_LOOKUP_NEW)) {
459  int res = cred->cr_ops->cr_init(auth, cred);
460  if (res < 0) {
461  put_rpccred(cred);
462  cred = ERR_PTR(res);
463  }
464  }
465  rpcauth_destroy_credlist(&free);
466 out:
467  return cred;
468 }
470 
471 struct rpc_cred *
472 rpcauth_lookupcred(struct rpc_auth *auth, int flags)
473 {
474  struct auth_cred acred;
475  struct rpc_cred *ret;
476  const struct cred *cred = current_cred();
477 
478  dprintk("RPC: looking up %s cred\n",
479  auth->au_ops->au_name);
480 
481  memset(&acred, 0, sizeof(acred));
482  acred.uid = cred->fsuid;
483  acred.gid = cred->fsgid;
484  acred.group_info = get_group_info(((struct cred *)cred)->group_info);
485 
486  ret = auth->au_ops->lookup_cred(auth, &acred, flags);
487  put_group_info(acred.group_info);
488  return ret;
489 }
490 
491 void
492 rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
493  struct rpc_auth *auth, const struct rpc_credops *ops)
494 {
495  INIT_HLIST_NODE(&cred->cr_hash);
496  INIT_LIST_HEAD(&cred->cr_lru);
497  atomic_set(&cred->cr_count, 1);
498  cred->cr_auth = auth;
499  cred->cr_ops = ops;
500  cred->cr_expire = jiffies;
501 #ifdef RPC_DEBUG
502  cred->cr_magic = RPCAUTH_CRED_MAGIC;
503 #endif
504  cred->cr_uid = acred->uid;
505 }
507 
508 struct rpc_cred *
509 rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags)
510 {
511  dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid,
512  cred->cr_auth->au_ops->au_name, cred);
513  return get_rpccred(cred);
514 }
516 
517 static struct rpc_cred *
518 rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
519 {
520  struct rpc_auth *auth = task->tk_client->cl_auth;
521  struct auth_cred acred = {
522  .uid = 0,
523  .gid = 0,
524  };
525 
526  dprintk("RPC: %5u looking up %s cred\n",
527  task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
528  return auth->au_ops->lookup_cred(auth, &acred, lookupflags);
529 }
530 
531 static struct rpc_cred *
532 rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags)
533 {
534  struct rpc_auth *auth = task->tk_client->cl_auth;
535 
536  dprintk("RPC: %5u looking up %s cred\n",
537  task->tk_pid, auth->au_ops->au_name);
538  return rpcauth_lookupcred(auth, lookupflags);
539 }
540 
541 static int
542 rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags)
543 {
544  struct rpc_rqst *req = task->tk_rqstp;
545  struct rpc_cred *new;
546  int lookupflags = 0;
547 
548  if (flags & RPC_TASK_ASYNC)
549  lookupflags |= RPCAUTH_LOOKUP_NEW;
550  if (cred != NULL)
551  new = cred->cr_ops->crbind(task, cred, lookupflags);
552  else if (flags & RPC_TASK_ROOTCREDS)
553  new = rpcauth_bind_root_cred(task, lookupflags);
554  else
555  new = rpcauth_bind_new_cred(task, lookupflags);
556  if (IS_ERR(new))
557  return PTR_ERR(new);
558  if (req->rq_cred != NULL)
559  put_rpccred(req->rq_cred);
560  req->rq_cred = new;
561  return 0;
562 }
563 
564 void
565 put_rpccred(struct rpc_cred *cred)
566 {
567  /* Fast path for unhashed credentials */
568  if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) == 0) {
569  if (atomic_dec_and_test(&cred->cr_count))
570  cred->cr_ops->crdestroy(cred);
571  return;
572  }
573 
574  if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
575  return;
576  if (!list_empty(&cred->cr_lru)) {
577  number_cred_unused--;
578  list_del_init(&cred->cr_lru);
579  }
580  if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
581  if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) {
582  cred->cr_expire = jiffies;
583  list_add_tail(&cred->cr_lru, &cred_unused);
584  number_cred_unused++;
585  goto out_nodestroy;
586  }
587  if (!rpcauth_unhash_cred(cred)) {
588  /* We were hashed and someone looked us up... */
589  goto out_nodestroy;
590  }
591  }
592  spin_unlock(&rpc_credcache_lock);
593  cred->cr_ops->crdestroy(cred);
594  return;
595 out_nodestroy:
596  spin_unlock(&rpc_credcache_lock);
597 }
599 
600 __be32 *
602 {
603  struct rpc_cred *cred = task->tk_rqstp->rq_cred;
604 
605  dprintk("RPC: %5u marshaling %s cred %p\n",
606  task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
607 
608  return cred->cr_ops->crmarshal(task, p);
609 }
610 
611 __be32 *
613 {
614  struct rpc_cred *cred = task->tk_rqstp->rq_cred;
615 
616  dprintk("RPC: %5u validating %s cred %p\n",
617  task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
618 
619  return cred->cr_ops->crvalidate(task, p);
620 }
621 
622 static void rpcauth_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp,
623  __be32 *data, void *obj)
624 {
625  struct xdr_stream xdr;
626 
627  xdr_init_encode(&xdr, &rqstp->rq_snd_buf, data);
628  encode(rqstp, &xdr, obj);
629 }
630 
631 int
632 rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp,
633  __be32 *data, void *obj)
634 {
635  struct rpc_cred *cred = task->tk_rqstp->rq_cred;
636 
637  dprintk("RPC: %5u using %s cred %p to wrap rpc data\n",
638  task->tk_pid, cred->cr_ops->cr_name, cred);
639  if (cred->cr_ops->crwrap_req)
640  return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
641  /* By default, we encode the arguments normally. */
642  rpcauth_wrap_req_encode(encode, rqstp, data, obj);
643  return 0;
644 }
645 
646 static int
647 rpcauth_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
648  __be32 *data, void *obj)
649 {
650  struct xdr_stream xdr;
651 
652  xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, data);
653  return decode(rqstp, &xdr, obj);
654 }
655 
656 int
657 rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp,
658  __be32 *data, void *obj)
659 {
660  struct rpc_cred *cred = task->tk_rqstp->rq_cred;
661 
662  dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n",
663  task->tk_pid, cred->cr_ops->cr_name, cred);
664  if (cred->cr_ops->crunwrap_resp)
665  return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
666  data, obj);
667  /* By default, we decode the arguments normally. */
668  return rpcauth_unwrap_req_decode(decode, rqstp, data, obj);
669 }
670 
671 int
673 {
674  struct rpc_cred *cred;
675  int err;
676 
677  cred = task->tk_rqstp->rq_cred;
678  if (cred == NULL) {
679  err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags);
680  if (err < 0)
681  goto out;
682  cred = task->tk_rqstp->rq_cred;
683  }
684  dprintk("RPC: %5u refreshing %s cred %p\n",
685  task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
686 
687  err = cred->cr_ops->crrefresh(task);
688 out:
689  if (err < 0)
690  task->tk_status = err;
691  return err;
692 }
693 
694 void
696 {
697  struct rpc_cred *cred = task->tk_rqstp->rq_cred;
698 
699  dprintk("RPC: %5u invalidating %s cred %p\n",
700  task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
701  if (cred)
702  clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
703 }
704 
705 int
707 {
708  struct rpc_cred *cred = task->tk_rqstp->rq_cred;
709 
710  return cred == NULL ||
711  test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
712 }
713 
714 static struct shrinker rpc_cred_shrinker = {
715  .shrink = rpcauth_cache_shrinker,
716  .seeks = DEFAULT_SEEKS,
717 };
718 
720 {
721  int err;
722 
723  err = rpc_init_authunix();
724  if (err < 0)
725  goto out1;
726  err = rpc_init_generic_auth();
727  if (err < 0)
728  goto out2;
729  register_shrinker(&rpc_cred_shrinker);
730  return 0;
731 out2:
733 out1:
734  return err;
735 }
736 
738 {
741  unregister_shrinker(&rpc_cred_shrinker);
742 }