11d658336SSimo Sorce /* 21d658336SSimo Sorce * GSS Proxy upcall module 31d658336SSimo Sorce * 41d658336SSimo Sorce * Copyright (C) 2012 Simo Sorce <simo@redhat.com> 51d658336SSimo Sorce * 61d658336SSimo Sorce * This program is free software; you can redistribute it and/or modify 71d658336SSimo Sorce * it under the terms of the GNU General Public License as published by 81d658336SSimo Sorce * the Free Software Foundation; either version 2 of the License, or 91d658336SSimo Sorce * (at your option) any later version. 101d658336SSimo Sorce * 111d658336SSimo Sorce * This program is distributed in the hope that it will be useful, 121d658336SSimo Sorce * but WITHOUT ANY WARRANTY; without even the implied warranty of 131d658336SSimo Sorce * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141d658336SSimo Sorce * GNU General Public License for more details. 151d658336SSimo Sorce * 161d658336SSimo Sorce * You should have received a copy of the GNU General Public License 171d658336SSimo Sorce * along with this program; if not, write to the Free Software 181d658336SSimo Sorce * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 191d658336SSimo Sorce */ 201d658336SSimo Sorce 211d658336SSimo Sorce #include <linux/sunrpc/svcauth.h> 221d658336SSimo Sorce #include "gss_rpc_xdr.h" 231d658336SSimo Sorce 241d658336SSimo Sorce static int gssx_enc_bool(struct xdr_stream *xdr, int v) 251d658336SSimo Sorce { 261d658336SSimo Sorce __be32 *p; 271d658336SSimo Sorce 281d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 291d658336SSimo Sorce if (unlikely(p == NULL)) 301d658336SSimo Sorce return -ENOSPC; 311d658336SSimo Sorce *p = v ? xdr_one : xdr_zero; 321d658336SSimo Sorce return 0; 331d658336SSimo Sorce } 341d658336SSimo Sorce 351d658336SSimo Sorce static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v) 361d658336SSimo Sorce { 371d658336SSimo Sorce __be32 *p; 381d658336SSimo Sorce 391d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 401d658336SSimo Sorce if (unlikely(p == NULL)) 411d658336SSimo Sorce return -ENOSPC; 421d658336SSimo Sorce *v = be32_to_cpu(*p); 431d658336SSimo Sorce return 0; 441d658336SSimo Sorce } 451d658336SSimo Sorce 461d658336SSimo Sorce static int gssx_enc_buffer(struct xdr_stream *xdr, 471d658336SSimo Sorce gssx_buffer *buf) 481d658336SSimo Sorce { 491d658336SSimo Sorce __be32 *p; 501d658336SSimo Sorce 511d658336SSimo Sorce p = xdr_reserve_space(xdr, sizeof(u32) + buf->len); 521d658336SSimo Sorce if (!p) 531d658336SSimo Sorce return -ENOSPC; 541d658336SSimo Sorce xdr_encode_opaque(p, buf->data, buf->len); 551d658336SSimo Sorce return 0; 561d658336SSimo Sorce } 571d658336SSimo Sorce 581d658336SSimo Sorce static int gssx_enc_in_token(struct xdr_stream *xdr, 591d658336SSimo Sorce struct gssp_in_token *in) 601d658336SSimo Sorce { 611d658336SSimo Sorce __be32 *p; 621d658336SSimo Sorce 631d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 641d658336SSimo Sorce if (!p) 651d658336SSimo Sorce return -ENOSPC; 661d658336SSimo Sorce *p = cpu_to_be32(in->page_len); 671d658336SSimo Sorce 681d658336SSimo Sorce /* all we need to do is to write pages */ 691d658336SSimo Sorce xdr_write_pages(xdr, in->pages, in->page_base, in->page_len); 701d658336SSimo Sorce 711d658336SSimo Sorce return 0; 721d658336SSimo Sorce } 731d658336SSimo Sorce 741d658336SSimo Sorce 751d658336SSimo Sorce static int gssx_dec_buffer(struct xdr_stream *xdr, 761d658336SSimo Sorce gssx_buffer *buf) 771d658336SSimo Sorce { 781d658336SSimo Sorce u32 length; 791d658336SSimo Sorce __be32 *p; 801d658336SSimo Sorce 811d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 821d658336SSimo Sorce if (unlikely(p == NULL)) 831d658336SSimo Sorce return -ENOSPC; 841d658336SSimo Sorce 851d658336SSimo Sorce length = be32_to_cpup(p); 861d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 871d658336SSimo Sorce if (unlikely(p == NULL)) 881d658336SSimo Sorce return -ENOSPC; 891d658336SSimo Sorce 901d658336SSimo Sorce if (buf->len == 0) { 911d658336SSimo Sorce /* we intentionally are not interested in this buffer */ 921d658336SSimo Sorce return 0; 931d658336SSimo Sorce } 941d658336SSimo Sorce if (length > buf->len) 951d658336SSimo Sorce return -ENOSPC; 961d658336SSimo Sorce 971d658336SSimo Sorce if (!buf->data) { 981d658336SSimo Sorce buf->data = kmemdup(p, length, GFP_KERNEL); 991d658336SSimo Sorce if (!buf->data) 1001d658336SSimo Sorce return -ENOMEM; 1011d658336SSimo Sorce } else { 1021d658336SSimo Sorce memcpy(buf->data, p, length); 1031d658336SSimo Sorce } 1041d658336SSimo Sorce buf->len = length; 1051d658336SSimo Sorce return 0; 1061d658336SSimo Sorce } 1071d658336SSimo Sorce 1081d658336SSimo Sorce static int gssx_enc_option(struct xdr_stream *xdr, 1091d658336SSimo Sorce struct gssx_option *opt) 1101d658336SSimo Sorce { 1111d658336SSimo Sorce int err; 1121d658336SSimo Sorce 1131d658336SSimo Sorce err = gssx_enc_buffer(xdr, &opt->option); 1141d658336SSimo Sorce if (err) 1151d658336SSimo Sorce return err; 1161d658336SSimo Sorce err = gssx_enc_buffer(xdr, &opt->value); 1171d658336SSimo Sorce return err; 1181d658336SSimo Sorce } 1191d658336SSimo Sorce 1201d658336SSimo Sorce static int gssx_dec_option(struct xdr_stream *xdr, 1211d658336SSimo Sorce struct gssx_option *opt) 1221d658336SSimo Sorce { 1231d658336SSimo Sorce int err; 1241d658336SSimo Sorce 1251d658336SSimo Sorce err = gssx_dec_buffer(xdr, &opt->option); 1261d658336SSimo Sorce if (err) 1271d658336SSimo Sorce return err; 1281d658336SSimo Sorce err = gssx_dec_buffer(xdr, &opt->value); 1291d658336SSimo Sorce return err; 1301d658336SSimo Sorce } 1311d658336SSimo Sorce 1321d658336SSimo Sorce static int dummy_enc_opt_array(struct xdr_stream *xdr, 1331d658336SSimo Sorce struct gssx_option_array *oa) 1341d658336SSimo Sorce { 1351d658336SSimo Sorce __be32 *p; 1361d658336SSimo Sorce 1371d658336SSimo Sorce if (oa->count != 0) 1381d658336SSimo Sorce return -EINVAL; 1391d658336SSimo Sorce 1401d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 1411d658336SSimo Sorce if (!p) 1421d658336SSimo Sorce return -ENOSPC; 1431d658336SSimo Sorce *p = 0; 1441d658336SSimo Sorce 1451d658336SSimo Sorce return 0; 1461d658336SSimo Sorce } 1471d658336SSimo Sorce 1481d658336SSimo Sorce static int dummy_dec_opt_array(struct xdr_stream *xdr, 1491d658336SSimo Sorce struct gssx_option_array *oa) 1501d658336SSimo Sorce { 1511d658336SSimo Sorce struct gssx_option dummy; 1521d658336SSimo Sorce u32 count, i; 1531d658336SSimo Sorce __be32 *p; 1541d658336SSimo Sorce 1551d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 1561d658336SSimo Sorce if (unlikely(p == NULL)) 1571d658336SSimo Sorce return -ENOSPC; 1581d658336SSimo Sorce count = be32_to_cpup(p++); 1591d658336SSimo Sorce memset(&dummy, 0, sizeof(dummy)); 1601d658336SSimo Sorce for (i = 0; i < count; i++) { 1611d658336SSimo Sorce gssx_dec_option(xdr, &dummy); 1621d658336SSimo Sorce } 1631d658336SSimo Sorce 1641d658336SSimo Sorce oa->count = 0; 1651d658336SSimo Sorce oa->data = NULL; 1661d658336SSimo Sorce return 0; 1671d658336SSimo Sorce } 1681d658336SSimo Sorce 1696a36978eSJ. Bruce Fields static int get_host_u32(struct xdr_stream *xdr, u32 *res) 1701d658336SSimo Sorce { 171778e512bSJ. Bruce Fields __be32 *p; 172778e512bSJ. Bruce Fields 173778e512bSJ. Bruce Fields p = xdr_inline_decode(xdr, 4); 174778e512bSJ. Bruce Fields if (!p) 1751d658336SSimo Sorce return -EINVAL; 1766a36978eSJ. Bruce Fields /* Contents of linux creds are all host-endian: */ 1776a36978eSJ. Bruce Fields memcpy(res, p, sizeof(u32)); 1781d658336SSimo Sorce return 0; 1791d658336SSimo Sorce } 1801d658336SSimo Sorce 1811d658336SSimo Sorce static int gssx_dec_linux_creds(struct xdr_stream *xdr, 1821d658336SSimo Sorce struct svc_cred *creds) 1831d658336SSimo Sorce { 1841d658336SSimo Sorce u32 length; 1851d658336SSimo Sorce __be32 *p; 1866a36978eSJ. Bruce Fields u32 tmp; 1876a36978eSJ. Bruce Fields u32 N; 1886a36978eSJ. Bruce Fields int i, err; 1891d658336SSimo Sorce 1901d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 1911d658336SSimo Sorce if (unlikely(p == NULL)) 1921d658336SSimo Sorce return -ENOSPC; 1931d658336SSimo Sorce 1941d658336SSimo Sorce length = be32_to_cpup(p); 1951d658336SSimo Sorce 196778e512bSJ. Bruce Fields if (length > (3 + NGROUPS_MAX) * sizeof(u32)) 1971d658336SSimo Sorce return -ENOSPC; 1981d658336SSimo Sorce 1991d658336SSimo Sorce /* uid */ 2006a36978eSJ. Bruce Fields err = get_host_u32(xdr, &tmp); 2011d658336SSimo Sorce if (err) 2021d658336SSimo Sorce return err; 203d28fcc83SJ. Bruce Fields creds->cr_uid = make_kuid(&init_user_ns, tmp); 2041d658336SSimo Sorce 2051d658336SSimo Sorce /* gid */ 2066a36978eSJ. Bruce Fields err = get_host_u32(xdr, &tmp); 2071d658336SSimo Sorce if (err) 2081d658336SSimo Sorce return err; 209d28fcc83SJ. Bruce Fields creds->cr_gid = make_kgid(&init_user_ns, tmp); 2101d658336SSimo Sorce 2111d658336SSimo Sorce /* number of additional gid's */ 2126a36978eSJ. Bruce Fields err = get_host_u32(xdr, &tmp); 2131d658336SSimo Sorce if (err) 2141d658336SSimo Sorce return err; 2151d658336SSimo Sorce N = tmp; 216778e512bSJ. Bruce Fields if ((3 + N) * sizeof(u32) != length) 217778e512bSJ. Bruce Fields return -EINVAL; 2181d658336SSimo Sorce creds->cr_group_info = groups_alloc(N); 2191d658336SSimo Sorce if (creds->cr_group_info == NULL) 2201d658336SSimo Sorce return -ENOMEM; 2211d658336SSimo Sorce 2221d658336SSimo Sorce /* gid's */ 2231d658336SSimo Sorce for (i = 0; i < N; i++) { 224d28fcc83SJ. Bruce Fields kgid_t kgid; 2256a36978eSJ. Bruce Fields err = get_host_u32(xdr, &tmp); 226d28fcc83SJ. Bruce Fields if (err) 227d28fcc83SJ. Bruce Fields goto out_free_groups; 228d28fcc83SJ. Bruce Fields err = -EINVAL; 229d28fcc83SJ. Bruce Fields kgid = make_kgid(&init_user_ns, tmp); 230d28fcc83SJ. Bruce Fields if (!gid_valid(kgid)) 231d28fcc83SJ. Bruce Fields goto out_free_groups; 232d28fcc83SJ. Bruce Fields GROUP_AT(creds->cr_group_info, i) = kgid; 2331d658336SSimo Sorce } 2341d658336SSimo Sorce 2351d658336SSimo Sorce return 0; 236d28fcc83SJ. Bruce Fields out_free_groups: 237d28fcc83SJ. Bruce Fields groups_free(creds->cr_group_info); 238d28fcc83SJ. Bruce Fields return err; 2391d658336SSimo Sorce } 2401d658336SSimo Sorce 2411d658336SSimo Sorce static int gssx_dec_option_array(struct xdr_stream *xdr, 2421d658336SSimo Sorce struct gssx_option_array *oa) 2431d658336SSimo Sorce { 2441d658336SSimo Sorce struct svc_cred *creds; 2451d658336SSimo Sorce u32 count, i; 2461d658336SSimo Sorce __be32 *p; 2471d658336SSimo Sorce int err; 2481d658336SSimo Sorce 2491d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2501d658336SSimo Sorce if (unlikely(p == NULL)) 2511d658336SSimo Sorce return -ENOSPC; 2521d658336SSimo Sorce count = be32_to_cpup(p++); 2539fd40c5aSGeert Uytterhoeven if (!count) 2549fd40c5aSGeert Uytterhoeven return 0; 2559fd40c5aSGeert Uytterhoeven 2561d658336SSimo Sorce /* we recognize only 1 currently: CREDS_VALUE */ 2571d658336SSimo Sorce oa->count = 1; 2581d658336SSimo Sorce 2591d658336SSimo Sorce oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL); 2601d658336SSimo Sorce if (!oa->data) 2611d658336SSimo Sorce return -ENOMEM; 2621d658336SSimo Sorce 2631d658336SSimo Sorce creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL); 2641d658336SSimo Sorce if (!creds) { 2651d658336SSimo Sorce kfree(oa->data); 2661d658336SSimo Sorce return -ENOMEM; 2671d658336SSimo Sorce } 2681d658336SSimo Sorce 2691d658336SSimo Sorce oa->data[0].option.data = CREDS_VALUE; 2701d658336SSimo Sorce oa->data[0].option.len = sizeof(CREDS_VALUE); 2711d658336SSimo Sorce oa->data[0].value.data = (void *)creds; 2721d658336SSimo Sorce oa->data[0].value.len = 0; 2739fd40c5aSGeert Uytterhoeven 2741d658336SSimo Sorce for (i = 0; i < count; i++) { 2751d658336SSimo Sorce gssx_buffer dummy = { 0, NULL }; 2761d658336SSimo Sorce u32 length; 2771d658336SSimo Sorce 2781d658336SSimo Sorce /* option buffer */ 2791d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2801d658336SSimo Sorce if (unlikely(p == NULL)) 2811d658336SSimo Sorce return -ENOSPC; 2821d658336SSimo Sorce 2831d658336SSimo Sorce length = be32_to_cpup(p); 2841d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 2851d658336SSimo Sorce if (unlikely(p == NULL)) 2861d658336SSimo Sorce return -ENOSPC; 2871d658336SSimo Sorce 2881d658336SSimo Sorce if (length == sizeof(CREDS_VALUE) && 2891d658336SSimo Sorce memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) { 2901d658336SSimo Sorce /* We have creds here. parse them */ 2911d658336SSimo Sorce err = gssx_dec_linux_creds(xdr, creds); 2921d658336SSimo Sorce if (err) 2931d658336SSimo Sorce return err; 2941d658336SSimo Sorce oa->data[0].value.len = 1; /* presence */ 2951d658336SSimo Sorce } else { 2961d658336SSimo Sorce /* consume uninteresting buffer */ 2971d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy); 2981d658336SSimo Sorce if (err) 2991d658336SSimo Sorce return err; 3001d658336SSimo Sorce } 3011d658336SSimo Sorce } 3021d658336SSimo Sorce return 0; 3031d658336SSimo Sorce } 3041d658336SSimo Sorce 3051d658336SSimo Sorce static int gssx_dec_status(struct xdr_stream *xdr, 3061d658336SSimo Sorce struct gssx_status *status) 3071d658336SSimo Sorce { 3081d658336SSimo Sorce __be32 *p; 3091d658336SSimo Sorce int err; 3101d658336SSimo Sorce 3111d658336SSimo Sorce /* status->major_status */ 3121d658336SSimo Sorce p = xdr_inline_decode(xdr, 8); 3131d658336SSimo Sorce if (unlikely(p == NULL)) 3141d658336SSimo Sorce return -ENOSPC; 3151d658336SSimo Sorce p = xdr_decode_hyper(p, &status->major_status); 3161d658336SSimo Sorce 3171d658336SSimo Sorce /* status->mech */ 3181d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->mech); 3191d658336SSimo Sorce if (err) 3201d658336SSimo Sorce return err; 3211d658336SSimo Sorce 3221d658336SSimo Sorce /* status->minor_status */ 3231d658336SSimo Sorce p = xdr_inline_decode(xdr, 8); 3241d658336SSimo Sorce if (unlikely(p == NULL)) 3251d658336SSimo Sorce return -ENOSPC; 3261d658336SSimo Sorce p = xdr_decode_hyper(p, &status->minor_status); 3271d658336SSimo Sorce 3281d658336SSimo Sorce /* status->major_status_string */ 3291d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->major_status_string); 3301d658336SSimo Sorce if (err) 3311d658336SSimo Sorce return err; 3321d658336SSimo Sorce 3331d658336SSimo Sorce /* status->minor_status_string */ 3341d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->minor_status_string); 3351d658336SSimo Sorce if (err) 3361d658336SSimo Sorce return err; 3371d658336SSimo Sorce 3381d658336SSimo Sorce /* status->server_ctx */ 3391d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->server_ctx); 3401d658336SSimo Sorce if (err) 3411d658336SSimo Sorce return err; 3421d658336SSimo Sorce 3431d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 3441d658336SSimo Sorce /* status->options */ 3451d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &status->options); 3461d658336SSimo Sorce 3471d658336SSimo Sorce return err; 3481d658336SSimo Sorce } 3491d658336SSimo Sorce 3501d658336SSimo Sorce static int gssx_enc_call_ctx(struct xdr_stream *xdr, 3511d658336SSimo Sorce struct gssx_call_ctx *ctx) 3521d658336SSimo Sorce { 3531d658336SSimo Sorce struct gssx_option opt; 3541d658336SSimo Sorce __be32 *p; 3551d658336SSimo Sorce int err; 3561d658336SSimo Sorce 3571d658336SSimo Sorce /* ctx->locale */ 3581d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->locale); 3591d658336SSimo Sorce if (err) 3601d658336SSimo Sorce return err; 3611d658336SSimo Sorce 3621d658336SSimo Sorce /* ctx->server_ctx */ 3631d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->server_ctx); 3641d658336SSimo Sorce if (err) 3651d658336SSimo Sorce return err; 3661d658336SSimo Sorce 3671d658336SSimo Sorce /* we always want to ask for lucid contexts */ 3681d658336SSimo Sorce /* ctx->options */ 3691d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 3701d658336SSimo Sorce *p = cpu_to_be32(2); 3711d658336SSimo Sorce 3721d658336SSimo Sorce /* we want a lucid_v1 context */ 3731d658336SSimo Sorce opt.option.data = LUCID_OPTION; 3741d658336SSimo Sorce opt.option.len = sizeof(LUCID_OPTION); 3751d658336SSimo Sorce opt.value.data = LUCID_VALUE; 3761d658336SSimo Sorce opt.value.len = sizeof(LUCID_VALUE); 3771d658336SSimo Sorce err = gssx_enc_option(xdr, &opt); 3781d658336SSimo Sorce 3791d658336SSimo Sorce /* ..and user creds */ 3801d658336SSimo Sorce opt.option.data = CREDS_OPTION; 3811d658336SSimo Sorce opt.option.len = sizeof(CREDS_OPTION); 3821d658336SSimo Sorce opt.value.data = CREDS_VALUE; 3831d658336SSimo Sorce opt.value.len = sizeof(CREDS_VALUE); 3841d658336SSimo Sorce err = gssx_enc_option(xdr, &opt); 3851d658336SSimo Sorce 3861d658336SSimo Sorce return err; 3871d658336SSimo Sorce } 3881d658336SSimo Sorce 3891d658336SSimo Sorce static int gssx_dec_name_attr(struct xdr_stream *xdr, 3901d658336SSimo Sorce struct gssx_name_attr *attr) 3911d658336SSimo Sorce { 3921d658336SSimo Sorce int err; 3931d658336SSimo Sorce 3941d658336SSimo Sorce /* attr->attr */ 3951d658336SSimo Sorce err = gssx_dec_buffer(xdr, &attr->attr); 3961d658336SSimo Sorce if (err) 3971d658336SSimo Sorce return err; 3981d658336SSimo Sorce 3991d658336SSimo Sorce /* attr->value */ 4001d658336SSimo Sorce err = gssx_dec_buffer(xdr, &attr->value); 4011d658336SSimo Sorce if (err) 4021d658336SSimo Sorce return err; 4031d658336SSimo Sorce 4041d658336SSimo Sorce /* attr->extensions */ 4051d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &attr->extensions); 4061d658336SSimo Sorce 4071d658336SSimo Sorce return err; 4081d658336SSimo Sorce } 4091d658336SSimo Sorce 4101d658336SSimo Sorce static int dummy_enc_nameattr_array(struct xdr_stream *xdr, 4111d658336SSimo Sorce struct gssx_name_attr_array *naa) 4121d658336SSimo Sorce { 4131d658336SSimo Sorce __be32 *p; 4141d658336SSimo Sorce 4151d658336SSimo Sorce if (naa->count != 0) 4161d658336SSimo Sorce return -EINVAL; 4171d658336SSimo Sorce 4181d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 4191d658336SSimo Sorce if (!p) 4201d658336SSimo Sorce return -ENOSPC; 4211d658336SSimo Sorce *p = 0; 4221d658336SSimo Sorce 4231d658336SSimo Sorce return 0; 4241d658336SSimo Sorce } 4251d658336SSimo Sorce 4261d658336SSimo Sorce static int dummy_dec_nameattr_array(struct xdr_stream *xdr, 4271d658336SSimo Sorce struct gssx_name_attr_array *naa) 4281d658336SSimo Sorce { 429dc43376cSJ. Bruce Fields struct gssx_name_attr dummy = { .attr = {.len = 0} }; 4301d658336SSimo Sorce u32 count, i; 4311d658336SSimo Sorce __be32 *p; 4321d658336SSimo Sorce 4331d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 4341d658336SSimo Sorce if (unlikely(p == NULL)) 4351d658336SSimo Sorce return -ENOSPC; 4361d658336SSimo Sorce count = be32_to_cpup(p++); 4371d658336SSimo Sorce for (i = 0; i < count; i++) { 4381d658336SSimo Sorce gssx_dec_name_attr(xdr, &dummy); 4391d658336SSimo Sorce } 4401d658336SSimo Sorce 4411d658336SSimo Sorce naa->count = 0; 4421d658336SSimo Sorce naa->data = NULL; 4431d658336SSimo Sorce return 0; 4441d658336SSimo Sorce } 4451d658336SSimo Sorce 4461d658336SSimo Sorce static struct xdr_netobj zero_netobj = {}; 4471d658336SSimo Sorce 4481d658336SSimo Sorce static struct gssx_name_attr_array zero_name_attr_array = {}; 4491d658336SSimo Sorce 4501d658336SSimo Sorce static struct gssx_option_array zero_option_array = {}; 4511d658336SSimo Sorce 4521d658336SSimo Sorce static int gssx_enc_name(struct xdr_stream *xdr, 4531d658336SSimo Sorce struct gssx_name *name) 4541d658336SSimo Sorce { 4551d658336SSimo Sorce int err; 4561d658336SSimo Sorce 4571d658336SSimo Sorce /* name->display_name */ 4581d658336SSimo Sorce err = gssx_enc_buffer(xdr, &name->display_name); 4591d658336SSimo Sorce if (err) 4601d658336SSimo Sorce return err; 4611d658336SSimo Sorce 4621d658336SSimo Sorce /* name->name_type */ 4631d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4641d658336SSimo Sorce if (err) 4651d658336SSimo Sorce return err; 4661d658336SSimo Sorce 4671d658336SSimo Sorce /* name->exported_name */ 4681d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4691d658336SSimo Sorce if (err) 4701d658336SSimo Sorce return err; 4711d658336SSimo Sorce 4721d658336SSimo Sorce /* name->exported_composite_name */ 4731d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4741d658336SSimo Sorce if (err) 4751d658336SSimo Sorce return err; 4761d658336SSimo Sorce 4771d658336SSimo Sorce /* leave name_attributes empty for now, will add once we have any 4781d658336SSimo Sorce * to pass up at all */ 4791d658336SSimo Sorce /* name->name_attributes */ 4801d658336SSimo Sorce err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array); 4811d658336SSimo Sorce if (err) 4821d658336SSimo Sorce return err; 4831d658336SSimo Sorce 4841d658336SSimo Sorce /* leave options empty for now, will add once we have any options 4851d658336SSimo Sorce * to pass up at all */ 4861d658336SSimo Sorce /* name->extensions */ 4871d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &zero_option_array); 4881d658336SSimo Sorce 4891d658336SSimo Sorce return err; 4901d658336SSimo Sorce } 4911d658336SSimo Sorce 492dc43376cSJ. Bruce Fields 4931d658336SSimo Sorce static int gssx_dec_name(struct xdr_stream *xdr, 4941d658336SSimo Sorce struct gssx_name *name) 4951d658336SSimo Sorce { 496dc43376cSJ. Bruce Fields struct xdr_netobj dummy_netobj = { .len = 0 }; 497dc43376cSJ. Bruce Fields struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 }; 498dc43376cSJ. Bruce Fields struct gssx_option_array dummy_option_array = { .count = 0 }; 4991d658336SSimo Sorce int err; 5001d658336SSimo Sorce 5011d658336SSimo Sorce /* name->display_name */ 5021d658336SSimo Sorce err = gssx_dec_buffer(xdr, &name->display_name); 5031d658336SSimo Sorce if (err) 5041d658336SSimo Sorce return err; 5051d658336SSimo Sorce 5061d658336SSimo Sorce /* name->name_type */ 5071d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5081d658336SSimo Sorce if (err) 5091d658336SSimo Sorce return err; 5101d658336SSimo Sorce 5111d658336SSimo Sorce /* name->exported_name */ 5121d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5131d658336SSimo Sorce if (err) 5141d658336SSimo Sorce return err; 5151d658336SSimo Sorce 5161d658336SSimo Sorce /* name->exported_composite_name */ 5171d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5181d658336SSimo Sorce if (err) 5191d658336SSimo Sorce return err; 5201d658336SSimo Sorce 5211d658336SSimo Sorce /* we assume we have no attributes for now, so simply consume them */ 5221d658336SSimo Sorce /* name->name_attributes */ 5231d658336SSimo Sorce err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array); 5241d658336SSimo Sorce if (err) 5251d658336SSimo Sorce return err; 5261d658336SSimo Sorce 5271d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 5281d658336SSimo Sorce /* name->extensions */ 5291d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &dummy_option_array); 5301d658336SSimo Sorce 5311d658336SSimo Sorce return err; 5321d658336SSimo Sorce } 5331d658336SSimo Sorce 5341d658336SSimo Sorce static int dummy_enc_credel_array(struct xdr_stream *xdr, 5351d658336SSimo Sorce struct gssx_cred_element_array *cea) 5361d658336SSimo Sorce { 5371d658336SSimo Sorce __be32 *p; 5381d658336SSimo Sorce 5391d658336SSimo Sorce if (cea->count != 0) 5401d658336SSimo Sorce return -EINVAL; 5411d658336SSimo Sorce 5421d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 5431d658336SSimo Sorce if (!p) 5441d658336SSimo Sorce return -ENOSPC; 5451d658336SSimo Sorce *p = 0; 5461d658336SSimo Sorce 5471d658336SSimo Sorce return 0; 5481d658336SSimo Sorce } 5491d658336SSimo Sorce 5501d658336SSimo Sorce static int gssx_enc_cred(struct xdr_stream *xdr, 5511d658336SSimo Sorce struct gssx_cred *cred) 5521d658336SSimo Sorce { 5531d658336SSimo Sorce int err; 5541d658336SSimo Sorce 5551d658336SSimo Sorce /* cred->desired_name */ 5561d658336SSimo Sorce err = gssx_enc_name(xdr, &cred->desired_name); 5571d658336SSimo Sorce if (err) 5581d658336SSimo Sorce return err; 5591d658336SSimo Sorce 5601d658336SSimo Sorce /* cred->elements */ 5611d658336SSimo Sorce err = dummy_enc_credel_array(xdr, &cred->elements); 562b26ec9b1SJ. Bruce Fields if (err) 563b26ec9b1SJ. Bruce Fields return err; 5641d658336SSimo Sorce 5651d658336SSimo Sorce /* cred->cred_handle_reference */ 5661d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cred->cred_handle_reference); 5671d658336SSimo Sorce if (err) 5681d658336SSimo Sorce return err; 5691d658336SSimo Sorce 5701d658336SSimo Sorce /* cred->needs_release */ 5711d658336SSimo Sorce err = gssx_enc_bool(xdr, cred->needs_release); 5721d658336SSimo Sorce 5731d658336SSimo Sorce return err; 5741d658336SSimo Sorce } 5751d658336SSimo Sorce 5761d658336SSimo Sorce static int gssx_enc_ctx(struct xdr_stream *xdr, 5771d658336SSimo Sorce struct gssx_ctx *ctx) 5781d658336SSimo Sorce { 5791d658336SSimo Sorce __be32 *p; 5801d658336SSimo Sorce int err; 5811d658336SSimo Sorce 5821d658336SSimo Sorce /* ctx->exported_context_token */ 5831d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->exported_context_token); 5841d658336SSimo Sorce if (err) 5851d658336SSimo Sorce return err; 5861d658336SSimo Sorce 5871d658336SSimo Sorce /* ctx->state */ 5881d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->state); 5891d658336SSimo Sorce if (err) 5901d658336SSimo Sorce return err; 5911d658336SSimo Sorce 5921d658336SSimo Sorce /* ctx->need_release */ 5931d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->need_release); 5941d658336SSimo Sorce if (err) 5951d658336SSimo Sorce return err; 5961d658336SSimo Sorce 5971d658336SSimo Sorce /* ctx->mech */ 5981d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->mech); 5991d658336SSimo Sorce if (err) 6001d658336SSimo Sorce return err; 6011d658336SSimo Sorce 6021d658336SSimo Sorce /* ctx->src_name */ 6031d658336SSimo Sorce err = gssx_enc_name(xdr, &ctx->src_name); 6041d658336SSimo Sorce if (err) 6051d658336SSimo Sorce return err; 6061d658336SSimo Sorce 6071d658336SSimo Sorce /* ctx->targ_name */ 6081d658336SSimo Sorce err = gssx_enc_name(xdr, &ctx->targ_name); 6091d658336SSimo Sorce if (err) 6101d658336SSimo Sorce return err; 6111d658336SSimo Sorce 6121d658336SSimo Sorce /* ctx->lifetime */ 6131d658336SSimo Sorce p = xdr_reserve_space(xdr, 8+8); 6141d658336SSimo Sorce if (!p) 6151d658336SSimo Sorce return -ENOSPC; 6161d658336SSimo Sorce p = xdr_encode_hyper(p, ctx->lifetime); 6171d658336SSimo Sorce 6181d658336SSimo Sorce /* ctx->ctx_flags */ 6191d658336SSimo Sorce p = xdr_encode_hyper(p, ctx->ctx_flags); 6201d658336SSimo Sorce 6211d658336SSimo Sorce /* ctx->locally_initiated */ 6221d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->locally_initiated); 6231d658336SSimo Sorce if (err) 6241d658336SSimo Sorce return err; 6251d658336SSimo Sorce 6261d658336SSimo Sorce /* ctx->open */ 6271d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->open); 6281d658336SSimo Sorce if (err) 6291d658336SSimo Sorce return err; 6301d658336SSimo Sorce 6311d658336SSimo Sorce /* leave options empty for now, will add once we have any options 6321d658336SSimo Sorce * to pass up at all */ 6331d658336SSimo Sorce /* ctx->options */ 6341d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &ctx->options); 6351d658336SSimo Sorce 6361d658336SSimo Sorce return err; 6371d658336SSimo Sorce } 6381d658336SSimo Sorce 6391d658336SSimo Sorce static int gssx_dec_ctx(struct xdr_stream *xdr, 6401d658336SSimo Sorce struct gssx_ctx *ctx) 6411d658336SSimo Sorce { 6421d658336SSimo Sorce __be32 *p; 6431d658336SSimo Sorce int err; 6441d658336SSimo Sorce 6451d658336SSimo Sorce /* ctx->exported_context_token */ 6461d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->exported_context_token); 6471d658336SSimo Sorce if (err) 6481d658336SSimo Sorce return err; 6491d658336SSimo Sorce 6501d658336SSimo Sorce /* ctx->state */ 6511d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->state); 6521d658336SSimo Sorce if (err) 6531d658336SSimo Sorce return err; 6541d658336SSimo Sorce 6551d658336SSimo Sorce /* ctx->need_release */ 6561d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->need_release); 6571d658336SSimo Sorce if (err) 6581d658336SSimo Sorce return err; 6591d658336SSimo Sorce 6601d658336SSimo Sorce /* ctx->mech */ 6611d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->mech); 6621d658336SSimo Sorce if (err) 6631d658336SSimo Sorce return err; 6641d658336SSimo Sorce 6651d658336SSimo Sorce /* ctx->src_name */ 6661d658336SSimo Sorce err = gssx_dec_name(xdr, &ctx->src_name); 6671d658336SSimo Sorce if (err) 6681d658336SSimo Sorce return err; 6691d658336SSimo Sorce 6701d658336SSimo Sorce /* ctx->targ_name */ 6711d658336SSimo Sorce err = gssx_dec_name(xdr, &ctx->targ_name); 6721d658336SSimo Sorce if (err) 6731d658336SSimo Sorce return err; 6741d658336SSimo Sorce 6751d658336SSimo Sorce /* ctx->lifetime */ 6761d658336SSimo Sorce p = xdr_inline_decode(xdr, 8+8); 6771d658336SSimo Sorce if (unlikely(p == NULL)) 6781d658336SSimo Sorce return -ENOSPC; 6791d658336SSimo Sorce p = xdr_decode_hyper(p, &ctx->lifetime); 6801d658336SSimo Sorce 6811d658336SSimo Sorce /* ctx->ctx_flags */ 6821d658336SSimo Sorce p = xdr_decode_hyper(p, &ctx->ctx_flags); 6831d658336SSimo Sorce 6841d658336SSimo Sorce /* ctx->locally_initiated */ 6851d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->locally_initiated); 6861d658336SSimo Sorce if (err) 6871d658336SSimo Sorce return err; 6881d658336SSimo Sorce 6891d658336SSimo Sorce /* ctx->open */ 6901d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->open); 6911d658336SSimo Sorce if (err) 6921d658336SSimo Sorce return err; 6931d658336SSimo Sorce 6941d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 6951d658336SSimo Sorce /* ctx->options */ 6961d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &ctx->options); 6971d658336SSimo Sorce 6981d658336SSimo Sorce return err; 6991d658336SSimo Sorce } 7001d658336SSimo Sorce 7011d658336SSimo Sorce static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb) 7021d658336SSimo Sorce { 7031d658336SSimo Sorce __be32 *p; 7041d658336SSimo Sorce int err; 7051d658336SSimo Sorce 7061d658336SSimo Sorce /* cb->initiator_addrtype */ 7071d658336SSimo Sorce p = xdr_reserve_space(xdr, 8); 7081d658336SSimo Sorce if (!p) 7091d658336SSimo Sorce return -ENOSPC; 7101d658336SSimo Sorce p = xdr_encode_hyper(p, cb->initiator_addrtype); 7111d658336SSimo Sorce 7121d658336SSimo Sorce /* cb->initiator_address */ 7131d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->initiator_address); 7141d658336SSimo Sorce if (err) 7151d658336SSimo Sorce return err; 7161d658336SSimo Sorce 7171d658336SSimo Sorce /* cb->acceptor_addrtype */ 7181d658336SSimo Sorce p = xdr_reserve_space(xdr, 8); 7191d658336SSimo Sorce if (!p) 7201d658336SSimo Sorce return -ENOSPC; 7211d658336SSimo Sorce p = xdr_encode_hyper(p, cb->acceptor_addrtype); 7221d658336SSimo Sorce 7231d658336SSimo Sorce /* cb->acceptor_address */ 7241d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->acceptor_address); 7251d658336SSimo Sorce if (err) 7261d658336SSimo Sorce return err; 7271d658336SSimo Sorce 7281d658336SSimo Sorce /* cb->application_data */ 7291d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->application_data); 7301d658336SSimo Sorce 7311d658336SSimo Sorce return err; 7321d658336SSimo Sorce } 7331d658336SSimo Sorce 7341d658336SSimo Sorce void gssx_enc_accept_sec_context(struct rpc_rqst *req, 7351d658336SSimo Sorce struct xdr_stream *xdr, 7361d658336SSimo Sorce struct gssx_arg_accept_sec_context *arg) 7371d658336SSimo Sorce { 7381d658336SSimo Sorce int err; 7391d658336SSimo Sorce 7401d658336SSimo Sorce err = gssx_enc_call_ctx(xdr, &arg->call_ctx); 7411d658336SSimo Sorce if (err) 7421d658336SSimo Sorce goto done; 7431d658336SSimo Sorce 7441d658336SSimo Sorce /* arg->context_handle */ 745b26ec9b1SJ. Bruce Fields if (arg->context_handle) 7461d658336SSimo Sorce err = gssx_enc_ctx(xdr, arg->context_handle); 747b26ec9b1SJ. Bruce Fields else 748b26ec9b1SJ. Bruce Fields err = gssx_enc_bool(xdr, 0); 7491d658336SSimo Sorce if (err) 7501d658336SSimo Sorce goto done; 7511d658336SSimo Sorce 7521d658336SSimo Sorce /* arg->cred_handle */ 753b26ec9b1SJ. Bruce Fields if (arg->cred_handle) 7541d658336SSimo Sorce err = gssx_enc_cred(xdr, arg->cred_handle); 755b26ec9b1SJ. Bruce Fields else 756b26ec9b1SJ. Bruce Fields err = gssx_enc_bool(xdr, 0); 7571d658336SSimo Sorce if (err) 7581d658336SSimo Sorce goto done; 7591d658336SSimo Sorce 7601d658336SSimo Sorce /* arg->input_token */ 7611d658336SSimo Sorce err = gssx_enc_in_token(xdr, &arg->input_token); 7621d658336SSimo Sorce if (err) 7631d658336SSimo Sorce goto done; 7641d658336SSimo Sorce 7651d658336SSimo Sorce /* arg->input_cb */ 766b26ec9b1SJ. Bruce Fields if (arg->input_cb) 7671d658336SSimo Sorce err = gssx_enc_cb(xdr, arg->input_cb); 768b26ec9b1SJ. Bruce Fields else 769b26ec9b1SJ. Bruce Fields err = gssx_enc_bool(xdr, 0); 7701d658336SSimo Sorce if (err) 7711d658336SSimo Sorce goto done; 7721d658336SSimo Sorce 7731d658336SSimo Sorce err = gssx_enc_bool(xdr, arg->ret_deleg_cred); 7741d658336SSimo Sorce if (err) 7751d658336SSimo Sorce goto done; 7761d658336SSimo Sorce 7771d658336SSimo Sorce /* leave options empty for now, will add once we have any options 7781d658336SSimo Sorce * to pass up at all */ 7791d658336SSimo Sorce /* arg->options */ 7801d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &arg->options); 7811d658336SSimo Sorce 7829dfd87daSJ. Bruce Fields xdr_inline_pages(&req->rq_rcv_buf, 7839dfd87daSJ. Bruce Fields PAGE_SIZE/2 /* pretty arbitrary */, 7849dfd87daSJ. Bruce Fields arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE); 7851d658336SSimo Sorce done: 7861d658336SSimo Sorce if (err) 7871d658336SSimo Sorce dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); 7881d658336SSimo Sorce } 7891d658336SSimo Sorce 7901d658336SSimo Sorce int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, 7911d658336SSimo Sorce struct xdr_stream *xdr, 7921d658336SSimo Sorce struct gssx_res_accept_sec_context *res) 7931d658336SSimo Sorce { 794fb43f11cSJ. Bruce Fields u32 value_follows; 7951d658336SSimo Sorce int err; 7969507271dSScott Mayhew struct page *scratch; 7979507271dSScott Mayhew 7989507271dSScott Mayhew scratch = alloc_page(GFP_KERNEL); 7999507271dSScott Mayhew if (!scratch) 8009507271dSScott Mayhew return -ENOMEM; 8019507271dSScott Mayhew xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE); 8021d658336SSimo Sorce 8031d658336SSimo Sorce /* res->status */ 8041d658336SSimo Sorce err = gssx_dec_status(xdr, &res->status); 8051d658336SSimo Sorce if (err) 8069507271dSScott Mayhew goto out_free; 8071d658336SSimo Sorce 8081d658336SSimo Sorce /* res->context_handle */ 809fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 810fb43f11cSJ. Bruce Fields if (err) 8119507271dSScott Mayhew goto out_free; 812fb43f11cSJ. Bruce Fields if (value_follows) { 8131d658336SSimo Sorce err = gssx_dec_ctx(xdr, res->context_handle); 8141d658336SSimo Sorce if (err) 8159507271dSScott Mayhew goto out_free; 8161d658336SSimo Sorce } else { 8171d658336SSimo Sorce res->context_handle = NULL; 8181d658336SSimo Sorce } 8191d658336SSimo Sorce 8201d658336SSimo Sorce /* res->output_token */ 821fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 822fb43f11cSJ. Bruce Fields if (err) 8239507271dSScott Mayhew goto out_free; 824fb43f11cSJ. Bruce Fields if (value_follows) { 8251d658336SSimo Sorce err = gssx_dec_buffer(xdr, res->output_token); 8261d658336SSimo Sorce if (err) 8279507271dSScott Mayhew goto out_free; 8281d658336SSimo Sorce } else { 8291d658336SSimo Sorce res->output_token = NULL; 8301d658336SSimo Sorce } 8311d658336SSimo Sorce 8321d658336SSimo Sorce /* res->delegated_cred_handle */ 833fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 834fb43f11cSJ. Bruce Fields if (err) 8359507271dSScott Mayhew goto out_free; 836fb43f11cSJ. Bruce Fields if (value_follows) { 8371d658336SSimo Sorce /* we do not support upcall servers sending this data. */ 8389507271dSScott Mayhew err = -EINVAL; 8399507271dSScott Mayhew goto out_free; 8401d658336SSimo Sorce } 8411d658336SSimo Sorce 8421d658336SSimo Sorce /* res->options */ 8431d658336SSimo Sorce err = gssx_dec_option_array(xdr, &res->options); 8441d658336SSimo Sorce 8459507271dSScott Mayhew out_free: 8469507271dSScott Mayhew __free_page(scratch); 8471d658336SSimo Sorce return err; 8481d658336SSimo Sorce } 849