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