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