Coverage for /root/GitHubProjects/impacket/impacket/dcerpc/v5/nspi.py: 46%

# Coverage for /root/GitHubProjects/impacket/impacket/dcerpc/v5/nspi.py : 46%

## 590 statements

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1# SECUREAUTH LABS. Copyright 2020 SecureAuth Corporation. All rights reserved.

2#

3# This software is provided under a slightly modified version

4# of the Apache Software License. See the accompanying LICENSE file

5# for more information.

6#

7# Description:

8# [MS-NSPI]: Name Service Provider Interface (NSPI) Protocol

9# [MS-OXNSPI]: Exchange Server Name Service Provider Interface (NSPI) Protocol

10#

11# Authors:

12# Arseniy Sharoglazov <mohemiv@gmail.com> / Positive Technologies (https://www.ptsecurity.com/)

13#

14# Tested for MS-OXNSPI, some operation may not work for MS-NSPI

15#

16# ToDo:

17# [ ] Test commented NDRCALLs and write helpers for them

18# [ ] Test restriction structures

19

20 from __future__ import division

21 from __future__ import print_function

22 from struct import unpack

23 from datetime import datetime

24 from six import PY2

25 import binascii

26

27 from impacket import hresult_errors, mapi_constants, uuid

28 from impacket.uuid import EMPTY_UUID

29 from impacket.structure import Structure

30 from impacket.dcerpc.v5.dtypes import NULL, STR, DWORD, LPDWORD, UUID, PUUID, LONG, ULONG, \

31 FILETIME, PFILETIME, BYTE, SHORT, LPSTR, LPWSTR, USHORT, LPLONG, DWORD_ARRAY

32 from impacket.ldap.ldaptypes import LDAP_SID

33 from impacket.dcerpc.v5.ndr import NDR, NDRCALL, NDRPOINTER, NDRSTRUCT, NDRUNION, \

34 NDRUniConformantVaryingArray, NDRUniConformantArray, NDRUniVaryingArray

35 from impacket.dcerpc.v5.rpcrt import DCERPCException

36 from impacket.uuid import string_to_bin, uuidtup_to_bin, EMPTY_UUID

37

38 MSRPC_UUID_NSPI = uuidtup_to_bin(('F5CC5A18-4264-101A-8C59-08002B2F8426', '56.0'))

39

40 class DCERPCSessionError(DCERPCException):

41 def __str__( self ):

42 key = self.error_code

43 if key in mapi_constants.ERROR_MESSAGES:

44 error_msg_short = mapi_constants.ERROR_MESSAGES[key]

45 return 'NSPI SessionError: code: 0x%x - %s' % (self.error_code, error_msg_short)

46 elif key in hresult_errors.ERROR_MESSAGES:

47 error_msg_short = hresult_errors.ERROR_MESSAGES[key][0]

48 error_msg_verbose = hresult_errors.ERROR_MESSAGES[key][1]

49 return 'NSPI SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)

50 else:

51 return 'NSPI SessionError: unknown error code: 0x%x' % self.error_code

52

53################################################################################

54# STRUCTURES

55################################################################################

56 class handle_t(NDRSTRUCT):

57 structure = (

58 ('context_handle_attributes',ULONG),

59 ('context_handle_uuid',UUID),

60 )

61

62 def __init__(self, data=None, isNDR64=False):

63 NDRSTRUCT.__init__(self, data, isNDR64)

64 self['context_handle_uuid'] = b'\x00'*16

65

66 def isNull(self):

67 return self['context_handle_uuid'] == b'\x00'*16

68

69# 2.2.1 Permitted Property Type Values

70 PtypEmbeddedTable = 0x0000000D

71 PtypNull = 0x00000001

72 PtypUnspecified = 0x00000000

73

74# 2.2.3 Display Type Values

75 DT_MAILUSER = 0x00000000

76 DT_DISTLIST = 0x00000001

77 DT_FORUM = 0x00000002

78 DT_AGENT = 0x00000003

79 DT_ORGANIZATION = 0x00000004

80 DT_PRIVATE_DISTLIST = 0x00000005

81 DT_REMOTE_MAILUSER = 0x00000006

82 DT_CONTAINER = 0x00000100

83 DT_TEMPLATE = 0x00000101

84 DT_ADDRESS_TEMPLATE = 0x00000102

85 DT_SEARCH = 0x00000200

86

87# 2.2.4 Default Language Code Identifier

88 NSPI_DEFAULT_LOCALE = 0x00000409

89

90# 2.2.5 Required Codepages

91 CP_TELETEX = 0x00004F25

92 CP_WINUNICODE = 0x000004B0

93

94# 2.2.6.1 Comparison Flags

95 NORM_IGNORECASE = 1 << 0

96 NORM_IGNORENONSPACE = 1 << 1

97 NORM_IGNORESYMBOLS = 1 << 2

98 SORT_STRINGSORT = 1 << 12

99 NORM_IGNOREKANATYPE = 1 << 16

100 NORM_IGNOREWIDTH = 1 << 17

101

102# 2.2.7 Permanent Entry ID GUID

103 GUID_NSPI = string_to_bin("C840A7DC-42C0-1A10-B4B9-08002B2FE182")

104

105# 2.2.8 Positioning Minimal Entry IDs

106 MID_BEGINNING_OF_TABLE = 0x00000000

107 MID_END_OF_TABLE = 0x00000002

108 MID_CURRENT = 0x00000001

109

110# 2.2.9 Ambiguous Name Resolution Minimal Entry IDs

111 MID_UNRESOLVED = 0x00000000

112 MID_AMBIGUOUS = 0x00000001

113 MID_RESOLVED = 0x00000002

114

115# 2.2.10 Table Sort Orders

116 SortTypeDisplayName = 0

117 SortTypePhoneticDisplayName = 0x00000003

118 SortTypeDisplayName_RO = 0x000003E8

119 SortTypeDisplayName_W = 0x000003E9

120

121# 2.2.11 NspiBind Flags

122 fAnonymousLogin = 0x00000020

123

124# 2.2.12 Retrieve Property Flags

125 fSkipObjects = 0x00000001

126 fEphID = 0x00000002

127

128# 2.2.13 NspiGetSpecialTable Flags

129 NspiAddressCreationTemplates = 0x00000002

130 NspiUnicodeStrings = 0x00000004

131

132# 2.2.14 NspiQueryColumns Flags

133 NspiUnicodeProptypes = 0x80000000

134

135# 2.2.15 NspiGetIDsFromNames Flags

