Commit d541986e73f6c04b7078a52b4bde97ebd78bdc87

Authored by Wiebe Cazemier
1 parent 421a666b

Handle loading various invalid files

https://github.com/halfgaar/FlashMQ/issues/2
configfileparser.cpp
... ... @@ -22,6 +22,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>.
22 22 #include <sstream>
23 23 #include "fstream"
24 24 #include <regex>
  25 +#include "sys/stat.h"
25 26  
26 27 #include "openssl/ssl.h"
27 28 #include "openssl/err.h"
... ... @@ -42,7 +43,7 @@ void ConfigFileParser::testKeyValidity(const std::string &amp;key, const std::set&lt;st
42 43 }
43 44 }
44 45  
45   -void ConfigFileParser::checkFileExistsAndReadable(const std::string &key, const std::string &pathToCheck) const
  46 +void ConfigFileParser::checkFileExistsAndReadable(const std::string &key, const std::string &pathToCheck, ssize_t max_size) const
46 47 {
47 48 if (access(pathToCheck.c_str(), R_OK) != 0)
48 49 {
... ... @@ -50,6 +51,21 @@ void ConfigFileParser::checkFileExistsAndReadable(const std::string &amp;key, const
50 51 oss << "Error for '" << key << "': " << pathToCheck << " is not there or not readable";
51 52 throw ConfigFileException(oss.str());
52 53 }
  54 +
  55 + struct stat statbuf;
  56 + memset(&statbuf, 0, sizeof(struct stat));
  57 + if (stat(path.c_str(), &statbuf) < 0)
  58 + throw ConfigFileException(formatString("Reading stat of '%s' failed.", pathToCheck.c_str()));
  59 +
  60 + if (!S_ISREG(statbuf.st_mode))
  61 + {
  62 + throw ConfigFileException(formatString("Error for '%s': '%s' is not a regular file.", key.c_str(), pathToCheck.c_str()));
  63 + }
  64 +
  65 + if (statbuf.st_size > max_size)
  66 + {
  67 + throw ConfigFileException(formatString("Error for '%s': '%s' is bigger than %ld bytes.", key.c_str(), pathToCheck.c_str(), max_size));
  68 + }
53 69 }
54 70  
55 71 void ConfigFileParser::checkFileOrItsDirWritable(const std::string &filepath) const
... ... @@ -105,7 +121,7 @@ void ConfigFileParser::loadFile(bool test)
105 121 if (path.empty())
106 122 return;
107 123  
108   - checkFileExistsAndReadable("application config file", path);
  124 + checkFileExistsAndReadable("application config file", path, 1024*1024*10);
109 125  
110 126 std::ifstream infile(path, std::ios::in);
111 127  
... ... @@ -236,10 +252,12 @@ void ConfigFileParser::loadFile(bool test)
236 252 }
237 253 else if (key == "fullchain")
238 254 {
  255 + checkFileExistsAndReadable("SSL fullchain", value, 1024*1024);
239 256 curListener->sslFullchain = value;
240 257 }
241 258 if (key == "privkey")
242 259 {
  260 + checkFileExistsAndReadable("SSL privkey", value, 1024*1024);
243 261 curListener->sslPrivkey = value;
244 262 }
245 263 if (key == "inet_protocol")
... ... @@ -278,7 +296,7 @@ void ConfigFileParser::loadFile(bool test)
278 296  
279 297 if (key == "auth_plugin")
280 298 {
281   - checkFileExistsAndReadable(key, value);
  299 + checkFileExistsAndReadable(key, value, 1024*1024*100);
282 300 tmpSettings->authPluginPath = value;
283 301 }
284 302  
... ... @@ -346,11 +364,13 @@ void ConfigFileParser::loadFile(bool test)
346 364  
347 365 if (key == "mosquitto_password_file")
348 366 {
  367 + checkFileExistsAndReadable("mosquitto_password_file", value, 1024*1024*1024);
349 368 tmpSettings->mosquittoPasswordFile = value;
350 369 }
351 370  
352 371 if (key == "mosquitto_acl_file")
353 372 {
  373 + checkFileExistsAndReadable("mosquitto_acl_file", value, 1024*1024*1024);
354 374 tmpSettings->mosquittoAclFile = value;
355 375 }
356 376  
... ...
configfileparser.h
... ... @@ -24,6 +24,7 @@ License along with FlashMQ. If not, see &lt;https://www.gnu.org/licenses/&gt;.
24 24 #include <vector>
25 25 #include <memory>
26 26 #include <list>
  27 +#include <limits>
27 28  
28 29 #include "sslctxmanager.h"
29 30 #include "listener.h"
... ... @@ -44,7 +45,7 @@ class ConfigFileParser
44 45 std::set<std::string> validListenKeys;
45 46  
46 47 void testKeyValidity(const std::string &key, const std::set<std::string> &validKeys) const;
47   - void checkFileExistsAndReadable(const std::string &key, const std::string &pathToCheck) const;
  48 + void checkFileExistsAndReadable(const std::string &key, const std::string &pathToCheck, ssize_t max_size = std::numeric_limits<ssize_t>::max()) const;
48 49 void checkFileOrItsDirWritable(const std::string &filepath) const;
49 50 public:
50 51 ConfigFileParser(const std::string &path);
... ...
utils.cpp
... ... @@ -15,6 +15,8 @@ You should have received a copy of the GNU Affero General Public
15 15 License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>.
16 16 */
17 17  
  18 +#include "sys/stat.h"
  19 +
18 20 #include "utils.h"
19 21  
20 22 #include "sys/time.h"
... ... @@ -465,6 +467,12 @@ void testSsl(const std::string &amp;fullchain, const std::string &amp;privkey)
465 467 if (privkey.empty())
466 468 throw ConfigFileException("No fullchain specified for private key");
467 469  
  470 + if (getFileSize(fullchain) == 0)
  471 + throw ConfigFileException(formatString("SSL 'fullchain' file '%s' is empty or invalid", fullchain.c_str()));
  472 +
  473 + if (getFileSize(privkey) == 0)
  474 + throw ConfigFileException(formatString("SSL 'privkey' file '%s' is empty or invalid", privkey.c_str()));
  475 +
468 476 SslCtxManager sslCtx;
469 477 if (SSL_CTX_use_certificate_file(sslCtx.get(), fullchain.c_str(), SSL_FILETYPE_PEM) != 1)
470 478 {
... ... @@ -541,3 +549,13 @@ BindAddr getBindAddr(int family, const std::string &amp;bindAddress, int port)
541 549  
542 550 return result;
543 551 }
  552 +
  553 +ssize_t getFileSize(const std::string &path)
  554 +{
  555 + struct stat statbuf;
  556 + memset(&statbuf, 0, sizeof(struct stat));
  557 + if (stat(path.c_str(), &statbuf) < 0)
  558 + return -1;
  559 +
  560 + return statbuf.st_size;
  561 +}
... ...
... ... @@ -86,5 +86,7 @@ std::string dirnameOf(const std::string&amp; fname);
86 86  
87 87 BindAddr getBindAddr(int family, const std::string &bindAddress, int port);
88 88  
  89 +ssize_t getFileSize(const std::string &path);
  90 +
89 91  
90 92 #endif // UTILS_H
... ...