Linux Audio

Check our new training course

Loading...
v4.17
 
  1/*
  2 * GSS Proxy upcall module
  3 *
  4 *  Copyright (C) 2012 Simo Sorce <simo@redhat.com>
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License as published by
  8 * the Free Software Foundation; either version 2 of the License, or
  9 * (at your option) any later version.
 10 *
 11 * This program is distributed in the hope that it will be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 * GNU General Public License for more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program; if not, write to the Free Software
 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 19 */
 20
 21#include <linux/sunrpc/svcauth.h>
 22#include "gss_rpc_xdr.h"
 23
 24static int gssx_enc_bool(struct xdr_stream *xdr, int v)
 25{
 26	__be32 *p;
 27
 28	p = xdr_reserve_space(xdr, 4);
 29	if (unlikely(p == NULL))
 30		return -ENOSPC;
 31	*p = v ? xdr_one : xdr_zero;
 32	return 0;
 33}
 34
 35static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v)
 36{
 37	__be32 *p;
 38
 39	p = xdr_inline_decode(xdr, 4);
 40	if (unlikely(p == NULL))
 41		return -ENOSPC;
 42	*v = be32_to_cpu(*p);
 43	return 0;
 44}
 45
 46static int gssx_enc_buffer(struct xdr_stream *xdr,
 47			   const gssx_buffer *buf)
 48{
 49	__be32 *p;
 50
 51	p = xdr_reserve_space(xdr, sizeof(u32) + buf->len);
 52	if (!p)
 53		return -ENOSPC;
 54	xdr_encode_opaque(p, buf->data, buf->len);
 55	return 0;
 56}
 57
 58static int gssx_enc_in_token(struct xdr_stream *xdr,
 59			     const struct gssp_in_token *in)
 60{
 61	__be32 *p;
 62
 63	p = xdr_reserve_space(xdr, 4);
 64	if (!p)
 65		return -ENOSPC;
 66	*p = cpu_to_be32(in->page_len);
 67
 68	/* all we need to do is to write pages */
 69	xdr_write_pages(xdr, in->pages, in->page_base, in->page_len);
 70
 71	return 0;
 72}
 73
 74
 75static int gssx_dec_buffer(struct xdr_stream *xdr,
 76			   gssx_buffer *buf)
 77{
 78	u32 length;
 79	__be32 *p;
 80
 81	p = xdr_inline_decode(xdr, 4);
 82	if (unlikely(p == NULL))
 83		return -ENOSPC;
 84
 85	length = be32_to_cpup(p);
 86	p = xdr_inline_decode(xdr, length);
 87	if (unlikely(p == NULL))
 88		return -ENOSPC;
 89
 90	if (buf->len == 0) {
 91		/* we intentionally are not interested in this buffer */
 92		return 0;
 93	}
 94	if (length > buf->len)
 95		return -ENOSPC;
 96
 97	if (!buf->data) {
 98		buf->data = kmemdup(p, length, GFP_KERNEL);
 99		if (!buf->data)
100			return -ENOMEM;
101	} else {
102		memcpy(buf->data, p, length);
103	}
104	buf->len = length;
105	return 0;
106}
107
108static int gssx_enc_option(struct xdr_stream *xdr,
109			   struct gssx_option *opt)
110{
111	int err;
112
113	err = gssx_enc_buffer(xdr, &opt->option);
114	if (err)
115		return err;
116	err = gssx_enc_buffer(xdr, &opt->value);
117	return err;
118}
119
120static int gssx_dec_option(struct xdr_stream *xdr,
121			   struct gssx_option *opt)
122{
123	int err;
124
125	err = gssx_dec_buffer(xdr, &opt->option);
126	if (err)
127		return err;
128	err = gssx_dec_buffer(xdr, &opt->value);
129	return err;
130}
131
132static int dummy_enc_opt_array(struct xdr_stream *xdr,
133				const struct gssx_option_array *oa)
134{
135	__be32 *p;
136
137	if (oa->count != 0)
138		return -EINVAL;
139
140	p = xdr_reserve_space(xdr, 4);
141	if (!p)
142		return -ENOSPC;
143	*p = 0;
144
145	return 0;
146}
147
148static int dummy_dec_opt_array(struct xdr_stream *xdr,
149				struct gssx_option_array *oa)
150{
151	struct gssx_option dummy;
152	u32 count, i;
153	__be32 *p;
154
155	p = xdr_inline_decode(xdr, 4);
156	if (unlikely(p == NULL))
157		return -ENOSPC;
158	count = be32_to_cpup(p++);
159	memset(&dummy, 0, sizeof(dummy));
160	for (i = 0; i < count; i++) {
161		gssx_dec_option(xdr, &dummy);
162	}
163
164	oa->count = 0;
165	oa->data = NULL;
166	return 0;
167}
168
169static int get_host_u32(struct xdr_stream *xdr, u32 *res)
170{
171	__be32 *p;
172
173	p = xdr_inline_decode(xdr, 4);
174	if (!p)
175		return -EINVAL;
176	/* Contents of linux creds are all host-endian: */
177	memcpy(res, p, sizeof(u32));
178	return 0;
179}
180
181static int gssx_dec_linux_creds(struct xdr_stream *xdr,
182				struct svc_cred *creds)
183{
184	u32 length;
185	__be32 *p;
186	u32 tmp;
187	u32 N;
188	int i, err;
189
190	p = xdr_inline_decode(xdr, 4);
191	if (unlikely(p == NULL))
192		return -ENOSPC;
193
194	length = be32_to_cpup(p);
195
196	if (length > (3 + NGROUPS_MAX) * sizeof(u32))
197		return -ENOSPC;
198
199	/* uid */
200	err = get_host_u32(xdr, &tmp);
201	if (err)
202		return err;
203	creds->cr_uid = make_kuid(&init_user_ns, tmp);
204
205	/* gid */
206	err = get_host_u32(xdr, &tmp);
207	if (err)
208		return err;
209	creds->cr_gid = make_kgid(&init_user_ns, tmp);
210
211	/* number of additional gid's */
212	err = get_host_u32(xdr, &tmp);
213	if (err)
214		return err;
215	N = tmp;
216	if ((3 + N) * sizeof(u32) != length)
217		return -EINVAL;
218	creds->cr_group_info = groups_alloc(N);
219	if (creds->cr_group_info == NULL)
220		return -ENOMEM;
221
222	/* gid's */
223	for (i = 0; i < N; i++) {
224		kgid_t kgid;
225		err = get_host_u32(xdr, &tmp);
226		if (err)
227			goto out_free_groups;
228		err = -EINVAL;
229		kgid = make_kgid(&init_user_ns, tmp);
230		if (!gid_valid(kgid))
231			goto out_free_groups;
232		creds->cr_group_info->gid[i] = kgid;
233	}
234	groups_sort(creds->cr_group_info);
235
236	return 0;
237out_free_groups:
238	groups_free(creds->cr_group_info);
239	return err;
240}
241
242static int gssx_dec_option_array(struct xdr_stream *xdr,
243				 struct gssx_option_array *oa)
244{
245	struct svc_cred *creds;
246	u32 count, i;
247	__be32 *p;
248	int err;
249
250	p = xdr_inline_decode(xdr, 4);
251	if (unlikely(p == NULL))
252		return -ENOSPC;
253	count = be32_to_cpup(p++);
254	if (!count)
255		return 0;
256
257	/* we recognize only 1 currently: CREDS_VALUE */
258	oa->count = 1;
259
260	oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL);
261	if (!oa->data)
262		return -ENOMEM;
263
264	creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL);
265	if (!creds) {
266		kfree(oa->data);
267		return -ENOMEM;
268	}
269
270	oa->data[0].option.data = CREDS_VALUE;
271	oa->data[0].option.len = sizeof(CREDS_VALUE);
272	oa->data[0].value.data = (void *)creds;
273	oa->data[0].value.len = 0;
274
275	for (i = 0; i < count; i++) {
276		gssx_buffer dummy = { 0, NULL };
277		u32 length;
278
279		/* option buffer */
280		p = xdr_inline_decode(xdr, 4);
281		if (unlikely(p == NULL))
282			return -ENOSPC;
 
 
283
284		length = be32_to_cpup(p);
285		p = xdr_inline_decode(xdr, length);
286		if (unlikely(p == NULL))
287			return -ENOSPC;
 
 
288
289		if (length == sizeof(CREDS_VALUE) &&
290		    memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) {
291			/* We have creds here. parse them */
292			err = gssx_dec_linux_creds(xdr, creds);
293			if (err)
294				return err;
295			oa->data[0].value.len = 1; /* presence */
296		} else {
297			/* consume uninteresting buffer */
298			err = gssx_dec_buffer(xdr, &dummy);
299			if (err)
300				return err;
301		}
302	}
303	return 0;
 
 
 
 
 
 
 
