This file is indexed.

/usr/lib/python2.7/dist-packages/impacket/dcerpc/v5/drsuapi.py is in python-impacket 0.9.15-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
# Copyright (c) 2003-2016 CORE Security Technologies
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Author: Alberto Solino (@agsolino)
#
# Description:
#   [MS-DRSR] Directory Replication Service (DRS) DRSUAPI Interface implementation
#
#   Best way to learn how to use these calls is to grab the protocol standard
#   so you understand what the call does, and then read the test case located
#   at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC
#
#   Some calls have helper functions, which makes it even easier to use.
#   They are located at the end of this file. 
#   Helper functions start with "h"<name of the call>.
#   There are test cases for them too. 
#
import hashlib
from struct import pack

from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRUNION, NDR, NDRENUM
from impacket.dcerpc.v5.dtypes import PUUID, DWORD, NULL, GUID, LPWSTR, BOOL, ULONG, UUID, LONGLONG, ULARGE_INTEGER, LARGE_INTEGER
from impacket import hresult_errors, system_errors
from impacket.structure import Structure
from impacket.uuid import uuidtup_to_bin, string_to_bin
from impacket.dcerpc.v5.enum import Enum
from impacket.dcerpc.v5.rpcrt import DCERPCException
from impacket.krb5 import crypto
from pyasn1.type import univ
from pyasn1.codec.ber import decoder

try:
    from Crypto.Cipher import ARC4, DES
except Exception:
    LOG.critical("Warning: You don't have any crypto installed. You need PyCrypto")
    LOG.critical("See http://www.pycrypto.org/")

MSRPC_UUID_DRSUAPI = uuidtup_to_bin(('E3514235-4B06-11D1-AB04-00C04FC2DCD2','4.0'))

class DCERPCSessionError(DCERPCException):
    def __init__(self, error_string=None, error_code=None, packet=None):
        DCERPCException.__init__(self, error_string, error_code, packet)

    def __str__( self ):
        key = self.error_code
        if hresult_errors.ERROR_MESSAGES.has_key(key):
            error_msg_short = hresult_errors.ERROR_MESSAGES[key][0]
            error_msg_verbose = hresult_errors.ERROR_MESSAGES[key][1]
            return 'DRSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
        elif system_errors.ERROR_MESSAGES.has_key(key & 0xffff):
            error_msg_short = system_errors.ERROR_MESSAGES[key & 0xffff][0]
            error_msg_verbose = system_errors.ERROR_MESSAGES[key & 0xffff][1]
            return 'DRSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
        else:
            return 'DRSR SessionError: unknown error code: 0x%x' % self.error_code

################################################################################
# CONSTANTS
################################################################################
# 4.1.10.2.17 EXOP_ERR Codes
class EXOP_ERR(NDRENUM):
    align = 4
    align64 = 4
    structure = (
        ('Data', '<L'),
    )
    class enumItems(Enum):
        EXOP_ERR_SUCCESS               = 0x00000001
        EXOP_ERR_UNKNOWN_OP            = 0x00000002
        EXOP_ERR_FSMO_NOT_OWNER        = 0x00000003
        EXOP_ERR_UPDATE_ERR            = 0x00000004
        EXOP_ERR_EXCEPTION             = 0x00000005
        EXOP_ERR_UNKNOWN_CALLER        = 0x00000006
        EXOP_ERR_RID_ALLOC             = 0x00000007
        EXOP_ERR_FSMO_OWNER_DELETED    = 0x00000008
        EXOP_ERR_FSMO_PENDING_OP       = 0x00000009
        EXOP_ERR_MISMATCH              = 0x0000000A
        EXOP_ERR_COULDNT_CONTACT       = 0x0000000B
        EXOP_ERR_FSMO_REFUSING_ROLES   = 0x0000000C
        EXOP_ERR_DIR_ERROR             = 0x0000000D
        EXOP_ERR_FSMO_MISSING_SETTINGS = 0x0000000E
        EXOP_ERR_ACCESS_DENIED         = 0x0000000F
        EXOP_ERR_PARAM_ERROR           = 0x00000010

    def dump(self, msg = None, indent = 0):
        if msg is None: msg = self.__class__.__name__
        if msg != '':
            print msg,

        try:
            print " %s" % self.enumItems(self.fields['Data']).name,
        except ValueError:
            print " %d" % self.fields['Data']

# 4.1.10.2.18 EXOP_REQ Codes
EXOP_FSMO_REQ_ROLE = 0x00000001
EXOP_FSMO_REQ_RID_ALLOC = 0x00000002
EXOP_FSMO_RID_REQ_ROLE = 0x00000003
EXOP_FSMO_REQ_PDC = 0x00000004
EXOP_FSMO_ABANDON_ROLE = 0x00000005
EXOP_REPL_OBJ = 0x00000006
EXOP_REPL_SECRETS = 0x00000007

# 5.14 ATTRTYP
ATTRTYP = ULONG

# 5.51 DSTIME
DSTIME = LONGLONG

# 5.39 DRS_EXTENSIONS_INT
DRS_EXT_BASE = 0x00000001
DRS_EXT_ASYNCREPL = 0x00000002
DRS_EXT_REMOVEAPI = 0x00000004
DRS_EXT_MOVEREQ_V2 = 0x00000008
DRS_EXT_GETCHG_DEFLATE = 0x00000010
DRS_EXT_DCINFO_V1 = 0x00000020
DRS_EXT_RESTORE_USN_OPTIMIZATION = 0x00000040
DRS_EXT_ADDENTRY = 0x00000080
DRS_EXT_KCC_EXECUTE = 0x00000100
DRS_EXT_ADDENTRY_V2 = 0x00000200
DRS_EXT_LINKED_VALUE_REPLICATION = 0x00000400
DRS_EXT_DCINFO_V2 = 0x00000800
DRS_EXT_INSTANCE_TYPE_NOT_REQ_ON_MOD = 0x00001000
DRS_EXT_CRYPTO_BIND = 0x00002000
DRS_EXT_GET_REPL_INFO = 0x00004000
DRS_EXT_STRONG_ENCRYPTION = 0x00008000
DRS_EXT_DCINFO_VFFFFFFFF = 0x00010000
DRS_EXT_TRANSITIVE_MEMBERSHIP = 0x00020000
DRS_EXT_ADD_SID_HISTORY = 0x00040000
DRS_EXT_POST_BETA3 = 0x00080000
DRS_EXT_GETCHGREQ_V5 = 0x00100000
DRS_EXT_GETMEMBERSHIPS2 = 0x00200000
DRS_EXT_GETCHGREQ_V6 = 0x00400000
DRS_EXT_NONDOMAIN_NCS = 0x00800000
DRS_EXT_GETCHGREQ_V8 = 0x01000000
DRS_EXT_GETCHGREPLY_V5 = 0x02000000
DRS_EXT_GETCHGREPLY_V6 = 0x04000000
DRS_EXT_GETCHGREPLY_V9 = 0x00000100
DRS_EXT_WHISTLER_BETA3 = 0x08000000
DRS_EXT_W2K3_DEFLATE = 0x10000000
DRS_EXT_GETCHGREQ_V10 = 0x20000000
DRS_EXT_RESERVED_FOR_WIN2K_OR_DOTNET_PART2 = 0x40000000
DRS_EXT_RESERVED_FOR_WIN2K_OR_DOTNET_PART3 = 0x80000000

# dwFlagsExt
DRS_EXT_ADAM = 0x00000001
DRS_EXT_LH_BETA2 = 0x00000002
DRS_EXT_RECYCLE_BIN = 0x00000004

