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