]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 4033: Rebuild corrupted ssl_db/size file
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Tue, 25 Nov 2014 16:46:38 +0000 (18:46 +0200)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Tue, 25 Nov 2014 16:46:38 +0000 (18:46 +0200)
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
src/ssl/certificate_db.h
src/ssl/ssl_crtd.cc

index ea205c7da74077583ea88981d04117892d7b3f49..d144d34ead91d850deb71b4c398831ecab3ab86b 100644 (file)
@@ -248,7 +248,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)
@@ -384,9 +384,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) {
@@ -411,37 +436,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;
index 15019e2eb51519021bca25c0fe70df773690ae71..ac0f38c899752e4e032fc924181ef5bfea951daa 100644 (file)
@@ -106,19 +106,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);
 
index 1e56b684ba25f2200aad3fc6b2b518276a77e9c1..24da4ce92f5034242842a477b8046ad15b256f92 100644 (file)
@@ -293,7 +293,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);
         }
         // Initialize SSL subsystem
         SSL_load_error_strings();