136 NspiVerifyNames = 0x00000002

137

138# 2.2.16 NspiGetTemplateInfo Flags

139 TI_TEMPLATE = 0x00000001

140 TI_SCRIPT = 0x00000004

141 TI_EMT = 0x00000010

142 TI_HELPFILE_NAME = 0x00000020

143 TI_HELPFILE_CONTENTS = 0x00000040

144

145# 2.2.17 NspiModLinkAtt Flags

146 fDelete = 0x00000001

147

148# 2.3.1.1 FlatUID_r

149 FlatUID_r = UUID

150 PFlatUID_r = PUUID

151

152# 2.3.1.2 PropertyTagArray_r

153 class PropertyTagArray(NDRUniConformantVaryingArray):

154 item = DWORD

155

156 class PropertyTagArray_r(NDRSTRUCT):

157 structure = (

158 ('cValues', ULONG),

159 ('aulPropTag', PropertyTagArray)

160 )

161

162 class PPropertyTagArray_r(NDRPOINTER):

163 referent = (

164 ('Data', PropertyTagArray_r),

165 )

166

167# 2.3.1.3 Binary_r

168 class Binary(NDRUniConformantArray):

169 item = 'c'

170

171 class PBinary(NDRPOINTER):

172 referent = (

173 ('Data', Binary),

174 )

175

176 class Binary_r(NDRSTRUCT):

177 structure = (

178 ('cValues', DWORD),

179 ('lpb', PBinary),

180 )

181

182# 2.3.1.4 ShortArray_r

183 class ShortArray(NDRUniConformantArray):

184 item = SHORT

185

186 class PShortArray(NDRPOINTER):

187 referent = (

188 ('Data', ShortArray),

189 )

190

191 class ShortArray_r(NDRSTRUCT):

192 structure = (

193 ('cValues', DWORD),

194 ('lpi', PShortArray),

195 )

196

197# 2.3.1.5 LongArray_r

198 class LongArray(NDRUniConformantArray):

199 item = LONG

200

201 class PLongArray(NDRPOINTER):

202 referent = (

203 ('Data', LongArray),

204 )

205

206 class LongArray_r(NDRSTRUCT):

207 structure = (

208 ('cValues', DWORD),

209 ('lpl', PLongArray)

210 )

211

212# 2.3.1.6 StringArray_r

213 class StringArray(NDRUniConformantArray):

214 item = LPSTR

215

216 class PStringArray(NDRPOINTER):

217 referent = (

218 ('Data', StringArray),

219 )

220

221 class StringArray_r(NDRSTRUCT):

222 structure = (

223 ('cValues', DWORD),

224 ('lppszA', PStringArray)

225 )

226

227# 2.3.1.7 BinaryArray_r

228 class BinaryArray(NDRUniConformantArray):

229 item = Binary_r

230

231 class PBinaryArray(NDRPOINTER):

232 referent = (

233 ('Data', BinaryArray),

234 )

235

236 class BinaryArray_r(NDRSTRUCT):

237 structure = (

238 ('cValues', DWORD),

239 ('lpbin', PBinaryArray)

240 )

241

242# 2.3.1.8 FlatUIDArray_r

243 class FlatUIDArray(NDRUniConformantArray):

244 item = PFlatUID_r

245

246 class PFlatUIDArray(NDRPOINTER):

247 referent = (

248 ('Data', FlatUIDArray),

249 )

250

251 class FlatUIDArray_r(NDRSTRUCT):

252 structure = (

253 ('cValues', DWORD),

254 ('lpguid', PFlatUIDArray)

255 )

256

257# 2.3.1.9 WStringArray_r

258 class WStringArray(NDRUniConformantArray):

259 item = LPWSTR

260

261 class PWStringArray(NDRPOINTER):

262 referent = (

263 ('Data', WStringArray),

264 )

265

266 class WStringArray_r(NDRSTRUCT):

267 structure = (

268 ('cValues', DWORD),

269 ('lppszW', PWStringArray)

270 )

271

272# 2.3.1.10 DateTimeArray_r

273 class DateTimeArray(NDRUniConformantArray):

274 item = PFILETIME

275

276 class PDateTimeArray(NDRPOINTER):

277 referent = (

278 ('Data', DateTimeArray),

279 )

280

281 class DateTimeArray_r(NDRSTRUCT):

282 structure = (

283 ('cValues', DWORD),

284 ('lpft', PDateTimeArray)

285 )

286

287# 2.3.1.11 PROP_VAL_UNION

288 class PROP_VAL_UNION(NDRUNION):

289 commonHdr = (

290 ('tag', DWORD),

291 )

292

293 union = {

294 0x0002: ('i', SHORT), # PtypInteger16

295 0x0003: ('l', LONG), # PtypInteger32

296 0x000B: ('b', USHORT), # PtypBoolean

297 0x001E: ('lpszA', LPSTR), # PtypString8

298 0x0102: ('bin', Binary_r), # PtypBinary

299 0x001F: ('lpszW', LPWSTR), # PtypString

300 0x0048: ('lpguid', PFlatUID_r), # PtypGuid

301 0x0040: ('ft', FILETIME), # PtypTime

302 0x000A: ('err', ULONG), # PtypErrorCode

303 0x1002: ('MVi', ShortArray_r), # PtypMultipleInteger16

304 0x1003: ('MVl', LongArray_r), # PtypMultipleInteger32

305 0x101E: ('MVszA', StringArray_r), # PtypMultipleString8

306 0x1102: ('MVbin', BinaryArray_r), # PtypMultipleBinary

307 0x1048: ('MVguid', FlatUIDArray_r), # PtypMultipleGuid

308 0x101F: ('MVszW', WStringArray_r), # PtypMultipleString

309 0x1040: ('MVft', DateTimeArray_r), # PtypMultipleTime

310 0x0001: ('lReserved', LONG), # PtypNull

311 0x000D: ('lReserved', LONG), # PtypEmbeddedTable

312 0x0000: ('lReserved', LONG), # PtypUnspecified

313 }

314

315# 2.3.1.12 PropertyValue_r

316 class PropertyValue_r(NDRSTRUCT):

317 structure = (

318 ('ulPropTag', DWORD),

319 ('ulReserved', DWORD), # dwAlignPad

320 ('Value', PROP_VAL_UNION),

321 )

322

323 class PPropertyValue_r(NDRPOINTER):

324 referent = (

325 ('Data', PropertyValue_r),

326 )

327

328# 2.3.2 PropertyRow_r

