diff --git a/salt/modules/shadow.py b/salt/modules/shadow.py index 3a52c63784..5e49686e9c 100644 --- a/salt/modules/shadow.py +++ b/salt/modules/shadow.py @@ -13,6 +13,7 @@ except ImportError: # Import salt libs import salt.utils +import salt.utils.pycrypt def __virtual__(): @@ -129,6 +130,29 @@ def set_mindays(name, mindays): return False +def gen_password(password, crypt_salt=None, algorithm='sha512'): + ''' + Generate hashed password + + password + Clear text password + + crypt_salt + Crpytographic salt. If not given, will generate random 8-characters + + algorithm + Hashing algorithm. Support ``md5``, ``blowfish``, ``sha256``, ``sha512``(default). + + CLI Example: + + .. code-block:: bash + + salt '*' shadow.gen_password 'I_am_password' + salt '*' shadow.gen_password 'I_am_password' 'I_am_salt' sha256 + ''' + return salt.utils.pycrypt.gen_hash(crypt_salt, password, algorithm) + + def set_password(name, password, use_usermod=False): ''' Set the password for a named user. The password must be a properly defined diff --git a/salt/utils/pycrypto.py b/salt/utils/pycrypto.py index ab622aa30f..ddf448bba7 100644 --- a/salt/utils/pycrypto.py +++ b/salt/utils/pycrypto.py @@ -12,29 +12,39 @@ except ImportError: HAS_RANDOM = False import crypt import re +import string +import random +# Import salt libs +import salt.exceptions def secure_password(length=20): ''' Generate a secure password. ''' - if not HAS_RANDOM: - raise ImportError('generating passwords requires >= pycrypto v2.1.0') pw = '' while len(pw) < length: - pw += re.sub(r'\W', '', Crypto.Random.get_random_bytes(1)) + if HAS_RANDOM: + pw += re.sub(r'\W', '', Crypto.Random.get_random_bytes(1)) + else: + pw += random.choice(string.ascii_letters + string.digits) return pw -def gen_hash(salt=None, password=None): +def gen_hash(crypt_salt=None, password=None, algorithm='sha512'): ''' Generate /etc/shadow hash ''' + hash_algorithms = {'md5':'$1$', 'blowfish':'$2a$', 'sha256':'$5$', 'sha512':'$6$'} + if algorithm not in hash_algorithms: + raise salt.exceptions.SaltInvocationError('Not support {0} algorithm'.format(algorithm)) if password is None: password = secure_password() - if salt is None: - salt = '$6' + secure_password(8) + if crypt_salt is None: + crypt_salt = secure_password(8) - return crypt.crypt(password, salt) + crypt_salt = hash_algorithms[algorithm] + crypt_salt + + return crypt.crypt(password, crypt_salt)