diff --git a/lib/ansible/parsing/vault/__init__.py b/lib/ansible/parsing/vault/__init__.py index 1d4eeef4653..f38525e028d 100644 --- a/lib/ansible/parsing/vault/__init__.py +++ b/lib/ansible/parsing/vault/__init__.py @@ -220,69 +220,69 @@ class VaultEditor: def __init__(self, password): self.vault = VaultLib(password) - + def _shred_file_custom(self, tmp_path): """"Destroy a file, when shred (core-utils) is not available - - Unix `shred' destroys files "so that they can be recovered only with great difficulty with - specialised hardware, if at all". It is based on the method from the paper - "Secure Deletion of Data from Magnetic and Solid-State Memory", + + Unix `shred' destroys files "so that they can be recovered only with great difficulty with + specialised hardware, if at all". It is based on the method from the paper + "Secure Deletion of Data from Magnetic and Solid-State Memory", Proceedings of the Sixth USENIX Security Symposium (San Jose, California, July 22-25, 1996). - + We do not go to that length to re-implement shred in Python; instead, overwriting with a block - of random data should suffice. - + of random data should suffice. + See https://github.com/ansible/ansible/pull/13700 . """ - + file_len = os.path.getsize(tmp_path) max_chunk_len = min(1024*1024*2, file_len) - + passes = 3 with open(tmp_path, "wb") as fh: for _ in range(passes): fh.seek(0, 0) # get a random chunk of data, each pass with other length - chunk_len = random.randint(max_chunk_len/2, max_chunk_len) + chunk_len = random.randint(max_chunk_len//2, max_chunk_len) data = os.urandom(chunk_len) - + for _ in range(0, file_len // chunk_len): fh.write(data) fh.write(data[:file_len % chunk_len]) - + assert(fh.tell() == file_len) # FIXME remove this assert once we have unittests to check its accuracy os.fsync(fh) - - + + def _shred_file(self, tmp_path): """Securely destroy a decrypted file - Note standard limitations of GNU shred apply (For flash, overwriting would have no effect + Note standard limitations of GNU shred apply (For flash, overwriting would have no effect due to wear leveling; for other storage systems, the async kernel->filesystem->disk calls never - guarantee data hits the disk; etc). Furthermore, if your tmp dirs is on tmpfs (ramdisks), - it is a non-issue. - - Nevertheless, some form of overwriting the data (instead of just removing the fs index entry) is - a good idea. If shred is not available (e.g. on windows, or no core-utils installed), fall back on + guarantee data hits the disk; etc). Furthermore, if your tmp dirs is on tmpfs (ramdisks), + it is a non-issue. + + Nevertheless, some form of overwriting the data (instead of just removing the fs index entry) is + a good idea. If shred is not available (e.g. on windows, or no core-utils installed), fall back on a custom shredding method. """ - + if not os.path.isfile(tmp_path): # file is already gone - return - + return + try: r = call(['shred', tmp_path]) except OSError as e: - # shred is not available on this system, or some other error occured. + # shred is not available on this system, or some other error occured. r = 1 - + if r != 0: - # we could not successfully execute unix shred; therefore, do custom shred. + # we could not successfully execute unix shred; therefore, do custom shred. self._shred_file_custom(tmp_path) - + os.remove(tmp_path) - + def _edit_file_helper(self, filename, existing_data=None, force_save=False): # Create a tempfile @@ -294,11 +294,11 @@ class VaultEditor: # drop the user into an editor on the tmp file try: call(self._editor_shell_command(tmp_path)) - except: + except: # whatever happens, destroy the decrypted file self._shred_file(tmp_path) - raise - + raise + tmpdata = self.read_data(tmp_path) # Do nothing if the content has not changed