Source code of Windows XP (NT5)
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.

1187 lines
29 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. sample.cxx
  5. Abstract:
  6. This file implements a sample peristance provider.
  7. This sample does not address buffer overflows, puts large buffers on the stack, etc.
  8. Caveat Emptor.
  9. Author:
  10. Cliff Van Dyke (cliffv) 9-May-2001
  11. --*/
  12. #include "pch.hxx"
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. //
  16. // Local Storage
  17. //
  18. // Each provider is given a single PVOID on the AZP_ADMIN_MANAGER structure.
  19. // That PVOID is a pointer to whatever context the provider needs to maintain a
  20. // description of the local storage.
  21. //
  22. // The structure below is that context for the sample provider.
  23. //
  24. typedef struct _AZP_SAMPLE_CONTEXT {
  25. //
  26. // Handle to the file
  27. //
  28. HANDLE FileHandle;
  29. //
  30. // The next GUID to assign to an object
  31. // ??? A real provider would allocate a real GUID
  32. //
  33. ULONG LastUsedGuid;
  34. } AZP_SAMPLE_CONTEXT, *PAZP_SAMPLE_CONTEXT;
  35. //
  36. // Table of object type to text string mappings
  37. //
  38. LPWSTR ObjectTypeNames[] = {
  39. L"[ROOT]",
  40. L"[ADMIN_MANAGER]",
  41. L"[APPLICATION]",
  42. L"[OPERATION]",
  43. L"[TASK]",
  44. L"[SCOPE]",
  45. L"[GROUP]",
  46. L"[ROLE]",
  47. L"[JUNCTION_POINT]",
  48. L"[SID]" };
  49. #define ObjectTypeNamesSize (sizeof(ObjectTypeNames)/sizeof(ObjectTypeNames[0]))
  50. //
  51. // Delimiter between names
  52. //
  53. #define SAMPLE_DELIM L"-->"
  54. #define SAMPLE_DELIM_SIZE (sizeof(SAMPLE_DELIM)-sizeof(WCHAR))
  55. //
  56. // Define a buffer large enough for an object name
  57. //
  58. #define HUGE_BUFFER_SIZE (70000*sizeof(WCHAR))
  59. DWORD
  60. SampleReadFile(
  61. IN LPWSTR FileName,
  62. IN BOOL CreatePolicy,
  63. OUT HANDLE *RetFileHandle,
  64. OUT LPBYTE *RetBuffer,
  65. OUT PULONG RetBufferSize
  66. )
  67. /*++
  68. Routine Description:
  69. This routine read the policy file into a buffer.
  70. Arguments:
  71. FileName - Name of the file containing the policy
  72. CreatePolicy - TRUE if the policy database is to be created.
  73. FALSE if the policy database already exists
  74. RetFileHandle - Returns a handle to the open file.
  75. The caller should close this file by calling CloseHandle.
  76. RetBuffer - Returns a pointer to a buffer containing the contents of the file
  77. The caller should free this buffer by calling AzpFreeHeap.
  78. RetBufferSize - Size (in bytes) of RetBuffer
  79. Return Value:
  80. Status of the operation
  81. --*/
  82. {
  83. DWORD WinStatus;
  84. HANDLE FileHandle;
  85. LPBYTE Buffer = NULL;
  86. ULONG BufferSize = 0;;
  87. ULONG BytesRead;
  88. //
  89. // Open the file
  90. //
  91. *RetFileHandle = INVALID_HANDLE_VALUE;
  92. *RetBuffer = NULL;
  93. *RetBufferSize = 0;
  94. FileHandle = CreateFileW( FileName,
  95. GENERIC_READ|GENERIC_WRITE,
  96. FILE_SHARE_READ|FILE_SHARE_WRITE,
  97. NULL,
  98. CreatePolicy ? CREATE_NEW : OPEN_EXISTING,
  99. FILE_ATTRIBUTE_NORMAL,
  100. NULL );
  101. if ( FileHandle == INVALID_HANDLE_VALUE ) {
  102. WinStatus = GetLastError();
  103. AzPrint(( AZD_PERSIST, "SampleReadFile: Cannot CreateFile %ld\n", WinStatus ));
  104. goto Cleanup;
  105. }
  106. //
  107. // Allocate a buffer to read the file into
  108. //
  109. BufferSize = GetFileSize( FileHandle, NULL );
  110. if ( BufferSize == 0xFFFFFFFF ) {
  111. WinStatus = GetLastError();
  112. AzPrint(( AZD_PERSIST, "SampleReadFile: Cannot GetFileSize %ld\n", WinStatus ));
  113. goto Cleanup;
  114. }
  115. Buffer = (LPBYTE) AzpAllocateHeap( BufferSize + sizeof(WCHAR) );
  116. if ( Buffer == NULL ) {
  117. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  118. goto Cleanup;
  119. }
  120. if ( BufferSize == 0 ) {
  121. *(LPWSTR)Buffer = '\0';
  122. WinStatus = NO_ERROR;
  123. goto Cleanup;
  124. }
  125. //
  126. // Read the file into the buffer
  127. //
  128. if ( !ReadFile( FileHandle,
  129. Buffer,
  130. BufferSize,
  131. &BytesRead,
  132. NULL ) ) { // Not Overlapped
  133. WinStatus = GetLastError();
  134. AzPrint(( AZD_PERSIST, "SampleReadFile: Cannot ReadFile %ld\n", WinStatus ));
  135. goto Cleanup;
  136. }
  137. if ( BytesRead != BufferSize ) {
  138. WinStatus = ERROR_INTERNAL_DB_CORRUPTION;
  139. AzPrint(( AZD_PERSIST, "SampleReadFile: Cannot ReadFile right size %ld\n", WinStatus ));
  140. goto Cleanup;
  141. }
  142. WinStatus = NO_ERROR;
  143. //
  144. // Return the information to the caller
  145. //
  146. Cleanup:
  147. if ( WinStatus == NO_ERROR ) {
  148. *RetFileHandle = FileHandle;
  149. *RetBuffer = Buffer;
  150. Buffer = NULL;
  151. *RetBufferSize = BufferSize;
  152. }
  153. //
  154. // Free locally used resources
  155. //
  156. if ( Buffer != NULL ) {
  157. AzpFreeHeap( Buffer );
  158. }
  159. return WinStatus;
  160. }
  161. BOOL
  162. SampleGetALine(
  163. IN OUT LPWSTR * LinePointer,
  164. OUT PULONG RetLevel,
  165. OUT PULONG RetObjectType,
  166. OUT PULONG Guid,
  167. OUT LPWSTR FullNameBuffer,
  168. OUT LPWSTR *Name
  169. )
  170. /*++
  171. Routine Description:
  172. This routine gets the next line from a buffer containing the policy file.
  173. Arguments:
  174. LinePointer - On input, points to the address of the line to read.
  175. On output, points to the next line.
  176. RetLevel - Returns the parent/child "generation" level of the current line.
  177. 0 is AdminManager itself. Children of AdminManager are 1. etc.
  178. RetObjectType - Returns the object type of the line
  179. Guid - Returns the GUID of the object
  180. FullNameBuffer - Returns the full parent/child name of the object. (e.g.
  181. AppName->ScopeName->RoleName) Pass in a huge buffer here.
  182. Name - Returns a pointer into FullNameBuffer of the last component name.
  183. (e.g., a pointer to RoleName in the sample above)
  184. Return Value:
  185. TRUE: Line was valid
  186. FALSE: EOF
  187. --*/
  188. {
  189. BOOL RetVal;
  190. LPWSTR Line = *LinePointer;
  191. LPWSTR Next = NULL;
  192. WCHAR *p;
  193. LONG Level = 0;
  194. ULONG ObjectTypeLength;
  195. LPWSTR ObjectTypeString;
  196. ULONG ObjectType = 0;
  197. ULONG ObjectNameLength;
  198. LPWSTR ObjectNameString;
  199. //
  200. // Get a pointer to the next line of the file
  201. //
  202. Next = wcschr( Line, '\n' );
  203. if ( Next == NULL ) {
  204. RetVal = FALSE;
  205. goto Cleanup;
  206. }
  207. Next ++;
  208. p = Line;
  209. //
  210. // Parse off the "Guid"
  211. //
  212. *Guid = wcstoul( p, &p, 10 );
  213. if ( *Guid == 0 ) {
  214. AzPrint(( AZD_PERSIST, "SampleGetALine: No Guid on line %ws\n", Line ));
  215. RetVal = FALSE;
  216. goto Cleanup;
  217. }
  218. // Skip over the space
  219. p++;
  220. //
  221. // Parse off the object name
  222. //
  223. ObjectNameString = p;
  224. ObjectNameLength = wcscspn( p, L"[\n" );
  225. if ( ObjectNameLength == 0 || ObjectNameLength == 1 ) {
  226. AzPrint(( AZD_PERSIST, "SampleGetALine: No object name on line %ws\n", Line ));
  227. RetVal = FALSE;
  228. goto Cleanup;
  229. }
  230. ObjectNameLength--;
  231. if ( ObjectNameString[ObjectNameLength] != ' ' ) {
  232. AzPrint(( AZD_PERSIST, "SampleGetALine: object name not blank terminated on line %ws\n", Line ));
  233. RetVal = FALSE;
  234. goto Cleanup;
  235. }
  236. RtlCopyMemory( FullNameBuffer, ObjectNameString, ObjectNameLength*sizeof(WCHAR) );
  237. FullNameBuffer[ObjectNameLength] = '\0';
  238. p = &p[ObjectNameLength+1];
  239. //
  240. // Parse off the object type string
  241. //
  242. ObjectTypeString = p;
  243. ObjectTypeLength = wcscspn( p, L" \n" );
  244. if ( ObjectTypeLength == 0 ) {
  245. AzPrint(( AZD_PERSIST, "SampleGetALine: No object type on line %ws\n", Line ));
  246. RetVal = FALSE;
  247. goto Cleanup;
  248. }
  249. p = &p[ObjectTypeLength+1];
  250. //
  251. // Convert the string to a number
  252. //
  253. for ( ObjectType = 0; ObjectType < ObjectTypeNamesSize; ObjectType++ ) {
  254. if ( wcsncmp( ObjectTypeString, ObjectTypeNames[ObjectType], ObjectTypeLength ) == 0 ) {
  255. break;
  256. }
  257. }
  258. if ( ObjectType >= ObjectTypeNamesSize ) {
  259. AzPrint(( AZD_PERSIST, "SampleGetALine: Bad object type %ws\n", Line ));
  260. RetVal = FALSE;
  261. goto Cleanup;
  262. }
  263. //
  264. // Determine the level of this entry
  265. //
  266. Level = 1; // AdminManager is level 0
  267. p = FullNameBuffer;
  268. *Name = p;
  269. for (;;) {
  270. p = wcsstr(p, SAMPLE_DELIM );
  271. if ( p == NULL ) {
  272. break;
  273. }
  274. p += SAMPLE_DELIM_SIZE/sizeof(WCHAR);
  275. Level ++;
  276. *Name = p;
  277. }
  278. RetVal = TRUE;
  279. //
  280. // Free locally used resources
  281. //
  282. Cleanup:
  283. *RetObjectType = ObjectType;
  284. *RetLevel = Level;
  285. *LinePointer = Next;
  286. return RetVal;
  287. }
  288. DWORD
  289. SamplePersistOpen(
  290. IN PAZP_ADMIN_MANAGER AdminManager,
  291. IN BOOL CreatePolicy
  292. )
  293. /*++
  294. Routine Description:
  295. This routine submits reads the authz policy database from storage.
  296. This routine also reads the policy database into cache.
  297. On Success, the caller should call SamplePersistClose to free any resources
  298. consumed by the open.
  299. On entry, AzGlResource must be locked exclusive.
  300. Arguments:
  301. AdminManager - Specifies the policy database that is to be read.
  302. CreatePolicy - TRUE if the policy database is to be created.
  303. FALSE if the policy database already exists
  304. Return Value:
  305. NO_ERROR - The operation was successful
  306. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  307. Other status codes
  308. --*/
  309. {
  310. DWORD WinStatus;
  311. PAZP_SAMPLE_CONTEXT PersistContext = NULL;
  312. LPWSTR Line;
  313. LPWSTR Next;
  314. LPBYTE Buffer = NULL;
  315. ULONG BufferSize;
  316. ULONG Level;
  317. ULONG CurrentLevel = 0;
  318. PGENERIC_OBJECT GenericObjectStack[8];
  319. LPWSTR BigBuffer = NULL;
  320. //
  321. // Initialization
  322. //
  323. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  324. RtlZeroMemory( &GenericObjectStack[0], sizeof(GenericObjectStack) );
  325. GenericObjectStack[0] = (PGENERIC_OBJECT) AdminManager;
  326. SafeAllocaAllocate( BigBuffer, HUGE_BUFFER_SIZE );
  327. if ( BigBuffer == NULL ) {
  328. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  329. goto Cleanup;
  330. }
  331. //
  332. // Allocate a context describing this provider
  333. //
  334. PersistContext = (PAZP_SAMPLE_CONTEXT) AzpAllocateHeap( sizeof(*PersistContext) );
  335. if ( PersistContext == NULL ) {
  336. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  337. goto Cleanup;
  338. }
  339. PersistContext->LastUsedGuid = 0;
  340. //
  341. // Read the file into a buffer
  342. //
  343. WinStatus = SampleReadFile( AdminManager->PolicyUrl.String,
  344. CreatePolicy,
  345. &PersistContext->FileHandle,
  346. &Buffer,
  347. &BufferSize );
  348. if ( WinStatus != NO_ERROR ) {
  349. AzPrint(( AZD_PERSIST, "SamplePersistOpen: Cannot SampleReadFile %ld\n", WinStatus ));
  350. goto Cleanup;
  351. }
  352. //
  353. // Loop through the file a line at a time
  354. //
  355. for ( Line = (LPWSTR)Buffer; Line != NULL ; Line = Next ) {
  356. ULONG ObjectType;
  357. LPWSTR ObjectNameString;
  358. AZP_STRING ObjectName;
  359. ULONG ObjectGuid;
  360. PGENERIC_OBJECT_HEAD ChildGenericObjectHead;
  361. //
  362. // Grab a line from the file
  363. //
  364. Next = Line;
  365. if ( !SampleGetALine( &Next,
  366. &Level,
  367. &ObjectType,
  368. &ObjectGuid,
  369. BigBuffer,
  370. &ObjectNameString ) ) {
  371. break;
  372. }
  373. //
  374. // Cannot be more than one greater than the previous level
  375. //
  376. ASSERT( Level >= 1 );
  377. if ( Level > CurrentLevel+1 ) {
  378. AzPrint(( AZD_PERSIST, "SamplePersistOpen: %ld %ld File broken on line %ws\n", Level, CurrentLevel, Line ));
  379. WinStatus = ERROR_INTERNAL_DB_CORRUPTION;
  380. goto Cleanup;
  381. }
  382. //
  383. // Close any stacked pointers we'll no longer use
  384. //
  385. while ( CurrentLevel >= Level ) {
  386. ObDereferenceObject( GenericObjectStack[CurrentLevel] );
  387. GenericObjectStack[CurrentLevel] = NULL;
  388. CurrentLevel --;
  389. }
  390. CurrentLevel = Level;
  391. AzPrint(( AZD_PERSIST_MORE, "Open: %ws\n", ObjectNameString ));
  392. AzpInitString( &ObjectName, ObjectNameString );
  393. //
  394. // Search for the list to link this item into
  395. //
  396. for ( ChildGenericObjectHead = GenericObjectStack[CurrentLevel-1]->ChildGenericObjectHead;
  397. ChildGenericObjectHead != NULL;
  398. ChildGenericObjectHead = ChildGenericObjectHead->SiblingGenericObjectHead ) {
  399. if ( ObjectType == ChildGenericObjectHead->ObjectType ) {
  400. break;
  401. }
  402. }
  403. if ( ChildGenericObjectHead == NULL ) {
  404. AzPrint(( AZD_PERSIST,
  405. "SamplePersistOpen: Parent doesn't support this child %ld %ws\n",
  406. ObjectType,
  407. ObjectNameString ));
  408. WinStatus = ERROR_INTERNAL_DB_CORRUPTION;
  409. goto Cleanup;
  410. }
  411. //
  412. // Actually create the object in the cache
  413. //
  414. WinStatus = ObCreateObject(
  415. GenericObjectStack[CurrentLevel-1], // ParentGenericObject
  416. ChildGenericObjectHead,
  417. ObjectType,
  418. &ObjectName,
  419. &GenericObjectStack[CurrentLevel] ); // Save pointer to generic object
  420. if ( ObjectType >= ObjectTypeNamesSize ) {
  421. AzPrint(( AZD_PERSIST,
  422. "SamplePersistOpen: Cannot CreateObject from DB %ld %ld %ws\n",
  423. WinStatus,
  424. ObjectType,
  425. ObjectNameString ));
  426. goto Cleanup;
  427. }
  428. //
  429. // Remember the GUID of the object
  430. //
  431. *(PULONG)&GenericObjectStack[CurrentLevel]->PersistenceGuid = ObjectGuid;
  432. PersistContext->LastUsedGuid = ObjectGuid;
  433. //
  434. // ??? A Real provider would set the attributes on the object here
  435. //
  436. }
  437. //
  438. // Return the context to the caller
  439. //
  440. AdminManager->PersistContext = PersistContext;
  441. PersistContext = NULL;
  442. WinStatus = NO_ERROR;
  443. //
  444. // Free locally used resources
  445. //
  446. Cleanup:
  447. if ( PersistContext != NULL ) {
  448. AdminManager->PersistContext = PersistContext;
  449. SamplePersistClose( AdminManager );
  450. }
  451. while ( CurrentLevel >= 1 ) {
  452. ObDereferenceObject( GenericObjectStack[CurrentLevel] );
  453. GenericObjectStack[CurrentLevel] = NULL;
  454. CurrentLevel --;
  455. }
  456. if ( Buffer != NULL ) {
  457. AzpFreeHeap( Buffer );
  458. }
  459. SafeAllocaFree( BigBuffer );
  460. return WinStatus;
  461. }
  462. VOID
  463. SamplePersistClose(
  464. IN PAZP_ADMIN_MANAGER AdminManager
  465. )
  466. /*++
  467. Routine Description:
  468. This routine submits close the authz policy database storage handles.
  469. On entry, AzGlResource must be locked exclusive.
  470. Arguments:
  471. AdminManager - Specifies the policy database that is to be read.
  472. Return Value:
  473. NO_ERROR - The operation was successful
  474. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  475. Other status codes
  476. --*/
  477. {
  478. PAZP_SAMPLE_CONTEXT PersistContext = (PAZP_SAMPLE_CONTEXT) AdminManager->PersistContext;
  479. ASSERT(PersistContext != NULL);
  480. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  481. //
  482. // Close the file handle
  483. //
  484. CloseHandle( PersistContext->FileHandle );
  485. //
  486. // Free the context itself
  487. //
  488. AzpFreeHeap( PersistContext );
  489. AdminManager->PersistContext = NULL;
  490. }
  491. DWORD
  492. SamplePersistSubmit(
  493. IN PGENERIC_OBJECT GenericObject,
  494. IN BOOLEAN DeleteMe
  495. )
  496. /*++
  497. Routine Description:
  498. This routine submits changes made to the authz policy database.
  499. If the object is being created, the GenericObject->PersistenceGuid field will be
  500. zero on input. Upon successful creation, this routine will set PersistenceGuid to
  501. non-zero. Upon failed creation, this routine will leave PersistenceGuid as zero.
  502. On entry, AzGlResource must be locked exclusive.
  503. Arguments:
  504. GenericObject - Specifies the object in the database that is to be updated
  505. in the underlying store.
  506. DeleteMe - TRUE if the object and all of its children are to be deleted.
  507. FALSE if the object is to be updated.
  508. Return Value:
  509. NO_ERROR - The operation was successful
  510. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  511. Other status codes
  512. --*/
  513. {
  514. DWORD WinStatus;
  515. PAZP_SAMPLE_CONTEXT PersistContext = (PAZP_SAMPLE_CONTEXT) GenericObject->AdminManagerObject->PersistContext;
  516. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  517. BOOLEAN AllocatedGuid = FALSE;
  518. // Variables describing the GenericObject entry
  519. LPWSTR NewEntryBuffer = NULL;
  520. ULONG NewEntryLevel;
  521. ULONG NewEntryNameByteCount;
  522. AZP_STRING NewEntryObjectName;
  523. ULONG NewGuid;
  524. BOOL NewInserted = FALSE;
  525. PGENERIC_OBJECT CurrentGenericObject;
  526. PGENERIC_OBJECT NextGenericObject;
  527. ULONG BytesWritten;
  528. LPBYTE Where;
  529. LPWSTR Line;
  530. LPWSTR Next;
  531. LPWSTR CurrentFullObjectName = NULL;
  532. // Variables describing the existing file contents
  533. LPBYTE Buffer = NULL;
  534. ULONG BufferSize;
  535. //
  536. // Stack of descriptors of the buffers to write to the file
  537. //
  538. ULONG Index;
  539. ULONG StackIndex;
  540. LPBYTE BufferStack[30];
  541. ULONG SizeStack[30];
  542. LPSTR CommentStack[30];
  543. //
  544. // Initialization
  545. //
  546. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  547. SafeAllocaAllocate( CurrentFullObjectName, HUGE_BUFFER_SIZE );
  548. if ( CurrentFullObjectName == NULL ) {
  549. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  550. goto Cleanup;
  551. }
  552. //
  553. // If the object doesn't yet have a GUID,
  554. // give it one.
  555. //
  556. if ( (*(PULONG)(&GenericObject->PersistenceGuid)) == 0 ) {
  557. PersistContext->LastUsedGuid ++;
  558. *(PULONG)(&GenericObject->PersistenceGuid) = PersistContext->LastUsedGuid;
  559. AllocatedGuid = TRUE;
  560. }
  561. NewGuid = *(PULONG)(&GenericObject->PersistenceGuid);
  562. //
  563. // Build the bytes to write to the file for the entry representing GenericObject
  564. //
  565. //
  566. SafeAllocaAllocate( NewEntryBuffer, HUGE_BUFFER_SIZE );
  567. if ( NewEntryBuffer == NULL ) {
  568. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  569. goto Cleanup;
  570. }
  571. NewEntryBuffer[0] = 0;
  572. NewEntryLevel = 0;
  573. //
  574. // Build the "GUID" first
  575. //
  576. swprintf( NewEntryBuffer, L"%ld ", *(PULONG)(&GenericObject->PersistenceGuid) );
  577. //
  578. // Build the object name next
  579. //
  580. Where = ((LPBYTE)NewEntryBuffer) + HUGE_BUFFER_SIZE - sizeof(WCHAR);
  581. NewEntryNameByteCount = sizeof(WCHAR);
  582. *((LPWSTR)Where) = '\0';
  583. for ( CurrentGenericObject=GenericObject;
  584. CurrentGenericObject != NULL;
  585. CurrentGenericObject=NextGenericObject ) {
  586. //
  587. // Copy the delimiter into the buffer
  588. //
  589. if ( CurrentGenericObject != GenericObject ) {
  590. Where -= SAMPLE_DELIM_SIZE;
  591. NewEntryNameByteCount += SAMPLE_DELIM_SIZE;
  592. RtlCopyMemory(
  593. Where,
  594. SAMPLE_DELIM,
  595. SAMPLE_DELIM_SIZE );
  596. }
  597. //
  598. // Copy the name of the current object into the buffer
  599. //
  600. Where -= CurrentGenericObject->ObjectName.StringSize-sizeof(WCHAR);
  601. NewEntryNameByteCount += CurrentGenericObject->ObjectName.StringSize-sizeof(WCHAR);
  602. RtlCopyMemory(
  603. Where,
  604. CurrentGenericObject->ObjectName.String,
  605. CurrentGenericObject->ObjectName.StringSize-sizeof(WCHAR) );
  606. //
  607. // Get the address of the current object
  608. //
  609. NextGenericObject = CurrentGenericObject->ParentGenericObjectHead->ParentGenericObject;
  610. if ( NextGenericObject->ObjectType == OBJECT_TYPE_ADMIN_MANAGER ) {
  611. break;
  612. }
  613. }
  614. //
  615. // Move the data to the right spot in the buffer
  616. //
  617. NewEntryObjectName.String = &NewEntryBuffer[ (wcslen(NewEntryBuffer) * sizeof(WCHAR)) / sizeof(WCHAR) ];
  618. NewEntryObjectName.StringSize = NewEntryNameByteCount;
  619. RtlMoveMemory( NewEntryObjectName.String,
  620. Where,
  621. NewEntryNameByteCount );
  622. //
  623. // Output the object type
  624. //
  625. wcscat( NewEntryBuffer, L" " );
  626. if ( GenericObject->ObjectType < ObjectTypeNamesSize ) {
  627. wcscat( NewEntryBuffer, ObjectTypeNames[GenericObject->ObjectType] );
  628. } else {
  629. wcscat( NewEntryBuffer, L"[unknown]" );
  630. }
  631. //
  632. // Add modifiers
  633. // ??? A real provider actually should persist the attributes of the object
  634. //
  635. if ( GenericObject->Flags & GENOBJ_FLAGS_DELETED ) {
  636. wcscat( NewEntryBuffer, L" [DEL]" );
  637. }
  638. if ( GenericObject->Flags & GENOBJ_FLAGS_DIRTY ) {
  639. wcscat( NewEntryBuffer, L" [DIRTY]" );
  640. }
  641. wcscat( NewEntryBuffer, L"\n" );
  642. AzPrint(( AZD_PERSIST_MORE, "%ws", NewEntryBuffer ));
  643. //
  644. // Read the file into a buffer
  645. //
  646. WinStatus = SampleReadFile( GenericObject->AdminManagerObject->PolicyUrl.String,
  647. FALSE, // Open existing file
  648. &FileHandle,
  649. &Buffer,
  650. &BufferSize );
  651. if ( WinStatus != NO_ERROR ) {
  652. AzPrint(( AZD_PERSIST, "SamplePersistOpen: Cannot SampleReadFile %ld\n", WinStatus ));
  653. goto Cleanup;
  654. }
  655. //
  656. // Loop through the file a line at a time.
  657. //
  658. // Build a stack of the buffer fragments to write to the destination file.
  659. // Essentially, write the entire original buffer.
  660. // But, delete the object from the original buffer that has a guid matching the written object
  661. // And, insert the written object at the correct spot in the hierarchy.
  662. //
  663. //
  664. // The stack index points at the entry descrbing the 'remainder' of the buffer
  665. //
  666. StackIndex = 0;
  667. BufferStack[StackIndex] = Buffer;
  668. SizeStack[StackIndex] = BufferSize;
  669. CommentStack[StackIndex] = "First";
  670. for ( Line = (LPWSTR)Buffer; Line != NULL ; Line = Next ) {
  671. ULONG CurrentObjectType;
  672. LPWSTR CurrentObjectNameString;
  673. AZP_STRING CurrentObjectName;
  674. ULONG CurrentLevel;
  675. ULONG CurrentGuid;
  676. LONG CompareResult;
  677. BOOL InsertHere;
  678. //
  679. // Grab a line from the file
  680. //
  681. Next = Line;
  682. if ( !SampleGetALine( &Next,
  683. &CurrentLevel,
  684. &CurrentObjectType,
  685. &CurrentGuid,
  686. CurrentFullObjectName,
  687. &CurrentObjectNameString ) ) {
  688. break;
  689. }
  690. AzpInitString( &CurrentObjectName, CurrentFullObjectName );
  691. //
  692. // Delete the object that has the matching guid
  693. //
  694. if ( CurrentGuid == NewGuid ) {
  695. //
  696. // Truncate the current buffer remainder to stop right before the current line
  697. //
  698. SizeStack[StackIndex] = (ULONG)(((LPBYTE)Line) - BufferStack[StackIndex]);
  699. //
  700. // Push a new 'remainder' onto the stack
  701. //
  702. StackIndex++;
  703. BufferStack[StackIndex] = (LPBYTE) Next;
  704. SizeStack[StackIndex] = (ULONG)(BufferSize - (BufferStack[StackIndex] - Buffer));
  705. CommentStack[StackIndex] = "Guid";
  706. continue;
  707. }
  708. //
  709. // Determine if this is where we insert the object being written
  710. //
  711. InsertHere = FALSE;
  712. CompareResult = AzpCompareStrings( &CurrentObjectName,
  713. &NewEntryObjectName );
  714. if ( CompareResult == 0 ) {
  715. WinStatus = GetLastError();
  716. goto Cleanup;
  717. //
  718. // If the current line has the same name as the one being written,
  719. // inspect the types.
  720. //
  721. } else if ( CompareResult == CSTR_EQUAL ) {
  722. //
  723. // If the object types are the same,
  724. // replace the current object.
  725. //
  726. if ( CurrentObjectType == GenericObject->ObjectType ) {
  727. ASSERT( FALSE ); // The GUIDS didn't match
  728. AzPrint(( AZD_PERSIST_MORE, "equal equal '%ws' '%ws'\n", CurrentObjectName.String, NewEntryObjectName.String ));
  729. continue;
  730. //
  731. // if the current object type is greater than the one being written,
  732. // we've already passed it.
  733. //
  734. } else if ( CurrentObjectType > GenericObject->ObjectType ) {
  735. AzPrint(( AZD_PERSIST_MORE, "equal lt '%ws' '%ws'\n", CurrentObjectName.String, NewEntryObjectName.String ));
  736. InsertHere = TRUE;
  737. } else {
  738. }
  739. //
  740. // If the current line is greater than the one being written,
  741. // we've already passed it. We're done looping
  742. //
  743. } else if ( CompareResult == CSTR_GREATER_THAN ) {
  744. AzPrint(( AZD_PERSIST_MORE, "gt '%ws' '%ws'\n", CurrentObjectName.String, NewEntryObjectName.String ));
  745. InsertHere = TRUE;
  746. }
  747. //
  748. // Put the current object here
  749. //
  750. if ( InsertHere ) {
  751. if ( !DeleteMe ) {
  752. //
  753. // Truncate the current buffer remainder to stop right before the current line
  754. //
  755. SizeStack[StackIndex] = (ULONG)(((LPBYTE)Line) - BufferStack[StackIndex]);
  756. //
  757. // Push the new object onto the stack
  758. //
  759. StackIndex++;
  760. BufferStack[StackIndex] = (LPBYTE) NewEntryBuffer;
  761. SizeStack[StackIndex] = wcslen(NewEntryBuffer) * sizeof(WCHAR);
  762. CommentStack[StackIndex] = "New";
  763. NewInserted = TRUE;
  764. //
  765. // Push a new 'remainder' onto the stack
  766. //
  767. StackIndex++;
  768. BufferStack[StackIndex] = (LPBYTE) Line;
  769. SizeStack[StackIndex] = (ULONG)(BufferSize - (BufferStack[StackIndex] - Buffer));
  770. CommentStack[StackIndex] = "Post";
  771. }
  772. break;
  773. }
  774. }
  775. //
  776. // If we didn't insert it yet,
  777. // do it now
  778. if ( !NewInserted && !DeleteMe ) {
  779. //
  780. // Push the new object onto the stack
  781. //
  782. StackIndex++;
  783. BufferStack[StackIndex] = (LPBYTE) NewEntryBuffer;
  784. SizeStack[StackIndex] = wcslen(NewEntryBuffer) * sizeof(WCHAR);
  785. CommentStack[StackIndex] = "New";
  786. NewInserted = TRUE;
  787. }
  788. //
  789. // Truncate the file since we're writing it from scratch
  790. // ??? A real provider wouldn't write the whole database from scratch
  791. //
  792. if ( SetFilePointer( FileHandle, 0, NULL, FILE_BEGIN ) == INVALID_SET_FILE_POINTER ) {
  793. WinStatus = GetLastError();
  794. AzPrint(( AZD_PERSIST, "SamplePersistSubmit: Cannot SetFilePointer %ld\n", WinStatus ));
  795. goto Cleanup;
  796. }
  797. if ( !SetEndOfFile( FileHandle ) ) {
  798. WinStatus = GetLastError();
  799. AzPrint(( AZD_PERSIST, "SamplePersistSubmit: Cannot SetEndofFile %ld\n", WinStatus ));
  800. goto Cleanup;
  801. }
  802. //
  803. // Write the various parts of the data back to the file
  804. //
  805. // ??? A real provider should ensure that a failed write
  806. // doesn't destroy previous good written data. Either the write
  807. // of the entire database can be atomic. Or the write of this
  808. // particular object can be atomic.
  809. //
  810. for ( Index=0; Index<=StackIndex; Index++ ) {
  811. if ( BufferStack[Index] != NULL && SizeStack[Index] != 0 ) {
  812. AzPrint(( AZD_PERSIST_MORE,
  813. "%s: %ld %*.*ws\n",
  814. CommentStack[Index],
  815. SizeStack[Index],
  816. SizeStack[Index]/sizeof(WCHAR),
  817. SizeStack[Index]/sizeof(WCHAR),
  818. BufferStack[Index] ));
  819. if ( !WriteFile( FileHandle,
  820. BufferStack[Index],
  821. SizeStack[Index],
  822. &BytesWritten,
  823. NULL ) ) {
  824. WinStatus = GetLastError();
  825. AzPrint(( AZD_PERSIST, "SamplePersistSubmit: Cannot WriteFile %ld\n", WinStatus ));
  826. goto Cleanup;
  827. }
  828. }
  829. }
  830. WinStatus = NO_ERROR;
  831. //
  832. // Free locally used resources
  833. //
  834. Cleanup:
  835. if ( WinStatus != NO_ERROR ) {
  836. if ( AllocatedGuid ) {
  837. RtlZeroMemory( &GenericObject->PersistenceGuid, sizeof(GenericObject->PersistenceGuid) );
  838. }
  839. }
  840. if ( Buffer != NULL ) {
  841. AzpFreeHeap( Buffer );
  842. }
  843. if ( FileHandle != INVALID_HANDLE_VALUE ) {
  844. CloseHandle( FileHandle );
  845. }
  846. SafeAllocaFree( NewEntryBuffer );
  847. SafeAllocaFree( CurrentFullObjectName );
  848. return WinStatus;
  849. }
  850. DWORD
  851. SamplePersistRefresh(
  852. IN PGENERIC_OBJECT GenericObject
  853. )
  854. /*++
  855. Routine Description:
  856. This routine updates the attributes of the object from the policy database.
  857. On entry, AzGlResource must be locked exclusive.
  858. Arguments:
  859. GenericObject - Specifies the object in the database whose cache entry is to be
  860. updated
  861. The GenericObject->PersistenceGuid field should be non-zero on input.
  862. Return Value:
  863. NO_ERROR - The operation was successful
  864. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  865. Other status codes
  866. --*/
  867. {
  868. DWORD WinStatus = NO_ERROR;
  869. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  870. UNREFERENCED_PARAMETER( GenericObject );
  871. //
  872. // ??? A real provider needs to implement this routine
  873. //
  874. return WinStatus;
  875. }