# 5.41 DRS_OPTIONS
DRS_ASYNC_OP = 0x00000001
DRS_GETCHG_CHECK = 0x00000002
DRS_UPDATE_NOTIFICATION = 0x00000002
DRS_ADD_REF = 0x00000004
DRS_SYNC_ALL = 0x00000008
DRS_DEL_REF = 0x00000008
DRS_WRIT_REP = 0x00000010
DRS_INIT_SYNC = 0x00000020
DRS_PER_SYNC = 0x00000040
DRS_MAIL_REP = 0x00000080
DRS_ASYNC_REP = 0x00000100
DRS_IGNORE_ERROR = 0x00000100
DRS_TWOWAY_SYNC = 0x00000200
DRS_CRITICAL_ONLY = 0x00000400
DRS_GET_ANC = 0x00000800
DRS_GET_NC_SIZE = 0x00001000
DRS_LOCAL_ONLY = 0x00001000
DRS_NONGC_RO_REP = 0x00002000
DRS_SYNC_BYNAME = 0x00004000
DRS_REF_OK = 0x00004000
DRS_FULL_SYNC_NOW = 0x00008000
DRS_NO_SOURCE = 0x00008000
DRS_FULL_SYNC_IN_PROGRESS = 0x00010000
DRS_FULL_SYNC_PACKET = 0x00020000
DRS_SYNC_REQUEUE = 0x00040000
DRS_SYNC_URGENT = 0x00080000
DRS_REF_GCSPN = 0x00100000
DRS_NO_DISCARD = 0x00100000
DRS_NEVER_SYNCED = 0x00200000
DRS_SPECIAL_SECRET_PROCESSING = 0x00400000
DRS_INIT_SYNC_NOW = 0x00800000
DRS_PREEMPTED = 0x01000000
DRS_SYNC_FORCED = 0x02000000
DRS_DISABLE_AUTO_SYNC = 0x04000000
DRS_DISABLE_PERIODIC_SYNC = 0x08000000
DRS_USE_COMPRESSION = 0x10000000
DRS_NEVER_NOTIFY = 0x20000000
DRS_SYNC_PAS = 0x40000000
DRS_GET_ALL_GROUP_MEMBERSHIP = 0x80000000


# 5.113 LDAP_CONN_PROPERTIES
BND = 0x00000001
SSL = 0x00000002
UDP = 0x00000004
GC = 0x00000008
GSS = 0x00000010
NGO = 0x00000020
SPL = 0x00000040
MD5 = 0x00000080
SGN = 0x00000100
SL = 0x00000200

# 5.137 NTSAPI_CLIENT_GUID
NTDSAPI_CLIENT_GUID = string_to_bin('e24d201a-4fd6-11d1-a3da-0000f875ae0d')

# 5.139 NULLGUID
NULLGUID = string_to_bin('00000000-0000-0000-0000-000000000000')

# 5.205 USN
USN = LONGLONG

# 4.1.4.1.2 DRS_MSG_CRACKREQ_V1
DS_NAME_FLAG_GCVERIFY = 0x00000004
DS_NAME_FLAG_TRUST_REFERRAL = 0x00000008
DS_NAME_FLAG_PRIVATE_RESOLVE_FPOS = 0x80000000

DS_LIST_SITES = 0xFFFFFFFF
DS_LIST_SERVERS_IN_SITE = 0xFFFFFFFE
DS_LIST_DOMAINS_IN_SITE = 0xFFFFFFFD
DS_LIST_SERVERS_FOR_DOMAIN_IN_SITE = 0xFFFFFFFC
DS_LIST_INFO_FOR_SERVER = 0xFFFFFFFB
DS_LIST_ROLES = 0xFFFFFFFA
DS_NT4_ACCOUNT_NAME_SANS_DOMAIN = 0xFFFFFFF9
DS_MAP_SCHEMA_GUID = 0xFFFFFFF8
DS_LIST_DOMAINS = 0xFFFFFFF7
DS_LIST_NCS = 0xFFFFFFF6
DS_ALT_SECURITY_IDENTITIES_NAME = 0xFFFFFFF5
DS_STRING_SID_NAME = 0xFFFFFFF4
DS_LIST_SERVERS_WITH_DCS_IN_SITE = 0xFFFFFFF3
DS_LIST_GLOBAL_CATALOG_SERVERS = 0xFFFFFFF1
DS_NT4_ACCOUNT_NAME_SANS_DOMAIN_EX = 0xFFFFFFF0
DS_USER_PRINCIPAL_NAME_AND_ALTSECID = 0xFFFFFFEF

DS_USER_PRINCIPAL_NAME_FOR_LOGON = 0xFFFFFFF2

# 5.53 ENTINF
ENTINF_FROM_MASTER = 0x00000001
ENTINF_DYNAMIC_OBJECT = 0x00000002
ENTINF_REMOTE_MODIFY = 0x00010000

# 4.1.27.1.2 DRS_MSG_VERIFYREQ_V1
DRS_VERIFY_DSNAMES = 0x00000000
DRS_VERIFY_SIDS = 0x00000001
DRS_VERIFY_SAM_ACCOUNT_NAMES = 0x00000002
DRS_VERIFY_FPOS = 0x00000003

# 4.1.11.1.2 DRS_MSG_NT4_CHGLOG_REQ_V1
DRS_NT4_CHGLOG_GET_CHANGE_LOG = 0x00000001
DRS_NT4_CHGLOG_GET_SERIAL_NUMBERS = 0x00000002

# 4.1.10.2.15 DRS_MSG_GETCHGREPLY_NATIVE_VERSION_NUMBER
DRS_MSG_GETCHGREPLY_NATIVE_VERSION_NUMBER = 9
################################################################################
# STRUCTURES
################################################################################
# 4.1.10.2.16 ENCRYPTED_PAYLOAD
class ENCRYPTED_PAYLOAD(Structure):
    structure = (
        ('Salt','16s'),
        ('CheckSum','<L'),
        ('EncryptedData',':'),
    )

# 5.136 NT4SID
class NT4SID(NDRSTRUCT):
    structure =  (
        ('Data','28s=""'),
    )
    def getAlignment(self):
        return 4

# 5.40 DRS_HANDLE
class DRS_HANDLE(NDRSTRUCT):
    structure =  (
        ('Data','20s=""'),
    )
    def getAlignment(self):
        return 4

class PDRS_HANDLE(NDRPOINTER):
    referent = (
        ('Data',DRS_HANDLE),
    )

# 5.38 DRS_EXTENSIONS
class BYTE_ARRAY(NDRUniConformantArray):
    item = 'c'

class PBYTE_ARRAY(NDRPOINTER):
    referent = (
        ('Data',BYTE_ARRAY),
    )

class DRS_EXTENSIONS(NDRSTRUCT):
    structure =  (
        ('cb',DWORD),
        ('rgb',BYTE_ARRAY),
    )

class PDRS_EXTENSIONS(NDRPOINTER):
    referent = (
        ('Data',DRS_EXTENSIONS),
    )

# 5.39 DRS_EXTENSIONS_INT
class DRS_EXTENSIONS_INT(Structure):
    structure =  (
        ('dwFlags','<L=0'),
        ('SiteObjGuid','16s=""'),
        ('Pid','<L=0'),
        ('dwReplEpoch','<L=0'),
        ('dwFlagsExt','<L=0'),
        ('ConfigObjGUID','16s=""'),
        ('dwExtCaps','<L=0'),
    )

# 4.1.5.1.2 DRS_MSG_DCINFOREQ_V1
class DRS_MSG_DCINFOREQ_V1(NDRSTRUCT):
    structure =  (
        ('Domain',LPWSTR),
        ('InfoLevel',DWORD),
    )

# 4.1.5.1.1 DRS_MSG_DCINFOREQ
class DRS_MSG_DCINFOREQ(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_DCINFOREQ_V1),
    }

