def test_change_notify_on_a_file(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection, smb_real[0], smb_real[1])
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "file-watch.txt")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                FilePipePrinterAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_NON_DIRECTORY_FILE)

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME)
            expected = "Received unexpected status from the server: (3221225485) STATUS_INVALID_PARAMETER"
            with pytest.raises(SMBResponseException,
                               match=re.escape(expected)):
                watcher.wait()
        finally:
            connection.disconnect(True)
Example #2
0
def _resolve_dfs(raw_io):
    """
    Resolves a DFS path for a failed Open request.

    :param raw_io: The SMBRawIO to resolve the DFS path for.
    :return: A new Open for each DFS target that was resolved.
    """
    if not raw_io.fd.tree_connect.is_dfs_share:
        return

    # Path is on a DFS root that is linked to another server.
    client_config = ClientConfig()
    raw_path = raw_io.name

    referral = dfs_request(raw_io.fd.tree_connect, raw_path[1:])
    client_config.cache_referral(referral)
    info = client_config.lookup_referral(
        [p for p in raw_path.split("\\") if p])
    connection_kwargs = getattr(raw_io, '_%s__kwargs' % type(raw_io).__name__,
                                {})

    for target in info:
        new_path = raw_path.replace(info.dfs_path, target.target_path, 1)

        try:
            tree, fd_path = get_smb_tree(new_path, **connection_kwargs)

        except SMBResponseException as link_exc:
            log.warning("Failed to connect to DFS link target %s: %s" %
                        (str(target), link_exc))
            continue

        # Record the target that worked for future reference.
        info.target_hint = target
        yield Open(tree, fd_path)
Example #3
0
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)
Example #4
0
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.warn("PATH: %s %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)
Example #5
0
    def test_change_notify_on_a_file(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection, smb_real[0], smb_real[1])
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "file-watch.txt")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                FilePipePrinterAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_NON_DIRECTORY_FILE)

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME)
            with pytest.raises(InvalidParameter):
                watcher.wait()
        finally:
            connection.disconnect(True)
Example #6
0
    def cleanup(self):
        """
        Cleans up any old services or payloads that may have been left behind
        on a previous failure. This will search C:\\Windows for any files
        starting with PAExec-*.exe and delete them. It will also stop and
        remove any services that start with PAExec-* if they exist.

        Before calling this function, the connect() function must have already
        been called.
        """
        scmr = self._service._scmr
        services = scmr.enum_services_status_w(
            self._service._scmr_handle, ServiceType.SERVICE_WIN32_OWN_PROCESS,
            EnumServiceState.SERVICE_STATE_ALL)
        for service in services:
            if service['service_name'].lower().startswith("paexec"):
                svc = Service(service['service_name'], self.session)
                svc.open()
                svc.delete()

        smb_tree = TreeConnect(self.session,
                               r"\\%s\ADMIN$" % self.connection.server_name)
        smb_tree.connect()

        share = Open(smb_tree, "")
        query_msgs = [
            share.create(ImpersonationLevel.Impersonation,
                         DirectoryAccessMask.FILE_READ_ATTRIBUTES
                         | DirectoryAccessMask.SYNCHRONIZE
                         | DirectoryAccessMask.FILE_LIST_DIRECTORY,
                         FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                         ShareAccess.FILE_SHARE_READ
                         | ShareAccess.FILE_SHARE_WRITE
                         | ShareAccess.FILE_SHARE_DELETE,
                         CreateDisposition.FILE_OPEN,
                         CreateOptions.FILE_DIRECTORY_FILE,
                         send=False),
            share.query_directory("PAExec-*.exe",
                                  FileInformationClass.FILE_NAMES_INFORMATION,
                                  send=False),
            share.close(False, send=False)
        ]
        query_reqs = self.connection.send_compound([x[0] for x in query_msgs],
                                                   self.session.session_id,
                                                   smb_tree.tree_connect_id,
                                                   related=True)
        # receive response for open and close
        query_msgs[0][1](query_reqs[0])
        query_msgs[2][1](query_reqs[2])
        try:
            # receive the response for query_directory
            files = query_msgs[1][1](query_reqs[1])
        except SMBResponseException as exc:
            if exc.status != NtStatus.STATUS_NO_SUCH_FILE:
                raise exc
            files = []

        for file in files:
            file_name = file['file_name'].get_value().decode('utf-16-le')
            self._delete_file(smb_tree, file_name)
