1 /* 2 * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * lib/krb5/os/init_ctx.c 10 * 11 * Copyright 1994 by the Massachusetts Institute of Technology. 12 * All Rights Reserved. 13 * 14 * Export of this software from the United States of America may 15 * require a specific license from the United States Government. 16 * It is the responsibility of any person or organization contemplating 17 * export to obtain such a license before exporting. 18 * 19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20 * distribute this software and its documentation for any purpose and 21 * without fee is hereby granted, provided that the above copyright 22 * notice appear in all copies and that both that copyright notice and 23 * this permission notice appear in supporting documentation, and that 24 * the name of M.I.T. not be used in advertising or publicity pertaining 25 * to distribution of the software without specific, written prior 26 * permission. Furthermore if you modify this software you must label 27 * your software as modified software and not distribute it in such a 28 * fashion that it might be confused with the original M.I.T. software. 29 * M.I.T. makes no representations about the suitability of 30 * this software for any purpose. It is provided "as is" without express 31 * or implied warranty. 32 * 33 * krb5_init_contex() 34 */ 35 36 #define NEED_WINDOWS 37 #include <k5-int.h> 38 39 #ifdef macintosh 40 #include <PreferencesLib.h> 41 #endif /* macintosh */ 42 43 #if defined(_MSDOS) || defined(_WIN32) 44 45 static krb5_error_code 46 get_from_windows_dir( 47 char **pname 48 ) 49 { 50 UINT size = GetWindowsDirectory(0, 0); 51 *pname = malloc(size + 1 + 52 strlen(DEFAULT_PROFILE_FILENAME) + 1); 53 if (*pname) 54 { 55 GetWindowsDirectory(*pname, size); 56 strcat(*pname, "\\"); 57 strcat(*pname, DEFAULT_PROFILE_FILENAME); 58 return 0; 59 } else { 60 return KRB5_CONFIG_CANTOPEN; 61 } 62 } 63 64 static krb5_error_code 65 get_from_module_dir( 66 char **pname 67 ) 68 { 69 const DWORD size = 1024; /* fixed buffer */ 70 int found = 0; 71 char *p; 72 char *name; 73 struct _stat s; 74 75 *pname = 0; 76 77 name = MALLOC(size); 78 if (!name) 79 return ENOMEM; 80 81 if (!GetModuleFileName(GetModuleHandle("krb5_32"), name, size)) 82 goto cleanup; 83 84 p = name + strlen(name); 85 while ((p >= name) && (*p != '\\') && (*p != '/')) p--; 86 if (p < name) 87 goto cleanup; 88 p++; 89 strncpy(p, DEFAULT_PROFILE_FILENAME, size - (p - name)); 90 name[size - 1] = 0; 91 found = !_stat(name, &s); 92 93 cleanup: 94 if (found) 95 *pname = name; 96 else 97 if (name) FREE(name, size); 98 return 0; 99 } 100 101 /* 102 * get_from_registry 103 * 104 * This will find a profile in the registry. *pbuffer != 0 if we 105 * found something. Make sure to free(*pbuffer) when done. It will 106 * return an error code if there is an error the user should know 107 * about. We maintain the invariant: return value != 0 => 108 * *pbuffer == 0. 109 */ 110 static krb5_error_code 111 get_from_registry( 112 char** pbuffer, 113 HKEY hBaseKey 114 ) 115 { 116 HKEY hKey = 0; 117 LONG rc = 0; 118 DWORD size = 0; 119 krb5_error_code retval = 0; 120 const char *key_path = "Software\\MIT\\Kerberos5"; 121 const char *value_name = "config"; 122 123 /* a wannabe assertion */ 124 if (!pbuffer) 125 { 126 /* 127 * We have a programming error! For now, we segfault :) 128 * There is no good mechanism to deal. 129 */ 130 } 131 *pbuffer = 0; 132 133 if ((rc = RegOpenKeyEx(hBaseKey, key_path, 0, KEY_QUERY_VALUE, 134 &hKey)) != ERROR_SUCCESS) 135 { 136 /* not a real error */ 137 goto cleanup; 138 } 139 rc = RegQueryValueEx(hKey, value_name, 0, 0, 0, &size); 140 if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA)) 141 { 142 /* not a real error */ 143 goto cleanup; 144 } 145 *pbuffer = MALLOC(size); 146 if (!*pbuffer) 147 { 148 retval = ENOMEM; 149 goto cleanup; 150 } 151 if ((rc = RegQueryValueEx(hKey, value_name, 0, 0, *pbuffer, &size)) != 152 ERROR_SUCCESS) 153 { 154 /* 155 * Let's not call it a real error in case it disappears, but 156 * we need to free so that we say we did not find anything. 157 */ 158 FREE(*pbuffer, size); 159 *pbuffer = 0; 160 goto cleanup; 161 } 162 cleanup: 163 if (hKey) 164 RegCloseKey(hKey); 165 if (retval && *pbuffer) 166 { 167 FREE(*pbuffer, size); 168 /* Let's say we did not find anything: */ 169 *pbuffer = 0; 170 } 171 return retval; 172 } 173 174 #endif /* _MSDOS || _WIN32 */ 175 176 #ifndef _KERNEL 177 static void 178 free_filespecs(files) 179 profile_filespec_t *files; 180 { 181 #ifndef macintosh 182 char **cp; 183 184 if (files == 0) 185 return; 186 187 for (cp = files; *cp; cp++) 188 free(*cp); 189 #endif 190 free(files); 191 } 192 193 static krb5_error_code 194 os_get_default_config_files(pfiles, secure) 195 profile_filespec_t ** pfiles; 196 krb5_boolean secure; 197 { 198 profile_filespec_t* files; 199 #ifdef macintosh 200 FSSpec* preferencesFiles = nil; 201 UInt32 numPreferencesFiles; 202 FSSpec* preferencesFilesToInit = nil; 203 UInt32 numPreferencesFilesToInit; 204 UInt32 i; 205 Boolean foundPreferences = false; 206 Boolean writtenPreferences = false; 207 SInt16 refNum = -1; 208 SInt32 length = 0; 209 210 OSErr err = KPGetListOfPreferencesFiles ( 211 secure ? kpSystemPreferences : kpUserPreferences | kpSystemPreferences, 212 &preferencesFiles, 213 &numPreferencesFiles); 214 215 if (err == noErr) { 216 /* After we get the list of files, check whether any of them contain any useful information */ 217 for (i = 0; i < numPreferencesFiles; i++) { 218 if (KPPreferencesFileIsReadable (&preferencesFiles [i]) == noErr) { 219 /* It's readable, check if it has anything in the data fork */ 220 err = FSpOpenDF (&preferencesFiles [i], fsRdPerm, &refNum); 221 if (err == noErr) { 222 err = GetEOF (refNum, &length); 223 } 224 225 if (refNum != -1) { 226 FSClose (refNum); 227 } 228 229 if (length != 0) { 230 foundPreferences = true; 231 break; 232 } 233 } 234 } 235 236 if (!foundPreferences) { 237 /* We found no profile data in any of those files; try to initialize one */ 238 /* If we are running "secure" do not try to initialize preferences */ 239 if (!secure) { 240 err = KPGetListOfPreferencesFiles (kpUserPreferences, &preferencesFilesToInit, &numPreferencesFilesToInit); 241 if (err == noErr) { 242 for (i = 0; i < numPreferencesFilesToInit; i++) { 243 if (KPPreferencesFileIsWritable (&preferencesFilesToInit [i]) == noErr) { 244 err = noErr; 245 /* If not readable, create it */ 246 if (KPPreferencesFileIsReadable (&preferencesFilesToInit [i]) != noErr) { 247 err = KPCreatePreferencesFile (&preferencesFilesToInit [i]); 248 } 249 /* Initialize it */ 250 if (err == noErr) { 251 err = KPInitializeWithDefaultKerberosLibraryPreferences (&preferencesFilesToInit [i]); 252 } 253 break; 254 } 255 } 256 } 257 } 258 } 259 } 260 261 if (err == noErr) { 262 files = malloc ((numPreferencesFiles + 1) * sizeof (FSSpec)); 263 if (files == NULL) 264 err = memFullErr; 265 } 266 267 if (err == noErr) { 268 for (i = 0; i < numPreferencesFiles; i++) { 269 files [i] = preferencesFiles [i]; 270 } 271 272 files [numPreferencesFiles].vRefNum = 0; 273 files [numPreferencesFiles].parID = 0; 274 files [numPreferencesFiles].name[0] = '\0'; 275 } 276 277 if (preferencesFiles != nil) 278 KPFreeListOfPreferencesFiles (preferencesFiles); 279 280 if (preferencesFilesToInit != nil) 281 KPFreeListOfPreferencesFiles (preferencesFilesToInit); 282 283 if (err == memFullErr) 284 return ENOMEM; 285 else if (err != noErr) 286 return ENOENT; 287 288 #else /* !macintosh */ 289 #if defined(_MSDOS) || defined(_WIN32) 290 krb5_error_code retval = 0; 291 char *name = 0; 292 293 if (!secure) 294 { 295 char *env = getenv("KRB5_CONFIG"); 296 if (env) 297 { 298 name = malloc(strlen(env) + 1); 299 if (!name) return ENOMEM; 300 strcpy(name, env); 301 } 302 } 303 if (!name && !secure) 304 { 305 /* HKCU */ 306 retval = get_from_registry(&name, HKEY_CURRENT_USER); 307 if (retval) return retval; 308 } 309 if (!name) 310 { 311 /* HKLM */ 312 retval = get_from_registry(&name, HKEY_LOCAL_MACHINE); 313 if (retval) return retval; 314 } 315 if (!name && !secure) 316 { 317 /* module dir */ 318 retval = get_from_module_dir(&name); 319 if (retval) return retval; 320 } 321 if (!name) 322 { 323 /* windows dir */ 324 retval = get_from_windows_dir(&name); 325 } 326 if (retval) 327 return retval; 328 if (!name) 329 return KRB5_CONFIG_CANTOPEN; /* should never happen */ 330 331 files = malloc(2 * sizeof(char *)); 332 files[0] = name; 333 files[1] = 0; 334 #else /* !_MSDOS && !_WIN32 */ 335 char* filepath = 0; 336 int n_entries, i; 337 int ent_len; 338 const char *s, *t; 339 340 if (!secure) filepath = getenv("KRB5_CONFIG"); 341 if (!filepath) filepath = DEFAULT_PROFILE_PATH; 342 343 /* count the distinct filename components */ 344 for(s = filepath, n_entries = 1; *s; s++) { 345 if (*s == ':') 346 n_entries++; 347 } 348 349 /* the array is NULL terminated */ 350 files = (char**) MALLOC((n_entries+1) * sizeof(char*)); 351 if (files == 0) 352 return ENOMEM; 353 354 /* measure, copy, and skip each one */ 355 /*LINTED*/ 356 for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) 357 { 358 ent_len = t-s; 359 files[i] = (char*) malloc(ent_len + 1); 360 if (files[i] == 0) { 361 /* if malloc fails, free the ones that worked */ 362 while(--i >= 0) free(files[i]); 363 free(files); 364 return ENOMEM; 365 } 366 strncpy(files[i], s, ent_len); 367 files[i][ent_len] = 0; 368 if (*t == 0) { 369 i++; 370 break; 371 } 372 } 373 /* cap the array */ 374 files[i] = 0; 375 #endif /* !_MSDOS && !_WIN32 */ 376 #endif /* !macintosh */ 377 *pfiles = files; 378 return 0; 379 } 380 381 382 /* Set the profile paths in the context. If secure is set to TRUE then 383 do not include user paths (from environment variables, etc.) 384 */ 385 static krb5_error_code 386 os_init_paths(ctx) 387 krb5_context ctx; 388 { 389 krb5_error_code retval = 0; 390 profile_filespec_t *files = 0; 391 krb5_boolean secure = ctx->profile_secure; 392 393 #ifdef KRB5_DNS_LOOKUP 394 ctx->profile_in_memory = 0; 395 #endif /* KRB5_DNS_LOOKUP */ 396 397 retval = os_get_default_config_files(&files, secure); 398 399 if (!retval) { 400 retval = profile_init((const_profile_filespec_t *) files, 401 &ctx->profile); 402 #ifdef KRB5_DNS_LOOKUP 403 /* if none of the filenames can be opened use an empty profile */ 404 if (retval == ENOENT) { 405 retval = profile_init(NULL, &ctx->profile); 406 if (!retval) 407 ctx->profile_in_memory = 1; 408 } 409 #endif /* KRB5_DNS_LOOKUP */ 410 } 411 412 if (files) 413 free_filespecs(files); 414 415 if (retval) 416 ctx->profile = 0; 417 418 if (retval == ENOENT) 419 return KRB5_CONFIG_CANTOPEN; 420 421 if ((retval == PROF_SECTION_NOTOP) || 422 (retval == PROF_SECTION_SYNTAX) || 423 (retval == PROF_RELATION_SYNTAX) || 424 (retval == PROF_EXTRA_CBRACE) || 425 (retval == PROF_MISSING_OBRACE)) 426 return KRB5_CONFIG_BADFORMAT; 427 428 return retval; 429 } 430 #endif /* !_KERNEL */ 431 432 krb5_error_code 433 krb5_os_init_context(ctx) 434 krb5_context ctx; 435 { 436 krb5_os_context os_ctx; 437 krb5_error_code retval = 0; 438 439 if (ctx->os_context) 440 return 0; 441 442 os_ctx = MALLOC(sizeof(struct _krb5_os_context)); 443 if (!os_ctx) 444 return ENOMEM; 445 (void) memset(os_ctx, 0, sizeof(struct _krb5_os_context)); 446 os_ctx->magic = KV5M_OS_CONTEXT; 447 448 ctx->os_context = (void *) os_ctx; 449 450 os_ctx->time_offset = 0; 451 os_ctx->usec_offset = 0; 452 os_ctx->os_flags = 0; 453 os_ctx->default_ccname = 0; 454 os_ctx->default_ccprincipal = 0; 455 456 #ifndef _KERNEL 457 krb5_cc_set_default_name(ctx, NULL); 458 retval = os_init_paths(ctx); 459 #endif 460 /* 461 * If there's an error in the profile, return an error. Just 462 * ignoring the error is a Bad Thing (tm). 463 */ 464 465 return retval; 466 } 467 468 #ifndef _KERNEL 469 470 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 471 krb5_get_profile (ctx, profile) 472 krb5_context ctx; 473 profile_t* profile; 474 { 475 krb5_error_code retval = 0; 476 profile_filespec_t *files = 0; 477 478 retval = os_get_default_config_files(&files, ctx->profile_secure); 479 480 if (!retval) 481 retval = profile_init((const_profile_filespec_t *) files, profile); 482 483 if (files) 484 free_filespecs(files); 485 486 if (retval == ENOENT) 487 return KRB5_CONFIG_CANTOPEN; 488 489 if ((retval == PROF_SECTION_NOTOP) || 490 (retval == PROF_SECTION_SYNTAX) || 491 (retval == PROF_RELATION_SYNTAX) || 492 (retval == PROF_EXTRA_CBRACE) || 493 (retval == PROF_MISSING_OBRACE)) 494 return KRB5_CONFIG_BADFORMAT; 495 496 return retval; 497 } 498 499 #endif 500 501 #ifndef macintosh 502 #ifndef _KERNEL 503 504 krb5_error_code 505 krb5_set_config_files(ctx, filenames) 506 krb5_context ctx; 507 const char **filenames; 508 { 509 krb5_error_code retval; 510 profile_t profile; 511 512 retval = profile_init(filenames, &profile); 513 if (retval) 514 return retval; 515 516 if (ctx->profile) 517 profile_release(ctx->profile); 518 ctx->profile = profile; 519 520 return 0; 521 } 522 523 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 524 krb5_get_default_config_files(pfilenames) 525 char ***pfilenames; 526 { 527 if (!pfilenames) 528 return EINVAL; 529 return os_get_default_config_files(pfilenames, FALSE); 530 } 531 532 KRB5_DLLIMP void KRB5_CALLCONV 533 krb5_free_config_files(filenames) 534 char **filenames; 535 { 536 free_filespecs(filenames); 537 } 538 539 #endif /* _KERNEL */ 540 #endif /* macintosh */ 541 542 #ifndef _KERNEL 543 544 krb5_error_code 545 krb5_secure_config_files(ctx) 546 krb5_context ctx; 547 { 548 /* Obsolete interface; always return an error. 549 550 This function should be removed next time a major version 551 number change happens. */ 552 krb5_error_code retval; 553 554 if (ctx->profile) { 555 profile_release(ctx->profile); 556 ctx->profile = 0; 557 } 558 559 ctx->profile_secure = TRUE; 560 retval = os_init_paths(ctx); 561 if (retval) 562 return retval; 563 564 return KRB5_OBSOLETE_FN; 565 } 566 567 #endif /* _KERNEL */ 568 569 void 570 krb5_os_free_context(ctx) 571 krb5_context ctx; 572 { 573 krb5_os_context os_ctx; 574 575 os_ctx = ctx->os_context; 576 577 if (!os_ctx) 578 return; 579 580 if (os_ctx->default_ccname) { 581 FREE(os_ctx->default_ccname, 582 strlen(os_ctx->default_ccname) + 1); 583 os_ctx->default_ccname = 0; 584 } 585 586 if (os_ctx->default_ccprincipal) { 587 krb5_free_principal (ctx, os_ctx->default_ccprincipal); 588 os_ctx->default_ccprincipal = 0; 589 } 590 591 os_ctx->magic = 0; 592 FREE(os_ctx, sizeof(struct _krb5_os_context)); 593 ctx->os_context = 0; 594 595 #ifndef _KERNEL 596 if (ctx->profile) { 597 profile_release(ctx->profile); 598 ctx->profile = 0; 599 } 600 #endif 601 } 602