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