2 * GSS Proxy upcall module
4 * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
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.
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.
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.
21 #include <linux/sunrpc/svcauth.h>
22 #include "gss_rpc_xdr.h"
24 static int gssx_enc_bool(struct xdr_stream
*xdr
, int v
)
28 p
= xdr_reserve_space(xdr
, 4);
29 if (unlikely(p
== NULL
))
31 *p
= v
? xdr_one
: xdr_zero
;
35 static int gssx_dec_bool(struct xdr_stream
*xdr
, u32
*v
)
39 p
= xdr_inline_decode(xdr
, 4);
40 if (unlikely(p
== NULL
))
46 static int gssx_enc_buffer(struct xdr_stream
*xdr
,
51 p
= xdr_reserve_space(xdr
, sizeof(u32
) + buf
->len
);
54 xdr_encode_opaque(p
, buf
->data
, buf
->len
);
58 static int gssx_enc_in_token(struct xdr_stream
*xdr
,
59 struct gssp_in_token
*in
)
63 p
= xdr_reserve_space(xdr
, 4);
66 *p
= cpu_to_be32(in
->page_len
);
68 /* all we need to do is to write pages */
69 xdr_write_pages(xdr
, in
->pages
, in
->page_base
, in
->page_len
);
75 static int gssx_dec_buffer(struct xdr_stream
*xdr
,
81 p
= xdr_inline_decode(xdr
, 4);
82 if (unlikely(p
== NULL
))
85 length
= be32_to_cpup(p
);
86 p
= xdr_inline_decode(xdr
, length
);
87 if (unlikely(p
== NULL
))
91 /* we intentionally are not interested in this buffer */
94 if (length
> buf
->len
)
98 buf
->data
= kmemdup(p
, length
, GFP_KERNEL
);
102 memcpy(buf
->data
, p
, length
);
108 static int gssx_enc_option(struct xdr_stream
*xdr
,
109 struct gssx_option
*opt
)
113 err
= gssx_enc_buffer(xdr
, &opt
->option
);
116 err
= gssx_enc_buffer(xdr
, &opt
->value
);
120 static int gssx_dec_option(struct xdr_stream
*xdr
,
121 struct gssx_option
*opt
)
125 err
= gssx_dec_buffer(xdr
, &opt
->option
);
128 err
= gssx_dec_buffer(xdr
, &opt
->value
);
132 static int dummy_enc_opt_array(struct xdr_stream
*xdr
,
133 struct gssx_option_array
*oa
)
140 p
= xdr_reserve_space(xdr
, 4);
148 static int dummy_dec_opt_array(struct xdr_stream
*xdr
,
149 struct gssx_option_array
*oa
)
151 struct gssx_option dummy
;
155 p
= xdr_inline_decode(xdr
, 4);
156 if (unlikely(p
== NULL
))
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
);
169 static int get_s32(void **p
, void *max
, s32
*res
)
172 void *next
= (void *)((char *)base
+ sizeof(s32
));
173 if (unlikely(next
> max
|| next
< base
))
175 memcpy(res
, base
, sizeof(s32
));
180 static int gssx_dec_linux_creds(struct xdr_stream
*xdr
,
181 struct svc_cred
*creds
)
189 p
= xdr_inline_decode(xdr
, 4);
190 if (unlikely(p
== NULL
))
193 length
= be32_to_cpup(p
);
195 /* FIXME: we do not want to use the scratch buffer for this one
196 * may need to use functions that allows us to access an io vector
198 p
= xdr_inline_decode(xdr
, length
);
199 if (unlikely(p
== NULL
))
206 err
= get_s32(&q
, end
, &tmp
);
209 creds
->cr_uid
= make_kuid(&init_user_ns
, tmp
);
212 err
= get_s32(&q
, end
, &tmp
);
215 creds
->cr_gid
= make_kgid(&init_user_ns
, tmp
);
217 /* number of additional gid's */
218 err
= get_s32(&q
, end
, &tmp
);
222 creds
->cr_group_info
= groups_alloc(N
);
223 if (creds
->cr_group_info
== NULL
)
227 for (i
= 0; i
< N
; i
++) {
229 err
= get_s32(&q
, end
, &tmp
);
231 goto out_free_groups
;
233 kgid
= make_kgid(&init_user_ns
, tmp
);
234 if (!gid_valid(kgid
))
235 goto out_free_groups
;
236 GROUP_AT(creds
->cr_group_info
, i
) = kgid
;
241 groups_free(creds
->cr_group_info
);
245 static int gssx_dec_option_array(struct xdr_stream
*xdr
,
246 struct gssx_option_array
*oa
)
248 struct svc_cred
*creds
;
253 p
= xdr_inline_decode(xdr
, 4);
254 if (unlikely(p
== NULL
))
256 count
= be32_to_cpup(p
++);
260 /* we recognize only 1 currently: CREDS_VALUE */
263 oa
->data
= kmalloc(sizeof(struct gssx_option
), GFP_KERNEL
);
267 creds
= kmalloc(sizeof(struct svc_cred
), GFP_KERNEL
);
273 oa
->data
[0].option
.data
= CREDS_VALUE
;
274 oa
->data
[0].option
.len
= sizeof(CREDS_VALUE
);
275 oa
->data
[0].value
.data
= (void *)creds
;
276 oa
->data
[0].value
.len
= 0;
278 for (i
= 0; i
< count
; i
++) {
279 gssx_buffer dummy
= { 0, NULL
};
283 p
= xdr_inline_decode(xdr
, 4);
284 if (unlikely(p
== NULL
))
287 length
= be32_to_cpup(p
);
288 p
= xdr_inline_decode(xdr
, length
);
289 if (unlikely(p
== NULL
))
292 if (length
== sizeof(CREDS_VALUE
) &&
293 memcmp(p
, CREDS_VALUE
, sizeof(CREDS_VALUE
)) == 0) {
294 /* We have creds here. parse them */
295 err
= gssx_dec_linux_creds(xdr
, creds
);
298 oa
->data
[0].value
.len
= 1; /* presence */
300 /* consume uninteresting buffer */
301 err
= gssx_dec_buffer(xdr
, &dummy
);
309 static int gssx_dec_status(struct xdr_stream
*xdr
,
310 struct gssx_status
*status
)
315 /* status->major_status */
316 p
= xdr_inline_decode(xdr
, 8);
317 if (unlikely(p
== NULL
))
319 p
= xdr_decode_hyper(p
, &status
->major_status
);
322 err
= gssx_dec_buffer(xdr
, &status
->mech
);
326 /* status->minor_status */
327 p
= xdr_inline_decode(xdr
, 8);
328 if (unlikely(p
== NULL
))
330 p
= xdr_decode_hyper(p
, &status
->minor_status
);
332 /* status->major_status_string */
333 err
= gssx_dec_buffer(xdr
, &status
->major_status_string
);
337 /* status->minor_status_string */
338 err
= gssx_dec_buffer(xdr
, &status
->minor_status_string
);
342 /* status->server_ctx */
343 err
= gssx_dec_buffer(xdr
, &status
->server_ctx
);
347 /* we assume we have no options for now, so simply consume them */
348 /* status->options */
349 err
= dummy_dec_opt_array(xdr
, &status
->options
);
354 static int gssx_enc_call_ctx(struct xdr_stream
*xdr
,
355 struct gssx_call_ctx
*ctx
)
357 struct gssx_option opt
;
362 err
= gssx_enc_buffer(xdr
, &ctx
->locale
);
366 /* ctx->server_ctx */
367 err
= gssx_enc_buffer(xdr
, &ctx
->server_ctx
);
371 /* we always want to ask for lucid contexts */
373 p
= xdr_reserve_space(xdr
, 4);
376 /* we want a lucid_v1 context */
377 opt
.option
.data
= LUCID_OPTION
;
378 opt
.option
.len
= sizeof(LUCID_OPTION
);
379 opt
.value
.data
= LUCID_VALUE
;
380 opt
.value
.len
= sizeof(LUCID_VALUE
);
381 err
= gssx_enc_option(xdr
, &opt
);
383 /* ..and user creds */
384 opt
.option
.data
= CREDS_OPTION
;
385 opt
.option
.len
= sizeof(CREDS_OPTION
);
386 opt
.value
.data
= CREDS_VALUE
;
387 opt
.value
.len
= sizeof(CREDS_VALUE
);
388 err
= gssx_enc_option(xdr
, &opt
);
393 static int gssx_dec_name_attr(struct xdr_stream
*xdr
,
394 struct gssx_name_attr
*attr
)
399 err
= gssx_dec_buffer(xdr
, &attr
->attr
);
404 err
= gssx_dec_buffer(xdr
, &attr
->value
);
408 /* attr->extensions */
409 err
= dummy_dec_opt_array(xdr
, &attr
->extensions
);
414 static int dummy_enc_nameattr_array(struct xdr_stream
*xdr
,
415 struct gssx_name_attr_array
*naa
)
422 p
= xdr_reserve_space(xdr
, 4);
430 static int dummy_dec_nameattr_array(struct xdr_stream
*xdr
,
431 struct gssx_name_attr_array
*naa
)
433 struct gssx_name_attr dummy
= { .attr
= {.len
= 0} };
437 p
= xdr_inline_decode(xdr
, 4);
438 if (unlikely(p
== NULL
))
440 count
= be32_to_cpup(p
++);
441 for (i
= 0; i
< count
; i
++) {
442 gssx_dec_name_attr(xdr
, &dummy
);
450 static struct xdr_netobj zero_netobj
= {};
452 static struct gssx_name_attr_array zero_name_attr_array
= {};
454 static struct gssx_option_array zero_option_array
= {};
456 static int gssx_enc_name(struct xdr_stream
*xdr
,
457 struct gssx_name
*name
)
461 /* name->display_name */
462 err
= gssx_enc_buffer(xdr
, &name
->display_name
);
466 /* name->name_type */
467 err
= gssx_enc_buffer(xdr
, &zero_netobj
);
471 /* name->exported_name */
472 err
= gssx_enc_buffer(xdr
, &zero_netobj
);
476 /* name->exported_composite_name */
477 err
= gssx_enc_buffer(xdr
, &zero_netobj
);
481 /* leave name_attributes empty for now, will add once we have any
482 * to pass up at all */
483 /* name->name_attributes */
484 err
= dummy_enc_nameattr_array(xdr
, &zero_name_attr_array
);
488 /* leave options empty for now, will add once we have any options
489 * to pass up at all */
490 /* name->extensions */
491 err
= dummy_enc_opt_array(xdr
, &zero_option_array
);
497 static int gssx_dec_name(struct xdr_stream
*xdr
,
498 struct gssx_name
*name
)
500 struct xdr_netobj dummy_netobj
= { .len
= 0 };
501 struct gssx_name_attr_array dummy_name_attr_array
= { .count
= 0 };
502 struct gssx_option_array dummy_option_array
= { .count
= 0 };
505 /* name->display_name */
506 err
= gssx_dec_buffer(xdr
, &name
->display_name
);
510 /* name->name_type */
511 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
515 /* name->exported_name */
516 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
520 /* name->exported_composite_name */
521 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
525 /* we assume we have no attributes for now, so simply consume them */
526 /* name->name_attributes */
527 err
= dummy_dec_nameattr_array(xdr
, &dummy_name_attr_array
);
531 /* we assume we have no options for now, so simply consume them */
532 /* name->extensions */
533 err
= dummy_dec_opt_array(xdr
, &dummy_option_array
);
538 static int dummy_enc_credel_array(struct xdr_stream
*xdr
,
539 struct gssx_cred_element_array
*cea
)
546 p
= xdr_reserve_space(xdr
, 4);
554 static int gssx_enc_cred(struct xdr_stream
*xdr
,
555 struct gssx_cred
*cred
)
559 /* cred->desired_name */
560 err
= gssx_enc_name(xdr
, &cred
->desired_name
);
565 err
= dummy_enc_credel_array(xdr
, &cred
->elements
);
567 /* cred->cred_handle_reference */
568 err
= gssx_enc_buffer(xdr
, &cred
->cred_handle_reference
);
572 /* cred->needs_release */
573 err
= gssx_enc_bool(xdr
, cred
->needs_release
);
578 static int gssx_enc_ctx(struct xdr_stream
*xdr
,
579 struct gssx_ctx
*ctx
)
584 /* ctx->exported_context_token */
585 err
= gssx_enc_buffer(xdr
, &ctx
->exported_context_token
);
590 err
= gssx_enc_buffer(xdr
, &ctx
->state
);
594 /* ctx->need_release */
595 err
= gssx_enc_bool(xdr
, ctx
->need_release
);
600 err
= gssx_enc_buffer(xdr
, &ctx
->mech
);
605 err
= gssx_enc_name(xdr
, &ctx
->src_name
);
610 err
= gssx_enc_name(xdr
, &ctx
->targ_name
);
615 p
= xdr_reserve_space(xdr
, 8+8);
618 p
= xdr_encode_hyper(p
, ctx
->lifetime
);
621 p
= xdr_encode_hyper(p
, ctx
->ctx_flags
);
623 /* ctx->locally_initiated */
624 err
= gssx_enc_bool(xdr
, ctx
->locally_initiated
);
629 err
= gssx_enc_bool(xdr
, ctx
->open
);
633 /* leave options empty for now, will add once we have any options
634 * to pass up at all */
636 err
= dummy_enc_opt_array(xdr
, &ctx
->options
);
641 static int gssx_dec_ctx(struct xdr_stream
*xdr
,
642 struct gssx_ctx
*ctx
)
647 /* ctx->exported_context_token */
648 err
= gssx_dec_buffer(xdr
, &ctx
->exported_context_token
);
653 err
= gssx_dec_buffer(xdr
, &ctx
->state
);
657 /* ctx->need_release */
658 err
= gssx_dec_bool(xdr
, &ctx
->need_release
);
663 err
= gssx_dec_buffer(xdr
, &ctx
->mech
);
668 err
= gssx_dec_name(xdr
, &ctx
->src_name
);
673 err
= gssx_dec_name(xdr
, &ctx
->targ_name
);
678 p
= xdr_inline_decode(xdr
, 8+8);
679 if (unlikely(p
== NULL
))
681 p
= xdr_decode_hyper(p
, &ctx
->lifetime
);
684 p
= xdr_decode_hyper(p
, &ctx
->ctx_flags
);
686 /* ctx->locally_initiated */
687 err
= gssx_dec_bool(xdr
, &ctx
->locally_initiated
);
692 err
= gssx_dec_bool(xdr
, &ctx
->open
);
696 /* we assume we have no options for now, so simply consume them */
698 err
= dummy_dec_opt_array(xdr
, &ctx
->options
);
703 static int gssx_enc_cb(struct xdr_stream
*xdr
, struct gssx_cb
*cb
)
708 /* cb->initiator_addrtype */
709 p
= xdr_reserve_space(xdr
, 8);
712 p
= xdr_encode_hyper(p
, cb
->initiator_addrtype
);
714 /* cb->initiator_address */
715 err
= gssx_enc_buffer(xdr
, &cb
->initiator_address
);
719 /* cb->acceptor_addrtype */
720 p
= xdr_reserve_space(xdr
, 8);
723 p
= xdr_encode_hyper(p
, cb
->acceptor_addrtype
);
725 /* cb->acceptor_address */
726 err
= gssx_enc_buffer(xdr
, &cb
->acceptor_address
);
730 /* cb->application_data */
731 err
= gssx_enc_buffer(xdr
, &cb
->application_data
);
736 void gssx_enc_accept_sec_context(struct rpc_rqst
*req
,
737 struct xdr_stream
*xdr
,
738 struct gssx_arg_accept_sec_context
*arg
)
742 err
= gssx_enc_call_ctx(xdr
, &arg
->call_ctx
);
746 /* arg->context_handle */
747 if (arg
->context_handle
) {
748 err
= gssx_enc_ctx(xdr
, arg
->context_handle
);
752 err
= gssx_enc_bool(xdr
, 0);
755 /* arg->cred_handle */
756 if (arg
->cred_handle
) {
757 err
= gssx_enc_cred(xdr
, arg
->cred_handle
);
761 err
= gssx_enc_bool(xdr
, 0);
764 /* arg->input_token */
765 err
= gssx_enc_in_token(xdr
, &arg
->input_token
);
771 err
= gssx_enc_cb(xdr
, arg
->input_cb
);
775 err
= gssx_enc_bool(xdr
, 0);
778 err
= gssx_enc_bool(xdr
, arg
->ret_deleg_cred
);
782 /* leave options empty for now, will add once we have any options
783 * to pass up at all */
785 err
= dummy_enc_opt_array(xdr
, &arg
->options
);
789 dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err
);
792 int gssx_dec_accept_sec_context(struct rpc_rqst
*rqstp
,
793 struct xdr_stream
*xdr
,
794 struct gssx_res_accept_sec_context
*res
)
800 err
= gssx_dec_status(xdr
, &res
->status
);
804 /* res->context_handle */
805 err
= gssx_dec_bool(xdr
, &value_follows
);
809 err
= gssx_dec_ctx(xdr
, res
->context_handle
);
813 res
->context_handle
= NULL
;
816 /* res->output_token */
817 err
= gssx_dec_bool(xdr
, &value_follows
);
821 err
= gssx_dec_buffer(xdr
, res
->output_token
);
825 res
->output_token
= NULL
;
828 /* res->delegated_cred_handle */
829 err
= gssx_dec_bool(xdr
, &value_follows
);
833 /* we do not support upcall servers sending this data. */
838 err
= gssx_dec_option_array(xdr
, &res
->options
);