329 class PropertyValue(NDRUniConformantArray):

330 item = PropertyValue_r

331

332 class PPropertyValue(NDRPOINTER):

333 referent = (

334 ('Data', PropertyValue),

335 )

336

337 class PropertyRow_r(NDRSTRUCT):

338 structure = (

339 ('Reserved', DWORD), # ulAdrEntryPad

340 ('cValues', DWORD),

341 ('lpProps', PPropertyValue)

342 )

343

344 class PPropertyRow_r(NDRPOINTER):

345 referent = (

346 ('Data', PropertyRow_r),

347 )

348

349# 2.3.3 PropertyRowSet_r

350 class PropertyRowSet(NDRUniConformantArray):

351 item = PropertyRow_r

352

353 class PropertyRowSet_r(NDRSTRUCT):

354 structure = (

355 ('cRows', DWORD),

356 ('aRow', PropertyRowSet),

357 )

358

359 class PPropertyRowSet_r(NDRPOINTER):

360 referent = (

361 ('Data', PropertyRowSet_r),

362 )

363

364# 2.3.4 Restrictions

365 class Restriction_r(NDRSTRUCT):

366 pass

367

368 class PRestriction_r(NDRPOINTER):

369 referent = (

370 ('Data', Restriction_r),

371 )

372

373# 2.3.4.1 AndRestriction_r, OrRestriction_r

374 class AndRestriction(NDRUniConformantArray):

375 item = Restriction_r

376

377 class PAndRestriction(NDRPOINTER):

378 referent = (

379 ('Data', AndRestriction),

380 )

381

382 class AndRestriction_r(NDRSTRUCT):

383 structure = (

384 ('cRes', DWORD),

385 ('lpRes', PAndRestriction),

386 )

387

388 OrRestriction_r = AndRestriction_r

389

390# 2.3.4.2 NotRestriction_r

391 class NotRestriction_r(NDRSTRUCT):

392 structure = (

393 ('lpRes', PRestriction_r),

394 )

395

396# 2.3.4.3 ContentRestriction_r

397 class ContentRestriction_r(NDRSTRUCT):

398 structure = (

399 ('ulFuzzyLevel', DWORD),

400 ('ulPropTag', DWORD),

401 ('lpProp', PPropertyValue_r),

402 )

403

404# 2.3.4.4 BitMaskRestriction_r

405 class BitMaskRestriction_r(NDRSTRUCT):

406 structure = (

407 ('relBMR', DWORD),

408 ('ulPropTag', DWORD),

409 ('ulMask', DWORD),

410 )

411

412# 2.3.4.5 PropertyRestriction_r

413 class PropertyRestriction_r(NDRSTRUCT):

414 structure = (

415 ('relop', DWORD),

416 ('ulPropTag', DWORD),

417 ('lpProp', PPropertyValue_r),

418 )

419

420# 2.3.4.6 ComparePropsRestriction_r

421 class ComparePropsRestriction_r(NDRSTRUCT):

422 structure = (

423 ('relop', DWORD),

424 ('ulPropTag1', DWORD),

425 ('ulPropTag2', DWORD),

426 )

427

428# 2.3.4.7 SubRestriction_r

429 class SubRestriction_r(NDRSTRUCT):

430 structure = (

431 ('ulSubObject', DWORD),

432 ('lpRes', PRestriction_r),

433 )

434

435# 2.3.4.8 SizeRestriction_r

436 class SizeRestriction_r(NDRSTRUCT):

437 structure = (

438 ('relop', DWORD),

439 ('ulPropTag', DWORD),

440 ('cb', DWORD),

441 )

442

443# 2.3.4.9 ExistRestriction_r

444 class ExistRestriction_r(NDRSTRUCT):

445 structure = (

446 ('ulReserved1', DWORD),

447 ('ulPropTag', DWORD),

448 ('ulReserved2', DWORD),

449 )

450

451# 2.3.4.10 RestrictionUnion_r

452 class RestrictionUnion_r(NDRUNION):

453 commonHdr = (

454 ('tag', DWORD),

455 )

456

457 union = {

458 0x00000000: ('resAnd', AndRestriction_r),

459 0x00000001: ('resOr', OrRestriction_r),

460 0x00000002: ('resNot', NotRestriction_r),

461 0x00000003: ('resContent', ContentRestriction_r),

462 0x00000004: ('resProperty', PropertyRestriction_r),

463 0x00000005: ('resCompareProps', ComparePropsRestriction_r),

464 0x00000006: ('resBitMask', BitMaskRestriction_r),

465 0x00000007: ('resSize', SizeRestriction_r),

466 0x00000008: ('resExist', ExistRestriction_r),

467 0x00000009: ('resSubRestriction', SubRestriction_r),

468 }

469

470# 2.3.4.11 Restriction_r

471 Restriction_r.structure = (

472 ('rt', DWORD),

473 ('res', RestrictionUnion_r),

474)

475

476# 2.3.5.1 PropertyName_r

477 class PropertyName_r(NDRSTRUCT):

478 structure = (

479 ('lpguid', PFlatUID_r),

480 ('ulReserved', DWORD),

481 ('lID', LONG),

482 )

483

484 class PPropertyName_r(NDRPOINTER):

485 referent = (

486 ('Data', PropertyName_r),

487 )

488

489# 2.3.5.2 PropertyNameSet_r

490 class PropertyNameSet(NDRUniConformantArray):

491 item = PropertyName_r

492

493 class PropertyNameSet_r(NDRSTRUCT):

494 structure = (

495 ('cNames', DWORD),

496 ('aulPropTag', PropertyNameSet)

497 )

498

499 class PPropertyNameSet_r(NDRPOINTER):

500 referent = (

501 ('Data', PropertyNameSet_r),

502 )

503

504# 2.3.6.1 StringsArray_r

505 class StringsArray(NDRUniConformantArray):

506 item = LPSTR

507

508 class StringsArray_r(NDRSTRUCT):

509 structure = (

510 ('Count', DWORD),

511 ('Strings', StringsArray)

512 )

513

514# 2.3.6.1 StringsArray_r

515 class WStringsArray(NDRUniConformantArray):

516 item = LPWSTR

517

518 class WStringsArray_r(NDRSTRUCT):

519 structure = (

520 ('Count', DWORD),

521 ('Strings', WStringsArray)

522 )

523

524# 2.3.7 STAT

525 class STAT(NDRSTRUCT):