Example #7
0
    def create_service(self):
        # check if the service exists and delete it
        log.debug("Ensuring service is deleted before starting")
        self._service.delete()

        # copy across the PAExec payload to C:\Windows\
        smb_tree = TreeConnect(self.session,
                               r"\\%s\ADMIN$" % self.connection.server_name)
        log.info("Connecting to SMB Tree %s" % smb_tree.share_name)
        smb_tree.connect()
        paexec_file = Open(smb_tree, self._exe_file)
        log.debug("Creating open to PAExec file")
        paexec_file.open(ImpersonationLevel.Impersonation,
                         FilePipePrinterAccessMask.FILE_WRITE_DATA,
                         FileAttributes.FILE_ATTRIBUTE_NORMAL,
                         ShareAccess.FILE_SHARE_READ,
                         CreateDisposition.FILE_OVERWRITE_IF,
                         CreateOptions.FILE_NON_DIRECTORY_FILE)
        log.info("Creating PAExec executable at %s\\%s" %
                 (smb_tree.share_name, self._exe_file))
        for (data, o) in paexec_out_stream(self.connection.max_write_size):
            paexec_file.write(data, o)
        log.debug("Closing open to PAExec file")
        paexec_file.close(False)
        log.info("Disconnecting from SMB Tree %s" % smb_tree.share_name)
        smb_tree.disconnect()

        # create the PAExec service
        service_path = r'"%SystemRoot%\{0}" -service'.format(self._exe_file)
        log.info("Creating PAExec service %s" % self.service_name)
        self._service.create(service_path)
    def test_change_notify_underlying_close(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection, smb_real[0], smb_real[1])
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "directory-watch")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                DirectoryAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_DIRECTORY_FILE)

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME)
            assert watcher.result is None
            assert watcher.response_event.is_set() is False

            open.close()

            expected = "Received unexpected status from the server: (267) STATUS_NOTIFY_CLEANUP"
            with pytest.raises(SMBResponseException,
                               match=re.escape(expected)):
                watcher.wait()
        finally:
            connection.disconnect(True)
Example #9
0
    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
Example #10
0
 def _delete_file(self, tree, name):
     file_open = Open(tree, name)
     file_open.open(
         ImpersonationLevel.Impersonation, FilePipePrinterAccessMask.DELETE,
         FileAttributes.FILE_ATTRIBUTE_NORMAL, 0,
         CreateDisposition.FILE_OPEN_IF,
         CreateOptions.FILE_NON_DIRECTORY_FILE
         | CreateOptions.FILE_DELETE_ON_CLOSE)
     file_open.close(get_attributes=False)
 def _remove_file(self, tree, name):
     file_open = Open(tree, name)
     file_open.create(
         ImpersonationLevel.Impersonation, FilePipePrinterAccessMask.DELETE,
         FileAttributes.FILE_ATTRIBUTE_NORMAL, ShareAccess.FILE_SHARE_READ
         | ShareAccess.FILE_SHARE_WRITE | ShareAccess.FILE_SHARE_DELETE,
         CreateDisposition.FILE_OPEN_IF,
         CreateOptions.FILE_NON_DIRECTORY_FILE
         | CreateOptions.FILE_DELETE_ON_CLOSE),
     file_open.close()
Example #12
0
 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
