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# Impacket - Collection of Python classes for working with network protocols.

2#

3# SECUREAUTH LABS. Copyright (C) 2020 SecureAuth Corporation. All rights reserved.

4#

5# This software is provided under a slightly modified version

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

7# for more information.

8#

9# Description:

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

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

12#

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

14#

15# Author:

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

17#

18# ToDo:

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

20# [ ] Test restriction structures

21#

22

23 from __future__ import division

24 from __future__ import print_function

25 from struct import unpack

26 from datetime import datetime

27 from six import PY2

28 import binascii

29

30 from impacket import hresult_errors, mapi_constants, uuid

31 from impacket.uuid import EMPTY_UUID

32 from impacket.structure import Structure

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

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

35 from impacket.ldap.ldaptypes import LDAP_SID

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

37 NDRUniConformantVaryingArray, NDRUniConformantArray, NDRUniVaryingArray

38 from impacket.dcerpc.v5.rpcrt import DCERPCException

39 from impacket.uuid import string_to_bin, uuidtup_to_bin, EMPTY_UUID

40

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

42

43 class DCERPCSessionError(DCERPCException):

44 def __str__( self ):

45 key = self.error_code

46 if key in mapi_constants.ERROR_MESSAGES:

47 error_msg_short = mapi_constants.ERROR_MESSAGES[key]

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

49 elif key in hresult_errors.ERROR_MESSAGES:

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

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

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

53 else:

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

55

56################################################################################

57# STRUCTURES

58################################################################################

59 class handle_t(NDRSTRUCT):

60 structure = (

61 ('context_handle_attributes',ULONG),

62 ('context_handle_uuid',UUID),

63 )

64

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

66 NDRSTRUCT.__init__(self, data, isNDR64)

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

68

69 def isNull(self):

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

71

72# 2.2.1 Permitted Property Type Values

73 PtypEmbeddedTable = 0x0000000D

74 PtypNull = 0x00000001

75 PtypUnspecified = 0x00000000

76

77# 2.2.3 Display Type Values

78 DT_MAILUSER = 0x00000000

79 DT_DISTLIST = 0x00000001

80 DT_FORUM = 0x00000002

81 DT_AGENT = 0x00000003

82 DT_ORGANIZATION = 0x00000004

83 DT_PRIVATE_DISTLIST = 0x00000005

84 DT_REMOTE_MAILUSER = 0x00000006

85 DT_CONTAINER = 0x00000100

86 DT_TEMPLATE = 0x00000101

87 DT_ADDRESS_TEMPLATE = 0x00000102

88 DT_SEARCH = 0x00000200

89

90# 2.2.4 Default Language Code Identifier

91 NSPI_DEFAULT_LOCALE = 0x00000409

92

93# 2.2.5 Required Codepages

94 CP_TELETEX = 0x00004F25

95 CP_WINUNICODE = 0x000004B0

96

97# 2.2.6.1 Comparison Flags

98 NORM_IGNORECASE = 1 << 0

99 NORM_IGNORENONSPACE = 1 << 1

100 NORM_IGNORESYMBOLS = 1 << 2

101 SORT_STRINGSORT = 1 << 12

102 NORM_IGNOREKANATYPE = 1 << 16

103 NORM_IGNOREWIDTH = 1 << 17

104

105# 2.2.7 Permanent Entry ID GUID

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

107

108# 2.2.8 Positioning Minimal Entry IDs

109 MID_BEGINNING_OF_TABLE = 0x00000000

110 MID_END_OF_TABLE = 0x00000002

111 MID_CURRENT = 0x00000001

112

113# 2.2.9 Ambiguous Name Resolution Minimal Entry IDs

114 MID_UNRESOLVED = 0x00000000

115 MID_AMBIGUOUS = 0x00000001

116 MID_RESOLVED = 0x00000002

117

118# 2.2.10 Table Sort Orders

119 SortTypeDisplayName = 0

120 SortTypePhoneticDisplayName = 0x00000003

121 SortTypeDisplayName_RO = 0x000003E8

122 SortTypeDisplayName_W = 0x000003E9

123

124# 2.2.11 NspiBind Flags

125 fAnonymousLogin = 0x00000020

126

127# 2.2.12 Retrieve Property Flags

128 fSkipObjects = 0x00000001

129 fEphID = 0x00000002

130

131# 2.2.13 NspiGetSpecialTable Flags

132 NspiAddressCreationTemplates = 0x00000002

133 NspiUnicodeStrings = 0x00000004

134

135# 2.2.14 NspiQueryColumns Flags

136 NspiUnicodeProptypes = 0x80000000

137

138# 2.2.15 NspiGetIDsFromNames Flags

139 NspiVerifyNames = 0x00000002

140

141# 2.2.16 NspiGetTemplateInfo Flags

142 TI_TEMPLATE = 0x00000001

143 TI_SCRIPT = 0x00000004

144 TI_EMT = 0x00000010

145 TI_HELPFILE_NAME = 0x00000020

146 TI_HELPFILE_CONTENTS = 0x00000040

147

148# 2.2.17 NspiModLinkAtt Flags

