1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * GSS Proxy upcall module 4 * 5 * Copyright (C) 2012 Simo Sorce <simo@redhat.com> 6 */ 7 8 #include <linux/sunrpc/svcauth.h> 9 #include "gss_rpc_xdr.h" 10 11 static int gssx_enc_bool(struct xdr_stream *xdr, int v) 12 { 13 __be32 *p; 14 15 p = xdr_reserve_space(xdr, 4); 16 if (unlikely(p == NULL)) 17 return -ENOSPC; 18 *p = v ? xdr_one : xdr_zero; 19 return 0; 20 } 21 22 static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v) 23 { 24 __be32 *p; 25 26 p = xdr_inline_decode(xdr, 4); 27 if (unlikely(p == NULL)) 28 return -ENOSPC; 29 *v = be32_to_cpu(*p); 30 return 0; 31 } 32 33 static int gssx_enc_buffer(struct xdr_stream *xdr, 34 const gssx_buffer *buf) 35 { 36 __be32 *p; 37 38 p = xdr_reserve_space(xdr, sizeof(u32) + buf->len); 39 if (!p) 40 return -ENOSPC; 41 xdr_encode_opaque(p, buf->data, buf->len); 42 return 0; 43 } 44 45 static int gssx_enc_in_token(struct xdr_stream *xdr, 46 const struct gssp_in_token *in) 47 { 48 __be32 *p; 49 50 p = xdr_reserve_space(xdr, 4); 51 if (!p) 52 return -ENOSPC; 53 *p = cpu_to_be32(in->page_len); 54 55 /* all we need to do is to write pages */ 56 xdr_write_pages(xdr, in->pages, in->page_base, in->page_len); 57 58 return 0; 59 } 60 61 62 static int gssx_dec_buffer(struct xdr_stream *xdr, 63 gssx_buffer *buf) 64 { 65 u32 length; 66 __be32 *p; 67 68 p = xdr_inline_decode(xdr, 4); 69 if (unlikely(p == NULL)) 70 return -ENOSPC; 71 72 length = be32_to_cpup(p); 73 p = xdr_inline_decode(xdr, length); 74 if (unlikely(p == NULL)) 75 return -ENOSPC; 76 77 if (buf->len == 0) { 78 /* we intentionally are not interested in this buffer */ 79 return 0; 80 } 81 if (length > buf->len) 82 return -ENOSPC; 83 84 if (!buf->data) { 85 buf->data = kmemdup(p, length, GFP_KERNEL); 86 if (!buf->data) 87 return -ENOMEM; 88 } else { 89 memcpy(buf->data, p, length); 90 } 91 buf->len = length; 92 return 0; 93 } 94 95 static int gssx_enc_option(struct xdr_stream *xdr, 96 struct gssx_option *opt) 97 { 98 int err; 99 100 err = gssx_enc_buffer(xdr, &opt->option); 101 if (err) 102 return err; 103 err = gssx_enc_buffer(xdr, &opt->value); 104 return err; 105 } 106 107 static int gssx_dec_option(struct xdr_stream *xdr, 108 struct gssx_option *opt) 109 { 110 int err; 111 112 err = gssx_dec_buffer(xdr, &opt->option); 113 if (err) 114 return err; 115 err = gssx_dec_buffer(xdr, &opt->value); 116 return err; 117 } 118 119 static int dummy_enc_opt_array(struct xdr_stream *xdr, 120 const struct gssx_option_array *oa) 121 { 122 __be32 *p; 123 124 if (oa->count != 0) 125 return -EINVAL; 126 127 p = xdr_reserve_space(xdr, 4); 128 if (!p) 129 return -ENOSPC; 130 *p = 0; 131 132 return 0; 133 } 134 135 static int dummy_dec_opt_array(struct xdr_stream *xdr, 136 struct gssx_option_array *oa) 137 { 138 struct gssx_option dummy; 139 u32 count, i; 140 __be32 *p; 141 142 p = xdr_inline_decode(xdr, 4); 143 if (unlikely(p == NULL)) 144 return -ENOSPC; 145 count = be32_to_cpup(p++); 146 memset(&dummy, 0, sizeof(dummy)); 147 for (i = 0; i < count; i++) { 148 gssx_dec_option(xdr, &dummy); 149 } 150 151 oa->count = 0; 152 oa->data = NULL; 153 return 0; 154 } 155 156 static int get_host_u32(struct xdr_stream *xdr, u32 *res) 157 { 158 __be32 *p; 159 160 p = xdr_inline_decode(xdr, 4); 161 if (!p) 162 return -EINVAL; 163 /* Contents of linux creds are all host-endian: */ 164 memcpy(res, p, sizeof(u32)); 165 return 0; 166 } 167 168 static int gssx_dec_linux_creds(struct xdr_stream *xdr, 169 struct svc_cred *creds) 170 { 171 u32 length; 172 __be32 *p; 173 u32 tmp; 174 u32 N; 175 int i, err; 176 177 p = xdr_inline_decode(xdr, 4); 178 if (unlikely(p == NULL)) 179 return -ENOSPC; 180 181 length = be32_to_cpup(p); 182 183 if (length > (3 + NGROUPS_MAX) * sizeof(u32)) 184 return -ENOSPC; 185 186 /* uid */ 187 err = get_host_u32(xdr, &tmp); 188 if (err) 189 return err; 190 creds->cr_uid = make_kuid(&init_user_ns, tmp); 191 192 /* gid */ 193 err = get_host_u32(xdr, &tmp); 194 if (err) 195 return err; 196 creds->cr_gid = make_kgid(&init_user_ns, tmp); 197 198 /* number of additional gid's */ 199 err = get_host_u32(xdr, &tmp); 200 if (err) 201 return err; 202 N = tmp; 203 if ((3 + N) * sizeof(u32) != length) 204 return -EINVAL; 205 creds->cr_group_info = groups_alloc(N); 206 if (creds->cr_group_info == NULL) 207 return -ENOMEM; 208 209 /* gid's */ 210 for (i = 0; i < N; i++) { 211 kgid_t kgid; 212 err = get_host_u32(xdr, &tmp); 213 if (err) 214 goto out_free_groups; 215 err = -EINVAL; 216 kgid = make_kgid(&init_user_ns, tmp); 217 if (!gid_valid(kgid)) 218 goto out_free_groups; 219 creds->cr_group_info->gid[i] = kgid; 220 } 221 groups_sort(creds->cr_group_info); 222 223 return 0; 224 out_free_groups: 225 groups_free(creds->cr_group_info); 226 return err; 227 } 228 229 static int gssx_dec_option_array(struct xdr_stream *xdr, 230 struct gssx_option_array *oa) 231 { 232 struct svc_cred *creds; 233 u32 count, i; 234 __be32 *p; 235 int err; 236 237 p = xdr_inline_decode(xdr, 4); 238 if (unlikely(p == NULL)) 239 return -ENOSPC; 240 count = be32_to_cpup(p++); 241 if (!count) 242 return 0; 243 244 /* we recognize only 1 currently: CREDS_VALUE */ 245 oa->count = 1; 246 247 oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL); 248 if (!oa->data) 249 return -ENOMEM; 250 251 creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL); 252 if (!creds) { 253 kfree(oa->data); 254 return -ENOMEM; 255 } 256 257 oa->data[0].option.data = CREDS_VALUE; 258 oa->data[0].option.len = sizeof(CREDS_VALUE); 259 oa->data[0].value.data = (void *)creds; 260 oa->data[0].value.len = 0; 261 262 for (i = 0; i < count; i++) { 263 gssx_buffer dummy = { 0, NULL }; 264 u32 length; 265 266 /* option buffer */ 267 p = xdr_inline_decode(xdr, 4); 268 if (unlikely(p == NULL)) 269 return -ENOSPC; 270 271 length = be32_to_cpup(p); 272 p = xdr_inline_decode(xdr, length); 273 if (unlikely(p == NULL)) 274 return -ENOSPC; 275 276 if (length == sizeof(CREDS_VALUE) && 277 memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) { 278 /* We have creds here. parse them */ 279 err = gssx_dec_linux_creds(xdr, creds); 280 if (err) 281 return err; 282 oa->data[0].value.len = 1; /* presence */ 283 } else { 284 /* consume uninteresting buffer */ 285 err = gssx_dec_buffer(xdr, &dummy); 286 if (err) 287 return err; 288 } 289 } 290 return 0; 291 } 292 293 static int gssx_dec_status(struct xdr_stream *xdr, 294 struct gssx_status *status) 295 { 296 __be32 *p; 297 int err; 298 299 /* status->major_status */ 300 p = xdr_inline_decode(xdr, 8); 301 if (unlikely(p == NULL)) 302 return -ENOSPC; 303 p = xdr_decode_hyper(p, &status->major_status); 304 305 /* status->mech */ 306 err = gssx_dec_buffer(xdr, &status->mech); 307 if (err) 308 return err; 309 310 /* status->minor_status */ 311 p = xdr_inline_decode(xdr, 8); 312 if (unlikely(p == NULL)) 313 return -ENOSPC; 314 p = xdr_decode_hyper(p, &status->minor_status); 315 316 /* status->major_status_string */ 317 err = gssx_dec_buffer(xdr, &status->major_status_string); 318 if (err) 319 return err; 320 321 /* status->minor_status_string */ 322 err = gssx_dec_buffer(xdr, &status->minor_status_string); 323 if (err) 324 return err; 325 326 /* status->server_ctx */ 327 err = gssx_dec_buffer(xdr, &status->server_ctx); 328 if (err) 329 return err; 330 331 /* we assume we have no options for now, so simply consume them */ 332 /* status->options */ 333 err = dummy_dec_opt_array(xdr, &status->options); 334 335 return err; 336 } 337 338 static int gssx_enc_call_ctx(struct xdr_stream *xdr, 339 const struct gssx_call_ctx *ctx) 340 { 341 struct gssx_option opt; 342 __be32 *p; 343 int err; 344 345 /* ctx->locale */ 346 err = gssx_enc_buffer(xdr, &ctx->locale); 347 if (err) 348 return err; 349 350 /* ctx->server_ctx */ 351 err = gssx_enc_buffer(xdr, &ctx->server_ctx); 352 if (err) 353 return err; 354 355 /* we always want to ask for lucid contexts */ 356 /* ctx->options */ 357 p = xdr_reserve_space(xdr, 4); 358 *p = cpu_to_be32(2); 359 360 /* we want a lucid_v1 context */ 361 opt.option.data = LUCID_OPTION; 362 opt.option.len = sizeof(LUCID_OPTION); 363 opt.value.data = LUCID_VALUE; 364 opt.value.len = sizeof(LUCID_VALUE); 365 err = gssx_enc_option(xdr, &opt); 366 367 /* ..and user creds */ 368 opt.option.data = CREDS_OPTION; 369 opt.option.len = sizeof(CREDS_OPTION); 370 opt.value.data = CREDS_VALUE; 371 opt.value.len = sizeof(CREDS_VALUE); 372 err = gssx_enc_option(xdr, &opt); 373 374 return err; 375 } 376 377 static int gssx_dec_name_attr(struct xdr_stream *xdr, 378 struct gssx_name_attr *attr) 379 { 380 int err; 381 382 /* attr->attr */ 383 err = gssx_dec_buffer(xdr, &attr->attr); 384 if (err) 385 return err; 386 387 /* attr->value */ 388 err = gssx_dec_buffer(xdr, &attr->value); 389 if (err) 390 return err; 391 392 /* attr->extensions */ 393 err = dummy_dec_opt_array(xdr, &attr->extensions); 394 395 return err; 396 } 397 398 static int dummy_enc_nameattr_array(struct xdr_stream *xdr, 399 struct gssx_name_attr_array *naa) 400 { 401 __be32 *p; 402 403 if (naa->count != 0) 404 return -EINVAL; 405 406 p = xdr_reserve_space(xdr, 4); 407 if (!p) 408 return -ENOSPC; 409 *p = 0; 410 411 return 0; 412 } 413 414 static int dummy_dec_nameattr_array(struct xdr_stream *xdr, 415 struct gssx_name_attr_array *naa) 416 { 417 struct gssx_name_attr dummy = { .attr = {.len = 0} }; 418 u32 count, i; 419 __be32 *p; 420 421 p = xdr_inline_decode(xdr, 4); 422 if (unlikely(p == NULL)) 423 return -ENOSPC; 424 count = be32_to_cpup(p++); 425 for (i = 0; i < count; i++) { 426 gssx_dec_name_attr(xdr, &dummy); 427 } 428 429 naa->count = 0; 430 naa->data = NULL; 431 return 0; 432 } 433 434 static struct xdr_netobj zero_netobj = {}; 435 436 static struct gssx_name_attr_array zero_name_attr_array = {}; 437 438 static struct gssx_option_array zero_option_array = {}; 439 440 static int gssx_enc_name(struct xdr_stream *xdr, 441 struct gssx_name *name) 442 { 443 int err; 444 445 /* name->display_name */ 446 err = gssx_enc_buffer(xdr, &name->display_name); 447 if (err) 448 return err; 449 450 /* name->name_type */ 451 err = gssx_enc_buffer(xdr, &zero_netobj); 452 if (err) 453 return err; 454 455 /* name->exported_name */ 456 err = gssx_enc_buffer(xdr, &zero_netobj); 457 if (err) 458 return err; 459 460 /* name->exported_composite_name */ 461 err = gssx_enc_buffer(xdr, &zero_netobj); 462 if (err) 463 return err; 464 465 /* leave name_attributes empty for now, will add once we have any 466 * to pass up at all */ 467 /* name->name_attributes */ 468 err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array); 469 if (err) 470 return err; 471 472 /* leave options empty for now, will add once we have any options 473 * to pass up at all */ 474 /* name->extensions */ 475 err = dummy_enc_opt_array(xdr, &zero_option_array); 476 477 return err; 478 } 479 480 481 static int gssx_dec_name(struct xdr_stream *xdr, 482 struct gssx_name *name) 483 { 484 struct xdr_netobj dummy_netobj = { .len = 0 }; 485 struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 }; 486 struct gssx_option_array dummy_option_array = { .count = 0 }; 487 int err; 488 489 /* name->display_name */ 490 err = gssx_dec_buffer(xdr, &name->display_name); 491 if (err) 492 return err; 493 494 /* name->name_type */ 495 err = gssx_dec_buffer(xdr, &dummy_netobj); 496 if (err) 497 return err; 498 499 /* name->exported_name */ 500 err = gssx_dec_buffer(xdr, &dummy_netobj); 501 if (err) 502 return err; 503 504 /* name->exported_composite_name */ 505 err = gssx_dec_buffer(xdr, &dummy_netobj); 506 if (err) 507 return err; 508 509 /* we assume we have no attributes for now, so simply consume them */ 510 /* name->name_attributes */ 511 err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array); 512 if (err) 513 return err; 514 515 /* we assume we have no options for now, so simply consume them */ 516 /* name->extensions */ 517 err = dummy_dec_opt_array(xdr, &dummy_option_array); 518 519 return err; 520 } 521 522 static int dummy_enc_credel_array(struct xdr_stream *xdr, 523 struct gssx_cred_element_array *cea) 524 { 525 __be32 *p; 526 527 if (cea->count != 0) 528 return -EINVAL; 529 530 p = xdr_reserve_space(xdr, 4); 531 if (!p) 532 return -ENOSPC; 533 *p = 0; 534 535 return 0; 536 } 537 538 static int gssx_enc_cred(struct xdr_stream *xdr, 539 struct gssx_cred *cred) 540 { 541 int err; 542 543 /* cred->desired_name */ 544 err = gssx_enc_name(xdr, &cred->desired_name); 545 if (err) 546 return err; 547 548 /* cred->elements */ 549 err = dummy_enc_credel_array(xdr, &cred->elements); 550 if (err) 551 return err; 552 553 /* cred->cred_handle_reference */ 554 err = gssx_enc_buffer(xdr, &cred->cred_handle_reference); 555 if (err) 556 return err; 557 558 /* cred->needs_release */ 559 err = gssx_enc_bool(xdr, cred->needs_release); 560 561 return err; 562 } 563 564 static int gssx_enc_ctx(struct xdr_stream *xdr, 565 struct gssx_ctx *ctx) 566 { 567 __be32 *p; 568 int err; 569 570 /* ctx->exported_context_token */ 571 err = gssx_enc_buffer(xdr, &ctx->exported_context_token); 572 if (err) 573 return err; 574 575 /* ctx->state */ 576 err = gssx_enc_buffer(xdr, &ctx->state); 577 if (err) 578 return err; 579 580 /* ctx->need_release */ 581 err = gssx_enc_bool(xdr, ctx->need_release); 582 if (err) 583 return err; 584 585 /* ctx->mech */ 586 err = gssx_enc_buffer(xdr, &ctx->mech); 587 if (err) 588 return err; 589 590 /* ctx->src_name */ 591 err = gssx_enc_name(xdr, &ctx->src_name); 592 if (err) 593 return err; 594 595 /* ctx->targ_name */ 596 err = gssx_enc_name(xdr, &ctx->targ_name); 597 if (err) 598 return err; 599 600 /* ctx->lifetime */ 601 p = xdr_reserve_space(xdr, 8+8); 602 if (!p) 603 return -ENOSPC; 604 p = xdr_encode_hyper(p, ctx->lifetime); 605 606 /* ctx->ctx_flags */ 607 p = xdr_encode_hyper(p, ctx->ctx_flags); 608 609 /* ctx->locally_initiated */ 610 err = gssx_enc_bool(xdr, ctx->locally_initiated); 611 if (err) 612 return err; 613 614 /* ctx->open */ 615 err = gssx_enc_bool(xdr, ctx->open); 616 if (err) 617 return err; 618 619 /* leave options empty for now, will add once we have any options 620 * to pass up at all */ 621 /* ctx->options */ 622 err = dummy_enc_opt_array(xdr, &ctx->options); 623 624 return err; 625 } 626 627 static int gssx_dec_ctx(struct xdr_stream *xdr, 628 struct gssx_ctx *ctx) 629 { 630 __be32 *p; 631 int err; 632 633 /* ctx->exported_context_token */ 634 err = gssx_dec_buffer(xdr, &ctx->exported_context_token); 635 if (err) 636 return err; 637 638 /* ctx->state */ 639 err = gssx_dec_buffer(xdr, &ctx->state); 640 if (err) 641 return err; 642 643 /* ctx->need_release */ 644 err = gssx_dec_bool(xdr, &ctx->need_release); 645 if (err) 646 return err; 647 648 /* ctx->mech */ 649 err = gssx_dec_buffer(xdr, &ctx->mech); 650 if (err) 651 return err; 652 653 /* ctx->src_name */ 654 err = gssx_dec_name(xdr, &ctx->src_name); 655 if (err) 656 return err; 657 658 /* ctx->targ_name */ 659 err = gssx_dec_name(xdr, &ctx->targ_name); 660 if (err) 661 return err; 662 663 /* ctx->lifetime */ 664 p = xdr_inline_decode(xdr, 8+8); 665 if (unlikely(p == NULL)) 666 return -ENOSPC; 667 p = xdr_decode_hyper(p, &ctx->lifetime); 668 669 /* ctx->ctx_flags */ 670 p = xdr_decode_hyper(p, &ctx->ctx_flags); 671 672 /* ctx->locally_initiated */ 673 err = gssx_dec_bool(xdr, &ctx->locally_initiated); 674 if (err) 675 return err; 676 677 /* ctx->open */ 678 err = gssx_dec_bool(xdr, &ctx->open); 679 if (err) 680 return err; 681 682 /* we assume we have no options for now, so simply consume them */ 683 /* ctx->options */ 684 err = dummy_dec_opt_array(xdr, &ctx->options); 685 686 return err; 687 } 688 689 static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb) 690 { 691 __be32 *p; 692 int err; 693 694 /* cb->initiator_addrtype */ 695 p = xdr_reserve_space(xdr, 8); 696 if (!p) 697 return -ENOSPC; 698 p = xdr_encode_hyper(p, cb->initiator_addrtype); 699 700 /* cb->initiator_address */ 701 err = gssx_enc_buffer(xdr, &cb->initiator_address); 702 if (err) 703 return err; 704 705 /* cb->acceptor_addrtype */ 706 p = xdr_reserve_space(xdr, 8); 707 if (!p) 708 return -ENOSPC; 709 p = xdr_encode_hyper(p, cb->acceptor_addrtype); 710 711 /* cb->acceptor_address */ 712 err = gssx_enc_buffer(xdr, &cb->acceptor_address); 713 if (err) 714 return err; 715 716 /* cb->application_data */ 717 err = gssx_enc_buffer(xdr, &cb->application_data); 718 719 return err; 720 } 721 722 void gssx_enc_accept_sec_context(struct rpc_rqst *req, 723 struct xdr_stream *xdr, 724 const void *data) 725 { 726 const struct gssx_arg_accept_sec_context *arg = data; 727 int err; 728 729 err = gssx_enc_call_ctx(xdr, &arg->call_ctx); 730 if (err) 731 goto done; 732 733 /* arg->context_handle */ 734 if (arg->context_handle) 735 err = gssx_enc_ctx(xdr, arg->context_handle); 736 else 737 err = gssx_enc_bool(xdr, 0); 738 if (err) 739 goto done; 740 741 /* arg->cred_handle */ 742 if (arg->cred_handle) 743 err = gssx_enc_cred(xdr, arg->cred_handle); 744 else 745 err = gssx_enc_bool(xdr, 0); 746 if (err) 747 goto done; 748 749 /* arg->input_token */ 750 err = gssx_enc_in_token(xdr, &arg->input_token); 751 if (err) 752 goto done; 753 754 /* arg->input_cb */ 755 if (arg->input_cb) 756 err = gssx_enc_cb(xdr, arg->input_cb); 757 else 758 err = gssx_enc_bool(xdr, 0); 759 if (err) 760 goto done; 761 762 err = gssx_enc_bool(xdr, arg->ret_deleg_cred); 763 if (err) 764 goto done; 765 766 /* leave options empty for now, will add once we have any options 767 * to pass up at all */ 768 /* arg->options */ 769 err = dummy_enc_opt_array(xdr, &arg->options); 770 771 xdr_inline_pages(&req->rq_rcv_buf, 772 PAGE_SIZE/2 /* pretty arbitrary */, 773 arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE); 774 req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; 775 done: 776 if (err) 777 dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); 778 } 779 780 int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, 781 struct xdr_stream *xdr, 782 void *data) 783 { 784 struct gssx_res_accept_sec_context *res = data; 785 u32 value_follows; 786 int err; 787 struct page *scratch; 788 789 scratch = alloc_page(GFP_KERNEL); 790 if (!scratch) 791 return -ENOMEM; 792 xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE); 793 794 /* res->status */ 795 err = gssx_dec_status(xdr, &res->status); 796 if (err) 797 goto out_free; 798 799 /* res->context_handle */ 800 err = gssx_dec_bool(xdr, &value_follows); 801 if (err) 802 goto out_free; 803 if (value_follows) { 804 err = gssx_dec_ctx(xdr, res->context_handle); 805 if (err) 806 goto out_free; 807 } else { 808 res->context_handle = NULL; 809 } 810 811 /* res->output_token */ 812 err = gssx_dec_bool(xdr, &value_follows); 813 if (err) 814 goto out_free; 815 if (value_follows) { 816 err = gssx_dec_buffer(xdr, res->output_token); 817 if (err) 818 goto out_free; 819 } else { 820 res->output_token = NULL; 821 } 822 823 /* res->delegated_cred_handle */ 824 err = gssx_dec_bool(xdr, &value_follows); 825 if (err) 826 goto out_free; 827 if (value_follows) { 828 /* we do not support upcall servers sending this data. */ 829 err = -EINVAL; 830 goto out_free; 831 } 832 833 /* res->options */ 834 err = gssx_dec_option_array(xdr, &res->options); 835 836 out_free: 837 __free_page(scratch); 838 return err; 839 } 840