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 	if (err)
563 		return err;
564 
565 	/* cred->cred_handle_reference */
566 	err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
567 	if (err)
568 		return err;
569 
570 	/* cred->needs_release */
571 	err = gssx_enc_bool(xdr, cred->needs_release);
572 
573 	return err;
574 }
575 
576 static int gssx_enc_ctx(struct xdr_stream *xdr,
577 			struct gssx_ctx *ctx)
578 {
579 	__be32 *p;
580 	int err;
581 
582 	/* ctx->exported_context_token */
583 	err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
584 	if (err)
585 		return err;
586 
587 	/* ctx->state */
588 	err = gssx_enc_buffer(xdr, &ctx->state);
589 	if (err)
590 		return err;
591 
592 	/* ctx->need_release */
593 	err = gssx_enc_bool(xdr, ctx->need_release);
594 	if (err)
595 		return err;
596 
597 	/* ctx->mech */
598 	err = gssx_enc_buffer(xdr, &ctx->mech);
599 	if (err)
600 		return err;
601 
602 	/* ctx->src_name */
603 	err = gssx_enc_name(xdr, &ctx->src_name);
604 	if (err)
605 		return err;
606 
607 	/* ctx->targ_name */
608 	err = gssx_enc_name(xdr, &ctx->targ_name);
609 	if (err)
610 		return err;
611 
612 	/* ctx->lifetime */
613 	p = xdr_reserve_space(xdr, 8+8);
614 	if (!p)
615 		return -ENOSPC;
616 	p = xdr_encode_hyper(p, ctx->lifetime);
617 
618 	/* ctx->ctx_flags */
619 	p = xdr_encode_hyper(p, ctx->ctx_flags);
620 
621 	/* ctx->locally_initiated */
622 	err = gssx_enc_bool(xdr, ctx->locally_initiated);
623 	if (err)
624 		return err;
625 
626 	/* ctx->open */
627 	err = gssx_enc_bool(xdr, ctx->open);
628 	if (err)
629 		return err;
630 
631 	/* leave options empty for now, will add once we have any options
632 	 * to pass up at all */
633 	/* ctx->options */
634 	err = dummy_enc_opt_array(xdr, &ctx->options);
635 
636 	return err;
637 }
638 
639 static int gssx_dec_ctx(struct xdr_stream *xdr,
640 			struct gssx_ctx *ctx)
641 {
642 	__be32 *p;
643 	int err;
644 
645 	/* ctx->exported_context_token */
646 	err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
647 	if (err)
648 		return err;
649 
650 	/* ctx->state */
651 	err = gssx_dec_buffer(xdr, &ctx->state);
652 	if (err)
653 		return err;
654 
655 	/* ctx->need_release */
656 	err = gssx_dec_bool(xdr, &ctx->need_release);
657 	if (err)
658 		return err;
659 
660 	/* ctx->mech */
661 	err = gssx_dec_buffer(xdr, &ctx->mech);
662 	if (err)
663 		return err;
664 
665 	/* ctx->src_name */
666 	err = gssx_dec_name(xdr, &ctx->src_name);
667 	if (err)
668 		return err;
669 
670 	/* ctx->targ_name */
671 	err = gssx_dec_name(xdr, &ctx->targ_name);
672 	if (err)
673 		return err;
674 
675 	/* ctx->lifetime */
676 	p = xdr_inline_decode(xdr, 8+8);
677 	if (unlikely(p == NULL))
678 		return -ENOSPC;
679 	p = xdr_decode_hyper(p, &ctx->lifetime);
680 
681 	/* ctx->ctx_flags */
682 	p = xdr_decode_hyper(p, &ctx->ctx_flags);
683 
684 	/* ctx->locally_initiated */
685 	err = gssx_dec_bool(xdr, &ctx->locally_initiated);
686 	if (err)
687 		return err;
688 
689 	/* ctx->open */
690 	err = gssx_dec_bool(xdr, &ctx->open);
691 	if (err)
692 		return err;
693 
694 	/* we assume we have no options for now, so simply consume them */
695 	/* ctx->options */
696 	err = dummy_dec_opt_array(xdr, &ctx->options);
697 
698 	return err;
699 }
700 
701 static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
702 {
703 	__be32 *p;
704 	int err;
705 
706 	/* cb->initiator_addrtype */
707 	p = xdr_reserve_space(xdr, 8);
708 	if (!p)
709 		return -ENOSPC;
710 	p = xdr_encode_hyper(p, cb->initiator_addrtype);
711 
712 	/* cb->initiator_address */
713 	err = gssx_enc_buffer(xdr, &cb->initiator_address);
714 	if (err)
715 		return err;
716 
717 	/* cb->acceptor_addrtype */
718 	p = xdr_reserve_space(xdr, 8);
719 	if (!p)
720 		return -ENOSPC;
721 	p = xdr_encode_hyper(p, cb->acceptor_addrtype);
722 
723 	/* cb->acceptor_address */
724 	err = gssx_enc_buffer(xdr, &cb->acceptor_address);
725 	if (err)
726 		return err;
727 
728 	/* cb->application_data */
729 	err = gssx_enc_buffer(xdr, &cb->application_data);
730 
731 	return err;
732 }
733 
734 void gssx_enc_accept_sec_context(struct rpc_rqst *req,
735 				 struct xdr_stream *xdr,
736 				 struct gssx_arg_accept_sec_context *arg)
737 {
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);
785 done:
786 	if (err)
787 		dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
788 }
789 
790 int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
791 				struct xdr_stream *xdr,
792 				struct gssx_res_accept_sec_context *res)
793 {
794 	u32 value_follows;
795 	int err;
796 	struct page *scratch;
797 
798 	scratch = alloc_page(GFP_KERNEL);
799 	if (!scratch)
800 		return -ENOMEM;
801 	xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE);
802 
803 	/* res->status */
804 	err = gssx_dec_status(xdr, &res->status);
805 	if (err)
806 		goto out_free;
807 
808 	/* res->context_handle */
809 	err = gssx_dec_bool(xdr, &value_follows);
810 	if (err)
811 		goto out_free;
812 	if (value_follows) {
813 		err = gssx_dec_ctx(xdr, res->context_handle);
814 		if (err)
815 			goto out_free;
816 	} else {
817 		res->context_handle = NULL;
818 	}
819 
820 	/* res->output_token */
821 	err = gssx_dec_bool(xdr, &value_follows);
822 	if (err)
823 		goto out_free;
824 	if (value_follows) {
825 		err = gssx_dec_buffer(xdr, res->output_token);
826 		if (err)
827 			goto out_free;
828 	} else {
829 		res->output_token = NULL;
830 	}
831 
832 	/* res->delegated_cred_handle */
833 	err = gssx_dec_bool(xdr, &value_follows);
834 	if (err)
835 		goto out_free;
836 	if (value_follows) {
837 		/* we do not support upcall servers sending this data. */
838 		err = -EINVAL;
839 		goto out_free;
840 	}
841 
842 	/* res->options */
843 	err = gssx_dec_option_array(xdr, &res->options);
844 
845 out_free:
846 	__free_page(scratch);
847 	return err;
848 }
849