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