X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/2d3f15fac22aad183784edf0a378e7c4229cd238..8f5f26d24e18e267dd56e8c0b7d856027f63e41c:/windows/winstore.c diff --git a/windows/winstore.c b/windows/winstore.c index 743283f6..0e7638f5 100644 --- a/windows/winstore.c +++ b/windows/winstore.c @@ -9,12 +9,24 @@ #include "putty.h" #include "storage.h" -static const char *const puttystr = PUTTY_REG_POS "\\Sessions"; +#include +#ifndef CSIDL_APPDATA +#define CSIDL_APPDATA 0x001a +#endif +#ifndef CSIDL_LOCAL_APPDATA +#define CSIDL_LOCAL_APPDATA 0x001c +#endif -static char seedpath[2 * MAX_PATH + 10] = "\0"; +static const char *const puttystr = PUTTY_REG_POS "\\Sessions"; static const char hex[16] = "0123456789ABCDEF"; +static int tried_shgetfolderpath = FALSE; +static HMODULE shell32_module = NULL; +typedef HRESULT (WINAPI *p_SHGetFolderPath_t) + (HWND, int, HANDLE, DWORD, LPTSTR); +static p_SHGetFolderPath_t p_SHGetFolderPath = NULL; + static void mungestr(const char *in, char *out) { int candot = 0; @@ -104,7 +116,7 @@ void write_setting_i(void *handle, const char *key, int value) { if (handle) RegSetValueEx((HKEY) handle, key, 0, REG_DWORD, - (CONST BYTE *) & value, sizeof(value)); + (CONST BYTE *) &value, sizeof(value)); } void close_settings_w(void *handle) @@ -157,7 +169,7 @@ int read_setting_i(void *handle, const char *key, int defvalue) if (!handle || RegQueryValueEx((HKEY) handle, key, 0, &type, - (BYTE *) & val, &size) != ERROR_SUCCESS || + (BYTE *) &val, &size) != ERROR_SUCCESS || size != sizeof(val) || type != REG_DWORD) return defvalue; else @@ -406,22 +418,61 @@ void store_host_key(const char *hostname, int port, hostkey_regname(regname, hostname, port, keytype); if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys", - &rkey) != ERROR_SUCCESS) - return; /* key does not exist in registry */ - RegSetValueEx(rkey, regname, 0, REG_SZ, key, strlen(key) + 1); - RegCloseKey(rkey); + &rkey) == ERROR_SUCCESS) { + RegSetValueEx(rkey, regname, 0, REG_SZ, key, strlen(key) + 1); + RegCloseKey(rkey); + } /* else key does not exist in registry */ + + sfree(regname); } /* - * Find the random seed file path and store it in `seedpath'. + * Open (or delete) the random seed file. */ -static void get_seedpath(void) +enum { DEL, OPEN_R, OPEN_W }; +static int try_random_seed(char const *path, int action, HANDLE *ret) +{ + if (action == DEL) { + remove(path); + *ret = INVALID_HANDLE_VALUE; + return FALSE; /* so we'll do the next ones too */ + } + + *ret = CreateFile(path, + action == OPEN_W ? GENERIC_WRITE : GENERIC_READ, + action == OPEN_W ? 0 : (FILE_SHARE_READ | + FILE_SHARE_WRITE), + NULL, + action == OPEN_W ? CREATE_ALWAYS : OPEN_EXISTING, + action == OPEN_W ? FILE_ATTRIBUTE_NORMAL : 0, + NULL); + + return (*ret != INVALID_HANDLE_VALUE); +} + +static HANDLE access_random_seed(int action) { HKEY rkey; DWORD type, size; + HANDLE rethandle; + char seedpath[2 * MAX_PATH + 10] = "\0"; - size = sizeof(seedpath); + /* + * Iterate over a selection of possible random seed paths until + * we find one that works. + * + * We do this iteration separately for reading and writing, + * meaning that we will automatically migrate random seed files + * if a better location becomes available (by reading from the + * best location in which we actually find one, and then + * writing to the best location in which we can _create_ one). + */ + /* + * First, try the location specified by the user in the + * Registry, if any. + */ + size = sizeof(seedpath); if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS, &rkey) == ERROR_SUCCESS) { int ret = RegQueryValueEx(rkey, "RandSeedFile", @@ -429,10 +480,51 @@ static void get_seedpath(void) if (ret != ERROR_SUCCESS || type != REG_SZ) seedpath[0] = '\0'; RegCloseKey(rkey); - } else - seedpath[0] = '\0'; - if (!seedpath[0]) { + if (*seedpath && try_random_seed(seedpath, action, &rethandle)) + return rethandle; + } + + /* + * Next, try the user's local Application Data directory, + * followed by their non-local one. This is found using the + * SHGetFolderPath function, which won't be present on all + * versions of Windows. + */ + if (!tried_shgetfolderpath) { + /* This is likely only to bear fruit on systems with IE5+ + * installed, or WinMe/2K+. There is some faffing with + * SHFOLDER.DLL we could do to try to find an equivalent + * on older versions of Windows if we cared enough. + * However, the invocation below requires IE5+ anyway, + * so stuff that. */ + shell32_module = LoadLibrary("SHELL32.DLL"); + if (shell32_module) { + p_SHGetFolderPath = (p_SHGetFolderPath_t) + GetProcAddress(shell32_module, "SHGetFolderPathA"); + } + } + if (p_SHGetFolderPath) { + if (SUCCEEDED(p_SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, + NULL, SHGFP_TYPE_CURRENT, seedpath))) { + strcat(seedpath, "\\PUTTY.RND"); + if (try_random_seed(seedpath, action, &rethandle)) + return rethandle; + } + + if (SUCCEEDED(p_SHGetFolderPath(NULL, CSIDL_APPDATA, + NULL, SHGFP_TYPE_CURRENT, seedpath))) { + strcat(seedpath, "\\PUTTY.RND"); + if (try_random_seed(seedpath, action, &rethandle)) + return rethandle; + } + } + + /* + * Failing that, try %HOMEDRIVE%%HOMEPATH% as a guess at the + * user's home directory. + */ + { int len, ret; len = @@ -441,25 +533,30 @@ static void get_seedpath(void) ret = GetEnvironmentVariable("HOMEPATH", seedpath + len, sizeof(seedpath) - len); - if (ret == 0) { /* probably win95; store in \WINDOWS */ - GetWindowsDirectory(seedpath, sizeof(seedpath)); - len = strlen(seedpath); - } else - len += ret; - strcpy(seedpath + len, "\\PUTTY.RND"); + if (ret != 0) { + strcat(seedpath, "\\PUTTY.RND"); + if (try_random_seed(seedpath, action, &rethandle)) + return rethandle; + } } + + /* + * And finally, fall back to C:\WINDOWS. + */ + GetWindowsDirectory(seedpath, sizeof(seedpath)); + strcat(seedpath, "\\PUTTY.RND"); + if (try_random_seed(seedpath, action, &rethandle)) + return rethandle; + + /* + * If even that failed, give up. + */ + return INVALID_HANDLE_VALUE; } void read_random_seed(noise_consumer_t consumer) { - HANDLE seedf; - - if (!seedpath[0]) - get_seedpath(); - - seedf = CreateFile(seedpath, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, NULL); + HANDLE seedf = access_random_seed(OPEN_R); if (seedf != INVALID_HANDLE_VALUE) { while (1) { @@ -477,13 +574,7 @@ void read_random_seed(noise_consumer_t consumer) void write_random_seed(void *data, int len) { - HANDLE seedf; - - if (!seedpath[0]) - get_seedpath(); - - seedf = CreateFile(seedpath, GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE seedf = access_random_seed(OPEN_W); if (seedf != INVALID_HANDLE_VALUE) { DWORD lenwritten; @@ -519,11 +610,10 @@ void cleanup_all(void) char name[MAX_PATH + 1]; /* ------------------------------------------------------------ - * Wipe out the random seed file. + * Wipe out the random seed file, in all of its possible + * locations. */ - if (!seedpath[0]) - get_seedpath(); - remove(seedpath); + access_random_seed(DEL); /* ------------------------------------------------------------ * Destroy all registry information associated with PuTTY.