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
;
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
);
496 static int gssx_dec_name(struct xdr_stream
*xdr
,
497 struct gssx_name
*name
)
499 struct xdr_netobj dummy_netobj
;
500 struct gssx_name_attr_array dummy_name_attr_array
;
501 struct gssx_option_array dummy_option_array
;
504 /* name->display_name */
505 err
= gssx_dec_buffer(xdr
, &name
->display_name
);
509 /* name->name_type */
510 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
514 /* name->exported_name */
515 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
519 /* name->exported_composite_name */
520 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
524 /* we assume we have no attributes for now, so simply consume them */
525 /* name->name_attributes */
526 err
= dummy_dec_nameattr_array(xdr
, &dummy_name_attr_array
);
530 /* we assume we have no options for now, so simply consume them */
531 /* name->extensions */
532 err
= dummy_dec_opt_array(xdr
, &dummy_option_array
);
537 static int dummy_enc_credel_array(struct xdr_stream
*xdr
,
538 struct gssx_cred_element_array
*cea
)
545 p
= xdr_reserve_space(xdr
, 4);
553 static int gssx_enc_cred(struct xdr_stream
*xdr
,
554 struct gssx_cred
*cred
)
558 /* cred->desired_name */
559 err
= gssx_enc_name(xdr
, &cred
->desired_name
);
564 err
= dummy_enc_credel_array(xdr
, &cred
->elements
);
566 /* cred->cred_handle_reference */
567 err
= gssx_enc_buffer(xdr
, &cred
->cred_handle_reference
);
571 /* cred->needs_release */
572 err
= gssx_enc_bool(xdr
, cred
->needs_release
);
577 static int gssx_enc_ctx(struct xdr_stream
*xdr
,
578 struct gssx_ctx
*ctx
)
583 /* ctx->exported_context_token */
584 err
= gssx_enc_buffer(xdr
, &ctx
->exported_context_token
);
589 err
= gssx_enc_buffer(xdr
, &ctx
->state
);
593 /* ctx->need_release */
594 err
= gssx_enc_bool(xdr
, ctx
->need_release
);
599 err
= gssx_enc_buffer(xdr
, &ctx
->mech
);
604 err
= gssx_enc_name(xdr
, &ctx
->src_name
);
609 err
= gssx_enc_name(xdr
, &ctx
->targ_name
);
614 p
= xdr_reserve_space(xdr
, 8+8);
617 p
= xdr_encode_hyper(p
, ctx
->lifetime
);
620 p
= xdr_encode_hyper(p
, ctx
->ctx_flags
);
622 /* ctx->locally_initiated */
623 err
= gssx_enc_bool(xdr
, ctx
->locally_initiated
);
628 err
= gssx_enc_bool(xdr
, ctx
->open
);
632 /* leave options empty for now, will add once we have any options
633 * to pass up at all */
635 err
= dummy_enc_opt_array(xdr
, &ctx
->options
);
640 static int gssx_dec_ctx(struct xdr_stream
*xdr
,
641 struct gssx_ctx
*ctx
)
646 /* ctx->exported_context_token */
647 err
= gssx_dec_buffer(xdr
, &ctx
->exported_context_token
);
652 err
= gssx_dec_buffer(xdr
, &ctx
->state
);
656 /* ctx->need_release */
657 err
= gssx_dec_bool(xdr
, &ctx
->need_release
);
662 err
= gssx_dec_buffer(xdr
, &ctx
->mech
);
667 err
= gssx_dec_name(xdr
, &ctx
->src_name
);
672 err
= gssx_dec_name(xdr
, &ctx
->targ_name
);
677 p
= xdr_inline_decode(xdr
, 8+8);
678 if (unlikely(p
== NULL
))
680 p
= xdr_decode_hyper(p
, &ctx
->lifetime
);
683 p
= xdr_decode_hyper(p
, &ctx
->ctx_flags
);
685 /* ctx->locally_initiated */
686 err
= gssx_dec_bool(xdr
, &ctx
->locally_initiated
);
691 err
= gssx_dec_bool(xdr
, &ctx
->open
);
695 /* we assume we have no options for now, so simply consume them */
697 err
= dummy_dec_opt_array(xdr
, &ctx
->options
);
702 static int gssx_enc_cb(struct xdr_stream
*xdr
, struct gssx_cb
*cb
)
707 /* cb->initiator_addrtype */
708 p
= xdr_reserve_space(xdr
, 8);
711 p
= xdr_encode_hyper(p
, cb
->initiator_addrtype
);
713 /* cb->initiator_address */
714 err
= gssx_enc_buffer(xdr
, &cb
->initiator_address
);
718 /* cb->acceptor_addrtype */
719 p
= xdr_reserve_space(xdr
, 8);
722 p
= xdr_encode_hyper(p
, cb
->acceptor_addrtype
);
724 /* cb->acceptor_address */
725 err
= gssx_enc_buffer(xdr
, &cb
->acceptor_address
);
729 /* cb->application_data */
730 err
= gssx_enc_buffer(xdr
, &cb
->application_data
);
735 void gssx_enc_accept_sec_context(struct rpc_rqst
*req
,
736 struct xdr_stream
*xdr
,
737 struct gssx_arg_accept_sec_context
*arg
)
741 err
= gssx_enc_call_ctx(xdr
, &arg
->call_ctx
);
745 /* arg->context_handle */
746 if (arg
->context_handle
) {
747 err
= gssx_enc_ctx(xdr
, arg
->context_handle
);
751 err
= gssx_enc_bool(xdr
, 0);
754 /* arg->cred_handle */
755 if (arg
->cred_handle
) {
756 err
= gssx_enc_cred(xdr
, arg
->cred_handle
);
760 err
= gssx_enc_bool(xdr
, 0);
763 /* arg->input_token */
764 err
= gssx_enc_in_token(xdr
, &arg
->input_token
);
770 err
= gssx_enc_cb(xdr
, arg
->input_cb
);
774 err
= gssx_enc_bool(xdr
, 0);
777 err
= gssx_enc_bool(xdr
, arg
->ret_deleg_cred
);
781 /* leave options empty for now, will add once we have any options
782 * to pass up at all */
784 err
= dummy_enc_opt_array(xdr
, &arg
->options
);
788 dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err
);
791 int gssx_dec_accept_sec_context(struct rpc_rqst
*rqstp
,
792 struct xdr_stream
*xdr
,
793 struct gssx_res_accept_sec_context
*res
)
799 err
= gssx_dec_status(xdr
, &res
->status
);
803 /* res->context_handle */
804 err
= gssx_dec_bool(xdr
, &value_follows
);
808 err
= gssx_dec_ctx(xdr
, res
->context_handle
);
812 res
->context_handle
= NULL
;
815 /* res->output_token */
816 err
= gssx_dec_bool(xdr
, &value_follows
);
820 err
= gssx_dec_buffer(xdr
, res
->output_token
);
824 res
->output_token
= NULL
;
827 /* res->delegated_cred_handle */
828 err
= gssx_dec_bool(xdr
, &value_follows
);
832 /* we do not support upcall servers sending this data. */
837 err
= gssx_dec_option_array(xdr
, &res
->options
);