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