149 fDelete = 0x00000001

150

151# 2.3.1.1 FlatUID_r

152 FlatUID_r = UUID

153 PFlatUID_r = PUUID

154

155# 2.3.1.2 PropertyTagArray_r

156 class PropertyTagArray(NDRUniConformantVaryingArray):

157 item = DWORD

158

159 class PropertyTagArray_r(NDRSTRUCT):

160 structure = (

161 ('cValues', ULONG),

162 ('aulPropTag', PropertyTagArray)

163 )

164

165 class PPropertyTagArray_r(NDRPOINTER):

166 referent = (

167 ('Data', PropertyTagArray_r),

168 )

169

170# 2.3.1.3 Binary_r

171 class Binary(NDRUniConformantArray):

172 item = 'c'

173

174 class PBinary(NDRPOINTER):

175 referent = (

176 ('Data', Binary),

177 )

178

179 class Binary_r(NDRSTRUCT):

180 structure = (

181 ('cValues', DWORD),

182 ('lpb', PBinary),

183 )

184

185# 2.3.1.4 ShortArray_r

186 class ShortArray(NDRUniConformantArray):

187 item = SHORT

188

189 class PShortArray(NDRPOINTER):

190 referent = (

191 ('Data', ShortArray),

192 )

193

194 class ShortArray_r(NDRSTRUCT):

195 structure = (

196 ('cValues', DWORD),

197 ('lpi', PShortArray),

198 )

199

200# 2.3.1.5 LongArray_r

201 class LongArray(NDRUniConformantArray):

202 item = LONG

203

204 class PLongArray(NDRPOINTER):

205 referent = (

206 ('Data', LongArray),

207 )

208

209 class LongArray_r(NDRSTRUCT):

210 structure = (

211 ('cValues', DWORD),

212 ('lpl', PLongArray)

213 )

214

215# 2.3.1.6 StringArray_r

216 class StringArray(NDRUniConformantArray):

217 item = LPSTR

218

219 class PStringArray(NDRPOINTER):

220 referent = (

221 ('Data', StringArray),

222 )

223

224 class StringArray_r(NDRSTRUCT):

225 structure = (

226 ('cValues', DWORD),

227 ('lppszA', PStringArray)

228 )

229

230# 2.3.1.7 BinaryArray_r

231 class BinaryArray(NDRUniConformantArray):

232 item = Binary_r

233

234 class PBinaryArray(NDRPOINTER):

235 referent = (

236 ('Data', BinaryArray),

237 )

238

239 class BinaryArray_r(NDRSTRUCT):

240 structure = (

241 ('cValues', DWORD),

242 ('lpbin', PBinaryArray)

243 )

244

245# 2.3.1.8 FlatUIDArray_r

246 class FlatUIDArray(NDRUniConformantArray):

247 item = PFlatUID_r

248

249 class PFlatUIDArray(NDRPOINTER):

250 referent = (

251 ('Data', FlatUIDArray),

252 )

253

254 class FlatUIDArray_r(NDRSTRUCT):

255 structure = (

256 ('cValues', DWORD),

257 ('lpguid', PFlatUIDArray)

258 )

259

260# 2.3.1.9 WStringArray_r

261 class WStringArray(NDRUniConformantArray):

262 item = LPWSTR

263

264 class PWStringArray(NDRPOINTER):

265 referent = (

266 ('Data', WStringArray),

267 )

268

269 class WStringArray_r(NDRSTRUCT):

270 structure = (

271 ('cValues', DWORD),

272 ('lppszW', PWStringArray)

273 )

274

275# 2.3.1.10 DateTimeArray_r

276 class DateTimeArray(NDRUniConformantArray):

277 item = PFILETIME

278

279 class PDateTimeArray(NDRPOINTER):

280 referent = (

281 ('Data', DateTimeArray),

282 )

283

284 class DateTimeArray_r(NDRSTRUCT):

285 structure = (

286 ('cValues', DWORD),

287 ('lpft', PDateTimeArray)

288 )

289

290# 2.3.1.11 PROP_VAL_UNION

291 class PROP_VAL_UNION(NDRUNION):

292 commonHdr = (

293 ('tag', DWORD),

294 )

295

296 union = {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

316 }

317

318# 2.3.1.12 PropertyValue_r

319 class PropertyValue_r(NDRSTRUCT):

320 structure = (

321 ('ulPropTag', DWORD),

322 ('ulReserved', DWORD), # dwAlignPad

323 ('Value', PROP_VAL_UNION),

324 )

325

326 class PPropertyValue_r(NDRPOINTER):

327 referent = (

328 ('Data', PropertyValue_r),

329 )

330

331# 2.3.2 PropertyRow_r

332 class PropertyValue(NDRUniConformantArray):

333 item = PropertyValue_r

334

335 class PPropertyValue(NDRPOINTER):

336 referent = (

337 ('Data', PropertyValue),

338 )

339

340 class PropertyRow_r(NDRSTRUCT):

341 structure = (

342 ('Reserved', DWORD), # ulAdrEntryPad

343 ('cValues', DWORD),

344 ('lpProps', PPropertyValue)

345 )

