callback.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * linux/fs/nfs/callback.c
  3. *
  4. * Copyright (C) 2004 Trond Myklebust
  5. *
  6. * NFSv4 callback handling
  7. */
  8. #include <linux/completion.h>
  9. #include <linux/ip.h>
  10. #include <linux/module.h>
  11. #include <linux/smp_lock.h>
  12. #include <linux/sunrpc/svc.h>
  13. #include <linux/sunrpc/svcsock.h>
  14. #include <linux/nfs_fs.h>
  15. #include <linux/mutex.h>
  16. #include <linux/freezer.h>
  17. #include <linux/kthread.h>
  18. #include <linux/sunrpc/svcauth_gss.h>
  19. #include <net/inet_sock.h>
  20. #include "nfs4_fs.h"
  21. #include "callback.h"
  22. #include "internal.h"
  23. #define NFSDBG_FACILITY NFSDBG_CALLBACK
  24. struct nfs_callback_data {
  25. unsigned int users;
  26. struct svc_rqst *rqst;
  27. struct task_struct *task;
  28. };
  29. static struct nfs_callback_data nfs_callback_info;
  30. static DEFINE_MUTEX(nfs_callback_mutex);
  31. static struct svc_program nfs4_callback_program;
  32. unsigned int nfs_callback_set_tcpport;
  33. unsigned short nfs_callback_tcpport;
  34. unsigned short nfs_callback_tcpport6;
  35. static const int nfs_set_port_min = 0;
  36. static const int nfs_set_port_max = 65535;
  37. static int param_set_port(const char *val, struct kernel_param *kp)
  38. {
  39. char *endp;
  40. int num = simple_strtol(val, &endp, 0);
  41. if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
  42. return -EINVAL;
  43. *((int *)kp->arg) = num;
  44. return 0;
  45. }
  46. module_param_call(callback_tcpport, param_set_port, param_get_int,
  47. &nfs_callback_set_tcpport, 0644);
  48. /*
  49. * This is the callback kernel thread.
  50. */
  51. static int
  52. nfs_callback_svc(void *vrqstp)
  53. {
  54. int err, preverr = 0;
  55. struct svc_rqst *rqstp = vrqstp;
  56. set_freezable();
  57. /*
  58. * FIXME: do we really need to run this under the BKL? If so, please
  59. * add a comment about what it's intended to protect.
  60. */
  61. lock_kernel();
  62. while (!kthread_should_stop()) {
  63. /*
  64. * Listen for a request on the socket
  65. */
  66. err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
  67. if (err == -EAGAIN || err == -EINTR) {
  68. preverr = err;
  69. continue;
  70. }
  71. if (err < 0) {
  72. if (err != preverr) {
  73. printk(KERN_WARNING "%s: unexpected error "
  74. "from svc_recv (%d)\n", __func__, err);
  75. preverr = err;
  76. }
  77. schedule_timeout_uninterruptible(HZ);
  78. continue;
  79. }
  80. preverr = err;
  81. svc_process(rqstp);
  82. }
  83. unlock_kernel();
  84. return 0;
  85. }
  86. /*
  87. * Bring up the callback thread if it is not already up.
  88. */
  89. int nfs_callback_up(void)
  90. {
  91. struct svc_serv *serv = NULL;
  92. int ret = 0;
  93. mutex_lock(&nfs_callback_mutex);
  94. if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
  95. goto out;
  96. serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
  97. ret = -ENOMEM;
  98. if (!serv)
  99. goto out_err;
  100. ret = svc_create_xprt(serv, "tcp", PF_INET,
  101. nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
  102. if (ret <= 0)
  103. goto out_err;
  104. nfs_callback_tcpport = ret;
  105. dprintk("NFS: Callback listener port = %u (af %u)\n",
  106. nfs_callback_tcpport, PF_INET);
  107. #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  108. ret = svc_create_xprt(serv, "tcp", PF_INET6,
  109. nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
  110. if (ret > 0) {
  111. nfs_callback_tcpport6 = ret;
  112. dprintk("NFS: Callback listener port = %u (af %u)\n",
  113. nfs_callback_tcpport6, PF_INET6);
  114. } else if (ret != -EAFNOSUPPORT)
  115. goto out_err;
  116. #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
  117. nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
  118. if (IS_ERR(nfs_callback_info.rqst)) {
  119. ret = PTR_ERR(nfs_callback_info.rqst);
  120. nfs_callback_info.rqst = NULL;
  121. goto out_err;
  122. }
  123. svc_sock_update_bufs(serv);
  124. nfs_callback_info.task = kthread_run(nfs_callback_svc,
  125. nfs_callback_info.rqst,
  126. "nfsv4-svc");
  127. if (IS_ERR(nfs_callback_info.task)) {
  128. ret = PTR_ERR(nfs_callback_info.task);
  129. svc_exit_thread(nfs_callback_info.rqst);
  130. nfs_callback_info.rqst = NULL;
  131. nfs_callback_info.task = NULL;
  132. goto out_err;
  133. }
  134. out:
  135. /*
  136. * svc_create creates the svc_serv with sv_nrthreads == 1, and then
  137. * svc_prepare_thread increments that. So we need to call svc_destroy
  138. * on both success and failure so that the refcount is 1 when the
  139. * thread exits.
  140. */
  141. if (serv)
  142. svc_destroy(serv);
  143. mutex_unlock(&nfs_callback_mutex);
  144. return ret;
  145. out_err:
  146. dprintk("NFS: Couldn't create callback socket or server thread; "
  147. "err = %d\n", ret);
  148. nfs_callback_info.users--;
  149. goto out;
  150. }
  151. /*
  152. * Kill the callback thread if it's no longer being used.
  153. */
  154. void nfs_callback_down(void)
  155. {
  156. mutex_lock(&nfs_callback_mutex);
  157. nfs_callback_info.users--;
  158. if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) {
  159. kthread_stop(nfs_callback_info.task);
  160. svc_exit_thread(nfs_callback_info.rqst);
  161. nfs_callback_info.rqst = NULL;
  162. nfs_callback_info.task = NULL;
  163. }
  164. mutex_unlock(&nfs_callback_mutex);
  165. }
  166. static int check_gss_callback_principal(struct nfs_client *clp,
  167. struct svc_rqst *rqstp)
  168. {
  169. struct rpc_clnt *r = clp->cl_rpcclient;
  170. char *p = svc_gss_principal(rqstp);
  171. /*
  172. * It might just be a normal user principal, in which case
  173. * userspace won't bother to tell us the name at all.
  174. */
  175. if (p == NULL)
  176. return SVC_DENIED;
  177. /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
  178. if (memcmp(p, "nfs@", 4) != 0)
  179. return SVC_DENIED;
  180. p += 4;
  181. if (strcmp(p, r->cl_server) != 0)
  182. return SVC_DENIED;
  183. return SVC_OK;
  184. }
  185. static int nfs_callback_authenticate(struct svc_rqst *rqstp)
  186. {
  187. struct nfs_client *clp;
  188. RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
  189. int ret = SVC_OK;
  190. /* Don't talk to strangers */
  191. clp = nfs_find_client(svc_addr(rqstp), 4);
  192. if (clp == NULL)
  193. return SVC_DROP;
  194. dprintk("%s: %s NFSv4 callback!\n", __func__,
  195. svc_print_addr(rqstp, buf, sizeof(buf)));
  196. switch (rqstp->rq_authop->flavour) {
  197. case RPC_AUTH_NULL:
  198. if (rqstp->rq_proc != CB_NULL)
  199. ret = SVC_DENIED;
  200. break;
  201. case RPC_AUTH_UNIX:
  202. break;
  203. case RPC_AUTH_GSS:
  204. ret = check_gss_callback_principal(clp, rqstp);
  205. break;
  206. default:
  207. ret = SVC_DENIED;
  208. }
  209. nfs_put_client(clp);
  210. return ret;
  211. }
  212. /*
  213. * Define NFS4 callback program
  214. */
  215. static struct svc_version *nfs4_callback_version[] = {
  216. [1] = &nfs4_callback_version1,
  217. };
  218. static struct svc_stat nfs4_callback_stats;
  219. static struct svc_program nfs4_callback_program = {
  220. .pg_prog = NFS4_CALLBACK, /* RPC service number */
  221. .pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */
  222. .pg_vers = nfs4_callback_version, /* version table */
  223. .pg_name = "NFSv4 callback", /* service name */
  224. .pg_class = "nfs", /* authentication class */
  225. .pg_stats = &nfs4_callback_stats,
  226. .pg_authenticate = nfs_callback_authenticate,
  227. };