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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * glue routine for gss_acquire_cred 31 */ 32 33 #include <mechglueP.h> 34 #include <stdio.h> 35 #ifdef HAVE_STDLIB_H 36 #include <stdlib.h> 37 #endif 38 #include <string.h> 39 #include <errno.h> 40 #include <time.h> 41 /* local functions */ 42 static gss_OID_set create_actual_mechs(const gss_OID, int); 43 44 static gss_OID_set 45 create_actual_mechs(mechs_array, count) 46 const gss_OID mechs_array; 47 int count; 48 { 49 gss_OID_set actual_mechs; 50 int i; 51 OM_uint32 minor; 52 53 actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc)); 54 if (!actual_mechs) 55 return (NULL); 56 57 actual_mechs->elements = (gss_OID) 58 malloc(sizeof (gss_OID_desc) * count); 59 if (!actual_mechs->elements) { 60 free(actual_mechs); 61 return (NULL); 62 } 63 64 actual_mechs->count = 0; 65 66 for (i = 0; i < count; i++) { 67 actual_mechs->elements[i].elements = (void *) 68 malloc(mechs_array[i].length); 69 if (actual_mechs->elements[i].elements == NULL) { 70 (void) gss_release_oid_set(&minor, &actual_mechs); 71 return (NULL); 72 } 73 g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]); 74 actual_mechs->count++; 75 } 76 77 return (actual_mechs); 78 } 79 80 81 OM_uint32 82 gss_acquire_cred(minor_status, 83 desired_name, 84 time_req, 85 desired_mechs, 86 cred_usage, 87 output_cred_handle, 88 actual_mechs, 89 time_rec) 90 91 OM_uint32 * minor_status; 92 const gss_name_t desired_name; 93 OM_uint32 time_req; 94 const gss_OID_set desired_mechs; 95 int cred_usage; 96 gss_cred_id_t *output_cred_handle; 97 gss_OID_set * actual_mechs; 98 OM_uint32 * time_rec; 99 100 { 101 OM_uint32 major = GSS_S_FAILURE; 102 OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE; 103 gss_OID_set_desc default_OID_set; 104 gss_OID_set mechs; 105 gss_OID_desc default_OID; 106 gss_mechanism mech; 107 int i; 108 gss_union_cred_t creds; 109 110 /* start by checking parameters */ 111 if (!minor_status) 112 return (GSS_S_CALL_INACCESSIBLE_WRITE); 113 *minor_status = 0; 114 115 if (!output_cred_handle) 116 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); 117 118 *output_cred_handle = GSS_C_NO_CREDENTIAL; 119 120 /* Set output parameters to NULL for now */ 121 if (actual_mechs) 122 *actual_mechs = GSS_C_NULL_OID_SET; 123 124 if (time_rec) 125 *time_rec = 0; 126 127 /* 128 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an 129 * appropriate default. We use the first mechanism in the 130 * mechansim list as the default. This set is created with 131 * statics thus needs not be freed 132 */ 133 if (desired_mechs == GSS_C_NULL_OID_SET) { 134 mech = __gss_get_mechanism(NULL); 135 if (mech == NULL) 136 return (GSS_S_BAD_MECH); 137 138 mechs = &default_OID_set; 139 default_OID_set.count = 1; 140 default_OID_set.elements = &default_OID; 141 default_OID.length = mech->mech_type.length; 142 default_OID.elements = mech->mech_type.elements; 143 } else 144 mechs = desired_mechs; 145 146 if (mechs->count == NULL) 147 return (GSS_S_BAD_MECH); 148 149 /* allocate the output credential structure */ 150 creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc)); 151 if (creds == NULL) 152 return (GSS_S_FAILURE); 153 154 /* initialize to 0s */ 155 (void) memset(creds, 0, sizeof (gss_union_cred_desc)); 156 157 /* for each requested mech attempt to obtain a credential */ 158 for (i = 0; i < mechs->count; i++) { 159 major = gss_add_cred(minor_status, (gss_cred_id_t)creds, 160 desired_name, 161 &mechs->elements[i], 162 cred_usage, time_req, time_req, NULL, 163 NULL, &initTimeOut, &acceptTimeOut); 164 if (major == GSS_S_COMPLETE) { 165 /* update the credential's time */ 166 if (cred_usage == GSS_C_ACCEPT) { 167 if (outTime > acceptTimeOut) 168 outTime = acceptTimeOut; 169 } else if (cred_usage == GSS_C_INITIATE) { 170 if (outTime > initTimeOut) 171 outTime = initTimeOut; 172 } else { 173 /* 174 * time_rec is the lesser of the 175 * init/accept times 176 */ 177 if (initTimeOut > acceptTimeOut) 178 outTime = (outTime > acceptTimeOut) ? 179 acceptTimeOut : outTime; 180 else 181 outTime = (outTime > initTimeOut) ? 182 initTimeOut : outTime; 183 } 184 } 185 } /* for */ 186 187 /* ensure that we have at least one credential element */ 188 if (creds->count < 1) { 189 free(creds); 190 return (major); 191 } 192 193 /* 194 * fill in output parameters 195 * setup the actual mechs output parameter 196 */ 197 if (actual_mechs != NULL) { 198 if ((*actual_mechs = create_actual_mechs(creds->mechs_array, 199 creds->count)) == NULL) { 200 (void) gss_release_cred(minor_status, 201 (gss_cred_id_t *)&creds); 202 *minor_status = 0; 203 return (GSS_S_FAILURE); 204 } 205 } 206 207 if (time_rec) 208 *time_rec = outTime; 209 210 211 *output_cred_handle = (gss_cred_id_t)creds; 212 return (GSS_S_COMPLETE); 213 } 214 215 /* V2 INTERFACE */ 216 OM_uint32 217 gss_add_cred(minor_status, input_cred_handle, 218 desired_name, desired_mech, cred_usage, 219 initiator_time_req, acceptor_time_req, 220 output_cred_handle, actual_mechs, 221 initiator_time_rec, acceptor_time_rec) 222 OM_uint32 *minor_status; 223 const gss_cred_id_t input_cred_handle; 224 const gss_name_t desired_name; 225 const gss_OID desired_mech; 226 gss_cred_usage_t cred_usage; 227 OM_uint32 initiator_time_req; 228 OM_uint32 acceptor_time_req; 229 gss_cred_id_t *output_cred_handle; 230 gss_OID_set *actual_mechs; 231 OM_uint32 *initiator_time_rec; 232 OM_uint32 *acceptor_time_rec; 233 { 234 OM_uint32 status, time_req, time_rec, temp_minor_status; 235 gss_mechanism mech; 236 gss_union_name_t union_name = NULL; 237 gss_union_cred_t union_cred, new_union_cred; 238 gss_name_t internal_name = GSS_C_NO_NAME; 239 gss_name_t allocated_name = GSS_C_NO_NAME; 240 gss_cred_id_t cred = NULL; 241 gss_OID new_mechs_array = NULL; 242 gss_cred_id_t *new_cred_array = NULL; 243 244 /* check input parameters */ 245 if (minor_status == NULL) 246 return (GSS_S_CALL_INACCESSIBLE_WRITE); 247 *minor_status = 0; 248 249 if (input_cred_handle == GSS_C_NO_CREDENTIAL && 250 output_cred_handle == NULL) 251 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); 252 253 if (output_cred_handle) 254 *output_cred_handle = GSS_C_NO_CREDENTIAL; 255 256 if (actual_mechs) 257 *actual_mechs = NULL; 258 259 if (acceptor_time_rec) 260 *acceptor_time_rec = 0; 261 262 if (initiator_time_rec) 263 *initiator_time_rec = 0; 264 265 mech = __gss_get_mechanism(desired_mech); 266 if (!mech) 267 return (GSS_S_BAD_MECH); 268 else if (!mech->gss_acquire_cred) 269 return (GSS_S_UNAVAILABLE); 270 271 if (input_cred_handle == GSS_C_NO_CREDENTIAL) { 272 union_cred = malloc(sizeof (gss_union_cred_desc)); 273 if (union_cred == NULL) 274 return (GSS_S_FAILURE); 275 276 (void) memset(union_cred, 0, sizeof (gss_union_cred_desc)); 277 278 /* for default credentials we will use GSS_C_NO_NAME */ 279 internal_name = GSS_C_NO_NAME; 280 } else { 281 union_cred = (gss_union_cred_t)input_cred_handle; 282 if (__gss_get_mechanism_cred(union_cred, desired_mech) != 283 GSS_C_NO_CREDENTIAL) 284 return (GSS_S_DUPLICATE_ELEMENT); 285 286 /* may need to create a mechanism specific name */ 287 if (desired_name) { 288 union_name = (gss_union_name_t)desired_name; 289 if (union_name->mech_type && 290 g_OID_equal(union_name->mech_type, 291 &mech->mech_type)) 292 internal_name = union_name->mech_name; 293 else { 294 if (__gss_import_internal_name(minor_status, 295 &mech->mech_type, union_name, 296 &allocated_name) != GSS_S_COMPLETE) 297 return (GSS_S_BAD_NAME); 298 internal_name = allocated_name; 299 } 300 } 301 } 302 303 304 if (cred_usage == GSS_C_ACCEPT) 305 time_req = acceptor_time_req; 306 else if (cred_usage == GSS_C_INITIATE) 307 time_req = initiator_time_req; 308 else if (cred_usage == GSS_C_BOTH) 309 time_req = (acceptor_time_req > initiator_time_req) ? 310 acceptor_time_req : initiator_time_req; 311 312 status = mech->gss_acquire_cred(mech->context, minor_status, 313 internal_name, time_req, 314 GSS_C_NULL_OID_SET, cred_usage, 315 &cred, NULL, &time_rec); 316 317 if (status != GSS_S_COMPLETE) 318 goto errout; 319 320 /* may need to set credential auxinfo strucutre */ 321 if (union_cred->auxinfo.creation_time == 0) { 322 union_cred->auxinfo.creation_time = time(NULL); 323 union_cred->auxinfo.time_rec = time_rec; 324 union_cred->auxinfo.cred_usage = cred_usage; 325 326 /* 327 * we must set the name; if name is not supplied 328 * we must do inquire cred to get it 329 */ 330 if (internal_name == NULL) { 331 if (mech->gss_inquire_cred == NULL || 332 ((status = mech->gss_inquire_cred( 333 mech->context, 334 &temp_minor_status, cred, 335 &allocated_name, NULL, NULL, 336 NULL)) != GSS_S_COMPLETE)) 337 goto errout; 338 internal_name = allocated_name; 339 } 340 341 if ((status = mech->gss_display_name(mech->context, 342 &temp_minor_status, internal_name, 343 &union_cred->auxinfo.name, 344 &union_cred->auxinfo.name_type)) != 345 GSS_S_COMPLETE) 346 goto errout; 347 } 348 349 /* now add the new credential elements */ 350 new_mechs_array = (gss_OID) 351 malloc(sizeof (gss_OID_desc) * (union_cred->count+1)); 352 353 new_cred_array = (gss_cred_id_t *) 354 malloc(sizeof (gss_cred_id_t) * (union_cred->count+1)); 355 356 if (!new_mechs_array || !new_cred_array) { 357 status = GSS_S_FAILURE; 358 goto errout; 359 } 360 361 if (acceptor_time_rec) 362 if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) 363 *acceptor_time_rec = time_rec; 364 if (initiator_time_rec) 365 if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) 366 *initiator_time_rec = time_rec; 367 368 /* 369 * OK, expand the mechanism array and the credential array 370 */ 371 (void) memcpy(new_mechs_array, union_cred->mechs_array, 372 sizeof (gss_OID_desc) * union_cred->count); 373 (void) memcpy(new_cred_array, union_cred->cred_array, 374 sizeof (gss_cred_id_t) * union_cred->count); 375 376 new_cred_array[union_cred->count] = cred; 377 if ((new_mechs_array[union_cred->count].elements = 378 malloc(mech->mech_type.length)) == NULL) 379 goto errout; 380 381 g_OID_copy(&new_mechs_array[union_cred->count], 382 &mech->mech_type); 383 384 if (actual_mechs) { 385 *actual_mechs = create_actual_mechs(new_mechs_array, 386 union_cred->count + 1); 387 if (*actual_mechs == NULL) { 388 free(new_mechs_array[union_cred->count].elements); 389 goto errout; 390 } 391 } 392 393 if (output_cred_handle == NULL) { 394 free(union_cred->mechs_array); 395 free(union_cred->cred_array); 396 new_union_cred = union_cred; 397 } else { 398 new_union_cred = malloc(sizeof (gss_union_cred_desc)); 399 if (new_union_cred == NULL) { 400 free(new_mechs_array[union_cred->count].elements); 401 goto errout; 402 } 403 *new_union_cred = *union_cred; 404 *output_cred_handle = (gss_cred_id_t)new_union_cred; 405 } 406 407 new_union_cred->mechs_array = new_mechs_array; 408 new_union_cred->cred_array = new_cred_array; 409 new_union_cred->count++; 410 411 /* We're done with the internal name. Free it if we allocated it. */ 412 413 if (allocated_name) 414 (void) __gss_release_internal_name(&temp_minor_status, 415 &mech->mech_type, 416 &allocated_name); 417 418 return (GSS_S_COMPLETE); 419 420 errout: 421 if (new_mechs_array) 422 free(new_mechs_array); 423 if (new_cred_array) 424 free(new_cred_array); 425 426 if (cred != NULL && mech->gss_release_cred) 427 mech->gss_release_cred(mech->context, 428 &temp_minor_status, &cred); 429 430 if (allocated_name) 431 (void) __gss_release_internal_name(&temp_minor_status, 432 &mech->mech_type, 433 &allocated_name); 434 435 if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) { 436 if (union_cred->auxinfo.name.value) 437 free(union_cred->auxinfo.name.value); 438 free(union_cred); 439 } 440 441 return (status); 442 } 443