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
57uint_t gss_log = 1;
58
59#endif /* GSSDEBUG */
60
61#ifdef  DEBUG
62extern void prom_printf(const char *, ...);
63#endif
64
65char *server = "localhost";
66
67static OM_uint32 kgss_sign_wrapped(void *, OM_uint32 *, gss_ctx_id_t, int,
68	gss_buffer_t, gss_buffer_t,  OM_uint32);
69
70static 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
73static 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
76static 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
80static OM_uint32 kgss_delete_sec_context_wrapped(void *, OM_uint32 *,
81	gssd_ctx_id_t *, gss_buffer_t, OM_uint32);
82
83static void __kgss_reset_mech(gss_mechanism *, gss_OID);
84
85#define	DEFAULT_MINOR_STAT	((OM_uint32) ~0)
86
87OM_uint32
88kgss_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
264OM_uint32
265kgss_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
300OM_uint32
301kgss_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
464OM_uint32
465kgss_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
509OM_uint32
510kgss_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
583OM_uint32
584kgss_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
608static OM_uint32
609kgss_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
817static 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
830void
831kgss_free_oid(gss_OID oid)
832{
833	FREE(oid->elements, oid->length);
834	FREE(oid, sizeof (gss_OID_desc));
835}
836
837OM_uint32
838kgss_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
919static OM_uint32
920kgss_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
1116OM_uint32
1117kgss_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
1185OM_uint32
1186kgss_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*/
1254static OM_uint32
1255kgss_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
1338OM_uint32
1339kgss_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
1381OM_uint32
1382kgss_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
1464OM_uint32
1465kgss_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
1511OM_uint32
1512kgss_import_sec_context(minor_status,
1513			interprocess_token,
1514			context_handle)
1515
1516OM_uint32 *		minor_status;
1517const gss_buffer_t	interprocess_token;
1518gss_ctx_id_t		context_handle;
1519
1520{
1521OM_uint32 status;
1522struct kgss_ctx	*kctx;
1523
1524size_t		length;
1525char		*p;
1526gss_buffer_desc token;
1527gss_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*/
1580OM_uint32
1581kgss_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*/
1594static OM_uint32
1595kgss_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
1673OM_uint32
1674kgss_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*/
1688static OM_uint32
1689kgss_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
1763OM_uint32
1764kgss_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*/
1777static OM_uint32
1778kgss_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*/
1874OM_uint32
1875kgss_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*/
1893static OM_uint32
1894kgss_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
1990OM_uint32
1991kgss_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
2006OM_uint32
2007kgss_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*/
2099OM_uint32
2100kgss_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
2170OM_uint32
2171kgss_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
2322OM_uint32
2323kgss_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
2350OM_uint32
2351kgss_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
2420OM_uint32
2421kgss_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
2442OM_uint32
2443kgsscred_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
2516OM_uint32
2517kgsscred_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
2609OM_uint32
2610kgss_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
2661static char *
2662kgss_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
2696static gss_mechanism	kgss_mech_head;
2697static gss_mechanism	kgss_mech_tail;
2698kmutex_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 */
2705static 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 */
2799void
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 */
2819gss_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