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/utils/ |
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/utils/win_functions.py |
""" Various functions to be used by windows during start up and to monkey patch missing functions in other modules. """ import ctypes import platform import re from salt.exceptions import CommandExecutionError try: import psutil import pywintypes import win32api import win32net import win32security from win32con import HWND_BROADCAST, SMTO_ABORTIFHUNG, WM_SETTINGCHANGE HAS_WIN32 = True except ImportError: HAS_WIN32 = False # Although utils are often directly imported, it is also possible to use the # loader. def __virtual__(): """ Only load if Win32 Libraries are installed """ if not HAS_WIN32: return False, "This utility requires pywin32" return "win_functions" def get_parent_pid(): """ This is a monkey patch for os.getppid. Used in: - salt.utils.parsers Returns: int: The parent process id """ return psutil.Process().ppid() def is_admin(name): """ Is the passed user a member of the Administrators group Args: name (str): The name to check Returns: bool: True if user is a member of the Administrators group, False otherwise """ groups = get_user_groups(name, True) for group in groups: if group in ("S-1-5-32-544", "S-1-5-18"): return True return False def get_user_groups(name, sid=False): """ Get the groups to which a user belongs Args: name (str): The user name to query sid (bool): True will return a list of SIDs, False will return a list of group names Returns: list: A list of group names or sids """ groups = [] if name.upper() == "SYSTEM": # 'win32net.NetUserGetLocalGroups' will fail if you pass in 'SYSTEM'. groups = ["SYSTEM"] else: try: groups = win32net.NetUserGetLocalGroups(None, name) except (win32net.error, pywintypes.error) as exc: # ERROR_ACCESS_DENIED, NERR_DCNotFound, RPC_S_SERVER_UNAVAILABLE if exc.winerror in (5, 1722, 2453, 1927, 1355): # Try without LG_INCLUDE_INDIRECT flag, because the user might # not have permissions for it or something is wrong with DC groups = win32net.NetUserGetLocalGroups(None, name, 0) else: # If this fails, try once more but instead with global groups. try: groups = win32net.NetUserGetGroups(None, name) except win32net.error as exc: if exc.winerror in (5, 1722, 2453, 1927, 1355): # Try without LG_INCLUDE_INDIRECT flag, because the user might # not have permissions for it or something is wrong with DC groups = win32net.NetUserGetLocalGroups(None, name, 0) except pywintypes.error: if exc.winerror in (5, 1722, 2453, 1927, 1355): # Try with LG_INCLUDE_INDIRECT flag, because the user might # not have permissions for it or something is wrong with DC groups = win32net.NetUserGetLocalGroups(None, name, 1) else: raise if not sid: return groups ret_groups = [] for group in groups: ret_groups.append(get_sid_from_name(group)) return ret_groups def get_sid_from_name(name): """ This is a tool for getting a sid from a name. The name can be any object. Usually a user or a group Args: name (str): The name of the user or group for which to get the sid Returns: str: The corresponding SID """ # If None is passed, use the Universal Well-known SID "Null SID" if name is None: name = "NULL SID" try: sid = win32security.LookupAccountName(None, name)[0] except pywintypes.error as exc: raise CommandExecutionError(f"User {name} not found: {exc}") return win32security.ConvertSidToStringSid(sid) def get_current_user(with_domain=True): """ Gets the user executing the process Args: with_domain (bool): ``True`` will prepend the user name with the machine name or domain separated by a backslash Returns: str: The user name """ try: user_name = win32api.GetUserNameEx(win32api.NameSamCompatible) if user_name[-1] == "$": # Make the system account easier to identify. # Fetch sid so as to handle other language than english test_user = win32api.GetUserName() if test_user == "SYSTEM": user_name = "SYSTEM" elif get_sid_from_name(test_user) == "S-1-5-18": user_name = "SYSTEM" elif not with_domain: user_name = win32api.GetUserName() except pywintypes.error as exc: raise CommandExecutionError(f"Failed to get current user: {exc}") if not user_name: return False return user_name def get_sam_name(username): r""" Gets the SAM name for a user. It basically prefixes a username without a backslash with the computer name. If the user does not exist, a SAM compatible name will be returned using the local hostname as the domain. i.e. salt.utils.get_same_name('Administrator') would return 'DOMAIN.COM\Administrator' .. note:: Long computer names are truncated to 15 characters """ # Some special identity groups require special handling. They do not have # the domain prepended to the name. They should be added here as they are # discovered. Use the SID to be locale agnostic. # Everyone: S-1-1-0 special_id_groups = ["S-1-1-0"] try: sid_obj = win32security.LookupAccountName(None, username)[0] except pywintypes.error: return "\\".join([platform.node()[:15].upper(), username]) sid = win32security.ConvertSidToStringSid(sid_obj) username, domain, _ = win32security.LookupAccountSid(None, sid_obj) if sid in special_id_groups: return username return "\\".join([domain, username]) def enable_ctrl_logoff_handler(): """ Set the control handler on the console """ if HAS_WIN32: ctrl_logoff_event = 5 win32api.SetConsoleCtrlHandler( lambda event: True if event == ctrl_logoff_event else False, 1 ) def escape_argument(arg, escape=True): """ Escape the argument for the cmd.exe shell. See http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx First we escape the quote chars to produce a argument suitable for CommandLineToArgvW. We don't need to do this for simple arguments. Args: arg (str): a single command line argument to escape for the cmd.exe shell Kwargs: escape (bool): True will call the escape_for_cmd_exe() function which escapes the characters '()%!^"<>&|'. False will not call the function and only quotes the cmd Returns: str: an escaped string suitable to be passed as a program argument to the cmd.exe shell """ if not arg or re.search(r'(["\s])', arg): arg = '"' + arg.replace('"', r"\"") + '"' if not escape: return arg return escape_for_cmd_exe(arg) def escape_for_cmd_exe(arg): """ Escape an argument string to be suitable to be passed to cmd.exe on Windows This method takes an argument that is expected to already be properly escaped for the receiving program to be properly parsed. This argument will be further escaped to pass the interpolation performed by cmd.exe unchanged. Any meta-characters will be escaped, removing the ability to e.g. use redirects or variables. Args: arg (str): a single command line argument to escape for cmd.exe Returns: str: an escaped string suitable to be passed as a program argument to cmd.exe """ meta_chars = '()%!^"<>&|' meta_re = re.compile( "(" + "|".join(re.escape(char) for char in list(meta_chars)) + ")" ) meta_map = {char: f"^{char}" for char in meta_chars} def escape_meta_chars(m): char = m.group(1) return meta_map[char] return meta_re.sub(escape_meta_chars, arg) def broadcast_setting_change(message="Environment"): """ Send a WM_SETTINGCHANGE Broadcast to all Windows Args: message (str): A string value representing the portion of the system that has been updated and needs to be refreshed. Default is ``Environment``. These are some common values: - "Environment" : to effect a change in the environment variables - "intl" : to effect a change in locale settings - "Policy" : to effect a change in Group Policy Settings - a leaf node in the registry - the name of a section in the ``Win.ini`` file See lParam within msdn docs for `WM_SETTINGCHANGE <https://msdn.microsoft.com/en-us/library/ms725497%28VS.85%29.aspx>`_ for more information on Broadcasting Messages. See GWL_WNDPROC within msdn docs for `SetWindowLong <https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v=vs.85).aspx>`_ for information on how to retrieve those messages. .. note:: This will only affect new processes that aren't launched by services. To apply changes to the path or registry to services, the host must be restarted. The ``salt-minion``, if running as a service, will not see changes to the environment until the system is restarted. Services inherit their environment from ``services.exe`` which does not respond to messaging events. See `MSDN Documentation <https://support.microsoft.com/en-us/help/821761/changes-that-you-make-to-environment-variables-do-not-affect-services>`_ for more information. CLI Example: .. code-block:: python import salt.utils.win_functions salt.utils.win_functions.broadcast_setting_change('Environment') """ # Listen for messages sent by this would involve working with the # SetWindowLong function. This can be accessed via win32gui or through # ctypes. You can find examples on how to do this by searching for # `Accessing WGL_WNDPROC` on the internet. Here are some examples of how # this might work: # # # using win32gui # import win32con # import win32gui # old_function = win32gui.SetWindowLong(window_handle, win32con.GWL_WNDPROC, new_function) # # # using ctypes # import ctypes # import win32con # from ctypes import c_long, c_int # user32 = ctypes.WinDLL('user32', use_last_error=True) # WndProcType = ctypes.WINFUNCTYPE(c_int, c_long, c_int, c_int) # new_function = WndProcType # old_function = user32.SetWindowLongW(window_handle, win32con.GWL_WNDPROC, new_function) broadcast_message = ctypes.create_unicode_buffer(message) user32 = ctypes.WinDLL("user32", use_last_error=True) result = user32.SendMessageTimeoutW( HWND_BROADCAST, WM_SETTINGCHANGE, 0, broadcast_message, SMTO_ABORTIFHUNG, 5000, 0, ) return result == 1 def guid_to_squid(guid): """ Converts a GUID to a compressed guid (SQUID) Each Guid has 5 parts separated by '-'. For the first three each one will be totally reversed, and for the remaining two each one will be reversed by every other character. Then the final compressed Guid will be constructed by concatenating all the reversed parts without '-'. .. Example:: Input: 2BE0FA87-5B36-43CF-95C8-C68D6673FB94 Reversed: 78AF0EB2-63B5-FC34-598C-6CD86637BF49 Final Compressed Guid: 78AF0EB263B5FC34598C6CD86637BF49 Args: guid (str): A valid GUID Returns: str: A valid compressed GUID (SQUID) """ guid_pattern = re.compile( r"^\{(\w{8})-(\w{4})-(\w{4})-(\w\w)(\w\w)-(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)\}$" ) guid_match = guid_pattern.match(guid) squid = "" if guid_match is not None: for index in range(1, 12): squid += guid_match.group(index)[::-1] return squid def squid_to_guid(squid): """ Converts a compressed GUID (SQUID) back into a GUID Args: squid (str): A valid compressed GUID Returns: str: A valid GUID """ squid_pattern = re.compile( r"^(\w{8})(\w{4})(\w{4})(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)$" ) squid_match = squid_pattern.match(squid) guid = "" if squid_match is not None: guid = ( "{" + squid_match.group(1)[::-1] + "-" + squid_match.group(2)[::-1] + "-" + squid_match.group(3)[::-1] + "-" + squid_match.group(4)[::-1] + squid_match.group(5)[::-1] + "-" ) for index in range(6, 12): guid += squid_match.group(index)[::-1] guid += "}" return guid