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
24static 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
35static 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
46static 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
58static 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
75static 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
108static 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
120static 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
132static 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
148static 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
169static 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
181static 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;
236out_free_groups:
237	groups_free(creds->cr_group_info);
238	return err;
239}
240
241static 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
305static 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
350static 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
389static 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
410static 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
426static 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
446static struct xdr_netobj zero_netobj = {};
447
448static struct gssx_name_attr_array zero_name_attr_array = {};
449
450static struct gssx_option_array zero_option_array = {};
451
452static 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
493static 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
534static 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
550static 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
576static 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
639static 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
701static 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
734void 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);
785done:
786	if (err)
787		dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
788}
789
790int 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
845out_free:
846	__free_page(scratch);
847	return err;
848}
849