1# Copyright (c) 2003-2016 CORE Security Technologies
2#
3# This software is provided under under a slightly modified version
4# of the Apache Software License. See the accompanying LICENSE file
5# for more information.
6#
7# Author: Alberto Solino (@agsolino)
8#
9# Description:
10#   [MS-VDS]: Virtual Disk Service (VDS) Protocol
11#             This was used as a way to test the DCOM runtime. Further
12#             testing is needed to verify it is working as expected
13#
14#   Best way to learn how to use these calls is to grab the protocol standard
15#   so you understand what the call does, and then read the test case located
16#   at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC
17#
18#   Since DCOM is like an OO RPC, instead of helper functions you will see the
19#   classes described in the standards developed.
20#   There are test cases for them too.
21#
22from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRUniConformantVaryingArray, NDRENUM
23from impacket.dcerpc.v5.dcomrt import DCOMCALL, DCOMANSWER, IRemUnknown2, PMInterfacePointer, INTERFACE
24from impacket.dcerpc.v5.dtypes import LPWSTR, ULONG, DWORD, SHORT, GUID
25from impacket.dcerpc.v5.rpcrt import DCERPCException
26from impacket.dcerpc.v5.enum import Enum
27from impacket import hresult_errors
28from impacket.uuid import string_to_bin
29
30class DCERPCSessionError(DCERPCException):
31    def __init__(self, error_string=None, error_code=None, packet=None):
32        DCERPCException.__init__(self, error_string, error_code, packet)
33
34    def __str__( self ):
35        if hresult_errors.ERROR_MESSAGES.has_key(self.error_code):
36            error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0]
37            error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1]
38            return 'VDS SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
39        else:
40            return 'VDS SessionError: unknown error code: 0x%x' % (self.error_code)
41
42################################################################################
43# CONSTANTS
44################################################################################
45# 1.9 Standards Assignments
46CLSID_VirtualDiskService = string_to_bin('7D1933CB-86F6-4A98-8628-01BE94C9A575')
47IID_IEnumVdsObject = string_to_bin('118610B7-8D94-4030-B5B8-500889788E4E')
48IID_IVdsAdviseSink = string_to_bin('8326CD1D-CF59-4936-B786-5EFC08798E25')
49IID_IVdsAsync = string_to_bin('D5D23B6D-5A55-4492-9889-397A3C2D2DBC')
50IID_IVdsServiceInitialization = string_to_bin('4AFC3636-DB01-4052-80C3-03BBCB8D3C69')
51IID_IVdsService = string_to_bin('0818A8EF-9BA9-40D8-A6F9-E22833CC771E')
52IID_IVdsSwProvider = string_to_bin('9AA58360-CE33-4F92-B658-ED24B14425B8')
53IID_IVdsProvider = string_to_bin('10C5E575-7984-4E81-A56B-431F5F92AE42')
54
55error_status_t = ULONG
56
57# 2.2.1.1.3 VDS_OBJECT_ID
58VDS_OBJECT_ID = GUID
59
60################################################################################
61# STRUCTURES
62################################################################################
63# 2.2.2.1.3.1 VDS_SERVICE_PROP
64class VDS_SERVICE_PROP(NDRSTRUCT):
65    structure = (
66        ('pwszVersion',LPWSTR),
67        ('ulFlags',ULONG),
68    )
69
70class OBJECT_ARRAY(NDRUniConformantVaryingArray):
71    item = PMInterfacePointer
72
73# 2.2.2.7.1.1 VDS_PROVIDER_TYPE
74class VDS_PROVIDER_TYPE(NDRENUM):
75    class enumItems(Enum):
76        VDS_PT_UNKNOWN     = 0
77        VDS_PT_SOFTWARE    = 1
78        VDS_PT_HARDWARE    = 2
79        VDS_PT_VIRTUALDISK = 3
80        VDS_PT_MAX         = 4
81
82# 2.2.2.7.2.1 VDS_PROVIDER_PROP
83class VDS_PROVIDER_PROP(NDRSTRUCT):
84    structure = (
85        ('id',VDS_OBJECT_ID),
86        ('pwszName',LPWSTR),
87        ('guidVersionId',GUID),
88        ('pwszVersion',LPWSTR),
89        ('type',VDS_PROVIDER_TYPE),
90        ('ulFlags',ULONG),
91        ('ulStripeSizeFlags',ULONG),
92        ('sRebuildPriority',SHORT),
93    )
94
95################################################################################
96# RPC CALLS
97################################################################################
98
99# 3.4.5.2.5.1 IVdsServiceInitialization::Initialize (Opnum 3)
100class IVdsServiceInitialization_Initialize(DCOMCALL):
101    opnum = 3
102    structure = (
103       ('pwszMachineName', LPWSTR),
104    )
105
106class IVdsServiceInitialization_InitializeResponse(DCOMANSWER):
107    structure = (
108       ('ErrorCode', error_status_t),
109    )
110
111# 3.4.5.2.4.1 IVdsService::IsServiceReady (Opnum 3)
112class IVdsService_IsServiceReady(DCOMCALL):
113    opnum = 3
114    structure = (
115    )
116
117class IVdsService_IsServiceReadyResponse(DCOMANSWER):
118    structure = (
119       ('ErrorCode', error_status_t),
120    )
121
122# 3.4.5.2.4.2 IVdsService::WaitForServiceReady (Opnum 4)
123class IVdsService_WaitForServiceReady(DCOMCALL):
124    opnum = 4
125    structure = (
126    )
127
128class IVdsService_WaitForServiceReadyResponse(DCOMANSWER):
129    structure = (
130       ('ErrorCode', error_status_t),
131    )
132
133# 3.4.5.2.4.3 IVdsService::GetProperties (Opnum 5)
134class IVdsService_GetProperties(DCOMCALL):
135    opnum = 5
136    structure = (
137    )
138
139class IVdsService_GetPropertiesResponse(DCOMANSWER):
140    structure = (
141       ('pServiceProp', VDS_SERVICE_PROP),
142       ('ErrorCode', error_status_t),
143    )
144
145# 3.4.5.2.4.4 IVdsService::QueryProviders (Opnum 6)
146class IVdsService_QueryProviders(DCOMCALL):
147    opnum = 6
148    structure = (
149        ('masks', DWORD),
150    )
151
152class IVdsService_QueryProvidersResponse(DCOMANSWER):
153    structure = (
154       ('ppEnum', PMInterfacePointer),
155       ('ErrorCode', error_status_t),
156    )
157
158# 3.1.1.1 IEnumVdsObject Interface
159# 3.4.5.2.1.1 IEnumVdsObject::Next (Opnum 3)
160class IEnumVdsObject_Next(DCOMCALL):
161    opnum = 3
162    structure = (
163       ('celt', ULONG),
164    )
165
166class IEnumVdsObject_NextResponse(DCOMANSWER):
167    structure = (
168       ('ppObjectArray', OBJECT_ARRAY),
169       ('pcFetched', ULONG),
170       ('ErrorCode', error_status_t),
171    )
172# 3.4.5.2.14.1 IVdsProvider::GetProperties (Opnum 3)
173class IVdsProvider_GetProperties(DCOMCALL):
174    opnum = 3
175    structure = (
176    )
177
178class IVdsProvider_GetPropertiesResponse(DCOMANSWER):
179    structure = (
180       ('pProviderProp', VDS_PROVIDER_PROP),
181       ('ErrorCode', error_status_t),
182    )
183
184################################################################################
185# OPNUMs and their corresponding structures
186################################################################################
187OPNUMS = {
188}
189
190################################################################################
191# HELPER FUNCTIONS AND INTERFACES
192################################################################################
193class IEnumVdsObject(IRemUnknown2):
194    def Next(self, celt=0xffff):
195        request = IEnumVdsObject_Next()
196        request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
197        request['ORPCthis']['flags'] = 0
198        request['celt'] = celt
199        try:
200            resp = self.request(request, uuid = self.get_iPid())
201        except Exception, e:
202            resp = e.get_packet()
203            # If it is S_FALSE(1) means less items were returned
204            if resp['ErrorCode'] != 1:
205                raise
206        interfaces = list()
207        for interface in resp['ppObjectArray']:
208            interfaces.append(IRemUnknown2(INTERFACE(self.get_cinstance(), ''.join(interface['abData']), self.get_ipidRemUnknown(), target = self.get_target())))
209        return interfaces
210
211class IVdsProvider(IRemUnknown2):
212    def GetProperties(self):
213        request = IVdsProvider_GetProperties()
214        request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
215        request['ORPCthis']['flags'] = 0
216        resp = self.request(request, uuid = self.get_iPid())
217        return resp
218
219class IVdsServiceInitialization(IRemUnknown2):
220    def __init__(self, interface):
221        IRemUnknown2.__init__(self, interface)
222
223    def Initialize(self):
224        request = IVdsServiceInitialization_Initialize()
225        request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
226        request['ORPCthis']['flags'] = 0
227        request['pwszMachineName'] = '\x00'
228        resp = self.request(request, uuid = self.get_iPid())
229        return resp
230
231class IVdsService(IRemUnknown2):
232    def __init__(self, interface):
233        IRemUnknown2.__init__(self, interface)
234
235    def IsServiceReady(self):
236        request = IVdsService_IsServiceReady()
237        request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
238        request['ORPCthis']['flags'] = 0
239        try:
240            resp = self.request(request, uuid = self.get_iPid())
241        except Exception, e:
242            resp = e.get_packet()
243        return resp
244
245    def WaitForServiceReady(self):
246        request = IVdsService_WaitForServiceReady()
247        request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
248        request['ORPCthis']['flags'] = 0
249        resp = self.request(request, uuid = self.get_iPid())
250        return resp
251
252    def GetProperties(self):
253        request = IVdsService_GetProperties()
254        request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
255        request['ORPCthis']['flags'] = 0
256        resp = self.request(request, uuid = self.get_iPid())
257        return resp
258
259    def QueryProviders(self, masks):
260        request = IVdsService_QueryProviders()
261        request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
262        request['ORPCthis']['flags'] = 0
263        request['masks'] = masks
264        resp = self.request(request, uuid = self.get_iPid())
265        return IEnumVdsObject(INTERFACE(self.get_cinstance(), ''.join(resp['ppEnum']['abData']), self.get_ipidRemUnknown(), target = self.get_target()))
266
267
268
269
270