# 4.1.5.1.8 DS_DOMAIN_CONTROLLER_INFO_1W
class DS_DOMAIN_CONTROLLER_INFO_1W(NDRSTRUCT):
    structure =  (
        ('NetbiosName',LPWSTR),
        ('DnsHostName',LPWSTR),
        ('SiteName',LPWSTR),
        ('ComputerObjectName',LPWSTR),
        ('ServerObjectName',LPWSTR),
        ('fIsPdc',BOOL),
        ('fDsEnabled',BOOL),
    )

class DS_DOMAIN_CONTROLLER_INFO_1W_ARRAY(NDRUniConformantArray):
    item = DS_DOMAIN_CONTROLLER_INFO_1W

class PDS_DOMAIN_CONTROLLER_INFO_1W_ARRAY(NDRPOINTER):
    referent = (
        ('Data',DS_DOMAIN_CONTROLLER_INFO_1W_ARRAY),
    )

# 4.1.5.1.4 DRS_MSG_DCINFOREPLY_V1
class DRS_MSG_DCINFOREPLY_V1(NDRSTRUCT):
    structure =  (
        ('cItems',DWORD),
        ('rItems',PDS_DOMAIN_CONTROLLER_INFO_1W_ARRAY),
    )

# 4.1.5.1.9 DS_DOMAIN_CONTROLLER_INFO_2W
class DS_DOMAIN_CONTROLLER_INFO_2W(NDRSTRUCT):
    structure =  (
        ('NetbiosName',LPWSTR),
        ('DnsHostName',LPWSTR),
        ('SiteName',LPWSTR),
        ('SiteObjectName',LPWSTR),
        ('ComputerObjectName',LPWSTR),
        ('ServerObjectName',LPWSTR),
        ('NtdsDsaObjectName',LPWSTR),
        ('fIsPdc',BOOL),
        ('fDsEnabled',BOOL),
        ('fIsGc',BOOL),
        ('SiteObjectGuid',GUID),
        ('ComputerObjectGuid',GUID),
        ('ServerObjectGuid',GUID),
        ('NtdsDsaObjectGuid',GUID),
    )

class DS_DOMAIN_CONTROLLER_INFO_2W_ARRAY(NDRUniConformantArray):
    item = DS_DOMAIN_CONTROLLER_INFO_2W

class PDS_DOMAIN_CONTROLLER_INFO_2W_ARRAY(NDRPOINTER):
    referent = (
        ('Data',DS_DOMAIN_CONTROLLER_INFO_2W_ARRAY),
    )

# 4.1.5.1.5 DRS_MSG_DCINFOREPLY_V2
class DRS_MSG_DCINFOREPLY_V2(NDRSTRUCT):
    structure =  (
        ('cItems',DWORD),
        ('rItems',PDS_DOMAIN_CONTROLLER_INFO_2W_ARRAY),
    )

# 4.1.5.1.10 DS_DOMAIN_CONTROLLER_INFO_3W
class DS_DOMAIN_CONTROLLER_INFO_3W(NDRSTRUCT):
    structure =  (
        ('NetbiosName',LPWSTR),
        ('DnsHostName',LPWSTR),
        ('SiteName',LPWSTR),
        ('SiteObjectName',LPWSTR),
        ('ComputerObjectName',LPWSTR),
        ('ServerObjectName',LPWSTR),
        ('NtdsDsaObjectName',LPWSTR),
        ('fIsPdc',BOOL),
        ('fDsEnabled',BOOL),
        ('fIsGc',BOOL),
        ('fIsRodc',BOOL),
        ('SiteObjectGuid',GUID),
        ('ComputerObjectGuid',GUID),
        ('ServerObjectGuid',GUID),
        ('NtdsDsaObjectGuid',GUID),
    )

class DS_DOMAIN_CONTROLLER_INFO_3W_ARRAY(NDRUniConformantArray):
    item = DS_DOMAIN_CONTROLLER_INFO_3W

class PDS_DOMAIN_CONTROLLER_INFO_3W_ARRAY(NDRPOINTER):
    referent = (
        ('Data',DS_DOMAIN_CONTROLLER_INFO_3W_ARRAY),
    )

# 4.1.5.1.6 DRS_MSG_DCINFOREPLY_V3
class DRS_MSG_DCINFOREPLY_V3(NDRSTRUCT):
    structure =  (
        ('cItems',DWORD),
        ('rItems',PDS_DOMAIN_CONTROLLER_INFO_3W_ARRAY),
    )

# 4.1.5.1.11 DS_DOMAIN_CONTROLLER_INFO_FFFFFFFFW
class DS_DOMAIN_CONTROLLER_INFO_FFFFFFFFW(NDRSTRUCT):
    structure =  (
        ('IPAddress',DWORD),
        ('NotificationCount',DWORD),
        ('secTimeConnected',DWORD),
        ('Flags',DWORD),
        ('TotalRequests',DWORD),
        ('Reserved1',DWORD),
        ('UserName',LPWSTR),
    )

class DS_DOMAIN_CONTROLLER_INFO_FFFFFFFFW_ARRAY(NDRUniConformantArray):
    item = DS_DOMAIN_CONTROLLER_INFO_FFFFFFFFW

class PDS_DOMAIN_CONTROLLER_INFO_FFFFFFFFW_ARRAY(NDRPOINTER):
    referent = (
        ('Data',DS_DOMAIN_CONTROLLER_INFO_FFFFFFFFW_ARRAY),
    )

# 4.1.5.1.7 DRS_MSG_DCINFOREPLY_VFFFFFFFF
class DRS_MSG_DCINFOREPLY_VFFFFFFFF(NDRSTRUCT):
    structure =  (
        ('cItems',DWORD),
        ('rItems',PDS_DOMAIN_CONTROLLER_INFO_FFFFFFFFW_ARRAY),
    )

# 4.1.5.1.3 DRS_MSG_DCINFOREPLY
class DRS_MSG_DCINFOREPLY(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_DCINFOREPLY_V1),
        2  : ('V2', DRS_MSG_DCINFOREPLY_V2),
        3  : ('V3', DRS_MSG_DCINFOREPLY_V3),
        0xffffffff  : ('V1', DRS_MSG_DCINFOREPLY_VFFFFFFFF),
    }

# 4.1.4.1.2 DRS_MSG_CRACKREQ_V1
class LPWSTR_ARRAY(NDRUniConformantArray):
    item = LPWSTR

class PLPWSTR_ARRAY(NDRPOINTER):
    referent = (
        ('Data',LPWSTR_ARRAY),
    )

class DRS_MSG_CRACKREQ_V1(NDRSTRUCT):
    structure =  (
        ('CodePage',ULONG),
        ('LocaleId',ULONG),
        ('dwFlags',DWORD),
        ('formatOffered',DWORD),
        ('formatDesired',DWORD),
        ('cNames',DWORD),
        ('rpNames',PLPWSTR_ARRAY),
    )

# 4.1.4.1.1 DRS_MSG_CRACKREQ
class DRS_MSG_CRACKREQ(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_CRACKREQ_V1),
    }

# 4.1.4.1.3 DS_NAME_FORMAT
class DS_NAME_FORMAT(NDRENUM):
    class enumItems(Enum):
        DS_UNKNOWN_NAME            = 0
        DS_FQDN_1779_NAME          = 1
        DS_NT4_ACCOUNT_NAME        = 2
        DS_DISPLAY_NAME            = 3
        DS_UNIQUE_ID_NAME          = 6
        DS_CANONICAL_NAME          = 7
        DS_USER_PRINCIPAL_NAME     = 8
        DS_CANONICAL_NAME_EX       = 9
        DS_SERVICE_PRINCIPAL_NAME  = 10
        DS_SID_OR_SID_HISTORY_NAME = 11
        DS_DNS_DOMAIN_NAME         = 12

