#include <assert.h>
#include <errno.h>
#include <ctype.h>
+#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include "storage.h"
#include "tree234.h"
+#ifdef PATH_MAX
+#define FNLEN PATH_MAX
+#else
+#define FNLEN 1024 /* XXX */
+#endif
+
enum {
- INDEX_DIR, INDEX_HOSTKEYS, INDEX_RANDSEED,
+ INDEX_DIR, INDEX_HOSTKEYS, INDEX_HOSTKEYS_TMP, INDEX_RANDSEED,
INDEX_SESSIONDIR, INDEX_SESSION,
};
char *home;
int len;
home = getenv("HOME");
- strncpy(filename, home, FILENAME_MAX);
+ if (!home)
+ home="/";
+ strncpy(filename, home, FNLEN);
len = strlen(filename);
if (index == INDEX_SESSION) {
char *munged = mungestr(subname);
char *fn = dupprintf("/.putty/sessions/%s", munged);
- strncpy(filename + len, fn, FILENAME_MAX - len);
+ strncpy(filename + len, fn, FNLEN - len);
sfree(fn);
sfree(munged);
} else {
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;
+ "/.putty/ERROR", FNLEN - len);
}
- ret[len] = '\0';
- return ret;
+ filename[FNLEN-1] = '\0';
}
void *open_settings_w(const char *sessionname, char **errmsg)
{
- char filename[FILENAME_MAX];
+ char filename[FNLEN];
FILE *fp;
*errmsg = NULL;
void *open_settings_r(const char *sessionname)
{
- char filename[FILENAME_MAX];
+ char filename[FNLEN];
FILE *fp;
char *line;
tree234 *ret;
void del_settings(const char *sessionname)
{
- char filename[FILENAME_MAX];
+ char filename[FNLEN];
make_filename(filename, INDEX_SESSION, sessionname);
unlink(filename);
}
void *enum_settings_start(void)
{
DIR *dp;
- char filename[FILENAME_MAX];
+ char filename[FNLEN];
make_filename(filename, INDEX_SESSIONDIR, NULL);
dp = opendir(filename);
DIR *dp = (DIR *)handle;
struct dirent *de;
struct stat st;
- char fullpath[FILENAME_MAX];
+ char fullpath[FNLEN];
int len;
char *unmunged;
len = strlen(fullpath);
while ( (de = readdir(dp)) != NULL ) {
- if (len < FILENAME_MAX) {
+ if (len < FNLEN) {
fullpath[len] = '/';
- strncpy(fullpath+len+1, de->d_name, FILENAME_MAX-(len+1));
- fullpath[FILENAME_MAX-1] = '\0';
+ strncpy(fullpath+len+1, de->d_name, FNLEN-(len+1));
+ fullpath[FNLEN-1] = '\0';
}
if (stat(fullpath, &st) < 0 || !S_ISREG(st.st_mode))
const char *keytype, const char *key)
{
FILE *fp;
- char filename[FILENAME_MAX];
+ char filename[FNLEN];
char *line;
int 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[FNLEN], tmpfilename[FNLEN];
- 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[FNLEN];
+
+ 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)
{
int fd;
- char fname[FILENAME_MAX];
+ char fname[FNLEN];
make_filename(fname, INDEX_RANDSEED, NULL);
fd = open(fname, O_RDONLY);
void write_random_seed(void *data, int len)
{
int fd;
- char fname[FILENAME_MAX];
+ char fname[FNLEN];
make_filename(fname, INDEX_RANDSEED, NULL);
/*
*/
fd = open(fname, O_CREAT | O_WRONLY, 0600);
if (fd < 0) {
- char dir[FILENAME_MAX];
+ char dir[FNLEN];
make_filename(dir, INDEX_DIR, NULL);
mkdir(dir, 0700);