526 structure = (

527 ('SortType', DWORD),

528 ('ContainerID', DWORD),

529 ('CurrentRec', DWORD),

530 ('Delta', LONG),

531 ('NumPos', DWORD),

532 ('TotalRecs', DWORD),

533 ('CodePage', DWORD),

534 ('TemplateLocale', DWORD),

535 ('SortLocale', DWORD),

536 )

537

538 class PSTAT(NDRPOINTER):

539 referent = (

540 ('Data', STAT),

541 )

542

543# 2.3.8.1 MinimalEntryID

544 MinEntryID = '<L=0'

545

546# 2.3.8.2 EphemeralEntryID

547 class EphemeralEntryID(Structure):

548 structure = (

549 ('IDType','<B=0x87'),

550 ('R1','<B=0'),

551 ('R2','<B=0'),

552 ('R3','<B=0'),

553 ('ProviderUID','16s=b"\\x00"*16'),

554 ('R4','<L=0x0000001'),

555 ('DisplayType','<L'),

556 ('MId',MinEntryID),

557 )

558

559# 2.3.8.3 PermanentEntryID

560 class PermanentEntryID(Structure):

561 default_guid = GUID_NSPI

562 structure = (

563 ('IDType','<B=0'),

564 ('R1','<B=0'),

565 ('R2','<B=0'),

566 ('R3','<B=0'),

567 ('ProviderUID','16s=self["default_guid"]'),

568 ('R4','<L=0x0000001'),

569 ('DisplayType','<L'),

570 ('DistinguishedName','z'),

571 )

572

573 def __str__(self):

574 return self["DistinguishedName"]

575

576################################################################################

577# RPC CALLS

578################################################################################

579

580# 3.1.4.1 RfrGetNewDSA (opnum 0)

581 class NspiBind(NDRCALL):

582 opnum = 0

583 structure = (

584 ('dwFlags', DWORD),

585 ('pStat', STAT),

586 ('pServerGuid', PFlatUID_r),

587 )

588

589 class NspiBindResponse(NDRCALL):

590 structure = (

591 ('pServerGuid', PFlatUID_r),

592 ('contextHandle', handle_t),

593 ('ErrorCode', ULONG),

594 )

595

596# 3.1.4.2 NspiUnbind (Opnum 1)

597 class NspiUnbind(NDRCALL):

598 opnum = 1

599 structure = (

600 ('contextHandle', handle_t),

601 ('Reserved', DWORD), # flags

602 )

603

604 class NspiUnbindResponse(NDRCALL):

605 structure = (

606 ('contextHandle', handle_t),

607 ('ErrorCode', ULONG),

608 )

609

610# 3.1.4.4 NspiUpdateStat (Opnum 2)

611 class NspiUpdateStat(NDRCALL):

612 opnum = 2

613 structure = (

614 ('hRpc', handle_t),

615 ('Reserved', DWORD), # flags

616 ('pStat', STAT),

617 ('plDelta', LPLONG),

618 )

619

620 class NspiUpdateStatResponse(NDRCALL):

621 structure = (

622 ('pStat', STAT),

623 ('plDelta', LPLONG),

624 ('ErrorCode', ULONG),

625 )

626

627# 3.1.4.8 NspiQueryRows (Opnum 3)

628 class DWORD_ARRAY(NDRUniConformantArray):

629 item = DWORD

630

631 class PDWORD_ARRAY(NDRPOINTER):

632 referent = (

633 ('Data', DWORD_ARRAY),

634 )

635

636 class NspiQueryRows(NDRCALL):

637 opnum = 3

638 structure = (

639 ('hRpc', handle_t),

640 ('dwFlags', DWORD),

641 ('pStat', STAT),

642 ('dwETableCount', DWORD),

643 ('lpETable', PDWORD_ARRAY),

644 ('Count', DWORD),

645 ('pPropTags', PPropertyTagArray_r),

646 )

647

648 class NspiQueryRowsResponse(NDRCALL):

649 structure = (

650 ('pStat', STAT),

651 ('ppRows', PPropertyRowSet_r),

652 ('ErrorCode', ULONG),

653 )

654

655# 3.1.4.9 NspiSeekEntries (Opnum 4)

656 class NspiSeekEntries(NDRCALL):

657 opnum = 4

658 structure = (

659 ('hRpc', handle_t),

660 ('Reserved', DWORD), # flags

661 ('pStat', STAT),

662 ('pTarget', PropertyValue_r),

663 ('lpETable', PropertyTagArray_r),

664 ('pPropTags', PropertyTagArray_r),

665 )

666

667 class NspiSeekEntriesResponse(NDRCALL):

668 structure = (

669 ('pStat', STAT),

670 ('ppRows', PPropertyRowSet_r),

671 ('ErrorCode', ULONG),

672 )

673

674# 3.1.4.10 NspiGetMatches (Opnum 5)

675#class NspiGetMatches(NDRCALL):

676# opnum = 5

677# structure = (

678# ('hRpc', handle_t),

679# ('Reserved1', DWORD), # flags

680# ('pStat', STAT),

681# ('pReserved', PropertyTagArray_r), # mids

682# ('Reserved2', DWORD), # interfaceOptions

683# ('Filter', Restriction_r),

684# ('lpPropName', PropertyName_r),

685# ('ulRequested', DWORD),

686# ('pPropTags', PropertyTagArray_r),

687# )

688

689#class NspiGetMatchesResponse(NDRCALL):

690# structure = (

691# ('pStat', PSTAT),

692# ('ppOutMIds', PPropertyTagArray_r),

693# ('ppRows', PPropertyRowSet_r),

694# ('ErrorCode', ULONG),

695# )

696

697# 3.1.4.11 NspiResortRestriction (Opnum 6)

698#class NspiResortRestriction(NDRCALL):

699# opnum = 6

700# structure = (

701# ('hRpc', handle_t),

702# ('Reserved', DWORD),

703# ('pStat', STAT),

704# ('pInMIds', PropertyTagArray_r),

705# ('ppOutMIds', PPropertyTagArray_r),

706# )

707

708#class NspiResortRestrictionResponse(NDRCALL):

709# structure = (

710# ('pStat', PSTAT),

711# ('ppOutMIds', PPropertyTagArray_r),

712# ('ErrorCode', ULONG),

713# )

714

715# 3.1.4.13 NspiDNToMId (Opnum 7)

716 class NspiDNToMId(NDRCALL):

717 opnum = 7

718 structure = (

719 ('hRpc', handle_t),

720 ('Reserved', DWORD), # flags

721 ('pNames', StringsArray_r),

722 )

723

