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_host_u32(struct xdr_stream
*xdr
, u32
*res
)
173 p
= xdr_inline_decode(xdr
, 4);
176 /* Contents of linux creds are all host-endian: */
177 memcpy(res
, p
, sizeof(u32
));
181 static int gssx_dec_linux_creds(struct xdr_stream
*xdr
,
182 struct svc_cred
*creds
)
190 p
= xdr_inline_decode(xdr
, 4);
191 if (unlikely(p
== NULL
))
194 length
= be32_to_cpup(p
);
196 if (length
> (3 + NGROUPS_MAX
) * sizeof(u32
))
200 err
= get_host_u32(xdr
, &tmp
);
203 creds
->cr_uid
= make_kuid(&init_user_ns
, tmp
);
206 err
= get_host_u32(xdr
, &tmp
);
209 creds
->cr_gid
= make_kgid(&init_user_ns
, tmp
);
211 /* number of additional gid's */
212 err
= get_host_u32(xdr
, &tmp
);
216 if ((3 + N
) * sizeof(u32
) != length
)
218 creds
->cr_group_info
= groups_alloc(N
);
219 if (creds
->cr_group_info
== NULL
)
223 for (i
= 0; i
< N
; i
++) {
225 err
= get_host_u32(xdr
, &tmp
);
227 goto out_free_groups
;
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
;
237 groups_free(creds
->cr_group_info
);
241 static int gssx_dec_option_array(struct xdr_stream
*xdr
,
242 struct gssx_option_array
*oa
)
244 struct svc_cred
*creds
;
249 p
= xdr_inline_decode(xdr
, 4);
250 if (unlikely(p
== NULL
))
252 count
= be32_to_cpup(p
++);
256 /* we recognize only 1 currently: CREDS_VALUE */
259 oa
->data
= kmalloc(sizeof(struct gssx_option
), GFP_KERNEL
);
263 creds
= kmalloc(sizeof(struct svc_cred
), GFP_KERNEL
);
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;
274 for (i
= 0; i
< count
; i
++) {
275 gssx_buffer dummy
= { 0, NULL
};
279 p
= xdr_inline_decode(xdr
, 4);
280 if (unlikely(p
== NULL
))
283 length
= be32_to_cpup(p
);
284 p
= xdr_inline_decode(xdr
, length
);
285 if (unlikely(p
== NULL
))
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
);
294 oa
->data
[0].value
.len
= 1; /* presence */
296 /* consume uninteresting buffer */
297 err
= gssx_dec_buffer(xdr
, &dummy
);
305 static int gssx_dec_status(struct xdr_stream
*xdr
,
306 struct gssx_status
*status
)
311 /* status->major_status */
312 p
= xdr_inline_decode(xdr
, 8);
313 if (unlikely(p
== NULL
))
315 p
= xdr_decode_hyper(p
, &status
->major_status
);
318 err
= gssx_dec_buffer(xdr
, &status
->mech
);
322 /* status->minor_status */
323 p
= xdr_inline_decode(xdr
, 8);
324 if (unlikely(p
== NULL
))
326 p
= xdr_decode_hyper(p
, &status
->minor_status
);
328 /* status->major_status_string */
329 err
= gssx_dec_buffer(xdr
, &status
->major_status_string
);
333 /* status->minor_status_string */
334 err
= gssx_dec_buffer(xdr
, &status
->minor_status_string
);
338 /* status->server_ctx */
339 err
= gssx_dec_buffer(xdr
, &status
->server_ctx
);
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
);
350 static int gssx_enc_call_ctx(struct xdr_stream
*xdr
,
351 struct gssx_call_ctx
*ctx
)
353 struct gssx_option opt
;
358 err
= gssx_enc_buffer(xdr
, &ctx
->locale
);
362 /* ctx->server_ctx */
363 err
= gssx_enc_buffer(xdr
, &ctx
->server_ctx
);
367 /* we always want to ask for lucid contexts */
369 p
= xdr_reserve_space(xdr
, 4);
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
);
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
);
389 static int gssx_dec_name_attr(struct xdr_stream
*xdr
,
390 struct gssx_name_attr
*attr
)
395 err
= gssx_dec_buffer(xdr
, &attr
->attr
);
400 err
= gssx_dec_buffer(xdr
, &attr
->value
);
404 /* attr->extensions */
405 err
= dummy_dec_opt_array(xdr
, &attr
->extensions
);
410 static int dummy_enc_nameattr_array(struct xdr_stream
*xdr
,
411 struct gssx_name_attr_array
*naa
)
418 p
= xdr_reserve_space(xdr
, 4);
426 static int dummy_dec_nameattr_array(struct xdr_stream
*xdr
,
427 struct gssx_name_attr_array
*naa
)
429 struct gssx_name_attr dummy
= { .attr
= {.len
= 0} };
433 p
= xdr_inline_decode(xdr
, 4);
434 if (unlikely(p
== NULL
))
436 count
= be32_to_cpup(p
++);
437 for (i
= 0; i
< count
; i
++) {
438 gssx_dec_name_attr(xdr
, &dummy
);
446 static struct xdr_netobj zero_netobj
= {};
448 static struct gssx_name_attr_array zero_name_attr_array
= {};
450 static struct gssx_option_array zero_option_array
= {};
452 static int gssx_enc_name(struct xdr_stream
*xdr
,
453 struct gssx_name
*name
)
457 /* name->display_name */
458 err
= gssx_enc_buffer(xdr
, &name
->display_name
);
462 /* name->name_type */
463 err
= gssx_enc_buffer(xdr
, &zero_netobj
);
467 /* name->exported_name */
468 err
= gssx_enc_buffer(xdr
, &zero_netobj
);
472 /* name->exported_composite_name */
473 err
= gssx_enc_buffer(xdr
, &zero_netobj
);
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
);
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
);
493 static int gssx_dec_name(struct xdr_stream
*xdr
,
494 struct gssx_name
*name
)
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 };
501 /* name->display_name */
502 err
= gssx_dec_buffer(xdr
, &name
->display_name
);
506 /* name->name_type */
507 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
511 /* name->exported_name */
512 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
516 /* name->exported_composite_name */
517 err
= gssx_dec_buffer(xdr
, &dummy_netobj
);
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
);
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
);
534 static int dummy_enc_credel_array(struct xdr_stream
*xdr
,
535 struct gssx_cred_element_array
*cea
)
542 p
= xdr_reserve_space(xdr
, 4);
550 static int gssx_enc_cred(struct xdr_stream
*xdr
,
551 struct gssx_cred
*cred
)
555 /* cred->desired_name */
556 err
= gssx_enc_name(xdr
, &cred
->desired_name
);
561 err
= dummy_enc_credel_array(xdr
, &cred
->elements
);
565 /* cred->cred_handle_reference */
566 err
= gssx_enc_buffer(xdr
, &cred
->cred_handle_reference
);
570 /* cred->needs_release */
571 err
= gssx_enc_bool(xdr
, cred
->needs_release
);
576 static int gssx_enc_ctx(struct xdr_stream
*xdr
,
577 struct gssx_ctx
*ctx
)
582 /* ctx->exported_context_token */
583 err
= gssx_enc_buffer(xdr
, &ctx
->exported_context_token
);
588 err
= gssx_enc_buffer(xdr
, &ctx
->state
);
592 /* ctx->need_release */
593 err
= gssx_enc_bool(xdr
, ctx
->need_release
);
598 err
= gssx_enc_buffer(xdr
, &ctx
->mech
);
603 err
= gssx_enc_name(xdr
, &ctx
->src_name
);
608 err
= gssx_enc_name(xdr
, &ctx
->targ_name
);
613 p
= xdr_reserve_space(xdr
, 8+8);
616 p
= xdr_encode_hyper(p
, ctx
->lifetime
);
619 p
= xdr_encode_hyper(p
, ctx
->ctx_flags
);
621 /* ctx->locally_initiated */
622 err
= gssx_enc_bool(xdr
, ctx
->locally_initiated
);
627 err
= gssx_enc_bool(xdr
, ctx
->open
);
631 /* leave options empty for now, will add once we have any options
632 * to pass up at all */
634 err
= dummy_enc_opt_array(xdr
, &ctx
->options
);
639 static int gssx_dec_ctx(struct xdr_stream
*xdr
,
640 struct gssx_ctx
*ctx
)
645 /* ctx->exported_context_token */
646 err
= gssx_dec_buffer(xdr
, &ctx
->exported_context_token
);
651 err
= gssx_dec_buffer(xdr
, &ctx
->state
);
655 /* ctx->need_release */
656 err
= gssx_dec_bool(xdr
, &ctx
->need_release
);
661 err
= gssx_dec_buffer(xdr
, &ctx
->mech
);
666 err
= gssx_dec_name(xdr
, &ctx
->src_name
);
671 err
= gssx_dec_name(xdr
, &ctx
->targ_name
);
676 p
= xdr_inline_decode(xdr
, 8+8);
677 if (unlikely(p
== NULL
))
679 p
= xdr_decode_hyper(p
, &ctx
->lifetime
);
682 p
= xdr_decode_hyper(p
, &ctx
->ctx_flags
);
684 /* ctx->locally_initiated */
685 err
= gssx_dec_bool(xdr
, &ctx
->locally_initiated
);
690 err
= gssx_dec_bool(xdr
, &ctx
->open
);
694 /* we assume we have no options for now, so simply consume them */
696 err
= dummy_dec_opt_array(xdr
, &ctx
->options
);
701 static int gssx_enc_cb(struct xdr_stream
*xdr
, struct gssx_cb
*cb
)
706 /* cb->initiator_addrtype */
707 p
= xdr_reserve_space(xdr
, 8);
710 p
= xdr_encode_hyper(p
, cb
->initiator_addrtype
);
712 /* cb->initiator_address */
713 err
= gssx_enc_buffer(xdr
, &cb
->initiator_address
);
717 /* cb->acceptor_addrtype */
718 p
= xdr_reserve_space(xdr
, 8);
721 p
= xdr_encode_hyper(p
, cb
->acceptor_addrtype
);
723 /* cb->acceptor_address */
724 err
= gssx_enc_buffer(xdr
, &cb
->acceptor_address
);
728 /* cb->application_data */
729 err
= gssx_enc_buffer(xdr
, &cb
->application_data
);
734 void gssx_enc_accept_sec_context(struct rpc_rqst
*req
,
735 struct xdr_stream
*xdr
,
736 struct gssx_arg_accept_sec_context
*arg
)
740 err
= gssx_enc_call_ctx(xdr
, &arg
->call_ctx
);
744 /* arg->context_handle */
745 if (arg
->context_handle
)
746 err
= gssx_enc_ctx(xdr
, arg
->context_handle
);
748 err
= gssx_enc_bool(xdr
, 0);
752 /* arg->cred_handle */
753 if (arg
->cred_handle
)
754 err
= gssx_enc_cred(xdr
, arg
->cred_handle
);
756 err
= gssx_enc_bool(xdr
, 0);
760 /* arg->input_token */
761 err
= gssx_enc_in_token(xdr
, &arg
->input_token
);
767 err
= gssx_enc_cb(xdr
, arg
->input_cb
);
769 err
= gssx_enc_bool(xdr
, 0);
773 err
= gssx_enc_bool(xdr
, arg
->ret_deleg_cred
);
777 /* leave options empty for now, will add once we have any options
778 * to pass up at all */
780 err
= dummy_enc_opt_array(xdr
, &arg
->options
);
782 xdr_inline_pages(&req
->rq_rcv_buf
,
783 PAGE_SIZE
/2 /* pretty arbitrary */,
784 arg
->pages
, 0 /* page base */, arg
->npages
* PAGE_SIZE
);
787 dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err
);
790 int gssx_dec_accept_sec_context(struct rpc_rqst
*rqstp
,
791 struct xdr_stream
*xdr
,
792 struct gssx_res_accept_sec_context
*res
)
798 err
= gssx_dec_status(xdr
, &res
->status
);
802 /* res->context_handle */
803 err
= gssx_dec_bool(xdr
, &value_follows
);
807 err
= gssx_dec_ctx(xdr
, res
->context_handle
);
811 res
->context_handle
= NULL
;
814 /* res->output_token */
815 err
= gssx_dec_bool(xdr
, &value_follows
);
819 err
= gssx_dec_buffer(xdr
, res
->output_token
);
823 res
->output_token
= NULL
;
826 /* res->delegated_cred_handle */
827 err
= gssx_dec_bool(xdr
, &value_follows
);
831 /* we do not support upcall servers sending this data. */
836 err
= gssx_dec_option_array(xdr
, &res
->options
);