pycrypto.py (salt-3002.1) | : | pycrypto.py (salt-3002.2) | ||
---|---|---|---|---|
# -*- coding: utf-8 -*- | ||||
""" | """ | |||
Use pycrypto to generate random passwords on the fly. | Use pycrypto to generate random passwords on the fly. | |||
""" | """ | |||
# Import python libraries | # Import python libraries | |||
from __future__ import absolute_import, print_function, unicode_literals | ||||
import logging | import logging | |||
import random | import random | |||
import re | import re | |||
import string | import string | |||
# Import salt libs | ||||
import salt.utils.stringutils | import salt.utils.stringutils | |||
from salt.exceptions import CommandExecutionError, SaltInvocationError | from salt.exceptions import CommandExecutionError, SaltInvocationError | |||
from salt.ext import six | ||||
# Import 3rd-party libs | ||||
try: | try: | |||
try: | try: | |||
from M2Crypto.Rand import rand_bytes as get_random_bytes | from M2Crypto.Rand import rand_bytes as get_random_bytes | |||
except ImportError: | except ImportError: | |||
try: | try: | |||
from Cryptodome.Random import get_random_bytes # pylint: disable=E0 611 | from Cryptodome.Random import get_random_bytes # pylint: disable=E0 611 | |||
except ImportError: | except ImportError: | |||
from Crypto.Random import get_random_bytes # pylint: disable=E0611 | from Crypto.Random import get_random_bytes # pylint: disable=E0611 | |||
HAS_RANDOM = True | HAS_RANDOM = True | |||
except ImportError: | except ImportError: | |||
skipping to change at line 65 | skipping to change at line 60 | |||
while len(pw) < length: | while len(pw) < length: | |||
if HAS_RANDOM and use_random: | if HAS_RANDOM and use_random: | |||
while True: | while True: | |||
try: | try: | |||
char = salt.utils.stringutils.to_str(get_random_bytes(1) ) | char = salt.utils.stringutils.to_str(get_random_bytes(1) ) | |||
break | break | |||
except UnicodeDecodeError: | except UnicodeDecodeError: | |||
continue | continue | |||
pw += re.sub( | pw += re.sub( | |||
salt.utils.stringutils.to_str(r"[\W_]"), | salt.utils.stringutils.to_str(r"[\W_]"), | |||
str(), # future lint: disable=blacklisted-function | "", # future lint: disable=blacklisted-function | |||
char, | char, | |||
) | ) | |||
else: | else: | |||
pw += random.SystemRandom().choice(string.ascii_letters + string .digits) | pw += random.SystemRandom().choice(string.ascii_letters + string .digits) | |||
return pw | return pw | |||
except Exception as exc: # pylint: disable=broad-except | except Exception as exc: # pylint: disable=broad-except | |||
log.exception("Failed to generate secure passsword") | log.exception("Failed to generate secure passsword") | |||
raise CommandExecutionError(six.text_type(exc)) | raise CommandExecutionError(str(exc)) | |||
if HAS_CRYPT: | if HAS_CRYPT: | |||
methods = {m.name.lower(): m for m in crypt.methods} | methods = {m.name.lower(): m for m in crypt.methods} | |||
else: | else: | |||
methods = {} | methods = {} | |||
known_methods = ["sha512", "sha256", "blowfish", "md5", "crypt"] | known_methods = ["sha512", "sha256", "blowfish", "md5", "crypt"] | |||
def _gen_hash_passlib(crypt_salt=None, password=None, algorithm=None): | def _gen_hash_passlib(crypt_salt=None, password=None, algorithm=None): | |||
""" | """ | |||
Generate a /etc/shadow-compatible hash for a non-local system | Generate a /etc/shadow-compatible hash for a non-local system | |||
skipping to change at line 115 | skipping to change at line 110 | |||
""" | """ | |||
if crypt_salt is None: | if crypt_salt is None: | |||
# setting crypt_salt to the algorithm makes crypt generate | # setting crypt_salt to the algorithm makes crypt generate | |||
# a salt compatible with the specified algorithm. | # a salt compatible with the specified algorithm. | |||
crypt_salt = methods[algorithm] | crypt_salt = methods[algorithm] | |||
else: | else: | |||
if algorithm != "crypt": | if algorithm != "crypt": | |||
# all non-crypt algorithms are specified as part of the salt | # all non-crypt algorithms are specified as part of the salt | |||
crypt_salt = "${}${}".format(methods[algorithm].ident, crypt_salt) | crypt_salt = "${}${}".format(methods[algorithm].ident, crypt_salt) | |||
return crypt.crypt(password, crypt_salt) | try: | |||
ret = crypt.crypt(password, crypt_salt) | ||||
except OSError: | ||||
ret = None | ||||
return ret | ||||
def gen_hash(crypt_salt=None, password=None, algorithm=None): | def gen_hash(crypt_salt=None, password=None, algorithm=None): | |||
""" | """ | |||
Generate /etc/shadow hash | Generate /etc/shadow hash | |||
""" | """ | |||
if password is None: | if password is None: | |||
password = secure_password() | password = secure_password() | |||
if algorithm is None: | if algorithm is None: | |||
# prefer the most secure natively supported method | # prefer the most secure natively supported method | |||
skipping to change at line 141 | skipping to change at line 140 | |||
if HAS_CRYPT and algorithm in methods: | if HAS_CRYPT and algorithm in methods: | |||
return _gen_hash_crypt( | return _gen_hash_crypt( | |||
crypt_salt=crypt_salt, password=password, algorithm=algorithm | crypt_salt=crypt_salt, password=password, algorithm=algorithm | |||
) | ) | |||
elif HAS_PASSLIB and algorithm in known_methods: | elif HAS_PASSLIB and algorithm in known_methods: | |||
return _gen_hash_passlib( | return _gen_hash_passlib( | |||
crypt_salt=crypt_salt, password=password, algorithm=algorithm | crypt_salt=crypt_salt, password=password, algorithm=algorithm | |||
) | ) | |||
else: | else: | |||
raise SaltInvocationError( | raise SaltInvocationError( | |||
"Cannot hash using '{0}' hash algorithm. Natively supported " | "Cannot hash using '{}' hash algorithm. Natively supported " | |||
"algorithms are: {1}. If passlib is installed ({2}), the supported " | "algorithms are: {}. If passlib is installed ({}), the supported " | |||
"algorithms are: {3}.".format( | "algorithms are: {}.".format( | |||
algorithm, list(methods), HAS_PASSLIB, known_methods | algorithm, list(methods), HAS_PASSLIB, known_methods | |||
) | ) | |||
) | ) | |||
End of changes. 9 change blocks. | ||||
11 lines changed or deleted | 10 lines changed or added |