xref: /linux/net/sunrpc/auth_gss/gss_rpc_xdr.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
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 
gssx_enc_bool(struct xdr_stream * xdr,int v)11 static 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 
gssx_dec_bool(struct xdr_stream * xdr,u32 * v)22 static 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 
gssx_enc_buffer(struct xdr_stream * xdr,const gssx_buffer * buf)33 static 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 
gssx_enc_in_token(struct xdr_stream * xdr,const struct gssp_in_token * in)45 static 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 
gssx_dec_buffer(struct xdr_stream * xdr,gssx_buffer * buf)62 static 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 
gssx_enc_option(struct xdr_stream * xdr,struct gssx_option * opt)95 static 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 
gssx_dec_option(struct xdr_stream * xdr,struct gssx_option * opt)107 static 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 
dummy_enc_opt_array(struct xdr_stream * xdr,const struct gssx_option_array * oa)119 static 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 
dummy_dec_opt_array(struct xdr_stream * xdr,struct gssx_option_array * oa)135 static 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 
get_host_u32(struct xdr_stream * xdr,u32 * res)156 static 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 
gssx_dec_linux_creds(struct xdr_stream * xdr,struct svc_cred * creds)168 static 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;
224 out_free_groups:
225 	groups_free(creds->cr_group_info);
226 	return err;
227 }
228 
gssx_dec_option_array(struct xdr_stream * xdr,struct gssx_option_array * oa)229 static 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 
296 free_creds:
297 	kfree(creds);
298 free_oa:
299 	kfree(oa->data);
300 	oa->data = NULL;
301 	return err;
302 }
303 
gssx_dec_status(struct xdr_stream * xdr,struct gssx_status * status)304 static 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 
gssx_enc_call_ctx(struct xdr_stream * xdr,const struct gssx_call_ctx * ctx)349 static 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 
gssx_dec_name_attr(struct xdr_stream * xdr,struct gssx_name_attr * attr)388 static 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 
dummy_enc_nameattr_array(struct xdr_stream * xdr,struct gssx_name_attr_array * naa)409 static 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 
dummy_dec_nameattr_array(struct xdr_stream * xdr,struct gssx_name_attr_array * naa)425 static 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 
445 static struct xdr_netobj zero_netobj = {};
446 
447 static struct gssx_name_attr_array zero_name_attr_array = {};
448 
449 static struct gssx_option_array zero_option_array = {};
450 
gssx_enc_name(struct xdr_stream * xdr,struct gssx_name * name)451 static 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 
gssx_dec_name(struct xdr_stream * xdr,struct gssx_name * name)492 static 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 
dummy_enc_credel_array(struct xdr_stream * xdr,struct gssx_cred_element_array * cea)533 static 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 
gssx_enc_cred(struct xdr_stream * xdr,struct gssx_cred * cred)549 static 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 
gssx_enc_ctx(struct xdr_stream * xdr,struct gssx_ctx * ctx)575 static 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 
gssx_dec_ctx(struct xdr_stream * xdr,struct gssx_ctx * ctx)638 static 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 
gssx_enc_cb(struct xdr_stream * xdr,struct gssx_cb * cb)700 static 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 
gssx_enc_accept_sec_context(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)733 void 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);
785 done:
786 	if (err)
787 		dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
788 }
789 
gssx_dec_accept_sec_context(struct rpc_rqst * rqstp,struct xdr_stream * xdr,void * data)790 int 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 
846 out_free:
847 	__free_page(scratch);
848 	return err;
849 }
850