1# Copyright (c) 2003-2017 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-DHCPM] Interface implementation
11#
12#   Best way to learn how to use these calls is to grab the protocol standard
13#   so you understand what the call does, and then read the test case located
14#   at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC
15#
16#   Some calls have helper functions, which makes it even easier to use.
17#   They are located at the end of this file.
18#   Helper functions start with "h"<name of the call>.
19#   There are test cases for them too.
20#
21
22from impacket import system_errors
23from impacket.dcerpc.v5.dtypes import LPWSTR, ULONG, NULL, DWORD, BOOL, BYTE, LPDWORD, WORD
24from impacket.dcerpc.v5.ndr import NDRCALL, NDRUniConformantArray, NDRPOINTER, NDRSTRUCT, NDRENUM, NDRUNION
25from impacket.dcerpc.v5.rpcrt import DCERPCException
26from impacket.dcerpc.v5.enum import Enum
27from impacket.uuid import uuidtup_to_bin
28
29MSRPC_UUID_DHCPSRV = uuidtup_to_bin(('6BFFD098-A112-3610-9833-46C3F874532D', '1.0'))
30MSRPC_UUID_DHCPSRV2 = uuidtup_to_bin(('5B821720-F63B-11D0-AAD2-00C04FC324DB', '1.0'))
31
32
33class DCERPCSessionError(DCERPCException):
34    ERROR_MESSAGES = {
35        0x00004E2D: ("ERROR_DHCP_JET_ERROR", "An error occurred while accessing the DHCP server database."),
36        0x00004E25: ("ERROR_DHCP_SUBNET_NOT_PRESENT", "The specified IPv4 subnet does not exist."),
37        0x00004E54: ("ERROR_DHCP_SUBNET_EXISTS", "The IPv4 scope parameters are incorrect. Either the IPv4 scope already"
38                                                 " exists, corresponding to the SubnetAddress and SubnetMask members of "
39                                                 "the structure DHCP_SUBNET_INFO (section 2.2.1.2.8), or there is a "
40                                                 "range overlap of IPv4 addresses between those associated with the "
41                                                 "SubnetAddress and SubnetMask fields of the new IPv4 scope and the "
42                                                 "subnet address and mask of an already existing IPv4 scope"),
43
44    }
45    def __init__(self, error_string=None, error_code=None, packet=None):
46        DCERPCException.__init__(self, error_string, error_code, packet)
47
48    def __str__(self):
49        key = self.error_code
50        if system_errors.ERROR_MESSAGES.has_key(key):
51            error_msg_short = system_errors.ERROR_MESSAGES[key][0]
52            error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
53            return 'DHCPM SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
54        elif self.ERROR_MESSAGES.has_key(key):
55            error_msg_short = self.ERROR_MESSAGES[key][0]
56            error_msg_verbose = self.ERROR_MESSAGES[key][1]
57            return 'DHCPM SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
58        else:
59            return 'DHCPM SessionError: unknown error code: 0x%x' % self.error_code
60
61################################################################################
62# CONSTANTS
63################################################################################
64DHCP_SRV_HANDLE = LPWSTR
65DHCP_IP_ADDRESS = DWORD
66DHCP_IP_MASK = DWORD
67DHCP_OPTION_ID = DWORD
68
69# DHCP enumeratiom flags
70DHCP_FLAGS_OPTION_DEFAULT = 0x00000000
71DHCP_FLAGS_OPTION_IS_VENDOR = 0x00000003
72
73# Errors
74ERROR_DHCP_JET_ERROR = 0x00004E2D
75ERROR_DHCP_SUBNET_NOT_PRESENT = 0x00004E25
76ERROR_DHCP_SUBNET_EXISTS = 0x00004E54
77################################################################################
78# STRUCTURES
79################################################################################
80# 2.2.1.1.3 DHCP_SEARCH_INFO_TYPE
81class DHCP_SEARCH_INFO_TYPE(NDRENUM):
82    class enumItems(Enum):
83        DhcpClientIpAddress       = 0
84        DhcpClientHardwareAddress = 1
85        DhcpClientName            = 2
86
87# 2.2.1.1.11 QuarantineStatus
88class QuarantineStatus(NDRENUM):
89    class enumItems(Enum):
90        NOQUARANTINE        = 0
91        RESTRICTEDACCESS    = 1
92        DROPPACKET          = 2
93        PROBATION           = 3
94        EXEMPT              = 4
95        DEFAULTQUARSETTING  = 5
96        NOQUARINFO          = 6
97
98# 2.2.1.2.7 DHCP_HOST_INFO
99class DHCP_HOST_INFO(NDRSTRUCT):
100    structure = (
101        ('IpAddress', DHCP_IP_ADDRESS),
102        ('NetBiosName', LPWSTR),
103        ('HostName', LPWSTR),
104    )
105
106# 2.2.1.2.9 DHCP_BINARY_DATA
107class BYTE_ARRAY(NDRUniConformantArray):
108    item = 'c'
109
110class PBYTE_ARRAY(NDRPOINTER):
111    referent = (
112        ('Data', BYTE_ARRAY),
113    )
114
115class DHCP_BINARY_DATA(NDRSTRUCT):
116    structure = (
117        ('DataLength', DWORD),
118        ('Data_', PBYTE_ARRAY),
119    )
120
121DHCP_CLIENT_UID = DHCP_BINARY_DATA
122
123# 2.2.1.2.11 DATE_TIME
124class DATE_TIME(NDRSTRUCT):
125    structure = (
126        ('dwLowDateTime', DWORD),
127        ('dwHighDateTime', DWORD),
128    )
129
130# 2.2.1.2.19 DHCP_CLIENT_INFO_VQ
131class DHCP_CLIENT_INFO_VQ(NDRSTRUCT):
132    structure = (
133        ('ClientIpAddress', DHCP_IP_ADDRESS),
134        ('SubnetMask', DHCP_IP_MASK),
135        ('ClientHardwareAddress', DHCP_CLIENT_UID),
136        ('ClientName', LPWSTR),
137        ('ClientComment', LPWSTR),
138        ('ClientLeaseExpires', DATE_TIME),
139        ('OwnerHost', DHCP_HOST_INFO),
140        ('bClientType', BYTE),
141        ('AddressState', BYTE),
142        ('Status', QuarantineStatus),
143        ('ProbationEnds', DATE_TIME),
144        ('QuarantineCapable', BOOL),
145    )
146
147class DHCP_CLIENT_SEARCH_UNION(NDRUNION):
148    union = {
149        DHCP_SEARCH_INFO_TYPE.DhcpClientIpAddress:       ('ClientIpAddress', DHCP_IP_ADDRESS),
150        DHCP_SEARCH_INFO_TYPE.DhcpClientHardwareAddress: ('ClientHardwareAddress', DHCP_CLIENT_UID),
151        DHCP_SEARCH_INFO_TYPE.DhcpClientName:            ('ClientName', LPWSTR),
152    }
153
154class DHCP_SEARCH_INFO(NDRSTRUCT):
155    structure = (
156        ('SearchType', DHCP_SEARCH_INFO_TYPE),
157        ('SearchInfo', DHCP_CLIENT_SEARCH_UNION),
158    )
159
160# 2.2.1.2.14 DHCP_CLIENT_INFO_V4
161class DHCP_CLIENT_INFO_V4(NDRSTRUCT):
162    structure = (
163        ('ClientIpAddress', DHCP_IP_ADDRESS),
164        ('SubnetMask', DHCP_IP_MASK),
165        ('ClientHardwareAddress', DHCP_CLIENT_UID),
166        ('ClientName', LPWSTR),
167        ('ClientComment', LPWSTR),
168        ('ClientLeaseExpires', DATE_TIME),
169        ('OwnerHost', DHCP_HOST_INFO),
170        ('bClientType', BYTE),
171    )
172
173class DHCP_CLIENT_INFO_V5(NDRSTRUCT):
174    structure = (
175        ('ClientIpAddress', DHCP_IP_ADDRESS),
176        ('SubnetMask', DHCP_IP_MASK),
177        ('ClientHardwareAddress', DHCP_CLIENT_UID),
178        ('ClientName', LPWSTR),
179        ('ClientComment', LPWSTR),
180        ('ClientLeaseExpires', DATE_TIME),
181        ('OwnerHost', DHCP_HOST_INFO),
182        ('bClientType', BYTE),
183        ('AddressState', BYTE),
184    )
185
186class LPDHCP_CLIENT_INFO_V4(NDRPOINTER):
187    referent = (
188        ('Data', DHCP_CLIENT_INFO_V4),
189    )
190
191class LPDHCP_CLIENT_INFO_V5(NDRPOINTER):
192    referent = (
193        ('Data', DHCP_CLIENT_INFO_V5),
194    )
195
196# 2.2.1.2.115 DHCP_CLIENT_INFO_PB
197class DHCP_CLIENT_INFO_PB(NDRSTRUCT):
198    structure = (
199        ('ClientIpAddress', DHCP_IP_ADDRESS),
200        ('SubnetMask', DHCP_IP_MASK),
201        ('ClientHardwareAddress', DHCP_CLIENT_UID),
202        ('ClientName', LPWSTR),
203        ('ClientComment', LPWSTR),
204        ('ClientLeaseExpires', DATE_TIME),
205        ('OwnerHost', DHCP_HOST_INFO),
206        ('bClientType', BYTE),
207        ('AddressState', BYTE),
208        ('Status', QuarantineStatus),
209        ('ProbationEnds', DATE_TIME),
210        ('QuarantineCapable', BOOL),
211        ('FilterStatus', DWORD),
212        ('PolicyName', LPWSTR),
213    )
214
215class LPDHCP_CLIENT_INFO_PB(NDRPOINTER):
216    referent = (
217        ('Data', DHCP_CLIENT_INFO_PB),
218    )
219
220class LPDHCP_CLIENT_INFO_VQ(NDRPOINTER):
221    referent = (
222        ('Data', DHCP_CLIENT_INFO_VQ),
223    )
224
225class DHCP_CLIENT_INFO_VQ_ARRAY(NDRUniConformantArray):
226    item = LPDHCP_CLIENT_INFO_VQ
227
228class LPDHCP_CLIENT_INFO_VQ_ARRAY(NDRPOINTER):
229    referent = (
230        ('Data', DHCP_CLIENT_INFO_VQ_ARRAY),
231    )
232
233class DHCP_CLIENT_INFO_ARRAY_VQ(NDRSTRUCT):
234    structure = (
235        ('NumElements', DWORD),
236        ('Clients', LPDHCP_CLIENT_INFO_VQ_ARRAY),
237    )
238
239class LPDHCP_CLIENT_INFO_ARRAY_VQ(NDRPOINTER):
240    referent = (
241        ('Data', DHCP_CLIENT_INFO_ARRAY_VQ),
242    )
243
244class DHCP_CLIENT_INFO_V4_ARRAY(NDRUniConformantArray):
245    item = LPDHCP_CLIENT_INFO_V4
246
247class DHCP_CLIENT_INFO_V5_ARRAY(NDRUniConformantArray):
248    item = LPDHCP_CLIENT_INFO_V5
249
250class LPDHCP_CLIENT_INFO_V4_ARRAY(NDRPOINTER):
251    referent = (
252        ('Data', DHCP_CLIENT_INFO_V4_ARRAY),
253    )
254
255class LPDHCP_CLIENT_INFO_V5_ARRAY(NDRPOINTER):
256    referent = (
257        ('Data', DHCP_CLIENT_INFO_V5_ARRAY),
258    )
259
260class DHCP_CLIENT_INFO_ARRAY_V4(NDRSTRUCT):
261    structure = (
262        ('NumElements', DWORD),
263        ('Clients', LPDHCP_CLIENT_INFO_V4_ARRAY),
264    )
265
266class DHCP_CLIENT_INFO_ARRAY_V5(NDRSTRUCT):
267    structure = (
268        ('NumElements', DWORD),
269        ('Clients', LPDHCP_CLIENT_INFO_V4_ARRAY),
270    )
271
272class LPDHCP_CLIENT_INFO_ARRAY_V5(NDRPOINTER):
273    referent = (
274        ('Data', DHCP_CLIENT_INFO_ARRAY_V5),
275    )
276
277class LPDHCP_CLIENT_INFO_ARRAY_V4(NDRPOINTER):
278    referent = (
279        ('Data', DHCP_CLIENT_INFO_ARRAY_V4),
280    )
281
282class DHCP_IP_ADDRESS_ARRAY(NDRUniConformantArray):
283    item = DHCP_IP_ADDRESS
284
285class LPDHCP_IP_ADDRESS_ARRAY(NDRPOINTER):
286    referent = (
287        ('Data', DHCP_IP_ADDRESS_ARRAY),
288    )
289
290class DHCP_IP_ARRAY(NDRSTRUCT):
291    structure = (
292        ('NumElements', DWORD),
293        ('Elements', LPDHCP_IP_ADDRESS_ARRAY),
294    )
295
296class DHCP_SUBNET_STATE(NDRENUM):
297    class enumItems(Enum):
298        DhcpSubnetEnabled           = 0
299        DhcpSubnetDisabled          = 1
300        DhcpSubnetEnabledSwitched   = 2
301        DhcpSubnetDisabledSwitched  = 3
302        DhcpSubnetInvalidState      = 4
303
304class DHCP_SUBNET_INFO(NDRSTRUCT):
305    structure = (
306        ('SubnetAddress', DHCP_IP_ADDRESS),
307        ('SubnetMask', DHCP_IP_MASK),
308        ('SubnetName', LPWSTR),
309        ('SubnetComment', LPWSTR),
310        ('PrimaryHost', DHCP_HOST_INFO),
311        ('SubnetState', DHCP_SUBNET_STATE),
312    )
313
314class LPDHCP_SUBNET_INFO(NDRPOINTER):
315    referent = (
316        ('Data', DHCP_SUBNET_INFO),
317    )
318
319class DHCP_OPTION_SCOPE_TYPE(NDRENUM):
320    class enumItems(Enum):
321        DhcpDefaultOptions  = 0
322        DhcpGlobalOptions   = 1
323        DhcpSubnetOptions   = 2
324        DhcpReservedOptions = 3
325        DhcpMScopeOptions   = 4
326
327class DHCP_RESERVED_SCOPE(NDRSTRUCT):
328    structure = (
329        ('ReservedIpAddress', DHCP_IP_ADDRESS),
330        ('ReservedIpSubnetAddress', DHCP_IP_ADDRESS),
331    )
332
333class DHCP_OPTION_SCOPE_UNION(NDRUNION):
334    union = {
335        DHCP_OPTION_SCOPE_TYPE.DhcpDefaultOptions   : (),
336        DHCP_OPTION_SCOPE_TYPE.DhcpGlobalOptions    : (),
337        DHCP_OPTION_SCOPE_TYPE.DhcpSubnetOptions    : ('SubnetScopeInfo', DHCP_IP_ADDRESS),
338        DHCP_OPTION_SCOPE_TYPE.DhcpReservedOptions  : ('ReservedScopeInfo', DHCP_RESERVED_SCOPE),
339        DHCP_OPTION_SCOPE_TYPE.DhcpMScopeOptions    : ('MScopeInfo', LPWSTR),
340    }
341
342class DHCP_OPTION_SCOPE_INFO(NDRSTRUCT):
343    structure = (
344        ('ScopeType', DHCP_OPTION_SCOPE_TYPE),
345        ('ScopeInfo', DHCP_OPTION_SCOPE_UNION),
346    )
347
348class LPDHCP_OPTION_SCOPE_INFO(NDRPOINTER):
349    referent = (
350        ('Data', DHCP_OPTION_SCOPE_INFO)
351    )
352
353class DWORD_DWORD(NDRSTRUCT):
354    structure = (
355        ('DWord1', DWORD),
356        ('DWord2', DWORD),
357    )
358
359class DHCP_BOOTP_IP_RANGE(NDRSTRUCT):
360    structure = (
361        ('StartAddress', DHCP_IP_ADDRESS),
362        ('EndAddress', DHCP_IP_ADDRESS),
363        ('BootpAllocated', ULONG),
364        ('MaxBootpAllowed', DHCP_IP_ADDRESS),
365        ('MaxBootpAllowed', ULONG ),
366    )
367
368class DHCP_IP_RESERVATION_V4(NDRSTRUCT):
369    structure = (
370        ('ReservedIpAddress', DHCP_IP_ADDRESS),
371        ('ReservedForClient', DHCP_CLIENT_UID),
372        ('bAllowedClientTypes', BYTE),
373    )
374
375class DHCP_IP_RANGE(NDRSTRUCT):
376    structure = (
377        ('StartAddress', DHCP_IP_ADDRESS),
378        ('EndAddress', DHCP_IP_ADDRESS),
379    )
380
381class DHCP_IP_CLUSTER(NDRSTRUCT):
382    structure = (
383        ('ClusterAddress', DHCP_IP_ADDRESS),
384        ('ClusterMask', DWORD),
385    )
386
387class DHCP_SUBNET_ELEMENT_TYPE(NDRENUM):
388    class enumItems(Enum):
389        DhcpIpRanges           = 0
390        DhcpSecondaryHosts     = 1
391        DhcpReservedIps        = 2
392        DhcpExcludedIpRanges   = 3
393        DhcpIpUsedClusters     = 4
394        DhcpIpRangesDhcpOnly   = 5
395        DhcpIpRangesDhcpBootp  = 6
396        DhcpIpRangesBootpOnly  = 7
397
398class DHCP_SUBNET_ELEMENT_UNION_V5(NDRUNION):
399    union = {
400        DHCP_SUBNET_ELEMENT_TYPE.DhcpIpRanges           : ('IpRange', DHCP_BOOTP_IP_RANGE),
401        DHCP_SUBNET_ELEMENT_TYPE.DhcpSecondaryHosts     : ('SecondaryHost', DHCP_HOST_INFO),
402        DHCP_SUBNET_ELEMENT_TYPE.DhcpReservedIps        : ('ReservedIp', DHCP_IP_RESERVATION_V4),
403        DHCP_SUBNET_ELEMENT_TYPE.DhcpExcludedIpRanges   : ('ExcludeIpRange', DHCP_IP_RANGE),
404        DHCP_SUBNET_ELEMENT_TYPE.DhcpIpUsedClusters     : ('IpUsedCluster', DHCP_IP_CLUSTER),
405    }
406
407class DHCP_SUBNET_ELEMENT_DATA_V5(NDRSTRUCT):
408    structure = (
409        ('ElementType', DHCP_SUBNET_ELEMENT_TYPE),
410        ('Element', DHCP_SUBNET_ELEMENT_UNION_V5),
411    )
412
413class LPDHCP_SUBNET_ELEMENT_DATA_V5(NDRUniConformantArray):
414    item = DHCP_SUBNET_ELEMENT_DATA_V5
415
416class DHCP_SUBNET_ELEMENT_INFO_ARRAY_V5(NDRSTRUCT):
417    structure = (
418        ('NumElements', DWORD),
419        ('Elements', LPDHCP_SUBNET_ELEMENT_DATA_V5),
420    )
421
422class LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V5(NDRPOINTER):
423    referent = (
424        ('Data', DHCP_SUBNET_ELEMENT_INFO_ARRAY_V5)
425    )
426
427class DHCP_OPTION_DATA_TYPE(NDRENUM):
428    class enumItems(Enum):
429        DhcpByteOption              = 0
430        DhcpWordOption              = 1
431        DhcpDWordOption             = 2
432        DhcpDWordDWordOption        = 3
433        DhcpIpAddressOption         = 4
434        DhcpStringDataOption        = 5
435        DhcpBinaryDataOption        = 6
436        DhcpEncapsulatedDataOption  = 7
437        DhcpIpv6AddressOption       = 8
438
439class DHCP_OPTION_ELEMENT_UNION(NDRUNION):
440    commonHdr = (
441        ('tag', DHCP_OPTION_DATA_TYPE),
442    )
443    union = {
444        DHCP_OPTION_DATA_TYPE.enumItems.DhcpByteOption            : ('ByteOption', BYTE),
445        DHCP_OPTION_DATA_TYPE.enumItems.DhcpWordOption            : ('WordOption', WORD),
446        DHCP_OPTION_DATA_TYPE.enumItems.DhcpDWordOption           : ('DWordOption', DWORD),
447        DHCP_OPTION_DATA_TYPE.enumItems.DhcpDWordDWordOption      : ('DWordDWordOption', DWORD_DWORD),
448        DHCP_OPTION_DATA_TYPE.enumItems.DhcpIpAddressOption       : ('IpAddressOption', DHCP_IP_ADDRESS),
449        DHCP_OPTION_DATA_TYPE.enumItems.DhcpStringDataOption      : ('StringDataOption', LPWSTR),
450        DHCP_OPTION_DATA_TYPE.enumItems.DhcpBinaryDataOption      : ('BinaryDataOption', DHCP_BINARY_DATA),
451        DHCP_OPTION_DATA_TYPE.enumItems.DhcpEncapsulatedDataOption: ('EncapsulatedDataOption', DHCP_BINARY_DATA),
452        DHCP_OPTION_DATA_TYPE.enumItems.DhcpIpv6AddressOption     : ('Ipv6AddressDataOption', LPWSTR),
453    }
454
455class DHCP_OPTION_DATA_ELEMENT(NDRSTRUCT):
456    structure = (
457        ('OptionType', DHCP_OPTION_DATA_TYPE),
458        ('Element', DHCP_OPTION_ELEMENT_UNION),
459    )
460
461class DHCP_OPTION_DATA_ELEMENT_ARRAY2(NDRUniConformantArray):
462    item = DHCP_OPTION_DATA_ELEMENT
463
464class LPDHCP_OPTION_DATA_ELEMENT(NDRPOINTER):
465    referent = (
466        ('Data', DHCP_OPTION_DATA_ELEMENT_ARRAY2),
467    )
468
469class DHCP_OPTION_DATA(NDRSTRUCT):
470    structure = (
471        ('NumElements', DWORD),
472        ('Elements', LPDHCP_OPTION_DATA_ELEMENT),
473    )
474
475class DHCP_OPTION_VALUE(NDRSTRUCT):
476    structure = (
477        ('OptionID', DHCP_OPTION_ID),
478        ('Value', DHCP_OPTION_DATA),
479    )
480
481class PDHCP_OPTION_VALUE(NDRPOINTER):
482    referent = (
483        ('Data', DHCP_OPTION_VALUE),
484    )
485
486class DHCP_OPTION_VALUE_ARRAY2(NDRUniConformantArray):
487    item = DHCP_OPTION_VALUE
488
489class LPDHCP_OPTION_VALUE(NDRPOINTER):
490    referent = (
491        ('Data', DHCP_OPTION_VALUE_ARRAY2),
492    )
493
494class DHCP_OPTION_VALUE_ARRAY(NDRSTRUCT):
495    structure = (
496        ('NumElements', DWORD),
497        ('Values', LPDHCP_OPTION_VALUE),
498    )
499
500class LPDHCP_OPTION_VALUE_ARRAY(NDRPOINTER):
501    referent = (
502        ('Data', DHCP_OPTION_VALUE_ARRAY),
503    )
504
505class DHCP_ALL_OPTION_VALUES(NDRSTRUCT):
506    structure = (
507        ('ClassName', LPWSTR),
508        ('VendorName', LPWSTR),
509        ('IsVendor', BOOL),
510        ('OptionsArray', LPDHCP_OPTION_VALUE_ARRAY),
511    )
512
513class OPTION_VALUES_ARRAY(NDRUniConformantArray):
514    item = DHCP_ALL_OPTION_VALUES
515
516class LPOPTION_VALUES_ARRAY(NDRPOINTER):
517    referent = (
518        ('Data', OPTION_VALUES_ARRAY),
519    )
520
521class DHCP_ALL_OPTION_VALUES(NDRSTRUCT):
522    structure = (
523        ('Flags', DWORD),
524        ('NumElements', DWORD),
525        ('Options', LPOPTION_VALUES_ARRAY),
526    )
527
528class LPDHCP_ALL_OPTION_VALUES(NDRPOINTER):
529    referent = (
530        ('Data', DHCP_ALL_OPTION_VALUES),
531    )
532
533################################################################################
534# RPC CALLS
535################################################################################
536# Interface dhcpsrv
537class DhcpGetSubnetInfo(NDRCALL):
538    opnum = 2
539    structure = (
540        ('ServerIpAddress', DHCP_SRV_HANDLE),
541        ('SubnetAddress', DHCP_IP_ADDRESS),
542    )
543
544class DhcpGetSubnetInfoResponse(NDRCALL):
545    structure = (
546        ('SubnetInfo', LPDHCP_SUBNET_INFO),
547        ('ErrorCode', ULONG),
548    )
549
550class DhcpEnumSubnets(NDRCALL):
551    opnum = 3
552    structure = (
553        ('ServerIpAddress', DHCP_SRV_HANDLE),
554        ('ResumeHandle', LPDWORD),
555        ('PreferredMaximum', DWORD),
556    )
557
558class DhcpEnumSubnetsResponse(NDRCALL):
559    structure = (
560        ('ResumeHandle', LPDWORD),
561        ('EnumInfo', DHCP_IP_ARRAY),
562        ('EnumRead', DWORD),
563        ('EnumTotal', DWORD),
564        ('ErrorCode', ULONG),
565    )
566
567class DhcpGetOptionValue(NDRCALL):
568    opnum = 13
569    structure = (
570        ('ServerIpAddress', DHCP_SRV_HANDLE),
571        ('OptionID', DHCP_OPTION_ID),
572        ('ScopeInfo', DHCP_OPTION_SCOPE_INFO),
573    )
574
575class DhcpGetOptionValueResponse(NDRCALL):
576    structure = (
577        ('OptionValue', PDHCP_OPTION_VALUE),
578        ('ErrorCode', ULONG),
579    )
580
581class DhcpEnumOptionValues(NDRCALL):
582    opnum = 14
583    structure = (
584        ('ServerIpAddress', DHCP_SRV_HANDLE),
585        ('ScopeInfo', DHCP_OPTION_SCOPE_INFO),
586        ('ResumeHandle', LPDWORD),
587        ('PreferredMaximum', DWORD),
588    )
589
590class DhcpEnumOptionValuesResponse(NDRCALL):
591    structure = (
592        ('ResumeHandle', DWORD),
593        ('OptionValues', LPDHCP_OPTION_VALUE_ARRAY),
594        ('OptionsRead', DWORD),
595        ('OptionsTotal', DWORD),
596        ('ErrorCode', ULONG),
597    )
598
599class DhcpGetClientInfoV4(NDRCALL):
600    opnum = 34
601    structure = (
602        ('ServerIpAddress', DHCP_SRV_HANDLE),
603        ('SearchInfo', DHCP_SEARCH_INFO),
604    )
605
606class DhcpGetClientInfoV4Response(NDRCALL):
607    structure = (
608        ('ClientInfo', LPDHCP_CLIENT_INFO_V4),
609        ('ErrorCode', ULONG),
610    )
611
612class DhcpEnumSubnetClientsV4(NDRCALL):
613    opnum = 35
614    structure = (
615        ('ServerIpAddress', DHCP_SRV_HANDLE),
616        ('SubnetAddress', DHCP_IP_ADDRESS),
617        ('ResumeHandle', DWORD),
618        ('PreferredMaximum', DWORD),
619    )
620
621class DhcpEnumSubnetClientsV4Response(NDRCALL):
622    structure = (
623        ('ResumeHandle', LPDWORD),
624        ('ClientInfo', LPDHCP_CLIENT_INFO_ARRAY_V4),
625        ('ClientsRead', DWORD),
626        ('ClientsTotal', DWORD),
627        ('ErrorCode', ULONG),
628    )
629
630# Interface dhcpsrv2
631
632class DhcpEnumSubnetClientsV5(NDRCALL):
633    opnum = 0
634    structure = (
635        ('ServerIpAddress', DHCP_SRV_HANDLE),
636        ('SubnetAddress', DHCP_IP_ADDRESS),
637        ('ResumeHandle', LPDWORD),
638        ('PreferredMaximum', DWORD),
639    )
640
641class DhcpEnumSubnetClientsV5Response(NDRCALL):
642    structure = (
643        ('ResumeHandle', DWORD),
644        ('ClientsInfo', LPDHCP_CLIENT_INFO_ARRAY_V5),
645        ('ClientsRead', DWORD),
646        ('ClientsTotal', DWORD),
647    )
648
649class DhcpGetOptionValueV5(NDRCALL):
650    opnum = 21
651    structure = (
652        ('ServerIpAddress', DHCP_SRV_HANDLE),
653        ('Flags', DWORD),
654        ('OptionID', DHCP_OPTION_ID),
655        ('ClassName', LPWSTR),
656        ('VendorName', LPWSTR),
657        ('ScopeInfo', DHCP_OPTION_SCOPE_INFO),
658    )
659
660class DhcpGetOptionValueV5Response(NDRCALL):
661    structure = (
662        ('OptionValue', PDHCP_OPTION_VALUE),
663        ('ErrorCode', ULONG),
664    )
665
666class DhcpEnumOptionValuesV5(NDRCALL):
667    opnum = 22
668    structure = (
669        ('ServerIpAddress', DHCP_SRV_HANDLE),
670        ('Flags', DWORD),
671        ('ClassName', LPWSTR),
672        ('VendorName', LPWSTR),
673        ('ScopeInfo', DHCP_OPTION_SCOPE_INFO),
674        ('ResumeHandle', LPDWORD),
675        ('PreferredMaximum', DWORD),
676    )
677
678class DhcpEnumOptionValuesV5Response(NDRCALL):
679    structure = (
680        ('ResumeHandle', DWORD),
681        ('OptionValues', LPDHCP_OPTION_VALUE_ARRAY),
682        ('OptionsRead', DWORD),
683        ('OptionsTotal', DWORD),
684        ('ErrorCode', ULONG),
685    )
686
687class DhcpGetAllOptionValues(NDRCALL):
688    opnum = 30
689    structure = (
690        ('ServerIpAddress', DHCP_SRV_HANDLE),
691        ('Flags', DWORD),
692        ('ScopeInfo', DHCP_OPTION_SCOPE_INFO),
693    )
694
695class DhcpGetAllOptionValuesResponse(NDRCALL):
696    structure = (
697        ('Values', LPDHCP_ALL_OPTION_VALUES),
698        ('ErrorCode', ULONG),
699    )
700
701class DhcpEnumSubnetElementsV5(NDRCALL):
702    opnum = 38
703    structure = (
704        ('ServerIpAddress', DHCP_SRV_HANDLE),
705        ('SubnetAddress', DHCP_IP_ADDRESS),
706        ('EnumElementType', DHCP_SUBNET_ELEMENT_TYPE),
707        ('ResumeHandle', LPDWORD),
708        ('PreferredMaximum', DWORD),
709    )
710
711class DhcpEnumSubnetElementsV5Response(NDRCALL):
712    structure = (
713        ('ResumeHandle', DWORD),
714        ('EnumElementInfo', LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V5),
715        ('ElementsRead', DWORD),
716        ('ElementsTotal', DWORD),
717        ('ErrorCode', ULONG),
718    )
719
720class DhcpEnumSubnetClientsVQ(NDRCALL):
721    opnum = 47
722    structure = (
723        ('ServerIpAddress', DHCP_SRV_HANDLE),
724        ('SubnetAddress', DHCP_IP_ADDRESS),
725        ('ResumeHandle', LPDWORD),
726        ('PreferredMaximum', DWORD),
727    )
728
729class DhcpEnumSubnetClientsVQResponse(NDRCALL):
730    structure = (
731        ('ResumeHandle', LPDWORD),
732        ('ClientInfo', LPDHCP_CLIENT_INFO_ARRAY_VQ),
733        ('ClientsRead', DWORD),
734        ('ClientsTotal', DWORD),
735        ('ErrorCode', ULONG),
736    )
737
738class DhcpV4GetClientInfo(NDRCALL):
739    opnum = 123
740    structure = (
741        ('ServerIpAddress', DHCP_SRV_HANDLE),
742        ('SearchInfo', DHCP_SEARCH_INFO),
743    )
744
745class DhcpV4GetClientInfoResponse(NDRCALL):
746    structure = (
747        ('ClientInfo', LPDHCP_CLIENT_INFO_PB),
748        ('ErrorCode', ULONG),
749    )
750
751################################################################################
752# OPNUMs and their corresponding structures
753################################################################################
754OPNUMS = {
755    0: (DhcpEnumSubnetClientsV5, DhcpEnumSubnetClientsV5Response),
756    2: (DhcpGetSubnetInfo, DhcpGetSubnetInfoResponse),
757    3: (DhcpEnumSubnets, DhcpEnumSubnetsResponse),
758    13: (DhcpGetOptionValue, DhcpGetOptionValueResponse),
759    14: (DhcpEnumOptionValues, DhcpEnumOptionValuesResponse),
760    21: (DhcpGetOptionValueV5, DhcpGetOptionValueV5Response),
761    22: (DhcpEnumOptionValuesV5, DhcpEnumOptionValuesV5Response),
762    30: (DhcpGetAllOptionValues, DhcpGetAllOptionValuesResponse),
763    34: (DhcpGetClientInfoV4, DhcpGetClientInfoV4Response),
764    35: (DhcpEnumSubnetClientsV4, DhcpEnumSubnetClientsV4Response),
765    38: (DhcpEnumSubnetElementsV5, DhcpEnumSubnetElementsV5Response),
766    47: (DhcpEnumSubnetClientsVQ, DhcpEnumSubnetClientsVQResponse),
767    123: (DhcpV4GetClientInfo, DhcpV4GetClientInfoResponse),
768}
769
770
771################################################################################
772# HELPER FUNCTIONS
773################################################################################
774def hDhcpGetClientInfoV4(dce, searchType, searchValue):
775    request = DhcpGetClientInfoV4()
776
777    request['ServerIpAddress'] = NULL
778    request['SearchInfo']['SearchType'] = searchType
779    request['SearchInfo']['SearchInfo']['tag'] = searchType
780    if searchType == DHCP_SEARCH_INFO_TYPE.DhcpClientIpAddress:
781        request['SearchInfo']['SearchInfo']['ClientIpAddress'] = searchValue
782    elif searchType == DHCP_SEARCH_INFO_TYPE.DhcpClientHardwareAddress:
783        # This should be a DHCP_BINARY_DATA
784        request['SearchInfo']['SearchInfo']['ClientHardwareAddress'] = searchValue
785    else:
786        request['SearchInfo']['SearchInfo']['ClientName'] = searchValue
787
788    return dce.request(request)
789
790def hDhcpGetSubnetInfo(dce, subnetaddress):
791    request = DhcpGetSubnetInfo()
792
793    request['ServerIpAddress'] = NULL
794    request['SubnetAddress'] = subnetaddress
795    resp = dce.request(request)
796
797    return resp
798
799def hDhcpGetOptionValue(dce, optionID, scopetype=DHCP_OPTION_SCOPE_TYPE.DhcpDefaultOptions, options=NULL):
800    request = DhcpGetOptionValue()
801
802    request['ServerIpAddress'] = NULL
803    request['OptionID'] = optionID
804    request['ScopeInfo']['ScopeType'] = scopetype
805    if scopetype != DHCP_OPTION_SCOPE_TYPE.DhcpDefaultOptions and scopetype != DHCP_OPTION_SCOPE_TYPE.DhcpGlobalOptions:
806        request['ScopeInfo']['ScopeInfo']['tag'] = scopetype
807    if scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpSubnetOptions:
808        request['ScopeInfo']['ScopeInfo']['SubnetScopeInfo'] = options
809    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpReservedOptions:
810        request['ScopeInfo']['ScopeInfo']['ReservedScopeInfo'] = options
811    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpMScopeOptions:
812        request['ScopeInfo']['ScopeInfo']['MScopeInfo'] = options
813
814    status = system_errors.ERROR_MORE_DATA
815    while status == system_errors.ERROR_MORE_DATA:
816        try:
817            resp = dce.request(request)
818        except DCERPCException, e:
819            if str(e).find('ERROR_NO_MORE_ITEMS') < 0:
820                raise
821            resp = e.get_packet()
822        return resp
823
824def hDhcpEnumOptionValues(dce, scopetype=DHCP_OPTION_SCOPE_TYPE.DhcpDefaultOptions, options=NULL,
825                          preferredMaximum=0xffffffff):
826    request = DhcpEnumOptionValues()
827
828    request['ServerIpAddress'] = NULL
829    request['ScopeInfo']['ScopeType'] = scopetype
830    if scopetype != DHCP_OPTION_SCOPE_TYPE.DhcpDefaultOptions and scopetype != DHCP_OPTION_SCOPE_TYPE.DhcpGlobalOptions:
831        request['ScopeInfo']['ScopeInfo']['tag'] = scopetype
832    if scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpSubnetOptions:
833        request['ScopeInfo']['ScopeInfo']['SubnetScopeInfo'] = options
834    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpReservedOptions:
835        request['ScopeInfo']['ScopeInfo']['ReservedScopeInfo'] = options
836    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpMScopeOptions:
837        request['ScopeInfo']['ScopeInfo']['MScopeInfo'] = options
838    request['ResumeHandle'] = NULL
839    request['PreferredMaximum'] = preferredMaximum
840
841    status = system_errors.ERROR_MORE_DATA
842    while status == system_errors.ERROR_MORE_DATA:
843        try:
844            resp = dce.request(request)
845        except DCERPCException, e:
846            if str(e).find('ERROR_NO_MORE_ITEMS') < 0:
847                raise
848            resp = e.get_packet()
849        return resp
850
851def hDhcpEnumOptionValuesV5(dce, flags=DHCP_FLAGS_OPTION_DEFAULT, classname=NULL, vendorname=NULL,
852                            scopetype=DHCP_OPTION_SCOPE_TYPE.DhcpDefaultOptions, options=NULL,
853                            preferredMaximum=0xffffffff):
854    request = DhcpEnumOptionValuesV5()
855
856    request['ServerIpAddress'] = NULL
857    request['Flags'] = flags
858    request['ClassName'] = classname
859    request['VendorName'] = vendorname
860    request['ScopeInfo']['ScopeType'] = scopetype
861    request['ScopeInfo']['ScopeInfo']['tag'] = scopetype
862    if scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpSubnetOptions:
863        request['ScopeInfo']['ScopeInfo']['SubnetScopeInfo'] = options
864    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpReservedOptions:
865        request['ScopeInfo']['ScopeInfo']['ReservedScopeInfo'] = options
866    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpMScopeOptions:
867        request['ScopeInfo']['ScopeInfo']['MScopeInfo'] = options
868    request['ResumeHandle'] = NULL
869    request['PreferredMaximum'] = preferredMaximum
870
871    status = system_errors.ERROR_MORE_DATA
872    while status == system_errors.ERROR_MORE_DATA:
873        try:
874            resp = dce.request(request)
875        except DCERPCException, e:
876            if str(e).find('ERROR_NO_MORE_ITEMS') < 0:
877                raise
878            resp = e.get_packet()
879        return resp
880
881def hDhcpGetOptionValueV5(dce, option_id, flags=DHCP_FLAGS_OPTION_DEFAULT, classname=NULL, vendorname=NULL,
882                            scopetype=DHCP_OPTION_SCOPE_TYPE.DhcpDefaultOptions, options=NULL):
883    request = DhcpGetOptionValueV5()
884
885    request['ServerIpAddress'] = NULL
886    request['Flags'] = flags
887    request['OptionID'] = option_id
888    request['ClassName'] = classname
889    request['VendorName'] = vendorname
890    request['ScopeInfo']['ScopeType'] = scopetype
891    request['ScopeInfo']['ScopeInfo']['tag'] = scopetype.value
892    if scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpSubnetOptions:
893        request['ScopeInfo']['ScopeInfo']['SubnetScopeInfo'] = options
894    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpReservedOptions:
895        request['ScopeInfo']['ScopeInfo']['ReservedScopeInfo'] = options
896    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpMScopeOptions:
897        request['ScopeInfo']['ScopeInfo']['MScopeInfo'] = options
898
899    status = system_errors.ERROR_MORE_DATA
900    while status == system_errors.ERROR_MORE_DATA:
901        try:
902            resp = dce.request(request)
903        except DCERPCException, e:
904            if str(e).find('ERROR_NO_MORE_ITEMS') < 0:
905                raise
906            resp = e.get_packet()
907        return resp
908
909def hDhcpGetAllOptionValues(dce, scopetype=DHCP_OPTION_SCOPE_TYPE.DhcpDefaultOptions, options=NULL):
910    request = DhcpGetAllOptionValues()
911
912    request['ServerIpAddress'] = NULL
913    request['Flags'] = NULL
914    request['ScopeInfo']['ScopeType'] = scopetype
915    request['ScopeInfo']['ScopeInfo']['tag'] = scopetype
916    if scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpSubnetOptions:
917        request['ScopeInfo']['ScopeInfo']['SubnetScopeInfo'] = options
918    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpReservedOptions:
919        request['ScopeInfo']['ScopeInfo']['ReservedScopeInfo'] = options
920    elif scopetype == DHCP_OPTION_SCOPE_TYPE.DhcpMScopeOptions:
921        request['ScopeInfo']['ScopeInfo']['MScopeInfo'] = options
922
923    status = system_errors.ERROR_MORE_DATA
924    while status == system_errors.ERROR_MORE_DATA:
925        try:
926            resp = dce.request(request)
927        except DCERPCException, e:
928            if str(e).find('ERROR_NO_MORE_ITEMS') < 0:
929                raise
930            resp = e.get_packet()
931        return resp
932
933def hDhcpEnumSubnets(dce, preferredMaximum=0xffffffff):
934    request = DhcpEnumSubnets()
935
936    request['ServerIpAddress'] = NULL
937    request['ResumeHandle'] = NULL
938    request['PreferredMaximum'] = preferredMaximum
939    status = system_errors.ERROR_MORE_DATA
940    while status == system_errors.ERROR_MORE_DATA:
941        try:
942            resp = dce.request(request)
943        except DCERPCException, e:
944            if str(e).find('STATUS_MORE_ENTRIES') < 0:
945                raise
946            resp = e.get_packet()
947        return resp
948
949def hDhcpEnumSubnetClientsVQ(dce, preferredMaximum=0xffffffff):
950    request = DhcpEnumSubnetClientsVQ()
951
952    request['ServerIpAddress'] = NULL
953    request['SubnetAddress'] = NULL
954    request['ResumeHandle'] = NULL
955    request['PreferredMaximum'] = preferredMaximum
956    status = system_errors.ERROR_MORE_DATA
957    while status == system_errors.ERROR_MORE_DATA:
958        try:
959            resp = dce.request(request)
960        except DCERPCException, e:
961            if str(e).find('STATUS_MORE_ENTRIES') < 0:
962                raise
963            resp = e.get_packet()
964        return resp
965
966def hDhcpEnumSubnetClientsV4(dce, preferredMaximum=0xffffffff):
967    request = DhcpEnumSubnetClientsV4()
968
969    request['ServerIpAddress'] = NULL
970    request['SubnetAddress'] = NULL
971    request['ResumeHandle'] = NULL
972    request['PreferredMaximum'] = preferredMaximum
973    status = system_errors.ERROR_MORE_DATA
974    while status == system_errors.ERROR_MORE_DATA:
975        try:
976            resp = dce.request(request)
977        except DCERPCException, e:
978            if str(e).find('STATUS_MORE_ENTRIES') < 0:
979                raise
980            resp = e.get_packet()
981        return resp
982
983def hDhcpEnumSubnetClientsV5(dce, subnetAddress=0, preferredMaximum=0xffffffff):
984    request = DhcpEnumSubnetClientsV5()
985
986    request['ServerIpAddress'] = NULL
987    request['SubnetAddress'] = subnetAddress
988    request['ResumeHandle'] = NULL
989    request['PreferredMaximum'] = preferredMaximum
990    status = system_errors.ERROR_MORE_DATA
991    while status == system_errors.ERROR_MORE_DATA:
992        try:
993            resp = dce.request(request)
994        except DCERPCSessionError, e:
995            if str(e).find('STATUS_MORE_ENTRIES') < 0:
996                raise
997            resp = e.get_packet()
998        return resp
999
1000def hDhcpEnumSubnetElementsV5(dce, subnet_address, element_type=DHCP_SUBNET_ELEMENT_TYPE.DhcpIpRanges, preferredMaximum=0xffffffff):
1001    request = DhcpEnumSubnetElementsV5()
1002
1003    request['ServerIpAddress'] = NULL
1004    request['SubnetAddress'] = subnet_address
1005    request['EnumElementType'] = element_type
1006    request['ResumeHandle'] = NULL
1007    request['PreferredMaximum'] = preferredMaximum
1008
1009    status = system_errors.ERROR_MORE_DATA
1010    while status == system_errors.ERROR_MORE_DATA:
1011        try:
1012            resp = dce.request(request)
1013        except DCERPCException, e:
1014            if str(e).find('ERROR_NO_MORE_ITEMS') < 0:
1015                raise
1016            resp = e.get_packet()
1017        return resp
1018