online $ˆl–Ðz¾”Ji?u4 ^¸ËwÒ˜´oÈ „ßÇÀÊ) # (c) 2012-2014, Michael DeHaan # (c) 2017 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import (absolute_import, division, print_function) __metaclass__ = type import multiprocessing import random import re import string import sys from collections import namedtuple from ansible import constants as C from ansible.errors import AnsibleError, AnsibleAssertionError from ansible.module_utils.six import text_type from ansible.module_utils._text import to_text, to_bytes from ansible.utils.display import Display PASSLIB_E = CRYPT_E = None HAS_CRYPT = PASSLIB_AVAILABLE = False try: import passlib import passlib.hash from passlib.utils.handlers import HasRawSalt, PrefixWrapper try: from passlib.utils.binary import bcrypt64 except ImportError: from passlib.utils import bcrypt64 PASSLIB_AVAILABLE = True except Exception as e: PASSLIB_E = e try: import crypt HAS_CRYPT = True except Exception as e: CRYPT_E = e display = Display() __all__ = ['do_encrypt'] _LOCK = multiprocessing.Lock() DEFAULT_PASSWORD_LENGTH = 20 def random_password(length=DEFAULT_PASSWORD_LENGTH, chars=C.DEFAULT_PASSWORD_CHARS, seed=None): '''Return a random password string of length containing only chars :kwarg length: The number of characters in the new password. Defaults to 20. :kwarg chars: The characters to choose from. The default is all ascii letters, ascii digits, and these symbols ``.,:-_`` ''' if not isinstance(chars, text_type): raise AnsibleAssertionError('%s (%s) is not a text_type' % (chars, type(chars))) if seed is None: random_generator = random.SystemRandom() else: random_generator = random.Random(seed) return u''.join(random_generator.choice(chars) for dummy in range(length)) def random_salt(length=8): """Return a text string suitable for use as a salt for the hash functions we use to encrypt passwords. """ # Note passlib salt values must be pure ascii so we can't let the user # configure this salt_chars = string.ascii_letters + string.digits + u'./' return random_password(length=length, chars=salt_chars) class BaseHash(object): algo = namedtuple('algo', ['crypt_id', 'salt_size', 'implicit_rounds', 'salt_exact', 'implicit_ident']) algorithms = { 'md5_crypt': algo(crypt_id='1', salt_size=8, implicit_rounds=None, salt_exact=False, implicit_ident=None), 'bcrypt': algo(crypt_id='2b', salt_size=22, implicit_rounds=12, salt_exact=True, implicit_ident='2b'), 'sha256_crypt': algo(crypt_id='5', salt_size=16, implicit_rounds=535000, salt_exact=False, implicit_ident=None), 'sha512_crypt': algo(crypt_id='6', salt_size=16, implicit_rounds=656000, salt_exact=False, implicit_ident=None), } def __init__(self, algorithm): self.algorithm = algorithm class CryptHash(BaseHash): def __init__(self, algorithm): super(CryptHash, self).__init__(algorithm) if not HAS_CRYPT: raise AnsibleError("crypt.crypt cannot be used as the 'crypt' python library is not installed or is unusable.", orig_exc=CRYPT_E) if sys.platform.startswith('darwin'): raise AnsibleError("crypt.crypt not supported on Mac OS X/Darwin, install passlib python module") if algorithm not in self.algorithms: raise AnsibleError("crypt.crypt does not support '%s' algorithm" % self.algorithm) display.deprecated( "Encryption using the Python crypt module is deprecated. The " "Python crypt module is deprecated and will be removed from " "Python 3.13. Install the passlib library for continued " "encryption functionality.", version=2.17 ) self.algo_data = self.algorithms[algorithm] def hash(self, secret, salt=None, salt_size=None, rounds=None, ident=None): salt =