Beispiel #1
0
    def test_create_message(self):
        share = u'\\\\server\\shares\\%s' % UNICODE_TEXT

        message = DFSReferralRequestEx()
        message['max_referral_level'] = 4
        message['request_flags'] = DFSReferralRequestFlags.SITE_NAME
        message['request_file_name'] = share
        message['site_name'] = UNICODE_TEXT

        expected = b"\x04\x00" \
                   b"\x01\x00" \
                   b"\x44\x00\x00\x00" \
                   b"\x30\x00" \
                   b"\x5C\x00\x5C\x00\x73\x00\x65\x00" \
                   b"\x72\x00\x76\x00\x65\x00\x72\x00" \
                   b"\x5C\x00\x73\x00\x68\x00\x61\x00" \
                   b"\x72\x00\x65\x00\x73\x00\x5C\x00" \
                   b"\x55\x00\x08\x03\x73\x00\x65\x00" \
                   b"\xDC\x04\x34\xD8\x1E\xDD\x00\x00" \
                   b"\x10\x00" \
                   b"\x55\x00\x08\x03\x73\x00\x65\x00" \
                   b"\xDC\x04\x34\xD8\x1E\xDD\x00\x00"
        actual = message.pack()

        assert len(message) == 76
        assert actual == expected
        assert str(message['request_file_name']) == to_native(share)
        assert str(message['site_name']) == to_native(UNICODE_TEXT)
    def __str__(self):
        struct_name = self.__class__.__name__
        raw_hex = _bytes_to_hex(self.pack(), True, hex_per_line=0)
        field_strings = []

        for name, field in self.fields.items():
            # the field header is slightly different for a StructureField
            # remove the leading space and put the value on the next line
            if isinstance(field, StructureField):
                field_header = "%s =\n%s"
            else:
                field_header = "%s = %s"

            field_string = field_header % (field.name, str(field))
            field_strings.append(_indent_lines(field_string, TAB))

        field_strings.append("")
        field_strings.append(_indent_lines("Raw Hex:", TAB))
        hex_wrapper = textwrap.TextWrapper(
            width=33,  # set to show 8 hex values per line, 33 for 8, 56 for 16
            initial_indent=TAB + TAB,
            subsequent_indent=TAB + TAB)
        field_strings.append(hex_wrapper.fill(raw_hex))

        string = "%s:\n%s" % (to_native(struct_name), '\n'.join(
            [to_native(s) for s in field_strings]))

        return string
Beispiel #3
0
    def __init__(self, ntstatus, filename, filename2=None):
        self.ntstatus = ntstatus
        self.filename2 = to_native(filename2) if filename2 else None

        ntstatus_name = 'STATUS_UNKNOWN'
        for name, val in vars(NtStatus).items():
            if ntstatus == val:
                ntstatus_name = name
                break

        error_details = {
            NtStatus.STATUS_OBJECT_NAME_NOT_FOUND: errno.ENOENT,
            NtStatus.STATUS_OBJECT_PATH_NOT_FOUND: errno.ENOENT,
            NtStatus.STATUS_OBJECT_NAME_COLLISION: errno.EEXIST,
            NtStatus.STATUS_PRIVILEGE_NOT_HELD: (errno.EACCES, "Required privilege not held"),
            NtStatus.STATUS_SHARING_VIOLATION: (errno.EPERM, "The process cannot access the file because it is being "
                                                             "used by another process"),
            NtStatus.STATUS_NOT_A_REPARSE_POINT: (errno.EINVAL, "The file or directory is not a reparse point"),
            NtStatus.STATUS_FILE_IS_A_DIRECTORY: errno.EISDIR,
            NtStatus.STATUS_NOT_A_DIRECTORY: errno.ENOTDIR,
            NtStatus.STATUS_DIRECTORY_NOT_EMPTY: errno.ENOTEMPTY,
            NtStatus.STATUS_END_OF_FILE: getattr(errno, 'ENODATA', 120),  # Not present on py2 for Windows.
        }.get(ntstatus, (0, "Unknown NtStatus error returned '%s'" % ntstatus_name))

        if not isinstance(error_details, tuple):
            error_details = (error_details, os.strerror(error_details))

        super(SMBOSError, self).__init__(error_details[0], error_details[1], to_native(filename))
Beispiel #4
0
    def message(self):  # type: () -> str
        error_details = []

        for detail in self.error_details:
            if isinstance(detail, SMB2SymbolicLinkErrorResponse):
                flag = str(detail['flags'])
                print_name = detail.get_print_name()
                sub_name = detail.get_substitute_name()
                error_details.append("Flag: %s, Print Name: %s, Substitute Name: %s" % (flag, print_name, sub_name))

            elif isinstance(detail, SMB2ShareRedirectErrorContext):
                ip_addresses = []
                for ip_addr in detail['ip_addr_move_list'].get_value():
                    ip_addresses.append(ip_addr.get_ipaddress())

                resource_name = to_text(detail['resource_name'].get_value(), encoding='utf-16-le')
                error_details.append("IP Addresses: '%s', Resource Name: %s"
                                     % ("', '".join(ip_addresses), resource_name))

            else:
                # unknown error details in response, output raw bytes
                error_details.append("Raw: %s" % to_text(binascii.hexlify(detail)))

        error_msg = '%s %s: 0x%s' % (self._BASE_MESSAGE, str(self.header['status']), format(self.status, 'x').zfill(8))
        if error_details:
            error_msg += " - %s" % ", ".join(error_details)

        return to_native("Received unexpected status from the server: %s" % error_msg)
 def test_create_message(self):
     message = FileNotifyInformation()
     message['action'] = 1
     message['file_name'] = u"café"
     actual = message.pack()
     assert len(message) == 20
     assert actual == self.DATA
     assert str(message['file_name']) == to_native(u"café")
