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-WKST] 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#
21from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRENUM, NDRUNION, NDRUniConformantArray, NDRUniFixedArray, \
22    NDRPOINTER
23from impacket.dcerpc.v5.dtypes import NULL, WSTR, ULONG, LPWSTR, LONG, LARGE_INTEGER, WIDESTR, RPC_UNICODE_STRING, \
24    LPULONG, LPLONG
25from impacket import system_errors
26from impacket.uuid import uuidtup_to_bin
27from impacket.dcerpc.v5.enum import Enum
28from impacket.dcerpc.v5.rpcrt import DCERPCException
29
30MSRPC_UUID_WKST   = uuidtup_to_bin(('6BFFD098-A112-3610-9833-46C3F87E345A', '1.0'))
31
32class DCERPCSessionError(DCERPCException):
33    def __init__(self, error_string=None, error_code=None, packet=None):
34        DCERPCException.__init__(self, error_string, error_code, packet)
35
36    def __str__( self ):
37        key = self.error_code
38        if system_errors.ERROR_MESSAGES.has_key(key):
39            error_msg_short = system_errors.ERROR_MESSAGES[key][0]
40            error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
41            return 'WKST SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
42        else:
43            return 'WKST SessionError: unknown error code: 0x%x' % self.error_code
44
45################################################################################
46# CONSTANTS
47################################################################################
48
49# 2.2.1.1 JOIN_MAX_PASSWORD_LENGTH
50JOIN_MAX_PASSWORD_LENGTH = 256
51
52# 2.2.1.2 JOIN_OBFUSCATOR_LENGTH
53JOIN_OBFUSCATOR_LENGTH = 8
54
55# 2.2.1.3 MAX_PREFERRED_LENGTH
56MAX_PREFERRED_LENGTH = 0xffffffff
57
58# 2.2.5.22 USE_INFO_1
59USE_OK       = 0x00000000
60USE_PAUSED   = 0x00000001
61USE_SESSLOST = 0x00000002
62USE_NETERR   = 0x00000003
63USE_CONN     = 0x00000004
64USE_RECONN   = 0x00000005
65
66USE_WILDCARD = 0xFFFFFFFF
67USE_DISKDEV  = 0x00000000
68USE_SPOOLDEV = 0x00000001
69USE_CHARDEV  = 0x00000002
70USE_IPC      = 0x00000003
71
72# 3.2.4.9 NetrUseDel (Opnum 10)
73# Force Level
74USE_NOFORCE       = 0x00000000
75USE_FORCE         = 0x00000001
76USE_LOTS_OF_FORCE = 0x00000002
77
78# 3.2.4.13 NetrJoinDomain2 (Opnum 22)
79# Options
80NETSETUP_JOIN_DOMAIN           = 0x00000001
81NETSETUP_ACCT_CREATE           = 0x00000002
82NETSETUP_ACCT_DELETE           = 0x00000004
83NETSETUP_DOMAIN_JOIN_IF_JOINED = 0x00000020
84NETSETUP_JOIN_UNSECURE         = 0x00000040
85NETSETUP_MACHINE_PWD_PASSED    = 0x00000080
86NETSETUP_DEFER_SPN_SET         = 0x00000100
87NETSETUP_JOIN_DC_ACCOUNT       = 0x00000200
88NETSETUP_JOIN_WITH_NEW_NAME    = 0x00000400
89NETSETUP_INSTALL_INVOCATION    = 0x00040000
90
91# 3.2.4.14 NetrUnjoinDomain2 (Opnum 23)
92# Options
93NETSETUP_ACCT_DELETE              = 0x00000004
94NETSETUP_IGNORE_UNSUPPORTED_FLAGS = 0x10000000
95
96# 3.2.4.15 NetrRenameMachineInDomain2 (Opnum 24)
97# Options
98NETSETUP_ACCT_CREATE           = 0x00000002
99NETSETUP_DNS_NAME_CHANGES_ONLY = 0x00001000
100
101################################################################################
102# STRUCTURES
103################################################################################
104
105# 2.2.2.1 WKSSVC_IDENTIFY_HANDLE
106class WKSSVC_IDENTIFY_HANDLE(NDRSTRUCT):
107    structure =  (
108        ('Data', WSTR),
109    )
110
111class LPWKSSVC_IDENTIFY_HANDLE(NDRPOINTER):
112    referent = (
113        ('Data', WKSSVC_IDENTIFY_HANDLE),
114    )
115
116# 2.2.2.2 WKSSVC_IMPERSONATE_HANDLE
117class WKSSVC_IMPERSONATE_HANDLE(NDRSTRUCT):
118    structure =  (
119        ('Data',WSTR),
120    )
121
122class LPWKSSVC_IMPERSONATE_HANDLE(NDRPOINTER):
123    referent = (
124        ('Data', WKSSVC_IMPERSONATE_HANDLE),
125    )
126
127# 2.2.3.1 NETSETUP_JOIN_STATUS
128class NETSETUP_JOIN_STATUS(NDRENUM):
129    class enumItems(Enum):
130        NetSetupUnknownStatus = 1
131        NetSetupUnjoined      = 2
132        NetSetupWorkgroupName = 3
133        NetSetupDomainName    = 4
134
135# 2.2.3.2 NETSETUP_NAME_TYPE
136class NETSETUP_NAME_TYPE(NDRENUM):
137    class enumItems(Enum):
138        NetSetupUnknown           = 0
139        NetSetupMachine           = 1
140        NetSetupWorkgroup         = 2
141        NetSetupDomain            = 3
142        NetSetupNonExistentDomain = 4
143        NetSetupDnsMachine        = 5
144
145# 2.2.3.3 NET_COMPUTER_NAME_TYPE
146class NET_COMPUTER_NAME_TYPE(NDRENUM):
147    class enumItems(Enum):
148        NetPrimaryComputerName    = 0
149        NetAlternateComputerNames = 1
150        NetAllComputerNames       = 2
151        NetComputerNameTypeMax    = 3
152
153# 2.2.5.1 WKSTA_INFO_100
154class WKSTA_INFO_100(NDRSTRUCT):
155    structure = (
156        ('wki100_platform_id', ULONG),
157        ('wki100_computername', LPWSTR),
158        ('wki100_langroup', LPWSTR),
159        ('wki100_ver_major', ULONG),
160        ('wki100_ver_minor', ULONG),
161    )
162
163class LPWKSTA_INFO_100(NDRPOINTER):
164    referent = (
165        ('Data', WKSTA_INFO_100),
166    )
167
168# 2.2.5.2 WKSTA_INFO_101
169class WKSTA_INFO_101(NDRSTRUCT):
170    structure = (
171        ('wki101_platform_id', ULONG),
172        ('wki101_computername', LPWSTR),
173        ('wki101_langroup', LPWSTR),
174        ('wki101_ver_major', ULONG),
175        ('wki101_ver_minor', ULONG),
176        ('wki101_lanroot', LPWSTR),
177    )
178
179class LPWKSTA_INFO_101(NDRPOINTER):
180    referent = (
181        ('Data', WKSTA_INFO_101),
182    )
183
184# 2.2.5.3 WKSTA_INFO_102
185class WKSTA_INFO_102(NDRSTRUCT):
186    structure = (
187        ('wki102_platform_id', ULONG),
188        ('wki102_computername', LPWSTR),
189        ('wki102_langroup', LPWSTR),
190        ('wki102_ver_major', ULONG),
191        ('wki102_ver_minor', ULONG),
192        ('wki102_lanroot', LPWSTR),
193        ('wki102_logged_on_users', ULONG),
194    )
195
196class LPWKSTA_INFO_102(NDRPOINTER):
197    referent = (
198        ('Data', WKSTA_INFO_102),
199    )
200
201# 2.2.5.4 WKSTA_INFO_502
202class WKSTA_INFO_502(NDRSTRUCT):
203    structure = (
204        ('wki502_char_wait', ULONG),
205        ('wki502_collection_time', ULONG),
206        ('wki502_maximum_collection_count', ULONG),
207        ('wki502_keep_conn', ULONG),
208        ('wki502_max_cmds', ULONG),
209        ('wki502_sess_timeout', ULONG),
210        ('wki502_siz_char_buf', ULONG),
211        ('wki502_max_threads', ULONG),
212        ('wki502_lock_quota', ULONG),
213        ('wki502_lock_increment', ULONG),
214        ('wki502_lock_maximum', ULONG),
215        ('wki502_pipe_increment', ULONG),
216        ('wki502_pipe_maximum', ULONG),
217        ('wki502_cache_file_timeout', ULONG),
218        ('wki502_dormant_file_limit', ULONG),
219        ('wki502_read_ahead_throughput', ULONG),
220        ('wki502_num_mailslot_buffers', ULONG),
221        ('wki502_num_srv_announce_buffers', ULONG),
222        ('wki502_max_illegal_datagram_events', ULONG),
223        ('wki502_illegal_datagram_event_reset_frequency', ULONG),
224        ('wki502_log_election_packets', LONG),
225        ('wki502_use_opportunistic_locking', LONG),
226        ('wki502_use_unlock_behind', LONG),
227        ('wki502_use_close_behind', LONG),
228        ('wki502_buf_named_pipes', LONG),
229        ('wki502_use_lock_read_unlock', LONG),
230        ('wki502_utilize_nt_caching', LONG),
231        ('wki502_use_raw_read', LONG),
232        ('wki502_use_raw_write', LONG),
233        ('wki502_use_write_raw_data', LONG),
234        ('wki502_use_encryption', LONG),
235        ('wki502_buf_files_deny_write', LONG),
236        ('wki502_buf_read_only_files', LONG),
237        ('wki502_force_core_create_mode', LONG),
238        ('wki502_use_512_byte_max_transfer', LONG),
239    )
240
241class LPWKSTA_INFO_502(NDRPOINTER):
242    referent = (
243        ('Data', WKSTA_INFO_502),
244    )
245
246# 2.2.5.5 WKSTA_INFO_1013
247class WKSTA_INFO_1013(NDRSTRUCT):
248    structure = (
249        ('wki1013_keep_conn', ULONG),
250    )
251
252class LPWKSTA_INFO_1013(NDRPOINTER):
253    referent = (
254        ('Data', WKSTA_INFO_1013),
255    )
256
257# 2.2.5.6 WKSTA_INFO_1018
258class WKSTA_INFO_1018(NDRSTRUCT):
259    structure = (
260        ('wki1018_sess_timeout', ULONG),
261    )
262
263class LPWKSTA_INFO_1018(NDRPOINTER):
264    referent = (
265        ('Data', WKSTA_INFO_1018),
266    )
267
268# 2.2.5.7 WKSTA_INFO_1046
269class WKSTA_INFO_1046(NDRSTRUCT):
270    structure = (
271        ('wki1046_dormant_file_limit', ULONG),
272    )
273
274class LPWKSTA_INFO_1046(NDRPOINTER):
275    referent = (
276        ('Data', WKSTA_INFO_1046),
277    )
278
279# 2.2.4.1 WKSTA_INFO
280class WKSTA_INFO(NDRUNION):
281    commonHdr = (
282        ('tag', ULONG),
283    )
284    union = {
285        100: ('WkstaInfo100', LPWKSTA_INFO_100),
286        101: ('WkstaInfo101', LPWKSTA_INFO_101),
287        102: ('WkstaInfo102', LPWKSTA_INFO_102),
288        502: ('WkstaInfo502', LPWKSTA_INFO_502),
289        1013: ('WkstaInfo1013', LPWKSTA_INFO_1013),
290        1018: ('WkstaInfo1018', LPWKSTA_INFO_1018),
291        1046: ('WkstaInfo1046', LPWKSTA_INFO_1046),
292    }
293
294class LPWKSTA_INFO(NDRPOINTER):
295    referent = (
296        ('Data', WKSTA_INFO),
297    )
298
299# 2.2.5.8 WKSTA_TRANSPORT_INFO_0
300class WKSTA_TRANSPORT_INFO_0(NDRSTRUCT):
301    structure = (
302        ('wkti0_quality_of_service', ULONG),
303        ('wkti0_number_of_vcs', ULONG),
304        ('wkti0_transport_name', LPWSTR),
305        ('wkti0_transport_address', LPWSTR),
306        ('wkti0_wan_ish', ULONG),
307    )
308
309# 2.2.5.9 WKSTA_USER_INFO_0
310class WKSTA_USER_INFO_0(NDRSTRUCT):
311    structure = (
312        ('wkui0_username', LPWSTR),
313    )
314
315# 2.2.5.10 WKSTA_USER_INFO_1
316class WKSTA_USER_INFO_1(NDRSTRUCT):
317    structure = (
318        ('wkui1_username', LPWSTR),
319        ('wkui1_logon_domain', LPWSTR),
320        ('wkui1_oth_domains', LPWSTR),
321        ('wkui1_logon_server', LPWSTR),
322    )
323
324# 2.2.5.11 STAT_WORKSTATION_0
325class STAT_WORKSTATION_0(NDRSTRUCT):
326    structure = (
327        ('StatisticsStartTime', LARGE_INTEGER),
328        ('BytesReceived', LARGE_INTEGER),
329        ('SmbsReceived', LARGE_INTEGER),
330        ('PagingReadBytesRequested', LARGE_INTEGER),
331        ('NonPagingReadBytesRequested', LARGE_INTEGER),
332        ('CacheReadBytesRequested', LARGE_INTEGER),
333        ('NetworkReadBytesRequested', LARGE_INTEGER),
334        ('BytesTransmitted', LARGE_INTEGER),
335        ('SmbsTransmitted', LARGE_INTEGER),
336        ('PagingWriteBytesRequested', LARGE_INTEGER),
337        ('NonPagingWriteBytesRequested', LARGE_INTEGER),
338        ('CacheWriteBytesRequested', LARGE_INTEGER),
339        ('NetworkWriteBytesRequested', LARGE_INTEGER),
340        ('InitiallyFailedOperations', ULONG),
341        ('FailedCompletionOperations', ULONG),
342        ('ReadOperations', ULONG),
343        ('RandomReadOperations', ULONG),
344        ('ReadSmbs', ULONG),
345        ('LargeReadSmbs', ULONG),
346        ('SmallReadSmbs', ULONG),
347        ('WriteOperations', ULONG),
348        ('RandomWriteOperations', ULONG),
349        ('WriteSmbs', ULONG),
350        ('LargeWriteSmbs', ULONG),
351        ('SmallWriteSmbs', ULONG),
352        ('RawReadsDenied', ULONG),
353        ('RawWritesDenied', ULONG),
354        ('NetworkErrors', ULONG),
355        ('Sessions', ULONG),
356        ('FailedSessions', ULONG),
357        ('Reconnects', ULONG),
358        ('CoreConnects', ULONG),
359        ('Lanman20Connects', ULONG),
360        ('Lanman21Connects', ULONG),
361        ('LanmanNtConnects', ULONG),
362        ('ServerDisconnects', ULONG),
363        ('HungSessions', ULONG),
364        ('UseCount', ULONG),
365        ('FailedUseCount', ULONG),
366        ('CurrentCommands', ULONG),
367    )
368
369class LPSTAT_WORKSTATION_0(NDRPOINTER):
370    referent = (
371        ('Data', STAT_WORKSTATION_0),
372    )
373
374# 2.2.5.12 WKSTA_USER_INFO_0_CONTAINER
375class WKSTA_USER_INFO_0_ARRAY(NDRUniConformantArray):
376    item = WKSTA_USER_INFO_0
377
378class LPWKSTA_USER_INFO_0_ARRAY(NDRPOINTER):
379    referent = (
380        ('Data', WKSTA_USER_INFO_0_ARRAY),
381    )
382
383class WKSTA_USER_INFO_0_CONTAINER(NDRSTRUCT):
384    structure = (
385        ('EntriesRead', ULONG),
386        ('Buffer', LPWKSTA_USER_INFO_0_ARRAY),
387    )
388
389class LPWKSTA_USER_INFO_0_CONTAINER(NDRPOINTER):
390    referent = (
391        ('Data', WKSTA_USER_INFO_0_CONTAINER),
392    )
393
394# 2.2.5.13 WKSTA_USER_INFO_1_CONTAINER
395class WKSTA_USER_INFO_1_ARRAY(NDRUniConformantArray):
396    item = WKSTA_USER_INFO_1
397
398class LPWKSTA_USER_INFO_1_ARRAY(NDRPOINTER):
399    referent = (
400        ('Data', WKSTA_USER_INFO_1_ARRAY),
401    )
402
403class WKSTA_USER_INFO_1_CONTAINER(NDRSTRUCT):
404    structure = (
405        ('EntriesRead', ULONG),
406        ('Buffer', LPWKSTA_USER_INFO_1_ARRAY),
407    )
408
409class LPWKSTA_USER_INFO_1_CONTAINER(NDRPOINTER):
410    referent = (
411        ('Data', WKSTA_USER_INFO_1_CONTAINER),
412    )
413
414# 2.2.5.14 WKSTA_USER_ENUM_STRUCT
415class WKSTA_USER_ENUM_UNION(NDRUNION):
416    commonHdr = (
417        ('tag', ULONG),
418    )
419
420    union = {
421        0: ('Level0', LPWKSTA_USER_INFO_0_CONTAINER),
422        1: ('Level1', LPWKSTA_USER_INFO_1_CONTAINER),
423    }
424
425class WKSTA_USER_ENUM_STRUCT(NDRSTRUCT):
426    structure = (
427        ('Level', ULONG),
428        ('WkstaUserInfo', WKSTA_USER_ENUM_UNION),
429    )
430
431
432# 2.2.5.15 WKSTA_TRANSPORT_INFO_0_CONTAINER
433class WKSTA_TRANSPORT_INFO_0_ARRAY(NDRUniConformantArray):
434    item = WKSTA_TRANSPORT_INFO_0
435
436class LPWKSTA_TRANSPORT_INFO_0_ARRAY(NDRPOINTER):
437    referent = (
438        ('Data', WKSTA_TRANSPORT_INFO_0_ARRAY),
439    )
440
441class WKSTA_TRANSPORT_INFO_0_CONTAINER(NDRSTRUCT):
442    structure = (
443        ('EntriesRead', ULONG),
444        ('Buffer', LPWKSTA_TRANSPORT_INFO_0_ARRAY),
445    )
446
447class LPWKSTA_TRANSPORT_INFO_0_CONTAINER(NDRPOINTER):
448    referent = (
449        ('Data', WKSTA_TRANSPORT_INFO_0_CONTAINER),
450    )
451
452# 2.2.5.16 WKSTA_TRANSPORT_ENUM_STRUCT
453class WKSTA_TRANSPORT_ENUM_UNION(NDRUNION):
454    commonHdr = (
455        ('tag', ULONG),
456    )
457
458    union = {
459        0: ('Level0', LPWKSTA_TRANSPORT_INFO_0_CONTAINER),
460    }
461
462class WKSTA_TRANSPORT_ENUM_STRUCT(NDRSTRUCT):
463    structure = (
464        ('Level', ULONG),
465        ('WkstaTransportInfo', WKSTA_TRANSPORT_ENUM_UNION),
466    )
467
468# 2.2.5.17 JOINPR_USER_PASSWORD
469class WCHAR_ARRAY(WIDESTR):
470    def getDataLen(self, data):
471        return JOIN_MAX_PASSWORD_LENGTH
472
473class CHAR_ARRAY(NDRUniFixedArray):
474    def getDataLen(self, data):
475        return JOIN_OBFUSCATOR_LENGTH
476
477class JOINPR_USER_PASSWORD(NDRSTRUCT):
478    structure = (
479        ('Obfuscator', CHAR_ARRAY),
480        ('Buffer', WCHAR_ARRAY),
481    )
482
483# 2.2.5.18 JOINPR_ENCRYPTED_USER_PASSWORD
484class JOINPR_ENCRYPTED_USER_PASSWORD(NDRSTRUCT):
485    structure = (
486        ('Buffer', '524s=""'),
487    )
488    def getAlignment(self):
489        return 1
490
491class PJOINPR_ENCRYPTED_USER_PASSWORD(NDRPOINTER):
492    referent = (
493        ('Data', JOINPR_ENCRYPTED_USER_PASSWORD),
494    )
495
496# 2.2.5.19 UNICODE_STRING
497UNICODE_STRING = WSTR
498class PUNICODE_STRING(NDRPOINTER):
499    referent = (
500        ('Data', UNICODE_STRING),
501    )
502
503# 2.2.5.20 NET_COMPUTER_NAME_ARRAY
504class UNICODE_STRING_ARRAY(NDRUniConformantArray):
505    item = RPC_UNICODE_STRING
506
507class PUNICODE_STRING_ARRAY(NDRPOINTER):
508    referent = (
509        ('Data', UNICODE_STRING_ARRAY),
510    )
511
512class NET_COMPUTER_NAME_ARRAY(NDRSTRUCT):
513    structure = (
514        ('EntriesRead', ULONG),
515        ('ComputerNames', PUNICODE_STRING_ARRAY),
516    )
517
518class PNET_COMPUTER_NAME_ARRAY(NDRPOINTER):
519    referent = (
520        ('Data', NET_COMPUTER_NAME_ARRAY),
521    )
522
523# 2.2.5.21 USE_INFO_0
524class USE_INFO_0(NDRSTRUCT):
525    structure = (
526        ('ui0_local', LPWSTR),
527        ('ui0_remote', LPWSTR),
528    )
529
530class LPUSE_INFO_0(NDRPOINTER):
531    referent = (
532        ('Data', USE_INFO_0),
533    )
534
535# 2.2.5.22 USE_INFO_1
536class USE_INFO_1(NDRSTRUCT):
537    structure = (
538        ('ui1_local', LPWSTR),
539        ('ui1_remote', LPWSTR),
540        ('ui1_password', LPWSTR),
541        ('ui1_status', ULONG),
542        ('ui1_asg_type', ULONG),
543        ('ui1_refcount', ULONG),
544        ('ui1_usecount', ULONG),
545    )
546
547class LPUSE_INFO_1(NDRPOINTER):
548    referent = (
549        ('Data', USE_INFO_1),
550    )
551
552# 2.2.5.23 USE_INFO_2
553class USE_INFO_2(NDRSTRUCT):
554    structure = (
555        ('ui2_useinfo', USE_INFO_1),
556        ('ui2_username', LPWSTR),
557        ('ui2_domainname', LPWSTR),
558    )
559
560class LPUSE_INFO_2(NDRPOINTER):
561    referent = (
562        ('Data', USE_INFO_2),
563    )
564
565# 2.2.5.24 USE_INFO_3
566class USE_INFO_3(NDRSTRUCT):
567    structure = (
568        ('ui3_ui2', USE_INFO_2),
569        ('ui3_flags', ULONG),
570    )
571
572class LPUSE_INFO_3(NDRPOINTER):
573    referent = (
574        ('Data', USE_INFO_3),
575    )
576
577# 2.2.4.2 USE_INFO
578class USE_INFO(NDRUNION):
579    commonHdr = (
580        ('tag', ULONG),
581    )
582
583    union = {
584        0: ('UseInfo0', LPUSE_INFO_0),
585        1: ('UseInfo1', LPUSE_INFO_1),
586        2: ('UseInfo2', LPUSE_INFO_2),
587        3: ('UseInfo3', LPUSE_INFO_3),
588    }
589
590# 2.2.5.25 USE_INFO_0_CONTAINER
591class USE_INFO_0_CONTAINER(NDRSTRUCT):
592    structure = (
593        ('EntriesRead', ULONG),
594        ('Buffer', LPUSE_INFO_0),
595    )
596
597class LPUSE_INFO_0_CONTAINER(NDRPOINTER):
598    referent = (
599        ('Data', USE_INFO_0_CONTAINER),
600    )
601
602# 2.2.5.26 USE_INFO_1_CONTAINER
603class USE_INFO_1_CONTAINER(NDRSTRUCT):
604    structure = (
605        ('EntriesRead', ULONG),
606        ('Buffer', LPUSE_INFO_1),
607    )
608
609class LPUSE_INFO_1_CONTAINER(NDRPOINTER):
610    referent = (
611        ('Data', USE_INFO_1_CONTAINER),
612    )
613
614# 2.2.5.27 USE_INFO_2_CONTAINER
615class USE_INFO_2_CONTAINER(NDRSTRUCT):
616    structure = (
617        ('EntriesRead', ULONG),
618        ('Buffer', LPUSE_INFO_2),
619    )
620
621class LPUSE_INFO_2_CONTAINER(NDRPOINTER):
622    referent = (
623        ('Data', USE_INFO_2_CONTAINER),
624    )
625
626# 2.2.5.28 USE_ENUM_STRUCT
627class USE_ENUM_UNION(NDRUNION):
628    commonHdr = (
629        ('tag', ULONG),
630    )
631
632    union = {
633        0: ('Level0', LPUSE_INFO_0_CONTAINER),
634        1: ('Level1', LPUSE_INFO_1_CONTAINER),
635        2: ('Level2', LPUSE_INFO_2_CONTAINER),
636    }
637
638class USE_ENUM_STRUCT(NDRSTRUCT):
639    structure = (
640        ('Level', ULONG),
641        ('UseInfo', USE_ENUM_UNION),
642    )
643
644################################################################################
645# RPC CALLS
646################################################################################
647
648# 3.2.4.1 NetrWkstaGetInfo (Opnum 0)
649class NetrWkstaGetInfo(NDRCALL):
650    opnum = 0
651    structure = (
652       ('ServerName', LPWKSSVC_IDENTIFY_HANDLE),
653       ('Level', ULONG),
654    )
655
656class NetrWkstaGetInfoResponse(NDRCALL):
657    structure = (
658       ('WkstaInfo',WKSTA_INFO),
659       ('ErrorCode',ULONG),
660    )
661
662# 3.2.4.2 NetrWkstaSetInfo (Opnum 1)
663class NetrWkstaSetInfo(NDRCALL):
664    opnum = 1
665    structure = (
666       ('ServerName', LPWKSSVC_IDENTIFY_HANDLE),
667       ('Level', ULONG),
668       ('WkstaInfo',WKSTA_INFO),
669       ('ErrorParameter',LPULONG),
670    )
671
672class NetrWkstaSetInfoResponse(NDRCALL):
673    structure = (
674       ('ErrorParameter',LPULONG),
675       ('ErrorCode',ULONG),
676    )
677
678# 3.2.4.3 NetrWkstaUserEnum (Opnum 2)
679class NetrWkstaUserEnum(NDRCALL):
680    opnum = 2
681    structure = (
682       ('ServerName', LPWKSSVC_IDENTIFY_HANDLE),
683       ('UserInfo', WKSTA_USER_ENUM_STRUCT),
684       ('PreferredMaximumLength', ULONG),
685       ('ResumeHandle', LPULONG),
686    )
687
688class NetrWkstaUserEnumResponse(NDRCALL):
689    structure = (
690       ('UserInfo',WKSTA_USER_ENUM_STRUCT),
691       ('TotalEntries',ULONG),
692       ('ResumeHandle',ULONG),
693       ('ErrorCode',ULONG),
694    )
695
696# 3.2.4.4 NetrWkstaTransportEnum (Opnum 5)
697class NetrWkstaTransportEnum(NDRCALL):
698    opnum = 5
699    structure = (
700       ('ServerName', LPWKSSVC_IDENTIFY_HANDLE),
701       ('TransportInfo', WKSTA_TRANSPORT_ENUM_STRUCT),
702       ('PreferredMaximumLength', ULONG),
703       ('ResumeHandle', LPULONG),
704    )
705
706class NetrWkstaTransportEnumResponse(NDRCALL):
707    structure = (
708       ('TransportInfo',WKSTA_TRANSPORT_ENUM_STRUCT),
709       ('TotalEntries',ULONG),
710       ('ResumeHandle',ULONG),
711       ('ErrorCode',ULONG),
712    )
713
714# 3.2.4.5 NetrWkstaTransportAdd (Opnum 6)
715class NetrWkstaTransportAdd(NDRCALL):
716    opnum = 6
717    structure = (
718       ('ServerName', LPWKSSVC_IDENTIFY_HANDLE),
719       ('Level', ULONG),
720       ('TransportInfo',WKSTA_TRANSPORT_INFO_0),
721       ('ErrorParameter',LPULONG),
722    )
723
724class NetrWkstaTransportAddResponse(NDRCALL):
725    structure = (
726       ('ErrorParameter',LPULONG),
727       ('ErrorCode',ULONG),
728    )
729
730# 3.2.4.7 NetrUseAdd (Opnum 8)
731class NetrUseAdd(NDRCALL):
732    opnum = 8
733    structure = (
734       ('ServerName', LPWKSSVC_IMPERSONATE_HANDLE),
735       ('Level', ULONG),
736       ('InfoStruct',USE_INFO),
737       ('ErrorParameter',LPULONG),
738    )
739
740class NetrUseAddResponse(NDRCALL):
741    structure = (
742       ('ErrorParameter',LPULONG),
743       ('ErrorCode',ULONG),
744    )
745
746# 3.2.4.8 NetrUseGetInfo (Opnum 9)
747class NetrUseGetInfo(NDRCALL):
748    opnum = 9
749    structure = (
750       ('ServerName', LPWKSSVC_IMPERSONATE_HANDLE),
751       ('UseName', WSTR),
752       ('Level',ULONG),
753    )
754
755class NetrUseGetInfoResponse(NDRCALL):
756    structure = (
757       ('InfoStruct',USE_INFO),
758       ('ErrorCode',ULONG),
759    )
760
761# 3.2.4.9 NetrUseDel (Opnum 10)
762class NetrUseDel(NDRCALL):
763    opnum = 10
764    structure = (
765       ('ServerName', LPWKSSVC_IMPERSONATE_HANDLE),
766       ('UseName', WSTR),
767       ('ForceLevel',ULONG),
768    )
769
770class NetrUseDelResponse(NDRCALL):
771    structure = (
772       ('ErrorCode',ULONG),
773    )
774
775# 3.2.4.10 NetrUseEnum (Opnum 11)
776class NetrUseEnum(NDRCALL):
777    opnum = 11
778    structure = (
779       ('ServerName', LPWKSSVC_IMPERSONATE_HANDLE),
780       ('InfoStruct', USE_ENUM_STRUCT),
781       ('PreferredMaximumLength',ULONG),
782       ('ResumeHandle',LPULONG),
783    )
784
785class NetrUseEnumResponse(NDRCALL):
786    structure = (
787       ('InfoStruct',USE_ENUM_STRUCT),
788       ('TotalEntries',ULONG),
789       ('ResumeHandle',LPULONG),
790       ('ErrorCode',ULONG),
791    )
792
793# 3.2.4.11 NetrWorkstationStatisticsGet (Opnum 13)
794class NetrWorkstationStatisticsGet(NDRCALL):
795    opnum = 13
796    structure = (
797       ('ServerName', LPWKSSVC_IDENTIFY_HANDLE),
798       ('ServiceName', LPWSTR),
799       ('Level',ULONG),
800       ('Options',ULONG),
801    )
802
803class NetrWorkstationStatisticsGetResponse(NDRCALL):
804    structure = (
805       ('Buffer',LPSTAT_WORKSTATION_0),
806       ('ErrorCode',ULONG),
807    )
808
809# 3.2.4.12 NetrGetJoinInformation (Opnum 20)
810class NetrGetJoinInformation(NDRCALL):
811    opnum = 20
812    structure = (
813       ('ServerName', LPWKSSVC_IMPERSONATE_HANDLE),
814       ('NameBuffer', LPWSTR),
815    )
816
817class NetrGetJoinInformationResponse(NDRCALL):
818    structure = (
819       ('NameBuffer',LPWSTR),
820       ('BufferType',NETSETUP_JOIN_STATUS),
821       ('ErrorCode',ULONG),
822    )
823
824# 3.2.4.13 NetrJoinDomain2 (Opnum 22)
825class NetrJoinDomain2(NDRCALL):
826    opnum = 22
827    structure = (
828       ('ServerName', LPWSTR),
829       ('DomainNameParam', WSTR),
830       ('MachineAccountOU', LPWSTR),
831       ('AccountName', LPWSTR),
832       ('Password', PJOINPR_ENCRYPTED_USER_PASSWORD),
833       ('Options', ULONG),
834    )
835
836class NetrJoinDomain2Response(NDRCALL):
837    structure = (
838       ('ErrorCode',ULONG),
839    )
840
841# 3.2.4.14 NetrUnjoinDomain2 (Opnum 23)
842class NetrUnjoinDomain2(NDRCALL):
843    opnum = 23
844    structure = (
845       ('ServerName', LPWSTR),
846       ('AccountName', LPWSTR),
847       ('Password', PJOINPR_ENCRYPTED_USER_PASSWORD),
848       ('Options', ULONG),
849    )
850
851class NetrUnjoinDomain2Response(NDRCALL):
852    structure = (
853       ('ErrorCode',ULONG),
854    )
855
856# 3.2.4.15 NetrRenameMachineInDomain2 (Opnum 24)
857class NetrRenameMachineInDomain2(NDRCALL):
858    opnum = 24
859    structure = (
860       ('ServerName', LPWSTR),
861       ('MachineName', LPWSTR),
862       ('AccountName', LPWSTR),
863       ('Password', PJOINPR_ENCRYPTED_USER_PASSWORD),
864       ('Options', ULONG),
865    )
866
867class NetrRenameMachineInDomain2Response(NDRCALL):
868    structure = (
869       ('ErrorCode',ULONG),
870    )
871
872# 3.2.4.16 NetrValidateName2 (Opnum 25)
873class NetrValidateName2(NDRCALL):
874    opnum = 25
875    structure = (
876       ('ServerName', LPWSTR),
877       ('NameToValidate', WSTR),
878       ('AccountName', LPWSTR),
879       ('Password', PJOINPR_ENCRYPTED_USER_PASSWORD),
880       ('NameType', NETSETUP_NAME_TYPE),
881    )
882
883class NetrValidateName2Response(NDRCALL):
884    structure = (
885       ('ErrorCode',ULONG),
886    )
887
888# 3.2.4.17 NetrGetJoinableOUs2 (Opnum 26)
889class NetrGetJoinableOUs2(NDRCALL):
890    opnum = 26
891    structure = (
892       ('ServerName', LPWSTR),
893       ('DomainNameParam', WSTR),
894       ('AccountName', LPWSTR),
895       ('Password', PJOINPR_ENCRYPTED_USER_PASSWORD),
896       ('OUCount', ULONG),
897    )
898
899class NetrGetJoinableOUs2Response(NDRCALL):
900    structure = (
901       ('OUCount', LPLONG),
902       ('OUs',PUNICODE_STRING_ARRAY),
903       ('ErrorCode',ULONG),
904    )
905
906# 3.2.4.18 NetrAddAlternateComputerName (Opnum 27)
907class NetrAddAlternateComputerName(NDRCALL):
908    opnum = 27
909    structure = (
910       ('ServerName', LPWSTR),
911       ('AlternateName', LPWSTR),
912       ('DomainAccount', LPWSTR),
913       ('EncryptedPassword', PJOINPR_ENCRYPTED_USER_PASSWORD),
914       ('Reserved', ULONG),
915    )
916
917class NetrAddAlternateComputerNameResponse(NDRCALL):
918    structure = (
919       ('ErrorCode',ULONG),
920    )
921
922# 3.2.4.19 NetrRemoveAlternateComputerName (Opnum 28)
923class NetrRemoveAlternateComputerName(NDRCALL):
924    opnum = 28
925    structure = (
926       ('ServerName', LPWSTR),
927       ('AlternateName', LPWSTR),
928       ('DomainAccount', LPWSTR),
929       ('EncryptedPassword', PJOINPR_ENCRYPTED_USER_PASSWORD),
930       ('Reserved', ULONG),
931    )
932
933class NetrRemoveAlternateComputerNameResponse(NDRCALL):
934    structure = (
935       ('ErrorCode',ULONG),
936    )
937
938# 3.2.4.20 NetrSetPrimaryComputerName (Opnum 29)
939class NetrSetPrimaryComputerName(NDRCALL):
940    opnum = 29
941    structure = (
942       ('ServerName', LPWSTR),
943       ('PrimaryName', LPWSTR),
944       ('DomainAccount', LPWSTR),
945       ('EncryptedPassword', PJOINPR_ENCRYPTED_USER_PASSWORD),
946       ('Reserved', ULONG),
947    )
948
949class NetrSetPrimaryComputerNameResponse(NDRCALL):
950    structure = (
951       ('ErrorCode',ULONG),
952    )
953
954# 3.2.4.21 NetrEnumerateComputerNames (Opnum 30)
955class NetrEnumerateComputerNames(NDRCALL):
956    opnum = 30
957    structure = (
958       ('ServerName', LPWKSSVC_IMPERSONATE_HANDLE),
959       ('NameType', NET_COMPUTER_NAME_TYPE),
960       ('Reserved', ULONG),
961    )
962
963class NetrEnumerateComputerNamesResponse(NDRCALL):
964    structure = (
965       ('ComputerNames',PNET_COMPUTER_NAME_ARRAY),
966       ('ErrorCode',ULONG),
967    )
968
969################################################################################
970# OPNUMs and their corresponding structures
971################################################################################
972OPNUMS = {
973 0 : (NetrWkstaGetInfo, NetrWkstaGetInfoResponse),
974 1 : (NetrWkstaSetInfo, NetrWkstaSetInfoResponse),
975 2 : (NetrWkstaUserEnum, NetrWkstaUserEnumResponse),
976 5 : (NetrWkstaTransportEnum, NetrWkstaTransportEnumResponse),
977 6 : (NetrWkstaTransportAdd, NetrWkstaTransportAddResponse),
978# 7 : (NetrWkstaTransportDel, NetrWkstaTransportDelResponse),
979 8 : (NetrUseAdd, NetrUseAddResponse),
980 9 : (NetrUseGetInfo, NetrUseGetInfoResponse),
98110 : (NetrUseDel, NetrUseDelResponse),
98211 : (NetrUseEnum, NetrUseEnumResponse),
98313 : (NetrWorkstationStatisticsGet, NetrWorkstationStatisticsGetResponse),
98420 : (NetrGetJoinInformation, NetrGetJoinInformationResponse),
98522 : (NetrJoinDomain2, NetrJoinDomain2Response),
98623 : (NetrUnjoinDomain2, NetrUnjoinDomain2Response),
98724 : (NetrRenameMachineInDomain2, NetrRenameMachineInDomain2Response),
98825 : (NetrValidateName2, NetrValidateName2Response),
98926 : (NetrGetJoinableOUs2, NetrGetJoinableOUs2Response),
99027 : (NetrAddAlternateComputerName, NetrAddAlternateComputerNameResponse),
99128 : (NetrRemoveAlternateComputerName, NetrRemoveAlternateComputerNameResponse),
99229 : (NetrSetPrimaryComputerName, NetrSetPrimaryComputerNameResponse),
99330 : (NetrEnumerateComputerNames, NetrEnumerateComputerNamesResponse),
994}
995
996################################################################################
997# HELPER FUNCTIONS
998################################################################################
999def checkNullString(string):
1000    if string == NULL:
1001        return string
1002
1003    if string[-1:] != '\x00':
1004        return string + '\x00'
1005    else:
1006        return string
1007
1008def hNetrWkstaGetInfo(dce, level):
1009    request = NetrWkstaGetInfo()
1010    request['ServerName'] = '\x00'*10
1011    request['Level'] = level
1012    return dce.request(request)
1013
1014def hNetrWkstaUserEnum(dce, level, preferredMaximumLength=0xffffffff):
1015    request = NetrWkstaUserEnum()
1016    request['ServerName'] = '\x00'*10
1017    request['UserInfo']['Level'] = level
1018    request['UserInfo']['WkstaUserInfo']['tag'] = level
1019    request['PreferredMaximumLength'] = preferredMaximumLength
1020    return dce.request(request)
1021
1022def hNetrWkstaTransportEnum(dce, level, resumeHandle = 0, preferredMaximumLength = 0xffffffff):
1023    request = NetrWkstaTransportEnum()
1024    request['ServerName'] = '\x00'*10
1025    request['TransportInfo']['Level'] = level
1026    request['TransportInfo']['WkstaTransportInfo']['tag'] = level
1027    request['ResumeHandle'] = resumeHandle
1028    request['PreferredMaximumLength'] = preferredMaximumLength
1029    return dce.request(request)
1030
1031def hNetrWkstaSetInfo(dce, level, wkstInfo):
1032    request = NetrWkstaSetInfo()
1033    request['ServerName'] = '\x00'*10
1034    request['Level'] = level
1035    request['WkstaInfo']['tag'] = level
1036    request['WkstaInfo']['WkstaInfo%d'% level] = wkstInfo
1037    return dce.request(request)
1038
1039def hNetrWorkstationStatisticsGet(dce, serviceName, level, options):
1040    request = NetrWorkstationStatisticsGet()
1041    request['ServerName'] = '\x00'*10
1042    request['ServiceName'] = serviceName
1043    request['Level'] = level
1044    request['Options'] = options
1045    return dce.request(request)
1046
1047def hNetrGetJoinInformation(dce, nameBuffer):
1048    request = NetrGetJoinInformation()
1049    request['ServerName'] = '\x00'*10
1050    request['NameBuffer'] = nameBuffer
1051    return dce.request(request)
1052
1053def hNetrJoinDomain2(dce, domainNameParam, machineAccountOU, accountName, password, options):
1054    request = NetrJoinDomain2()
1055    request['ServerName'] = '\x00'*10
1056    request['DomainNameParam'] = checkNullString(domainNameParam)
1057    request['MachineAccountOU'] = checkNullString(machineAccountOU)
1058    request['AccountName'] = checkNullString(accountName)
1059    if password == NULL:
1060        request['Password'] = NULL
1061    else:
1062        request['Password']['Buffer'] = password
1063    request['Options'] = options
1064    return dce.request(request)
1065
1066def hNetrUnjoinDomain2(dce, accountName, password, options):
1067    request = NetrUnjoinDomain2()
1068    request['ServerName'] = '\x00'*10
1069    request['AccountName'] = checkNullString(accountName)
1070    if password == NULL:
1071        request['Password'] = NULL
1072    else:
1073        request['Password']['Buffer'] = password
1074    request['Options'] = options
1075    return dce.request(request)
1076
1077def hNetrRenameMachineInDomain2(dce, machineName, accountName, password, options):
1078    request = NetrRenameMachineInDomain2()
1079    request['ServerName'] = '\x00'*10
1080    request['MachineName'] = checkNullString(machineName)
1081    request['AccountName'] = checkNullString(accountName)
1082    if password == NULL:
1083        request['Password'] = NULL
1084    else:
1085        request['Password']['Buffer'] = password
1086    request['Options'] = options
1087    return dce.request(request)
1088
1089def hNetrValidateName2(dce, nameToValidate, accountName, password, nameType):
1090    request = NetrValidateName2()
1091    request['ServerName'] = '\x00'*10
1092    request['NameToValidate'] = checkNullString(nameToValidate)
1093    request['AccountName'] = checkNullString(accountName)
1094    if password == NULL:
1095        request['Password'] = NULL
1096    else:
1097        request['Password']['Buffer'] = password
1098    request['NameType'] = nameType
1099    return dce.request(request)
1100
1101def hNetrGetJoinableOUs2(dce, domainNameParam, accountName, password, OUCount):
1102    request = NetrGetJoinableOUs2()
1103    request['ServerName'] = '\x00'*10
1104    request['DomainNameParam'] = checkNullString(domainNameParam)
1105    request['AccountName'] = checkNullString(accountName)
1106    if password == NULL:
1107        request['Password'] = NULL
1108    else:
1109        request['Password']['Buffer'] = password
1110    request['OUCount'] = OUCount
1111    return dce.request(request)
1112
1113def hNetrAddAlternateComputerName(dce, alternateName, domainAccount, encryptedPassword):
1114    request = NetrAddAlternateComputerName()
1115    request['ServerName'] = '\x00'*10
1116    request['AlternateName'] = checkNullString(alternateName)
1117    request['DomainAccount'] = checkNullString(domainAccount)
1118    if encryptedPassword == NULL:
1119        request['EncryptedPassword'] = NULL
1120    else:
1121        request['EncryptedPassword']['Buffer'] = encryptedPassword
1122    return dce.request(request)
1123
1124def hNetrRemoveAlternateComputerName(dce, alternateName, domainAccount, encryptedPassword):
1125    request = NetrRemoveAlternateComputerName()
1126    request['ServerName'] = '\x00'*10
1127    request['AlternateName'] = checkNullString(alternateName)
1128    request['DomainAccount'] = checkNullString(domainAccount)
1129    if encryptedPassword == NULL:
1130        request['EncryptedPassword'] = NULL
1131    else:
1132        request['EncryptedPassword']['Buffer'] = encryptedPassword
1133    return dce.request(request)
1134
1135def hNetrSetPrimaryComputerName(dce, primaryName, domainAccount, encryptedPassword):
1136    request = NetrSetPrimaryComputerName()
1137    request['ServerName'] = '\x00'*10
1138    request['PrimaryName'] = checkNullString(primaryName)
1139    request['DomainAccount'] = checkNullString(domainAccount)
1140    if encryptedPassword == NULL:
1141        request['EncryptedPassword'] = NULL
1142    else:
1143        request['EncryptedPassword']['Buffer'] = encryptedPassword
1144    return dce.request(request)
1145
1146def hNetrEnumerateComputerNames(dce, nameType):
1147    request = NetrEnumerateComputerNames()
1148    request['ServerName'] = '\x00'*10
1149    request['NameType'] = nameType
1150    return dce.request(request)
1151
1152def hNetrUseAdd(dce, level, infoStruct):
1153    request = NetrUseAdd()
1154    request['ServerName'] = '\x00'*10
1155    request['Level'] = level
1156    request['InfoStruct']['tag'] = level
1157    request['InfoStruct']['UseInfo%d' % level] = infoStruct
1158    return dce.request(request)
1159
1160def hNetrUseEnum(dce, level, resumeHandle = 0, preferredMaximumLength = 0xffffffff):
1161    request = NetrUseEnum()
1162    request['ServerName'] = '\x00'*10
1163    request['InfoStruct']['Level'] = level
1164    request['InfoStruct']['UseInfo']['tag'] = level
1165    request['InfoStruct']['UseInfo']['Level%d'%level]['Buffer'] = NULL
1166    request['PreferredMaximumLength'] = preferredMaximumLength
1167    request['ResumeHandle'] = resumeHandle
1168    return dce.request(request)
1169
1170def hNetrUseGetInfo(dce, useName, level):
1171    request = NetrUseGetInfo()
1172    request['ServerName'] = '\x00'*10
1173    request['UseName'] = checkNullString(useName)
1174    request['Level'] = level
1175    return dce.request(request)
1176
1177def hNetrUseDel(dce, useName, forceLevel=USE_LOTS_OF_FORCE):
1178    request = NetrUseDel()
1179    request['ServerName'] = '\x00'*10
1180    request['UseName'] = checkNullString(useName)
1181    request['ForceLevel'] = forceLevel
1182    return dce.request(request)
1183
1184