724 class NspiDNToMIdResponse(NDRCALL):

725 structure = (

726 ('ppOutMIds', PPropertyTagArray_r),

727 ('ErrorCode', ULONG),

728 )

729

730# 3.1.4.6 NspiGetPropList (Opnum 8)

731 class NspiGetPropList(NDRCALL):

732 opnum = 8

733 structure = (

734 ('hRpc', handle_t),

735 ('dwFlags', DWORD),

736 ('dwMId', DWORD),

737 ('CodePage', DWORD),

738 )

739

740 class NspiGetPropListResponse(NDRCALL):

741 structure = (

742 ('ppOutMIds', PPropertyTagArray_r),

743 ('ErrorCode', ULONG),

744 )

745

746# 3.1.4.7 NspiGetProps (Opnum 9)

747 class NspiGetProps(NDRCALL):

748 opnum = 9

749 structure = (

750 ('hRpc', handle_t),

751 ('dwFlags', DWORD),

752 ('pStat', PSTAT),

753 ('pPropTags', PPropertyTagArray_r),

754 )

755

756 class NspiGetPropsResponse(NDRCALL):

757 structure = (

758 ('ppRows', PPropertyRow_r),

759 ('ErrorCode', ULONG),

760 )

761

762# 3.1.4.12 NspiCompareMIds (Opnum 10)

763 class NspiCompareMIds(NDRCALL):

764 opnum = 10

765 structure = (

766 ('hRpc', handle_t),

767 ('Reserved', DWORD), # flags

768 ('pStat', STAT),

769 ('MId1', DWORD),

770 ('MId2', DWORD),

771 )

772

773 class NspiCompareMIdsResponse(NDRCALL):

774 structure = (

775 ('plResult', LONG),

776 ('ErrorCode', ULONG),

777 )

778

779# 3.1.4.14 NspiModProps (Opnum 11)

780#class NspiModProps(NDRCALL):

781# opnum = 11

782# structure = (

783# ('hRpc', handle_t),

784# ('Reserved', DWORD), # flags

785# ('pStat', STAT),

786# ('pPropTags', PropertyTagArray_r),

787# ('pRow', PropertyRow_r),

788# )

789

790#class NspiModPropsResponse(NDRCALL):

791# structure = (

792# ('plResult', LPLONG),

793# ('ErrorCode', ULONG),

794# )

795

796# 3.1.4.3 NspiGetSpecialTable (Opnum 12)

797 class NspiGetSpecialTable(NDRCALL):

798 opnum = 12

799 structure = (

800 ('hRpc', handle_t),

801 ('dwFlags', DWORD),

802 ('pStat', PSTAT),

803 ('lpVersion', LPDWORD),

804 )

805

806 class NspiGetSpecialTableResponse(NDRCALL):

807 structure = (

808 # In Exchange 2013 / 2016 / 2019 lpVersion is

809 # a RuntimeHelpers.GetHashCode value, and it will be

810 # different each call

811 ('lpVersion', DWORD),

812 ('ppRows', PPropertyRowSet_r),

813 ('ErrorCode', DWORD),

814 )

815

816# 3.1.4.20 NspiGetTemplateInfo (Opnum 13)

817 class NspiGetTemplateInfo(NDRCALL):

818 opnum = 13

819 structure = (

820 ('hRpc', handle_t),

821 ('dwFlags', DWORD),

822 ('ulType', DWORD),

823 ('pDN', LPSTR),

824 ('dwCodePage', DWORD),

825 ('dwLocaleID', DWORD),

826 )

827

828 class NspiGetTemplateInfoResponse(NDRCALL):

829 structure = (

830 ('ppData', PPropertyRow_r),

831 ('ErrorCode', ULONG),

832 )

833

834# 3.1.4.15 NspiModLinkAtt (Opnum 14)

835 class NspiModLinkAtt(NDRCALL):

836 opnum = 14

837 structure = (

838 ('hRpc', handle_t),

839 ('dwFlags', DWORD),

840 ('ulPropTag', DWORD),

841 ('dwMId', DWORD),

842 ('lpEntryIds', BinaryArray_r),

843 )

844

845 class NspiModLinkAttResponse(NDRCALL):

846 structure = (

847 ('ErrorCode', ULONG),

848 )

849

850# Undocumented opnum 15

851#class NspiDeleteEntries(NDRCALL):

852# opnum = 15

853# structure = (

854# ('hRpc', handle_t),

855# ('dwFlags', DWORD),

856# ('dwMId', DWORD),

857# ('entryIds', BinaryArray_r),

858# )

859

860#class NspiDeleteEntriesResponse(NDRCALL):

861# structure = (

862# ('ErrorCode', ULONG),

863# )

864

865# 3.1.4.5 NspiQueryColumns (Opnum 16)

866 class NspiQueryColumns(NDRCALL):

867 opnum = 16

868 structure = (

869 ('hRpc', handle_t),

870 ('Reserved', DWORD), # flags

871 ('dwFlags', DWORD), # mapiFlags

872 )

873

874 class NspiQueryColumnsResponse(NDRCALL):

875 structure = (

876 ('ppColumns', PPropertyTagArray_r),

877 ('ErrorCode', ULONG),

878 )

879

880# 3.1.4.16 NspiGetNamesFromIDs (Opnum 17)

881 class NspiGetNamesFromIDs(NDRCALL):

882 opnum = 17

883 structure = (

884 ('hRpc', handle_t),

885 ('Reserved', DWORD), # flags

886 ('lpguid', PFlatUID_r),

887 ('pPropTags', PPropertyTagArray_r),

888 )

889

890 class NspiGetNamesFromIDsResponse(NDRCALL):

891 structure = (

892 ('ppReturnedPropTags', PPropertyTagArray_r),

893 ('ppNames', PPropertyNameSet_r),

894 ('ErrorCode', ULONG),

895 )

896

897# 3.1.4.17 NspiGetIDsFromNames (Opnum 18)

898 class PropertyName_r_ARRAY(NDRUniConformantVaryingArray):

899 item = PropertyName_r

900

901 class NspiGetIDsFromNames(NDRCALL):

902 opnum = 18

903 structure = (

904 ('hRpc', handle_t),

905 ('Reserved', DWORD), # flags

906 ('dwFlags', DWORD), # mapiFlags

907 ('cPropNames', DWORD),

908 ('pNames', PropertyName_r_ARRAY),

909 )

910

911 class NspiGetIDsFromNamesResponse(NDRCALL):

