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