346

347 class PPropertyRow_r(NDRPOINTER):

348 referent = (

349 ('Data', PropertyRow_r),

350 )

351

352# 2.3.3 PropertyRowSet_r

353 class PropertyRowSet(NDRUniConformantArray):

354 item = PropertyRow_r

355

356 class PropertyRowSet_r(NDRSTRUCT):

357 structure = (

358 ('cRows', DWORD),

359 ('aRow', PropertyRowSet),

360 )

361

362 class PPropertyRowSet_r(NDRPOINTER):

363 referent = (

364 ('Data', PropertyRowSet_r),

365 )

366

367# 2.3.4 Restrictions

368 class Restriction_r(NDRSTRUCT):

369 pass

370

371 class PRestriction_r(NDRPOINTER):

372 referent = (

373 ('Data', Restriction_r),

374 )

375

376# 2.3.4.1 AndRestriction_r, OrRestriction_r

377 class AndRestriction(NDRUniConformantArray):

378 item = Restriction_r

379

380 class PAndRestriction(NDRPOINTER):

381 referent = (

382 ('Data', AndRestriction),

383 )

384

385 class AndRestriction_r(NDRSTRUCT):

386 structure = (

387 ('cRes', DWORD),

388 ('lpRes', PAndRestriction),

389 )

390

391 OrRestriction_r = AndRestriction_r

392

393# 2.3.4.2 NotRestriction_r

394 class NotRestriction_r(NDRSTRUCT):

395 structure = (

396 ('lpRes', PRestriction_r),

397 )

398

399# 2.3.4.3 ContentRestriction_r

400 class ContentRestriction_r(NDRSTRUCT):

401 structure = (

402 ('ulFuzzyLevel', DWORD),

403 ('ulPropTag', DWORD),

404 ('lpProp', PPropertyValue_r),

405 )

406

407# 2.3.4.4 BitMaskRestriction_r

408 class BitMaskRestriction_r(NDRSTRUCT):

409 structure = (

410 ('relBMR', DWORD),

411 ('ulPropTag', DWORD),

412 ('ulMask', DWORD),

413 )

414

415# 2.3.4.5 PropertyRestriction_r

416 class PropertyRestriction_r(NDRSTRUCT):

417 structure = (

418 ('relop', DWORD),

419 ('ulPropTag', DWORD),

420 ('lpProp', PPropertyValue_r),

421 )

422

423# 2.3.4.6 ComparePropsRestriction_r

424 class ComparePropsRestriction_r(NDRSTRUCT):

425 structure = (

426 ('relop', DWORD),

427 ('ulPropTag1', DWORD),

428 ('ulPropTag2', DWORD),

429 )

430

431# 2.3.4.7 SubRestriction_r

432 class SubRestriction_r(NDRSTRUCT):

433 structure = (

434 ('ulSubObject', DWORD),

435 ('lpRes', PRestriction_r),

436 )

437

438# 2.3.4.8 SizeRestriction_r

439 class SizeRestriction_r(NDRSTRUCT):

440 structure = (

441 ('relop', DWORD),

442 ('ulPropTag', DWORD),

443 ('cb', DWORD),

444 )

445

446# 2.3.4.9 ExistRestriction_r

447 class ExistRestriction_r(NDRSTRUCT):

448 structure = (

449 ('ulReserved1', DWORD),

450 ('ulPropTag', DWORD),

451 ('ulReserved2', DWORD),

452 )

453

454# 2.3.4.10 RestrictionUnion_r

455 class RestrictionUnion_r(NDRUNION):

456 commonHdr = (

457 ('tag', DWORD),

458 )

459

460 union = {

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

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

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

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

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

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

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

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

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

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

471 }

472

473# 2.3.4.11 Restriction_r

474 Restriction_r.structure = (

475 ('rt', DWORD),

476 ('res', RestrictionUnion_r),

477)

478

479# 2.3.5.1 PropertyName_r

480 class PropertyName_r(NDRSTRUCT):

481 structure = (

482 ('lpguid', PFlatUID_r),

483 ('ulReserved', DWORD),

484 ('lID', LONG),

485 )

486

487 class PPropertyName_r(NDRPOINTER):

488 referent = (

489 ('Data', PropertyName_r),

490 )

491

492# 2.3.5.2 PropertyNameSet_r

493 class PropertyNameSet(NDRUniConformantArray):

494 item = PropertyName_r

495

496 class PropertyNameSet_r(NDRSTRUCT):

497 structure = (

498 ('cNames', DWORD),

499 ('aulPropTag', PropertyNameSet)

500 )

501

502 class PPropertyNameSet_r(NDRPOINTER):

503 referent = (

504 ('Data', PropertyNameSet_r),

505 )

506

507# 2.3.6.1 StringsArray_r

508 class StringsArray(NDRUniConformantArray):

509 item = LPSTR

510

511 class StringsArray_r(NDRSTRUCT):

512 structure = (

513 ('Count', DWORD),

514 ('Strings', StringsArray)

515 )

516

517# 2.3.6.1 StringsArray_r

518 class WStringsArray(NDRUniConformantArray):