# 4.1.4.1.4 DS_NAME_RESULT_ITEMW
class DS_NAME_RESULT_ITEMW(NDRSTRUCT):
    structure =  (
        ('status',DWORD),
        ('pDomain',LPWSTR),
        ('pName',LPWSTR),
    )

class DS_NAME_RESULT_ITEMW_ARRAY(NDRUniConformantArray):
    item = DS_NAME_RESULT_ITEMW

class PDS_NAME_RESULT_ITEMW_ARRAY(NDRPOINTER):
    referent = (
        ('Data',DS_NAME_RESULT_ITEMW_ARRAY),
    )

# 4.1.4.1.5 DS_NAME_RESULTW
class DS_NAME_RESULTW(NDRSTRUCT):
    structure =  (
        ('cItems',DWORD),
        ('rItems',PDS_NAME_RESULT_ITEMW_ARRAY),
    )

class PDS_NAME_RESULTW(NDRPOINTER):
    referent = (
        ('Data',DS_NAME_RESULTW),
    )

# 4.1.4.1.7 DRS_MSG_CRACKREPLY_V1
class DRS_MSG_CRACKREPLY_V1(NDRSTRUCT):
    structure =  (
        ('pResult',PDS_NAME_RESULTW),
    )

# 4.1.4.1.6 DRS_MSG_CRACKREPLY
class DRS_MSG_CRACKREPLY(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_CRACKREPLY_V1),
    }

# 5.198 UPTODATE_CURSOR_V1
class UPTODATE_CURSOR_V1(NDRSTRUCT):
    structure =  (
        ('uuidDsa',UUID),
        ('usnHighPropUpdate',USN),
    )

class UPTODATE_CURSOR_V1_ARRAY(NDRUniConformantArray):
    item = UPTODATE_CURSOR_V1

# 5.200 UPTODATE_VECTOR_V1_EXT
class UPTODATE_VECTOR_V1_EXT(NDRSTRUCT):
    structure =  (
        ('dwVersion',DWORD),
        ('dwReserved1',DWORD),
        ('cNumCursors',DWORD),
        ('dwReserved2',DWORD),
        ('rgCursors',UPTODATE_CURSOR_V1_ARRAY),
    )

class PUPTODATE_VECTOR_V1_EXT(NDRPOINTER):
    referent = (
        ('Data',UPTODATE_VECTOR_V1_EXT),
    )

# 5.206 USN_VECTOR
class USN_VECTOR(NDRSTRUCT):
    structure =  (
        ('usnHighObjUpdate',USN),
        ('usnReserved',USN),
        ('usnHighPropUpdate',USN),
    )

# 5.50 DSNAME
class WCHAR_ARRAY(NDRUniConformantArray):
    item  = 'H'

    def __setitem__(self, key, value):
        self.fields['MaximumCount'] = None
        self.data = None        # force recompute
        return NDRUniConformantArray.__setitem__(self, key, [ord(c) for c in value])

    def __getitem__(self, key):
        if key == 'Data':
            return ''.join([chr(i) for i in self.fields[key]])
        else:
            return NDR.__getitem__(self,key)

class DSNAME(NDRSTRUCT):
    structure =  (
        ('structLen',ULONG),
        ('SidLen',ULONG),
        ('Guid',GUID),
        ('Sid',NT4SID),
        ('NameLen',ULONG),
        ('StringName', WCHAR_ARRAY),
    )
    def getDataLen(self, data):
        return self['NameLen']
    def getData(self, soFar = 0):
        return NDRSTRUCT.getData(self, soFar)

class PDSNAME(NDRPOINTER):
    referent = (
        ('Data',DSNAME),
    )

class PDSNAME_ARRAY(NDRUniConformantArray):
    item = PDSNAME

class PPDSNAME_ARRAY(NDRPOINTER):
    referent = (
        ('Data',PDSNAME_ARRAY),
    )

class ATTRTYP_ARRAY(NDRUniConformantArray):
    item = ATTRTYP

# 5.145 PARTIAL_ATTR_VECTOR_V1_EXT
class PARTIAL_ATTR_VECTOR_V1_EXT(NDRSTRUCT):
    structure =  (
        ('dwVersion',DWORD),
        ('dwReserved1',DWORD),
        ('cAttrs',DWORD),
        ('rgPartialAttr',ATTRTYP_ARRAY),
    )

class PPARTIAL_ATTR_VECTOR_V1_EXT(NDRPOINTER):
    referent = (
        ('Data',PARTIAL_ATTR_VECTOR_V1_EXT),
    )

# 5.142 OID_t
class OID_t(NDRSTRUCT):
    structure =  (
        ('length',ULONG),
        ('elements',PBYTE_ARRAY),
    )

# 5.153 PrefixTableEntry
class PrefixTableEntry(NDRSTRUCT):
    structure =  (
        ('ndx',ULONG),
        ('prefix',OID_t),
    )

class PrefixTableEntry_ARRAY(NDRUniConformantArray):
    item = PrefixTableEntry

class PPrefixTableEntry_ARRAY(NDRPOINTER):
    referent = (
        ('Data',PrefixTableEntry_ARRAY),
    )

# 5.177 SCHEMA_PREFIX_TABLE
class SCHEMA_PREFIX_TABLE(NDRSTRUCT):
    structure =  (
        ('PrefixCount',DWORD),
        ('pPrefixEntry',PPrefixTableEntry_ARRAY),
    )

# 4.1.10.2.2 DRS_MSG_GETCHGREQ_V3
class DRS_MSG_GETCHGREQ_V3(NDRSTRUCT):
    structure =  (
        ('uuidDsaObjDest',UUID),
        ('uuidInvocIdSrc',UUID),
        ('pNC',PDSNAME),
        ('usnvecFrom',USN_VECTOR),
        ('pUpToDateVecDestV1',PUPTODATE_VECTOR_V1_EXT),
        ('pPartialAttrVecDestV1',PPARTIAL_ATTR_VECTOR_V1_EXT),
        ('PrefixTableDest',SCHEMA_PREFIX_TABLE),
        ('ulFlags',ULONG),
        ('cMaxObjects',ULONG),
        ('cMaxBytes',ULONG),
        ('ulExtendedOp',ULONG),
    )

# 5.131 MTX_ADDR
class MTX_ADDR(NDRSTRUCT):
    structure =  (
        ('mtx_namelen',ULONG),
        ('mtx_name',PBYTE_ARRAY),
    )

class PMTX_ADDR(NDRPOINTER):
    referent = (
        ('Data',MTX_ADDR),
    )

# 4.1.10.2.3 DRS_MSG_GETCHGREQ_V4
class DRS_MSG_GETCHGREQ_V4(NDRSTRUCT):
    structure =  (
        ('uuidTransportObj',UUID),
        ('pmtxReturnAddress',PMTX_ADDR),
        ('V3',DRS_MSG_GETCHGREQ_V3),
    )

# 4.1.10.2.4 DRS_MSG_GETCHGREQ_V5
class DRS_MSG_GETCHGREQ_V5(NDRSTRUCT):
    structure =  (
        ('uuidDsaObjDest',UUID),
        ('uuidInvocIdSrc',UUID),
        ('pNC',PDSNAME),
        ('usnvecFrom',USN_VECTOR),
        ('pUpToDateVecDestV1',PUPTODATE_VECTOR_V1_EXT),
        ('ulFlags',ULONG),
        ('cMaxObjects',ULONG),
        ('cMaxBytes',ULONG),
        ('ulExtendedOp',ULONG),
        ('liFsmoInfo',ULARGE_INTEGER),
    )