912 structure = (

913 ('ppPropTags', PPropertyTagArray_r),

914 ('ErrorCode', ULONG),

915 )

916

917# 3.1.4.18 NspiResolveNames (Opnum 19)

918 class NspiResolveNames(NDRCALL):

919 opnum = 19

920 structure = (

921 ('hRpc', handle_t),

922 ('Reserved', DWORD), # flags

923 ('pStat', STAT),

924 ('pPropTags', PPropertyTagArray_r),

925 ('paStr', StringsArray_r),

926 )

927

928 class NspiResolveNamesResponse(NDRCALL):

929 structure = (

930 ('ppMIds', PPropertyTagArray_r),

931 ('ppRows', PPropertyRowSet_r),

932 ('ErrorCode', ULONG),

933 )

934

935# 3.1.4.19 NspiResolveNamesW (Opnum 20)

936 class NspiResolveNamesW(NDRCALL):

937 opnum = 20

938 structure = (

939 ('hRpc', handle_t),

940 ('Reserved', DWORD), # flags

941 ('pStat', STAT),

942 ('pPropTags', PPropertyTagArray_r),

943 ('paStr', WStringsArray_r),

944 )

945

946 class NspiResolveNamesWResponse(NDRCALL):

947 structure = (

948 ('ppMIds', PPropertyTagArray_r),

949 ('ppRows', PPropertyRowSet_r),

950 ('ErrorCode', ULONG),

951 )

952

953################################################################################

954# OPNUMs and their corresponding structures

955################################################################################

956 OPNUMS = {

957 0 : (NspiBind, NspiBindResponse),

958 1 : (NspiUnbind, NspiUnbindResponse),

959 2 : (NspiUpdateStat, NspiUpdateStatResponse),

960 3 : (NspiQueryRows, NspiQueryRowsResponse),

961 4 : (NspiSeekEntries, NspiSeekEntriesResponse),

962# 5 : (NspiGetMatches, NspiGetMatchesResponse),

963# 6 : (NspiResortRestriction, NspiResortRestrictionResponse),

964 7 : (NspiDNToMId, NspiDNToMIdResponse),

965 8 : (NspiGetPropList, NspiGetPropListResponse),

966 9 : (NspiGetProps, NspiGetPropsResponse),

967 10 : (NspiCompareMIds, NspiCompareMIdsResponse),

968# 11 : (NspiModProps, NspiModPropsResponse),

969 12 : (NspiGetSpecialTable, NspiGetSpecialTableResponse),

970 13 : (NspiGetTemplateInfo, NspiGetTemplateInfoResponse),

971 14 : (NspiModLinkAtt, NspiModLinkAttResponse),

972# 15 : (NspiDeleteEntries, NspiDeleteEntriesResponse),

973 16 : (NspiQueryColumns, NspiQueryColumnsResponse),

974 17 : (NspiGetNamesFromIDs, NspiGetNamesFromIDsResponse),

975 18 : (NspiGetIDsFromNames, NspiGetIDsFromNamesResponse),

976 19 : (NspiResolveNames, NspiResolveNamesResponse),

977 20 : (NspiResolveNamesW, NspiResolveNamesWResponse),

978}

979

980################################################################################

981# HELPER FUNCTIONS

982################################################################################

983 def checkNullString(string):

984 if string == NULL:

985 return string

986

987 if string[-1:] != '\x00':

988 return string + '\x00'

989 else:

990 return string

991

992 def get_guid_from_dn(legacyDN):

993 legacyDN = str(legacyDN)

994 guid = legacyDN[legacyDN.rfind("=")+1:]

995

996 return uuid.string_to_bin(guid)

997

998 def get_dn_from_guid(guid, minimize=False):

999 if minimize:

1000 # MS-OXNSPI

1001 dn_template = "/guid="

1002 else:

1003 # MS-NSPI and MS-OXNSPI

1004 dn_template = "/o=NT5/ou=00000000000000000000000000000000/cn="

1005

1006 guid_bin = string_to_bin(guid)

1007

1008 if PY2:

1009 return "%s%s" % (dn_template, binascii.hexlify(guid_bin))

1010 else:

1011 return "%s%s" % (dn_template, str(binascii.hexlify(guid_bin), 'ascii'))

1012

1013 class EXCH_SID(LDAP_SID):

1014 def __str__(self):

1015 return self.formatCanonical()

1016

1017 class ExchBinaryObject(bytes):

1018 pass

1019

1020 def getUnixTime(t):

1021 t -= 116444736000000000

1022 t //= 10000000

1023 return t

1024

1025 def simplifyPropertyRow(rowSetElem):

1026 row = {}

1027

1028 for prop in rowSetElem['lpProps']:

1029 prop_name_in_union = prop['Value'].structure[0][0]

1030 prop_value = prop['Value'].fields[prop_name_in_union]

1031

1032 PropTag = prop['ulPropTag']

1033

1034 if isinstance(prop_value, SHORT) or \

1035 isinstance(prop_value, USHORT) or \

1036 isinstance(prop_value, LONG) or \

1037 isinstance(prop_value, ULONG):

1038 row[PropTag] = int(prop_value['Data'])

1039 elif isinstance(prop_value, LPWSTR):

1040 if PropTag in [0x8c38001f]:

1041 # What is this field for?

1042 row[PropTag] = ExchBinaryObject(prop_value['Data'].encode("utf-16le")[:-2])

1043 else:

1044 row[PropTag] = prop_value['Data'][:-1]

1045 elif isinstance(prop_value, LPSTR):

1046 row[PropTag] = prop_value['Data'][:-1]

1047 elif isinstance(prop_value, Binary_r):

1048 value = b''.join(prop_value['lpb'])

1049

1050 if PropTag in [0x80270102, 0x8c750102]:

1051 value = EXCH_SID(value)

1052 elif PropTag == 0x300b0102:

1053 value = value[:-1].decode("utf-8")

1054 elif value[4:20] == GUID_NSPI and value[20:24] == b'\x01\x00\x00\x00' and value[:4] == b'\x00\x00\x00\x00':

1055 value = PermanentEntryID(value)

1056 elif value[:4] == b'\x87\x00\x00\x00' and value[20:24] == b'\x01\x00\x00\x00' and len(value) == 32:

1057 value = EphemeralEntryID(value)

1058 elif PropTag in [0x8c6d0102, 0x68c40102, 0x8c730102, 0x0ff80102]:

1059 value = uuid.bin_to_string(value).lower()

1060 elif PropTag == 0x0ff60102:

1061 value = unpack('<l', value)[0]

