------------------------------------------------------------ revno: 13191 revision-id: squid3@treenet.co.nz-20141203115837-5098wzicrpnntmcm parent: squid3@treenet.co.nz-20141203115640-sg68gi9cf0fxp2mr fixes bug: http://bugs.squid-cache.org/show_bug.cgi?id=4033 author: Christos Tsantilas committer: Amos Jeffries branch nick: 3.4 timestamp: Wed 2014-12-03 03:58:37 -0800 message: 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 ------------------------------------------------------------ # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: squid3@treenet.co.nz-20141203115837-5098wzicrpnntmcm # target_branch: http://bzr.squid-cache.org/bzr/squid3/3.4 # testament_sha1: 9196df98cc7dd755e64a0b4dfe0fe717f285e75d # timestamp: 2014-12-03 12:01:57 +0000 # source_branch: http://bzr.squid-cache.org/bzr/squid3/3.4 # base_revision_id: squid3@treenet.co.nz-20141203115640-\ # sg68gi9cf0fxp2mr # # Begin patch === modified file 'src/ssl/certificate_db.cc' --- src/ssl/certificate_db.cc 2013-07-04 00:10:48 +0000 +++ src/ssl/certificate_db.cc 2014-12-03 11:58:37 +0000 @@ -245,7 +245,7 @@ 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 @@ 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 @@ 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; === modified file 'src/ssl/certificate_db.h' --- src/ssl/certificate_db.h 2013-05-15 15:41:43 +0000 +++ src/ssl/certificate_db.h 2014-12-03 11:58:37 +0000 @@ -99,19 +99,20 @@ /// 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); === modified file 'src/ssl/ssl_crtd.cc' --- src/ssl/ssl_crtd.cc 2013-05-30 10:10:29 +0000 +++ src/ssl/ssl_crtd.cc 2014-12-03 11:58:37 +0000 @@ -295,7 +295,7 @@ } { - Ssl::CertificateDb::check(db_path, max_db_size); + Ssl::CertificateDb::check(db_path, max_db_size, fs_block_size); } // proccess request. for (;;) {