# 4.1.10.2.5 DRS_MSG_GETCHGREQ_V7
class DRS_MSG_GETCHGREQ_V7(NDRSTRUCT):
    structure =  (
        ('uuidTransportObj',UUID),
        ('pmtxReturnAddress',PMTX_ADDR),
        ('V3',DRS_MSG_GETCHGREQ_V3),
        ('pPartialAttrSet',PPARTIAL_ATTR_VECTOR_V1_EXT),
        ('pPartialAttrSetEx1',PPARTIAL_ATTR_VECTOR_V1_EXT),
        ('PrefixTableDest',SCHEMA_PREFIX_TABLE),
    )

# 4.1.10.2.6 DRS_MSG_GETCHGREQ_V8
class DRS_MSG_GETCHGREQ_V8(NDRSTRUCT):
    structure =  (
        ('uuidDsaObjDest',UUID),
        ('uuidInvocIdSrc',UUID),
        ('pNC',PDSNAME),
        ('usnvecFrom',USN_VECTOR),
        ('pUpToDateVecDest',PUPTODATE_VECTOR_V1_EXT),
        ('ulFlags',ULONG),
        ('cMaxObjects',ULONG),
        ('cMaxBytes',ULONG),
        ('ulExtendedOp',ULONG),
        ('liFsmoInfo',ULARGE_INTEGER),
        ('pPartialAttrSet',PPARTIAL_ATTR_VECTOR_V1_EXT),
        ('pPartialAttrSetEx1',PPARTIAL_ATTR_VECTOR_V1_EXT),
        ('PrefixTableDest',SCHEMA_PREFIX_TABLE),
    )

# 4.1.10.2.7 DRS_MSG_GETCHGREQ_V10
class DRS_MSG_GETCHGREQ_V10(NDRSTRUCT):
    structure =  (
        ('uuidDsaObjDest',UUID),
        ('uuidInvocIdSrc',UUID),
        ('pNC',PDSNAME),
        ('usnvecFrom',USN_VECTOR),
        ('pUpToDateVecDest',PUPTODATE_VECTOR_V1_EXT),
        ('ulFlags',ULONG),
        ('cMaxObjects',ULONG),
        ('cMaxBytes',ULONG),
        ('ulExtendedOp',ULONG),
        ('liFsmoInfo',ULARGE_INTEGER),
        ('pPartialAttrSet',PPARTIAL_ATTR_VECTOR_V1_EXT),
        ('pPartialAttrSetEx1',PPARTIAL_ATTR_VECTOR_V1_EXT),
        ('PrefixTableDest',SCHEMA_PREFIX_TABLE),
        ('ulMoreFlags',ULONG),
    )

# 4.1.10.2.1 DRS_MSG_GETCHGREQ
class DRS_MSG_GETCHGREQ(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        4  : ('V4', DRS_MSG_GETCHGREQ_V4),
        5  : ('V5', DRS_MSG_GETCHGREQ_V5),
        7  : ('V7', DRS_MSG_GETCHGREQ_V7),
        8  : ('V8', DRS_MSG_GETCHGREQ_V8),
        10 : ('V10', DRS_MSG_GETCHGREQ_V10),
    }

# 5.16 ATTRVAL
class ATTRVAL(NDRSTRUCT):
    structure =  (
        ('valLen',ULONG),
        ('pVal',PBYTE_ARRAY),
    )

class ATTRVAL_ARRAY(NDRUniConformantArray):
    item = ATTRVAL

class PATTRVAL_ARRAY(NDRPOINTER):
    referent = (
        ('Data',ATTRVAL_ARRAY),
    )

# 5.17 ATTRVALBLOCK
class ATTRVALBLOCK(NDRSTRUCT):
    structure =  (
        ('valCount',ULONG),
        ('pAVal',PATTRVAL_ARRAY),
    )

# 5.9 ATTR
class ATTR(NDRSTRUCT):
    structure =  (
        ('attrTyp',ATTRTYP),
        ('AttrVal',ATTRVALBLOCK),
    )

class ATTR_ARRAY(NDRUniConformantArray):
    item = ATTR

class PATTR_ARRAY(NDRPOINTER):
    referent = (
        ('Data',ATTR_ARRAY),
    )

# 5.10 ATTRBLOCK
class ATTRBLOCK(NDRSTRUCT):
    structure =  (
        ('attrCount',ULONG),
        ('pAttr',PATTR_ARRAY),
    )

# 5.53 ENTINF
class ENTINF(NDRSTRUCT):
    structure =  (
        ('pName',PDSNAME),
        ('ulFlags',ULONG),
        ('AttrBlock',ATTRBLOCK),
    )

class ENTINF_ARRAY(NDRUniConformantArray):
    item = ENTINF

class PENTINF_ARRAY(NDRPOINTER):
    referent = (
        ('Data',ENTINF_ARRAY),
    )

# 5.154 PROPERTY_META_DATA_EXT
class PROPERTY_META_DATA_EXT(NDRSTRUCT):
    structure =  (
        ('dwVersion',DWORD),
        ('timeChanged',DSTIME),
        ('uuidDsaOriginating',UUID),
        ('usnOriginating',USN),
    )

class PROPERTY_META_DATA_EXT_ARRAY(NDRUniConformantArray):
    item = PROPERTY_META_DATA_EXT

# 5.155 PROPERTY_META_DATA_EXT_VECTOR
class PROPERTY_META_DATA_EXT_VECTOR(NDRSTRUCT):
    structure =  (
        ('cNumProps',DWORD),
        ('rgMetaData',PROPERTY_META_DATA_EXT_ARRAY),
    )

class PPROPERTY_META_DATA_EXT_VECTOR(NDRPOINTER):
    referent = (
        ('Data',PROPERTY_META_DATA_EXT_VECTOR),
    )

# 5.161 REPLENTINFLIST

class REPLENTINFLIST(NDRSTRUCT):
    structure =  (
        ('pNextEntInf',NDRPOINTER),
        ('Entinf',ENTINF),
        ('fIsNCPrefix',BOOL),
        ('pParentGuidm',PUUID),
        ('pMetaDataExt',PPROPERTY_META_DATA_EXT_VECTOR),
    )
    # ToDo: Here we should work with getData and fromString beacuse we're cheating with pNextEntInf
    def fromString(self, data, soFar = 0 ):
        # Here we're changing the struct so we can represent a linked list with NDR
        self.fields['pNextEntInf'] = PREPLENTINFLIST(isNDR64 = self._isNDR64)
        retVal = NDRSTRUCT.fromString(self, data, soFar)
        return retVal

class PREPLENTINFLIST(NDRPOINTER):
    referent = (
        ('Data',REPLENTINFLIST),
    )

# 4.1.10.2.9 DRS_MSG_GETCHGREPLY_V1
class DRS_MSG_GETCHGREPLY_V1(NDRSTRUCT):
    structure =  (
        ('uuidDsaObjSrc',UUID),
        ('uuidInvocIdSrc',UUID),
        ('pNC',PDSNAME),
        ('usnvecFrom',USN_VECTOR),
        ('usnvecTo',USN_VECTOR),
        ('pUpToDateVecSrcV1',PUPTODATE_VECTOR_V1_EXT),
        ('PrefixTableSrc',SCHEMA_PREFIX_TABLE),
        ('ulExtendedRet',EXOP_ERR),
        ('cNumObjects',ULONG),
        ('cNumBytes',ULONG),
        ('pObjects',PREPLENTINFLIST),
        ('fMoreData',BOOL),
    )

