- if (error_abort) {
- /* closing p[0] on timeout causes the entropy command to
- * SIGPIPE. Take whatever output we got, and mark this command
- * as slow */
- debug2("Command '%s' timed out", src->cmdstring);
- src->sticky_badness *= 2;
- src->badness = src->sticky_badness;
- return(total_bytes_read);
- }
-
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status)==0) {
- return(total_bytes_read);
- } else {
- debug2("Command '%s' exit status was %d", src->cmdstring,
- WEXITSTATUS(status));
- src->badness = src->sticky_badness = 128;
- return (0.0);
- }
- } else if (WIFSIGNALED(status)) {
- debug2("Command '%s' returned on uncaught signal %d !", src->cmdstring,
- status);
- src->badness = src->sticky_badness = 128;
- return(0.0);
- } else
- return(0.0);
-}
-
-/*
- * prng seedfile functions
- */
-int
-prng_check_seedfile(char *filename) {
-
- struct stat st;
-
- /* FIXME raceable: eg replace seed between this stat and subsequent open */
- /* Not such a problem because we don't trust the seed file anyway */
- if (lstat(filename, &st) == -1) {
- /* Give up on hard errors */
- if (errno != ENOENT)
- debug("WARNING: Couldn't stat random seed file \"%s\": %s",
- filename, strerror(errno));
-
- return(0);
- }
-
- /* regular file? */
- if (!S_ISREG(st.st_mode))
- fatal("PRNG seedfile %.100s is not a regular file", filename);
-
- /* mode 0600, owned by root or the current user? */
- if (((st.st_mode & 0177) != 0) || !(st.st_uid == original_uid)) {
- debug("WARNING: PRNG seedfile %.100s must be mode 0600, owned by uid %d",
- filename, getuid());
- return(0);
- }
-
- return(1);
-}
-
-void
-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);
-}