1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1914 casper * Common Development and Distribution License (the "License"). 6 1914 casper * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 9698 Peter * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel /* 27 0 stevel * This file contains functions to initialize the gssapi library and 28 0 stevel * load mechanism libraries. 29 0 stevel * 30 0 stevel * It also contain functions requiring direct access to the mechanism's 31 0 stevel * list (gss_inidicate_mechs and gss_release_oid) as well as support 32 0 stevel * functions which translate the mechanism strings to oids and vise versa. 33 0 stevel * 34 0 stevel * The mechanism libraries are loaded on demand. This is triggered 35 0 stevel * through the get_mechanism function call. 36 0 stevel * 37 0 stevel * Updates to the mechList are performed with the following restrictions: 38 0 stevel * - once a library is loaded, none of the fields are updated 39 0 stevel * - existing entiries for non-loaded mechs, will have the 40 0 stevel * library and kernel module names updated only 41 0 stevel * (i.e. the mech oid and mech name will not be updated) 42 0 stevel */ 43 0 stevel 44 0 stevel #include <mechglueP.h> 45 0 stevel #include <stdio.h> 46 0 stevel #include <syslog.h> 47 0 stevel #include <stdlib.h> 48 0 stevel #include <string.h> 49 0 stevel #include <sys/stat.h> 50 0 stevel #include <ctype.h> 51 0 stevel #include <errno.h> 52 0 stevel #include <synch.h> 53 0 stevel #include <dlfcn.h> 54 0 stevel #include <libintl.h> 55 0 stevel 56 0 stevel 57 0 stevel #ifndef TEXT_DOMAIN 58 0 stevel #error TEXT_DOMAIN not defined 59 0 stevel #endif 60 0 stevel 61 0 stevel #define MECH_CONF "/etc/gss/mech" 62 0 stevel 63 0 stevel #define MECH_LIB_PREFIX1 "/usr/lib/" 64 0 stevel 65 0 stevel /* 66 0 stevel * This #ifdef mess figures out if we are to be compiled into 67 0 stevel * a sparcv9/lp64 binary for the purposes of figuring the absolute location 68 0 stevel * of gss-api mechanism modules. 69 0 stevel */ 70 0 stevel #ifdef _LP64 71 0 stevel 72 0 stevel #ifdef __sparc 73 0 stevel 74 0 stevel #define MECH_LIB_PREFIX2 "sparcv9/" 75 0 stevel 76 0 stevel #elif defined(__amd64) 77 0 stevel 78 0 stevel #define MECH_LIB_PREFIX2 "amd64/" 79 0 stevel 80 0 stevel #else /* __sparc */ 81 0 stevel 82 0 stevel you need to define where under /usr the LP64 libraries live for this platform 83 0 stevel 84 0 stevel #endif /* __sparc */ 85 0 stevel 86 0 stevel #else /* _LP64 */ 87 0 stevel 88 0 stevel #define MECH_LIB_PREFIX2 "" 89 0 stevel 90 0 stevel #endif /* _LP64 */ 91 0 stevel 92 0 stevel #define MECH_LIB_DIR "gss/" 93 0 stevel 94 0 stevel #define MECH_LIB_PREFIX MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 MECH_LIB_DIR 95 0 stevel 96 0 stevel 97 0 stevel #ifndef MECH_SYM 98 0 stevel #define MECH_SYM "gss_mech_initialize" 99 0 stevel #endif 100 0 stevel 101 0 stevel #define M_DEFAULT "default" 102 0 stevel 103 0 stevel /* Local functions */ 104 0 stevel static gss_mech_info searchMechList(const gss_OID); 105 0 stevel static void loadConfigFile(const char *); 106 0 stevel static void updateMechList(void); 107 0 stevel 108 0 stevel 109 0 stevel /* 110 0 stevel * list of mechanism libraries and their entry points. 111 0 stevel * the list also maintains state of the mech libraries (loaded or not). 112 0 stevel */ 113 0 stevel static gss_mech_info g_mechList = NULL; 114 0 stevel static gss_mech_info g_mechListTail = NULL; 115 0 stevel static mutex_t g_mechListLock; 116 0 stevel static time_t g_confFileModTime = (time_t)0; 117 0 stevel 118 0 stevel /* 119 0 stevel * function used to reclaim the memory used by a gss_OID structure. 120 0 stevel * This routine requires direct access to the mechList. 121 0 stevel */ 122 0 stevel OM_uint32 123 0 stevel gss_release_oid(minor_status, oid) 124 0 stevel OM_uint32 *minor_status; 125 0 stevel gss_OID *oid; 126 0 stevel { 127 0 stevel OM_uint32 major; 128 0 stevel gss_mech_info aMech = g_mechList; 129 0 stevel 130 0 stevel if (minor_status == NULL) 131 0 stevel return (GSS_S_CALL_INACCESSIBLE_WRITE); 132 0 stevel 133 0 stevel *minor_status = 0; 134 0 stevel 135 0 stevel while (aMech != NULL) { 136 0 stevel 137 0 stevel /* 138 0 stevel * look through the loaded mechanism libraries for 139 0 stevel * gss_internal_release_oid until one returns success. 140 0 stevel * gss_internal_release_oid will only return success when 141 0 stevel * the OID was recognized as an internal mechanism OID. if no 142 0 stevel * mechanisms recognize the OID, then call the generic version. 143 0 stevel */ 144 0 stevel 145 0 stevel /* 146 0 stevel * we can walk the mechanism list without a mutex, because we 147 0 stevel * are only looking at fields which once read will never change. 148 0 stevel * Mechanism entries are always added to the end, and as 149 0 stevel * complete entries. 150 0 stevel */ 151 0 stevel if (aMech->mech && aMech->mech->gss_internal_release_oid) { 152 0 stevel major = aMech->mech->gss_internal_release_oid( 153 0 stevel aMech->mech->context, 154 0 stevel minor_status, oid); 155 0 stevel if (major == GSS_S_COMPLETE) 156 0 stevel return (GSS_S_COMPLETE); 157 0 stevel } 158 0 stevel aMech = aMech->next; 159 0 stevel } /* while */ 160 0 stevel 161 0 stevel return (generic_gss_release_oid(minor_status, oid)); 162 0 stevel } /* gss_release_oid */ 163 0 stevel 164 0 stevel 165 0 stevel /* 166 0 stevel * this function will return an oid set indicating available mechanisms. 167 0 stevel * The set returned is based on configuration file entries and 168 0 stevel * NOT on the loaded mechanisms. This function does not check if any 169 0 stevel * of these can actually be loaded. 170 0 stevel * This routine needs direct access to the mechanism list. 171 0 stevel * To avoid reading the configuration file each call, we will save a 172 0 stevel * a mech oid set, and only update it once the file has changed. 173 0 stevel */ 174 0 stevel static time_t g_mechSetTime = (time_t)0; 175 0 stevel static gss_OID_set_desc g_mechSet = { 0, NULL }; 176 0 stevel static mutex_t g_mechSetLock; 177 0 stevel 178 0 stevel 179 0 stevel OM_uint32 180 0 stevel gss_indicate_mechs(minorStatus, mechSet) 181 0 stevel OM_uint32 *minorStatus; 182 0 stevel gss_OID_set *mechSet; 183 0 stevel { 184 0 stevel gss_mech_info mList; 185 0 stevel char *fileName; 186 0 stevel struct stat fileInfo; 187 0 stevel int count, i, j; 188 0 stevel gss_OID curItem; 189 0 stevel 190 9698 Peter /* Initialize outputs. */ 191 0 stevel 192 9698 Peter if (minorStatus != NULL) 193 9698 Peter *minorStatus = 0; 194 0 stevel 195 9698 Peter if (mechSet != NULL) 196 9698 Peter *mechSet = GSS_C_NO_OID_SET; 197 0 stevel 198 9698 Peter /* Validate arguments. */ 199 9698 Peter if (minorStatus == NULL || mechSet == NULL) 200 0 stevel return (GSS_S_CALL_INACCESSIBLE_WRITE); 201 0 stevel 202 0 stevel fileName = MECH_CONF; 203 0 stevel 204 0 stevel /* 205 0 stevel * If we have already computed the mechanisms supported and if it 206 0 stevel * is still valid; make a copy and return to caller, 207 0 stevel * otherwise build it first. 208 0 stevel */ 209 0 stevel if ((stat(fileName, &fileInfo) == 0 && 210 0 stevel fileInfo.st_mtime > g_mechSetTime)) { 211 0 stevel /* 212 0 stevel * lock the mutex since we will be updating 213 0 stevel * the mechList structure 214 0 stevel * we need to keep the lock while we build the mechanism list 215 0 stevel * since we are accessing parts of the mechList which could be 216 0 stevel * modified. 217 0 stevel */ 218 0 stevel (void) mutex_lock(&g_mechListLock); 219 0 stevel 220 0 stevel /* 221 0 stevel * this checks for the case when we need to re-construct the 222 0 stevel * g_mechSet structure, but the mechanism list is upto date 223 0 stevel * (because it has been read by someone calling 224 0 stevel * __gss_get_mechanism) 225 0 stevel */ 226 0 stevel if (fileInfo.st_mtime > g_confFileModTime) 227 0 stevel { 228 0 stevel g_confFileModTime = fileInfo.st_mtime; 229 0 stevel loadConfigFile(fileName); 230 0 stevel } 231 0 stevel 232 0 stevel /* 233 0 stevel * we need to lock the mech set so that no one else will 234 0 stevel * try to read it as we are re-creating it 235 0 stevel */ 236 0 stevel (void) mutex_lock(&g_mechSetLock); 237 0 stevel 238 0 stevel /* if the oid list already exists we must free it first */ 239 0 stevel if (g_mechSet.count != 0) { 240 0 stevel for (i = 0; i < g_mechSet.count; i++) 241 0 stevel free(g_mechSet.elements[i].elements); 242 0 stevel free(g_mechSet.elements); 243 0 stevel g_mechSet.elements = NULL; 244 0 stevel g_mechSet.count = 0; 245 0 stevel } 246 0 stevel 247 0 stevel /* determine how many elements to have in the list */ 248 0 stevel mList = g_mechList; 249 0 stevel count = 0; 250 0 stevel while (mList != NULL) { 251 0 stevel count++; 252 0 stevel mList = mList->next; 253 0 stevel } 254 0 stevel 255 0 stevel /* this should always be true, but.... */ 256 0 stevel if (count > 0) { 257 0 stevel g_mechSet.elements = 258 0 stevel (gss_OID) calloc(count, sizeof (gss_OID_desc)); 259 0 stevel if (g_mechSet.elements == NULL) { 260 0 stevel (void) mutex_unlock(&g_mechSetLock); 261 0 stevel (void) mutex_unlock(&g_mechListLock); 262 0 stevel return (GSS_S_FAILURE); 263 0 stevel } 264 0 stevel 265 0 stevel (void) memset(g_mechSet.elements, 0, 266 0 stevel count * sizeof (gss_OID_desc)); 267 0 stevel 268 0 stevel /* now copy each oid element */ 269 0 stevel g_mechSet.count = count; 270 0 stevel count = 0; 271 0 stevel mList = g_mechList; 272 0 stevel while (mList != NULL) { 273 0 stevel curItem = &(g_mechSet.elements[count]); 274 0 stevel curItem->elements = (void*) 275 0 stevel malloc(mList->mech_type->length); 276 0 stevel if (curItem->elements == NULL) { 277 0 stevel /* 278 0 stevel * this is nasty - we must delete the 279 0 stevel * part of the array already copied 280 0 stevel */ 281 0 stevel for (i = 0; i < count; i++) { 282 0 stevel free(g_mechSet.elements[i]. 283 0 stevel elements); 284 0 stevel } 285 0 stevel free(g_mechSet.elements); 286 0 stevel g_mechSet.count = 0; 287 0 stevel g_mechSet.elements = NULL; 288 0 stevel (void) mutex_unlock(&g_mechSetLock); 289 0 stevel (void) mutex_unlock(&g_mechListLock); 290 0 stevel return (GSS_S_FAILURE); 291 0 stevel } 292 0 stevel g_OID_copy(curItem, mList->mech_type); 293 0 stevel count++; 294 0 stevel mList = mList->next; 295 0 stevel } 296 0 stevel } 297 0 stevel 298 0 stevel g_mechSetTime = fileInfo.st_mtime; 299 0 stevel (void) mutex_unlock(&g_mechSetLock); 300 0 stevel (void) mutex_unlock(&g_mechListLock); 301 0 stevel } /* if g_mechSet is out of date or not initialized */ 302 0 stevel 303 0 stevel /* 304 0 stevel * the mech set is created and it is up to date 305 0 stevel * so just copy it to caller 306 0 stevel */ 307 0 stevel if ((*mechSet = 308 0 stevel (gss_OID_set) malloc(sizeof (gss_OID_set_desc))) == NULL) 309 0 stevel { 310 0 stevel return (GSS_S_FAILURE); 311 0 stevel } 312 0 stevel 313 0 stevel /* 314 0 stevel * need to lock the g_mechSet in case someone tries to update it while 315 0 stevel * I'm copying it. 316 0 stevel */ 317 0 stevel (void) mutex_lock(&g_mechSetLock); 318 0 stevel 319 0 stevel /* allocate space for the oid structures */ 320 0 stevel if (((*mechSet)->elements = 321 0 stevel (void*) calloc(g_mechSet.count, sizeof (gss_OID_desc))) 322 0 stevel == NULL) 323 0 stevel { 324 0 stevel (void) mutex_unlock(&g_mechSetLock); 325 0 stevel free(*mechSet); 326 0 stevel *mechSet = NULL; 327 0 stevel return (GSS_S_FAILURE); 328 0 stevel } 329 0 stevel 330 0 stevel /* now copy the oid structures */ 331 0 stevel (void) memcpy((*mechSet)->elements, g_mechSet.elements, 332 0 stevel g_mechSet.count * sizeof (gss_OID_desc)); 333 0 stevel 334 0 stevel (*mechSet)->count = g_mechSet.count; 335 0 stevel 336 0 stevel /* still need to copy each of the oid elements arrays */ 337 0 stevel for (i = 0; i < (*mechSet)->count; i++) { 338 0 stevel curItem = &((*mechSet)->elements[i]); 339 0 stevel curItem->elements = 340 0 stevel (void *) malloc(g_mechSet.elements[i].length); 341 0 stevel if (curItem->elements == NULL) { 342 0 stevel (void) mutex_unlock(&g_mechSetLock); 343 0 stevel /* 344 0 stevel * must still free the allocated elements for 345 0 stevel * each allocated gss_OID_desc 346 0 stevel */ 347 0 stevel for (j = 0; j < i; j++) { 348 0 stevel free((*mechSet)->elements[j].elements); 349 0 stevel } 350 0 stevel free((*mechSet)->elements); 351 0 stevel free(mechSet); 352 0 stevel *mechSet = NULL; 353 0 stevel return (GSS_S_FAILURE); 354 0 stevel } 355 0 stevel g_OID_copy(curItem, &g_mechSet.elements[i]); 356 0 stevel } 357 0 stevel (void) mutex_unlock(&g_mechSetLock); 358 0 stevel return (GSS_S_COMPLETE); 359 0 stevel } /* gss_indicate_mechs */ 360 0 stevel 361 0 stevel /* 362 0 stevel * this function has been added for use by modules that need to 363 0 stevel * know what (if any) optional parameters are supplied in the 364 0 stevel * config file (MECH_CONF). 365 0 stevel * It will return the option string for a specified mechanism. 366 0 stevel * caller is responsible for freeing the memory 367 0 stevel */ 368 0 stevel char * 369 0 stevel __gss_get_modOptions(oid) 370 0 stevel const gss_OID oid; 371 0 stevel { 372 0 stevel gss_mech_info aMech; 373 0 stevel char *modOptions = NULL; 374 0 stevel 375 0 stevel /* make sure we have fresh data */ 376 0 stevel (void) mutex_lock(&g_mechListLock); 377 0 stevel updateMechList(); 378 0 stevel (void) mutex_unlock(&g_mechListLock); 379 0 stevel 380 0 stevel /* searching the list does not require a lock */ 381 0 stevel if ((aMech = searchMechList(oid)) == NULL || 382 0 stevel aMech->optionStr == NULL) { 383 0 stevel return (NULL); 384 0 stevel } 385 0 stevel 386 0 stevel /* 387 0 stevel * need to obtain a lock on this structure in case someone else 388 0 stevel * will try to update it during the copy 389 0 stevel */ 390 0 stevel (void) mutex_lock(&g_mechListLock); 391 0 stevel if (aMech->optionStr) 392 0 stevel modOptions = strdup(aMech->optionStr); 393 0 stevel (void) mutex_unlock(&g_mechListLock); 394 0 stevel 395 0 stevel return (modOptions); 396 0 stevel } /* __gss_get_modOptions */ 397 0 stevel 398 0 stevel /* 399 0 stevel * this function has been added for use by gssd. 400 0 stevel * It will return the kernel module name for a specified mechanism. 401 0 stevel * caller is responsible for freeing the memory 402 0 stevel */ 403 0 stevel char * 404 0 stevel __gss_get_kmodName(oid) 405 0 stevel const gss_OID oid; 406 0 stevel { 407 0 stevel gss_mech_info aMech; 408 0 stevel char *kmodName = NULL; 409 0 stevel 410 0 stevel /* make sure we have fresh data */ 411 0 stevel (void) mutex_lock(&g_mechListLock); 412 0 stevel updateMechList(); 413 0 stevel (void) mutex_unlock(&g_mechListLock); 414 0 stevel 415 0 stevel /* searching the list does not require a lock */ 416 0 stevel if ((aMech = searchMechList(oid)) == NULL || aMech->kmodName == NULL) { 417 0 stevel return (NULL); 418 0 stevel } 419 0 stevel 420 0 stevel /* 421 0 stevel * need to obtain a lock on this structure in case someone else 422 0 stevel * will try to update it during the copy 423 0 stevel */ 424 0 stevel (void) mutex_lock(&g_mechListLock); 425 0 stevel if (aMech->kmodName) 426 0 stevel kmodName = strdup(aMech->kmodName); 427 0 stevel (void) mutex_unlock(&g_mechListLock); 428 0 stevel 429 0 stevel return (kmodName); 430 0 stevel } /* __gss_get_kmodName */ 431 0 stevel 432 0 stevel 433 0 stevel /* 434 0 stevel * given a mechanism string return the mechanism oid 435 0 stevel */ 436 0 stevel OM_uint32 437 0 stevel __gss_mech_to_oid(const char *mechStr, gss_OID* oid) 438 0 stevel { 439 0 stevel gss_mech_info aMech; 440 0 stevel 441 0 stevel if (oid == NULL) 442 0 stevel return (GSS_S_CALL_INACCESSIBLE_WRITE); 443 0 stevel 444 0 stevel *oid = GSS_C_NULL_OID; 445 0 stevel 446 0 stevel if ((mechStr == NULL) || (strlen(mechStr) == 0) || 447 0 stevel (strcasecmp(mechStr, M_DEFAULT) == 0)) 448 0 stevel return (GSS_S_COMPLETE); 449 0 stevel 450 0 stevel /* ensure we have fresh data */ 451 0 stevel (void) mutex_lock(&g_mechListLock); 452 0 stevel updateMechList(); 453 0 stevel (void) mutex_unlock(&g_mechListLock); 454 0 stevel 455 0 stevel aMech = g_mechList; 456 0 stevel 457 0 stevel /* no lock required - only looking at fields that are not updated */ 458 0 stevel while (aMech != NULL) { 459 0 stevel if ((aMech->mechNameStr) && 460 0 stevel strcmp(aMech->mechNameStr, mechStr) == 0) { 461 0 stevel *oid = aMech->mech_type; 462 0 stevel return (GSS_S_COMPLETE); 463 0 stevel } 464 0 stevel aMech = aMech->next; 465 0 stevel } 466 0 stevel return (GSS_S_FAILURE); 467 0 stevel } /* __gss_mech_to_oid */ 468 0 stevel 469 0 stevel 470 0 stevel /* 471 0 stevel * Given the mechanism oid, return the readable mechanism name 472 0 stevel * associated with that oid from the mech config file 473 0 stevel * (/etc/gss/mech). 474 0 stevel */ 475 0 stevel const char * 476 0 stevel __gss_oid_to_mech(const gss_OID oid) 477 0 stevel { 478 0 stevel gss_mech_info aMech; 479 0 stevel 480 0 stevel if (oid == GSS_C_NULL_OID) 481 0 stevel return (M_DEFAULT); 482 0 stevel 483 0 stevel /* ensure we have fresh data */ 484 0 stevel (void) mutex_lock(&g_mechListLock); 485 0 stevel updateMechList(); 486 0 stevel (void) mutex_unlock(&g_mechListLock); 487 0 stevel 488 0 stevel if ((aMech = searchMechList(oid)) == NULL) 489 0 stevel return (NULL); 490 0 stevel 491 0 stevel return (aMech->mechNameStr); 492 0 stevel } /* __gss_oid_to_mech */ 493 0 stevel 494 0 stevel 495 0 stevel /* 496 0 stevel * return a list of mechanism strings supported 497 0 stevel * upon return the array is terminated with a NULL entry 498 0 stevel */ 499 0 stevel OM_uint32 500 0 stevel __gss_get_mechanisms(char *mechArray[], int arrayLen) 501 0 stevel { 502 0 stevel gss_mech_info aMech; 503 0 stevel int i; 504 0 stevel 505 0 stevel if (mechArray == NULL || arrayLen < 1) 506 0 stevel return (GSS_S_CALL_INACCESSIBLE_WRITE); 507 0 stevel 508 0 stevel /* ensure we have fresh data */ 509 0 stevel (void) mutex_lock(&g_mechListLock); 510 0 stevel updateMechList(); 511 0 stevel (void) mutex_unlock(&g_mechListLock); 512 0 stevel 513 0 stevel aMech = g_mechList; 514 0 stevel 515 0 stevel /* no lock required - only looking at fields that are not updated */ 516 0 stevel for (i = 1; i < arrayLen; i++) { 517 0 stevel if (aMech != NULL) { 518 0 stevel *mechArray = aMech->mechNameStr; 519 0 stevel mechArray++; 520 0 stevel aMech = aMech->next; 521 0 stevel } else 522 0 stevel break; 523 0 stevel } 524 0 stevel *mechArray = NULL; 525 0 stevel return (GSS_S_COMPLETE); 526 0 stevel } /* gss_get_mechanisms */ 527 0 stevel 528 0 stevel 529 0 stevel /* 530 0 stevel * determines if the mechList needs to be updated from file 531 0 stevel * and performs the update. 532 0 stevel * this functions must be called with a lock of g_mechListLock 533 0 stevel */ 534 0 stevel static void 535 0 stevel updateMechList(void) 536 0 stevel { 537 0 stevel char *fileName; 538 0 stevel struct stat fileInfo; 539 0 stevel 540 0 stevel fileName = MECH_CONF; 541 0 stevel 542 0 stevel /* check if mechList needs updating */ 543 0 stevel if (stat(fileName, &fileInfo) == 0 && 544 0 stevel (fileInfo.st_mtime > g_confFileModTime)) { 545 0 stevel loadConfigFile(fileName); 546 0 stevel g_confFileModTime = fileInfo.st_mtime; 547 0 stevel } 548 0 stevel } /* updateMechList */ 549 0 stevel 550 0 stevel 551 0 stevel /* 552 0 stevel * given the mechanism type, return the mechanism structure 553 0 stevel * containing the mechanism library entry points. 554 0 stevel * will return NULL if mech type is not found 555 0 stevel * This function will also trigger the loading of the mechanism 556 0 stevel * module if it has not been already loaded. 557 0 stevel */ 558 0 stevel gss_mechanism 559 0 stevel __gss_get_mechanism(oid) 560 0 stevel const gss_OID oid; 561 0 stevel { 562 0 stevel gss_mech_info aMech; 563 0 stevel gss_mechanism (*sym)(const gss_OID); 564 0 stevel void *dl; 565 0 stevel 566 0 stevel /* check if the mechanism is already loaded */ 567 0 stevel if ((aMech = searchMechList(oid)) != NULL && aMech->mech) { 568 0 stevel return (aMech->mech); 569 0 stevel } 570 0 stevel 571 0 stevel /* 572 0 stevel * might need to re-read the configuration file before loading 573 0 stevel * the mechanism to ensure we have the latest info. 574 0 stevel */ 575 0 stevel (void) mutex_lock(&g_mechListLock); 576 0 stevel updateMechList(); 577 0 stevel 578 0 stevel aMech = searchMechList(oid); 579 0 stevel 580 0 stevel /* is the mechanism present in the list ? */ 581 0 stevel if (aMech == NULL) { 582 0 stevel (void) mutex_unlock(&g_mechListLock); 583 0 stevel return ((gss_mechanism)NULL); 584 0 stevel } 585 0 stevel 586 0 stevel /* has another thread loaded the mech */ 587 0 stevel if (aMech->mech) { 588 0 stevel (void) mutex_unlock(&g_mechListLock); 589 0 stevel return (aMech->mech); 590 0 stevel } 591 0 stevel 592 0 stevel /* we found the mechanism, but it is not loaded */ 593 0 stevel if ((dl = dlopen(aMech->uLibName, RTLD_NOW)) == NULL) { 594 0 stevel (void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n", 595 0 stevel aMech->uLibName, dlerror()); 596 0 stevel (void) mutex_unlock(&g_mechListLock); 597 0 stevel return ((gss_mechanism)NULL); 598 0 stevel } 599 0 stevel 600 0 stevel if ((sym = (gss_mechanism (*)(const gss_OID))dlsym(dl, MECH_SYM)) 601 0 stevel == NULL) { 602 0 stevel (void) dlclose(dl); 603 0 stevel (void) syslog(LOG_INFO, "unable to initialize mechanism" 604 0 stevel " library [%s]\n", aMech->uLibName); 605 0 stevel (void) mutex_unlock(&g_mechListLock); 606 0 stevel return ((gss_mechanism)NULL); 607 0 stevel } 608 0 stevel 609 0 stevel /* Call the symbol to get the mechanism table */ 610 0 stevel aMech->mech = (*sym)(aMech->mech_type); 611 0 stevel 612 0 stevel if (aMech->mech == NULL) { 613 0 stevel (void) dlclose(dl); 614 0 stevel (void) syslog(LOG_INFO, "unable to initialize mechanism" 615 0 stevel " library [%s]\n", aMech->uLibName); 616 0 stevel (void) mutex_unlock(&g_mechListLock); 617 0 stevel return ((gss_mechanism)NULL); 618 0 stevel } 619 0 stevel 620 0 stevel aMech->dl_handle = dl; 621 0 stevel 622 0 stevel (void) mutex_unlock(&g_mechListLock); 623 0 stevel return (aMech->mech); 624 0 stevel } /* __gss_get_mechanism */ 625 0 stevel 626 0 stevel gss_mechanism_ext 627 0 stevel __gss_get_mechanism_ext(oid) 628 0 stevel const gss_OID oid; 629 0 stevel { 630 0 stevel gss_mech_info aMech; 631 0 stevel gss_mechanism_ext mech_ext; 632 0 stevel 633 0 stevel /* check if the mechanism is already loaded */ 634 0 stevel if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext != NULL) 635 0 stevel return (aMech->mech_ext); 636 0 stevel 637 0 stevel if (__gss_get_mechanism(oid) == NULL) 638 0 stevel return (NULL); 639 0 stevel 640 0 stevel if (aMech->dl_handle == NULL) 641 0 stevel return (NULL); 642 0 stevel 643 0 stevel /* Load the gss_config_ext struct for this mech */ 644 0 stevel 645 0 stevel mech_ext = (gss_mechanism_ext)malloc(sizeof (struct gss_config_ext)); 646 0 stevel 647 0 stevel if (mech_ext == NULL) 648 0 stevel return (NULL); 649 0 stevel 650 0 stevel /* 651 0 stevel * dlsym() the mech's 'method' functions for the extended APIs 652 0 stevel * 653 0 stevel * NOTE: Until the void *context argument is removed from the 654 0 stevel * SPI method functions' signatures it will be necessary to have 655 0 stevel * different function pointer typedefs and function names for 656 0 stevel * the SPI methods than for the API. When this argument is 657 0 stevel * removed it will be possible to rename gss_*_sfct to gss_*_fct 658 0 stevel * and and gssspi_* to gss_*. 659 0 stevel */ 660 0 stevel mech_ext->gss_acquire_cred_with_password = 661 0 stevel (gss_acquire_cred_with_password_sfct)dlsym(aMech->dl_handle, 662 0 stevel "gssspi_acquire_cred_with_password"); 663 0 stevel 664 0 stevel /* Set aMech->mech_ext */ 665 0 stevel (void) mutex_lock(&g_mechListLock); 666 0 stevel 667 0 stevel if (aMech->mech_ext == NULL) 668 0 stevel aMech->mech_ext = mech_ext; 669 0 stevel else 670 0 stevel free(mech_ext); /* we raced and lost; don't leak */ 671 0 stevel 672 0 stevel (void) mutex_unlock(&g_mechListLock); 673 0 stevel 674 0 stevel return (aMech->mech_ext); 675 0 stevel 676 0 stevel } /* __gss_get_mechanism_ext */ 677 0 stevel 678 0 stevel 679 0 stevel /* 680 0 stevel * this routine is used for searching the list of mechanism data. 681 0 stevel * it needs not be mutex protected because we only add new structures 682 0 stevel * from the end and they are fully initialized before being added. 683 0 stevel */ 684 0 stevel static gss_mech_info searchMechList(oid) 685 0 stevel const gss_OID oid; 686 0 stevel { 687 0 stevel gss_mech_info aMech = g_mechList; 688 0 stevel 689 0 stevel /* if oid is null -> then get default which is the first in the list */ 690 0 stevel if (oid == GSS_C_NULL_OID) 691 0 stevel return (aMech); 692 0 stevel 693 0 stevel while (aMech != NULL) { 694 0 stevel if (g_OID_equal(aMech->mech_type, oid)) 695 0 stevel return (aMech); 696 0 stevel aMech = aMech->next; 697 0 stevel } 698 0 stevel 699 0 stevel /* none found */ 700 0 stevel return ((gss_mech_info) NULL); 701 0 stevel } /* searchMechList */ 702 0 stevel 703 0 stevel 704 0 stevel /* 705 0 stevel * loads the configuration file 706 0 stevel * this is called while having a mutex lock on the mechanism list 707 0 stevel * entries for libraries that have been loaded can't be modified 708 0 stevel * mechNameStr and mech_type fields are not updated during updates 709 0 stevel */ 710 0 stevel static void loadConfigFile(fileName) 711 0 stevel const char *fileName; 712 0 stevel { 713 0 stevel char buffer[BUFSIZ], *oidStr, *oid, *sharedLib, *kernMod, *endp; 714 0 stevel char *modOptions; 715 0 stevel char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ]; 716 0 stevel char *tmpStr; 717 0 stevel FILE *confFile; 718 0 stevel gss_OID mechOid; 719 0 stevel gss_mech_info aMech, tmp; 720 0 stevel OM_uint32 minor; 721 0 stevel gss_buffer_desc oidBuf; 722 0 stevel 723 1914 casper if ((confFile = fopen(fileName, "rF")) == NULL) { 724 0 stevel return; 725 0 stevel } 726 0 stevel 727 0 stevel (void) memset(buffer, 0, sizeof (buffer)); 728 0 stevel while (fgets(buffer, BUFSIZ, confFile) != NULL) { 729 0 stevel 730 0 stevel /* ignore lines beginning with # */ 731 0 stevel if (*buffer == '#') 732 0 stevel continue; 733 0 stevel 734 0 stevel /* 735 0 stevel * find the first white-space character after 736 0 stevel * the mechanism name 737 0 stevel */ 738 0 stevel oidStr = buffer; 739 0 stevel for (oid = buffer; *oid && !isspace(*oid); oid++); 740 0 stevel 741 0 stevel /* Now find the first non-white-space character */ 742 0 stevel if (*oid) { 743 0 stevel *oid = '\0'; 744 0 stevel oid++; 745 0 stevel while (*oid && isspace(*oid)) 746 0 stevel oid++; 747 0 stevel } 748 0 stevel 749 0 stevel /* 750 0 stevel * If that's all, then this is a corrupt entry. Skip it. 751 0 stevel */ 752 0 stevel if (! *oid) 753 0 stevel continue; 754 0 stevel 755 0 stevel /* Find the end of the oid and make sure it is NULL-ended */ 756 0 stevel for (endp = oid; *endp && !isspace(*endp); endp++) 757 0 stevel ; 758 0 stevel 759 0 stevel if (*endp) { 760 0 stevel *endp = '\0'; 761 0 stevel } 762 0 stevel 763 0 stevel /* 764 0 stevel * check if an entry for this oid already exists 765 0 stevel * if it does, and the library is already loaded then 766 0 stevel * we can't modify it, so skip it 767 0 stevel */ 768 0 stevel oidBuf.value = (void *)oid; 769 0 stevel oidBuf.length = strlen(oid); 770 0 stevel if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid) 771 0 stevel != GSS_S_COMPLETE) { 772 0 stevel (void) syslog(LOG_INFO, "invalid mechanism oid" 773 0 stevel " [%s] in configuration file", oid); 774 0 stevel continue; 775 0 stevel } 776 0 stevel 777 0 stevel aMech = searchMechList(mechOid); 778 0 stevel if (aMech && aMech->mech) { 779 0 stevel free(mechOid->elements); 780 0 stevel free(mechOid); 781 0 stevel continue; 782 0 stevel } 783 0 stevel 784 0 stevel /* Find the start of the shared lib name */ 785 0 stevel for (sharedLib = endp+1; *sharedLib && isspace(*sharedLib); 786 0 stevel sharedLib++) 787 0 stevel ; 788 0 stevel 789 0 stevel /* 790 0 stevel * If that's all, then this is a corrupt entry. Skip it. 791 0 stevel */ 792 0 stevel if (! *sharedLib) { 793 0 stevel free(mechOid->elements); 794 0 stevel free(mechOid); 795 0 stevel continue; 796 0 stevel } 797 0 stevel 798 0 stevel /* 799 0 stevel * Find the end of the shared lib name and make sure it is 800 0 stevel * NULL-terminated. 801 0 stevel */ 802 0 stevel for (endp = sharedLib; *endp && !isspace(*endp); endp++) 803 0 stevel ; 804 0 stevel 805 0 stevel if (*endp) { 806 0 stevel *endp = '\0'; 807 0 stevel } 808 0 stevel 809 0 stevel /* Find the start of the optional kernel module lib name */ 810 0 stevel for (kernMod = endp+1; *kernMod && isspace(*kernMod); 811 0 stevel kernMod++) 812 0 stevel ; 813 0 stevel 814 0 stevel /* 815 0 stevel * If this item starts with a bracket "[", then 816 0 stevel * it is not a kernel module, but is a list of 817 0 stevel * options for the user module to parse later. 818 0 stevel */ 819 0 stevel if (*kernMod && *kernMod != '[') { 820 0 stevel /* 821 0 stevel * Find the end of the shared lib name and make sure 822 0 stevel * it is NULL-terminated. 823 0 stevel */ 824 0 stevel for (endp = kernMod; *endp && !isspace(*endp); endp++) 825 0 stevel ; 826 0 stevel 827 0 stevel if (*endp) { 828 0 stevel *endp = '\0'; 829 0 stevel } 830 0 stevel } else 831 0 stevel kernMod = NULL; 832 0 stevel 833 0 stevel /* Find the start of the optional module options list */ 834 0 stevel for (modOptions = endp+1; *modOptions && isspace(*modOptions); 835 0 stevel modOptions++); 836 0 stevel 837 0 stevel if (*modOptions == '[') { 838 0 stevel /* move past the opening bracket */ 839 0 stevel for (modOptions = modOptions+1; 840 0 stevel *modOptions && isspace(*modOptions); 841 0 stevel modOptions++); 842 0 stevel 843 0 stevel /* Find the closing bracket */ 844 0 stevel for (endp = modOptions; 845 0 stevel *endp && *endp != ']'; endp++); 846 0 stevel 847 0 stevel if (endp) 848 0 stevel *endp = '\0'; 849 0 stevel 850 0 stevel } else { 851 0 stevel modOptions = NULL; 852 0 stevel } 853 0 stevel 854 0 stevel (void) strcpy(sharedPath, MECH_LIB_PREFIX); 855 0 stevel (void) strcat(sharedPath, sharedLib); 856 0 stevel 857 0 stevel /* 858 0 stevel * are we creating a new mechanism entry or 859 0 stevel * just modifying existing (non loaded) mechanism entry 860 0 stevel */ 861 0 stevel if (aMech) { 862 0 stevel /* 863 0 stevel * delete any old values and set new 864 0 stevel * mechNameStr and mech_type are not modified 865 0 stevel */ 866 0 stevel if (aMech->kmodName) { 867 0 stevel free(aMech->kmodName); 868 0 stevel aMech->kmodName = NULL; 869 0 stevel } 870 0 stevel 871 0 stevel if (aMech->optionStr) { 872 0 stevel free(aMech->optionStr); 873 0 stevel aMech->optionStr = NULL; 874 0 stevel } 875 0 stevel 876 0 stevel if ((tmpStr = strdup(sharedPath)) != NULL) { 877 0 stevel if (aMech->uLibName) 878 0 stevel free(aMech->uLibName); 879 0 stevel aMech->uLibName = tmpStr; 880 0 stevel } 881 0 stevel 882 0 stevel if (kernMod) /* this is an optional parameter */ 883 0 stevel aMech->kmodName = strdup(kernMod); 884 0 stevel 885 0 stevel if (modOptions) /* optional module options */ 886 0 stevel aMech->optionStr = strdup(modOptions); 887 0 stevel 888 0 stevel /* the oid is already set */ 889 0 stevel free(mechOid->elements); 890 0 stevel free(mechOid); 891 0 stevel continue; 892 0 stevel } 893 0 stevel 894 0 stevel /* adding a new entry */ 895 0 stevel aMech = malloc(sizeof (struct gss_mech_config)); 896 0 stevel if (aMech == NULL) { 897 0 stevel free(mechOid->elements); 898 0 stevel free(mechOid); 899 0 stevel continue; 900 0 stevel } 901 0 stevel (void) memset(aMech, 0, sizeof (struct gss_mech_config)); 902 0 stevel aMech->mech_type = mechOid; 903 0 stevel aMech->uLibName = strdup(sharedPath); 904 0 stevel aMech->mechNameStr = strdup(oidStr); 905 0 stevel 906 0 stevel /* check if any memory allocations failed - bad news */ 907 0 stevel if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) { 908 0 stevel if (aMech->uLibName) 909 0 stevel free(aMech->uLibName); 910 0 stevel if (aMech->mechNameStr) 911 0 stevel free(aMech->mechNameStr); 912 0 stevel free(mechOid->elements); 913 0 stevel free(mechOid); 914 0 stevel free(aMech); 915 0 stevel continue; 916 0 stevel } 917 0 stevel if (kernMod) /* this is an optional parameter */ 918 0 stevel aMech->kmodName = strdup(kernMod); 919 0 stevel 920 0 stevel if (modOptions) 921 0 stevel aMech->optionStr = strdup(modOptions); 922 0 stevel /* 923 0 stevel * add the new entry to the end of the list - make sure 924 0 stevel * that only complete entries are added because other 925 0 stevel * threads might currently be searching the list. 926 0 stevel */ 927 0 stevel tmp = g_mechListTail; 928 0 stevel g_mechListTail = aMech; 929 0 stevel 930 0 stevel if (tmp != NULL) 931 0 stevel tmp->next = aMech; 932 0 stevel 933 0 stevel if (g_mechList == NULL) 934 0 stevel g_mechList = aMech; 935 0 stevel } /* while */ 936 0 stevel (void) fclose(confFile); 937 0 stevel } /* loadConfigFile */ 938