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