519 item = LPWSTR

520

521 class WStringsArray_r(NDRSTRUCT):

522 structure = (

523 ('Count', DWORD),

524 ('Strings', WStringsArray)

525 )

526

527# 2.3.7 STAT

528 class STAT(NDRSTRUCT):

529 structure = (

530 ('SortType', DWORD),

531 ('ContainerID', DWORD),

532 ('CurrentRec', DWORD),

533 ('Delta', LONG),

534 ('NumPos', DWORD),

535 ('TotalRecs', DWORD),

536 ('CodePage', DWORD),

537 ('TemplateLocale', DWORD),

538 ('SortLocale', DWORD),

539 )

540

541 class PSTAT(NDRPOINTER):

542 referent = (

543 ('Data', STAT),

544 )

545

546# 2.3.8.1 MinimalEntryID

547 MinEntryID = '<L=0'

548

549# 2.3.8.2 EphemeralEntryID

550 class EphemeralEntryID(Structure):

551 structure = (

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

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

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

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

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

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

558 ('DisplayType','<L'),

559 ('MId',MinEntryID),

560 )

561

562# 2.3.8.3 PermanentEntryID

563 class PermanentEntryID(Structure):

564 default_guid = GUID_NSPI

565 structure = (

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

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

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

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

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

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

572 ('DisplayType','<L'),

573 ('DistinguishedName','z'),

574 )

575

576 def __str__(self):

577 return self["DistinguishedName"]

578

579################################################################################

580# RPC CALLS

581################################################################################

582

583# 3.1.4.1 RfrGetNewDSA (opnum 0)

584 class NspiBind(NDRCALL):

585 opnum = 0

586 structure = (

587 ('dwFlags', DWORD),

588 ('pStat', STAT),

589 ('pServerGuid', PFlatUID_r),

590 )

591

592 class NspiBindResponse(NDRCALL):

593 structure = (

594 ('pServerGuid', PFlatUID_r),

595 ('contextHandle', handle_t),

596 ('ErrorCode', ULONG),

597 )

598

599# 3.1.4.2 NspiUnbind (Opnum 1)

600 class NspiUnbind(NDRCALL):

601 opnum = 1

602 structure = (

603 ('contextHandle', handle_t),

604 ('Reserved', DWORD), # flags

605 )

606

607 class NspiUnbindResponse(NDRCALL):

608 structure = (

609 ('contextHandle', handle_t),

610 ('ErrorCode', ULONG),

611 )

612

613# 3.1.4.4 NspiUpdateStat (Opnum 2)

614 class NspiUpdateStat(NDRCALL):

615 opnum = 2

616 structure = (

617 ('hRpc', handle_t),

618 ('Reserved', DWORD), # flags

619 ('pStat', STAT),

620 ('plDelta', LPLONG),

621 )

622

623 class NspiUpdateStatResponse(NDRCALL):

624 structure = (

625 ('pStat', STAT),

626 ('plDelta', LPLONG),

627 ('ErrorCode', ULONG),

628 )

629

630# 3.1.4.8 NspiQueryRows (Opnum 3)

631 class DWORD_ARRAY(NDRUniConformantArray):

632 item = DWORD

633

634 class PDWORD_ARRAY(NDRPOINTER):

635 referent = (

636 ('Data', DWORD_ARRAY),

637 )

638

639 class NspiQueryRows(NDRCALL):

640 opnum = 3

641 structure = (

642 ('hRpc', handle_t),

643 ('dwFlags', DWORD),

644 ('pStat', STAT),

645 ('dwETableCount', DWORD),

646 ('lpETable', PDWORD_ARRAY),

647 ('Count', DWORD),

648 ('pPropTags', PPropertyTagArray_r),

649 )

650

651 class NspiQueryRowsResponse(NDRCALL):

652 structure = (

653 ('pStat', STAT),

654 ('ppRows', PPropertyRowSet_r),

655 ('ErrorCode', ULONG),

656 )

657

658# 3.1.4.9 NspiSeekEntries (Opnum 4)

659 class NspiSeekEntries(NDRCALL):

660 opnum = 4

661 structure = (

662 ('hRpc', handle_t),

663 ('Reserved', DWORD), # flags

664 ('pStat', STAT),

665 ('pTarget', PropertyValue_r),

666 ('lpETable', PropertyTagArray_r),

667 ('pPropTags', PropertyTagArray_r),

668 )

669

670 class NspiSeekEntriesResponse(NDRCALL):

671 structure = (

672 ('pStat', STAT),

673 ('ppRows', PPropertyRowSet_r),

674 ('ErrorCode', ULONG),

675 )

676

677# 3.1.4.10 NspiGetMatches (Opnum 5)

678#class NspiGetMatches(NDRCALL):

679# opnum = 5

680# structure = (

681# ('hRpc', handle_t),

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

683# ('pStat', STAT),

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

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

686# ('Filter', Restriction_r),

687# ('lpPropName', PropertyName_r),

688# ('ulRequested', DWORD),

689# ('pPropTags', PropertyTagArray_r),

690# )

691

692#class NspiGetMatchesResponse(NDRCALL):