# 4.1.10.2.15 DRS_COMPRESSED_BLOB
class DRS_COMPRESSED_BLOB(NDRSTRUCT):
    structure =  (
        ('cbUncompressedSize',DWORD),
        ('cbCompressedSize',DWORD),
        ('pbCompressedData',BYTE_ARRAY),
    )

# 4.1.10.2.10 DRS_MSG_GETCHGREPLY_V2
class DRS_MSG_GETCHGREPLY_V2(NDRSTRUCT):
    structure =  (
        ('CompressedV1',DRS_COMPRESSED_BLOB),
    )

# 5.199 UPTODATE_CURSOR_V2
class UPTODATE_CURSOR_V2(NDRSTRUCT):
    structure =  (
        ('uuidDsa',UUID),
        ('usnHighPropUpdate',USN),
        ('timeLastSyncSuccess',DSTIME),
    )

class UPTODATE_CURSOR_V2_ARRAY(NDRUniConformantArray):
    item = UPTODATE_CURSOR_V2

# 5.201 UPTODATE_VECTOR_V2_EXT
class UPTODATE_VECTOR_V2_EXT(NDRSTRUCT):
    structure =  (
        ('dwVersion',DWORD),
        ('dwReserved1',DWORD),
        ('cNumCursors',DWORD),
        ('dwReserved2',DWORD),
        ('rgCursors',UPTODATE_CURSOR_V2_ARRAY),
    )

class PUPTODATE_VECTOR_V2_EXT(NDRPOINTER):
    referent = (
        ('Data',UPTODATE_VECTOR_V2_EXT),
    )

# 5.211 VALUE_META_DATA_EXT_V1
class VALUE_META_DATA_EXT_V1(NDRSTRUCT):
    structure =  (
        ('timeCreated',DSTIME),
        ('MetaData',PROPERTY_META_DATA_EXT),
    )

# 5.215 VALUE_META_DATA_EXT_V3
class VALUE_META_DATA_EXT_V3(NDRSTRUCT):
    structure =  (
        ('timeCreated',DSTIME),
        ('MetaData',PROPERTY_META_DATA_EXT),
        ('unused1',DWORD),
        ('unused1',DWORD),
        ('unused1',DWORD),
        ('timeExpired',DSTIME),
    )

# 5.167 REPLVALINF_V1
class REPLVALINF_V1(NDRSTRUCT):
    structure =  (
        ('pObject',PDSNAME),
        ('attrTyp',ATTRTYP),
        ('Aval',ATTRVAL),
        ('fIsPresent',BOOL),
        ('MetaData',VALUE_META_DATA_EXT_V1),
    )

    def fromString(self, data, soFar = 0):
        retVal = NDRSTRUCT.fromString(self, data, soFar)
        #self.dumpRaw()
        return retVal

class REPLVALINF_V1_ARRAY(NDRUniConformantArray):
    item = REPLVALINF_V1

class PREPLVALINF_V1_ARRAY(NDRPOINTER):
    referent = (
        ('Data', REPLVALINF_V1_ARRAY),
    )

# 5.168 REPLVALINF_V3
class REPLVALINF_V3(NDRSTRUCT):
    structure = (
        ('pObject', PDSNAME),
        ('attrTyp', ATTRTYP),
        ('Aval', ATTRVAL),
        ('fIsPresent', BOOL),
        ('MetaData', VALUE_META_DATA_EXT_V3),
    )

    def fromString(self, data, soFar=0):
        retVal = NDRSTRUCT.fromString(self, data, soFar)
        # self.dumpRaw()
        return retVal

class REPLVALINF_V3_ARRAY(NDRUniConformantArray):
    item = REPLVALINF_V3

class PREPLVALINF_V3_ARRAY(NDRPOINTER):
    referent = (
        ('Data', REPLVALINF_V3_ARRAY),
    )

# 5.169 REPLVALINF_NATIVE
REPLVALINF_NATIVE = REPLVALINF_V3

# 4.1.10.2.11 DRS_MSG_GETCHGREPLY_V6
class DRS_MSG_GETCHGREPLY_V6(NDRSTRUCT):
    structure =  (
        ('uuidDsaObjSrc',UUID),
        ('uuidInvocIdSrc',UUID),
        ('pNC',PDSNAME),
        ('usnvecFrom',USN_VECTOR),
        ('usnvecTo',USN_VECTOR),
        ('pUpToDateVecSrc',PUPTODATE_VECTOR_V2_EXT),
        ('PrefixTableSrc',SCHEMA_PREFIX_TABLE),
        ('ulExtendedRet',EXOP_ERR),
        ('cNumObjects',ULONG),
        ('cNumBytes',ULONG),
        ('pObjects',PREPLENTINFLIST),
        ('fMoreData',BOOL),
        ('cNumNcSizeObjectsc',ULONG),
        ('cNumNcSizeValues',ULONG),
        ('cNumValues',DWORD),
        #('rgValues',PREPLVALINF_V1_ARRAY),
        # ToDo: Once we find out what's going on with PREPLVALINF_ARRAY get it back
        # Seems there's something in there that is not being parsed correctly
        ('rgValues',DWORD),
        ('dwDRSError',DWORD),
    )

# 4.1.10.2.14 DRS_COMP_ALG_TYPE
class DRS_COMP_ALG_TYPE(NDRENUM):
    class enumItems(Enum):
        DRS_COMP_ALG_NONE   = 0
        DRS_COMP_ALG_UNUSED = 1
        DRS_COMP_ALG_MSZIP  = 2
        DRS_COMP_ALG_WIN2K3 = 3

# 4.1.10.2.12 DRS_MSG_GETCHGREPLY_V7
class DRS_MSG_GETCHGREPLY_V7(NDRSTRUCT):
    structure =  (
        ('dwCompressedVersion',DWORD),
        ('CompressionAlg',DRS_COMP_ALG_TYPE),
        ('CompressedAny',DRS_COMPRESSED_BLOB),
    )

# 4.1.10.2.13 DRS_MSG_GETCHGREPLY_V9
class DRS_MSG_GETCHGREPLY_V9(NDRSTRUCT):
    structure =  (
        ('uuidDsaObjSrc',UUID),
        ('uuidInvocIdSrc',UUID),
        ('pNC',PDSNAME),
        ('usnvecFrom',USN_VECTOR),
        ('usnvecTo',USN_VECTOR),
        ('pUpToDateVecSrc',PUPTODATE_VECTOR_V2_EXT),
        ('PrefixTableSrc',SCHEMA_PREFIX_TABLE),
        ('ulExtendedRet',EXOP_ERR),
        ('cNumObjects',ULONG),
        ('cNumBytes',ULONG),
        ('pObjects',PREPLENTINFLIST),
        ('fMoreData',BOOL),
        ('cNumNcSizeObjectsc',ULONG),
        ('cNumNcSizeValues',ULONG),
        ('cNumValues',DWORD),
        #('rgValues',PREPLVALINF_V3_ARRAY),
        # ToDo: Once we find out what's going on with PREPLVALINF_ARRAY get it back
        # Seems there's something in there that is not being parsed correctly
        ('rgValues',DWORD),
        ('dwDRSError',DWORD),
    )

# 4.1.10.2.14 DRS_MSG_GETCHGREPLY_NATIVE
DRS_MSG_GETCHGREPLY_NATIVE = DRS_MSG_GETCHGREPLY_V9

# 4.1.10.2.8 DRS_MSG_GETCHGREPLY
class DRS_MSG_GETCHGREPLY(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_GETCHGREPLY_V1),
        2  : ('V2', DRS_MSG_GETCHGREPLY_V2),
        6  : ('V6', DRS_MSG_GETCHGREPLY_V6),
        7  : ('V7', DRS_MSG_GETCHGREPLY_V7),
        9  : ('V9', DRS_MSG_GETCHGREPLY_V9),
    }

