1 /* 2 * Copyright 2005 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 #ifndef _KERNEL 39 #include "os-proto.h" 40 #endif 41 42 /* SUNW14resync: Solaris kerb does not need this feature in this file */ 43 #ifdef USE_LOGIN_LIBRARY 44 #undef USE_LOGIN_LIBRARY 45 #endif 46 47 #ifdef USE_LOGIN_LIBRARY 48 #include "KerberosLoginPrivate.h" 49 #endif 50 51 #if defined(_WIN32) 52 53 static krb5_error_code 54 get_from_windows_dir( 55 char **pname 56 ) 57 { 58 UINT size = GetWindowsDirectory(0, 0); 59 *pname = malloc(size + 1 + 60 strlen(DEFAULT_PROFILE_FILENAME) + 1); 61 if (*pname) 62 { 63 GetWindowsDirectory(*pname, size); 64 strcat(*pname, "\\"); 65 strcat(*pname, DEFAULT_PROFILE_FILENAME); 66 return 0; 67 } else { 68 return KRB5_CONFIG_CANTOPEN; 69 } 70 } 71 72 static krb5_error_code 73 get_from_module_dir( 74 char **pname 75 ) 76 { 77 const DWORD size = 1024; /* fixed buffer */ 78 int found = 0; 79 char *p; 80 char *name; 81 struct _stat s; 82 83 *pname = 0; 84 85 name = MALLOC(size); 86 if (!name) 87 return ENOMEM; 88 89 if (!GetModuleFileName(GetModuleHandle("krb5_32"), name, size)) 90 goto cleanup; 91 92 p = name + strlen(name); 93 while ((p >= name) && (*p != '\\') && (*p != '/')) p--; 94 if (p < name) 95 goto cleanup; 96 p++; 97 strncpy(p, DEFAULT_PROFILE_FILENAME, size - (p - name)); 98 name[size - 1] = 0; 99 found = !_stat(name, &s); 100 101 cleanup: 102 if (found) 103 *pname = name; 104 else 105 if (name) FREE(name, size); 106 return 0; 107 } 108 109 /* 110 * get_from_registry 111 * 112 * This will find a profile in the registry. *pbuffer != 0 if we 113 * found something. Make sure to free(*pbuffer) when done. It will 114 * return an error code if there is an error the user should know 115 * about. We maintain the invariant: return value != 0 => 116 * *pbuffer == 0. 117 */ 118 static krb5_error_code 119 get_from_registry( 120 char** pbuffer, 121 HKEY hBaseKey 122 ) 123 { 124 HKEY hKey = 0; 125 LONG rc = 0; 126 DWORD size = 0; 127 krb5_error_code retval = 0; 128 const char *key_path = "Software\\MIT\\Kerberos5"; 129 const char *value_name = "config"; 130 131 /* a wannabe assertion */ 132 if (!pbuffer) 133 { 134 /* 135 * We have a programming error! For now, we segfault :) 136 * There is no good mechanism to deal. 137 */ 138 } 139 *pbuffer = 0; 140 141 if ((rc = RegOpenKeyEx(hBaseKey, key_path, 0, KEY_QUERY_VALUE, 142 &hKey)) != ERROR_SUCCESS) 143 { 144 /* not a real error */ 145 goto cleanup; 146 } 147 rc = RegQueryValueEx(hKey, value_name, 0, 0, 0, &size); 148 if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA)) 149 { 150 /* not a real error */ 151 goto cleanup; 152 } 153 *pbuffer = MALLOC(size); 154 if (!*pbuffer) 155 { 156 retval = ENOMEM; 157 goto cleanup; 158 } 159 if ((rc = RegQueryValueEx(hKey, value_name, 0, 0, *pbuffer, &size)) != 160 ERROR_SUCCESS) 161 { 162 /* 163 * Let's not call it a real error in case it disappears, but 164 * we need to free so that we say we did not find anything. 165 */ 166 FREE(*pbuffer, size); 167 *pbuffer = 0; 168 goto cleanup; 169 } 170 cleanup: 171 if (hKey) 172 RegCloseKey(hKey); 173 if (retval && *pbuffer) 174 { 175 FREE(*pbuffer, size); 176 /* Let's say we did not find anything: */ 177 *pbuffer = 0; 178 } 179 return retval; 180 } 181 182 #endif /* _WIN32 */ 183 184 #ifndef _KERNEL 185 static void 186 free_filespecs(profile_filespec_t *files) 187 { 188 char **cp; 189 190 if (files == 0) 191 return; 192 193 for (cp = files; *cp; cp++) 194 free(*cp); 195 free(files); 196 } 197 198 /* This function is needed by KfM's KerberosPreferences API 199 * because it needs to be able to specify "secure" */ 200 krb5_error_code 201 os_get_default_config_files(profile_filespec_t **pfiles, krb5_boolean secure) 202 { 203 profile_filespec_t* files; 204 #if defined(_WIN32) 205 krb5_error_code retval = 0; 206 char *name = 0; 207 208 if (!secure) 209 { 210 char *env = getenv("KRB5_CONFIG"); 211 if (env) 212 { 213 name = malloc(strlen(env) + 1); 214 if (!name) return ENOMEM; 215 strcpy(name, env); 216 } 217 } 218 if (!name && !secure) 219 { 220 /* HKCU */ 221 retval = get_from_registry(&name, HKEY_CURRENT_USER); 222 if (retval) return retval; 223 } 224 if (!name) 225 { 226 /* HKLM */ 227 retval = get_from_registry(&name, HKEY_LOCAL_MACHINE); 228 if (retval) return retval; 229 } 230 if (!name && !secure) 231 { 232 /* module dir */ 233 retval = get_from_module_dir(&name); 234 if (retval) return retval; 235 } 236 if (!name) 237 { 238 /* windows dir */ 239 retval = get_from_windows_dir(&name); 240 } 241 if (retval) 242 return retval; 243 if (!name) 244 return KRB5_CONFIG_CANTOPEN; /* should never happen */ 245 246 files = malloc(2 * sizeof(char *)); 247 files[0] = name; 248 files[1] = 0; 249 #else /* !_WIN32 */ 250 char* filepath = 0; 251 int n_entries, i; 252 unsigned int ent_len; 253 const char *s, *t; 254 255 #ifdef USE_LOGIN_LIBRARY 256 /* If __KLAllowHomeDirectoryAccess() == FALSE, we are probably 257 trying to authenticate to a fileserver for the user's homedir. */ 258 if (secure || !__KLAllowHomeDirectoryAccess ()) { 259 #else 260 if (secure) { 261 #endif 262 filepath = DEFAULT_SECURE_PROFILE_PATH; 263 } else { 264 filepath = getenv("KRB5_CONFIG"); 265 if (!filepath) filepath = DEFAULT_PROFILE_PATH; 266 } 267 268 /* count the distinct filename components */ 269 for(s = filepath, n_entries = 1; *s; s++) { 270 if (*s == ':') 271 n_entries++; 272 } 273 274 /* the array is NULL terminated */ 275 files = (char**) MALLOC((n_entries+1) * sizeof(char*)); 276 if (files == 0) 277 return ENOMEM; 278 279 /* measure, copy, and skip each one */ 280 /*LINTED*/ 281 for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) 282 { 283 ent_len = t-s; 284 files[i] = (char*) malloc(ent_len + 1); 285 if (files[i] == 0) { 286 /* if malloc fails, free the ones that worked */ 287 while(--i >= 0) free(files[i]); 288 free(files); 289 return ENOMEM; 290 } 291 strncpy(files[i], s, ent_len); 292 files[i][ent_len] = 0; 293 if (*t == 0) { 294 i++; 295 break; 296 } 297 } 298 /* cap the array */ 299 files[i] = 0; 300 #endif /* !_WIN32 */ 301 *pfiles = (profile_filespec_t *)files; 302 return 0; 303 } 304 305 306 /* Set the profile paths in the context. If secure is set to TRUE then 307 do not include user paths (from environment variables, etc.) 308 */ 309 static krb5_error_code 310 os_init_paths(krb5_context ctx) 311 { 312 krb5_error_code retval = 0; 313 profile_filespec_t *files = 0; 314 krb5_boolean secure = ctx->profile_secure; 315 316 #ifdef KRB5_DNS_LOOKUP 317 ctx->profile_in_memory = 0; 318 #endif /* KRB5_DNS_LOOKUP */ 319 320 retval = os_get_default_config_files(&files, secure); 321 322 if (!retval) { 323 retval = profile_init((const_profile_filespec_t *) files, 324 &ctx->profile); 325 326 #ifdef KRB5_DNS_LOOKUP 327 /* if none of the filenames can be opened use an empty profile */ 328 if (retval == ENOENT) { 329 retval = profile_init(NULL, &ctx->profile); 330 if (!retval) 331 ctx->profile_in_memory = 1; 332 } 333 #endif /* KRB5_DNS_LOOKUP */ 334 } 335 336 if (files) 337 free_filespecs(files); 338 339 if (retval) 340 ctx->profile = 0; 341 342 if (retval == ENOENT) 343 return KRB5_CONFIG_CANTOPEN; 344 345 if ((retval == PROF_SECTION_NOTOP) || 346 (retval == PROF_SECTION_SYNTAX) || 347 (retval == PROF_RELATION_SYNTAX) || 348 (retval == PROF_EXTRA_CBRACE) || 349 (retval == PROF_MISSING_OBRACE)) 350 return KRB5_CONFIG_BADFORMAT; 351 352 return retval; 353 } 354 #endif /* !_KERNEL */ 355 356 krb5_error_code 357 krb5_os_init_context(krb5_context ctx) 358 { 359 krb5_os_context os_ctx; 360 krb5_error_code retval = 0; 361 362 os_ctx = ctx->os_context; 363 os_ctx->magic = KV5M_OS_CONTEXT; 364 365 os_ctx->time_offset = 0; 366 os_ctx->usec_offset = 0; 367 os_ctx->os_flags = 0; 368 os_ctx->default_ccname = 0; 369 370 #ifndef _KERNEL 371 krb5_cc_set_default_name(ctx, NULL); 372 373 retval = os_init_paths(ctx); 374 #endif 375 /* 376 * If there's an error in the profile, return an error. Just 377 * ignoring the error is a Bad Thing (tm). 378 */ 379 380 return retval; 381 } 382 383 #ifndef _KERNEL 384 385 krb5_error_code KRB5_CALLCONV 386 krb5_get_profile (krb5_context ctx, profile_t *profile) 387 { 388 krb5_error_code retval = 0; 389 profile_filespec_t *files = 0; 390 391 retval = os_get_default_config_files(&files, ctx->profile_secure); 392 393 if (!retval) { 394 retval = profile_init((const_profile_filespec_t *) files, 395 profile); 396 } 397 398 if (files) 399 free_filespecs(files); 400 401 if (retval == ENOENT) 402 return KRB5_CONFIG_CANTOPEN; 403 404 if ((retval == PROF_SECTION_NOTOP) || 405 (retval == PROF_SECTION_SYNTAX) || 406 (retval == PROF_RELATION_SYNTAX) || 407 (retval == PROF_EXTRA_CBRACE) || 408 (retval == PROF_MISSING_OBRACE)) 409 return KRB5_CONFIG_BADFORMAT; 410 411 return retval; 412 } 413 414 #endif 415 416 #ifndef _KERNEL 417 418 krb5_error_code 419 krb5_set_config_files(krb5_context ctx, const char **filenames) 420 { 421 krb5_error_code retval; 422 profile_t profile; 423 424 retval = profile_init(filenames, &profile); 425 if (retval) 426 return retval; 427 428 if (ctx->profile) 429 profile_release(ctx->profile); 430 ctx->profile = profile; 431 432 return 0; 433 } 434 435 krb5_error_code KRB5_CALLCONV 436 krb5_get_default_config_files(char ***pfilenames) 437 { 438 if (!pfilenames) 439 return EINVAL; 440 return os_get_default_config_files(pfilenames, FALSE); 441 } 442 443 void KRB5_CALLCONV 444 krb5_free_config_files(char **filenames) 445 { 446 free_filespecs(filenames); 447 } 448 449 #endif /* _KERNEL */ 450 451 #ifndef _KERNEL 452 453 krb5_error_code 454 krb5_secure_config_files(krb5_context ctx) 455 { 456 /* Obsolete interface; always return an error. 457 458 This function should be removed next time a major version 459 number change happens. */ 460 krb5_error_code retval; 461 462 if (ctx->profile) { 463 profile_release(ctx->profile); 464 ctx->profile = 0; 465 } 466 467 ctx->profile_secure = TRUE; 468 retval = os_init_paths(ctx); 469 if (retval) 470 return retval; 471 472 return KRB5_OBSOLETE_FN; 473 } 474 475 #endif /* _KERNEL */ 476 477 void 478 krb5_os_free_context(krb5_context ctx) 479 { 480 krb5_os_context os_ctx; 481 482 os_ctx = ctx->os_context; 483 484 if (os_ctx->default_ccname) { 485 FREE(os_ctx->default_ccname, 486 strlen(os_ctx->default_ccname) + 1); 487 os_ctx->default_ccname = 0; 488 } 489 490 os_ctx->magic = 0; 491 492 #ifndef _KERNEL 493 if (ctx->profile) { 494 profile_release(ctx->profile); 495 ctx->profile = 0; 496 } 497 #endif 498 } 499