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