12573a464SChuck Lever // SPDX-License-Identifier: GPL-2.0+ 21d658336SSimo Sorce /* 31d658336SSimo Sorce * GSS Proxy upcall module 41d658336SSimo Sorce * 51d658336SSimo Sorce * Copyright (C) 2012 Simo Sorce <simo@redhat.com> 61d658336SSimo Sorce */ 71d658336SSimo Sorce 81d658336SSimo Sorce #include <linux/sunrpc/svcauth.h> 91d658336SSimo Sorce #include "gss_rpc_xdr.h" 101d658336SSimo Sorce 111d658336SSimo Sorce static int gssx_enc_bool(struct xdr_stream *xdr, int v) 121d658336SSimo Sorce { 131d658336SSimo Sorce __be32 *p; 141d658336SSimo Sorce 151d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 161d658336SSimo Sorce if (unlikely(p == NULL)) 171d658336SSimo Sorce return -ENOSPC; 181d658336SSimo Sorce *p = v ? xdr_one : xdr_zero; 191d658336SSimo Sorce return 0; 201d658336SSimo Sorce } 211d658336SSimo Sorce 221d658336SSimo Sorce static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v) 231d658336SSimo Sorce { 241d658336SSimo Sorce __be32 *p; 251d658336SSimo Sorce 261d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 271d658336SSimo Sorce if (unlikely(p == NULL)) 281d658336SSimo Sorce return -ENOSPC; 291d658336SSimo Sorce *v = be32_to_cpu(*p); 301d658336SSimo Sorce return 0; 311d658336SSimo Sorce } 321d658336SSimo Sorce 331d658336SSimo Sorce static int gssx_enc_buffer(struct xdr_stream *xdr, 3489daf360SChristoph Hellwig const gssx_buffer *buf) 351d658336SSimo Sorce { 361d658336SSimo Sorce __be32 *p; 371d658336SSimo Sorce 381d658336SSimo Sorce p = xdr_reserve_space(xdr, sizeof(u32) + buf->len); 391d658336SSimo Sorce if (!p) 401d658336SSimo Sorce return -ENOSPC; 411d658336SSimo Sorce xdr_encode_opaque(p, buf->data, buf->len); 421d658336SSimo Sorce return 0; 431d658336SSimo Sorce } 441d658336SSimo Sorce 451d658336SSimo Sorce static int gssx_enc_in_token(struct xdr_stream *xdr, 4689daf360SChristoph Hellwig const struct gssp_in_token *in) 471d658336SSimo Sorce { 481d658336SSimo Sorce __be32 *p; 491d658336SSimo Sorce 501d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 511d658336SSimo Sorce if (!p) 521d658336SSimo Sorce return -ENOSPC; 531d658336SSimo Sorce *p = cpu_to_be32(in->page_len); 541d658336SSimo Sorce 551d658336SSimo Sorce /* all we need to do is to write pages */ 561d658336SSimo Sorce xdr_write_pages(xdr, in->pages, in->page_base, in->page_len); 571d658336SSimo Sorce 581d658336SSimo Sorce return 0; 591d658336SSimo Sorce } 601d658336SSimo Sorce 611d658336SSimo Sorce 621d658336SSimo Sorce static int gssx_dec_buffer(struct xdr_stream *xdr, 631d658336SSimo Sorce gssx_buffer *buf) 641d658336SSimo Sorce { 651d658336SSimo Sorce u32 length; 661d658336SSimo Sorce __be32 *p; 671d658336SSimo Sorce 681d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 691d658336SSimo Sorce if (unlikely(p == NULL)) 701d658336SSimo Sorce return -ENOSPC; 711d658336SSimo Sorce 721d658336SSimo Sorce length = be32_to_cpup(p); 731d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 741d658336SSimo Sorce if (unlikely(p == NULL)) 751d658336SSimo Sorce return -ENOSPC; 761d658336SSimo Sorce 771d658336SSimo Sorce if (buf->len == 0) { 781d658336SSimo Sorce /* we intentionally are not interested in this buffer */ 791d658336SSimo Sorce return 0; 801d658336SSimo Sorce } 811d658336SSimo Sorce if (length > buf->len) 821d658336SSimo Sorce return -ENOSPC; 831d658336SSimo Sorce 841d658336SSimo Sorce if (!buf->data) { 851d658336SSimo Sorce buf->data = kmemdup(p, length, GFP_KERNEL); 861d658336SSimo Sorce if (!buf->data) 871d658336SSimo Sorce return -ENOMEM; 881d658336SSimo Sorce } else { 891d658336SSimo Sorce memcpy(buf->data, p, length); 901d658336SSimo Sorce } 911d658336SSimo Sorce buf->len = length; 921d658336SSimo Sorce return 0; 931d658336SSimo Sorce } 941d658336SSimo Sorce 951d658336SSimo Sorce static int gssx_enc_option(struct xdr_stream *xdr, 961d658336SSimo Sorce struct gssx_option *opt) 971d658336SSimo Sorce { 981d658336SSimo Sorce int err; 991d658336SSimo Sorce 1001d658336SSimo Sorce err = gssx_enc_buffer(xdr, &opt->option); 1011d658336SSimo Sorce if (err) 1021d658336SSimo Sorce return err; 1031d658336SSimo Sorce err = gssx_enc_buffer(xdr, &opt->value); 1041d658336SSimo Sorce return err; 1051d658336SSimo Sorce } 1061d658336SSimo Sorce 1071d658336SSimo Sorce static int gssx_dec_option(struct xdr_stream *xdr, 1081d658336SSimo Sorce struct gssx_option *opt) 1091d658336SSimo Sorce { 1101d658336SSimo Sorce int err; 1111d658336SSimo Sorce 1121d658336SSimo Sorce err = gssx_dec_buffer(xdr, &opt->option); 1131d658336SSimo Sorce if (err) 1141d658336SSimo Sorce return err; 1151d658336SSimo Sorce err = gssx_dec_buffer(xdr, &opt->value); 1161d658336SSimo Sorce return err; 1171d658336SSimo Sorce } 1181d658336SSimo Sorce 1191d658336SSimo Sorce static int dummy_enc_opt_array(struct xdr_stream *xdr, 12089daf360SChristoph Hellwig const struct gssx_option_array *oa) 1211d658336SSimo Sorce { 1221d658336SSimo Sorce __be32 *p; 1231d658336SSimo Sorce 1241d658336SSimo Sorce if (oa->count != 0) 1251d658336SSimo Sorce return -EINVAL; 1261d658336SSimo Sorce 1271d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 1281d658336SSimo Sorce if (!p) 1291d658336SSimo Sorce return -ENOSPC; 1301d658336SSimo Sorce *p = 0; 1311d658336SSimo Sorce 1321d658336SSimo Sorce return 0; 1331d658336SSimo Sorce } 1341d658336SSimo Sorce 1351d658336SSimo Sorce static int dummy_dec_opt_array(struct xdr_stream *xdr, 1361d658336SSimo Sorce struct gssx_option_array *oa) 1371d658336SSimo Sorce { 1381d658336SSimo Sorce struct gssx_option dummy; 1391d658336SSimo Sorce u32 count, i; 1401d658336SSimo Sorce __be32 *p; 1411d658336SSimo Sorce 1421d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 1431d658336SSimo Sorce if (unlikely(p == NULL)) 1441d658336SSimo Sorce return -ENOSPC; 1451d658336SSimo Sorce count = be32_to_cpup(p++); 1461d658336SSimo Sorce memset(&dummy, 0, sizeof(dummy)); 1471d658336SSimo Sorce for (i = 0; i < count; i++) { 1481d658336SSimo Sorce gssx_dec_option(xdr, &dummy); 1491d658336SSimo Sorce } 1501d658336SSimo Sorce 1511d658336SSimo Sorce oa->count = 0; 1521d658336SSimo Sorce oa->data = NULL; 1531d658336SSimo Sorce return 0; 1541d658336SSimo Sorce } 1551d658336SSimo Sorce 1566a36978eSJ. Bruce Fields static int get_host_u32(struct xdr_stream *xdr, u32 *res) 1571d658336SSimo Sorce { 158778e512bSJ. Bruce Fields __be32 *p; 159778e512bSJ. Bruce Fields 160778e512bSJ. Bruce Fields p = xdr_inline_decode(xdr, 4); 161778e512bSJ. Bruce Fields if (!p) 1621d658336SSimo Sorce return -EINVAL; 1636a36978eSJ. Bruce Fields /* Contents of linux creds are all host-endian: */ 1646a36978eSJ. Bruce Fields memcpy(res, p, sizeof(u32)); 1651d658336SSimo Sorce return 0; 1661d658336SSimo Sorce } 1671d658336SSimo Sorce 1681d658336SSimo Sorce static int gssx_dec_linux_creds(struct xdr_stream *xdr, 1691d658336SSimo Sorce struct svc_cred *creds) 1701d658336SSimo Sorce { 1711d658336SSimo Sorce u32 length; 1721d658336SSimo Sorce __be32 *p; 1736a36978eSJ. Bruce Fields u32 tmp; 1746a36978eSJ. Bruce Fields u32 N; 1756a36978eSJ. Bruce Fields int i, err; 1761d658336SSimo Sorce 1771d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 1781d658336SSimo Sorce if (unlikely(p == NULL)) 1791d658336SSimo Sorce return -ENOSPC; 1801d658336SSimo Sorce 1811d658336SSimo Sorce length = be32_to_cpup(p); 1821d658336SSimo Sorce 183778e512bSJ. Bruce Fields if (length > (3 + NGROUPS_MAX) * sizeof(u32)) 1841d658336SSimo Sorce return -ENOSPC; 1851d658336SSimo Sorce 1861d658336SSimo Sorce /* uid */ 1876a36978eSJ. Bruce Fields err = get_host_u32(xdr, &tmp); 1881d658336SSimo Sorce if (err) 1891d658336SSimo Sorce return err; 190d28fcc83SJ. Bruce Fields creds->cr_uid = make_kuid(&init_user_ns, tmp); 1911d658336SSimo Sorce 1921d658336SSimo Sorce /* gid */ 1936a36978eSJ. Bruce Fields err = get_host_u32(xdr, &tmp); 1941d658336SSimo Sorce if (err) 1951d658336SSimo Sorce return err; 196d28fcc83SJ. Bruce Fields creds->cr_gid = make_kgid(&init_user_ns, tmp); 1971d658336SSimo Sorce 1981d658336SSimo Sorce /* number of additional gid's */ 1996a36978eSJ. Bruce Fields err = get_host_u32(xdr, &tmp); 2001d658336SSimo Sorce if (err) 2011d658336SSimo Sorce return err; 2021d658336SSimo Sorce N = tmp; 203778e512bSJ. Bruce Fields if ((3 + N) * sizeof(u32) != length) 204778e512bSJ. Bruce Fields return -EINVAL; 2051d658336SSimo Sorce creds->cr_group_info = groups_alloc(N); 2061d658336SSimo Sorce if (creds->cr_group_info == NULL) 2071d658336SSimo Sorce return -ENOMEM; 2081d658336SSimo Sorce 2091d658336SSimo Sorce /* gid's */ 2101d658336SSimo Sorce for (i = 0; i < N; i++) { 211d28fcc83SJ. Bruce Fields kgid_t kgid; 2126a36978eSJ. Bruce Fields err = get_host_u32(xdr, &tmp); 213d28fcc83SJ. Bruce Fields if (err) 214d28fcc83SJ. Bruce Fields goto out_free_groups; 215d28fcc83SJ. Bruce Fields err = -EINVAL; 216d28fcc83SJ. Bruce Fields kgid = make_kgid(&init_user_ns, tmp); 217d28fcc83SJ. Bruce Fields if (!gid_valid(kgid)) 218d28fcc83SJ. Bruce Fields goto out_free_groups; 21981243eacSAlexey Dobriyan creds->cr_group_info->gid[i] = kgid; 2201d658336SSimo Sorce } 221bdcf0a42SThiago Rafael Becker groups_sort(creds->cr_group_info); 2221d658336SSimo Sorce 2231d658336SSimo Sorce return 0; 224d28fcc83SJ. Bruce Fields out_free_groups: 225d28fcc83SJ. Bruce Fields groups_free(creds->cr_group_info); 226d28fcc83SJ. Bruce Fields return err; 2271d658336SSimo Sorce } 2281d658336SSimo Sorce 2291d658336SSimo Sorce static int gssx_dec_option_array(struct xdr_stream *xdr, 2301d658336SSimo Sorce struct gssx_option_array *oa) 2311d658336SSimo Sorce { 2321d658336SSimo Sorce struct svc_cred *creds; 2331d658336SSimo Sorce u32 count, i; 2341d658336SSimo Sorce __be32 *p; 2351d658336SSimo Sorce int err; 2361d658336SSimo Sorce 2371d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2381d658336SSimo Sorce if (unlikely(p == NULL)) 2391d658336SSimo Sorce return -ENOSPC; 2401d658336SSimo Sorce count = be32_to_cpup(p++); 2419fd40c5aSGeert Uytterhoeven if (!count) 2429fd40c5aSGeert Uytterhoeven return 0; 2439fd40c5aSGeert Uytterhoeven 2441d658336SSimo Sorce /* we recognize only 1 currently: CREDS_VALUE */ 2451d658336SSimo Sorce oa->count = 1; 2461d658336SSimo Sorce 2471d658336SSimo Sorce oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL); 2481d658336SSimo Sorce if (!oa->data) 2491d658336SSimo Sorce return -ENOMEM; 2501d658336SSimo Sorce 251034dd34fSJ. Bruce Fields creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL); 2521d658336SSimo Sorce if (!creds) { 2531d658336SSimo Sorce kfree(oa->data); 2541d658336SSimo Sorce return -ENOMEM; 2551d658336SSimo Sorce } 2561d658336SSimo Sorce 2571d658336SSimo Sorce oa->data[0].option.data = CREDS_VALUE; 2581d658336SSimo Sorce oa->data[0].option.len = sizeof(CREDS_VALUE); 2591d658336SSimo Sorce oa->data[0].value.data = (void *)creds; 2601d658336SSimo Sorce oa->data[0].value.len = 0; 2619fd40c5aSGeert Uytterhoeven 2621d658336SSimo Sorce for (i = 0; i < count; i++) { 2631d658336SSimo Sorce gssx_buffer dummy = { 0, NULL }; 2641d658336SSimo Sorce u32 length; 2651d658336SSimo Sorce 2661d658336SSimo Sorce /* option buffer */ 2671d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2681d658336SSimo Sorce if (unlikely(p == NULL)) 2691d658336SSimo Sorce return -ENOSPC; 2701d658336SSimo Sorce 2711d658336SSimo Sorce length = be32_to_cpup(p); 2721d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 2731d658336SSimo Sorce if (unlikely(p == NULL)) 2741d658336SSimo Sorce return -ENOSPC; 2751d658336SSimo Sorce 2761d658336SSimo Sorce if (length == sizeof(CREDS_VALUE) && 2771d658336SSimo Sorce memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) { 2781d658336SSimo Sorce /* We have creds here. parse them */ 2791d658336SSimo Sorce err = gssx_dec_linux_creds(xdr, creds); 2801d658336SSimo Sorce if (err) 2811d658336SSimo Sorce return err; 2821d658336SSimo Sorce oa->data[0].value.len = 1; /* presence */ 2831d658336SSimo Sorce } else { 2841d658336SSimo Sorce /* consume uninteresting buffer */ 2851d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy); 2861d658336SSimo Sorce if (err) 2871d658336SSimo Sorce return err; 2881d658336SSimo Sorce } 2891d658336SSimo Sorce } 2901d658336SSimo Sorce return 0; 2911d658336SSimo Sorce } 2921d658336SSimo Sorce 2931d658336SSimo Sorce static int gssx_dec_status(struct xdr_stream *xdr, 2941d658336SSimo Sorce struct gssx_status *status) 2951d658336SSimo Sorce { 2961d658336SSimo Sorce __be32 *p; 2971d658336SSimo Sorce int err; 2981d658336SSimo Sorce 2991d658336SSimo Sorce /* status->major_status */ 3001d658336SSimo Sorce p = xdr_inline_decode(xdr, 8); 3011d658336SSimo Sorce if (unlikely(p == NULL)) 3021d658336SSimo Sorce return -ENOSPC; 3031d658336SSimo Sorce p = xdr_decode_hyper(p, &status->major_status); 3041d658336SSimo Sorce 3051d658336SSimo Sorce /* status->mech */ 3061d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->mech); 3071d658336SSimo Sorce if (err) 3081d658336SSimo Sorce return err; 3091d658336SSimo Sorce 3101d658336SSimo Sorce /* status->minor_status */ 3111d658336SSimo Sorce p = xdr_inline_decode(xdr, 8); 3121d658336SSimo Sorce if (unlikely(p == NULL)) 3131d658336SSimo Sorce return -ENOSPC; 3141d658336SSimo Sorce p = xdr_decode_hyper(p, &status->minor_status); 3151d658336SSimo Sorce 3161d658336SSimo Sorce /* status->major_status_string */ 3171d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->major_status_string); 3181d658336SSimo Sorce if (err) 3191d658336SSimo Sorce return err; 3201d658336SSimo Sorce 3211d658336SSimo Sorce /* status->minor_status_string */ 3221d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->minor_status_string); 3231d658336SSimo Sorce if (err) 3241d658336SSimo Sorce return err; 3251d658336SSimo Sorce 3261d658336SSimo Sorce /* status->server_ctx */ 3271d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->server_ctx); 3281d658336SSimo Sorce if (err) 3291d658336SSimo Sorce return err; 3301d658336SSimo Sorce 3311d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 3321d658336SSimo Sorce /* status->options */ 3331d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &status->options); 3341d658336SSimo Sorce 3351d658336SSimo Sorce return err; 3361d658336SSimo Sorce } 3371d658336SSimo Sorce 3381d658336SSimo Sorce static int gssx_enc_call_ctx(struct xdr_stream *xdr, 33989daf360SChristoph Hellwig const struct gssx_call_ctx *ctx) 3401d658336SSimo Sorce { 3411d658336SSimo Sorce struct gssx_option opt; 3421d658336SSimo Sorce __be32 *p; 3431d658336SSimo Sorce int err; 3441d658336SSimo Sorce 3451d658336SSimo Sorce /* ctx->locale */ 3461d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->locale); 3471d658336SSimo Sorce if (err) 3481d658336SSimo Sorce return err; 3491d658336SSimo Sorce 3501d658336SSimo Sorce /* ctx->server_ctx */ 3511d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->server_ctx); 3521d658336SSimo Sorce if (err) 3531d658336SSimo Sorce return err; 3541d658336SSimo Sorce 3551d658336SSimo Sorce /* we always want to ask for lucid contexts */ 3561d658336SSimo Sorce /* ctx->options */ 3571d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 3581d658336SSimo Sorce *p = cpu_to_be32(2); 3591d658336SSimo Sorce 3601d658336SSimo Sorce /* we want a lucid_v1 context */ 3611d658336SSimo Sorce opt.option.data = LUCID_OPTION; 3621d658336SSimo Sorce opt.option.len = sizeof(LUCID_OPTION); 3631d658336SSimo Sorce opt.value.data = LUCID_VALUE; 3641d658336SSimo Sorce opt.value.len = sizeof(LUCID_VALUE); 3651d658336SSimo Sorce err = gssx_enc_option(xdr, &opt); 3661d658336SSimo Sorce 3671d658336SSimo Sorce /* ..and user creds */ 3681d658336SSimo Sorce opt.option.data = CREDS_OPTION; 3691d658336SSimo Sorce opt.option.len = sizeof(CREDS_OPTION); 3701d658336SSimo Sorce opt.value.data = CREDS_VALUE; 3711d658336SSimo Sorce opt.value.len = sizeof(CREDS_VALUE); 3721d658336SSimo Sorce err = gssx_enc_option(xdr, &opt); 3731d658336SSimo Sorce 3741d658336SSimo Sorce return err; 3751d658336SSimo Sorce } 3761d658336SSimo Sorce 3771d658336SSimo Sorce static int gssx_dec_name_attr(struct xdr_stream *xdr, 3781d658336SSimo Sorce struct gssx_name_attr *attr) 3791d658336SSimo Sorce { 3801d658336SSimo Sorce int err; 3811d658336SSimo Sorce 3821d658336SSimo Sorce /* attr->attr */ 3831d658336SSimo Sorce err = gssx_dec_buffer(xdr, &attr->attr); 3841d658336SSimo Sorce if (err) 3851d658336SSimo Sorce return err; 3861d658336SSimo Sorce 3871d658336SSimo Sorce /* attr->value */ 3881d658336SSimo Sorce err = gssx_dec_buffer(xdr, &attr->value); 3891d658336SSimo Sorce if (err) 3901d658336SSimo Sorce return err; 3911d658336SSimo Sorce 3921d658336SSimo Sorce /* attr->extensions */ 3931d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &attr->extensions); 3941d658336SSimo Sorce 3951d658336SSimo Sorce return err; 3961d658336SSimo Sorce } 3971d658336SSimo Sorce 3981d658336SSimo Sorce static int dummy_enc_nameattr_array(struct xdr_stream *xdr, 3991d658336SSimo Sorce struct gssx_name_attr_array *naa) 4001d658336SSimo Sorce { 4011d658336SSimo Sorce __be32 *p; 4021d658336SSimo Sorce 4031d658336SSimo Sorce if (naa->count != 0) 4041d658336SSimo Sorce return -EINVAL; 4051d658336SSimo Sorce 4061d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 4071d658336SSimo Sorce if (!p) 4081d658336SSimo Sorce return -ENOSPC; 4091d658336SSimo Sorce *p = 0; 4101d658336SSimo Sorce 4111d658336SSimo Sorce return 0; 4121d658336SSimo Sorce } 4131d658336SSimo Sorce 4141d658336SSimo Sorce static int dummy_dec_nameattr_array(struct xdr_stream *xdr, 4151d658336SSimo Sorce struct gssx_name_attr_array *naa) 4161d658336SSimo Sorce { 417dc43376cSJ. Bruce Fields struct gssx_name_attr dummy = { .attr = {.len = 0} }; 4181d658336SSimo Sorce u32 count, i; 4191d658336SSimo Sorce __be32 *p; 4201d658336SSimo Sorce 4211d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 4221d658336SSimo Sorce if (unlikely(p == NULL)) 4231d658336SSimo Sorce return -ENOSPC; 4241d658336SSimo Sorce count = be32_to_cpup(p++); 4251d658336SSimo Sorce for (i = 0; i < count; i++) { 4261d658336SSimo Sorce gssx_dec_name_attr(xdr, &dummy); 4271d658336SSimo Sorce } 4281d658336SSimo Sorce 4291d658336SSimo Sorce naa->count = 0; 4301d658336SSimo Sorce naa->data = NULL; 4311d658336SSimo Sorce return 0; 4321d658336SSimo Sorce } 4331d658336SSimo Sorce 4341d658336SSimo Sorce static struct xdr_netobj zero_netobj = {}; 4351d658336SSimo Sorce 4361d658336SSimo Sorce static struct gssx_name_attr_array zero_name_attr_array = {}; 4371d658336SSimo Sorce 4381d658336SSimo Sorce static struct gssx_option_array zero_option_array = {}; 4391d658336SSimo Sorce 4401d658336SSimo Sorce static int gssx_enc_name(struct xdr_stream *xdr, 4411d658336SSimo Sorce struct gssx_name *name) 4421d658336SSimo Sorce { 4431d658336SSimo Sorce int err; 4441d658336SSimo Sorce 4451d658336SSimo Sorce /* name->display_name */ 4461d658336SSimo Sorce err = gssx_enc_buffer(xdr, &name->display_name); 4471d658336SSimo Sorce if (err) 4481d658336SSimo Sorce return err; 4491d658336SSimo Sorce 4501d658336SSimo Sorce /* name->name_type */ 4511d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4521d658336SSimo Sorce if (err) 4531d658336SSimo Sorce return err; 4541d658336SSimo Sorce 4551d658336SSimo Sorce /* name->exported_name */ 4561d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4571d658336SSimo Sorce if (err) 4581d658336SSimo Sorce return err; 4591d658336SSimo Sorce 4601d658336SSimo Sorce /* name->exported_composite_name */ 4611d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4621d658336SSimo Sorce if (err) 4631d658336SSimo Sorce return err; 4641d658336SSimo Sorce 4651d658336SSimo Sorce /* leave name_attributes empty for now, will add once we have any 4661d658336SSimo Sorce * to pass up at all */ 4671d658336SSimo Sorce /* name->name_attributes */ 4681d658336SSimo Sorce err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array); 4691d658336SSimo Sorce if (err) 4701d658336SSimo Sorce return err; 4711d658336SSimo Sorce 4721d658336SSimo Sorce /* leave options empty for now, will add once we have any options 4731d658336SSimo Sorce * to pass up at all */ 4741d658336SSimo Sorce /* name->extensions */ 4751d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &zero_option_array); 4761d658336SSimo Sorce 4771d658336SSimo Sorce return err; 4781d658336SSimo Sorce } 4791d658336SSimo Sorce 480dc43376cSJ. Bruce Fields 4811d658336SSimo Sorce static int gssx_dec_name(struct xdr_stream *xdr, 4821d658336SSimo Sorce struct gssx_name *name) 4831d658336SSimo Sorce { 484dc43376cSJ. Bruce Fields struct xdr_netobj dummy_netobj = { .len = 0 }; 485dc43376cSJ. Bruce Fields struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 }; 486dc43376cSJ. Bruce Fields struct gssx_option_array dummy_option_array = { .count = 0 }; 4871d658336SSimo Sorce int err; 4881d658336SSimo Sorce 4891d658336SSimo Sorce /* name->display_name */ 4901d658336SSimo Sorce err = gssx_dec_buffer(xdr, &name->display_name); 4911d658336SSimo Sorce if (err) 4921d658336SSimo Sorce return err; 4931d658336SSimo Sorce 4941d658336SSimo Sorce /* name->name_type */ 4951d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 4961d658336SSimo Sorce if (err) 4971d658336SSimo Sorce return err; 4981d658336SSimo Sorce 4991d658336SSimo Sorce /* name->exported_name */ 5001d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5011d658336SSimo Sorce if (err) 5021d658336SSimo Sorce return err; 5031d658336SSimo Sorce 5041d658336SSimo Sorce /* name->exported_composite_name */ 5051d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5061d658336SSimo Sorce if (err) 5071d658336SSimo Sorce return err; 5081d658336SSimo Sorce 5091d658336SSimo Sorce /* we assume we have no attributes for now, so simply consume them */ 5101d658336SSimo Sorce /* name->name_attributes */ 5111d658336SSimo Sorce err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array); 5121d658336SSimo Sorce if (err) 5131d658336SSimo Sorce return err; 5141d658336SSimo Sorce 5151d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 5161d658336SSimo Sorce /* name->extensions */ 5171d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &dummy_option_array); 5181d658336SSimo Sorce 5191d658336SSimo Sorce return err; 5201d658336SSimo Sorce } 5211d658336SSimo Sorce 5221d658336SSimo Sorce static int dummy_enc_credel_array(struct xdr_stream *xdr, 5231d658336SSimo Sorce struct gssx_cred_element_array *cea) 5241d658336SSimo Sorce { 5251d658336SSimo Sorce __be32 *p; 5261d658336SSimo Sorce 5271d658336SSimo Sorce if (cea->count != 0) 5281d658336SSimo Sorce return -EINVAL; 5291d658336SSimo Sorce 5301d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 5311d658336SSimo Sorce if (!p) 5321d658336SSimo Sorce return -ENOSPC; 5331d658336SSimo Sorce *p = 0; 5341d658336SSimo Sorce 5351d658336SSimo Sorce return 0; 5361d658336SSimo Sorce } 5371d658336SSimo Sorce 5381d658336SSimo Sorce static int gssx_enc_cred(struct xdr_stream *xdr, 5391d658336SSimo Sorce struct gssx_cred *cred) 5401d658336SSimo Sorce { 5411d658336SSimo Sorce int err; 5421d658336SSimo Sorce 5431d658336SSimo Sorce /* cred->desired_name */ 5441d658336SSimo Sorce err = gssx_enc_name(xdr, &cred->desired_name); 5451d658336SSimo Sorce if (err) 5461d658336SSimo Sorce return err; 5471d658336SSimo Sorce 5481d658336SSimo Sorce /* cred->elements */ 5491d658336SSimo Sorce err = dummy_enc_credel_array(xdr, &cred->elements); 550b26ec9b1SJ. Bruce Fields if (err) 551b26ec9b1SJ. Bruce Fields return err; 5521d658336SSimo Sorce 5531d658336SSimo Sorce /* cred->cred_handle_reference */ 5541d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cred->cred_handle_reference); 5551d658336SSimo Sorce if (err) 5561d658336SSimo Sorce return err; 5571d658336SSimo Sorce 5581d658336SSimo Sorce /* cred->needs_release */ 5591d658336SSimo Sorce err = gssx_enc_bool(xdr, cred->needs_release); 5601d658336SSimo Sorce 5611d658336SSimo Sorce return err; 5621d658336SSimo Sorce } 5631d658336SSimo Sorce 5641d658336SSimo Sorce static int gssx_enc_ctx(struct xdr_stream *xdr, 5651d658336SSimo Sorce struct gssx_ctx *ctx) 5661d658336SSimo Sorce { 5671d658336SSimo Sorce __be32 *p; 5681d658336SSimo Sorce int err; 5691d658336SSimo Sorce 5701d658336SSimo Sorce /* ctx->exported_context_token */ 5711d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->exported_context_token); 5721d658336SSimo Sorce if (err) 5731d658336SSimo Sorce return err; 5741d658336SSimo Sorce 5751d658336SSimo Sorce /* ctx->state */ 5761d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->state); 5771d658336SSimo Sorce if (err) 5781d658336SSimo Sorce return err; 5791d658336SSimo Sorce 5801d658336SSimo Sorce /* ctx->need_release */ 5811d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->need_release); 5821d658336SSimo Sorce if (err) 5831d658336SSimo Sorce return err; 5841d658336SSimo Sorce 5851d658336SSimo Sorce /* ctx->mech */ 5861d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->mech); 5871d658336SSimo Sorce if (err) 5881d658336SSimo Sorce return err; 5891d658336SSimo Sorce 5901d658336SSimo Sorce /* ctx->src_name */ 5911d658336SSimo Sorce err = gssx_enc_name(xdr, &ctx->src_name); 5921d658336SSimo Sorce if (err) 5931d658336SSimo Sorce return err; 5941d658336SSimo Sorce 5951d658336SSimo Sorce /* ctx->targ_name */ 5961d658336SSimo Sorce err = gssx_enc_name(xdr, &ctx->targ_name); 5971d658336SSimo Sorce if (err) 5981d658336SSimo Sorce return err; 5991d658336SSimo Sorce 6001d658336SSimo Sorce /* ctx->lifetime */ 6011d658336SSimo Sorce p = xdr_reserve_space(xdr, 8+8); 6021d658336SSimo Sorce if (!p) 6031d658336SSimo Sorce return -ENOSPC; 6041d658336SSimo Sorce p = xdr_encode_hyper(p, ctx->lifetime); 6051d658336SSimo Sorce 6061d658336SSimo Sorce /* ctx->ctx_flags */ 6071d658336SSimo Sorce p = xdr_encode_hyper(p, ctx->ctx_flags); 6081d658336SSimo Sorce 6091d658336SSimo Sorce /* ctx->locally_initiated */ 6101d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->locally_initiated); 6111d658336SSimo Sorce if (err) 6121d658336SSimo Sorce return err; 6131d658336SSimo Sorce 6141d658336SSimo Sorce /* ctx->open */ 6151d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->open); 6161d658336SSimo Sorce if (err) 6171d658336SSimo Sorce return err; 6181d658336SSimo Sorce 6191d658336SSimo Sorce /* leave options empty for now, will add once we have any options 6201d658336SSimo Sorce * to pass up at all */ 6211d658336SSimo Sorce /* ctx->options */ 6221d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &ctx->options); 6231d658336SSimo Sorce 6241d658336SSimo Sorce return err; 6251d658336SSimo Sorce } 6261d658336SSimo Sorce 6271d658336SSimo Sorce static int gssx_dec_ctx(struct xdr_stream *xdr, 6281d658336SSimo Sorce struct gssx_ctx *ctx) 6291d658336SSimo Sorce { 6301d658336SSimo Sorce __be32 *p; 6311d658336SSimo Sorce int err; 6321d658336SSimo Sorce 6331d658336SSimo Sorce /* ctx->exported_context_token */ 6341d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->exported_context_token); 6351d658336SSimo Sorce if (err) 6361d658336SSimo Sorce return err; 6371d658336SSimo Sorce 6381d658336SSimo Sorce /* ctx->state */ 6391d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->state); 6401d658336SSimo Sorce if (err) 6411d658336SSimo Sorce return err; 6421d658336SSimo Sorce 6431d658336SSimo Sorce /* ctx->need_release */ 6441d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->need_release); 6451d658336SSimo Sorce if (err) 6461d658336SSimo Sorce return err; 6471d658336SSimo Sorce 6481d658336SSimo Sorce /* ctx->mech */ 6491d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->mech); 6501d658336SSimo Sorce if (err) 6511d658336SSimo Sorce return err; 6521d658336SSimo Sorce 6531d658336SSimo Sorce /* ctx->src_name */ 6541d658336SSimo Sorce err = gssx_dec_name(xdr, &ctx->src_name); 6551d658336SSimo Sorce if (err) 6561d658336SSimo Sorce return err; 6571d658336SSimo Sorce 6581d658336SSimo Sorce /* ctx->targ_name */ 6591d658336SSimo Sorce err = gssx_dec_name(xdr, &ctx->targ_name); 6601d658336SSimo Sorce if (err) 6611d658336SSimo Sorce return err; 6621d658336SSimo Sorce 6631d658336SSimo Sorce /* ctx->lifetime */ 6641d658336SSimo Sorce p = xdr_inline_decode(xdr, 8+8); 6651d658336SSimo Sorce if (unlikely(p == NULL)) 6661d658336SSimo Sorce return -ENOSPC; 6671d658336SSimo Sorce p = xdr_decode_hyper(p, &ctx->lifetime); 6681d658336SSimo Sorce 6691d658336SSimo Sorce /* ctx->ctx_flags */ 6701d658336SSimo Sorce p = xdr_decode_hyper(p, &ctx->ctx_flags); 6711d658336SSimo Sorce 6721d658336SSimo Sorce /* ctx->locally_initiated */ 6731d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->locally_initiated); 6741d658336SSimo Sorce if (err) 6751d658336SSimo Sorce return err; 6761d658336SSimo Sorce 6771d658336SSimo Sorce /* ctx->open */ 6781d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->open); 6791d658336SSimo Sorce if (err) 6801d658336SSimo Sorce return err; 6811d658336SSimo Sorce 6821d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 6831d658336SSimo Sorce /* ctx->options */ 6841d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &ctx->options); 6851d658336SSimo Sorce 6861d658336SSimo Sorce return err; 6871d658336SSimo Sorce } 6881d658336SSimo Sorce 6891d658336SSimo Sorce static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb) 6901d658336SSimo Sorce { 6911d658336SSimo Sorce __be32 *p; 6921d658336SSimo Sorce int err; 6931d658336SSimo Sorce 6941d658336SSimo Sorce /* cb->initiator_addrtype */ 6951d658336SSimo Sorce p = xdr_reserve_space(xdr, 8); 6961d658336SSimo Sorce if (!p) 6971d658336SSimo Sorce return -ENOSPC; 6981d658336SSimo Sorce p = xdr_encode_hyper(p, cb->initiator_addrtype); 6991d658336SSimo Sorce 7001d658336SSimo Sorce /* cb->initiator_address */ 7011d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->initiator_address); 7021d658336SSimo Sorce if (err) 7031d658336SSimo Sorce return err; 7041d658336SSimo Sorce 7051d658336SSimo Sorce /* cb->acceptor_addrtype */ 7061d658336SSimo Sorce p = xdr_reserve_space(xdr, 8); 7071d658336SSimo Sorce if (!p) 7081d658336SSimo Sorce return -ENOSPC; 7091d658336SSimo Sorce p = xdr_encode_hyper(p, cb->acceptor_addrtype); 7101d658336SSimo Sorce 7111d658336SSimo Sorce /* cb->acceptor_address */ 7121d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->acceptor_address); 7131d658336SSimo Sorce if (err) 7141d658336SSimo Sorce return err; 7151d658336SSimo Sorce 7161d658336SSimo Sorce /* cb->application_data */ 7171d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->application_data); 7181d658336SSimo Sorce 7191d658336SSimo Sorce return err; 7201d658336SSimo Sorce } 7211d658336SSimo Sorce 7221d658336SSimo Sorce void gssx_enc_accept_sec_context(struct rpc_rqst *req, 7231d658336SSimo Sorce struct xdr_stream *xdr, 72489daf360SChristoph Hellwig const void *data) 7251d658336SSimo Sorce { 72689daf360SChristoph Hellwig const struct gssx_arg_accept_sec_context *arg = data; 7271d658336SSimo Sorce int err; 7281d658336SSimo Sorce 7291d658336SSimo Sorce err = gssx_enc_call_ctx(xdr, &arg->call_ctx); 7301d658336SSimo Sorce if (err) 7311d658336SSimo Sorce goto done; 7321d658336SSimo Sorce 7331d658336SSimo Sorce /* arg->context_handle */ 734b26ec9b1SJ. Bruce Fields if (arg->context_handle) 7351d658336SSimo Sorce err = gssx_enc_ctx(xdr, arg->context_handle); 736b26ec9b1SJ. Bruce Fields else 737b26ec9b1SJ. Bruce Fields err = gssx_enc_bool(xdr, 0); 7381d658336SSimo Sorce if (err) 7391d658336SSimo Sorce goto done; 7401d658336SSimo Sorce 7411d658336SSimo Sorce /* arg->cred_handle */ 742b26ec9b1SJ. Bruce Fields if (arg->cred_handle) 7431d658336SSimo Sorce err = gssx_enc_cred(xdr, arg->cred_handle); 744b26ec9b1SJ. Bruce Fields else 745b26ec9b1SJ. Bruce Fields err = gssx_enc_bool(xdr, 0); 7461d658336SSimo Sorce if (err) 7471d658336SSimo Sorce goto done; 7481d658336SSimo Sorce 7491d658336SSimo Sorce /* arg->input_token */ 7501d658336SSimo Sorce err = gssx_enc_in_token(xdr, &arg->input_token); 7511d658336SSimo Sorce if (err) 7521d658336SSimo Sorce goto done; 7531d658336SSimo Sorce 7541d658336SSimo Sorce /* arg->input_cb */ 755b26ec9b1SJ. Bruce Fields if (arg->input_cb) 7561d658336SSimo Sorce err = gssx_enc_cb(xdr, arg->input_cb); 757b26ec9b1SJ. Bruce Fields else 758b26ec9b1SJ. Bruce Fields err = gssx_enc_bool(xdr, 0); 7591d658336SSimo Sorce if (err) 7601d658336SSimo Sorce goto done; 7611d658336SSimo Sorce 7621d658336SSimo Sorce err = gssx_enc_bool(xdr, arg->ret_deleg_cred); 7631d658336SSimo Sorce if (err) 7641d658336SSimo Sorce goto done; 7651d658336SSimo Sorce 7661d658336SSimo Sorce /* leave options empty for now, will add once we have any options 7671d658336SSimo Sorce * to pass up at all */ 7681d658336SSimo Sorce /* arg->options */ 7691d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &arg->options); 7701d658336SSimo Sorce 7719dfd87daSJ. Bruce Fields xdr_inline_pages(&req->rq_rcv_buf, 7729dfd87daSJ. Bruce Fields PAGE_SIZE/2 /* pretty arbitrary */, 7739dfd87daSJ. Bruce Fields arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE); 774431f6eb3STrond Myklebust req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; 7751d658336SSimo Sorce done: 7761d658336SSimo Sorce if (err) 7771d658336SSimo Sorce dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); 7781d658336SSimo Sorce } 7791d658336SSimo Sorce 7801d658336SSimo Sorce int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, 7811d658336SSimo Sorce struct xdr_stream *xdr, 782305c6241SChristoph Hellwig void *data) 7831d658336SSimo Sorce { 784305c6241SChristoph Hellwig struct gssx_res_accept_sec_context *res = data; 785fb43f11cSJ. Bruce Fields u32 value_follows; 7861d658336SSimo Sorce int err; 7879507271dSScott Mayhew struct page *scratch; 7889507271dSScott Mayhew 7899507271dSScott Mayhew scratch = alloc_page(GFP_KERNEL); 7909507271dSScott Mayhew if (!scratch) 7919507271dSScott Mayhew return -ENOMEM; 792*0ae4c3e8SChuck Lever xdr_set_scratch_page(xdr, scratch); 7931d658336SSimo Sorce 7941d658336SSimo Sorce /* res->status */ 7951d658336SSimo Sorce err = gssx_dec_status(xdr, &res->status); 7961d658336SSimo Sorce if (err) 7979507271dSScott Mayhew goto out_free; 7981d658336SSimo Sorce 7991d658336SSimo Sorce /* res->context_handle */ 800fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 801fb43f11cSJ. Bruce Fields if (err) 8029507271dSScott Mayhew goto out_free; 803fb43f11cSJ. Bruce Fields if (value_follows) { 8041d658336SSimo Sorce err = gssx_dec_ctx(xdr, res->context_handle); 8051d658336SSimo Sorce if (err) 8069507271dSScott Mayhew goto out_free; 8071d658336SSimo Sorce } else { 8081d658336SSimo Sorce res->context_handle = NULL; 8091d658336SSimo Sorce } 8101d658336SSimo Sorce 8111d658336SSimo Sorce /* res->output_token */ 812fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 813fb43f11cSJ. Bruce Fields if (err) 8149507271dSScott Mayhew goto out_free; 815fb43f11cSJ. Bruce Fields if (value_follows) { 8161d658336SSimo Sorce err = gssx_dec_buffer(xdr, res->output_token); 8171d658336SSimo Sorce if (err) 8189507271dSScott Mayhew goto out_free; 8191d658336SSimo Sorce } else { 8201d658336SSimo Sorce res->output_token = NULL; 8211d658336SSimo Sorce } 8221d658336SSimo Sorce 8231d658336SSimo Sorce /* res->delegated_cred_handle */ 824fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 825fb43f11cSJ. Bruce Fields if (err) 8269507271dSScott Mayhew goto out_free; 827fb43f11cSJ. Bruce Fields if (value_follows) { 8281d658336SSimo Sorce /* we do not support upcall servers sending this data. */ 8299507271dSScott Mayhew err = -EINVAL; 8309507271dSScott Mayhew goto out_free; 8311d658336SSimo Sorce } 8321d658336SSimo Sorce 8331d658336SSimo Sorce /* res->options */ 8341d658336SSimo Sorce err = gssx_dec_option_array(xdr, &res->options); 8351d658336SSimo Sorce 8369507271dSScott Mayhew out_free: 8379507271dSScott Mayhew __free_page(scratch); 8381d658336SSimo Sorce return err; 8391d658336SSimo Sorce } 840