Exemplo n.º 1
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 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
Exemplo n.º 2
0
 def test_caught_with_oserror(self):
     with pytest.raises(OSError) as err:
         raise SMBOSError(NtStatus.STATUS_OBJECT_NAME_NOT_FOUND,
                          u"filéname")
     assert str(
         err.value
     ) == "[Error 2] [NtStatus 0xc0000034] No such file or directory: 'filéname'"
Exemplo n.º 3
0
    def commit(self):
        """
        Sends a compound request to the server. Optionally opens and closes a handle in the same request if the handle
        is not already opened.

        :return: A list of each response for the requests set on the transaction.
        """
        remove_index = []
        if self.raw.closed:
            self.raw.open(transaction=self)
            self._actions.insert(
                0,
                self._actions.pop(-1))  # Need to move the create to the start
            remove_index.append(0)

            self.raw.close(transaction=self)
            remove_index.append(len(self._actions) - 1)

        send_msgs = []
        unpack_functions = []
        for action in self._actions:
            send_msgs.append(action[0])
            unpack_functions.append(action[1])

        sid = self.raw.fd.tree_connect.session.session_id
        tid = self.raw.fd.tree_connect.tree_connect_id
        requests = self.raw.fd.connection.send_compound(send_msgs,
                                                        sid,
                                                        tid,
                                                        related=True)

        # Due to a wonderful threading issue we need to ensure we call .receive() for each message we sent so cannot
        # just enumerate the list in 1 line in case it throws an exception.
        failures = []
        responses = []
        for idx, func in enumerate(unpack_functions):
            try:
                responses.append(func(requests[idx]))
            except SMBResponseException as exc:
                failures.append(SMBOSError(exc.status, self.raw.name))

        # If there was a failure, just raise the first exception found.
        if failures:
            raise failures[0]

        remove_index.sort(
            reverse=True)  # Need to remove from highest index first.
        [responses.pop(i) for i in remove_index
         ]  # Remove the open and close response if commit() did that work.
        self.results = tuple(responses)
Exemplo n.º 4
0
 def test_error_with_override(self):
     with pytest.raises(SMBOSError) as err:
         raise SMBOSError(NtStatus.STATUS_PRIVILEGE_NOT_HELD, u"filéname")
     assert str(err.value) == "[Error 13] [NtStatus 0xc0000061] Required privilege not held: 'filéname'"
Exemplo n.º 5
0
 def test_error_with_unknown_error(self):
     with pytest.raises(SMBOSError) as err:
         raise SMBOSError(1, u"filéname")
     assert str(err.value) == "[Error 0] [NtStatus 0x00000001] Unknown NtStatus error returned 'STATUS_UNKNOWN': " \
                              "'filéname'"
Exemplo n.º 6
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
Exemplo n.º 7
0
    def commit(self):
        """
        Sends a compound request to the server. Optionally opens and closes a handle in the same request if the handle
        is not already opened.
        """
        remove_index = []
        if (self.raw.closed and
            (not self._actions
             or not isinstance(self._actions[0][0], SMB2CreateRequest))):
            self.raw.open(transaction=self)
            self._actions.insert(
                0,
                self._actions.pop(-1))  # Need to move the create to the start
            remove_index.insert(0, 0)

            self.raw.close(transaction=self)
            remove_index.insert(0, len(self._actions) - 1)

        send_msgs = []
        unpack_functions = []
        for action in self._actions:
            send_msgs.append(action[0])
            unpack_functions.append(action[1])

        sid = self.raw.fd.tree_connect.session.session_id
        tid = self.raw.fd.tree_connect.tree_connect_id
        requests = self.raw.fd.connection.send_compound(send_msgs,
                                                        sid,
                                                        tid,
                                                        related=True)

        # Due to a wonderful threading issue we need to ensure we call .receive() for each message we sent so cannot
        # just enumerate the list in 1 line in case it throws an exception.
        failures = []
        responses = []
        try_again = False
        for idx, func in enumerate(unpack_functions):
            res = None

            try:
                try:
                    res = func(requests[idx])

                except (PathNotCovered, ObjectNameNotFound,
                        ObjectPathNotFound):
                    # The MS-DFSC docs state 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 the first action is not a CreateRequest then we can't resolve the DFS path in the transaction.
                    if not (idx == 0
                            and isinstance(send_msgs[0], SMB2CreateRequest)):
                        raise

                    for smb_open in _resolve_dfs(self.raw):
                        if smb_open.tree_connect.share_name == self.raw.fd.tree_connect.share_name:
                            continue

                        self.raw.fd = smb_open

                        # In case this is a transaction with an explicit open we want to reopen it with the new params
                        # before trying it again.
                        self.raw.open(transaction=self)
                        self._actions[0] = self._actions.pop(-1)

                        try_again = True
                        break

                    else:
                        # Either there wasn't any DFS referrals or none of them worked, just reraise the error.
                        raise

            except SMBResponseException as exc:
                failures.append(SMBOSError(exc.status, self.raw.name))

            finally:
                responses.append(res)

        # Remove the existing open/close actions this transaction added internally.
        for idx in remove_index:
            del self._actions[idx]
            del responses[idx]

        if try_again:
            # If we updated the SMB Tree due to a DFS referral hit then try again.
            self.commit()

        elif failures:
            # If there was a failure, just raise the first exception found.
            raise failures[0]

        else:
            self.results = tuple(responses)