12573a464SChuck Lever // SPDX-License-Identifier: GPL-2.0+
21d658336SSimo Sorce /*
31d658336SSimo Sorce  * GSS Proxy upcall module
41d658336SSimo Sorce  *
51d658336SSimo Sorce  *  Copyright (C) 2012 Simo Sorce <simo@redhat.com>
61d658336SSimo Sorce  */
71d658336SSimo Sorce 
81d658336SSimo Sorce #include <linux/sunrpc/svcauth.h>
91d658336SSimo Sorce #include "gss_rpc_xdr.h"
101d658336SSimo Sorce 
gssx_enc_bool(struct xdr_stream * xdr,int v)111d658336SSimo Sorce static int gssx_enc_bool(struct xdr_stream *xdr, int v)
121d658336SSimo Sorce {
131d658336SSimo Sorce 	__be32 *p;
141d658336SSimo Sorce 
151d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 4);
161d658336SSimo Sorce 	if (unlikely(p == NULL))
171d658336SSimo Sorce 		return -ENOSPC;
181d658336SSimo Sorce 	*p = v ? xdr_one : xdr_zero;
191d658336SSimo Sorce 	return 0;
201d658336SSimo Sorce }
211d658336SSimo Sorce 
gssx_dec_bool(struct xdr_stream * xdr,u32 * v)221d658336SSimo Sorce static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v)
231d658336SSimo Sorce {
241d658336SSimo Sorce 	__be32 *p;
251d658336SSimo Sorce 
261d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 4);
271d658336SSimo Sorce 	if (unlikely(p == NULL))
281d658336SSimo Sorce 		return -ENOSPC;
291d658336SSimo Sorce 	*v = be32_to_cpu(*p);
301d658336SSimo Sorce 	return 0;
311d658336SSimo Sorce }
321d658336SSimo Sorce 
gssx_enc_buffer(struct xdr_stream * xdr,const gssx_buffer * buf)331d658336SSimo Sorce static int gssx_enc_buffer(struct xdr_stream *xdr,
3489daf360SChristoph Hellwig 			   const gssx_buffer *buf)
351d658336SSimo Sorce {
361d658336SSimo Sorce 	__be32 *p;
371d658336SSimo Sorce 
381d658336SSimo Sorce 	p = xdr_reserve_space(xdr, sizeof(u32) + buf->len);
391d658336SSimo Sorce 	if (!p)
401d658336SSimo Sorce 		return -ENOSPC;
411d658336SSimo Sorce 	xdr_encode_opaque(p, buf->data, buf->len);
421d658336SSimo Sorce 	return 0;
431d658336SSimo Sorce }
441d658336SSimo Sorce 
gssx_enc_in_token(struct xdr_stream * xdr,const struct gssp_in_token * in)451d658336SSimo Sorce static int gssx_enc_in_token(struct xdr_stream *xdr,
4689daf360SChristoph Hellwig 			     const struct gssp_in_token *in)
471d658336SSimo Sorce {
481d658336SSimo Sorce 	__be32 *p;
491d658336SSimo Sorce 
501d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 4);
511d658336SSimo Sorce 	if (!p)
521d658336SSimo Sorce 		return -ENOSPC;
531d658336SSimo Sorce 	*p = cpu_to_be32(in->page_len);
541d658336SSimo Sorce 
551d658336SSimo Sorce 	/* all we need to do is to write pages */
561d658336SSimo Sorce 	xdr_write_pages(xdr, in->pages, in->page_base, in->page_len);
571d658336SSimo Sorce 
581d658336SSimo Sorce 	return 0;
591d658336SSimo Sorce }
601d658336SSimo Sorce 
611d658336SSimo Sorce 
gssx_dec_buffer(struct xdr_stream * xdr,gssx_buffer * buf)621d658336SSimo Sorce static int gssx_dec_buffer(struct xdr_stream *xdr,
631d658336SSimo Sorce 			   gssx_buffer *buf)
641d658336SSimo Sorce {
651d658336SSimo Sorce 	u32 length;
661d658336SSimo Sorce 	__be32 *p;
671d658336SSimo Sorce 
681d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 4);
691d658336SSimo Sorce 	if (unlikely(p == NULL))
701d658336SSimo Sorce 		return -ENOSPC;
711d658336SSimo Sorce 
721d658336SSimo Sorce 	length = be32_to_cpup(p);
731d658336SSimo Sorce 	p = xdr_inline_decode(xdr, length);
741d658336SSimo Sorce 	if (unlikely(p == NULL))
751d658336SSimo Sorce 		return -ENOSPC;
761d658336SSimo Sorce 
771d658336SSimo Sorce 	if (buf->len == 0) {
781d658336SSimo Sorce 		/* we intentionally are not interested in this buffer */
791d658336SSimo Sorce 		return 0;
801d658336SSimo Sorce 	}
811d658336SSimo Sorce 	if (length > buf->len)
821d658336SSimo Sorce 		return -ENOSPC;
831d658336SSimo Sorce 
841d658336SSimo Sorce 	if (!buf->data) {
851d658336SSimo Sorce 		buf->data = kmemdup(p, length, GFP_KERNEL);
861d658336SSimo Sorce 		if (!buf->data)
871d658336SSimo Sorce 			return -ENOMEM;
881d658336SSimo Sorce 	} else {
891d658336SSimo Sorce 		memcpy(buf->data, p, length);
901d658336SSimo Sorce 	}
911d658336SSimo Sorce 	buf->len = length;
921d658336SSimo Sorce 	return 0;
931d658336SSimo Sorce }
941d658336SSimo Sorce 
gssx_enc_option(struct xdr_stream * xdr,struct gssx_option * opt)951d658336SSimo Sorce static int gssx_enc_option(struct xdr_stream *xdr,
961d658336SSimo Sorce 			   struct gssx_option *opt)
971d658336SSimo Sorce {
981d658336SSimo Sorce 	int err;
991d658336SSimo Sorce 
1001d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &opt->option);
1011d658336SSimo Sorce 	if (err)
1021d658336SSimo Sorce 		return err;
1031d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &opt->value);
1041d658336SSimo Sorce 	return err;
1051d658336SSimo Sorce }
1061d658336SSimo Sorce 
gssx_dec_option(struct xdr_stream * xdr,struct gssx_option * opt)1071d658336SSimo Sorce static int gssx_dec_option(struct xdr_stream *xdr,
1081d658336SSimo Sorce 			   struct gssx_option *opt)
1091d658336SSimo Sorce {
1101d658336SSimo Sorce 	int err;
1111d658336SSimo Sorce 
1121d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &opt->option);
1131d658336SSimo Sorce 	if (err)
1141d658336SSimo Sorce 		return err;
1151d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &opt->value);
1161d658336SSimo Sorce 	return err;
1171d658336SSimo Sorce }
1181d658336SSimo Sorce 
dummy_enc_opt_array(struct xdr_stream * xdr,const struct gssx_option_array * oa)1191d658336SSimo Sorce static int dummy_enc_opt_array(struct xdr_stream *xdr,
12089daf360SChristoph Hellwig 				const struct gssx_option_array *oa)
1211d658336SSimo Sorce {
1221d658336SSimo Sorce 	__be32 *p;
1231d658336SSimo Sorce 
1241d658336SSimo Sorce 	if (oa->count != 0)
1251d658336SSimo Sorce 		return -EINVAL;
1261d658336SSimo Sorce 
1271d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 4);
1281d658336SSimo Sorce 	if (!p)
1291d658336SSimo Sorce 		return -ENOSPC;
1301d658336SSimo Sorce 	*p = 0;
1311d658336SSimo Sorce 
1321d658336SSimo Sorce 	return 0;
1331d658336SSimo Sorce }
1341d658336SSimo Sorce 
dummy_dec_opt_array(struct xdr_stream * xdr,struct gssx_option_array * oa)1351d658336SSimo Sorce static int dummy_dec_opt_array(struct xdr_stream *xdr,
1361d658336SSimo Sorce 				struct gssx_option_array *oa)
1371d658336SSimo Sorce {
1381d658336SSimo Sorce 	struct gssx_option dummy;
1391d658336SSimo Sorce 	u32 count, i;
1401d658336SSimo Sorce 	__be32 *p;
1411d658336SSimo Sorce 
1421d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 4);
1431d658336SSimo Sorce 	if (unlikely(p == NULL))
1441d658336SSimo Sorce 		return -ENOSPC;
1451d658336SSimo Sorce 	count = be32_to_cpup(p++);
1461d658336SSimo Sorce 	memset(&dummy, 0, sizeof(dummy));
1471d658336SSimo Sorce 	for (i = 0; i < count; i++) {
1481d658336SSimo Sorce 		gssx_dec_option(xdr, &dummy);
1491d658336SSimo Sorce 	}
1501d658336SSimo Sorce 
1511d658336SSimo Sorce 	oa->count = 0;
1521d658336SSimo Sorce 	oa->data = NULL;
1531d658336SSimo Sorce 	return 0;
1541d658336SSimo Sorce }
1551d658336SSimo Sorce 
get_host_u32(struct xdr_stream * xdr,u32 * res)1566a36978eSJ. Bruce Fields static int get_host_u32(struct xdr_stream *xdr, u32 *res)
1571d658336SSimo Sorce {
158778e512bSJ. Bruce Fields 	__be32 *p;
159778e512bSJ. Bruce Fields 
160778e512bSJ. Bruce Fields 	p = xdr_inline_decode(xdr, 4);
161778e512bSJ. Bruce Fields 	if (!p)
1621d658336SSimo Sorce 		return -EINVAL;
1636a36978eSJ. Bruce Fields 	/* Contents of linux creds are all host-endian: */
1646a36978eSJ. Bruce Fields 	memcpy(res, p, sizeof(u32));
1651d658336SSimo Sorce 	return 0;
1661d658336SSimo Sorce }
1671d658336SSimo Sorce 
gssx_dec_linux_creds(struct xdr_stream * xdr,struct svc_cred * creds)1681d658336SSimo Sorce static int gssx_dec_linux_creds(struct xdr_stream *xdr,
1691d658336SSimo Sorce 				struct svc_cred *creds)
1701d658336SSimo Sorce {
1711d658336SSimo Sorce 	u32 length;
1721d658336SSimo Sorce 	__be32 *p;
1736a36978eSJ. Bruce Fields 	u32 tmp;
1746a36978eSJ. Bruce Fields 	u32 N;
1756a36978eSJ. Bruce Fields 	int i, err;
1761d658336SSimo Sorce 
1771d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 4);
1781d658336SSimo Sorce 	if (unlikely(p == NULL))
1791d658336SSimo Sorce 		return -ENOSPC;
1801d658336SSimo Sorce 
1811d658336SSimo Sorce 	length = be32_to_cpup(p);
1821d658336SSimo Sorce 
183778e512bSJ. Bruce Fields 	if (length > (3 + NGROUPS_MAX) * sizeof(u32))
1841d658336SSimo Sorce 		return -ENOSPC;
1851d658336SSimo Sorce 
1861d658336SSimo Sorce 	/* uid */
1876a36978eSJ. Bruce Fields 	err = get_host_u32(xdr, &tmp);
1881d658336SSimo Sorce 	if (err)
1891d658336SSimo Sorce 		return err;
190d28fcc83SJ. Bruce Fields 	creds->cr_uid = make_kuid(&init_user_ns, tmp);
1911d658336SSimo Sorce 
1921d658336SSimo Sorce 	/* gid */
1936a36978eSJ. Bruce Fields 	err = get_host_u32(xdr, &tmp);
1941d658336SSimo Sorce 	if (err)
1951d658336SSimo Sorce 		return err;
196d28fcc83SJ. Bruce Fields 	creds->cr_gid = make_kgid(&init_user_ns, tmp);
1971d658336SSimo Sorce 
1981d658336SSimo Sorce 	/* number of additional gid's */
1996a36978eSJ. Bruce Fields 	err = get_host_u32(xdr, &tmp);
2001d658336SSimo Sorce 	if (err)
2011d658336SSimo Sorce 		return err;
2021d658336SSimo Sorce 	N = tmp;
203778e512bSJ. Bruce Fields 	if ((3 + N) * sizeof(u32) != length)
204778e512bSJ. Bruce Fields 		return -EINVAL;
2051d658336SSimo Sorce 	creds->cr_group_info = groups_alloc(N);
2061d658336SSimo Sorce 	if (creds->cr_group_info == NULL)
2071d658336SSimo Sorce 		return -ENOMEM;
2081d658336SSimo Sorce 
2091d658336SSimo Sorce 	/* gid's */
2101d658336SSimo Sorce 	for (i = 0; i < N; i++) {
211d28fcc83SJ. Bruce Fields 		kgid_t kgid;
2126a36978eSJ. Bruce Fields 		err = get_host_u32(xdr, &tmp);
213d28fcc83SJ. Bruce Fields 		if (err)
214d28fcc83SJ. Bruce Fields 			goto out_free_groups;
215d28fcc83SJ. Bruce Fields 		err = -EINVAL;
216d28fcc83SJ. Bruce Fields 		kgid = make_kgid(&init_user_ns, tmp);
217d28fcc83SJ. Bruce Fields 		if (!gid_valid(kgid))
218d28fcc83SJ. Bruce Fields 			goto out_free_groups;
21981243eacSAlexey Dobriyan 		creds->cr_group_info->gid[i] = kgid;
2201d658336SSimo Sorce 	}
221bdcf0a42SThiago Rafael Becker 	groups_sort(creds->cr_group_info);
2221d658336SSimo Sorce 
2231d658336SSimo Sorce 	return 0;
224d28fcc83SJ. Bruce Fields out_free_groups:
225d28fcc83SJ. Bruce Fields 	groups_free(creds->cr_group_info);
226d28fcc83SJ. Bruce Fields 	return err;
2271d658336SSimo Sorce }
2281d658336SSimo Sorce 
gssx_dec_option_array(struct xdr_stream * xdr,struct gssx_option_array * oa)2291d658336SSimo Sorce static int gssx_dec_option_array(struct xdr_stream *xdr,
2301d658336SSimo Sorce 				 struct gssx_option_array *oa)
2311d658336SSimo Sorce {
2321d658336SSimo Sorce 	struct svc_cred *creds;
2331d658336SSimo Sorce 	u32 count, i;
2341d658336SSimo Sorce 	__be32 *p;
2351d658336SSimo Sorce 	int err;
2361d658336SSimo Sorce 
2371d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 4);
2381d658336SSimo Sorce 	if (unlikely(p == NULL))
2391d658336SSimo Sorce 		return -ENOSPC;
2401d658336SSimo Sorce 	count = be32_to_cpup(p++);
2419fd40c5aSGeert Uytterhoeven 	if (!count)
2429fd40c5aSGeert Uytterhoeven 		return 0;
2439fd40c5aSGeert Uytterhoeven 
2441d658336SSimo Sorce 	/* we recognize only 1 currently: CREDS_VALUE */
2451d658336SSimo Sorce 	oa->count = 1;
2461d658336SSimo Sorce 
2471d658336SSimo Sorce 	oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL);
2481d658336SSimo Sorce 	if (!oa->data)
2491d658336SSimo Sorce 		return -ENOMEM;
2501d658336SSimo Sorce 
251034dd34fSJ. Bruce Fields 	creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL);
2521d658336SSimo Sorce 	if (!creds) {
253*5e6013aeSZhipeng Lu 		err = -ENOMEM;
254*5e6013aeSZhipeng Lu 		goto free_oa;
2551d658336SSimo Sorce 	}
2561d658336SSimo Sorce 
2571d658336SSimo Sorce 	oa->data[0].option.data = CREDS_VALUE;
2581d658336SSimo Sorce 	oa->data[0].option.len = sizeof(CREDS_VALUE);
2591d658336SSimo Sorce 	oa->data[0].value.data = (void *)creds;
2601d658336SSimo Sorce 	oa->data[0].value.len = 0;
2619fd40c5aSGeert Uytterhoeven 
2621d658336SSimo Sorce 	for (i = 0; i < count; i++) {
2631d658336SSimo Sorce 		gssx_buffer dummy = { 0, NULL };
2641d658336SSimo Sorce 		u32 length;
2651d658336SSimo Sorce 
2661d658336SSimo Sorce 		/* option buffer */
2671d658336SSimo Sorce 		p = xdr_inline_decode(xdr, 4);
268*5e6013aeSZhipeng Lu 		if (unlikely(p == NULL)) {
269*5e6013aeSZhipeng Lu 			err = -ENOSPC;
270*5e6013aeSZhipeng Lu 			goto free_creds;
271*5e6013aeSZhipeng Lu 		}
2721d658336SSimo Sorce 
2731d658336SSimo Sorce 		length = be32_to_cpup(p);
2741d658336SSimo Sorce 		p = xdr_inline_decode(xdr, length);
275*5e6013aeSZhipeng Lu 		if (unlikely(p == NULL)) {
276*5e6013aeSZhipeng Lu 			err = -ENOSPC;
277*5e6013aeSZhipeng Lu 			goto free_creds;
278*5e6013aeSZhipeng Lu 		}
2791d658336SSimo Sorce 
2801d658336SSimo Sorce 		if (length == sizeof(CREDS_VALUE) &&
2811d658336SSimo Sorce 		    memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) {
2821d658336SSimo Sorce 			/* We have creds here. parse them */
2831d658336SSimo Sorce 			err = gssx_dec_linux_creds(xdr, creds);
2841d658336SSimo Sorce 			if (err)
285*5e6013aeSZhipeng Lu 				goto free_creds;
2861d658336SSimo Sorce 			oa->data[0].value.len = 1; /* presence */
2871d658336SSimo Sorce 		} else {
2881d658336SSimo Sorce 			/* consume uninteresting buffer */
2891d658336SSimo Sorce 			err = gssx_dec_buffer(xdr, &dummy);
2901d658336SSimo Sorce 			if (err)
291*5e6013aeSZhipeng Lu 				goto free_creds;
2921d658336SSimo Sorce 		}
2931d658336SSimo Sorce 	}
2941d658336SSimo Sorce 	return 0;
295*5e6013aeSZhipeng Lu 
296*5e6013aeSZhipeng Lu free_creds:
297*5e6013aeSZhipeng Lu 	kfree(creds);
298*5e6013aeSZhipeng Lu free_oa:
299*5e6013aeSZhipeng Lu 	kfree(oa->data);
300*5e6013aeSZhipeng Lu 	oa->data = NULL;
301*5e6013aeSZhipeng Lu 	return err;
3021d658336SSimo Sorce }
3031d658336SSimo Sorce 
gssx_dec_status(struct xdr_stream * xdr,struct gssx_status * status)3041d658336SSimo Sorce static int gssx_dec_status(struct xdr_stream *xdr,
3051d658336SSimo Sorce 			   struct gssx_status *status)
3061d658336SSimo Sorce {
3071d658336SSimo Sorce 	__be32 *p;
3081d658336SSimo Sorce 	int err;
3091d658336SSimo Sorce 
3101d658336SSimo Sorce 	/* status->major_status */
3111d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 8);
3121d658336SSimo Sorce 	if (unlikely(p == NULL))
3131d658336SSimo Sorce 		return -ENOSPC;
3141d658336SSimo Sorce 	p = xdr_decode_hyper(p, &status->major_status);
3151d658336SSimo Sorce 
3161d658336SSimo Sorce 	/* status->mech */
3171d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &status->mech);
3181d658336SSimo Sorce 	if (err)
3191d658336SSimo Sorce 		return err;
3201d658336SSimo Sorce 
3211d658336SSimo Sorce 	/* status->minor_status */
3221d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 8);
3231d658336SSimo Sorce 	if (unlikely(p == NULL))
3241d658336SSimo Sorce 		return -ENOSPC;
3251d658336SSimo Sorce 	p = xdr_decode_hyper(p, &status->minor_status);
3261d658336SSimo Sorce 
3271d658336SSimo Sorce 	/* status->major_status_string */
3281d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &status->major_status_string);
3291d658336SSimo Sorce 	if (err)
3301d658336SSimo Sorce 		return err;
3311d658336SSimo Sorce 
3321d658336SSimo Sorce 	/* status->minor_status_string */
3331d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &status->minor_status_string);
3341d658336SSimo Sorce 	if (err)
3351d658336SSimo Sorce 		return err;
3361d658336SSimo Sorce 
3371d658336SSimo Sorce 	/* status->server_ctx */
3381d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &status->server_ctx);
3391d658336SSimo Sorce 	if (err)
3401d658336SSimo Sorce 		return err;
3411d658336SSimo Sorce 
3421d658336SSimo Sorce 	/* we assume we have no options for now, so simply consume them */
3431d658336SSimo Sorce 	/* status->options */
3441d658336SSimo Sorce 	err = dummy_dec_opt_array(xdr, &status->options);
3451d658336SSimo Sorce 
3461d658336SSimo Sorce 	return err;
3471d658336SSimo Sorce }
3481d658336SSimo Sorce 
gssx_enc_call_ctx(struct xdr_stream * xdr,const struct gssx_call_ctx * ctx)3491d658336SSimo Sorce static int gssx_enc_call_ctx(struct xdr_stream *xdr,
35089daf360SChristoph Hellwig 			     const struct gssx_call_ctx *ctx)
3511d658336SSimo Sorce {
3521d658336SSimo Sorce 	struct gssx_option opt;
3531d658336SSimo Sorce 	__be32 *p;
3541d658336SSimo Sorce 	int err;
3551d658336SSimo Sorce 
3561d658336SSimo Sorce 	/* ctx->locale */
3571d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &ctx->locale);
3581d658336SSimo Sorce 	if (err)
3591d658336SSimo Sorce 		return err;
3601d658336SSimo Sorce 
3611d658336SSimo Sorce 	/* ctx->server_ctx */
3621d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &ctx->server_ctx);
3631d658336SSimo Sorce 	if (err)
3641d658336SSimo Sorce 		return err;
3651d658336SSimo Sorce 
3661d658336SSimo Sorce 	/* we always want to ask for lucid contexts */
3671d658336SSimo Sorce 	/* ctx->options */
3681d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 4);
3691d658336SSimo Sorce 	*p = cpu_to_be32(2);
3701d658336SSimo Sorce 
3711d658336SSimo Sorce 	/* we want a lucid_v1 context */
3721d658336SSimo Sorce 	opt.option.data = LUCID_OPTION;
3731d658336SSimo Sorce 	opt.option.len = sizeof(LUCID_OPTION);
3741d658336SSimo Sorce 	opt.value.data = LUCID_VALUE;
3751d658336SSimo Sorce 	opt.value.len = sizeof(LUCID_VALUE);
3761d658336SSimo Sorce 	err = gssx_enc_option(xdr, &opt);
3771d658336SSimo Sorce 
3781d658336SSimo Sorce 	/* ..and user creds */
3791d658336SSimo Sorce 	opt.option.data = CREDS_OPTION;
3801d658336SSimo Sorce 	opt.option.len = sizeof(CREDS_OPTION);
3811d658336SSimo Sorce 	opt.value.data = CREDS_VALUE;
3821d658336SSimo Sorce 	opt.value.len = sizeof(CREDS_VALUE);
3831d658336SSimo Sorce 	err = gssx_enc_option(xdr, &opt);
3841d658336SSimo Sorce 
3851d658336SSimo Sorce 	return err;
3861d658336SSimo Sorce }
3871d658336SSimo Sorce 
gssx_dec_name_attr(struct xdr_stream * xdr,struct gssx_name_attr * attr)3881d658336SSimo Sorce static int gssx_dec_name_attr(struct xdr_stream *xdr,
3891d658336SSimo Sorce 			     struct gssx_name_attr *attr)
3901d658336SSimo Sorce {
3911d658336SSimo Sorce 	int err;
3921d658336SSimo Sorce 
3931d658336SSimo Sorce 	/* attr->attr */
3941d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &attr->attr);
3951d658336SSimo Sorce 	if (err)
3961d658336SSimo Sorce 		return err;
3971d658336SSimo Sorce 
3981d658336SSimo Sorce 	/* attr->value */
3991d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &attr->value);
4001d658336SSimo Sorce 	if (err)
4011d658336SSimo Sorce 		return err;
4021d658336SSimo Sorce 
4031d658336SSimo Sorce 	/* attr->extensions */
4041d658336SSimo Sorce 	err = dummy_dec_opt_array(xdr, &attr->extensions);
4051d658336SSimo Sorce 
4061d658336SSimo Sorce 	return err;
4071d658336SSimo Sorce }
4081d658336SSimo Sorce 
dummy_enc_nameattr_array(struct xdr_stream * xdr,struct gssx_name_attr_array * naa)4091d658336SSimo Sorce static int dummy_enc_nameattr_array(struct xdr_stream *xdr,
4101d658336SSimo Sorce 				    struct gssx_name_attr_array *naa)
4111d658336SSimo Sorce {
4121d658336SSimo Sorce 	__be32 *p;
4131d658336SSimo Sorce 
4141d658336SSimo Sorce 	if (naa->count != 0)
4151d658336SSimo Sorce 		return -EINVAL;
4161d658336SSimo Sorce 
4171d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 4);
4181d658336SSimo Sorce 	if (!p)
4191d658336SSimo Sorce 		return -ENOSPC;
4201d658336SSimo Sorce 	*p = 0;
4211d658336SSimo Sorce 
4221d658336SSimo Sorce 	return 0;
4231d658336SSimo Sorce }
4241d658336SSimo Sorce 
dummy_dec_nameattr_array(struct xdr_stream * xdr,struct gssx_name_attr_array * naa)4251d658336SSimo Sorce static int dummy_dec_nameattr_array(struct xdr_stream *xdr,
4261d658336SSimo Sorce 				    struct gssx_name_attr_array *naa)
4271d658336SSimo Sorce {
428dc43376cSJ. Bruce Fields 	struct gssx_name_attr dummy = { .attr = {.len = 0} };
4291d658336SSimo Sorce 	u32 count, i;
4301d658336SSimo Sorce 	__be32 *p;
4311d658336SSimo Sorce 
4321d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 4);
4331d658336SSimo Sorce 	if (unlikely(p == NULL))
4341d658336SSimo Sorce 		return -ENOSPC;
4351d658336SSimo Sorce 	count = be32_to_cpup(p++);
4361d658336SSimo Sorce 	for (i = 0; i < count; i++) {
4371d658336SSimo Sorce 		gssx_dec_name_attr(xdr, &dummy);
4381d658336SSimo Sorce 	}
4391d658336SSimo Sorce 
4401d658336SSimo Sorce 	naa->count = 0;
4411d658336SSimo Sorce 	naa->data = NULL;
4421d658336SSimo Sorce 	return 0;
4431d658336SSimo Sorce }
4441d658336SSimo Sorce 
4451d658336SSimo Sorce static struct xdr_netobj zero_netobj = {};
4461d658336SSimo Sorce 
4471d658336SSimo Sorce static struct gssx_name_attr_array zero_name_attr_array = {};
4481d658336SSimo Sorce 
4491d658336SSimo Sorce static struct gssx_option_array zero_option_array = {};
4501d658336SSimo Sorce 
gssx_enc_name(struct xdr_stream * xdr,struct gssx_name * name)4511d658336SSimo Sorce static int gssx_enc_name(struct xdr_stream *xdr,
4521d658336SSimo Sorce 			 struct gssx_name *name)
4531d658336SSimo Sorce {
4541d658336SSimo Sorce 	int err;
4551d658336SSimo Sorce 
4561d658336SSimo Sorce 	/* name->display_name */
4571d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &name->display_name);
4581d658336SSimo Sorce 	if (err)
4591d658336SSimo Sorce 		return err;
4601d658336SSimo Sorce 
4611d658336SSimo Sorce 	/* name->name_type */
4621d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &zero_netobj);
4631d658336SSimo Sorce 	if (err)
4641d658336SSimo Sorce 		return err;
4651d658336SSimo Sorce 
4661d658336SSimo Sorce 	/* name->exported_name */
4671d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &zero_netobj);
4681d658336SSimo Sorce 	if (err)
4691d658336SSimo Sorce 		return err;
4701d658336SSimo Sorce 
4711d658336SSimo Sorce 	/* name->exported_composite_name */
4721d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &zero_netobj);
4731d658336SSimo Sorce 	if (err)
4741d658336SSimo Sorce 		return err;
4751d658336SSimo Sorce 
4761d658336SSimo Sorce 	/* leave name_attributes empty for now, will add once we have any
4771d658336SSimo Sorce 	 * to pass up at all */
4781d658336SSimo Sorce 	/* name->name_attributes */
4791d658336SSimo Sorce 	err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array);
4801d658336SSimo Sorce 	if (err)
4811d658336SSimo Sorce 		return err;
4821d658336SSimo Sorce 
4831d658336SSimo Sorce 	/* leave options empty for now, will add once we have any options
4841d658336SSimo Sorce 	 * to pass up at all */
4851d658336SSimo Sorce 	/* name->extensions */
4861d658336SSimo Sorce 	err = dummy_enc_opt_array(xdr, &zero_option_array);
4871d658336SSimo Sorce 
4881d658336SSimo Sorce 	return err;
4891d658336SSimo Sorce }
4901d658336SSimo Sorce 
491dc43376cSJ. Bruce Fields 
gssx_dec_name(struct xdr_stream * xdr,struct gssx_name * name)4921d658336SSimo Sorce static int gssx_dec_name(struct xdr_stream *xdr,
4931d658336SSimo Sorce 			 struct gssx_name *name)
4941d658336SSimo Sorce {
495dc43376cSJ. Bruce Fields 	struct xdr_netobj dummy_netobj = { .len = 0 };
496dc43376cSJ. Bruce Fields 	struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 };
497dc43376cSJ. Bruce Fields 	struct gssx_option_array dummy_option_array = { .count = 0 };
4981d658336SSimo Sorce 	int err;
4991d658336SSimo Sorce 
5001d658336SSimo Sorce 	/* name->display_name */
5011d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &name->display_name);
5021d658336SSimo Sorce 	if (err)
5031d658336SSimo Sorce 		return err;
5041d658336SSimo Sorce 
5051d658336SSimo Sorce 	/* name->name_type */
5061d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &dummy_netobj);
5071d658336SSimo Sorce 	if (err)
5081d658336SSimo Sorce 		return err;
5091d658336SSimo Sorce 
5101d658336SSimo Sorce 	/* name->exported_name */
5111d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &dummy_netobj);
5121d658336SSimo Sorce 	if (err)
5131d658336SSimo Sorce 		return err;
5141d658336SSimo Sorce 
5151d658336SSimo Sorce 	/* name->exported_composite_name */
5161d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &dummy_netobj);
5171d658336SSimo Sorce 	if (err)
5181d658336SSimo Sorce 		return err;
5191d658336SSimo Sorce 
5201d658336SSimo Sorce 	/* we assume we have no attributes for now, so simply consume them */
5211d658336SSimo Sorce 	/* name->name_attributes */
5221d658336SSimo Sorce 	err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
5231d658336SSimo Sorce 	if (err)
5241d658336SSimo Sorce 		return err;
5251d658336SSimo Sorce 
5261d658336SSimo Sorce 	/* we assume we have no options for now, so simply consume them */
5271d658336SSimo Sorce 	/* name->extensions */
5281d658336SSimo Sorce 	err = dummy_dec_opt_array(xdr, &dummy_option_array);
5291d658336SSimo Sorce 
5301d658336SSimo Sorce 	return err;
5311d658336SSimo Sorce }
5321d658336SSimo Sorce 
dummy_enc_credel_array(struct xdr_stream * xdr,struct gssx_cred_element_array * cea)5331d658336SSimo Sorce static int dummy_enc_credel_array(struct xdr_stream *xdr,
5341d658336SSimo Sorce 				  struct gssx_cred_element_array *cea)
5351d658336SSimo Sorce {
5361d658336SSimo Sorce 	__be32 *p;
5371d658336SSimo Sorce 
5381d658336SSimo Sorce 	if (cea->count != 0)
5391d658336SSimo Sorce 		return -EINVAL;
5401d658336SSimo Sorce 
5411d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 4);
5421d658336SSimo Sorce 	if (!p)
5431d658336SSimo Sorce 		return -ENOSPC;
5441d658336SSimo Sorce 	*p = 0;
5451d658336SSimo Sorce 
5461d658336SSimo Sorce 	return 0;
5471d658336SSimo Sorce }
5481d658336SSimo Sorce 
gssx_enc_cred(struct xdr_stream * xdr,struct gssx_cred * cred)5491d658336SSimo Sorce static int gssx_enc_cred(struct xdr_stream *xdr,
5501d658336SSimo Sorce 			 struct gssx_cred *cred)
5511d658336SSimo Sorce {
5521d658336SSimo Sorce 	int err;
5531d658336SSimo Sorce 
5541d658336SSimo Sorce 	/* cred->desired_name */
5551d658336SSimo Sorce 	err = gssx_enc_name(xdr, &cred->desired_name);
5561d658336SSimo Sorce 	if (err)
5571d658336SSimo Sorce 		return err;
5581d658336SSimo Sorce 
5591d658336SSimo Sorce 	/* cred->elements */
5601d658336SSimo Sorce 	err = dummy_enc_credel_array(xdr, &cred->elements);
561b26ec9b1SJ. Bruce Fields 	if (err)
562b26ec9b1SJ. Bruce Fields 		return err;
5631d658336SSimo Sorce 
5641d658336SSimo Sorce 	/* cred->cred_handle_reference */
5651d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
5661d658336SSimo Sorce 	if (err)
5671d658336SSimo Sorce 		return err;
5681d658336SSimo Sorce 
5691d658336SSimo Sorce 	/* cred->needs_release */
5701d658336SSimo Sorce 	err = gssx_enc_bool(xdr, cred->needs_release);
5711d658336SSimo Sorce 
5721d658336SSimo Sorce 	return err;
5731d658336SSimo Sorce }
5741d658336SSimo Sorce 
gssx_enc_ctx(struct xdr_stream * xdr,struct gssx_ctx * ctx)5751d658336SSimo Sorce static int gssx_enc_ctx(struct xdr_stream *xdr,
5761d658336SSimo Sorce 			struct gssx_ctx *ctx)
5771d658336SSimo Sorce {
5781d658336SSimo Sorce 	__be32 *p;
5791d658336SSimo Sorce 	int err;
5801d658336SSimo Sorce 
5811d658336SSimo Sorce 	/* ctx->exported_context_token */
5821d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
5831d658336SSimo Sorce 	if (err)
5841d658336SSimo Sorce 		return err;
5851d658336SSimo Sorce 
5861d658336SSimo Sorce 	/* ctx->state */
5871d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &ctx->state);
5881d658336SSimo Sorce 	if (err)
5891d658336SSimo Sorce 		return err;
5901d658336SSimo Sorce 
5911d658336SSimo Sorce 	/* ctx->need_release */
5921d658336SSimo Sorce 	err = gssx_enc_bool(xdr, ctx->need_release);
5931d658336SSimo Sorce 	if (err)
5941d658336SSimo Sorce 		return err;
5951d658336SSimo Sorce 
5961d658336SSimo Sorce 	/* ctx->mech */
5971d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &ctx->mech);
5981d658336SSimo Sorce 	if (err)
5991d658336SSimo Sorce 		return err;
6001d658336SSimo Sorce 
6011d658336SSimo Sorce 	/* ctx->src_name */
6021d658336SSimo Sorce 	err = gssx_enc_name(xdr, &ctx->src_name);
6031d658336SSimo Sorce 	if (err)
6041d658336SSimo Sorce 		return err;
6051d658336SSimo Sorce 
6061d658336SSimo Sorce 	/* ctx->targ_name */
6071d658336SSimo Sorce 	err = gssx_enc_name(xdr, &ctx->targ_name);
6081d658336SSimo Sorce 	if (err)
6091d658336SSimo Sorce 		return err;
6101d658336SSimo Sorce 
6111d658336SSimo Sorce 	/* ctx->lifetime */
6121d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 8+8);
6131d658336SSimo Sorce 	if (!p)
6141d658336SSimo Sorce 		return -ENOSPC;
6151d658336SSimo Sorce 	p = xdr_encode_hyper(p, ctx->lifetime);
6161d658336SSimo Sorce 
6171d658336SSimo Sorce 	/* ctx->ctx_flags */
6181d658336SSimo Sorce 	p = xdr_encode_hyper(p, ctx->ctx_flags);
6191d658336SSimo Sorce 
6201d658336SSimo Sorce 	/* ctx->locally_initiated */
6211d658336SSimo Sorce 	err = gssx_enc_bool(xdr, ctx->locally_initiated);
6221d658336SSimo Sorce 	if (err)
6231d658336SSimo Sorce 		return err;
6241d658336SSimo Sorce 
6251d658336SSimo Sorce 	/* ctx->open */
6261d658336SSimo Sorce 	err = gssx_enc_bool(xdr, ctx->open);
6271d658336SSimo Sorce 	if (err)
6281d658336SSimo Sorce 		return err;
6291d658336SSimo Sorce 
6301d658336SSimo Sorce 	/* leave options empty for now, will add once we have any options
6311d658336SSimo Sorce 	 * to pass up at all */
6321d658336SSimo Sorce 	/* ctx->options */
6331d658336SSimo Sorce 	err = dummy_enc_opt_array(xdr, &ctx->options);
6341d658336SSimo Sorce 
6351d658336SSimo Sorce 	return err;
6361d658336SSimo Sorce }
6371d658336SSimo Sorce 
gssx_dec_ctx(struct xdr_stream * xdr,struct gssx_ctx * ctx)6381d658336SSimo Sorce static int gssx_dec_ctx(struct xdr_stream *xdr,
6391d658336SSimo Sorce 			struct gssx_ctx *ctx)
6401d658336SSimo Sorce {
6411d658336SSimo Sorce 	__be32 *p;
6421d658336SSimo Sorce 	int err;
6431d658336SSimo Sorce 
6441d658336SSimo Sorce 	/* ctx->exported_context_token */
6451d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
6461d658336SSimo Sorce 	if (err)
6471d658336SSimo Sorce 		return err;
6481d658336SSimo Sorce 
6491d658336SSimo Sorce 	/* ctx->state */
6501d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &ctx->state);
6511d658336SSimo Sorce 	if (err)
6521d658336SSimo Sorce 		return err;
6531d658336SSimo Sorce 
6541d658336SSimo Sorce 	/* ctx->need_release */
6551d658336SSimo Sorce 	err = gssx_dec_bool(xdr, &ctx->need_release);
6561d658336SSimo Sorce 	if (err)
6571d658336SSimo Sorce 		return err;
6581d658336SSimo Sorce 
6591d658336SSimo Sorce 	/* ctx->mech */
6601d658336SSimo Sorce 	err = gssx_dec_buffer(xdr, &ctx->mech);
6611d658336SSimo Sorce 	if (err)
6621d658336SSimo Sorce 		return err;
6631d658336SSimo Sorce 
6641d658336SSimo Sorce 	/* ctx->src_name */
6651d658336SSimo Sorce 	err = gssx_dec_name(xdr, &ctx->src_name);
6661d658336SSimo Sorce 	if (err)
6671d658336SSimo Sorce 		return err;
6681d658336SSimo Sorce 
6691d658336SSimo Sorce 	/* ctx->targ_name */
6701d658336SSimo Sorce 	err = gssx_dec_name(xdr, &ctx->targ_name);
6711d658336SSimo Sorce 	if (err)
6721d658336SSimo Sorce 		return err;
6731d658336SSimo Sorce 
6741d658336SSimo Sorce 	/* ctx->lifetime */
6751d658336SSimo Sorce 	p = xdr_inline_decode(xdr, 8+8);
6761d658336SSimo Sorce 	if (unlikely(p == NULL))
6771d658336SSimo Sorce 		return -ENOSPC;
6781d658336SSimo Sorce 	p = xdr_decode_hyper(p, &ctx->lifetime);
6791d658336SSimo Sorce 
6801d658336SSimo Sorce 	/* ctx->ctx_flags */
6811d658336SSimo Sorce 	p = xdr_decode_hyper(p, &ctx->ctx_flags);
6821d658336SSimo Sorce 
6831d658336SSimo Sorce 	/* ctx->locally_initiated */
6841d658336SSimo Sorce 	err = gssx_dec_bool(xdr, &ctx->locally_initiated);
6851d658336SSimo Sorce 	if (err)
6861d658336SSimo Sorce 		return err;
6871d658336SSimo Sorce 
6881d658336SSimo Sorce 	/* ctx->open */
6891d658336SSimo Sorce 	err = gssx_dec_bool(xdr, &ctx->open);
6901d658336SSimo Sorce 	if (err)
6911d658336SSimo Sorce 		return err;
6921d658336SSimo Sorce 
6931d658336SSimo Sorce 	/* we assume we have no options for now, so simply consume them */
6941d658336SSimo Sorce 	/* ctx->options */
6951d658336SSimo Sorce 	err = dummy_dec_opt_array(xdr, &ctx->options);
6961d658336SSimo Sorce 
6971d658336SSimo Sorce 	return err;
6981d658336SSimo Sorce }
6991d658336SSimo Sorce 
gssx_enc_cb(struct xdr_stream * xdr,struct gssx_cb * cb)7001d658336SSimo Sorce static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
7011d658336SSimo Sorce {
7021d658336SSimo Sorce 	__be32 *p;
7031d658336SSimo Sorce 	int err;
7041d658336SSimo Sorce 
7051d658336SSimo Sorce 	/* cb->initiator_addrtype */
7061d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 8);
7071d658336SSimo Sorce 	if (!p)
7081d658336SSimo Sorce 		return -ENOSPC;
7091d658336SSimo Sorce 	p = xdr_encode_hyper(p, cb->initiator_addrtype);
7101d658336SSimo Sorce 
7111d658336SSimo Sorce 	/* cb->initiator_address */
7121d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &cb->initiator_address);
7131d658336SSimo Sorce 	if (err)
7141d658336SSimo Sorce 		return err;
7151d658336SSimo Sorce 
7161d658336SSimo Sorce 	/* cb->acceptor_addrtype */
7171d658336SSimo Sorce 	p = xdr_reserve_space(xdr, 8);
7181d658336SSimo Sorce 	if (!p)
7191d658336SSimo Sorce 		return -ENOSPC;
7201d658336SSimo Sorce 	p = xdr_encode_hyper(p, cb->acceptor_addrtype);
7211d658336SSimo Sorce 
7221d658336SSimo Sorce 	/* cb->acceptor_address */
7231d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &cb->acceptor_address);
7241d658336SSimo Sorce 	if (err)
7251d658336SSimo Sorce 		return err;
7261d658336SSimo Sorce 
7271d658336SSimo Sorce 	/* cb->application_data */
7281d658336SSimo Sorce 	err = gssx_enc_buffer(xdr, &cb->application_data);
7291d658336SSimo Sorce 
7301d658336SSimo Sorce 	return err;
7311d658336SSimo Sorce }
7321d658336SSimo Sorce 
gssx_enc_accept_sec_context(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)7331d658336SSimo Sorce void gssx_enc_accept_sec_context(struct rpc_rqst *req,
7341d658336SSimo Sorce 				 struct xdr_stream *xdr,
73589daf360SChristoph Hellwig 				 const void *data)
7361d658336SSimo Sorce {
73789daf360SChristoph Hellwig 	const struct gssx_arg_accept_sec_context *arg = data;
7381d658336SSimo Sorce 	int err;
7391d658336SSimo Sorce 
7401d658336SSimo Sorce 	err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
7411d658336SSimo Sorce 	if (err)
7421d658336SSimo Sorce 		goto done;
7431d658336SSimo Sorce 
7441d658336SSimo Sorce 	/* arg->context_handle */
745b26ec9b1SJ. Bruce Fields 	if (arg->context_handle)
7461d658336SSimo Sorce 		err = gssx_enc_ctx(xdr, arg->context_handle);
747b26ec9b1SJ. Bruce Fields 	else
748b26ec9b1SJ. Bruce Fields 		err = gssx_enc_bool(xdr, 0);
7491d658336SSimo Sorce 	if (err)
7501d658336SSimo Sorce 		goto done;
7511d658336SSimo Sorce 
7521d658336SSimo Sorce 	/* arg->cred_handle */
753b26ec9b1SJ. Bruce Fields 	if (arg->cred_handle)
7541d658336SSimo Sorce 		err = gssx_enc_cred(xdr, arg->cred_handle);
755b26ec9b1SJ. Bruce Fields 	else
756b26ec9b1SJ. Bruce Fields 		err = gssx_enc_bool(xdr, 0);
7571d658336SSimo Sorce 	if (err)
7581d658336SSimo Sorce 		goto done;
7591d658336SSimo Sorce 
7601d658336SSimo Sorce 	/* arg->input_token */
7611d658336SSimo Sorce 	err = gssx_enc_in_token(xdr, &arg->input_token);
7621d658336SSimo Sorce 	if (err)
7631d658336SSimo Sorce 		goto done;
7641d658336SSimo Sorce 
7651d658336SSimo Sorce 	/* arg->input_cb */
766b26ec9b1SJ. Bruce Fields 	if (arg->input_cb)
7671d658336SSimo Sorce 		err = gssx_enc_cb(xdr, arg->input_cb);
768b26ec9b1SJ. Bruce Fields 	else
769b26ec9b1SJ. Bruce Fields 		err = gssx_enc_bool(xdr, 0);
7701d658336SSimo Sorce 	if (err)
7711d658336SSimo Sorce 		goto done;
7721d658336SSimo Sorce 
7731d658336SSimo Sorce 	err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
7741d658336SSimo Sorce 	if (err)
7751d658336SSimo Sorce 		goto done;
7761d658336SSimo Sorce 
7771d658336SSimo Sorce 	/* leave options empty for now, will add once we have any options
7781d658336SSimo Sorce 	 * to pass up at all */
7791d658336SSimo Sorce 	/* arg->options */
7801d658336SSimo Sorce 	err = dummy_enc_opt_array(xdr, &arg->options);
7811d658336SSimo Sorce 
7829dfd87daSJ. Bruce Fields 	xdr_inline_pages(&req->rq_rcv_buf,
7839dfd87daSJ. Bruce Fields 		PAGE_SIZE/2 /* pretty arbitrary */,
7849dfd87daSJ. Bruce Fields 		arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
7851d658336SSimo Sorce done:
7861d658336SSimo Sorce 	if (err)
7871d658336SSimo Sorce 		dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
7881d658336SSimo Sorce }
7891d658336SSimo Sorce 
gssx_dec_accept_sec_context(struct rpc_rqst * rqstp,struct xdr_stream * xdr,void * data)7901d658336SSimo Sorce int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
7911d658336SSimo Sorce 				struct xdr_stream *xdr,
792305c6241SChristoph Hellwig 				void *data)
7931d658336SSimo Sorce {
794305c6241SChristoph Hellwig 	struct gssx_res_accept_sec_context *res = data;
795fb43f11cSJ. Bruce Fields 	u32 value_follows;
7961d658336SSimo Sorce 	int err;
7979507271dSScott Mayhew 	struct page *scratch;
7989507271dSScott Mayhew 
7999507271dSScott Mayhew 	scratch = alloc_page(GFP_KERNEL);
8009507271dSScott Mayhew 	if (!scratch)
8019507271dSScott Mayhew 		return -ENOMEM;
8020ae4c3e8SChuck Lever 	xdr_set_scratch_page(xdr, scratch);
8031d658336SSimo Sorce 
8041d658336SSimo Sorce 	/* res->status */
8051d658336SSimo Sorce 	err = gssx_dec_status(xdr, &res->status);
8061d658336SSimo Sorce 	if (err)
8079507271dSScott Mayhew 		goto out_free;
8081d658336SSimo Sorce 
8091d658336SSimo Sorce 	/* res->context_handle */
810fb43f11cSJ. Bruce Fields 	err = gssx_dec_bool(xdr, &value_follows);
811fb43f11cSJ. Bruce Fields 	if (err)
8129507271dSScott Mayhew 		goto out_free;
813fb43f11cSJ. Bruce Fields 	if (value_follows) {
8141d658336SSimo Sorce 		err = gssx_dec_ctx(xdr, res->context_handle);
8151d658336SSimo Sorce 		if (err)
8169507271dSScott Mayhew 			goto out_free;
8171d658336SSimo Sorce 	} else {
8181d658336SSimo Sorce 		res->context_handle = NULL;
8191d658336SSimo Sorce 	}
8201d658336SSimo Sorce 
8211d658336SSimo Sorce 	/* res->output_token */
822fb43f11cSJ. Bruce Fields 	err = gssx_dec_bool(xdr, &value_follows);
823fb43f11cSJ. Bruce Fields 	if (err)
8249507271dSScott Mayhew 		goto out_free;
825fb43f11cSJ. Bruce Fields 	if (value_follows) {
8261d658336SSimo Sorce 		err = gssx_dec_buffer(xdr, res->output_token);
8271d658336SSimo Sorce 		if (err)
8289507271dSScott Mayhew 			goto out_free;
8291d658336SSimo Sorce 	} else {
8301d658336SSimo Sorce 		res->output_token = NULL;
8311d658336SSimo Sorce 	}
8321d658336SSimo Sorce 
8331d658336SSimo Sorce 	/* res->delegated_cred_handle */
834fb43f11cSJ. Bruce Fields 	err = gssx_dec_bool(xdr, &value_follows);
835fb43f11cSJ. Bruce Fields 	if (err)
8369507271dSScott Mayhew 		goto out_free;
837fb43f11cSJ. Bruce Fields 	if (value_follows) {
8381d658336SSimo Sorce 		/* we do not support upcall servers sending this data. */
8399507271dSScott Mayhew 		err = -EINVAL;
8409507271dSScott Mayhew 		goto out_free;
8411d658336SSimo Sorce 	}
8421d658336SSimo Sorce 
8431d658336SSimo Sorce 	/* res->options */
8441d658336SSimo Sorce 	err = gssx_dec_option_array(xdr, &res->options);
8451d658336SSimo Sorce 
8469507271dSScott Mayhew out_free:
8479507271dSScott Mayhew 	__free_page(scratch);
8481d658336SSimo Sorce 	return err;
8491d658336SSimo Sorce }
850