693# structure = (

694# ('pStat', PSTAT),

695# ('ppOutMIds', PPropertyTagArray_r),

696# ('ppRows', PPropertyRowSet_r),

697# ('ErrorCode', ULONG),

698# )

699

700# 3.1.4.11 NspiResortRestriction (Opnum 6)

701#class NspiResortRestriction(NDRCALL):

702# opnum = 6

703# structure = (

704# ('hRpc', handle_t),

705# ('Reserved', DWORD),

706# ('pStat', STAT),

707# ('pInMIds', PropertyTagArray_r),

708# ('ppOutMIds', PPropertyTagArray_r),

709# )

710

711#class NspiResortRestrictionResponse(NDRCALL):

712# structure = (

713# ('pStat', PSTAT),

714# ('ppOutMIds', PPropertyTagArray_r),

715# ('ErrorCode', ULONG),

716# )

717

718# 3.1.4.13 NspiDNToMId (Opnum 7)

719 class NspiDNToMId(NDRCALL):

720 opnum = 7

721 structure = (

722 ('hRpc', handle_t),

723 ('Reserved', DWORD), # flags

724 ('pNames', StringsArray_r),

725 )

726

727 class NspiDNToMIdResponse(NDRCALL):

728 structure = (

729 ('ppOutMIds', PPropertyTagArray_r),

730 ('ErrorCode', ULONG),

731 )

732

733# 3.1.4.6 NspiGetPropList (Opnum 8)

734 class NspiGetPropList(NDRCALL):

735 opnum = 8

736 structure = (

737 ('hRpc', handle_t),

738 ('dwFlags', DWORD),

739 ('dwMId', DWORD),

740 ('CodePage', DWORD),

741 )

742

743 class NspiGetPropListResponse(NDRCALL):

744 structure = (

745 ('ppOutMIds', PPropertyTagArray_r),

746 ('ErrorCode', ULONG),

747 )

748

749# 3.1.4.7 NspiGetProps (Opnum 9)

750 class NspiGetProps(NDRCALL):

751 opnum = 9

752 structure = (

753 ('hRpc', handle_t),

754 ('dwFlags', DWORD),

755 ('pStat', PSTAT),

756 ('pPropTags', PPropertyTagArray_r),

757 )

758

759 class NspiGetPropsResponse(NDRCALL):

760 structure = (

761 ('ppRows', PPropertyRow_r),

762 ('ErrorCode', ULONG),

763 )

764

765# 3.1.4.12 NspiCompareMIds (Opnum 10)

766 class NspiCompareMIds(NDRCALL):

767 opnum = 10

768 structure = (

769 ('hRpc', handle_t),

770 ('Reserved', DWORD), # flags

771 ('pStat', STAT),

772 ('MId1', DWORD),

773 ('MId2', DWORD),

774 )

775

776 class NspiCompareMIdsResponse(NDRCALL):

777 structure = (

778 ('plResult', LONG),

779 ('ErrorCode', ULONG),

780 )

781

782# 3.1.4.14 NspiModProps (Opnum 11)

783#class NspiModProps(NDRCALL):

784# opnum = 11

785# structure = (

786# ('hRpc', handle_t),

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

788# ('pStat', STAT),

789# ('pPropTags', PropertyTagArray_r),

790# ('pRow', PropertyRow_r),

791# )

792

793#class NspiModPropsResponse(NDRCALL):

794# structure = (

795# ('plResult', LPLONG),

796# ('ErrorCode', ULONG),

797# )

798

799# 3.1.4.3 NspiGetSpecialTable (Opnum 12)

800 class NspiGetSpecialTable(NDRCALL):

801 opnum = 12

802 structure = (

803 ('hRpc', handle_t),

804 ('dwFlags', DWORD),

805 ('pStat', PSTAT),

806 ('lpVersion', LPDWORD),

807 )

808

809 class NspiGetSpecialTableResponse(NDRCALL):

810 structure = (

811 # In Exchange 2013 / 2016 / 2019 lpVersion is

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

813 # different each call

814 ('lpVersion', DWORD),

815 ('ppRows', PPropertyRowSet_r),

816 ('ErrorCode', DWORD),

817 )

818

819# 3.1.4.20 NspiGetTemplateInfo (Opnum 13)

820 class NspiGetTemplateInfo(NDRCALL):

821 opnum = 13

822 structure = (

823 ('hRpc', handle_t),

824 ('dwFlags', DWORD),

825 ('ulType', DWORD),

826 ('pDN', LPSTR),

827 ('dwCodePage', DWORD),

828 ('dwLocaleID', DWORD),

829 )

830

831 class NspiGetTemplateInfoResponse(NDRCALL):

832 structure = (

833 ('ppData', PPropertyRow_r),

834 ('ErrorCode', ULONG),

835 )

836

837# 3.1.4.15 NspiModLinkAtt (Opnum 14)

838 class NspiModLinkAtt(NDRCALL):

839 opnum = 14

840 structure = (

841 ('hRpc', handle_t),

842 ('dwFlags', DWORD),

843 ('ulPropTag', DWORD),

844 ('dwMId', DWORD),

845 ('lpEntryIds', BinaryArray_r),

846 )

