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 1691d658336SSimo Sorce static int get_s32(void **p, void *max, s32 *res) 1701d658336SSimo Sorce { 1711d658336SSimo Sorce void *base = *p; 1721d658336SSimo Sorce void *next = (void *)((char *)base + sizeof(s32)); 1731d658336SSimo Sorce if (unlikely(next > max || next < base)) 1741d658336SSimo Sorce return -EINVAL; 1751d658336SSimo Sorce memcpy(res, base, sizeof(s32)); 1761d658336SSimo Sorce *p = next; 1771d658336SSimo Sorce return 0; 1781d658336SSimo Sorce } 1791d658336SSimo Sorce 1801d658336SSimo Sorce static int gssx_dec_linux_creds(struct xdr_stream *xdr, 1811d658336SSimo Sorce struct svc_cred *creds) 1821d658336SSimo Sorce { 1831d658336SSimo Sorce u32 length; 1841d658336SSimo Sorce __be32 *p; 1851d658336SSimo Sorce void *q, *end; 1861d658336SSimo Sorce s32 tmp; 1871d658336SSimo Sorce int N, i, err; 1881d658336SSimo Sorce 1891d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 1901d658336SSimo Sorce if (unlikely(p == NULL)) 1911d658336SSimo Sorce return -ENOSPC; 1921d658336SSimo Sorce 1931d658336SSimo Sorce length = be32_to_cpup(p); 1941d658336SSimo Sorce 1951d658336SSimo Sorce /* FIXME: we do not want to use the scratch buffer for this one 1961d658336SSimo Sorce * may need to use functions that allows us to access an io vector 1971d658336SSimo Sorce * directly */ 1981d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 1991d658336SSimo Sorce if (unlikely(p == NULL)) 2001d658336SSimo Sorce return -ENOSPC; 2011d658336SSimo Sorce 2021d658336SSimo Sorce q = p; 2031d658336SSimo Sorce end = q + length; 2041d658336SSimo Sorce 2051d658336SSimo Sorce /* uid */ 2061d658336SSimo Sorce err = get_s32(&q, end, &tmp); 2071d658336SSimo Sorce if (err) 2081d658336SSimo Sorce return err; 209d28fcc83SJ. Bruce Fields creds->cr_uid = make_kuid(&init_user_ns, tmp); 2101d658336SSimo Sorce 2111d658336SSimo Sorce /* gid */ 2121d658336SSimo Sorce err = get_s32(&q, end, &tmp); 2131d658336SSimo Sorce if (err) 2141d658336SSimo Sorce return err; 215d28fcc83SJ. Bruce Fields creds->cr_gid = make_kgid(&init_user_ns, tmp); 2161d658336SSimo Sorce 2171d658336SSimo Sorce /* number of additional gid's */ 2181d658336SSimo Sorce err = get_s32(&q, end, &tmp); 2191d658336SSimo Sorce if (err) 2201d658336SSimo Sorce return err; 2211d658336SSimo Sorce N = tmp; 2221d658336SSimo Sorce creds->cr_group_info = groups_alloc(N); 2231d658336SSimo Sorce if (creds->cr_group_info == NULL) 2241d658336SSimo Sorce return -ENOMEM; 2251d658336SSimo Sorce 2261d658336SSimo Sorce /* gid's */ 2271d658336SSimo Sorce for (i = 0; i < N; i++) { 228d28fcc83SJ. Bruce Fields kgid_t kgid; 2291d658336SSimo Sorce err = get_s32(&q, end, &tmp); 230d28fcc83SJ. Bruce Fields if (err) 231d28fcc83SJ. Bruce Fields goto out_free_groups; 232d28fcc83SJ. Bruce Fields err = -EINVAL; 233d28fcc83SJ. Bruce Fields kgid = make_kgid(&init_user_ns, tmp); 234d28fcc83SJ. Bruce Fields if (!gid_valid(kgid)) 235d28fcc83SJ. Bruce Fields goto out_free_groups; 236d28fcc83SJ. Bruce Fields GROUP_AT(creds->cr_group_info, i) = kgid; 2371d658336SSimo Sorce } 2381d658336SSimo Sorce 2391d658336SSimo Sorce return 0; 240d28fcc83SJ. Bruce Fields out_free_groups: 241d28fcc83SJ. Bruce Fields groups_free(creds->cr_group_info); 242d28fcc83SJ. Bruce Fields return err; 2431d658336SSimo Sorce } 2441d658336SSimo Sorce 2451d658336SSimo Sorce static int gssx_dec_option_array(struct xdr_stream *xdr, 2461d658336SSimo Sorce struct gssx_option_array *oa) 2471d658336SSimo Sorce { 2481d658336SSimo Sorce struct svc_cred *creds; 2491d658336SSimo Sorce u32 count, i; 2501d658336SSimo Sorce __be32 *p; 2511d658336SSimo Sorce int err; 2521d658336SSimo Sorce 2531d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2541d658336SSimo Sorce if (unlikely(p == NULL)) 2551d658336SSimo Sorce return -ENOSPC; 2561d658336SSimo Sorce count = be32_to_cpup(p++); 2579fd40c5aSGeert Uytterhoeven if (!count) 2589fd40c5aSGeert Uytterhoeven return 0; 2599fd40c5aSGeert Uytterhoeven 2601d658336SSimo Sorce /* we recognize only 1 currently: CREDS_VALUE */ 2611d658336SSimo Sorce oa->count = 1; 2621d658336SSimo Sorce 2631d658336SSimo Sorce oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL); 2641d658336SSimo Sorce if (!oa->data) 2651d658336SSimo Sorce return -ENOMEM; 2661d658336SSimo Sorce 2671d658336SSimo Sorce creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL); 2681d658336SSimo Sorce if (!creds) { 2691d658336SSimo Sorce kfree(oa->data); 2701d658336SSimo Sorce return -ENOMEM; 2711d658336SSimo Sorce } 2721d658336SSimo Sorce 2731d658336SSimo Sorce oa->data[0].option.data = CREDS_VALUE; 2741d658336SSimo Sorce oa->data[0].option.len = sizeof(CREDS_VALUE); 2751d658336SSimo Sorce oa->data[0].value.data = (void *)creds; 2761d658336SSimo Sorce oa->data[0].value.len = 0; 2779fd40c5aSGeert Uytterhoeven 2781d658336SSimo Sorce for (i = 0; i < count; i++) { 2791d658336SSimo Sorce gssx_buffer dummy = { 0, NULL }; 2801d658336SSimo Sorce u32 length; 2811d658336SSimo Sorce 2821d658336SSimo Sorce /* option buffer */ 2831d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 2841d658336SSimo Sorce if (unlikely(p == NULL)) 2851d658336SSimo Sorce return -ENOSPC; 2861d658336SSimo Sorce 2871d658336SSimo Sorce length = be32_to_cpup(p); 2881d658336SSimo Sorce p = xdr_inline_decode(xdr, length); 2891d658336SSimo Sorce if (unlikely(p == NULL)) 2901d658336SSimo Sorce return -ENOSPC; 2911d658336SSimo Sorce 2921d658336SSimo Sorce if (length == sizeof(CREDS_VALUE) && 2931d658336SSimo Sorce memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) { 2941d658336SSimo Sorce /* We have creds here. parse them */ 2951d658336SSimo Sorce err = gssx_dec_linux_creds(xdr, creds); 2961d658336SSimo Sorce if (err) 2971d658336SSimo Sorce return err; 2981d658336SSimo Sorce oa->data[0].value.len = 1; /* presence */ 2991d658336SSimo Sorce } else { 3001d658336SSimo Sorce /* consume uninteresting buffer */ 3011d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy); 3021d658336SSimo Sorce if (err) 3031d658336SSimo Sorce return err; 3041d658336SSimo Sorce } 3051d658336SSimo Sorce } 3061d658336SSimo Sorce return 0; 3071d658336SSimo Sorce } 3081d658336SSimo Sorce 3091d658336SSimo Sorce static int gssx_dec_status(struct xdr_stream *xdr, 3101d658336SSimo Sorce struct gssx_status *status) 3111d658336SSimo Sorce { 3121d658336SSimo Sorce __be32 *p; 3131d658336SSimo Sorce int err; 3141d658336SSimo Sorce 3151d658336SSimo Sorce /* status->major_status */ 3161d658336SSimo Sorce p = xdr_inline_decode(xdr, 8); 3171d658336SSimo Sorce if (unlikely(p == NULL)) 3181d658336SSimo Sorce return -ENOSPC; 3191d658336SSimo Sorce p = xdr_decode_hyper(p, &status->major_status); 3201d658336SSimo Sorce 3211d658336SSimo Sorce /* status->mech */ 3221d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->mech); 3231d658336SSimo Sorce if (err) 3241d658336SSimo Sorce return err; 3251d658336SSimo Sorce 3261d658336SSimo Sorce /* status->minor_status */ 3271d658336SSimo Sorce p = xdr_inline_decode(xdr, 8); 3281d658336SSimo Sorce if (unlikely(p == NULL)) 3291d658336SSimo Sorce return -ENOSPC; 3301d658336SSimo Sorce p = xdr_decode_hyper(p, &status->minor_status); 3311d658336SSimo Sorce 3321d658336SSimo Sorce /* status->major_status_string */ 3331d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->major_status_string); 3341d658336SSimo Sorce if (err) 3351d658336SSimo Sorce return err; 3361d658336SSimo Sorce 3371d658336SSimo Sorce /* status->minor_status_string */ 3381d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->minor_status_string); 3391d658336SSimo Sorce if (err) 3401d658336SSimo Sorce return err; 3411d658336SSimo Sorce 3421d658336SSimo Sorce /* status->server_ctx */ 3431d658336SSimo Sorce err = gssx_dec_buffer(xdr, &status->server_ctx); 3441d658336SSimo Sorce if (err) 3451d658336SSimo Sorce return err; 3461d658336SSimo Sorce 3471d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 3481d658336SSimo Sorce /* status->options */ 3491d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &status->options); 3501d658336SSimo Sorce 3511d658336SSimo Sorce return err; 3521d658336SSimo Sorce } 3531d658336SSimo Sorce 3541d658336SSimo Sorce static int gssx_enc_call_ctx(struct xdr_stream *xdr, 3551d658336SSimo Sorce struct gssx_call_ctx *ctx) 3561d658336SSimo Sorce { 3571d658336SSimo Sorce struct gssx_option opt; 3581d658336SSimo Sorce __be32 *p; 3591d658336SSimo Sorce int err; 3601d658336SSimo Sorce 3611d658336SSimo Sorce /* ctx->locale */ 3621d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->locale); 3631d658336SSimo Sorce if (err) 3641d658336SSimo Sorce return err; 3651d658336SSimo Sorce 3661d658336SSimo Sorce /* ctx->server_ctx */ 3671d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->server_ctx); 3681d658336SSimo Sorce if (err) 3691d658336SSimo Sorce return err; 3701d658336SSimo Sorce 3711d658336SSimo Sorce /* we always want to ask for lucid contexts */ 3721d658336SSimo Sorce /* ctx->options */ 3731d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 3741d658336SSimo Sorce *p = cpu_to_be32(2); 3751d658336SSimo Sorce 3761d658336SSimo Sorce /* we want a lucid_v1 context */ 3771d658336SSimo Sorce opt.option.data = LUCID_OPTION; 3781d658336SSimo Sorce opt.option.len = sizeof(LUCID_OPTION); 3791d658336SSimo Sorce opt.value.data = LUCID_VALUE; 3801d658336SSimo Sorce opt.value.len = sizeof(LUCID_VALUE); 3811d658336SSimo Sorce err = gssx_enc_option(xdr, &opt); 3821d658336SSimo Sorce 3831d658336SSimo Sorce /* ..and user creds */ 3841d658336SSimo Sorce opt.option.data = CREDS_OPTION; 3851d658336SSimo Sorce opt.option.len = sizeof(CREDS_OPTION); 3861d658336SSimo Sorce opt.value.data = CREDS_VALUE; 3871d658336SSimo Sorce opt.value.len = sizeof(CREDS_VALUE); 3881d658336SSimo Sorce err = gssx_enc_option(xdr, &opt); 3891d658336SSimo Sorce 3901d658336SSimo Sorce return err; 3911d658336SSimo Sorce } 3921d658336SSimo Sorce 3931d658336SSimo Sorce static int gssx_dec_name_attr(struct xdr_stream *xdr, 3941d658336SSimo Sorce struct gssx_name_attr *attr) 3951d658336SSimo Sorce { 3961d658336SSimo Sorce int err; 3971d658336SSimo Sorce 3981d658336SSimo Sorce /* attr->attr */ 3991d658336SSimo Sorce err = gssx_dec_buffer(xdr, &attr->attr); 4001d658336SSimo Sorce if (err) 4011d658336SSimo Sorce return err; 4021d658336SSimo Sorce 4031d658336SSimo Sorce /* attr->value */ 4041d658336SSimo Sorce err = gssx_dec_buffer(xdr, &attr->value); 4051d658336SSimo Sorce if (err) 4061d658336SSimo Sorce return err; 4071d658336SSimo Sorce 4081d658336SSimo Sorce /* attr->extensions */ 4091d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &attr->extensions); 4101d658336SSimo Sorce 4111d658336SSimo Sorce return err; 4121d658336SSimo Sorce } 4131d658336SSimo Sorce 4141d658336SSimo Sorce static int dummy_enc_nameattr_array(struct xdr_stream *xdr, 4151d658336SSimo Sorce struct gssx_name_attr_array *naa) 4161d658336SSimo Sorce { 4171d658336SSimo Sorce __be32 *p; 4181d658336SSimo Sorce 4191d658336SSimo Sorce if (naa->count != 0) 4201d658336SSimo Sorce return -EINVAL; 4211d658336SSimo Sorce 4221d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 4231d658336SSimo Sorce if (!p) 4241d658336SSimo Sorce return -ENOSPC; 4251d658336SSimo Sorce *p = 0; 4261d658336SSimo Sorce 4271d658336SSimo Sorce return 0; 4281d658336SSimo Sorce } 4291d658336SSimo Sorce 4301d658336SSimo Sorce static int dummy_dec_nameattr_array(struct xdr_stream *xdr, 4311d658336SSimo Sorce struct gssx_name_attr_array *naa) 4321d658336SSimo Sorce { 433dc43376cSJ. Bruce Fields struct gssx_name_attr dummy = { .attr = {.len = 0} }; 4341d658336SSimo Sorce u32 count, i; 4351d658336SSimo Sorce __be32 *p; 4361d658336SSimo Sorce 4371d658336SSimo Sorce p = xdr_inline_decode(xdr, 4); 4381d658336SSimo Sorce if (unlikely(p == NULL)) 4391d658336SSimo Sorce return -ENOSPC; 4401d658336SSimo Sorce count = be32_to_cpup(p++); 4411d658336SSimo Sorce for (i = 0; i < count; i++) { 4421d658336SSimo Sorce gssx_dec_name_attr(xdr, &dummy); 4431d658336SSimo Sorce } 4441d658336SSimo Sorce 4451d658336SSimo Sorce naa->count = 0; 4461d658336SSimo Sorce naa->data = NULL; 4471d658336SSimo Sorce return 0; 4481d658336SSimo Sorce } 4491d658336SSimo Sorce 4501d658336SSimo Sorce static struct xdr_netobj zero_netobj = {}; 4511d658336SSimo Sorce 4521d658336SSimo Sorce static struct gssx_name_attr_array zero_name_attr_array = {}; 4531d658336SSimo Sorce 4541d658336SSimo Sorce static struct gssx_option_array zero_option_array = {}; 4551d658336SSimo Sorce 4561d658336SSimo Sorce static int gssx_enc_name(struct xdr_stream *xdr, 4571d658336SSimo Sorce struct gssx_name *name) 4581d658336SSimo Sorce { 4591d658336SSimo Sorce int err; 4601d658336SSimo Sorce 4611d658336SSimo Sorce /* name->display_name */ 4621d658336SSimo Sorce err = gssx_enc_buffer(xdr, &name->display_name); 4631d658336SSimo Sorce if (err) 4641d658336SSimo Sorce return err; 4651d658336SSimo Sorce 4661d658336SSimo Sorce /* name->name_type */ 4671d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4681d658336SSimo Sorce if (err) 4691d658336SSimo Sorce return err; 4701d658336SSimo Sorce 4711d658336SSimo Sorce /* name->exported_name */ 4721d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4731d658336SSimo Sorce if (err) 4741d658336SSimo Sorce return err; 4751d658336SSimo Sorce 4761d658336SSimo Sorce /* name->exported_composite_name */ 4771d658336SSimo Sorce err = gssx_enc_buffer(xdr, &zero_netobj); 4781d658336SSimo Sorce if (err) 4791d658336SSimo Sorce return err; 4801d658336SSimo Sorce 4811d658336SSimo Sorce /* leave name_attributes empty for now, will add once we have any 4821d658336SSimo Sorce * to pass up at all */ 4831d658336SSimo Sorce /* name->name_attributes */ 4841d658336SSimo Sorce err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array); 4851d658336SSimo Sorce if (err) 4861d658336SSimo Sorce return err; 4871d658336SSimo Sorce 4881d658336SSimo Sorce /* leave options empty for now, will add once we have any options 4891d658336SSimo Sorce * to pass up at all */ 4901d658336SSimo Sorce /* name->extensions */ 4911d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &zero_option_array); 4921d658336SSimo Sorce 4931d658336SSimo Sorce return err; 4941d658336SSimo Sorce } 4951d658336SSimo Sorce 496dc43376cSJ. Bruce Fields 4971d658336SSimo Sorce static int gssx_dec_name(struct xdr_stream *xdr, 4981d658336SSimo Sorce struct gssx_name *name) 4991d658336SSimo Sorce { 500dc43376cSJ. Bruce Fields struct xdr_netobj dummy_netobj = { .len = 0 }; 501dc43376cSJ. Bruce Fields struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 }; 502dc43376cSJ. Bruce Fields struct gssx_option_array dummy_option_array = { .count = 0 }; 5031d658336SSimo Sorce int err; 5041d658336SSimo Sorce 5051d658336SSimo Sorce /* name->display_name */ 5061d658336SSimo Sorce err = gssx_dec_buffer(xdr, &name->display_name); 5071d658336SSimo Sorce if (err) 5081d658336SSimo Sorce return err; 5091d658336SSimo Sorce 5101d658336SSimo Sorce /* name->name_type */ 5111d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5121d658336SSimo Sorce if (err) 5131d658336SSimo Sorce return err; 5141d658336SSimo Sorce 5151d658336SSimo Sorce /* name->exported_name */ 5161d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5171d658336SSimo Sorce if (err) 5181d658336SSimo Sorce return err; 5191d658336SSimo Sorce 5201d658336SSimo Sorce /* name->exported_composite_name */ 5211d658336SSimo Sorce err = gssx_dec_buffer(xdr, &dummy_netobj); 5221d658336SSimo Sorce if (err) 5231d658336SSimo Sorce return err; 5241d658336SSimo Sorce 5251d658336SSimo Sorce /* we assume we have no attributes for now, so simply consume them */ 5261d658336SSimo Sorce /* name->name_attributes */ 5271d658336SSimo Sorce err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array); 5281d658336SSimo Sorce if (err) 5291d658336SSimo Sorce return err; 5301d658336SSimo Sorce 5311d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 5321d658336SSimo Sorce /* name->extensions */ 5331d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &dummy_option_array); 5341d658336SSimo Sorce 5351d658336SSimo Sorce return err; 5361d658336SSimo Sorce } 5371d658336SSimo Sorce 5381d658336SSimo Sorce static int dummy_enc_credel_array(struct xdr_stream *xdr, 5391d658336SSimo Sorce struct gssx_cred_element_array *cea) 5401d658336SSimo Sorce { 5411d658336SSimo Sorce __be32 *p; 5421d658336SSimo Sorce 5431d658336SSimo Sorce if (cea->count != 0) 5441d658336SSimo Sorce return -EINVAL; 5451d658336SSimo Sorce 5461d658336SSimo Sorce p = xdr_reserve_space(xdr, 4); 5471d658336SSimo Sorce if (!p) 5481d658336SSimo Sorce return -ENOSPC; 5491d658336SSimo Sorce *p = 0; 5501d658336SSimo Sorce 5511d658336SSimo Sorce return 0; 5521d658336SSimo Sorce } 5531d658336SSimo Sorce 5541d658336SSimo Sorce static int gssx_enc_cred(struct xdr_stream *xdr, 5551d658336SSimo Sorce struct gssx_cred *cred) 5561d658336SSimo Sorce { 5571d658336SSimo Sorce int err; 5581d658336SSimo Sorce 5591d658336SSimo Sorce /* cred->desired_name */ 5601d658336SSimo Sorce err = gssx_enc_name(xdr, &cred->desired_name); 5611d658336SSimo Sorce if (err) 5621d658336SSimo Sorce return err; 5631d658336SSimo Sorce 5641d658336SSimo Sorce /* cred->elements */ 5651d658336SSimo Sorce err = dummy_enc_credel_array(xdr, &cred->elements); 5661d658336SSimo Sorce 5671d658336SSimo Sorce /* cred->cred_handle_reference */ 5681d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cred->cred_handle_reference); 5691d658336SSimo Sorce if (err) 5701d658336SSimo Sorce return err; 5711d658336SSimo Sorce 5721d658336SSimo Sorce /* cred->needs_release */ 5731d658336SSimo Sorce err = gssx_enc_bool(xdr, cred->needs_release); 5741d658336SSimo Sorce 5751d658336SSimo Sorce return err; 5761d658336SSimo Sorce } 5771d658336SSimo Sorce 5781d658336SSimo Sorce static int gssx_enc_ctx(struct xdr_stream *xdr, 5791d658336SSimo Sorce struct gssx_ctx *ctx) 5801d658336SSimo Sorce { 5811d658336SSimo Sorce __be32 *p; 5821d658336SSimo Sorce int err; 5831d658336SSimo Sorce 5841d658336SSimo Sorce /* ctx->exported_context_token */ 5851d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->exported_context_token); 5861d658336SSimo Sorce if (err) 5871d658336SSimo Sorce return err; 5881d658336SSimo Sorce 5891d658336SSimo Sorce /* ctx->state */ 5901d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->state); 5911d658336SSimo Sorce if (err) 5921d658336SSimo Sorce return err; 5931d658336SSimo Sorce 5941d658336SSimo Sorce /* ctx->need_release */ 5951d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->need_release); 5961d658336SSimo Sorce if (err) 5971d658336SSimo Sorce return err; 5981d658336SSimo Sorce 5991d658336SSimo Sorce /* ctx->mech */ 6001d658336SSimo Sorce err = gssx_enc_buffer(xdr, &ctx->mech); 6011d658336SSimo Sorce if (err) 6021d658336SSimo Sorce return err; 6031d658336SSimo Sorce 6041d658336SSimo Sorce /* ctx->src_name */ 6051d658336SSimo Sorce err = gssx_enc_name(xdr, &ctx->src_name); 6061d658336SSimo Sorce if (err) 6071d658336SSimo Sorce return err; 6081d658336SSimo Sorce 6091d658336SSimo Sorce /* ctx->targ_name */ 6101d658336SSimo Sorce err = gssx_enc_name(xdr, &ctx->targ_name); 6111d658336SSimo Sorce if (err) 6121d658336SSimo Sorce return err; 6131d658336SSimo Sorce 6141d658336SSimo Sorce /* ctx->lifetime */ 6151d658336SSimo Sorce p = xdr_reserve_space(xdr, 8+8); 6161d658336SSimo Sorce if (!p) 6171d658336SSimo Sorce return -ENOSPC; 6181d658336SSimo Sorce p = xdr_encode_hyper(p, ctx->lifetime); 6191d658336SSimo Sorce 6201d658336SSimo Sorce /* ctx->ctx_flags */ 6211d658336SSimo Sorce p = xdr_encode_hyper(p, ctx->ctx_flags); 6221d658336SSimo Sorce 6231d658336SSimo Sorce /* ctx->locally_initiated */ 6241d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->locally_initiated); 6251d658336SSimo Sorce if (err) 6261d658336SSimo Sorce return err; 6271d658336SSimo Sorce 6281d658336SSimo Sorce /* ctx->open */ 6291d658336SSimo Sorce err = gssx_enc_bool(xdr, ctx->open); 6301d658336SSimo Sorce if (err) 6311d658336SSimo Sorce return err; 6321d658336SSimo Sorce 6331d658336SSimo Sorce /* leave options empty for now, will add once we have any options 6341d658336SSimo Sorce * to pass up at all */ 6351d658336SSimo Sorce /* ctx->options */ 6361d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &ctx->options); 6371d658336SSimo Sorce 6381d658336SSimo Sorce return err; 6391d658336SSimo Sorce } 6401d658336SSimo Sorce 6411d658336SSimo Sorce static int gssx_dec_ctx(struct xdr_stream *xdr, 6421d658336SSimo Sorce struct gssx_ctx *ctx) 6431d658336SSimo Sorce { 6441d658336SSimo Sorce __be32 *p; 6451d658336SSimo Sorce int err; 6461d658336SSimo Sorce 6471d658336SSimo Sorce /* ctx->exported_context_token */ 6481d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->exported_context_token); 6491d658336SSimo Sorce if (err) 6501d658336SSimo Sorce return err; 6511d658336SSimo Sorce 6521d658336SSimo Sorce /* ctx->state */ 6531d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->state); 6541d658336SSimo Sorce if (err) 6551d658336SSimo Sorce return err; 6561d658336SSimo Sorce 6571d658336SSimo Sorce /* ctx->need_release */ 6581d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->need_release); 6591d658336SSimo Sorce if (err) 6601d658336SSimo Sorce return err; 6611d658336SSimo Sorce 6621d658336SSimo Sorce /* ctx->mech */ 6631d658336SSimo Sorce err = gssx_dec_buffer(xdr, &ctx->mech); 6641d658336SSimo Sorce if (err) 6651d658336SSimo Sorce return err; 6661d658336SSimo Sorce 6671d658336SSimo Sorce /* ctx->src_name */ 6681d658336SSimo Sorce err = gssx_dec_name(xdr, &ctx->src_name); 6691d658336SSimo Sorce if (err) 6701d658336SSimo Sorce return err; 6711d658336SSimo Sorce 6721d658336SSimo Sorce /* ctx->targ_name */ 6731d658336SSimo Sorce err = gssx_dec_name(xdr, &ctx->targ_name); 6741d658336SSimo Sorce if (err) 6751d658336SSimo Sorce return err; 6761d658336SSimo Sorce 6771d658336SSimo Sorce /* ctx->lifetime */ 6781d658336SSimo Sorce p = xdr_inline_decode(xdr, 8+8); 6791d658336SSimo Sorce if (unlikely(p == NULL)) 6801d658336SSimo Sorce return -ENOSPC; 6811d658336SSimo Sorce p = xdr_decode_hyper(p, &ctx->lifetime); 6821d658336SSimo Sorce 6831d658336SSimo Sorce /* ctx->ctx_flags */ 6841d658336SSimo Sorce p = xdr_decode_hyper(p, &ctx->ctx_flags); 6851d658336SSimo Sorce 6861d658336SSimo Sorce /* ctx->locally_initiated */ 6871d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->locally_initiated); 6881d658336SSimo Sorce if (err) 6891d658336SSimo Sorce return err; 6901d658336SSimo Sorce 6911d658336SSimo Sorce /* ctx->open */ 6921d658336SSimo Sorce err = gssx_dec_bool(xdr, &ctx->open); 6931d658336SSimo Sorce if (err) 6941d658336SSimo Sorce return err; 6951d658336SSimo Sorce 6961d658336SSimo Sorce /* we assume we have no options for now, so simply consume them */ 6971d658336SSimo Sorce /* ctx->options */ 6981d658336SSimo Sorce err = dummy_dec_opt_array(xdr, &ctx->options); 6991d658336SSimo Sorce 7001d658336SSimo Sorce return err; 7011d658336SSimo Sorce } 7021d658336SSimo Sorce 7031d658336SSimo Sorce static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb) 7041d658336SSimo Sorce { 7051d658336SSimo Sorce __be32 *p; 7061d658336SSimo Sorce int err; 7071d658336SSimo Sorce 7081d658336SSimo Sorce /* cb->initiator_addrtype */ 7091d658336SSimo Sorce p = xdr_reserve_space(xdr, 8); 7101d658336SSimo Sorce if (!p) 7111d658336SSimo Sorce return -ENOSPC; 7121d658336SSimo Sorce p = xdr_encode_hyper(p, cb->initiator_addrtype); 7131d658336SSimo Sorce 7141d658336SSimo Sorce /* cb->initiator_address */ 7151d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->initiator_address); 7161d658336SSimo Sorce if (err) 7171d658336SSimo Sorce return err; 7181d658336SSimo Sorce 7191d658336SSimo Sorce /* cb->acceptor_addrtype */ 7201d658336SSimo Sorce p = xdr_reserve_space(xdr, 8); 7211d658336SSimo Sorce if (!p) 7221d658336SSimo Sorce return -ENOSPC; 7231d658336SSimo Sorce p = xdr_encode_hyper(p, cb->acceptor_addrtype); 7241d658336SSimo Sorce 7251d658336SSimo Sorce /* cb->acceptor_address */ 7261d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->acceptor_address); 7271d658336SSimo Sorce if (err) 7281d658336SSimo Sorce return err; 7291d658336SSimo Sorce 7301d658336SSimo Sorce /* cb->application_data */ 7311d658336SSimo Sorce err = gssx_enc_buffer(xdr, &cb->application_data); 7321d658336SSimo Sorce 7331d658336SSimo Sorce return err; 7341d658336SSimo Sorce } 7351d658336SSimo Sorce 7361d658336SSimo Sorce void gssx_enc_accept_sec_context(struct rpc_rqst *req, 7371d658336SSimo Sorce struct xdr_stream *xdr, 7381d658336SSimo Sorce struct gssx_arg_accept_sec_context *arg) 7391d658336SSimo Sorce { 7401d658336SSimo Sorce int err; 7411d658336SSimo Sorce 7421d658336SSimo Sorce err = gssx_enc_call_ctx(xdr, &arg->call_ctx); 7431d658336SSimo Sorce if (err) 7441d658336SSimo Sorce goto done; 7451d658336SSimo Sorce 7461d658336SSimo Sorce /* arg->context_handle */ 7471d658336SSimo Sorce if (arg->context_handle) { 7481d658336SSimo Sorce err = gssx_enc_ctx(xdr, arg->context_handle); 7491d658336SSimo Sorce if (err) 7501d658336SSimo Sorce goto done; 7511d658336SSimo Sorce } else { 7521d658336SSimo Sorce err = gssx_enc_bool(xdr, 0); 7531d658336SSimo Sorce } 7541d658336SSimo Sorce 7551d658336SSimo Sorce /* arg->cred_handle */ 7561d658336SSimo Sorce if (arg->cred_handle) { 7571d658336SSimo Sorce err = gssx_enc_cred(xdr, arg->cred_handle); 7581d658336SSimo Sorce if (err) 7591d658336SSimo Sorce goto done; 7601d658336SSimo Sorce } else { 7611d658336SSimo Sorce err = gssx_enc_bool(xdr, 0); 7621d658336SSimo Sorce } 7631d658336SSimo Sorce 7641d658336SSimo Sorce /* arg->input_token */ 7651d658336SSimo Sorce err = gssx_enc_in_token(xdr, &arg->input_token); 7661d658336SSimo Sorce if (err) 7671d658336SSimo Sorce goto done; 7681d658336SSimo Sorce 7691d658336SSimo Sorce /* arg->input_cb */ 7701d658336SSimo Sorce if (arg->input_cb) { 7711d658336SSimo Sorce err = gssx_enc_cb(xdr, arg->input_cb); 7721d658336SSimo Sorce if (err) 7731d658336SSimo Sorce goto done; 7741d658336SSimo Sorce } else { 7751d658336SSimo Sorce err = gssx_enc_bool(xdr, 0); 7761d658336SSimo Sorce } 7771d658336SSimo Sorce 7781d658336SSimo Sorce err = gssx_enc_bool(xdr, arg->ret_deleg_cred); 7791d658336SSimo Sorce if (err) 7801d658336SSimo Sorce goto done; 7811d658336SSimo Sorce 7821d658336SSimo Sorce /* leave options empty for now, will add once we have any options 7831d658336SSimo Sorce * to pass up at all */ 7841d658336SSimo Sorce /* arg->options */ 7851d658336SSimo Sorce err = dummy_enc_opt_array(xdr, &arg->options); 7861d658336SSimo Sorce 7871d658336SSimo Sorce done: 7881d658336SSimo Sorce if (err) 7891d658336SSimo Sorce dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); 7901d658336SSimo Sorce } 7911d658336SSimo Sorce 7921d658336SSimo Sorce int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, 7931d658336SSimo Sorce struct xdr_stream *xdr, 7941d658336SSimo Sorce struct gssx_res_accept_sec_context *res) 7951d658336SSimo Sorce { 796fb43f11cSJ. Bruce Fields u32 value_follows; 7971d658336SSimo Sorce int err; 7981d658336SSimo Sorce 7991d658336SSimo Sorce /* res->status */ 8001d658336SSimo Sorce err = gssx_dec_status(xdr, &res->status); 8011d658336SSimo Sorce if (err) 8021d658336SSimo Sorce return err; 8031d658336SSimo Sorce 8041d658336SSimo Sorce /* res->context_handle */ 805fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 806fb43f11cSJ. Bruce Fields if (err) 807fb43f11cSJ. Bruce Fields return err; 808fb43f11cSJ. Bruce Fields if (value_follows) { 8091d658336SSimo Sorce err = gssx_dec_ctx(xdr, res->context_handle); 8101d658336SSimo Sorce if (err) 8111d658336SSimo Sorce return err; 8121d658336SSimo Sorce } else { 8131d658336SSimo Sorce res->context_handle = NULL; 8141d658336SSimo Sorce } 8151d658336SSimo Sorce 8161d658336SSimo Sorce /* res->output_token */ 817fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 818fb43f11cSJ. Bruce Fields if (err) 819fb43f11cSJ. Bruce Fields return err; 820fb43f11cSJ. Bruce Fields if (value_follows) { 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 */ 829fb43f11cSJ. Bruce Fields err = gssx_dec_bool(xdr, &value_follows); 830fb43f11cSJ. Bruce Fields if (err) 831fb43f11cSJ. Bruce Fields return err; 832fb43f11cSJ. Bruce Fields if (value_follows) { 8331d658336SSimo Sorce /* we do not support upcall servers sending this data. */ 8341d658336SSimo Sorce return -EINVAL; 8351d658336SSimo Sorce } 8361d658336SSimo Sorce 8371d658336SSimo Sorce /* res->options */ 8381d658336SSimo Sorce err = gssx_dec_option_array(xdr, &res->options); 8391d658336SSimo Sorce 8401d658336SSimo Sorce return err; 8411d658336SSimo Sorce } 842