1# -*- coding: utf-8 -*-
2# Copyright: (c) 2019, 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.header import (
10    NtStatus,
11)
12
13from smbprotocol.structure import (
14    BoolField,
15    BytesField,
16    DateTimeField,
17    EnumField,
18    FlagField,
19    IntField,
20    Structure,
21    UuidField,
22)
23
24
25class CreateContextName(object):
26    """
27    [MS-SMB2] v53.0 2017-09-15
28
29    2.2.13.2 SMB2_CREATE_CONTEXT Request Values
30    Valid names for the name to set on a SMB2_CREATE_CONTEXT Request entry
31    """
32    SMB2_CREATE_EA_BUFFER = b"\x45\x78\x74\x41"
33
34    # note: the structures for this are located in security_descriptor.py
35    SMB2_CREATE_SD_BUFFER = b"\x53\x65\x63\x44"
36    SMB2_CREATE_DURABLE_HANDLE_REQUEST = b"\x44\x48\x6e\x51"
37    SMB2_CREATE_DURABLE_HANDLE_RECONNECT = b"\x44\x48\x6e\x43"
38    SMB2_CREATE_ALLOCATION_SIZE = b"\x41\x6c\x53\x69"
39    SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST = b"\x4d\x78\x41\x63"
40    SMB2_CREATE_TIMEWARP_TOKEN = b"\x54\x57\x72\x70"
41    SMB2_CREATE_QUERY_ON_DISK_ID = b"\x51\x46\x69\x64"
42    SMB2_CREATE_REQUEST_LEASE = b"\x52\x71\x4c\x73"
43    SMB2_CREATE_REQUEST_LEASE_V2 = b"\x52\x71\x4c\x73"
44    SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 = b"\x44\x48\x32\x51"
45    SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 = b"\x44\x48\x32\x43"
46    SMB2_CREATE_APP_INSTANCE_ID = b"\x45\xBC\xA6\x6A\xEF\xA7\xF7\x4A" \
47                                  b"\x90\x08\xFA\x46\x2E\x14\x4D\x74"
48    SMB2_CREATE_APP_INSTANCE_VERSION = b"\xB9\x82\xD0\xB7\x3B\x56\x07\x4F" \
49                                       b"\xA0\x7B\x52\x4A\x81\x16\xA0\x10"
50    SVHDX_OPEN_DEVICE_CONTEXT = b"\x9C\xCB\xCF\x9E\x04\xC1\xE6\x43" \
51                                b"\x98\x0E\x15\x8D\xA1\xF6\xEC\x83"
52
53    @staticmethod
54    def get_response_structure(name, size=None):
55        """
56        Returns the response structure for a know list of create context
57        responses.
58
59        :param name: The constant value above
60        :param size: Specify the size of the context buffer, used to differenciate between REQUEST_LEASE and
61            REQUEST_LEASE_V2.
62        :return: The response structure or None if unknown
63        """
64        # Special handling for request lease here the header name has the same value, use the size to differenciate.
65        if name == CreateContextName.SMB2_CREATE_REQUEST_LEASE:
66            return {
67                32: SMB2CreateResponseLease(),
68                52: SMB2CreateResponseLeaseV2(),
69            }.get(size, None)
70
71        return {
72            CreateContextName.SMB2_CREATE_DURABLE_HANDLE_REQUEST: SMB2CreateDurableHandleResponse(),
73            CreateContextName.SMB2_CREATE_DURABLE_HANDLE_RECONNECT: SMB2CreateDurableHandleReconnect(),
74            CreateContextName.SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST: SMB2CreateQueryMaximalAccessResponse(),
75            CreateContextName.SMB2_CREATE_QUERY_ON_DISK_ID: SMB2CreateQueryOnDiskIDResponse(),
76            CreateContextName.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: SMB2CreateDurableHandleResponseV2(),
77            CreateContextName.SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: SMB2CreateDurableHandleReconnectV2,
78            CreateContextName.SMB2_CREATE_APP_INSTANCE_ID: SMB2CreateAppInstanceId(),
79            CreateContextName.SMB2_CREATE_APP_INSTANCE_VERSION: SMB2CreateAppInstanceVersion()
80        }.get(name, None)
81
82
83class EAFlags(object):
84    """
85    [MS-FSCC]
86
87    2.4.15 FileFullEaInformation Flags
88    Specifies the flag used when setting extended attributes.
89    """
90    NONE = 0x0000000
91    FILE_NEED_EA = 0x00000080
92
93
94class LeaseState(object):
95    """
96    [MS-SMB2]
97
98    2.2.13.2.8 SMB2_CREATE_REQUEST_LEASE LeaseState
99    The requested lease state, field is constructed with a combination of the
100    following values.
101    """
102    SMB2_LEASE_NONE = 0x00
103    SMB2_LEASE_READ_CACHING = 0x01
104    SMB2_LEASE_HANDLE_CACHING = 0x02
105    SMB2_LEASE_WRITE_CACHING = 0x04
106
107
108class LeaseRequestFlags(object):
109    """
110    [MS-SMB2]
111
112    2.2.13.2.10 SMB2_CREATE_REQUEST_LEASE_V2
113    The flags to use on an SMB2CreateRequestLeaseV2 packet.
114    """
115    SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET = 0x00000004
116
117
118class LeaseResponseFlags(object):
119    """
120    [MS-SMB2]
121
122    2.2.14.2.10 SMB2_CREATE_RESPONSE_LEASE
123    """
124    SMB2_LEASE_FLAG_BREAK_IN_PROGRESS = 0x00000002
125    SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET = 0x00000004  # V2 Response
126
127
128class DurableHandleFlags(object):
129    """
130    [MS-SMB2]
131
132    2.2.13.2.11 SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2
133    Flags used on an SMB2CreateDurableHandleRequestV2 packet.
134    """
135    SMB2_DHANDLE_FLAG_PERSISTENT = 0x00000002
136
137
138class SVHDXOriginatorFlags(object):
139    """
140    [MS-RSVD] 2.2.4.12 SVHDX_OPEN_DEVICE_CONTEXT OriginatorFlags
141    Used to indicate which component has originated or issued the operations.
142    """
143    SVHDX_ORIGINATOR_PVHDPARSER = 0x00000001
144    SVHDX_ORIGINATOR_VHDMP = 0x00000004
145
146
147class SMB2CreateContextRequest(Structure):
148    """
149    [MS-SMB2] v53.0 2017-09-15
150
151    2.2.13.2 SMB2_CREATE_CONTEXT Request Values
152    Structure used in the SMB2 CREATE Request and SMB2 CREATE Response to
153    encode additional flags and attributes
154    """
155
156    def __init__(self):
157        self.fields = OrderedDict([
158            ('next', IntField(size=4)),
159            ('name_offset', IntField(
160                size=2,
161                default=16
162            )),
163            ('name_length', IntField(
164                size=2,
165                default=lambda s: len(s['buffer_name'])
166            )),
167            ('reserved', IntField(size=2)),
168            ('data_offset', IntField(
169                size=2,
170                default=lambda s: self._buffer_data_offset(s)
171            )),
172            ('data_length', IntField(
173                size=4,
174                default=lambda s: len(s['buffer_data'])
175            )),
176            ('buffer_name', BytesField(
177                size=lambda s: s['name_length'].get_value()
178            )),
179            ('padding', BytesField(
180                size=lambda s: self._padding_size(s),
181                default=lambda s: b"\x00" * self._padding_size(s)
182            )),
183            ('buffer_data', BytesField(
184                size=lambda s: s['data_length'].get_value()
185            )),
186            # not actually a field but each list entry must start at the 8 byte
187            # alignment
188            ('padding2', BytesField(
189                size=lambda s: self._padding2_size(s),
190                default=lambda s: b"\x00" * self._padding2_size(s)
191            ))
192        ])
193        super(SMB2CreateContextRequest, self).__init__()
194
195    def _buffer_data_offset(self, structure):
196        if structure['data_length'].get_value() == 0:
197            return 0
198        else:
199            return structure['name_offset'].get_value() + \
200                   len(structure['buffer_name']) + len(structure['padding'])
201
202    def _padding_size(self, structure):
203        if structure['data_length'].get_value() == 0:
204            return 0
205
206        buffer_name_len = structure['name_length'].get_value()
207        mod = buffer_name_len % 8
208        return mod if mod == 0 else 8 - mod
209
210    def _padding2_size(self, structure):
211        data_length = len(structure['buffer_name']) + \
212            len(structure['padding']) + len(structure['buffer_data'])
213        mod = data_length % 8
214        return mod if mod == 0 else 8 - mod
215
216    def get_context_data(self):
217        """
218        Get the buffer_data value of a context response and try to convert it
219        to the relevant structure based on the buffer_name used. If it is an
220        unknown structure then the raw bytes are returned.
221
222        :return: relevant Structure of buffer_data or bytes if unknown name
223        """
224        buffer_name = self['buffer_name'].get_value()
225        structure = CreateContextName.get_response_structure(buffer_name, size=self['data_length'].get_value())
226        if structure:
227            structure.unpack(self['buffer_data'].get_value())
228            return structure
229        else:
230            # unknown structure, just return the raw bytes
231            return self['buffer_data'].get_value()
232
233    @staticmethod
234    def pack_multiple(messages):
235        """
236        Converts a list of SMB2CreateContextRequest structures and packs them
237        as a bytes object used when setting to the SMB2CreateRequest
238        buffer_contexts field. This should be used as it would calculate the
239        correct next field value for each context entry.
240
241        :param messages: List of SMB2CreateContextRequest structures
242        :return: bytes object that is set on the SMB2CreateRequest
243            buffer_contexts field.
244        """
245        data = b""
246        msg_count = len(messages)
247        for i, msg in enumerate(messages):
248            if not isinstance(msg, SMB2CreateContextRequest):
249                buffer = msg
250                buffer_name = getattr(msg, 'NAME', None)
251                if buffer_name is None:
252                    raise ValueError("Invalid context message, must be either a SMB2CreateContextRequest or a "
253                                     "predefined structure object with NAME defined.")
254                msg = SMB2CreateContextRequest()
255                msg['buffer_name'] = buffer_name
256                msg['buffer_data'] = buffer
257
258            if i == msg_count - 1:
259                msg['next'] = 0
260            else:
261                # because the end padding2 val won't be populated if the entry
262                # offset is 0, we set to 1 so the len calc is correct
263                msg['next'] = 1
264                msg['next'] = len(msg)
265
266            data += msg.pack()
267        return data
268
269
270class SMB2CreateEABuffer(Structure):
271    """
272    [MS-SMB2] 2.2.13.2.1 SMB2_CREATE_EA_BUFFER
273    [MS-FSCC] 2.4.15 FileFullEaInformation
274
275    Used to apply extended attributes as part of creating a new file.
276    """
277
278    NAME = CreateContextName.SMB2_CREATE_EA_BUFFER
279
280    def __init__(self):
281        self.fields = OrderedDict([
282            # 0 if no more entries, otherwise offset after ea_value
283            ('next_entry_offset', IntField(size=4)),
284            ('flags', FlagField(
285                size=1,
286                flag_type=EAFlags
287            )),
288            ('ea_name_length', IntField(
289                size=1,
290                default=lambda s: len(s['ea_name']) - 1  # minus \x00
291            )),
292            ('ea_value_length', IntField(
293                size=2,
294                default=lambda s: len(s['ea_value'])
295            )),
296            # ea_name is ASCII byte encoded and needs a null terminator '\x00'
297            ('ea_name', BytesField(
298                size=lambda s: s['ea_name_length'].get_value() + 1
299            )),
300            ('ea_value', BytesField(
301                size=lambda s: s['ea_value_length'].get_value()
302            )),
303            # not actually a field but each list entry must start at the 4 byte
304            # alignment
305            ('padding', BytesField(
306                size=lambda s: self._padding_size(s),
307                default=lambda s: b"\x00" * self._padding_size(s)
308            ))
309        ])
310        super(SMB2CreateEABuffer, self).__init__()
311
312    def _padding_size(self, structure):
313        if structure['next_entry_offset'].get_value() == 0:
314            return 0
315
316        data_length = len(structure['ea_name']) + len(structure['ea_value'])
317        mod = data_length % 4
318        return mod if mod == 0 else 4 - mod
319
320    @staticmethod
321    def pack_multiple(messages):
322        """
323        Converts a list of SMB2CreateEABuffer structures and packs them as a
324        bytes object used when setting to the SMB2CreateContextRequest
325        buffer_data field. This should be used as it would calculate the
326        correct next_entry_offset field value for each buffer entry.
327
328        :param messages: List of SMB2CreateEABuffer structures
329        :return: bytes object that is set on the SMB2CreateContextRequest
330            buffer_data field.
331        """
332        data = b""
333        msg_count = len(messages)
334        for i, msg in enumerate(messages):
335            if i == msg_count - 1:
336                msg['next_entry_offset'] = 0
337            else:
338                # because the end padding val won't be populated if the entry
339                # offset is 0, we set to 1 so the len calc is correct
340                msg['next_entry_offset'] = 1
341                msg['next_entry_offset'] = len(msg)
342            data += msg.pack()
343
344        return data
345
346
347class SMB2CreateDurableHandleRequest(Structure):
348    """
349    [MS-SMB2] 2.2.13.2.3 SMB2_CREATE_DURABLE_HANDLE_REQUEST
350
351    Used by the client to mark the open as a durable open.
352    """
353
354    NAME = CreateContextName.SMB2_CREATE_DURABLE_HANDLE_REQUEST
355
356    def __init__(self):
357        self.fields = OrderedDict([
358            ('durable_request', BytesField(size=16, default=b"\x00" * 16))
359        ])
360        super(SMB2CreateDurableHandleRequest, self).__init__()
361
362
363class SMB2CreateDurableHandleResponse(Structure):
364    """
365    [MS-SMB2] 2.2.14.2.3 SMB2_CREATE_DURABLE_HANDLE_RESPONSE
366
367    Sent by the server in response to an SMB2CreateDurableHandleRequest packet.
368    """
369
370    def __init__(self):
371        self.fields = OrderedDict([
372            ('reserved', IntField(size=8))
373        ])
374        super(SMB2CreateDurableHandleResponse, self).__init__()
375
376
377class SMB2CreateDurableHandleReconnect(Structure):
378    """
379    [MS-SMB2] 2.2.13.2.4 SMB2_CREATE_DURABLE_HANDLE_RECONNECT
380
381    Used by the client when attempting to reestablish a durable open
382    """
383
384    NAME = CreateContextName.SMB2_CREATE_DURABLE_HANDLE_RECONNECT
385
386    def __init__(self):
387        self.fields = OrderedDict([
388            ('data', BytesField(size=16))
389        ])
390        super(SMB2CreateDurableHandleReconnect, self).__init__()
391
392
393class SMB2CreateQueryMaximalAccessRequest(Structure):
394    """
395    [MS-SMB2] 2.2.13.2.5 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST
396
397    Used by the client to retrieve maximal access information as part of
398    processing the open.
399    """
400
401    NAME = CreateContextName.SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST
402
403    def __init__(self):
404        self.fields = OrderedDict([
405            ('timestamp', DateTimeField())
406        ])
407        super(SMB2CreateQueryMaximalAccessRequest, self).__init__()
408
409
410class SMB2CreateQueryMaximalAccessResponse(Structure):
411    """
412    [MS-SMB2] 2.2.14.2.5 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE
413
414    Used by the server in response to an SMB2CreateQueryMaximalAccessRequest
415    packet.
416    """
417
418    def __init__(self):
419        self.fields = OrderedDict([
420            ('query_status', EnumField(
421                size=4,
422                enum_type=NtStatus,
423                enum_strict=False
424            )),
425            # either FilePipePrinterAccessMask or DirectoryAccessMask
426            ('maximal_access', IntField(size=4))
427        ])
428        super(SMB2CreateQueryMaximalAccessResponse, self).__init__()
429
430
431class SMB2CreateAllocationSize(Structure):
432    """
433    [MS-SMB2] 2.2.13.2.6 SMB2_CREATE_ALLOCATION_SIZE
434
435    Used by the client to set the allocation size of a file that is being
436    newly created or overwritten.
437    """
438
439    NAME = CreateContextName.SMB2_CREATE_ALLOCATION_SIZE
440
441    def __init__(self):
442        self.fields = OrderedDict([
443            ('allocation_size', IntField(size=8))
444        ])
445        super(SMB2CreateAllocationSize, self).__init__()
446
447
448class SMB2CreateTimewarpToken(Structure):
449    """
450    [MS-SMB2] 2.2.13.2.7 SMB2_CREATE_TIMEWARP_TOKEN
451
452    Used by the client when requesting the server to open a version of the file
453    at a previous point in time.
454    """
455
456    NAME = CreateContextName.SMB2_CREATE_TIMEWARP_TOKEN
457
458    def __init__(self):
459        self.fields = OrderedDict([
460            ('timestamp', DateTimeField())
461        ])
462        super(SMB2CreateTimewarpToken, self).__init__()
463
464
465class SMB2CreateRequestLease(Structure):
466    """
467    [MS-SMB2] 2.2.13.2.8 SMB2_CREATE_REQUEST_LEASE
468
469    Used by the cliet when requesting the server to return a lease.
470    """
471
472    NAME = CreateContextName.SMB2_CREATE_REQUEST_LEASE
473
474    def __init__(self):
475        self.fields = OrderedDict([
476            ('lease_key', BytesField(size=16)),
477            ('lease_state', FlagField(
478                size=4,
479                flag_type=LeaseState
480            )),
481            ('lease_flags', IntField(size=4)),
482            ('lease_duration', IntField(size=8))
483        ])
484        super(SMB2CreateRequestLease, self).__init__()
485
486
487class SMB2CreateResponseLease(Structure):
488    """
489    [MS-SMB2] 2.2.14.2.10 SMB2_CREATE_RESPONSE_LEASE
490
491    Sent by the server in response to an SMB2CreateRequestLease
492    """
493
494    def __init__(self):
495        self.fields = OrderedDict([
496            ('lease_key', BytesField(size=16)),
497            ('lease_state', FlagField(
498                size=4,
499                flag_type=LeaseState
500            )),
501            ('lease_flags', FlagField(
502                size=4,
503                flag_type=LeaseResponseFlags
504            )),
505            ('lease_duration', IntField(size=8))
506        ])
507        super(SMB2CreateResponseLease, self).__init__()
508
509
510class SMB2CreateQueryOnDiskIDResponse(Structure):
511    """
512    [MS-SMB2] 2.2.14.2.9 SMB2_CREATE_QUERY_ON_DISK_ID
513
514    Sent by the server in response to an SMB2CreateQueryOnDiskIDRequest packet.
515    """
516
517    NAME = CreateContextName.SMB2_CREATE_QUERY_ON_DISK_ID
518
519    def __init__(self):
520        self.fields = OrderedDict([
521            ('disk_file_id', IntField(size=8)),
522            ('volume_id', IntField(size=8)),
523            ('reserved', BytesField(
524                size=16,
525                default=b"\x00" * 16
526            ))
527        ])
528        super(SMB2CreateQueryOnDiskIDResponse, self).__init__()
529
530
531class SMB2CreateRequestLeaseV2(Structure):
532    """
533    [MS-SMB2] 2.2.13.2.10 SMB2_CREATE_REQUEST_LEASE_V2
534
535    Used when the client is requesting the server to return a lease on a file
536    or directory.
537    Valid for the SMB 3.x family only
538    """
539
540    NAME = CreateContextName.SMB2_CREATE_REQUEST_LEASE_V2
541
542    def __init__(self):
543        self.fields = OrderedDict([
544            ('lease_key', BytesField(size=16)),
545            ('lease_state', FlagField(
546                size=4,
547                flag_type=LeaseState
548            )),
549            ('lease_flags', FlagField(
550                size=4,
551                flag_type=LeaseRequestFlags
552            )),
553            ('lease_duration', IntField(size=8)),
554            ('parent_lease_key', BytesField(size=16)),
555            ('epoch', BytesField(size=2)),
556            ('reserved', IntField(size=2))
557        ])
558        super(SMB2CreateRequestLeaseV2, self).__init__()
559
560
561class SMB2CreateResponseLeaseV2(Structure):
562    """
563    [MS-SMB2] 2.2.14.2.11 SMB2_CREATE_RESPONSE_LEASE_V2
564
565    Sent by the server in response to an SMB2CreateRequestLeaseV2 packet.
566    """
567
568    def __init__(self):
569        self.fields = OrderedDict([
570            ('lease_key', BytesField(size=16)),
571            ('lease_state', FlagField(
572                size=4,
573                flag_type=LeaseState
574            )),
575            ('flags', FlagField(
576                size=4,
577                flag_type=LeaseResponseFlags
578            )),
579            ('lease_duration', IntField(size=8)),
580            ('parent_lease_key', BytesField(size=16)),
581            ('epoch', IntField(size=2)),
582            ('reserved', IntField(size=2))
583        ])
584        super(SMB2CreateResponseLeaseV2, self).__init__()
585
586
587class SMB2CreateDurableHandleRequestV2(Structure):
588    """
589    [MS-SMB2] 2.2.13.2.11 SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2
590
591    Used by the client to request the server mark the open as durable or
592    persistent.
593    Valid for the SMB 3.x family only
594    """
595
596    NAME = CreateContextName.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2
597
598    def __init__(self):
599        self.fields = OrderedDict([
600            # timeout in milliseconds
601            ('timeout', IntField(size=4)),
602            ('flags', FlagField(
603                size=4,
604                flag_type=DurableHandleFlags
605            )),
606            ('reserved', IntField(size=8)),
607            ('create_guid', UuidField(size=16))
608        ])
609        super(SMB2CreateDurableHandleRequestV2, self).__init__()
610
611
612class SMB2CreateDurableHandleReconnectV2(Structure):
613    """
614    [MS-SMB2] 2.2.13.2.12 SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2
615
616    Used by the client when reestablishing a durable open.
617    Valid for the SMB 3.x family only
618    """
619
620    NAME = CreateContextName.SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2
621
622    def __init__(self):
623        self.fields = OrderedDict([
624            ('file_id', BytesField(size=16)),
625            ('create_guid', UuidField(size=16)),
626            ('flags', FlagField(
627                size=4,
628                flag_type=DurableHandleFlags
629            ))
630        ])
631        super(SMB2CreateDurableHandleReconnectV2, self).__init__()
632
633
634class SMB2CreateDurableHandleResponseV2(Structure):
635    """
636    [MS-SMB2] 2.2.14.2.12 SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2
637
638    Sent by the server in response to an SMB2CreateDurableHandleRequestV2
639    packet.
640    """
641
642    def __init__(self):
643        self.fields = OrderedDict([
644            ('timeout', IntField(size=4)),
645            ('flags', FlagField(
646                size=4,
647                flag_type=DurableHandleFlags
648            ))
649        ])
650        super(SMB2CreateDurableHandleResponseV2, self).__init__()
651
652
653class SMB2CreateAppInstanceId(Structure):
654    """
655    [MS-SMB2] 2.2.13.2.13 SMB2_CREATE_APP_INSTANCE_ID
656
657    Used by the client when supplying an identifier provided by an application.
658    Valid for the SMB 3.x family and should also have an durable handle on the
659    create request.
660    """
661
662    NAME = CreateContextName.SMB2_CREATE_APP_INSTANCE_ID
663
664    def __init__(self):
665        self.fields = OrderedDict([
666            ('structure_size', IntField(
667                size=2,
668                default=20
669            )),
670            ('reserved', IntField(size=2)),
671            ('app_instance_id', BytesField(size=16))
672        ])
673        super(SMB2CreateAppInstanceId, self).__init__()
674
675
676class SMB2SVHDXOpenDeviceContextRequest(Structure):
677    """
678    [MS-SMB2] 2.2.13.2.14 SVHDX_OPEN_DEVICE_CONTEXT
679    [MS-RSVD] 2.2.4.12 SVHDX_OPEN_DEVICE_CONTEXT
680
681    Used to open the shared virtual disk file.
682    """
683
684    NAME = CreateContextName.SVHDX_OPEN_DEVICE_CONTEXT
685
686    def __init__(self):
687        self.fields = OrderedDict([
688            ('version', IntField(
689                size=4,
690                default=1
691            )),
692            ('has_initiator_id', BoolField(
693                size=1,
694                default=lambda s: len(s['initiator_host_name']) > 0
695            )),
696            ('reserved', BytesField(
697                size=3,
698                default=b"\x00\x00\x00"
699            )),
700            ('initiator_id', UuidField(size=16)),
701            ('originator_flags', EnumField(
702                size=4,
703                enum_type=SVHDXOriginatorFlags
704            )),
705            ('open_request_id', IntField(size=8)),
706            ('initiator_host_name_length', IntField(
707                size=2,
708                default=lambda s: len(s['initiator_host_name'])
709            )),
710            # utf-16-le encoded string
711            ('initiator_host_name', BytesField(
712                size=lambda s: s['initiator_host_name_length'].get_value()
713            ))
714        ])
715        super(SMB2SVHDXOpenDeviceContextRequest, self).__init__()
716
717
718class SMB2SVHDXOpenDeviceContextResponse(Structure):
719    """
720    [MS-SMB2] 2.2.14.2.14 SVHDX_OPEN_DEVICE_CONTEXT_RESPONSE
721    [MS-RSVD] 2.2.4.31  SVHDX_OPEN_DEVICE_CONTEXT_RESPONSE
722
723    The response packet sent by the server in response to an
724    SMB2VHDXOpenDeviceContextRequest
725    """
726
727    def __init__(self):
728        self.fields = OrderedDict([
729            ('version', IntField(
730                size=4,
731                default=1
732            )),
733            ('has_initiator_id', BoolField(
734                size=1,
735                default=lambda s: len(s['initiator_host_name']) > 0
736            )),
737            ('reserved', BytesField(
738                size=3,
739                default=b"\x00\x00\x00"
740            )),
741            ('initiator_id', UuidField(size=16)),
742            ('flags', IntField(size=4)),
743            ('originator_flags', EnumField(
744                size=4,
745                enum_type=SVHDXOriginatorFlags
746            )),
747            ('open_request_id', IntField(size=8)),
748            ('initiator_host_name_length', IntField(
749                size=2,
750                default=lambda s: len(s['initiator_host_name'])
751            )),
752            # utf-16-le encoded string
753            ('initiator_host_name', BytesField(
754                size=lambda s: s['initiator_host_name_length'].get_value()
755            ))
756        ])
757        super(SMB2SVHDXOpenDeviceContextResponse, self).__init__()
758
759
760class SMB2SVHDXOpenDeviceContextV2Request(Structure):
761    """
762    [MS-SMB2] 2.2.13.2.14 SVHDX_OPEN_DEVICE_CONTEXT
763    [MS-RSVD] 2.2.4.32 SVHDX_OPEN_DEVICE_CONTEXT_V2
764
765    Used to open the shared virtual disk file on the RSVD Protocol version 2
766    """
767
768    NAME = CreateContextName.SVHDX_OPEN_DEVICE_CONTEXT
769
770    def __init__(self):
771        self.fields = OrderedDict([
772            ('version', IntField(
773                size=4,
774                default=2
775            )),
776            ('has_initiator_id', BoolField(
777                size=1,
778                default=lambda s: len(s['initiator_host_name']) > 0
779            )),
780            ('reserved', BytesField(
781                size=3,
782                default=b"\x00\x00\x00"
783            )),
784            ('initiator_id', UuidField(size=16)),
785            ('originator_flags', EnumField(
786                size=4,
787                enum_type=SVHDXOriginatorFlags
788            )),
789            ('open_request_id', IntField(size=8)),
790            ('initiator_host_name_length', IntField(
791                size=2,
792                default=lambda s: len(s['initiator_host_name'])
793            )),
794            # utf-16-le encoded string
795            ('initiator_host_name', BytesField(
796                size=lambda s: s['initiator_host_name_length'].get_value()
797            )),
798            ('virtual_disk_properties_initialized', IntField(size=4)),
799            ('server_service_version', IntField(size=4)),
800            ('virtual_sector_size', IntField(size=4)),
801            ('physical_sector_size', IntField(size=4)),
802            ('virtual_size', IntField(size=8))
803        ])
804        super(SMB2SVHDXOpenDeviceContextV2Request, self).__init__()
805
806
807class SMB2SVHDXOpenDeviceContextV2Response(Structure):
808    """
809    [MS-SMB2] 2.2.14.2.14 SVHDX_OPEN_DEVICE_CONTEXT_RESPONSE
810    [MS-RSVD] 2.2.4.32 SVHDX_OPEN_DEVICE_CONTEXT_V2_RESPONSE
811
812    The response packet sent by the server in response to an
813    SMB2VHDXOpenDeviceContextV2Request
814    """
815
816    def __init__(self):
817        self.fields = OrderedDict([
818            ('version', IntField(
819                size=4,
820                default=2
821            )),
822            ('has_initiator_id', BoolField(
823                size=1,
824                default=lambda s: len(s['initiator_host_name']) > 0
825            )),
826            ('reserved', BytesField(
827                size=3,
828                default=b"\x00\x00\x00"
829            )),
830            ('initiator_id', UuidField(size=16)),
831            ('flags', IntField(size=4)),
832            ('originator_flags', EnumField(
833                size=4,
834                enum_type=SVHDXOriginatorFlags
835            )),
836            ('open_request_id', IntField(size=8)),
837            ('initiator_host_name_length', IntField(
838                size=2,
839                default=lambda s: len(s['initiator_host_name'])
840            )),
841            # utf-16-le encoded string
842            ('initiator_host_name', BytesField(
843                size=lambda s: s['initiator_host_name_length'].get_value()
844            )),
845            ('virtual_disk_properties_initialized', IntField(size=4)),
846            ('server_service_version', IntField(size=4)),
847            ('virtual_sector_size', IntField(size=4)),
848            ('physical_sector_size', IntField(size=4)),
849            ('virtual_size', IntField(size=8))
850        ])
851        super(SMB2SVHDXOpenDeviceContextV2Response, self).__init__()
852
853
854class SMB2CreateAppInstanceVersion(Structure):
855    """
856    [MS-SMB2] 2.2.13.2.15 SMB2_CREATE_APP_INSTANCE_VERSION
857
858    Used when the client is supplying a version for the app instance identifier
859    provided by an application.
860    Valid for the SMB 3.1.1+ family
861    """
862
863    NAME = CreateContextName.SMB2_CREATE_APP_INSTANCE_VERSION
864
865    def __init__(self):
866        self.fields = OrderedDict([
867            ('structure_size', IntField(
868                size=2,
869                default=24
870            )),
871            ('reserved', IntField(size=2)),
872            ('padding', IntField(size=4)),
873            ('app_instance_version_high', IntField(size=8)),
874            ('app_instance_version_low', IntField(size=8))
875        ])
876        super(SMB2CreateAppInstanceVersion, self).__init__()
877