# 4.1.27.1.2 DRS_MSG_VERIFYREQ_V1
class DRS_MSG_VERIFYREQ_V1(NDRSTRUCT):
    structure =  (
        ('dwFlags',DWORD),
        ('cNames',DWORD),
        ('rpNames',PPDSNAME_ARRAY),
        ('RequiredAttrs',ATTRBLOCK),
        ('PrefixTable',SCHEMA_PREFIX_TABLE),
    )

# 4.1.27.1.1 DRS_MSG_VERIFYREQ
class DRS_MSG_VERIFYREQ(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_VERIFYREQ_V1),
    }

# 4.1.27.1.4 DRS_MSG_VERIFYREPLY_V1
class DRS_MSG_VERIFYREPLY_V1(NDRSTRUCT):
    structure =  (
        ('error',DWORD),
        ('cNames',DWORD),
        ('rpEntInf',PENTINF_ARRAY),
        ('PrefixTable',SCHEMA_PREFIX_TABLE),
    )

# 4.1.27.1.3 DRS_MSG_VERIFYREPLY
class DRS_MSG_VERIFYREPLY(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_VERIFYREPLY_V1),
    }

# 4.1.11.1.2 DRS_MSG_NT4_CHGLOG_REQ_V1
class DRS_MSG_NT4_CHGLOG_REQ_V1(NDRSTRUCT):
    structure =  (
        ('dwFlags',DWORD),
        ('PreferredMaximumLength',DWORD),
        ('cbRestart',DWORD),
        ('pRestart',PBYTE_ARRAY),
    )

# 4.1.11.1.1 DRS_MSG_NT4_CHGLOG_REQ
class DRS_MSG_NT4_CHGLOG_REQ(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_NT4_CHGLOG_REQ_V1),
    }

# 4.1.11.1.5 NT4_REPLICATION_STATE
class NT4_REPLICATION_STATE(NDRSTRUCT):
    structure =  (
        ('SamSerialNumber',LARGE_INTEGER),
        ('SamCreationTime',LARGE_INTEGER),
        ('BuiltinSerialNumber',LARGE_INTEGER),
        ('BuiltinCreationTime',LARGE_INTEGER),
        ('LsaSerialNumber',LARGE_INTEGER),
        ('LsaCreationTime',LARGE_INTEGER),
    )

# 4.1.11.1.4 DRS_MSG_NT4_CHGLOG_REPLY_V1
class DRS_MSG_NT4_CHGLOG_REPLY_V1(NDRSTRUCT):
    structure =  (
        ('cbRestart',DWORD),
        ('cbLog',DWORD),
        ('ReplicationState',NT4_REPLICATION_STATE),
        ('ActualNtStatus',DWORD),
        ('pRestart',PBYTE_ARRAY),
        ('pLog',PBYTE_ARRAY),
    )

# 4.1.11.1.3 DRS_MSG_NT4_CHGLOG_REPLY
class DRS_MSG_NT4_CHGLOG_REPLY(NDRUNION):
    commonHdr = (
        ('tag', DWORD),
    )
    union = {
        1  : ('V1', DRS_MSG_NT4_CHGLOG_REPLY_V1),
    }

################################################################################
# RPC CALLS
################################################################################
# 4.1.3 IDL_DRSBind (Opnum 0)
class DRSBind(NDRCALL):
    opnum = 0
    structure = (
        ('puuidClientDsa', PUUID),
        ('pextClient', PDRS_EXTENSIONS),
    )

class DRSBindResponse(NDRCALL):
    structure = (
        ('ppextServer', PDRS_EXTENSIONS),
        ('phDrs', DRS_HANDLE),
        ('ErrorCode',DWORD),
    )

# 4.1.10 IDL_DRSGetNCChanges (Opnum 3)
class DRSGetNCChanges(NDRCALL):
    opnum = 3
    structure = (
        ('hDrs', DRS_HANDLE),
        ('dwInVersion', DWORD),
        ('pmsgIn', DRS_MSG_GETCHGREQ),
    )

class DRSGetNCChangesResponse(NDRCALL):
    structure = (
        ('pdwOutVersion', DWORD),
        ('pmsgOut', DRS_MSG_GETCHGREPLY),
        ('ErrorCode',DWORD),
    )

# 4.1.27 IDL_DRSVerifyNames (Opnum 8)
class DRSVerifyNames(NDRCALL):
    opnum = 8
    structure = (
        ('hDrs', DRS_HANDLE),
        ('dwInVersion', DWORD),
        ('pmsgIn', DRS_MSG_VERIFYREQ),
    )

class DRSVerifyNamesResponse(NDRCALL):
    structure = (
        ('pdwOutVersion', DWORD),
        ('pmsgOut', DRS_MSG_VERIFYREPLY),
        ('ErrorCode',DWORD),
    )
# 4.1.11 IDL_DRSGetNT4ChangeLog (Opnum 11)
class DRSGetNT4ChangeLog(NDRCALL):
    opnum = 11
    structure = (
        ('hDrs', DRS_HANDLE),
        ('dwInVersion', DWORD),
        ('pmsgIn', DRS_MSG_NT4_CHGLOG_REQ),
    )

class DRSGetNT4ChangeLogResponse(NDRCALL):
    structure = (
        ('pdwOutVersion', DWORD),
        ('pmsgOut', DRS_MSG_NT4_CHGLOG_REPLY),
        ('ErrorCode',DWORD),
    )

# 4.1.4 IDL_DRSCrackNames (Opnum 12)
class DRSCrackNames(NDRCALL):
    opnum = 12
    structure = (
        ('hDrs', DRS_HANDLE),
        ('dwInVersion', DWORD),
        ('pmsgIn', DRS_MSG_CRACKREQ),
    )

class DRSCrackNamesResponse(NDRCALL):
    structure = (
        ('pdwOutVersion', DWORD),
        ('pmsgOut', DRS_MSG_CRACKREPLY),
        ('ErrorCode',DWORD),
    )

# 4.1.5 IDL_DRSDomainControllerInfo (Opnum 16)
class DRSDomainControllerInfo(NDRCALL):
    opnum = 16
    structure = (
        ('hDrs', DRS_HANDLE),
        ('dwInVersion', DWORD),
        ('pmsgIn', DRS_MSG_DCINFOREQ),
    )

class DRSDomainControllerInfoResponse(NDRCALL):
    structure = (
        ('pdwOutVersion', DWORD),
        ('pmsgOut', DRS_MSG_DCINFOREPLY),
        ('ErrorCode',DWORD),
    )

################################################################################
# OPNUMs and their corresponding structures
################################################################################
OPNUMS = {
 0 : (DRSBind,DRSBindResponse ),
 3 : (DRSGetNCChanges,DRSGetNCChangesResponse ),
 12: (DRSCrackNames,DRSCrackNamesResponse ),
 16: (DRSDomainControllerInfo,DRSDomainControllerInfoResponse ),
}

################################################################################
# HELPER FUNCTIONS
################################################################################
def checkNullString(string):
    if string == NULL:
        return string

    if string[-1:] != '\x00':
        return string + '\x00'
    else:
        return string

def hDRSDomainControllerInfo(dce, hDrs, domain, infoLevel):
    request = DRSDomainControllerInfo()
    request['hDrs'] = hDrs
    request['dwInVersion'] = 1

    request['pmsgIn']['tag'] = 1
    request['pmsgIn']['V1']['Domain'] = checkNullString(domain)
    request['pmsgIn']['V1']['InfoLevel'] = infoLevel
    return dce.request(request)

