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 bool gssx_check_pointer(struct xdr_stream *xdr) 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 return *p?true:false; 321d658336SSimo Sorce } 331d658336SSimo Sorce 341d658336SSimo Sorce static int gssx_enc_bool(struct xdr_stream *xdr, int v) 351d658336SSimo Sorce { 361d658336SSimo Sorce __be32 *p; 371d658336SSimo Sorce 381d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 391d658336SSimo Sorce if (unlikely(p == NULL)) 401d658336SSimo Sorce return -ENOSPC; 411d658336SSimo Sorce *p = v ? xdr_one : xdr_zero; 421d658336SSimo Sorce return 0; 431d658336SSimo Sorce } 441d658336SSimo Sorce 451d658336SSimo Sorce static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v) 461d658336SSimo Sorce { 471d658336SSimo Sorce __be32 *p; 481d658336SSimo Sorce 491d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 501d658336SSimo Sorce if (unlikely(p == NULL)) 511d658336SSimo Sorce return -ENOSPC; 521d658336SSimo Sorce *v = be32_to_cpu(*p); 531d658336SSimo Sorce return 0; 541d658336SSimo Sorce } 551d658336SSimo Sorce 561d658336SSimo Sorce static int gssx_enc_buffer(struct xdr_stream *xdr, 571d658336SSimo Sorce gssx_buffer *buf) 581d658336SSimo Sorce { 591d658336SSimo Sorce __be32 *p; 601d658336SSimo Sorce 611d658336SSimo Sorce p = xdr_reserve_space(xdr, sizeof(u32) + buf->len); 621d658336SSimo Sorce if (!p) 631d658336SSimo Sorce return -ENOSPC; 641d658336SSimo Sorce xdr_encode_opaque(p, buf->data, buf->len); 651d658336SSimo Sorce return 0; 661d658336SSimo Sorce } 671d658336SSimo Sorce 681d658336SSimo Sorce static int gssx_enc_in_token(struct xdr_stream *xdr, 691d658336SSimo Sorce struct gssp_in_token *in) 701d658336SSimo Sorce { 711d658336SSimo Sorce __be32 *p; 721d658336SSimo Sorce 731d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 741d658336SSimo Sorce if (!p) 751d658336SSimo Sorce return -ENOSPC; 761d658336SSimo Sorce *p = cpu_to_be32(in->page_len); 771d658336SSimo Sorce 781d658336SSimo Sorce /* all we need to do is to write pages */ 791d658336SSimo Sorce xdr_write_pages(xdr, in->pages, in->page_base, in->page_len); 801d658336SSimo Sorce 811d658336SSimo Sorce return 0; 821d658336SSimo Sorce } 831d658336SSimo Sorce 841d658336SSimo Sorce 851d658336SSimo Sorce static int gssx_dec_buffer(struct xdr_stream *xdr, 861d658336SSimo Sorce gssx_buffer *buf) 871d658336SSimo Sorce { 881d658336SSimo Sorce u32 length; 891d658336SSimo Sorce __be32 *p; 901d658336SSimo Sorce 911d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 921d658336SSimo Sorce if (unlikely(p == NULL)) 931d658336SSimo Sorce return -ENOSPC; 941d658336SSimo Sorce 951d658336SSimo Sorce length = be32_to_cpup(p); 961d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 971d658336SSimo Sorce if (unlikely(p == NULL)) 981d658336SSimo Sorce return -ENOSPC; 991d658336SSimo Sorce 1001d658336SSimo Sorce if (buf->len == 0) { 1011d658336SSimo Sorce /* we intentionally are not interested in this buffer */ 1021d658336SSimo Sorce return 0; 1031d658336SSimo Sorce } 1041d658336SSimo Sorce if (length > buf->len) 1051d658336SSimo Sorce return -ENOSPC; 1061d658336SSimo Sorce 1071d658336SSimo Sorce if (!buf->data) { 1081d658336SSimo Sorce buf->data = kmemdup(p, length, GFP_KERNEL); 1091d658336SSimo Sorce if (!buf->data) 1101d658336SSimo Sorce return -ENOMEM; 1111d658336SSimo Sorce } else { 1121d658336SSimo Sorce memcpy(buf->data, p, length); 1131d658336SSimo Sorce } 1141d658336SSimo Sorce buf->len = length; 1151d658336SSimo Sorce return 0; 1161d658336SSimo Sorce } 1171d658336SSimo Sorce 1181d658336SSimo Sorce static int gssx_enc_option(struct xdr_stream *xdr, 1191d658336SSimo Sorce struct gssx_option *opt) 1201d658336SSimo Sorce { 1211d658336SSimo Sorce int err; 1221d658336SSimo Sorce 1231d658336SSimo Sorce err = gssx_enc_buffer(xdr, &opt->option); 1241d658336SSimo Sorce if (err) 1251d658336SSimo Sorce return err; 1261d658336SSimo Sorce err = gssx_enc_buffer(xdr, &opt->value); 1271d658336SSimo Sorce return err; 1281d658336SSimo Sorce } 1291d658336SSimo Sorce 1301d658336SSimo Sorce static int gssx_dec_option(struct xdr_stream *xdr, 1311d658336SSimo Sorce struct gssx_option *opt) 1321d658336SSimo Sorce { 1331d658336SSimo Sorce int err; 1341d658336SSimo Sorce 1351d658336SSimo Sorce err = gssx_dec_buffer(xdr, &opt->option); 1361d658336SSimo Sorce if (err) 1371d658336SSimo Sorce return err; 1381d658336SSimo Sorce err = gssx_dec_buffer(xdr, &opt->value); 1391d658336SSimo Sorce return err; 1401d658336SSimo Sorce } 1411d658336SSimo Sorce 1421d658336SSimo Sorce static int dummy_enc_opt_array(struct xdr_stream *xdr, 1431d658336SSimo Sorce struct gssx_option_array *oa) 1441d658336SSimo Sorce { 1451d658336SSimo Sorce __be32 *p; 1461d658336SSimo Sorce 1471d658336SSimo Sorce if (oa->count != 0) 1481d658336SSimo Sorce return -EINVAL; 1491d658336SSimo Sorce 1501d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 1511d658336SSimo Sorce if (!p) 1521d658336SSimo Sorce return -ENOSPC; 1531d658336SSimo Sorce *p = 0; 1541d658336SSimo Sorce 1551d658336SSimo Sorce return 0; 1561d658336SSimo Sorce } 1571d658336SSimo Sorce 1581d658336SSimo Sorce static int dummy_dec_opt_array(struct xdr_stream *xdr, 1591d658336SSimo Sorce struct gssx_option_array *oa) 1601d658336SSimo Sorce { 1611d658336SSimo Sorce struct gssx_option dummy; 1621d658336SSimo Sorce u32 count, i; 1631d658336SSimo Sorce __be32 *p; 1641d658336SSimo Sorce 1651d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 1661d658336SSimo Sorce if (unlikely(p == NULL)) 1671d658336SSimo Sorce return -ENOSPC; 1681d658336SSimo Sorce count = be32_to_cpup(p++); 1691d658336SSimo Sorce memset(&dummy, 0, sizeof(dummy)); 1701d658336SSimo Sorce for (i = 0; i < count; i++) { 1711d658336SSimo Sorce gssx_dec_option(xdr, &dummy); 1721d658336SSimo Sorce } 1731d658336SSimo Sorce 1741d658336SSimo Sorce oa->count = 0; 1751d658336SSimo Sorce oa->data = NULL; 1761d658336SSimo Sorce return 0; 1771d658336SSimo Sorce } 1781d658336SSimo Sorce 1791d658336SSimo Sorce static int get_s32(void **p, void *max, s32 *res) 1801d658336SSimo Sorce { 1811d658336SSimo Sorce void *base = *p; 1821d658336SSimo Sorce void *next = (void *)((char *)base + sizeof(s32)); 1831d658336SSimo Sorce if (unlikely(next > max || next < base)) 1841d658336SSimo Sorce return -EINVAL; 1851d658336SSimo Sorce memcpy(res, base, sizeof(s32)); 1861d658336SSimo Sorce *p = next; 1871d658336SSimo Sorce return 0; 1881d658336SSimo Sorce } 1891d658336SSimo Sorce 1901d658336SSimo Sorce static int gssx_dec_linux_creds(struct xdr_stream *xdr, 1911d658336SSimo Sorce struct svc_cred *creds) 1921d658336SSimo Sorce { 1931d658336SSimo Sorce u32 length; 1941d658336SSimo Sorce __be32 *p; 1951d658336SSimo Sorce void *q, *end; 1961d658336SSimo Sorce s32 tmp; 1971d658336SSimo Sorce int N, i, err; 1981d658336SSimo Sorce 1991d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2001d658336SSimo Sorce if (unlikely(p == NULL)) 2011d658336SSimo Sorce return -ENOSPC; 2021d658336SSimo Sorce 2031d658336SSimo Sorce length = be32_to_cpup(p); 2041d658336SSimo Sorce 2051d658336SSimo Sorce /* FIXME: we do not want to use the scratch buffer for this one 2061d658336SSimo Sorce * may need to use functions that allows us to access an io vector 2071d658336SSimo Sorce * directly */ 2081d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 2091d658336SSimo Sorce if (unlikely(p == NULL)) 2101d658336SSimo Sorce return -ENOSPC; 2111d658336SSimo Sorce 2121d658336SSimo Sorce q = p; 2131d658336SSimo Sorce end = q + length; 2141d658336SSimo Sorce 2151d658336SSimo Sorce /* uid */ 2161d658336SSimo Sorce err = get_s32(&q, end, &tmp); 2171d658336SSimo Sorce if (err) 2181d658336SSimo Sorce return err; 219d28fcc83SJ. Bruce Fields creds->cr_uid = make_kuid(&init_user_ns, tmp); 2201d658336SSimo Sorce 2211d658336SSimo Sorce /* gid */ 2221d658336SSimo Sorce err = get_s32(&q, end, &tmp); 2231d658336SSimo Sorce if (err) 2241d658336SSimo Sorce return err; 225d28fcc83SJ. Bruce Fields creds->cr_gid = make_kgid(&init_user_ns, tmp); 2261d658336SSimo Sorce 2271d658336SSimo Sorce /* number of additional gid's */ 2281d658336SSimo Sorce err = get_s32(&q, end, &tmp); 2291d658336SSimo Sorce if (err) 2301d658336SSimo Sorce return err; 2311d658336SSimo Sorce N = tmp; 2321d658336SSimo Sorce creds->cr_group_info = groups_alloc(N); 2331d658336SSimo Sorce if (creds->cr_group_info == NULL) 2341d658336SSimo Sorce return -ENOMEM; 2351d658336SSimo Sorce 2361d658336SSimo Sorce /* gid's */ 2371d658336SSimo Sorce for (i = 0; i < N; i++) { 238d28fcc83SJ. Bruce Fields kgid_t kgid; 2391d658336SSimo Sorce err = get_s32(&q, end, &tmp); 240d28fcc83SJ. Bruce Fields if (err) 241d28fcc83SJ. Bruce Fields goto out_free_groups; 242d28fcc83SJ. Bruce Fields err = -EINVAL; 243d28fcc83SJ. Bruce Fields kgid = make_kgid(&init_user_ns, tmp); 244d28fcc83SJ. Bruce Fields if (!gid_valid(kgid)) 245d28fcc83SJ. Bruce Fields goto out_free_groups; 246d28fcc83SJ. Bruce Fields GROUP_AT(creds->cr_group_info, i) = kgid; 2471d658336SSimo Sorce } 2481d658336SSimo Sorce 2491d658336SSimo Sorce return 0; 250d28fcc83SJ. Bruce Fields out_free_groups: 251d28fcc83SJ. Bruce Fields groups_free(creds->cr_group_info); 252d28fcc83SJ. Bruce Fields return err; 2531d658336SSimo Sorce } 2541d658336SSimo Sorce 2551d658336SSimo Sorce static int gssx_dec_option_array(struct xdr_stream *xdr, 2561d658336SSimo Sorce struct gssx_option_array *oa) 2571d658336SSimo Sorce { 2581d658336SSimo Sorce struct svc_cred *creds; 2591d658336SSimo Sorce u32 count, i; 2601d658336SSimo Sorce __be32 *p; 2611d658336SSimo Sorce int err; 2621d658336SSimo Sorce 2631d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2641d658336SSimo Sorce if (unlikely(p == NULL)) 2651d658336SSimo Sorce return -ENOSPC; 2661d658336SSimo Sorce count = be32_to_cpup(p++); 2671d658336SSimo Sorce if (count != 0) { 2681d658336SSimo Sorce /* we recognize only 1 currently: CREDS_VALUE */ 2691d658336SSimo Sorce oa->count = 1; 2701d658336SSimo Sorce 2711d658336SSimo Sorce oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL); 2721d658336SSimo Sorce if (!oa->data) 2731d658336SSimo Sorce return -ENOMEM; 2741d658336SSimo Sorce 2751d658336SSimo Sorce creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL); 2761d658336SSimo Sorce if (!creds) { 2771d658336SSimo Sorce kfree(oa->data); 2781d658336SSimo Sorce return -ENOMEM; 2791d658336SSimo Sorce } 2801d658336SSimo Sorce 2811d658336SSimo Sorce oa->data[0].option.data = CREDS_VALUE; 2821d658336SSimo Sorce oa->data[0].option.len = sizeof(CREDS_VALUE); 2831d658336SSimo Sorce oa->data[0].value.data = (void *)creds; 2841d658336SSimo Sorce oa->data[0].value.len = 0; 2851d658336SSimo Sorce } 2861d658336SSimo Sorce for (i = 0; i < count; i++) { 2871d658336SSimo Sorce gssx_buffer dummy = { 0, NULL }; 2881d658336SSimo Sorce u32 length; 2891d658336SSimo Sorce 2901d658336SSimo Sorce /* option buffer */ 2911d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2921d658336SSimo Sorce if (unlikely(p == NULL)) 2931d658336SSimo Sorce return -ENOSPC; 2941d658336SSimo Sorce 2951d658336SSimo Sorce length = be32_to_cpup(p); 2961d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 2971d658336SSimo Sorce if (unlikely(p == NULL)) 2981d658336SSimo Sorce return -ENOSPC; 2991d658336SSimo Sorce 3001d658336SSimo Sorce if (length == sizeof(CREDS_VALUE) && 3011d658336SSimo Sorce memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) { 3021d658336SSimo Sorce /* We have creds here. parse them */ 3031d658336SSimo Sorce err = gssx_dec_linux_creds(xdr, creds); 3041d658336SSimo Sorce if (err) 3051d658336SSimo Sorce return err; 3061d658336SSimo Sorce oa->data[0].value.len = 1; /* presence */ 3071d658336SSimo Sorce } else { 3081d658336SSimo Sorce /* consume uninteresting buffer */ 3091d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy); 3101d658336SSimo Sorce if (err) 3111d658336SSimo Sorce return err; 3121d658336SSimo Sorce } 3131d658336SSimo Sorce } 3141d658336SSimo Sorce return 0; 3151d658336SSimo Sorce } 3161d658336SSimo Sorce 3171d658336SSimo Sorce static int gssx_dec_status(struct xdr_stream *xdr, 3181d658336SSimo Sorce struct gssx_status *status) 3191d658336SSimo Sorce { 3201d658336SSimo Sorce __be32 *p; 3211d658336SSimo Sorce int err; 3221d658336SSimo Sorce 3231d658336SSimo Sorce /* status->major_status */ 3241d658336SSimo Sorce p = xdr_inline_decode(xdr, 8); 3251d658336SSimo Sorce if (unlikely(p == NULL)) 3261d658336SSimo Sorce return -ENOSPC; 3271d658336SSimo Sorce p = xdr_decode_hyper(p, &status->major_status); 3281d658336SSimo Sorce 3291d658336SSimo Sorce /* status->mech */ 3301d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->mech); 3311d658336SSimo Sorce if (err) 3321d658336SSimo Sorce return err; 3331d658336SSimo Sorce 3341d658336SSimo Sorce /* status->minor_status */ 3351d658336SSimo Sorce p = xdr_inline_decode(xdr, 8); 3361d658336SSimo Sorce if (unlikely(p == NULL)) 3371d658336SSimo Sorce return -ENOSPC; 3381d658336SSimo Sorce p = xdr_decode_hyper(p, &status->minor_status); 3391d658336SSimo Sorce 3401d658336SSimo Sorce /* status->major_status_string */ 3411d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->major_status_string); 3421d658336SSimo Sorce if (err) 3431d658336SSimo Sorce return err; 3441d658336SSimo Sorce 3451d658336SSimo Sorce /* status->minor_status_string */ 3461d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->minor_status_string); 3471d658336SSimo Sorce if (err) 3481d658336SSimo Sorce return err; 3491d658336SSimo Sorce 3501d658336SSimo Sorce /* status->server_ctx */ 3511d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->server_ctx); 3521d658336SSimo Sorce if (err) 3531d658336SSimo Sorce return err; 3541d658336SSimo Sorce 3551d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 3561d658336SSimo Sorce /* status->options */ 3571d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &status->options); 3581d658336SSimo Sorce 3591d658336SSimo Sorce return err; 3601d658336SSimo Sorce } 3611d658336SSimo Sorce 3621d658336SSimo Sorce static int gssx_enc_call_ctx(struct xdr_stream *xdr, 3631d658336SSimo Sorce struct gssx_call_ctx *ctx) 3641d658336SSimo Sorce { 3651d658336SSimo Sorce struct gssx_option opt; 3661d658336SSimo Sorce __be32 *p; 3671d658336SSimo Sorce int err; 3681d658336SSimo Sorce 3691d658336SSimo Sorce /* ctx->locale */ 3701d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->locale); 3711d658336SSimo Sorce if (err) 3721d658336SSimo Sorce return err; 3731d658336SSimo Sorce 3741d658336SSimo Sorce /* ctx->server_ctx */ 3751d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->server_ctx); 3761d658336SSimo Sorce if (err) 3771d658336SSimo Sorce return err; 3781d658336SSimo Sorce 3791d658336SSimo Sorce /* we always want to ask for lucid contexts */ 3801d658336SSimo Sorce /* ctx->options */ 3811d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 3821d658336SSimo Sorce *p = cpu_to_be32(2); 3831d658336SSimo Sorce 3841d658336SSimo Sorce /* we want a lucid_v1 context */ 3851d658336SSimo Sorce opt.option.data = LUCID_OPTION; 3861d658336SSimo Sorce opt.option.len = sizeof(LUCID_OPTION); 3871d658336SSimo Sorce opt.value.data = LUCID_VALUE; 3881d658336SSimo Sorce opt.value.len = sizeof(LUCID_VALUE); 3891d658336SSimo Sorce err = gssx_enc_option(xdr, &opt); 3901d658336SSimo Sorce 3911d658336SSimo Sorce /* ..and user creds */ 3921d658336SSimo Sorce opt.option.data = CREDS_OPTION; 3931d658336SSimo Sorce opt.option.len = sizeof(CREDS_OPTION); 3941d658336SSimo Sorce opt.value.data = CREDS_VALUE; 3951d658336SSimo Sorce opt.value.len = sizeof(CREDS_VALUE); 3961d658336SSimo Sorce err = gssx_enc_option(xdr, &opt); 3971d658336SSimo Sorce 3981d658336SSimo Sorce return err; 3991d658336SSimo Sorce } 4001d658336SSimo Sorce 4011d658336SSimo Sorce static int gssx_dec_name_attr(struct xdr_stream *xdr, 4021d658336SSimo Sorce struct gssx_name_attr *attr) 4031d658336SSimo Sorce { 4041d658336SSimo Sorce int err; 4051d658336SSimo Sorce 4061d658336SSimo Sorce /* attr->attr */ 4071d658336SSimo Sorce err = gssx_dec_buffer(xdr, &attr->attr); 4081d658336SSimo Sorce if (err) 4091d658336SSimo Sorce return err; 4101d658336SSimo Sorce 4111d658336SSimo Sorce /* attr->value */ 4121d658336SSimo Sorce err = gssx_dec_buffer(xdr, &attr->value); 4131d658336SSimo Sorce if (err) 4141d658336SSimo Sorce return err; 4151d658336SSimo Sorce 4161d658336SSimo Sorce /* attr->extensions */ 4171d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &attr->extensions); 4181d658336SSimo Sorce 4191d658336SSimo Sorce return err; 4201d658336SSimo Sorce } 4211d658336SSimo Sorce 4221d658336SSimo Sorce static int dummy_enc_nameattr_array(struct xdr_stream *xdr, 4231d658336SSimo Sorce struct gssx_name_attr_array *naa) 4241d658336SSimo Sorce { 4251d658336SSimo Sorce __be32 *p; 4261d658336SSimo Sorce 4271d658336SSimo Sorce if (naa->count != 0) 4281d658336SSimo Sorce return -EINVAL; 4291d658336SSimo Sorce 4301d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 4311d658336SSimo Sorce if (!p) 4321d658336SSimo Sorce return -ENOSPC; 4331d658336SSimo Sorce *p = 0; 4341d658336SSimo Sorce 4351d658336SSimo Sorce return 0; 4361d658336SSimo Sorce } 4371d658336SSimo Sorce 4381d658336SSimo Sorce static int dummy_dec_nameattr_array(struct xdr_stream *xdr, 4391d658336SSimo Sorce struct gssx_name_attr_array *naa) 4401d658336SSimo Sorce { 4411d658336SSimo Sorce struct gssx_name_attr dummy; 4421d658336SSimo Sorce u32 count, i; 4431d658336SSimo Sorce __be32 *p; 4441d658336SSimo Sorce 4451d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 4461d658336SSimo Sorce if (unlikely(p == NULL)) 4471d658336SSimo Sorce return -ENOSPC; 4481d658336SSimo Sorce count = be32_to_cpup(p++); 4491d658336SSimo Sorce for (i = 0; i < count; i++) { 4501d658336SSimo Sorce gssx_dec_name_attr(xdr, &dummy); 4511d658336SSimo Sorce } 4521d658336SSimo Sorce 4531d658336SSimo Sorce naa->count = 0; 4541d658336SSimo Sorce naa->data = NULL; 4551d658336SSimo Sorce return 0; 4561d658336SSimo Sorce } 4571d658336SSimo Sorce 4581d658336SSimo Sorce static struct xdr_netobj zero_netobj = {}; 4591d658336SSimo Sorce 4601d658336SSimo Sorce static struct gssx_name_attr_array zero_name_attr_array = {}; 4611d658336SSimo Sorce 4621d658336SSimo Sorce static struct gssx_option_array zero_option_array = {}; 4631d658336SSimo Sorce 4641d658336SSimo Sorce static int gssx_enc_name(struct xdr_stream *xdr, 4651d658336SSimo Sorce struct gssx_name *name) 4661d658336SSimo Sorce { 4671d658336SSimo Sorce int err; 4681d658336SSimo Sorce 4691d658336SSimo Sorce /* name->display_name */ 4701d658336SSimo Sorce err = gssx_enc_buffer(xdr, &name->display_name); 4711d658336SSimo Sorce if (err) 4721d658336SSimo Sorce return err; 4731d658336SSimo Sorce 4741d658336SSimo Sorce /* name->name_type */ 4751d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4761d658336SSimo Sorce if (err) 4771d658336SSimo Sorce return err; 4781d658336SSimo Sorce 4791d658336SSimo Sorce /* name->exported_name */ 4801d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4811d658336SSimo Sorce if (err) 4821d658336SSimo Sorce return err; 4831d658336SSimo Sorce 4841d658336SSimo Sorce /* name->exported_composite_name */ 4851d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4861d658336SSimo Sorce if (err) 4871d658336SSimo Sorce return err; 4881d658336SSimo Sorce 4891d658336SSimo Sorce /* leave name_attributes empty for now, will add once we have any 4901d658336SSimo Sorce * to pass up at all */ 4911d658336SSimo Sorce /* name->name_attributes */ 4921d658336SSimo Sorce err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array); 4931d658336SSimo Sorce if (err) 4941d658336SSimo Sorce return err; 4951d658336SSimo Sorce 4961d658336SSimo Sorce /* leave options empty for now, will add once we have any options 4971d658336SSimo Sorce * to pass up at all */ 4981d658336SSimo Sorce /* name->extensions */ 4991d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &zero_option_array); 5001d658336SSimo Sorce 5011d658336SSimo Sorce return err; 5021d658336SSimo Sorce } 5031d658336SSimo Sorce 5041d658336SSimo Sorce static int gssx_dec_name(struct xdr_stream *xdr, 5051d658336SSimo Sorce struct gssx_name *name) 5061d658336SSimo Sorce { 5071d658336SSimo Sorce struct xdr_netobj dummy_netobj; 5081d658336SSimo Sorce struct gssx_name_attr_array dummy_name_attr_array; 5091d658336SSimo Sorce struct gssx_option_array dummy_option_array; 5101d658336SSimo Sorce int err; 5111d658336SSimo Sorce 5121d658336SSimo Sorce /* name->display_name */ 5131d658336SSimo Sorce err = gssx_dec_buffer(xdr, &name->display_name); 5141d658336SSimo Sorce if (err) 5151d658336SSimo Sorce return err; 5161d658336SSimo Sorce 5171d658336SSimo Sorce /* name->name_type */ 5181d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5191d658336SSimo Sorce if (err) 5201d658336SSimo Sorce return err; 5211d658336SSimo Sorce 5221d658336SSimo Sorce /* name->exported_name */ 5231d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5241d658336SSimo Sorce if (err) 5251d658336SSimo Sorce return err; 5261d658336SSimo Sorce 5271d658336SSimo Sorce /* name->exported_composite_name */ 5281d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5291d658336SSimo Sorce if (err) 5301d658336SSimo Sorce return err; 5311d658336SSimo Sorce 5321d658336SSimo Sorce /* we assume we have no attributes for now, so simply consume them */ 5331d658336SSimo Sorce /* name->name_attributes */ 5341d658336SSimo Sorce err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array); 5351d658336SSimo Sorce if (err) 5361d658336SSimo Sorce return err; 5371d658336SSimo Sorce 5381d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 5391d658336SSimo Sorce /* name->extensions */ 5401d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &dummy_option_array); 5411d658336SSimo Sorce 5421d658336SSimo Sorce return err; 5431d658336SSimo Sorce } 5441d658336SSimo Sorce 5451d658336SSimo Sorce static int dummy_enc_credel_array(struct xdr_stream *xdr, 5461d658336SSimo Sorce struct gssx_cred_element_array *cea) 5471d658336SSimo Sorce { 5481d658336SSimo Sorce __be32 *p; 5491d658336SSimo Sorce 5501d658336SSimo Sorce if (cea->count != 0) 5511d658336SSimo Sorce return -EINVAL; 5521d658336SSimo Sorce 5531d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 5541d658336SSimo Sorce if (!p) 5551d658336SSimo Sorce return -ENOSPC; 5561d658336SSimo Sorce *p = 0; 5571d658336SSimo Sorce 5581d658336SSimo Sorce return 0; 5591d658336SSimo Sorce } 5601d658336SSimo Sorce 5611d658336SSimo Sorce static int gssx_enc_cred(struct xdr_stream *xdr, 5621d658336SSimo Sorce struct gssx_cred *cred) 5631d658336SSimo Sorce { 5641d658336SSimo Sorce int err; 5651d658336SSimo Sorce 5661d658336SSimo Sorce /* cred->desired_name */ 5671d658336SSimo Sorce err = gssx_enc_name(xdr, &cred->desired_name); 5681d658336SSimo Sorce if (err) 5691d658336SSimo Sorce return err; 5701d658336SSimo Sorce 5711d658336SSimo Sorce /* cred->elements */ 5721d658336SSimo Sorce err = dummy_enc_credel_array(xdr, &cred->elements); 5731d658336SSimo Sorce 5741d658336SSimo Sorce /* cred->cred_handle_reference */ 5751d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cred->cred_handle_reference); 5761d658336SSimo Sorce if (err) 5771d658336SSimo Sorce return err; 5781d658336SSimo Sorce 5791d658336SSimo Sorce /* cred->needs_release */ 5801d658336SSimo Sorce err = gssx_enc_bool(xdr, cred->needs_release); 5811d658336SSimo Sorce 5821d658336SSimo Sorce return err; 5831d658336SSimo Sorce } 5841d658336SSimo Sorce 5851d658336SSimo Sorce static int gssx_enc_ctx(struct xdr_stream *xdr, 5861d658336SSimo Sorce struct gssx_ctx *ctx) 5871d658336SSimo Sorce { 5881d658336SSimo Sorce __be32 *p; 5891d658336SSimo Sorce int err; 5901d658336SSimo Sorce 5911d658336SSimo Sorce /* ctx->exported_context_token */ 5921d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->exported_context_token); 5931d658336SSimo Sorce if (err) 5941d658336SSimo Sorce return err; 5951d658336SSimo Sorce 5961d658336SSimo Sorce /* ctx->state */ 5971d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->state); 5981d658336SSimo Sorce if (err) 5991d658336SSimo Sorce return err; 6001d658336SSimo Sorce 6011d658336SSimo Sorce /* ctx->need_release */ 6021d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->need_release); 6031d658336SSimo Sorce if (err) 6041d658336SSimo Sorce return err; 6051d658336SSimo Sorce 6061d658336SSimo Sorce /* ctx->mech */ 6071d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->mech); 6081d658336SSimo Sorce if (err) 6091d658336SSimo Sorce return err; 6101d658336SSimo Sorce 6111d658336SSimo Sorce /* ctx->src_name */ 6121d658336SSimo Sorce err = gssx_enc_name(xdr, &ctx->src_name); 6131d658336SSimo Sorce if (err) 6141d658336SSimo Sorce return err; 6151d658336SSimo Sorce 6161d658336SSimo Sorce /* ctx->targ_name */ 6171d658336SSimo Sorce err = gssx_enc_name(xdr, &ctx->targ_name); 6181d658336SSimo Sorce if (err) 6191d658336SSimo Sorce return err; 6201d658336SSimo Sorce 6211d658336SSimo Sorce /* ctx->lifetime */ 6221d658336SSimo Sorce p = xdr_reserve_space(xdr, 8+8); 6231d658336SSimo Sorce if (!p) 6241d658336SSimo Sorce return -ENOSPC; 6251d658336SSimo Sorce p = xdr_encode_hyper(p, ctx->lifetime); 6261d658336SSimo Sorce 6271d658336SSimo Sorce /* ctx->ctx_flags */ 6281d658336SSimo Sorce p = xdr_encode_hyper(p, ctx->ctx_flags); 6291d658336SSimo Sorce 6301d658336SSimo Sorce /* ctx->locally_initiated */ 6311d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->locally_initiated); 6321d658336SSimo Sorce if (err) 6331d658336SSimo Sorce return err; 6341d658336SSimo Sorce 6351d658336SSimo Sorce /* ctx->open */ 6361d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->open); 6371d658336SSimo Sorce if (err) 6381d658336SSimo Sorce return err; 6391d658336SSimo Sorce 6401d658336SSimo Sorce /* leave options empty for now, will add once we have any options 6411d658336SSimo Sorce * to pass up at all */ 6421d658336SSimo Sorce /* ctx->options */ 6431d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &ctx->options); 6441d658336SSimo Sorce 6451d658336SSimo Sorce return err; 6461d658336SSimo Sorce } 6471d658336SSimo Sorce 6481d658336SSimo Sorce static int gssx_dec_ctx(struct xdr_stream *xdr, 6491d658336SSimo Sorce struct gssx_ctx *ctx) 6501d658336SSimo Sorce { 6511d658336SSimo Sorce __be32 *p; 6521d658336SSimo Sorce int err; 6531d658336SSimo Sorce 6541d658336SSimo Sorce /* ctx->exported_context_token */ 6551d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->exported_context_token); 6561d658336SSimo Sorce if (err) 6571d658336SSimo Sorce return err; 6581d658336SSimo Sorce 6591d658336SSimo Sorce /* ctx->state */ 6601d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->state); 6611d658336SSimo Sorce if (err) 6621d658336SSimo Sorce return err; 6631d658336SSimo Sorce 6641d658336SSimo Sorce /* ctx->need_release */ 6651d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->need_release); 6661d658336SSimo Sorce if (err) 6671d658336SSimo Sorce return err; 6681d658336SSimo Sorce 6691d658336SSimo Sorce /* ctx->mech */ 6701d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->mech); 6711d658336SSimo Sorce if (err) 6721d658336SSimo Sorce return err; 6731d658336SSimo Sorce 6741d658336SSimo Sorce /* ctx->src_name */ 6751d658336SSimo Sorce err = gssx_dec_name(xdr, &ctx->src_name); 6761d658336SSimo Sorce if (err) 6771d658336SSimo Sorce return err; 6781d658336SSimo Sorce 6791d658336SSimo Sorce /* ctx->targ_name */ 6801d658336SSimo Sorce err = gssx_dec_name(xdr, &ctx->targ_name); 6811d658336SSimo Sorce if (err) 6821d658336SSimo Sorce return err; 6831d658336SSimo Sorce 6841d658336SSimo Sorce /* ctx->lifetime */ 6851d658336SSimo Sorce p = xdr_inline_decode(xdr, 8+8); 6861d658336SSimo Sorce if (unlikely(p == NULL)) 6871d658336SSimo Sorce return -ENOSPC; 6881d658336SSimo Sorce p = xdr_decode_hyper(p, &ctx->lifetime); 6891d658336SSimo Sorce 6901d658336SSimo Sorce /* ctx->ctx_flags */ 6911d658336SSimo Sorce p = xdr_decode_hyper(p, &ctx->ctx_flags); 6921d658336SSimo Sorce 6931d658336SSimo Sorce /* ctx->locally_initiated */ 6941d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->locally_initiated); 6951d658336SSimo Sorce if (err) 6961d658336SSimo Sorce return err; 6971d658336SSimo Sorce 6981d658336SSimo Sorce /* ctx->open */ 6991d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->open); 7001d658336SSimo Sorce if (err) 7011d658336SSimo Sorce return err; 7021d658336SSimo Sorce 7031d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 7041d658336SSimo Sorce /* ctx->options */ 7051d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &ctx->options); 7061d658336SSimo Sorce 7071d658336SSimo Sorce return err; 7081d658336SSimo Sorce } 7091d658336SSimo Sorce 7101d658336SSimo Sorce static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb) 7111d658336SSimo Sorce { 7121d658336SSimo Sorce __be32 *p; 7131d658336SSimo Sorce int err; 7141d658336SSimo Sorce 7151d658336SSimo Sorce /* cb->initiator_addrtype */ 7161d658336SSimo Sorce p = xdr_reserve_space(xdr, 8); 7171d658336SSimo Sorce if (!p) 7181d658336SSimo Sorce return -ENOSPC; 7191d658336SSimo Sorce p = xdr_encode_hyper(p, cb->initiator_addrtype); 7201d658336SSimo Sorce 7211d658336SSimo Sorce /* cb->initiator_address */ 7221d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->initiator_address); 7231d658336SSimo Sorce if (err) 7241d658336SSimo Sorce return err; 7251d658336SSimo Sorce 7261d658336SSimo Sorce /* cb->acceptor_addrtype */ 7271d658336SSimo Sorce p = xdr_reserve_space(xdr, 8); 7281d658336SSimo Sorce if (!p) 7291d658336SSimo Sorce return -ENOSPC; 7301d658336SSimo Sorce p = xdr_encode_hyper(p, cb->acceptor_addrtype); 7311d658336SSimo Sorce 7321d658336SSimo Sorce /* cb->acceptor_address */ 7331d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->acceptor_address); 7341d658336SSimo Sorce if (err) 7351d658336SSimo Sorce return err; 7361d658336SSimo Sorce 7371d658336SSimo Sorce /* cb->application_data */ 7381d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->application_data); 7391d658336SSimo Sorce 7401d658336SSimo Sorce return err; 7411d658336SSimo Sorce } 7421d658336SSimo Sorce 7431d658336SSimo Sorce void gssx_enc_accept_sec_context(struct rpc_rqst *req, 7441d658336SSimo Sorce struct xdr_stream *xdr, 7451d658336SSimo Sorce struct gssx_arg_accept_sec_context *arg) 7461d658336SSimo Sorce { 7471d658336SSimo Sorce int err; 7481d658336SSimo Sorce 7491d658336SSimo Sorce err = gssx_enc_call_ctx(xdr, &arg->call_ctx); 7501d658336SSimo Sorce if (err) 7511d658336SSimo Sorce goto done; 7521d658336SSimo Sorce 7531d658336SSimo Sorce /* arg->context_handle */ 7541d658336SSimo Sorce if (arg->context_handle) { 7551d658336SSimo Sorce err = gssx_enc_ctx(xdr, arg->context_handle); 7561d658336SSimo Sorce if (err) 7571d658336SSimo Sorce goto done; 7581d658336SSimo Sorce } else { 7591d658336SSimo Sorce err = gssx_enc_bool(xdr, 0); 7601d658336SSimo Sorce } 7611d658336SSimo Sorce 7621d658336SSimo Sorce /* arg->cred_handle */ 7631d658336SSimo Sorce if (arg->cred_handle) { 7641d658336SSimo Sorce err = gssx_enc_cred(xdr, arg->cred_handle); 7651d658336SSimo Sorce if (err) 7661d658336SSimo Sorce goto done; 7671d658336SSimo Sorce } else { 7681d658336SSimo Sorce err = gssx_enc_bool(xdr, 0); 7691d658336SSimo Sorce } 7701d658336SSimo Sorce 7711d658336SSimo Sorce /* arg->input_token */ 7721d658336SSimo Sorce err = gssx_enc_in_token(xdr, &arg->input_token); 7731d658336SSimo Sorce if (err) 7741d658336SSimo Sorce goto done; 7751d658336SSimo Sorce 7761d658336SSimo Sorce /* arg->input_cb */ 7771d658336SSimo Sorce if (arg->input_cb) { 7781d658336SSimo Sorce err = gssx_enc_cb(xdr, arg->input_cb); 7791d658336SSimo Sorce if (err) 7801d658336SSimo Sorce goto done; 7811d658336SSimo Sorce } else { 7821d658336SSimo Sorce err = gssx_enc_bool(xdr, 0); 7831d658336SSimo Sorce } 7841d658336SSimo Sorce 7851d658336SSimo Sorce err = gssx_enc_bool(xdr, arg->ret_deleg_cred); 7861d658336SSimo Sorce if (err) 7871d658336SSimo Sorce goto done; 7881d658336SSimo Sorce 7891d658336SSimo Sorce /* leave options empty for now, will add once we have any options 7901d658336SSimo Sorce * to pass up at all */ 7911d658336SSimo Sorce /* arg->options */ 7921d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &arg->options); 7931d658336SSimo Sorce 7941d658336SSimo Sorce done: 7951d658336SSimo Sorce if (err) 7961d658336SSimo Sorce dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); 7971d658336SSimo Sorce } 7981d658336SSimo Sorce 7991d658336SSimo Sorce int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, 8001d658336SSimo Sorce struct xdr_stream *xdr, 8011d658336SSimo Sorce struct gssx_res_accept_sec_context *res) 8021d658336SSimo Sorce { 8031d658336SSimo Sorce int err; 8041d658336SSimo Sorce 8051d658336SSimo Sorce /* res->status */ 8061d658336SSimo Sorce err = gssx_dec_status(xdr, &res->status); 8071d658336SSimo Sorce if (err) 8081d658336SSimo Sorce return err; 8091d658336SSimo Sorce 8101d658336SSimo Sorce /* res->context_handle */ 8111d658336SSimo Sorce if (gssx_check_pointer(xdr)) { 8121d658336SSimo Sorce err = gssx_dec_ctx(xdr, res->context_handle); 8131d658336SSimo Sorce if (err) 8141d658336SSimo Sorce return err; 8151d658336SSimo Sorce } else { 8161d658336SSimo Sorce res->context_handle = NULL; 8171d658336SSimo Sorce } 8181d658336SSimo Sorce 8191d658336SSimo Sorce /* res->output_token */ 8201d658336SSimo Sorce if (gssx_check_pointer(xdr)) { 8211d658336SSimo Sorce err = gssx_dec_buffer(xdr, res->output_token); 8221d658336SSimo Sorce if (err) 8231d658336SSimo Sorce return err; 8241d658336SSimo Sorce } else { 8251d658336SSimo Sorce res->output_token = NULL; 8261d658336SSimo Sorce } 8271d658336SSimo Sorce 8281d658336SSimo Sorce /* res->delegated_cred_handle */ 8291d658336SSimo Sorce if (gssx_check_pointer(xdr)) { 8301d658336SSimo Sorce /* we do not support upcall servers sending this data. */ 8311d658336SSimo Sorce return -EINVAL; 8321d658336SSimo Sorce } 8331d658336SSimo Sorce 8341d658336SSimo Sorce /* res->options */ 8351d658336SSimo Sorce err = gssx_dec_option_array(xdr, &res->options); 8361d658336SSimo Sorce 8371d658336SSimo Sorce return err; 8381d658336SSimo Sorce } 839