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