def hDRSCrackNames(dce, hDrs, flags, formatOffered, formatDesired, rpNames = ()):
    request = DRSCrackNames()
    request['hDrs'] = hDrs
    request['dwInVersion'] = 1

    request['pmsgIn']['tag'] = 1
    request['pmsgIn']['V1']['CodePage'] = 0
    request['pmsgIn']['V1']['LocaleId'] = 0
    request['pmsgIn']['V1']['dwFlags'] = flags
    request['pmsgIn']['V1']['formatOffered'] = formatOffered
    request['pmsgIn']['V1']['formatDesired'] = formatDesired
    request['pmsgIn']['V1']['cNames'] = len(rpNames)
    for name in rpNames:
        record = LPWSTR()
        record['Data'] = checkNullString(name)
        request['pmsgIn']['V1']['rpNames'].append(record)

    return dce.request(request)

def transformKey(InputKey):
        # Section 2.2.11.1.2 Encrypting a 64-Bit Block with a 7-Byte Key
        OutputKey = []
        OutputKey.append( chr(ord(InputKey[0]) >> 0x01) )
        OutputKey.append( chr(((ord(InputKey[0])&0x01)<<6) | (ord(InputKey[1])>>2)) )
        OutputKey.append( chr(((ord(InputKey[1])&0x03)<<5) | (ord(InputKey[2])>>3)) )
        OutputKey.append( chr(((ord(InputKey[2])&0x07)<<4) | (ord(InputKey[3])>>4)) )
        OutputKey.append( chr(((ord(InputKey[3])&0x0F)<<3) | (ord(InputKey[4])>>5)) )
        OutputKey.append( chr(((ord(InputKey[4])&0x1F)<<2) | (ord(InputKey[5])>>6)) )
        OutputKey.append( chr(((ord(InputKey[5])&0x3F)<<1) | (ord(InputKey[6])>>7)) )
        OutputKey.append( chr(ord(InputKey[6]) & 0x7F) )

        for i in range(8):
            OutputKey[i] = chr((ord(OutputKey[i]) << 1) & 0xfe)

        return "".join(OutputKey)

def deriveKey(baseKey):
        # 2.2.11.1.3 Deriving Key1 and Key2 from a Little-Endian, Unsigned Integer Key
        # Let I be the little-endian, unsigned integer.
        # Let I[X] be the Xth byte of I, where I is interpreted as a zero-base-index array of bytes.
        # Note that because I is in little-endian byte order, I[0] is the least significant byte.
        # Key1 is a concatenation of the following values: I[0], I[1], I[2], I[3], I[0], I[1], I[2].
        # Key2 is a concatenation of the following values: I[3], I[0], I[1], I[2], I[3], I[0], I[1]
        key = pack('<L',baseKey)
        key1 = key[0] + key[1] + key[2] + key[3] + key[0] + key[1] + key[2]
        key2 = key[3] + key[0] + key[1] + key[2] + key[3] + key[0] + key[1]
        return transformKey(key1),transformKey(key2)

def removeDESLayer(cryptedHash, rid):
        Key1,Key2 = deriveKey(rid)

        Crypt1 = DES.new(Key1, DES.MODE_ECB)
        Crypt2 = DES.new(Key2, DES.MODE_ECB)

        decryptedHash = Crypt1.decrypt(cryptedHash[:8]) + Crypt2.decrypt(cryptedHash[8:])

        return decryptedHash

def DecryptAttributeValue(dce, attribute):
    sessionKey = dce.get_session_key()
    # Is it a Kerberos Session Key?
    if isinstance(sessionKey, crypto.Key):
        # Extract its contents and move on
        sessionKey = sessionKey.contents

    encryptedPayload = ENCRYPTED_PAYLOAD(attribute)

    md5 = hashlib.new('md5')
    md5.update(sessionKey)
    md5.update(encryptedPayload['Salt'])
    finalMD5 = md5.digest()

    cipher = ARC4.new(finalMD5)
    plainText = cipher.decrypt(attribute[16:])

    #chkSum = (binascii.crc32(plainText[4:])) & 0xffffffff
    #if unpack('<L',plainText[:4])[0] != chkSum:
    #    print "RECEIVED 0x%x" % unpack('<L',plainText[:4])[0]
    #    print "CALCULATED 0x%x" % chkSum

    return plainText[4:]

# 5.16.4 ATTRTYP-to-OID Conversion
def MakeAttid(prefixTable, oid):
    # get the last value in the original OID: the value * after the last '.'
    lastValue = int(oid.split('.')[-1])

    # convert the dotted form of OID into a BER encoded binary * format.
    # The BER encoding of OID is described in section * 8.19 of [ITUX690]
    from pyasn1.type import univ
    from pyasn1.codec.ber import encoder
    binaryOID = encoder.encode(univ.ObjectIdentifier(oid))[2:]

    # get the prefix of the OID
    if lastValue < 128:
        oidPrefix = list(binaryOID[:-1])
    else:
        oidPrefix = list(binaryOID[:-2])

    # search the prefix in the prefix table, if none found, add
    # one entry for the new prefix.
    fToAdd = True
    pos = len(prefixTable)
    for j, item in enumerate(prefixTable):
        if item['prefix']['elements'] == oidPrefix:
            fToAdd = False
            pos = j
            break

    if fToAdd is True:
        entry = PrefixTableEntry()
        entry['ndx'] = pos
        entry['prefix']['length'] = len(oidPrefix)
        entry['prefix']['elements'] = oidPrefix
        prefixTable.append(entry)

    # compose the attid
    lowerWord = lastValue % 16384
    if lastValue >= 16384:
        # mark it so that it is known to not be the whole lastValue
        lowerWord += 32768

    upperWord = pos

    attrTyp = ATTRTYP()
    attrTyp['Data'] = (upperWord << 16) + lowerWord
    return attrTyp

def OidFromAttid(prefixTable, attr):
    # separate the ATTRTYP into two parts
    upperWord = attr / 65536
    lowerWord = attr % 65536

    # search in the prefix table to find the upperWord, if found,
    # construct the binary OID by appending lowerWord to the end of
    # found prefix.

    binaryOID = None
    for j, item in enumerate(prefixTable):
        if item['ndx'] == upperWord:
            binaryOID = item['prefix']['elements'][:item['prefix']['length']]
            if lowerWord < 128:
                binaryOID.append(chr(lowerWord))
            else:
                if lowerWord >= 32768:
                    lowerWord -= 32768
                binaryOID.append(chr(((lowerWord/128) % 128)+128))
                binaryOID.append(chr(lowerWord%128))
            break

    if binaryOID is None:
        return None

    return str(decoder.decode('\x06' + chr(len(binaryOID)) + ''.join(binaryOID), asn1Spec = univ.ObjectIdentifier())[0])

if __name__ == '__main__':
    prefixTable = []
    oid0 = '1.2.840.113556.1.4.94'
    oid1 = '2.5.6.2'
    oid2 = '1.2.840.113556.1.2.1'
    oid3 = '1.2.840.113556.1.3.223'
    oid4 = '1.2.840.113556.1.5.7000.53'

    o0 = MakeAttid(prefixTable, oid0)
    print hex(o0)
    o1 = MakeAttid(prefixTable, oid1)
    print hex(o1)
    o2 = MakeAttid(prefixTable, oid2)
    print hex(o2)
    o3 = MakeAttid(prefixTable, oid3)
    print hex(o3)
    o4 = MakeAttid(prefixTable, oid4)
    print hex(o4)
    jj = OidFromAttid(prefixTable, o0)
    print jj
    jj = OidFromAttid(prefixTable, o1)
    print jj
    jj = OidFromAttid(prefixTable, o2)
    print jj
    jj = OidFromAttid(prefixTable, o3)
    print jj
    jj = OidFromAttid(prefixTable, o4)
    print jj