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