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