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