Imported Upstream version 0.2.5
[platform/upstream/libtirpc.git] / src / auth_gss.c
1 /*
2   auth_gss.c
3
4   RPCSEC_GSS client routines.
5
6   Copyright (c) 2000 The Regents of the University of Michigan.
7   All rights reserved.
8
9   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
10   All rights reserved, all wrongs reversed.
11
12   Redistribution and use in source and binary forms, with or without
13   modification, are permitted provided that the following conditions
14   are met:
15
16   1. Redistributions of source code must retain the above copyright
17      notice, this list of conditions and the following disclaimer.
18   2. Redistributions in binary form must reproduce the above copyright
19      notice, this list of conditions and the following disclaimer in the
20      documentation and/or other materials provided with the distribution.
21   3. Neither the name of the University nor the names of its
22      contributors may be used to endorse or promote products derived
23      from this software without specific prior written permission.
24
25   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
26   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <rpc/types.h>
45 #include <rpc/xdr.h>
46 #include <rpc/auth.h>
47 #include <rpc/auth_gss.h>
48 #include <rpc/clnt.h>
49 #include <netinet/in.h>
50 #include <gssapi/gssapi.h>
51
52 #include "debug.h"
53
54 static void     authgss_nextverf(AUTH *);
55 static bool_t   authgss_marshal(AUTH *, XDR *);
56 static bool_t   authgss_refresh(AUTH *, void *);
57 static bool_t   authgss_validate(AUTH *, struct opaque_auth *);
58 static void     authgss_destroy(AUTH *);
59 static void     authgss_destroy_context(AUTH *);
60 static bool_t   authgss_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);
61 static bool_t   authgss_unwrap(AUTH *, XDR *, xdrproc_t, caddr_t);
62
63
64 /*
65  * from mit-krb5-1.2.1 mechglue/mglueP.h:
66  * Array of context IDs typed by mechanism OID
67  */
68 typedef struct gss_union_ctx_id_t {
69         gss_OID     mech_type;
70         gss_ctx_id_t    internal_ctx_id;
71 } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
72
73 static struct auth_ops authgss_ops = {
74         authgss_nextverf,
75         authgss_marshal,
76         authgss_validate,
77         authgss_refresh,
78         authgss_destroy,
79         authgss_wrap,
80         authgss_unwrap
81 };
82
83
84 /* useful as i add more mechanisms */
85 void
86 print_rpc_gss_sec(struct rpc_gss_sec *ptr)
87 {
88 int i;
89 char *p;
90
91         if (libtirpc_debug_level < 4 || log_stderr == 0)
92                 return;
93
94         gss_log_debug("rpc_gss_sec:");
95         if(ptr->mech == NULL)
96                 gss_log_debug("NULL gss_OID mech");
97         else {
98                 fprintf(stderr, "     mechanism_OID: {");
99                 p = (char *)ptr->mech->elements;
100                 for (i=0; i < ptr->mech->length; i++)
101                         /* First byte of OIDs encoded to save a byte */
102                         if (i == 0) {
103                                 int first, second;
104                                 if (*p < 40) {
105                                         first = 0;
106                                         second = *p;
107                                 }
108                                 else if (40 <= *p && *p < 80) {
109                                         first = 1;
110                                         second = *p - 40;
111                                 }
112                                 else if (80 <= *p && *p < 127) {
113                                         first = 2;
114                                         second = *p - 80;
115                                 }
116                                 else {
117                                         /* Invalid value! */
118                                         first = -1;
119                                         second = -1;
120                                 }
121                                 fprintf(stderr, " %u %u", first, second);
122                                 p++;
123                         }
124                         else {
125                                 fprintf(stderr, " %u", (unsigned char)*p++);
126                         }
127                 fprintf(stderr, " }\n");
128         }
129         fprintf(stderr, "     qop: %d\n", ptr->qop);
130         fprintf(stderr, "     service: %d\n", ptr->svc);
131         fprintf(stderr, "     cred: %p\n", ptr->cred);
132 }
133
134 struct rpc_gss_data {
135         bool_t                   established;   /* context established */
136         gss_buffer_desc          gc_wire_verf;  /* save GSS_S_COMPLETE NULL RPC verfier
137                                                  * to process at end of context negotiation*/
138         CLIENT                  *clnt;          /* client handle */
139         gss_name_t               name;          /* service name */
140         struct rpc_gss_sec       sec;           /* security tuple */
141         gss_ctx_id_t             ctx;           /* context id */
142         struct rpc_gss_cred      gc;            /* client credentials */
143         u_int                    win;           /* sequence window */
144 };
145
146 #define AUTH_PRIVATE(auth)      ((struct rpc_gss_data *)auth->ah_private)
147
148 static struct timeval AUTH_TIMEOUT = { 25, 0 };
149
150 AUTH *
151 authgss_create(CLIENT *clnt, gss_name_t name, struct rpc_gss_sec *sec)
152 {
153         AUTH                    *auth, *save_auth;
154         struct rpc_gss_data     *gd;
155         OM_uint32               min_stat = 0;
156
157         gss_log_debug("in authgss_create()");
158
159         memset(&rpc_createerr, 0, sizeof(rpc_createerr));
160
161         if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
162                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
163                 rpc_createerr.cf_error.re_errno = ENOMEM;
164                 return (NULL);
165         }
166         if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
167                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
168                 rpc_createerr.cf_error.re_errno = ENOMEM;
169                 free(auth);
170                 return (NULL);
171         }
172         LIBTIRPC_DEBUG(3, ("authgss_create: name is %p", name));
173         if (name != GSS_C_NO_NAME) {
174                 if (gss_duplicate_name(&min_stat, name, &gd->name)
175                                                 != GSS_S_COMPLETE) {
176                         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
177                         rpc_createerr.cf_error.re_errno = ENOMEM;
178                         free(auth);
179                         return (NULL);
180                 }
181         }
182         else
183                 gd->name = name;
184
185         LIBTIRPC_DEBUG(3, ("authgss_create: gd->name is %p", gd->name));
186         gd->clnt = clnt;
187         gd->ctx = GSS_C_NO_CONTEXT;
188         gd->sec = *sec;
189
190         gd->gc.gc_v = RPCSEC_GSS_VERSION;
191         gd->gc.gc_proc = RPCSEC_GSS_INIT;
192         gd->gc.gc_svc = gd->sec.svc;
193
194         auth->ah_ops = &authgss_ops;
195         auth->ah_private = (caddr_t)gd;
196
197         save_auth = clnt->cl_auth;
198         clnt->cl_auth = auth;
199
200         if (!authgss_refresh(auth, NULL))
201                 auth = NULL;
202         else
203                 auth_get(auth); /* Reference for caller */
204
205         clnt->cl_auth = save_auth;
206
207         return (auth);
208 }
209
210 AUTH *
211 authgss_create_default(CLIENT *clnt, char *service, struct rpc_gss_sec *sec)
212 {
213         AUTH                    *auth;
214         OM_uint32                maj_stat = 0, min_stat = 0;
215         gss_buffer_desc          sname;
216         gss_name_t               name = GSS_C_NO_NAME;
217
218         gss_log_debug("in authgss_create_default()");
219
220
221         sname.value = service;
222         sname.length = strlen(service);
223
224         maj_stat = gss_import_name(&min_stat, &sname,
225                 (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
226                 &name);
227
228         if (maj_stat != GSS_S_COMPLETE) {
229                 gss_log_status("authgss_create_default: gss_import_name", 
230                         maj_stat, min_stat);
231                 rpc_createerr.cf_stat = RPC_AUTHERROR;
232                 return (NULL);
233         }
234
235         auth = authgss_create(clnt, name, sec);
236
237         if (name != GSS_C_NO_NAME) {
238                 LIBTIRPC_DEBUG(3, ("authgss_create_default: freeing name %p", name));
239                 gss_release_name(&min_stat, &name);
240         }
241
242         return (auth);
243 }
244
245 bool_t
246 authgss_get_private_data(AUTH *auth, struct authgss_private_data *pd)
247 {
248         struct rpc_gss_data     *gd;
249
250         gss_log_debug("in authgss_get_private_data()");
251
252         if (!auth || !pd)
253                 return (FALSE);
254
255         gd = AUTH_PRIVATE(auth);
256
257         if (!gd || !gd->established)
258                 return (FALSE);
259
260         pd->pd_ctx = gd->ctx;
261         pd->pd_ctx_hndl = gd->gc.gc_ctx;
262         pd->pd_seq_win = gd->win;
263         /*
264          * We've given this away -- don't try to use it ourself any more
265          * Caller should call authgss_free_private_data to free data.
266          * This also ensures that authgss_destroy_context() won't try to
267          * send an RPCSEC_GSS_DESTROY request which might inappropriately
268          * destroy the context.
269          */
270         gd->ctx = GSS_C_NO_CONTEXT;
271         gd->gc.gc_ctx.length = 0;
272         gd->gc.gc_ctx.value = NULL;
273
274         return (TRUE);
275 }
276
277 bool_t
278 authgss_free_private_data(struct authgss_private_data *pd)
279 {
280         OM_uint32       min_stat;
281         gss_log_debug("in authgss_free_private_data()");
282
283         if (!pd)
284                 return (FALSE);
285
286         if (pd->pd_ctx != GSS_C_NO_CONTEXT)
287                 gss_delete_sec_context(&min_stat, &pd->pd_ctx, NULL);
288         gss_release_buffer(&min_stat, &pd->pd_ctx_hndl);
289         memset(&pd->pd_ctx_hndl, 0, sizeof(pd->pd_ctx_hndl));
290         pd->pd_seq_win = 0;
291
292         return (TRUE);
293 }
294
295 static void
296 authgss_nextverf(AUTH *auth)
297 {
298         gss_log_debug("in authgss_nextverf()");
299         /* no action necessary */
300 }
301
302 static bool_t
303 authgss_marshal(AUTH *auth, XDR *xdrs)
304 {
305         XDR                      tmpxdrs;
306         char                     tmp[MAX_AUTH_BYTES];
307         struct rpc_gss_data     *gd;
308         gss_buffer_desc          rpcbuf, checksum;
309         OM_uint32                maj_stat, min_stat;
310         bool_t                   xdr_stat;
311
312         gss_log_debug("in authgss_marshal()");
313
314         gd = AUTH_PRIVATE(auth);
315
316         if (gd->established)
317                 gd->gc.gc_seq++;
318
319         xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE);
320
321         if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) {
322                 XDR_DESTROY(&tmpxdrs);
323                 return (FALSE);
324         }
325         auth->ah_cred.oa_flavor = RPCSEC_GSS;
326         auth->ah_cred.oa_base = tmp;
327         auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs);
328
329         XDR_DESTROY(&tmpxdrs);
330
331         if (!xdr_opaque_auth(xdrs, &auth->ah_cred))
332                 return (FALSE);
333
334         if (gd->gc.gc_proc == RPCSEC_GSS_INIT ||
335             gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
336                 return (xdr_opaque_auth(xdrs, &_null_auth));
337         }
338         /* Checksum serialized RPC header, up to and including credential. */
339         rpcbuf.length = XDR_GETPOS(xdrs);
340         XDR_SETPOS(xdrs, 0);
341         rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length);
342
343         maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop,
344                             &rpcbuf, &checksum);
345
346         if (maj_stat != GSS_S_COMPLETE) {
347                 gss_log_status("authgss_marshal: gss_get_mic", 
348                         maj_stat, min_stat);
349                 if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
350                         gd->established = FALSE;
351                         authgss_destroy_context(auth);
352                 }
353                 return (FALSE);
354         }
355         auth->ah_verf.oa_flavor = RPCSEC_GSS;
356         auth->ah_verf.oa_base = checksum.value;
357         auth->ah_verf.oa_length = checksum.length;
358
359         xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf);
360         gss_release_buffer(&min_stat, &checksum);
361
362         return (xdr_stat);
363 }
364
365 static bool_t
366 authgss_validate(AUTH *auth, struct opaque_auth *verf)
367 {
368         struct rpc_gss_data     *gd;
369         u_int                    num, qop_state;
370         gss_buffer_desc          signbuf, checksum;
371         OM_uint32                maj_stat, min_stat;
372
373         gss_log_debug("in authgss_validate()");
374
375         gd = AUTH_PRIVATE(auth);
376
377         if (gd->established == FALSE) {
378                 /* would like to do this only on NULL rpc --
379                  * gc->established is good enough.
380                  * save the on the wire verifier to validate last
381                  * INIT phase packet after decode if the major
382                  * status is GSS_S_COMPLETE
383                  */
384                 if ((gd->gc_wire_verf.value =
385                                 mem_alloc(verf->oa_length)) == NULL) {
386                         fprintf(stderr, "gss_validate: out of memory\n");
387                         return (FALSE);
388                 }
389                 memcpy(gd->gc_wire_verf.value, verf->oa_base, verf->oa_length);
390                 gd->gc_wire_verf.length = verf->oa_length;
391                 return (TRUE);
392         }
393
394         if (gd->gc.gc_proc == RPCSEC_GSS_INIT ||
395             gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
396                 num = htonl(gd->win);
397         }
398         else num = htonl(gd->gc.gc_seq);
399
400         signbuf.value = &num;
401         signbuf.length = sizeof(num);
402
403         checksum.value = verf->oa_base;
404         checksum.length = verf->oa_length;
405
406         maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf,
407                                   &checksum, &qop_state);
408
409         if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) {
410                 gss_log_status("authgss_validate: gss_verify_mic", 
411                         maj_stat, min_stat);
412                 if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
413                         gd->established = FALSE;
414                         authgss_destroy_context(auth);
415                 }
416                 return (FALSE);
417         }
418         return (TRUE);
419 }
420
421 static bool_t
422 authgss_refresh(AUTH *auth, void *dummy)
423 {
424         struct rpc_gss_data     *gd;
425         struct rpc_gss_init_res  gr;
426         gss_buffer_desc         *recv_tokenp, send_token;
427         OM_uint32                maj_stat, min_stat, call_stat, ret_flags;
428
429         gss_log_debug("in authgss_refresh()");
430
431         gd = AUTH_PRIVATE(auth);
432
433         if (gd->established)
434                 return (TRUE);
435
436         /* GSS context establishment loop. */
437         memset(&gr, 0, sizeof(gr));
438         recv_tokenp = GSS_C_NO_BUFFER;
439
440         print_rpc_gss_sec(&gd->sec);
441
442         for (;;) {
443                 /* print the token we just received */
444                 if (recv_tokenp != GSS_C_NO_BUFFER) {
445                         gss_log_debug("The token we just received (length %d):",
446                                   recv_tokenp->length);
447                         gss_log_hexdump(recv_tokenp->value, recv_tokenp->length, 0);
448                 }
449                 maj_stat = gss_init_sec_context(&min_stat,
450                                                 gd->sec.cred,
451                                                 &gd->ctx,
452                                                 gd->name,
453                                                 gd->sec.mech,
454                                                 gd->sec.req_flags,
455                                                 0,              /* time req */
456                                                 NULL,           /* channel */
457                                                 recv_tokenp,
458                                                 NULL,           /* used mech */
459                                                 &send_token,
460                                                 &ret_flags,
461                                                 NULL);          /* time rec */
462
463                 if (recv_tokenp != GSS_C_NO_BUFFER) {
464                         gss_release_buffer(&min_stat, &gr.gr_token);
465                         recv_tokenp = GSS_C_NO_BUFFER;
466                 }
467                 if (maj_stat != GSS_S_COMPLETE &&
468                     maj_stat != GSS_S_CONTINUE_NEEDED) {
469                         gss_log_status("authgss_refresh: gss_init_sec_context", 
470                                 maj_stat, min_stat);
471                         break;
472                 }
473                 if (send_token.length != 0) {
474                         memset(&gr, 0, sizeof(gr));
475
476                         /* print the token we are about to send */
477                         gss_log_debug("The token being sent (length %d):",
478                                   send_token.length);
479                         gss_log_hexdump(send_token.value, send_token.length, 0);
480
481                         call_stat = clnt_call(gd->clnt, NULLPROC,
482                                               (xdrproc_t)xdr_rpc_gss_init_args,
483                                               &send_token,
484                                               (xdrproc_t)xdr_rpc_gss_init_res,
485                                               (caddr_t)&gr, AUTH_TIMEOUT);
486
487                         gss_release_buffer(&min_stat, &send_token);
488
489                         if (call_stat != RPC_SUCCESS ||
490                             (gr.gr_major != GSS_S_COMPLETE &&
491                              gr.gr_major != GSS_S_CONTINUE_NEEDED))
492                                 return FALSE;
493
494                         if (gr.gr_ctx.length != 0) {
495                                 if (gd->gc.gc_ctx.value)
496                                         gss_release_buffer(&min_stat,
497                                                            &gd->gc.gc_ctx);
498                                 gd->gc.gc_ctx = gr.gr_ctx;
499                         }
500                         if (gr.gr_token.length != 0) {
501                                 if (maj_stat != GSS_S_CONTINUE_NEEDED)
502                                         break;
503                                 recv_tokenp = &gr.gr_token;
504                         }
505                         gd->gc.gc_proc = RPCSEC_GSS_CONTINUE_INIT;
506                 }
507
508                 /* GSS_S_COMPLETE => check gss header verifier,
509                  * usually checked in gss_validate
510                  */
511                 if (maj_stat == GSS_S_COMPLETE) {
512                         gss_buffer_desc   bufin;
513                         gss_buffer_desc   bufout;
514                         u_int seq, qop_state = 0;
515
516                         seq = htonl(gr.gr_win);
517                         bufin.value = (unsigned char *)&seq;
518                         bufin.length = sizeof(seq);
519                         bufout.value = (unsigned char *)gd->gc_wire_verf.value;
520                         bufout.length = gd->gc_wire_verf.length;
521
522                         maj_stat = gss_verify_mic(&min_stat, gd->ctx,
523                                 &bufin, &bufout, &qop_state);
524
525                         if (maj_stat != GSS_S_COMPLETE
526                                         || qop_state != gd->sec.qop) {
527                                 gss_log_status("authgss_refresh: gss_verify_mic", 
528                                         maj_stat, min_stat);
529                                 if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
530                                         gd->established = FALSE;
531                                         authgss_destroy_context(auth);
532                                 }
533                                 return (FALSE);
534                         }
535                         gd->established = TRUE;
536                         gd->gc.gc_proc = RPCSEC_GSS_DATA;
537                         gd->gc.gc_seq = 0;
538                         gd->win = gr.gr_win;
539                         break;
540                 }
541         }
542         /* End context negotiation loop. */
543         if (gd->gc.gc_proc != RPCSEC_GSS_DATA) {
544                 if (gr.gr_token.length != 0)
545                         gss_release_buffer(&min_stat, &gr.gr_token);
546
547                 authgss_destroy(auth);
548                 auth = NULL;
549                 rpc_createerr.cf_stat = RPC_AUTHERROR;
550
551                 return (FALSE);
552         }
553         return (TRUE);
554 }
555
556 bool_t
557 authgss_service(AUTH *auth, int svc)
558 {
559         struct rpc_gss_data     *gd;
560
561         gss_log_debug("in authgss_service()");
562
563         if (!auth)
564                 return(FALSE);
565         gd = AUTH_PRIVATE(auth);
566         if (!gd || !gd->established)
567                 return (FALSE);
568         gd->sec.svc = svc;
569         gd->gc.gc_svc = svc;
570         return (TRUE);
571 }
572
573 static void
574 authgss_destroy_context(AUTH *auth)
575 {
576         struct rpc_gss_data     *gd;
577         OM_uint32                min_stat;
578
579         gss_log_debug("in authgss_destroy_context()");
580
581         gd = AUTH_PRIVATE(auth);
582
583         if (gd->gc.gc_ctx.length != 0) {
584                 if (gd->established) {
585                         AUTH *save_auth = NULL;
586
587                         /* Make sure we use the right auth_ops */
588                         if (gd->clnt->cl_auth != auth) {
589                                 save_auth = gd->clnt->cl_auth;
590                                 gd->clnt->cl_auth = auth;
591                         }
592
593                         gd->gc.gc_proc = RPCSEC_GSS_DESTROY;
594                         clnt_call(gd->clnt, NULLPROC, (xdrproc_t)xdr_void, NULL,
595                                   (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT);
596                         
597                         if (save_auth != NULL)
598                                 gd->clnt->cl_auth = save_auth;
599                 }
600                 gss_release_buffer(&min_stat, &gd->gc.gc_ctx);
601                 /* XXX ANDROS check size of context  - should be 8 */
602                 memset(&gd->gc.gc_ctx, 0, sizeof(gd->gc.gc_ctx));
603         }
604         if (gd->ctx != GSS_C_NO_CONTEXT) {
605                 gss_delete_sec_context(&min_stat, &gd->ctx, NULL);
606                 gd->ctx = GSS_C_NO_CONTEXT;
607         }
608
609         /* free saved wire verifier (if any) */
610         mem_free(gd->gc_wire_verf.value, gd->gc_wire_verf.length);
611         gd->gc_wire_verf.value = NULL;
612         gd->gc_wire_verf.length = 0;
613
614         gd->established = FALSE;
615 }
616
617 static void
618 authgss_destroy(AUTH *auth)
619 {
620         struct rpc_gss_data     *gd;
621         OM_uint32                min_stat;
622
623         gss_log_debug("in authgss_destroy()");
624
625         gd = AUTH_PRIVATE(auth);
626
627         authgss_destroy_context(auth);
628
629         LIBTIRPC_DEBUG(3, ("authgss_destroy: freeing name %p", gd->name));
630         if (gd->name != GSS_C_NO_NAME)
631                 gss_release_name(&min_stat, &gd->name);
632
633         free(gd);
634         free(auth);
635 }
636
637 static bool_t
638 authgss_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
639 {
640         struct rpc_gss_data     *gd;
641
642         gss_log_debug("in authgss_wrap()");
643
644         gd = AUTH_PRIVATE(auth);
645
646         if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
647                 return ((*xdr_func)(xdrs, xdr_ptr));
648         }
649         return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
650                                  gd->ctx, gd->sec.qop,
651                                  gd->sec.svc, gd->gc.gc_seq));
652 }
653
654 static bool_t
655 authgss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
656 {
657         struct rpc_gss_data     *gd;
658
659         gss_log_debug("in authgss_unwrap()");
660
661         gd = AUTH_PRIVATE(auth);
662
663         if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
664                 return ((*xdr_func)(xdrs, xdr_ptr));
665         }
666         return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
667                                  gd->ctx, gd->sec.qop,
668                                  gd->sec.svc, gd->gc.gc_seq));
669 }