1 /** 2 * File Tree Walking EntropySource 3 * 4 * Copyright: 5 * (C) 1999-2008 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.entropy.proc_walk; 12 13 import botan.constants; 14 version(Posix): 15 static if (BOTAN_HAS_ENTROPY_SRC_PROC_WALKER): 16 17 import botan.entropy.entropy_src; 18 import memutils.vector; 19 import botan.utils.types; 20 import core.stdc.string; 21 import core.stdc.config; 22 import core.sys.posix.sys.types; 23 import core.sys.posix.sys.stat; 24 import core.sys.posix.fcntl; 25 import core.sys.posix.unistd; 26 import core.sys.posix.dirent; 27 import std.string : toStringz; 28 import std.array; 29 30 final class DirectoryWalker : FileDescriptorSource 31 { 32 public: 33 this(in string root) 34 { 35 m_cur_dir = makePair!(DIR*, string)(null, ""); 36 if (DIR* root_dir = opendir(root.toStringz)) 37 m_cur_dir = makePair(root_dir, root); 38 } 39 40 ~this() 41 { 42 if (m_cur_dir.first) 43 closedir(m_cur_dir.first); 44 } 45 46 override int nextFd() 47 { 48 while (true) 49 { 50 Pair!(dirent*, string) entry = getNextDirent(); 51 52 if (!entry.first) 53 break; // no more dirs 54 55 const string filename = cast(string) entry.first.d_name[0 .. strlen(entry.first.d_name.ptr)]; 56 57 if (filename == "." || filename == "..") 58 continue; 59 60 const string full_path = entry.second ~ '/' ~ filename; 61 62 stat_t stat_buf; 63 if (.lstat(full_path.toStringz, &stat_buf) == -1) 64 continue; 65 version(ARM){ 66 bool s_isdir = S_ISDIR(cast(ushort)stat_buf.st_mode); 67 bool s_isreg = S_ISREG(cast(ushort)stat_buf.st_mode); 68 } 69 else { 70 bool s_isdir = S_ISDIR(stat_buf.st_mode); 71 bool s_isreg = S_ISREG(stat_buf.st_mode); 72 } 73 if (s_isdir) 74 { 75 addDirectory(full_path); 76 } 77 else if (s_isreg && (stat_buf.st_mode & S_IROTH)) 78 { 79 int fd = .open(full_path.toStringz, O_RDONLY | O_NOCTTY); 80 81 if (fd > 0) 82 return fd; 83 } 84 } 85 86 return -1; 87 } 88 89 private: 90 void addDirectory(in string dirname) 91 { 92 m_dirlist.insertBack(dirname); 93 } 94 95 Pair!(dirent*, string) getNextDirent() 96 { 97 while (m_cur_dir.first) 98 { 99 if (dirent* dir = readdir(m_cur_dir.first)) 100 return makePair(dir, m_cur_dir.second); 101 102 closedir(m_cur_dir.first); 103 m_cur_dir = makePair!(DIR*, string)(null, ""); 104 105 while (!m_dirlist.empty && !m_cur_dir.first) 106 { 107 const string next_dir_name = m_dirlist.front; 108 m_dirlist = Vector!string(m_dirlist[1 .. $]); 109 110 if (DIR* next_dir = opendir(next_dir_name.toStringz)) 111 m_cur_dir = makePair(next_dir, next_dir_name); 112 } 113 } 114 115 return Pair!(dirent*, string)(); // nothing left 116 } 117 118 Pair!(DIR*, string) m_cur_dir; 119 Vector!string m_dirlist; 120 } 121 122 123 interface FileDescriptorSource 124 { 125 public: 126 abstract int nextFd(); 127 128 } 129 130 /** 131 * File Tree Walking Entropy Source 132 */ 133 final class ProcWalkingEntropySource : EntropySource 134 { 135 public: 136 @property string name() const { return "Proc Walker"; } 137 138 void poll(ref EntropyAccumulator accum) 139 { 140 __gshared immutable size_t MAX_FILES_READ_PER_POLL = 2048; 141 const double ENTROPY_ESTIMATE = 1.0 / (8*1024); 142 143 if (!m_dir) 144 m_dir = new DirectoryWalker(m_path); 145 146 SecureVector!ubyte* io_buffer = &accum.getIoBuffer(4096); 147 foreach (size_t i; 0 .. MAX_FILES_READ_PER_POLL) 148 { 149 int fd = m_dir.nextFd(); 150 151 // If we've exhaused this walk of the directory, halt the poll 152 if (fd == -1) 153 { 154 destroy(m_dir); 155 m_dir = null; 156 break; 157 } 158 159 ssize_t got = .read(fd, io_buffer.ptr, 4096); 160 close(fd); 161 162 if (got > 0) 163 accum.add(io_buffer.ptr, got, ENTROPY_ESTIMATE); 164 165 if (accum.pollingGoalAchieved()) 166 break; 167 } 168 } 169 170 this(in string root_dir) 171 { 172 m_path = root_dir; 173 } 174 175 ~this() { if (m_dir) destroy(m_dir); } 176 177 private: 178 const string m_path; 179 FileDescriptorSource m_dir; 180 } 181 182 @nogc nothrow pure private: 183 bool S_ISTYPE( mode_t mode, uint mask ) { return ( mode & S_IFMT ) == mask; } 184 bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); } 185 bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }