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