aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/entropy/unix_procs/es_unix.cpp119
-rw-r--r--src/entropy/unix_procs/es_unix.h39
-rw-r--r--src/entropy/unix_procs/info.txt14
-rw-r--r--src/entropy/unix_procs/unix_cmd.cpp246
-rw-r--r--src/entropy/unix_procs/unix_cmd.h77
-rw-r--r--src/entropy/unix_procs/unix_proc_sources.cpp65
-rw-r--r--src/entropy/unix_procs/unix_procs.cpp277
-rw-r--r--src/entropy/unix_procs/unix_procs.h83
-rw-r--r--src/entropy/unix_procs/unix_src.cpp65
9 files changed, 429 insertions, 556 deletions
diff --git a/src/entropy/unix_procs/es_unix.cpp b/src/entropy/unix_procs/es_unix.cpp
deleted file mode 100644
index 1c6b53ede..000000000
--- a/src/entropy/unix_procs/es_unix.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
-* Unix EntropySource
-* (C) 1999-2009 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/es_unix.h>
-#include <botan/internal/unix_cmd.h>
-#include <botan/parsing.h>
-#include <algorithm>
-
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-#include <unistd.h>
-
-namespace Botan {
-
-namespace {
-
-/**
-* Sort ordering by priority
-*/
-bool Unix_Program_Cmp(const Unix_Program& a, const Unix_Program& b)
- {
- if(a.priority == b.priority)
- return (a.name_and_args < b.name_and_args);
-
- return (a.priority < b.priority);
- }
-
-}
-
-/**
-* Unix_EntropySource Constructor
-*/
-Unix_EntropySource::Unix_EntropySource(const std::vector<std::string>& path) :
- PATH(path)
- {
- std::vector<Unix_Program> default_sources = get_default_sources();
- add_sources(&default_sources[0], default_sources.size());
- }
-
-/**
-* Add sources to the list
-*/
-void Unix_EntropySource::add_sources(const Unix_Program srcs[], size_t count)
- {
- sources.insert(sources.end(), srcs, srcs + count);
- std::sort(sources.begin(), sources.end(), Unix_Program_Cmp);
- }
-
-/**
-* Poll for entropy on a generic Unix system, first by grabbing various
-* statistics (stat on common files, getrusage, etc), and then, if more
-* is required, by exec'ing various programs like uname and rpcinfo and
-* reading the output.
-*/
-void Unix_EntropySource::poll(Entropy_Accumulator& accum)
- {
- const char* stat_targets[] = {
- "/",
- "/tmp",
- "/var/tmp",
- "/usr",
- "/home",
- "/etc/passwd",
- ".",
- "..",
- nullptr };
-
- for(size_t i = 0; stat_targets[i]; i++)
- {
- struct stat statbuf;
- clear_mem(&statbuf, 1);
- ::stat(stat_targets[i], &statbuf);
- accum.add(&statbuf, sizeof(statbuf), .005);
- }
-
- accum.add(::getpid(), 0);
- accum.add(::getppid(), 0);
- accum.add(::getuid(), 0);
- accum.add(::getgid(), 0);
- accum.add(::getpgrp(), 0);
-
- struct ::rusage usage;
- ::getrusage(RUSAGE_SELF, &usage);
- accum.add(usage, .005);
-
- ::getrusage(RUSAGE_CHILDREN, &usage);
- accum.add(usage, .005);
-
- const size_t MINIMAL_WORKING = 16;
-
- secure_vector<byte>& io_buffer = accum.get_io_buffer(4*1024);
-
- for(size_t i = 0; i != sources.size(); i++)
- {
- DataSource_Command pipe(sources[i].name_and_args, PATH);
-
- size_t got_from_src = 0;
-
- while(!pipe.end_of_data())
- {
- size_t got_this_loop = pipe.read(&io_buffer[0], io_buffer.size());
- got_from_src += got_this_loop;
-
- accum.add(&io_buffer[0], got_this_loop, .005);
- }
-
- sources[i].working = (got_from_src >= MINIMAL_WORKING) ? true : false;
-
- if(accum.polling_goal_achieved())
- break;
- }
- }
-
-}
diff --git a/src/entropy/unix_procs/es_unix.h b/src/entropy/unix_procs/es_unix.h
deleted file mode 100644
index 9c217ebe7..000000000
--- a/src/entropy/unix_procs/es_unix.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-* Unix EntropySource
-* (C) 1999-2009 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_ENTROPY_SRC_UNIX_H__
-#define BOTAN_ENTROPY_SRC_UNIX_H__
-
-#include <botan/entropy_src.h>
-#include <botan/internal/unix_cmd.h>
-#include <vector>
-
-namespace Botan {
-
-/**
-* Unix Entropy Source
-*/
-class Unix_EntropySource : public EntropySource
- {
- public:
- std::string name() const { return "Unix Entropy Source"; }
-
- void poll(Entropy_Accumulator& accum);
-
- void add_sources(const Unix_Program[], size_t);
- Unix_EntropySource(const std::vector<std::string>& path);
- private:
- static std::vector<Unix_Program> get_default_sources();
- void fast_poll(Entropy_Accumulator& accum);
-
- const std::vector<std::string> PATH;
- std::vector<Unix_Program> sources;
- };
-
-}
-
-#endif
diff --git a/src/entropy/unix_procs/info.txt b/src/entropy/unix_procs/info.txt
index d2a15f13d..dc086a5fa 100644
--- a/src/entropy/unix_procs/info.txt
+++ b/src/entropy/unix_procs/info.txt
@@ -1,14 +1,12 @@
-define ENTROPY_SRC_UNIX
+define ENTROPY_SRC_UNIX_PROCESS_RUNNER
<source>
-es_unix.cpp
-unix_cmd.cpp
-unix_src.cpp
+unix_procs.cpp
+unix_proc_sources.cpp
</source>
<header:internal>
-es_unix.h
-unix_cmd.h
+unix_procs.h
</header:internal>
<os>
@@ -25,7 +23,3 @@ qnx
solaris
tru64
</os>
-
-<requires>
-filters
-</requires>
diff --git a/src/entropy/unix_procs/unix_cmd.cpp b/src/entropy/unix_procs/unix_cmd.cpp
deleted file mode 100644
index 07386dbc5..000000000
--- a/src/entropy/unix_procs/unix_cmd.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
-* Unix Command Execution
-* (C) 1999-2007 Jack Lloyd
-* 2012 Markus Wanner
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/unix_cmd.h>
-#include <botan/parsing.h>
-#include <botan/exceptn.h>
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-
-namespace Botan {
-
-namespace {
-
-/**
-* Attempt to execute the command
-*/
-void do_exec(const std::vector<std::string>& arg_list,
- const std::vector<std::string>& paths)
- {
- const size_t args = arg_list.size() - 1;
-
- const char* arg1 = (args >= 1) ? arg_list[1].c_str() : nullptr;
- const char* arg2 = (args >= 2) ? arg_list[2].c_str() : nullptr;
- const char* arg3 = (args >= 3) ? arg_list[3].c_str() : nullptr;
- const char* arg4 = (args >= 4) ? arg_list[4].c_str() : nullptr;
-
- for(size_t j = 0; j != paths.size(); j++)
- {
- const std::string full_path = paths[j] + "/" + arg_list[0];
- const char* fsname = full_path.c_str();
-
- ::execl(fsname, fsname, arg1, arg2, arg3, arg4, NULL);
- }
- }
-
-}
-
-/**
-* Local information about the pipe
-*/
-struct pipe_wrapper
- {
- int fd;
- pid_t pid;
-
- pipe_wrapper(int f, pid_t p) : fd(f), pid(p) {}
- ~pipe_wrapper() { ::close(fd); }
- };
-
-/**
-* Read from the pipe
-*/
-size_t DataSource_Command::read(byte buf[], size_t length)
- {
- if(end_of_data())
- return 0;
-
- fd_set set;
- FD_ZERO(&set);
- FD_SET(pipe->fd, &set);
-
- struct ::timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = MAX_BLOCK_USECS;
-
- ssize_t got = 0;
- if(::select(pipe->fd + 1, &set, nullptr, nullptr, &tv) == 1)
- {
- if(FD_ISSET(pipe->fd, &set))
- got = ::read(pipe->fd, buf, length);
- }
-
- if(got <= 0)
- {
- shutdown_pipe();
- return 0;
- }
-
- bytes_read += got;
- return static_cast<size_t>(got);
- }
-
-/**
-* Peek at the pipe contents
-*/
-size_t DataSource_Command::peek(byte[], size_t, size_t) const
- {
- if(end_of_data())
- throw Invalid_State("DataSource_Command: Cannot peek when out of data");
- throw Stream_IO_Error("Cannot peek/seek on a command pipe");
- }
-
-/**
-* Check if we reached EOF
-*/
-bool DataSource_Command::end_of_data() const
- {
- return (pipe) ? false : true;
- }
-
-size_t DataSource_Command::get_bytes_read() const
- {
- return bytes_read;
- }
-
-/**
-* Return the Unix file descriptor of the pipe
-*/
-int DataSource_Command::fd() const
- {
- if(!pipe)
- return -1;
- return pipe->fd;
- }
-
-/**
-* Return a human-readable ID for this stream
-*/
-std::string DataSource_Command::id() const
- {
- return "Unix command: " + arg_list[0];
- }
-
-/**
-* Create the pipe
-*/
-void DataSource_Command::create_pipe(const std::vector<std::string>& paths)
- {
- bool found_something = false;
-
- for(size_t j = 0; j != paths.size(); j++)
- {
- const std::string full_path = paths[j] + "/" + arg_list[0];
- if(::access(full_path.c_str(), X_OK) == 0)
- {
- found_something = true;
- break;
- }
- }
-
- if(!found_something)
- return;
-
- int pipe_fd[2];
- if(::pipe(pipe_fd) != 0)
- return;
-
- pid_t pid = ::fork();
-
- if(pid == -1)
- {
- ::close(pipe_fd[0]);
- ::close(pipe_fd[1]);
- }
- else if(pid > 0)
- {
- pipe = new pipe_wrapper(pipe_fd[0], pid);
- ::close(pipe_fd[1]);
- }
- else
- {
- if(dup2(pipe_fd[1], STDOUT_FILENO) == -1)
- ::exit(127);
- if(close(pipe_fd[0]) != 0 || close(pipe_fd[1]) != 0)
- ::exit(127);
- if(close(STDERR_FILENO) != 0)
- ::exit(127);
-
- do_exec(arg_list, paths);
- ::exit(127);
- }
- }
-
-/**
-* Shutdown the pipe
-*/
-void DataSource_Command::shutdown_pipe()
- {
- if(pipe)
- {
- pid_t reaped = waitpid(pipe->pid, nullptr, WNOHANG);
-
- if(reaped == 0)
- {
- kill(pipe->pid, SIGTERM);
-
- struct ::timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = KILL_WAIT;
- select(0, nullptr, nullptr, nullptr, &tv);
-
- reaped = ::waitpid(pipe->pid, nullptr, WNOHANG);
-
- if(reaped == 0)
- {
- ::kill(pipe->pid, SIGKILL);
- do
- reaped = ::waitpid(pipe->pid, nullptr, 0);
- while(reaped == -1);
- }
- }
-
- delete pipe;
- pipe = nullptr;
- }
- }
-
-/**
-* DataSource_Command Constructor
-*/
-DataSource_Command::DataSource_Command(const std::string& prog_and_args,
- const std::vector<std::string>& paths) :
- MAX_BLOCK_USECS(100000), KILL_WAIT(10000)
- {
- arg_list = split_on(prog_and_args, ' ');
-
- if(arg_list.size() == 0)
- throw Invalid_Argument("DataSource_Command: No command given");
- if(arg_list.size() > 5)
- throw Invalid_Argument("DataSource_Command: Too many args");
-
- pipe = nullptr;
- create_pipe(paths);
- }
-
-/**
-* DataSource_Command Destructor
-*/
-DataSource_Command::~DataSource_Command()
- {
- if(!end_of_data())
- shutdown_pipe();
- }
-
-}
diff --git a/src/entropy/unix_procs/unix_cmd.h b/src/entropy/unix_procs/unix_cmd.h
deleted file mode 100644
index 7c2483c10..000000000
--- a/src/entropy/unix_procs/unix_cmd.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* Unix Command Execution
-* (C) 1999-2007 Jack Lloyd
-* 2012 Markus Wanner
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_UNIX_CMD_H__
-#define BOTAN_UNIX_CMD_H__
-
-#include <botan/types.h>
-#include <botan/data_src.h>
-#include <string>
-#include <vector>
-
-namespace Botan {
-
-/**
-* Unix Program Info
-*/
-struct Unix_Program
- {
- /**
- * @param n is the name and arguments of what we are going run
- * @param p is the priority level (lower prio numbers get polled first)
- */
- Unix_Program(const char* n, size_t p)
- { name_and_args = n; priority = p; working = true; }
-
- /**
- * The name and arguments for this command
- */
- std::string name_and_args;
-
- /**
- * Priority: we scan from low to high
- */
- size_t priority;
-
- /**
- * Does this source seem to be working?
- */
- bool working;
- };
-
-/**
-* Command Output DataSource
-*/
-class DataSource_Command : public DataSource
- {
- public:
- size_t read(byte[], size_t);
- size_t peek(byte[], size_t, size_t) const;
- bool end_of_data() const;
- std::string id() const;
- size_t get_bytes_read() const;
-
- int fd() const;
-
- DataSource_Command(const std::string&,
- const std::vector<std::string>& paths);
- ~DataSource_Command();
- private:
- void create_pipe(const std::vector<std::string>&);
- void shutdown_pipe();
-
- const size_t MAX_BLOCK_USECS, KILL_WAIT;
-
- std::vector<std::string> arg_list;
- struct pipe_wrapper* pipe;
- size_t bytes_read;
- };
-
-}
-
-#endif
diff --git a/src/entropy/unix_procs/unix_proc_sources.cpp b/src/entropy/unix_procs/unix_proc_sources.cpp
new file mode 100644
index 000000000..6cf185064
--- /dev/null
+++ b/src/entropy/unix_procs/unix_proc_sources.cpp
@@ -0,0 +1,65 @@
+/*
+* Program List for Unix_EntropySource
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/unix_procs.h>
+
+namespace Botan {
+
+/**
+* Default Commands for Entropy Gathering
+*/
+std::vector<std::vector<std::string>> Unix_EntropySource::get_default_sources()
+ {
+ std::vector<std::vector<std::string>> srcs;
+
+ srcs.push_back({ "netstat", "-in" });
+ srcs.push_back({ "pfstat" });
+ srcs.push_back({ "vmstat", "-s" });
+ srcs.push_back({ "vmstat" });
+
+ srcs.push_back({ "arp", "-a", "-n" });
+ srcs.push_back({ "ifconfig", "-a" });
+ srcs.push_back({ "iostat" });
+ srcs.push_back({ "ipcs", "-a" });
+ srcs.push_back({ "mpstat" });
+ srcs.push_back({ "netstat", "-an" });
+ srcs.push_back({ "netstat", "-s" });
+ srcs.push_back({ "nfsstat" });
+ srcs.push_back({ "portstat" });
+ srcs.push_back({ "procinfo", "-a" });
+ srcs.push_back({ "pstat", "-T" });
+ srcs.push_back({ "pstat", "-s" });
+ srcs.push_back({ "uname", "-a" });
+ srcs.push_back({ "uptime" });
+
+ srcs.push_back({ "listarea" });
+ srcs.push_back({ "listdev" });
+ srcs.push_back({ "ps", "-A" });
+ srcs.push_back({ "sysinfo" });
+
+ srcs.push_back({ "finger" });
+ srcs.push_back({ "mailstats" });
+ srcs.push_back({ "rpcinfo", "-p", "localhost" });
+ srcs.push_back({ "who" });
+
+ srcs.push_back({ "df", "-l" });
+ srcs.push_back({ "dmesg" });
+ srcs.push_back({ "last", "-5" });
+ srcs.push_back({ "ls", "-alni", "/proc" });
+ srcs.push_back({ "ls", "-alni", "/tmp" });
+ srcs.push_back({ "pstat", "-f" });
+
+ srcs.push_back({ "ps", "-elf" });
+ srcs.push_back({ "ps", "aux" });
+
+ srcs.push_back({ "lsof", "-n" });
+ srcs.push_back({ "sar", "-A" });
+
+ return srcs;
+ }
+
+}
diff --git a/src/entropy/unix_procs/unix_procs.cpp b/src/entropy/unix_procs/unix_procs.cpp
new file mode 100644
index 000000000..8d7bf4e48
--- /dev/null
+++ b/src/entropy/unix_procs/unix_procs.cpp
@@ -0,0 +1,277 @@
+/*
+* Gather entropy by running various system commands in the hopes that
+* some of the output cannot be guessed by a remote attacker.
+*
+* (C) 1999-2009,2013 Jack Lloyd
+* 2012 Markus Wanner
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/unix_procs.h>
+#include <botan/parsing.h>
+#include <algorithm>
+
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+namespace Botan {
+
+namespace {
+
+std::string find_full_path_if_exists(const std::vector<std::string>& trusted_path,
+ const std::string& proc)
+ {
+ for(auto dir : trusted_path)
+ {
+ const std::string full_path = dir + "/" + proc;
+ if(::access(full_path.c_str(), X_OK) == 0)
+ return full_path;
+ }
+
+ return "";
+ }
+
+size_t concurrent_processes(size_t user_request)
+ {
+ const size_t DEFAULT_CONCURRENT = 2;
+ const size_t MAX_CONCURRENT = 8;
+
+ if(user_request > 0 && user_request < MAX_CONCURRENT)
+ return user_request;
+
+ const long online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
+
+ if(online_cpus > 0)
+ return static_cast<size_t>(online_cpus); // maybe fewer?
+
+ return DEFAULT_CONCURRENT;
+ }
+
+}
+
+/**
+* Unix_EntropySource Constructor
+*/
+Unix_EntropySource::Unix_EntropySource(const std::vector<std::string>& trusted_path,
+ size_t proc_cnt) :
+ m_trusted_paths(trusted_path),
+ m_concurrent(concurrent_processes(proc_cnt))
+ {
+ }
+
+void Unix_EntropySource::fast_poll(Entropy_Accumulator& accum)
+ {
+ const char* stat_targets[] = {
+ "/",
+ "/tmp",
+ "/var/tmp",
+ "/usr",
+ "/home",
+ "/etc/passwd",
+ ".",
+ "..",
+ nullptr
+ };
+
+ for(size_t i = 0; stat_targets[i]; i++)
+ {
+ struct stat statbuf;
+ clear_mem(&statbuf, 1);
+ ::stat(stat_targets[i], &statbuf);
+ accum.add(&statbuf, sizeof(statbuf), 0.0);
+ }
+
+ accum.add(::getpid(), 0.0);
+ accum.add(::getppid(), 0.0);
+ accum.add(::getuid(), 0.0);
+ accum.add(::getgid(), 0.0);
+ accum.add(::getpgrp(), 0.0);
+
+ struct ::rusage usage;
+ ::getrusage(RUSAGE_SELF, &usage);
+ accum.add(usage, 0.0);
+
+ ::getrusage(RUSAGE_CHILDREN, &usage);
+ accum.add(usage, 0.0);
+ }
+
+namespace {
+
+void do_exec(const std::vector<std::string>& args)
+ {
+ // cleaner way to do this?
+ const char* arg0 = (args.size() > 0) ? args[0].c_str() : nullptr;
+ const char* arg1 = (args.size() > 1) ? args[1].c_str() : nullptr;
+ const char* arg2 = (args.size() > 2) ? args[2].c_str() : nullptr;
+ const char* arg3 = (args.size() > 3) ? args[3].c_str() : nullptr;
+ const char* arg4 = (args.size() > 4) ? args[4].c_str() : nullptr;
+
+ ::execl(arg0, arg0, arg1, arg2, arg3, arg4, NULL);
+ }
+
+}
+
+void Unix_EntropySource::Unix_Process::spawn(const std::vector<std::string>& args)
+ {
+ shutdown();
+
+ int pipe[2];
+ if(::pipe(pipe) != 0)
+ return;
+
+ pid_t pid = ::fork();
+
+ if(pid == -1)
+ {
+ ::close(pipe[0]);
+ ::close(pipe[1]);
+ }
+ else if(pid > 0) // in parent
+ {
+ m_pid = pid;
+ m_fd = pipe[0];
+ ::close(pipe[1]);
+ }
+ else // in child
+ {
+ if(::dup2(pipe[1], STDOUT_FILENO) == -1)
+ ::exit(127);
+ if(::close(pipe[0]) != 0 || ::close(pipe[1]) != 0)
+ ::exit(127);
+ if(close(STDERR_FILENO) != 0)
+ ::exit(127);
+
+ do_exec(args);
+ ::exit(127);
+ }
+ }
+
+void Unix_EntropySource::Unix_Process::shutdown()
+ {
+ if(m_pid == -1)
+ return;
+
+ ::close(m_fd);
+ m_fd = -1;
+
+ pid_t reaped = waitpid(m_pid, nullptr, WNOHANG);
+
+ if(reaped == 0)
+ {
+ /*
+ * Child is still alive - send it SIGTERM, sleep for a bit and
+ * try to reap again, if still alive send SIGKILL
+ */
+ kill(m_pid, SIGTERM);
+
+ struct ::timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select(0, nullptr, nullptr, nullptr, &tv);
+
+ reaped = ::waitpid(m_pid, nullptr, WNOHANG);
+
+ if(reaped == 0)
+ {
+ ::kill(m_pid, SIGKILL);
+ do
+ reaped = ::waitpid(m_pid, nullptr, 0);
+ while(reaped == -1);
+ }
+ }
+
+ m_pid = -1;
+ }
+
+const std::vector<std::string>& Unix_EntropySource::next_source()
+ {
+ const auto& src = m_sources.at(m_sources_idx);
+ m_sources_idx = (m_sources_idx + 1) % m_sources.size();
+ return src;
+ }
+
+void Unix_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ //fast_poll(accum);
+
+ // refuse to run as root (maybe instead setuid to nobody before exec?)
+ // fixme: this should also check for setgid
+ if(::getuid() == 0 || ::geteuid() == 0)
+ return;
+
+ if(m_sources.empty())
+ {
+ auto sources = get_default_sources();
+
+ for(auto src : sources)
+ {
+ const std::string path = find_full_path_if_exists(m_trusted_paths, src[0]);
+ if(path != "")
+ {
+ src[0] = path;
+ m_sources.push_back(src);
+ }
+ }
+ }
+
+ if(m_sources.empty())
+ return; // still empty, really nothing to try
+
+ const size_t MS_WAIT_TIME = 32;
+ const double ENTROPY_ESTIMATE = 1.0 / 1024;
+
+ secure_vector<byte>& io_buffer = accum.get_io_buffer(4*1024); // page
+
+ while(!accum.polling_goal_achieved())
+ {
+ while(m_procs.size() < m_concurrent)
+ m_procs.emplace_back(Unix_Process(next_source()));
+
+ fd_set read_set;
+ FD_ZERO(&read_set);
+
+ std::vector<int> fds;
+
+ for(auto& proc : m_procs)
+ {
+ int fd = proc.fd();
+ if(fd > 0)
+ {
+ fds.push_back(fd);
+ FD_SET(fd, &read_set);
+ }
+ }
+
+ if(fds.empty())
+ break;
+
+ const int max_fd = *std::max_element(fds.begin(), fds.end());
+
+ struct ::timeval timeout;
+ timeout.tv_sec = (MS_WAIT_TIME / 1000);
+ timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000;
+
+ if(::select(max_fd + 1, &read_set, 0, 0, &timeout) < 0)
+ return; // or continue?
+
+ for(auto& proc : m_procs)
+ {
+ int fd = proc.fd();
+
+ if(FD_ISSET(fd, &read_set))
+ {
+ const ssize_t got = ::read(fd, &io_buffer[0], io_buffer.size());
+ if(got > 0)
+ accum.add(&io_buffer[0], got, ENTROPY_ESTIMATE);
+ else
+ proc.spawn(next_source());
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/entropy/unix_procs/unix_procs.h b/src/entropy/unix_procs/unix_procs.h
new file mode 100644
index 000000000..fa92fbe20
--- /dev/null
+++ b/src/entropy/unix_procs/unix_procs.h
@@ -0,0 +1,83 @@
+/*
+* Unix EntropySource
+* (C) 1999-2009,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_UNIX_H__
+#define BOTAN_ENTROPY_SRC_UNIX_H__
+
+#include <botan/entropy_src.h>
+#include <vector>
+#include <sys/types.h>
+
+namespace Botan {
+
+/**
+* Entropy source for generic Unix. Runs various programs trying to
+* gather data hard for a remote attacker to guess. Probably not too
+* effective against local attackers as they can sample from the same
+* distribution.
+*/
+class Unix_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "Unix Process Runner"; }
+
+ void poll(Entropy_Accumulator& accum) override;
+
+ void fast_poll(Entropy_Accumulator& accum);
+
+ /**
+ * @param trusted_paths is a list of directories that are assumed
+ * to contain only 'safe' binaries. If an attacker can write
+ * an executable to one of these directories then we will
+ * run arbitrary code.
+ */
+ Unix_EntropySource(const std::vector<std::string>& trusted_paths,
+ size_t concurrent_processes = 0);
+ private:
+ static std::vector<std::vector<std::string>> get_default_sources();
+
+ class Unix_Process
+ {
+ public:
+ int fd() const { return m_fd; }
+
+ void spawn(const std::vector<std::string>& args);
+ void shutdown();
+
+ Unix_Process() {}
+
+ Unix_Process(const std::vector<std::string>& args) { spawn(args); }
+
+ ~Unix_Process() { shutdown(); }
+
+ Unix_Process(Unix_Process&& other)
+ {
+ std::swap(m_fd, other.m_fd);
+ std::swap(m_pid, other.m_pid);
+ }
+
+ Unix_Process(const Unix_Process&) = delete;
+ Unix_Process& operator=(const Unix_Process&) = delete;
+ private:
+ int m_fd = -1;
+ pid_t m_pid = -1;
+ };
+
+ const std::vector<std::string>& next_source();
+
+ const std::vector<std::string> m_trusted_paths;
+ const size_t m_concurrent;
+
+ std::vector<std::vector<std::string>> m_sources;
+ size_t m_sources_idx = 0;
+
+ std::vector<Unix_Process> m_procs;
+ };
+
+}
+
+#endif
diff --git a/src/entropy/unix_procs/unix_src.cpp b/src/entropy/unix_procs/unix_src.cpp
deleted file mode 100644
index 51af6bd40..000000000
--- a/src/entropy/unix_procs/unix_src.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* Program List for Unix_EntropySource
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/es_unix.h>
-
-namespace Botan {
-
-/**
-* Default Commands for Entropy Gathering
-*/
-std::vector<Unix_Program> Unix_EntropySource::get_default_sources()
- {
- std::vector<Unix_Program> srcs;
-
- srcs.push_back(Unix_Program("netstat -in", 1));
- srcs.push_back(Unix_Program("pfstat", 1));
- srcs.push_back(Unix_Program("vmstat -s", 1));
- srcs.push_back(Unix_Program("vmstat", 1));
-
- srcs.push_back(Unix_Program("arp -a -n", 2));
- srcs.push_back(Unix_Program("ifconfig -a", 2));
- srcs.push_back(Unix_Program("iostat", 2));
- srcs.push_back(Unix_Program("ipcs -a", 2));
- srcs.push_back(Unix_Program("mpstat", 2));
- srcs.push_back(Unix_Program("netstat -an", 2));
- srcs.push_back(Unix_Program("netstat -s", 2));
- srcs.push_back(Unix_Program("nfsstat", 2));
- srcs.push_back(Unix_Program("portstat", 2));
- srcs.push_back(Unix_Program("procinfo -a", 2));
- srcs.push_back(Unix_Program("pstat -T", 2));
- srcs.push_back(Unix_Program("pstat -s", 2));
- srcs.push_back(Unix_Program("uname -a", 2));
- srcs.push_back(Unix_Program("uptime", 2));
-
- srcs.push_back(Unix_Program("listarea", 3));
- srcs.push_back(Unix_Program("listdev", 3));
- srcs.push_back(Unix_Program("ps -A", 3));
- srcs.push_back(Unix_Program("sysinfo", 3));
-
- srcs.push_back(Unix_Program("finger", 4));
- srcs.push_back(Unix_Program("mailstats", 4));
- srcs.push_back(Unix_Program("rpcinfo -p localhost", 4));
- srcs.push_back(Unix_Program("who", 4));
-
- srcs.push_back(Unix_Program("df -l", 4));
- srcs.push_back(Unix_Program("dmesg", 4));
- srcs.push_back(Unix_Program("last -5", 4));
- srcs.push_back(Unix_Program("ls -alni /proc", 4));
- srcs.push_back(Unix_Program("ls -alni /tmp", 4));
- srcs.push_back(Unix_Program("pstat -f", 4));
-
- srcs.push_back(Unix_Program("ps -elf", 5));
- srcs.push_back(Unix_Program("ps aux", 5));
-
- srcs.push_back(Unix_Program("lsof -n", 6));
- srcs.push_back(Unix_Program("sar -A", 6));
-
- return srcs;
- }
-
-}