D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
saltstack
/
salt
/
lib
/
python3.10
/
site-packages
/
salt
/
modules
/
Filename :
solaris_shadow.py
back
Copy
""" Manage the password database on Solaris systems .. important:: If you feel that Salt should be using this module to manage passwords on a minion, and it is using a different module (or gives an error similar to *'shadow.info' is not available*), see :ref:`here <module-provider-override>`. """ import os import salt.utils.files from salt.exceptions import CommandExecutionError try: import spwd HAS_SPWD = True except ImportError: # SmartOS joyent_20130322T181205Z does not have spwd HAS_SPWD = False try: import pwd except ImportError: pass # We're most likely on a Windows machine. try: import salt.utils.pycrypto HAS_CRYPT = True except ImportError: HAS_CRYPT = False # Define the module's virtual name __virtualname__ = "shadow" def __virtual__(): """ Only work on POSIX-like systems """ if __grains__.get("kernel", "") == "SunOS": return __virtualname__ return ( False, "The solaris_shadow execution module failed to load: only available on Solaris" " systems.", ) def default_hash(): """ Returns the default hash used for unset passwords CLI Example: .. code-block:: bash salt '*' shadow.default_hash """ return "!" def info(name): """ Return information for the specified user CLI Example: .. code-block:: bash salt '*' shadow.info root """ if HAS_SPWD: try: data = spwd.getspnam(name) ret = { "name": data.sp_nam, "passwd": data.sp_pwd, "lstchg": data.sp_lstchg, "min": data.sp_min, "max": data.sp_max, "warn": data.sp_warn, "inact": data.sp_inact, "expire": data.sp_expire, } except KeyError: ret = { "name": "", "passwd": "", "lstchg": "", "min": "", "max": "", "warn": "", "inact": "", "expire": "", } return ret # SmartOS joyent_20130322T181205Z does not have spwd, but not all is lost # Return what we can know ret = { "name": "", "passwd": "", "lstchg": "", "min": "", "max": "", "warn": "", "inact": "", "expire": "", } try: data = pwd.getpwnam(name) ret.update({"name": name}) except KeyError: return ret # To compensate for lack of spwd module, read in password hash from /etc/shadow s_file = "/etc/shadow" if not os.path.isfile(s_file): return ret with salt.utils.files.fopen(s_file, "r") as ifile: for line in ifile: comps = line.strip().split(":") if comps[0] == name: ret.update({"passwd": comps[1]}) # For SmartOS `passwd -s <username>` and the output format is: # name status mm/dd/yy min max warn # # Fields: # 1. Name: username # 2. Status: # - LK: locked # - NL: no login # - NP: No password # - PS: Password # 3. Last password change # 4. Minimum age # 5. Maximum age # 6. Warning period output = __salt__["cmd.run_all"]("passwd -s {}".format(name), python_shell=False) if output["retcode"] != 0: return ret fields = output["stdout"].split() if len(fields) == 2: # For example: # root NL return ret # We have all fields: # buildbot L 05/09/2013 0 99999 7 ret.update( { "name": data.pw_name, "lstchg": fields[2], "min": int(fields[3]), "max": int(fields[4]), "warn": int(fields[5]), "inact": "", "expire": "", } ) return ret def set_maxdays(name, maxdays): """ Set the maximum number of days during which a password is valid. See man passwd. CLI Example: .. code-block:: bash salt '*' shadow.set_maxdays username 90 """ pre_info = info(name) if maxdays == pre_info["max"]: return True cmd = "passwd -x {} {}".format(maxdays, name) __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["max"] != pre_info["max"]: return post_info["max"] == maxdays def set_mindays(name, mindays): """ Set the minimum number of days between password changes. See man passwd. CLI Example: .. code-block:: bash salt '*' shadow.set_mindays username 7 """ pre_info = info(name) if mindays == pre_info["min"]: return True cmd = "passwd -n {} {}".format(mindays, name) __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["min"] != pre_info["min"]: return post_info["min"] == mindays return False def gen_password(password, crypt_salt=None, algorithm="sha512"): """ .. versionadded:: 2015.8.8 Generate hashed password .. note:: When called this function is called directly via remote-execution, the password argument may be displayed in the system's process list. This may be a security risk on certain systems. password Plaintext password to be hashed. crypt_salt Crpytographic salt. If not given, a random 8-character salt will be generated. algorithm The following hash algorithms are supported: * md5 * blowfish (not in mainline glibc, only available in distros that add it) * sha256 * sha512 (default) CLI Example: .. code-block:: bash salt '*' shadow.gen_password 'I_am_password' salt '*' shadow.gen_password 'I_am_password' crypt_salt='I_am_salt' algorithm=sha256 """ if not HAS_CRYPT: raise CommandExecutionError( "gen_password is not available on this operating system " 'because the "crypt" python module is not available.' ) return salt.utils.pycrypto.gen_hash(crypt_salt, password, algorithm) def del_password(name): """ .. versionadded:: 2015.8.8 Delete the password from name user CLI Example: .. code-block:: bash salt '*' shadow.del_password username """ cmd = "passwd -d {}".format(name) __salt__["cmd.run"](cmd, python_shell=False, output_loglevel="quiet") uinfo = info(name) return not uinfo["passwd"] def set_password(name, password): """ Set the password for a named user. The password must be a properly defined hash, the password hash can be generated with this command: ``openssl passwd -1 <plaintext password>`` CLI Example: .. code-block:: bash salt '*' shadow.set_password root $1$UYCIxa628.9qXjpQCjM4a.. """ s_file = "/etc/shadow" ret = {} if not os.path.isfile(s_file): return ret lines = [] with salt.utils.files.fopen(s_file, "r") as ifile: for line in ifile: comps = line.strip().split(":") if comps[0] != name: lines.append(line) continue comps[1] = password line = ":".join(comps) lines.append("{}\n".format(line)) with salt.utils.files.fopen(s_file, "w+") as ofile: lines = [salt.utils.stringutils.to_str(_l) for _l in lines] ofile.writelines(lines) uinfo = info(name) return uinfo["passwd"] == password def set_warndays(name, warndays): """ Set the number of days of warning before a password change is required. See man passwd. CLI Example: .. code-block:: bash salt '*' shadow.set_warndays username 7 """ pre_info = info(name) if warndays == pre_info["warn"]: return True cmd = "passwd -w {} {}".format(warndays, name) __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["warn"] != pre_info["warn"]: return post_info["warn"] == warndays return False