lib/krb5: krb5_get_instance does not work on Windows 7
krb5_get_instance() is meant to ensure that the shared library instance of heimdal loaded by a plugin matches the instance that loaded the plugin. It works by declaring a static C string whose memory address will be used as an instance identifier. If the instance returned from the plugin matches the instance obtain by the code that loads the plugin, then we can conclude the two instances are the same. This doesn't work on Windows 7. When heimdal.dll loads a plugin that is linked to heimdal.dll, the plugin's heimdal.dll is always a new instance. However, the requirement for plugin safety is not that the plugin be the same instance in memory but that they be the same instance on disk. This change loads the path name and version string for the module and generates a hash of those strings as an instance identifier. Change-Id: I1c0651969e9738c5feecb0b323969d13efd4704d
This commit is contained in:

committed by
Nico Williams

parent
1a65611f61
commit
d4c0d34548
@@ -53,7 +53,9 @@ DLLSDKDEPS= \
|
||||
secur32.lib \
|
||||
shell32.lib \
|
||||
dnsapi.lib \
|
||||
shlwapi.lib
|
||||
shlwapi.lib \
|
||||
version.lib
|
||||
|
||||
|
||||
dlllflags=$(dlllflags) /DELAYLOAD:bcrypt.dll
|
||||
DLLSDKDEPS=$(DLLSDKDEPS)\
|
||||
|
@@ -170,13 +170,39 @@ _krb5_plugin_run_f(krb5_context context,
|
||||
* @ingroup krb5_support
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
static uintptr_t
|
||||
djb2(uintptr_t hash, unsigned char *str)
|
||||
{
|
||||
int c;
|
||||
|
||||
while (c = *str++)
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
KRB5_LIB_FUNCTION uintptr_t KRB5_LIB_CALL
|
||||
krb5_get_instance(const char *libname)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char *version;
|
||||
char *name;
|
||||
uintptr_t instance;
|
||||
|
||||
if (win32_getLibraryVersion("heimdal", &name, &version))
|
||||
return 0;
|
||||
instance = djb2(5381, name);
|
||||
instance = djb2(instance, version);
|
||||
free(name);
|
||||
free(version);
|
||||
return instance;
|
||||
#else
|
||||
static const char *instance = "libkrb5";
|
||||
|
||||
if (strcmp(libname, "krb5") == 0)
|
||||
return (uintptr_t)instance;
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@@ -130,6 +130,7 @@ libroken_la_OBJS = \
|
||||
$(OBJ)\warnerr.obj \
|
||||
$(OBJ)\warnx.obj \
|
||||
$(OBJ)\win32_alloc.obj \
|
||||
$(OBJ)\win32_version.obj \
|
||||
$(OBJ)\writev.obj \
|
||||
$(OBJ)\xfree.obj
|
||||
|
||||
|
@@ -1321,6 +1321,10 @@ int ROKEN_LIB_FUNCTION rk_socket(int, int, int);
|
||||
#define EWOULDBLOCK 140
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
||||
win32_getLibraryVersion(const char *libname, char **outname, char **outversion);
|
||||
#endif
|
||||
|
||||
#ifdef SOCKET_WRAPPER_REPLACE
|
||||
#include <socket_wrapper.h>
|
||||
|
128
lib/roken/win32_version.c
Normal file
128
lib/roken/win32_version.c
Normal file
@@ -0,0 +1,128 @@
|
||||
#include <config.h>
|
||||
#include "roken.h"
|
||||
#include <psapi.h>
|
||||
|
||||
static DWORD
|
||||
GetVersionInfo(CHAR *filename, CHAR *szOutput, DWORD dwOutput)
|
||||
{
|
||||
DWORD dwVersionHandle;
|
||||
LPVOID pVersionInfo = 0;
|
||||
DWORD retval = 0;
|
||||
LPDWORD pLangInfo = 0;
|
||||
LPTSTR szVersion = 0;
|
||||
UINT len = 0;
|
||||
TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion");
|
||||
DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle);
|
||||
|
||||
if (!size)
|
||||
return GetLastError();
|
||||
|
||||
pVersionInfo = malloc(size);
|
||||
if (!pVersionInfo)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo);
|
||||
if (retval = GetLastError())
|
||||
goto cleanup;
|
||||
|
||||
VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"),
|
||||
(LPVOID*)&pLangInfo, &len);
|
||||
if (retval = GetLastError())
|
||||
goto cleanup;
|
||||
|
||||
wsprintf(szVerQ,
|
||||
TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
|
||||
LOWORD(*pLangInfo), HIWORD(*pLangInfo));
|
||||
|
||||
VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
|
||||
if (retval = GetLastError()) {
|
||||
/* try again with language 409 since the old binaries were tagged wrong */
|
||||
wsprintf(szVerQ,
|
||||
TEXT("\\StringFileInfo\\0409%04x\\FileVersion"),
|
||||
HIWORD(*pLangInfo));
|
||||
|
||||
VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
|
||||
if (retval = GetLastError())
|
||||
goto cleanup;
|
||||
}
|
||||
snprintf(szOutput, dwOutput, TEXT("%s"), szVersion);
|
||||
szOutput[dwOutput - 1] = 0;
|
||||
|
||||
cleanup:
|
||||
free(pVersionInfo);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
||||
win32_getLibraryVersion(const char *libname, char **outname, char **outversion)
|
||||
{
|
||||
CHAR modVersion[128];
|
||||
HMODULE hMods[1024];
|
||||
HANDLE hProcess;
|
||||
DWORD cbNeeded;
|
||||
unsigned int i;
|
||||
int success = -1;
|
||||
HINSTANCE hPSAPI;
|
||||
DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
|
||||
BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
|
||||
|
||||
if (outversion)
|
||||
*outversion = NULL;
|
||||
if (outname)
|
||||
*outname = NULL;
|
||||
|
||||
hPSAPI = LoadLibrary("psapi");
|
||||
if ( hPSAPI == NULL )
|
||||
return -1;
|
||||
|
||||
if (((FARPROC) pGetModuleFileNameExA =
|
||||
GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
|
||||
((FARPROC) pEnumProcessModules =
|
||||
GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Get a list of all the modules in this process.
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
||||
FALSE, GetCurrentProcessId());
|
||||
|
||||
if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
|
||||
{
|
||||
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
|
||||
{
|
||||
char szModName[2048];
|
||||
|
||||
// Get the full path to the module's file.
|
||||
if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
|
||||
{
|
||||
CHAR checkName[1024];
|
||||
lstrcpy(checkName, szModName);
|
||||
strlwr(checkName);
|
||||
|
||||
if (strstr(checkName, libname)) {
|
||||
if (GetVersionInfo(szModName, modVersion, sizeof(modVersion)) == 0) {
|
||||
success = 0;
|
||||
if (outversion) {
|
||||
*outversion = strdup(modVersion);
|
||||
if (*outversion == NULL)
|
||||
success = -1;
|
||||
}
|
||||
if (outname) {
|
||||
*outname = strdup(szModName);
|
||||
if (*outname == NULL)
|
||||
success = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
|
||||
out:
|
||||
FreeLibrary(hPSAPI);
|
||||
return success;
|
||||
}
|
Reference in New Issue
Block a user