Example #13
0
    def _get_paexec_files_and_services(self, client):
        server = os.environ['PYPSEXEC_SERVER']
        username = os.environ.get('PYPSEXEC_USERNAME', None)
        password = os.environ.get('PYPSEXEC_PASSWORD', None)
        paexec_services = []

        # need to close and reopen the connection to ensure deletes are
        # processed
        client.disconnect()
        client = Client(server, username=username, password=password)
        client.connect()
        scmr = client._service._scmr
        scmr_handle = client._service._scmr_handle

        services = scmr.enum_services_status_w(scmr_handle,
                                               ServiceType.
                                               SERVICE_WIN32_OWN_PROCESS,
                                               EnumServiceState.
                                               SERVICE_STATE_ALL)
        for service in services:
            if service['service_name'].lower().startswith("paexec"):
                paexec_services.append(service['service_name'])

        smb_tree = TreeConnect(client.session,
                               r"\\%s\ADMIN$" % client.connection.server_name)
        smb_tree.connect()

        share = Open(smb_tree, "")
        share.create(ImpersonationLevel.Impersonation,
                     DirectoryAccessMask.FILE_READ_ATTRIBUTES |
                     DirectoryAccessMask.SYNCHRONIZE |
                     DirectoryAccessMask.FILE_LIST_DIRECTORY,
                     FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                     ShareAccess.FILE_SHARE_READ |
                     ShareAccess.FILE_SHARE_WRITE |
                     ShareAccess.FILE_SHARE_DELETE,
                     CreateDisposition.FILE_OPEN,
                     CreateOptions.FILE_DIRECTORY_FILE)
        try:
            paexec_files = share.query_directory("PAExec-*.exe",
                                                 FileInformationClass.
                                                 FILE_NAMES_INFORMATION)
        except SMBResponseException as exc:
            if exc.status != NtStatus.STATUS_NO_SUCH_FILE:
                raise exc
            paexec_files = []

        return client, paexec_services, paexec_files
Example #14
0
def open_pipe(tree, name, access_mask, fsctl_wait=False):
    """
    Opened the requested pipe with the access mask specified. Will attempt
    to connect 3 times before failing in case the pipe's don't exist at the
    time.

    :param tree: The SMB TreeConnect of IPC$ to connect to
    :param name: The name of the pipe to connect to
    :param access_mask: The access mask to apply to the Open
    :param fsctl_wait: Runs the FSCTL_PIPE_WAIT command over an
        SMB2IOCTLRequest
    :return: A connected Open() object of the pipe
    """
    log.info("Creating SMB Open for pipe: %s" % name)
    pipe = Open(tree, name)

    if fsctl_wait:
        wait_pipe = SMB2IOCTLRequest()
        wait_pipe['ctl_code'] = CtlCode.FSCTL_PIPE_WAIT
        wait_pipe['file_id'] = b"\xff" * 16
        wait_pipe['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL

        fsctl_data = FSCTLPipeWait()
        fsctl_data['name'] = name.encode('utf-16-le')
        wait_pipe['buffer'] = fsctl_data

        log.info("Sending FSCTL_PIPE_WAIT for pipe %s" % name)
        log.debug(str(fsctl_data))
        request = tree.session.connection.send(
            wait_pipe,
            sid=tree.session.session_id,
            tid=tree.tree_connect_id
        )

        log.info("Receiving FSCTL_PIPE_WAIT response for pipe: %s"
                 % name)
        tree.session.connection.receive(request)

    pipe.create(ImpersonationLevel.Impersonation,
                access_mask,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                0,
                CreateDisposition.FILE_OPEN,
                CreateOptions.FILE_NON_DIRECTORY_FILE |
                CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT)

    return pipe
Example #15
0
    def __init__(self,
                 path,
                 mode='r',
                 share_access=None,
                 desired_access=None,
                 file_attributes=None,
                 create_options=0,
                 buffer_size=MAX_PAYLOAD_SIZE,
                 **kwargs):
        tree, fd_path = get_smb_tree(path, **kwargs)
        self.share_access = share_access
        self.fd = Open(tree, fd_path)
        self._mode = mode
        self._name = path
        self._offset = 0
        self._flush = False
        self._buffer_size = buffer_size
        self.__kwargs = kwargs  # Used in open for DFS referrals

        if desired_access is None:
            desired_access = 0

            # While we can open a directory, the values for FilePipePrinterAccessMask also apply to Dirs so just use
            # the same enum to simplify code.
            if 'r' in self.mode or '+' in self.mode:
                desired_access |= FilePipePrinterAccessMask.FILE_READ_DATA | \
                                  FilePipePrinterAccessMask.FILE_READ_ATTRIBUTES | \
                                  FilePipePrinterAccessMask.FILE_READ_EA
            if 'w' in self.mode or 'x' in self.mode or 'a' in self.mode or '+' in self.mode:
                desired_access |= FilePipePrinterAccessMask.FILE_WRITE_DATA | \
                                  FilePipePrinterAccessMask.FILE_WRITE_ATTRIBUTES | \
                                  FilePipePrinterAccessMask.FILE_WRITE_EA
        self._desired_access = desired_access

        if file_attributes is None:
            file_attributes = FileAttributes.FILE_ATTRIBUTE_DIRECTORY if self.FILE_TYPE == 'dir' \
                else FileAttributes.FILE_ATTRIBUTE_NORMAL
        self._file_attributes = file_attributes

        self._create_options = create_options
        self._create_options |= {
            'dir': CreateOptions.FILE_DIRECTORY_FILE,
            'file': CreateOptions.FILE_NON_DIRECTORY_FILE,
        }.get(self.FILE_TYPE, 0)

        super(SMBRawIO, self).__init__()
    def test_change_notify_cancel(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection,
                          smb_real[0],
                          smb_real[1],
                          require_encryption=False)
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "directory-watch")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                DirectoryAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_DIRECTORY_FILE)

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME)
            assert watcher.result is None
            assert watcher.response_event.is_set() is False

            # Makes sure that we cancel after the async response has been returned from the server.
            while watcher._request.async_id is None:
                pass

            assert watcher.result is None

            watcher.cancel()

            watcher.wait()
            assert watcher.cancelled is True
            assert watcher.result is None

            # Make sure it doesn't cause any weird errors when calling it again
            watcher.cancel()
        finally:
            connection.disconnect(True)