Beispiel #6
0
    def test_resolve_path_different_host(self):
        b_sub_name = to_bytes(u'\\??\\UNC\\sérver\\sharé2\\foldér', encoding='utf-16-le')
        b_print_name = to_bytes(u'\\\\sérver\\sharé2\\foldér', encoding='utf-16-le')
        resp = SMB2SymbolicLinkErrorResponse()
        resp['unparsed_path_length'] = 0
        resp['substitute_name_offset'] = 0
        resp['substitute_name_length'] = len(b_sub_name)
        resp['print_name_offset'] = len(b_sub_name)
        resp['print_name_length'] = len(b_print_name)
        resp['flags'] = SymbolicLinkErrorFlags.SYMLINK_FLAG_ABSOLUTE
        resp['path_buffer'] = b_sub_name + b_print_name

        link_path = u'\\\\sérver\\sharé\\foldér'
        expected = u"Encountered symlink at '%s' that points to '\\\\sérver\\sharé2\\foldér' which cannot be " \
                   u"redirected: Cannot resolve link targets that point to a different host/share" % link_path
        with pytest.raises(SMBLinkRedirectionError, match=re.escape(to_native(expected))):
            resp.resolve_path(link_path)
Beispiel #7
0
 def message(self):
     msg = "Encountered symlink at '%s' that points to '%s' which cannot be redirected: %s" \
           % (to_native(self.path), to_native(self.target), to_native(self.args[0]))
     return msg
def copyfile(src, dst, follow_symlinks=True, **kwargs):
    """
    Copy the contents (no metadata) of the file names src to a file named dst and return dst in the most efficient way
    possible. If the src and dst reside on the same UNC share then a more efficient remote side copy is used. If the
    src and dst reside on the same local path then the proper shutil.copyfile() method is called, otherwise the content
    is copied using copyfileobj() in chunks.

    dst must be the complete target file name; look at copy() for a copy that accepts a target directory path. If src
    dst specify the same file, ValueError is raised.

    The destination location must be writable; otherwise, an OSError exception will be raised. If dst already exists,
    it will be replaced. Special files such as character or block devices and pipes cannot be copied with this
    function.

    If follow_symlinks is 'False' and src is a symbolic link, a new symbolic link will be created instead of copying
    the file src points to. This will fail if the symbolic link at src is a different root as dst.

    :param src: The src filepath to copy.
    :param dst: The destinoation filepath to copy to.
    :param follow_symlinks: Whether to copy the symlink target of source or the symlink itself.
    :param kwargs: Common arguments used to build the SMB Session for any UNC paths.
    :return: The dst path.
    """
    def wrap_not_implemented(function_name):
        def raise_not_implemented(*args, **kwargs):
            raise NotImplementedError(
                "%s is unavailable on this platform as a local operation" %
                function_name)

        return raise_not_implemented

    norm_src = ntpath.normpath(src)
    if norm_src.startswith('\\\\'):
        src_root = ntpath.splitdrive(norm_src)[0]
        islink_func = islink
        readlink_func = readlink
        symlink_func = symlink
        src_open = open_file
        src_kwargs = kwargs
    else:
        src_root = None
        islink_func = os.path.islink
        # readlink and symlink are not available on Windows on Python 2.
        readlink_func = getattr(os, 'readlink',
                                wrap_not_implemented('readlink'))
        symlink_func = getattr(os, 'symlink', wrap_not_implemented('symlink'))
        src_open = open
        src_kwargs = {}

    norm_dst = ntpath.normpath(dst)
    if norm_dst.startswith('\\\\'):
        dst_root = ntpath.splitdrive(norm_dst)[0]
        dst_open = open_file
        dst_kwargs = kwargs
    else:
        dst_root = None
        dst_open = open
        dst_kwargs = {}

    if not follow_symlinks and islink_func(src, **src_kwargs):
        if src_root != dst_root:
            raise ValueError("Cannot copy a symlink on different roots.")

        symlink_func(readlink_func(src), dst, **src_kwargs)
        return dst

    if src_root is None and dst_root is None:
        # The files are local and follow_symlinks is True, rely on the builtin copyfile mechanism.
        shutil.copyfile(src, dst)
        return dst

    if src_root == dst_root:
        # The files are located on the same share and follow_symlinks is True, rely on smbclient.copyfile for an
        # efficient server side copy.
        try:
            is_same = samefile(src, dst, **kwargs)
        except OSError as err:
            if err.errno == errno.ENOENT:
                is_same = False
            else:
                raise

        if is_same:
            raise shutil.Error(
                to_native("'%s' and '%s' are the same file, cannot copy" %
                          (src, dst)))

        smbclient_copyfile(src, dst, **kwargs)
        return dst

    # Finally we are copying across different roots so we just chunk the data using copyfileobj
    with src_open(src, mode='rb',
                  **src_kwargs) as src_fd, dst_open(dst,
                                                    mode='wb',
                                                    **dst_kwargs) as dst_fd:
        copyfileobj(src_fd, dst_fd, MAX_PAYLOAD_SIZE)

    return dst