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 = { .attr = {.len = 0} };
 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
 496
 497static int gssx_dec_name(struct xdr_stream *xdr,
 498                         struct gssx_name *name)
 499{
 500        struct xdr_netobj dummy_netobj = { .len = 0 };
 501        struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 };
 502        struct gssx_option_array dummy_option_array = { .count = 0 };
 503        int err;
 504
 505        /* name->display_name */
 506        err = gssx_dec_buffer(xdr, &name->display_name);
 507        if (err)
 508                return err;
 509
 510        /* name->name_type */
 511        err = gssx_dec_buffer(xdr, &dummy_netobj);
 512        if (err)
 513                return err;
 514
 515        /* name->exported_name */
 516        err = gssx_dec_buffer(xdr, &dummy_netobj);
 517        if (err)
 518                return err;
 519
 520        /* name->exported_composite_name */
 521        err = gssx_dec_buffer(xdr, &dummy_netobj);
 522        if (err)
 523                return err;
 524
 525        /* we assume we have no attributes for now, so simply consume them */
 526        /* name->name_attributes */
 527        err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
 528        if (err)
 529                return err;
 530
 531        /* we assume we have no options for now, so simply consume them */
 532        /* name->extensions */
 533        err = dummy_dec_opt_array(xdr, &dummy_option_array);
 534
 535        return err;
 536}
 537
 538static int dummy_enc_credel_array(struct xdr_stream *xdr,
 539                                  struct gssx_cred_element_array *cea)
 540{
 541        __be32 *p;
 542
 543        if (cea->count != 0)
 544                return -EINVAL;
 545
 546        p = xdr_reserve_space(xdr, 4);
 547        if (!p)
 548                return -ENOSPC;
 549        *p = 0;
 550
 551        return 0;
 552}
 553
 554static int gssx_enc_cred(struct xdr_stream *xdr,
 555                         struct gssx_cred *cred)
 556{
 557        int err;
 558
 559        /* cred->desired_name */
 560        err = gssx_enc_name(xdr, &cred->desired_name);
 561        if (err)
 562                return err;
 563
 564        /* cred->elements */
 565        err = dummy_enc_credel_array(xdr, &cred->elements);
 566
 567        /* cred->cred_handle_reference */
 568        err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
 569        if (err)
 570                return err;
 571
 572        /* cred->needs_release */
 573        err = gssx_enc_bool(xdr, cred->needs_release);
 574
 575        return err;
 576}
 577
 578static int gssx_enc_ctx(struct xdr_stream *xdr,
 579                        struct gssx_ctx *ctx)
 580{
 581        __be32 *p;
 582        int err;
 583
 584        /* ctx->exported_context_token */
 585        err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
 586        if (err)
 587                return err;
 588
 589        /* ctx->state */
 590        err = gssx_enc_buffer(xdr, &ctx->state);
 591        if (err)
 592                return err;
 593
 594        /* ctx->need_release */
 595        err = gssx_enc_bool(xdr, ctx->need_release);
 596        if (err)
 597                return err;
 598
 599        /* ctx->mech */
 600        err = gssx_enc_buffer(xdr, &ctx->mech);
 601        if (err)
 602                return err;
 603
 604        /* ctx->src_name */
 605        err = gssx_enc_name(xdr, &ctx->src_name);
 606        if (err)
 607                return err;
 608
 609        /* ctx->targ_name */
 610        err = gssx_enc_name(xdr, &ctx->targ_name);
 611        if (err)
 612                return err;
 613
 614        /* ctx->lifetime */
 615        p = xdr_reserve_space(xdr, 8+8);
 616        if (!p)
 617                return -ENOSPC;
 618        p = xdr_encode_hyper(p, ctx->lifetime);
 619
 620        /* ctx->ctx_flags */
 621        p = xdr_encode_hyper(p, ctx->ctx_flags);
 622
 623        /* ctx->locally_initiated */
 624        err = gssx_enc_bool(xdr, ctx->locally_initiated);
 625        if (err)
 626                return err;
 627
 628        /* ctx->open */
 629        err = gssx_enc_bool(xdr, ctx->open);
 630        if (err)
 631                return err;
 632
 633        /* leave options empty for now, will add once we have any options
 634         * to pass up at all */
 635        /* ctx->options */
 636        err = dummy_enc_opt_array(xdr, &ctx->options);
 637
 638        return err;
 639}
 640
 641static int gssx_dec_ctx(struct xdr_stream *xdr,
 642                        struct gssx_ctx *ctx)
 643{
 644        __be32 *p;
 645        int err;
 646
 647        /* ctx->exported_context_token */
 648        err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
 649        if (err)
 650                return err;
 651
 652        /* ctx->state */
 653        err = gssx_dec_buffer(xdr, &ctx->state);
 654        if (err)
 655                return err;
 656
 657        /* ctx->need_release */
 658        err = gssx_dec_bool(xdr, &ctx->need_release);
 659        if (err)
 660                return err;
 661
 662        /* ctx->mech */
 663        err = gssx_dec_buffer(xdr, &ctx->mech);
 664        if (err)
 665                return err;
 666
 667        /* ctx->src_name */
 668        err = gssx_dec_name(xdr, &ctx->src_name);
 669        if (err)
 670                return err;
 671
 672        /* ctx->targ_name */
 673        err = gssx_dec_name(xdr, &ctx->targ_name);
 674        if (err)
 675                return err;
 676
 677        /* ctx->lifetime */
 678        p = xdr_inline_decode(xdr, 8+8);
 679        if (unlikely(p == NULL))
 680                return -ENOSPC;
 681        p = xdr_decode_hyper(p, &ctx->lifetime);
 682
 683        /* ctx->ctx_flags */
 684        p = xdr_decode_hyper(p, &ctx->ctx_flags);
 685
 686        /* ctx->locally_initiated */
 687        err = gssx_dec_bool(xdr, &ctx->locally_initiated);
 688        if (err)
 689                return err;
 690
 691        /* ctx->open */
 692        err = gssx_dec_bool(xdr, &ctx->open);
 693        if (err)
 694                return err;
 695
 696        /* we assume we have no options for now, so simply consume them */
 697        /* ctx->options */
 698        err = dummy_dec_opt_array(xdr, &ctx->options);
 699
 700        return err;
 701}
 702
 703static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
 704{
 705        __be32 *p;
 706        int err;
 707
 708        /* cb->initiator_addrtype */
 709        p = xdr_reserve_space(xdr, 8);
 710        if (!p)
 711                return -ENOSPC;
 712        p = xdr_encode_hyper(p, cb->initiator_addrtype);
 713
 714        /* cb->initiator_address */
 715        err = gssx_enc_buffer(xdr, &cb->initiator_address);
 716        if (err)
 717                return err;
 718
 719        /* cb->acceptor_addrtype */
 720        p = xdr_reserve_space(xdr, 8);
 721        if (!p)
 722                return -ENOSPC;
 723        p = xdr_encode_hyper(p, cb->acceptor_addrtype);
 724
 725        /* cb->acceptor_address */
 726        err = gssx_enc_buffer(xdr, &cb->acceptor_address);
 727        if (err)
 728                return err;
 729
 730        /* cb->application_data */
 731        err = gssx_enc_buffer(xdr, &cb->application_data);
 732
 733        return err;
 734}
 735
 736void gssx_enc_accept_sec_context(struct rpc_rqst *req,
 737                                 struct xdr_stream *xdr,
 738                                 struct gssx_arg_accept_sec_context *arg)
 739{
 740        int err;
 741
 742        err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
 743        if (err)
 744                goto done;
 745
 746        /* arg->context_handle */
 747        if (arg->context_handle) {
 748                err = gssx_enc_ctx(xdr, arg->context_handle);
 749                if (err)
 750                        goto done;
 751        } else {
 752                err = gssx_enc_bool(xdr, 0);
 753        }
 754
 755        /* arg->cred_handle */
 756        if (arg->cred_handle) {
 757                err = gssx_enc_cred(xdr, arg->cred_handle);
 758                if (err)
 759                        goto done;
 760        } else {
 761                err = gssx_enc_bool(xdr, 0);
 762        }
 763
 764        /* arg->input_token */
 765        err = gssx_enc_in_token(xdr, &arg->input_token);
 766        if (err)
 767                goto done;
 768
 769        /* arg->input_cb */
 770        if (arg->input_cb) {
 771                err = gssx_enc_cb(xdr, arg->input_cb);
 772                if (err)
 773                        goto done;
 774        } else {
 775                err = gssx_enc_bool(xdr, 0);
 776        }
 777
 778        err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
 779        if (err)
 780                goto done;
 781
 782        /* leave options empty for now, will add once we have any options
 783         * to pass up at all */
 784        /* arg->options */
 785        err = dummy_enc_opt_array(xdr, &arg->options);
 786
 787done:
 788        if (err)
 789                dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
 790}
 791
 792int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
 793                                struct xdr_stream *xdr,
 794                                struct gssx_res_accept_sec_context *res)
 795{
 796        u32 value_follows;
 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        err = gssx_dec_bool(xdr, &value_follows);
 806        if (err)
 807                return err;
 808        if (value_follows) {
 809                err = gssx_dec_ctx(xdr, res->context_handle);
 810                if (err)
 811                        return err;
 812        } else {
 813                res->context_handle = NULL;
 814        }
 815
 816        /* res->output_token */
 817        err = gssx_dec_bool(xdr, &value_follows);
 818        if (err)
 819                return err;
 820        if (value_follows) {
 821                err = gssx_dec_buffer(xdr, res->output_token);
 822                if (err)
 823                        return err;
 824        } else {
 825                res->output_token = NULL;
 826        }
 827
 828        /* res->delegated_cred_handle */
 829        err = gssx_dec_bool(xdr, &value_follows);
 830        if (err)
 831                return err;
 832        if (value_follows) {
 833                /* we do not support upcall servers sending this data. */
 834                return -EINVAL;
 835        }
 836
 837        /* res->options */
 838        err = gssx_dec_option_array(xdr, &res->options);
 839
 840        return err;
 841}
 842