Home | History | Annotate | Download | only in gssapi
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 /*
     29  *  GSSAPI library stub module for gssd.
     30  */
     31 
     32 #include <mechglueP.h>
     33 #include "gssd_prot.h"
     34 #include <rpc/rpc.h>
     35 
     36 #include <sys/systm.h>
     37 #include <sys/types.h>
     38 #include <sys/cmn_err.h>
     39 #include <sys/kmem.h>
     40 #include <gssapi/kgssapi_defs.h>
     41 #include <sys/debug.h>
     42 
     43 #ifdef GSSDEBUG
     44 /*
     45  * Kernel kgssd module debugging aid. The global variable "gss_log"
     46  * is a bit mask which allows various types of debugging messages
     47  * to be printed out.
     48  *
     49  *	 gss_log & 1  will cause actual failures to be printed.
     50  *	 gss_log & 2  will cause informational messages to be
     51  *	                 printed on the client side of kgssd.
     52  *	 gss_log & 4  will cause informational messages to be
     53  *	                 printed on the server side of kgssd.
     54  *	 gss_log & 8  will cause informational messages to be
     55  *	                 printed on both client and server side of kgssd.
     56  */
     57 
     58 uint_t gss_log = 1;
     59 
     60 #endif /* GSSDEBUG */
     61 
     62 #ifdef  DEBUG
     63 extern void prom_printf();
     64 #endif
     65 
     66 char *server = "localhost";
     67 
     68 static OM_uint32 kgss_sign_wrapped(void *, OM_uint32 *, gss_ctx_id_t, int,
     69 	gss_buffer_t, gss_buffer_t,  OM_uint32);
     70 
     71 static OM_uint32 kgss_verify_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
     72 	gss_buffer_t, gss_buffer_t, int *qop_state, OM_uint32);
     73 
     74 /* EXPORT DELETE START */
     75 static OM_uint32 kgss_seal_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
     76 	int, int, gss_buffer_t, int *, gss_buffer_t,  OM_uint32);
     77 
     78 static OM_uint32 kgss_unseal_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
     79 	gss_buffer_t, gss_buffer_t, int *conf_state, int *qop_state,
     80 	OM_uint32);
     81 /* EXPORT DELETE END */
     82 
     83 static OM_uint32 kgss_delete_sec_context_wrapped(void *, OM_uint32 *,
     84 	gssd_ctx_id_t *, gss_buffer_t, OM_uint32);
     85 
     86 static void __kgss_reset_mech(gss_mechanism *, gss_OID);
     87 
     88 #define	DEFAULT_MINOR_STAT	((OM_uint32) ~0)
     89 
     90 OM_uint32
     91 kgss_acquire_cred_wrapped(minor_status,
     92 			desired_name,
     93 			time_req,
     94 			desired_mechs,
     95 			cred_usage,
     96 			output_cred_handle,
     97 			actual_mechs,
     98 			time_rec,
     99 			uid,
    100 			gssd_cred_verifier)
    101 	OM_uint32 *minor_status;
    102 	const gss_name_t desired_name;
    103 	OM_uint32 time_req;
    104 	const gss_OID_set desired_mechs;
    105 	int cred_usage;
    106 	gssd_cred_id_t *output_cred_handle;
    107 	gss_OID_set *actual_mechs;
    108 	OM_uint32 *time_rec;
    109 	uid_t uid;
    110 	OM_uint32 *gssd_cred_verifier;
    111 {
    112 	CLIENT *clnt;
    113 
    114 	OM_uint32 	minor_status_temp;
    115 	gss_buffer_desc	external_name;
    116 	gss_OID		name_type;
    117 	enum clnt_stat	client_stat;
    118 	int		i;
    119 
    120 	gss_acquire_cred_arg arg;
    121 	gss_acquire_cred_res res;
    122 
    123 	/* get the client handle to GSSD */
    124 
    125 	if ((clnt = getgssd_handle()) == NULL) {
    126 		GSSLOG(1, "kgss_acquire_cred: can't connect to server on %s\n",
    127 			server);
    128 		return (GSS_S_FAILURE);
    129 	}
    130 
    131 	/* convert the desired name from internal to external format */
    132 
    133 	if (gss_display_name(&minor_status_temp, desired_name, &external_name,
    134 				&name_type) != GSS_S_COMPLETE) {
    135 
    136 		*minor_status = (OM_uint32) minor_status_temp;
    137 		killgssd_handle(clnt);
    138 		GSSLOG0(1, "kgss_acquire_cred: display name failed\n");
    139 		return ((OM_uint32) GSS_S_FAILURE);
    140 	}
    141 
    142 
    143 	/* copy the procedure arguments into the rpc arg parameter */
    144 
    145 	arg.uid = (OM_uint32) uid;
    146 
    147 	arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
    148 	arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value;
    149 
    150 	arg.name_type.GSS_OID_len =
    151 		name_type == GSS_C_NULL_OID ?
    152 			0 : (uint_t)name_type->length;
    153 
    154 	arg.name_type.GSS_OID_val =
    155 		name_type == GSS_C_NULL_OID ?
    156 			(char *)NULL : (char *)name_type->elements;
    157 
    158 	arg.time_req = time_req;
    159 
    160 	if (desired_mechs != GSS_C_NULL_OID_SET) {
    161 		arg.desired_mechs.GSS_OID_SET_len =
    162 			(uint_t)desired_mechs->count;
    163 		arg.desired_mechs.GSS_OID_SET_val = (GSS_OID *)
    164 			MALLOC(sizeof (GSS_OID) * desired_mechs->count);
    165 
    166 		for (i = 0; i < desired_mechs->count; i++) {
    167 		    arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len =
    168 			(uint_t)desired_mechs->elements[i].length;
    169 		    arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val =
    170 			(char *)MALLOC(desired_mechs->elements[i].length);
    171 		    (void) memcpy(
    172 			arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val,
    173 			desired_mechs->elements[i].elements,
    174 			desired_mechs->elements[i].length);
    175 		}
    176 	} else
    177 		arg.desired_mechs.GSS_OID_SET_len = 0;
    178 
    179 	arg.cred_usage = cred_usage;
    180 
    181 	/* call the remote procedure */
    182 
    183 	bzero((caddr_t)&res, sizeof (res));
    184 	client_stat = gss_acquire_cred_1(&arg, &res, clnt);
    185 
    186 	(void) gss_release_buffer(&minor_status_temp, &external_name);
    187 	if (desired_mechs != GSS_C_NULL_OID_SET) {
    188 		for (i = 0; i < desired_mechs->count; i++)
    189 			FREE(arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val,
    190 			    arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len);
    191 		FREE(arg.desired_mechs.GSS_OID_SET_val,
    192 		    arg.desired_mechs.GSS_OID_SET_len * sizeof (GSS_OID));
    193 	}
    194 
    195 	if (client_stat != RPC_SUCCESS) {
    196 
    197 		/*
    198 		 * if the RPC call times out, null out all return arguments,
    199 		 * set minor_status to its maximum value, and return
    200 		 * GSS_S_FAILURE
    201 		 */
    202 
    203 		if (minor_status != NULL)
    204 			*minor_status = DEFAULT_MINOR_STAT;
    205 		if (output_cred_handle != NULL)
    206 			*output_cred_handle = NULL;
    207 		if (actual_mechs != NULL)
    208 			*actual_mechs = NULL;
    209 		if (time_rec != NULL)
    210 			*time_rec = 0;
    211 
    212 		killgssd_handle(clnt);
    213 		GSSLOG0(1, "kgss_acquire_cred: RPC call times out\n");
    214 		return (GSS_S_FAILURE);
    215 	}
    216 
    217 	/* copy the rpc results into the return arguments */
    218 
    219 	if (minor_status != NULL)
    220 		*minor_status = res.minor_status;
    221 
    222 	if (output_cred_handle != NULL &&
    223 		(res.status == GSS_S_COMPLETE)) {
    224 	    *output_cred_handle =
    225 		*((gssd_cred_id_t *)res.output_cred_handle.GSS_CRED_ID_T_val);
    226 	    *gssd_cred_verifier = res.gssd_cred_verifier;
    227 	}
    228 
    229 	if (res.status == GSS_S_COMPLETE &&
    230 		res.actual_mechs.GSS_OID_SET_len != 0 &&
    231 		actual_mechs != NULL) {
    232 		*actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
    233 		(*actual_mechs)->count =
    234 					(int)res.actual_mechs.GSS_OID_SET_len;
    235 		(*actual_mechs)->elements = (gss_OID)
    236 			MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count);
    237 
    238 		for (i = 0; i < (*actual_mechs)->count; i++) {
    239 		    (*actual_mechs)->elements[i].length = (OM_uint32)
    240 			res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len;
    241 		    (*actual_mechs)->elements[i].elements =
    242 			(void *) MALLOC((*actual_mechs)->elements[i].length);
    243 		    (void) memcpy((*actual_mechs)->elements[i].elements,
    244 			res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
    245 			(*actual_mechs)->elements[i].length);
    246 		}
    247 	} else {
    248 		if (res.status == GSS_S_COMPLETE &&
    249 			actual_mechs != NULL)
    250 			(*actual_mechs) = NULL;
    251 	}
    252 
    253 	if (time_rec != NULL)
    254 		*time_rec = res.time_rec;
    255 
    256 	/*
    257 	 * free the memory allocated for the results and return with the status
    258 	 * received in the rpc call
    259 	 */
    260 
    261 	clnt_freeres(clnt, xdr_gss_acquire_cred_res, (caddr_t)&res);
    262 	killgssd_handle(clnt);
    263 	return (res.status);
    264 
    265 }
    266 
    267 OM_uint32
    268 kgss_acquire_cred(minor_status,
    269 		desired_name,
    270 		time_req,
    271 		desired_mechs,
    272 		cred_usage,
    273 		output_cred_handle,
    274 		actual_mechs,
    275 		time_rec,
    276 		uid)
    277 	OM_uint32 *minor_status;
    278 	const gss_name_t desired_name;
    279 	OM_uint32 time_req;
    280 	const gss_OID_set desired_mechs;
    281 	int cred_usage;
    282 	gss_cred_id_t *output_cred_handle;
    283 	gss_OID_set *actual_mechs;
    284 	OM_uint32 *time_rec;
    285 	uid_t uid;
    286 {
    287 
    288 	OM_uint32	err;
    289 	struct kgss_cred *kcred;
    290 
    291 	kcred = KGSS_CRED_ALLOC();
    292 	*output_cred_handle = (gss_cred_id_t)kcred;
    293 	err = kgss_acquire_cred_wrapped(minor_status, desired_name, time_req,
    294 		desired_mechs, cred_usage, &kcred->gssd_cred, actual_mechs,
    295 		time_rec, uid, &kcred->gssd_cred_verifier);
    296 	if (GSS_ERROR(err)) {
    297 		KGSS_CRED_FREE(kcred);
    298 		*output_cred_handle = GSS_C_NO_CREDENTIAL;
    299 	}
    300 	return (err);
    301 }
    302 
    303 OM_uint32
    304 kgss_add_cred_wrapped(minor_status,
    305 			input_cred_handle,
    306 			gssd_cred_verifier,
    307 			desired_name,
    308 			desired_mech_type,
    309 			cred_usage,
    310 			initiator_time_req,
    311 			acceptor_time_req,
    312 			actual_mechs,
    313 			initiator_time_rec,
    314 			acceptor_time_rec,
    315 			uid)
    316 	OM_uint32 *minor_status;
    317 	gssd_cred_id_t input_cred_handle;
    318 	OM_uint32 gssd_cred_verifier;
    319 	gss_name_t desired_name;
    320 	gss_OID desired_mech_type;
    321 	int cred_usage;
    322 	int initiator_time_req;
    323 	int acceptor_time_req;
    324 	gss_OID_set *actual_mechs;
    325 	OM_uint32 *initiator_time_rec;
    326 	OM_uint32 *acceptor_time_rec;
    327 	uid_t uid;
    328 {
    329 	CLIENT *clnt;
    330 
    331 	OM_uint32 	minor_status_temp;
    332 	gss_buffer_desc	external_name;
    333 	gss_OID		name_type;
    334 	int		i;
    335 
    336 	gss_add_cred_arg arg;
    337 	gss_add_cred_res res;
    338 
    339 
    340 	/*
    341 	 * NULL the params here once
    342 	 * If there are errors then we won't
    343 	 * have to do it for every error
    344 	 * case
    345 	 */
    346 
    347 	if (minor_status != NULL)
    348 		*minor_status = DEFAULT_MINOR_STAT;
    349 	if (actual_mechs != NULL)
    350 		*actual_mechs = NULL;
    351 	if (initiator_time_rec != NULL)
    352 		*initiator_time_rec = 0;
    353 	if (acceptor_time_rec != NULL)
    354 			*acceptor_time_rec = 0;
    355 	/* get the client handle to GSSD */
    356 
    357 	if ((clnt = getgssd_handle()) == NULL) {
    358 		GSSLOG(1, "kgss_add_cred: can't connect to server on %s\n",
    359 			server);
    360 		return (GSS_S_FAILURE);
    361 	}
    362 
    363 
    364 	/* convert the desired name from internal to external format */
    365 
    366 	if (gss_display_name(&minor_status_temp, desired_name, &external_name,
    367 				&name_type) != GSS_S_COMPLETE) {
    368 
    369 		*minor_status = (OM_uint32) minor_status_temp;
    370 		killgssd_handle(clnt);
    371 		GSSLOG0(1, "kgss_acquire_cred: display name failed\n");
    372 		return ((OM_uint32) GSS_S_FAILURE);
    373 	}
    374 
    375 
    376 	/* copy the procedure arguments into the rpc arg parameter */
    377 
    378 	arg.uid = (OM_uint32)uid;
    379 	arg.input_cred_handle.GSS_CRED_ID_T_len =
    380 			input_cred_handle ==
    381 			(gssd_cred_id_t)GSS_C_NO_CREDENTIAL ?
    382 			0 : (uint_t)sizeof (gssd_cred_id_t);
    383 	arg.input_cred_handle.GSS_CRED_ID_T_val = (char *)&input_cred_handle;
    384 	arg.gssd_cred_verifier = gssd_cred_verifier;
    385 	arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
    386 	arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value;
    387 	arg.name_type.GSS_OID_len =
    388 		name_type == GSS_C_NULL_OID ?
    389 			0 : (uint_t)name_type->length;
    390 	arg.name_type.GSS_OID_val =
    391 		name_type == GSS_C_NULL_OID ?
    392 			(char *)NULL : (char *)name_type->elements;
    393 
    394 	arg.desired_mech_type.GSS_OID_len =
    395 		(uint_t)(desired_mech_type != GSS_C_NULL_OID ?
    396 		desired_mech_type->length : 0);
    397 	arg.desired_mech_type.GSS_OID_val =
    398 		(char *)(desired_mech_type != GSS_C_NULL_OID ?
    399 		desired_mech_type->elements : 0);
    400 	arg.cred_usage = cred_usage;
    401 	arg.initiator_time_req = initiator_time_req;
    402 	arg.acceptor_time_req = acceptor_time_req;
    403 
    404 	/* call the remote procedure */
    405 
    406 	bzero((caddr_t)&res, sizeof (res));
    407 	if (gss_add_cred_1(&arg, &res, clnt) != RPC_SUCCESS) {
    408 
    409 		/*
    410 		 * if the RPC call times out, null out all return arguments,
    411 		 * set minor_status to its maximum value, and return
    412 		 * GSS_S_FAILURE
    413 		 */
    414 
    415 		killgssd_handle(clnt);
    416 		(void) gss_release_buffer(&minor_status_temp, &external_name);
    417 		GSSLOG0(1, "kgss_add_cred: RPC call times out\n");
    418 		return (GSS_S_FAILURE);
    419 	}
    420 
    421 	/* free the allocated memory for the flattened name */
    422 
    423 	(void) gss_release_buffer(&minor_status_temp, &external_name);
    424 
    425 	/* copy the rpc results into the return arguments */
    426 
    427 	if (minor_status != NULL)
    428 		*minor_status = res.minor_status;
    429 
    430 	if (res.status == GSS_S_COMPLETE &&
    431 		res.actual_mechs.GSS_OID_SET_len != 0 &&
    432 		actual_mechs != NULL) {
    433 		*actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
    434 		(*actual_mechs)->count =
    435 					(int)res.actual_mechs.GSS_OID_SET_len;
    436 		(*actual_mechs)->elements = (gss_OID)
    437 			MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count);
    438 
    439 		for (i = 0; i < (*actual_mechs)->count; i++) {
    440 		    (*actual_mechs)->elements[i].length = (OM_uint32)
    441 			res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len;
    442 		    (*actual_mechs)->elements[i].elements =
    443 			(void *) MALLOC((*actual_mechs)->elements[i].length);
    444 		    (void) memcpy((*actual_mechs)->elements[i].elements,
    445 			res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
    446 			(*actual_mechs)->elements[i].length);
    447 		}
    448 	} else {
    449 		if (res.status == GSS_S_COMPLETE && actual_mechs != NULL)
    450 			(*actual_mechs) = NULL;
    451 	}
    452 	if (initiator_time_rec != NULL)
    453 		*initiator_time_rec = res.acceptor_time_rec;
    454 	if (acceptor_time_rec != NULL)
    455 		*acceptor_time_rec = res.acceptor_time_rec;
    456 
    457 	/*
    458 	 * free the memory allocated for the results and return with the status
    459 	 * received in the rpc call
    460 	 */
    461 
    462 	clnt_freeres(clnt, xdr_gss_add_cred_res, (caddr_t)&res);
    463 	killgssd_handle(clnt);
    464 	return (res.status);
    465 
    466 }
    467 
    468 OM_uint32
    469 kgss_add_cred(minor_status,
    470 			input_cred_handle,
    471 			desired_name,
    472 			desired_mech_type,
    473 			cred_usage,
    474 			initiator_time_req,
    475 			acceptor_time_req,
    476 			actual_mechs,
    477 			initiator_time_rec,
    478 			acceptor_time_rec,
    479 			uid)
    480 	OM_uint32 *minor_status;
    481 	gss_cred_id_t input_cred_handle;
    482 	gss_name_t desired_name;
    483 	gss_OID desired_mech_type;
    484 	int cred_usage;
    485 	int initiator_time_req;
    486 	int acceptor_time_req;
    487 	gss_OID_set *actual_mechs;
    488 	OM_uint32 *initiator_time_rec;
    489 	OM_uint32 *acceptor_time_rec;
    490 	uid_t uid;
    491 {
    492 
    493 	OM_uint32	err;
    494 	OM_uint32 gssd_cred_verifier;
    495 	gssd_cred_id_t gssd_input_cred_handle;
    496 
    497 	if (input_cred_handle != GSS_C_NO_CREDENTIAL) {
    498 		gssd_cred_verifier = KCRED_TO_CREDV(input_cred_handle);
    499 		gssd_input_cred_handle = KCRED_TO_CRED(input_cred_handle);
    500 	} else
    501 		gssd_input_cred_handle = (gssd_cred_id_t)GSS_C_NO_CREDENTIAL;
    502 
    503 	err = kgss_add_cred_wrapped(minor_status, gssd_input_cred_handle,
    504 			gssd_cred_verifier, desired_name, desired_mech_type,
    505 			cred_usage, initiator_time_req, acceptor_time_req,
    506 			actual_mechs, initiator_time_rec,
    507 			acceptor_time_rec, uid);
    508 	return (err);
    509 }
    510 
    511 
    512 OM_uint32
    513 kgss_release_cred_wrapped(minor_status,
    514 			cred_handle,
    515 			uid,
    516 			gssd_cred_verifier)
    517     OM_uint32 *minor_status;
    518     gssd_cred_id_t *cred_handle;
    519     uid_t uid;
    520     OM_uint32  gssd_cred_verifier;
    521 {
    522 	CLIENT *clnt;
    523 
    524 	gss_release_cred_arg arg;
    525 	gss_release_cred_res res;
    526 
    527 
    528 	/* get the client handle to GSSD */
    529 
    530 	if ((clnt = getgssd_handle()) == NULL) {
    531 		GSSLOG(1, "kgss_release_cred: can't connect to server on %s\n",
    532 			server);
    533 		return (GSS_S_FAILURE);
    534 	}
    535 
    536 	/* copy the procedure arguments into the rpc arg parameter */
    537 
    538 	arg.uid = (OM_uint32)uid;
    539 	arg.gssd_cred_verifier = gssd_cred_verifier;
    540 
    541 	if (cred_handle != NULL) {
    542 		arg.cred_handle.GSS_CRED_ID_T_len =
    543 					(uint_t)sizeof (gssd_cred_id_t);
    544 		arg.cred_handle.GSS_CRED_ID_T_val = (char *)cred_handle;
    545 	} else
    546 		arg.cred_handle.GSS_CRED_ID_T_len = 0;
    547 
    548 	/* call the remote procedure */
    549 
    550 	bzero((caddr_t)&res, sizeof (res));
    551 	if (gss_release_cred_1(&arg, &res, clnt) != RPC_SUCCESS) {
    552 
    553 	/*
    554 	 * if the RPC call times out, null out all return arguments, set
    555 	 * minor_status to its maximum value, and return GSS_S_FAILURE
    556 	 */
    557 
    558 		if (minor_status != NULL)
    559 			*minor_status = DEFAULT_MINOR_STAT;
    560 		if (cred_handle != NULL)
    561 			*cred_handle = NULL;
    562 
    563 		killgssd_handle(clnt);
    564 		GSSLOG0(1, "kgss_release_cred: RPC call times out\n");
    565 		return (GSS_S_FAILURE);
    566 	}
    567 
    568 	/* if the release succeeded, null out the cred_handle */
    569 
    570 	if (res.status == GSS_S_COMPLETE && cred_handle != NULL)
    571 		*cred_handle = NULL;
    572 
    573 	/* copy the rpc results into the return arguments */
    574 
    575 	if (minor_status != NULL)
    576 		*minor_status = res.minor_status;
    577 
    578 	/* return with status returned in rpc call */
    579 
    580 	killgssd_handle(clnt);
    581 
    582 	return (res.status);
    583 
    584 }
    585 
    586 OM_uint32
    587 kgss_release_cred(minor_status,
    588 			cred_handle,
    589 			uid)
    590     OM_uint32 *minor_status;
    591     gss_cred_id_t *cred_handle;
    592     uid_t uid;
    593 
    594 {
    595 
    596 	OM_uint32	err;
    597 	struct kgss_cred *kcred;
    598 
    599 	if (*cred_handle == GSS_C_NO_CREDENTIAL)
    600 		return (GSS_S_COMPLETE);
    601 	else
    602 		kcred = KCRED_TO_KGSS_CRED(*cred_handle);
    603 
    604 	err = kgss_release_cred_wrapped(minor_status, &kcred->gssd_cred,
    605 		uid, kcred->gssd_cred_verifier);
    606 	KGSS_CRED_FREE(kcred);
    607 	*cred_handle = GSS_C_NO_CREDENTIAL;
    608 	return (err);
    609 }
    610 
    611 static OM_uint32
    612 kgss_init_sec_context_wrapped(
    613 	OM_uint32 *minor_status,
    614 	const gssd_cred_id_t claimant_cred_handle,
    615 	OM_uint32 gssd_cred_verifier,
    616 	gssd_ctx_id_t *context_handle,
    617 	OM_uint32 *gssd_context_verifier,
    618 	const gss_name_t target_name,
    619 	const gss_OID mech_type,
    620 	int req_flags,
    621 	OM_uint32 time_req,
    622 	const gss_channel_bindings_t input_chan_bindings,
    623 	const gss_buffer_t input_token,
    624 	gss_OID *actual_mech_type,
    625 	gss_buffer_t output_token,
    626 	int *ret_flags,
    627 	OM_uint32 *time_rec,
    628 	uid_t uid)
    629 {
    630 	CLIENT *clnt;
    631 
    632 	OM_uint32 	minor_status_temp;
    633 	gss_buffer_desc	external_name;
    634 	gss_OID		name_type;
    635 
    636 	gss_init_sec_context_arg arg;
    637 	gss_init_sec_context_res res;
    638 
    639 	/* get the client handle to GSSD */
    640 
    641 	if ((clnt = getgssd_handle()) == NULL) {
    642 		GSSLOG(1,
    643 		"kgss_init_sec_context: can't connect to server on %s\n",
    644 		server);
    645 		return (GSS_S_FAILURE);
    646 	}
    647 
    648 	/* convert the target name from internal to external format */
    649 
    650 	if (gss_display_name(&minor_status_temp, target_name,
    651 		&external_name, &name_type) != GSS_S_COMPLETE) {
    652 
    653 		*minor_status = (OM_uint32) minor_status_temp;
    654 		killgssd_handle(clnt);
    655 		GSSLOG0(1, "kgss_init_sec_context: can't display name\n");
    656 		return ((OM_uint32) GSS_S_FAILURE);
    657 	}
    658 
    659 
    660 	/* copy the procedure arguments into the rpc arg parameter */
    661 
    662 	arg.uid = (OM_uint32)uid;
    663 
    664 	arg.context_handle.GSS_CTX_ID_T_len =
    665 		*context_handle == (gssd_ctx_id_t)GSS_C_NO_CONTEXT ?
    666 			0 : (uint_t)sizeof (gssd_ctx_id_t);
    667 	arg.context_handle.GSS_CTX_ID_T_val =  (char *)context_handle;
    668 
    669 	arg.gssd_context_verifier =  *gssd_context_verifier;
    670 
    671 	arg.claimant_cred_handle.GSS_CRED_ID_T_len =
    672 		claimant_cred_handle == (gssd_cred_id_t)GSS_C_NO_CREDENTIAL ?
    673 			0 : (uint_t)sizeof (gssd_cred_id_t);
    674 	arg.claimant_cred_handle.GSS_CRED_ID_T_val =
    675 						(char *)&claimant_cred_handle;
    676 	arg.gssd_cred_verifier = gssd_cred_verifier;
    677 
    678 	arg.target_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
    679 	arg.target_name.GSS_BUFFER_T_val = (char *)external_name.value;
    680 
    681 	arg.name_type.GSS_OID_len =
    682 		name_type == GSS_C_NULL_OID ?
    683 			0 : (uint_t)name_type->length;
    684 
    685 	arg.name_type.GSS_OID_val =
    686 		name_type == GSS_C_NULL_OID ?
    687 			(char *)NULL : (char *)name_type->elements;
    688 
    689 	arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ?
    690 						mech_type->length : 0);
    691 	arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ?
    692 						mech_type->elements : 0);
    693 
    694 	arg.req_flags = req_flags;
    695 
    696 	arg.time_req = time_req;
    697 
    698 	if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
    699 		arg.input_chan_bindings.present = YES;
    700 		arg.input_chan_bindings.initiator_addrtype =
    701 			input_chan_bindings->initiator_addrtype;
    702 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len =
    703 			(uint_t)input_chan_bindings->initiator_address.length;
    704 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val =
    705 			(void *)input_chan_bindings->initiator_address.value;
    706 		arg.input_chan_bindings.acceptor_addrtype =
    707 			input_chan_bindings->acceptor_addrtype;
    708 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len =
    709 			(uint_t)input_chan_bindings->acceptor_address.length;
    710 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val =
    711 			(void *)input_chan_bindings->acceptor_address.value;
    712 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_len =
    713 			(uint_t)input_chan_bindings->application_data.length;
    714 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_val =
    715 			(void *)input_chan_bindings->application_data.value;
    716 	} else {
    717 		arg.input_chan_bindings.present = NO;
    718 		arg.input_chan_bindings.initiator_addrtype = 0;
    719 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0;
    720 		arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0;
    721 		arg.input_chan_bindings.acceptor_addrtype = 0;
    722 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0;
    723 		arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0;
    724 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0;
    725 		arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0;
    726 	}
    727 
    728 	arg.input_token.GSS_BUFFER_T_len =
    729 		(uint_t)(input_token != GSS_C_NO_BUFFER ?
    730 		input_token->length : 0);
    731 	arg.input_token.GSS_BUFFER_T_val =
    732 		(char *)(input_token != GSS_C_NO_BUFFER ?
    733 		input_token->value : 0);
    734 
    735 	/* call the remote procedure */
    736 
    737 	bzero((caddr_t)&res, sizeof (res));
    738 	if (gss_init_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
    739 
    740 	/*
    741 	 * if the RPC call times out, null out all return arguments, set
    742 	 * minor_status to its maximum value, and return GSS_S_FAILURE
    743 	 */
    744 
    745 		if (minor_status != NULL)
    746 			*minor_status = DEFAULT_MINOR_STAT;
    747 		if (actual_mech_type != NULL)
    748 			*actual_mech_type = NULL;
    749 		if (output_token != NULL)
    750 			output_token->length = 0;
    751 		if (ret_flags != NULL)
    752 			*ret_flags = 0;
    753 		if (time_rec != NULL)
    754 			*time_rec = 0;
    755 
    756 		killgssd_handle(clnt);
    757 		(void) gss_release_buffer(&minor_status_temp, &external_name);
    758 		GSSLOG0(1, "kgss_init_sec_context: RPC call times out\n");
    759 		return (GSS_S_FAILURE);
    760 	}
    761 
    762 	/* free the allocated memory for the flattened name */
    763 
    764 	(void) gss_release_buffer(&minor_status_temp, &external_name);
    765 
    766 	if (minor_status != NULL)
    767 		*minor_status = res.minor_status;
    768 
    769 	/* if the call was successful, copy out the results */
    770 	if (res.status == (OM_uint32) GSS_S_COMPLETE ||
    771 		res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) {
    772 		/*
    773 		 * if the return code is GSS_S_CONTINUE_NEEDED
    774 		 * ignore all return parameters except for
    775 		 * status codes, output token and context handle.
    776 		 */
    777 		*context_handle =
    778 			*((gssd_ctx_id_t *)
    779 			res.context_handle.GSS_CTX_ID_T_val);
    780 		*gssd_context_verifier = res.gssd_context_verifier;
    781 
    782 		if (output_token != NULL) {
    783 			output_token->length =
    784 				(size_t)res.output_token.GSS_BUFFER_T_len;
    785 			output_token->value =
    786 				(void *)MALLOC(output_token->length);
    787 			(void) memcpy(output_token->value,
    788 				res.output_token.GSS_BUFFER_T_val,
    789 				output_token->length);
    790 		}
    791 
    792 		if (res.status == GSS_S_COMPLETE) {
    793 			if (actual_mech_type != NULL) {
    794 				*actual_mech_type =
    795 					(gss_OID) MALLOC(sizeof (gss_OID_desc));
    796 				(*actual_mech_type)->length =
    797 					(OM_UINT32)
    798 					res.actual_mech_type.GSS_OID_len;
    799 				(*actual_mech_type)->elements =
    800 					(void *)
    801 					MALLOC((*actual_mech_type)->length);
    802 				(void) memcpy((*actual_mech_type)->elements,
    803 					(void *)
    804 					res.actual_mech_type.GSS_OID_val,
    805 					(*actual_mech_type)->length);
    806 			}
    807 
    808 
    809 			if (ret_flags != NULL)
    810 				*ret_flags = res.ret_flags;
    811 
    812 			if (time_rec != NULL)
    813 				*time_rec = res.time_rec;
    814 		}
    815 	}
    816 
    817 	/*
    818 	 * free the memory allocated for the results and return with the status
    819 	 * received in the rpc call
    820 	 */
    821 
    822 	clnt_freeres(clnt, xdr_gss_init_sec_context_res, (caddr_t)&res);
    823 	killgssd_handle(clnt);
    824 	return (res.status);
    825 
    826 }
    827 
    828 static struct gss_config default_gc = {
    829 	{ 0, NULL},
    830 	NULL,
    831 	NULL,
    832 	0,
    833 /* EXPORT DELETE START */ /* CRYPT DELETE START */
    834 	kgss_unseal_wrapped,
    835 /* EXPORT DELETE END */ /* CRYPT DELETE END */
    836 	NULL,		/* kgss_delete_sec_context_wrapped */
    837 /* EXPORT DELETE START */ /* CRYPT DELETE START */
    838 	kgss_seal_wrapped,
    839 /* EXPORT DELETE END */ /* CRYPT DELETE END */
    840 	NULL,		/* kgss_import_sec_context */
    841 /* EXPORT DELETE START */
    842 /* CRYPT DELETE START */
    843 #if 0
    844 /* CRYPT DELETE END */
    845 	kgss_seal_wrapped,
    846 	kgss_unseal_wrapped,
    847 /* CRYPT DELETE START */
    848 #endif
    849 /* CRYPT DELETE END */
    850 /* EXPORT DELETE END */
    851 	kgss_sign_wrapped,
    852 	kgss_verify_wrapped
    853 };
    854 
    855 void
    856 kgss_free_oid(gss_OID oid)
    857 {
    858 	FREE(oid->elements, oid->length);
    859 	FREE(oid, sizeof (gss_OID_desc));
    860 }
    861 
    862 OM_uint32
    863 kgss_init_sec_context(
    864 	OM_uint32 *minor_status,
    865 	const gss_cred_id_t claimant_cred_handle,
    866 	gss_ctx_id_t *context_handle,
    867 	const gss_name_t target_name,
    868 	const gss_OID mech_type,
    869 	int req_flags,
    870 	OM_uint32 time_req,
    871 	const gss_channel_bindings_t input_chan_bindings,
    872 	const gss_buffer_t input_token,
    873 	gss_OID *actual_mech_type,
    874 	gss_buffer_t output_token,
    875 	int *ret_flags,
    876 	OM_uint32 *time_rec,
    877 	uid_t uid)
    878 {
    879 	OM_uint32	err;
    880 	struct kgss_ctx	*kctx;
    881 	gss_OID	amt;
    882 	gssd_cred_id_t gssd_cl_cred_handle;
    883 	OM_uint32 gssd_cred_verifier;
    884 
    885 	/*
    886 	 * If this is an initial call, we'll need to create the
    887 	 * wrapper struct that contains kernel state information, and
    888 	 * a reference to the handle from gssd.
    889 	 */
    890 	if (*context_handle == GSS_C_NO_CONTEXT) {
    891 		kctx = KGSS_ALLOC();
    892 		/*
    893 		 * The default gss-mechanism struct as pointers to
    894 		 * the sign/seal/verify/unseal routines that make
    895 		 * upcalls to gssd.
    896 		 */
    897 		kctx->mech = &default_gc;
    898 		kctx->gssd_ctx = (gssd_ctx_id_t)GSS_C_NO_CONTEXT;
    899 		*context_handle = (gss_ctx_id_t)kctx;
    900 	} else
    901 		kctx = (struct kgss_ctx *)*context_handle;
    902 
    903 	if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
    904 		gssd_cred_verifier = KCRED_TO_CREDV(claimant_cred_handle);
    905 		gssd_cl_cred_handle = KCRED_TO_CRED(claimant_cred_handle);
    906 	} else
    907 		gssd_cl_cred_handle = (gssd_cred_id_t)GSS_C_NO_CREDENTIAL;
    908 
    909 	/*
    910 	 * We need to know the resulting mechanism oid, so allocate
    911 	 * it if the caller won't.
    912 	 */
    913 	if (actual_mech_type == NULL)
    914 		actual_mech_type = &amt;
    915 
    916 	err = kgss_init_sec_context_wrapped(minor_status, gssd_cl_cred_handle,
    917 		gssd_cred_verifier, &kctx->gssd_ctx, &kctx->gssd_ctx_verifier,
    918 		target_name, mech_type, req_flags, time_req,
    919 		input_chan_bindings, input_token, actual_mech_type,
    920 		output_token, ret_flags, time_rec, uid);
    921 
    922 	if (GSS_ERROR(err)) {
    923 		KGSS_FREE(kctx);
    924 		*context_handle = GSS_C_NO_CONTEXT;
    925 	} else if (err == GSS_S_COMPLETE) {
    926 		/*
    927 		 * Now check if there is a kernel module for this
    928 		 * mechanism OID. If so, set the gss_mechanism structure
    929 		 * in the wrapper context to point to the kernel mech.
    930 		 */
    931 		__kgss_reset_mech(&kctx->mech, *actual_mech_type);
    932 
    933 		/*
    934 		 * If the mech oid was allocated for us, free it.
    935 		 */
    936 		if (&amt == actual_mech_type) {
    937 			kgss_free_oid(amt);
    938 		}
    939 	}
    940 	return (err);
    941 }
    942 
    943 static OM_uint32
    944 kgss_accept_sec_context_wrapped(
    945 	OM_uint32 *minor_status,
    946 	gssd_ctx_id_t *context_handle,
    947 	OM_uint32 *gssd_context_verifier,
    948 	const gssd_cred_id_t verifier_cred_handle,
    949 	OM_uint32 gssd_cred_verifier,
    950 	const gss_buffer_t input_token,
    951 	const gss_channel_bindings_t input_chan_bindings,
    952 	gss_buffer_t src_name,
    953 	gss_OID *mech_type,
    954 	gss_buffer_t output_token,
    955 	int *ret_flags,
    956 	OM_uint32 *time_rec,
    957 	gss_cred_id_t *delegated_cred_handle,
    958 	uid_t uid)
    959 {
    960 	CLIENT *clnt;
    961 
    962 	gss_accept_sec_context_arg arg;
    963 	gss_accept_sec_context_res res;
    964 	struct kgss_cred *kcred;
    965 
    966 	/* get the client handle to GSSD */
    967 
    968 	if ((clnt = getgssd_handle()) == NULL) {
    969 		GSSLOG(1,
    970 		"kgss_accept_sec_context: can't connect to server on %s\n",
    971 		server);
    972 		return (GSS_S_FAILURE);
    973 	}
    974 
    975 	/* copy the procedure arguments into the rpc arg parameter */
    976 
    977 	arg.uid = (OM_uint32)uid;
    978 
    979 	arg.context_handle.GSS_CTX_ID_T_len =
    980 		*context_handle == (gssd_ctx_id_t)GSS_C_NO_CONTEXT ?
    981 			0 : (uint_t)sizeof (gssd_ctx_id_t);
    982 	arg.context_handle.GSS_CTX_ID_T_val =  (char *)context_handle;
    983 	arg.gssd_context_verifier = *gssd_context_verifier;
    984 
    985 	arg.verifier_cred_handle.GSS_CRED_ID_T_len =
    986 			verifier_cred_handle ==
    987 			(gssd_cred_id_t)GSS_C_NO_CREDENTIAL ?
    988 			0 : (uint_t)sizeof (gssd_cred_id_t);
    989 	arg.verifier_cred_handle.GSS_CRED_ID_T_val =
    990 						(char *)&verifier_cred_handle;
    991 	arg.gssd_cred_verifier = gssd_cred_verifier;
    992 
    993 	arg.input_token_buffer.GSS_BUFFER_T_len =
    994 			(uint_t)(input_token != GSS_C_NO_BUFFER ?
    995 						input_token->length : 0);
    996 	arg.input_token_buffer.GSS_BUFFER_T_val =
    997 			(char *)(input_token != GSS_C_NO_BUFFER ?
    998 						input_token->value : 0);
    999 
   1000 	if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
   1001 		arg.input_chan_bindings.present = YES;
   1002 		arg.input_chan_bindings.initiator_addrtype =
   1003 			input_chan_bindings->initiator_addrtype;
   1004 		arg.input_chan_bindings.