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