/* * lib/krb5/os/init_ctx.c * * Copyright 1994 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * krb5_init_contex() */ #define NEED_WINDOWS #include "k5-int.h" #include "os-proto.h" #ifdef USE_LOGIN_LIBRARY #include "KerberosLoginPrivate.h" #endif #if defined(_WIN32) static krb5_error_code get_from_windows_dir( char **pname ) { UINT size = GetWindowsDirectory(0, 0); *pname = malloc(size + 1 + strlen(DEFAULT_PROFILE_FILENAME) + 1); if (*pname) { GetWindowsDirectory(*pname, size); strcat(*pname, "\\"); strcat(*pname, DEFAULT_PROFILE_FILENAME); return 0; } else { return KRB5_CONFIG_CANTOPEN; } } static krb5_error_code get_from_module_dir( char **pname ) { const DWORD size = 1024; /* fixed buffer */ int found = 0; char *p; char *name; struct _stat s; *pname = 0; name = malloc(size); if (!name) return ENOMEM; if (!GetModuleFileName(GetModuleHandle("krb5_32"), name, size)) goto cleanup; p = name + strlen(name); while ((p >= name) && (*p != '\\') && (*p != '/')) p--; if (p < name) goto cleanup; p++; strncpy(p, DEFAULT_PROFILE_FILENAME, size - (p - name)); name[size - 1] = 0; found = !_stat(name, &s); cleanup: if (found) *pname = name; else if (name) free(name); return 0; } /* * get_from_registry * * This will find a profile in the registry. *pbuffer != 0 if we * found something. Make sure to free(*pbuffer) when done. It will * return an error code if there is an error the user should know * about. We maintain the invariant: return value != 0 => * *pbuffer == 0. */ static krb5_error_code get_from_registry( char** pbuffer, HKEY hBaseKey ) { HKEY hKey = 0; LONG rc = 0; DWORD size = 0; krb5_error_code retval = 0; const char *key_path = "Software\\MIT\\Kerberos5"; const char *value_name = "config"; /* a wannabe assertion */ if (!pbuffer) { /* * We have a programming error! For now, we segfault :) * There is no good mechanism to deal. */ } *pbuffer = 0; if ((rc = RegOpenKeyEx(hBaseKey, key_path, 0, KEY_QUERY_VALUE, &hKey)) != ERROR_SUCCESS) { /* not a real error */ goto cleanup; } rc = RegQueryValueEx(hKey, value_name, 0, 0, 0, &size); if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA)) { /* not a real error */ goto cleanup; } *pbuffer = malloc(size); if (!*pbuffer) { retval = ENOMEM; goto cleanup; } if ((rc = RegQueryValueEx(hKey, value_name, 0, 0, *pbuffer, &size)) != ERROR_SUCCESS) { /* * Let's not call it a real error in case it disappears, but * we need to free so that we say we did not find anything. */ free(*pbuffer); *pbuffer = 0; goto cleanup; } cleanup: if (hKey) RegCloseKey(hKey); if (retval && *pbuffer) { free(*pbuffer); /* Let's say we did not find anything: */ *pbuffer = 0; } return retval; } #endif /* _WIN32 */ static void free_filespecs(profile_filespec_t *files) { char **cp; if (files == 0) return; for (cp = files; *cp; cp++) free(*cp); free(files); } /* This function is needed by KfM's KerberosPreferences API * because it needs to be able to specify "secure" */ krb5_error_code os_get_default_config_files(profile_filespec_t **pfiles, krb5_boolean secure) { profile_filespec_t* files; #if defined(_WIN32) krb5_error_code retval = 0; char *name = 0; if (!secure) { char *env = getenv("KRB5_CONFIG"); if (env) { name = malloc(strlen(env) + 1); if (!name) return ENOMEM; strcpy(name, env); } } if (!name && !secure) { /* HKCU */ retval = get_from_registry(&name, HKEY_CURRENT_USER); if (retval) return retval; } if (!name) { /* HKLM */ retval = get_from_registry(&name, HKEY_LOCAL_MACHINE); if (retval) return retval; } if (!name && !secure) { /* module dir */ retval = get_from_module_dir(&name); if (retval) return retval; } if (!name) { /* windows dir */ retval = get_from_windows_dir(&name); } if (retval) return retval; if (!name) return KRB5_CONFIG_CANTOPEN; /* should never happen */ files = malloc(2 * sizeof(char *)); files[0] = name; files[1] = 0; #else /* !_WIN32 */ char* filepath = 0; int n_entries, i; unsigned int ent_len; const char *s, *t; #ifdef USE_LOGIN_LIBRARY /* If __KLAllowHomeDirectoryAccess() == FALSE, we are probably trying to authenticate to a fileserver for the user's homedir. */ if (secure || !__KLAllowHomeDirectoryAccess ()) { #else if (secure) { #endif filepath = DEFAULT_SECURE_PROFILE_PATH; } else { filepath = getenv("KRB5_CONFIG"); if (!filepath) filepath = DEFAULT_PROFILE_PATH; } /* count the distinct filename components */ for(s = filepath, n_entries = 1; *s; s++) { if (*s == ':') n_entries++; } /* the array is NULL terminated */ files = (char**) malloc((n_entries+1) * sizeof(char*)); if (files == 0) return ENOMEM; /* measure, copy, and skip each one */ for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) { ent_len = t-s; files[i] = (char*) malloc(ent_len + 1); if (files[i] == 0) { /* if malloc fails, free the ones that worked */ while(--i >= 0) free(files[i]); free(files); return ENOMEM; } strncpy(files[i], s, ent_len); files[i][ent_len] = 0; if (*t == 0) { i++; break; } } /* cap the array */ files[i] = 0; #endif /* !_WIN32 */ *pfiles = (profile_filespec_t *)files; return 0; } /* Set the profile paths in the context. If secure is set to TRUE then do not include user paths (from environment variables, etc.) */ static krb5_error_code os_init_paths(krb5_context ctx) { krb5_error_code retval = 0; profile_filespec_t *files = 0; krb5_boolean secure = ctx->profile_secure; #ifdef KRB5_DNS_LOOKUP ctx->profile_in_memory = 0; #endif /* KRB5_DNS_LOOKUP */ retval = os_get_default_config_files(&files, secure); if (!retval) { retval = profile_init((const_profile_filespec_t *) files, &ctx->profile); #ifdef KRB5_DNS_LOOKUP /* if none of the filenames can be opened use an empty profile */ if (retval == ENOENT) { retval = profile_init(NULL, &ctx->profile); if (!retval) ctx->profile_in_memory = 1; } #endif /* KRB5_DNS_LOOKUP */ } if (files) free_filespecs(files); if (retval) ctx->profile = 0; if (retval == ENOENT) return KRB5_CONFIG_CANTOPEN; if ((retval == PROF_SECTION_NOTOP) || (retval == PROF_SECTION_SYNTAX) || (retval == PROF_RELATION_SYNTAX) || (retval == PROF_EXTRA_CBRACE) || (retval == PROF_MISSING_OBRACE)) return KRB5_CONFIG_BADFORMAT; return retval; } krb5_error_code krb5_os_init_context(krb5_context ctx) { krb5_os_context os_ctx; krb5_error_code retval = 0; os_ctx = ctx->os_context; os_ctx->magic = KV5M_OS_CONTEXT; os_ctx->time_offset = 0; os_ctx->usec_offset = 0; os_ctx->os_flags = 0; os_ctx->default_ccname = 0; krb5_cc_set_default_name(ctx, NULL); retval = os_init_paths(ctx); /* * If there's an error in the profile, return an error. Just * ignoring the error is a Bad Thing (tm). */ return retval; } krb5_error_code KRB5_CALLCONV krb5_get_profile (krb5_context ctx, profile_t *profile) { krb5_error_code retval = 0; profile_filespec_t *files = 0; retval = os_get_default_config_files(&files, ctx->profile_secure); if (!retval) { retval = profile_init((const_profile_filespec_t *) files, profile); } if (files) free_filespecs(files); if (retval == ENOENT) return KRB5_CONFIG_CANTOPEN; if ((retval == PROF_SECTION_NOTOP) || (retval == PROF_SECTION_SYNTAX) || (retval == PROF_RELATION_SYNTAX) || (retval == PROF_EXTRA_CBRACE) || (retval == PROF_MISSING_OBRACE)) return KRB5_CONFIG_BADFORMAT; return retval; } krb5_error_code krb5_set_config_files(krb5_context ctx, const char **filenames) { krb5_error_code retval; profile_t profile; retval = profile_init(filenames, &profile); if (retval) return retval; if (ctx->profile) profile_release(ctx->profile); ctx->profile = profile; return 0; } krb5_error_code KRB5_CALLCONV krb5_get_default_config_files(char ***pfilenames) { if (!pfilenames) return EINVAL; return os_get_default_config_files(pfilenames, FALSE); } void KRB5_CALLCONV krb5_free_config_files(char **filenames) { free_filespecs(filenames); } krb5_error_code krb5_secure_config_files(krb5_context ctx) { /* Obsolete interface; always return an error. This function should be removed next time a major version number change happens. */ krb5_error_code retval; if (ctx->profile) { profile_release(ctx->profile); ctx->profile = 0; } ctx->profile_secure = TRUE; retval = os_init_paths(ctx); if (retval) return retval; return KRB5_OBSOLETE_FN; } void krb5_os_free_context(krb5_context ctx) { krb5_os_context os_ctx; os_ctx = ctx->os_context; if (os_ctx->default_ccname) { free(os_ctx->default_ccname); os_ctx->default_ccname = 0; } os_ctx->magic = 0; if (ctx->profile) { profile_release(ctx->profile); ctx->profile = 0; } }