/net/sunrpc/svcauth.c

http://github.com/mirrors/linux · C · 207 lines · 145 code · 36 blank · 26 comment · 17 complexity · ed6bef6f93b3f793a8ba20d0a68214f8 MD5 · raw file

  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/net/sunrpc/svcauth.c
  4. *
  5. * The generic interface for RPC authentication on the server side.
  6. *
  7. * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  8. *
  9. * CHANGES
  10. * 19-Apr-2000 Chris Evans - Security fix
  11. */
  12. #include <linux/types.h>
  13. #include <linux/module.h>
  14. #include <linux/sunrpc/types.h>
  15. #include <linux/sunrpc/xdr.h>
  16. #include <linux/sunrpc/svcsock.h>
  17. #include <linux/sunrpc/svcauth.h>
  18. #include <linux/err.h>
  19. #include <linux/hash.h>
  20. #include <trace/events/sunrpc.h>
  21. #define RPCDBG_FACILITY RPCDBG_AUTH
  22. /*
  23. * Table of authenticators
  24. */
  25. extern struct auth_ops svcauth_null;
  26. extern struct auth_ops svcauth_unix;
  27. static struct auth_ops __rcu *authtab[RPC_AUTH_MAXFLAVOR] = {
  28. [RPC_AUTH_NULL] = (struct auth_ops __force __rcu *)&svcauth_null,
  29. [RPC_AUTH_UNIX] = (struct auth_ops __force __rcu *)&svcauth_unix,
  30. };
  31. static struct auth_ops *
  32. svc_get_auth_ops(rpc_authflavor_t flavor)
  33. {
  34. struct auth_ops *aops;
  35. if (flavor >= RPC_AUTH_MAXFLAVOR)
  36. return NULL;
  37. rcu_read_lock();
  38. aops = rcu_dereference(authtab[flavor]);
  39. if (aops != NULL && !try_module_get(aops->owner))
  40. aops = NULL;
  41. rcu_read_unlock();
  42. return aops;
  43. }
  44. static void
  45. svc_put_auth_ops(struct auth_ops *aops)
  46. {
  47. module_put(aops->owner);
  48. }
  49. int
  50. svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
  51. {
  52. rpc_authflavor_t flavor;
  53. struct auth_ops *aops;
  54. *authp = rpc_auth_ok;
  55. flavor = svc_getnl(&rqstp->rq_arg.head[0]);
  56. dprintk("svc: svc_authenticate (%d)\n", flavor);
  57. aops = svc_get_auth_ops(flavor);
  58. if (aops == NULL) {
  59. *authp = rpc_autherr_badcred;
  60. return SVC_DENIED;
  61. }
  62. rqstp->rq_auth_slack = 0;
  63. init_svc_cred(&rqstp->rq_cred);
  64. rqstp->rq_authop = aops;
  65. return aops->accept(rqstp, authp);
  66. }
  67. EXPORT_SYMBOL_GPL(svc_authenticate);
  68. int svc_set_client(struct svc_rqst *rqstp)
  69. {
  70. rqstp->rq_client = NULL;
  71. return rqstp->rq_authop->set_client(rqstp);
  72. }
  73. EXPORT_SYMBOL_GPL(svc_set_client);
  74. /* A request, which was authenticated, has now executed.
  75. * Time to finalise the credentials and verifier
  76. * and release and resources
  77. */
  78. int svc_authorise(struct svc_rqst *rqstp)
  79. {
  80. struct auth_ops *aops = rqstp->rq_authop;
  81. int rv = 0;
  82. rqstp->rq_authop = NULL;
  83. if (aops) {
  84. rv = aops->release(rqstp);
  85. svc_put_auth_ops(aops);
  86. }
  87. return rv;
  88. }
  89. int
  90. svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
  91. {
  92. struct auth_ops *old;
  93. int rv = -EINVAL;
  94. if (flavor < RPC_AUTH_MAXFLAVOR) {
  95. old = cmpxchg((struct auth_ops ** __force)&authtab[flavor], NULL, aops);
  96. if (old == NULL || old == aops)
  97. rv = 0;
  98. }
  99. return rv;
  100. }
  101. EXPORT_SYMBOL_GPL(svc_auth_register);
  102. void
  103. svc_auth_unregister(rpc_authflavor_t flavor)
  104. {
  105. if (flavor < RPC_AUTH_MAXFLAVOR)
  106. rcu_assign_pointer(authtab[flavor], NULL);
  107. }
  108. EXPORT_SYMBOL_GPL(svc_auth_unregister);
  109. /**************************************************
  110. * 'auth_domains' are stored in a hash table indexed by name.
  111. * When the last reference to an 'auth_domain' is dropped,
  112. * the object is unhashed and freed.
  113. * If auth_domain_lookup fails to find an entry, it will return
  114. * it's second argument 'new'. If this is non-null, it will
  115. * have been atomically linked into the table.
  116. */
  117. #define DN_HASHBITS 6
  118. #define DN_HASHMAX (1<<DN_HASHBITS)
  119. static struct hlist_head auth_domain_table[DN_HASHMAX];
  120. static DEFINE_SPINLOCK(auth_domain_lock);
  121. static void auth_domain_release(struct kref *kref)
  122. __releases(&auth_domain_lock)
  123. {
  124. struct auth_domain *dom = container_of(kref, struct auth_domain, ref);
  125. hlist_del_rcu(&dom->hash);
  126. dom->flavour->domain_release(dom);
  127. spin_unlock(&auth_domain_lock);
  128. }
  129. void auth_domain_put(struct auth_domain *dom)
  130. {
  131. kref_put_lock(&dom->ref, auth_domain_release, &auth_domain_lock);
  132. }
  133. EXPORT_SYMBOL_GPL(auth_domain_put);
  134. struct auth_domain *
  135. auth_domain_lookup(char *name, struct auth_domain *new)
  136. {
  137. struct auth_domain *hp;
  138. struct hlist_head *head;
  139. head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
  140. spin_lock(&auth_domain_lock);
  141. hlist_for_each_entry(hp, head, hash) {
  142. if (strcmp(hp->name, name)==0) {
  143. kref_get(&hp->ref);
  144. spin_unlock(&auth_domain_lock);
  145. return hp;
  146. }
  147. }
  148. if (new)
  149. hlist_add_head_rcu(&new->hash, head);
  150. spin_unlock(&auth_domain_lock);
  151. return new;
  152. }
  153. EXPORT_SYMBOL_GPL(auth_domain_lookup);
  154. struct auth_domain *auth_domain_find(char *name)
  155. {
  156. struct auth_domain *hp;
  157. struct hlist_head *head;
  158. head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
  159. rcu_read_lock();
  160. hlist_for_each_entry_rcu(hp, head, hash) {
  161. if (strcmp(hp->name, name)==0) {
  162. if (!kref_get_unless_zero(&hp->ref))
  163. hp = NULL;
  164. rcu_read_unlock();
  165. return hp;
  166. }
  167. }
  168. rcu_read_unlock();
  169. return NULL;
  170. }
  171. EXPORT_SYMBOL_GPL(auth_domain_find);