Example #17
0
    def session(self):
        server = os.environ.get('PYPSEXEC_SERVER', None)
        username = os.environ.get('PYPSEXEC_USERNAME', None)
        password = os.environ.get('PYPSEXEC_PASSWORD', None)

        if server:
            connection = Connection(uuid.uuid4(), server, 445)
            session = Session(connection, username, password)
            tree = TreeConnect(session, r"\\%s\ADMIN$" % server)
            paexec_file = Open(tree, "PAExec.exe")

            connection.connect()
            try:

                session.connect()
                tree.connect()

                paexec_file.create(ImpersonationLevel.Impersonation,
                                   FilePipePrinterAccessMask.FILE_WRITE_DATA,
                                   FileAttributes.FILE_ATTRIBUTE_NORMAL,
                                   ShareAccess.FILE_SHARE_READ,
                                   CreateDisposition.FILE_OVERWRITE_IF,
                                   CreateOptions.FILE_NON_DIRECTORY_FILE)
                paexec_file.write(pkgutil.get_data('pypsexec', 'paexec.exe'),
                                  0)
                paexec_file.close(get_attributes=False)

                yield session
            finally:
                paexec_file.create(ImpersonationLevel.Impersonation,
                                   FilePipePrinterAccessMask.DELETE,
                                   FileAttributes.FILE_ATTRIBUTE_NORMAL,
                                   ShareAccess.FILE_SHARE_DELETE,
                                   CreateDisposition.FILE_OVERWRITE_IF,
                                   CreateOptions.FILE_DELETE_ON_CLOSE)
                paexec_file.close(get_attributes=False)
                connection.disconnect(True)

        else:
            pytest.skip("PYPSEXEC_SERVER, PYPSEXEC_USERNAME, PYPSEXEC_PASSWORD"
                        " environment variables were not set. Integration "
                        "tests will be skipped")
 def _delete_file(self, tree, name):
     file_open = Open(tree, name)
     msgs = [
         file_open.create(ImpersonationLevel.Impersonation,
                          FilePipePrinterAccessMask.DELETE,
                          FileAttributes.FILE_ATTRIBUTE_NORMAL,
                          0,
                          CreateDisposition.FILE_OPEN_IF,
                          CreateOptions.FILE_NON_DIRECTORY_FILE
                          | CreateOptions.FILE_DELETE_ON_CLOSE,
                          send=False),
         file_open.close(get_attributes=False, send=False)
     ]
     reqs = self.connection.send_compound([x[0] for x in msgs],
                                          sid=self.session.session_id,
                                          tid=tree.tree_connect_id,
                                          related=True)
     # remove the responses from the SMB outstanding requests
     msgs[0][1](reqs[0])
     msgs[1][1](reqs[1])
