X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/8dacc30e3a1bd57526c21b701383f69ef93a6703..0980c4f28e5909a05be74af88732fddd7086f2f6:/unix/uxstore.c diff --git a/unix/uxstore.c b/unix/uxstore.c index b049c285..85d72ca7 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include #include #include @@ -17,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, }; @@ -27,7 +29,7 @@ static char *mungestr(const char *in) { char *out, *ret; - if (!in) + if (!in || !*in) in = "Default Settings"; ret = out = snewn(3*strlen(in)+1, char); @@ -83,6 +85,8 @@ static void make_filename(char *filename, int index, const char *subname) char *home; int len; home = getenv("HOME"); + if (!home) + home="/"; strncpy(filename, home, FILENAME_MAX); len = strlen(filename); if (index == INDEX_SESSION) { @@ -96,60 +100,39 @@ 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); } filename[FILENAME_MAX-1] = '\0'; } -/* - * Read an entire line of text from a file. Return a buffer - * malloced to be as big as necessary (caller must free). - */ -static char *fgetline(FILE *fp) -{ - char *ret = snewn(512, char); - int size = 512, len = 0; - while (fgets(ret + len, size - len, fp)) { - len += strlen(ret + len); - if (ret[len-1] == '\n') - break; /* got a newline, we're done */ - size = len + 512; - ret = sresize(ret, size, char); - } - if (len == 0) { /* first fgets returned NULL */ - sfree(ret); - return NULL; - } - ret[len] = '\0'; - 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) +void *open_settings_w(const char *sessionname, char **errmsg) { char filename[FILENAME_MAX]; FILE *fp; + *errmsg = NULL; + /* - * Start by making sure the sessions subdir exists. Ignore the - * error return from mkdir since it's perfectly likely to be - * `already exists', and any other error will trip us up later - * on so there's no real need to catch it now. + * Start by making sure the .putty directory and its sessions + * subdir actually exist. Ignore error returns from mkdir since + * they're perfectly likely to be `already exists', and any + * other error will trip us up later on so there's no real need + * to catch it now. */ + make_filename(filename, INDEX_DIR, sessionname); + mkdir(filename, 0700); make_filename(filename, INDEX_SESSIONDIR, sessionname); mkdir(filename, 0700); make_filename(filename, INDEX_SESSION, sessionname); fp = fopen(filename, "w"); - if (!fp) - return NULL; /* can't open */ + if (!fp) { + *errmsg = dupprintf("Unable to create %s: %s", + filename, strerror(errno)); + return NULL; /* can't open */ + } return fp; } @@ -178,6 +161,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 { @@ -484,32 +468,60 @@ 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(tmpfilename, INDEX_HOSTKEYS_TMP, NULL); + wfp = fopen(tmpfilename, "w"); + if (!wfp) { + char dir[FILENAME_MAX]; + + make_filename(dir, INDEX_DIR, NULL); + mkdir(dir, 0700); + wfp = fopen(tmpfilename, "w"); } - if (fd < 0) { - perror(filename); - exit(1); + 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); } - 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(wfp); + + rename(tmpfilename, filename); + + sfree(newtext); } void read_random_seed(noise_consumer_t consumer)