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 
24 static 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 
35 static 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 
46 static int gssx_enc_buffer(struct xdr_stream *xdr,
47 			   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 
58 static int gssx_enc_in_token(struct xdr_stream *xdr,
59 			     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 
75 static 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 
108 static 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 
120 static 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 
132 static int dummy_enc_opt_array(struct xdr_stream *xdr,
133 				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 
148 static 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 
169 static 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 
181 static 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 		GROUP_AT(creds->cr_group_info, i) = kgid;
233 	}
234 
235 	return 0;
236 out_free_groups:
237 	groups_free(creds->cr_group_info);
238 	return err;
239 }
240 
241 static int gssx_dec_option_array(struct xdr_stream *xdr,
242 				 struct gssx_option_array *oa)
243 {
244 	struct svc_cred *creds;
245 	u32 count, i;
246 	__be32 *p;
247 	int err;
248 
249 	p = xdr_inline_decode(xdr, 4);
250 	if (unlikely(p == NULL))
251 		return -ENOSPC;
252 	count = be32_to_cpup(p++);
253 	if (!count)
254 		return 0;
255 
256 	/* we recognize only 1 currently: CREDS_VALUE */
257 	oa->count = 1;
258 
259 	oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL);
260 	if (!oa->data)
261 		return -ENOMEM;
262 
263 	creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL);
264 	if (!creds) {
265 		kfree(oa->data);
266 		return -ENOMEM;
267 	}
268 
269 	oa->data[0].option.data = CREDS_VALUE;
270 	oa->data[0].option.len = sizeof(CREDS_VALUE);
271 	oa->data[0].value.data = (void *)creds;
272 	oa->data[0].value.len = 0;
273 
274 	for (i = 0; i < count; i++) {
275 		gssx_buffer dummy = { 0, NULL };
276 		u32 length;
277 
278 		/* option buffer */
279 		p = xdr_inline_decode(xdr, 4);
280 		if (unlikely(p == NULL))
281 			return -ENOSPC;
282 
283 		length = be32_to_cpup(p);
284 		p = xdr_inline_decode(xdr, length);
285 		if (unlikely(p == NULL))
286 			return -ENOSPC;
287 
288 		if (length == sizeof(CREDS_VALUE) &&
289 		    memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) {
290 			/* We have creds here. parse them */
291 			err = gssx_dec_linux_creds(xdr, creds);
292 			if (err)
293 				return err;
294 			oa->data[0].value.len = 1; /* presence */
295 		} else {
296 			/* consume uninteresting buffer */
297 			err = gssx_dec_buffer(xdr, &dummy);
298 			if (err)
299 				return err;
300 		}
301 	}
302 	return 0;
303 }
304 
305 static int gssx_dec_status(struct xdr_stream *xdr,
306 			   struct gssx_status *status)
307 {
308 	__be32 *p;
309 	int err;
310 
311 	/* status->major_status */
312 	p = xdr_inline_decode(xdr, 8);
313 	if (unlikely(p == NULL))
314 		return -ENOSPC;
315 	p = xdr_decode_hyper(p, &status->major_status);
316 
317 	/* status->mech */
318 	err = gssx_dec_buffer(xdr, &status->mech);
319 	if (err)
320 		return err;
321 
322 	/* status->minor_status */
323 	p = xdr_inline_decode(xdr, 8);
324 	if (unlikely(p == NULL))
325 		return -ENOSPC;
326 	p = xdr_decode_hyper(p, &status->minor_status);
327 
328 	/* status->major_status_string */
329 	err = gssx_dec_buffer(xdr, &status->major_status_string);
330 	if (err)
331 		return err;
332 
333 	/* status->minor_status_string */
334 	err = gssx_dec_buffer(xdr, &status->minor_status_string);
335 	if (err)
336 		return err;
337 
338 	/* status->server_ctx */
339 	err = gssx_dec_buffer(xdr, &status->server_ctx);
340 	if (err)
341 		return err;
342 
343 	/* we assume we have no options for now, so simply consume them */
344 	/* status->options */
345 	err = dummy_dec_opt_array(xdr, &status->options);
346 
347 	return err;
348 }
349 
350 static int gssx_enc_call_ctx(struct xdr_stream *xdr,
351 			     struct gssx_call_ctx *ctx)
352 {
353 	struct gssx_option opt;
354 	__be32 *p;
355 	int err;
356 
357 	/* ctx->locale */
358 	err = gssx_enc_buffer(xdr, &ctx->locale);
359 	if (err)
360 		return err;
361 
362 	/* ctx->server_ctx */
363 	err = gssx_enc_buffer(xdr, &ctx->server_ctx);
364 	if (err)
365 		return err;
366 
367 	/* we always want to ask for lucid contexts */
368 	/* ctx->options */
369 	p = xdr_reserve_space(xdr, 4);
370 	*p = cpu_to_be32(2);
371 
372 	/* we want a lucid_v1 context */
373 	opt.option.data = LUCID_OPTION;
374 	opt.option.len = sizeof(LUCID_OPTION);
375 	opt.value.data = LUCID_VALUE;
376 	opt.value.len = sizeof(LUCID_VALUE);
377 	err = gssx_enc_option(xdr, &opt);
378 
379 	/* ..and user creds */
380 	opt.option.data = CREDS_OPTION;
381 	opt.option.len = sizeof(CREDS_OPTION);
382 	opt.value.data = CREDS_VALUE;
383 	opt.value.len = sizeof(CREDS_VALUE);
384 	err = gssx_enc_option(xdr, &opt);
385 
386 	return err;
387 }
388 
389 static int gssx_dec_name_attr(struct xdr_stream *xdr,
390 			     struct gssx_name_attr *attr)
391 {
392 	int err;
393 
394 	/* attr->attr */
395 	err = gssx_dec_buffer(xdr, &attr->attr);
396 	if (err)
397 		return err;
398 
399 	/* attr->value */
400 	err = gssx_dec_buffer(xdr, &attr->value);
401 	if (err)
402 		return err;
403 
404 	/* attr->extensions */
405 	err = dummy_dec_opt_array(xdr, &attr->extensions);
406 
407 	return err;
408 }
409 
410 static int dummy_enc_nameattr_array(struct xdr_stream *xdr,
411 				    struct gssx_name_attr_array *naa)
412 {
413 	__be32 *p;
414 
415 	if (naa->count != 0)
416 		return -EINVAL;
417 
418 	p = xdr_reserve_space(xdr, 4);
419 	if (!p)
420 		return -ENOSPC;
421 	*p = 0;
422 
423 	return 0;
424 }
425 
426 static int dummy_dec_nameattr_array(struct xdr_stream *xdr,
427 				    struct gssx_name_attr_array *naa)
428 {
429 	struct gssx_name_attr dummy = { .attr = {.len = 0} };
430 	u32 count, i;
431 	__be32 *p;
432 
433 	p = xdr_inline_decode(xdr, 4);
434 	if (unlikely(p == NULL))
435 		return -ENOSPC;
436 	count = be32_to_cpup(p++);
437 	for (i = 0; i < count; i++) {
438 		gssx_dec_name_attr(xdr, &dummy);
439 	}
440 
441 	naa->count = 0;
442 	naa->data = NULL;
443 	return 0;
444 }
445 
446 static struct xdr_netobj zero_netobj = {};
447 
448 static struct gssx_name_attr_array zero_name_attr_array = {};
449 
450 static struct gssx_option_array zero_option_array = {};
451 
452 static int gssx_enc_name(struct xdr_stream *xdr,
453 			 struct gssx_name *name)
454 {
455 	int err;
456 
457 	/* name->display_name */
458 	err = gssx_enc_buffer(xdr, &name->display_name);
459 	if (err)
460 		return err;
461 
462 	/* name->name_type */
463 	err = gssx_enc_buffer(xdr, &zero_netobj);
464 	if (err)
465 		return err;
466 
467 	/* name->exported_name */
468 	err = gssx_enc_buffer(xdr, &zero_netobj);
469 	if (err)
470 		return err;
471 
472 	/* name->exported_composite_name */
473 	err = gssx_enc_buffer(xdr, &zero_netobj);
474 	if (err)
475 		return err;
476 
477 	/* leave name_attributes empty for now, will add once we have any
478 	 * to pass up at all */
479 	/* name->name_attributes */
480 	err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array);
481 	if (err)
482 		return err;
483 
484 	/* leave options empty for now, will add once we have any options
485 	 * to pass up at all */
486 	/* name->extensions */
487 	err = dummy_enc_opt_array(xdr, &zero_option_array);
488 
489 	return err;
490 }
491 
492 
493 static int gssx_dec_name(struct xdr_stream *xdr,
494 			 struct gssx_name *name)
495 {
496 	struct xdr_netobj dummy_netobj = { .len = 0 };
497 	struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 };
498 	struct gssx_option_array dummy_option_array = { .count = 0 };
499 	int err;
500 
501 	/* name->display_name */
502 	err = gssx_dec_buffer(xdr, &name->display_name);
503 	if (err)
504 		return err;
505 
506 	/* name->name_type */
507 	err = gssx_dec_buffer(xdr, &dummy_netobj);
508 	if (err)
509 		return err;
510 
511 	/* name->exported_name */
512 	err = gssx_dec_buffer(xdr, &dummy_netobj);
513 	if (err)
514 		return err;
515 
516 	/* name->exported_composite_name */
517 	err = gssx_dec_buffer(xdr, &dummy_netobj);
518 	if (err)
519 		return err;
520 
521 	/* we assume we have no attributes for now, so simply consume them */
522 	/* name->name_attributes */
523 	err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
524 	if (err)
525 		return err;
526 
527 	/* we assume we have no options for now, so simply consume them */
528 	/* name->extensions */
529 	err = dummy_dec_opt_array(xdr, &dummy_option_array);
530 
531 	return err;
532 }
533 
534 static int dummy_enc_credel_array(struct xdr_stream *xdr,
535 				  struct gssx_cred_element_array *cea)
536 {
537 	__be32 *p;
538 
539 	if (cea->count != 0)
540 		return -EINVAL;
541 
542 	p = xdr_reserve_space(xdr, 4);
543 	if (!p)
544 		return -ENOSPC;
545 	*p = 0;
546 
547 	return 0;
548 }
549 
550 static int gssx_enc_cred(struct xdr_stream *xdr,
551 			 struct gssx_cred *cred)
552 {
553 	int err;
554 
555 	/* cred->desired_name */
556 	err = gssx_enc_name(xdr, &cred->desired_name);
557 	if (err)
558 		return err;
559 
560 	/* cred->elements */
561 	err = dummy_enc_credel_array(xdr, &cred->elements);
562 
563 	/* cred->cred_handle_reference */
564 	err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
565 	if (err)
566 		return err;
567 
568 	/* cred->needs_release */
569 	err = gssx_enc_bool(xdr, cred->needs_release);
570 
571 	return err;
572 }
573 
574 static int gssx_enc_ctx(struct xdr_stream *xdr,
575 			struct gssx_ctx *ctx)
576 {
577 	__be32 *p;
578 	int err;
579 
580 	/* ctx->exported_context_token */
581 	err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
582 	if (err)
583 		return err;
584 
585 	/* ctx->state */
586 	err = gssx_enc_buffer(xdr, &ctx->state);
587 	if (err)
588 		return err;
589 
590 	/* ctx->need_release */
591 	err = gssx_enc_bool(xdr, ctx->need_release);
592 	if (err)
593 		return err;
594 
595 	/* ctx->mech */
596 	err = gssx_enc_buffer(xdr, &ctx->mech);
597 	if (err)
598 		return err;
599 
600 	/* ctx->src_name */
601 	err = gssx_enc_name(xdr, &ctx->src_name);
602 	if (err)
603 		return err;
604 
605 	/* ctx->targ_name */
606 	err = gssx_enc_name(xdr, &ctx->targ_name);
607 	if (err)
608 		return err;
609 
610 	/* ctx->lifetime */
611 	p = xdr_reserve_space(xdr, 8+8);
612 	if (!p)
613 		return -ENOSPC;
614 	p = xdr_encode_hyper(p, ctx->lifetime);
615 
616 	/* ctx->ctx_flags */
617 	p = xdr_encode_hyper(p, ctx->ctx_flags);
618 
619 	/* ctx->locally_initiated */
620 	err = gssx_enc_bool(xdr, ctx->locally_initiated);
621 	if (err)
622 		return err;
623 
624 	/* ctx->open */
625 	err = gssx_enc_bool(xdr, ctx->open);
626 	if (err)
627 		return err;
628 
629 	/* leave options empty for now, will add once we have any options
630 	 * to pass up at all */
631 	/* ctx->options */
632 	err = dummy_enc_opt_array(xdr, &ctx->options);
633 
634 	return err;
635 }
636 
637 static int gssx_dec_ctx(struct xdr_stream *xdr,
638 			struct gssx_ctx *ctx)
639 {
640 	__be32 *p;
641 	int err;
642 
643 	/* ctx->exported_context_token */
644 	err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
645 	if (err)
646 		return err;
647 
648 	/* ctx->state */
649 	err = gssx_dec_buffer(xdr, &ctx->state);
650 	if (err)
651 		return err;
652 
653 	/* ctx->need_release */
654 	err = gssx_dec_bool(xdr, &ctx->need_release);
655 	if (err)
656 		return err;
657 
658 	/* ctx->mech */
659 	err = gssx_dec_buffer(xdr, &ctx->mech);
660 	if (err)
661 		return err;
662 
663 	/* ctx->src_name */
664 	err = gssx_dec_name(xdr, &ctx->src_name);
665 	if (err)
666 		return err;
667 
668 	/* ctx->targ_name */
669 	err = gssx_dec_name(xdr, &ctx->targ_name);
670 	if (err)
671 		return err;
672 
673 	/* ctx->lifetime */
674 	p = xdr_inline_decode(xdr, 8+8);
675 	if (unlikely(p == NULL))
676 		return -ENOSPC;
677 	p = xdr_decode_hyper(p, &ctx->lifetime);
678 
679 	/* ctx->ctx_flags */
680 	p = xdr_decode_hyper(p, &ctx->ctx_flags);
681 
682 	/* ctx->locally_initiated */
683 	err = gssx_dec_bool(xdr, &ctx->locally_initiated);
684 	if (err)
685 		return err;
686 
687 	/* ctx->open */
688 	err = gssx_dec_bool(xdr, &ctx->open);
689 	if (err)
690 		return err;
691 
692 	/* we assume we have no options for now, so simply consume them */
693 	/* ctx->options */
694 	err = dummy_dec_opt_array(xdr, &ctx->options);
695 
696 	return err;
697 }
698 
699 static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
700 {
701 	__be32 *p;
702 	int err;
703 
704 	/* cb->initiator_addrtype */
705 	p = xdr_reserve_space(xdr, 8);
706 	if (!p)
707 		return -ENOSPC;
708 	p = xdr_encode_hyper(p, cb->initiator_addrtype);
709 
710 	/* cb->initiator_address */
711 	err = gssx_enc_buffer(xdr, &cb->initiator_address);
712 	if (err)
713 		return err;
714 
715 	/* cb->acceptor_addrtype */
716 	p = xdr_reserve_space(xdr, 8);
717 	if (!p)
718 		return -ENOSPC;
719 	p = xdr_encode_hyper(p, cb->acceptor_addrtype);
720 
721 	/* cb->acceptor_address */
722 	err = gssx_enc_buffer(xdr, &cb->acceptor_address);
723 	if (err)
724 		return err;
725 
726 	/* cb->application_data */
727 	err = gssx_enc_buffer(xdr, &cb->application_data);
728 
729 	return err;
730 }
731 
732 void gssx_enc_accept_sec_context(struct rpc_rqst *req,
733 				 struct xdr_stream *xdr,
734 				 struct gssx_arg_accept_sec_context *arg)
735 {
736 	int err;
737 
738 	err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
739 	if (err)
740 		goto done;
741 
742 	/* arg->context_handle */
743 	if (arg->context_handle) {
744 		err = gssx_enc_ctx(xdr, arg->context_handle);
745 		if (err)
746 			goto done;
747 	} else {
748 		err = gssx_enc_bool(xdr, 0);
749 	}
750 
751 	/* arg->cred_handle */
752 	if (arg->cred_handle) {
753 		err = gssx_enc_cred(xdr, arg->cred_handle);
754 		if (err)
755 			goto done;
756 	} else {
757 		err = gssx_enc_bool(xdr, 0);
758 	}
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 		if (err)
769 			goto done;
770 	} else {
771 		err = gssx_enc_bool(xdr, 0);
772 	}
773 
774 	err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
775 	if (err)
776 		goto done;
777 
778 	/* leave options empty for now, will add once we have any options
779 	 * to pass up at all */
780 	/* arg->options */
781 	err = dummy_enc_opt_array(xdr, &arg->options);
782 
783 done:
784 	if (err)
785 		dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
786 }
787 
788 int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
789 				struct xdr_stream *xdr,
790 				struct gssx_res_accept_sec_context *res)
791 {
792 	u32 value_follows;
793 	int err;
794 
795 	/* res->status */
796 	err = gssx_dec_status(xdr, &res->status);
797 	if (err)
798 		return err;
799 
800 	/* res->context_handle */
801 	err = gssx_dec_bool(xdr, &value_follows);
802 	if (err)
803 		return err;
804 	if (value_follows) {
805 		err = gssx_dec_ctx(xdr, res->context_handle);
806 		if (err)
807 			return err;
808 	} else {
809 		res->context_handle = NULL;
810 	}
811 
812 	/* res->output_token */
813 	err = gssx_dec_bool(xdr, &value_follows);
814 	if (err)
815 		return err;
816 	if (value_follows) {
817 		err = gssx_dec_buffer(xdr, res->output_token);
818 		if (err)
819 			return err;
820 	} else {
821 		res->output_token = NULL;
822 	}
823 
824 	/* res->delegated_cred_handle */
825 	err = gssx_dec_bool(xdr, &value_follows);
826 	if (err)
827 		return err;
828 	if (value_follows) {
829 		/* we do not support upcall servers sending this data. */
830 		return -EINVAL;
831 	}
832 
833 	/* res->options */
834 	err = gssx_dec_option_array(xdr, &res->options);
835 
836 	return err;
837 }
838