#define NEED_WINDOWS
#include "k5-int.h"
#include "os-proto.h"
#include "../krb/int-proto.h"
#if defined(_WIN32)
#include <winsock.h>
#include <Shlobj.h>
static krb5_error_code
get_from_windows_dir(
char **pname
)
{
UINT size = GetWindowsDirectory(0, 0);
*pname = malloc(size + strlen(DEFAULT_PROFILE_FILENAME) + 2);
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;
int found = 0;
char *p = NULL;
char *name = NULL;
struct _stat s;
*pname = 0;
name = malloc(size);
if (!name)
return ENOMEM;
#ifdef _WIN64
if (!GetModuleFileName(GetModuleHandle("krb5_64"), name, size))
#else
if (!GetModuleFileName(GetModuleHandle("krb5_32"), name, size))
#endif
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
free(name);
return 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";
assert(pbuffer != NULL);
*pbuffer = NULL;
if ((rc = RegOpenKeyEx(hBaseKey, key_path, 0, KEY_QUERY_VALUE,
&hKey)) != ERROR_SUCCESS) {
goto cleanup;
}
rc = RegQueryValueEx(hKey, value_name, 0, 0, 0, &size);
if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA)) {
goto cleanup;
}
*pbuffer = malloc(size);
if (!*pbuffer) {
retval = ENOMEM;
goto cleanup;
}
if ((rc = RegQueryValueEx(hKey, value_name, 0, 0, *pbuffer, &size)) !=
ERROR_SUCCESS) {
free(*pbuffer);
*pbuffer = 0;
goto cleanup;
}
cleanup:
if (hKey)
RegCloseKey(hKey);
if (retval && *pbuffer) {
free(*pbuffer);
*pbuffer = 0;
}
return retval;
}
static krb5_error_code
get_from_known_folder(
int folderId,
char** pbuffer
)
{
char szPath[MAX_PATH];
const char * software_suffix = "\\MIT\\Kerberos5";
krb5_error_code retval = 0;
size_t size;
struct _stat s;
assert(pbuffer);
*pbuffer = NULL;
if (SUCCEEDED(SHGetFolderPath(NULL,
folderId ,
NULL,
SHGFP_TYPE_CURRENT,
szPath))) {
size = strlen(software_suffix) + strlen("\\" DEFAULT_PROFILE_FILENAME) + strlen(szPath);
if ((size + 1) >= sizeof(szPath)) {
goto cleanup;
}
strlcat(szPath, software_suffix, sizeof(szPath));
strlcat(szPath, "\\", sizeof(szPath));
strlcat(szPath, DEFAULT_PROFILE_FILENAME, sizeof(szPath));
} else {
goto cleanup;
}
if (_stat(szPath, &s)) {
goto cleanup;
}
*pbuffer = malloc(size + 1);
if (!*pbuffer) {
retval = ENOMEM;
goto cleanup;
}
strlcpy (*pbuffer, szPath, size + 1);
cleanup:
if (retval && *pbuffer) {
free(*pbuffer);
*pbuffer = 0;
}
return retval;
}
#endif
static void
free_filespecs(profile_filespec_t *files)
{
char **cp;
if (files == 0)
return;
for (cp = files; *cp; cp++)
free(*cp);
free(files);
}
static 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 = secure_getenv("KRB5_CONFIG");
if (env) {
name = strdup(env);
if (!name) return ENOMEM;
}
}
if (!name && !secure) {
retval = get_from_registry(&name, HKEY_CURRENT_USER);
if (retval) return retval;
}
if (!name) {
retval = get_from_registry(&name, HKEY_LOCAL_MACHINE);
if (retval) return retval;
}
if (!name && !secure) {
retval = get_from_known_folder(CSIDL_APPDATA, &name);
if (retval) return retval;
}
if (!name) {
retval = get_from_known_folder(CSIDL_COMMON_APPDATA, &name);
if (retval) return retval;
}
if (!name && !secure) {
retval = get_from_module_dir(&name);
if (retval) return retval;
}
if (!name) {
retval = get_from_windows_dir(&name);
}
if (retval)
return retval;
if (!name)
return KRB5_CONFIG_CANTOPEN;
files = malloc(2 * sizeof(char *));
if (!files)
return ENOMEM;
files[0] = name;
files[1] = 0;
#else
char* filepath = 0;
int n_entries, i;
unsigned int ent_len;
const char *s, *t;
if (secure) {
filepath = DEFAULT_SECURE_PROFILE_PATH;
} else {
filepath = secure_getenv("KRB5_CONFIG");
if (!filepath) filepath = DEFAULT_PROFILE_PATH;
}
for(s = filepath, n_entries = 1; *s; s++) {
if (*s == ':')
n_entries++;
}
files = (char**) malloc((n_entries+1) * sizeof(char*));
if (files == 0)
return ENOMEM;
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) {
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;
}
}
files[i] = 0;
#endif
*pfiles = (profile_filespec_t *)files;
return 0;
}
static krb5_error_code
add_kdc_config_file(profile_filespec_t **pfiles)
{
char *file = NULL;
size_t count = 0;
profile_filespec_t *newfiles;
file = secure_getenv(KDC_PROFILE_ENV);
if (file == NULL)
file = DEFAULT_KDC_PROFILE;
for (count = 0; (*pfiles)[count]; count++)
;
count += 2;
newfiles = malloc(count * sizeof(*newfiles));
if (newfiles == NULL)
return ENOMEM;
memcpy(newfiles + 1, *pfiles, (count-1) * sizeof(*newfiles));
newfiles[0] = strdup(file);
if (newfiles[0] == NULL) {
int e = ENOMEM;
free(newfiles);
return e;
}
free(*pfiles);
*pfiles = newfiles;
return 0;
}
static krb5_error_code
os_init_paths(krb5_context ctx, krb5_boolean kdc)
{
krb5_error_code retval = 0;
profile_filespec_t *files = 0;
krb5_boolean secure = ctx->profile_secure;
retval = os_get_default_config_files(&files, secure);
if (retval == 0 && kdc)
retval = add_kdc_config_file(&files);
if (!retval) {
retval = profile_init_flags((const_profile_filespec_t *) files,
PROFILE_INIT_ALLOW_MODULE, &ctx->profile);
if (retval == ENOENT)
retval = profile_init(NULL, &ctx->profile);
}
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
k5_os_init_context(krb5_context ctx, profile_t profile, krb5_flags flags)
{
krb5_os_context os_ctx;
krb5_error_code retval = 0;
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
#endif
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;
PLUGIN_DIR_INIT(&ctx->libkrb5_plugins);
ctx->preauth_context = NULL;
if (profile)
retval = profile_copy(profile, &ctx->profile);
else
retval = os_init_paths(ctx, (flags & KRB5_INIT_CONTEXT_KDC) != 0);
if (retval)
return retval;
#ifdef _WIN32
wVersionRequested = 0x0101;
WSAStartup (wVersionRequested, &wsaData);
#endif
return 0;
}
krb5_error_code KRB5_CALLCONV
krb5_get_profile (krb5_context ctx, profile_t *profile)
{
return profile_copy (ctx->profile, profile);
}
krb5_error_code
krb5_set_config_files(krb5_context ctx, const char **filenames)
{
krb5_error_code retval = 0;
profile_t profile;
retval = profile_init_flags(filenames, PROFILE_INIT_ALLOW_MODULE,
&profile);
if (retval)
return retval;
if (ctx->profile)
profile_abandon(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);
}
void
k5_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_abandon(ctx->profile);
ctx->profile = 0;
}
if (ctx->preauth_context) {
k5_free_preauth_context(ctx);
ctx->preauth_context = NULL;
}
krb5int_close_plugin_dirs (&ctx->libkrb5_plugins);
#ifdef _WIN32
WSACleanup();
#endif
}