847

848 class NspiModLinkAttResponse(NDRCALL):

849 structure = (

850 ('ErrorCode', ULONG),

851 )

852

853# Undocumented opnum 15

854#class NspiDeleteEntries(NDRCALL):

855# opnum = 15

856# structure = (

857# ('hRpc', handle_t),

858# ('dwFlags', DWORD),

859# ('dwMId', DWORD),

860# ('entryIds', BinaryArray_r),

861# )

862

863#class NspiDeleteEntriesResponse(NDRCALL):

864# structure = (

865# ('ErrorCode', ULONG),

866# )

867

868# 3.1.4.5 NspiQueryColumns (Opnum 16)

869 class NspiQueryColumns(NDRCALL):

870 opnum = 16

871 structure = (

872 ('hRpc', handle_t),

873 ('Reserved', DWORD), # flags

874 ('dwFlags', DWORD), # mapiFlags

875 )

876

877 class NspiQueryColumnsResponse(NDRCALL):

878 structure = (

879 ('ppColumns', PPropertyTagArray_r),

880 ('ErrorCode', ULONG),

881 )

882

883# 3.1.4.16 NspiGetNamesFromIDs (Opnum 17)

884 class NspiGetNamesFromIDs(NDRCALL):

885 opnum = 17

886 structure = (

887 ('hRpc', handle_t),

888 ('Reserved', DWORD), # flags

889 ('lpguid', PFlatUID_r),

890 ('pPropTags', PPropertyTagArray_r),

891 )

892

893 class NspiGetNamesFromIDsResponse(NDRCALL):

894 structure = (

895 ('ppReturnedPropTags', PPropertyTagArray_r),

896 ('ppNames', PPropertyNameSet_r),

897 ('ErrorCode', ULONG),

898 )

899

900# 3.1.4.17 NspiGetIDsFromNames (Opnum 18)

901 class PropertyName_r_ARRAY(NDRUniConformantVaryingArray):

902 item = PropertyName_r

903

904 class NspiGetIDsFromNames(NDRCALL):

905 opnum = 18

906 structure = (

907 ('hRpc', handle_t),

908 ('Reserved', DWORD), # flags

909 ('dwFlags', DWORD), # mapiFlags

910 ('cPropNames', DWORD),

911 ('pNames', PropertyName_r_ARRAY),

912 )

913

914 class NspiGetIDsFromNamesResponse(NDRCALL):

915 structure = (

916 ('ppPropTags', PPropertyTagArray_r),

917 ('ErrorCode', ULONG),

918 )

919

920# 3.1.4.18 NspiResolveNames (Opnum 19)

921 class NspiResolveNames(NDRCALL):

922 opnum = 19

923 structure = (

924 ('hRpc', handle_t),

925 ('Reserved', DWORD), # flags

926 ('pStat', STAT),

927 ('pPropTags', PPropertyTagArray_r),

928 ('paStr', StringsArray_r),

929 )

930

931 class NspiResolveNamesResponse(NDRCALL):

932 structure = (

933 ('ppMIds', PPropertyTagArray_r),

934 ('ppRows', PPropertyRowSet_r),

935 ('ErrorCode', ULONG),

936 )

937

938# 3.1.4.19 NspiResolveNamesW (Opnum 20)

939 class NspiResolveNamesW(NDRCALL):

940 opnum = 20

941 structure = (

942 ('hRpc', handle_t),

943 ('Reserved', DWORD), # flags

944 ('pStat', STAT),

945 ('pPropTags', PPropertyTagArray_r),

946 ('paStr', WStringsArray_r),

947 )

948

949 class NspiResolveNamesWResponse(NDRCALL):

950 structure = (

951 ('ppMIds', PPropertyTagArray_r),

952 ('ppRows', PPropertyRowSet_r),

953 ('ErrorCode', ULONG),

954 )

955

956################################################################################

957# OPNUMs and their corresponding structures

958################################################################################

959 OPNUMS = {

960 0 : (NspiBind, NspiBindResponse),

961 1 : (NspiUnbind, NspiUnbindResponse),

962 2 : (NspiUpdateStat, NspiUpdateStatResponse),

963 3 : (NspiQueryRows, NspiQueryRowsResponse),

964 4 : (NspiSeekEntries, NspiSeekEntriesResponse),

965# 5 : (NspiGetMatches, NspiGetMatchesResponse),

966# 6 : (NspiResortRestriction, NspiResortRestrictionResponse),

967 7 : (NspiDNToMId, NspiDNToMIdResponse),

968 8 : (NspiGetPropList, NspiGetPropListResponse),

969 9 : (NspiGetProps, NspiGetPropsResponse),

970 10 : (NspiCompareMIds, NspiCompareMIdsResponse),

971# 11 : (NspiModProps, NspiModPropsResponse),

972 12 : (NspiGetSpecialTable, NspiGetSpecialTableResponse),

973 13 : (NspiGetTemplateInfo, NspiGetTemplateInfoResponse),

974 14 : (NspiModLinkAtt, NspiModLinkAttResponse),

975# 15 : (NspiDeleteEntries, NspiDeleteEntriesResponse),

976 16 : (NspiQueryColumns, NspiQueryColumnsResponse),

977 17 : (NspiGetNamesFromIDs, NspiGetNamesFromIDsResponse),

978 18 : (NspiGetIDsFromNames, NspiGetIDsFromNamesResponse),

979 19 : (NspiResolveNames, NspiResolveNamesResponse),

980 20 : (NspiResolveNamesW, NspiResolveNamesWResponse),

981}

