Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2514 lines
54 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. util.cxx
  5. Abstract:
  6. Utility routines
  7. Author:
  8. Cliff Van Dyke (cliffv) 11-Apr-2001
  9. --*/
  10. #include "pch.hxx"
  11. #include <dispex.h>
  12. #if DBG
  13. //
  14. // List of all allocated blocks
  15. // AccessSerialized by AzGlAllocatorCritSect
  16. LIST_ENTRY AzGlAllocatedBlocks;
  17. SAFE_CRITICAL_SECTION AzGlAllocatorCritSect;
  18. //
  19. // Force C++ to use our allocator
  20. //
  21. void * __cdecl operator new(size_t s) {
  22. return AzpAllocateHeap( s, "UTILNEW" );
  23. }
  24. void __cdecl operator delete(void *pv) {
  25. AzpFreeHeap( pv );
  26. }
  27. #endif // DBG
  28. DWORD
  29. AzpGetCurrentToken(
  30. OUT PHANDLE hToken
  31. )
  32. /*++
  33. Routine Description
  34. Returns the effective token on the thread.
  35. Arguments
  36. hToken - To return the handle to the effective token.
  37. Return Value
  38. DWORD error value.
  39. --*/
  40. {
  41. DWORD WinStatus;
  42. //
  43. // First open the thread token.
  44. //
  45. if ( OpenThreadToken(
  46. GetCurrentThread(),
  47. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  48. TRUE,
  49. hToken ) ) {
  50. return NO_ERROR;
  51. }
  52. WinStatus = GetLastError();
  53. //
  54. // If we failed because of any error other than thread not impersonating,
  55. // give up and return the error.
  56. //
  57. if ( WinStatus != ERROR_NO_TOKEN ) {
  58. return WinStatus;
  59. }
  60. //
  61. // We are not impersonating. Open the process token instead.
  62. //
  63. if ( OpenProcessToken(
  64. GetCurrentProcess(),
  65. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  66. hToken ) ) {
  67. return NO_ERROR;
  68. }
  69. return GetLastError();
  70. }
  71. DWORD
  72. AzpChangeSinglePrivilege(
  73. IN DWORD PrivilegeValue,
  74. IN HANDLE hToken,
  75. IN PTOKEN_PRIVILEGES NewPrivilegeState,
  76. OUT PTOKEN_PRIVILEGES OldPrivilegeState OPTIONAL
  77. )
  78. /*++
  79. Routine Description
  80. This routine has two functions:
  81. 1. Enable a given privilege and return the Old state of the privilege in
  82. the token.
  83. 2. Revert back to the original state once the operation for which we had
  84. enabled the privilege has been performed.
  85. Arguments
  86. PrivilegeValue - The privilege to enable. This is ignored when
  87. OldPrivilegesState is NULL.
  88. hToken - Token to adjust.
  89. NewPrivilegeState - The new value for the privilege.
  90. OldPrivilegeState - Buffer to hold the Old privilege state. The size of this
  91. is assumed to be sizeof(TOKEN_PRIVILEGES) and is sufficient to hold the
  92. Old state since we are only adjusting a single privilege.
  93. When this is NULL, we are reverting.
  94. Return Value
  95. Returns a pointer to the allocated memory.
  96. NULL - Not enough memory
  97. --*/
  98. {
  99. DWORD BufferSize = 0;
  100. //
  101. // When there is no Old state, we enable the privilege supplied.
  102. // When there is Old state we set it back.
  103. //
  104. if ( ARGUMENT_PRESENT( OldPrivilegeState ) ) {
  105. NewPrivilegeState->PrivilegeCount = 1;
  106. NewPrivilegeState->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  107. NewPrivilegeState->Privileges[0].Luid = RtlConvertLongToLuid( PrivilegeValue );
  108. } else if ( NewPrivilegeState->PrivilegeCount == 0) {
  109. return NO_ERROR;
  110. }
  111. //
  112. // Adjust the token to change the privilege state.
  113. //
  114. AdjustTokenPrivileges (
  115. hToken,
  116. FALSE,
  117. NewPrivilegeState,
  118. sizeof(TOKEN_PRIVILEGES),
  119. OldPrivilegeState,
  120. &BufferSize );
  121. return GetLastError();
  122. }
  123. PVOID
  124. AzpAllocateHeap(
  125. IN SIZE_T Size,
  126. IN LPSTR pDescr OPTIONAL
  127. )
  128. /*++
  129. Routine Description
  130. Memory allocator. The pDescr field is ignored for Free builds
  131. Arguments
  132. Size - Size (in bytes) to allocate
  133. pDescr - Optional string identifying the block of not more than 8 chars.
  134. Return Value
  135. Returns a pointer to the allocated memory.
  136. NULL - Not enough memory
  137. --*/
  138. {
  139. DBG_UNREFERENCED_PARAMETER( pDescr ); //ignore
  140. #if DBG
  141. ULONG HeaderSize;
  142. ULONG DescrSize = sizeof(DWORD) * 2;
  143. PLIST_ENTRY RealBlock;
  144. HeaderSize = ROUND_UP_COUNT( sizeof(LIST_ENTRY) + DescrSize,
  145. ALIGN_WORST );
  146. //
  147. // Allocate a block with a header
  148. //
  149. RealBlock = (PLIST_ENTRY) LocalAlloc( 0, HeaderSize + Size );
  150. if ( RealBlock == NULL ) {
  151. return NULL;
  152. }
  153. //
  154. // Link the block since we're nosey.
  155. //
  156. ASSERT( pDescr != NULL );
  157. RtlZeroMemory( ((LPBYTE)RealBlock)+sizeof(LIST_ENTRY), DescrSize );
  158. if ( pDescr != NULL ) {
  159. memcpy( ((LPBYTE)RealBlock)+sizeof(LIST_ENTRY),
  160. (LPBYTE)pDescr,
  161. DescrSize
  162. );
  163. }
  164. SafeEnterCriticalSection( &AzGlAllocatorCritSect );
  165. InsertHeadList( &AzGlAllocatedBlocks, RealBlock );
  166. SafeLeaveCriticalSection( &AzGlAllocatorCritSect );
  167. return (PVOID)(((LPBYTE)RealBlock)+HeaderSize);
  168. #else // DBG
  169. return LocalAlloc( 0, Size );
  170. #endif // DBG
  171. }
  172. PVOID
  173. AzpAllocateHeapSafe(
  174. IN SIZE_T Size
  175. )
  176. /*++
  177. Routine Description:
  178. Memory allocator for SafeAlloca. Calls
  179. AzpAllocateHeap in return
  180. Arguments:
  181. Size - Size of block to be allocated
  182. Return Values:
  183. Returns a pointer to the allocated memory.
  184. NULL - Not enough memory
  185. --*/
  186. {
  187. return AzpAllocateHeap( Size, "UTILSAFE" );
  188. }
  189. VOID
  190. AzpFreeHeap(
  191. IN PVOID Buffer
  192. )
  193. /*++
  194. Routine Description
  195. Memory de-allocator.
  196. Arguments
  197. Buffer - address of buffer to free
  198. Return Value
  199. None
  200. --*/
  201. {
  202. if ( Buffer == NULL ) {
  203. return;
  204. }
  205. #if DBG
  206. ULONG HeaderSize;
  207. ULONG DescrSize = sizeof(DWORD) * 2;
  208. PLIST_ENTRY RealBlock;
  209. HeaderSize = ROUND_UP_COUNT( sizeof(LIST_ENTRY) + DescrSize,
  210. ALIGN_WORST );
  211. RealBlock = (PLIST_ENTRY)(((LPBYTE)Buffer)-HeaderSize);
  212. SafeEnterCriticalSection( &AzGlAllocatorCritSect );
  213. RemoveEntryList( RealBlock );
  214. SafeLeaveCriticalSection( &AzGlAllocatorCritSect );
  215. LocalFree( RealBlock );
  216. #else // DBG
  217. LocalFree( Buffer );
  218. #endif // DBG
  219. }
  220. PVOID
  221. AzpAvlAllocate(
  222. IN PRTL_GENERIC_TABLE Table,
  223. IN CLONG ByteSize
  224. )
  225. /*++
  226. Routine Description:
  227. This routine will allocate space to hold an entry in a generic AVL table.
  228. Arguments:
  229. IN PRTL_GENERIC_TABLE Table - Supplies the table to allocate entries for.
  230. IN CLONG ByteSize - Supplies the number of bytes to allocate for the entry.
  231. Return Value:
  232. None.
  233. --*/
  234. {
  235. return AzpAllocateHeap( ByteSize, "UTILAVL" );
  236. UNREFERENCED_PARAMETER(Table);
  237. }
  238. VOID
  239. AzpAvlFree(
  240. IN PRTL_GENERIC_TABLE Table,
  241. IN PVOID Buffer
  242. )
  243. /*++
  244. Routine Description:
  245. This routine will free an entry in a AVL generic table
  246. Arguments:
  247. IN PRTL_GENERIC_TABLE Table - Supplies the table to allocate entries for.
  248. IN PVOID Buffer - Supplies the buffer to free.
  249. Return Value:
  250. None.
  251. --*/
  252. {
  253. AzpFreeHeap( Buffer );
  254. UNREFERENCED_PARAMETER(Table);
  255. }
  256. VOID
  257. AzpInitString(
  258. OUT PAZP_STRING AzpString,
  259. IN LPCWSTR String OPTIONAL
  260. )
  261. /*++
  262. Routine Description
  263. Initialize our private string structure to point to a passed in string.
  264. Arguments
  265. AzpString - Initialized string
  266. String - zero terminated string to be reference
  267. If NULL, AzpString will be initialized to empty.
  268. Return Value
  269. None
  270. --*/
  271. {
  272. //
  273. // Initialization
  274. //
  275. if ( String == NULL ) {
  276. AzpString->String = NULL;
  277. AzpString->StringSize = 0;
  278. } else {
  279. AzpString->String = (LPWSTR)String;
  280. AzpString->StringSize = (ULONG) ((wcslen(String)+1)*sizeof(WCHAR));
  281. }
  282. AzpString->IsSid = FALSE;
  283. }
  284. DWORD
  285. AzpCaptureString(
  286. OUT PAZP_STRING AzpString,
  287. IN LPCWSTR String,
  288. IN ULONG MaximumLength,
  289. IN BOOLEAN NullOk
  290. )
  291. /*++
  292. Routine Description
  293. Capture the passed in string.
  294. Arguments
  295. AzpString - Captured copy of the passed in string.
  296. On success, string must be freed using AzpFreeString
  297. String - zero terminated string to capture
  298. MaximumLength - Maximum length of the string (in characters).
  299. NullOk - if TRUE, a NULL string or zero length string is OK.
  300. pDescr - An optional description string
  301. Return Value
  302. NO_ERROR - The operation was successful
  303. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  304. Other exception status codes
  305. --*/
  306. {
  307. ULONG WinStatus;
  308. ULONG StringSize;
  309. //
  310. // Initialization
  311. //
  312. AzpInitString( AzpString, NULL );
  313. if ( String == NULL ) {
  314. if ( !NullOk ) {
  315. AzPrint(( AZD_INVPARM, "AzpCaptureString: NULL not ok\n" ));
  316. return ERROR_INVALID_PARAMETER;
  317. }
  318. return NO_ERROR;
  319. }
  320. __try {
  321. //
  322. // Validate a passed in LPWSTR
  323. //
  324. ULONG StringLength;
  325. StringLength = (ULONG) wcslen( String );
  326. if ( StringLength == 0 ) {
  327. if ( !NullOk ) {
  328. AzPrint(( AZD_INVPARM, "AzpCaptureString: zero length not ok\n" ));
  329. return ERROR_INVALID_PARAMETER;
  330. }
  331. return NO_ERROR;
  332. }
  333. if ( StringLength > MaximumLength ) {
  334. AzPrint(( AZD_INVPARM, "AzpCaptureString: string too long %ld %ld %ws\n", StringLength, MaximumLength, String ));
  335. return ERROR_INVALID_PARAMETER;
  336. }
  337. StringSize = (StringLength+1)*sizeof(WCHAR);
  338. //
  339. // Allocate and copy the string
  340. //
  341. AzpString->String = (LPWSTR) AzpAllocateHeap( StringSize, "UTILSTR" );
  342. if ( AzpString->String == NULL ) {
  343. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  344. } else {
  345. RtlCopyMemory( AzpString->String,
  346. String,
  347. StringSize );
  348. AzpString->StringSize = StringSize;
  349. AzpString->IsSid = FALSE;
  350. WinStatus = NO_ERROR;
  351. }
  352. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  353. WinStatus = RtlNtStatusToDosError( GetExceptionCode());
  354. AzpFreeString( AzpString );
  355. }
  356. return WinStatus;
  357. }
  358. VOID
  359. AzpInitSid(
  360. OUT PAZP_STRING AzpString,
  361. IN PSID Sid
  362. )
  363. /*++
  364. Routine Description
  365. Initialize an AZ_STRING structure to point to a sid
  366. Arguments
  367. AzpString - String structure to initialize
  368. Sid - Sid to capture
  369. Return Value
  370. None
  371. --*/
  372. {
  373. // Initialization
  374. //
  375. AzpString->String = (LPWSTR)Sid;
  376. AzpString->StringSize = RtlLengthSid( Sid );
  377. AzpString->IsSid = TRUE;
  378. }
  379. DWORD
  380. AzpCaptureSid(
  381. OUT PAZP_STRING AzpString,
  382. IN PSID Sid
  383. )
  384. /*++
  385. Routine Description
  386. Capture the passed in SID
  387. Arguments
  388. AzpString - Captured copy of the passed in sid.
  389. On success, string must be freed using AzpFreeString
  390. Sid - Sid to capture
  391. Return Value
  392. NO_ERROR - The operation was successful
  393. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  394. Other exception status codes
  395. --*/
  396. {
  397. ULONG WinStatus;
  398. ULONG StringSize;
  399. //
  400. // Initialization
  401. //
  402. AzpInitString( AzpString, NULL );
  403. __try {
  404. //
  405. // Validate a passed in SID
  406. //
  407. if ( !RtlValidSid( Sid ) ) {
  408. AzPrint(( AZD_INVPARM, "AzpCaptureString: SID not valid\n" ));
  409. return ERROR_INVALID_PARAMETER;
  410. }
  411. StringSize = RtlLengthSid( Sid );
  412. //
  413. // Allocate and copy the SID
  414. //
  415. AzpString->String = (LPWSTR) AzpAllocateHeap( StringSize, "UTILSID" );
  416. if ( AzpString->String == NULL ) {
  417. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  418. } else {
  419. RtlCopyMemory( AzpString->String,
  420. Sid,
  421. StringSize );
  422. AzpString->StringSize = StringSize;
  423. AzpString->IsSid = TRUE;
  424. WinStatus = NO_ERROR;
  425. }
  426. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  427. WinStatus = RtlNtStatusToDosError( GetExceptionCode());
  428. AzpFreeString( AzpString );
  429. }
  430. return WinStatus;
  431. }
  432. DWORD
  433. AzpCaptureLong(
  434. IN PVOID PropertyValue,
  435. OUT PLONG UlongValue
  436. )
  437. /*++
  438. Routine Description
  439. Support routine for the SetProperty API.
  440. Capture a parameter for the user application.
  441. Arguments
  442. PropertyValue - Specifies a pointer to the property.
  443. UlongValue - Value to return to make a copy of.
  444. Return Value
  445. NO_ERROR - The operation was successful
  446. Other exception status codes
  447. --*/
  448. {
  449. DWORD WinStatus;
  450. __try {
  451. *UlongValue = *(PULONG)PropertyValue;
  452. WinStatus = NO_ERROR;
  453. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  454. WinStatus = RtlNtStatusToDosError( GetExceptionCode());
  455. }
  456. return WinStatus;
  457. }
  458. DWORD
  459. AzpDuplicateString(
  460. OUT PAZP_STRING AzpOutString,
  461. IN PAZP_STRING AzpInString
  462. )
  463. /*++
  464. Routine Description
  465. Make a duplicate of the passed in string
  466. Arguments
  467. AzpOutString - Returns a copy of the passed in string.
  468. On success, string must be freed using AzpFreeString.
  469. AzpInString - Specifies a string to make a copy of.
  470. Return Value
  471. NO_ERROR - The operation was successful
  472. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  473. --*/
  474. {
  475. ULONG WinStatus;
  476. //
  477. // Initialization
  478. //
  479. AzpInitString( AzpOutString, NULL );
  480. //
  481. // Handle an empty string
  482. //
  483. if ( AzpInString->StringSize == 0 || AzpInString->String == NULL ) {
  484. WinStatus = NO_ERROR;
  485. //
  486. // Allocate and copy the string
  487. //
  488. } else {
  489. AzpOutString->String = (LPWSTR) AzpAllocateHeap( AzpInString->StringSize, "UTILDUP" );
  490. if ( AzpOutString->String == NULL ) {
  491. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  492. } else {
  493. RtlCopyMemory( AzpOutString->String,
  494. AzpInString->String,
  495. AzpInString->StringSize );
  496. AzpOutString->StringSize = AzpInString->StringSize;
  497. AzpOutString->IsSid = AzpInString->IsSid;
  498. WinStatus = NO_ERROR;
  499. }
  500. }
  501. return WinStatus;
  502. }
  503. BOOL
  504. AzpEqualStrings(
  505. IN PAZP_STRING AzpString1,
  506. IN PAZP_STRING AzpString2
  507. )
  508. /*++
  509. Routine Description
  510. Does a case insensitive comparison of two strings
  511. Arguments
  512. AzpString1 - First string to compare
  513. AzpString2 - Second string to compare
  514. Return Value
  515. TRUE: the strings are equal
  516. FALSE: the strings are not equal
  517. --*/
  518. {
  519. //
  520. // Simply compare the strings
  521. //
  522. return (AzpCompareStrings( AzpString1, AzpString2 ) == CSTR_EQUAL);
  523. }
  524. LONG
  525. AzpCompareSidWorker(
  526. IN PSID Sid1,
  527. IN ULONG Sid1Size,
  528. IN PSID Sid2,
  529. IN ULONG Sid2Size
  530. )
  531. /*++
  532. Routine description:
  533. SID comparison routine for non-equality
  534. Arguments:
  535. Sid1 - First Sid to compare
  536. Sid1Size - Size (in bytes) of Sid1
  537. Sid2 - Second Sid to compare
  538. Sid2Size - Size (in bytes) of Sid2
  539. Returns:
  540. CSTR_LESS_THAN: String 1 is less than string 2
  541. CSTR_EQUAL: String 1 is equal to string 2
  542. CSTR_GREATER_THAN: String 1 is greater than string 2
  543. this is the same code as RtlEqualSid, except it returns
  544. CSTR_*
  545. --*/
  546. {
  547. LONG Result;
  548. ULONG i;
  549. ASSERT( Sid1 && RtlValidSid( (PSID)(Sid1) ));
  550. ASSERT( Sid2 && RtlValidSid( (PSID)(Sid2) ));
  551. //
  552. // First compare lengths
  553. //
  554. if ( Sid1Size < Sid2Size ) {
  555. return CSTR_LESS_THAN;
  556. }
  557. if ( Sid1Size > Sid2Size ) {
  558. return CSTR_GREATER_THAN;
  559. }
  560. //
  561. // Compare the individual bytes
  562. //
  563. ASSERT( (Sid1Size % 4) == 0 );
  564. Result = CSTR_EQUAL;
  565. for ( i = 0; i < (Sid1Size/4); i++ ) {
  566. const ULONG& b1 = ((PULONG)Sid1)[i];
  567. const ULONG& b2 = ((PULONG)Sid2)[i];
  568. if ( b1 == b2 ) {
  569. continue;
  570. } else if ( b1 < b2 ) {
  571. Result = CSTR_LESS_THAN;
  572. } else {
  573. Result = CSTR_GREATER_THAN;
  574. }
  575. break;
  576. }
  577. return Result;
  578. }
  579. LONG
  580. AzpCompareSid(
  581. IN PSID Sid1,
  582. IN PSID Sid2
  583. )
  584. /*++
  585. Routine description:
  586. SID comparison routine for non-equality
  587. Arguments:
  588. Sid1 - First Sid to compare
  589. Sid2 - Second Sid to compare
  590. Returns:
  591. CSTR_LESS_THAN: String 1 is less than string 2
  592. CSTR_EQUAL: String 1 is equal to string 2
  593. CSTR_GREATER_THAN: String 1 is greater than string 2
  594. this is the same code as RtlEqualSid, except it returns
  595. CSTR_*
  596. --*/
  597. {
  598. //
  599. // Call the worker routine
  600. //
  601. return AzpCompareSidWorker(
  602. Sid1,
  603. RtlLengthSid(Sid1),
  604. Sid2,
  605. RtlLengthSid(Sid2) );
  606. }
  607. LONG
  608. AzpCompareSidString(
  609. IN PAZP_STRING AzpString1,
  610. IN PAZP_STRING AzpString2
  611. )
  612. /*++
  613. Routine description:
  614. SID comparison routine for non-equality
  615. Arguments:
  616. AzpString1 - First string to compare
  617. AzpString2 - Second string to compare
  618. Returns:
  619. CSTR_LESS_THAN: String 1 is less than string 2
  620. CSTR_EQUAL: String 1 is equal to string 2
  621. CSTR_GREATER_THAN: String 1 is greater than string 2
  622. this is the same code as RtlEqualSid, except it returns
  623. CSTR_*
  624. --*/
  625. {
  626. //
  627. // Call the worker routine
  628. //
  629. return AzpCompareSidWorker(
  630. AzpString1->String,
  631. AzpString1->StringSize,
  632. AzpString2->String,
  633. AzpString2->StringSize );
  634. }
  635. LONG
  636. AzpCompareStrings(
  637. IN PAZP_STRING AzpString1,
  638. IN PAZP_STRING AzpString2
  639. )
  640. /*++
  641. Routine Description
  642. Does a case insensitive comparison of two strings
  643. Arguments
  644. AzpString1 - First string to compare
  645. AzpString2 - Second string to compare
  646. Return Value
  647. 0: An error ocurred. Call GetLastError();
  648. CSTR_LESS_THAN: String 1 is less than string 2
  649. CSTR_EQUAL: String 1 is equal to string 2
  650. CSTR_GREATER_THAN: String 1 is greater than string 2
  651. --*/
  652. {
  653. LONG Result;
  654. //
  655. // Handle NULL
  656. //
  657. ASSERT( (AzpString1->IsSid && AzpString2->IsSid) || (!AzpString1->IsSid && !AzpString2->IsSid) );
  658. if ( AzpString1->String == NULL ) {
  659. if ( AzpString2->String == NULL ) {
  660. return CSTR_EQUAL;
  661. }else {
  662. return CSTR_LESS_THAN;
  663. }
  664. } else {
  665. if ( AzpString2->String == NULL ) {
  666. return CSTR_GREATER_THAN;
  667. }
  668. }
  669. //
  670. // Compare the sids
  671. //
  672. if ( AzpString1->IsSid ) {
  673. Result = AzpCompareSidString( AzpString1, AzpString2 );
  674. //
  675. // Compare the Unicode strings
  676. // Don't compare the trailing zero character.
  677. // (Some callers pass in strings where the trailing character isn't a zero.)
  678. //
  679. } else {
  680. Result = CompareStringW( LOCALE_SYSTEM_DEFAULT,
  681. NORM_IGNORECASE,
  682. AzpString1->String,
  683. (AzpString1->StringSize/sizeof(WCHAR))-1,
  684. AzpString2->String,
  685. (AzpString2->StringSize/sizeof(WCHAR))-1 );
  686. }
  687. return Result;
  688. }
  689. VOID
  690. AzpSwapStrings(
  691. IN OUT PAZP_STRING AzpString1,
  692. IN OUT PAZP_STRING AzpString2
  693. )
  694. /*++
  695. Routine Description
  696. Swap two strings
  697. Arguments
  698. AzpString1 - First string to swap
  699. AzpString2 - Second string to swap
  700. Return Value
  701. None
  702. --*/
  703. {
  704. AZP_STRING TempString;
  705. TempString = *AzpString1;
  706. *AzpString1 = *AzpString2;
  707. *AzpString2 = TempString;
  708. }
  709. VOID
  710. AzpFreeString(
  711. IN PAZP_STRING AzpString
  712. )
  713. /*++
  714. Routine Description
  715. Free the specified string
  716. Arguments
  717. AzpString - String to be freed.
  718. pDescr - An optional description string
  719. Return Value
  720. None
  721. --*/
  722. {
  723. if ( AzpString->String != NULL ) {
  724. AzpFreeHeap( AzpString->String );
  725. }
  726. AzpInitString( AzpString, NULL );
  727. }
  728. BOOLEAN
  729. AzpBsearchPtr (
  730. IN PAZP_PTR_ARRAY AzpPtrArray,
  731. IN PVOID Key,
  732. IN LONG (*Compare)(const void *, const void *),
  733. OUT PULONG InsertionPoint OPTIONAL
  734. )
  735. /*++
  736. Routine Description:
  737. This routine does a binary search on the array of pointers
  738. Code stolen from the libc bsearch() routine
  739. Arguments:
  740. AzpPtrArray - Array that the pointer will be searched for
  741. Key - Pointer to be searched for
  742. Compare - Pointer to a routine to do the comparison. Routine returns
  743. CSTR_LESS_THAN: String 1 is less than string 2
  744. CSTR_EQUAL: String 1 is equal to string 2
  745. CSTR_GREATER_THAN: String 1 is greater than string 2
  746. InsertionPoint - On FALSE, returns the point where one would insert the named object.
  747. On TRUE, returns an index to the object.
  748. Return Value:
  749. TRUE - Object was found
  750. FALSE - Object was not found
  751. --*/
  752. {
  753. LONG lo = 0;
  754. LONG num = AzpPtrArray->UsedCount;
  755. LONG hi = num - 1;
  756. LONG mid;
  757. LONG half;
  758. LONG result;
  759. LONG TempInsertionPoint = 0;
  760. while (lo <= hi) {
  761. ASSERT( num == hi-lo+1 );
  762. // Handle more than one element left
  763. half = num / 2;
  764. if ( half ) {
  765. // Compare key to element in the middle of the array left
  766. mid = lo + (num & 1 ? half : (half - 1));
  767. result = (*Compare)( Key, AzpPtrArray->Array[mid] );
  768. // We lucked out and hit it right on the nose
  769. if ( result == CSTR_EQUAL ) {
  770. *InsertionPoint = mid;
  771. return TRUE;
  772. // Key is in the first half
  773. } else if ( result == CSTR_LESS_THAN ) {
  774. hi = mid - 1;
  775. num = num & 1 ? half : half-1;
  776. TempInsertionPoint = mid;
  777. // Key is in the second half
  778. } else {
  779. lo = mid+1;
  780. num = half;
  781. TempInsertionPoint = mid+1;
  782. }
  783. // Handle exactly one element left
  784. } else if (num) {
  785. ASSERT( hi == lo );
  786. ASSERT( num == 1 );
  787. result = (*Compare)( Key, AzpPtrArray->Array[lo] );
  788. if ( result == CSTR_EQUAL ) {
  789. *InsertionPoint = lo;
  790. return TRUE;
  791. } else if ( result == CSTR_LESS_THAN ) {
  792. TempInsertionPoint = lo;
  793. break;
  794. } else {
  795. TempInsertionPoint = lo+1;
  796. break;
  797. }
  798. // Handle exactly zero elements left
  799. } else {
  800. break;
  801. }
  802. }
  803. *InsertionPoint = TempInsertionPoint;
  804. return FALSE;
  805. }
  806. DWORD
  807. AzpAddPtr(
  808. IN PAZP_PTR_ARRAY AzpPtrArray,
  809. IN PVOID Pointer,
  810. IN ULONG Index
  811. )
  812. /*++
  813. Routine Description
  814. Inserts a pointer into the array of pointers.
  815. The array will be automatically expanded to be large enough to contain the new pointer.
  816. All existing pointers from slot # 'Index' through the end of the existing array will
  817. be shifted to later slots.
  818. Arguments
  819. AzpPtrArray - Array that the pointer will be inserted into.
  820. Pointer - Pointer to be inserted.
  821. Index - Index into the array where the 'Pointer' will be inserted
  822. If Index is larger than the current size of the array or AZP_ADD_ENDOFLIST,
  823. 'Pointer' will be inserted after the existing elements of the array.
  824. Return Value
  825. NO_ERROR - The operation was successful
  826. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  827. --*/
  828. {
  829. //
  830. // Ensure Index isn't too large
  831. //
  832. if ( Index > AzpPtrArray->UsedCount ) {
  833. Index = AzpPtrArray->UsedCount;
  834. }
  835. //
  836. // If the array isn't large enough, make it bigger
  837. //
  838. if ( AzpPtrArray->UsedCount >= AzpPtrArray->AllocatedCount ) {
  839. PVOID *TempArray;
  840. //
  841. // Allocate a new array
  842. //
  843. TempArray = (PVOID *) AzpAllocateHeap(
  844. (AzpPtrArray->AllocatedCount + AZP_PTR_ARRAY_INCREMENT) * sizeof(PVOID),
  845. "UTILADD" );
  846. if ( TempArray == NULL ) {
  847. return ERROR_NOT_ENOUGH_MEMORY;
  848. }
  849. //
  850. // Copy the data into the new array and free the old array
  851. //
  852. if ( AzpPtrArray->Array != NULL ) {
  853. RtlCopyMemory( TempArray,
  854. AzpPtrArray->Array,
  855. AzpPtrArray->AllocatedCount * sizeof(PVOID) );
  856. AzpFreeHeap( AzpPtrArray->Array );
  857. AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: Free old array\n", AzpPtrArray, AzpPtrArray->Array ));
  858. }
  859. //
  860. // Grab the pointer to the new array and clear the new part of the array
  861. //
  862. AzpPtrArray->Array = TempArray;
  863. AzPrint(( AZD_OBJLIST, "0x%lx: 0x%lx: Allocate array\n", AzpPtrArray, AzpPtrArray->Array ));
  864. RtlZeroMemory( &TempArray[AzpPtrArray->UsedCount],
  865. AZP_PTR_ARRAY_INCREMENT * sizeof(PVOID) );
  866. AzpPtrArray->AllocatedCount += AZP_PTR_ARRAY_INCREMENT;
  867. }
  868. //
  869. // Shift any old data
  870. //
  871. if ( Index != AzpPtrArray->UsedCount ) {
  872. RtlMoveMemory( &(AzpPtrArray->Array[Index+1]),
  873. &(AzpPtrArray->Array[Index]),
  874. (AzpPtrArray->UsedCount-Index) * sizeof(PVOID) );
  875. }
  876. //
  877. // Insert the new element
  878. //
  879. AzpPtrArray->Array[Index] = Pointer;
  880. AzpPtrArray->UsedCount ++;
  881. return NO_ERROR;
  882. }
  883. VOID
  884. AzpRemovePtrByIndex(
  885. IN PAZP_PTR_ARRAY AzpPtrArray,
  886. IN ULONG Index
  887. )
  888. /*++
  889. Routine Description
  890. Remove a pointer from the array of pointers.
  891. All existing pointers from slot # 'Index' through the end of the existing array will
  892. be shifted to earlier slots.
  893. Arguments
  894. AzpPtrArray - Array that the pointer will be removed into.
  895. Index - Index into the array where the 'Pointer' will be removed from.
  896. Return Value
  897. None
  898. --*/
  899. {
  900. //
  901. // Ensure Index isn't too large
  902. //
  903. ASSERT( Index < AzpPtrArray->UsedCount );
  904. //
  905. // Shift any old data
  906. //
  907. if ( Index+1 != AzpPtrArray->UsedCount ) {
  908. RtlMoveMemory( &(AzpPtrArray->Array[Index]),
  909. &(AzpPtrArray->Array[Index+1]),
  910. (AzpPtrArray->UsedCount-Index-1) * sizeof(PVOID) );
  911. }
  912. //
  913. // Clear the last element
  914. //
  915. AzpPtrArray->UsedCount--;
  916. AzpPtrArray->Array[AzpPtrArray->UsedCount] = NULL;
  917. }
  918. VOID
  919. AzpRemovePtrByPtr(
  920. IN PAZP_PTR_ARRAY AzpPtrArray,
  921. IN PVOID Pointer
  922. )
  923. /*++
  924. Routine Description
  925. Removes a pointer from the array of pointers.
  926. All existing pointers following the specified pointer will
  927. be shifted to earlier slots.
  928. Arguments
  929. AzpPtrArray - Array that the pointer will be removed into.
  930. Pointer - Pointer to be removed
  931. Return Value
  932. None
  933. --*/
  934. {
  935. ULONG i;
  936. BOOLEAN FoundIt = FALSE;
  937. for ( i=0; i<AzpPtrArray->UsedCount; i++ ) {
  938. if ( Pointer == AzpPtrArray->Array[i] ) {
  939. AzpRemovePtrByIndex( AzpPtrArray, i );
  940. FoundIt = TRUE;
  941. break;
  942. }
  943. }
  944. ASSERT( FoundIt );
  945. }
  946. PVOID
  947. AzpGetStringProperty(
  948. IN PAZP_STRING AzpString
  949. )
  950. /*++
  951. Routine Description
  952. Support routine for the GetProperty API. Convert an AzpString to the form
  953. supported by GetProperty.
  954. Empty string are returned as Zero length string instead of NULL
  955. Arguments
  956. AzpString - Specifies a string to make a copy of.
  957. Return Value
  958. Pointer to allocated string.
  959. String should be freed using AzFreeMemory.
  960. NULL - Not enough memory was available to allocate the string
  961. --*/
  962. {
  963. LPWSTR String;
  964. ULONG AllocatedSize;
  965. //
  966. // Allocate and copy the string
  967. //
  968. AllocatedSize = AzpString->StringSize ? AzpString->StringSize : (ULONG)sizeof(WCHAR);
  969. String = (LPWSTR) AzpAllocateHeap( AllocatedSize, "UTILGSTR" );
  970. if ( String != NULL ) {
  971. //
  972. // Convert NULL strings to zero length strings
  973. //
  974. if ( AzpString->StringSize == 0 ) {
  975. *String = L'\0';
  976. } else {
  977. RtlCopyMemory( String,
  978. AzpString->String,
  979. AzpString->StringSize );
  980. }
  981. }
  982. return String;
  983. }
  984. PVOID
  985. AzpGetUlongProperty(
  986. IN ULONG UlongValue
  987. )
  988. /*++
  989. Routine Description
  990. Support routine for the GetProperty API. Convert a ULONG to the form
  991. supported by GetProperty.
  992. Arguments
  993. UlongValue - Value to return to make a copy of.
  994. Return Value
  995. Pointer to allocated string.
  996. String should be freed using AzFreeMemory.
  997. NULL - Not enough memory was available to allocate the string
  998. --*/
  999. {
  1000. PULONG RetValue;
  1001. //
  1002. // Allocate and copy the string
  1003. //
  1004. RetValue = (PULONG) AzpAllocateHeap( sizeof(ULONG), "UTILGLNG" );
  1005. if ( RetValue != NULL ) {
  1006. *RetValue = UlongValue;
  1007. }
  1008. return RetValue;
  1009. }
  1010. BOOLEAN
  1011. AzpTimeHasElapsed(
  1012. IN PLARGE_INTEGER StartTime,
  1013. IN DWORD Timeout
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. Determine if "Timeout" milliseconds has has elapsed since StartTime.
  1018. Arguments:
  1019. StartTime - Specifies an absolute time when the event started (100ns units).
  1020. Timeout - Specifies a relative time in milliseconds. 0xFFFFFFFF indicates
  1021. that the time will never expire.
  1022. Return Value:
  1023. TRUE -- iff Timeout milliseconds have elapsed since StartTime.
  1024. --*/
  1025. {
  1026. LARGE_INTEGER TimeNow;
  1027. LARGE_INTEGER ElapsedTime;
  1028. LARGE_INTEGER Period;
  1029. //
  1030. // If the period to too large to handle (i.e., 0xffffffff is forever),
  1031. // just indicate that the timer has not expired.
  1032. //
  1033. // (0xffffffff is a little over 48 days).
  1034. //
  1035. if ( Timeout == 0xffffffff ) {
  1036. return FALSE;
  1037. }
  1038. //
  1039. // Compute the elapsed time since we last authenticated
  1040. //
  1041. GetSystemTimeAsFileTime( (PFILETIME)&TimeNow );
  1042. ElapsedTime.QuadPart = TimeNow.QuadPart - StartTime->QuadPart;
  1043. //
  1044. // Compute Period from milliseconds into 100ns units.
  1045. //
  1046. Period.QuadPart = UInt32x32To64( Timeout, 10000 );
  1047. //
  1048. // If the elapsed time is negative (totally bogus) or greater than the
  1049. // maximum allowed, indicate that enough time has passed.
  1050. //
  1051. if ( ElapsedTime.QuadPart < 0 || ElapsedTime.QuadPart > Period.QuadPart ) {
  1052. return TRUE;
  1053. }
  1054. return FALSE;
  1055. }
  1056. DWORD
  1057. AzpHresultToWinStatus(
  1058. HRESULT hr
  1059. )
  1060. /*++
  1061. Routine Description
  1062. Convert an Hresult to a WIN 32 status code
  1063. Arguments
  1064. hr - Hresult to convert
  1065. Return Value
  1066. --*/
  1067. {
  1068. DWORD WinStatus = ERROR_INTERNAL_ERROR;
  1069. //
  1070. // Success is still success
  1071. //
  1072. if ( hr == NO_ERROR ) {
  1073. WinStatus = NO_ERROR;
  1074. //
  1075. // If the facility is WIN32,
  1076. // the translation is easy.
  1077. //
  1078. } else if ((HRESULT_FACILITY(hr) == FACILITY_WIN32) && (FAILED(hr))) {
  1079. WinStatus = HRESULT_CODE(hr);
  1080. if ( WinStatus == ERROR_SUCCESS ) {
  1081. WinStatus = ERROR_INTERNAL_ERROR;
  1082. }
  1083. //
  1084. // All others should be left intact
  1085. //
  1086. } else {
  1087. WinStatus = hr;
  1088. }
  1089. return WinStatus;
  1090. }
  1091. DWORD
  1092. AzpSafeArrayPointerFromVariant(
  1093. IN VARIANT* Variant,
  1094. IN BOOLEAN NullOk,
  1095. OUT SAFEARRAY **retSafeArray
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. This routine takes a pointer to a variant and returns a pointer to a SafeArray.
  1100. Any levels of VT_BYREF are skipped.
  1101. This routine also requires that the array be unidimensional and be an array of variants.
  1102. VBScript has two syntaxes for calling dispinterfaces:
  1103. 1. obj.Method (arg)
  1104. 2. obj.Method arg
  1105. The first syntax will pass arg by value, which our dispinterfaces will
  1106. be able to handle. If Method takes a BSTR argument, the VARIANT that
  1107. arrives at Method will be of type VT_BSTR.
  1108. The second syntax will pass arg by reference. In this case Method will
  1109. receive a VARIANT of type (VT_VARIANT | VT_BYREF). The VARIANT that is
  1110. referenced will be of type VT_BSTR.
  1111. This function will canoicalizes the two cases.
  1112. Optionally, VT_EMPTY, VT_NULL and VT_ERROR variants are allowed.
  1113. Arguments:
  1114. Variant - Variant to check
  1115. NullOk - TRUE if VT_EMPTY, VT_NULL and VT_ERROR variants are to be allowed. If TRUE,
  1116. and Variant is such a null variant, the retSafeArray returns a NULL pointer.
  1117. retSafeArray - Returns a pointer to the SafeArray.
  1118. Return Value:
  1119. NO_ERROR - The function was successful
  1120. ERROR_INVALID_PARAMETER - The parameter is invalid
  1121. --*/
  1122. {
  1123. SAFEARRAY *SafeArray;
  1124. VARTYPE Vartype;
  1125. HRESULT hr;
  1126. //
  1127. // Skip over any pointers to variant.
  1128. //
  1129. *retSafeArray = NULL;
  1130. while ((Variant != NULL) && (V_VT(Variant) == (VT_VARIANT | VT_BYREF))) {
  1131. Variant = V_VARIANTREF(Variant);
  1132. }
  1133. //
  1134. // If null parameters are OK,
  1135. // allow them
  1136. //
  1137. // EMPTY is uninitialized
  1138. // NULL is explicitly null
  1139. // ERROR is unspecified optional parameter
  1140. //
  1141. if ( Variant == NULL || V_VT(Variant) == VT_EMPTY || V_VT(Variant) == VT_NULL || V_VT(Variant) == VT_ERROR ) {
  1142. return NullOk ? NO_ERROR : ERROR_INVALID_PARAMETER;
  1143. }
  1144. //
  1145. // Ensure this is an array.
  1146. //
  1147. if ( !V_ISARRAY(Variant) ) {
  1148. AzPrint(( AZD_INVPARM, "AzpSafeArrayPointerFromVariant: parameter is not an array 0x%lx.\n", V_VT(Variant) ));
  1149. return ERROR_INVALID_PARAMETER;
  1150. }
  1151. //
  1152. // Get the pointer to the safe array
  1153. //
  1154. if ( V_ISBYREF( Variant) ) {
  1155. SafeArray = *(SAFEARRAY **)V_BYREF( Variant );
  1156. } else {
  1157. SafeArray = V_ARRAY( Variant );
  1158. }
  1159. //
  1160. // Handle NULL safe array
  1161. //
  1162. if ( SafeArray == NULL ) {
  1163. return NullOk ? NO_ERROR : ERROR_INVALID_PARAMETER;
  1164. }
  1165. //
  1166. // Array must have one dimension
  1167. //
  1168. if ( SafeArrayGetDim( SafeArray ) != 1 ) {
  1169. AzPrint(( AZD_INVPARM, "AzpSafeArrayPointerFromVariant: Array %lx isn't single dimension array\n", SafeArrayGetDim( SafeArray ) ));
  1170. return ERROR_INVALID_PARAMETER;
  1171. }
  1172. //
  1173. // The type of the values array must be variant
  1174. //
  1175. hr = SafeArrayGetVartype( SafeArray, &Vartype );
  1176. if ( FAILED(hr) || Vartype != VT_VARIANT ) {
  1177. AzPrint(( AZD_INVPARM, "AzpSafeArrayPointerFromVariant: Array isn't array of VARIANT 0x%lx %lx\n", hr, Vartype ));
  1178. return ERROR_INVALID_PARAMETER;
  1179. }
  1180. *retSafeArray = SafeArray;
  1181. return NO_ERROR;
  1182. }
  1183. DWORD
  1184. AzpConvertAbsoluteSDToSelfRelative(
  1185. IN PSECURITY_DESCRIPTOR pAbsoluteSD,
  1186. OUT PSECURITY_DESCRIPTOR *ppSelfRelativeSD
  1187. )
  1188. /*++
  1189. Routine Description:
  1190. This routine returns a self-relative SD for a passed
  1191. in absolute form SD. The returned SD needs to be freed using
  1192. LocalFree routine.
  1193. Arguments:
  1194. pAbsoluteSD - Passed in absolute form SD
  1195. ppSelfRelativeSD - Returned self-relative form SD
  1196. Return Values:
  1197. NO_ERROR - The self-relative form SD was created successfully
  1198. Other status codes
  1199. --*/
  1200. {
  1201. DWORD WinStatus = 0;
  1202. DWORD dSelfRelativeSDLen = 0;
  1203. //
  1204. // Figure out the size needed for the self relatiVe SD
  1205. //
  1206. if ( !MakeSelfRelativeSD(
  1207. pAbsoluteSD,
  1208. NULL,
  1209. &dSelfRelativeSDLen
  1210. ) ) {
  1211. WinStatus = GetLastError();
  1212. if ( WinStatus == ERROR_INSUFFICIENT_BUFFER ) {
  1213. WinStatus = NO_ERROR;
  1214. //
  1215. // The required length is returned on insufficient buffer failure
  1216. //
  1217. *ppSelfRelativeSD = (PSECURITY_DESCRIPTOR) AzpAllocateHeap( dSelfRelativeSDLen, "UTILSD2" );
  1218. if ( *ppSelfRelativeSD == NULL ) {
  1219. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1220. goto Cleanup;
  1221. }
  1222. if ( !MakeSelfRelativeSD(
  1223. pAbsoluteSD,
  1224. *ppSelfRelativeSD,
  1225. &dSelfRelativeSDLen
  1226. ) ) {
  1227. WinStatus = GetLastError();
  1228. }
  1229. }
  1230. }
  1231. Cleanup:
  1232. if ( WinStatus != NO_ERROR ) {
  1233. if ( *ppSelfRelativeSD != NULL ) {
  1234. LocalFree( *ppSelfRelativeSD );
  1235. *ppSelfRelativeSD = NULL;
  1236. }
  1237. }
  1238. return WinStatus;
  1239. }
  1240. DWORD
  1241. AzpADSetDefaultLdapOptions (
  1242. IN OUT PLDAP pHandleLdap,
  1243. IN PCWSTR pDomainName OPTIONAL
  1244. )
  1245. /*++
  1246. Routine Description:
  1247. This routine sets our default common ldap binding options.
  1248. Arguments:
  1249. pHandle - a valid (already initialized) LDAP handle
  1250. pDomainName - an optional domain name
  1251. Return Values:
  1252. NO_ERROR if all set correctly.
  1253. Other error status codes in case of errors. These error codes
  1254. have already been converted from ldap error codes to win status codes.
  1255. --*/
  1256. {
  1257. LONG LdapOption = 0;
  1258. ULONG LdapStatus = 0;
  1259. DWORD dwStatus = NO_ERROR;
  1260. //
  1261. // Don't chase referals
  1262. //
  1263. LdapOption = PtrToLong( LDAP_OPT_OFF );
  1264. LdapStatus = ldap_set_option( pHandleLdap,
  1265. LDAP_OPT_REFERRALS,
  1266. &LdapOption );
  1267. if ( LdapStatus != LDAP_SUCCESS ) {
  1268. dwStatus = LdapMapErrorToWin32( LdapStatus );
  1269. AzPrint(( AZD_AD,
  1270. "AzpADSetDefaultLdapOptions: ldap_set_option LDAP_OPT_REFERRALS"
  1271. " failed: %ld\n",
  1272. dwStatus
  1273. ));
  1274. goto Cleanup;
  1275. }
  1276. //
  1277. // Set the option telling LDAP that I passed it an explicit DC name and
  1278. // that it can avoid the DsGetDcName.
  1279. //
  1280. LdapOption = PtrToLong( LDAP_OPT_ON );
  1281. LdapStatus = ldap_set_option( pHandleLdap,
  1282. LDAP_OPT_AREC_EXCLUSIVE,
  1283. &LdapOption );
  1284. if ( LdapStatus != LDAP_SUCCESS ) {
  1285. dwStatus = LdapMapErrorToWin32( LdapStatus );
  1286. AzPrint(( AZD_AD,
  1287. "AzpADSetDefaultLdapOptions: ldap_set_option LDAP_OPT_AREC_EXCLUSIVE"
  1288. " failed: %ld\n",
  1289. dwStatus
  1290. ));
  1291. goto Cleanup;
  1292. }
  1293. //
  1294. // We will encrypt our ldap communication, so turn on the encrypt option
  1295. //
  1296. LdapOption = PtrToLong( LDAP_OPT_ON );
  1297. LdapStatus = ldap_set_option( pHandleLdap,
  1298. LDAP_OPT_ENCRYPT,
  1299. &LdapOption
  1300. );
  1301. if ( LdapStatus != LDAP_SUCCESS ) {
  1302. dwStatus = LdapMapErrorToWin32( LdapStatus );
  1303. AzPrint(( AZD_AD,
  1304. "AzpADSetDefaultLdapOptions: ldap_set_option LDAP_OPT_ENCRYPT"
  1305. " failed: %ld\n",
  1306. dwStatus
  1307. ));
  1308. goto Cleanup;
  1309. }
  1310. if ( pDomainName != NULL ) {
  1311. //
  1312. // We need to set the option to enforce mutual authentication with the DC
  1313. //
  1314. LdapStatus = ldap_set_option( pHandleLdap,
  1315. LDAP_OPT_DNSDOMAIN_NAME,
  1316. &pDomainName
  1317. );
  1318. if ( LdapStatus != LDAP_SUCCESS ) {
  1319. dwStatus = LdapMapErrorToWin32( LdapStatus );
  1320. AzPrint(( AZD_AD,
  1321. "AzpADSetDefaultLdapOptions: ldap_set_option LDAP_OPT_DNSDOMAIN_NAME"
  1322. " failed: %ld\n",
  1323. dwStatus
  1324. ));
  1325. goto Cleanup;
  1326. }
  1327. }
  1328. Cleanup:
  1329. return dwStatus;
  1330. }
  1331. HRESULT AzpGetSafearrayFromArrayObject (
  1332. IN VARIANT varSAorObj,
  1333. OUT SAFEARRAY** ppsaData)
  1334. /*++
  1335. Routine Description:
  1336. This routine converts a JScript style Array object to safearray.
  1337. Arguments:
  1338. varSAorObj - The VARIANT that holds a IDispatchEx object.
  1339. ppsaData - Receives the safearray.
  1340. Return Values:
  1341. Success: S_OK
  1342. Failures: various error code
  1343. Note:
  1344. JScript doesn't use safearrays. Instead, it uses its own intrinsic object
  1345. Array for arrays. For clients that uses such object for arrays, we need
  1346. special handling because our routines expect safearray.
  1347. --*/
  1348. {
  1349. if (ppsaData == NULL)
  1350. {
  1351. return E_POINTER;
  1352. }
  1353. *ppsaData = NULL;
  1354. if (varSAorObj.vt != VT_DISPATCH)
  1355. {
  1356. return E_INVALIDARG;
  1357. }
  1358. CComPtr<IDispatchEx> srpDispEx;
  1359. HRESULT hr = varSAorObj.pdispVal->QueryInterface(IID_IDispatchEx, (void**)&srpDispEx);
  1360. DISPID id = DISPID_STARTENUM;
  1361. //
  1362. // It's sad that we can't use vectors. EH causes compiler errors once we use <vector>
  1363. // So, we have to go two passes. The first is to find the count.
  1364. //
  1365. ULONG uCount = 0;
  1366. while (S_OK == hr)
  1367. {
  1368. hr = srpDispEx->GetNextDispID(fdexEnumAll, id, &id);
  1369. if (S_OK == hr)
  1370. {
  1371. ++uCount;
  1372. }
  1373. }
  1374. //
  1375. // now we know the count, we can create the safearray
  1376. //
  1377. UINT i;
  1378. if (SUCCEEDED(hr))
  1379. {
  1380. SAFEARRAYBOUND rgsaBound[1];
  1381. rgsaBound[0].lLbound = 0; //array index from 0
  1382. rgsaBound[0].cElements = uCount;
  1383. SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsaBound );
  1384. if (psa == NULL)
  1385. {
  1386. hr = E_OUTOFMEMORY;
  1387. }
  1388. else
  1389. {
  1390. long lArrayIndex[1];
  1391. lArrayIndex[0] = 0;
  1392. //
  1393. // put each element into the safearray
  1394. //
  1395. id = DISPID_STARTENUM;
  1396. DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
  1397. for (i = 0; i < uCount; ++i)
  1398. {
  1399. hr = srpDispEx->GetNextDispID(fdexEnumAll, id, &id);
  1400. //
  1401. // GetNextDispID will return S_FALSE when there is no more
  1402. //
  1403. if (S_OK == hr)
  1404. {
  1405. //
  1406. // We have to get the property by invoking the IDispatchEx.
  1407. //
  1408. CComVariant var;
  1409. hr = srpDispEx->Invoke( id,
  1410. IID_NULL,
  1411. LOCALE_USER_DEFAULT,
  1412. DISPATCH_PROPERTYGET,
  1413. &dispparamsNoArgs,
  1414. &var,
  1415. NULL,
  1416. NULL
  1417. );
  1418. if (SUCCEEDED(hr))
  1419. {
  1420. hr = SafeArrayPutElement( psa, lArrayIndex, &var );
  1421. ++(lArrayIndex[0]);
  1422. }
  1423. if (FAILED(hr))
  1424. {
  1425. //
  1426. // This is an error that shouldn't happen.
  1427. //
  1428. AZASSERT(FALSE);
  1429. break;
  1430. }
  1431. }
  1432. else
  1433. {
  1434. //
  1435. // hr may be S_FALSE if no more items are found
  1436. //
  1437. break;
  1438. }
  1439. }
  1440. }
  1441. if (SUCCEEDED(hr))
  1442. {
  1443. *ppsaData = psa;
  1444. }
  1445. else
  1446. {
  1447. SafeArrayDestroy(psa);
  1448. }
  1449. }
  1450. return SUCCEEDED(hr) ? S_OK : hr;
  1451. }
  1452. DWORD
  1453. AzpRetrieveApplicationSequenceNumber(
  1454. IN AZ_HANDLE AzAppHandle
  1455. )
  1456. /*++
  1457. Routine Description:
  1458. This routine returns the sequence number of an AzApplication object
  1459. that can be used to determine if a certain COM handle is valid or not
  1460. after the AzApplication object has been closed
  1461. Arguments:
  1462. AzAppHandle - Handle to the application object whose sequence number needs to
  1463. be retrieved
  1464. Return Values:
  1465. The value of the sequence number
  1466. --*/
  1467. {
  1468. AzpLockResourceShared(&AzGlResource);
  1469. DWORD dwSN = ((PAZP_APPLICATION)AzAppHandle)->AppSequenceNumber;
  1470. AzpUnlockResource(&AzGlResource);
  1471. return dwSN;
  1472. }
  1473. //
  1474. // Debugging support
  1475. //
  1476. #ifdef AZROLESDBG
  1477. #include <stdio.h>
  1478. SAFE_CRITICAL_SECTION AzGlLogFileCritSect;
  1479. ULONG AzGlDbFlag;
  1480. // HANDLE AzGlLogFile;
  1481. #define MAX_PRINTF_LEN 1024 // Arbitrary.
  1482. VOID
  1483. AzpDumpGuid(
  1484. IN DWORD DebugFlag,
  1485. IN GUID *Guid OPTIONAL
  1486. )
  1487. /*++
  1488. Routine Description:
  1489. Dumps a GUID to the debugger output.
  1490. Arguments:
  1491. DebugFlag: Debug flag to pass on to AzPrintRoutine
  1492. Guid: Guid to print
  1493. Return Value:
  1494. none
  1495. --*/
  1496. {
  1497. RPC_STATUS RpcStatus;
  1498. unsigned char *StringGuid;
  1499. //
  1500. // If we aren't debugging this functionality, just return.
  1501. //
  1502. if ( DebugFlag != 0 && (AzGlDbFlag & DebugFlag) == 0 ) {
  1503. return;
  1504. }
  1505. if ( Guid == NULL ) {
  1506. AzPrint(( DebugFlag, "(null)" ));
  1507. } else {
  1508. RpcStatus = UuidToStringA( Guid, &StringGuid );
  1509. if ( RpcStatus != RPC_S_OK ) {
  1510. return;
  1511. }
  1512. AzPrint(( DebugFlag, "%s", StringGuid ));
  1513. RpcStringFreeA( &StringGuid );
  1514. }
  1515. }
  1516. VOID
  1517. AzpDumpGoRef(
  1518. IN LPSTR Text,
  1519. IN struct _GENERIC_OBJECT *GenericObject
  1520. )
  1521. /*++
  1522. Routine Description:
  1523. Dumps the ref count for a generic object
  1524. Arguments:
  1525. Text - Description of why the ref count is changing
  1526. GenericObject - a pointer to the object being ref counted
  1527. Return Value:
  1528. none
  1529. --*/
  1530. {
  1531. LPWSTR StringSid = NULL;
  1532. LPWSTR StringToPrint;
  1533. //
  1534. // If we aren't debugging this functionality, just return.
  1535. //
  1536. if ( (AzGlDbFlag & AZD_REF) == 0 ) {
  1537. return;
  1538. }
  1539. //
  1540. // Convert the sid to a string
  1541. //
  1542. if ( GenericObject->ObjectName == NULL ) {
  1543. StringToPrint = NULL;
  1544. } else if ( GenericObject->ObjectName->ObjectName.IsSid ) {
  1545. if ( ConvertSidToStringSid( (PSID)GenericObject->ObjectName->ObjectName.String, &StringSid)) {
  1546. StringToPrint = StringSid;
  1547. } else {
  1548. StringToPrint = L"<Invalid Sid>";
  1549. }
  1550. } else {
  1551. StringToPrint = GenericObject->ObjectName->ObjectName.String;
  1552. }
  1553. AzPrint(( AZD_REF, "0x%lx %ld (%ld) %ws: %s\n", GenericObject, GenericObject->ObjectType, GenericObject->ReferenceCount, StringToPrint, Text ));
  1554. if ( StringSid != NULL ) {
  1555. LocalFree( StringSid );
  1556. }
  1557. }
  1558. VOID
  1559. AzpPrintRoutineV(
  1560. IN DWORD DebugFlag,
  1561. IN LPSTR Format,
  1562. va_list arglist
  1563. )
  1564. /*++
  1565. Routine Description
  1566. Debug routine for azroles
  1567. Arguments
  1568. DebugFlag - Flag to indicating the functionality being debugged
  1569. --- Other printf parameters
  1570. Return Value
  1571. --*/
  1572. {
  1573. static LPSTR AzGlLogFileOutputBuffer = NULL;
  1574. ULONG length;
  1575. int lengthTmp;
  1576. // DWORD BytesWritten;
  1577. static BeginningOfLine = TRUE;
  1578. static LineCount = 0;
  1579. static TruncateLogFileInProgress = FALSE;
  1580. static LogProblemWarned = FALSE;
  1581. //
  1582. // If we aren't debugging this functionality, just return.
  1583. //
  1584. if ( DebugFlag != 0 && (AzGlDbFlag & DebugFlag) == 0 ) {
  1585. return;
  1586. }
  1587. //
  1588. // Allocate a buffer to build the line in.
  1589. // If there isn't already one.
  1590. //
  1591. length = 0;
  1592. if ( AzGlLogFileOutputBuffer == NULL ) {
  1593. AzGlLogFileOutputBuffer = (LPSTR) LocalAlloc( 0, MAX_PRINTF_LEN + 1 );
  1594. if ( AzGlLogFileOutputBuffer == NULL ) {
  1595. return;
  1596. }
  1597. }
  1598. //
  1599. // Handle the beginning of a new line.
  1600. //
  1601. //
  1602. if ( BeginningOfLine ) {
  1603. //
  1604. // Never print empty lines.
  1605. //
  1606. if ( Format[0] == '\n' && Format[1] == '\0' ) {
  1607. return;
  1608. }
  1609. #if 0
  1610. //
  1611. // If the log file is getting huge,
  1612. // truncate it.
  1613. //
  1614. if ( AzGlLogFile != INVALID_HANDLE_VALUE &&
  1615. !TruncateLogFileInProgress ) {
  1616. //
  1617. // Only check every 50 lines,
  1618. //
  1619. LineCount++;
  1620. if ( LineCount >= 50 ) {
  1621. DWORD FileSize;
  1622. LineCount = 0;
  1623. //
  1624. // Is the log file too big?
  1625. //
  1626. FileSize = GetFileSize( AzGlLogFile, NULL );
  1627. if ( FileSize == 0xFFFFFFFF ) {
  1628. (void) DbgPrint( "[NETLOGON] Cannot GetFileSize %ld\n",
  1629. GetLastError );
  1630. } else if ( FileSize > AzGlParameters.LogFileMaxSize ) {
  1631. TruncateLogFileInProgress = TRUE;
  1632. SafeLeaveCriticalSection( &AzGlLogFileCritSect );
  1633. NlOpenDebugFile( TRUE );
  1634. NlPrint(( NL_MISC,
  1635. "Logfile truncated because it was larger than %ld bytes\n",
  1636. AzGlParameters.LogFileMaxSize ));
  1637. SafeEnterCriticalSection( &AzGlLogFileCritSect );
  1638. TruncateLogFileInProgress = FALSE;
  1639. }
  1640. }
  1641. }
  1642. //
  1643. // If we're writing to the debug terminal,
  1644. // indicate this is a azroles message.
  1645. //
  1646. if ( AzGlLogFile == INVALID_HANDLE_VALUE ) {
  1647. length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length], "[AZROLES] " );
  1648. }
  1649. //
  1650. // Put the timestamp at the begining of the line.
  1651. //
  1652. {
  1653. SYSTEMTIME SystemTime;
  1654. GetLocalTime( &SystemTime );
  1655. length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length],
  1656. "%02u/%02u %02u:%02u:%02u ",
  1657. SystemTime.wMonth,
  1658. SystemTime.wDay,
  1659. SystemTime.wHour,
  1660. SystemTime.wMinute,
  1661. SystemTime.wSecond );
  1662. }
  1663. #endif // 0
  1664. //
  1665. // Indicate the type of message on the line
  1666. //
  1667. {
  1668. char *Text;
  1669. switch (DebugFlag) {
  1670. case AZD_HANDLE:
  1671. Text = "HANDLE"; break;
  1672. case AZD_OBJLIST:
  1673. Text = "OBJLIST"; break;
  1674. case AZD_INVPARM:
  1675. Text = "INVPARM"; break;
  1676. case AZD_PERSIST:
  1677. case AZD_PERSIST_MORE:
  1678. Text = "PERSIST"; break;
  1679. case AZD_REF:
  1680. Text = "OBJREF"; break;
  1681. case AZD_DISPATCH:
  1682. Text = "DISPATCH"; break;
  1683. case AZD_ACCESS:
  1684. case AZD_ACCESS_MORE:
  1685. Text = "ACCESS"; break;
  1686. case AZD_DOMREF:
  1687. Text = "DOMREF"; break;
  1688. case AZD_XML:
  1689. Text = "XML"; break;
  1690. case AZD_AD:
  1691. Text = "AD"; break;
  1692. case AZD_SCRIPT:
  1693. case AZD_SCRIPT_MORE:
  1694. Text = "SCRIPT"; break;
  1695. case AZD_CRITICAL:
  1696. Text = "CRITICAL"; break;
  1697. default:
  1698. Text = "UNKNOWN"; break;
  1699. case 0:
  1700. Text = NULL;
  1701. }
  1702. if ( Text != NULL ) {
  1703. length += (ULONG) sprintf( &AzGlLogFileOutputBuffer[length], "[%s] ", Text );
  1704. }
  1705. }
  1706. }
  1707. //
  1708. // Put a the information requested by the caller onto the line
  1709. //
  1710. lengthTmp = (ULONG) _vsnprintf( &AzGlLogFileOutputBuffer[length],
  1711. MAX_PRINTF_LEN - length - 1,
  1712. Format,
  1713. arglist );
  1714. if ( lengthTmp < 0 ) {
  1715. length = MAX_PRINTF_LEN - 1;
  1716. // always end the line which cannot fit into the buffer
  1717. AzGlLogFileOutputBuffer[length-1] = '\n';
  1718. } else {
  1719. length += lengthTmp;
  1720. }
  1721. BeginningOfLine = (length > 0 && AzGlLogFileOutputBuffer[length-1] == '\n' );
  1722. if ( BeginningOfLine ) {
  1723. AzGlLogFileOutputBuffer[length-1] = '\r';
  1724. AzGlLogFileOutputBuffer[length] = '\n';
  1725. AzGlLogFileOutputBuffer[length+1] = '\0';
  1726. length++;
  1727. }
  1728. #if 0
  1729. //
  1730. // If the log file isn't open,
  1731. // just output to the debug terminal
  1732. //
  1733. if ( AzGlLogFile == INVALID_HANDLE_VALUE ) {
  1734. #if DBG
  1735. if ( !LogProblemWarned ) {
  1736. (void) DbgPrint( "[NETLOGON] Cannot write to log file [Invalid Handle]\n" );
  1737. LogProblemWarned = TRUE;
  1738. }
  1739. #endif // DBG
  1740. //
  1741. // Write the debug info to the log file.
  1742. //
  1743. } else {
  1744. if ( !WriteFile( AzGlLogFile,
  1745. AzGlLogFileOutputBuffer,
  1746. length,
  1747. &BytesWritten,
  1748. NULL ) ) {
  1749. #if DBG
  1750. if ( !LogProblemWarned ) {
  1751. (void) DbgPrint( "[NETLOGON] Cannot write to log file %ld\n", GetLastError() );
  1752. LogProblemWarned = TRUE;
  1753. }
  1754. #endif // DBG
  1755. }
  1756. }
  1757. #else // 0
  1758. printf( "%s", AzGlLogFileOutputBuffer );
  1759. #endif // 0
  1760. }
  1761. VOID
  1762. AzpPrintRoutine(
  1763. IN DWORD DebugFlag,
  1764. IN LPSTR Format,
  1765. ...
  1766. )
  1767. {
  1768. va_list arglist;
  1769. //
  1770. // vsprintf isn't multithreaded + we don't want to intermingle output
  1771. // from different threads.
  1772. //
  1773. SafeEnterCriticalSection( &AzGlLogFileCritSect );
  1774. //
  1775. // Simply change arguments to va_list form and call NlPrintRoutineV
  1776. //
  1777. va_start(arglist, Format);
  1778. AzpPrintRoutineV( DebugFlag, Format, arglist );
  1779. va_end(arglist);
  1780. SafeLeaveCriticalSection( &AzGlLogFileCritSect );
  1781. } // AzPrintRoutine
  1782. #endif // AZROLESDBG