From fc14f94b58f652174b639614f25b8ccd45d33d64 Mon Sep 17 00:00:00 2001 From: Christos Tsantilas Date: Wed, 3 Dec 2014 03:58:37 -0800 Subject: [PATCH] Bug 4033: Rebuild corrupted ssl_db/size file The certificate db size file may become empty (for reasons beyond Squid control such as server reboots, and possibly some unknown Squid bugs). When it becomes empty, all ssl_crtd helpers (and then Squid) quit. This change is required to make ssl_crtd more robust by recovering lost db size information. This patch: - Adds the "size" rebuild operation in CertificateDB and ssl_crtd daemon. Rebuild ssl_db/size file if it is empty: * Inside Ssl::CertificateDb::check method * When a CertificateDB operation try to read size from ssl_db/size file - If no fs_block_size parameter given for CertificateDB then consider a default value of 2048. Currently set to 0, which is may cause segfault to ssl_crtd daemon. This is a Measurement Factory project --- src/ssl/certificate_db.cc | 55 ++++++++++++++++++++++++++++++--------- src/ssl/certificate_db.h | 7 ++--- src/ssl/ssl_crtd.cc | 2 +- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/ssl/certificate_db.cc b/src/ssl/certificate_db.cc index f58f84db4c..346fd2a406 100644 --- a/src/ssl/certificate_db.cc +++ b/src/ssl/certificate_db.cc @@ -245,7 +245,7 @@ Ssl::CertificateDb::CertificateDb(std::string const & aDb_path, size_t aMax_db_s size_full(aDb_path + "/" + size_file), db(NULL), max_db_size(aMax_db_size), - fs_block_size(aFs_block_size), + fs_block_size((aFs_block_size ? aFs_block_size : 2048)), dbLock(db_full), enabled_disk_store(true) { if (db_path.empty() && !max_db_size) @@ -381,9 +381,34 @@ void Ssl::CertificateDb::create(std::string const & db_path) { throw std::runtime_error("Cannot open " + db_full + " to open"); } -void Ssl::CertificateDb::check(std::string const & db_path, size_t max_db_size) { - CertificateDb db(db_path, max_db_size, 0); +void Ssl::CertificateDb::check(std::string const & db_path, size_t max_db_size, size_t fs_block_size) { + CertificateDb db(db_path, max_db_size, fs_block_size); db.load(); + + // Call readSize to force rebuild size file in the case it is corrupted + (void)db.readSize(); +} + +size_t Ssl::CertificateDb::rebuildSize() +{ + size_t dbSize = 0; +#if SQUID_SSLTXTDB_PSTRINGDATA + for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) { +#if SQUID_STACKOF_PSTRINGDATA_HACK + const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i)); +#else + const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i)); +#endif +#else + for (int i = 0; i < sk_num(db.get()->data); ++i) { + const char ** current_row = ((const char **)sk_value(db.get()->data, i)); +#endif + const std::string filename(cert_full + "/" + current_row[cnlSerial] + ".pem"); + const size_t fSize = getFileSize(filename); + dbSize += fSize; + } + writeSize(dbSize); + return dbSize; } bool Ssl::CertificateDb::pure_find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey) { @@ -408,37 +433,43 @@ bool Ssl::CertificateDb::pure_find(std::string const & host_name, Ssl::X509_Poin return true; } -size_t Ssl::CertificateDb::size() const { +size_t Ssl::CertificateDb::size() { return readSize(); } void Ssl::CertificateDb::addSize(std::string const & filename) { - writeSize(readSize() + getFileSize(filename)); + // readSize will rebuild 'size' file if missing or it is corrupted + size_t dbSize = readSize(); + dbSize += getFileSize(filename); + writeSize(dbSize); } void Ssl::CertificateDb::subSize(std::string const & filename) { - writeSize(readSize() - getFileSize(filename)); + // readSize will rebuild 'size' file if missing or it is corrupted + size_t dbSize = readSize(); + dbSize -= getFileSize(filename); + writeSize(dbSize); } -size_t Ssl::CertificateDb::readSize() const { +size_t Ssl::CertificateDb::readSize() { std::ifstream ifstr(size_full.c_str()); - if (!ifstr && enabled_disk_store) - throw std::runtime_error("cannot open for reading: " + size_full); size_t db_size = 0; - if (!(ifstr >> db_size)) - throw std::runtime_error("error while reading " + size_full); + if (!ifstr || !(ifstr >> db_size)) + return rebuildSize(); return db_size; } void Ssl::CertificateDb::writeSize(size_t db_size) { std::ofstream ofstr(size_full.c_str()); - if (!ofstr && enabled_disk_store) + if (!ofstr) throw std::runtime_error("cannot write \"" + size_full + "\" file"); ofstr << db_size; } size_t Ssl::CertificateDb::getFileSize(std::string const & filename) { std::ifstream file(filename.c_str(), std::ios::binary); + if (!file) + return 0; file.seekg(0, std::ios_base::end); size_t file_size = file.tellg(); return ((file_size + fs_block_size - 1) / fs_block_size) * fs_block_size; diff --git a/src/ssl/certificate_db.h b/src/ssl/certificate_db.h index 41422fc99d..36ddc68ce8 100644 --- a/src/ssl/certificate_db.h +++ b/src/ssl/certificate_db.h @@ -99,19 +99,20 @@ public: /// Create and initialize a database under the db_path static void create(std::string const & db_path); /// Check the database stored under the db_path. - static void check(std::string const & db_path, size_t max_db_size); + static void check(std::string const & db_path, size_t max_db_size, size_t fs_block_size); bool IsEnabledDiskStore() const; ///< Check enabled of dist store. private: void load(); ///< Load db from disk. void save(); ///< Save db to disk. - size_t size() const; ///< Get db size on disk in bytes. + size_t size(); ///< Get db size on disk in bytes. /// Increase db size by the given file size and update size_file void addSize(std::string const & filename); /// Decrease db size by the given file size and update size_file void subSize(std::string const & filename); - size_t readSize() const; ///< Read size from file size_file + size_t readSize(); ///< Read size from file size_file void writeSize(size_t db_size); ///< Write size to file size_file. size_t getFileSize(std::string const & filename); ///< get file size on disk. + size_t rebuildSize(); ///< Rebuild size_file /// Only find certificate in current db and return it. bool pure_find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey); diff --git a/src/ssl/ssl_crtd.cc b/src/ssl/ssl_crtd.cc index 3b139ebb06..443bdfee5f 100644 --- a/src/ssl/ssl_crtd.cc +++ b/src/ssl/ssl_crtd.cc @@ -295,7 +295,7 @@ int main(int argc, char *argv[]) } { - Ssl::CertificateDb::check(db_path, max_db_size); + Ssl::CertificateDb::check(db_path, max_db_size, fs_block_size); } // proccess request. for (;;) { -- 2.47.2