gss_rpc_upcall.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * linux/net/sunrpc/gss_rpc_upcall.c
  4. *
  5. * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
  6. */
  7. #include <linux/types.h>
  8. #include <linux/un.h>
  9. #include <linux/sunrpc/svcauth.h>
  10. #include "gss_rpc_upcall.h"
  11. #define GSSPROXY_SOCK_PATHNAME "/var/run/gssproxy.sock"
  12. #define GSSPROXY_PROGRAM (400112u)
  13. #define GSSPROXY_VERS_1 (1u)
  14. /*
  15. * Encoding/Decoding functions
  16. */
  17. enum {
  18. GSSX_NULL = 0, /* Unused */
  19. GSSX_INDICATE_MECHS = 1,
  20. GSSX_GET_CALL_CONTEXT = 2,
  21. GSSX_IMPORT_AND_CANON_NAME = 3,
  22. GSSX_EXPORT_CRED = 4,
  23. GSSX_IMPORT_CRED = 5,
  24. GSSX_ACQUIRE_CRED = 6,
  25. GSSX_STORE_CRED = 7,
  26. GSSX_INIT_SEC_CONTEXT = 8,
  27. GSSX_ACCEPT_SEC_CONTEXT = 9,
  28. GSSX_RELEASE_HANDLE = 10,
  29. GSSX_GET_MIC = 11,
  30. GSSX_VERIFY = 12,
  31. GSSX_WRAP = 13,
  32. GSSX_UNWRAP = 14,
  33. GSSX_WRAP_SIZE_LIMIT = 15,
  34. };
  35. #define PROC(proc, name) \
  36. [GSSX_##proc] = { \
  37. .p_proc = GSSX_##proc, \
  38. .p_encode = gssx_enc_##name, \
  39. .p_decode = gssx_dec_##name, \
  40. .p_arglen = GSSX_ARG_##name##_sz, \
  41. .p_replen = GSSX_RES_##name##_sz, \
  42. .p_statidx = GSSX_##proc, \
  43. .p_name = #proc, \
  44. }
  45. static const struct rpc_procinfo gssp_procedures[] = {
  46. PROC(INDICATE_MECHS, indicate_mechs),
  47. PROC(GET_CALL_CONTEXT, get_call_context),
  48. PROC(IMPORT_AND_CANON_NAME, import_and_canon_name),
  49. PROC(EXPORT_CRED, export_cred),
  50. PROC(IMPORT_CRED, import_cred),
  51. PROC(ACQUIRE_CRED, acquire_cred),
  52. PROC(STORE_CRED, store_cred),
  53. PROC(INIT_SEC_CONTEXT, init_sec_context),
  54. PROC(ACCEPT_SEC_CONTEXT, accept_sec_context),
  55. PROC(RELEASE_HANDLE, release_handle),
  56. PROC(GET_MIC, get_mic),
  57. PROC(VERIFY, verify),
  58. PROC(WRAP, wrap),
  59. PROC(UNWRAP, unwrap),
  60. PROC(WRAP_SIZE_LIMIT, wrap_size_limit),
  61. };
  62. /*
  63. * Common transport functions
  64. */
  65. static const struct rpc_program gssp_program;
  66. static int gssp_rpc_create(struct net *net, struct rpc_clnt **_clnt)
  67. {
  68. static const struct sockaddr_un gssp_localaddr = {
  69. .sun_family = AF_LOCAL,
  70. .sun_path = GSSPROXY_SOCK_PATHNAME,
  71. };
  72. struct rpc_create_args args = {
  73. .net = net,
  74. .protocol = XPRT_TRANSPORT_LOCAL,
  75. .address = (struct sockaddr *)&gssp_localaddr,
  76. .addrsize = sizeof(gssp_localaddr),
  77. .servername = "localhost",
  78. .program = &gssp_program,
  79. .version = GSSPROXY_VERS_1,
  80. .authflavor = RPC_AUTH_NULL,
  81. /*
  82. * Note we want connection to be done in the caller's
  83. * filesystem namespace. We therefore turn off the idle
  84. * timeout, which would result in reconnections being
  85. * done without the correct namespace:
  86. */
  87. .flags = RPC_CLNT_CREATE_NOPING |
  88. RPC_CLNT_CREATE_CONNECTED |
  89. RPC_CLNT_CREATE_NO_IDLE_TIMEOUT
  90. };
  91. struct rpc_clnt *clnt;
  92. int result = 0;
  93. clnt = rpc_create(&args);
  94. if (IS_ERR(clnt)) {
  95. dprintk("RPC: failed to create AF_LOCAL gssproxy "
  96. "client (errno %ld).\n", PTR_ERR(clnt));
  97. result = PTR_ERR(clnt);
  98. *_clnt = NULL;
  99. goto out;
  100. }
  101. dprintk("RPC: created new gssp local client (gssp_local_clnt: "
  102. "%p)\n", clnt);
  103. *_clnt = clnt;
  104. out:
  105. return result;
  106. }
  107. void init_gssp_clnt(struct sunrpc_net *sn)
  108. {
  109. mutex_init(&sn->gssp_lock);
  110. sn->gssp_clnt = NULL;
  111. }
  112. int set_gssp_clnt(struct net *net)
  113. {
  114. struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
  115. struct rpc_clnt *clnt;
  116. int ret;
  117. mutex_lock(&sn->gssp_lock);
  118. ret = gssp_rpc_create(net, &clnt);
  119. if (!ret) {
  120. if (sn->gssp_clnt)
  121. rpc_shutdown_client(sn->gssp_clnt);
  122. sn->gssp_clnt = clnt;
  123. }
  124. mutex_unlock(&sn->gssp_lock);
  125. return ret;
  126. }
  127. void clear_gssp_clnt(struct sunrpc_net *sn)
  128. {
  129. mutex_lock(&sn->gssp_lock);
  130. if (sn->gssp_clnt) {
  131. rpc_shutdown_client(sn->gssp_clnt);
  132. sn->gssp_clnt = NULL;
  133. }
  134. mutex_unlock(&sn->gssp_lock);
  135. }
  136. static struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn)
  137. {
  138. struct rpc_clnt *clnt;
  139. mutex_lock(&sn->gssp_lock);
  140. clnt = sn->gssp_clnt;
  141. if (clnt)
  142. refcount_inc(&clnt->cl_count);
  143. mutex_unlock(&sn->gssp_lock);
  144. return clnt;
  145. }
  146. static int gssp_call(struct net *net, struct rpc_message *msg)
  147. {
  148. struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
  149. struct rpc_clnt *clnt;
  150. int status;
  151. clnt = get_gssp_clnt(sn);
  152. if (!clnt)
  153. return -EIO;
  154. status = rpc_call_sync(clnt, msg, 0);
  155. if (status < 0) {
  156. dprintk("gssp: rpc_call returned error %d\n", -status);
  157. switch (status) {
  158. case -EPROTONOSUPPORT:
  159. status = -EINVAL;
  160. break;
  161. case -ECONNREFUSED:
  162. case -ETIMEDOUT:
  163. case -ENOTCONN:
  164. status = -EAGAIN;
  165. break;
  166. case -ERESTARTSYS:
  167. if (signalled ())
  168. status = -EINTR;
  169. break;
  170. default:
  171. break;
  172. }
  173. }
  174. rpc_release_client(clnt);
  175. return status;
  176. }
  177. static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg)
  178. {
  179. unsigned int i;
  180. for (i = 0; i < arg->npages && arg->pages[i]; i++)
  181. __free_page(arg->pages[i]);
  182. kfree(arg->pages);
  183. }
  184. static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
  185. {
  186. unsigned int i;
  187. arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE);
  188. arg->pages = kzalloc_objs(struct page *, arg->npages);
  189. if (!arg->pages)
  190. return -ENOMEM;
  191. for (i = 0; i < arg->npages; i++) {
  192. arg->pages[i] = alloc_page(GFP_KERNEL);
  193. if (!arg->pages[i]) {
  194. gssp_free_receive_pages(arg);
  195. return -ENOMEM;
  196. }
  197. }
  198. return 0;
  199. }
  200. static char *gssp_stringify(struct xdr_netobj *netobj)
  201. {
  202. return kmemdup_nul(netobj->data, netobj->len, GFP_KERNEL);
  203. }
  204. static void gssp_hostbased_service(char **principal)
  205. {
  206. char *c;
  207. if (!*principal)
  208. return;
  209. /* terminate and remove realm part */
  210. c = strchr(*principal, '@');
  211. if (c) {
  212. *c = '\0';
  213. /* change service-hostname delimiter */
  214. c = strchr(*principal, '/');
  215. if (c)
  216. *c = '@';
  217. }
  218. if (!c) {
  219. /* not a service principal */
  220. kfree(*principal);
  221. *principal = NULL;
  222. }
  223. }
  224. /*
  225. * Public functions
  226. */
  227. /* numbers somewhat arbitrary but large enough for current needs */
  228. #define GSSX_MAX_OUT_HANDLE 128
  229. #define GSSX_MAX_SRC_PRINC 256
  230. #define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
  231. GSSX_max_oid_sz + \
  232. GSSX_max_princ_sz + \
  233. sizeof(struct svc_cred))
  234. int gssp_accept_sec_context_upcall(struct net *net,
  235. struct gssp_upcall_data *data)
  236. {
  237. struct gssx_ctx ctxh = {
  238. .state = data->in_handle
  239. };
  240. struct gssx_arg_accept_sec_context arg = {
  241. .input_token = data->in_token,
  242. };
  243. struct gssx_ctx rctxh = {
  244. /*
  245. * pass in the max length we expect for each of these
  246. * buffers but let the xdr code kmalloc them:
  247. */
  248. .exported_context_token.len = GSSX_max_output_handle_sz,
  249. .mech.len = GSS_OID_MAX_LEN,
  250. .targ_name.display_name.len = GSSX_max_princ_sz,
  251. .src_name.display_name.len = GSSX_max_princ_sz
  252. };
  253. struct gssx_res_accept_sec_context res = {
  254. .context_handle = &rctxh,
  255. .output_token = &data->out_token
  256. };
  257. struct rpc_message msg = {
  258. .rpc_proc = &gssp_procedures[GSSX_ACCEPT_SEC_CONTEXT],
  259. .rpc_argp = &arg,
  260. .rpc_resp = &res,
  261. .rpc_cred = NULL, /* FIXME ? */
  262. };
  263. struct xdr_netobj client_name = { 0 , NULL };
  264. struct xdr_netobj target_name = { 0, NULL };
  265. int ret;
  266. if (data->in_handle.len != 0)
  267. arg.context_handle = &ctxh;
  268. res.output_token->len = GSSX_max_output_token_sz;
  269. ret = gssp_alloc_receive_pages(&arg);
  270. if (ret)
  271. return ret;
  272. ret = gssp_call(net, &msg);
  273. gssp_free_receive_pages(&arg);
  274. /* we need to fetch all data even in case of error so
  275. * that we can free special strctures is they have been allocated */
  276. data->major_status = res.status.major_status;
  277. data->minor_status = res.status.minor_status;
  278. if (res.context_handle) {
  279. data->out_handle = rctxh.exported_context_token;
  280. data->mech_oid.len = rctxh.mech.len;
  281. if (rctxh.mech.data) {
  282. memcpy(data->mech_oid.data, rctxh.mech.data,
  283. data->mech_oid.len);
  284. kfree(rctxh.mech.data);
  285. }
  286. client_name = rctxh.src_name.display_name;
  287. target_name = rctxh.targ_name.display_name;
  288. }
  289. if (res.options.count == 1) {
  290. gssx_buffer *value = &res.options.data[0].value;
  291. /* Currently we only decode CREDS_VALUE, if we add
  292. * anything else we'll have to loop and match on the
  293. * option name */
  294. if (value->len == 1) {
  295. /* steal group info from struct svc_cred */
  296. data->creds = *(struct svc_cred *)value->data;
  297. data->found_creds = 1;
  298. }
  299. /* whether we use it or not, free data */
  300. kfree(value->data);
  301. }
  302. if (res.options.count != 0) {
  303. kfree(res.options.data);
  304. }
  305. /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */
  306. if (data->found_creds) {
  307. if (client_name.data) {
  308. data->creds.cr_raw_principal =
  309. gssp_stringify(&client_name);
  310. data->creds.cr_principal =
  311. gssp_stringify(&client_name);
  312. gssp_hostbased_service(&data->creds.cr_principal);
  313. }
  314. if (target_name.data) {
  315. data->creds.cr_targ_princ =
  316. gssp_stringify(&target_name);
  317. gssp_hostbased_service(&data->creds.cr_targ_princ);
  318. }
  319. }
  320. kfree(client_name.data);
  321. kfree(target_name.data);
  322. return ret;
  323. }
  324. void gssp_free_upcall_data(struct gssp_upcall_data *data)
  325. {
  326. kfree(data->in_handle.data);
  327. kfree(data->out_handle.data);
  328. kfree(data->out_token.data);
  329. free_svc_cred(&data->creds);
  330. }
  331. /*
  332. * Initialization stuff
  333. */
  334. static unsigned int gssp_version1_counts[ARRAY_SIZE(gssp_procedures)];
  335. static const struct rpc_version gssp_version1 = {
  336. .number = GSSPROXY_VERS_1,
  337. .nrprocs = ARRAY_SIZE(gssp_procedures),
  338. .procs = gssp_procedures,
  339. .counts = gssp_version1_counts,
  340. };
  341. static const struct rpc_version *gssp_version[] = {
  342. NULL,
  343. &gssp_version1,
  344. };
  345. static struct rpc_stat gssp_stats;
  346. static const struct rpc_program gssp_program = {
  347. .name = "gssproxy",
  348. .number = GSSPROXY_PROGRAM,
  349. .nrvers = ARRAY_SIZE(gssp_version),
  350. .version = gssp_version,
  351. .stats = &gssp_stats,
  352. };