auth.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/nfs/rpcauth.c
  3.  *
  4.  * Generic RPC authentication API.
  5.  *
  6.  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  7.  */
  8. #include <linux/types.h>
  9. #include <linux/sched.h>
  10. #include <linux/slab.h>
  11. #include <linux/errno.h>
  12. #include <linux/socket.h>
  13. #include <linux/sunrpc/clnt.h>
  14. #include <linux/spinlock.h>
  15. #ifdef RPC_DEBUG
  16. # define RPCDBG_FACILITY RPCDBG_AUTH
  17. #endif
  18. #define RPC_MAXFLAVOR 8
  19. static struct rpc_authops * auth_flavors[RPC_MAXFLAVOR] = {
  20. &authnull_ops, /* AUTH_NULL */
  21. &authunix_ops, /* AUTH_UNIX */
  22. NULL, /* others can be loadable modules */
  23. };
  24. int
  25. rpcauth_register(struct rpc_authops *ops)
  26. {
  27. unsigned int flavor;
  28. if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR)
  29. return -EINVAL;
  30. if (auth_flavors[flavor] != NULL)
  31. return -EPERM; /* what else? */
  32. auth_flavors[flavor] = ops;
  33. return 0;
  34. }
  35. int
  36. rpcauth_unregister(struct rpc_authops *ops)
  37. {
  38. unsigned int flavor;
  39. if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR)
  40. return -EINVAL;
  41. if (auth_flavors[flavor] != ops)
  42. return -EPERM; /* what else? */
  43. auth_flavors[flavor] = NULL;
  44. return 0;
  45. }
  46. struct rpc_auth *
  47. rpcauth_create(unsigned int flavor, struct rpc_clnt *clnt)
  48. {
  49. struct rpc_authops *ops;
  50. if (flavor >= RPC_MAXFLAVOR || !(ops = auth_flavors[flavor]))
  51. return NULL;
  52. clnt->cl_auth = ops->create(clnt);
  53. return clnt->cl_auth;
  54. }
  55. void
  56. rpcauth_destroy(struct rpc_auth *auth)
  57. {
  58. auth->au_ops->destroy(auth);
  59. }
  60. static spinlock_t rpc_credcache_lock = SPIN_LOCK_UNLOCKED;
  61. /*
  62.  * Initialize RPC credential cache
  63.  */
  64. void
  65. rpcauth_init_credcache(struct rpc_auth *auth)
  66. {
  67. memset(auth->au_credcache, 0, sizeof(auth->au_credcache));
  68. auth->au_nextgc = jiffies + (auth->au_expire >> 1);
  69. }
  70. /*
  71.  * Destroy an unreferenced credential
  72.  */
  73. static inline void
  74. rpcauth_crdestroy(struct rpc_cred *cred)
  75. {
  76. #ifdef RPC_DEBUG
  77. if (cred->cr_magic != RPCAUTH_CRED_MAGIC)
  78. BUG();
  79. cred->cr_magic = 0;
  80. if (atomic_read(&cred->cr_count) || cred->cr_auth)
  81. BUG();
  82. #endif
  83. cred->cr_ops->crdestroy(cred);
  84. }
  85. /*
  86.  * Destroy a list of credentials
  87.  */
  88. static inline
  89. void rpcauth_destroy_credlist(struct rpc_cred *head)
  90. {
  91. struct rpc_cred *cred;
  92. while ((cred = head) != NULL) {
  93. head = cred->cr_next;
  94. rpcauth_crdestroy(cred);
  95. }
  96. }
  97. /*
  98.  * Clear the RPC credential cache, and delete those credentials
  99.  * that are not referenced.
  100.  */
  101. void
  102. rpcauth_free_credcache(struct rpc_auth *auth)
  103. {
  104. struct rpc_cred **q, *cred, *free = NULL;
  105. int i;
  106. spin_lock(&rpc_credcache_lock);
  107. for (i = 0; i < RPC_CREDCACHE_NR; i++) {
  108. q = &auth->au_credcache[i];
  109. while ((cred = *q) != NULL) {
  110. *q = cred->cr_next;
  111. cred->cr_auth = NULL;
  112. if (atomic_read(&cred->cr_count) == 0) {
  113. cred->cr_next = free;
  114. free = cred;
  115. } else
  116. cred->cr_next = NULL;
  117. }
  118. }
  119. spin_unlock(&rpc_credcache_lock);
  120. rpcauth_destroy_credlist(free);
  121. }
  122. /*
  123.  * Remove stale credentials. Avoid sleeping inside the loop.
  124.  */
  125. static void
  126. rpcauth_gc_credcache(struct rpc_auth *auth)
  127. {
  128. struct rpc_cred **q, *cred, *free = NULL;
  129. int i;
  130. dprintk("RPC: gc'ing RPC credentials for auth %pn", auth);
  131. spin_lock(&rpc_credcache_lock);
  132. for (i = 0; i < RPC_CREDCACHE_NR; i++) {
  133. q = &auth->au_credcache[i];
  134. while ((cred = *q) != NULL) {
  135. if (!atomic_read(&cred->cr_count) &&
  136.     time_before(cred->cr_expire, jiffies)) {
  137. *q = cred->cr_next;
  138. cred->cr_auth = NULL;
  139. cred->cr_next = free;
  140. free = cred;
  141. continue;
  142. }
  143. q = &cred->cr_next;
  144. }
  145. }
  146. spin_unlock(&rpc_credcache_lock);
  147. rpcauth_destroy_credlist(free);
  148. auth->au_nextgc = jiffies + auth->au_expire;
  149. }
  150. /*
  151.  * Insert credential into cache
  152.  */
  153. void
  154. rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
  155. {
  156. int nr;
  157. nr = (cred->cr_uid & RPC_CREDCACHE_MASK);
  158. spin_lock(&rpc_credcache_lock);
  159. cred->cr_next = auth->au_credcache[nr];
  160. auth->au_credcache[nr] = cred;
  161. cred->cr_auth = auth;
  162. get_rpccred(cred);
  163. spin_unlock(&rpc_credcache_lock);
  164. }
  165. /*
  166.  * Look up a process' credentials in the authentication cache
  167.  */
  168. static struct rpc_cred *
  169. rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
  170. {
  171. struct rpc_cred **q, *cred = NULL;
  172. int nr = 0;
  173. if (!(taskflags & RPC_TASK_ROOTCREDS))
  174. nr = current->uid & RPC_CREDCACHE_MASK;
  175. if (time_before(auth->au_nextgc, jiffies))
  176. rpcauth_gc_credcache(auth);
  177. spin_lock(&rpc_credcache_lock);
  178. q = &auth->au_credcache[nr];
  179. while ((cred = *q) != NULL) {
  180. if (!(cred->cr_flags & RPCAUTH_CRED_DEAD) &&
  181.     cred->cr_ops->crmatch(cred, taskflags)) {
  182. *q = cred->cr_next;
  183. break;
  184. }
  185. q = &cred->cr_next;
  186. }
  187. spin_unlock(&rpc_credcache_lock);
  188. if (!cred) {
  189. cred = auth->au_ops->crcreate(taskflags);
  190. #ifdef RPC_DEBUG
  191. if (cred)
  192. cred->cr_magic = RPCAUTH_CRED_MAGIC;
  193. #endif
  194. }
  195. if (cred)
  196. rpcauth_insert_credcache(auth, cred);
  197. return (struct rpc_cred *) cred;
  198. }
  199. /*
  200.  * Remove cred handle from cache
  201.  */
  202. static void
  203. rpcauth_remove_credcache(struct rpc_cred *cred)
  204. {
  205. struct rpc_auth *auth = cred->cr_auth;
  206. struct rpc_cred **q, *cr;
  207. int nr;
  208. nr = (cred->cr_uid & RPC_CREDCACHE_MASK);
  209. q = &auth->au_credcache[nr];
  210. while ((cr = *q) != NULL) {
  211. if (cred == cr) {
  212. *q = cred->cr_next;
  213. cred->cr_next = NULL;
  214. cred->cr_auth = NULL;
  215. break;
  216. }
  217. q = &cred->cr_next;
  218. }
  219. }
  220. struct rpc_cred *
  221. rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
  222. {
  223. dprintk("RPC:     looking up %s credn",
  224. auth->au_ops->au_name);
  225. return rpcauth_lookup_credcache(auth, taskflags);
  226. }
  227. struct rpc_cred *
  228. rpcauth_bindcred(struct rpc_task *task)
  229. {
  230. struct rpc_auth *auth = task->tk_auth;
  231. dprintk("RPC: %4d looking up %s credn",
  232. task->tk_pid, task->tk_auth->au_ops->au_name);
  233. task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, task->tk_flags);
  234. if (task->tk_msg.rpc_cred == 0)
  235. task->tk_status = -ENOMEM;
  236. return task->tk_msg.rpc_cred;
  237. }
  238. int
  239. rpcauth_matchcred(struct rpc_auth *auth, struct rpc_cred *cred, int taskflags)
  240. {
  241. dprintk("RPC:     matching %s cred %dn",
  242. auth->au_ops->au_name, taskflags);
  243. return cred->cr_ops->crmatch(cred, taskflags);
  244. }
  245. void
  246. rpcauth_holdcred(struct rpc_task *task)
  247. {
  248. dprintk("RPC: %4d holding %s cred %pn",
  249. task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
  250. if (task->tk_msg.rpc_cred)
  251. get_rpccred(task->tk_msg.rpc_cred);
  252. }
  253. void
  254. put_rpccred(struct rpc_cred *cred)
  255. {
  256. if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
  257. return;
  258. if (cred->cr_auth && cred->cr_flags & RPCAUTH_CRED_DEAD)
  259. rpcauth_remove_credcache(cred);
  260. if (!cred->cr_auth) {
  261. spin_unlock(&rpc_credcache_lock);
  262. rpcauth_crdestroy(cred);
  263. return;
  264. }
  265. cred->cr_expire = jiffies + cred->cr_auth->au_expire;
  266. spin_unlock(&rpc_credcache_lock);
  267. }
  268. void
  269. rpcauth_unbindcred(struct rpc_task *task)
  270. {
  271. struct rpc_auth *auth = task->tk_auth;
  272. struct rpc_cred *cred = task->tk_msg.rpc_cred;
  273. dprintk("RPC: %4d releasing %s cred %pn",
  274. task->tk_pid, auth->au_ops->au_name, cred);
  275. put_rpccred(cred);
  276. task->tk_msg.rpc_cred = NULL;
  277. }
  278. u32 *
  279. rpcauth_marshcred(struct rpc_task *task, u32 *p)
  280. {
  281. struct rpc_auth *auth = task->tk_auth;
  282. struct rpc_cred *cred = task->tk_msg.rpc_cred;
  283. dprintk("RPC: %4d marshaling %s cred %pn",
  284. task->tk_pid, auth->au_ops->au_name, cred);
  285. return cred->cr_ops->crmarshal(task, p,
  286. task->tk_flags & RPC_CALL_REALUID);
  287. }
  288. u32 *
  289. rpcauth_checkverf(struct rpc_task *task, u32 *p)
  290. {
  291. struct rpc_auth *auth = task->tk_auth;
  292. struct rpc_cred *cred = task->tk_msg.rpc_cred;
  293. dprintk("RPC: %4d validating %s cred %pn",
  294. task->tk_pid, auth->au_ops->au_name, cred);
  295. return cred->cr_ops->crvalidate(task, p);
  296. }
  297. int
  298. rpcauth_refreshcred(struct rpc_task *task)
  299. {
  300. struct rpc_auth *auth = task->tk_auth;
  301. struct rpc_cred *cred = task->tk_msg.rpc_cred;
  302. dprintk("RPC: %4d refreshing %s cred %pn",
  303. task->tk_pid, auth->au_ops->au_name, cred);
  304. task->tk_status = cred->cr_ops->crrefresh(task);
  305. return task->tk_status;
  306. }
  307. void
  308. rpcauth_invalcred(struct rpc_task *task)
  309. {
  310. dprintk("RPC: %4d invalidating %s cred %pn",
  311. task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
  312. spin_lock(&rpc_credcache_lock);
  313. if (task->tk_msg.rpc_cred)
  314. task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
  315. spin_unlock(&rpc_credcache_lock);
  316. }
  317. int
  318. rpcauth_uptodatecred(struct rpc_task *task)
  319. {
  320. int retval;
  321. spin_lock(&rpc_credcache_lock);
  322. retval = !(task->tk_msg.rpc_cred) ||
  323. (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
  324. spin_unlock(&rpc_credcache_lock);
  325. return retval;
  326. }