Commit d541986e73f6c04b7078a52b4bde97ebd78bdc87
1 parent
421a666b
Handle loading various invalid files
https://github.com/halfgaar/FlashMQ/issues/2
Showing
4 changed files
with
45 additions
and
4 deletions
configfileparser.cpp
| @@ -22,6 +22,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | @@ -22,6 +22,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | ||
| 22 | #include <sstream> | 22 | #include <sstream> |
| 23 | #include "fstream" | 23 | #include "fstream" |
| 24 | #include <regex> | 24 | #include <regex> |
| 25 | +#include "sys/stat.h" | ||
| 25 | 26 | ||
| 26 | #include "openssl/ssl.h" | 27 | #include "openssl/ssl.h" |
| 27 | #include "openssl/err.h" | 28 | #include "openssl/err.h" |
| @@ -42,7 +43,7 @@ void ConfigFileParser::testKeyValidity(const std::string &key, const std::set<st | @@ -42,7 +43,7 @@ void ConfigFileParser::testKeyValidity(const std::string &key, const std::set<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 | if (access(pathToCheck.c_str(), R_OK) != 0) | 48 | if (access(pathToCheck.c_str(), R_OK) != 0) |
| 48 | { | 49 | { |
| @@ -50,6 +51,21 @@ void ConfigFileParser::checkFileExistsAndReadable(const std::string &key, const | @@ -50,6 +51,21 @@ void ConfigFileParser::checkFileExistsAndReadable(const std::string &key, const | ||
| 50 | oss << "Error for '" << key << "': " << pathToCheck << " is not there or not readable"; | 51 | oss << "Error for '" << key << "': " << pathToCheck << " is not there or not readable"; |
| 51 | throw ConfigFileException(oss.str()); | 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 | void ConfigFileParser::checkFileOrItsDirWritable(const std::string &filepath) const | 71 | void ConfigFileParser::checkFileOrItsDirWritable(const std::string &filepath) const |
| @@ -105,7 +121,7 @@ void ConfigFileParser::loadFile(bool test) | @@ -105,7 +121,7 @@ void ConfigFileParser::loadFile(bool test) | ||
| 105 | if (path.empty()) | 121 | if (path.empty()) |
| 106 | return; | 122 | return; |
| 107 | 123 | ||
| 108 | - checkFileExistsAndReadable("application config file", path); | 124 | + checkFileExistsAndReadable("application config file", path, 1024*1024*10); |
| 109 | 125 | ||
| 110 | std::ifstream infile(path, std::ios::in); | 126 | std::ifstream infile(path, std::ios::in); |
| 111 | 127 | ||
| @@ -236,10 +252,12 @@ void ConfigFileParser::loadFile(bool test) | @@ -236,10 +252,12 @@ void ConfigFileParser::loadFile(bool test) | ||
| 236 | } | 252 | } |
| 237 | else if (key == "fullchain") | 253 | else if (key == "fullchain") |
| 238 | { | 254 | { |
| 255 | + checkFileExistsAndReadable("SSL fullchain", value, 1024*1024); | ||
| 239 | curListener->sslFullchain = value; | 256 | curListener->sslFullchain = value; |
| 240 | } | 257 | } |
| 241 | if (key == "privkey") | 258 | if (key == "privkey") |
| 242 | { | 259 | { |
| 260 | + checkFileExistsAndReadable("SSL privkey", value, 1024*1024); | ||
| 243 | curListener->sslPrivkey = value; | 261 | curListener->sslPrivkey = value; |
| 244 | } | 262 | } |
| 245 | if (key == "inet_protocol") | 263 | if (key == "inet_protocol") |
| @@ -278,7 +296,7 @@ void ConfigFileParser::loadFile(bool test) | @@ -278,7 +296,7 @@ void ConfigFileParser::loadFile(bool test) | ||
| 278 | 296 | ||
| 279 | if (key == "auth_plugin") | 297 | if (key == "auth_plugin") |
| 280 | { | 298 | { |
| 281 | - checkFileExistsAndReadable(key, value); | 299 | + checkFileExistsAndReadable(key, value, 1024*1024*100); |
| 282 | tmpSettings->authPluginPath = value; | 300 | tmpSettings->authPluginPath = value; |
| 283 | } | 301 | } |
| 284 | 302 | ||
| @@ -346,11 +364,13 @@ void ConfigFileParser::loadFile(bool test) | @@ -346,11 +364,13 @@ void ConfigFileParser::loadFile(bool test) | ||
| 346 | 364 | ||
| 347 | if (key == "mosquitto_password_file") | 365 | if (key == "mosquitto_password_file") |
| 348 | { | 366 | { |
| 367 | + checkFileExistsAndReadable("mosquitto_password_file", value, 1024*1024*1024); | ||
| 349 | tmpSettings->mosquittoPasswordFile = value; | 368 | tmpSettings->mosquittoPasswordFile = value; |
| 350 | } | 369 | } |
| 351 | 370 | ||
| 352 | if (key == "mosquitto_acl_file") | 371 | if (key == "mosquitto_acl_file") |
| 353 | { | 372 | { |
| 373 | + checkFileExistsAndReadable("mosquitto_acl_file", value, 1024*1024*1024); | ||
| 354 | tmpSettings->mosquittoAclFile = value; | 374 | tmpSettings->mosquittoAclFile = value; |
| 355 | } | 375 | } |
| 356 | 376 |
configfileparser.h
| @@ -24,6 +24,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | @@ -24,6 +24,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | ||
| 24 | #include <vector> | 24 | #include <vector> |
| 25 | #include <memory> | 25 | #include <memory> |
| 26 | #include <list> | 26 | #include <list> |
| 27 | +#include <limits> | ||
| 27 | 28 | ||
| 28 | #include "sslctxmanager.h" | 29 | #include "sslctxmanager.h" |
| 29 | #include "listener.h" | 30 | #include "listener.h" |
| @@ -44,7 +45,7 @@ class ConfigFileParser | @@ -44,7 +45,7 @@ class ConfigFileParser | ||
| 44 | std::set<std::string> validListenKeys; | 45 | std::set<std::string> validListenKeys; |
| 45 | 46 | ||
| 46 | void testKeyValidity(const std::string &key, const std::set<std::string> &validKeys) const; | 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 | void checkFileOrItsDirWritable(const std::string &filepath) const; | 49 | void checkFileOrItsDirWritable(const std::string &filepath) const; |
| 49 | public: | 50 | public: |
| 50 | ConfigFileParser(const std::string &path); | 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,6 +15,8 @@ You should have received a copy of the GNU Affero General Public | ||
| 15 | License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | 15 | License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | +#include "sys/stat.h" | ||
| 19 | + | ||
| 18 | #include "utils.h" | 20 | #include "utils.h" |
| 19 | 21 | ||
| 20 | #include "sys/time.h" | 22 | #include "sys/time.h" |
| @@ -465,6 +467,12 @@ void testSsl(const std::string &fullchain, const std::string &privkey) | @@ -465,6 +467,12 @@ void testSsl(const std::string &fullchain, const std::string &privkey) | ||
| 465 | if (privkey.empty()) | 467 | if (privkey.empty()) |
| 466 | throw ConfigFileException("No fullchain specified for private key"); | 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 | SslCtxManager sslCtx; | 476 | SslCtxManager sslCtx; |
| 469 | if (SSL_CTX_use_certificate_file(sslCtx.get(), fullchain.c_str(), SSL_FILETYPE_PEM) != 1) | 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 &bindAddress, int port) | @@ -541,3 +549,13 @@ BindAddr getBindAddr(int family, const std::string &bindAddress, int port) | ||
| 541 | 549 | ||
| 542 | return result; | 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 | +} |
utils.h
| @@ -86,5 +86,7 @@ std::string dirnameOf(const std::string& fname); | @@ -86,5 +86,7 @@ std::string dirnameOf(const std::string& fname); | ||
| 86 | 86 | ||
| 87 | BindAddr getBindAddr(int family, const std::string &bindAddress, int port); | 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 | #endif // UTILS_H | 92 | #endif // UTILS_H |