PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/mac_shadow.py |
""" Manage macOS local directory passwords and policies .. versionadded:: 2016.3.0 Note that it is usually better to apply password policies through the creation of a configuration profile. """ # Authentication concepts reference: # https://developer.apple.com/library/mac/documentation/Networking/Conceptual/Open_Directory/openDirectoryConcepts/openDirectoryConcepts.html#//apple_ref/doc/uid/TP40000917-CH3-CIFCAIBB import logging from datetime import datetime import salt.utils.mac_utils import salt.utils.platform from salt.exceptions import CommandExecutionError try: import pwd HAS_PWD = True except ImportError: HAS_PWD = False log = logging.getLogger(__name__) # Start logging __virtualname__ = "shadow" def __virtual__(): # Is this macOS? if not salt.utils.platform.is_darwin(): return False, "Not macOS" if HAS_PWD: return __virtualname__ else: return (False, "The pwd module failed to load.") def _get_account_policy(name): """ Get the entire accountPolicy and return it as a dictionary. For use by this module only :param str name: The user name :return: a dictionary containing all values for the accountPolicy :rtype: dict :raises: CommandExecutionError on user not found or any other unknown error """ cmd = f"pwpolicy -u {name} -getpolicy" try: ret = salt.utils.mac_utils.execute_return_result(cmd) except CommandExecutionError as exc: if f"Error: user <{name}> not found" in exc.strerror: raise CommandExecutionError(f"User not found: {name}") raise CommandExecutionError(f"Unknown error: {exc.strerror}") try: policy_list = ret.split("\n")[1].split(" ") policy_dict = {} for policy in policy_list: if "=" in policy: key, value = policy.split("=") policy_dict[key] = value return policy_dict except IndexError: return {} def _set_account_policy(name, policy): """ Set a value in the user accountPolicy. For use by this module only :param str name: The user name :param str policy: The policy to apply :return: True if success, otherwise False :rtype: bool :raises: CommandExecutionError on user not found or any other unknown error """ cmd = f'pwpolicy -u {name} -setpolicy "{policy}"' try: return salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if f"Error: user <{name}> not found" in exc.strerror: raise CommandExecutionError(f"User not found: {name}") raise CommandExecutionError(f"Unknown error: {exc.strerror}") def _get_account_policy_data_value(name, key): """ Return the value for a key in the accountPolicy section of the user's plist file. For use by this module only :param str name: The username :param str key: The accountPolicy key :return: The value contained within the key :rtype: str :raises: CommandExecutionError on user not found or any other unknown error """ cmd = f"dscl . -readpl /Users/{name} accountPolicyData {key}" try: ret = salt.utils.mac_utils.execute_return_result(cmd) except CommandExecutionError as exc: if "eDSUnknownNodeName" in exc.strerror: raise CommandExecutionError(f"User not found: {name}") if "eDSUnknownMatchType" in exc.strerror: raise CommandExecutionError(f"Value not found: {key}") raise CommandExecutionError(f"Unknown error: {exc.strerror}") return ret def _convert_to_datetime(unix_timestamp): """ Converts a unix timestamp to a human readable date/time :param float unix_timestamp: A unix timestamp :return: A date/time in the format YYYY-mm-dd HH:MM:SS :rtype: str """ try: unix_timestamp = float(unix_timestamp) return datetime.fromtimestamp(unix_timestamp).strftime("%Y-%m-%d %H:%M:%S") except (ValueError, TypeError): return "Invalid Timestamp" def info(name): """ Return information for the specified user :param str name: The username :return: A dictionary containing the user's shadow information :rtype: dict CLI Example: .. code-block:: bash salt '*' shadow.info admin """ try: data = pwd.getpwnam(name) return { "name": data.pw_name, "passwd": data.pw_passwd, "account_created": get_account_created(name), "login_failed_count": get_login_failed_count(name), "login_failed_last": get_login_failed_last(name), "lstchg": get_last_change(name), "max": get_maxdays(name), "expire": get_expire(name), "change": get_change(name), "min": "Unavailable", "warn": "Unavailable", "inact": "Unavailable", } except KeyError: log.debug("User not found: %s", name) return { "name": "", "passwd": "", "account_created": "", "login_failed_count": "", "login_failed_last": "", "lstchg": "", "max": "", "expire": "", "change": "", "min": "", "warn": "", "inact": "", } def get_account_created(name): """ Get the date/time the account was created :param str name: The username of the account :return: The date/time the account was created (yyyy-mm-dd hh:mm:ss) or 0 if the value is not defined :rtype: str :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.get_account_created admin """ try: ret = _get_account_policy_data_value(name, "creationTime") except CommandExecutionError as exc: if "Value not found" in exc.message: return "0" else: raise unix_timestamp = salt.utils.mac_utils.parse_return(ret) return _convert_to_datetime(unix_timestamp) def get_last_change(name): """ Get the date/time the account was changed :param str name: The username of the account :return: The date/time the account was modified (yyyy-mm-dd hh:mm:ss) or 0 if the value is not defined :rtype: str :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.get_last_change admin """ try: ret = _get_account_policy_data_value(name, "passwordLastSetTime") except CommandExecutionError as exc: if "Value not found" in exc.message: return "0" else: raise unix_timestamp = salt.utils.mac_utils.parse_return(ret) return _convert_to_datetime(unix_timestamp) def get_login_failed_count(name): """ Get the number of failed login attempts :param str name: The username of the account :return: The number of failed login attempts. 0 may mean there are no failed login attempts or the value is not defined :rtype: str :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.get_login_failed_count admin """ try: ret = _get_account_policy_data_value(name, "failedLoginCount") except CommandExecutionError as exc: if "Value not found" in exc.message: return "0" else: raise return salt.utils.mac_utils.parse_return(ret) def get_login_failed_last(name): """ Get the date/time of the last failed login attempt :param str name: The username of the account :return: The date/time of the last failed login attempt on this account (yyyy-mm-dd hh:mm:ss) or 0 if the value is not defined :rtype: str :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.get_login_failed_last admin """ try: ret = _get_account_policy_data_value(name, "failedLoginTimestamp") except CommandExecutionError as exc: if "Value not found" in exc.message: return "0" else: raise unix_timestamp = salt.utils.mac_utils.parse_return(ret) return _convert_to_datetime(unix_timestamp) def set_maxdays(name, days): """ Set the maximum age of the password in days :param str name: The username of the account :param int days: The maximum age of the account in days :return: True if successful, False if not :rtype: bool :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.set_maxdays admin 90 """ minutes = days * 24 * 60 _set_account_policy(name, f"maxMinutesUntilChangePassword={minutes}") return get_maxdays(name) == days def get_maxdays(name): """ Get the maximum age of the password :param str name: The username of the account :return: The maximum age of the password in days :rtype: int :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.get_maxdays admin 90 """ policies = _get_account_policy(name) if "maxMinutesUntilChangePassword" in policies: max_minutes = policies["maxMinutesUntilChangePassword"] return int(max_minutes) / 24 / 60 return 0 def set_mindays(name, days): """ Set the minimum password age in days. Not available in macOS. :param str name: The user name :param int days: The number of days :return: Will always return False until macOS supports this feature. :rtype: bool CLI Example: .. code-block:: bash salt '*' shadow.set_mindays admin 90 """ return False def set_inactdays(name, days): """ Set the number if inactive days before the account is locked. Not available in macOS :param str name: The user name :param int days: The number of days :return: Will always return False until macOS supports this feature. :rtype: bool CLI Example: .. code-block:: bash salt '*' shadow.set_inactdays admin 90 """ return False def set_warndays(name, days): """ Set the number of days before the password expires that the user will start to see a warning. Not available in macOS :param str name: The user name :param int days: The number of days :return: Will always return False until macOS supports this feature. :rtype: bool CLI Example: .. code-block:: bash salt '*' shadow.set_warndays admin 90 """ return False def set_change(name, date): """ Sets the date on which the password expires. The user will be required to change their password. Format is mm/dd/yyyy :param str name: The name of the user account :param date date: The date the password will expire. Must be in mm/dd/yyyy format. :return: True if successful, otherwise False :rtype: bool :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.set_change username 09/21/2016 """ _set_account_policy(name, f"usingExpirationDate=1 expirationDateGMT={date}") return get_change(name) == date def get_change(name): """ Gets the date on which the password expires :param str name: The name of the user account :return: The date the password will expire :rtype: str :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.get_change username """ policies = _get_account_policy(name) if "expirationDateGMT" in policies: return policies["expirationDateGMT"] return "Value not set" def set_expire(name, date): """ Sets the date on which the account expires. The user will not be able to login after this date. Date format is mm/dd/yyyy :param str name: The name of the user account :param datetime date: The date the account will expire. Format must be mm/dd/yyyy. :return: True if successful, False if not :rtype: bool :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.set_expire username 07/23/2015 """ _set_account_policy(name, f"usingHardExpirationDate=1 hardExpireDateGMT={date}") return get_expire(name) == date def get_expire(name): """ Gets the date on which the account expires :param str name: The name of the user account :return: The date the account expires :rtype: str :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.get_expire username """ policies = _get_account_policy(name) if "hardExpireDateGMT" in policies: return policies["hardExpireDateGMT"] return "Value not set" def del_password(name): """ Deletes the account password :param str name: The user name of the account :return: True if successful, otherwise False :rtype: bool :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' shadow.del_password username """ # This removes the password cmd = f"dscl . -passwd /Users/{name} ''" try: salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "eDSUnknownNodeName" in exc.strerror: raise CommandExecutionError(f"User not found: {name}") raise CommandExecutionError(f"Unknown error: {exc.strerror}") # This is so it looks right in shadow.info cmd = f"dscl . -create /Users/{name} Password '*'" salt.utils.mac_utils.execute_return_success(cmd) return info(name)["passwd"] == "*" def set_password(name, password): """ Set the password for a named user (insecure, the password will be in the process list while the command is running) :param str name: The name of the local user, which is assumed to be in the local directory service :param str password: The plaintext password to set :return: True if successful, otherwise False :rtype: bool :raises: CommandExecutionError on user not found or any other unknown error CLI Example: .. code-block:: bash salt '*' mac_shadow.set_password macuser macpassword """ cmd = f"dscl . -passwd /Users/{name} '{password}'" try: salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "eDSUnknownNodeName" in exc.strerror: raise CommandExecutionError(f"User not found: {name}") raise CommandExecutionError(f"Unknown error: {exc.strerror}") return True