304}
305
306static int gssx_dec_status(struct xdr_stream *xdr,
307			   struct gssx_status *status)
308{
309	__be32 *p;
310	int err;
311
312	/* status->major_status */
313	p = xdr_inline_decode(xdr, 8);
314	if (unlikely(p == NULL))
315		return -ENOSPC;
316	p = xdr_decode_hyper(p, &status->major_status);
317
318	/* status->mech */
319	err = gssx_dec_buffer(xdr, &status->mech);
320	if (err)
321		return err;
322
323	/* status->minor_status */
324	p = xdr_inline_decode(xdr, 8);
325	if (unlikely(p == NULL))
326		return -ENOSPC;
327	p = xdr_decode_hyper(p, &status->minor_status);
328
329	/* status->major_status_string */
330	err = gssx_dec_buffer(xdr, &status->major_status_string);
331	if (err)
332		return err;
333
334	/* status->minor_status_string */
335	err = gssx_dec_buffer(xdr, &status->minor_status_string);
336	if (err)
337		return err;
338
339	/* status->server_ctx */
340	err = gssx_dec_buffer(xdr, &status->server_ctx);
341	if (err)
342		return err;
343
344	/* we assume we have no options for now, so simply consume them */
345	/* status->options */
346	err = dummy_dec_opt_array(xdr, &status->options);
347
348	return err;
349}
350
351static int gssx_enc_call_ctx(struct xdr_stream *xdr,
352			     const struct gssx_call_ctx *ctx)
353{
354	struct gssx_option opt;
355	__be32 *p;
356	int err;
357
358	/* ctx->locale */
359	err = gssx_enc_buffer(xdr, &ctx->locale);
360	if (err)
361		return err;
362
363	/* ctx->server_ctx */
364	err = gssx_enc_buffer(xdr, &ctx->server_ctx);
365	if (err)
366		return err;
367
368	/* we always want to ask for lucid contexts */
369	/* ctx->options */
370	p = xdr_reserve_space(xdr, 4);
371	*p = cpu_to_be32(2);
372
373	/* we want a lucid_v1 context */
374	opt.option.data = LUCID_OPTION;
375	opt.option.len = sizeof(LUCID_OPTION);
376	opt.value.data = LUCID_VALUE;
377	opt.value.len = sizeof(LUCID_VALUE);
378	err = gssx_enc_option(xdr, &opt);
379
380	/* ..and user creds */
381	opt.option.data = CREDS_OPTION;
382	opt.option.len = sizeof(CREDS_OPTION);
383	opt.value.data = CREDS_VALUE;
384	opt.value.len = sizeof(CREDS_VALUE);
385	err = gssx_enc_option(xdr, &opt);
386
387	return err;
388}
389
390static int gssx_dec_name_attr(struct xdr_stream *xdr,
391			     struct gssx_name_attr *attr)
392{
393	int err;
394
395	/* attr->attr */
396	err = gssx_dec_buffer(xdr, &attr->attr);
397	if (err)
398		return err;
399
400	/* attr->value */
401	err = gssx_dec_buffer(xdr, &attr->value);
402	if (err)
403		return err;
404
405	/* attr->extensions */
406	err = dummy_dec_opt_array(xdr, &attr->extensions);
407
408	return err;
409}
410
411static int dummy_enc_nameattr_array(struct xdr_stream *xdr,
412				    struct gssx_name_attr_array *naa)
413{
414	__be32 *p;
415
416	if (naa->count != 0)
417		return -EINVAL;
418
419	p = xdr_reserve_space(xdr, 4);
420	if (!p)
421		return -ENOSPC;
422	*p = 0;
423
424	return 0;
425}
426
427static int dummy_dec_nameattr_array(struct xdr_stream *xdr,
428				    struct gssx_name_attr_array *naa)
429{
430	struct gssx_name_attr dummy = { .attr = {.len = 0} };
431	u32 count, i;
432	__be32 *p;
433
434	p = xdr_inline_decode(xdr, 4);
435	if (unlikely(p == NULL))
436		return -ENOSPC;
437	count = be32_to_cpup(p++);
438	for (i = 0; i < count; i++) {
439		gssx_dec_name_attr(xdr, &dummy);
440	}
441
442	naa->count = 0;
443	naa->data = NULL;
444	return 0;
445}
446
447static struct xdr_netobj zero_netobj = {};
448
449static struct gssx_name_attr_array zero_name_attr_array = {};
450
451static struct gssx_option_array zero_option_array = {};
452
453static int gssx_enc_name(struct xdr_stream *xdr,
454			 struct gssx_name *name)
455{
456	int err;
457
458	/* name->display_name */
459	err = gssx_enc_buffer(xdr, &name->display_name);
460	if (err)
461		return err;
462
463	/* name->name_type */
464	err = gssx_enc_buffer(xdr, &zero_netobj);
465	if (err)
466		return err;
467
468	/* name->exported_name */
469	err = gssx_enc_buffer(xdr, &zero_netobj);
470	if (err)
471		return err;
472
473	/* name->exported_composite_name */
474	err = gssx_enc_buffer(xdr, &zero_netobj);
475	if (err)
476		return err;
477
478	/* leave name_attributes empty for now, will add once we have any
479	 * to pass up at all */
480	/* name->name_attributes */
481	err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array);
482	if (err)
483		return err;
484
485	/* leave options empty for now, will add once we have any options
486	 * to pass up at all */
487	/* name->extensions */
488	err = dummy_enc_opt_array(xdr, &zero_option_array);
489
490	return err;
491}
492
493
494static int gssx_dec_name(struct xdr_stream *xdr,
495			 struct gssx_name *name)
496{
497	struct xdr_netobj dummy_netobj = { .len = 0 };
498	struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 };
499	struct gssx_option_array dummy_option_array = { .count = 0 };
500	int err;
501
502	/* name->display_name */
503	err = gssx_dec_buffer(xdr, &name->display_name);
504	if (err)
505		return err;
506
507	/* name->name_type */
508	err = gssx_dec_buffer(xdr, &dummy_netobj);
509	if (err)
510		return err;
511
512	/* name->exported_name */
513	err = gssx_dec_buffer(xdr, &dummy_netobj);
514	if (err)
515		return err;
516
517	/* name->exported_composite_name */
518	err = gssx_dec_buffer(xdr, &dummy_netobj);
519	if (err)
520		return err;
521
522	/* we assume we have no attributes for now, so simply consume them */
523	/* name->name_attributes */
524	err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
525	if (err)
526		return err;
527
528	/* we assume we have no options for now, so simply consume them */
529	/* name->extensions */
530	err = dummy_dec_opt_array(xdr, &dummy_option_array);
531
532	return err;
533}
534
535static int dummy_enc_credel_array(struct xdr_stream *xdr,
536				  struct gssx_cred_element_array *cea)
537{
538	__be32 *p;
539
540	if (cea->count != 0)
541		return -EINVAL;
542
543	p = xdr_reserve_space(xdr, 4);
544	if (!p)
545		return -ENOSPC;
546	*p = 0;
547
548	return 0;
549}
550
551static int gssx_enc_cred(struct xdr_stream *xdr,
552			 struct gssx_cred *cred)
553{
554	int err;
555
556	/* cred->desired_name */
557	err = gssx_enc_name(xdr, &cred->desired_name);
558	if (err)
559		return err;
560
561	/* cred->elements */
562	err = dummy_enc_credel_array(xdr, &cred->elements);
563	if (err)
564		return err;
565
566	/* cred->cred_handle_reference */
567	err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
568	if (err)
569		return err;
570
571	/* cred->needs_release */
572	err = gssx_enc_bool(xdr, cred->needs_release);
573
574	return err;
575}
576
577static int gssx_enc_ctx(struct xdr_stream *xdr,
578			struct gssx_ctx *ctx)
579{
580	__be32 *p;
581	int err;
582
583	/* ctx->exported_context_token */
584	err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
585	if (err)
586		return err;
587
588	/* ctx->state */
589	err = gssx_enc_buffer(xdr, &ctx->state);
590	if (err)
591		return err;
592
593	/* ctx->need_release */
594	err = gssx_enc_bool(xdr, ctx->need_release);
595	if (err)
596		return err;
597
598	/* ctx->mech */
599	err = gssx_enc_buffer(xdr, &ctx->mech);
600	if (err)
601		return err;
602
603	/* ctx->src_name */
604	err = gssx_enc_name(xdr, &ctx->src_name);
605	if (err)
606		return err;
607
608	/* ctx->targ_name */
609	err = gssx_enc_name(xdr, &ctx->targ_name);
610	if (err)
611		return err;
612
613	/* ctx->lifetime */
614	p = xdr_reserve_space(xdr, 8+8);
615	if (!p)
616		return -ENOSPC;
617	p = xdr_encode_hyper(p, ctx->lifetime);
618
619	/* ctx->ctx_flags */
620	p = xdr_encode_hyper(p, ctx->ctx_flags);
621
622	/* ctx->locally_initiated */
623	err = gssx_enc_bool(xdr, ctx->locally_initiated);
624	if (err)
625		return err;
626
627	/* ctx->open */
628	err = gssx_enc_bool(xdr, ctx->open);
629	if (err)
630		return err;
631
632	/* leave options empty for now, will add once we have any options
633	 * to pass up at all */
634	/* ctx->options */
635	err = dummy_enc_opt_array(xdr, &ctx->options);
636
637	return err;
638}
639
640static int gssx_dec_ctx(struct xdr_stream *xdr,
641			struct gssx_ctx *ctx)
642{
643	__be32 *p;
644	int err;
645
646	/* ctx->exported_context_token */
647	err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
648	if (err)
649		return err;
650
651	/* ctx->state */
652	err = gssx_dec_buffer(xdr, &ctx->state);
653	if (err)
654		return err;
655
656	/* ctx->need_release */
657	err = gssx_dec_bool(xdr, &ctx->need_release);
658	if (err)
659		return err;
660
661	/* ctx->mech */
662	err = gssx_dec_buffer(xdr, &ctx->mech);
663	if (err)
664		return err;
665
666	/* ctx->src_name */
667	err = gssx_dec_name(xdr, &ctx->src_name);
668	if (err)
669		return err;
670
671	/* ctx->targ_name */
672	err = gssx_dec_name(xdr, &ctx->targ_name);
673	if (err)
674		return err;
675
676	/* ctx->lifetime */
677	p = xdr_inline_decode(xdr, 8+8);
678	if (unlikely(p == NULL))
679		return -ENOSPC;
680	p = xdr_decode_hyper(p, &ctx->lifetime);
681
682	/* ctx->ctx_flags */
683	p = xdr_decode_hyper(p, &ctx->ctx_flags);
684
685	/* ctx->locally_initiated */
686	err = gssx_dec_bool(xdr, &ctx->locally_initiated);
687	if (err)
688		return err;
689
690	/* ctx->open */
691	err = gssx_dec_bool(xdr, &ctx->open);
692	if (err)
693		return err;
694
695	/* we assume we have no options for now, so simply consume them */
696	/* ctx->options */
697	err = dummy_dec_opt_array(xdr, &ctx->options);
698
699	return err;
700}
701
702static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
703{
704	__be32 *p;
705	int err;
706
707	/* cb->initiator_addrtype */
708	p = xdr_reserve_space(xdr, 8);
709	if (!p)
710		return -ENOSPC;
711	p = xdr_encode_hyper(p, cb->initiator_addrtype);
712
713	/* cb->initiator_address */
714	err = gssx_enc_buffer(xdr, &cb->initiator_address);
715	if (err)
716		return err;
717
718	/* cb->acceptor_addrtype */
719	p = xdr_reserve_space(xdr, 8);
720	if (!p)
721		return -ENOSPC;
722	p = xdr_encode_hyper(p, cb->acceptor_addrtype);
723
724	/* cb->acceptor_address */
725	err = gssx_enc_buffer(xdr, &cb->acceptor_address);
726	if (err)
727		return err;
728
729	/* cb->application_data */
730	err = gssx_enc_buffer(xdr, &cb->application_data);
731
732	return err;
733}
734
735void gssx_enc_accept_sec_context(struct rpc_rqst *req,
736				 struct xdr_stream *xdr,
737				 const void *data)
738{
739	const struct gssx_arg_accept_sec_context *arg = data;
740	int err;
741
742	err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
743	if (err)
744		goto done;
745
746	/* arg->context_handle */
747	if (arg->context_handle)
748		err = gssx_enc_ctx(xdr, arg->context_handle);
749	else
750		err = gssx_enc_bool(xdr, 0);
751	if (err)
752		goto done;
753
754	/* arg->cred_handle */
755	if (arg->cred_handle)
756		err = gssx_enc_cred(xdr, arg->cred_handle);
757	else
758		err = gssx_enc_bool(xdr, 0);
759	if (err)
760		goto done;
761
762	/* arg->input_token */
763	err = gssx_enc_in_token(xdr, &arg->input_token);
764	if (err)
765		goto done;
766
767	/* arg->input_cb */
768	if (arg->input_cb)
769		err = gssx_enc_cb(xdr, arg->input_cb);
770	else
771		err = gssx_enc_bool(xdr, 0);
772	if (err)
773		goto done;
774
775	err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
776	if (err)
777		goto done;
778
779	/* leave options empty for now, will add once we have any options
780	 * to pass up at all */
781	/* arg->options */
782	err = dummy_enc_opt_array(xdr, &arg->options);
783
784	xdr_inline_pages(&req->rq_rcv_buf,
785		PAGE_SIZE/2 /* pretty arbitrary */,
786		arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
787done:
788	if (err)
789		dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
790}
791
792int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
793				struct xdr_stream *xdr,
794				void *data)
795{
796	struct gssx_res_accept_sec_context *res = data;
797	u32 value_follows;
798	int err;
799	struct page *scratch;
800
801	scratch = alloc_page(GFP_KERNEL);
802	if (!scratch)
803		return -ENOMEM;
804	xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE);
805
806	/* res->status */
807	err = gssx_dec_status(xdr, &res->status);
808	if (err)
809		goto out_free;
810
811	/* res->context_handle */
812	err = gssx_dec_bool(xdr, &value_follows);
813	if (err)
814		goto out_free;
815	if (value_follows) {
816		err = gssx_dec_ctx(xdr, res->context_handle);
817		if (err)
818			goto out_free;
819	} else {
820		res->context_handle = NULL;
821	}
822
823	/* res->output_token */
824	err = gssx_dec_bool(xdr, &value_follows);
825	if (err)
826		goto out_free;
827	if (value_follows) {
828		err = gssx_dec_buffer(xdr, res->output_token);
829		if (err)
830			goto out_free;
831	} else {
832		res->output_token = NULL;
833	}
834
835	/* res->delegated_cred_handle */
836	err = gssx_dec_bool(xdr, &value_follows);
837	if (err)
838		goto out_free;
839	if (value_follows) {
840		/* we do not support upcall servers sending this data. */
841		err = -EINVAL;
842		goto out_free;
843	}
844
845	/* res->options */
846	err = gssx_dec_option_array(xdr, &res->options);
847
848out_free:
849	__free_page(scratch);
850	return err;
851}
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * GSS Proxy upcall module
  4 *
  5 *  Copyright (C) 2012 Simo Sorce <simo@redhat.com>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  6 */
  7
  8#include <linux/sunrpc/svcauth.h>
  9#include "gss_rpc_xdr.h"
 10
 11static int gssx_enc_bool(struct xdr_stream *xdr, int v)
 12{
 13	__be32 *p;
 14
 15	p = xdr_reserve_space(xdr, 4);
 16	if (unlikely(p == NULL))
 17		return -ENOSPC;
 18	*p = v ? xdr_one : xdr_zero;
 19	return 0;
 20}
 21
 22static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v)
 23{
 24	__be32 *p;
 25
 26	p = xdr_inline_decode(xdr, 4);
 27	if (unlikely(p == NULL))
 28		return -ENOSPC;
 29	*v = be32_to_cpu(*p);
 30	return 0;
 31}
 32
 33static int gssx_enc_buffer(struct xdr_stream *xdr,
 34			   const gssx_buffer *buf)
 35{
 36	__be32 *p;
 37
 38	p = xdr_reserve_space(xdr, sizeof(u32) + buf->len);
 39	if (!p)
 40		return -ENOSPC;
 41	xdr_encode_opaque(p, buf->data, buf->len);
 42	return 0;
 43}
 44
 45static int gssx_enc_in_token(struct xdr_stream *xdr,
 46			     const struct gssp_in_token *in)
 47{
 48	__be32 *p;
 49
 50	p = xdr_reserve_space(xdr, 4);
 51	if (!p)
 52		return -ENOSPC;
 53	*p = cpu_to_be32(in->page_len);
 54
 55	/* all we need to do is to write pages */
 56	xdr_write_pages(xdr, in->pages, in->page_base, in->page_len);
 57
 58	return 0;
 59}
 60
 61
 62static int gssx_dec_buffer(struct xdr_stream *xdr,
 63			   gssx_buffer *buf)
 64{
 65	u32 length;
 66	__be32 *p;
 67
 68	p = xdr_inline_decode(xdr, 4);
 69	if (unlikely(p == NULL))
 70		return -ENOSPC;
 71
 72	length = be32_to_cpup(p);
 73	p = xdr_inline_decode(xdr, length);
 74	if (unlikely(p == NULL))
 75		return -ENOSPC;
 76
 77	if (buf->len == 0) {
 78		/* we intentionally are not interested in this buffer */
 79		return 0;
 80	}
 81	if (length > buf->len)
 82		return -ENOSPC;
 83
 84	if (!buf->data) {
 85		buf->data = kmemdup(p, length, GFP_KERNEL);
 86		if (!buf->data)
 87			return -ENOMEM;
 88	} else {
 89		memcpy(buf->data, p, length);
 90	}
 91	buf->len = length;
 92	return 0;
 93}
 94
 95static int gssx_enc_option(struct xdr_stream *xdr,
 96			   struct gssx_option *opt)
 97{
 98	int err;
 99
100	err = gssx_enc_buffer(xdr, &opt->option);
101	if (err)
102		return err;
103	err = gssx_enc_buffer(xdr, &opt->value);
104	return err;
105}
106
107static int gssx_dec_option(struct xdr_stream *xdr,
108			   struct gssx_option *opt)
109{
110	int err;
111
112	err = gssx_dec_buffer(xdr, &opt->option);
113	if (err)
114		return err;
115	err = gssx_dec_buffer(xdr, &opt->value);
116	return err;
117}
118
119static int dummy_enc_opt_array(struct xdr_stream *xdr,
120				const struct gssx_option_array *oa)
121{
122	__be32 *p;
123
124	if (oa->count != 0)
125		return -EINVAL;
126
127	p = xdr_reserve_space(xdr, 4);
128	if (!p)
129		return -ENOSPC;
130	*p = 0;
131
132	return 0;
133}
134
135static int dummy_dec_opt_array(struct xdr_stream *xdr,
136				struct gssx_option_array *oa)
137{
138	struct gssx_option dummy;
139	u32 count, i;
140	__be32 *p;
141
142	p = xdr_inline_decode(xdr, 4);
143	if (unlikely(p == NULL))
144		return -ENOSPC;
145	count = be32_to_cpup(p++);
146	memset(&dummy, 0, sizeof(dummy));
147	for (i = 0; i < count; i++) {
148		gssx_dec_option(xdr, &dummy);
149	}
150
151	oa->count = 0;
152	oa->data = NULL;
153	return 0;
154}
155
156static int get_host_u32(struct xdr_stream *xdr, u32 *res)
157{
158	__be32 *p;
159
160	p = xdr_inline_decode(xdr, 4);
161	if (!p)
162		return -EINVAL;
163	/* Contents of linux creds are all host-endian: */
164	memcpy(res, p, sizeof(u32));
165	return 0;
166}
167
168static int gssx_dec_linux_creds(struct xdr_stream *xdr,
169				struct svc_cred *creds)
170{
171	u32 length;
172	__be32 *p;
173	u32 tmp;
174	u32 N;
175	int i, err;
176
177	p = xdr_inline_decode(xdr, 4);
178	if (unlikely(p == NULL))
179		return -ENOSPC;
180
181	length = be32_to_cpup(p);
182
183	if (length > (3 + NGROUPS_MAX) * sizeof(u32))
184		return -ENOSPC;
185
186	/* uid */
187	err = get_host_u32(xdr, &tmp);
188	if (err)
189		return err;
190	creds->cr_uid = make_kuid(&init_user_ns, tmp);
191
192	/* gid */
193	err = get_host_u32(xdr, &tmp);
194	if (err)
195		return err;
196	creds->cr_gid = make_kgid(&init_user_ns, tmp);
197
198	/* number of additional gid's */
199	err = get_host_u32(xdr, &tmp);
200	if (err)
201		return err;
202	N = tmp;
203	if ((3 + N) * sizeof(u32) != length)
204		return -EINVAL;
205	creds->cr_group_info = groups_alloc(N);
206	if (creds->cr_group_info == NULL)
207		return -ENOMEM;
208
209	/* gid's */
210	for (i = 0; i < N; i++) {
211		kgid_t kgid;
212		err = get_host_u32(xdr, &tmp);
213		if (err)
214			goto out_free_groups;
215		err = -EINVAL;
216		kgid = make_kgid(&init_user_ns, tmp);
217		if (!gid_valid(kgid))
218			goto out_free_groups;
219		creds->cr_group_info->gid[i] = kgid;
220	}
221	groups_sort(creds->cr_group_info);
222
223	return 0;
224out_free_groups:
225	groups_free(creds->cr_group_info);
226	return err;
227}
228
229static int gssx_dec_option_array(struct xdr_stream *xdr,
230				 struct gssx_option_array *oa)
231{
232	struct svc_cred *creds;
233	u32 count, i;
234	__be32 *p;
235	int err;
236
237	p = xdr_inline_decode(xdr, 4);
238	if (unlikely(p == NULL))
239		return -ENOSPC;
240	count = be32_to_cpup(p++);
241	if (!count)
242		return 0;
243
244	/* we recognize only 1 currently: CREDS_VALUE */
245	oa->count = 1;
246
247	oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL);
248	if (!oa->data)
249		return -ENOMEM;
250
251	creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL);
252	if (!creds) {
253		err = -ENOMEM;
254		goto free_oa;
255	}
256
257	oa->data[0].option.data = CREDS_VALUE;
258	oa->data[0].option.len = sizeof(CREDS_VALUE);
259	oa->data[0].value.data = (void *)creds;
260	oa->data[0].value.len = 0;
261
262	for (i = 0; i < count; i++) {
263		gssx_buffer dummy = { 0, NULL };
264		u32 length;
265
266		/* option buffer */
267		p = xdr_inline_decode(xdr, 4);
268		if (unlikely(p == NULL)) {
269			err = -ENOSPC;
270			goto free_creds;
271		}
272
273		length = be32_to_cpup(p);
274		p = xdr_inline_decode(xdr, length);
275		if (unlikely(p == NULL)) {
276			err = -ENOSPC;
277			goto free_creds;
278		}
279
280		if (length == sizeof(CREDS_VALUE) &&
281		    memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) {
282			/* We have creds here. parse them */
283			err = gssx_dec_linux_creds(xdr, creds);
284			if (err)
285				goto free_creds;
286			oa->data[0].value.len = 1; /* presence */
287		} else {
288			/* consume uninteresting buffer */
289			err = gssx_dec_buffer(xdr, &dummy);
290			if (err)
291				goto free_creds;
292		}
293	}
294	return 0;
295
296free_creds:
297	kfree(creds);
298free_oa:
299	kfree(oa->data);
300	oa->data = NULL;
301	return err;
302}
303
304static int gssx_dec_status(struct xdr_stream *xdr,
305			   struct gssx_status *status)
306{
307	__be32 *p;
308	int err;
309
310	/* status->major_status */
311	p = xdr_inline_decode(xdr, 8);
312	if (unlikely(p == NULL))
313		return -ENOSPC;
314	p = xdr_decode_hyper(p, &status->major_status);
315
316	/* status->mech */
317	err = gssx_dec_buffer(xdr, &status->mech);
318	if (err)
319		return err;
320
321	/* status->minor_status */
322	p = xdr_inline_decode(xdr, 8);
323	if (unlikely(p == NULL))
324		return -ENOSPC;
325	p = xdr_decode_hyper(p, &status->minor_status);
326
327	/* status->major_status_string */
328	err = gssx_dec_buffer(xdr, &status->major_status_string);
329	if (err)
330		return err;
331
332	/* status->minor_status_string */
333	err = gssx_dec_buffer(xdr, &status->minor_status_string);
334	if (err)
335		return err;
336
337	/* status->server_ctx */
338	err = gssx_dec_buffer(xdr, &status->server_ctx);
339	if (err)
340		return err;
341
342	/* we assume we have no options for now, so simply consume them */
343	/* status->options */
344	err = dummy_dec_opt_array(xdr, &status->options);
345
346	return err;
347}
348
349static int gssx_enc_call_ctx(struct xdr_stream *xdr,
350			     const struct gssx_call_ctx *ctx)
351{
352	struct gssx_option opt;
353	__be32 *p;
354	int err;
355
356	/* ctx->locale */
357	err = gssx_enc_buffer(xdr, &ctx->locale);
358	if (err)
359		return err;
360
361	/* ctx->server_ctx */
362	err = gssx_enc_buffer(xdr, &ctx->server_ctx);
363	if (err)
364		return err;
365
366	/* we always want to ask for lucid contexts */
367	/* ctx->options */
368	p = xdr_reserve_space(xdr, 4);
369	*p = cpu_to_be32(2);
370
371	/* we want a lucid_v1 context */
372	opt.option.data = LUCID_OPTION;
373	opt.option.len = sizeof(LUCID_OPTION);
374	opt.value.data = LUCID_VALUE;
375	opt.value.len = sizeof(LUCID_VALUE);
376	err = gssx_enc_option(xdr, &opt);
377
378	/* ..and user creds */
379	opt.option.data = CREDS_OPTION;
380	opt.option.len = sizeof(CREDS_OPTION);
381	opt.value.data = CREDS_VALUE;
382	opt.value.len = sizeof(CREDS_VALUE);
383	err = gssx_enc_option(xdr, &opt);
384
385	return err;
386}
387
388static int gssx_dec_name_attr(struct xdr_stream *xdr,
389			     struct gssx_name_attr *attr)
390{
391	int err;
392
393	/* attr->attr */
394	err = gssx_dec_buffer(xdr, &attr->attr);
395	if (err)
396		return err;
397
398	/* attr->value */
399	err = gssx_dec_buffer(xdr, &attr->value);
400	if (err)
401		return err;
402
403	/* attr->extensions */
404	err = dummy_dec_opt_array(xdr, &attr->extensions);
405
406	return err;
407}
408
409static int dummy_enc_nameattr_array(struct xdr_stream *xdr,
410				    struct gssx_name_attr_array *naa)
411{
412	__be32 *p;
413
414	if (naa->count != 0)
415		return -EINVAL;
416
417	p = xdr_reserve_space(xdr, 4);
418	if (!p)
419		return -ENOSPC;
420	*p = 0;
421
422	return 0;
423}
424
425static int dummy_dec_nameattr_array(struct xdr_stream *xdr,
426				    struct gssx_name_attr_array *naa)
427{
428	struct gssx_name_attr dummy = { .attr = {.len = 0} };
429	u32 count, i;
430	__be32 *p;
431
432	p = xdr_inline_decode(xdr, 4);
433	if (unlikely(p == NULL))
434		return -ENOSPC;
435	count = be32_to_cpup(p++);
436	for (i = 0; i < count; i++) {
437		gssx_dec_name_attr(xdr, &dummy);
438	}
439
440	naa->count = 0;
441	naa->data = NULL;
442	return 0;
443}
444
445static struct xdr_netobj zero_netobj = {};
446
447static struct gssx_name_attr_array zero_name_attr_array = {};
448
449static struct gssx_option_array zero_option_array = {};
450
451static int gssx_enc_name(struct xdr_stream *xdr,
452			 struct gssx_name *name)
453{
454	int err;
455
456	/* name->display_name */
457	err = gssx_enc_buffer(xdr, &name->display_name);
458	if (err)
459		return err;
460
461	/* name->name_type */
462	err = gssx_enc_buffer(xdr, &zero_netobj);
463	if (err)
464		return err;
465
466	/* name->exported_name */
467	err = gssx_enc_buffer(xdr, &zero_netobj);
468	if (err)
469		return err;
470
471	/* name->exported_composite_name */
472	err = gssx_enc_buffer(xdr, &zero_netobj);
473	if (err)
474		return err;
475
476	/* leave name_attributes empty for now, will add once we have any
477	 * to pass up at all */
478	/* name->name_attributes */
479	err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array);
480	if (err)
481		return err;
482
483	/* leave options empty for now, will add once we have any options
484	 * to pass up at all */
485	/* name->extensions */
486	err = dummy_enc_opt_array(xdr, &zero_option_array);
487
488	return err;
489}
490
491
492static int gssx_dec_name(struct xdr_stream *xdr,
493			 struct gssx_name *name)
494{
495	struct xdr_netobj dummy_netobj = { .len = 0 };
496	struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 };
497	struct gssx_option_array dummy_option_array = { .count = 0 };
498	int err;
499
500	/* name->display_name */
501	err = gssx_dec_buffer(xdr, &name->display_name);
502	if (err)
503		return err;
504
505	/* name->name_type */
506	err = gssx_dec_buffer(xdr, &dummy_netobj);
507	if (err)
508		return err;
509
510	/* name->exported_name */
511	err = gssx_dec_buffer(xdr, &dummy_netobj);
512	if (err)
513		return err;
514
515	/* name->exported_composite_name */
516	err = gssx_dec_buffer(xdr, &dummy_netobj);
517	if (err)
518		return err;
519
520	/* we assume we have no attributes for now, so simply consume them */
521	/* name->name_attributes */
522	err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
523	if (err)
524		return err;
525
526	/* we assume we have no options for now, so simply consume them */
527	/* name->extensions */
528	err = dummy_dec_opt_array(xdr, &dummy_option_array);
529
530	return err;
531}
532
533static int dummy_enc_credel_array(struct xdr_stream *xdr,
534				  struct gssx_cred_element_array *cea)
535{
536	__be32 *p;
537
538	if (cea->count != 0)
539		return -EINVAL;
540
541	p = xdr_reserve_space(xdr, 4);
542	if (!p)
543		return -ENOSPC;
544	*p = 0;
545
546	return 0;
547}
548
549static int gssx_enc_cred(struct xdr_stream *xdr,
550			 struct gssx_cred *cred)
551{
552	int err;
553
554	/* cred->desired_name */
555	err = gssx_enc_name(xdr, &cred->desired_name);
556	if (err)
557		return err;
558
559	/* cred->elements */
560	err = dummy_enc_credel_array(xdr, &cred->elements);
561	if (err)
562		return err;
563
564	/* cred->cred_handle_reference */
565	err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
566	if (err)
567		return err;
568
569	/* cred->needs_release */
570	err = gssx_enc_bool(xdr, cred->needs_release);
571
572	return err;
573}
574
575static int gssx_enc_ctx(struct xdr_stream *xdr,
576			struct gssx_ctx *ctx)
577{
578	__be32 *p;
579	int err;
580
581	/* ctx->exported_context_token */
582	err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
583	if (err)
584		return err;
585
586	/* ctx->state */
587	err = gssx_enc_buffer(xdr, &ctx->state);
588	if (err)
589		return err;
590
591	/* ctx->need_release */
592	err = gssx_enc_bool(xdr, ctx->need_release);
593	if (err)
594		return err;
595
596	/* ctx->mech */
597	err = gssx_enc_buffer(xdr, &ctx->mech);
598	if (err)
599		return err;
600
601	/* ctx->src_name */
602	err = gssx_enc_name(xdr, &ctx->src_name);
603	if (err)
604		return err;
605
606	/* ctx->targ_name */
607	err = gssx_enc_name(xdr, &ctx->targ_name);
608	if (err)
609		return err;
610
611	/* ctx->lifetime */
612	p = xdr_reserve_space(xdr, 8+8);
613	if (!p)
614		return -ENOSPC;
615	p = xdr_encode_hyper(p, ctx->lifetime);
616
617	/* ctx->ctx_flags */
618	p = xdr_encode_hyper(p, ctx->ctx_flags);
619
620	/* ctx->locally_initiated */
621	err = gssx_enc_bool(xdr, ctx->locally_initiated);
622	if (err)
623		return err;
624
625	/* ctx->open */
626	err = gssx_enc_bool(xdr, ctx->open);
627	if (err)
628		return err;
629
630	/* leave options empty for now, will add once we have any options
631	 * to pass up at all */
632	/* ctx->options */
633	err = dummy_enc_opt_array(xdr, &ctx->options);
634
635	return err;
636}
637
638static int gssx_dec_ctx(struct xdr_stream *xdr,
639			struct gssx_ctx *ctx)
640{
641	__be32 *p;
642	int err;
643
644	/* ctx->exported_context_token */
645	err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
646	if (err)
647		return err;
648
649	/* ctx->state */
650	err = gssx_dec_buffer(xdr, &ctx->state);
651	if (err)
652		return err;
653
654	/* ctx->need_release */
655	err = gssx_dec_bool(xdr, &ctx->need_release);
656	if (err)
657		return err;
658
659	/* ctx->mech */
660	err = gssx_dec_buffer(xdr, &ctx->mech);
661	if (err)
662		return err;
663
664	/* ctx->src_name */
665	err = gssx_dec_name(xdr, &ctx->src_name);
666	if (err)
667		return err;
668
669	/* ctx->targ_name */
670	err = gssx_dec_name(xdr, &ctx->targ_name);
671	if (err)
672		return err;
673
674	/* ctx->lifetime */
675	p = xdr_inline_decode(xdr, 8+8);
676	if (unlikely(p == NULL))
677		return -ENOSPC;
678	p = xdr_decode_hyper(p, &ctx->lifetime);
679
680	/* ctx->ctx_flags */
681	p = xdr_decode_hyper(p, &ctx->ctx_flags);
682
683	/* ctx->locally_initiated */
684	err = gssx_dec_bool(xdr, &ctx->locally_initiated);
685	if (err)
686		return err;
687
688	/* ctx->open */
689	err = gssx_dec_bool(xdr, &ctx->open);
690	if (err)
691		return err;
692
693	/* we assume we have no options for now, so simply consume them */
694	/* ctx->options */
695	err = dummy_dec_opt_array(xdr, &ctx->options);
696
697	return err;
698}
699
700static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
701{
702	__be32 *p;
703	int err;
704
705	/* cb->initiator_addrtype */
706	p = xdr_reserve_space(xdr, 8);
707	if (!p)
708		return -ENOSPC;
709	p = xdr_encode_hyper(p, cb->initiator_addrtype);
710
711	/* cb->initiator_address */
712	err = gssx_enc_buffer(xdr, &cb->initiator_address);
713	if (err)
714		return err;
715
716	/* cb->acceptor_addrtype */
717	p = xdr_reserve_space(xdr, 8);
718	if (!p)
719		return -ENOSPC;
720	p = xdr_encode_hyper(p, cb->acceptor_addrtype);
721
722	/* cb->acceptor_address */
723	err = gssx_enc_buffer(xdr, &cb->acceptor_address);
724	if (err)
725		return err;
726
727	/* cb->application_data */
728	err = gssx_enc_buffer(xdr, &cb->application_data);
729
730	return err;
731}
732
733void gssx_enc_accept_sec_context(struct rpc_rqst *req,
734				 struct xdr_stream *xdr,
735				 const void *data)
736{
737	const struct gssx_arg_accept_sec_context *arg = data;
738	int err;
739
740	err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
741	if (err)
742		goto done;
743
744	/* arg->context_handle */
745	if (arg->context_handle)
746		err = gssx_enc_ctx(xdr, arg->context_handle);
747	else
748		err = gssx_enc_bool(xdr, 0);
749	if (err)
750		goto done;
751
752	/* arg->cred_handle */
753	if (arg->cred_handle)
754		err = gssx_enc_cred(xdr, arg->cred_handle);
755	else
756		err = gssx_enc_bool(xdr, 0);
757	if (err)
758		goto done;
759
760	/* arg->input_token */
761	err = gssx_enc_in_token(xdr, &arg->input_token);
762	if (err)
763		goto done;
764
765	/* arg->input_cb */
766	if (arg->input_cb)
767		err = gssx_enc_cb(xdr, arg->input_cb);
768	else
769		err = gssx_enc_bool(xdr, 0);
770	if (err)
771		goto done;
772
773	err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
774	if (err)
775		goto done;
776
777	/* leave options empty for now, will add once we have any options
778	 * to pass up at all */
779	/* arg->options */
780	err = dummy_enc_opt_array(xdr, &arg->options);
781
782	xdr_inline_pages(&req->rq_rcv_buf,
783		PAGE_SIZE/2 /* pretty arbitrary */,
784		arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
785done:
786	if (err)
787		dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
788}
789
790int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
791				struct xdr_stream *xdr,
792				void *data)
793{
794	struct gssx_res_accept_sec_context *res = data;
795	u32 value_follows;
796	int err;
797	struct page *scratch;
798
799	scratch = alloc_page(GFP_KERNEL);
800	if (!scratch)
801		return -ENOMEM;
802	xdr_set_scratch_page(xdr, scratch);
803
804	/* res->status */
805	err = gssx_dec_status(xdr, &res->status);
806	if (err)
807		goto out_free;
808
809	/* res->context_handle */
810	err = gssx_dec_bool(xdr, &value_follows);
811	if (err)
812		goto out_free;
813	if (value_follows) {
814		err = gssx_dec_ctx(xdr, res->context_handle);
815		if (err)
816			goto out_free;
817	} else {
818		res->context_handle = NULL;
819	}
820
821	/* res->output_token */
822	err = gssx_dec_bool(xdr, &value_follows);
823	if (err)
824		goto out_free;
825	if (value_follows) {
826		err = gssx_dec_buffer(xdr, res->output_token);
827		if (err)
828			goto out_free;
829	} else {
830		res->output_token = NULL;
831	}
832
833	/* res->delegated_cred_handle */
834	err = gssx_dec_bool(xdr, &value_follows);
835	if (err)
836		goto out_free;
837	if (value_follows) {
838		/* we do not support upcall servers sending this data. */
839		err = -EINVAL;
840		goto out_free;
841	}
842
843	/* res->options */
844	err = gssx_dec_option_array(xdr, &res->options);
845
846out_free:
847	__free_page(scratch);
848	return err;
849}