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