X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/797f6ff3e6da533570a0dc074771d485619e49c8..2b5567cf51478b76b3048939b4803f686c5d41cb:/unix/uxstore.c diff --git a/unix/uxstore.c b/unix/uxstore.c index e12af036..3d2e2412 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -19,7 +19,7 @@ #include "tree234.h" enum { - INDEX_DIR, INDEX_HOSTKEYS, INDEX_RANDSEED, + INDEX_DIR, INDEX_HOSTKEYS, INDEX_HOSTKEYS_TMP, INDEX_RANDSEED, INDEX_SESSIONDIR, INDEX_SESSION, }; @@ -98,6 +98,7 @@ static void make_filename(char *filename, int index, const char *subname) index == INDEX_DIR ? "/.putty" : index == INDEX_SESSIONDIR ? "/.putty/sessions" : index == INDEX_HOSTKEYS ? "/.putty/sshhostkeys" : + index == INDEX_HOSTKEYS_TMP ? "/.putty/sshhostkeys.tmp" : index == INDEX_RANDSEED ? "/.putty/randomseed" : "/.putty/ERROR", FILENAME_MAX - len); } @@ -127,13 +128,6 @@ static char *fgetline(FILE *fp) return ret; } -/* - * For the moment, the only existing Unix utility is pterm and that - * has no GUI configuration at all, so our write routines need do - * nothing. Eventually I suppose these will read and write an rc - * file somewhere or other. - */ - void *open_settings_w(const char *sessionname, char **errmsg) { char filename[FILENAME_MAX]; @@ -188,6 +182,7 @@ void close_settings_w(void *handle) * PuTTY's inbuilt defaults, but that the disk files will then * override those. This isn't optimal, but it's the best I can * immediately work out. + * FIXME: the above comment is a bit out of date. Did it happen? */ struct keyval { @@ -494,32 +489,55 @@ int verify_host_key(const char *hostname, int port, break; } + fclose(fp); return ret; } void store_host_key(const char *hostname, int port, const char *keytype, const char *key) { - FILE *fp; - int fd; - char filename[FILENAME_MAX]; + FILE *rfp, *wfp; + char *newtext, *line; + int headerlen; + char filename[FILENAME_MAX], tmpfilename[FILENAME_MAX]; - make_filename(filename, INDEX_HOSTKEYS, NULL); - fd = open(filename, O_CREAT | O_APPEND | O_RDWR, 0600); - if (fd < 0) { - char dir[FILENAME_MAX]; + newtext = dupprintf("%s@%d:%s %s\n", keytype, port, hostname, key); + headerlen = 1 + strcspn(newtext, " "); /* count the space too */ - make_filename(dir, INDEX_DIR, NULL); - mkdir(dir, 0700); - fd = open(filename, O_CREAT | O_APPEND | O_RDWR, 0600); + /* + * Open both the old file and a new file. + */ + make_filename(filename, INDEX_HOSTKEYS, NULL); + rfp = fopen(filename, "r"); + if (!rfp) + return; + make_filename(tmpfilename, INDEX_HOSTKEYS_TMP, NULL); + wfp = fopen(tmpfilename, "w"); + if (!wfp) { + fclose(rfp); + return; } - if (fd < 0) { - perror(filename); - exit(1); + + /* + * 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. + */ + while ( (line = fgetline(rfp)) ) { + if (strncmp(line, newtext, headerlen)) + fputs(line, wfp); } - fp = fdopen(fd, "a"); - fprintf(fp, "%s@%d:%s %s\n", keytype, port, hostname, key); - fclose(fp); + + /* + * Now add the new line at the end. + */ + fputs(newtext, wfp); + + fclose(rfp); + fclose(wfp); + + rename(tmpfilename, filename); + + sfree(newtext); } void read_random_seed(noise_consumer_t consumer)