Linux Audio

Check our new training course

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