Commit a5306278 authored by Vincent Pelletier's avatar Vincent Pelletier

caucase.utils: Tolerate broken symlinks

Otherwise, this causes an IOError to be raised in _getPEMTypeDict.
So move file existence check inside the loop. Also rely on isdir returning
False on non-existent inputs.
This may for example happen if openssl-rehash is used on these directories:
caucase-updater may delete an expired CA, breaking its symlink, triggering
this bug and crashing caucase-updater.
parent ba693499
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Janitorial: make updated code checkers happier. * Janitorial: make updated code checkers happier.
* Explicitly depend on ipaddress module on python 2.7 . * Explicitly depend on ipaddress module on python 2.7 .
* Be less sensitive to small client/server time disagreements. * Be less sensitive to small client/server time disagreements.
* Fix crashes when encountering broken symlinks in directories of PEM files.
0.9.13 (2021-12-22) 0.9.13 (2021-12-22)
=================== ===================
......
...@@ -3384,6 +3384,9 @@ class CaucaseTest(TestCase): ...@@ -3384,6 +3384,9 @@ class CaucaseTest(TestCase):
utils.getCRLList(self._client_ca_dir), utils.getCRLList(self._client_ca_dir),
[crl0_pem, crl1_pem], [crl0_pem, crl1_pem],
) )
# Broken symlink: does not get deleted, and does not cause errors
broken_symlink = os.path.join(self._client_ca_dir, 'is_a_trap')
os.symlink('does_not_exist', broken_symlink)
# On with the test for the CA side # On with the test for the CA side
utils.saveCertList(self._client_ca_dir, [crt0_pem]) utils.saveCertList(self._client_ca_dir, [crt0_pem])
self.assertTrue(os.path.exists(self._client_ca_dir)) self.assertTrue(os.path.exists(self._client_ca_dir))
...@@ -3404,6 +3407,7 @@ class CaucaseTest(TestCase): ...@@ -3404,6 +3407,7 @@ class CaucaseTest(TestCase):
utils.saveCertList(self._client_ca_dir, [crt0_pem]) utils.saveCertList(self._client_ca_dir, [crt0_pem])
self.assertTrue(os.path.exists(kept_file_path)) self.assertTrue(os.path.exists(kept_file_path))
self.assertFalse(os.path.exists(deleted_file_path)) self.assertFalse(os.path.exists(deleted_file_path))
self.assertTrue(os.path.lexists(broken_symlink))
os.unlink(kept_file_path) os.unlink(kept_file_path)
# Storing and loading multiple certificates # Storing and loading multiple certificates
utils.saveCertList(self._client_ca_dir, [crt0_pem, crt1_pem]) utils.saveCertList(self._client_ca_dir, [crt0_pem, crt1_pem])
...@@ -3430,6 +3434,8 @@ class CaucaseTest(TestCase): ...@@ -3430,6 +3434,8 @@ class CaucaseTest(TestCase):
utils.getCRLList(self._client_ca_dir), utils.getCRLList(self._client_ca_dir),
[crl0_pem, crl1_pem], [crl0_pem, crl1_pem],
) )
# The borken symlink is still present
self.assertTrue(os.path.lexists(broken_symlink))
def testHttpSSLRenewal(self): def testHttpSSLRenewal(self):
""" """
......
...@@ -152,17 +152,17 @@ def getCRLList(crl_path): ...@@ -152,17 +152,17 @@ def getCRLList(crl_path):
return _getPEMListFromPath(crl_path, pem.CertificateRevocationList) return _getPEMListFromPath(crl_path, pem.CertificateRevocationList)
def _getPEMListFromPath(path, pem_type): def _getPEMListFromPath(path, pem_type):
if not os.path.exists(path): result = []
return [] for file_name in (
return [ [os.path.join(path, x) for x in os.listdir(path)]
pem_object.as_bytes() if os.path.isdir(path) else
for file_name in ( [path]
[os.path.join(path, x) for x in os.listdir(path)] ):
if os.path.isdir(path) else # path is missing, or a symlink in path (if path is a directory) is broken
[path] if os.path.exists(file_name):
) for pem_object in _getPEMTypeDict(file_name).get(pem_type, ()):
for pem_object in _getPEMTypeDict(file_name).get(pem_type, ()) result.append(pem_object.as_bytes())
] return result
def saveCertList(crt_path, cert_pem_list): def saveCertList(crt_path, cert_pem_list):
""" """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment