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