*************** *** 227,578 **** - void enum_settings_finish(void *handle) - { - struct enumsettings *e = (struct enumsettings *) handle; - RegCloseKey(e->key); - sfree(e); } - static void hostkey_regname(char *buffer, const char *hostname, - int port, const char *keytype) { - int len; - strcpy(buffer, keytype); - strcat(buffer, "@"); - len = strlen(buffer); - len += sprintf(buffer + len, "%d:", port); - mungestr(hostname, buffer + strlen(buffer)); } int verify_host_key(const char *hostname, int port, const char *keytype, const char *key) { - char *otherstr, *regname; - int len; - HKEY rkey; - DWORD readlen; - DWORD type; - int ret, compare; - - len = 1 + strlen(key); - - /* - * Now read a saved key in from the registry and see what it - * says. - */ - otherstr = snewn(len, char); - regname = snewn(3 * (strlen(hostname) + strlen(keytype)) + 15, char); - hostkey_regname(regname, hostname, port, keytype); - if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys", - &rkey) != ERROR_SUCCESS) - return 1; /* key does not exist in registry */ - readlen = len; - ret = RegQueryValueEx(rkey, regname, NULL, &type, otherstr, &readlen); - if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA && - !strcmp(keytype, "rsa")) { - /* - * Key didn't exist. If the key type is RSA, we'll try - * another trick, which is to look up the _old_ key format - * under just the hostname and translate that. - */ - char *justhost = regname + 1 + strcspn(regname, ":"); - char *oldstyle = snewn(len + 10, char); /* safety margin */ - readlen = len; - ret = RegQueryValueEx(rkey, justhost, NULL, &type, - oldstyle, &readlen); - if (ret == ERROR_SUCCESS && type == REG_SZ) { /* - * The old format is two old-style bignums separated by - * a slash. An old-style bignum is made of groups of - * four hex digits: digits are ordered in sensible - * (most to least significant) order within each group, - * but groups are ordered in silly (least to most) - * order within the bignum. The new format is two - * ordinary C-format hex numbers (0xABCDEFG...XYZ, with - * A nonzero except in the special case 0x0, which - * doesn't appear anyway in RSA keys) separated by a - * comma. All hex digits are lowercase in both formats. */ - char *p = otherstr; - char *q = oldstyle; - int i, j; - - for (i = 0; i < 2; i++) { - int ndigits, nwords; - *p++ = '0'; - *p++ = 'x'; - ndigits = strcspn(q, "/"); /* find / or end of string */ - nwords = ndigits / 4; - /* now trim ndigits to remove leading zeros */ - while (q[(ndigits - 1) ^ 3] == '0' && ndigits > 1) - ndigits--; - /* now move digits over to new string */ - for (j = 0; j < ndigits; j++) - p[ndigits - 1 - j] = q[j ^ 3]; - p += ndigits; - q += nwords * 4; - if (*q) { - q++; /* eat the slash */ - *p++ = ','; /* add a comma */ - } - *p = '\0'; /* terminate the string */ - } - /* - * Now _if_ this key matches, we'll enter it in the new - * format. If not, we'll assume something odd went - * wrong, and hyper-cautiously do nothing. - */ - if (!strcmp(otherstr, key)) - RegSetValueEx(rkey, regname, 0, REG_SZ, otherstr, - strlen(otherstr) + 1); - } } - RegCloseKey(rkey); - - compare = strcmp(otherstr, key); - - sfree(otherstr); - sfree(regname); - - if (ret == ERROR_MORE_DATA || - (ret == ERROR_SUCCESS && type == REG_SZ && compare)) - return 2; /* key is different in registry */ - else if (ret != ERROR_SUCCESS || type != REG_SZ) - return 1; /* key does not exist in registry */ - else - return 0; /* key matched OK in registry */ } void store_host_key(const char *hostname, int port, const char *keytype, const char *key) { - char *regname; - HKEY rkey; - regname = snewn(3 * (strlen(hostname) + strlen(keytype)) + 15, char); - 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); - } - /* - * Find the random seed file path and store it in `seedpath'. */ - static void get_seedpath(void) - { - HKEY rkey; - DWORD type, size; - size = sizeof(seedpath); - if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS, &rkey) == - ERROR_SUCCESS) { - int ret = RegQueryValueEx(rkey, "RandSeedFile", - 0, &type, seedpath, &size); - if (ret != ERROR_SUCCESS || type != REG_SZ) - seedpath[0] = '\0'; - RegCloseKey(rkey); - } else - seedpath[0] = '\0'; - if (!seedpath[0]) { - int len, ret; - len = - GetEnvironmentVariable("HOMEDRIVE", seedpath, - sizeof(seedpath)); - 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"); - } } 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); - - if (seedf != INVALID_HANDLE_VALUE) { - while (1) { - char buf[1024]; - DWORD len; - if (ReadFile(seedf, buf, sizeof(buf), &len, NULL) && len) - consumer(buf, len); - else - break; - } - CloseHandle(seedf); } } 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); - - if (seedf != INVALID_HANDLE_VALUE) { - DWORD lenwritten; - - WriteFile(seedf, data, len, &lenwritten, NULL); - CloseHandle(seedf); - } - } - /* - * Recursively delete a registry key and everything under it. */ - static void registry_recursive_remove(HKEY key) - { - DWORD i; - char name[MAX_PATH + 1]; - HKEY subkey; - i = 0; - while (RegEnumKey(key, i, name, sizeof(name)) == ERROR_SUCCESS) { - if (RegOpenKey(key, name, &subkey) == ERROR_SUCCESS) { - registry_recursive_remove(subkey); - RegCloseKey(subkey); } - RegDeleteKey(key, name); } } void cleanup_all(void) { - HKEY key; - int ret; - char name[MAX_PATH + 1]; - /* ------------------------------------------------------------ - * Wipe out the random seed file. - */ - if (!seedpath[0]) - get_seedpath(); - remove(seedpath); - /* ------------------------------------------------------------ - * Destroy all registry information associated with PuTTY. - */ - - /* - * Open the main PuTTY registry key and remove everything in it. - */ - if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS, &key) == - ERROR_SUCCESS) { - registry_recursive_remove(key); - RegCloseKey(key); - } - /* - * Now open the parent key and remove the PuTTY main key. Once - * we've done that, see if the parent key has any other - * children. - */ - if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_PARENT, - &key) == ERROR_SUCCESS) { - RegDeleteKey(key, PUTTY_REG_PARENT_CHILD); - ret = RegEnumKey(key, 0, name, sizeof(name)); - RegCloseKey(key); - /* - * If the parent key had no other children, we must delete - * it in its turn. That means opening the _grandparent_ - * key. - */ - if (ret != ERROR_SUCCESS) { - if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_GPARENT, - &key) == ERROR_SUCCESS) { - RegDeleteKey(key, PUTTY_REG_GPARENT_CHILD); - RegCloseKey(key); - } - } - } - /* - * Now we're done. - */ - } --- 373,628 ---- + void enum_settings_finish(void *handle) { + DIR *dp = (DIR *)handle; + closedir(dp); } + /* + * Lines in the host keys file are of the form + * + * type@port:hostname keydata + * + * e.g. + * + * rsa@22:foovax.example.org 0x23,0x293487364395345345....2343 + */ int verify_host_key(const char *hostname, int port, const char *keytype, const char *key) { + FILE *fp; + char filename[FILENAME_MAX]; + char *line; + int ret; + make_filename(filename, INDEX_HOSTKEYS, NULL); + fp = fopen(filename, "r"); + if (!fp) + return 1; /* key does not exist */ + ret = 1; + while ( (line = fgetline(fp)) ) { + int i; + char *p = line; + char porttext[20]; + line[strcspn(line, "\n")] = '\0'; /* strip trailing newline */ + i = strlen(keytype); + if (strncmp(p, keytype, i)) + goto done; + p += i; + + if (*p != '@') + goto done; + p++; + + sprintf(porttext, "%d", port); + i = strlen(porttext); + if (strncmp(p, porttext, i)) + goto done; + p += i; + + if (*p != ':') + goto done; + p++; + + i = strlen(hostname); + if (strncmp(p, hostname, i)) + goto done; + p += i; + + if (*p != ' ') + goto done; + p++; /* + * Found the key. Now just work out whether it's the right + * one or not. */ + if (!strcmp(p, key)) + ret = 0; /* key matched OK */ + else + ret = 2; /* key mismatch */ + done: + sfree(line); + if (ret != 1) + break; } + fclose(fp); + return ret; } void store_host_key(const char *hostname, int port, const char *keytype, const char *key) { + FILE *rfp, *wfp; + char *newtext, *line; + int headerlen; + char filename[FILENAME_MAX], tmpfilename[FILENAME_MAX]; + newtext = dupprintf("%s@%d:%s %s\n", keytype, port, hostname, key); + headerlen = 1 + strcspn(newtext, " "); /* count the space too */ + /* + * Open both the old file and a new file. + */ + make_filename(tmpfilename, INDEX_HOSTKEYS_TMP, NULL); + wfp = fopen(tmpfilename, "w"); + if (!wfp) { + char dir[FILENAME_MAX]; + + make_filename(dir, INDEX_DIR, NULL); + _mkdir(dir); + wfp = fopen(tmpfilename, "w"); + } + if (!wfp) + return; + make_filename(filename, INDEX_HOSTKEYS, NULL); + rfp = fopen(filename, "r"); + /* + * Copy all lines from the old file to the new one that _don't_ + * involve the same host key identifier as the one we're adding. */ + if (rfp) { + while ( (line = fgetline(rfp)) ) { + if (strncmp(line, newtext, headerlen)) + fputs(line, wfp); + } + fclose(rfp); + } + /* + * Now add the new line at the end. + */ + fputs(newtext, wfp); + fclose(wfp); + _unlink(filename); + rename(tmpfilename, filename); + sfree(newtext); } void read_random_seed(noise_consumer_t consumer) { + int fd; + char fname[FILENAME_MAX]; + make_filename(fname, INDEX_RANDSEED, NULL); + fd = _open(fname, _O_RDONLY); + if (fd) { + char buf[512]; + int ret; + while ( (ret = _read(fd, buf, sizeof(buf))) > 0) + consumer(buf, ret); + _close(fd); } } void write_random_seed(void *data, int len) { + int fd; + char fname[FILENAME_MAX]; + make_filename(fname, INDEX_RANDSEED, NULL); + /* + * Don't truncate the random seed file if it already exists; if + * something goes wrong half way through writing it, it would + * be better to leave the old data there than to leave it empty. */ + fd = _open(fname, _O_CREAT | _O_WRONLY, 0600); + if (fd < 0) { + char dir[FILENAME_MAX]; + make_filename(dir, INDEX_DIR, NULL); + _mkdir(dir); + fd = _open(fname, _O_CREAT | _O_WRONLY, 0600); } + + while (len > 0) { + int ret = _write(fd, data, len); + if (ret <= 0) break; + len -= ret; + data = (char *)data + len; } + + _close(fd); } void cleanup_all(void) { + }