982

983################################################################################

984# HELPER FUNCTIONS

985################################################################################

986 def checkNullString(string):

987 if string == NULL:

988 return string

989

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

991 return string + '\x00'

992 else:

993 return string

994

995 def get_guid_from_dn(legacyDN):

996 legacyDN = str(legacyDN)

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

998

999 return uuid.string_to_bin(guid)

1000

1001 def get_dn_from_guid(guid, minimize=False):

1002 if minimize:

1003 # MS-OXNSPI

1004 dn_template = "/guid="

1005 else:

1006 # MS-NSPI and MS-OXNSPI

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

1008

1009 guid_bin = string_to_bin(guid)

1010

1011 if PY2:

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

1013 else:

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

1015

1016 class EXCH_SID(LDAP_SID):

1017 def __str__(self):

1018 return self.formatCanonical()

1019

1020 class ExchBinaryObject(bytes):

1021 pass

1022

1023 def getUnixTime(t):

1024 t -= 116444736000000000

1025 t //= 10000000

1026 return t

1027

1028 def simplifyPropertyRow(rowSetElem):

1029 row = {}

1030

1031 for prop in rowSetElem['lpProps']:

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

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

1034

1035 PropTag = prop['ulPropTag']

1036

1037 if isinstance(prop_value, SHORT) or \

1038 isinstance(prop_value, USHORT) or \

1039 isinstance(prop_value, LONG) or \

1040 isinstance(prop_value, ULONG):

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

1042 elif isinstance(prop_value, LPWSTR):

1043 if PropTag in [0x8c38001f]:

1044 # What is this field for?

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

1046 else:

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

1048 elif isinstance(prop_value, LPSTR):

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

1050 elif isinstance(prop_value, Binary_r):

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

1052

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

1054 value = EXCH_SID(value)

1055 elif PropTag == 0x300b0102:

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

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

1058 value = PermanentEntryID(value)

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

1060 value = EphemeralEntryID(value)

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

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

1063 elif PropTag == 0x0ff60102:

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

1065 else:

1066 value = ExchBinaryObject(value)

1067

1068 row[PropTag] = value

1069 elif isinstance(prop_value, BinaryArray_r):

1070 array = []

1071 for value in prop_value['lpbin']:

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

1073 row[PropTag] = array

1074 elif isinstance(prop_value, StringArray_r):

1075 array = []

1076 for value in prop_value['lppszA']:

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

1078 row[PropTag] = array

1079 elif isinstance(prop_value, WStringArray_r):

1080 array = []

1081 for value in prop_value['lppszW']:

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

1083 row[PropTag] = array

1084 elif isinstance(prop_value, FILETIME):

