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.

1585 lines
50 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. termutil.c
  5. Abstract:
  6. Terminal server support functions and inifile syncing/merging code
  7. Author:
  8. Revision History:
  9. --*/
  10. #include "basedll.h"
  11. #include "regapi.h"
  12. #define STRSAFE_NO_DEPRECATE
  13. #include <strsafe.h>
  14. #define TERMSRV_INIFILE_TIMES L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\IniFile Times"
  15. BOOL IsTerminalServerCompatible(VOID)
  16. {
  17. PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader( NtCurrentPeb()->ImageBaseAddress );
  18. if ((NtHeader) && (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)) {
  19. return TRUE;
  20. } else {
  21. return FALSE;
  22. }
  23. }
  24. NTSTATUS
  25. IsTSAppCompatEnabled(
  26. OUT PBOOL ReturnValue
  27. )
  28. {
  29. NTSTATUS NtStatus;
  30. const static UNICODE_STRING UniString_REG_NTAPI_CONTROL_TSERVER = RTL_CONSTANT_STRING(REG_NTAPI_CONTROL_TSERVER);
  31. const static UNICODE_STRING UniString_TSAppCompat = RTL_CONSTANT_STRING(L"TSAppCompat");
  32. const static OBJECT_ATTRIBUTES ObjectAttributes =
  33. RTL_CONSTANT_OBJECT_ATTRIBUTES(
  34. &UniString_REG_NTAPI_CONTROL_TSERVER,
  35. OBJ_CASE_INSENSITIVE
  36. );
  37. HKEY hKey = 0;
  38. ULONG ul, ulcbuf;
  39. PKEY_VALUE_PARTIAL_INFORMATION pKeyValInfo = NULL;
  40. BOOL retval = TRUE;
  41. // Determine the value info buffer size
  42. ulcbuf = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR) +
  43. sizeof(ULONG);
  44. pKeyValInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(RtlProcessHeap(),
  45. 0,
  46. ulcbuf);
  47. if (pKeyValInfo == NULL)
  48. return STATUS_NO_MEMORY;
  49. NtStatus = NtOpenKey(&hKey, KEY_READ, RTL_CONST_CAST(POBJECT_ATTRIBUTES)(&ObjectAttributes));
  50. if (NT_SUCCESS(NtStatus)) {
  51. NtStatus = NtQueryValueKey(hKey,
  52. RTL_CONST_CAST(PUNICODE_STRING)(&UniString_TSAppCompat),
  53. KeyValuePartialInformation,
  54. pKeyValInfo,
  55. ulcbuf,
  56. &ul);
  57. if (NT_SUCCESS(NtStatus) && (REG_DWORD == pKeyValInfo->Type)) {
  58. if ((*(PULONG)pKeyValInfo->Data) == 0) {
  59. retval = FALSE;
  60. }
  61. }
  62. NtClose(hKey);
  63. }
  64. // Free up the buffers we allocated
  65. // Need to zero out the buffers, because some apps (MS Internet Assistant)
  66. // won't install if the heap is not zero filled.
  67. memset(pKeyValInfo, 0, ulcbuf);
  68. RtlFreeHeap( RtlProcessHeap(), 0, pKeyValInfo );
  69. *ReturnValue = retval;
  70. return STATUS_SUCCESS;
  71. }
  72. BOOL IsSystemLUID(VOID)
  73. {
  74. HANDLE TokenHandle;
  75. UCHAR TokenInformation[ sizeof( TOKEN_STATISTICS ) ];
  76. ULONG ReturnLength;
  77. LUID CurrentLUID = { 0, 0 };
  78. LUID SystemLUID = SYSTEM_LUID;
  79. NTSTATUS Status;
  80. if ( CurrentLUID.LowPart == 0 && CurrentLUID.HighPart == 0 ) {
  81. Status = NtOpenProcessToken( NtCurrentProcess(),
  82. TOKEN_QUERY,
  83. &TokenHandle );
  84. if ( !NT_SUCCESS( Status ) )
  85. return(TRUE);
  86. NtQueryInformationToken( TokenHandle, TokenStatistics, TokenInformation,
  87. sizeof(TokenInformation), &ReturnLength );
  88. NtClose( TokenHandle );
  89. RtlCopyLuid(&CurrentLUID,
  90. &(((PTOKEN_STATISTICS)TokenInformation)->AuthenticationId));
  91. }
  92. if (RtlEqualLuid(&CurrentLUID, &SystemLUID)) {
  93. return(TRUE);
  94. } else {
  95. return(FALSE );
  96. }
  97. }
  98. typedef struct _BASEP_PROCNAME_PROCADDRESS_PAIR {
  99. PCSTR ProcName;
  100. PVOID * ProcAddress;
  101. } BASEP_PROCNAME_PROCADDRESS_PAIR, *PBASEP_PROCNAME_PROCADDRESS_PAIR;
  102. typedef const BASEP_PROCNAME_PROCADDRESS_PAIR *PCBASEP_PROCNAME_PROCADDRESS_PAIR;
  103. NTSTATUS
  104. BasepInitializeTermsrvFpns(
  105. VOID
  106. )
  107. {
  108. HANDLE dllHandle;
  109. BOOL TSAppCompatEnabled;
  110. NTSTATUS Status;
  111. SIZE_T i;
  112. const static BASEP_PROCNAME_PROCADDRESS_PAIR Procs[] = {
  113. { "TermsrvGetComputerName", (PVOID*)&gpTermsrvGetComputerName },
  114. { "TermsrvAdjustPhyMemLimits", (PVOID*)&gpTermsrvAdjustPhyMemLimits },
  115. { "TermsrvGetWindowsDirectoryA", (PVOID*)&gpTermsrvGetWindowsDirectoryA},
  116. { "TermsrvGetWindowsDirectoryW", (PVOID*)&gpTermsrvGetWindowsDirectoryW},
  117. { "TermsrvConvertSysRootToUserDir", (PVOID*)&gpTermsrvConvertSysRootToUserDir},
  118. { "TermsrvBuildIniFileName", (PVOID*)&gpTermsrvBuildIniFileName},
  119. { "TermsrvCORIniFile", (PVOID*)&gpTermsrvCORIniFile },
  120. { "GetTermsrCompatFlags", (PVOID*)&gpGetTermsrCompatFlags },
  121. { "TermsrvBuildSysIniPath", (PVOID*)&gpTermsrvBuildSysIniPath },
  122. { "TermsrvCopyIniFile", (PVOID*)&gpTermsrvCopyIniFile },
  123. { "TermsrvGetString", (PVOID*)&gpTermsrvGetString },
  124. { "TermsrvLogInstallIniFile", (PVOID*)&gpTermsrvLogInstallIniFile }
  125. };
  126. if (IsTerminalServerCompatible() ||
  127. (IsSystemLUID())) {
  128. Status = STATUS_SUCCESS;
  129. goto Exit;
  130. }
  131. Status = IsTSAppCompatEnabled(&TSAppCompatEnabled);
  132. if (!NT_SUCCESS(Status)) {
  133. goto Exit;
  134. }
  135. if (!TSAppCompatEnabled) {
  136. Status = STATUS_SUCCESS;
  137. goto Exit;
  138. }
  139. //
  140. // Load Terminal Server application compatibility dll
  141. //
  142. dllHandle = LoadLibraryW(L"tsappcmp.dll");
  143. if (dllHandle == NULL) {
  144. Status = NtCurrentTeb()->LastStatusValue;
  145. goto Exit;
  146. }
  147. for (i = 0 ; i != RTL_NUMBER_OF(Procs) ; ++i) {
  148. const PCBASEP_PROCNAME_PROCADDRESS_PAIR Proc = &Procs[i];
  149. *Proc->ProcAddress = GetProcAddress(dllHandle, Proc->ProcName);
  150. }
  151. Status = STATUS_SUCCESS;
  152. Exit:
  153. return Status;
  154. }
  155. /*****************************************************************************
  156. *
  157. * TermsrvAppInstallMode
  158. *
  159. * Returns whether the system is in Install mode or not
  160. *
  161. * ENTRY:
  162. * Param1 (input/output)
  163. * Comments
  164. *
  165. * EXIT:
  166. * STATUS_SUCCESS - no error
  167. *
  168. ****************************************************************************/
  169. WINBASEAPI
  170. BOOL
  171. WINAPI
  172. TermsrvAppInstallMode( VOID )
  173. {
  174. if ( BaseStaticServerData->fTermsrvAppInstallMode )
  175. return( TRUE );
  176. return( FALSE );
  177. }
  178. WINBASEAPI BOOL WINAPI IsCallerAdminOrSystem( VOID)
  179. {
  180. typedef BOOL ( APIENTRY Func_CheckTokenMembership )( HANDLE , PSID , PBOOL);
  181. BOOL rc;
  182. NTSTATUS Status;
  183. PSID pSid = NULL ;
  184. SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_NT_AUTHORITY;
  185. HINSTANCE dllHandle;
  186. dllHandle = LoadLibraryW(L"advapi32.dll");
  187. if (dllHandle)
  188. {
  189. Func_CheckTokenMembership *fPtr;
  190. fPtr = (Func_CheckTokenMembership * )GetProcAddress(dllHandle,"CheckTokenMembership");
  191. if (fPtr)
  192. {
  193. Status = RtlAllocateAndInitializeSid(
  194. &SidAuthority,
  195. 2,
  196. SECURITY_BUILTIN_DOMAIN_RID,
  197. DOMAIN_ALIAS_RID_ADMINS,
  198. 0, 0, 0, 0, 0, 0,
  199. &pSid
  200. );
  201. if (NT_SUCCESS(Status))
  202. {
  203. BOOL FoundAdmin;
  204. if ( fPtr (NULL, pSid , &FoundAdmin))
  205. {
  206. if (FoundAdmin)
  207. {
  208. SetLastError( ERROR_SUCCESS );
  209. rc = TRUE;
  210. }
  211. else
  212. {
  213. // caller does not have access
  214. SetLastError( ERROR_ACCESS_DENIED );
  215. rc = FALSE;
  216. }
  217. }
  218. else
  219. {
  220. // call to CheckTokenMembership() failed, it set the last error
  221. rc = FALSE;
  222. }
  223. }
  224. else
  225. {
  226. // attempt to allocate and init SID failed.
  227. SetLastError( RtlNtStatusToDosError( Status ) );
  228. rc = FALSE;
  229. }
  230. if (pSid)
  231. {
  232. RtlFreeSid( pSid );
  233. pSid = NULL;
  234. }
  235. // if caller is not admin, see if caller is local system
  236. if ( !rc )
  237. {
  238. Status = RtlAllocateAndInitializeSid(
  239. &SidAuthority,
  240. 1,
  241. SECURITY_LOCAL_SYSTEM_RID ,
  242. 0, 0, 0, 0, 0, 0, 0,
  243. &pSid
  244. );
  245. if (NT_SUCCESS(Status))
  246. {
  247. BOOL FoundLocalSystem;
  248. if ( fPtr (NULL, pSid , &FoundLocalSystem))
  249. {
  250. if (FoundLocalSystem)
  251. {
  252. SetLastError( ERROR_SUCCESS );
  253. rc = TRUE;
  254. }
  255. else
  256. {
  257. // caller does not have access
  258. SetLastError( ERROR_ACCESS_DENIED );
  259. rc = FALSE;
  260. }
  261. }
  262. else
  263. {
  264. // call to CheckTokenMembership() failed, it set the last error
  265. rc = FALSE;
  266. }
  267. }
  268. else
  269. {
  270. // attempt to allocate and init SID failed.
  271. SetLastError( RtlNtStatusToDosError( Status ) );
  272. rc = FALSE;
  273. }
  274. }
  275. }
  276. else
  277. {
  278. // function not found, GetProc() set the last error.
  279. rc = FALSE;
  280. }
  281. FreeLibrary( dllHandle );
  282. }
  283. else
  284. {
  285. // library not found, LoadLib() set the last error
  286. rc = FALSE;
  287. }
  288. if (pSid)
  289. {
  290. RtlFreeSid( pSid );
  291. }
  292. return rc;
  293. }
  294. /*****************************************************************************
  295. *
  296. * SetTermsrvAppInstallMode
  297. *
  298. * Turns App install mode on or off. Default is off
  299. *
  300. * ENTRY:
  301. * Param1 (input/output)
  302. * Comments
  303. *
  304. * EXIT:
  305. * STATUS_SUCCESS - no error
  306. *
  307. ****************************************************************************/
  308. BOOL
  309. WINAPI
  310. SetTermsrvAppInstallMode( BOOL bState )
  311. {
  312. BOOL rc = FALSE;
  313. NTSTATUS Status = STATUS_INTERNAL_ERROR;
  314. HINSTANCE dllHandle;
  315. BOOL TSAppCompatEnabled;
  316. #if !defined(BUILD_WOW6432)
  317. BASE_API_MSG m;
  318. PBASE_SET_TERMSRVAPPINSTALLMODE c;
  319. #endif
  320. if (!IsTerminalServer()) {
  321. //
  322. // last error should be set to something..
  323. //
  324. rc = FALSE;
  325. goto Exit;
  326. }
  327. Status = IsTSAppCompatEnabled(&TSAppCompatEnabled);
  328. if (!NT_SUCCESS(Status)) {
  329. SetLastError( RtlNtStatusToDosError( Status ) );
  330. rc = FALSE;
  331. goto Exit;
  332. }
  333. if (!TSAppCompatEnabled) {
  334. //
  335. // last error should be set to something..
  336. //
  337. rc = FALSE;
  338. goto Exit;
  339. }
  340. #if defined(BUILD_WOW6432)
  341. Status = CsrBasepSetTermsrvAppInstallMode(bState);
  342. #else
  343. c = (PBASE_SET_TERMSRVAPPINSTALLMODE)&m.u.SetTermsrvAppInstallMode;
  344. c->bState = bState;
  345. Status = CsrClientCallServer((PCSR_API_MSG)&m, NULL,
  346. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  347. BasepSetTermsrvAppInstallMode),
  348. sizeof( *c ));
  349. #endif
  350. if (!NT_SUCCESS(Status)) {
  351. SetLastError( RtlNtStatusToDosError( Status ) );
  352. rc = FALSE;
  353. goto Exit;
  354. }
  355. //
  356. // Load tsappcmp.dll
  357. //
  358. if (gpTermsrvUpdateAllUserMenu == NULL)
  359. {
  360. //
  361. // Load Terminal Server application compatibility dll
  362. //
  363. dllHandle = LoadLibraryW(L"tsappcmp.dll");
  364. if (dllHandle)
  365. {
  366. gpTermsrvUpdateAllUserMenu =
  367. (PTERMSRVUPDATEALLUSERMENU)GetProcAddress(dllHandle,"TermsrvUpdateAllUserMenu");
  368. }
  369. else
  370. {
  371. // ..
  372. }
  373. }
  374. if (gpTermsrvUpdateAllUserMenu)
  375. {
  376. gpTermsrvUpdateAllUserMenu( bState == TRUE ? 0 : 1 );
  377. }
  378. rc = TRUE;
  379. Exit:
  380. return rc;
  381. }
  382. /////////////////////////////////////////////////////////////////////////////
  383. /////////////////////////////////////////////////////////////////////////////
  384. /*
  385. Ini File syncing/merging code
  386. */
  387. //////////////////////////////////////////////////////////////////////////////
  388. /* External Functions */
  389. NTSTATUS
  390. BaseDllOpenIniFileOnDisk(
  391. PINIFILE_PARAMETERS a
  392. );
  393. NTSTATUS
  394. BaseDllWriteKeywordValue(
  395. IN PINIFILE_PARAMETERS a,
  396. IN PUNICODE_STRING VariableName OPTIONAL
  397. );
  398. NTSTATUS
  399. BaseDllCloseIniFileOnDisk(
  400. IN PINIFILE_PARAMETERS a
  401. );
  402. NTSTATUS
  403. BaseDllFindSection(
  404. IN PINIFILE_PARAMETERS a
  405. );
  406. NTSTATUS
  407. BaseDllFindKeyword(
  408. IN PINIFILE_PARAMETERS a
  409. );
  410. NTSTATUS
  411. TermsrvIniSyncLoop( HANDLE SrcHandle,
  412. PINIFILE_PARAMETERS a,
  413. PBOOLEAN pfIniUpdated
  414. );
  415. NTSTATUS
  416. TermsrvGetSyncTime( PUNICODE_STRING pSysIniPath,
  417. PUNICODE_STRING pUserBasePath,
  418. PLARGE_INTEGER pLastSyncTime
  419. );
  420. NTSTATUS
  421. TermsrvPutSyncTime( PUNICODE_STRING pSysIniPath,
  422. PUNICODE_STRING pUserBasePath,
  423. PLARGE_INTEGER pLastSyncTime
  424. );
  425. /*****************************************************************************
  426. *
  427. * TermsrvGetSyncTime
  428. *
  429. * This routine will get the time of the system ini file that the user ini
  430. * file was last sync'd with.
  431. *
  432. * ENTRY:
  433. * PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path
  434. * PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path
  435. * PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time
  436. *
  437. * EXIT:
  438. * STATUS_SUCCESS - successfully retrieved the last sync time from infile.upd
  439. *
  440. ****************************************************************************/
  441. NTSTATUS
  442. TermsrvGetSyncTime(
  443. PUNICODE_STRING pSysIniPath,
  444. PUNICODE_STRING pUserBasePath,
  445. PLARGE_INTEGER pLastSyncTime)
  446. {
  447. NTSTATUS Status;
  448. HANDLE hUpdate = NULL;
  449. OBJECT_ATTRIBUTES ObjAUpd;
  450. IO_STATUS_BLOCK Iosb;
  451. FILE_STANDARD_INFORMATION StandardInfo;
  452. WCHAR wcUpdateFile[MAX_PATH+1];
  453. UNICODE_STRING UniUpdateName = {0,
  454. sizeof(wcUpdateFile),
  455. wcUpdateFile};
  456. PCHAR pBuff = NULL, pBuffEnd;
  457. PWCH pwch;
  458. SIZE_T ulBuffSize;
  459. LONG lresult;
  460. if (!pSysIniPath) {
  461. return STATUS_INVALID_PARAMETER_1;
  462. }
  463. if (!pUserBasePath) {
  464. return STATUS_INVALID_PARAMETER_2;
  465. }
  466. if (!pLastSyncTime) {
  467. return STATUS_INVALID_PARAMETER_3;
  468. }
  469. Status = RtlAppendUnicodeStringToString(&UniUpdateName,
  470. pUserBasePath);
  471. if (NT_SUCCESS(Status)) {
  472. Status = RtlAppendUnicodeToString(&UniUpdateName,
  473. L"\\inifile.upd");
  474. }
  475. if (! NT_SUCCESS(Status)) {
  476. return Status;
  477. }
  478. pLastSyncTime->LowPart = 0;
  479. pLastSyncTime->HighPart = 0;
  480. InitializeObjectAttributes( &ObjAUpd,
  481. &UniUpdateName,
  482. OBJ_CASE_INSENSITIVE,
  483. NULL,
  484. NULL
  485. );
  486. // Open the update log
  487. Iosb.Status = STATUS_SUCCESS;
  488. Status = NtOpenFile( &hUpdate,
  489. FILE_GENERIC_READ,
  490. &ObjAUpd,
  491. &Iosb,
  492. FILE_SHARE_READ|FILE_SHARE_WRITE,
  493. FILE_SYNCHRONOUS_IO_NONALERT // OpenOptions
  494. );
  495. // Get the size of the file
  496. if (NT_SUCCESS( Status )) {
  497. Status = NtQueryInformationFile( hUpdate,
  498. &Iosb,
  499. &StandardInfo,
  500. sizeof(StandardInfo),
  501. FileStandardInformation
  502. );
  503. if (Status == STATUS_BUFFER_OVERFLOW) {
  504. Status = STATUS_SUCCESS;
  505. }
  506. #if DBG
  507. else if (!NT_SUCCESS( Status )) {
  508. DbgPrint( "TermsrvGetSyncTime: Unable to QueryInformation for %wZ - Status == %x\n", &UniUpdateName, Status );
  509. }
  510. #endif
  511. }
  512. if (NT_SUCCESS( Status )) {
  513. ulBuffSize = StandardInfo.EndOfFile.LowPart + 4 * sizeof(WCHAR);
  514. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  515. &pBuff,
  516. 0,
  517. &ulBuffSize,
  518. MEM_RESERVE,
  519. PAGE_READWRITE
  520. );
  521. }
  522. if (NT_SUCCESS( Status )) {
  523. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  524. &pBuff,
  525. 0,
  526. &ulBuffSize,
  527. MEM_COMMIT,
  528. PAGE_READWRITE
  529. );
  530. }
  531. if (NT_SUCCESS( Status )) {
  532. Status = NtReadFile( hUpdate,
  533. NULL,
  534. NULL,
  535. NULL,
  536. &Iosb,
  537. pBuff,
  538. StandardInfo.EndOfFile.LowPart,
  539. NULL,
  540. NULL
  541. );
  542. if ( Status == STATUS_PENDING ) {
  543. Status = NtWaitForSingleObject( hUpdate, FALSE, NULL );
  544. }
  545. if ( NT_SUCCESS(Status) ) {
  546. // Get final I/O status
  547. Status = Iosb.Status;
  548. }
  549. }
  550. // Look for this ini file in the list
  551. if (NT_SUCCESS(Status)) {
  552. pwch = (PWCHAR)pBuff;
  553. pBuffEnd = pBuff + StandardInfo.EndOfFile.LowPart;
  554. // Look for the file in the sorted list
  555. while ((pwch < (PWCHAR)pBuffEnd) &&
  556. ((lresult = _wcsicmp(pwch, pSysIniPath->Buffer)) < 0)) {
  557. pwch += wcslen(pwch) + sizeof(LARGE_INTEGER)/sizeof(WCHAR) + 1;
  558. }
  559. if ((pwch < (PWCHAR)pBuffEnd) && (lresult == 0)) {
  560. pwch += wcslen(pwch) + 1;
  561. pLastSyncTime->LowPart = ((LARGE_INTEGER UNALIGNED *)pwch)->LowPart;
  562. pLastSyncTime->HighPart = ((LARGE_INTEGER UNALIGNED *)pwch)->HighPart;
  563. }
  564. }
  565. if (NT_SUCCESS(Status) ) {
  566. // Get final I/O status
  567. Status = Iosb.Status;
  568. }
  569. if (pBuff) {
  570. NtFreeVirtualMemory( NtCurrentProcess(),
  571. &pBuff,
  572. &ulBuffSize,
  573. MEM_RELEASE
  574. );
  575. }
  576. if (hUpdate) {
  577. Status = NtClose( hUpdate );
  578. }
  579. return(Status);
  580. }
  581. /*****************************************************************************
  582. *
  583. * TermsrvPutSyncTime
  584. *
  585. * This routine will write the time of the system ini file that the user ini
  586. * file was last sync'd with.
  587. *
  588. * ENTRY:
  589. * PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path
  590. * PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path
  591. * PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time
  592. *
  593. * EXIT:
  594. * STATUS_SUCCESS - successfully stored the last sync time in infile.upd
  595. *
  596. ****************************************************************************/
  597. NTSTATUS
  598. TermsrvPutSyncTime(
  599. PUNICODE_STRING pSysIniPath,
  600. PUNICODE_STRING pUserBasePath,
  601. PLARGE_INTEGER pLastSyncTime)
  602. {
  603. NTSTATUS Status;
  604. HANDLE hUpdate = NULL;
  605. OBJECT_ATTRIBUTES ObjAUpd;
  606. IO_STATUS_BLOCK Iosb;
  607. FILE_STANDARD_INFORMATION StandardInfo;
  608. WCHAR wcUpdateFile[MAX_PATH+1];
  609. UNICODE_STRING UniUpdateName = {0,
  610. sizeof(wcUpdateFile),
  611. wcUpdateFile};
  612. PCHAR pBuff = NULL, pBuffEnd;
  613. PWCH pwch;
  614. SIZE_T ulBuffSize;
  615. ULONG ulLength;
  616. SIZE_T ulRegionSize;
  617. LONG lresult;
  618. LARGE_INTEGER FileLength;
  619. FILE_POSITION_INFORMATION CurrentPos;
  620. if (!pSysIniPath) {
  621. return STATUS_INVALID_PARAMETER_1;
  622. }
  623. if (!pUserBasePath) {
  624. return STATUS_INVALID_PARAMETER_2;
  625. }
  626. if (!pLastSyncTime) {
  627. return STATUS_INVALID_PARAMETER_3;
  628. }
  629. Status = RtlAppendUnicodeStringToString(&UniUpdateName,
  630. pUserBasePath);
  631. if (NT_SUCCESS(Status)) {
  632. Status = RtlAppendUnicodeToString(&UniUpdateName,
  633. L"\\inifile.upd");
  634. }
  635. if (! NT_SUCCESS(Status)) {
  636. return Status;
  637. }
  638. InitializeObjectAttributes( &ObjAUpd,
  639. &UniUpdateName,
  640. OBJ_CASE_INSENSITIVE,
  641. NULL,
  642. NULL
  643. );
  644. // Open the update log
  645. Iosb.Status = STATUS_SUCCESS;
  646. Status = NtCreateFile( &hUpdate,
  647. FILE_READ_DATA | FILE_WRITE_DATA |
  648. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  649. &ObjAUpd,
  650. &Iosb,
  651. NULL, // Allocation size
  652. FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
  653. FILE_SHARE_WRITE, // dwShareMode
  654. FILE_OPEN_IF, // CreateDisposition
  655. FILE_SYNCHRONOUS_IO_NONALERT |
  656. FILE_NON_DIRECTORY_FILE, // CreateFlags
  657. NULL, // EaBuffer
  658. 0 // EaLength
  659. );
  660. if (NT_SUCCESS( Status )) {
  661. Status = NtQueryInformationFile( hUpdate,
  662. &Iosb,
  663. &StandardInfo,
  664. sizeof(StandardInfo),
  665. FileStandardInformation
  666. );
  667. if (Status == STATUS_BUFFER_OVERFLOW) {
  668. Status = STATUS_SUCCESS;
  669. }
  670. #if DBG
  671. else if (!NT_SUCCESS( Status )) {
  672. DbgPrint( "TermsrvPutLastSyncTime: Unable to QueryInformation for %wZ - Status == %x\n", &UniUpdateName, Status );
  673. }
  674. #endif
  675. }
  676. if (NT_SUCCESS( Status )) {
  677. ulBuffSize = StandardInfo.EndOfFile.LowPart + 4 * sizeof(WCHAR);
  678. ulRegionSize = ulBuffSize + 0x1000; // Room for 4K of growth
  679. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  680. &pBuff,
  681. 0,
  682. &ulRegionSize,
  683. MEM_RESERVE,
  684. PAGE_READWRITE
  685. );
  686. }
  687. if (NT_SUCCESS( Status )) {
  688. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  689. &pBuff,
  690. 0,
  691. &ulBuffSize,
  692. MEM_COMMIT,
  693. PAGE_READWRITE
  694. );
  695. }
  696. if (NT_SUCCESS( Status ) && StandardInfo.EndOfFile.LowPart) {
  697. Status = NtReadFile( hUpdate,
  698. NULL,
  699. NULL,
  700. NULL,
  701. &Iosb,
  702. pBuff,
  703. StandardInfo.EndOfFile.LowPart,
  704. NULL,
  705. NULL
  706. );
  707. if ( Status == STATUS_PENDING ) {
  708. Status = NtWaitForSingleObject( hUpdate, FALSE, NULL );
  709. }
  710. if ( NT_SUCCESS(Status) ) {
  711. // Get final I/O status
  712. Status = Iosb.Status;
  713. }
  714. }
  715. // Look for this ini file in the list
  716. if (NT_SUCCESS(Status)) {
  717. pwch = (PWCHAR)pBuff;
  718. pBuffEnd = pBuff + StandardInfo.EndOfFile.LowPart;
  719. // Look for the file in the list
  720. while ((pwch < (PWCHAR)pBuffEnd) &&
  721. ((lresult = _wcsicmp(pwch, pSysIniPath->Buffer)) < 0)) {
  722. pwch += wcslen(pwch) + (sizeof(LARGE_INTEGER)/sizeof(WCHAR)) + 1;
  723. }
  724. // If the ini file is already in the file, just update the time
  725. if ((pwch < (PWCHAR)pBuffEnd) && (lresult == 0)) {
  726. pwch += wcslen(pwch) + 1;
  727. ((PLARGE_INTEGER)pwch)->LowPart = pLastSyncTime->LowPart;
  728. ((PLARGE_INTEGER)pwch)->HighPart = pLastSyncTime->HighPart;
  729. } else { // Ini file not in list
  730. // Figure out the size to grow the file
  731. ulLength = (pSysIniPath->Length + 2) + sizeof(LARGE_INTEGER);
  732. ulBuffSize += ulLength;
  733. // Grow the memory region
  734. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  735. &pBuff,
  736. 0,
  737. &ulBuffSize,
  738. MEM_COMMIT,
  739. PAGE_READWRITE
  740. );
  741. if (NT_SUCCESS(Status)) {
  742. // figure out where the entry goes in the file
  743. if (pwch < (PWCHAR)pBuffEnd) {
  744. RtlMoveMemory( pwch+(ulLength/sizeof(WCHAR)),
  745. pwch,
  746. pBuffEnd - (PCHAR)pwch
  747. );
  748. }
  749. pBuffEnd += ulLength;
  750. wcscpy(pwch, pSysIniPath->Buffer);
  751. pwch += (pSysIniPath->Length + 2)/sizeof(WCHAR);
  752. ((PLARGE_INTEGER)pwch)->LowPart = pLastSyncTime->LowPart;
  753. ((PLARGE_INTEGER)pwch)->HighPart = pLastSyncTime->HighPart;
  754. }
  755. }
  756. }
  757. if (NT_SUCCESS(Status)) {
  758. CurrentPos.CurrentByteOffset.LowPart = 0;
  759. CurrentPos.CurrentByteOffset.HighPart = 0;
  760. Status = NtSetInformationFile( hUpdate,
  761. &Iosb,
  762. &CurrentPos,
  763. sizeof(CurrentPos),
  764. FilePositionInformation
  765. );
  766. Status = NtWriteFile( hUpdate,
  767. NULL,
  768. NULL,
  769. NULL,
  770. &Iosb,
  771. pBuff,
  772. (ULONG)(pBuffEnd - pBuff + 1),
  773. NULL,
  774. NULL
  775. );
  776. if( Status == STATUS_PENDING ) {
  777. Status = NtWaitForSingleObject( hUpdate, FALSE, NULL );
  778. }
  779. if( NT_SUCCESS(Status) ) {
  780. // Get final I/O status
  781. Status = Iosb.Status;
  782. }
  783. }
  784. if (NT_SUCCESS( Status )) {
  785. FileLength.LowPart = (ULONG)(pBuffEnd - pBuff);
  786. FileLength.HighPart = 0;
  787. Status = NtSetInformationFile( hUpdate,
  788. &Iosb,
  789. &FileLength,
  790. sizeof( FileLength ),
  791. FileEndOfFileInformation
  792. );
  793. }
  794. if (pBuff) {
  795. NtFreeVirtualMemory( NtCurrentProcess(),
  796. &pBuff,
  797. &ulRegionSize,
  798. MEM_RELEASE
  799. );
  800. }
  801. if (hUpdate) {
  802. Status = NtClose( hUpdate );
  803. }
  804. return(Status);
  805. }
  806. /*****************************************************************************
  807. *
  808. * TermsrvCheckIniSync
  809. *
  810. * This routine will get the time of the system ini file that the user ini
  811. * file was last sync'd with.
  812. *
  813. * ENTRY:
  814. * PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path
  815. * PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path
  816. * BOOLEAN fGet (In) - TRUE means to get last sync time, FALSE means to write it
  817. * PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time
  818. *
  819. * EXIT:
  820. * TRUE - User ini file should be sync'd
  821. * FALSE - User ini file should be sync'd
  822. *
  823. ****************************************************************************/
  824. BOOLEAN
  825. TermsrvCheckIniSync(
  826. PUNICODE_STRING pSysIniPath,
  827. PUNICODE_STRING pUserBasePath)
  828. {
  829. LARGE_INTEGER LastSyncTime;
  830. OBJECT_ATTRIBUTES objaIni;
  831. FILE_NETWORK_OPEN_INFORMATION BasicInfo;
  832. NTSTATUS Status;
  833. // Get the last sync time of the ini file from the inifile.upd file
  834. Status = TermsrvGetSyncTime(pSysIniPath, pUserBasePath, &LastSyncTime);
  835. if (!NT_SUCCESS(Status) )
  836. {
  837. return FALSE; // if we can't get the time, no point doing an update.
  838. }
  839. // Get the last write time of the system ini file
  840. InitializeObjectAttributes(
  841. &objaIni,
  842. pSysIniPath,
  843. OBJ_CASE_INSENSITIVE,
  844. NULL,
  845. NULL
  846. );
  847. // Now query it
  848. Status = NtQueryFullAttributesFile( &objaIni, &BasicInfo );
  849. // If we couldn't get the time or the system ini file has been updated
  850. // since we last sync'd, return TRUE
  851. if (!NT_SUCCESS(Status) ||
  852. ((BasicInfo.LastWriteTime.HighPart > LastSyncTime.HighPart) ||
  853. ((BasicInfo.LastWriteTime.HighPart == LastSyncTime.HighPart) &&
  854. (BasicInfo.LastWriteTime.LowPart > LastSyncTime.LowPart)))) {
  855. return(TRUE);
  856. }
  857. return(FALSE);
  858. }
  859. /*****************************************************************************
  860. *
  861. * TermsrvDoesFileExist
  862. *
  863. * Returns whether the file exists or not.
  864. *
  865. * Must use NT, not WIN32 pathnames.
  866. *
  867. * ENTRY:
  868. * Param1 (input/output)
  869. * Comments
  870. *
  871. * EXIT:
  872. * STATUS_SUCCESS - no error
  873. *
  874. ****************************************************************************/
  875. BOOL
  876. TermsrvDoesFileExist(
  877. PUNICODE_STRING pFileName
  878. )
  879. {
  880. NTSTATUS Status;
  881. FILE_BASIC_INFORMATION BasicInfo;
  882. OBJECT_ATTRIBUTES Obja;
  883. InitializeObjectAttributes(
  884. &Obja,
  885. pFileName,
  886. OBJ_CASE_INSENSITIVE,
  887. NULL,
  888. NULL
  889. );
  890. /*
  891. * Now query it
  892. */
  893. Status = NtQueryAttributesFile( &Obja, &BasicInfo );
  894. if( NT_SUCCESS( Status ) ) {
  895. return( TRUE );
  896. }
  897. return( FALSE );
  898. }
  899. /*****************************************************************************
  900. *
  901. * TermsrvSyncUserIniFile
  902. *
  903. * This routine will check that the user's ini file is "sync'd" with the
  904. * system version of the ini file. This means that it walks through the
  905. * system ini file and checks that there is a corresponding entry in the
  906. * user's ini file.
  907. *
  908. * ENTRY:
  909. * IN PINIFILE_PARAMETERS a - ptr to inifile structure
  910. *
  911. * EXIT:
  912. * True - Ini file updated
  913. * False - User Ini file was unchanged
  914. *
  915. ****************************************************************************/
  916. BOOL TermsrvSyncUserIniFile(PINIFILE_PARAMETERS a)
  917. {
  918. WCHAR wcIniPath[MAX_PATH+1];
  919. PWCHAR pIniPathEnd;
  920. UNICODE_STRING IniFilePath = {MAX_PATH * sizeof(WCHAR),
  921. (MAX_PATH+1) * sizeof(WCHAR),
  922. wcIniPath};
  923. HRESULT hr;
  924. size_t cbIniPathRemaining;
  925. PWCH pwch, pwcIniName = NULL;
  926. UNICODE_STRING UniSysPath;
  927. UNICODE_STRING UserBasePath;
  928. NTSTATUS Status;
  929. HANDLE SrcHandle;
  930. ULONG ulCompatFlags;
  931. OBJECT_ATTRIBUTES SrcObja;
  932. IO_STATUS_BLOCK SrcIosb;
  933. INIFILE_OPERATION OrigOperation;
  934. BOOLEAN OrigWrite, OrigMultiValue, OrigUnicode,
  935. OrigWriteOperation, fIniUpdated = FALSE;
  936. ANSI_STRING OrigAppName, OrigVarName;
  937. ULONG OrigResultChars, OrigResultMaxChars;
  938. LPSTR OrigResultBuffer;
  939. OBJECT_ATTRIBUTES objaIni;
  940. FILE_NETWORK_OPEN_INFORMATION BasicInfo;
  941. // If INI file mapping is not on, return
  942. if (IsSystemLUID() || TermsrvAppInstallMode()) {
  943. return(FALSE);
  944. }
  945. // Build full system path to the Ini file, and get BasePath to user dir
  946. if ((gpTermsrvBuildSysIniPath == NULL) || !(gpTermsrvBuildSysIniPath(&a->NtFileName, &UniSysPath, &UserBasePath))) {
  947. #if DBG
  948. //DbgPrint("TermsrvSyncUserIniFile: Error building Sys Ini Path!\n");
  949. #endif
  950. return(FALSE);
  951. }
  952. // From here on out, execute the cleanup code.
  953. // Get the ini file name
  954. pwch = wcsrchr(a->NtFileName.Buffer, L'\\') ;
  955. if (pwch == NULL) {
  956. goto Cleanup;
  957. } else{
  958. pwch++;
  959. }
  960. pwcIniName = RtlAllocateHeap( RtlProcessHeap(),
  961. 0,
  962. (wcslen(pwch) + 1)*sizeof(WCHAR));
  963. if (pwcIniName == NULL) {
  964. goto Cleanup;
  965. }
  966. wcscpy(pwcIniName, pwch);
  967. pwch = wcsrchr(pwcIniName, L'.');
  968. if (pwch) {
  969. *pwch = L'\0';
  970. }
  971. if (gpGetTermsrCompatFlags)
  972. {
  973. if ( ! gpGetTermsrCompatFlags(pwcIniName, &ulCompatFlags, CompatibilityIniFile) )
  974. {
  975. goto Cleanup;
  976. }
  977. }
  978. else
  979. {
  980. goto Cleanup;
  981. }
  982. // If the INISYNC compatibility flag is set in the registry and the
  983. // system version of the ini file exists, sync up the user version
  984. if (((ulCompatFlags & (TERMSRV_COMPAT_INISYNC | TERMSRV_COMPAT_WIN16)) ==
  985. (TERMSRV_COMPAT_INISYNC | TERMSRV_COMPAT_WIN16)) &&
  986. TermsrvDoesFileExist(&UniSysPath) &&
  987. TermsrvCheckIniSync(&UniSysPath, &UserBasePath)) {
  988. // Create a backup copy of the original file (inifile.ctx)
  989. hr = StringCbCopyExW(wcIniPath,
  990. sizeof(wcIniPath),
  991. UserBasePath.Buffer,
  992. &pIniPathEnd,
  993. &cbIniPathRemaining,
  994. 0);
  995. if (FAILED(hr)) {
  996. goto Cleanup;
  997. }
  998. if (UserBasePath.Buffer[UserBasePath.Length/sizeof(WCHAR) - 1] != L'\\') {
  999. hr = StringCbCatExW(pIniPathEnd,
  1000. cbIniPathRemaining,
  1001. L"\\",
  1002. &pIniPathEnd,
  1003. &cbIniPathRemaining,
  1004. 0);
  1005. if (FAILED(hr)) {
  1006. goto Cleanup;
  1007. }
  1008. }
  1009. hr = StringCbCatExW(pIniPathEnd,
  1010. cbIniPathRemaining,
  1011. pwcIniName,
  1012. &pIniPathEnd,
  1013. &cbIniPathRemaining,
  1014. 0);
  1015. if (FAILED(hr)) {
  1016. goto Cleanup;
  1017. }
  1018. hr = StringCbCatExW(pIniPathEnd,
  1019. cbIniPathRemaining,
  1020. L".ctx",
  1021. &pIniPathEnd,
  1022. &cbIniPathRemaining,
  1023. 0);
  1024. if (FAILED(hr)) {
  1025. goto Cleanup;
  1026. }
  1027. IniFilePath.Length = (USHORT)((LPBYTE)pIniPathEnd - (LPBYTE)wcIniPath);
  1028. if (gpTermsrvCopyIniFile) {
  1029. BOOL copy_result = gpTermsrvCopyIniFile(&a->NtFileName, NULL, &IniFilePath);
  1030. #if DBG
  1031. if (!copy_result) {
  1032. DbgPrint("TermsrvSyncUserIniFile: Error creating backup ini file %ws\n",
  1033. wcIniPath);
  1034. }
  1035. #endif
  1036. } else {
  1037. goto Cleanup;
  1038. }
  1039. // Check that each entry in the system version is in the user's version
  1040. InitializeObjectAttributes(&SrcObja,
  1041. &UniSysPath,
  1042. OBJ_CASE_INSENSITIVE,
  1043. NULL,
  1044. NULL);
  1045. // Open the src
  1046. SrcIosb.Status = STATUS_SUCCESS;
  1047. Status = NtOpenFile(&SrcHandle,
  1048. FILE_GENERIC_READ,
  1049. &SrcObja,
  1050. &SrcIosb,
  1051. FILE_SHARE_READ|FILE_SHARE_WRITE,
  1052. FILE_SYNCHRONOUS_IO_NONALERT);
  1053. if( NT_SUCCESS(Status) ) {
  1054. // Get final I/O status
  1055. Status = SrcIosb.Status;
  1056. }
  1057. if( !NT_SUCCESS(Status) ) {
  1058. #if DBG
  1059. DbgPrint("TermsrvSyncUserIniFile: Error 0x%x opening SrcFile %ws\n",
  1060. Status,
  1061. &UniSysPath.Buffer);
  1062. #endif
  1063. goto Cleanup;
  1064. }
  1065. // Save the original values
  1066. OrigOperation = a->Operation;
  1067. OrigMultiValue = a->MultiValueStrings;
  1068. OrigAppName = a->ApplicationName;
  1069. OrigVarName = a->VariableName;
  1070. OrigResultChars = a->ResultChars;
  1071. OrigResultMaxChars = a->ResultMaxChars;
  1072. OrigResultBuffer = a->ResultBuffer;
  1073. OrigUnicode = a->Unicode;
  1074. OrigWriteOperation = a->WriteOperation;
  1075. // Set up the open for writes
  1076. a->WriteOperation = TRUE;
  1077. a->Operation = WriteKeyValue;
  1078. a->MultiValueStrings = FALSE;
  1079. a->Unicode = FALSE;
  1080. Status = BaseDllOpenIniFileOnDisk( a );
  1081. if( !NT_SUCCESS(Status) ) {
  1082. #if DBG
  1083. DbgPrint("TermsrvSyncUserIniFile: Error 0x%x opening DestFile %ws\n",
  1084. Status,
  1085. &a->NtFileName.Buffer);
  1086. #endif
  1087. NtClose( SrcHandle );
  1088. goto Cleanup;
  1089. }
  1090. // set the data up for writing
  1091. a->TextEnd = (PCHAR)a->IniFile->BaseAddress +
  1092. a->IniFile->EndOfFile;
  1093. a->TextCurrent = a->IniFile->BaseAddress;
  1094. // Make sure entries in system ini file are in user ini file
  1095. Status = TermsrvIniSyncLoop( SrcHandle, a, &fIniUpdated );
  1096. #if DBG
  1097. if( !NT_SUCCESS(Status) ) {
  1098. DbgPrint("TermsrvSyncUserIniFile: Error 0x%x Doing sync loop\n",Status);
  1099. }
  1100. #endif
  1101. // Close the file handles
  1102. NtClose( SrcHandle );
  1103. BaseDllCloseIniFileOnDisk( a );
  1104. // Restore the variables in the ini file structure
  1105. a->Operation = OrigOperation;
  1106. a->MultiValueStrings = OrigMultiValue;
  1107. a->ApplicationName = OrigAppName;
  1108. a->VariableName = OrigVarName;
  1109. a->ResultChars = OrigResultChars;
  1110. a->ResultMaxChars = OrigResultMaxChars;
  1111. a->ResultBuffer = OrigResultBuffer;
  1112. a->WriteOperation = FALSE;
  1113. a->Unicode = OrigUnicode;
  1114. a->WriteOperation = OrigWriteOperation;
  1115. // Get the last write time of the system ini file
  1116. InitializeObjectAttributes( &objaIni,
  1117. &UniSysPath,
  1118. OBJ_CASE_INSENSITIVE,
  1119. NULL,
  1120. NULL
  1121. );
  1122. // Now query it
  1123. Status = NtQueryFullAttributesFile( &objaIni, &BasicInfo );
  1124. // Update the sync time in the inisync file
  1125. if (NT_SUCCESS(Status)) {
  1126. TermsrvPutSyncTime( &UniSysPath,
  1127. &UserBasePath,
  1128. &BasicInfo.LastWriteTime
  1129. );
  1130. }
  1131. }
  1132. Cleanup:
  1133. // Free the unicode buffers
  1134. if (UniSysPath.Buffer) {
  1135. RtlFreeHeap( RtlProcessHeap(), 0, UniSysPath.Buffer );
  1136. }
  1137. if (UserBasePath.Buffer) {
  1138. RtlFreeHeap( RtlProcessHeap(), 0, UserBasePath.Buffer );
  1139. }
  1140. if (pwcIniName) {
  1141. RtlFreeHeap( RtlProcessHeap(), 0, pwcIniName);
  1142. }
  1143. return(fIniUpdated);
  1144. }
  1145. /*****************************************************************************
  1146. *
  1147. * TermsrvIniSyncLoop
  1148. *
  1149. * This routine will verify that there's a corresponding entry in the user's
  1150. * ini file for each entry in the system ini file.
  1151. *
  1152. * ENTRY:
  1153. * HANDLE SrcHandle (INPUT) - Handle to system ini file
  1154. * PINIFILE_PARAMETERS a (INPUT) - pointer to current ini file structure
  1155. * PBOOLEAN pfIniUpdated (OUTPUT) - Returns TRUE if user ini file is modified
  1156. *
  1157. * EXIT:
  1158. * STATUS_SUCCESS - no error
  1159. *
  1160. ****************************************************************************/
  1161. NTSTATUS
  1162. TermsrvIniSyncLoop(HANDLE SrcHandle,
  1163. PINIFILE_PARAMETERS a,
  1164. PBOOLEAN pfIniUpdated)
  1165. {
  1166. PCHAR pStr;
  1167. NTSTATUS Status;
  1168. ULONG StringSize;
  1169. CHAR IOBuf[512];
  1170. ULONG IOBufSize = 512;
  1171. ULONG IOBufIndex = 0;
  1172. ULONG IOBufFillSize = 0;
  1173. ANSI_STRING AnsiSection;
  1174. PCH pch;
  1175. PVOID pSection, origbase;
  1176. AnsiSection.Buffer = NULL;
  1177. *pfIniUpdated = FALSE;
  1178. while( 1 ) {
  1179. pStr = NULL;
  1180. StringSize = 0;
  1181. if (gpTermsrvGetString == NULL) {
  1182. return STATUS_UNSUCCESSFUL;
  1183. }
  1184. // Get a string from the source ini file
  1185. Status = gpTermsrvGetString(SrcHandle,
  1186. &pStr,
  1187. &StringSize,
  1188. IOBuf,
  1189. IOBufSize,
  1190. &IOBufIndex,
  1191. &IOBufFillSize);
  1192. if( !NT_SUCCESS(Status) ) {
  1193. ASSERT( pStr == NULL );
  1194. if( Status == STATUS_END_OF_FILE ) {
  1195. Status = STATUS_SUCCESS;
  1196. }
  1197. if (AnsiSection.Buffer) {
  1198. RtlFreeHeap( RtlProcessHeap(), 0, AnsiSection.Buffer );
  1199. }
  1200. a->IniFile->UpdateEndOffset = a->IniFile->EndOfFile;
  1201. return( Status );
  1202. }
  1203. // Make sure we got some actual data
  1204. ASSERT( pStr != NULL );
  1205. // Is this a section name?
  1206. if (*pStr == '[') {
  1207. if (AnsiSection.Buffer) {
  1208. RtlFreeHeap( RtlProcessHeap(), 0, AnsiSection.Buffer );
  1209. AnsiSection.Buffer = NULL;
  1210. }
  1211. pch = strrchr(pStr, ']');
  1212. if (pch) {
  1213. AnsiSection.MaximumLength = (USHORT)(pch - pStr);
  1214. *pch = '\0';
  1215. } else {
  1216. AnsiSection.Length = (USHORT)strlen(pStr);
  1217. }
  1218. AnsiSection.Length = AnsiSection.MaximumLength - 1;
  1219. AnsiSection.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  1220. 0,
  1221. AnsiSection.MaximumLength);
  1222. if (!AnsiSection.Buffer) {
  1223. return STATUS_INSUFFICIENT_RESOURCES;
  1224. }
  1225. strcpy(AnsiSection.Buffer, pStr+1);
  1226. a->ApplicationName = AnsiSection;
  1227. a->TextCurrent = a->IniFile->BaseAddress; // reset file pointer
  1228. // See if the section already exists, if so save the start of it
  1229. Status = BaseDllFindSection( a );
  1230. if (NT_SUCCESS(Status)) {
  1231. pSection = a->TextCurrent;
  1232. } else {
  1233. pSection = NULL;
  1234. }
  1235. // If it's not a comment, see if the entry is in the user's ini file
  1236. } else if (*pStr != ';') {
  1237. pch = strchr(pStr, '=');
  1238. if (pch) {
  1239. a->VariableName.Length = a->VariableName.MaximumLength =
  1240. (USHORT)(pch - pStr);
  1241. a->VariableName.Buffer = pStr;
  1242. a->ValueBuffer = (++pch);
  1243. a->ValueLength = 0;
  1244. while (*pch && (*pch != 0xa) && (*pch != 0xd)) {
  1245. pch++;
  1246. a->ValueLength++;
  1247. }
  1248. // If the section exists, check for the keyword in user's ini
  1249. if (pSection) {
  1250. a->TextCurrent = pSection;
  1251. Status = BaseDllFindKeyword( a );
  1252. }
  1253. // If variable isn't found, write it out
  1254. if (!pSection || !NT_SUCCESS( Status )) {
  1255. origbase = a->TextCurrent = a->IniFile->BaseAddress;
  1256. Status = BaseDllWriteKeywordValue( a, NULL );
  1257. a->TextEnd = (PCHAR)a->IniFile->BaseAddress +
  1258. a->IniFile->EndOfFile;
  1259. if (!NT_SUCCESS(Status)) {
  1260. #if DBG
  1261. DbgPrint("TermsrvIniSyncLoop: Error 0x%x write Key Value\n",
  1262. Status);
  1263. #endif
  1264. a->IniFile->UpdateEndOffset = a->IniFile->EndOfFile;
  1265. RtlFreeHeap( RtlProcessHeap(), 0, pStr );
  1266. if (AnsiSection.Buffer) {
  1267. RtlFreeHeap(RtlProcessHeap(),
  1268. 0,
  1269. AnsiSection.Buffer);
  1270. }
  1271. return(Status);
  1272. }
  1273. *pfIniUpdated = TRUE;
  1274. if (origbase != a->IniFile->BaseAddress) {
  1275. a->TextCurrent = a->IniFile->BaseAddress;
  1276. Status = BaseDllFindSection( a );
  1277. if (NT_SUCCESS(Status)) {
  1278. pSection = a->TextCurrent;
  1279. } else {
  1280. pSection = NULL;
  1281. }
  1282. }
  1283. }
  1284. }
  1285. }
  1286. } // end while(1)
  1287. }
  1288. /******************************************************************************
  1289. *
  1290. * GetPerUserWindowsDirectory
  1291. *
  1292. *
  1293. *
  1294. *****************************************************************************/
  1295. NTSTATUS
  1296. GetPerUserWindowsDirectory(
  1297. OUT PWCHAR TermSrvWindowsPath,
  1298. IN SIZE_T InLength,
  1299. OUT PSIZE_T OutLength
  1300. )
  1301. {
  1302. static const UNICODE_STRING BaseHomePathVariableName = RTL_CONSTANT_STRING(L"HOMEPATH");
  1303. static const UNICODE_STRING BaseHomeDriveVariableName = RTL_CONSTANT_STRING(L"HOMEDRIVE");
  1304. NTSTATUS Status;
  1305. UNICODE_STRING Path;
  1306. BOOL TSAppCompatEnabled;
  1307. UNICODE_STRING UnicodeString_TermSrvWindowsPath;
  1308. *OutLength = 0;
  1309. Status = IsTSAppCompatEnabled(&TSAppCompatEnabled);
  1310. if (!NT_SUCCESS(Status)) {
  1311. goto Exit;
  1312. }
  1313. if (!TSAppCompatEnabled) {
  1314. Status = STATUS_SUCCESS;
  1315. goto Exit;
  1316. }
  1317. if (IsSystemLUID()) {
  1318. Status = STATUS_SUCCESS;
  1319. goto Exit;
  1320. }
  1321. if (InLength < MAX_PATH) {
  1322. Status = STATUS_INVALID_PARAMETER;
  1323. goto Exit;
  1324. }
  1325. /*
  1326. * Check for HOMEDRIVE and HOMEPATH
  1327. */
  1328. Path.Buffer = TermSrvWindowsPath;
  1329. Path.Length = 0;
  1330. Path.MaximumLength = (MAX_PATH * sizeof(WCHAR)) - (9 * sizeof(WCHAR)); //MAX_PATH - wcslen(L"\\WINDOWS") + 1
  1331. Status = RtlQueryEnvironmentVariable_U(
  1332. NULL,
  1333. &BaseHomeDriveVariableName,
  1334. &Path);
  1335. if (NT_SUCCESS(Status)) {
  1336. UnicodeString_TermSrvWindowsPath.Buffer = TermSrvWindowsPath;
  1337. UnicodeString_TermSrvWindowsPath.MaximumLength = (RTL_STRING_LENGTH_TYPE)(InLength * sizeof(UnicodeString_TermSrvWindowsPath.Buffer[0]));
  1338. UnicodeString_TermSrvWindowsPath.Length = Path.Length;
  1339. Path.MaximumLength -= Path.Length;
  1340. Path.Buffer += Path.Length / sizeof(Path.Buffer[0]);
  1341. Path.Length = 0;
  1342. Status = RtlQueryEnvironmentVariable_U(
  1343. NULL,
  1344. &BaseHomePathVariableName,
  1345. &Path);
  1346. if (NT_SUCCESS(Status)) {
  1347. UnicodeString_TermSrvWindowsPath.Length += Path.Length;
  1348. }
  1349. }
  1350. if (!NT_SUCCESS(Status)) {
  1351. goto Exit;
  1352. }
  1353. /*
  1354. * Add a trailing backslash if one's not already there
  1355. */
  1356. if (RTL_STRING_GET_LAST_CHAR(&UnicodeString_TermSrvWindowsPath) != L'\\') {
  1357. RtlAppendUnicodeToString(&UnicodeString_TermSrvWindowsPath, L"\\");
  1358. }
  1359. RtlAppendUnicodeToString(&UnicodeString_TermSrvWindowsPath, L"WINDOWS");
  1360. *OutLength = RTL_STRING_GET_LENGTH_CHARS(&UnicodeString_TermSrvWindowsPath);
  1361. Status = STATUS_SUCCESS;
  1362. Exit:
  1363. if (!NT_SUCCESS(Status)) {
  1364. #if DBG
  1365. DbgPrint("GetPerUserWindowsDirectory Failed with Status %lx\n", Status);
  1366. #endif
  1367. }
  1368. return Status;
  1369. }