From e3cc5d5ece7593084a252e03f77a6fe5b3a9edc0 Mon Sep 17 00:00:00 2001 From: Sam Hartman Date: Mon, 19 Sep 2011 00:58:43 +0000 Subject: [PATCH] On Windows, parse mechanism info from Registry instead of mech file Currently the code parses @sysconfdir@/gss/mech as a set of GSS mechanisms to dynamically load. On Windows this should come from the registry. Signed-off-by: Kevin Wasserman Signed-off-by: Sam Hartman git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25198 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/gssapi/mechglue/g_initialize.c | 520 +++++++++++++++++-------- 1 file changed, 351 insertions(+), 169 deletions(-) diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c index b34f3cf37..89b2253ba 100644 --- a/src/lib/gssapi/mechglue/g_initialize.c +++ b/src/lib/gssapi/mechglue/g_initialize.c @@ -60,7 +60,17 @@ /* Local functions */ static gss_mech_info searchMechList(const gss_OID); +static void addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib, const char *kernMod, const char *modOptions); static void loadConfigFile(const char *); +#if defined(_WIN32) +#ifndef MECH_KEY +#define MECH_KEY "SOFTWARE\\gss\\mech" +#endif +static time_t getRegKeyModTime(HKEY hBaseKey, const char *keyPath); +static time_t getRegConfigModTime(const char *keyPath); +static void getRegKeyValue(HKEY key, const char *keyPath, const char *valueName, void **data, DWORD *dataLen); +static void loadConfigFromRegistry(HKEY keyBase, const char *keyPath); +#endif static void updateMechList(void); static void freeMechList(void); @@ -568,6 +578,15 @@ gssint_get_mechanisms(char *mechArray[], int arrayLen) static void updateMechList(void) { +#if defined(_WIN32) + time_t lastConfModTime = getRegConfigModTime(MECH_KEY); + if (g_confFileModTime < lastConfModTime) + { + g_confFileModTime = lastConfModTime; + loadConfigFromRegistry(HKEY_CURRENT_USER, MECH_KEY); + loadConfigFromRegistry(HKEY_LOCAL_MACHINE, MECH_KEY); + } +#else /* _WIN32 */ char *fileName; struct stat fileInfo; @@ -582,6 +601,7 @@ updateMechList(void) #if 0 init_hardcoded(); #endif +#endif /* !_WIN32 */ } /* updateMechList */ #ifdef _GSS_STATIC_LINK @@ -1026,7 +1046,6 @@ const gss_OID oid; return ((gss_mech_info) NULL); } /* searchMechList */ - /* * loads the configuration file * this is called while having a mutex lock on the mechanism list @@ -1036,16 +1055,9 @@ const gss_OID oid; static void loadConfigFile(fileName) const char *fileName; { - char buffer[BUFSIZ], *oidStr, *oid, *sharedLib, *kernMod, *endp; - char *modOptions; - char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ]; - char *tmpStr; + char *sharedLib, *kernMod, *modOptions, *oid, *endp; + char buffer[BUFSIZ], *oidStr; FILE *confFile; - gss_OID mechOid; - gss_mech_info aMech, tmp; - OM_uint32 minor; - gss_buffer_desc oidBuf; - if ((confFile = fopen(fileName, "r")) == NULL) { return; } @@ -1062,200 +1074,370 @@ const char *fileName; * the mechanism name */ oidStr = buffer; - for (oid = buffer; *oid && !isspace(*oid); oid++); + for (endp = buffer; *endp && !isspace(*endp); endp++); /* Now find the first non-white-space character */ - if (*oid) { - *oid = '\0'; - oid++; - while (*oid && isspace(*oid)) - oid++; - } - - /* - * If that's all, then this is a corrupt entry. Skip it. - */ - if (! *oid) - continue; - - /* Find the end of the oid and make sure it is NULL-ended */ - for (endp = oid; *endp && !isspace(*endp); endp++) - ; - if (*endp) { *endp = '\0'; + endp++; + while (*endp && isspace(*endp)) + endp++; } /* - * check if an entry for this oid already exists - * if it does, and the library is already loaded then - * we can't modify it, so skip it + * If that's all, then this is a corrupt entry. Skip it. */ - oidBuf.value = (void *)oid; - oidBuf.length = strlen(oid); - if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid) - != GSS_S_COMPLETE) { -#if 0 - (void) syslog(LOG_INFO, "invalid mechanism oid" - " [%s] in configuration file", oid); -#endif + if (! *endp) continue; - } - aMech = searchMechList(mechOid); - if (aMech && aMech->mech) { - generic_gss_release_oid(&minor, &mechOid); - continue; - } + /* Find the end of the oid and make sure it is NULL-ended */ + for (oid=endp; *endp && !isspace(*endp); endp++) + ; + + if (*endp) { + *endp = '\0'; + endp++; + } + + /* Find the start of the shared lib name */ + for (sharedLib = endp; *sharedLib && isspace(*sharedLib); + sharedLib++) + ; + + /* + * Find the end of the shared lib name and make sure it is + * NULL-terminated. + */ + for (endp = sharedLib; *endp && !isspace(*endp); endp++) + ; + + if (*endp) { + *endp = '\0'; + endp++; + } + + /* Find the start of the optional kernel module lib name */ + for (kernMod = endp; *kernMod && isspace(*kernMod); + kernMod++) + ; + + /* + * If this item starts with a bracket "[", then + * it is not a kernel module, but is a list of + * options for the user module to parse later. + */ + if (*kernMod && *kernMod != '[') { + /* + * Find the end of the shared lib name and make sure + * it is NULL-terminated. + */ + for (endp = kernMod; *endp && !isspace(*endp); endp++) + ; + + if (*endp) { + *endp = '\0'; + endp++; + } + } else + kernMod = NULL; + + /* Find the start of the optional module options list */ + for (modOptions = endp; *modOptions && isspace(*modOptions); + modOptions++); + + if (*modOptions == '[') { + /* move past the opening bracket */ + for (modOptions = modOptions+1; + *modOptions && isspace(*modOptions); + modOptions++); - /* Find the start of the shared lib name */ - for (sharedLib = endp+1; *sharedLib && isspace(*sharedLib); - sharedLib++) - ; + /* Find the closing bracket */ + for (endp = modOptions; + *endp && *endp != ']'; endp++); - /* - * If that's all, then this is a corrupt entry. Skip it. - */ - if (! *sharedLib) { - generic_gss_release_oid(&minor, &mechOid); - continue; - } + *endp = '\0'; + } else { + modOptions = NULL; + } - /* - * Find the end of the shared lib name and make sure it is - * NULL-terminated. - */ - for (endp = sharedLib; *endp && !isspace(*endp); endp++) - ; + addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions); + } /* while */ + (void) fclose(confFile); +} /* loadConfigFile */ - if (*endp) { - *endp = '\0'; - } +#if defined(_WIN32) - /* Find the start of the optional kernel module lib name */ - for (kernMod = endp+1; *kernMod && isspace(*kernMod); - kernMod++) - ; +static time_t +filetimeToTimet(const FILETIME *ft) +{ + ULARGE_INTEGER ull; + ull.LowPart = ft->dwLowDateTime; + ull.HighPart = ft->dwHighDateTime; + return (time_t )(ull.QuadPart / 10000000ULL - 11644473600ULL); +} - /* - * If this item starts with a bracket "[", then - * it is not a kernel module, but is a list of - * options for the user module to parse later. - */ - if (*kernMod && *kernMod != '[') { - /* - * Find the end of the shared lib name and make sure - * it is NULL-terminated. - */ - for (endp = kernMod; *endp && !isspace(*endp); endp++) - ; +static time_t +getRegConfigModTime(const char *keyPath) +{ + time_t currentUserModTime = getRegKeyModTime(HKEY_CURRENT_USER, keyPath); + time_t localMachineModTime = getRegKeyModTime(HKEY_LOCAL_MACHINE, keyPath); + return currentUserModTime > localMachineModTime ? currentUserModTime : localMachineModTime; +} - if (*endp) { - *endp = '\0'; - } - } else - kernMod = NULL; +static time_t +getRegKeyModTime(HKEY hBaseKey, const char *keyPath) +{ + HKEY hConfigKey; + HRESULT rc; + int iSubKey = 0; + time_t modTime = 0, keyModTime; + FILETIME keyLastWriteTime; + char subKeyName[256]; + if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0, KEY_ENUMERATE_SUB_KEYS, + &hConfigKey)) != ERROR_SUCCESS) { + /* TODO: log error message */ + return 0; + } + do { + int subKeyNameSize=256; + if ((rc = RegEnumKeyEx(hConfigKey, iSubKey++, subKeyName, &subKeyNameSize, NULL, NULL, NULL, &keyLastWriteTime)) != ERROR_SUCCESS) { + break; + } + keyModTime = filetimeToTimet(&keyLastWriteTime); + if (modTime < keyModTime) { + modTime = keyModTime; + } + } while (1); + RegCloseKey(hConfigKey); + return modTime; +} - /* Find the start of the optional module options list */ - for (modOptions = endp+1; *modOptions && isspace(*modOptions); - modOptions++); +static void +getRegKeyValue(HKEY hKey, const char *keyPath, const char *valueName, void **data, DWORD* dataLen) +{ + DWORD sizeRequired=*dataLen; + HRESULT hr; + /* Get data length required */ + if ((hr=RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL, NULL, &sizeRequired)) != ERROR_SUCCESS) + { + /* TODO: LOG registry error */ + return; + } + /* adjust data buffer size if necessary */ + if (*dataLen < sizeRequired) + { + *dataLen = sizeRequired; + *data = realloc(*data, sizeRequired); + if (!*data) + { + *dataLen = 0; + /* TODO: LOG OOM ERROR! */ + return; + } + } + /* get data */ + if ((hr=RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL, *data, &sizeRequired)) != ERROR_SUCCESS) + { + /* LOG registry error */ + return; + } +} - if (*modOptions == '[') { - /* move past the opening bracket */ - for (modOptions = modOptions+1; - *modOptions && isspace(*modOptions); - modOptions++); +static void +loadConfigFromRegistry(HKEY hBaseKey, const char *keyPath) +{ + HKEY hConfigKey; + DWORD iSubKey, nSubKeys, maxSubKeyNameLen; + DWORD dataBufferSize, dataSizeRequired; + char *oidStr=NULL, *oid=NULL, *sharedLib=NULL, *kernMod=NULL, *modOptions=NULL; + DWORD oidStrLen=0, oidLen=0, sharedLibLen=0, kernModLen=0, modOptionsLen=0; + HRESULT rc; + + if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0, KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, + &hConfigKey)) != ERROR_SUCCESS) { + /* TODO: log registry error */ + return; + } + + if ((rc = RegQueryInfoKey(hConfigKey, + NULL, /* lpClass */ + NULL, /* lpcClass */ + NULL, /* lpReserved */ + &nSubKeys, + &maxSubKeyNameLen, + NULL, /* lpcMaxClassLen */ + NULL, /* lpcValues */ + NULL, /* lpcMaxValueNameLen */ + NULL, /* lpcMaxValueLen */ + NULL, /* lpcbSecurityDescriptor */ + NULL /* lpftLastWriteTime */ )) != ERROR_SUCCESS) { + goto cleanup; + } + oidStr = malloc(++maxSubKeyNameLen); + if (!oidStr) { + goto cleanup; + } + for (iSubKey=0; iSubKeymech) { + generic_gss_release_oid(&minor, &mechOid); + return; + } + /* + * If that's all, then this is a corrupt entry. Skip it. + */ + if (! *sharedLib) { + generic_gss_release_oid(&minor, &mechOid); + return; + } +#if defined(_WIN32) + sharedPath = sharedLib; +#else + if (sharedLib[0] == '/') + snprintf(sharedPath, sizeof(sharedPath), "%s", sharedLib); + else + snprintf(sharedPath, sizeof(sharedPath), "%s%s", + MECH_LIB_PREFIX, sharedLib); +#endif + /* + * are we creating a new mechanism entry or + * just modifying existing (non loaded) mechanism entry + */ + if (aMech) { /* - * are we creating a new mechanism entry or - * just modifying existing (non loaded) mechanism entry + * delete any old values and set new + * mechNameStr and mech_type are not modified */ - if (aMech) { - /* - * delete any old values and set new - * mechNameStr and mech_type are not modified - */ - if (aMech->kmodName) { - free(aMech->kmodName); - aMech->kmodName = NULL; - } - - if (aMech->optionStr) { - free(aMech->optionStr); - aMech->optionStr = NULL; - } - - if ((tmpStr = strdup(sharedPath)) != NULL) { - if (aMech->uLibName) - free(aMech->uLibName); - aMech->uLibName = tmpStr; - } - - if (kernMod) /* this is an optional parameter */ - aMech->kmodName = strdup(kernMod); - - if (modOptions) /* optional module options */ - aMech->optionStr = strdup(modOptions); - - /* the oid is already set */ - generic_gss_release_oid(&minor, &mechOid); - continue; + if (aMech->kmodName) { + free(aMech->kmodName); + aMech->kmodName = NULL; } - /* adding a new entry */ - aMech = calloc(1, sizeof (struct gss_mech_config)); - if (aMech == NULL) { - generic_gss_release_oid(&minor, &mechOid); - continue; + if (aMech->optionStr) { + free(aMech->optionStr); + aMech->optionStr = NULL; } - aMech->mech_type = mechOid; - aMech->uLibName = strdup(sharedPath); - aMech->mechNameStr = strdup(oidStr); - aMech->freeMech = 0; - /* check if any memory allocations failed - bad news */ - if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) { + if ((tmpStr = strdup(sharedPath)) != NULL) { if (aMech->uLibName) free(aMech->uLibName); - if (aMech->mechNameStr) - free(aMech->mechNameStr); - generic_gss_release_oid(&minor, &mechOid); - free(aMech); - continue; + aMech->uLibName = tmpStr; } - if (kernMod) /* this is an optional parameter */ + + if (kernMod) /* this is an optional parameter */ aMech->kmodName = strdup(kernMod); - if (modOptions) + if (modOptions) /* optional module options */ aMech->optionStr = strdup(modOptions); - /* - * add the new entry to the end of the list - make sure - * that only complete entries are added because other - * threads might currently be searching the list. - */ - tmp = g_mechListTail; - g_mechListTail = aMech; - if (tmp != NULL) - tmp->next = aMech; + /* the oid is already set */ + generic_gss_release_oid(&minor, &mechOid); + return; + } + + /* adding a new entry */ + aMech = calloc(1, sizeof (struct gss_mech_config)); + if (aMech == NULL) { + generic_gss_release_oid(&minor, &mechOid); + return; + } + aMech->mech_type = mechOid; + aMech->uLibName = strdup(sharedPath); + aMech->mechNameStr = strdup(oidStr); + aMech->freeMech = 0; + + /* check if any memory allocations failed - bad news */ + if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) { + if (aMech->uLibName) + free(aMech->uLibName); + if (aMech->mechNameStr) + free(aMech->mechNameStr); + generic_gss_release_oid(&minor, &mechOid); + free(aMech); + return; + } + if (kernMod) /* this is an optional parameter */ + aMech->kmodName = strdup(kernMod); + + if (modOptions) + aMech->optionStr = strdup(modOptions); + /* + * add the new entry to the end of the list - make sure + * that only complete entries are added because other + * threads might currently be searching the list. + */ + tmp = g_mechListTail; + g_mechListTail = aMech; + + if (tmp != NULL) + tmp->next = aMech; + + if (g_mechList == NULL) + g_mechList = aMech; +} - if (g_mechList == NULL) - g_mechList = aMech; - } /* while */ - (void) fclose(confFile); -} /* loadConfigFile */ -- 2.26.2