termutil.c
上传用户:caisha3
上传日期:2013-09-21
资源大小:208739k
文件大小:39k
源码类别:

Windows编程

开发平台:

Visual C++

  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 "hydraregapi.h"
  12. #define TERMSRV_INIFILE_TIMES L"\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\IniFile Times"
  13. BOOL IsTerminalServerCompatible(VOID)
  14. {
  15. PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader( NtCurrentPeb()->ImageBaseAddress );
  16.     if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) {
  17.         return TRUE;
  18.     } else {
  19.         return FALSE;
  20.     }
  21. }
  22. BOOL IsTSAppCompatEnabled(VOID)
  23. {
  24.    NTSTATUS NtStatus;
  25.    OBJECT_ATTRIBUTES ObjectAttributes;
  26.    UNICODE_STRING UniString;
  27.    HKEY   hKey = 0;
  28.    ULONG  ul, ulcbuf;
  29.    PKEY_VALUE_PARTIAL_INFORMATION pKeyValInfo = NULL;
  30.    BOOL retval = TRUE;
  31.    RtlInitUnicodeString(&UniString,REG_NTAPI_CONTROL_TSERVER);
  32.    // Determine the value info buffer size
  33.    ulcbuf = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR) + 
  34.             sizeof(ULONG);
  35.    pKeyValInfo = RtlAllocateHeap(RtlProcessHeap(), 
  36.                                  0, 
  37.                                  ulcbuf);
  38.    // Did everything initialize OK?
  39.    if (UniString.Buffer && pKeyValInfo) {
  40.        InitializeObjectAttributes(&ObjectAttributes,
  41.                                   &UniString,
  42.                                   OBJ_CASE_INSENSITIVE,
  43.                                   NULL,
  44.                                   NULL
  45.                                  );
  46.    
  47.        NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  48.    
  49.        if (NT_SUCCESS(NtStatus)) {
  50.    
  51.            RtlInitUnicodeString(&UniString, 
  52.                                L"TSAppCompat");
  53.            NtStatus = NtQueryValueKey(hKey,
  54.                                       &UniString,
  55.                                       KeyValuePartialInformation,
  56.                                       pKeyValInfo,
  57.                                       ulcbuf,
  58.                                       &ul);
  59.            if (NT_SUCCESS(NtStatus) && (REG_DWORD == pKeyValInfo->Type)) {
  60.                if ((*(PULONG)pKeyValInfo->Data) == 0) {
  61.                   retval = FALSE;
  62.                }
  63.            }
  64.            NtClose(hKey);
  65.        }
  66.    }
  67.    // Free up the buffers we allocated
  68.    // Need to zero out the buffers, because some apps (MS Internet Assistant)
  69.    // won't install if the heap is not zero filled.
  70.    if (pKeyValInfo) {
  71.        memset(pKeyValInfo, 0, ulcbuf);
  72.        RtlFreeHeap( RtlProcessHeap(), 0, pKeyValInfo );
  73.    }
  74.    return(retval);
  75. }
  76. BOOL IsSystemLUID(VOID)
  77. {
  78.     HANDLE      TokenHandle;
  79.     UCHAR       TokenInformation[ sizeof( TOKEN_STATISTICS ) ];
  80.     ULONG       ReturnLength;
  81.     LUID        CurrentLUID = { 0, 0 };
  82.     LUID        SystemLUID = SYSTEM_LUID;
  83.     NTSTATUS Status;
  84.     if ( CurrentLUID.LowPart == 0 && CurrentLUID.HighPart == 0 ) {
  85.         Status = NtOpenProcessToken( NtCurrentProcess(),
  86.                                      TOKEN_QUERY,
  87.                                      &TokenHandle );
  88.         if ( !NT_SUCCESS( Status ) )
  89.             return(TRUE);
  90.         NtQueryInformationToken( TokenHandle, TokenStatistics, &TokenInformation,
  91.                                  sizeof(TokenInformation), &ReturnLength );
  92.         NtClose( TokenHandle );
  93.         RtlCopyLuid(&CurrentLUID,
  94.                     &(((PTOKEN_STATISTICS)TokenInformation)->AuthenticationId));
  95.     }
  96.     if (RtlEqualLuid(&CurrentLUID, &SystemLUID)) {
  97.         return(TRUE);
  98.     } else {
  99.         return(FALSE );
  100.     }
  101. }
  102. void InitializeTermsrvFpns(void)
  103. {
  104.     HANDLE          dllHandle;
  105.     if (IsTerminalServerCompatible() ||
  106.        (IsSystemLUID()) ||
  107.        (!IsTSAppCompatEnabled())) {
  108.         return;
  109.     }
  110.     //
  111.     // Load Terminal Server application compatibility dll
  112.     //
  113.     dllHandle = LoadLibrary("tsappcmp.dll");
  114.     if (dllHandle) {
  115.         gpTermsrvFormatObjectName =
  116.             (PTERMSRVFORMATOBJECTNAME)GetProcAddress(dllHandle,"TermsrvFormatObjectName");
  117.         gpTermsrvGetComputerName =
  118.             (PTERMSRVGETCOMPUTERNAME)GetProcAddress(dllHandle,"TermsrvGetComputerName");
  119.         gpTermsrvAdjustPhyMemLimits =
  120.                 (PTERMSRVADJUSTPHYMEMLIMITS)GetProcAddress(dllHandle,"TermsrvAdjustPhyMemLimits");
  121.         gpTermsrvGetWindowsDirectoryA =
  122.                 (PTERMSRVGETWINDOWSDIRECTORYA)GetProcAddress(dllHandle,"TermsrvGetWindowsDirectoryA");
  123.         gpTermsrvGetWindowsDirectoryW =
  124.                 (PTERMSRVGETWINDOWSDIRECTORYW)GetProcAddress(dllHandle,"TermsrvGetWindowsDirectoryW");
  125.         gpTermsrvConvertSysRootToUserDir =
  126.                 (PTERMSRVCONVERTSYSROOTTOUSERDIR)GetProcAddress(dllHandle,"TermsrvConvertSysRootToUserDir");
  127.         gpTermsrvBuildIniFileName =
  128.                 (PTERMSRVBUILDINIFILENAME)GetProcAddress(dllHandle,"TermsrvBuildIniFileName");
  129.         gpTermsrvCORIniFile =
  130.                 (PTERMSRVCORINIFILE)GetProcAddress(dllHandle,"TermsrvCORIniFile");
  131.         gpGetTermsrCompatFlags =
  132.                 (PGETTERMSRCOMPATFLAGS)GetProcAddress(dllHandle,"GetTermsrCompatFlags");
  133.         gpTermsrvBuildSysIniPath =
  134.                 (PTERMSRVBUILDSYSINIPATH)GetProcAddress(dllHandle,"TermsrvBuildSysIniPath");
  135.         gpTermsrvCopyIniFile =
  136.         (PTERMSRVCOPYINIFILE)GetProcAddress(dllHandle,"TermsrvCopyIniFile");
  137.         gpTermsrvGetString =
  138.         (PTERMSRVGETSTRING)GetProcAddress(dllHandle,"TermsrvGetString");
  139.         gpTermsrvLogInstallIniFile =
  140.         (PTERMSRVLOGINSTALLINIFILE)GetProcAddress(dllHandle,"TermsrvLogInstallIniFile");
  141.     }
  142. }
  143. /*****************************************************************************
  144.  *
  145.  *  TermsrvAppInstallMode
  146.  *
  147.  *   Returns whether the system is in Install mode or not
  148.  *
  149.  * ENTRY:
  150.  *   Param1 (input/output)
  151.  *     Comments
  152.  *
  153.  * EXIT:
  154.  *   STATUS_SUCCESS - no error
  155.  *
  156.  ****************************************************************************/
  157. WINBASEAPI
  158. BOOL
  159. WINAPI
  160. TermsrvAppInstallMode( VOID )
  161. {
  162.     if ( BaseStaticServerData->fTermsrvAppInstallMode )
  163.         return( TRUE );
  164.     return( FALSE );
  165. }
  166. /*****************************************************************************
  167.  *
  168.  *  SetTermsrvAppInstallMode
  169.  *
  170.  *   Turns App install mode on or off. Default is off
  171.  *
  172.  * ENTRY:
  173.  *   Param1 (input/output)
  174.  *     Comments
  175.  *
  176.  * EXIT:
  177.  *   STATUS_SUCCESS - no error
  178.  *
  179.  ****************************************************************************/
  180. WINBASEAPI
  181. BOOL
  182. WINAPI
  183. SetTermsrvAppInstallMode( BOOL bState )
  184. {
  185.     NTSTATUS Status;
  186. #if defined(BUILD_WOW6432)
  187.     Status = CsrBasepSetTermsrvAppInstallMode(bState);
  188. #else
  189.     BASE_API_MSG m;
  190.     PBASE_SET_TERMSRVAPPINSTALLMODE c= (PBASE_SET_TERMSRVAPPINSTALLMODE)&m.u.SetTermsrvAppInstallMode;
  191.     c->bState = bState;
  192.     Status = CsrClientCallServer((PCSR_API_MSG)&m, NULL,
  193.                                  CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  194.                                                      BasepSetTermsrvAppInstallMode),
  195.                                  sizeof( *c ));
  196. #endif
  197.     if ( !NT_SUCCESS( Status ) ) {
  198.         SetLastError( RtlNtStatusToDosError( Status ) );
  199.         return( FALSE );
  200.     }
  201.     if (IsTerminalServer() && IsTSAppCompatEnabled()) {
  202.         //
  203.         // Load tsappcmp.dll
  204.         //
  205.         if (gpTermsrvUpdateAllUserMenu == NULL) {
  206.             HANDLE          dllHandle;
  207.     
  208.             //
  209.             // Load Terminal Server application compatibility dll
  210.             //
  211.             dllHandle = LoadLibrary("tsappcmp.dll");
  212.     
  213.             if (dllHandle) {
  214.                 gpTermsrvUpdateAllUserMenu =
  215.                         (PTERMSRVUPDATEALLUSERMENU)GetProcAddress(dllHandle,"TermsrvUpdateAllUserMenu");
  216.             }
  217.         }
  218.     
  219.         if (gpTermsrvUpdateAllUserMenu) {
  220.             gpTermsrvUpdateAllUserMenu( bState == TRUE ? 0 : 1 );
  221.         }
  222.     }
  223.     return( TRUE );
  224. }
  225. /////////////////////////////////////////////////////////////////////////////
  226. /////////////////////////////////////////////////////////////////////////////
  227. /*
  228.   Ini File syncing/merging code
  229. */
  230. //////////////////////////////////////////////////////////////////////////////
  231. /* External Functions */
  232. NTSTATUS
  233. BaseDllOpenIniFileOnDisk(
  234.     PINIFILE_PARAMETERS a
  235.     );
  236. NTSTATUS
  237. BaseDllWriteKeywordValue(
  238.     IN PINIFILE_PARAMETERS a,
  239.     IN PUNICODE_STRING VariableName OPTIONAL
  240.     );
  241. NTSTATUS
  242. BaseDllCloseIniFileOnDisk(
  243.     IN PINIFILE_PARAMETERS a
  244.     );
  245. NTSTATUS
  246. BaseDllFindSection(
  247.     IN PINIFILE_PARAMETERS a
  248.     );
  249. NTSTATUS
  250. BaseDllFindKeyword(
  251.     IN PINIFILE_PARAMETERS a
  252.     );
  253. NTSTATUS
  254. TermsrvIniSyncLoop( HANDLE SrcHandle,
  255.                 PINIFILE_PARAMETERS a,
  256.                 PBOOLEAN pfIniUpdated
  257.               );
  258. NTSTATUS
  259. TermsrvGetSyncTime( PUNICODE_STRING pSysIniPath,
  260.                 PUNICODE_STRING pUserBasePath,
  261.                 PLARGE_INTEGER  pLastSyncTime
  262.               );
  263. NTSTATUS
  264. TermsrvPutSyncTime( PUNICODE_STRING pSysIniPath,
  265.                 PUNICODE_STRING pUserBasePath,
  266.                 PLARGE_INTEGER  pLastSyncTime
  267.               );
  268. /*****************************************************************************
  269.  *
  270.  *  TermsrvGetSyncTime
  271.  *
  272.  *  This routine will get the time of the system ini file that the user ini
  273.  *  file was last sync'd with.
  274.  *
  275.  * ENTRY:
  276.  *   PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path
  277.  *   PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path
  278.  *   PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time
  279.  *
  280.  * EXIT:
  281.  *   STATUS_SUCCESS - successfully retrieved the last sync time from infile.upd
  282.  *
  283.  ****************************************************************************/
  284. NTSTATUS
  285. TermsrvGetSyncTime(
  286.     PUNICODE_STRING pSysIniPath,
  287.     PUNICODE_STRING pUserBasePath,
  288.     PLARGE_INTEGER  pLastSyncTime)
  289. {
  290.     NTSTATUS Status;
  291.     HANDLE   hUpdate = NULL;
  292.     OBJECT_ATTRIBUTES ObjAUpd;
  293.     IO_STATUS_BLOCK   Iosb;
  294.     FILE_STANDARD_INFORMATION StandardInfo;
  295.     WCHAR             wcUpdateFile[MAX_PATH+1];
  296.     UNICODE_STRING    UniUpdateName = {0,
  297.                                        sizeof(wcUpdateFile),
  298.                                        wcUpdateFile};
  299.     PCHAR             pBuff = NULL, pBuffEnd;
  300.     PWCH              pwch;
  301.     SIZE_T            ulBuffSize;
  302.     LONG              lresult;
  303.     wcscpy(wcUpdateFile, pUserBasePath->Buffer);
  304.     wcscat(wcUpdateFile, L"\inifile.upd");
  305.     UniUpdateName.Length = wcslen(wcUpdateFile)*sizeof(WCHAR);
  306.     pLastSyncTime->LowPart = 0;
  307.     pLastSyncTime->HighPart = 0;
  308.     InitializeObjectAttributes( &ObjAUpd,
  309.                                 &UniUpdateName,
  310.                                 OBJ_CASE_INSENSITIVE,
  311.                                 NULL,
  312.                                 NULL
  313.                               );
  314.     // Open the update log
  315.     Iosb.Status = STATUS_SUCCESS;
  316.     Status = NtOpenFile( &hUpdate,
  317.                          FILE_GENERIC_READ,
  318.                          &ObjAUpd,
  319.                          &Iosb,
  320.                          FILE_SHARE_READ|FILE_SHARE_WRITE,
  321.                          FILE_SYNCHRONOUS_IO_NONALERT    // OpenOptions
  322.                        );
  323.     // Get the size of the file
  324.     if (NT_SUCCESS( Status )) {
  325.         Status = NtQueryInformationFile( hUpdate,
  326.                                          &Iosb,
  327.                                          &StandardInfo,
  328.                                          sizeof(StandardInfo),
  329.                                          FileStandardInformation
  330.                                        );
  331.         if (Status == STATUS_BUFFER_OVERFLOW) {
  332.             Status = STATUS_SUCCESS;
  333.         }
  334. #if DBG
  335.         else if (!NT_SUCCESS( Status )) {
  336.             DbgPrint( "TermsrvGetSyncTime: Unable to QueryInformation for %wZ - Status == %xn", &UniUpdateName, Status );
  337.         }
  338. #endif
  339.     }
  340.     if (NT_SUCCESS( Status )) {
  341.         ulBuffSize = StandardInfo.EndOfFile.LowPart + 4 * sizeof(WCHAR);
  342.         Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  343.                                           &pBuff,
  344.                                           0,
  345.                                           &ulBuffSize,
  346.                                           MEM_RESERVE,
  347.                                           PAGE_READWRITE
  348.                                         );
  349.     }
  350.     if (NT_SUCCESS( Status )) {
  351.         Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  352.                                           &pBuff,
  353.                                           0,
  354.                                           &ulBuffSize,
  355.                                           MEM_COMMIT,
  356.                                           PAGE_READWRITE
  357.                                         );
  358.     }
  359.     if (NT_SUCCESS( Status )) {
  360.         Status = NtReadFile( hUpdate,
  361.                              NULL,
  362.                              NULL,
  363.                              NULL,
  364.                              &Iosb,
  365.                              pBuff,
  366.                              StandardInfo.EndOfFile.LowPart,
  367.                              NULL,
  368.                              NULL
  369.                            );
  370.         if ( Status == STATUS_PENDING ) {
  371.             Status = NtWaitForSingleObject( hUpdate, FALSE, NULL );
  372.         }
  373.         if ( NT_SUCCESS(Status) ) {
  374.             // Get final I/O status
  375.             Status = Iosb.Status;
  376.         }
  377.     }
  378.     // Look for this ini file in the list
  379.     if (NT_SUCCESS(Status)) {
  380.         pwch = (PWCHAR)pBuff;
  381.         pBuffEnd = pBuff + StandardInfo.EndOfFile.LowPart;
  382.         // Look for the file in the sorted list
  383.         while ((pwch < (PWCHAR)pBuffEnd) &&
  384.                ((lresult = _wcsicmp(pwch, pSysIniPath->Buffer)) < 0)) {
  385.             pwch += wcslen(pwch) + sizeof(LARGE_INTEGER)/sizeof(WCHAR) + 1;
  386.         }
  387.         if ((pwch < (PWCHAR)pBuffEnd) && (lresult == 0)) {
  388.             pwch += wcslen(pwch) + 1;
  389.             pLastSyncTime->LowPart = ((PLARGE_INTEGER)pwch)->LowPart;
  390.             pLastSyncTime->HighPart = ((PLARGE_INTEGER)pwch)->HighPart;
  391.         }
  392.     }
  393.     if (NT_SUCCESS(Status) ) {
  394.         // Get final I/O status
  395.         Status = Iosb.Status;
  396.     }
  397.     if (pBuff) {
  398.         NtFreeVirtualMemory( NtCurrentProcess(),
  399.                              &pBuff,
  400.                              &ulBuffSize,
  401.                              MEM_RELEASE
  402.                            );
  403.     }
  404.     if (hUpdate) {
  405.         Status = NtClose( hUpdate );
  406.     }
  407.     return(Status);
  408. }
  409. /*****************************************************************************
  410.  *
  411.  *  TermsrvPutSyncTime
  412.  *
  413.  *  This routine will write the time of the system ini file that the user ini
  414.  *  file was last sync'd with.
  415.  *
  416.  * ENTRY:
  417.  *   PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path
  418.  *   PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path
  419.  *   PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time
  420.  *
  421.  * EXIT:
  422.  *   STATUS_SUCCESS - successfully stored the last sync time in infile.upd
  423.  *
  424.  ****************************************************************************/
  425. NTSTATUS
  426. TermsrvPutSyncTime(
  427.     PUNICODE_STRING pSysIniPath,
  428.     PUNICODE_STRING pUserBasePath,
  429.     PLARGE_INTEGER  pLastSyncTime)
  430. {
  431.     NTSTATUS Status;
  432.     HANDLE   hUpdate = NULL;
  433.     OBJECT_ATTRIBUTES ObjAUpd;
  434.     IO_STATUS_BLOCK   Iosb;
  435.     FILE_STANDARD_INFORMATION StandardInfo;
  436.     WCHAR             wcUpdateFile[MAX_PATH+1];
  437.     UNICODE_STRING    UniUpdateName = {0,
  438.                                        sizeof(wcUpdateFile),
  439.                                        wcUpdateFile};
  440.     PCHAR             pBuff = NULL, pBuffEnd;
  441.     PWCH              pwch;
  442.     SIZE_T            ulBuffSize;
  443.     ULONG             ulLength;
  444.     SIZE_T            ulRegionSize;
  445.     LONG              lresult;
  446.     LARGE_INTEGER     FileLength;
  447.     FILE_POSITION_INFORMATION CurrentPos;
  448.     wcscpy(wcUpdateFile, pUserBasePath->Buffer);
  449.     wcscat(wcUpdateFile, L"\inifile.upd");
  450.     UniUpdateName.Length = wcslen(wcUpdateFile)*sizeof(WCHAR);
  451.     InitializeObjectAttributes( &ObjAUpd,
  452.                                 &UniUpdateName,
  453.                                 OBJ_CASE_INSENSITIVE,
  454.                                 NULL,
  455.                                 NULL
  456.                               );
  457.     // Open the update log
  458.     Iosb.Status = STATUS_SUCCESS;
  459.     Status = NtCreateFile( &hUpdate,
  460.                              FILE_READ_DATA | FILE_WRITE_DATA |
  461.                                FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  462.                              &ObjAUpd,
  463.                              &Iosb,
  464.                            NULL,                  // Allocation size
  465.                            FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
  466.                              FILE_SHARE_WRITE,      // dwShareMode
  467.                            FILE_OPEN_IF,          // CreateDisposition
  468.                              FILE_SYNCHRONOUS_IO_NONALERT |
  469.                                FILE_NON_DIRECTORY_FILE, // CreateFlags
  470.                            NULL, // EaBuffer
  471.                            0     // EaLength
  472.                            );
  473.     if (NT_SUCCESS( Status )) {
  474.         Status = NtQueryInformationFile( hUpdate,
  475.                                          &Iosb,
  476.                                          &StandardInfo,
  477.                                          sizeof(StandardInfo),
  478.                                          FileStandardInformation
  479.                                        );
  480.         if (Status == STATUS_BUFFER_OVERFLOW) {
  481.             Status = STATUS_SUCCESS;
  482.         }
  483. #if DBG
  484.         else if (!NT_SUCCESS( Status )) {
  485.             DbgPrint( "TermsrvGetLastSyncTime: Unable to QueryInformation for %wZ - Status == %xn", &UniUpdateName, Status );
  486.         }
  487. #endif
  488.     }
  489.     if (NT_SUCCESS( Status )) {
  490.         ulBuffSize = StandardInfo.EndOfFile.LowPart + 4 * sizeof(WCHAR);
  491.         ulRegionSize = ulBuffSize + 0x1000; // Room for 4K of growth
  492.         Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  493.                                           &pBuff,
  494.                                           0,
  495.                                           &ulRegionSize,
  496.                                           MEM_RESERVE,
  497.                                           PAGE_READWRITE
  498.                                         );
  499.     }
  500.     if (NT_SUCCESS( Status )) {
  501.         Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  502.                                           &pBuff,
  503.                                           0,
  504.                                           &ulBuffSize,
  505.                                           MEM_COMMIT,
  506.                                           PAGE_READWRITE
  507.                                         );
  508.     }
  509.     if (NT_SUCCESS( Status ) && StandardInfo.EndOfFile.LowPart) {
  510.         Status = NtReadFile( hUpdate,
  511.                              NULL,
  512.                              NULL,
  513.                              NULL,
  514.                              &Iosb,
  515.                              pBuff,
  516.                              StandardInfo.EndOfFile.LowPart,
  517.                              NULL,
  518.                              NULL
  519.                            );
  520.         if ( Status == STATUS_PENDING ) {
  521.             Status = NtWaitForSingleObject( hUpdate, FALSE, NULL );
  522.         }
  523.         if ( NT_SUCCESS(Status) ) {
  524.             // Get final I/O status
  525.             Status = Iosb.Status;
  526.         }
  527.     }
  528.     // Look for this ini file in the list
  529.     if (NT_SUCCESS(Status)) {
  530.         pwch = (PWCHAR)pBuff;
  531.         pBuffEnd = pBuff + StandardInfo.EndOfFile.LowPart;
  532.         // Look for the file in the list
  533.         while ((pwch < (PWCHAR)pBuffEnd) &&
  534.                ((lresult = _wcsicmp(pwch, pSysIniPath->Buffer)) < 0)) {
  535.             pwch += wcslen(pwch) + (sizeof(LARGE_INTEGER)/sizeof(WCHAR)) + 1;
  536.         }
  537.         // If the ini file is already in the file, just update the time
  538.         if ((pwch < (PWCHAR)pBuffEnd) && (lresult == 0)) {
  539.             pwch += wcslen(pwch) + 1;
  540.             ((PLARGE_INTEGER)pwch)->LowPart = pLastSyncTime->LowPart;
  541.             ((PLARGE_INTEGER)pwch)->HighPart = pLastSyncTime->HighPart;
  542.         } else {                    // Ini file not in list
  543.             // Figure out the size to grow the file
  544.             ulLength = (pSysIniPath->Length + 2) + sizeof(LARGE_INTEGER);
  545.             ulBuffSize += ulLength;
  546.             // Grow the memory region
  547.             Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  548.                                               &pBuff,
  549.                                               0,
  550.                                               &ulBuffSize,
  551.                                               MEM_COMMIT,
  552.                                               PAGE_READWRITE
  553.                                             );
  554.             if (NT_SUCCESS(Status)) {
  555.                 // figure out where the entry goes in the file
  556.                 if (pwch < (PWCHAR)pBuffEnd) {
  557.                     RtlMoveMemory( pwch+(ulLength/sizeof(WCHAR)),
  558.                                    pwch,
  559.                                    pBuffEnd - (PCHAR)pwch
  560.                                  );
  561.                 }
  562.                 pBuffEnd += ulLength;
  563.                 wcscpy(pwch, pSysIniPath->Buffer);
  564.                 pwch += (pSysIniPath->Length + 2)/sizeof(WCHAR);
  565.                 ((PLARGE_INTEGER)pwch)->LowPart = pLastSyncTime->LowPart;
  566.                 ((PLARGE_INTEGER)pwch)->HighPart = pLastSyncTime->HighPart;
  567.             }
  568.         }
  569.     }
  570.     if (NT_SUCCESS(Status)) {
  571.         CurrentPos.CurrentByteOffset.LowPart = 0;
  572.         CurrentPos.CurrentByteOffset.HighPart = 0;
  573.         Status = NtSetInformationFile( hUpdate,
  574.                                        &Iosb,
  575.                                        &CurrentPos,
  576.                                        sizeof(CurrentPos),
  577.                                        FilePositionInformation
  578.                                      );
  579.         Status = NtWriteFile( hUpdate,
  580.                               NULL,
  581.                               NULL,
  582.                               NULL,
  583.                               &Iosb,
  584.                               pBuff,
  585.                               (ULONG)(pBuffEnd - pBuff + 1),
  586.                               NULL,
  587.                               NULL
  588.                             );
  589.         if( Status == STATUS_PENDING ) {
  590.             Status = NtWaitForSingleObject( hUpdate, FALSE, NULL );
  591.         }
  592.         if( NT_SUCCESS(Status) ) {
  593.             // Get final I/O status
  594.             Status = Iosb.Status;
  595.         }
  596.     }
  597.     if (NT_SUCCESS( Status )) {
  598.         FileLength.LowPart = (ULONG)(pBuffEnd - pBuff);
  599.         FileLength.HighPart = 0;
  600.         Status = NtSetInformationFile( hUpdate,
  601.                                        &Iosb,
  602.                                        &FileLength,
  603.                                        sizeof( FileLength ),
  604.                                        FileEndOfFileInformation
  605.                                      );
  606.     }
  607.     if (pBuff) {
  608.         NtFreeVirtualMemory( NtCurrentProcess(),
  609.                              &pBuff,
  610.                              &ulRegionSize,
  611.                              MEM_RELEASE
  612.                            );
  613.     }
  614.     if (hUpdate) {
  615.         Status = NtClose( hUpdate );
  616.     }
  617.     return(Status);
  618. }
  619. /*****************************************************************************
  620.  *
  621.  *  TermsrvCheckIniSync
  622.  *
  623.  *  This routine will get the time of the system ini file that the user ini
  624.  *  file was last sync'd with.
  625.  *
  626.  * ENTRY:
  627.  *   PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path
  628.  *   PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path
  629.  *   BOOLEAN fGet (In) - TRUE means to get last sync time, FALSE means to write it
  630.  *   PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time
  631.  *
  632.  * EXIT:
  633.  *   TRUE  - User ini file should be sync'd
  634.  *   FALSE - User ini file should be sync'd
  635.  *
  636.  ****************************************************************************/
  637. BOOLEAN
  638. TermsrvCheckIniSync(
  639.     PUNICODE_STRING pSysIniPath,
  640.     PUNICODE_STRING pUserBasePath)
  641. {
  642.     LARGE_INTEGER          LastSyncTime;
  643.     OBJECT_ATTRIBUTES      objaIni;
  644.     FILE_NETWORK_OPEN_INFORMATION BasicInfo;
  645.     NTSTATUS               Status;
  646.     // Get the last sync time of the ini file from the inifile.upd file
  647.     TermsrvGetSyncTime(pSysIniPath, pUserBasePath, &LastSyncTime);
  648.     // Get the last write time of the system ini file
  649.     InitializeObjectAttributes(
  650.         &objaIni,
  651.         pSysIniPath,
  652.         OBJ_CASE_INSENSITIVE,
  653.         NULL,
  654.         NULL
  655.         );
  656.     // Now query it
  657.     Status = NtQueryFullAttributesFile( &objaIni, &BasicInfo );
  658.     // If we couldn't get the time or the system ini file has been updated
  659.     // since we last sync'd, return TRUE
  660.     if (!NT_SUCCESS(Status) ||
  661.         ((BasicInfo.LastWriteTime.HighPart > LastSyncTime.HighPart) ||
  662.          ((BasicInfo.LastWriteTime.HighPart == LastSyncTime.HighPart) &&
  663.          (BasicInfo.LastWriteTime.LowPart > LastSyncTime.LowPart)))) {
  664.         return(TRUE);
  665.     }
  666.     return(FALSE);
  667. }
  668. /*****************************************************************************
  669.  *
  670.  *  TermsrvDoesFileExist
  671.  *
  672.  *   Returns whether the file exists or not.
  673.  *
  674.  *   Must use NT, not WIN32 pathnames.
  675.  *
  676.  * ENTRY:
  677.  *   Param1 (input/output)
  678.  *     Comments
  679.  *
  680.  * EXIT:
  681.  *   STATUS_SUCCESS - no error
  682.  *
  683.  ****************************************************************************/
  684. BOOL
  685. TermsrvDoesFileExist(
  686.     PUNICODE_STRING pFileName
  687.     )
  688. {
  689.     NTSTATUS Status;
  690.     FILE_BASIC_INFORMATION BasicInfo;
  691.     OBJECT_ATTRIBUTES Obja;
  692.     InitializeObjectAttributes(
  693.         &Obja,
  694.         pFileName,
  695.         OBJ_CASE_INSENSITIVE,
  696.         NULL,
  697.         NULL
  698.         );
  699.     /*
  700.      * Now query it
  701.      */
  702.     Status = NtQueryAttributesFile( &Obja, &BasicInfo );
  703.     if( NT_SUCCESS( Status ) ) {
  704.         return( TRUE );
  705.     }
  706.     return( FALSE );
  707. }
  708. /*****************************************************************************
  709.  *
  710.  *  TermsrvSyncUserIniFile
  711.  *
  712.  *   This routine will check that the user's ini file is "sync'd" with the
  713.  *   system version of the ini file.  This means that it walks through the
  714.  *   system ini file and checks that there is a corresponding entry in the
  715.  *   user's ini file.
  716.  *
  717.  * ENTRY:
  718.  *   IN PINIFILE_PARAMETERS a - ptr to inifile structure
  719.  *
  720.  * EXIT:
  721.  *   True  - Ini file updated
  722.  *   False - User Ini file was unchanged
  723.  *
  724.  ****************************************************************************/
  725. BOOL TermsrvSyncUserIniFile(PINIFILE_PARAMETERS a)
  726. {
  727.     WCHAR          wcIniPath[MAX_PATH+1];
  728.     UNICODE_STRING IniFilePath = {MAX_PATH,
  729.                                   MAX_PATH+1,
  730.                                   wcIniPath};
  731.     PWCH           pwch, pwcIniName;
  732.     UNICODE_STRING UniSysPath;
  733.     UNICODE_STRING UserBasePath;
  734.     NTSTATUS       Status;
  735.     HANDLE         SrcHandle;
  736.     ULONG          ulCompatFlags;
  737.     OBJECT_ATTRIBUTES SrcObja;
  738.     IO_STATUS_BLOCK   SrcIosb;
  739.     INIFILE_OPERATION OrigOperation;
  740.     BOOLEAN           OrigWrite, OrigMultiValue, OrigUnicode,
  741.                       OrigWriteOperation, fIniUpdated = FALSE;
  742.     ANSI_STRING       OrigAppName, OrigVarName;
  743.     ULONG             OrigResultChars, OrigResultMaxChars;
  744.     LPSTR             OrigResultBuffer;
  745.     OBJECT_ATTRIBUTES      objaIni;
  746.     FILE_NETWORK_OPEN_INFORMATION BasicInfo;
  747.     // If INI file mapping is not on, return
  748.     if (IsSystemLUID() || TermsrvAppInstallMode()) {
  749.         return(FALSE);
  750.     }
  751.     // Build full system path to the Ini file, and get BasePath to user dir
  752.     if ((gpTermsrvBuildSysIniPath == NULL) || !(gpTermsrvBuildSysIniPath(&a->NtFileName, &UniSysPath, &UserBasePath))) {
  753.         #if DBG
  754.         //DbgPrint("TermsrvSyncUserIniFile: Error building Sys Ini Path!n");
  755.         #endif
  756.         return(FALSE);
  757.     }
  758.     // Get the ini file name
  759.     pwch = wcsrchr(a->NtFileName.Buffer, L'\') + 1;
  760.     pwcIniName = RtlAllocateHeap( RtlProcessHeap(),
  761.                                   0,
  762.                                   (wcslen(pwch) + 1)*sizeof(WCHAR));
  763.     wcscpy(pwcIniName, pwch);
  764.     pwch = wcsrchr(pwcIniName, L'.');
  765.     if (pwch) {
  766.         *pwch = L'';
  767.     }
  768.     if (gpGetTermsrCompatFlags) {
  769.         gpGetTermsrCompatFlags(pwcIniName, &ulCompatFlags, CompatibilityIniFile);
  770.     } else {
  771.         return FALSE;
  772.     }
  773.     // If the INISYNC compatibility flag is set in the registry and the
  774.     // system version of the ini file exists, sync up the user version
  775.     if (((ulCompatFlags & (TERMSRV_COMPAT_INISYNC | TERMSRV_COMPAT_WIN16)) ==
  776.          (TERMSRV_COMPAT_INISYNC | TERMSRV_COMPAT_WIN16)) &&
  777.         TermsrvDoesFileExist(&UniSysPath) &&
  778.         TermsrvCheckIniSync(&UniSysPath, &UserBasePath)) {
  779.         // Create a backup copy of the original file (inifile.ctx)
  780.         wcscpy(wcIniPath, UserBasePath.Buffer);
  781.         if (UserBasePath.Buffer[UserBasePath.Length/sizeof(WCHAR) - 1] != L'\')
  782.             wcscat(wcIniPath, L"\");
  783.         wcscat(wcIniPath, pwcIniName);
  784.         wcscat(wcIniPath, L".ctx");
  785.         IniFilePath.Length = wcslen(wcIniPath)*sizeof(WCHAR);
  786.         if (gpTermsrvCopyIniFile) {
  787.             Status = gpTermsrvCopyIniFile(&a->NtFileName, NULL, &IniFilePath);
  788.     #if DBG
  789.             if (!NT_SUCCESS(Status)) {
  790.                 DbgPrint("TermsrvSyncUserIniFile: Error 0x%x creating backup ini file %wsn",
  791.                          Status,
  792.                          wcIniPath);
  793.             }
  794.     #endif
  795.         } else {
  796.             return FALSE;
  797.             }
  798.         // Check that each entry in the system version is in the user's version
  799.         InitializeObjectAttributes(&SrcObja,
  800.                                    &UniSysPath,
  801.                                    OBJ_CASE_INSENSITIVE,
  802.                                    NULL,
  803.                                    NULL);
  804.         // Open the src
  805.         SrcIosb.Status = STATUS_SUCCESS;
  806.         Status = NtOpenFile(&SrcHandle,
  807.                              FILE_GENERIC_READ,
  808.                             &SrcObja,
  809.                             &SrcIosb,
  810.                             FILE_SHARE_READ|FILE_SHARE_WRITE,
  811.                             FILE_SYNCHRONOUS_IO_NONALERT);
  812.         if( NT_SUCCESS(Status) ) {
  813.             // Get final I/O status
  814.                   Status = SrcIosb.Status;
  815.         }
  816.         if( !NT_SUCCESS(Status) ) {
  817. #if DBG
  818.             DbgPrint("TermsrvSyncUserIniFile: Error 0x%x opening SrcFile %wsn",
  819.                      Status,
  820.                      &UniSysPath.Buffer);
  821. #endif
  822.             goto Cleanup;
  823.         }
  824.         // Save the original values
  825.         OrigOperation = a->Operation;
  826.         OrigMultiValue = a->MultiValueStrings;
  827.         OrigAppName = a->ApplicationName;
  828.         OrigVarName = a->VariableName;
  829.         OrigResultChars = a->ResultChars;
  830.         OrigResultMaxChars = a->ResultMaxChars;
  831.         OrigResultBuffer = a->ResultBuffer;
  832.         OrigUnicode = a->Unicode;
  833.         OrigWriteOperation = a->WriteOperation;
  834.         // Set up the open for writes
  835.         a->WriteOperation = TRUE;
  836.         a->Operation = WriteKeyValue;
  837.         a->MultiValueStrings = FALSE;
  838.         a->Unicode = FALSE;
  839.         Status = BaseDllOpenIniFileOnDisk( a );
  840.         if( !NT_SUCCESS(Status) ) {
  841. #if DBG
  842.             DbgPrint("TermsrvSyncUserIniFile: Error 0x%x opening DestFile %wsn",
  843.                      Status,
  844.                      &a->NtFileName.Buffer);
  845. #endif
  846.             NtClose( SrcHandle );
  847.                 goto Cleanup;
  848.         }
  849.         // set the data up for writing
  850.         a->TextEnd = (PCHAR)a->IniFile->BaseAddress +
  851.                             a->IniFile->EndOfFile;
  852.         a->TextCurrent = a->IniFile->BaseAddress;
  853.         // Make sure entries in system ini file are in user ini file
  854.         Status = TermsrvIniSyncLoop( SrcHandle, a, &fIniUpdated );
  855. #if DBG
  856.         if( !NT_SUCCESS(Status) ) {
  857.             DbgPrint("TermsrvSyncUserIniFile: Error 0x%x Doing sync loopn",Status);
  858.         }
  859. #endif
  860.         // Close the file handles
  861.         NtClose( SrcHandle );
  862.         BaseDllCloseIniFileOnDisk( a );
  863.         // Restore the variables in the ini file structure
  864.         a->Operation = OrigOperation;
  865.         a->MultiValueStrings = OrigMultiValue;
  866.         a->ApplicationName = OrigAppName;
  867.         a->VariableName = OrigVarName;
  868.         a->ResultChars = OrigResultChars;
  869.         a->ResultMaxChars = OrigResultMaxChars;
  870.         a->ResultBuffer = OrigResultBuffer;
  871.         a->WriteOperation = FALSE;
  872.         a->Unicode = OrigUnicode;
  873.         a->WriteOperation = OrigWriteOperation;
  874.         // Get the last write time of the system ini file
  875.         InitializeObjectAttributes( &objaIni,
  876.                                     &UniSysPath,
  877.                                     OBJ_CASE_INSENSITIVE,
  878.                                     NULL,
  879.                                     NULL
  880.                                   );
  881.         // Now query it
  882.         Status = NtQueryFullAttributesFile( &objaIni, &BasicInfo );
  883.         // Update the sync time in the inisync file
  884.         if (NT_SUCCESS(Status)) {
  885.             TermsrvPutSyncTime( &UniSysPath,
  886.                             &UserBasePath,
  887.                             &BasicInfo.LastWriteTime
  888.                           );
  889.         }
  890.     }
  891. Cleanup:
  892.     // Free the unicode buffers
  893.     RtlFreeHeap( RtlProcessHeap(), 0, UniSysPath.Buffer );
  894.     RtlFreeHeap( RtlProcessHeap(), 0, UserBasePath.Buffer );
  895.     RtlFreeHeap( RtlProcessHeap(), 0, pwcIniName);
  896.     return(fIniUpdated);
  897. }
  898. /*****************************************************************************
  899.  *
  900.  *  TermsrvIniSyncLoop
  901.  *
  902.  *  This routine will verify that there's a corresponding entry in the user's
  903.  *  ini file for each entry in the system ini file.
  904.  *
  905.  * ENTRY:
  906.  *   HANDLE SrcHandle (INPUT)  - Handle to system ini file
  907.  *   PINIFILE_PARAMETERS a (INPUT) - pointer to current ini file structure
  908.  *   PBOOLEAN pfIniUpdated (OUTPUT) - Returns TRUE if user ini file is modified
  909.  *
  910.  * EXIT:
  911.  *   STATUS_SUCCESS - no error
  912.  *
  913.  ****************************************************************************/
  914. NTSTATUS
  915. TermsrvIniSyncLoop(HANDLE SrcHandle,
  916.                PINIFILE_PARAMETERS a,
  917.                PBOOLEAN pfIniUpdated)
  918. {
  919.     PCHAR pStr;
  920.     NTSTATUS Status;
  921.     ULONG StringSize;
  922.     CHAR  IOBuf[512];
  923.     ULONG IOBufSize = 512;
  924.     ULONG IOBufIndex = 0;
  925.     ULONG IOBufFillSize = 0;
  926.     ANSI_STRING AnsiSection;
  927.     PCH pch;
  928.     PVOID pSection, origbase;
  929.     AnsiSection.Buffer = NULL;
  930.     *pfIniUpdated = FALSE;
  931.     while( 1 ) {
  932.         pStr = NULL;
  933.         StringSize = 0;
  934.         if (gpTermsrvGetString == NULL) {
  935.             return STATUS_UNSUCCESSFUL;
  936.         }
  937.         // Get a string from the source ini file
  938.         Status = gpTermsrvGetString(SrcHandle,
  939.                                &pStr,
  940.                                &StringSize,
  941.                                IOBuf,
  942.                                IOBufSize,
  943.                               &IOBufIndex,
  944.                                &IOBufFillSize);
  945.         if( !NT_SUCCESS(Status) ) {
  946.             ASSERT( pStr == NULL );
  947.             if( Status == STATUS_END_OF_FILE ) {
  948.                 Status = STATUS_SUCCESS;
  949.             }
  950.             if (AnsiSection.Buffer) {
  951.                 RtlFreeHeap( RtlProcessHeap(), 0, AnsiSection.Buffer );
  952.             }
  953.             a->IniFile->UpdateEndOffset = a->IniFile->EndOfFile;
  954.             return( Status );
  955.         }
  956.         // Make sure we got some actual data
  957.         ASSERT( pStr != NULL );
  958.         // Is this a section name?
  959.         if (*pStr == '[') {
  960.             if (AnsiSection.Buffer) {
  961.                 RtlFreeHeap( RtlProcessHeap(), 0, AnsiSection.Buffer );
  962.                 AnsiSection.Buffer = NULL;
  963.             }
  964.             pch = strrchr(pStr, ']');
  965.             if (pch) {
  966.                 AnsiSection.MaximumLength = (USHORT)(pch - pStr);
  967.                 *pch = '';
  968.             } else {
  969.                 AnsiSection.Length = strlen(pStr);
  970.             }
  971.             AnsiSection.Length = AnsiSection.MaximumLength - 1;
  972.             AnsiSection.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  973.                                                  0,
  974.                                                  AnsiSection.MaximumLength);
  975.             strcpy(AnsiSection.Buffer, pStr+1);
  976.             a->ApplicationName = AnsiSection;
  977.             a->TextCurrent = a->IniFile->BaseAddress;   // reset file pointer
  978.             // See if the section already exists, if so save the start of it
  979.             Status = BaseDllFindSection( a );
  980.             if (NT_SUCCESS(Status)) {
  981.                 pSection = a->TextCurrent;
  982.             } else {
  983.                 pSection = NULL;
  984.             }
  985.         // If it's not a comment, see if the entry is in the user's ini file
  986.         } else if (*pStr != ';') {
  987.             pch = strchr(pStr, '=');
  988.             if (pch) {
  989.                 a->VariableName.Length = a->VariableName.MaximumLength =
  990.                     (USHORT)(pch - pStr);
  991.                 a->VariableName.Buffer = pStr;
  992.                 a->ValueBuffer = (++pch);
  993.                 a->ValueLength = 0;
  994.                 while (*pch && (*pch != 0xa) && (*pch != 0xd)) {
  995.                     pch++;
  996.                     a->ValueLength++;
  997.                 }
  998.                 // If the section exists, check for the keyword in user's ini
  999.                 if (pSection) {
  1000.                     a->TextCurrent = pSection;
  1001.                     Status = BaseDllFindKeyword( a );
  1002.                 }
  1003.                 // If variable isn't found, write it out
  1004.                 if (!pSection || !NT_SUCCESS( Status )) {
  1005.                     origbase = a->TextCurrent = a->IniFile->BaseAddress;
  1006.                     Status = BaseDllWriteKeywordValue( a, NULL );
  1007.                     a->TextEnd = (PCHAR)a->IniFile->BaseAddress +
  1008.                                         a->IniFile->EndOfFile;
  1009.                     if (!NT_SUCCESS(Status)) {
  1010.                               #if DBG
  1011.                               DbgPrint("TermsrvIniSyncLoop: Error 0x%x write Key Valuen",
  1012.                                   Status);
  1013.                               #endif
  1014.                         a->IniFile->UpdateEndOffset = a->IniFile->EndOfFile;
  1015.                         RtlFreeHeap( RtlProcessHeap(), 0, pStr );
  1016.                         if (AnsiSection.Buffer) {
  1017.                             RtlFreeHeap(RtlProcessHeap(),
  1018.                                         0,
  1019.                                         AnsiSection.Buffer);
  1020.                         }
  1021.                         return(Status);
  1022.                     }
  1023.                     *pfIniUpdated = TRUE;
  1024.                     if (origbase != a->IniFile->BaseAddress) {
  1025.                         a->TextCurrent = a->IniFile->BaseAddress;
  1026.                         Status = BaseDllFindSection( a );
  1027.                         if (NT_SUCCESS(Status)) {
  1028.                             pSection = a->TextCurrent;
  1029.                         } else {
  1030.                             pSection = NULL;
  1031.                         }
  1032.                     }
  1033.                 }
  1034.             }
  1035.         }
  1036.     } // end while(1)
  1037. }