1062 else:

1063 value = ExchBinaryObject(value)

1064

1065 row[PropTag] = value

1066 elif isinstance(prop_value, BinaryArray_r):

1067 array = []

1068 for value in prop_value['lpbin']:

1069 array.append(b''.join(value['lpb']))

1070 row[PropTag] = array

1071 elif isinstance(prop_value, StringArray_r):

1072 array = []

1073 for value in prop_value['lppszA']:

1074 array.append(value['Data'][:-1])

1075 row[PropTag] = array

1076 elif isinstance(prop_value, WStringArray_r):

1077 array = []

1078 for value in prop_value['lppszW']:

1079 array.append(value['Data'][:-1])

1080 row[PropTag] = array

1081 elif isinstance(prop_value, FILETIME):

1082 row[PropTag] = datetime.fromtimestamp( \

1083 getUnixTime(unpack('<Q', prop_value.getData())[0]))

1084 else:

1085 row[PropTag] = prop_value

1086

1087 return row

1088

1089 def simplifyPropertyRowSet(propertyRowSet):

1090 ret = []

1091

1092 for rowSet in propertyRowSet['aRow']:

1093 ret.append(simplifyPropertyRow(rowSet))

1094

1095 return ret

1096

1097 def hNspiBind(dce, pStat=None):

1098 request = NspiBind()

1099

1100 if pStat == None:

1101 request['pStat']['CodePage'] = CP_TELETEX

1102 else:

1103 request['pStat'] = pStat

1104

1105 resp = dce.request(request)

1106 return resp

1107

1108 def hNspiUnbind(dce, handler):

1109 request = NspiUnbind()

1110 request['contextHandle'] = handler

1111

1112 resp = dce.request(request, checkError=False)

1113 return resp

1114

1115 def hNspiUpdateStat(dce, handler, pStat, plDelta=NULL):

1116 request = NspiUpdateStat()

1117 request['hRpc'] = handler

1118 request['pStat'] = pStat

1119 request['plDelta'] = plDelta

1120

1121 resp = dce.request(request, checkError=False)

1122 return resp

1123

1124 def hNspiQueryRows(dce, handler, dwFlags=fSkipObjects, pStat=None, ContainerID=0,

1125 Count=50, pPropTags=[], pPropTagsRaw=NULL, lpETable=[]):

1126 request = NspiQueryRows()

1127 request['hRpc'] = handler

1128 request['dwFlags'] = dwFlags

1129 request['Count'] = Count

1130

1131 if pStat == None:

1132 request['pStat']['ContainerID'] = ContainerID

1133 else:

1134 request['pStat'] = pStat

1135

1136 if len(pPropTags) > 0:

1137 for aulPropTag in pPropTags:

1138 prop = DWORD()

1139 prop['Data'] = aulPropTag

1140 request['pPropTags']['aulPropTag'].append(prop)

1141 request['pPropTags']['cValues'] = len(pPropTags)

1142 request.fields['pPropTags'].fields['Data'].fields['aulPropTag'].fields['MaximumCount'] = len(pPropTags) + 1

1143 else:

1144 request['pPropTags'] = pPropTagsRaw

1145

1146 if len(lpETable) > 0:

1147 for mID in lpETable:

1148 elem = DWORD()

1149 elem['Data'] = mID

1150 request['lpETable'].append(elem)

1151 request['dwETableCount'] = len(lpETable)

1152 else:

1153 request['lpETable'] = NULL

1154 request['dwETableCount'] = 0

1155

1156 resp = dce.request(request)

1157 return resp

1158

1159 def hNspiSeekEntries(dce, handler, displayName, ContainerID=0, SortType=0, \

1160 lpETable=[], lpETableRaw=NULL, pPropTags=[], pPropTagsRaw=NULL):

1161 request = NspiSeekEntries()

1162 request['hRpc'] = handler

1163 request['pStat']['ContainerID'] = ContainerID

1164

1165 # MS-OXNSPI 3.1.4.1.9.9

1166 # If the SortType field in the input parameter pStat has any value other than

1167 # SortTypeDisplayName, the server MUST return the value GeneralFailure.

1168 request['pStat']['SortType'] = SortTypeDisplayName

1169

1170 # MS-OXNSPI 3.1.4.1.9.10

1171 # If the SortType field in the input parameter pStat is SortTypeDisplayName and the property

1172 # specified in the input parameter pTarget is anything other than PidTagDisplayName (with either

1173 # the Property Type PtypString8 or PtypString), the server MUST return the value

1174 # GeneralFailure.

1175 request['pTarget']['ulPropTag'] = 0x3001001F

1176 request['pTarget']['Value']['tag'] = 0x0000001F

1177 request['pTarget']['Value']['lpszW'] = checkNullString(displayName)

1178

1179 if len(lpETable) > 0:

1180 for mID in lpETable:

1181 elem = DWORD()

1182 elem['Data'] = mID

1183 request['lpETable'].append(elem)

1184 else:

1185 request['lpETable'] = lpETableRaw

1186

1187 if len(pPropTags) > 0:

1188 for aulPropTag in pPropTags:

1189 prop = DWORD()

1190 prop['Data'] = aulPropTag

1191 request['pPropTags']['aulPropTag'].append(prop)

1192 request.fields['pPropTags'].fields['aulPropTag'].fields['MaximumCount'] = len(pPropTags) + 1

1193 else:

1194 request['pPropTags'] = pPropTagsRaw

1195

1196 resp = dce.request(request)

1197 return resp

1198

1199 def hNspiDNToMId(dce, handler, pNames=[]):

1200 request = NspiDNToMId()

1201 request['hRpc'] = handler

1202 request['pNames']['Count'] = len(pNames)

1203

1204 for name in pNames:

1205 lpstr = LPSTR()

1206 lpstr['Data'] = checkNullString(name)

1207 request['pNames']['Strings'].append(lpstr)

1208

1209 resp = dce.request(request)

1210 return resp

1211

1212 def hNspiGetPropList(dce, handler, dwMId=0, dwFlags=fSkipObjects, CodePage=CP_TELETEX):

1213 request = NspiGetPropList()

1214 request['hRpc'] = handler

1215 request['dwMId'] = dwMId

1216 request['dwFlags'] = dwFlags

1217 request['CodePage'] = CodePage

1218 resp = dce.request(request)

1219

1220 return resp

1221

1222 def hNspiGetProps(dce, handler, ContainerID=0, CurrentRec=0, dwFlags=fSkipObjects, CodePage=CP_TELETEX, pPropTags=[]):

