gss_rpc_xdr.c (16896B)
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 11static 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 22static 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 33static 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 45static 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 62static 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 95static 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 107static 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 119static 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 135static 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 156static 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 168static 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; 224out_free_groups: 225 groups_free(creds->cr_group_info); 226 return err; 227} 228 229static 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 293static 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 338static 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 377static 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 398static 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 414static 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 434static struct xdr_netobj zero_netobj = {}; 435 436static struct gssx_name_attr_array zero_name_attr_array = {}; 437 438static struct gssx_option_array zero_option_array = {}; 439 440static 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 481static 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 522static 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 538static 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 564static 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 627static 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 689static 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 722void 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); 774done: 775 if (err) 776 dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); 777} 778 779int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, 780 struct xdr_stream *xdr, 781 void *data) 782{ 783 struct gssx_res_accept_sec_context *res = data; 784 u32 value_follows; 785 int err; 786 struct page *scratch; 787 788 scratch = alloc_page(GFP_KERNEL); 789 if (!scratch) 790 return -ENOMEM; 791 xdr_set_scratch_page(xdr, scratch); 792 793 /* res->status */ 794 err = gssx_dec_status(xdr, &res->status); 795 if (err) 796 goto out_free; 797 798 /* res->context_handle */ 799 err = gssx_dec_bool(xdr, &value_follows); 800 if (err) 801 goto out_free; 802 if (value_follows) { 803 err = gssx_dec_ctx(xdr, res->context_handle); 804 if (err) 805 goto out_free; 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 goto out_free; 814 if (value_follows) { 815 err = gssx_dec_buffer(xdr, res->output_token); 816 if (err) 817 goto out_free; 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 goto out_free; 826 if (value_follows) { 827 /* we do not support upcall servers sending this data. */ 828 err = -EINVAL; 829 goto out_free; 830 } 831 832 /* res->options */ 833 err = gssx_dec_option_array(xdr, &res->options); 834 835out_free: 836 __free_page(scratch); 837 return err; 838}