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