1223 request = NspiGetProps()

1224 request['hRpc'] = handler

1225 request['dwFlags'] = dwFlags

1226

1227 request['pStat']['CurrentRec'] = CurrentRec

1228 request['pStat']['ContainerID'] = ContainerID

1229 request['pStat']['CodePage'] = CodePage

1230

1231 for aulPropTag in pPropTags:

1232 prop = DWORD()

1233 prop['Data'] = aulPropTag

1234 request['pPropTags']['aulPropTag'].append(prop)

1235 request['pPropTags']['cValues'] = len(pPropTags) + 1

1236 request.fields['pPropTags'].fields['Data'].fields['aulPropTag'].fields['MaximumCount'] = len(pPropTags) + 1

1237

1238 resp = dce.request(request)

1239 return resp

1240

1241 def hNspiGetSpecialTable(dce, handler, dwFlags=NspiUnicodeStrings, pStat=STAT(), lpVersion=NULL):

1242 request = NspiGetSpecialTable()

1243 request['hRpc'] = handler

1244 request['dwFlags'] = dwFlags

1245 request['pStat'] = pStat

1246 request['lpVersion'] = lpVersion

1247

1248 resp = dce.request(request)

1249 return resp

1250

1251# Lookups specified LegacyDN or CN={ulType},CN={dwLocaleID},CN=Display-Templates,CN=Addressing in Configuration Naming Context

1252 def hNspiGetTemplateInfo(dce, handler, pDN=NULL, dwLocaleID=0, ulType=0, dwCodePage=0, dwFlags=0xFFFFFFFF):

1253 request = NspiGetTemplateInfo()

1254 request['hRpc'] = handler

1255 request['dwFlags'] = dwFlags

1256 request['ulType'] = ulType

1257 request['pDN'] = checkNullString(pDN)

1258 request['dwCodePage'] = dwCodePage

1259 request['dwLocaleID'] = dwLocaleID

1260

1261 resp = dce.request(request)

1262 return resp

1263

1264 def hNspiModLinkAtt(dce, handler, dwFlags, ulPropTag, dwMId, lpEntryIds):

1265 request = NspiModLinkAtt()

1266 request['hRpc'] = handler

1267 request['dwFlags'] = dwFlags

1268 request['ulPropTag'] = ulPropTag

1269 request['dwMId'] = dwMId

1270

1271 for lpEntryId in lpEntryIds:

1272 prop = Binary_r()

1273 prop['lpb'] = lpEntryId.getData()

1274 prop['cValues'] = len(prop['lpb'])

1275 request['lpEntryIds']['lpbin'].append(prop)

1276 request['lpEntryIds']['cValues'] = len(lpEntryIds)

1277

1278 resp = dce.request(request)

1279 return resp

1280

1281 def hNspiQueryColumns(dce, handler, dwFlags=NspiUnicodeProptypes):

1282 request = NspiQueryColumns()

1283 request['hRpc'] = handler

1284 request['dwFlags'] = dwFlags

1285

1286 resp = dce.request(request)

1287 return resp

1288

1289 def hNspiGetNamesFromIDs(dce, handler, lpguid=EMPTY_UUID, pPropTags=[], pPropTagsRaw=NULL):

1290 request = NspiGetNamesFromIDs()

1291 request['hRpc'] = handler

1292 request['lpguid'] = lpguid

1293

1294 if len(pPropTags) > 0:

1295 for aulPropTag in pPropTags:

1296 prop = DWORD()

1297 prop['Data'] = aulPropTag

1298 request['pPropTags']['aulPropTag'].append(prop)

1299 request['pPropTags']['cValues'] = len(pPropTags)

1300 request.fields['pPropTags'].fields['Data'].fields['aulPropTag'].fields['MaximumCount'] = len(pPropTags) + 1

1301 elif pPropTagsRaw == NULL:

1302 request.fields['pPropTags'] = NULL

1303 else:

1304 request['pPropTags'] = pPropTagsRaw

1305

1306 resp = dce.request(request)

1307 return resp

1308

1309 def hNspiResolveNames(dce, handler, ContainerID=0, pPropTags=[], pPropTagsRaw=NULL, paStr=[]):

1310 request = NspiResolveNames()

1311 request['hRpc'] = handler

1312 request['pStat']['ContainerID'] = ContainerID

1313

1314 if len(pPropTags) > 0:

1315 for aulPropTag in pPropTags:

1316 prop = DWORD()

1317 prop['Data'] = aulPropTag

1318 request['pPropTags']['aulPropTag'].append(prop)

1319 request['pPropTags']['cValues'] = len(pPropTags)

1320 request.fields['pPropTags'].fields['Data'].fields['aulPropTag'].fields['MaximumCount'] = len(pPropTags) + 1

1321 elif pPropTagsRaw == NULL:

1322 request.fields['pPropTags'] = NULL

1323 else:

1324 request['pPropTags'] = pPropTagsRaw

1325

1326 if len(paStr) > 0:

1327 for paStrElem in paStr:

1328 value = LPSTR()

1329 value['Data'] = checkNullString(paStrElem)

1330 request['paStr']['Strings'].append(value)

1331 request['paStr']['Count'] = len(paStr)

1332

1333 resp = dce.request(request)

1334 return resp

1335

1336 def hNspiResolveNamesW(dce, handler, ContainerID=0, pPropTags=[], pPropTagsRaw=NULL, paStr=[]):

1337 request = NspiResolveNamesW()

1338 request['hRpc'] = handler

1339 request['pStat']['ContainerID'] = ContainerID

1340

1341 if len(pPropTags) > 0:

1342 for aulPropTag in pPropTags:

1343 prop = DWORD()

1344 prop['Data'] = aulPropTag

1345 request['pPropTags']['aulPropTag'].append(prop)

1346 request['pPropTags']['cValues'] = len(pPropTags)

1347 request.fields['pPropTags'].fields['Data'].fields['aulPropTag'].fields['MaximumCount'] = len(pPropTags) + 1

1348 elif pPropTagsRaw == NULL:

1349 request.fields['pPropTags'] = NULL

1350 else:

1351 request['pPropTags'] = pPropTagsRaw

1352

1353 if len(paStr) > 0:

1354 for paStrElem in paStr:

1355 value = LPWSTR()

1356 value['Data'] = checkNullString(paStrElem)

1357 request['paStr']['Strings'].append(value)

1358 request['paStr']['Count'] = len(paStr)

1359

1360 resp = dce.request(request)

1361 return resp