Example #19
0
 def __init__(self, smb_session):
     # connect to the IPC tree and open a handle at svcctl
     self.tree = TreeConnect(
         smb_session, r"\\%s\IPC$" % smb_session.connection.server_name)
     self.handle = Open(self.tree, "svcctl")
     self.call_id = 0
Example #20
0
    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_name)
    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, create_contexts)

    # as the raw structure 'maximal_access' is an IntField, we create our own
    # flag field, set the value and get the human readble string
    max_access = FlagField(size=4,
                           flag_type=FilePipePrinterAccessMask,
                           flag_strict=False)
    max_access.set_value(open_info[0]['maximal_access'].get_value())
Example #21
0
    def open(self, transaction=None):
        if not self.closed:
            return

        share_access = _parse_share_access(self.share_access, self.mode)
        create_disposition = _parse_mode(self.mode, invalid=self._INVALID_MODE)

        try:
            # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wpo/feeb3122-cfe0-4b34-821d-e31c036d763c
            # Impersonation on SMB has little meaning when opening files but is important if using RPC so set to a sane
            # default of Impersonation.
            open_result = self.fd.create(
                ImpersonationLevel.Impersonation,
                self._desired_access,
                self._file_attributes,
                share_access,
                create_disposition,
                self._create_options,
                send=(transaction is None),
            )
        except (PathNotCovered, ObjectNameNotFound, ObjectPathNotFound) as exc:
            # The MS-DFSC docs status that STATUS_PATH_NOT_COVERED is used when encountering a link to a different
            # server but Samba seems to return the generic name or path not found.
            if not self.fd.tree_connect.is_dfs_share:
                raise SMBOSError(exc.status, self.name)

            # Path is on a DFS root that is linked to another server.
            client_config = ClientConfig()
            referral = dfs_request(self.fd.tree_connect, self.name[1:])
            client_config.cache_referral(referral)
            info = client_config.lookup_referral([p for p in self.name.split("\\") if p])

            for target in info:
                new_path = self.name.replace(info.dfs_path, target.target_path, 1)

                try:
                    tree, fd_path = get_smb_tree(new_path, **self.__kwargs)
                    self.fd = Open(tree, fd_path)
                    self.open(transaction=transaction)

                except SMBResponseException as link_exc:
                    log.warning("Failed to connect to DFS link target %s: %s" % (str(target), link_exc))

                else:
                    # Record the target that worked for future reference.
                    info.target_hint = target
                    break

            else:
                # None of the targets worked so raise the original error.
                raise SMBOSError(exc.status, self.name)

            return

        except SMBResponseException as exc:
            raise SMBOSError(exc.status, self.name)

        if transaction is not None:
            transaction += open_result
        elif 'a' in self.mode and self.FILE_TYPE != 'pipe':
            self._offset = self.fd.end_of_file
    def test_change_notify_no_data(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection, smb_real[0], smb_real[1])
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "directory-watch")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                DirectoryAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_DIRECTORY_FILE)

            self._remove_file(tree, "directory-watch\\created file")

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME,
                          output_buffer_length=0)
            assert watcher.result is None
            assert watcher.response_event.is_set() is False

            # Run the wait in a separate thread so we can create the dir
            def watcher_wait():
                watcher.wait()

            watcher_wait_thread = threading.Thread(target=watcher_wait)
            watcher_wait_thread.daemon = True
            watcher_wait_thread.start()

            def watcher_event():
                watcher.response_event.wait()

            watcher_event_thread = threading.Thread(target=watcher_event)
            watcher_event_thread.daemon = True
            watcher_event_thread.start()

            # Create the new file
            file_open = Open(tree, "directory-watch\\created file")
            file_open.create(
                ImpersonationLevel.Impersonation,
                FilePipePrinterAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_NON_DIRECTORY_FILE)
            file_open.close()

            watcher_wait_thread.join(timeout=2)
            watcher_event_thread.join(timeout=2)
            assert watcher_wait_thread.is_alive() is False
            assert watcher_event_thread.is_alive() is False

            assert watcher.response_event.is_set()
            assert watcher.result == []

            open.close()
        finally:
            connection.disconnect(True)
    def test_change_notify_on_dir_compound(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()

        # Cannot use encryption as Samba has a bug where the transform response has the wrong Session Id. Also there's
        # a special edge case of testing the Session Id of the plaintext response with signatures so don't use
        # encryption.
        # https://bugzilla.samba.org/show_bug.cgi?id=14189
        session = Session(connection,
                          smb_real[0],
                          smb_real[1],
                          require_encryption=False)
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "directory-watch")
        try:
            session.connect()
            tree.connect()

            # Ensure the dir is clean of files.
            open.create(
                ImpersonationLevel.Impersonation,
                DirectoryAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_DIRECTORY_FILE)
            self._remove_file(tree, "directory-watch\\created file")
            open.close()

            watcher = FileSystemWatcher(open)
            messages = [
                open.create(ImpersonationLevel.Impersonation,
                            DirectoryAccessMask.MAXIMUM_ALLOWED,
                            FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                            ShareAccess.FILE_SHARE_READ
                            | ShareAccess.FILE_SHARE_WRITE
                            | ShareAccess.FILE_SHARE_DELETE,
                            CreateDisposition.FILE_OPEN_IF,
                            CreateOptions.FILE_DIRECTORY_FILE,
                            send=False),
                watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME,
                              send=False)
            ]

            assert watcher.result is None
            assert watcher.response_event.is_set() is False

            requests = connection.send_compound([m[0] for m in messages],
                                                sid=session.session_id,
                                                tid=tree.tree_connect_id,
                                                related=True)
            [messages[i][1](req) for i, req in enumerate(requests)]

            # Run the wait in a separate thread so we can create the dir
            def watcher_wait():
                watcher.wait()

            watcher_wait_thread = threading.Thread(target=watcher_wait)
            watcher_wait_thread.daemon = True
            watcher_wait_thread.start()

            def watcher_event():
                watcher.response_event.wait()

            watcher_event_thread = threading.Thread(target=watcher_event)
            watcher_event_thread.daemon = True
            watcher_event_thread.start()

            # Create the new file
            file_open = Open(tree, "directory-watch\\created file")
            file_open.create(
                ImpersonationLevel.Impersonation,
                FilePipePrinterAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_NON_DIRECTORY_FILE)
            file_open.close()

            watcher_wait_thread.join(timeout=2)
            watcher_event_thread.join(timeout=2)
            assert watcher_wait_thread.is_alive() is False
            assert watcher_event_thread.is_alive() is False

            assert watcher.response_event.is_set()
            assert len(watcher.result) == 1

            assert watcher.result[0]['file_name'].get_value(
            ) == u"created file"
            assert watcher.result[0]['action'].get_value(
            ) == FileAction.FILE_ACTION_ADDED

            open.close()
        finally:
            connection.disconnect(True)
Example #24
0
username = "******"
password = "******"
share = r"\\%s\share" % server
dir_name = "directory"

connection = Connection(uuid.uuid4(), server, port)
connection.connect()

try:
    session = Session(connection, username, password)
    session.connect()
    tree = TreeConnect(session, share)
    tree.connect()

    # ensure directory is created
    dir_open = Open(tree, dir_name)
    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)

    # create some files in dir and query the contents as part of a compound
    # request
    directory_file = Open(tree, r"%s\file.txt" % dir_name)
    directory_file.create(
        ImpersonationLevel.Impersonation,
        FilePipePrinterAccessMask.GENERIC_WRITE
        | FilePipePrinterAccessMask.DELETE,
        FileAttributes.FILE_ATTRIBUTE_NORMAL, ShareAccess.FILE_SHARE_READ,