1# -*- coding: utf-8 -*-
2# Copyright: (c) 2020, Jordan Borean (@jborean93) <jborean93@gmail.com>
3# MIT License (see LICENSE or https://opensource.org/licenses/MIT)
4
5from collections import (
6    OrderedDict,
7)
8
9from smbprotocol.structure import (
10    BytesField,
11    EnumField,
12    FlagField,
13    IntField,
14    Structure,
15)
16
17try:
18    from queue import Queue
19except ImportError:  # pragma: no cover
20    from Queue import Queue
21
22
23class Commands(object):
24    """
25    [MS-SMB2] v53.0 2017-09-15
26
27    2.2.1.2 SMB2 Packet Header - SYNC Command
28    The command code of an SMB2 packet, it is used in the packet header.
29    """
30    SMB2_NEGOTIATE = 0x0000
31    SMB2_SESSION_SETUP = 0x0001
32    SMB2_LOGOFF = 0x0002
33    SMB2_TREE_CONNECT = 0x0003
34    SMB2_TREE_DISCONNECT = 0x0004
35    SMB2_CREATE = 0x0005
36    SMB2_CLOSE = 0x0006
37    SMB2_FLUSH = 0x0007
38    SMB2_READ = 0x0008
39    SMB2_WRITE = 0x0009
40    SMB2_LOCK = 0x000A
41    SMB2_IOCTL = 0x000B
42    SMB2_CANCEL = 0x000C
43    SMB2_ECHO = 0x000D
44    SMB2_QUERY_DIRECTORY = 0x000E
45    SMB2_CHANGE_NOTIFY = 0x000F
46    SMB2_QUERY_INFO = 0x0010
47    SMB2_SET_INFO = 0x0011
48    SMB2_OPLOCK_BREAK = 0x0012
49
50
51class NtStatus(object):
52    """
53    [MS-ERREF] https://msdn.microsoft.com/en-au/library/cc704588.aspx
54
55    2.3.1 NTSTATUS Values
56    These values are set in the status field of an SMB2Header response. This is
57    not an exhaustive list but common values that are returned.
58    """
59    STATUS_SUCCESS = 0x00000000
60    STATUS_UNSUCCESSFUL = 0xC0000001
61    STATUS_NETWORK_NAME_DELETED = 0xC00000C9
62    STATUS_PENDING = 0x00000103
63    STATUS_NOTIFY_CLEANUP = 0x0000010B
64    STATUS_NOTIFY_ENUM_DIR = 0x0000010C
65    STATUS_BUFFER_OVERFLOW = 0x80000005
66    STATUS_NO_MORE_FILES = 0x80000006
67    STATUS_END_OF_FILE = 0xC0000011
68    STATUS_INVALID_EA_NAME = 0x80000013
69    STATUS_EA_LIST_INCONSISTENT = 0x80000014
70    STATUS_STOPPED_ON_SYMLINK = 0x8000002D
71    STATUS_INVALID_INFO_CLASS = 0xC0000003
72    STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
73    STATUS_INVALID_PARAMETER = 0xC000000D
74    STATUS_NO_SUCH_FILE = 0xC000000F
75    STATUS_INVALID_DEVICE_REQUEST = 0xC0000010
76    STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016
77    STATUS_ACCESS_DENIED = 0xC0000022
78    STATUS_BUFFER_TOO_SMALL = 0xC0000023
79    STATUS_OBJECT_NAME_INVALID = 0xC0000033
80    STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034
81    STATUS_OBJECT_NAME_COLLISION = 0xC0000035
82    STATUS_OBJECT_PATH_INVALID = 0xC0000039
83    STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A
84    STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B
85    STATUS_SHARING_VIOLATION = 0xC0000043
86    STATUS_EAS_NOT_SUPPORTED = 0xC000004F
87    STATUS_EA_TOO_LARGE = 0xC0000050
88    STATUS_NONEXISTENT_EA_ENTRY = 0xC0000051
89    STATUS_NO_EAS_ON_FILE = 0xC0000052
90    STATUS_EA_CORRUPT_ERROR = 0xC0000053
91    STATUS_DELETE_PENDING = 0xC0000056
92    STATUS_PRIVILEGE_NOT_HELD = 0xC0000061
93    STATUS_WRONG_PASSWORD = 0xC000006A
94    STATUS_LOGON_FAILURE = 0xC000006D
95    STATUS_PASSWORD_EXPIRED = 0xC0000071
96    STATUS_NONE_MAPPED = 0xC0000073
97    STATUS_INSUFFICIENT_RESOURCES = 0xC000009A
98    STATUS_PIPE_NOT_AVAILABLE = 0xC00000AC
99    STATUS_PIPE_BUSY = 0xC00000AE
100    STATUS_PIPE_DISCONNECTED = 0xC00000B0
101    STATUS_PIPE_CLOSING = 0xC00000B1
102    STATUS_IO_TIMEOUT = 0xC00000B5
103    STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA
104    STATUS_NOT_SUPPORTED = 0xC00000BB
105    STATUS_BAD_NETWORK_NAME = 0xC00000CC
106    STATUS_REQUEST_NOT_ACCEPTED = 0xC00000D0
107    STATUS_PIPE_EMPTY = 0xC00000D9
108    STATUS_INTERNAL_ERROR = 0xC00000E5
109    STATUS_DIRECTORY_NOT_EMPTY = 0xC0000101
110    STATUS_NOT_A_DIRECTORY = 0xC0000103
111    STATUS_CANCELLED = 0xC0000120
112    STATUS_CANNOT_DELETE = 0xC0000121
113    STATUS_FILE_CLOSED = 0xC0000128
114    STATUS_PIPE_BROKEN = 0xC000014B
115    STATUS_FS_DRIVER_REQUIRED = 0xC000019C
116    STATUS_USER_SESSION_DELETED = 0xC0000203
117    STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205
118    STATUS_NOT_FOUND = 0xC0000225
119    STATUS_PATH_NOT_COVERED = 0xC0000257
120    STATUS_DFS_UNAVAILABLE = 0xC000026D
121    STATUS_NOT_A_REPARSE_POINT = 0xC0000275
122    STATUS_SERVER_UNAVAILABLE = 0xC0000466
123
124
125class Smb2Flags(object):
126    """
127    [MS-SMB2] v53.0 2017-09-15
128
129    2.2.1.2 SMB2 Packet Header - SYNC Flags
130    Indicates various processing rules that need to be done on the SMB2 packet.
131    """
132    SMB2_FLAGS_SERVER_TO_REDIR = 0x00000001
133    SMB2_FLAGS_ASYNC_COMMAND = 0x00000002
134    SMB2_FLAGS_RELATED_OPERATIONS = 0x00000004
135    SMB2_FLAGS_SIGNED = 0x00000008
136    SMB2_FLAGS_PRIORITY_MASK = 0x00000070
137    SMB2_FLAGS_DFS_OPERATIONS = 0x10000000
138    SMB2_FLAGS_REPLAY_OPERATIONS = 0x20000000
139
140
141class SMB2HeaderAsync(Structure):
142    """
143    [MS-SMB2] 2.2.1.1 SMB2 Packer Header - ASYNC
144    https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/ea4560b7-90da-4803-82b5-344754b92a79
145
146    The SMB2 Packet header for async commands.
147    """
148
149    def __init__(self):
150        self.fields = OrderedDict([
151            ('protocol_id', BytesField(
152                size=4,
153                default=b"\xfeSMB",
154            )),
155            ('structure_size', IntField(
156                size=2,
157                default=64,
158            )),
159            ('credit_charge', IntField(size=2)),
160            ('channel_sequence', IntField(size=2)),
161            ('reserved', IntField(size=2)),
162            ('command', EnumField(
163                size=2,
164                enum_type=Commands,
165            )),
166            ('credit_request', IntField(size=2)),
167            ('flags', FlagField(
168                size=4,
169                flag_type=Smb2Flags,
170            )),
171            ('next_command', IntField(size=4)),
172            ('message_id', IntField(size=8)),
173            ('async_id', IntField(size=8)),
174            ('session_id', IntField(size=8)),
175            ('signature', BytesField(
176                size=16,
177                default=b"\x00" * 16,
178            )),
179            ('data', BytesField())
180        ])
181        super(SMB2HeaderAsync, self).__init__()
182
183
184class SMB2HeaderRequest(Structure):
185    """
186    [MS-SMB2] v53.0 2017-09-15
187
188    2.2.1.2 SMB2 Packet Header - SYNC
189    This is the header definition that contains the ChannelSequence/Reserved
190    instead of the Status field used for a Packet request.
191    """
192
193    def __init__(self):
194        self.fields = OrderedDict([
195            ('protocol_id', BytesField(
196                size=4,
197                default=b"\xfeSMB",
198            )),
199            ('structure_size', IntField(
200                size=2,
201                default=64,
202            )),
203            ('credit_charge', IntField(size=2)),
204            ('channel_sequence', IntField(size=2)),
205            ('reserved', IntField(size=2)),
206            ('command', EnumField(
207                size=2,
208                enum_type=Commands
209            )),
210            ('credit_request', IntField(size=2)),
211            ('flags', FlagField(
212                size=4,
213                flag_type=Smb2Flags,
214            )),
215            ('next_command', IntField(size=4)),
216            ('message_id', IntField(size=8)),
217            ('process_id', IntField(size=4)),
218            ('tree_id', IntField(size=4)),
219            ('session_id', IntField(size=8)),
220            ('signature', BytesField(
221                size=16,
222                default=b"\x00" * 16,
223            )),
224            ('data', BytesField())
225        ])
226        super(SMB2HeaderRequest, self).__init__()
227
228
229class SMB2HeaderResponse(Structure):
230    """
231    [MS-SMB2] v53.0 2017-09-15
232
233    2.2.1.2 SMB2 Packet Header - SYNC
234    The header definition for an SMB Response that contains the Status field
235    instead of the ChannelSequence/Reserved used for a Packet response.
236    """
237
238    def __init__(self):
239        self.fields = OrderedDict([
240            ('protocol_id', BytesField(
241                size=4,
242                default=b'\xfeSMB',
243            )),
244            ('structure_size', IntField(
245                size=2,
246                default=64,
247            )),
248            ('credit_charge', IntField(size=2)),
249            ('status', EnumField(
250                size=4,
251                enum_type=NtStatus,
252                enum_strict=False
253            )),
254            ('command', EnumField(
255                size=2,
256                enum_type=Commands,
257                enum_strict=False,
258            )),
259            ('credit_response', IntField(size=2)),
260            ('flags', FlagField(
261                size=4,
262                flag_type=Smb2Flags,
263            )),
264            ('next_command', IntField(size=4)),
265            ('message_id', IntField(size=8)),
266            ('reserved', IntField(size=4)),
267            ('tree_id', IntField(size=4)),
268            ('session_id', IntField(size=8)),
269            ('signature', BytesField(
270                size=16,
271                default=b"\x00" * 16,
272            )),
273            ('data', BytesField()),
274        ])
275        super(SMB2HeaderResponse, self).__init__()
276