1085 row[PropTag] = datetime.fromtimestamp( \

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

1087 else:

1088 row[PropTag] = prop_value

1089

1090 return row

1091

1092 def simplifyPropertyRowSet(propertyRowSet):

1093 ret = []

1094

1095 for rowSet in propertyRowSet['aRow']:

1096 ret.append(simplifyPropertyRow(rowSet))

1097

1098 return ret

1099

1100 def hNspiBind(dce, pStat=None):

1101 request = NspiBind()

1102

1103 if pStat == None:

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

1105 else:

1106 request['pStat'] = pStat

1107

1108 resp = dce.request(request)

1109 return resp

1110

1111 def hNspiUnbind(dce, handler):

1112 request = NspiUnbind()

1113 request['contextHandle'] = handler

1114

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

1116 return resp

1117

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

1119 request = NspiUpdateStat()

1120 request['hRpc'] = handler

1121 request['pStat'] = pStat

1122 request['plDelta'] = plDelta

1123

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

1125 return resp

1126

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

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

1129 request = NspiQueryRows()

1130 request['hRpc'] = handler

1131 request['dwFlags'] = dwFlags

1132 request['Count'] = Count

1133

1134 if pStat == None:

1135 request['pStat']['ContainerID'] = ContainerID

1136 else:

1137 request['pStat'] = pStat

1138

1139 if len(pPropTags) > 0:

1140 for aulPropTag in pPropTags:

1141 prop = DWORD()

1142 prop['Data'] = aulPropTag

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

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

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

1146 else:

1147 request['pPropTags'] = pPropTagsRaw

1148

1149 if len(lpETable) > 0:

1150 for mID in lpETable:

1151 elem = DWORD()

1152 elem['Data'] = mID

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

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

1155 else:

1156 request['lpETable'] = NULL

1157 request['dwETableCount'] = 0

1158

1159 resp = dce.request(request)

1160 return resp

1161

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

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

1164 request = NspiSeekEntries()

1165 request['hRpc'] = handler

1166 request['pStat']['ContainerID'] = ContainerID

1167

1168 # MS-OXNSPI 3.1.4.1.9.9

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

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

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

1172

1173 # MS-OXNSPI 3.1.4.1.9.10

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

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

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

1177 # GeneralFailure.

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

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

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

1181

1182 if len(lpETable) > 0:

1183 for mID in lpETable:

1184 elem = DWORD()

1185 elem['Data'] = mID

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

1187 else:

1188 request['lpETable'] = lpETableRaw

1189

1190 if len(pPropTags) > 0:

1191 for aulPropTag in pPropTags:

1192 prop = DWORD()

1193 prop['Data'] = aulPropTag

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

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

1196 else:

1197 request['pPropTags'] = pPropTagsRaw

1198

1199 resp = dce.request(request)

1200 return resp

1201

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

1203 request = NspiDNToMId()

1204 request['hRpc'] = handler

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

1206

1207 for name in pNames:

1208 lpstr = LPSTR()

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

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

1211

1212 resp = dce.request(request)

1213 return resp

1214

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

1216 request = NspiGetPropList()

1217 request['hRpc'] = handler

1218 request['dwMId'] = dwMId

1219 request['dwFlags'] = dwFlags

1220 request['CodePage'] = CodePage

1221 resp = dce.request(request)

1222

1223 return resp

1224

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

1226 request = NspiGetProps()

1227 request['hRpc'] = handler

1228 request['dwFlags'] = dwFlags

1229

1230 request['pStat']['CurrentRec'] = CurrentRec

1231 request['pStat']['ContainerID'] = ContainerID

1232 request['pStat']['CodePage'] = CodePage

1233

1234 for aulPropTag in pPropTags:

1235 prop = DWORD()

1236 prop['Data'] = aulPropTag

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

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

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

1240

1241 resp = dce.request(request)

1242 return resp

1243

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

1245 request = NspiGetSpecialTable()

1246 request['hRpc'] = handler

1247 request['dwFlags'] = dwFlags

1248 request['pStat'] = pStat

1249 request['lpVersion'] = lpVersion

1250

1251 resp = dce.request(request)

1252 return resp

1253

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

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

1256 request = NspiGetTemplateInfo()

1257 request['hRpc'] = handler

1258 request['dwFlags'] = dwFlags

1259 request['ulType'] = ulType

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

1261 request['dwCodePage'] = dwCodePage

1262 request['dwLocaleID'] = dwLocaleID

1263

1264 resp = dce.request(request)

1265 return resp

1266

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

1268 request = NspiModLinkAtt()

1269 request['hRpc'] = handler

1270 request['dwFlags'] = dwFlags

1271 request['ulPropTag'] = ulPropTag

1272 request['dwMId'] = dwMId

1273

1274 for lpEntryId in lpEntryIds:

1275 prop = Binary_r()

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

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

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

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

1280

1281 resp = dce.request(request)

1282 return resp

1283

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

1285 request = NspiQueryColumns()

1286 request['hRpc'] = handler

1287 request['dwFlags'] = dwFlags

1288

1289 resp = dce.request(request)

1290 return resp

1291

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

1293 request = NspiGetNamesFromIDs()

1294 request['hRpc'] = handler

1295 request['lpguid'] = lpguid

1296

1297 if len(pPropTags) > 0:

1298 for aulPropTag in pPropTags:

1299 prop = DWORD()

1300 prop['Data'] = aulPropTag

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

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

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

1304 elif pPropTagsRaw == NULL:

1305 request.fields['pPropTags'] = NULL

1306 else:

1307 request['pPropTags'] = pPropTagsRaw

1308

1309 resp = dce.request(request)

1310 return resp

1311

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

1313 request = NspiResolveNames()

1314 request['hRpc'] = handler

1315 request['pStat']['ContainerID'] = ContainerID

1316

1317 if len(pPropTags) > 0:

1318 for aulPropTag in pPropTags:

1319 prop = DWORD()

1320 prop['Data'] = aulPropTag

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

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

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

1324 elif pPropTagsRaw == NULL:

1325 request.fields['pPropTags'] = NULL

1326 else:

1327 request['pPropTags'] = pPropTagsRaw

1328

1329 if len(paStr) > 0:

1330 for paStrElem in paStr:

1331 value = LPSTR()

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

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

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

1335

1336 resp = dce.request(request)

1337 return resp

1338

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

1340 request = NspiResolveNamesW()

1341 request['hRpc'] = handler

1342 request['pStat']['ContainerID'] = ContainerID

1343

1344 if len(pPropTags) > 0:

1345 for aulPropTag in pPropTags:

1346 prop = DWORD()

1347 prop['Data'] = aulPropTag

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

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

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

1351 elif pPropTagsRaw == NULL:

1352 request.fields['pPropTags'] = NULL

1353 else:

1354 request['pPropTags'] = pPropTagsRaw

1355

1356 if len(paStr) > 0:

1357 for paStrElem in paStr:

1358 value = LPWSTR()

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

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

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

1362

1363 resp = dce.request(request)

1364 return resp