xref: /illumos-gate/usr/src/uts/common/gssapi/gssd_clnt_stubs.c (revision 09a48d4ca0ddda4ad26cc885769745870d989baf)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2012 Milan Jurik. All rights reserved.
25  */
26 
27 /*
28  *  GSSAPI library stub module for gssd.
29  */
30 
31 #include <mechglueP.h>
32 #include "gssd_prot.h"
33 #include <rpc/rpc.h>
34 
35 #include <sys/systm.h>
36 #include <sys/types.h>
37 #include <sys/cmn_err.h>
38 #include <sys/kmem.h>
39 #include <gssapi/kgssapi_defs.h>
40 #include <sys/debug.h>
41 
42 #ifdef GSSDEBUG
43 /*
44  * Kernel kgssd module debugging aid. The global variable "gss_log"
45  * is a bit mask which allows various types of debugging messages
46  * to be printed out.
47  *
48  *	 gss_log & 1  will cause actual failures to be printed.
49  *	 gss_log & 2  will cause informational messages to be
50  *	                 printed on the client side of kgssd.
51  *	 gss_log & 4  will cause informational messages to be
52  *	                 printed on the server side of kgssd.
53  *	 gss_log & 8  will cause informational messages to be
54  *	                 printed on both client and server side of kgssd.
55  */
56 
57 uint_t gss_log = 1;
58 
59 #endif /* GSSDEBUG */
60 
61 #ifdef  DEBUG
62 extern void prom_printf(const char *, ...);
63 #endif
64 
65 char *server = "localhost";
66 
67 static OM_uint32 kgss_sign_wrapped(void *, OM_uint32 *, gss_ctx_id_t, int,
68 	gss_buffer_t, gss_buffer_t,  OM_uint32);
69 
70 static OM_uint32 kgss_verify_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
71 	gss_buffer_t, gss_buffer_t, int *qop_state, OM_uint32);
72 
73 /* EXPORT DELETE START */
74 static OM_uint32 kgss_seal_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
75 	int, int, gss_buffer_t, int *, gss_buffer_t,  OM_uint32);
76 
77 static OM_uint32 kgss_unseal_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
78 	gss_buffer_t, gss_buffer_t, int *conf_state, int *qop_state,
79 	OM_uint32);
80 /* EXPORT DELETE END */
81 
82 static OM_uint32 kgss_delete_sec_context_wrapped(void *, OM_uint32 *,
83 	gssd_ctx_id_t *, gss_buffer_t, OM_uint32);
84 
85 static void __kgss_reset_mech(gss_mechanism *, gss_OID);
86 
87 #define	DEFAULT_MINOR_STAT	((OM_uint32) ~0)
88 
89 OM_uint32
90 kgss_acquire_cred_wrapped(minor_status,
91 			desired_name,
92 			time_req,
93 			desired_mechs,
94 			cred_usage,
95 			output_cred_handle,
96 			actual_mechs,
97 			time_rec,
98 			uid,
99 			gssd_cred_verifier)
100 	OM_uint32 *minor_status;
101 	const gss_name_t desired_name;
102 	OM_uint32 time_req;
103 	const gss_OID_set desired_mechs;
104 	int cred_usage;
105 	gssd_cred_id_t *output_cred_handle;
106 	gss_OID_set *actual_mechs;
107 	OM_uint32 *time_rec;
108 	uid_t uid;
109 	OM_uint32 *gssd_cred_verifier;
110 {
111 	CLIENT *clnt;
112 
113 	OM_uint32 	minor_status_temp;
114 	gss_buffer_desc	external_name;
115 	gss_OID		name_type;
116 	enum clnt_stat	client_stat;
117 	int		i;
118 
119 	gss_acquire_cred_arg arg;
120 	gss_acquire_cred_res res;
121 
122 	/* get the client handle to GSSD */
123 
124 	if ((clnt = getgssd_handle()) == NULL) {
125 		GSSLOG(1, "kgss_acquire_cred: can't connect to server on %s\n",
126 			server);
127 		return (GSS_S_FAILURE);
128 	}
129 
130 	/* convert the desired name from internal to external format */
131 
132 	if (gss_display_name(&minor_status_temp, desired_name, &external_name,
133 				&name_type) != GSS_S_COMPLETE) {
134 
135 		*minor_status = (OM_uint32) minor_status_temp;
136 		killgssd_handle(clnt);
137 		GSSLOG0(1, "kgss_acquire_cred: display name failed\n");
138 		return ((OM_uint32) GSS_S_FAILURE);
139 	}
140 
141 
142 	/* copy the procedure arguments into the rpc arg parameter */
143 
144 	arg.uid = (OM_uint32) uid;
145 
146 	arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
147 	arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value;
148 
149 	arg.name_type.GSS_OID_len =
150 		name_type == GSS_C_NULL_OID ?
151 			0 : (uint_t)name_type->length;
152 
153 	arg.name_type.GSS_OID_val =
154 		name_type == GSS_C_NULL_OID ?
155 			(char *)NULL : (char *)name_type->elements;
156 
157 	arg.time_req = time_req;
158 
159 	if (desired_mechs != GSS_C_NULL_OID_SET) {
160 		arg.desired_mechs.GSS_OID_SET_len =
161 			(uint_t)desired_mechs->count;
162 		arg.desired_mechs.GSS_OID_SET_val = (GSS_OID *)
163 			MALLOC(sizeof (GSS_OID) * desired_mechs->count);
164 
165 		for (i = 0; i < desired_mechs->count; i++) {
166 		    arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len =
167 			(uint_t)desired_mechs->elements[i].length;
168 		    arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val =
169 			(char *)MALLOC(desired_mechs->elements[i].length);
170 		    (void) memcpy(
171 			arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val,
172 			desired_mechs->elements[i].elements,
173 			desired_mechs->elements[i].length);
174 		}
175 	} else
176 		arg.desired_mechs.GSS_OID_SET_len = 0;
177 
178 	arg.cred_usage = cred_usage;
179 
180 	/* call the remote procedure */
181 
182 	bzero((caddr_t)&res, sizeof (res));
183 	client_stat = gss_acquire_cred_1(&arg, &res, clnt);
184 
185 	(void) gss_release_buffer(&minor_status_temp, &external_name);
186 	if (desired_mechs != GSS_C_NULL_OID_SET) {
187 		for (i = 0; i < desired_mechs->count; i++)
188 			FREE(arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val,
189 			    arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len);
190 		FREE(arg.desired_mechs.GSS_OID_SET_val,
191 		    arg.desired_mechs.GSS_OID_SET_len * sizeof (GSS_OID));
192 	}
193 
194 	if (client_stat != RPC_SUCCESS) {
195 
196 		/*
197 		 * if the RPC call times out, null out all return arguments,
198 		 * set minor_status to its maximum value, and return
199 		 * GSS_S_FAILURE
200 		 */
201 
202 		if (minor_status != NULL)
203 			*minor_status = DEFAULT_MINOR_STAT;
204 		if (output_cred_handle != NULL)
205 			*output_cred_handle = NULL;
206 		if (actual_mechs != NULL)
207 			*actual_mechs = NULL;
208 		if (time_rec != NULL)
209 			*time_rec = 0;
210 
211 		killgssd_handle(clnt);
212 		GSSLOG0(1, "kgss_acquire_cred: RPC call times out\n");
213 		return (GSS_S_FAILURE);
214 	}
215 
216 	/* copy the rpc results into the return arguments */
217 
218 	if (minor_status != NULL)
219 		*minor_status = res.minor_status;
220 
221 	if (output_cred_handle != NULL &&
222 		(res.status == GSS_S_COMPLETE)) {
223 	    *output_cred_handle =
224 		*((gssd_cred_id_t *)res.output_cred_handle.GSS_CRED_ID_T_val);
225 	    *gssd_cred_verifier = res.gssd_cred_verifier;
226 	}
227 
228 	if (res.status == GSS_S_COMPLETE &&
229 		res.actual_mechs.GSS_OID_SET_len != 0 &&
230 		actual_mechs != NULL) {
231 		*actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
232 		(*actual_mechs)->count =
233 					(int)res.actual_mechs.GSS_OID_SET_len;
234 		(*actual_mechs)->elements = (gss_OID)
235 			MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count);
236 
237 		for (i = 0; i < (*actual_mechs)->count; i++) {
238 		    (*actual_mechs)->elements[i].length = (OM_uint32)
239 			res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len;
240 		    (*actual_mechs)->elements[i].elements =
241 			(void *) MALLOC((*actual_mechs)->elements[i].length);
242 		    (void) memcpy((*actual_mechs)->elements[i].elements,
243 			res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
244 			(*actual_mechs)->elements[i].length);
245 		}
246 	} else {
247 		if (res.status == GSS_S_COMPLETE &&
248 			actual_mechs != NULL)
249 			(*actual_mechs) = NULL;
250 	}
251 
252 	if (time_rec != NULL)
253 		*time_rec = res.time_rec;
254 
255 	/*
256 	 * free the memory allocated for the results and return with the status
257 	 * received in the rpc call
258 	 */
259 
260 	clnt_freeres(clnt, xdr_gss_acquire_cred_res, (caddr_t)&res);
261 	killgssd_handle(clnt);
262 	return (res.status);
263 
264 }
265 
266 OM_uint32
267 kgss_acquire_cred(minor_status,
268 		desired_name,
269 		time_req,
270 		desired_mechs,
271 		cred_usage,
272 		output_cred_handle,
273 		actual_mechs,
274 		time_rec,
275 		uid)
276 	OM_uint32 *minor_status;
277 	const gss_name_t desired_name;
278 	OM_uint32 time_req;
279 	const gss_OID_set desired_mechs;
280 	int cred_usage;
281 	gss_cred_id_t *output_cred_handle;
282 	gss_OID_set *actual_mechs;
283 	OM_uint32 *time_rec;
284 	uid_t uid;
285 {
286 
287 	OM_uint32	err;
288 	struct kgss_cred *kcred;
289 
290 	kcred = KGSS_CRED_ALLOC();
291 	*output_cred_handle = (gss_cred_id_t)kcred;
292 	err = kgss_acquire_cred_wrapped(minor_status, desired_name, time_req,
293 		desired_mechs, cred_usage, &kcred->gssd_cred, actual_mechs,
294 		time_rec, uid, &kcred->gssd_cred_verifier);
295 	if (GSS_ERROR(err)) {
296 		KGSS_CRED_FREE(kcred);
297 		*output_cred_handle = GSS_C_NO_CREDENTIAL;
298 	}
299 	return (err);
300 }
301 
302 OM_uint32
303 kgss_add_cred_wrapped(minor_status,
304 			input_cred_handle,
305 			gssd_cred_verifier,
306 			desired_name,
307 			desired_mech_type,
308 			cred_usage,
309 			initiator_time_req,
310 			acceptor_time_req,
311 			actual_mechs,
312 			initiator_time_rec,
313 			acceptor_time_rec,
314 			uid)
315 	OM_uint32 *minor_status;
316 	gssd_cred_id_t input_cred_handle;
317 	OM_uint32 gssd_cred_verifier;
318 	gss_name_t desired_name;
319 	gss_OID desired_mech_type;
320 	int cred_usage;
321 	int initiator_time_req;
322 	int acceptor_time_req;
323 	gss_OID_set *actual_mechs;
324 	OM_uint32 *initiator_time_rec;
325 	OM_uint32 *acceptor_time_rec;
326 	uid_t uid;
327 {
328 	CLIENT *clnt;
329 
330 	OM_uint32 	minor_status_temp;
331 	gss_buffer_desc	external_name;
332 	gss_OID		name_type;
333 	int		i;
334 
335 	gss_add_cred_arg arg;
336 	gss_add_cred_res res;
337 
338 
339 	/*
340 	 * NULL the params here once
341 	 * If there are errors then we won't
342 	 * have to do it for every error
343 	 * case
344 	 */
345 
346 	if (minor_status != NULL)
347 		*minor_status = DEFAULT_MINOR_STAT;
348 	if (actual_mechs != NULL)
349 		*actual_mechs = NULL;
350 	if (initiator_time_rec != NULL)
351 		*initiator_time_rec = 0;
352 	if (acceptor_time_rec != NULL)
353 			*acceptor_time_rec = 0;
354 	/* get the client handle to GSSD */
355 
356 	if ((clnt = getgssd_handle()) == NULL) {
357 		GSSLOG(1, "kgss_add_cred: can't connect to server on %s\n",
358 			server);
359 		return (GSS_S_FAILURE);
360 	}
361 
362 
363 	/* convert the desired name from internal to external format */
364 
365 	if (gss_display_name(&minor_status_temp, desired_name, &external_name,
366 				&name_type) != GSS_S_COMPLETE) {
367 
368 		*minor_status = (OM_uint32) minor_status_temp;
369 		killgssd_handle(clnt);
370 		GSSLOG0(1, "kgss_acquire_cred: display name failed\n");
371 		return ((OM_uint32) GSS_S_FAILURE);
372 	}
373 
374 
375 	/* copy the procedure arguments into the rpc arg parameter */
376 
377 	arg.uid = (OM_uint32)uid;
378 	arg.input_cred_handle.GSS_CRED_ID_T_len =
379 			input_cred_handle == GSSD_NO_CREDENTIAL ?
380 			0 : (uint_t)sizeof (gssd_cred_id_t);
381 	arg.input_cred_handle.GSS_CRED_ID_T_val = (char *)&input_cred_handle;
382 	arg.gssd_cred_verifier = gssd_cred_verifier;
383 	arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
384 	arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value;
385 	arg.name_type.GSS_OID_len =
386 		name_type == GSS_C_NULL_OID ?
387 			0 : (uint_t)name_type->length;
388 	arg.name_type.GSS_OID_val =
389 		name_type == GSS_C_NULL_OID ?
390 			(char *)NULL : (char *)name_type->elements;
391 
392 	arg.desired_mech_type.GSS_OID_len =
393 		(uint_t)(desired_mech_type != GSS_C_NULL_OID ?
394 		desired_mech_type->length : 0);
395 	arg.desired_mech_type.GSS_OID_val =
396 		(char *)(desired_mech_type != GSS_C_NULL_OID ?
397 		desired_mech_type->elements : 0);
398 	arg.cred_usage = cred_usage;
399 	arg.initiator_time_req = initiator_time_req;
400 	arg.acceptor_time_req = acceptor_time_req;
401 
402 	/* call the remote procedure */
403 
404 	bzero((caddr_t)&res, sizeof (res));
405 	if (gss_add_cred_1(&arg, &res, clnt) != RPC_SUCCESS) {
406 
407 		/*
408 		 * if the RPC call times out, null out all return arguments,
409 		 * set minor_status to its maximum value, and return
410 		 * GSS_S_FAILURE
411 		 */
412 
413 		killgssd_handle(clnt);
414 		(void) gss_release_buffer(&minor_status_temp, &external_name);
415 		GSSLOG0(1, "kgss_add_cred: RPC call times out\n");
416 		return (GSS_S_FAILURE);
417 	}
418 
419 	/* free the allocated memory for the flattened name */
420 
421 	(void) gss_release_buffer(&minor_status_temp, &external_name);
422 
423 	/* copy the rpc results into the return arguments */
424 
425 	if (minor_status != NULL)
426 		*minor_status = res.minor_status;
427 
428 	if (res.status == GSS_S_COMPLETE &&
429 		res.actual_mechs.GSS_OID_SET_len != 0 &&
430 		actual_mechs != NULL) {
431 		*actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
432 		(*actual_mechs)->count =
433 					(int)res.actual_mechs.GSS_OID_SET_len;
434 		(*actual_mechs)->elements = (gss_OID)
435 			MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count);
436 
437 		for (i = 0; i < (*actual_mechs)->count; i++) {
438 		    (*actual_mechs)->elements[i].length = (OM_uint32)
439 			res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len;
440 		    (*actual_mechs)->elements[i].elements =
441 			(void *) MALLOC((*actual_mechs)->elements[i].length);
442 		    (void) memcpy((*actual_mechs)->elements[i].elements,
443 			res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
444 			(*actual_mechs)->elements[i].length);
445 		}
446 	} else {
447 		if (res.status == GSS_S_COMPLETE && actual_mechs != NULL)
448 			(*actual_mechs) = NULL;
449 	}
450 	if (initiator_time_rec != NULL)
451 		*initiator_time_rec = res.acceptor_time_rec;
452 	if (acceptor_time_rec != NULL)
453 		*acceptor_time_rec = res.acceptor_time_rec;
454 
455 	/*
456 	 * free the memory allocated for the results and return with the status
457 	 * received in the rpc call
458 	 */
459 
460 	clnt_freeres(clnt, xdr_gss_add_cred_res, (caddr_t)&res);
461 	killgssd_handle(clnt);
462 	return (res.status);
463 
464 }
465 
466 OM_uint32
467 kgss_add_cred(minor_status,
468 			input_cred_handle,
469 			desired_name,
470 			desired_mech_type,
471 			cred_usage,
472 			initiator_time_req,
473 			acceptor_time_req,
474 			actual_mechs,
475 			initiator_time_rec,
476 			acceptor_time_rec,
477 			uid)
478 	OM_uint32 *minor_status;
479 	gss_cred_id_t input_cred_handle;
480 	gss_name_t desired_name;
481 	gss_OID desired_mech_type;
482 	int cred_usage;
483 	int initiator_time_req;
484 	int acceptor_time_req;
485 	gss_OID_set *actual_mechs;
486 	OM_uint32 *initiator_time_rec;
487 	OM_uint32 *acceptor_time_rec;
488 	uid_t uid;
489 {
490 
491 	OM_uint32	err;
492 	OM_uint32 gssd_cred_verifier;
493 	gssd_cred_id_t gssd_input_cred_handle;
494 
495 	if (input_cred_handle != GSS_C_NO_CREDENTIAL) {
496 		gssd_cred_verifier = KCRED_TO_CREDV(input_cred_handle);
497 		gssd_input_cred_handle = KCRED_TO_CRED(input_cred_handle);
498 	} else {
499 		gssd_input_cred_handle = GSSD_NO_CREDENTIAL;
500 	}
501 
502 	err = kgss_add_cred_wrapped(minor_status, gssd_input_cred_handle,
503 			gssd_cred_verifier, desired_name, desired_mech_type,
504 			cred_usage, initiator_time_req, acceptor_time_req,
505 			actual_mechs, initiator_time_rec,
506 			acceptor_time_rec, uid);
507 	return (err);
508 }
509 
510 
511 OM_uint32
512 kgss_release_cred_wrapped(minor_status,
513 			cred_handle,
514 			uid,
515 			gssd_cred_verifier)
516     OM_uint32 *minor_status;
517     gssd_cred_id_t *cred_handle;
518     uid_t uid;
519     OM_uint32  gssd_cred_verifier;
520 {
521 	CLIENT *clnt;
522 
523 	gss_release_cred_arg arg;
524 	gss_release_cred_res res;
525 
526 
527 	/* get the client handle to GSSD */
528 
529 	if ((clnt = getgssd_handle()) == NULL) {
530 		GSSLOG(1, "kgss_release_cred: can't connect to server on %s\n",
531 			server);
532 		return (GSS_S_FAILURE);
533 	}
534 
535 	/* copy the procedure arguments into the rpc arg parameter */
536 
537 	arg.uid = (OM_uint32)uid;
538 	arg.gssd_cred_verifier = gssd_cred_verifier;
539 
540 	if (cred_handle != NULL) {
541 		arg.cred_handle.GSS_CRED_ID_T_len =
542 					(uint_t)sizeof (gssd_cred_id_t);
543 		arg.cred_handle.GSS_CRED_ID_T_val = (char *)cred_handle;
544 	} else
545 		arg.cred_handle.GSS_CRED_ID_T_len = 0;
546 
547 	/* call the remote procedure */
548 
549 	bzero((caddr_t)&res, sizeof (res));
550 	if (gss_release_cred_1(&arg, &res, clnt) != RPC_SUCCESS) {
551 
552 	/*
553 	 * if the RPC call times out, null out all return arguments, set
554 	 * minor_status to its maximum value, and return GSS_S_FAILURE
555 	 */
556 
557 		if (minor_status != NULL)
558 			*minor_status = DEFAULT_MINOR_STAT;
559 		if (cred_handle != NULL)
560 			*cred_handle = NULL;
561 
562 		killgssd_handle(clnt);
563 		GSSLOG0(1, "kgss_release_cred: RPC call times out\n");
564 		return (GSS_S_FAILURE);
565 	}
566 
567 	/* if the release succeeded, null out the cred_handle */
568 
569 	if (res.status == GSS_S_COMPLETE && cred_handle != NULL)
570 		*cred_handle = NULL;
571 
572 	/* copy the rpc results into the return arguments */
573 
574 	if (minor_status != NULL)
575 		*minor_status = res.minor_status;
576 
577 	/* return with status returned in rpc call */
578 
579 	killgssd_handle(clnt);
580 
581 	return (res.status);
582 
583 }
584 
585 OM_uint32
586 kgss_release_cred(minor_status,
587 			cred_handle,
588 			uid)
589     OM_uint32 *minor_status;
590     gss_cred_id_t *cred_handle;
591     uid_t uid;
592 
593 {
594 
595 	OM_uint32	err;
596 	struct kgss_cred *kcred;
597 
598 	if (*cred_handle == GSS_C_NO_CREDENTIAL)
599 		return (GSS_S_COMPLETE);
600 	else
601 		kcred = KCRED_TO_KGSS_CRED(*cred_handle);
602 
603 	err = kgss_release_cred_wrapped(minor_status, &kcred->gssd_cred,
604 		uid, kcred->gssd_cred_verifier);
605 	KGSS_CRED_FREE(kcred);
606 	*cred_handle = GSS_C_NO_CREDENTIAL;
607 	return (err);
608 }
609 
610 static OM_uint32
611 kgss_init_sec_context_wrapped(
612 	OM_uint32 *minor_status,
613 	const gssd_cred_id_t claimant_cred_handle,
614 	OM_uint32 gssd_cred_verifier,
615 	gssd_ctx_id_t *context_handle,
616 	OM_uint32 *gssd_context_verifier,
617 	const gss_name_t target_name,
618 	const gss_OID mech_type,
619 	int req_flags,
620 	OM_uint32 time_req,
621 	const gss_channel_bindings_t input_chan_bindings,
622 	const gss_buffer_t input_token,
623 	gss_OID *actual_mech_type,
624 	gss_buffer_t output_token,
625 	int *ret_flags,
626 	OM_uint32 *time_rec,
627 	uid_t uid)
628 {
629 	CLIENT *clnt;
630 
631 	OM_uint32 	minor_status_temp;
632 	gss_buffer_desc	external_name;
633 	gss_OID		name_type;
634 
635 	gss_init_sec_context_arg arg;
636 	gss_init_sec_context_res res;
637 
638 	/* get the client handle to GSSD */
639 
640 	if ((clnt = getgssd_handle()) == NULL) {
641 		GSSLOG(1,
642 		    "kgss_init_sec_context: can't connect to server on %s\n",
643 		    server);
644 		return (GSS_S_FAILURE);
645 	}
646 
647 	/* convert the target name from internal to external format */
648 
649 	if (gss_display_name(&minor_status_temp, target_name,
650 	    &external_name, &name_type) != GSS_S_COMPLETE) {
651 
652 		*minor_status = (OM_uint32) minor_status_temp;
653 		killgssd_handle(clnt);
654 		GSSLOG0(1, "kgss_init_sec_context: can't display name\n");
655 		return ((OM_uint32) GSS_S_FAILURE);
656 	}
657 
658 
659 	/* copy the procedure arguments into the rpc arg parameter */
660 
661 	arg.uid = (OM_uint32)uid;
662 
663 	arg.context_handle.GSS_CTX_ID_T_len =
664 	    *context_handle == GSSD_NO_CONTEXT ?
665 	    0 : (uint_t)sizeof (gssd_ctx_id_t);
666 	arg.context_handle.GSS_CTX_ID_T_val =  (char *)context_handle;
667 
668 	arg.gssd_context_verifier =  *gssd_context_verifier;
669 
670 	arg.claimant_cred_handle.GSS_CRED_ID_T_len =
671 	    claimant_cred_handle == GSSD_NO_CREDENTIAL ?
672 	    0 : (uint_t)sizeof (gssd_cred_id_t);
673 	arg.claimant_cred_handle.GSS_CRED_ID_T_val =
674 	    (char *)&claimant_cred_handle;
675 	arg.gssd_cred_verifier = gssd_cred_verifier;
676 
677 	arg.target_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
678 	arg.target_name.GSS_BUFFER_T_val = (char *)external_name.value;
679 
680 	arg.name_type.GSS_OID_len =
681 	    name_type == GSS_C_NULL_OID ? 0 : (uint_t)name_type->length;
682 
683 	arg.name_type.GSS_OID_val =
684 	    name_type == GSS_C_NULL_OID ?
685 	    (char *)NULL : (char *)name_type->elements;
686 
687 	arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ?
688 	    mech_type->length : 0);
689 	arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ?
690 	    mech_type->elements : 0);
691 
692 	arg.req_flags = req_flags;
693 
694 	arg.time_req = time_req;
695 
696 	if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
697 		arg.input_chan_bindings.present = YES;
698 		arg.input_chan_bindings.initiator_addrtype =
699 		    input_chan_bindings->initiator_addrtype;
700 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len =
701 		    (uint_t)input_chan_bindings->initiator_address.length;
702 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val =
703 		    (void *)input_chan_bindings->initiator_address.value;
704 		arg.input_chan_bindings.acceptor_addrtype =
705 		    input_chan_bindings->acceptor_addrtype;
706 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len =
707 		    (uint_t)input_chan_bindings->acceptor_address.length;
708 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val =
709 		    (void *)input_chan_bindings->acceptor_address.value;
710 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_len =
711 		    (uint_t)input_chan_bindings->application_data.length;
712 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_val =
713 		    (void *)input_chan_bindings->application_data.value;
714 	} else {
715 		arg.input_chan_bindings.present = NO;
716 		arg.input_chan_bindings.initiator_addrtype = 0;
717 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0;
718 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0;
719 		arg.input_chan_bindings.acceptor_addrtype = 0;
720 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0;
721 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0;
722 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0;
723 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0;
724 	}
725 
726 	arg.input_token.GSS_BUFFER_T_len =
727 	    (uint_t)(input_token != GSS_C_NO_BUFFER ? input_token->length : 0);
728 	arg.input_token.GSS_BUFFER_T_val =
729 	    (char *)(input_token != GSS_C_NO_BUFFER ? input_token->value : 0);
730 
731 	/* call the remote procedure */
732 
733 	bzero((caddr_t)&res, sizeof (res));
734 	if (gss_init_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
735 
736 	/*
737 	 * if the RPC call times out, null out all return arguments, set
738 	 * minor_status to its maximum value, and return GSS_S_FAILURE
739 	 */
740 
741 		if (minor_status != NULL)
742 			*minor_status = DEFAULT_MINOR_STAT;
743 		if (actual_mech_type != NULL)
744 			*actual_mech_type = NULL;
745 		if (output_token != NULL)
746 			output_token->length = 0;
747 		if (ret_flags != NULL)
748 			*ret_flags = 0;
749 		if (time_rec != NULL)
750 			*time_rec = 0;
751 
752 		killgssd_handle(clnt);
753 		(void) gss_release_buffer(&minor_status_temp, &external_name);
754 		GSSLOG0(1, "kgss_init_sec_context: RPC call times out\n");
755 		return (GSS_S_FAILURE);
756 	}
757 
758 	/* free the allocated memory for the flattened name */
759 
760 	(void) gss_release_buffer(&minor_status_temp, &external_name);
761 
762 	if (minor_status != NULL)
763 		*minor_status = res.minor_status;
764 
765 	if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
766 		output_token->length =
767 		    (size_t)res.output_token.GSS_BUFFER_T_len;
768 		output_token->value =
769 		    (void *)MALLOC(output_token->length);
770 		(void) memcpy(output_token->value,
771 		    res.output_token.GSS_BUFFER_T_val, output_token->length);
772 	}
773 
774 	/* if the call was successful, copy out the results */
775 	if (res.status == (OM_uint32) GSS_S_COMPLETE ||
776 	    res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) {
777 		/*
778 		 * if the return code is GSS_S_CONTINUE_NEEDED
779 		 * ignore all return parameters except for
780 		 * status codes, output token and context handle.
781 		 */
782 		*context_handle =
783 		    *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val);
784 		*gssd_context_verifier = res.gssd_context_verifier;
785 
786 		if (res.status == GSS_S_COMPLETE) {
787 			if (actual_mech_type != NULL) {
788 				*actual_mech_type =
789 				    (gss_OID) MALLOC(sizeof (gss_OID_desc));
790 				(*actual_mech_type)->length =
791 				    (OM_UINT32)res.actual_mech_type.GSS_OID_len;
792 				(*actual_mech_type)->elements =
793 				    (void *)MALLOC((*actual_mech_type)->length);
794 				(void) memcpy((*actual_mech_type)->elements,
795 				    (void *)res.actual_mech_type.GSS_OID_val,
796 				    (*actual_mech_type)->length);
797 			}
798 
799 
800 			if (ret_flags != NULL)
801 				*ret_flags = res.ret_flags;
802 
803 			if (time_rec != NULL)
804 				*time_rec = res.time_rec;
805 		}
806 	}
807 
808 	/*
809 	 * free the memory allocated for the results and return with the status
810 	 * received in the rpc call
811 	 */
812 
813 	clnt_freeres(clnt, xdr_gss_init_sec_context_res, (caddr_t)&res);
814 	killgssd_handle(clnt);
815 	return (res.status);
816 
817 }
818 
819 static struct gss_config default_gc = {
820 	{ 0, NULL},
821 	NULL,
822 	NULL,
823 	0,
824 /* EXPORT DELETE START */ /* CRYPT DELETE START */
825 	kgss_unseal_wrapped,
826 /* EXPORT DELETE END */ /* CRYPT DELETE END */
827 	NULL,		/* kgss_delete_sec_context_wrapped */
828 /* EXPORT DELETE START */ /* CRYPT DELETE START */
829 	kgss_seal_wrapped,
830 /* EXPORT DELETE END */ /* CRYPT DELETE END */
831 	NULL,		/* kgss_import_sec_context */
832 /* EXPORT DELETE START */
833 /* CRYPT DELETE START */
834 #if 0
835 /* CRYPT DELETE END */
836 	kgss_seal_wrapped,
837 	kgss_unseal_wrapped,
838 /* CRYPT DELETE START */
839 #endif
840 /* CRYPT DELETE END */
841 /* EXPORT DELETE END */
842 	kgss_sign_wrapped,
843 	kgss_verify_wrapped
844 };
845 
846 void
847 kgss_free_oid(gss_OID oid)
848 {
849 	FREE(oid->elements, oid->length);
850 	FREE(oid, sizeof (gss_OID_desc));
851 }
852 
853 OM_uint32
854 kgss_init_sec_context(
855 	OM_uint32 *minor_status,
856 	const gss_cred_id_t claimant_cred_handle,
857 	gss_ctx_id_t *context_handle,
858 	const gss_name_t target_name,
859 	const gss_OID mech_type,
860 	int req_flags,
861 	OM_uint32 time_req,
862 	const gss_channel_bindings_t input_chan_bindings,
863 	const gss_buffer_t input_token,
864 	gss_OID *actual_mech_type,
865 	gss_buffer_t output_token,
866 	int *ret_flags,
867 	OM_uint32 *time_rec,
868 	uid_t uid)
869 {
870 	OM_uint32	err;
871 	struct kgss_ctx	*kctx;
872 	gss_OID	amt;
873 	gssd_cred_id_t gssd_cl_cred_handle;
874 	OM_uint32 gssd_cred_verifier;
875 
876 	/*
877 	 * If this is an initial call, we'll need to create the
878 	 * wrapper struct that contains kernel state information, and
879 	 * a reference to the handle from gssd.
880 	 */
881 	if (*context_handle == GSS_C_NO_CONTEXT) {
882 		kctx = KGSS_ALLOC();
883 		/*
884 		 * The default gss-mechanism struct as pointers to
885 		 * the sign/seal/verify/unseal routines that make
886 		 * upcalls to gssd.
887 		 */
888 		kctx->mech = &default_gc;
889 		kctx->gssd_ctx = GSSD_NO_CONTEXT;
890 		*context_handle = (gss_ctx_id_t)kctx;
891 	} else
892 		kctx = (struct kgss_ctx *)*context_handle;
893 
894 	if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
895 		gssd_cred_verifier = KCRED_TO_CREDV(claimant_cred_handle);
896 		gssd_cl_cred_handle = KCRED_TO_CRED(claimant_cred_handle);
897 	} else {
898 		gssd_cl_cred_handle = GSSD_NO_CREDENTIAL;
899 	}
900 
901 	/*
902 	 * We need to know the resulting mechanism oid, so allocate
903 	 * it if the caller won't.
904 	 */
905 	if (actual_mech_type == NULL)
906 		actual_mech_type = &amt;
907 
908 	err = kgss_init_sec_context_wrapped(minor_status, gssd_cl_cred_handle,
909 	    gssd_cred_verifier, &kctx->gssd_ctx, &kctx->gssd_ctx_verifier,
910 	    target_name, mech_type, req_flags, time_req,
911 	    input_chan_bindings, input_token, actual_mech_type,
912 	    output_token, ret_flags, time_rec, uid);
913 
914 	if (GSS_ERROR(err)) {
915 		KGSS_FREE(kctx);
916 		*context_handle = GSS_C_NO_CONTEXT;
917 	} else if (err == GSS_S_COMPLETE) {
918 		/*
919 		 * Now check if there is a kernel module for this
920 		 * mechanism OID. If so, set the gss_mechanism structure
921 		 * in the wrapper context to point to the kernel mech.
922 		 */
923 		__kgss_reset_mech(&kctx->mech, *actual_mech_type);
924 
925 		/*
926 		 * If the mech oid was allocated for us, free it.
927 		 */
928 		if (&amt == actual_mech_type) {
929 			kgss_free_oid(amt);
930 		}
931 	}
932 	return (err);
933 }
934 
935 static OM_uint32
936 kgss_accept_sec_context_wrapped(
937 	OM_uint32 *minor_status,
938 	gssd_ctx_id_t *context_handle,
939 	OM_uint32 *gssd_context_verifier,
940 	const gssd_cred_id_t verifier_cred_handle,
941 	OM_uint32 gssd_cred_verifier,
942 	const gss_buffer_t input_token,
943 	const gss_channel_bindings_t input_chan_bindings,
944 	gss_buffer_t src_name,
945 	gss_OID *mech_type,
946 	gss_buffer_t output_token,
947 	int *ret_flags,
948 	OM_uint32 *time_rec,
949 	gss_cred_id_t *delegated_cred_handle,
950 	uid_t uid)
951 {
952 	CLIENT *clnt;
953 
954 	gss_accept_sec_context_arg arg;
955 	gss_accept_sec_context_res res;
956 	struct kgss_cred *kcred;
957 
958 	/* get the client handle to GSSD */
959 
960 	if ((clnt = getgssd_handle()) == NULL) {
961 		GSSLOG(1,
962 		    "kgss_accept_sec_context: can't connect to server on %s\n",
963 		    server);
964 		return (GSS_S_FAILURE);
965 	}
966 
967 	/* copy the procedure arguments into the rpc arg parameter */
968 
969 	arg.uid = (OM_uint32)uid;
970 
971 	arg.context_handle.GSS_CTX_ID_T_len =
972 	    *context_handle == GSSD_NO_CONTEXT ?
973 	    0 : (uint_t)sizeof (gssd_ctx_id_t);
974 	arg.context_handle.GSS_CTX_ID_T_val =  (char *)context_handle;
975 	arg.gssd_context_verifier = *gssd_context_verifier;
976 
977 	arg.verifier_cred_handle.GSS_CRED_ID_T_len =
978 	    verifier_cred_handle == GSSD_NO_CREDENTIAL ?
979 	    0 : (uint_t)sizeof (gssd_cred_id_t);
980 	arg.verifier_cred_handle.GSS_CRED_ID_T_val =
981 	    (char *)&verifier_cred_handle;
982 	arg.gssd_cred_verifier = gssd_cred_verifier;
983 
984 	arg.input_token_buffer.GSS_BUFFER_T_len =
985 	    (uint_t)(input_token != GSS_C_NO_BUFFER ? input_token->length : 0);
986 	arg.input_token_buffer.GSS_BUFFER_T_val =
987 	    (char *)(input_token != GSS_C_NO_BUFFER ? input_token->value : 0);
988 
989 	if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
990 		arg.input_chan_bindings.present = YES;
991 		arg.input_chan_bindings.initiator_addrtype =
992 		    input_chan_bindings->initiator_addrtype;
993 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len =
994 		    (uint_t)input_chan_bindings->initiator_address.length;
995 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val =
996 		    (void *)input_chan_bindings->initiator_address.value;
997 		arg.input_chan_bindings.acceptor_addrtype =
998 		    input_chan_bindings->acceptor_addrtype;
999 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len =
1000 		    (uint_t)input_chan_bindings->acceptor_address.length;
1001 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val =
1002 		    (void *)input_chan_bindings->acceptor_address.value;
1003 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_len =
1004 		    (uint_t)input_chan_bindings->application_data.length;
1005 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_val =
1006 		    (void *)input_chan_bindings->application_data.value;
1007 	} else {
1008 
1009 		arg.input_chan_bindings.present = NO;
1010 		arg.input_chan_bindings.initiator_addrtype = 0;
1011 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0;
1012 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0;
1013 		arg.input_chan_bindings.acceptor_addrtype = 0;
1014 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0;
1015 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0;
1016 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0;
1017 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0;
1018 	}
1019 
1020 	/* set the return parameters in case of errors.... */
1021 	if (minor_status != NULL)
1022 		*minor_status = DEFAULT_MINOR_STAT;
1023 	if (src_name != NULL) {
1024 		src_name->length = 0;
1025 		src_name->value = NULL;
1026 	}
1027 	if (mech_type != NULL)
1028 		*mech_type = NULL;
1029 	if (output_token != NULL)
1030 		output_token->length = 0;
1031 	if (ret_flags != NULL)
1032 		*ret_flags = 0;
1033 	if (time_rec != NULL)
1034 		*time_rec = 0;
1035 	if (delegated_cred_handle != NULL)
1036 		*delegated_cred_handle = NULL;
1037 
1038 	/* call the remote procedure */
1039 
1040 	bzero((caddr_t)&res, sizeof (res));
1041 	if (gss_accept_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
1042 		killgssd_handle(clnt);
1043 		GSSLOG0(1, "kgss_accept_sec_context: RPC call times out\n");
1044 		return (GSS_S_FAILURE);
1045 	}
1046 
1047 	if (minor_status != NULL)
1048 		*minor_status = res.minor_status;
1049 
1050 	if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
1051 		output_token->length = res.output_token.GSS_BUFFER_T_len;
1052 		output_token->value = (void *)MALLOC(output_token->length);
1053 		(void) memcpy(output_token->value,
1054 		    res.output_token.GSS_BUFFER_T_val, output_token->length);
1055 	}
1056 
1057 	/* if the call was successful, copy out the results */
1058 
1059 	if (res.status == (OM_uint32)GSS_S_COMPLETE ||
1060 	    res.status == (OM_uint32)GSS_S_CONTINUE_NEEDED) {
1061 
1062 		/*
1063 		 * the only parameters that are ready when we
1064 		 * get GSS_S_CONTINUE_NEEDED are: minor, ctxt_handle,
1065 		 * and the output token to send to the peer.
1066 		 */
1067 
1068 		*context_handle = *((gssd_ctx_id_t *)
1069 		    res.context_handle.GSS_CTX_ID_T_val);
1070 		*gssd_context_verifier = res.gssd_context_verifier;
1071 
1072 		/* these other parameters are only ready upon GSS_S_COMPLETE */
1073 		if (res.status == (OM_uint32)GSS_S_COMPLETE) {
1074 
1075 			if (src_name != NULL) {
1076 				src_name->length =
1077 				    res.src_name.GSS_BUFFER_T_len;
1078 				src_name->value = res.src_name.GSS_BUFFER_T_val;
1079 				res.src_name.GSS_BUFFER_T_val = NULL;
1080 				res.src_name.GSS_BUFFER_T_len = 0;
1081 			}
1082 
1083 			/*
1084 			 * move mech type returned to mech_type
1085 			 * for gss_import_name_for_mech()
1086 			 */
1087 			if (mech_type != NULL) {
1088 				*mech_type =
1089 				    (gss_OID)MALLOC(sizeof (gss_OID_desc));
1090 				(*mech_type)->length =
1091 				    (OM_UINT32)res.mech_type.GSS_OID_len;
1092 				(*mech_type)->elements =
1093 				    (void *)MALLOC((*mech_type)->length);
1094 				(void) memcpy((*mech_type)->elements,
1095 				    res.mech_type.GSS_OID_val,
1096 				    (*mech_type)->length);
1097 			}
1098 
1099 			if (ret_flags != NULL)
1100 				*ret_flags = res.ret_flags;
1101 
1102 			if (time_rec != NULL)
1103 				*time_rec = res.time_rec;
1104 
1105 			if ((delegated_cred_handle != NULL) &&
1106 			    (res.delegated_cred_handle.GSS_CRED_ID_T_len
1107 			    != 0)) {
1108 				kcred = KGSS_CRED_ALLOC();
1109 				kcred->gssd_cred =
1110 				    *((gssd_cred_id_t *)
1111 				    res.delegated_cred_handle.GSS_CRED_ID_T_val);
1112 				kcred->gssd_cred_verifier =
1113 				    res.gssd_context_verifier;
1114 				*delegated_cred_handle = (gss_cred_id_t)kcred;
1115 			}
1116 
1117 		}
1118 	}
1119 
1120 
1121 	/*
1122 	 * free the memory allocated for the results and return with the status
1123 	 * received in the rpc call
1124 	 */
1125 
1126 	clnt_freeres(clnt, xdr_gss_accept_sec_context_res, (caddr_t)&res);
1127 	killgssd_handle(clnt);
1128 	return (res.status);
1129 
1130 }
1131 
1132 OM_uint32
1133 kgss_accept_sec_context(
1134 	OM_uint32 *minor_status,
1135 	gss_ctx_id_t *context_handle,
1136 	const gss_cred_id_t verifier_cred_handle,
1137 	const gss_buffer_t input_token,
1138 	const gss_channel_bindings_t input_chan_bindings,
1139 	gss_buffer_t src_name,
1140 	gss_OID *mech_type,
1141 	gss_buffer_t output_token,
1142 	int *ret_flags,
1143 	OM_uint32 *time_rec,
1144 	gss_cred_id_t *delegated_cred_handle,
1145 	uid_t uid)
1146 {
1147 	OM_uint32 err;
1148 	struct kgss_ctx	*kctx;
1149 	gss_OID mt;
1150 	OM_uint32 gssd_cred_verifier;
1151 	gssd_cred_id_t gssd_ver_cred_handle;
1152 
1153 
1154 	/*
1155 	 * See kgss_init_sec_context() to get an idea of what is going
1156 	 * on here.
1157 	 */
1158 	if (mech_type == NULL)
1159 		mech_type = &mt;
1160 
1161 	if (*context_handle == GSS_C_NO_CONTEXT) {
1162 		kctx = KGSS_ALLOC();
1163 		kctx->mech = &default_gc;
1164 		kctx->gssd_ctx = GSSD_NO_CONTEXT;
1165 		*context_handle = (gss_ctx_id_t)kctx;
1166 	} else
1167 		kctx = (struct kgss_ctx *)*context_handle;
1168 
1169 	if (verifier_cred_handle != GSS_C_NO_CREDENTIAL) {
1170 		gssd_cred_verifier = KCRED_TO_CREDV(verifier_cred_handle);
1171 		gssd_ver_cred_handle = KCRED_TO_CRED(verifier_cred_handle);
1172 	} else {
1173 		gssd_ver_cred_handle = GSSD_NO_CREDENTIAL;
1174 	}
1175 
1176 	err = kgss_accept_sec_context_wrapped(minor_status,
1177 	    &kctx->gssd_ctx, &kctx->gssd_ctx_verifier,
1178 	    gssd_ver_cred_handle, gssd_cred_verifier,
1179 	    input_token, input_chan_bindings, src_name,
1180 	    mech_type, output_token, ret_flags,
1181 	    time_rec, delegated_cred_handle, uid);
1182 
1183 	if (GSS_ERROR(err)) {
1184 		KGSS_FREE(kctx);
1185 		*context_handle = GSS_C_NO_CONTEXT;
1186 
1187 	} else if (err == GSS_S_COMPLETE) {
1188 		__kgss_reset_mech(&kctx->mech, *mech_type);
1189 
1190 		/*
1191 		 * If the mech oid was allocated for us, free it.
1192 		 */
1193 		if (&mt == mech_type) {
1194 			kgss_free_oid(mt);
1195 		}
1196 	}
1197 
1198 	return (err);
1199 }
1200 
1201 OM_uint32
1202 kgss_process_context_token(minor_status,
1203 				context_handle,
1204 				token_buffer,
1205 				uid)
1206 	OM_uint32 *minor_status;
1207 	const gss_ctx_id_t context_handle;
1208 	gss_buffer_t token_buffer;
1209 	uid_t uid;
1210 {
1211 	CLIENT *clnt;
1212 	OM_uint32 gssd_context_verifier;
1213 	gssd_ctx_id_t gssd_ctx_handle;
1214 	gss_process_context_token_arg arg;
1215 	gss_process_context_token_res res;
1216 
1217 	gssd_context_verifier = KGSS_CTX_TO_GSSD_CTXV(context_handle);
1218 	gssd_ctx_handle = (gssd_ctx_id_t)KGSS_CTX_TO_GSSD_CTX(context_handle);
1219 
1220 	/* get the client handle to GSSD */
1221 
1222 	if ((clnt = getgssd_handle()) == NULL) {
1223 		GSSLOG(1,
1224 		"kgss_process_context_token: can't connect to server on %s\n",
1225 		server);
1226 		return (GSS_S_FAILURE);
1227 	}
1228 
1229 	/* copy the procedure arguments into the rpc arg parameter */
1230 
1231 	arg.uid = (OM_uint32) uid;
1232 
1233 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1234 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&gssd_ctx_handle;
1235 	arg.gssd_context_verifier = gssd_context_verifier;
1236 	arg.token_buffer.GSS_BUFFER_T_len = (uint_t)token_buffer->length;
1237 	arg.token_buffer.GSS_BUFFER_T_val = (char *)token_buffer->value;
1238 
1239 	/* call the remote procedure */
1240 
1241 	bzero(&res, sizeof (res));
1242 
1243 	if (gss_process_context_token_1(&arg, &res, clnt) != RPC_SUCCESS) {
1244 
1245 	/*
1246 	 * if the RPC call times out, null out all return arguments, set
1247 	 * minor_status to its maximum value, and return GSS_S_FAILURE
1248 	 */
1249 
1250 		if (minor_status != NULL)
1251 			*minor_status = DEFAULT_MINOR_STAT;
1252 		GSSLOG0(1, "kgss_process_context_token: RPC call times out\n");
1253 		killgssd_handle(clnt);
1254 		return (GSS_S_FAILURE);
1255 	}
1256 
1257 	/* copy the rpc results into the return arguments */
1258 
1259 	if (minor_status != NULL)
1260 		*minor_status = res.minor_status;
1261 
1262 	/* return with status returned in rpc call */
1263 
1264 	killgssd_handle(clnt);
1265 	return (res.status);
1266 
1267 }
1268 
1269 /*ARGSUSED*/
1270 static OM_uint32
1271 kgss_delete_sec_context_wrapped(void *private,
1272 			OM_uint32 *minor_status,
1273 			gssd_ctx_id_t *context_handle,
1274 			gss_buffer_t output_token,
1275 			OM_uint32 gssd_context_verifier)
1276 
1277 
1278 {
1279 	CLIENT *clnt;
1280 
1281 	gss_delete_sec_context_arg arg;
1282 	gss_delete_sec_context_res res;
1283 
1284 
1285 	/* get the client handle to GSSD */
1286 
1287 	if ((clnt = getgssd_handle()) == NULL) {
1288 		GSSLOG(1,
1289 		"kgss_delete_sec_context: can't connect to server on %s\n",
1290 		server);
1291 		return (GSS_S_FAILURE);
1292 	}
1293 
1294 	/* copy the procedure arguments into the rpc arg parameter */
1295 
1296 	arg.context_handle.GSS_CTX_ID_T_len =
1297 		*context_handle == GSSD_NO_CONTEXT ?
1298 			0 : (uint_t)sizeof (gssd_ctx_id_t);
1299 	arg.context_handle.GSS_CTX_ID_T_val =  (char *)context_handle;
1300 
1301 	arg.gssd_context_verifier = gssd_context_verifier;
1302 
1303 	/* call the remote procedure */
1304 
1305 	bzero((caddr_t)&res, sizeof (res));
1306 	if (gss_delete_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
1307 
1308 	/*
1309 	 * if the RPC call times out, null out all return arguments, set
1310 	 * minor_status to its maximum value, and return GSS_S_FAILURE
1311 	 */
1312 
1313 		if (minor_status != NULL)
1314 			*minor_status = DEFAULT_MINOR_STAT;
1315 		if (context_handle != NULL)
1316 			*context_handle = NULL;
1317 		if (output_token != NULL)
1318 			output_token->length = 0;
1319 
1320 		killgssd_handle(clnt);
1321 		GSSLOG0(1, "kgssd_delete_sec_context: RPC call times out\n");
1322 		return (GSS_S_FAILURE);
1323 	}
1324 
1325 	/* copy the rpc results into the return arguments */
1326 
1327 	if (minor_status != NULL)
1328 		*minor_status = res.minor_status;
1329 
1330 	if (res.context_handle.GSS_CTX_ID_T_len == 0)
1331 		*context_handle = NULL;
1332 	else
1333 		*context_handle =
1334 		    *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val);
1335 
1336 	if (output_token != NULL) {
1337 		output_token->length = res.output_token.GSS_BUFFER_T_len;
1338 		output_token->value = res.output_token.GSS_BUFFER_T_val;
1339 		res.output_token.GSS_BUFFER_T_len = 0;
1340 		res.output_token.GSS_BUFFER_T_val = NULL;
1341 	}
1342 
1343 	/*
1344 	 * free the memory allocated for the results and return with the status
1345 	 * received in the rpc call
1346 	 */
1347 
1348 	clnt_freeres(clnt, xdr_gss_delete_sec_context_res, (caddr_t)&res);
1349 	killgssd_handle(clnt);
1350 	return (res.status);
1351 
1352 }
1353 
1354 OM_uint32
1355 kgss_delete_sec_context(
1356 		OM_uint32 *minor_status,
1357 		gss_ctx_id_t *context_handle,
1358 		gss_buffer_t output_token)
1359 {
1360 	OM_uint32 err;
1361 	struct kgss_ctx	*kctx;
1362 
1363 	if (*context_handle == GSS_C_NO_CONTEXT) {
1364 		GSSLOG0(8, "kgss_delete_sec_context: Null context handle \n");
1365 		return (GSS_S_COMPLETE);
1366 	} else
1367 		kctx = (struct kgss_ctx *)*context_handle;
1368 
1369 	if (kctx->ctx_imported == FALSE) {
1370 		if (kctx->gssd_ctx == GSSD_NO_CONTEXT) {
1371 			KGSS_FREE(kctx);
1372 			*context_handle = GSS_C_NO_CONTEXT;
1373 			return (GSS_S_COMPLETE);
1374 		}
1375 		err = kgss_delete_sec_context_wrapped(
1376 		    KCTX_TO_PRIVATE(*context_handle),
1377 		    minor_status,
1378 		    &kctx->gssd_ctx,
1379 		    output_token,
1380 		    kctx->gssd_ctx_verifier);
1381 	} else {
1382 		if (kctx->gssd_i_ctx == (gss_ctx_id_t)GSS_C_NO_CONTEXT) {
1383 			KGSS_FREE(kctx);
1384 			*context_handle = GSS_C_NO_CONTEXT;
1385 			return (GSS_S_COMPLETE);
1386 		}
1387 		err = KGSS_DELETE_SEC_CONTEXT(minor_status, kctx,
1388 		    &kctx->gssd_i_ctx,  output_token);
1389 	}
1390 	KGSS_FREE(kctx);
1391 	*context_handle = GSS_C_NO_CONTEXT;
1392 	return (err);
1393 
1394 }
1395 
1396 
1397 OM_uint32
1398 kgss_export_sec_context_wrapped(minor_status,
1399 				context_handle,
1400 				output_token,
1401 				gssd_context_verifier)
1402 	OM_uint32 *minor_status;
1403 	gssd_ctx_id_t *context_handle;
1404 	gss_buffer_t output_token;
1405 	OM_uint32 gssd_context_verifier;
1406 {
1407 	CLIENT *clnt;
1408 	gss_export_sec_context_arg arg;
1409 	gss_export_sec_context_res res;
1410 
1411 
1412 	/* get the client handle to GSSD */
1413 
1414 	if ((clnt = getgssd_handle()) == NULL) {
1415 		GSSLOG(1, "kgss_export_sec_context_wrapped :"
1416 			" can't connect to server on %s\n", server);
1417 		return (GSS_S_FAILURE);
1418 	}
1419 
1420 	/* copy the procedure arguments into the rpc arg parameter */
1421 
1422 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1423 	arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle;
1424 	arg.gssd_context_verifier = gssd_context_verifier;
1425 
1426 	/* call the remote procedure */
1427 
1428 	(void) memset(&res, 0, sizeof (res));
1429 	if (gss_export_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
1430 
1431 	/*
1432 	 * if the RPC call times out, null out all return arguments,
1433 	 * set minor_status to its maximum value, and return
1434 	 * GSS_S_FAILURE
1435 	 */
1436 
1437 		if (minor_status != NULL)
1438 			*minor_status = DEFAULT_MINOR_STAT;
1439 		if (context_handle != NULL)
1440 			*context_handle = NULL;
1441 		if (output_token != NULL)
1442 			output_token->length = 0;
1443 		killgssd_handle(clnt);
1444 		GSSLOG0(1,
1445 		"kgss_export_sec_context_wrapped: RPC call times out\n");
1446 		return (GSS_S_FAILURE);
1447 	}
1448 
1449 	/* copy the rpc results into the return arguments */
1450 
1451 	if (minor_status != NULL)
1452 		*minor_status = res.minor_status;
1453 
1454 	if (res.context_handle.GSS_CTX_ID_T_len == 0)
1455 		*context_handle = NULL;
1456 	else
1457 		*context_handle =
1458 		    *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val);
1459 
1460 	if (output_token != NULL) {
1461 		output_token->length = res.output_token.GSS_BUFFER_T_len;
1462 		output_token->value =
1463 			(void *)  MALLOC(output_token->length);
1464 		(void) memcpy(output_token->value,
1465 			res.output_token.GSS_BUFFER_T_val,
1466 			output_token->length);
1467 	}
1468 
1469 	/*
1470 	 * free the memory allocated for the results and return with the status
1471 	 * received in the rpc call
1472 	 */
1473 
1474 	clnt_freeres(clnt, xdr_gss_export_sec_context_res, (caddr_t)&res);
1475 	killgssd_handle(clnt);
1476 	return (res.status);
1477 
1478 }
1479 
1480 OM_uint32
1481 kgss_export_sec_context(minor_status,
1482 			context_handle,
1483 			output_token)
1484 	OM_uint32 *minor_status;
1485 	gss_ctx_id_t context_handle;
1486 	gss_buffer_t output_token;
1487 {
1488 	struct kgss_ctx	*kctx;
1489 
1490 	if (context_handle == GSS_C_NO_CONTEXT)
1491 		return (GSS_S_FAILURE);
1492 	else
1493 		kctx = (struct kgss_ctx *)context_handle;
1494 
1495 
1496 
1497 	/*
1498 	 *  If there is a kernel module then import_sec context must be
1499 	 *  supported and we make an upcall to export_sec_context.
1500 	 *  If there is no kernel module then we return an error
1501 	 */
1502 
1503 	*minor_status = 0;
1504 
1505 	if (kctx->mech->gss_import_sec_context) {
1506 		GSSLOG0(8, "kgss_export_sec_context: Kernel mod available \n");
1507 		return (kgss_export_sec_context_wrapped(minor_status,
1508 						&kctx->gssd_ctx,
1509 						output_token,
1510 						kctx->gssd_ctx_verifier));
1511 
1512 	} else {
1513 
1514 		/*
1515 		 * This is not the right error value; instead of
1516 		 * inventing  new error we return GSS_S_NAME_NOT_MN
1517 		 * This error is not returned by the export routine
1518 		 */
1519 
1520 		GSSLOG0(8, "kgss_export_sec_context: Kernel mod "
1521 			"unavailable \n");
1522 		return (GSS_S_NAME_NOT_MN);
1523 	}
1524 
1525 }
1526 
1527 OM_uint32
1528 kgss_import_sec_context(minor_status,
1529 			interprocess_token,
1530 			context_handle)
1531 
1532 OM_uint32 *		minor_status;
1533 const gss_buffer_t	interprocess_token;
1534 gss_ctx_id_t 		context_handle;
1535 
1536 {
1537 OM_uint32 status;
1538 struct kgss_ctx	*kctx;
1539 
1540 size_t		length;
1541 char		*p;
1542 gss_buffer_desc token;
1543 gss_ctx_id_t	internal_ctx_id;
1544 	kctx = (struct kgss_ctx *)context_handle;
1545 
1546 	if (kctx->gssd_ctx != GSSD_NO_CONTEXT) {
1547 		return (GSS_S_FAILURE);
1548 	}
1549 
1550 	if (!(KCTX_TO_MECH(context_handle)->gss_import_sec_context)) {
1551 
1552 	/*
1553 	 *  This should never happen
1554 	 *  If Kernel import sec context does not exist the export
1555 	 *  sec context should have caught this and returned an error
1556 	 *  and the caller should not have called this routine
1557 	 */
1558 		GSSLOG0(1, "import_sec_context  called improperly\n");
1559 		return (GSS_S_FAILURE);
1560 	}
1561 	*minor_status = 0;
1562 
1563 	if (interprocess_token->length == 0 || interprocess_token->value == 0)
1564 		return (GSS_S_DEFECTIVE_TOKEN);
1565 
1566 	status = GSS_S_FAILURE;
1567 
1568 	p = interprocess_token->value;
1569 	length = *p++;
1570 	length = (length << 8) + *p++;
1571 	length = (length << 8) + *p++;
1572 	length = (length << 8) + *p++;
1573 
1574 	p += length;
1575 
1576 	token.length = interprocess_token->length - 4 - length;
1577 	token.value = p;
1578 
1579 	/*
1580 	 * select the approprate underlying mechanism routine and
1581 	 * call it.
1582 	 */
1583 
1584 	status = KGSS_IMPORT_SEC_CONTEXT(minor_status, &token, kctx,
1585 				&internal_ctx_id);
1586 
1587 	if (status == GSS_S_COMPLETE) {
1588 		KCTX_TO_I_CTX(kctx) = internal_ctx_id;
1589 		kctx->ctx_imported = TRUE;
1590 		return (GSS_S_COMPLETE);
1591 	} else
1592 		return (status);
1593 }
1594 
1595 /*ARGSUSED*/
1596 OM_uint32
1597 kgss_context_time(minor_status,
1598 		context_handle,
1599 		time_rec,
1600 		uid)
1601 	OM_uint32 *minor_status;
1602 	const gss_ctx_id_t context_handle;
1603 	OM_uint32 *time_rec;
1604 	uid_t uid;
1605 {
1606 	return (GSS_S_FAILURE);
1607 }
1608 
1609 /*ARGSUSED*/
1610 static OM_uint32
1611 kgss_sign_wrapped(void *private,
1612 	OM_uint32 *minor_status,
1613 	const gss_ctx_id_t ctx_handle,
1614 	int qop_req,
1615 	const gss_buffer_t message_buffer,
1616 	gss_buffer_t msg_token,
1617 	OM_uint32 gssd_context_verifier)
1618 {
1619 	CLIENT *clnt;
1620 	gssd_ctx_id_t context_handle;
1621 
1622 	gss_sign_arg arg;
1623 	gss_sign_res res;
1624 	context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle);
1625 	/* get the client handle to GSSD */
1626 
1627 	if ((clnt = getgssd_handle()) == NULL) {
1628 		GSSLOG(1, "kgss_sign: can't connect to server on %s\n", server);
1629 		return (GSS_S_FAILURE);
1630 	}
1631 
1632 	/* copy the procedure arguments into the rpc arg parameter */
1633 
1634 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1635 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1636 
1637 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1638 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1639 	arg.gssd_context_verifier = gssd_context_verifier;
1640 
1641 	arg.qop_req = qop_req;
1642 
1643 	arg.message_buffer.GSS_BUFFER_T_len = (uint_t)message_buffer->length;
1644 	arg.message_buffer.GSS_BUFFER_T_val = (char *)message_buffer->value;
1645 
1646 	/* call the remote procedure */
1647 
1648 	bzero((caddr_t)&res, sizeof (res));
1649 	if (gss_sign_1(&arg, &res, clnt) != RPC_SUCCESS) {
1650 
1651 	/*
1652 	 * if the RPC call times out, null out all return arguments, set
1653 	 * minor_status to its maximum value, and return GSS_S_FAILURE
1654 	 */
1655 
1656 		if (minor_status != NULL)
1657 			*minor_status = DEFAULT_MINOR_STAT;
1658 		if (msg_token != NULL)
1659 			msg_token->length = 0;
1660 
1661 		killgssd_handle(clnt);
1662 		GSSLOG0(1, "kgss_sign: RPC call times out\n");
1663 		return (GSS_S_FAILURE);
1664 	}
1665 
1666 	/* copy the rpc results into the return arguments */
1667 
1668 	if (minor_status != NULL)
1669 		*minor_status = res.minor_status;
1670 
1671 	if (msg_token != NULL) {
1672 		msg_token->length = res.msg_token.GSS_BUFFER_T_len;
1673 		msg_token->value = (void *) MALLOC(msg_token->length);
1674 		(void) memcpy(msg_token->value, res.msg_token.GSS_BUFFER_T_val,
1675 		    msg_token->length);
1676 	}
1677 
1678 	/*
1679 	 * free the memory allocated for the results and return with the status
1680 	 * received in the rpc call
1681 	 */
1682 
1683 	clnt_freeres(clnt, xdr_gss_sign_res, (caddr_t)&res);
1684 	killgssd_handle(clnt);
1685 	return (res.status);
1686 
1687 }
1688 
1689 OM_uint32
1690 kgss_sign(
1691 	OM_uint32 *minor_status,
1692 	const gss_ctx_id_t context_handle,
1693 	int qop_req,
1694 	const gss_buffer_t message_buffer,
1695 	gss_buffer_t msg_token)
1696 {
1697 	if (context_handle == GSS_C_NO_CONTEXT)
1698 		return (GSS_S_FAILURE);
1699 	return (KGSS_SIGN(minor_status, context_handle, qop_req,
1700 	    message_buffer, msg_token));
1701 }
1702 
1703 /*ARGSUSED*/
1704 static OM_uint32
1705 kgss_verify_wrapped(void *private,
1706 	OM_uint32 *minor_status,
1707 	const gss_ctx_id_t ctx_handle,
1708 	const gss_buffer_t message_buffer,
1709 	const gss_buffer_t token_buffer,
1710 	int *qop_state,
1711 	OM_uint32 gssd_context_verifier)
1712 {
1713 	CLIENT *clnt;
1714 
1715 	gssd_ctx_id_t context_handle;
1716 	gss_verify_arg arg;
1717 	gss_verify_res res;
1718 
1719 	context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle);
1720 
1721 	/* get the client handle to GSSD */
1722 
1723 	if ((clnt = getgssd_handle()) == NULL) {
1724 		GSSLOG(1, "kgss_verify: can't connect to server on %s\n",
1725 		    server);
1726 		return (GSS_S_FAILURE);
1727 	}
1728 
1729 	/* copy the procedure arguments into the rpc arg parameter */
1730 
1731 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t);
1732 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1733 
1734 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1735 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1736 	arg.gssd_context_verifier = gssd_context_verifier;
1737 
1738 	arg.message_buffer.GSS_BUFFER_T_len = (uint_t)message_buffer->length;
1739 	arg.message_buffer.GSS_BUFFER_T_val = (char *)message_buffer->value;
1740 
1741 	arg.token_buffer.GSS_BUFFER_T_len = (uint_t)token_buffer->length;
1742 	arg.token_buffer.GSS_BUFFER_T_val = (char *)token_buffer->value;
1743 
1744 	/* call the remote procedure */
1745 
1746 	bzero((caddr_t)&res, sizeof (res));
1747 	if (gss_verify_1(&arg, &res, clnt) != RPC_SUCCESS) {
1748 
1749 	/*
1750 	 * if the RPC call times out, null out all return arguments, set
1751 	 * minor_status to its maximum value, and return GSS_S_FAILURE
1752 	 */
1753 
1754 		if (minor_status != NULL)
1755 			*minor_status = DEFAULT_MINOR_STAT;
1756 		if (qop_state != NULL)
1757 			*qop_state = 0;
1758 
1759 		killgssd_handle(clnt);
1760 		GSSLOG0(1, "kgss_verify: RPC call times out\n");
1761 		return (GSS_S_FAILURE);
1762 	}
1763 
1764 	/* copy the rpc results into the return arguments */
1765 
1766 	if (minor_status != NULL)
1767 		*minor_status = res.minor_status;
1768 
1769 	if (qop_state != NULL)
1770 		*qop_state = res.qop_state;
1771 
1772 	/* return with status returned in rpc call */
1773 
1774 	killgssd_handle(clnt);
1775 	return (res.status);
1776 
1777 }
1778 
1779 OM_uint32
1780 kgss_verify(OM_uint32 *minor_status,
1781 		const gss_ctx_id_t context_handle,
1782 		const gss_buffer_t message_buffer,
1783 		const gss_buffer_t token_buffer,
1784 		int *qop_state)
1785 {
1786 	if (context_handle == GSS_C_NO_CONTEXT)
1787 		return (GSS_S_FAILURE);
1788 	return (KGSS_VERIFY(minor_status, context_handle,
1789 	    message_buffer, token_buffer, qop_state));
1790 }
1791 
1792 /* EXPORT DELETE START */
1793 
1794 /*ARGSUSED*/
1795 static OM_uint32
1796 kgss_seal_wrapped(void *private,
1797 	OM_uint32 *minor_status,
1798 	const gss_ctx_id_t ctx_handle,
1799 	int conf_req_flag,
1800 	int qop_req,
1801 	const gss_buffer_t input_message_buffer,
1802 	int *conf_state,
1803 	gss_buffer_t output_message_buffer,
1804 	OM_uint32 gssd_context_verifier)
1805 {
1806 	CLIENT *clnt;
1807 	gssd_ctx_id_t	context_handle;
1808 
1809 	gss_seal_arg arg;
1810 	gss_seal_res res;
1811 
1812 	context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle);
1813 
1814 	/* get the client handle to GSSD */
1815 
1816 	if ((clnt = getgssd_handle()) == NULL) {
1817 		GSSLOG(1, "kgss_seal: can't connect to server on %s\n", server);
1818 		return (GSS_S_FAILURE);
1819 	}
1820 
1821 	/* copy the procedure arguments into the rpc arg parameter */
1822 
1823 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t);
1824 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1825 
1826 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (OM_uint32);
1827 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1828 	arg.gssd_context_verifier = gssd_context_verifier;
1829 
1830 	arg.conf_req_flag = conf_req_flag;
1831 
1832 	arg.qop_req = qop_req;
1833 
1834 	arg.input_message_buffer.GSS_BUFFER_T_len =
1835 	    (uint_t)input_message_buffer->length;
1836 
1837 	arg.input_message_buffer.GSS_BUFFER_T_val =
1838 	    (char *)input_message_buffer->value;
1839 
1840 	/* call the remote procedure */
1841 
1842 	bzero((caddr_t)&res, sizeof (res));
1843 	if (gss_seal_1(&arg, &res, clnt) != RPC_SUCCESS) {
1844 
1845 	/*
1846 	 * if the RPC call times out, null out all return arguments, set
1847 	 * minor_status to its maximum value, and return GSS_S_FAILURE
1848 	 */
1849 
1850 		if (minor_status != NULL)
1851 			*minor_status = DEFAULT_MINOR_STAT;
1852 		if (conf_state != NULL)
1853 			*conf_state = 0;
1854 		if (output_message_buffer != NULL)
1855 			output_message_buffer->length = 0;
1856 
1857 		killgssd_handle(clnt);
1858 		GSSLOG0(1, "kgss_seal: RPC call times out\n");
1859 		return (GSS_S_FAILURE);
1860 	}
1861 
1862 	/* copy the rpc results into the return arguments */
1863 
1864 	if (minor_status != NULL)
1865 		*minor_status = res.minor_status;
1866 
1867 	if (conf_state != NULL)
1868 		*conf_state = res.conf_state;
1869 
1870 	if (output_message_buffer != NULL) {
1871 		output_message_buffer->length =
1872 		    res.output_message_buffer.GSS_BUFFER_T_len;
1873 
1874 		output_message_buffer->value =
1875 		    (void *) MALLOC(output_message_buffer->length);
1876 		(void) memcpy(output_message_buffer->value,
1877 		    res.output_message_buffer.GSS_BUFFER_T_val,
1878 		    output_message_buffer->length);
1879 	}
1880 
1881 	/*
1882 	 * free the memory allocated for the results and return with the status
1883 	 * received in the rpc call
1884 	 */
1885 
1886 	clnt_freeres(clnt, xdr_gss_seal_res, (caddr_t)&res);
1887 	killgssd_handle(clnt);
1888 	return (res.status);
1889 }
1890 
1891 /*ARGSUSED*/
1892 OM_uint32
1893 kgss_seal(OM_uint32 *minor_status,
1894 	const gss_ctx_id_t context_handle,
1895 	int conf_req_flag,
1896 	int qop_req,
1897 	const gss_buffer_t input_message_buffer,
1898 	int *conf_state,
1899 	gss_buffer_t output_message_buffer)
1900 
1901 {
1902 	if (context_handle == GSS_C_NO_CONTEXT)
1903 		return (GSS_S_FAILURE);
1904 	return (KGSS_SEAL(minor_status, context_handle,
1905 		conf_req_flag, qop_req,
1906 		input_message_buffer, conf_state,
1907 		output_message_buffer));
1908 }
1909 
1910 /*ARGSUSED*/
1911 static OM_uint32
1912 kgss_unseal_wrapped(void *private,
1913 	OM_uint32 *minor_status,
1914 	const gss_ctx_id_t ctx_handle,
1915 	const gss_buffer_t input_message_buffer,
1916 	gss_buffer_t output_message_buffer,
1917 	int *conf_state,
1918 	int *qop_state,
1919 	OM_uint32 gssd_context_verifier)
1920 {
1921 	CLIENT *clnt;
1922 
1923 	gss_unseal_arg arg;
1924 	gss_unseal_res res;
1925 	gssd_ctx_id_t context_handle;
1926 
1927 	context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle);
1928 
1929 	/* get the client handle to GSSD */
1930 
1931 	if ((clnt = getgssd_handle()) == NULL) {
1932 		GSSLOG(1, "kgss_unseal: can't connect to server on %s\n",
1933 		    server);
1934 		return (GSS_S_FAILURE);
1935 	}
1936 
1937 	/* copy the procedure arguments into the rpc arg parameter */
1938 
1939 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t);
1940 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1941 
1942 	arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1943 	arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1944 	arg.gssd_context_verifier = gssd_context_verifier;
1945 
1946 	arg.input_message_buffer.GSS_BUFFER_T_len =
1947 	    (uint_t)input_message_buffer->length;
1948 
1949 	arg.input_message_buffer.GSS_BUFFER_T_val =
1950 	    (char *)input_message_buffer->value;
1951 
1952 	/* call the remote procedure */
1953 
1954 	bzero((caddr_t)&res, sizeof (res));
1955 	if (gss_unseal_1(&arg, &res, clnt) != RPC_SUCCESS) {
1956 
1957 	/*
1958 	 * if the RPC call times out, null out all return arguments, set
1959 	 * minor_status to its maximum value, and return GSS_S_FAILURE
1960 	 */
1961 
1962 		if (minor_status != NULL)
1963 			*minor_status = DEFAULT_MINOR_STAT;
1964 		if (output_message_buffer != NULL)
1965 			output_message_buffer->length = 0;
1966 		if (conf_state != NULL)
1967 			*conf_state = 0;
1968 		if (qop_state != NULL)
1969 			*qop_state = 0;
1970 
1971 		killgssd_handle(clnt);
1972 		GSSLOG0(1, "kgss_unseal: RPC call times out\n");
1973 		return (GSS_S_FAILURE);
1974 	}
1975 
1976 	/* copy the rpc results into the return arguments */
1977 
1978 	if (minor_status != NULL)
1979 		*minor_status = res.minor_status;
1980 
1981 	if (output_message_buffer != NULL) {
1982 		output_message_buffer->length =
1983 		    res.output_message_buffer.GSS_BUFFER_T_len;
1984 
1985 		output_message_buffer->value =
1986 		    (void *) MALLOC(output_message_buffer->length);
1987 		(void) memcpy(output_message_buffer->value,
1988 		    res.output_message_buffer.GSS_BUFFER_T_val,
1989 		    output_message_buffer->length);
1990 	}
1991 
1992 	if (conf_state != NULL)
1993 		*conf_state = res.conf_state;
1994 
1995 	if (qop_state != NULL)
1996 		*qop_state = res.qop_state;
1997 
1998 	/*
1999 	 * free the memory allocated for the results and return with the
2000 	 * status received in the rpc call
2001 	 */
2002 
2003 	clnt_freeres(clnt, xdr_gss_unseal_res, (caddr_t)&res);
2004 	killgssd_handle(clnt);
2005 	return (res.status);
2006 }
2007 
2008 OM_uint32
2009 kgss_unseal(OM_uint32 *minor_status,
2010 	const gss_ctx_id_t context_handle,
2011 	const gss_buffer_t input_message_buffer,
2012 	const gss_buffer_t output_message_buffer,
2013 	int *conf_state,
2014 	int *qop_state)
2015 {
2016 
2017 	if (context_handle == GSS_C_NO_CONTEXT)
2018 		return (GSS_S_FAILURE);
2019 
2020 	return (KGSS_UNSEAL(minor_status, context_handle, input_message_buffer,
2021 	    output_message_buffer, conf_state, qop_state));
2022 }
2023 
2024 /* EXPORT DELETE END */
2025 
2026 OM_uint32
2027 kgss_display_status(minor_status,
2028 		status_value,
2029 		status_type,
2030 		mech_type,
2031 		message_context,
2032 		status_string,
2033 		uid)
2034 	OM_uint32 *minor_status;
2035 	OM_uint32 status_value;
2036 	int status_type;
2037 	const gss_OID mech_type;
2038 	int *message_context;
2039 	gss_buffer_t status_string;
2040 	uid_t uid;
2041 {
2042 	CLIENT *clnt;
2043 
2044 	gss_display_status_arg arg;
2045 	gss_display_status_res res;
2046 
2047 	/* get the client handle to GSSD */
2048 
2049 	if ((clnt = getgssd_handle()) == NULL) {
2050 	GSSLOG(1, "kgss_display_status: can't connect to server on %s\n",
2051 			server);
2052 		return (GSS_S_FAILURE);
2053 	}
2054 
2055 	/* copy the procedure arguments into the rpc arg parameter */
2056 
2057 	arg.uid = (OM_uint32) uid;
2058 
2059 	arg.status_value = status_value;
2060 	arg.status_type = status_type;
2061 
2062 	arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ?
2063 						mech_type->length : 0);
2064 	arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ?
2065 						mech_type->elements : 0);
2066 
2067 	arg.message_context = *message_context;
2068 
2069 	/* call the remote procedure */
2070 
2071 	if (message_context != NULL)
2072 		*message_context = 0;
2073 	if (status_string != NULL) {
2074 		status_string->length = 0;
2075 		status_string->value = NULL;
2076 	}
2077 
2078 	bzero((caddr_t)&res, sizeof (res));
2079 	if (gss_display_status_1(&arg, &res, clnt) != RPC_SUCCESS) {
2080 
2081 	/*
2082 	 * if the RPC call times out, null out all return arguments, set
2083 	 * minor_status to its maximum value, and return GSS_S_FAILURE
2084 	 */
2085 
2086 		if (minor_status != NULL)
2087 			*minor_status = DEFAULT_MINOR_STAT;
2088 
2089 		killgssd_handle(clnt);
2090 		GSSLOG0(1, "kgss_display_status: RPC call time out\n");
2091 		return (GSS_S_FAILURE);
2092 	}
2093 
2094 
2095 	/* now process the results and pass them back to the caller */
2096 
2097 	if (res.status == GSS_S_COMPLETE) {
2098 		if (minor_status != NULL)
2099 			*minor_status = res.minor_status;
2100 		if (message_context != NULL)
2101 			*message_context = res.message_context;
2102 		if (status_string != NULL) {
2103 			status_string->length =
2104 				(size_t)res.status_string.GSS_BUFFER_T_len;
2105 			status_string->value =
2106 				(void *) MALLOC(status_string->length);
2107 			(void) memcpy(status_string->value,
2108 				res.status_string.GSS_BUFFER_T_val,
2109 				status_string->length);
2110 		}
2111 	}
2112 
2113 	clnt_freeres(clnt, xdr_gss_display_status_res, (caddr_t)&res);
2114 	killgssd_handle(clnt);
2115 	return (res.status);
2116 }
2117 
2118 /*ARGSUSED*/
2119 OM_uint32
2120 kgss_indicate_mechs(minor_status,
2121 			mech_set,
2122 			uid)
2123 	OM_uint32 *minor_status;
2124 	gss_OID_set *mech_set;
2125 	uid_t uid;
2126 {
2127 	CLIENT *clnt;
2128 	void *arg;
2129 	gss_indicate_mechs_res res;
2130 	int i;
2131 
2132 	/* get the client handle to GSSD */
2133 
2134 	if ((clnt = getgssd_handle()) == NULL) {
2135 	GSSLOG(1, "kgss_indicate_mechs: can't connect to server on %s\n",
2136 			server);
2137 		return (GSS_S_FAILURE);
2138 	}
2139 
2140 	bzero((caddr_t)&res, sizeof (res));
2141 	if (gss_indicate_mechs_1(&arg, &res, clnt) != RPC_SUCCESS) {
2142 
2143 	/*
2144 	 * if the RPC call times out, null out all return arguments, set
2145 	 * minor_status to its maximum value, and return GSS_S_FAILURE
2146 	 */
2147 
2148 		if (minor_status != NULL)
2149 			*minor_status = DEFAULT_MINOR_STAT;
2150 		if (mech_set != NULL)
2151 			*mech_set = NULL;
2152 
2153 		killgssd_handle(clnt);
2154 		GSSLOG0(1, "kgss_indicate_mechs: RPC call times out\n");
2155 		return (GSS_S_FAILURE);
2156 	}
2157 
2158 	/* copy the rpc results into the return arguments */
2159 
2160 	if (minor_status != NULL)
2161 		*minor_status = res.minor_status;
2162 
2163 	if (mech_set != NULL) {
2164 		*mech_set = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
2165 		(*mech_set)->count = res.mech_set.GSS_OID_SET_len;
2166 		(*mech_set)->elements = (void *)
2167 			MALLOC ((*mech_set)->count * sizeof (gss_OID_desc));
2168 		for (i = 0; i < (*mech_set)->count; i++) {
2169 			(*mech_set)->elements[i].length =
2170 				res.mech_set.GSS_OID_SET_val[i].GSS_OID_len;
2171 			(*mech_set)->elements[i].elements = (void *)
2172 				MALLOC ((*mech_set)->elements[i].length);
2173 			(void) memcpy((*mech_set)->elements[i].elements,
2174 				res.mech_set.GSS_OID_SET_val[i].GSS_OID_val,
2175 				(*mech_set)->elements[i].length);
2176 		}
2177 	}
2178 
2179 	/*
2180 	 * free the memory allocated for the results and return with the status
2181 	 * received in the rpc call
2182 	 */
2183 
2184 	clnt_freeres(clnt, xdr_gss_indicate_mechs_res, (caddr_t)&res);
2185 	killgssd_handle(clnt);
2186 	return (res.status);
2187 }
2188 
2189 
2190 OM_uint32
2191 kgss_inquire_cred_wrapped(minor_status,
2192 		cred_handle,
2193 		gssd_cred_verifier,
2194 		name,
2195 		lifetime,
2196 		cred_usage,
2197 		mechanisms,
2198 		uid)
2199 	OM_uint32 *minor_status;
2200 	const gssd_cred_id_t cred_handle;
2201 	OM_uint32 gssd_cred_verifier;
2202 	gss_name_t *name;
2203 	OM_uint32 *lifetime;
2204 	int *cred_usage;
2205 	gss_OID_set *mechanisms;
2206 	uid_t uid;
2207 {
2208 	CLIENT *clnt;
2209 
2210 	OM_uint32 	minor_status_temp;
2211 	gss_buffer_desc	external_name;
2212 	gss_OID_desc	name_type;
2213 	int		i;
2214 
2215 	gss_inquire_cred_arg arg;
2216 	gss_inquire_cred_res res;
2217 
2218 	/*
2219 	 * NULL the params here once
2220 	 * If there are errors then we won't
2221 	 * have to do it for every error
2222 	 * case
2223 	 */
2224 	if (minor_status != NULL)
2225 		*minor_status = DEFAULT_MINOR_STAT;
2226 	if (name != NULL)
2227 		*name = NULL;
2228 	if (lifetime != NULL)
2229 		*lifetime = 0;
2230 	if (cred_usage != NULL)
2231 		*cred_usage = 0;
2232 	if (mechanisms != NULL)
2233 		*mechanisms = NULL;
2234 
2235 	/* get the client handle to GSSD */
2236 
2237 	if ((clnt = getgssd_handle()) == NULL) {
2238 		GSSLOG(1, "kgss_inquire_cred: can't connect to server on %s\n",
2239 			server);
2240 		return (GSS_S_FAILURE);
2241 	}
2242 
2243 
2244 	/* copy the procedure arguments into the rpc arg parameter */
2245 
2246 	arg.uid = (OM_uint32) uid;
2247 
2248 	arg.cred_handle.GSS_CRED_ID_T_len =
2249 	    cred_handle == GSSD_NO_CREDENTIAL ?
2250 	    0 : (uint_t)sizeof (gssd_cred_id_t);
2251 	arg.cred_handle.GSS_CRED_ID_T_val = (char *)&cred_handle;
2252 	arg.gssd_cred_verifier = gssd_cred_verifier;
2253 
2254 	/* call the remote procedure */
2255 
2256 	bzero((caddr_t)&res, sizeof (res));
2257 	if (gss_inquire_cred_1(&arg, &res, clnt) != RPC_SUCCESS) {
2258 
2259 		/*
2260 		 * if the RPC call times out
2261 		 * kill the handle and return GSS_S_FAILURE
2262 		 * the parameters have been set to NULL already
2263 		 */
2264 
2265 		killgssd_handle(clnt);
2266 		GSSLOG0(1, "kgss_inquire_cred: RPC call times out\n");
2267 		return (GSS_S_FAILURE);
2268 	}
2269 
2270 	/* copy the rpc results into the return arguments */
2271 
2272 	if (minor_status != NULL)
2273 		*minor_status = res.minor_status;
2274 
2275 	/* convert name from external to internal format */
2276 
2277 	if (name != NULL) {
2278 		external_name.length = res.name.GSS_BUFFER_T_len;
2279 		external_name.value = res.name.GSS_BUFFER_T_val;
2280 
2281 		/*
2282 		 * we can pass a pointer to res structure
2283 		 * since gss_import_name treats the name_type
2284 		 * parameter as read only and performs a copy
2285 		 */
2286 
2287 		name_type.length = res.name_type.GSS_OID_len;
2288 		name_type.elements = (void *)res.name_type.GSS_OID_val;
2289 
2290 		if (gss_import_name(&minor_status_temp, &external_name,
2291 			&name_type, name) != GSS_S_COMPLETE) {
2292 
2293 			*minor_status = (OM_uint32) minor_status_temp;
2294 			clnt_freeres(clnt, xdr_gss_inquire_cred_res,
2295 							(caddr_t)&res);
2296 			killgssd_handle(clnt);
2297 			GSSLOG0(1, "kgss_inquire_cred: import name fails\n");
2298 			return ((OM_uint32) GSS_S_FAILURE);
2299 		}
2300 	}
2301 
2302 	if (lifetime != NULL)
2303 		*lifetime = res.lifetime;
2304 
2305 	if (cred_usage != NULL)
2306 		*cred_usage = res.cred_usage;
2307 
2308 	if (res.status == GSS_S_COMPLETE &&
2309 		res.mechanisms.GSS_OID_SET_len != 0 &&
2310 		mechanisms != NULL) {
2311 		*mechanisms = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
2312 		(*mechanisms)->count =
2313 			(int)res.mechanisms.GSS_OID_SET_len;
2314 		(*mechanisms)->elements = (gss_OID)
2315 			MALLOC(sizeof (gss_OID_desc) * (*mechanisms)->count);
2316 
2317 		for (i = 0; i < (*mechanisms)->count; i++) {
2318 		    (*mechanisms)->elements[i].length = (OM_uint32)
2319 			res.mechanisms.GSS_OID_SET_val[i].GSS_OID_len;
2320 		    (*mechanisms)->elements[i].elements =
2321 			(void *) MALLOC((*mechanisms)->elements[i].length);
2322 		    (void) memcpy((*mechanisms)->elements[i].elements,
2323 			res.mechanisms.GSS_OID_SET_val[i].GSS_OID_val,
2324 			(*mechanisms)->elements[i].length);
2325 		}
2326 	} else {
2327 		if (res.status == GSS_S_COMPLETE &&
2328 			mechanisms != NULL)
2329 			(*mechanisms) = NULL;
2330 	}
2331 	/*
2332 	 * free the memory allocated for the results and return with the status
2333 	 * received in the rpc call
2334 	 */
2335 
2336 	clnt_freeres(clnt, xdr_gss_inquire_cred_res, (caddr_t)&res);
2337 	killgssd_handle(clnt);
2338 	return (res.status);
2339 
2340 }
2341 
2342 OM_uint32
2343 kgss_inquire_cred(minor_status,
2344 			cred_handle,
2345 			name,
2346 			lifetime,
2347 			cred_usage,
2348 			mechanisms,
2349 			uid)
2350 	OM_uint32 *minor_status;
2351 	const gss_cred_id_t cred_handle;
2352 	gss_name_t *name;
2353 	OM_uint32 *lifetime;
2354 	int *cred_usage;
2355 	gss_OID_set * mechanisms;
2356 	uid_t uid;
2357 {
2358 
2359 	OM_uint32 gssd_cred_verifier;
2360 	OM_uint32 gssd_cred_handle;
2361 
2362 	gssd_cred_verifier = KCRED_TO_CREDV(cred_handle);
2363 	gssd_cred_handle = KCRED_TO_CRED(cred_handle);
2364 
2365 	return (kgss_inquire_cred_wrapped(minor_status,
2366 			gssd_cred_handle, gssd_cred_verifier,
2367 			name, lifetime, cred_usage, mechanisms, uid));
2368 }
2369 
2370 OM_uint32
2371 kgss_inquire_cred_by_mech_wrapped(minor_status,
2372 		cred_handle,
2373 		gssd_cred_verifier,
2374 		mech_type,
2375 		uid)
2376 	OM_uint32 *minor_status;
2377 	gssd_cred_id_t cred_handle;
2378 	OM_uint32 gssd_cred_verifier;
2379 	gss_OID mech_type;
2380 	uid_t uid;
2381 {
2382 	CLIENT *clnt;
2383 
2384 	gss_inquire_cred_by_mech_arg arg;
2385 	gss_inquire_cred_by_mech_res res;
2386 
2387 	/* get the client handle to GSSD */
2388 
2389 	if ((clnt = getgssd_handle()) == NULL) {
2390 		GSSLOG(1, "kgss_inquire_cred: can't connect to server on %s\n",
2391 			server);
2392 		return (GSS_S_FAILURE);
2393 	}
2394 
2395 
2396 	/* copy the procedure arguments into the rpc arg parameter */
2397 
2398 	arg.uid = (OM_uint32) uid;
2399 
2400 	arg.cred_handle.GSS_CRED_ID_T_len =
2401 	    cred_handle == GSSD_NO_CREDENTIAL ?
2402 	    0 : (uint_t)sizeof (gssd_cred_id_t);
2403 	arg.cred_handle.GSS_CRED_ID_T_val = (char *)&cred_handle;
2404 	arg.gssd_cred_verifier = gssd_cred_verifier;
2405 
2406 	arg.mech_type.GSS_OID_len =
2407 		(uint_t)(mech_type != GSS_C_NULL_OID ?
2408 		mech_type->length : 0);
2409 	arg.mech_type.GSS_OID_val =
2410 		(char *)(mech_type != GSS_C_NULL_OID ?
2411 		mech_type->elements : 0);
2412 	/* call the remote procedure */
2413 
2414 	bzero((caddr_t)&res, sizeof (res));
2415 	if (gss_inquire_cred_by_mech_1(&arg, &res, clnt) != RPC_SUCCESS) {
2416 
2417 	/*
2418 	 * if the RPC call times out, null out all return arguments, set
2419 	 * minor_status to its maximum value, and return GSS_S_FAILURE
2420 	 */
2421 
2422 		if (minor_status != NULL)
2423 			*minor_status = DEFAULT_MINOR_STAT;
2424 		killgssd_handle(clnt);
2425 		GSSLOG0(1, "kgss_inquire_cred: RPC call times out\n");
2426 		return (GSS_S_FAILURE);
2427 	}
2428 
2429 	/* copy the rpc results into the return arguments */
2430 
2431 	if (minor_status != NULL)
2432 		*minor_status = res.minor_status;
2433 
2434 	clnt_freeres(clnt, xdr_gss_inquire_cred_by_mech_res, (caddr_t)&res);
2435 	killgssd_handle(clnt);
2436 	return (res.status);
2437 
2438 }
2439 
2440 OM_uint32
2441 kgss_inquire_cred_by_mech(minor_status,
2442 			cred_handle,
2443 			mech_type,
2444 			uid)
2445 	OM_uint32 *minor_status;
2446 	gss_cred_id_t cred_handle;
2447 	gss_OID mech_type;
2448 	uid_t uid;
2449 {
2450 
2451 	OM_uint32 gssd_cred_verifier;
2452 	OM_uint32 gssd_cred_handle;
2453 
2454 	gssd_cred_verifier = KCRED_TO_CREDV(cred_handle);
2455 	gssd_cred_handle = KCRED_TO_CRED(cred_handle);
2456 
2457 	return (kgss_inquire_cred_by_mech_wrapped(minor_status,
2458 			gssd_cred_handle, gssd_cred_verifier,
2459 			mech_type, uid));
2460 }
2461 
2462 OM_uint32
2463 kgsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen, uid)
2464 	const gss_buffer_t expName;
2465 	uid_t *uidOut;
2466 	gid_t *gidOut;
2467 	gid_t *gids[];
2468 	int *gidsLen;
2469 	uid_t uid;
2470 {
2471 	CLIENT *clnt;
2472 	gsscred_expname_to_unix_cred_arg args;
2473 	gsscred_expname_to_unix_cred_res res;
2474 
2475 	/* check input/output parameters */
2476 	if (expName == NULL || expName->value == NULL)
2477 		return (GSS_S_CALL_INACCESSIBLE_READ);
2478 
2479 	if (uidOut == NULL)
2480 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
2481 
2482 	/* NULL out output parameters */
2483 	*uidOut = UID_NOBODY;
2484 	if (gidsLen)
2485 		*gidsLen = 0;
2486 
2487 	if (gids)
2488 		*gids = NULL;
2489 
2490 	/* get the client handle to gssd */
2491 	if ((clnt = getgssd_handle()) == NULL)
2492 	{
2493 		GSSLOG(1, "kgsscred_expname_to_unix_cred:"
2494 			" can't connect to server on %s\n", server);
2495 		return (GSS_S_FAILURE);
2496 	}
2497 
2498 	/* copy the procedure arguments */
2499 	args.uid = uid;
2500 	args.expname.GSS_BUFFER_T_val = expName->value;
2501 	args.expname.GSS_BUFFER_T_len = expName->length;
2502 
2503 	/* null out the return buffer and call the remote proc */
2504 	bzero(&res, sizeof (res));
2505 
2506 	if (gsscred_expname_to_unix_cred_1(&args, &res, clnt) != RPC_SUCCESS)
2507 	{
2508 		killgssd_handle(clnt);
2509 		GSSLOG0(1,
2510 			"kgsscred_expname_to_unix_cred: RPC call times out\n");
2511 		return (GSS_S_FAILURE);
2512 	}
2513 
2514 	/* copy the results into the result parameters */
2515 	if (res.major == GSS_S_COMPLETE)
2516 	{
2517 		*uidOut = res.uid;
2518 		if (gidOut)
2519 			*gidOut = res.gid;
2520 		if (gids && gidsLen)
2521 		{
2522 			*gids = res.gids.GSSCRED_GIDS_val;
2523 			*gidsLen = res.gids.GSSCRED_GIDS_len;
2524 			res.gids.GSSCRED_GIDS_val = NULL;
2525 			res.gids.GSSCRED_GIDS_len = 0;
2526 		}
2527 	}
2528 
2529 	/* free RPC results */
2530 	clnt_freeres(clnt, xdr_gsscred_expname_to_unix_cred_res, (caddr_t)&res);
2531 	killgssd_handle(clnt);
2532 
2533 	return (res.major);
2534 } /* kgsscred_expname_to_unix_cred */
2535 
2536 OM_uint32
2537 kgsscred_name_to_unix_cred(intName, mechType, uidOut, gidOut, gids,
2538 				gidsLen, uid)
2539 	const gss_name_t intName;
2540 	const gss_OID mechType;
2541 	uid_t *uidOut;
2542 	gid_t *gidOut;
2543 	gid_t *gids[];
2544 	int *gidsLen;
2545 	uid_t uid;
2546 {
2547 	CLIENT *clnt;
2548 	gsscred_name_to_unix_cred_arg args;
2549 	gsscred_name_to_unix_cred_res res;
2550 	OM_uint32 major, minor;
2551 	gss_OID nameOid;
2552 	gss_buffer_desc flatName = GSS_C_EMPTY_BUFFER;
2553 
2554 	/* check the input/output parameters */
2555 	if (intName == NULL || mechType == NULL)
2556 		return (GSS_S_CALL_INACCESSIBLE_READ);
2557 
2558 	if (uidOut == NULL)
2559 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
2560 
2561 	/* NULL out the output parameters */
2562 	*uidOut = UID_NOBODY;
2563 	if (gids)
2564 		*gids = NULL;
2565 
2566 	if (gidsLen)
2567 		*gidsLen = 0;
2568 
2569 	/* get the client handle to gssd */
2570 	if ((clnt = getgssd_handle()) == NULL)
2571 	{
2572 		GSSLOG(1,
2573 		"kgsscred_name_to_unix_cred: can't connect to server %s\n",
2574 				server);
2575 		return (GSS_S_FAILURE);
2576 	}
2577 
2578 	/* convert the name to flat representation */
2579 	if ((major = gss_display_name(&minor, intName, &flatName, &nameOid))
2580 			!= GSS_S_COMPLETE)
2581 	{
2582 		killgssd_handle(clnt);
2583 		GSSLOG0(1, "kgsscred_name_to_unix_cred: display name failed\n");
2584 		return (major);
2585 	}
2586 
2587 	/* set the rpc parameters */
2588 	args.uid = uid;
2589 	args.pname.GSS_BUFFER_T_len = flatName.length;
2590 	args.pname.GSS_BUFFER_T_val = flatName.value;
2591 	args.name_type.GSS_OID_len = nameOid->length;
2592 	args.name_type.GSS_OID_val = nameOid->elements;
2593 	args.mech_type.GSS_OID_len = mechType->length;
2594 	args.mech_type.GSS_OID_val = mechType->elements;
2595 
2596 	/* call the remote procedure */
2597 	bzero(&res, sizeof (res));
2598 	if (gsscred_name_to_unix_cred_1(&args, &res, clnt) != RPC_SUCCESS) {
2599 		killgssd_handle(clnt);
2600 		(void) gss_release_buffer(&minor, &flatName);
2601 		GSSLOG0(1, "kgsscred_name_to_unix_cred: RPC call times out\n");
2602 		return (GSS_S_FAILURE);
2603 	}
2604 
2605 	/* delete the flat name buffer */
2606 	(void) gss_release_buffer(&minor, &flatName);
2607 
2608 	/* copy the output parameters on output */
2609 	if (res.major == GSS_S_COMPLETE) {
2610 		*uidOut = res.uid;
2611 
2612 		if (gidOut)
2613 			*gidOut = res.gid;
2614 		if (gids && gidsLen) {
2615 			*gids = res.gids.GSSCRED_GIDS_val;
2616 			*gidsLen = res.gids.GSSCRED_GIDS_len;
2617 			res.gids.GSSCRED_GIDS_val = NULL;
2618 			res.gids.GSSCRED_GIDS_len = 0;
2619 		}
2620 	}
2621 
2622 	/* delete RPC allocated memory */
2623 	clnt_freeres(clnt, xdr_gsscred_name_to_unix_cred_res, (caddr_t)&res);
2624 	killgssd_handle(clnt);
2625 
2626 	return (res.major);
2627 } /* kgsscred_name_to_unix_cred */
2628 
2629 OM_uint32
2630 kgss_get_group_info(puid, gidOut, gids, gidsLen, uid)
2631 	const uid_t puid;
2632 	gid_t *gidOut;
2633 	gid_t *gids[];
2634 	int *gidsLen;
2635 	uid_t uid;
2636 {
2637 	CLIENT *clnt;
2638 	gss_get_group_info_arg args;
2639 	gss_get_group_info_res res;
2640 
2641 
2642 	/* check the output parameters */
2643 	if (gidOut == NULL || gids == NULL || gidsLen == NULL)
2644 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
2645 
2646 	/* get the client GSSD handle */
2647 	if ((clnt = getgssd_handle()) == NULL) {
2648 		GSSLOG(1,
2649 			"kgss_get_group_info: can't connect to server on %s\n",
2650 			server);
2651 		return (GSS_S_FAILURE);
2652 	}
2653 
2654 	/* set the input parameters */
2655 	args.uid = uid;
2656 	args.puid = puid;
2657 
2658 	/* call the remote procedure */
2659 	bzero(&res, sizeof (res));
2660 	if (gss_get_group_info_1(&args, &res, clnt) != RPC_SUCCESS) {
2661 		killgssd_handle(clnt);
2662 		GSSLOG0(1, "kgss_get_group_info: RPC call times out\n");
2663 		return (GSS_S_FAILURE);
2664 	}
2665 
2666 	/* copy the results */
2667 	if (res.major == GSS_S_COMPLETE) {
2668 		*gidOut = res.gid;
2669 		*gids = res.gids.GSSCRED_GIDS_val;
2670 		*gidsLen = res.gids.GSSCRED_GIDS_len;
2671 		res.gids.GSSCRED_GIDS_val = NULL;
2672 		res.gids.GSSCRED_GIDS_len = 0;
2673 	}
2674 
2675 	/* no results to free */
2676 	killgssd_handle(clnt);
2677 
2678 	return (res.major);
2679 } /* kgss_get_group_info */
2680 
2681 static char *
2682 kgss_get_kmod(gss_OID mech_oid)
2683 {
2684 	CLIENT *clnt;
2685 	gss_get_kmod_arg args;
2686 	gss_get_kmod_res res;
2687 
2688 
2689 	/* get the client GSSD handle */
2690 	if ((clnt = getgssd_handle()) == NULL) {
2691 		GSSLOG(1, "kgss_get_kmod: can't connect to server on %s\n",
2692 		    server);
2693 		return (NULL);
2694 	}
2695 
2696 	/* set the input parameters */
2697 	args.mech_oid.GSS_OID_len = mech_oid->length;
2698 	args.mech_oid.GSS_OID_val = mech_oid->elements;
2699 
2700 	/* call the remote procedure */
2701 	bzero(&res, sizeof (res));
2702 	if (gss_get_kmod_1(&args, &res, clnt) != RPC_SUCCESS) {
2703 		killgssd_handle(clnt);
2704 		GSSLOG0(1, "gss_get_kmod_1: RPC call times out\n");
2705 		return (NULL);
2706 	}
2707 	/* no results to free */
2708 	killgssd_handle(clnt);
2709 
2710 	if (res.module_follow == TRUE) {
2711 		return (res.gss_get_kmod_res_u.modname);
2712 	} else
2713 		return (NULL);
2714 } /* kgss_get_kmod */
2715 
2716 static gss_mechanism	kgss_mech_head;
2717 static gss_mechanism	kgss_mech_tail;
2718 kmutex_t	__kgss_mech_lock;
2719 
2720 /*
2721  * See if there is kernel mechanism module, and if so, attempt to
2722  * load it and reset the pointer (gss_mechanism) to the sign/seal/etc.
2723  * entry points to that of the kernel module.
2724  */
2725 static void
2726 __kgss_reset_mech(gss_mechanism *mechp, gss_OID mech_oid)
2727 {
2728 	gss_mechanism mech;
2729 	char *kmod;
2730 
2731 	/*
2732 	 * We can search the list without a mutex, becuase the list never
2733 	 * shrinks and we always add to the end.
2734 	 */
2735 	mech = __kgss_get_mechanism(mech_oid);
2736 	if (mech) {
2737 		*mechp = mech;
2738 		return;
2739 	}
2740 
2741 	/*
2742 	 * Get the module name from the kernel.
2743 	 */
2744 	kmod = kgss_get_kmod(mech_oid);
2745 
2746 	if (kmod) {
2747 		extern int modload(const char *, const char *);
2748 		if (modload("misc/kgss", kmod) < 0) {
2749 			/*
2750 			 * Modload of 'kmod' failed, so log an
2751 			 * appropriate comment
2752 			 */
2753 			cmn_err(CE_NOTE, "kgss_reset_mech: Algorithm modload "
2754 			    "(%s) failed. Userland gssd will now handle "
2755 			    "all GSSAPI calls, which may result in "
2756 			    "reduced performance.\n", kmod);
2757 		};
2758 
2759 		/*
2760 		 * Allocated in the XDR routine called by gss_get_kmod_1().
2761 		 */
2762 		FREE(kmod, strlen(kmod)+1);
2763 
2764 		mech = __kgss_get_mechanism(mech_oid);
2765 		if (mech) {
2766 			*mechp = mech;
2767 		}
2768 
2769 		/*
2770 		 * If for some reason the module load didn't take,
2771 		 * we return anyway and hope that the next context
2772 		 * creation succeeds.
2773 		 */
2774 		return;
2775 	}
2776 
2777 
2778 	/*
2779 	 * No kernel module, so enter this mech oid into the list
2780 	 * using the default sign/seal/etc. operations that upcall to
2781 	 * gssd.
2782 	 */
2783 	mutex_enter(&__kgss_mech_lock);
2784 	mech = __kgss_get_mechanism(mech_oid);
2785 	if (mech) {
2786 		mutex_exit(&__kgss_mech_lock);
2787 		*mechp = mech;
2788 		return;
2789 	}
2790 
2791 	/*
2792 	 * Allocate space for the mechanism entry.
2793 	 */
2794 	mech = kmem_zalloc(sizeof (struct gss_config), KM_SLEEP);
2795 
2796 	/*
2797 	 * Copy basic information from default mechanism struct.
2798 	 */
2799 	*mech = default_gc;
2800 
2801 	/*
2802 	 * Record the real mech OID.
2803 	 */
2804 	mech->mech_type.length = mech_oid->length;
2805 	mech->mech_type.elements = MALLOC(mech_oid->length);
2806 	bcopy(mech_oid->elements,  mech->mech_type.elements, mech_oid->length);
2807 
2808 	/*
2809 	 * Add it to the table.
2810 	 */
2811 	__kgss_add_mechanism(mech);
2812 	mutex_exit(&__kgss_mech_lock);
2813 	*mechp = mech;
2814 }
2815 
2816 /*
2817  * Called with __kgss_mech_lock held.
2818  */
2819 void
2820 __kgss_add_mechanism(gss_mechanism mech)
2821 {
2822 	gss_mechanism tmp;
2823 
2824 	tmp = kgss_mech_tail;
2825 	kgss_mech_tail = mech;
2826 
2827 	if (tmp != NULL)
2828 		tmp->next = mech;
2829 
2830 	if (kgss_mech_head == NULL)
2831 		kgss_mech_head = mech;
2832 }
2833 
2834 /*
2835  *  given the mechs_array and a mechanism OID, return the
2836  *  pointer to the mechanism, or NULL if that mechanism is
2837  *  not supported.
2838  */
2839 gss_mechanism
2840 __kgss_get_mechanism(gss_OID type)
2841 {
2842 	gss_mechanism mech;
2843 
2844 	mech = kgss_mech_head;
2845 
2846 	/*
2847 	 * Note that a reader can scan this list without the mutex held.
2848 	 * This is safe because we always append, and never shrink the list.
2849 	 * Moreover, the entry is fully initialized before it is ever
2850 	 * added to the list.
2851 	 */
2852 	while (mech != NULL) {
2853 		if ((mech->mech_type.length == type->length) &&
2854 		    (bcmp(mech->mech_type.elements, type->elements,
2855 		    type->length) == 0))
2856 			return (mech);
2857 
2858 		mech = mech->next;
2859 	}
2860 	return (NULL);
2861 }
2862