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/smb.py |
""" Utility functions for SMB connections :depends: impacket """ import logging import socket import uuid import salt.utils.files import salt.utils.stringutils import salt.utils.versions from salt.exceptions import MissingSmb log = logging.getLogger(__name__) try: from smbprotocol.connection import Connection from smbprotocol.create_contexts import ( CreateContextName, SMB2CreateContextRequest, SMB2CreateQueryMaximalAccessRequest, ) from smbprotocol.open import ( CreateDisposition, CreateOptions, DirectoryAccessMask, FileAttributes, FileInformationClass, FilePipePrinterAccessMask, ImpersonationLevel, Open, ShareAccess, ) from smbprotocol.security_descriptor import ( AccessAllowedAce, AccessMask, AclPacket, SDControl, SIDPacket, SMB2CreateSDBuffer, ) from smbprotocol.session import Session from smbprotocol.tree import TreeConnect logging.getLogger("smbprotocol").setLevel(logging.WARNING) HAS_SMBPROTOCOL = True except ImportError: HAS_SMBPROTOCOL = False class SMBProto: def __init__(self, server, username, password, port=445): connection_id = uuid.uuid4() addr = socket.getaddrinfo(server, None, 0, 0, socket.IPPROTO_TCP)[0][4][0] self.server = server connection = Connection(connection_id, addr, port, require_signing=True) self.session = Session(connection, username, password, require_encryption=False) def connect(self): self.connection.connect() self.session.connect() def close(self): self.session.connection.disconnect(True) @property def connection(self): return self.session.connection def tree_connect(self, share): if share.endswith("$"): share = rf"\\{self.server}\{share}" tree = TreeConnect(self.session, share) tree.connect() return tree @staticmethod def normalize_filename(file): return file.lstrip("\\") @classmethod def open_file(cls, tree, file): file = cls.normalize_filename(file) # ensure file is created, get maximal access, and set everybody read access max_req = SMB2CreateContextRequest() max_req["buffer_name"] = ( CreateContextName.SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST ) max_req["buffer_data"] = SMB2CreateQueryMaximalAccessRequest() # create security buffer that sets the ACL for everyone to have read access everyone_sid = SIDPacket() everyone_sid.from_string("S-1-1-0") ace = AccessAllowedAce() ace["mask"] = AccessMask.GENERIC_ALL ace["sid"] = everyone_sid acl = AclPacket() acl["aces"] = [ace] sec_desc = SMB2CreateSDBuffer() sec_desc["control"].set_flag(SDControl.SELF_RELATIVE) sec_desc.set_dacl(acl) sd_buffer = SMB2CreateContextRequest() sd_buffer["buffer_name"] = CreateContextName.SMB2_CREATE_SD_BUFFER sd_buffer["buffer_data"] = sec_desc create_contexts = [max_req, sd_buffer] file_open = Open(tree, file) open_info = file_open.create( ImpersonationLevel.Impersonation, FilePipePrinterAccessMask.GENERIC_READ | FilePipePrinterAccessMask.GENERIC_WRITE, FileAttributes.FILE_ATTRIBUTE_NORMAL, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OVERWRITE_IF, CreateOptions.FILE_NON_DIRECTORY_FILE, ) return file_open @staticmethod def open_directory(tree, name, create=False): # ensure directory is created dir_open = Open(tree, name) if create: dir_open.create( ImpersonationLevel.Impersonation, DirectoryAccessMask.GENERIC_READ | DirectoryAccessMask.GENERIC_WRITE, FileAttributes.FILE_ATTRIBUTE_DIRECTORY, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN_IF, CreateOptions.FILE_DIRECTORY_FILE, ) return dir_open def _get_conn_smbprotocol(host="", username="", password="", client_name="", port=445): conn = SMBProto(host, username, password, port) conn.connect() return conn def get_conn(host="", username=None, password=None, port=445): """ Get an SMB connection """ if HAS_SMBPROTOCOL: log.info("Get connection smbprotocol") return _get_conn_smbprotocol(host, username, password, port=port) else: return False def _mkdirs_smbprotocol( path, share="C$", conn=None, host=None, username=None, password=None ): if conn is None: conn = get_conn(host, username, password) if conn is False: return False tree = conn.tree_connect(share) comps = path.split("/") pos = 1 for comp in comps: cwd = "\\".join(comps[0:pos]) dir_open = conn.open_directory(tree, cwd, create=True) compound_messages = [ dir_open.query_directory( "*", FileInformationClass.FILE_NAMES_INFORMATION, send=False ), dir_open.close(False, send=False), ] requests = conn.session.connection.send_compound( [x[0] for x in compound_messages], conn.session.session_id, tree.tree_connect_id, ) for i, request in enumerate(requests): response = compound_messages[i][1](request) pos += 1 def mkdirs(path, share="C$", conn=None, host=None, username=None, password=None): if HAS_SMBPROTOCOL: return _mkdirs_smbprotocol( path, share, conn=conn, host=host, username=username, password=password ) raise MissingSmb("SMB library required (impacket or smbprotocol)") def _put_str_smbprotocol( content, path, share="C$", conn=None, host=None, username=None, password=None ): if conn is None: conn = get_conn(host, username, password) if conn is False: return False tree = conn.tree_connect(share) try: file_open = conn.open_file(tree, path) file_open.write(salt.utils.stringutils.to_bytes(content), 0) finally: file_open.close() def put_str( content, path, share="C$", conn=None, host=None, username=None, password=None ): """ Wrapper around impacket.smbconnection.putFile() that allows a string to be uploaded, without first writing it as a local file """ if HAS_SMBPROTOCOL: return _put_str_smbprotocol( content, path, share, conn=conn, host=host, username=username, password=password, ) raise MissingSmb("SMB library required (impacket or smbprotocol)") def _put_file_smbprotocol( local_path, path, share="C$", conn=None, host=None, username=None, password=None, chunk_size=1024 * 1024, ): if conn is None: conn = get_conn(host, username, password) if conn is False: return False tree = conn.tree_connect(share) file_open = conn.open_file(tree, path) with salt.utils.files.fopen(local_path, "rb") as fh_: try: position = 0 while True: chunk = fh_.read(chunk_size) if not chunk: break file_open.write(chunk, position) position += len(chunk) finally: file_open.close(False) def put_file( local_path, path, share="C$", conn=None, host=None, username=None, password=None ): """ Wrapper around impacket.smbconnection.putFile() that allows a file to be uploaded Example usage: import salt.utils.smb smb_conn = salt.utils.smb.get_conn('10.0.0.45', 'vagrant', 'vagrant') salt.utils.smb.put_file('/root/test.pdf', 'temp\\myfiles\\test1.pdf', conn=smb_conn) """ if HAS_SMBPROTOCOL: return _put_file_smbprotocol( local_path, path, share, conn=conn, host=host, username=username, password=password, ) raise MissingSmb("SMB library required (impacket or smbprotocol)") def _delete_file_smbprotocol( path, share="C$", conn=None, host=None, username=None, password=None ): if conn is None: conn = get_conn(host, username, password) if conn is False: return False tree = conn.tree_connect(share) file_open = Open(tree, path) delete_msgs = [ file_open.create( ImpersonationLevel.Impersonation, FilePipePrinterAccessMask.GENERIC_READ | FilePipePrinterAccessMask.DELETE, FileAttributes.FILE_ATTRIBUTE_NORMAL, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_DELETE_ON_CLOSE, send=False, ), file_open.close(False, send=False), ] requests = conn.connection.send_compound( [x[0] for x in delete_msgs], conn.session.session_id, tree.tree_connect_id, related=True, ) responses = [] for i, request in enumerate(requests): # A SMBResponseException will be raised if something went wrong response = delete_msgs[i][1](request) responses.append(response) def delete_file(path, share="C$", conn=None, host=None, username=None, password=None): if HAS_SMBPROTOCOL: return _delete_file_smbprotocol( path, share, conn=conn, host=host, username=username, password=password ) raise MissingSmb("SMB library required (impacket or smbprotocol)") def _delete_directory_smbprotocol( path, share="C$", conn=None, host=None, username=None, password=None ): if conn is None: conn = get_conn(host, username, password) if conn is False: return False log.debug("_delete_directory_smbprotocol - share: %s, path: %s", share, path) tree = conn.tree_connect(share) dir_open = Open(tree, path) delete_msgs = [ dir_open.create( ImpersonationLevel.Impersonation, DirectoryAccessMask.DELETE, FileAttributes.FILE_ATTRIBUTE_DIRECTORY, 0, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE | CreateOptions.FILE_DELETE_ON_CLOSE, send=False, ), dir_open.close(False, send=False), ] delete_reqs = conn.connection.send_compound( [x[0] for x in delete_msgs], sid=conn.session.session_id, tid=tree.tree_connect_id, related=True, ) for i, request in enumerate(delete_reqs): # A SMBResponseException will be raised if something went wrong response = delete_msgs[i][1](request) def delete_directory( path, share="C$", conn=None, host=None, username=None, password=None ): if HAS_SMBPROTOCOL: return _delete_directory_smbprotocol( path, share, conn=conn, host=host, username=username, password=password ) raise MissingSmb("SMB library required (impacket or smbprotocol)")