Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

proc_walk.cpp
Go to the documentation of this file.
1 /*
2 * Entropy source based on reading files in /proc on the assumption
3 * that a remote attacker will have difficulty guessing some of them.
4 *
5 * (C) 1999-2008,2012 Jack Lloyd
6 *
7 * Botan is released under the Simplified BSD License (see license.txt)
8 */
9
10 #include <botan/internal/proc_walk.h>
11 #include <botan/secmem.h>
12 #include <deque>
13
14 #ifndef _POSIX_C_SOURCE
15 #define _POSIX_C_SOURCE 199309
16 #endif
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <dirent.h>
22 #include <fcntl.h>
23
24 namespace Botan {
25
26 namespace {
27
28 class Directory_Walker : public File_Descriptor_Source
29 {
30 public:
31 explicit Directory_Walker(const std::string& root) :
32 m_cur_dir(std::make_pair<DIR*, std::string>(nullptr, ""))
33 {
34 if(DIR* root_dir = ::opendir(root.c_str()))
35 m_cur_dir = std::make_pair(root_dir, root);
36 }
37
38 ~Directory_Walker()
39 {
40 if(m_cur_dir.first)
41 ::closedir(m_cur_dir.first);
42 }
43
44 int next_fd() override;
45 private:
46 std::pair<struct dirent*, std::string> get_next_dirent();
47
48 std::pair<DIR*, std::string> m_cur_dir;
49 std::deque<std::string> m_dirlist;
50 };
51
52 std::pair<struct dirent*, std::string> Directory_Walker::get_next_dirent()
53 {
54 while(m_cur_dir.first)
55 {
56 if(struct dirent* dir = ::readdir(m_cur_dir.first))
57 return std::make_pair(dir, m_cur_dir.second);
58
59 ::closedir(m_cur_dir.first);
60 m_cur_dir = std::make_pair<DIR*, std::string>(nullptr, "");
61
62 while(!m_dirlist.empty() && !m_cur_dir.first)
63 {
64 const std::string next_dir_name = m_dirlist[0];
65 m_dirlist.pop_front();
66
67 if(DIR* next_dir = ::opendir(next_dir_name.c_str()))
68 m_cur_dir = std::make_pair(next_dir, next_dir_name);
69 }
70 }
71
72 return std::make_pair<struct dirent*, std::string>(nullptr, ""); // nothing left
73 }
74
75 int Directory_Walker::next_fd()
76 {
77 while(true)
78 {
79 std::pair<struct dirent*, std::string> entry = get_next_dirent();
80
81 if(!entry.first)
82 break; // no more dirs
83
84 const std::string filename = entry.first->d_name;
85
86 if(filename == "." || filename == "..")
87 continue;
88
89 const std::string full_path = entry.second + "/" + filename;
90
91 struct stat stat_buf;
92 if(::lstat(full_path.c_str(), &stat_buf) == -1)
93 continue;
94
95 if(S_ISDIR(stat_buf.st_mode))
96 {
97 m_dirlist.push_back(full_path);
98 }
99 else if(S_ISREG(stat_buf.st_mode) && (stat_buf.st_mode & S_IROTH))
100 {
101 int fd = ::open(full_path.c_str(), O_RDONLY | O_NOCTTY);
102
103 if(fd >= 0)
104 return fd;
105 }
106 }
107
108 return -1;
109 }
110
111 }
112
113 size_t ProcWalking_EntropySource::poll(RandomNumberGenerator& rng)
114 {
115 const size_t MAX_FILES_READ_PER_POLL = 2048;
116
117 lock_guard_type<mutex_type> lock(m_mutex);
118
119 if(!m_dir)
120 m_dir.reset(new Directory_Walker(m_path));
121
122 m_buf.resize(4096);
123
124 size_t bits = 0;
125
126 for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i)
127 {
128 int fd = m_dir->next_fd();
129
130 // If we've exhaused this walk of the directory, halt the poll
131 if(fd == -1)
132 {
133 m_dir.reset();
134 break;
135 }
136
137 ssize_t got = ::read(fd, m_buf.data(), m_buf.size());
138 ::close(fd);
139
140 if(got > 0)
141 {
142 rng.add_entropy(m_buf.data(), static_cast<size_t>(got));
143
144 // Conservative estimate of 4 bits per file
145 bits += 4;
146 }
147
148 if(bits > 128)
149 break;
150 }
151
152 return bits;
153 }
154
155 }
Botan::RandomNumberGenerator::add_entropy
virtual void add_entropy(const uint8_t input[], size_t length)=0
Botan::RandomNumberGenerator
Definition: rng.h:25
m_dirlist
std::deque< std::string > m_dirlist
Definition: proc_walk.cpp:49
m_cur_dir
std::pair< DIR *, std::string > m_cur_dir
Definition: proc_walk.cpp:48
O_NOCTTY
#define O_NOCTTY
Botan
Definition: alg_id.cpp:13
Botan::ProcWalking_EntropySource::poll
size_t poll(RandomNumberGenerator &rng) override
Definition: proc_walk.cpp:113