signing: disable signing if authentication failed but guest login is enabled
[scrambla.git] / smb2 / filesystem_info.py
1 # coding: utf-8
2
3 # Copyright (C) 2020 by Ronnie Sahlberg<ronniesahlberg@gmail.com>
4 #
5
6 import struct
7 from enum import Enum
8
9 from smb2.header import Direction
10 from smb2.timestamps import WinToTimeval, TimevalToWin
11 from smb2.unicode import UCS2toUTF8, UTF8toUCS2
12
13 #
14 # SMB2 FILESYSTEM INFORMATION CLASSES
15 #
16 class FSInfoClass(Enum):
17     VOLUME         =  1
18     DEVICE         =  4
19     ATTRIBUTE      =  5
20     FULL_SIZE      =  7
21     SECTOR_SIZE    = 11
22
23 #
24 # DEVICE TYPES
25 #
26 class DeviceType(Enum):
27     CD_ROM = 2
28     DISK   = 7
29
30 #
31 # CHARACTERISTICS
32 #
33 REMOVABLE_MEDIA                     = 0x00000001
34 READ_ONLY_DEVICE                    = 0x00000002
35 FLOPPY_DISKETTE                     = 0x00000004
36 WRITE_ONCE_MEDIA                    = 0x00000008
37 REMOTE_DEVICE                       = 0x00000010
38 DEVICE_IS_MOUNTED                   = 0x00000020
39 VIRTUAL_VOLUME                      = 0x00000040
40 DEVICE_SECURE_OPEN                  = 0x00000100
41 CHARACTERISTICS_TS_DEVICE           = 0x00001000
42 CHARACTERISTICS_WEBDAV_DEVICE       = 0x00001000
43 DEVICE_ALLOW_APPCONTAINER_TRAVERSAL = 0x00002000
44 PORTABLE_DEVICE                     = 0x00004000
45
46 #
47 # ATTRIBUTES
48 #
49 SUPPORTS_SPARSE_VDL                     = 0x10000000
50 SUPPORTS_BLOCK_REFCOUNTING              = 0x08000000
51 SUPPORTS_INTEGRITY_STREAMS              = 0x04000000
52 SUPPORTS_USN_JOURNAL                    = 0x02000000
53 SUPPORTS_OPEN_BY_FILE_ID                = 0x01000000
54 SUPPORTS_EXTENDED_ATTRIBUTES            = 0x00800000
55 SUPPORTS_HARD_LINKS                     = 0x00400000
56 SUPPORTS_TRANSACTIONS                   = 0x00200000
57 SEQUENTIAL_WRITE_ONCE                   = 0x00100000
58 READ_ONLY_VOLUME                        = 0x00080000
59 NAMED_STREAMS                           = 0x00040000
60 SUPPORTS_ENCRYPTION                     = 0x00020000
61 SUPPORTS_OBJECT_IDS                     = 0x00010000
62 VOLUME_IS_COMPRESSED                    = 0x00008000
63 SUPPORTS_REMOTE_STORAGE                 = 0x00000100
64 SUPPORTS_REPARSE_POINTS                 = 0x00000080
65 SUPPORTS_SPARSE_FILES                   = 0x00000040
66 VOLUME_QUOTAS                           = 0x00000020
67 FILE_COMPRESSION                        = 0x00000010
68 PERSISTENT_ACLS                         = 0x00000008
69 UNICODE_ON_DISK                         = 0x00000004
70 CASE_PRESERVED_NAMES                    = 0x00000002
71 CASE_SENSITIVE_SEARCH                   = 0x00000001
72
73 #
74 # SECTOR SIZE FLAGS
75 #
76 SSINFO_FLAGS_ALIGNED_DEVICE              = 0x00000001
77 SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE = 0x00000002
78 SSINFO_FLAGS_NO_SEEK_PENALTY             = 0x00000004
79 SSINFO_FLAGS_TRIM_ENABLED                = 0x00000008
80
81
82 def decode_attribute_info(buf):
83     i = {}
84     i.update({'attributes': struct.unpack_from('<I', buf, 0)[0]})
85     i.update({'maximum_component_name_length': struct.unpack_from('<I', buf, 4)[0]})
86     _len = struct.unpack_from('<I', buf, 8)[0]
87     if _len:
88         i.update({'file_system_name': UCS2toUTF8(buf[12:12 + _len])})
89
90     return i
91
92 def encode_attribute_info(i):
93     _b = bytearray(12)
94     struct.pack_into('<I', _b,  0, i['attributes'])
95     struct.pack_into('<I', _b,  4, i['maximum_component_name_length'])
96     _n = UTF8toUCS2(i['file_system_name'])
97     struct.pack_into('<I', _b, 8, len(_n))
98     _b = _b + _n
99
100     return _b
101
102 def decode_device_info(buf):
103     i = {}
104     i.update({'device_type': struct.unpack_from('<I', buf, 0)[0]})
105     i.update({'characteristics': struct.unpack_from('<I', buf, 4)[0]})
106
107     return i
108
109 def encode_device_info(i):
110     _b = bytearray(8)
111     struct.pack_into('<I', _b,  0, i['device_type'])
112     struct.pack_into('<I', _b,  4, i['characteristics'])
113
114     return _b
115
116 def decode_volume_info(buf):
117     i = {}
118     i.update({'creation_time': WinToTimeval(struct.unpack_from('<Q', buf, 0)[0])})
119     i.update({'serial_number': struct.unpack_from('<I', buf, 8)[0]})
120     i.update({'supports_objects': struct.unpack_from('<B', buf, 16)[0]})
121     _len = struct.unpack_from('<I', buf, 12)[0]
122     i.update({'label': UCS2toUTF8(buf[18:18 + _len])})
123
124     return i
125
126 def encode_volume_info(i):
127     _b = bytearray(18)
128     struct.pack_into('<Q', _b,  0, TimevalToWin(i['creation_time']))
129     struct.pack_into('<I', _b,  8, i['serial_number'])
130     struct.pack_into('<B', _b,  16, i['supports_objects'])
131     _lab = UTF8toUCS2(i['label'])
132     struct.pack_into('<I', _b,  12, len(_lab))
133     _b = _b + _lab
134     
135     return _b
136     
137 def encode_sector_size_info(i):
138     _b = bytearray(28)
139     struct.pack_into('<I', _b,  0, i['logical_bytes_per_sector'])
140     struct.pack_into('<I', _b,  4, i['physical_bytes_per_sector_for_atomicity'])
141     struct.pack_into('<I', _b,  8, i['physical_bytes_per_sector_for_performance'])
142     struct.pack_into('<I', _b, 12, i['effective_physical_bytes_per_sector_for_atomicity'])
143     struct.pack_into('<I', _b, 16, i['flags'])
144     struct.pack_into('<I', _b, 20, i['byte_offset_for_sector_alignment'])
145     struct.pack_into('<I', _b, 24, i['byte_offset_for_partition_alignment'])
146
147     return _b
148
149 def decode_sector_size_info(buf):
150     i = {}
151     i.update({'logical_bytes_per_sector': struct.unpack_from('<I', buf, 0)[0]})
152     i.update({'physical_bytes_per_sector_for_atomicity': struct.unpack_from('<I', buf, 4)[0]})
153     i.update({'physical_bytes_per_sector_for_performance': struct.unpack_from('<I', buf, 8)[0]})
154     i.update({'effective_physical_bytes_per_sector_for_atomicity': struct.unpack_from('<I', buf, 12)[0]})
155     i.update({'flags': struct.unpack_from('<I', buf, 16)[0]})
156     i.update({'byte_offset_for_sector_alignment': struct.unpack_from('<I', buf, 20)[0]})
157     i.update({'byte_offset_for_partition_alignment': struct.unpack_from('<I', buf, 24)[0]})
158
159     return i
160
161 def encode_full_size_info(i):
162     _b = bytearray(32)
163     struct.pack_into('<Q', _b,   0, i['total_allocation_units'])
164     struct.pack_into('<Q', _b,   8, i['caller_available_allocation_units'])
165     struct.pack_into('<Q', _b,  16, i['actual_available_allocation_units'])
166     struct.pack_into('<I', _b,  24, i['sectors_per_allocation_unit'])
167     struct.pack_into('<I', _b,  28, i['bytes_per_sector'])
168
169     return _b
170
171 def decode_full_size_info(buf):
172     i = {}
173     i.update({'total_allocation_units': struct.unpack_from('<Q', buf, 0)[0]})
174     i.update({'caller_available_allocation_units': struct.unpack_from('<Q', buf, 8)[0]})
175     i.update({'actual_available_allocation_units': struct.unpack_from('<Q', buf, 16)[0]})
176     i.update({'sectors_per_allocation_unit': struct.unpack_from('<I', buf, 24)[0]})
177     i.update({'bytes_per_sector': struct.unpack_from('<I', buf, 28)[0]})
178
179     return i
180
181     
182 dir_coders = {
183     FSInfoClass.VOLUME: (encode_volume_info,
184                          decode_volume_info),
185     FSInfoClass.DEVICE: (encode_device_info,
186                          decode_device_info),
187     FSInfoClass.ATTRIBUTE: (encode_attribute_info,
188                             decode_attribute_info),
189     FSInfoClass.SECTOR_SIZE: (encode_sector_size_info,
190                               decode_sector_size_info),
191     FSInfoClass.FULL_SIZE: (encode_full_size_info,
192                             decode_full_size_info),
193     }
194
195 class FSInfo(object):
196     """
197     A class for FSInfo
198     """
199
200     def __init__(self, **kwargs):
201         True
202
203     def __del__(self):
204         True
205
206     @staticmethod
207     def decode(dic, buf):
208         if dic in dir_coders:
209             info = dir_coders[dic][1](buf)
210             return info
211         
212         print('Unknown FSInfoClass', dic)
213         return []
214
215     @staticmethod
216     def encode(dic, info):
217         if dic in dir_coders:
218             buf = dir_coders[dic][0](info)
219             return buf
220
221         print('Unknown FSInfoClass', dic)
222         return bytearray(0)