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