+prng_write_seedfile(void) {
+ int fd;
+ char seed[1024];
+ char filename[1024];
+ struct passwd *pw;
+
+ /* Don't bother if we have already saved a seed */
+ if (prng_seed_saved)
+ return;
+
+ setuid(original_uid);
+
+ prng_seed_saved = 1;
+
+ pw = getpwuid(original_uid);
+ if (pw == NULL)
+ fatal("Couldn't get password entry for current user (%i): %s",
+ original_uid, strerror(errno));
+
+ /* Try to ensure that the parent directory is there */
+ snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
+ _PATH_SSH_USER_DIR);
+ mkdir(filename, 0700);
+
+ snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
+ SSH_PRNG_SEED_FILE);
+
+ debug("writing PRNG seed to file %.100s", filename);
+
+ RAND_bytes(seed, sizeof(seed));
+
+ /* Don't care if the seed doesn't exist */
+ prng_check_seedfile(filename);
+
+ if ((fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0600)) == -1) {
+ debug("WARNING: couldn't access PRNG seedfile %.100s (%.100s)",
+ filename, strerror(errno));
+ } else {
+ if (atomicio(write, fd, &seed, sizeof(seed)) != sizeof(seed))
+ fatal("problem writing PRNG seedfile %.100s (%.100s)", filename,
+ strerror(errno));
+
+ close(fd);
+ }
+}
+
+void
+prng_read_seedfile(void) {
+ int fd;
+ char seed[1024];
+ char filename[1024];
+ struct passwd *pw;
+
+ pw = getpwuid(original_uid);
+ if (pw == NULL)
+ fatal("Couldn't get password entry for current user (%i): %s",
+ original_uid, strerror(errno));
+
+ snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
+ SSH_PRNG_SEED_FILE);
+
+ debug("loading PRNG seed from file %.100s", filename);
+
+ if (!prng_check_seedfile(filename)) {
+ verbose("Random seed file not found or not valid, ignoring.");
+ return;
+ }
+
+ /* open the file and read in the seed */
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ fatal("could not open PRNG seedfile %.100s (%.100s)", filename,
+ strerror(errno));
+
+ if (atomicio(read, fd, &seed, sizeof(seed)) != sizeof(seed)) {
+ verbose("invalid or short read from PRNG seedfile %.100s - ignoring",
+ filename);
+ memset(seed, '\0', sizeof(seed));
+ }
+ close(fd);
+
+ /* stir in the seed, with estimated entropy zero */
+ RAND_add(&seed, sizeof(seed), 0.0);
+}
+
+
+/*
+ * entropy command initialisation functions
+ */
+int
+prng_read_commands(char *cmdfilename)
+{
+ FILE *f;
+ char *cp;
+ char line[1024];
+ char cmd[1024];
+ char path[256];
+ int linenum;
+ int num_cmds = 64;
+ int cur_cmd = 0;
+ double est;
+ entropy_source_t *entcmd;
+
+ f = fopen(cmdfilename, "r");
+ if (!f) {
+ fatal("couldn't read entropy commands file %.100s: %.100s",
+ cmdfilename, strerror(errno));
+ }
+
+ entcmd = (entropy_source_t *)xmalloc(num_cmds * sizeof(entropy_source_t));
+ memset(entcmd, '\0', num_cmds * sizeof(entropy_source_t));
+
+ /* Read in file */
+ linenum = 0;
+ while (fgets(line, sizeof(line), f)) {
+ int arg;
+ char *argv;
+
+ linenum++;
+
+ /* skip leading whitespace, test for blank line or comment */
+ cp = line + strspn(line, WHITESPACE);
+ if ((*cp == 0) || (*cp == '#'))
+ continue; /* done with this line */
+
+ /* First non-whitespace char should be double quote delimiting */
+ /* commandline */
+ if (*cp != '"') {
+ error("bad entropy command, %.100s line %d", cmdfilename,
+ linenum);
+ continue;
+ }
+
+ /* first token, command args (incl. argv[0]) in double quotes */
+ cp = strtok(cp, "\"");
+ if (cp == NULL) {
+ error("missing or bad command string, %.100s line %d -- ignored",
+ cmdfilename, linenum);
+ continue;
+ }
+ strlcpy(cmd, cp, sizeof(cmd));
+
+ /* second token, full command path */
+ if ((cp = strtok(NULL, WHITESPACE)) == NULL) {
+ error("missing command path, %.100s line %d -- ignored",
+ cmdfilename, linenum);
+ continue;
+ }
+
+ /* did configure mark this as dead? */
+ if (strncmp("undef", cp, 5) == 0)
+ continue;
+
+ strlcpy(path, cp, sizeof(path));
+
+ /* third token, entropy rate estimate for this command */
+ if ((cp = strtok(NULL, WHITESPACE)) == NULL) {
+ error("missing entropy estimate, %.100s line %d -- ignored",
+ cmdfilename, linenum);
+ continue;
+ }
+ est = strtod(cp, &argv);
+
+ /* end of line */
+ if ((cp = strtok(NULL, WHITESPACE)) != NULL) {
+ error("garbage at end of line %d in %.100s -- ignored", linenum,
+ cmdfilename);
+ continue;
+ }
+
+ /* save the command for debug messages */
+ entcmd[cur_cmd].cmdstring = xstrdup(cmd);
+
+ /* split the command args */
+ cp = strtok(cmd, WHITESPACE);
+ arg = 0;
+ argv = NULL;
+ do {
+ char *s = (char*)xmalloc(strlen(cp) + 1);
+ strncpy(s, cp, strlen(cp) + 1);
+ entcmd[cur_cmd].args[arg] = s;
+ arg++;
+ } while ((arg < 5) && (cp = strtok(NULL, WHITESPACE)));
+
+ if (strtok(NULL, WHITESPACE))
+ error("ignored extra command elements (max 5), %.100s line %d",
+ cmdfilename, linenum);
+
+ /* Copy the command path and rate estimate */
+ entcmd[cur_cmd].path = xstrdup(path);
+ entcmd[cur_cmd].rate = est;
+
+ /* Initialise other values */
+ entcmd[cur_cmd].sticky_badness = 1;
+
+ cur_cmd++;
+
+ /* If we've filled the array, reallocate it twice the size */
+ /* Do this now because even if this we're on the last command,
+ we need another slot to mark the last entry */
+ if (cur_cmd == num_cmds) {
+ num_cmds *= 2;
+ entcmd = xrealloc(entcmd, num_cmds * sizeof(entropy_source_t));
+ }
+ }
+
+ /* zero the last entry */
+ memset(&entcmd[cur_cmd], '\0', sizeof(entropy_source_t));
+
+ /* trim to size */
+ entropy_sources = xrealloc(entcmd, (cur_cmd+1) * sizeof(entropy_source_t));
+
+ debug("Loaded %d entropy commands from %.100s", cur_cmd, cmdfilename);
+
+ return (cur_cmd >= MIN_ENTROPY_SOURCES);
+}
+
+/*
+ * Write a keyfile at exit
+ */
+void
+prng_seed_cleanup(void *junk)