162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * GSS Proxy upcall module 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Simo Sorce <simo@redhat.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/sunrpc/svcauth.h> 962306a36Sopenharmony_ci#include "gss_rpc_xdr.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic int gssx_enc_bool(struct xdr_stream *xdr, int v) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci __be32 *p; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 4); 1662306a36Sopenharmony_ci if (unlikely(p == NULL)) 1762306a36Sopenharmony_ci return -ENOSPC; 1862306a36Sopenharmony_ci *p = v ? xdr_one : xdr_zero; 1962306a36Sopenharmony_ci return 0; 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic int gssx_dec_bool(struct xdr_stream *xdr, u32 *v) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci __be32 *p; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 2762306a36Sopenharmony_ci if (unlikely(p == NULL)) 2862306a36Sopenharmony_ci return -ENOSPC; 2962306a36Sopenharmony_ci *v = be32_to_cpu(*p); 3062306a36Sopenharmony_ci return 0; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int gssx_enc_buffer(struct xdr_stream *xdr, 3462306a36Sopenharmony_ci const gssx_buffer *buf) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci __be32 *p; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci p = xdr_reserve_space(xdr, sizeof(u32) + buf->len); 3962306a36Sopenharmony_ci if (!p) 4062306a36Sopenharmony_ci return -ENOSPC; 4162306a36Sopenharmony_ci xdr_encode_opaque(p, buf->data, buf->len); 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int gssx_enc_in_token(struct xdr_stream *xdr, 4662306a36Sopenharmony_ci const struct gssp_in_token *in) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci __be32 *p; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 4); 5162306a36Sopenharmony_ci if (!p) 5262306a36Sopenharmony_ci return -ENOSPC; 5362306a36Sopenharmony_ci *p = cpu_to_be32(in->page_len); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* all we need to do is to write pages */ 5662306a36Sopenharmony_ci xdr_write_pages(xdr, in->pages, in->page_base, in->page_len); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int gssx_dec_buffer(struct xdr_stream *xdr, 6362306a36Sopenharmony_ci gssx_buffer *buf) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci u32 length; 6662306a36Sopenharmony_ci __be32 *p; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 6962306a36Sopenharmony_ci if (unlikely(p == NULL)) 7062306a36Sopenharmony_ci return -ENOSPC; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci length = be32_to_cpup(p); 7362306a36Sopenharmony_ci p = xdr_inline_decode(xdr, length); 7462306a36Sopenharmony_ci if (unlikely(p == NULL)) 7562306a36Sopenharmony_ci return -ENOSPC; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (buf->len == 0) { 7862306a36Sopenharmony_ci /* we intentionally are not interested in this buffer */ 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci if (length > buf->len) 8262306a36Sopenharmony_ci return -ENOSPC; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (!buf->data) { 8562306a36Sopenharmony_ci buf->data = kmemdup(p, length, GFP_KERNEL); 8662306a36Sopenharmony_ci if (!buf->data) 8762306a36Sopenharmony_ci return -ENOMEM; 8862306a36Sopenharmony_ci } else { 8962306a36Sopenharmony_ci memcpy(buf->data, p, length); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci buf->len = length; 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int gssx_enc_option(struct xdr_stream *xdr, 9662306a36Sopenharmony_ci struct gssx_option *opt) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci int err; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &opt->option); 10162306a36Sopenharmony_ci if (err) 10262306a36Sopenharmony_ci return err; 10362306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &opt->value); 10462306a36Sopenharmony_ci return err; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int gssx_dec_option(struct xdr_stream *xdr, 10862306a36Sopenharmony_ci struct gssx_option *opt) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci int err; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &opt->option); 11362306a36Sopenharmony_ci if (err) 11462306a36Sopenharmony_ci return err; 11562306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &opt->value); 11662306a36Sopenharmony_ci return err; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int dummy_enc_opt_array(struct xdr_stream *xdr, 12062306a36Sopenharmony_ci const struct gssx_option_array *oa) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci __be32 *p; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (oa->count != 0) 12562306a36Sopenharmony_ci return -EINVAL; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 4); 12862306a36Sopenharmony_ci if (!p) 12962306a36Sopenharmony_ci return -ENOSPC; 13062306a36Sopenharmony_ci *p = 0; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int dummy_dec_opt_array(struct xdr_stream *xdr, 13662306a36Sopenharmony_ci struct gssx_option_array *oa) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct gssx_option dummy; 13962306a36Sopenharmony_ci u32 count, i; 14062306a36Sopenharmony_ci __be32 *p; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 14362306a36Sopenharmony_ci if (unlikely(p == NULL)) 14462306a36Sopenharmony_ci return -ENOSPC; 14562306a36Sopenharmony_ci count = be32_to_cpup(p++); 14662306a36Sopenharmony_ci memset(&dummy, 0, sizeof(dummy)); 14762306a36Sopenharmony_ci for (i = 0; i < count; i++) { 14862306a36Sopenharmony_ci gssx_dec_option(xdr, &dummy); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci oa->count = 0; 15262306a36Sopenharmony_ci oa->data = NULL; 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int get_host_u32(struct xdr_stream *xdr, u32 *res) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci __be32 *p; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 16162306a36Sopenharmony_ci if (!p) 16262306a36Sopenharmony_ci return -EINVAL; 16362306a36Sopenharmony_ci /* Contents of linux creds are all host-endian: */ 16462306a36Sopenharmony_ci memcpy(res, p, sizeof(u32)); 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int gssx_dec_linux_creds(struct xdr_stream *xdr, 16962306a36Sopenharmony_ci struct svc_cred *creds) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci u32 length; 17262306a36Sopenharmony_ci __be32 *p; 17362306a36Sopenharmony_ci u32 tmp; 17462306a36Sopenharmony_ci u32 N; 17562306a36Sopenharmony_ci int i, err; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 17862306a36Sopenharmony_ci if (unlikely(p == NULL)) 17962306a36Sopenharmony_ci return -ENOSPC; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci length = be32_to_cpup(p); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (length > (3 + NGROUPS_MAX) * sizeof(u32)) 18462306a36Sopenharmony_ci return -ENOSPC; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* uid */ 18762306a36Sopenharmony_ci err = get_host_u32(xdr, &tmp); 18862306a36Sopenharmony_ci if (err) 18962306a36Sopenharmony_ci return err; 19062306a36Sopenharmony_ci creds->cr_uid = make_kuid(&init_user_ns, tmp); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* gid */ 19362306a36Sopenharmony_ci err = get_host_u32(xdr, &tmp); 19462306a36Sopenharmony_ci if (err) 19562306a36Sopenharmony_ci return err; 19662306a36Sopenharmony_ci creds->cr_gid = make_kgid(&init_user_ns, tmp); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* number of additional gid's */ 19962306a36Sopenharmony_ci err = get_host_u32(xdr, &tmp); 20062306a36Sopenharmony_ci if (err) 20162306a36Sopenharmony_ci return err; 20262306a36Sopenharmony_ci N = tmp; 20362306a36Sopenharmony_ci if ((3 + N) * sizeof(u32) != length) 20462306a36Sopenharmony_ci return -EINVAL; 20562306a36Sopenharmony_ci creds->cr_group_info = groups_alloc(N); 20662306a36Sopenharmony_ci if (creds->cr_group_info == NULL) 20762306a36Sopenharmony_ci return -ENOMEM; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* gid's */ 21062306a36Sopenharmony_ci for (i = 0; i < N; i++) { 21162306a36Sopenharmony_ci kgid_t kgid; 21262306a36Sopenharmony_ci err = get_host_u32(xdr, &tmp); 21362306a36Sopenharmony_ci if (err) 21462306a36Sopenharmony_ci goto out_free_groups; 21562306a36Sopenharmony_ci err = -EINVAL; 21662306a36Sopenharmony_ci kgid = make_kgid(&init_user_ns, tmp); 21762306a36Sopenharmony_ci if (!gid_valid(kgid)) 21862306a36Sopenharmony_ci goto out_free_groups; 21962306a36Sopenharmony_ci creds->cr_group_info->gid[i] = kgid; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci groups_sort(creds->cr_group_info); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ciout_free_groups: 22562306a36Sopenharmony_ci groups_free(creds->cr_group_info); 22662306a36Sopenharmony_ci return err; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int gssx_dec_option_array(struct xdr_stream *xdr, 23062306a36Sopenharmony_ci struct gssx_option_array *oa) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct svc_cred *creds; 23362306a36Sopenharmony_ci u32 count, i; 23462306a36Sopenharmony_ci __be32 *p; 23562306a36Sopenharmony_ci int err; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 23862306a36Sopenharmony_ci if (unlikely(p == NULL)) 23962306a36Sopenharmony_ci return -ENOSPC; 24062306a36Sopenharmony_ci count = be32_to_cpup(p++); 24162306a36Sopenharmony_ci if (!count) 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* we recognize only 1 currently: CREDS_VALUE */ 24562306a36Sopenharmony_ci oa->count = 1; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL); 24862306a36Sopenharmony_ci if (!oa->data) 24962306a36Sopenharmony_ci return -ENOMEM; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL); 25262306a36Sopenharmony_ci if (!creds) { 25362306a36Sopenharmony_ci err = -ENOMEM; 25462306a36Sopenharmony_ci goto free_oa; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci oa->data[0].option.data = CREDS_VALUE; 25862306a36Sopenharmony_ci oa->data[0].option.len = sizeof(CREDS_VALUE); 25962306a36Sopenharmony_ci oa->data[0].value.data = (void *)creds; 26062306a36Sopenharmony_ci oa->data[0].value.len = 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci for (i = 0; i < count; i++) { 26362306a36Sopenharmony_ci gssx_buffer dummy = { 0, NULL }; 26462306a36Sopenharmony_ci u32 length; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* option buffer */ 26762306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 26862306a36Sopenharmony_ci if (unlikely(p == NULL)) { 26962306a36Sopenharmony_ci err = -ENOSPC; 27062306a36Sopenharmony_ci goto free_creds; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci length = be32_to_cpup(p); 27462306a36Sopenharmony_ci p = xdr_inline_decode(xdr, length); 27562306a36Sopenharmony_ci if (unlikely(p == NULL)) { 27662306a36Sopenharmony_ci err = -ENOSPC; 27762306a36Sopenharmony_ci goto free_creds; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (length == sizeof(CREDS_VALUE) && 28162306a36Sopenharmony_ci memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) { 28262306a36Sopenharmony_ci /* We have creds here. parse them */ 28362306a36Sopenharmony_ci err = gssx_dec_linux_creds(xdr, creds); 28462306a36Sopenharmony_ci if (err) 28562306a36Sopenharmony_ci goto free_creds; 28662306a36Sopenharmony_ci oa->data[0].value.len = 1; /* presence */ 28762306a36Sopenharmony_ci } else { 28862306a36Sopenharmony_ci /* consume uninteresting buffer */ 28962306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &dummy); 29062306a36Sopenharmony_ci if (err) 29162306a36Sopenharmony_ci goto free_creds; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cifree_creds: 29762306a36Sopenharmony_ci kfree(creds); 29862306a36Sopenharmony_cifree_oa: 29962306a36Sopenharmony_ci kfree(oa->data); 30062306a36Sopenharmony_ci oa->data = NULL; 30162306a36Sopenharmony_ci return err; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int gssx_dec_status(struct xdr_stream *xdr, 30562306a36Sopenharmony_ci struct gssx_status *status) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci __be32 *p; 30862306a36Sopenharmony_ci int err; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* status->major_status */ 31162306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 8); 31262306a36Sopenharmony_ci if (unlikely(p == NULL)) 31362306a36Sopenharmony_ci return -ENOSPC; 31462306a36Sopenharmony_ci p = xdr_decode_hyper(p, &status->major_status); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* status->mech */ 31762306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &status->mech); 31862306a36Sopenharmony_ci if (err) 31962306a36Sopenharmony_ci return err; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* status->minor_status */ 32262306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 8); 32362306a36Sopenharmony_ci if (unlikely(p == NULL)) 32462306a36Sopenharmony_ci return -ENOSPC; 32562306a36Sopenharmony_ci p = xdr_decode_hyper(p, &status->minor_status); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* status->major_status_string */ 32862306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &status->major_status_string); 32962306a36Sopenharmony_ci if (err) 33062306a36Sopenharmony_ci return err; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* status->minor_status_string */ 33362306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &status->minor_status_string); 33462306a36Sopenharmony_ci if (err) 33562306a36Sopenharmony_ci return err; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* status->server_ctx */ 33862306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &status->server_ctx); 33962306a36Sopenharmony_ci if (err) 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* we assume we have no options for now, so simply consume them */ 34362306a36Sopenharmony_ci /* status->options */ 34462306a36Sopenharmony_ci err = dummy_dec_opt_array(xdr, &status->options); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return err; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int gssx_enc_call_ctx(struct xdr_stream *xdr, 35062306a36Sopenharmony_ci const struct gssx_call_ctx *ctx) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct gssx_option opt; 35362306a36Sopenharmony_ci __be32 *p; 35462306a36Sopenharmony_ci int err; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* ctx->locale */ 35762306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &ctx->locale); 35862306a36Sopenharmony_ci if (err) 35962306a36Sopenharmony_ci return err; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* ctx->server_ctx */ 36262306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &ctx->server_ctx); 36362306a36Sopenharmony_ci if (err) 36462306a36Sopenharmony_ci return err; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* we always want to ask for lucid contexts */ 36762306a36Sopenharmony_ci /* ctx->options */ 36862306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 4); 36962306a36Sopenharmony_ci *p = cpu_to_be32(2); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* we want a lucid_v1 context */ 37262306a36Sopenharmony_ci opt.option.data = LUCID_OPTION; 37362306a36Sopenharmony_ci opt.option.len = sizeof(LUCID_OPTION); 37462306a36Sopenharmony_ci opt.value.data = LUCID_VALUE; 37562306a36Sopenharmony_ci opt.value.len = sizeof(LUCID_VALUE); 37662306a36Sopenharmony_ci err = gssx_enc_option(xdr, &opt); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* ..and user creds */ 37962306a36Sopenharmony_ci opt.option.data = CREDS_OPTION; 38062306a36Sopenharmony_ci opt.option.len = sizeof(CREDS_OPTION); 38162306a36Sopenharmony_ci opt.value.data = CREDS_VALUE; 38262306a36Sopenharmony_ci opt.value.len = sizeof(CREDS_VALUE); 38362306a36Sopenharmony_ci err = gssx_enc_option(xdr, &opt); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return err; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int gssx_dec_name_attr(struct xdr_stream *xdr, 38962306a36Sopenharmony_ci struct gssx_name_attr *attr) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci int err; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* attr->attr */ 39462306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &attr->attr); 39562306a36Sopenharmony_ci if (err) 39662306a36Sopenharmony_ci return err; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* attr->value */ 39962306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &attr->value); 40062306a36Sopenharmony_ci if (err) 40162306a36Sopenharmony_ci return err; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* attr->extensions */ 40462306a36Sopenharmony_ci err = dummy_dec_opt_array(xdr, &attr->extensions); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return err; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int dummy_enc_nameattr_array(struct xdr_stream *xdr, 41062306a36Sopenharmony_ci struct gssx_name_attr_array *naa) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci __be32 *p; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (naa->count != 0) 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 4); 41862306a36Sopenharmony_ci if (!p) 41962306a36Sopenharmony_ci return -ENOSPC; 42062306a36Sopenharmony_ci *p = 0; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int dummy_dec_nameattr_array(struct xdr_stream *xdr, 42662306a36Sopenharmony_ci struct gssx_name_attr_array *naa) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct gssx_name_attr dummy = { .attr = {.len = 0} }; 42962306a36Sopenharmony_ci u32 count, i; 43062306a36Sopenharmony_ci __be32 *p; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 43362306a36Sopenharmony_ci if (unlikely(p == NULL)) 43462306a36Sopenharmony_ci return -ENOSPC; 43562306a36Sopenharmony_ci count = be32_to_cpup(p++); 43662306a36Sopenharmony_ci for (i = 0; i < count; i++) { 43762306a36Sopenharmony_ci gssx_dec_name_attr(xdr, &dummy); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci naa->count = 0; 44162306a36Sopenharmony_ci naa->data = NULL; 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic struct xdr_netobj zero_netobj = {}; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic struct gssx_name_attr_array zero_name_attr_array = {}; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic struct gssx_option_array zero_option_array = {}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int gssx_enc_name(struct xdr_stream *xdr, 45262306a36Sopenharmony_ci struct gssx_name *name) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci int err; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* name->display_name */ 45762306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &name->display_name); 45862306a36Sopenharmony_ci if (err) 45962306a36Sopenharmony_ci return err; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* name->name_type */ 46262306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &zero_netobj); 46362306a36Sopenharmony_ci if (err) 46462306a36Sopenharmony_ci return err; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* name->exported_name */ 46762306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &zero_netobj); 46862306a36Sopenharmony_ci if (err) 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* name->exported_composite_name */ 47262306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &zero_netobj); 47362306a36Sopenharmony_ci if (err) 47462306a36Sopenharmony_ci return err; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* leave name_attributes empty for now, will add once we have any 47762306a36Sopenharmony_ci * to pass up at all */ 47862306a36Sopenharmony_ci /* name->name_attributes */ 47962306a36Sopenharmony_ci err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array); 48062306a36Sopenharmony_ci if (err) 48162306a36Sopenharmony_ci return err; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* leave options empty for now, will add once we have any options 48462306a36Sopenharmony_ci * to pass up at all */ 48562306a36Sopenharmony_ci /* name->extensions */ 48662306a36Sopenharmony_ci err = dummy_enc_opt_array(xdr, &zero_option_array); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return err; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic int gssx_dec_name(struct xdr_stream *xdr, 49362306a36Sopenharmony_ci struct gssx_name *name) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct xdr_netobj dummy_netobj = { .len = 0 }; 49662306a36Sopenharmony_ci struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 }; 49762306a36Sopenharmony_ci struct gssx_option_array dummy_option_array = { .count = 0 }; 49862306a36Sopenharmony_ci int err; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* name->display_name */ 50162306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &name->display_name); 50262306a36Sopenharmony_ci if (err) 50362306a36Sopenharmony_ci return err; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* name->name_type */ 50662306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &dummy_netobj); 50762306a36Sopenharmony_ci if (err) 50862306a36Sopenharmony_ci return err; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* name->exported_name */ 51162306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &dummy_netobj); 51262306a36Sopenharmony_ci if (err) 51362306a36Sopenharmony_ci return err; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* name->exported_composite_name */ 51662306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &dummy_netobj); 51762306a36Sopenharmony_ci if (err) 51862306a36Sopenharmony_ci return err; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* we assume we have no attributes for now, so simply consume them */ 52162306a36Sopenharmony_ci /* name->name_attributes */ 52262306a36Sopenharmony_ci err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array); 52362306a36Sopenharmony_ci if (err) 52462306a36Sopenharmony_ci return err; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* we assume we have no options for now, so simply consume them */ 52762306a36Sopenharmony_ci /* name->extensions */ 52862306a36Sopenharmony_ci err = dummy_dec_opt_array(xdr, &dummy_option_array); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return err; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int dummy_enc_credel_array(struct xdr_stream *xdr, 53462306a36Sopenharmony_ci struct gssx_cred_element_array *cea) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci __be32 *p; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (cea->count != 0) 53962306a36Sopenharmony_ci return -EINVAL; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 4); 54262306a36Sopenharmony_ci if (!p) 54362306a36Sopenharmony_ci return -ENOSPC; 54462306a36Sopenharmony_ci *p = 0; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic int gssx_enc_cred(struct xdr_stream *xdr, 55062306a36Sopenharmony_ci struct gssx_cred *cred) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci int err; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* cred->desired_name */ 55562306a36Sopenharmony_ci err = gssx_enc_name(xdr, &cred->desired_name); 55662306a36Sopenharmony_ci if (err) 55762306a36Sopenharmony_ci return err; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* cred->elements */ 56062306a36Sopenharmony_ci err = dummy_enc_credel_array(xdr, &cred->elements); 56162306a36Sopenharmony_ci if (err) 56262306a36Sopenharmony_ci return err; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* cred->cred_handle_reference */ 56562306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &cred->cred_handle_reference); 56662306a36Sopenharmony_ci if (err) 56762306a36Sopenharmony_ci return err; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* cred->needs_release */ 57062306a36Sopenharmony_ci err = gssx_enc_bool(xdr, cred->needs_release); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return err; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic int gssx_enc_ctx(struct xdr_stream *xdr, 57662306a36Sopenharmony_ci struct gssx_ctx *ctx) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci __be32 *p; 57962306a36Sopenharmony_ci int err; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* ctx->exported_context_token */ 58262306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &ctx->exported_context_token); 58362306a36Sopenharmony_ci if (err) 58462306a36Sopenharmony_ci return err; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* ctx->state */ 58762306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &ctx->state); 58862306a36Sopenharmony_ci if (err) 58962306a36Sopenharmony_ci return err; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* ctx->need_release */ 59262306a36Sopenharmony_ci err = gssx_enc_bool(xdr, ctx->need_release); 59362306a36Sopenharmony_ci if (err) 59462306a36Sopenharmony_ci return err; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* ctx->mech */ 59762306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &ctx->mech); 59862306a36Sopenharmony_ci if (err) 59962306a36Sopenharmony_ci return err; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* ctx->src_name */ 60262306a36Sopenharmony_ci err = gssx_enc_name(xdr, &ctx->src_name); 60362306a36Sopenharmony_ci if (err) 60462306a36Sopenharmony_ci return err; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* ctx->targ_name */ 60762306a36Sopenharmony_ci err = gssx_enc_name(xdr, &ctx->targ_name); 60862306a36Sopenharmony_ci if (err) 60962306a36Sopenharmony_ci return err; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* ctx->lifetime */ 61262306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 8+8); 61362306a36Sopenharmony_ci if (!p) 61462306a36Sopenharmony_ci return -ENOSPC; 61562306a36Sopenharmony_ci p = xdr_encode_hyper(p, ctx->lifetime); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* ctx->ctx_flags */ 61862306a36Sopenharmony_ci p = xdr_encode_hyper(p, ctx->ctx_flags); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* ctx->locally_initiated */ 62162306a36Sopenharmony_ci err = gssx_enc_bool(xdr, ctx->locally_initiated); 62262306a36Sopenharmony_ci if (err) 62362306a36Sopenharmony_ci return err; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* ctx->open */ 62662306a36Sopenharmony_ci err = gssx_enc_bool(xdr, ctx->open); 62762306a36Sopenharmony_ci if (err) 62862306a36Sopenharmony_ci return err; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* leave options empty for now, will add once we have any options 63162306a36Sopenharmony_ci * to pass up at all */ 63262306a36Sopenharmony_ci /* ctx->options */ 63362306a36Sopenharmony_ci err = dummy_enc_opt_array(xdr, &ctx->options); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return err; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int gssx_dec_ctx(struct xdr_stream *xdr, 63962306a36Sopenharmony_ci struct gssx_ctx *ctx) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci __be32 *p; 64262306a36Sopenharmony_ci int err; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* ctx->exported_context_token */ 64562306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &ctx->exported_context_token); 64662306a36Sopenharmony_ci if (err) 64762306a36Sopenharmony_ci return err; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* ctx->state */ 65062306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &ctx->state); 65162306a36Sopenharmony_ci if (err) 65262306a36Sopenharmony_ci return err; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* ctx->need_release */ 65562306a36Sopenharmony_ci err = gssx_dec_bool(xdr, &ctx->need_release); 65662306a36Sopenharmony_ci if (err) 65762306a36Sopenharmony_ci return err; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* ctx->mech */ 66062306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, &ctx->mech); 66162306a36Sopenharmony_ci if (err) 66262306a36Sopenharmony_ci return err; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* ctx->src_name */ 66562306a36Sopenharmony_ci err = gssx_dec_name(xdr, &ctx->src_name); 66662306a36Sopenharmony_ci if (err) 66762306a36Sopenharmony_ci return err; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* ctx->targ_name */ 67062306a36Sopenharmony_ci err = gssx_dec_name(xdr, &ctx->targ_name); 67162306a36Sopenharmony_ci if (err) 67262306a36Sopenharmony_ci return err; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* ctx->lifetime */ 67562306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 8+8); 67662306a36Sopenharmony_ci if (unlikely(p == NULL)) 67762306a36Sopenharmony_ci return -ENOSPC; 67862306a36Sopenharmony_ci p = xdr_decode_hyper(p, &ctx->lifetime); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci /* ctx->ctx_flags */ 68162306a36Sopenharmony_ci p = xdr_decode_hyper(p, &ctx->ctx_flags); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* ctx->locally_initiated */ 68462306a36Sopenharmony_ci err = gssx_dec_bool(xdr, &ctx->locally_initiated); 68562306a36Sopenharmony_ci if (err) 68662306a36Sopenharmony_ci return err; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* ctx->open */ 68962306a36Sopenharmony_ci err = gssx_dec_bool(xdr, &ctx->open); 69062306a36Sopenharmony_ci if (err) 69162306a36Sopenharmony_ci return err; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* we assume we have no options for now, so simply consume them */ 69462306a36Sopenharmony_ci /* ctx->options */ 69562306a36Sopenharmony_ci err = dummy_dec_opt_array(xdr, &ctx->options); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci return err; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci __be32 *p; 70362306a36Sopenharmony_ci int err; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* cb->initiator_addrtype */ 70662306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 8); 70762306a36Sopenharmony_ci if (!p) 70862306a36Sopenharmony_ci return -ENOSPC; 70962306a36Sopenharmony_ci p = xdr_encode_hyper(p, cb->initiator_addrtype); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* cb->initiator_address */ 71262306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &cb->initiator_address); 71362306a36Sopenharmony_ci if (err) 71462306a36Sopenharmony_ci return err; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* cb->acceptor_addrtype */ 71762306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 8); 71862306a36Sopenharmony_ci if (!p) 71962306a36Sopenharmony_ci return -ENOSPC; 72062306a36Sopenharmony_ci p = xdr_encode_hyper(p, cb->acceptor_addrtype); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* cb->acceptor_address */ 72362306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &cb->acceptor_address); 72462306a36Sopenharmony_ci if (err) 72562306a36Sopenharmony_ci return err; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* cb->application_data */ 72862306a36Sopenharmony_ci err = gssx_enc_buffer(xdr, &cb->application_data); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci return err; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_civoid gssx_enc_accept_sec_context(struct rpc_rqst *req, 73462306a36Sopenharmony_ci struct xdr_stream *xdr, 73562306a36Sopenharmony_ci const void *data) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci const struct gssx_arg_accept_sec_context *arg = data; 73862306a36Sopenharmony_ci int err; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci err = gssx_enc_call_ctx(xdr, &arg->call_ctx); 74162306a36Sopenharmony_ci if (err) 74262306a36Sopenharmony_ci goto done; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci /* arg->context_handle */ 74562306a36Sopenharmony_ci if (arg->context_handle) 74662306a36Sopenharmony_ci err = gssx_enc_ctx(xdr, arg->context_handle); 74762306a36Sopenharmony_ci else 74862306a36Sopenharmony_ci err = gssx_enc_bool(xdr, 0); 74962306a36Sopenharmony_ci if (err) 75062306a36Sopenharmony_ci goto done; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* arg->cred_handle */ 75362306a36Sopenharmony_ci if (arg->cred_handle) 75462306a36Sopenharmony_ci err = gssx_enc_cred(xdr, arg->cred_handle); 75562306a36Sopenharmony_ci else 75662306a36Sopenharmony_ci err = gssx_enc_bool(xdr, 0); 75762306a36Sopenharmony_ci if (err) 75862306a36Sopenharmony_ci goto done; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* arg->input_token */ 76162306a36Sopenharmony_ci err = gssx_enc_in_token(xdr, &arg->input_token); 76262306a36Sopenharmony_ci if (err) 76362306a36Sopenharmony_ci goto done; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* arg->input_cb */ 76662306a36Sopenharmony_ci if (arg->input_cb) 76762306a36Sopenharmony_ci err = gssx_enc_cb(xdr, arg->input_cb); 76862306a36Sopenharmony_ci else 76962306a36Sopenharmony_ci err = gssx_enc_bool(xdr, 0); 77062306a36Sopenharmony_ci if (err) 77162306a36Sopenharmony_ci goto done; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci err = gssx_enc_bool(xdr, arg->ret_deleg_cred); 77462306a36Sopenharmony_ci if (err) 77562306a36Sopenharmony_ci goto done; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* leave options empty for now, will add once we have any options 77862306a36Sopenharmony_ci * to pass up at all */ 77962306a36Sopenharmony_ci /* arg->options */ 78062306a36Sopenharmony_ci err = dummy_enc_opt_array(xdr, &arg->options); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci xdr_inline_pages(&req->rq_rcv_buf, 78362306a36Sopenharmony_ci PAGE_SIZE/2 /* pretty arbitrary */, 78462306a36Sopenharmony_ci arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE); 78562306a36Sopenharmony_cidone: 78662306a36Sopenharmony_ci if (err) 78762306a36Sopenharmony_ci dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ciint gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, 79162306a36Sopenharmony_ci struct xdr_stream *xdr, 79262306a36Sopenharmony_ci void *data) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct gssx_res_accept_sec_context *res = data; 79562306a36Sopenharmony_ci u32 value_follows; 79662306a36Sopenharmony_ci int err; 79762306a36Sopenharmony_ci struct page *scratch; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci scratch = alloc_page(GFP_KERNEL); 80062306a36Sopenharmony_ci if (!scratch) 80162306a36Sopenharmony_ci return -ENOMEM; 80262306a36Sopenharmony_ci xdr_set_scratch_page(xdr, scratch); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* res->status */ 80562306a36Sopenharmony_ci err = gssx_dec_status(xdr, &res->status); 80662306a36Sopenharmony_ci if (err) 80762306a36Sopenharmony_ci goto out_free; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* res->context_handle */ 81062306a36Sopenharmony_ci err = gssx_dec_bool(xdr, &value_follows); 81162306a36Sopenharmony_ci if (err) 81262306a36Sopenharmony_ci goto out_free; 81362306a36Sopenharmony_ci if (value_follows) { 81462306a36Sopenharmony_ci err = gssx_dec_ctx(xdr, res->context_handle); 81562306a36Sopenharmony_ci if (err) 81662306a36Sopenharmony_ci goto out_free; 81762306a36Sopenharmony_ci } else { 81862306a36Sopenharmony_ci res->context_handle = NULL; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* res->output_token */ 82262306a36Sopenharmony_ci err = gssx_dec_bool(xdr, &value_follows); 82362306a36Sopenharmony_ci if (err) 82462306a36Sopenharmony_ci goto out_free; 82562306a36Sopenharmony_ci if (value_follows) { 82662306a36Sopenharmony_ci err = gssx_dec_buffer(xdr, res->output_token); 82762306a36Sopenharmony_ci if (err) 82862306a36Sopenharmony_ci goto out_free; 82962306a36Sopenharmony_ci } else { 83062306a36Sopenharmony_ci res->output_token = NULL; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* res->delegated_cred_handle */ 83462306a36Sopenharmony_ci err = gssx_dec_bool(xdr, &value_follows); 83562306a36Sopenharmony_ci if (err) 83662306a36Sopenharmony_ci goto out_free; 83762306a36Sopenharmony_ci if (value_follows) { 83862306a36Sopenharmony_ci /* we do not support upcall servers sending this data. */ 83962306a36Sopenharmony_ci err = -EINVAL; 84062306a36Sopenharmony_ci goto out_free; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* res->options */ 84462306a36Sopenharmony_ci err = gssx_dec_option_array(xdr, &res->options); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ciout_free: 84762306a36Sopenharmony_ci __free_page(scratch); 84862306a36Sopenharmony_ci return err; 84962306a36Sopenharmony_ci} 850