linux/net/sunrpc/auth_gss/gss_rpc_xdr.c
<<
>>
Prefs
   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
  24static 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
  35static 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
  46static 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
  58static 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
  75static 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
 108static 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
 120static 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
 132static 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
 148static 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
 169static 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
 181static 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;
 236out_free_groups:
 237        groups_free(creds->cr_group_info);
 238        return err;
 239}
 240
 241static 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
 305static 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
 350static 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
 389static 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
 410static 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
 426static 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
 446static struct xdr_netobj zero_netobj = {};
 447
 448static struct gssx_name_attr_array zero_name_attr_array = {};
 449
 450static struct gssx_option_array zero_option_array = {};
 451
 452static 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
 493static 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
 534static 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
 550static 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        if (err)
 563                return err;
 564
 565        /* cred->cred_handle_reference */
 566        err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
 567        if (err)
 568                return err;
 569
 570        /* cred->needs_release */
 571        err = gssx_enc_bool(xdr, cred->needs_release);
 572
 573        return err;
 574}
 575
 576static int gssx_enc_ctx(struct xdr_stream *xdr,
 577                        struct gssx_ctx *ctx)
 578{
 579        __be32 *p;
 580        int err;
 581
 582        /* ctx->exported_context_token */
 583        err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
 584        if (err)
 585                return err;
 586
 587        /* ctx->state */
 588        err = gssx_enc_buffer(xdr, &ctx->state);
 589        if (err)
 590                return err;
 591
 592        /* ctx->need_release */
 593        err = gssx_enc_bool(xdr, ctx->need_release);
 594        if (err)
 595                return err;
 596
 597        /* ctx->mech */
 598        err = gssx_enc_buffer(xdr, &ctx->mech);
 599        if (err)
 600                return err;
 601
 602        /* ctx->src_name */
 603        err = gssx_enc_name(xdr, &ctx->src_name);
 604        if (err)
 605                return err;
 606
 607        /* ctx->targ_name */
 608        err = gssx_enc_name(xdr, &ctx->targ_name);
 609        if (err)
 610                return err;
 611
 612        /* ctx->lifetime */
 613        p = xdr_reserve_space(xdr, 8+8);
 614        if (!p)
 615                return -ENOSPC;
 616        p = xdr_encode_hyper(p, ctx->lifetime);
 617
 618        /* ctx->ctx_flags */
 619        p = xdr_encode_hyper(p, ctx->ctx_flags);
 620
 621        /* ctx->locally_initiated */
 622        err = gssx_enc_bool(xdr, ctx->locally_initiated);
 623        if (err)
 624                return err;
 625
 626        /* ctx->open */
 627        err = gssx_enc_bool(xdr, ctx->open);
 628        if (err)
 629                return err;
 630
 631        /* leave options empty for now, will add once we have any options
 632         * to pass up at all */
 633        /* ctx->options */
 634        err = dummy_enc_opt_array(xdr, &ctx->options);
 635
 636        return err;
 637}
 638
 639static int gssx_dec_ctx(struct xdr_stream *xdr,
 640                        struct gssx_ctx *ctx)
 641{
 642        __be32 *p;
 643        int err;
 644
 645        /* ctx->exported_context_token */
 646        err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
 647        if (err)
 648                return err;
 649
 650        /* ctx->state */
 651        err = gssx_dec_buffer(xdr, &ctx->state);
 652        if (err)
 653                return err;
 654
 655        /* ctx->need_release */
 656        err = gssx_dec_bool(xdr, &ctx->need_release);
 657        if (err)
 658                return err;
 659
 660        /* ctx->mech */
 661        err = gssx_dec_buffer(xdr, &ctx->mech);
 662        if (err)
 663                return err;
 664
 665        /* ctx->src_name */
 666        err = gssx_dec_name(xdr, &ctx->src_name);
 667        if (err)
 668                return err;
 669
 670        /* ctx->targ_name */
 671        err = gssx_dec_name(xdr, &ctx->targ_name);
 672        if (err)
 673                return err;
 674
 675        /* ctx->lifetime */
 676        p = xdr_inline_decode(xdr, 8+8);
 677        if (unlikely(p == NULL))
 678                return -ENOSPC;
 679        p = xdr_decode_hyper(p, &ctx->lifetime);
 680
 681        /* ctx->ctx_flags */
 682        p = xdr_decode_hyper(p, &ctx->ctx_flags);
 683
 684        /* ctx->locally_initiated */
 685        err = gssx_dec_bool(xdr, &ctx->locally_initiated);
 686        if (err)
 687                return err;
 688
 689        /* ctx->open */
 690        err = gssx_dec_bool(xdr, &ctx->open);
 691        if (err)
 692                return err;
 693
 694        /* we assume we have no options for now, so simply consume them */
 695        /* ctx->options */
 696        err = dummy_dec_opt_array(xdr, &ctx->options);
 697
 698        return err;
 699}
 700
 701static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
 702{
 703        __be32 *p;
 704        int err;
 705
 706        /* cb->initiator_addrtype */
 707        p = xdr_reserve_space(xdr, 8);
 708        if (!p)
 709                return -ENOSPC;
 710        p = xdr_encode_hyper(p, cb->initiator_addrtype);
 711
 712        /* cb->initiator_address */
 713        err = gssx_enc_buffer(xdr, &cb->initiator_address);
 714        if (err)
 715                return err;
 716
 717        /* cb->acceptor_addrtype */
 718        p = xdr_reserve_space(xdr, 8);
 719        if (!p)
 720                return -ENOSPC;
 721        p = xdr_encode_hyper(p, cb->acceptor_addrtype);
 722
 723        /* cb->acceptor_address */
 724        err = gssx_enc_buffer(xdr, &cb->acceptor_address);
 725        if (err)
 726                return err;
 727
 728        /* cb->application_data */
 729        err = gssx_enc_buffer(xdr, &cb->application_data);
 730
 731        return err;
 732}
 733
 734void gssx_enc_accept_sec_context(struct rpc_rqst *req,
 735                                 struct xdr_stream *xdr,
 736                                 struct gssx_arg_accept_sec_context *arg)
 737{
 738        int err;
 739
 740        err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
 741        if (err)
 742                goto done;
 743
 744        /* arg->context_handle */
 745        if (arg->context_handle)
 746                err = gssx_enc_ctx(xdr, arg->context_handle);
 747        else
 748                err = gssx_enc_bool(xdr, 0);
 749        if (err)
 750                goto done;
 751
 752        /* arg->cred_handle */
 753        if (arg->cred_handle)
 754                err = gssx_enc_cred(xdr, arg->cred_handle);
 755        else
 756                err = gssx_enc_bool(xdr, 0);
 757        if (err)
 758                goto done;
 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        else
 769                err = gssx_enc_bool(xdr, 0);
 770        if (err)
 771                goto done;
 772
 773        err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
 774        if (err)
 775                goto done;
 776
 777        /* leave options empty for now, will add once we have any options
 778         * to pass up at all */
 779        /* arg->options */
 780        err = dummy_enc_opt_array(xdr, &arg->options);
 781
 782        xdr_inline_pages(&req->rq_rcv_buf,
 783                PAGE_SIZE/2 /* pretty arbitrary */,
 784                arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
 785done:
 786        if (err)
 787                dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
 788}
 789
 790int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
 791                                struct xdr_stream *xdr,
 792                                struct gssx_res_accept_sec_context *res)
 793{
 794        u32 value_follows;
 795        int err;
 796        struct page *scratch;
 797
 798        scratch = alloc_page(GFP_KERNEL);
 799        if (!scratch)
 800                return -ENOMEM;
 801        xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE);
 802
 803        /* res->status */
 804        err = gssx_dec_status(xdr, &res->status);
 805        if (err)
 806                goto out_free;
 807
 808        /* res->context_handle */
 809        err = gssx_dec_bool(xdr, &value_follows);
 810        if (err)
 811                goto out_free;
 812        if (value_follows) {
 813                err = gssx_dec_ctx(xdr, res->context_handle);
 814                if (err)
 815                        goto out_free;
 816        } else {
 817                res->context_handle = NULL;
 818        }
 819
 820        /* res->output_token */
 821        err = gssx_dec_bool(xdr, &value_follows);
 822        if (err)
 823                goto out_free;
 824        if (value_follows) {
 825                err = gssx_dec_buffer(xdr, res->output_token);
 826                if (err)
 827                        goto out_free;
 828        } else {
 829                res->output_token = NULL;
 830        }
 831
 832        /* res->delegated_cred_handle */
 833        err = gssx_dec_bool(xdr, &value_follows);
 834        if (err)
 835                goto out_free;
 836        if (value_follows) {
 837                /* we do not support upcall servers sending this data. */
 838                err = -EINVAL;
 839                goto out_free;
 840        }
 841
 842        /* res->options */
 843        err = gssx_dec_option_array(xdr, &res->options);
 844
 845out_free:
 846        __free_page(scratch);
 847        return err;
 848}
 849