|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
termutil.c
Abstract:
Terminal server support functions and inifile syncing/merging code
Author:
Revision History:
--*/
#include "basedll.h"
#include "regapi.h"
#define TERMSRV_INIFILE_TIMES L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\IniFile Times"
BOOL IsTerminalServerCompatible(VOID) {
PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader( NtCurrentPeb()->ImageBaseAddress );
if ((NtHeader) && (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)) { return TRUE; } else { return FALSE; } }
BOOL IsTSAppCompatEnabled(VOID) {
NTSTATUS NtStatus; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UniString; HKEY hKey = 0; ULONG ul, ulcbuf; PKEY_VALUE_PARTIAL_INFORMATION pKeyValInfo = NULL;
BOOL retval = TRUE;
RtlInitUnicodeString(&UniString,REG_NTAPI_CONTROL_TSERVER);
// Determine the value info buffer size
ulcbuf = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR) + sizeof(ULONG);
pKeyValInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ulcbuf);
// Did everything initialize OK?
if (UniString.Buffer && pKeyValInfo) {
InitializeObjectAttributes(&ObjectAttributes, &UniString, OBJ_CASE_INSENSITIVE, NULL, NULL );
NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(NtStatus)) {
RtlInitUnicodeString(&UniString, L"TSAppCompat"); NtStatus = NtQueryValueKey(hKey, &UniString, KeyValuePartialInformation, pKeyValInfo, ulcbuf, &ul);
if (NT_SUCCESS(NtStatus) && (REG_DWORD == pKeyValInfo->Type)) {
if ((*(PULONG)pKeyValInfo->Data) == 0) { retval = FALSE; }
}
NtClose(hKey); } }
// Free up the buffers we allocated
// Need to zero out the buffers, because some apps (MS Internet Assistant)
// won't install if the heap is not zero filled.
if (pKeyValInfo) { memset(pKeyValInfo, 0, ulcbuf); RtlFreeHeap( RtlProcessHeap(), 0, pKeyValInfo ); }
return(retval);
}
BOOL IsSystemLUID(VOID) { HANDLE TokenHandle; UCHAR TokenInformation[ sizeof( TOKEN_STATISTICS ) ]; ULONG ReturnLength; LUID CurrentLUID = { 0, 0 }; LUID SystemLUID = SYSTEM_LUID; NTSTATUS Status;
if ( CurrentLUID.LowPart == 0 && CurrentLUID.HighPart == 0 ) {
Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_QUERY, &TokenHandle ); if ( !NT_SUCCESS( Status ) ) return(TRUE);
NtQueryInformationToken( TokenHandle, TokenStatistics, &TokenInformation, sizeof(TokenInformation), &ReturnLength ); NtClose( TokenHandle );
RtlCopyLuid(&CurrentLUID, &(((PTOKEN_STATISTICS)TokenInformation)->AuthenticationId)); }
if (RtlEqualLuid(&CurrentLUID, &SystemLUID)) { return(TRUE); } else { return(FALSE ); } }
void InitializeTermsrvFpns(void) {
HANDLE dllHandle;
if (IsTerminalServerCompatible() || (IsSystemLUID()) || (!IsTSAppCompatEnabled())) { return; }
//
// Load Terminal Server application compatibility dll
//
dllHandle = LoadLibraryW(L"tsappcmp.dll");
if (dllHandle) {
gpTermsrvFormatObjectName = (PTERMSRVFORMATOBJECTNAME)GetProcAddress(dllHandle,"TermsrvFormatObjectName");
gpTermsrvGetComputerName = (PTERMSRVGETCOMPUTERNAME)GetProcAddress(dllHandle,"TermsrvGetComputerName");
gpTermsrvAdjustPhyMemLimits = (PTERMSRVADJUSTPHYMEMLIMITS)GetProcAddress(dllHandle,"TermsrvAdjustPhyMemLimits");
gpTermsrvGetWindowsDirectoryA = (PTERMSRVGETWINDOWSDIRECTORYA)GetProcAddress(dllHandle,"TermsrvGetWindowsDirectoryA");
gpTermsrvGetWindowsDirectoryW = (PTERMSRVGETWINDOWSDIRECTORYW)GetProcAddress(dllHandle,"TermsrvGetWindowsDirectoryW");
gpTermsrvConvertSysRootToUserDir = (PTERMSRVCONVERTSYSROOTTOUSERDIR)GetProcAddress(dllHandle,"TermsrvConvertSysRootToUserDir");
gpTermsrvBuildIniFileName = (PTERMSRVBUILDINIFILENAME)GetProcAddress(dllHandle,"TermsrvBuildIniFileName");
gpTermsrvCORIniFile = (PTERMSRVCORINIFILE)GetProcAddress(dllHandle,"TermsrvCORIniFile");
gpGetTermsrCompatFlags = (PGETTERMSRCOMPATFLAGS)GetProcAddress(dllHandle,"GetTermsrCompatFlags");
gpTermsrvBuildSysIniPath = (PTERMSRVBUILDSYSINIPATH)GetProcAddress(dllHandle,"TermsrvBuildSysIniPath");
gpTermsrvCopyIniFile = (PTERMSRVCOPYINIFILE)GetProcAddress(dllHandle,"TermsrvCopyIniFile");
gpTermsrvGetString = (PTERMSRVGETSTRING)GetProcAddress(dllHandle,"TermsrvGetString");
gpTermsrvLogInstallIniFile = (PTERMSRVLOGINSTALLINIFILE)GetProcAddress(dllHandle,"TermsrvLogInstallIniFile");
} }
/*****************************************************************************
* * TermsrvAppInstallMode * * Returns whether the system is in Install mode or not * * ENTRY: * Param1 (input/output) * Comments * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/
WINBASEAPI BOOL WINAPI TermsrvAppInstallMode( VOID ) {
if ( BaseStaticServerData->fTermsrvAppInstallMode ) return( TRUE );
return( FALSE ); }
/*****************************************************************************
* * SetTermsrvAppInstallMode * * Turns App install mode on or off. Default is off * * ENTRY: * Param1 (input/output) * Comments * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/
WINBASEAPI BOOL WINAPI SetTermsrvAppInstallMode( BOOL bState ) { typedef BOOL ( APIENTRY Func_CheckTokenMembership )( HANDLE , PSID , PBOOL); BOOL rc; NTSTATUS Status; PSID pSid = NULL ; SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_NT_AUTHORITY;
HINSTANCE dllHandle; if ( !( IsTerminalServer() && IsTSAppCompatEnabled() ) ) { return FALSE; }
dllHandle = LoadLibraryW(L"advapi32.dll"); if (dllHandle) { Func_CheckTokenMembership *fPtr; fPtr = (Func_CheckTokenMembership * )GetProcAddress(dllHandle,"CheckTokenMembership"); if (fPtr) { Status = RtlAllocateAndInitializeSid( &SidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSid );
if (NT_SUCCESS(Status)) { BOOL FoundAdmin; if ( fPtr (NULL, pSid , &FoundAdmin)) { if (FoundAdmin) { // caller is admin, go ahead
#if defined(BUILD_WOW6432)
Status = CsrBasepSetTermsrvAppInstallMode(bState); #else
BASE_API_MSG m; PBASE_SET_TERMSRVAPPINSTALLMODE c= (PBASE_SET_TERMSRVAPPINSTALLMODE)&m.u.SetTermsrvAppInstallMode;
c->bState = bState; Status = CsrClientCallServer((PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetTermsrvAppInstallMode), sizeof( *c )); #endif
if ( NT_SUCCESS( Status ) ) { //
// Load tsappcmp.dll
//
if (gpTermsrvUpdateAllUserMenu == NULL) { HANDLE dllHandle;
//
// Load Terminal Server application compatibility dll
//
dllHandle = LoadLibraryW(L"tsappcmp.dll");
if (dllHandle) { gpTermsrvUpdateAllUserMenu = (PTERMSRVUPDATEALLUSERMENU)GetProcAddress(dllHandle,"TermsrvUpdateAllUserMenu"); } }
if (gpTermsrvUpdateAllUserMenu) { gpTermsrvUpdateAllUserMenu( bState == TRUE ? 0 : 1 ); } rc = TRUE; } else { SetLastError( RtlNtStatusToDosError( Status ) ); rc = FALSE; } } else { // user is not admin
SetLastError( ERROR_ACCESS_DENIED ); rc = FALSE; } } else { // call to CheckTokenMembership() failed, it set the last error
rc = FALSE; } } else { // attempt to allocate and init SID failed.
SetLastError( RtlNtStatusToDosError( Status ) ); rc = FALSE; } } else { // function not found, GetProc() set the last error.
rc = FALSE; } FreeLibrary( dllHandle ); } else { // library not found, LoadLib() set the last error
rc = FALSE; }
if (pSid) { RtlFreeSid( pSid ); }
return rc; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/*
Ini File syncing/merging code
*/ //////////////////////////////////////////////////////////////////////////////
/* External Functions */ NTSTATUS BaseDllOpenIniFileOnDisk( PINIFILE_PARAMETERS a );
NTSTATUS BaseDllWriteKeywordValue( IN PINIFILE_PARAMETERS a, IN PUNICODE_STRING VariableName OPTIONAL );
NTSTATUS BaseDllCloseIniFileOnDisk( IN PINIFILE_PARAMETERS a );
NTSTATUS BaseDllFindSection( IN PINIFILE_PARAMETERS a );
NTSTATUS BaseDllFindKeyword( IN PINIFILE_PARAMETERS a );
NTSTATUS TermsrvIniSyncLoop( HANDLE SrcHandle, PINIFILE_PARAMETERS a, PBOOLEAN pfIniUpdated ); NTSTATUS TermsrvGetSyncTime( PUNICODE_STRING pSysIniPath, PUNICODE_STRING pUserBasePath, PLARGE_INTEGER pLastSyncTime );
NTSTATUS TermsrvPutSyncTime( PUNICODE_STRING pSysIniPath, PUNICODE_STRING pUserBasePath, PLARGE_INTEGER pLastSyncTime );
/*****************************************************************************
* * TermsrvGetSyncTime * * This routine will get the time of the system ini file that the user ini * file was last sync'd with. * * ENTRY: * PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path * PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path * PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time * * EXIT: * STATUS_SUCCESS - successfully retrieved the last sync time from infile.upd * ****************************************************************************/
NTSTATUS TermsrvGetSyncTime( PUNICODE_STRING pSysIniPath, PUNICODE_STRING pUserBasePath, PLARGE_INTEGER pLastSyncTime) { NTSTATUS Status; HANDLE hUpdate = NULL; OBJECT_ATTRIBUTES ObjAUpd; IO_STATUS_BLOCK Iosb; FILE_STANDARD_INFORMATION StandardInfo; WCHAR wcUpdateFile[MAX_PATH+1]; UNICODE_STRING UniUpdateName = {0, sizeof(wcUpdateFile), wcUpdateFile}; PCHAR pBuff = NULL, pBuffEnd; PWCH pwch; SIZE_T ulBuffSize; LONG lresult;
if (!pSysIniPath) { return STATUS_INVALID_PARAMETER_1; } if (!pUserBasePath) { return STATUS_INVALID_PARAMETER_2; } if (!pLastSyncTime) { return STATUS_INVALID_PARAMETER_3; }
Status = RtlAppendUnicodeStringToString(&UniUpdateName, pUserBasePath); if (NT_SUCCESS(Status)) { Status = RtlAppendUnicodeToString(&UniUpdateName, L"\\inifile.upd"); }
if (! NT_SUCCESS(Status)) { return Status; }
pLastSyncTime->LowPart = 0; pLastSyncTime->HighPart = 0;
InitializeObjectAttributes( &ObjAUpd, &UniUpdateName, OBJ_CASE_INSENSITIVE, NULL, NULL );
// Open the update log
Iosb.Status = STATUS_SUCCESS; Status = NtOpenFile( &hUpdate, FILE_GENERIC_READ, &ObjAUpd, &Iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT // OpenOptions
);
// Get the size of the file
if (NT_SUCCESS( Status )) { Status = NtQueryInformationFile( hUpdate, &Iosb, &StandardInfo, sizeof(StandardInfo), FileStandardInformation ); if (Status == STATUS_BUFFER_OVERFLOW) { Status = STATUS_SUCCESS; } #if DBG
else if (!NT_SUCCESS( Status )) { DbgPrint( "TermsrvGetSyncTime: Unable to QueryInformation for %wZ - Status == %x\n", &UniUpdateName, Status ); } #endif
}
if (NT_SUCCESS( Status )) { ulBuffSize = StandardInfo.EndOfFile.LowPart + 4 * sizeof(WCHAR); Status = NtAllocateVirtualMemory( NtCurrentProcess(), &pBuff, 0, &ulBuffSize, MEM_RESERVE, PAGE_READWRITE ); }
if (NT_SUCCESS( Status )) { Status = NtAllocateVirtualMemory( NtCurrentProcess(), &pBuff, 0, &ulBuffSize, MEM_COMMIT, PAGE_READWRITE ); }
if (NT_SUCCESS( Status )) { Status = NtReadFile( hUpdate, NULL, NULL, NULL, &Iosb, pBuff, StandardInfo.EndOfFile.LowPart, NULL, NULL );
if ( Status == STATUS_PENDING ) { Status = NtWaitForSingleObject( hUpdate, FALSE, NULL ); }
if ( NT_SUCCESS(Status) ) { // Get final I/O status
Status = Iosb.Status; } }
// Look for this ini file in the list
if (NT_SUCCESS(Status)) {
pwch = (PWCHAR)pBuff; pBuffEnd = pBuff + StandardInfo.EndOfFile.LowPart;
// Look for the file in the sorted list
while ((pwch < (PWCHAR)pBuffEnd) && ((lresult = _wcsicmp(pwch, pSysIniPath->Buffer)) < 0)) { pwch += wcslen(pwch) + sizeof(LARGE_INTEGER)/sizeof(WCHAR) + 1; }
if ((pwch < (PWCHAR)pBuffEnd) && (lresult == 0)) { pwch += wcslen(pwch) + 1; pLastSyncTime->LowPart = ((PLARGE_INTEGER)pwch)->LowPart; pLastSyncTime->HighPart = ((PLARGE_INTEGER)pwch)->HighPart; } }
if (NT_SUCCESS(Status) ) { // Get final I/O status
Status = Iosb.Status; }
if (pBuff) { NtFreeVirtualMemory( NtCurrentProcess(), &pBuff, &ulBuffSize, MEM_RELEASE ); }
if (hUpdate) { Status = NtClose( hUpdate ); } return(Status); }
/*****************************************************************************
* * TermsrvPutSyncTime * * This routine will write the time of the system ini file that the user ini * file was last sync'd with. * * ENTRY: * PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path * PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path * PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time * * EXIT: * STATUS_SUCCESS - successfully stored the last sync time in infile.upd * ****************************************************************************/
NTSTATUS TermsrvPutSyncTime( PUNICODE_STRING pSysIniPath, PUNICODE_STRING pUserBasePath, PLARGE_INTEGER pLastSyncTime) { NTSTATUS Status; HANDLE hUpdate = NULL; OBJECT_ATTRIBUTES ObjAUpd; IO_STATUS_BLOCK Iosb; FILE_STANDARD_INFORMATION StandardInfo; WCHAR wcUpdateFile[MAX_PATH+1]; UNICODE_STRING UniUpdateName = {0, sizeof(wcUpdateFile), wcUpdateFile}; PCHAR pBuff = NULL, pBuffEnd; PWCH pwch; SIZE_T ulBuffSize; ULONG ulLength; SIZE_T ulRegionSize; LONG lresult; LARGE_INTEGER FileLength; FILE_POSITION_INFORMATION CurrentPos;
if (!pSysIniPath) { return STATUS_INVALID_PARAMETER_1; } if (!pUserBasePath) { return STATUS_INVALID_PARAMETER_2; } if (!pLastSyncTime) { return STATUS_INVALID_PARAMETER_3; }
Status = RtlAppendUnicodeStringToString(&UniUpdateName, pUserBasePath); if (NT_SUCCESS(Status)) { Status = RtlAppendUnicodeToString(&UniUpdateName, L"\\inifile.upd"); }
if (! NT_SUCCESS(Status)) { return Status; }
InitializeObjectAttributes( &ObjAUpd, &UniUpdateName, OBJ_CASE_INSENSITIVE, NULL, NULL );
// Open the update log
Iosb.Status = STATUS_SUCCESS; Status = NtCreateFile( &hUpdate, FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjAUpd, &Iosb, NULL, // Allocation size
FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
FILE_SHARE_WRITE, // dwShareMode
FILE_OPEN_IF, // CreateDisposition
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, // CreateFlags
NULL, // EaBuffer
0 // EaLength
);
if (NT_SUCCESS( Status )) { Status = NtQueryInformationFile( hUpdate, &Iosb, &StandardInfo, sizeof(StandardInfo), FileStandardInformation ); if (Status == STATUS_BUFFER_OVERFLOW) { Status = STATUS_SUCCESS; } #if DBG
else if (!NT_SUCCESS( Status )) { DbgPrint( "TermsrvPutLastSyncTime: Unable to QueryInformation for %wZ - Status == %x\n", &UniUpdateName, Status ); } #endif
}
if (NT_SUCCESS( Status )) { ulBuffSize = StandardInfo.EndOfFile.LowPart + 4 * sizeof(WCHAR); ulRegionSize = ulBuffSize + 0x1000; // Room for 4K of growth
Status = NtAllocateVirtualMemory( NtCurrentProcess(), &pBuff, 0, &ulRegionSize, MEM_RESERVE, PAGE_READWRITE ); }
if (NT_SUCCESS( Status )) { Status = NtAllocateVirtualMemory( NtCurrentProcess(), &pBuff, 0, &ulBuffSize, MEM_COMMIT, PAGE_READWRITE ); }
if (NT_SUCCESS( Status ) && StandardInfo.EndOfFile.LowPart) { Status = NtReadFile( hUpdate, NULL, NULL, NULL, &Iosb, pBuff, StandardInfo.EndOfFile.LowPart, NULL, NULL );
if ( Status == STATUS_PENDING ) { Status = NtWaitForSingleObject( hUpdate, FALSE, NULL ); }
if ( NT_SUCCESS(Status) ) { // Get final I/O status
Status = Iosb.Status; } }
// Look for this ini file in the list
if (NT_SUCCESS(Status)) {
pwch = (PWCHAR)pBuff; pBuffEnd = pBuff + StandardInfo.EndOfFile.LowPart;
// Look for the file in the list
while ((pwch < (PWCHAR)pBuffEnd) && ((lresult = _wcsicmp(pwch, pSysIniPath->Buffer)) < 0)) { pwch += wcslen(pwch) + (sizeof(LARGE_INTEGER)/sizeof(WCHAR)) + 1; }
// If the ini file is already in the file, just update the time
if ((pwch < (PWCHAR)pBuffEnd) && (lresult == 0)) { pwch += wcslen(pwch) + 1; ((PLARGE_INTEGER)pwch)->LowPart = pLastSyncTime->LowPart; ((PLARGE_INTEGER)pwch)->HighPart = pLastSyncTime->HighPart;
} else { // Ini file not in list
// Figure out the size to grow the file
ulLength = (pSysIniPath->Length + 2) + sizeof(LARGE_INTEGER); ulBuffSize += ulLength;
// Grow the memory region
Status = NtAllocateVirtualMemory( NtCurrentProcess(), &pBuff, 0, &ulBuffSize, MEM_COMMIT, PAGE_READWRITE );
if (NT_SUCCESS(Status)) { // figure out where the entry goes in the file
if (pwch < (PWCHAR)pBuffEnd) { RtlMoveMemory( pwch+(ulLength/sizeof(WCHAR)), pwch, pBuffEnd - (PCHAR)pwch ); }
pBuffEnd += ulLength; wcscpy(pwch, pSysIniPath->Buffer); pwch += (pSysIniPath->Length + 2)/sizeof(WCHAR); ((PLARGE_INTEGER)pwch)->LowPart = pLastSyncTime->LowPart; ((PLARGE_INTEGER)pwch)->HighPart = pLastSyncTime->HighPart; } } }
if (NT_SUCCESS(Status)) { CurrentPos.CurrentByteOffset.LowPart = 0; CurrentPos.CurrentByteOffset.HighPart = 0; Status = NtSetInformationFile( hUpdate, &Iosb, &CurrentPos, sizeof(CurrentPos), FilePositionInformation );
Status = NtWriteFile( hUpdate, NULL, NULL, NULL, &Iosb, pBuff, (ULONG)(pBuffEnd - pBuff + 1), NULL, NULL );
if( Status == STATUS_PENDING ) { Status = NtWaitForSingleObject( hUpdate, FALSE, NULL ); }
if( NT_SUCCESS(Status) ) { // Get final I/O status
Status = Iosb.Status; } }
if (NT_SUCCESS( Status )) { FileLength.LowPart = (ULONG)(pBuffEnd - pBuff); FileLength.HighPart = 0; Status = NtSetInformationFile( hUpdate, &Iosb, &FileLength, sizeof( FileLength ), FileEndOfFileInformation ); }
if (pBuff) { NtFreeVirtualMemory( NtCurrentProcess(), &pBuff, &ulRegionSize, MEM_RELEASE ); }
if (hUpdate) { Status = NtClose( hUpdate ); }
return(Status); }
/*****************************************************************************
* * TermsrvCheckIniSync * * This routine will get the time of the system ini file that the user ini * file was last sync'd with. * * ENTRY: * PUNICODE_STRING pSysIniPath (In) - NT fully qualified system ini path * PUNICODE_STRING pUserBasePath (In) - NT fully qualified user directory path * BOOLEAN fGet (In) - TRUE means to get last sync time, FALSE means to write it * PLARGE_INTEGER pLastSyncTime (OUT) - ptr to return last sync time * * EXIT: * TRUE - User ini file should be sync'd * FALSE - User ini file should be sync'd * ****************************************************************************/
BOOLEAN TermsrvCheckIniSync( PUNICODE_STRING pSysIniPath, PUNICODE_STRING pUserBasePath) { LARGE_INTEGER LastSyncTime; OBJECT_ATTRIBUTES objaIni; FILE_NETWORK_OPEN_INFORMATION BasicInfo; NTSTATUS Status;
// Get the last sync time of the ini file from the inifile.upd file
TermsrvGetSyncTime(pSysIniPath, pUserBasePath, &LastSyncTime);
// Get the last write time of the system ini file
InitializeObjectAttributes( &objaIni, pSysIniPath, OBJ_CASE_INSENSITIVE, NULL, NULL );
// Now query it
Status = NtQueryFullAttributesFile( &objaIni, &BasicInfo );
// If we couldn't get the time or the system ini file has been updated
// since we last sync'd, return TRUE
if (!NT_SUCCESS(Status) || ((BasicInfo.LastWriteTime.HighPart > LastSyncTime.HighPart) || ((BasicInfo.LastWriteTime.HighPart == LastSyncTime.HighPart) && (BasicInfo.LastWriteTime.LowPart > LastSyncTime.LowPart)))) { return(TRUE); } return(FALSE); } /*****************************************************************************
* * TermsrvDoesFileExist * * Returns whether the file exists or not. * * Must use NT, not WIN32 pathnames. * * ENTRY: * Param1 (input/output) * Comments * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/
BOOL TermsrvDoesFileExist( PUNICODE_STRING pFileName ) { NTSTATUS Status; FILE_BASIC_INFORMATION BasicInfo; OBJECT_ATTRIBUTES Obja;
InitializeObjectAttributes( &Obja, pFileName, OBJ_CASE_INSENSITIVE, NULL, NULL );
/*
* Now query it */ Status = NtQueryAttributesFile( &Obja, &BasicInfo );
if( NT_SUCCESS( Status ) ) { return( TRUE ); }
return( FALSE ); }
/*****************************************************************************
* * TermsrvSyncUserIniFile * * This routine will check that the user's ini file is "sync'd" with the * system version of the ini file. This means that it walks through the * system ini file and checks that there is a corresponding entry in the * user's ini file. * * ENTRY: * IN PINIFILE_PARAMETERS a - ptr to inifile structure * * EXIT: * True - Ini file updated * False - User Ini file was unchanged * ****************************************************************************/ BOOL TermsrvSyncUserIniFile(PINIFILE_PARAMETERS a) { WCHAR wcIniPath[MAX_PATH+1]; UNICODE_STRING IniFilePath = {MAX_PATH, MAX_PATH+1, wcIniPath}; PWCH pwch, pwcIniName; UNICODE_STRING UniSysPath; UNICODE_STRING UserBasePath; NTSTATUS Status; HANDLE SrcHandle; ULONG ulCompatFlags; OBJECT_ATTRIBUTES SrcObja; IO_STATUS_BLOCK SrcIosb; INIFILE_OPERATION OrigOperation; BOOLEAN OrigWrite, OrigMultiValue, OrigUnicode, OrigWriteOperation, fIniUpdated = FALSE; ANSI_STRING OrigAppName, OrigVarName; ULONG OrigResultChars, OrigResultMaxChars; LPSTR OrigResultBuffer; OBJECT_ATTRIBUTES objaIni; FILE_NETWORK_OPEN_INFORMATION BasicInfo;
// If INI file mapping is not on, return
if (IsSystemLUID() || TermsrvAppInstallMode()) { return(FALSE); }
// Build full system path to the Ini file, and get BasePath to user dir
if ((gpTermsrvBuildSysIniPath == NULL) || !(gpTermsrvBuildSysIniPath(&a->NtFileName, &UniSysPath, &UserBasePath))) { #if DBG
//DbgPrint("TermsrvSyncUserIniFile: Error building Sys Ini Path!\n");
#endif
return(FALSE); }
// Get the ini file name
pwch = wcsrchr(a->NtFileName.Buffer, L'\\') ; if (pwch == NULL) { return FALSE; } else{ pwch++; }
pwcIniName = RtlAllocateHeap( RtlProcessHeap(), 0, (wcslen(pwch) + 1)*sizeof(WCHAR)); if (pwcIniName == NULL) { return FALSE; }
wcscpy(pwcIniName, pwch); pwch = wcsrchr(pwcIniName, L'.'); if (pwch) { *pwch = L'\0'; }
if (gpGetTermsrCompatFlags) { gpGetTermsrCompatFlags(pwcIniName, &ulCompatFlags, CompatibilityIniFile); } else { return FALSE; }
// If the INISYNC compatibility flag is set in the registry and the
// system version of the ini file exists, sync up the user version
if (((ulCompatFlags & (TERMSRV_COMPAT_INISYNC | TERMSRV_COMPAT_WIN16)) == (TERMSRV_COMPAT_INISYNC | TERMSRV_COMPAT_WIN16)) && TermsrvDoesFileExist(&UniSysPath) && TermsrvCheckIniSync(&UniSysPath, &UserBasePath)) {
// Create a backup copy of the original file (inifile.ctx)
wcscpy(wcIniPath, UserBasePath.Buffer); if (UserBasePath.Buffer[UserBasePath.Length/sizeof(WCHAR) - 1] != L'\\') wcscat(wcIniPath, L"\\"); wcscat(wcIniPath, pwcIniName); wcscat(wcIniPath, L".ctx"); IniFilePath.Length = wcslen(wcIniPath)*sizeof(WCHAR);
if (gpTermsrvCopyIniFile) { Status = gpTermsrvCopyIniFile(&a->NtFileName, NULL, &IniFilePath); #if DBG
if (!NT_SUCCESS(Status)) { DbgPrint("TermsrvSyncUserIniFile: Error 0x%x creating backup ini file %ws\n", Status, wcIniPath); } #endif
} else { return FALSE; }
// Check that each entry in the system version is in the user's version
InitializeObjectAttributes(&SrcObja, &UniSysPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
// Open the src
SrcIosb.Status = STATUS_SUCCESS; Status = NtOpenFile(&SrcHandle, FILE_GENERIC_READ, &SrcObja, &SrcIosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
if( NT_SUCCESS(Status) ) { // Get final I/O status
Status = SrcIosb.Status; }
if( !NT_SUCCESS(Status) ) { #if DBG
DbgPrint("TermsrvSyncUserIniFile: Error 0x%x opening SrcFile %ws\n", Status, &UniSysPath.Buffer); #endif
goto Cleanup; }
// Save the original values
OrigOperation = a->Operation; OrigMultiValue = a->MultiValueStrings; OrigAppName = a->ApplicationName; OrigVarName = a->VariableName; OrigResultChars = a->ResultChars; OrigResultMaxChars = a->ResultMaxChars; OrigResultBuffer = a->ResultBuffer; OrigUnicode = a->Unicode; OrigWriteOperation = a->WriteOperation;
// Set up the open for writes
a->WriteOperation = TRUE; a->Operation = WriteKeyValue; a->MultiValueStrings = FALSE; a->Unicode = FALSE;
Status = BaseDllOpenIniFileOnDisk( a );
if( !NT_SUCCESS(Status) ) { #if DBG
DbgPrint("TermsrvSyncUserIniFile: Error 0x%x opening DestFile %ws\n", Status, &a->NtFileName.Buffer); #endif
NtClose( SrcHandle ); goto Cleanup; }
// set the data up for writing
a->TextEnd = (PCHAR)a->IniFile->BaseAddress + a->IniFile->EndOfFile; a->TextCurrent = a->IniFile->BaseAddress;
// Make sure entries in system ini file are in user ini file
Status = TermsrvIniSyncLoop( SrcHandle, a, &fIniUpdated ); #if DBG
if( !NT_SUCCESS(Status) ) { DbgPrint("TermsrvSyncUserIniFile: Error 0x%x Doing sync loop\n",Status); } #endif
// Close the file handles
NtClose( SrcHandle ); BaseDllCloseIniFileOnDisk( a );
// Restore the variables in the ini file structure
a->Operation = OrigOperation; a->MultiValueStrings = OrigMultiValue; a->ApplicationName = OrigAppName; a->VariableName = OrigVarName; a->ResultChars = OrigResultChars; a->ResultMaxChars = OrigResultMaxChars; a->ResultBuffer = OrigResultBuffer; a->WriteOperation = FALSE; a->Unicode = OrigUnicode; a->WriteOperation = OrigWriteOperation;
// Get the last write time of the system ini file
InitializeObjectAttributes( &objaIni, &UniSysPath, OBJ_CASE_INSENSITIVE, NULL, NULL );
// Now query it
Status = NtQueryFullAttributesFile( &objaIni, &BasicInfo );
// Update the sync time in the inisync file
if (NT_SUCCESS(Status)) { TermsrvPutSyncTime( &UniSysPath, &UserBasePath, &BasicInfo.LastWriteTime ); } }
Cleanup: // Free the unicode buffers
RtlFreeHeap( RtlProcessHeap(), 0, UniSysPath.Buffer ); RtlFreeHeap( RtlProcessHeap(), 0, UserBasePath.Buffer ); RtlFreeHeap( RtlProcessHeap(), 0, pwcIniName);
return(fIniUpdated); }
/*****************************************************************************
* * TermsrvIniSyncLoop * * This routine will verify that there's a corresponding entry in the user's * ini file for each entry in the system ini file. * * ENTRY: * HANDLE SrcHandle (INPUT) - Handle to system ini file * PINIFILE_PARAMETERS a (INPUT) - pointer to current ini file structure * PBOOLEAN pfIniUpdated (OUTPUT) - Returns TRUE if user ini file is modified * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/
NTSTATUS TermsrvIniSyncLoop(HANDLE SrcHandle, PINIFILE_PARAMETERS a, PBOOLEAN pfIniUpdated) { PCHAR pStr; NTSTATUS Status; ULONG StringSize; CHAR IOBuf[512]; ULONG IOBufSize = 512; ULONG IOBufIndex = 0; ULONG IOBufFillSize = 0; ANSI_STRING AnsiSection; PCH pch; PVOID pSection, origbase;
AnsiSection.Buffer = NULL; *pfIniUpdated = FALSE;
while( 1 ) {
pStr = NULL; StringSize = 0;
if (gpTermsrvGetString == NULL) { return STATUS_UNSUCCESSFUL; }
// Get a string from the source ini file
Status = gpTermsrvGetString(SrcHandle, &pStr, &StringSize, IOBuf, IOBufSize, &IOBufIndex, &IOBufFillSize);
if( !NT_SUCCESS(Status) ) {
ASSERT( pStr == NULL );
if( Status == STATUS_END_OF_FILE ) { Status = STATUS_SUCCESS; } if (AnsiSection.Buffer) { RtlFreeHeap( RtlProcessHeap(), 0, AnsiSection.Buffer ); }
a->IniFile->UpdateEndOffset = a->IniFile->EndOfFile; return( Status ); }
// Make sure we got some actual data
ASSERT( pStr != NULL );
// Is this a section name?
if (*pStr == '[') { if (AnsiSection.Buffer) { RtlFreeHeap( RtlProcessHeap(), 0, AnsiSection.Buffer ); AnsiSection.Buffer = NULL; } pch = strrchr(pStr, ']'); if (pch) { AnsiSection.MaximumLength = (USHORT)(pch - pStr); *pch = '\0'; } else { AnsiSection.Length = (USHORT)strlen(pStr); } AnsiSection.Length = AnsiSection.MaximumLength - 1; AnsiSection.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, AnsiSection.MaximumLength); if (!AnsiSection.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; } strcpy(AnsiSection.Buffer, pStr+1); a->ApplicationName = AnsiSection;
a->TextCurrent = a->IniFile->BaseAddress; // reset file pointer
// See if the section already exists, if so save the start of it
Status = BaseDllFindSection( a ); if (NT_SUCCESS(Status)) { pSection = a->TextCurrent; } else { pSection = NULL; }
// If it's not a comment, see if the entry is in the user's ini file
} else if (*pStr != ';') {
pch = strchr(pStr, '='); if (pch) { a->VariableName.Length = a->VariableName.MaximumLength = (USHORT)(pch - pStr); a->VariableName.Buffer = pStr; a->ValueBuffer = (++pch); a->ValueLength = 0; while (*pch && (*pch != 0xa) && (*pch != 0xd)) { pch++; a->ValueLength++; }
// If the section exists, check for the keyword in user's ini
if (pSection) { a->TextCurrent = pSection; Status = BaseDllFindKeyword( a ); }
// If variable isn't found, write it out
if (!pSection || !NT_SUCCESS( Status )) {
origbase = a->TextCurrent = a->IniFile->BaseAddress; Status = BaseDllWriteKeywordValue( a, NULL ); a->TextEnd = (PCHAR)a->IniFile->BaseAddress + a->IniFile->EndOfFile; if (!NT_SUCCESS(Status)) { #if DBG
DbgPrint("TermsrvIniSyncLoop: Error 0x%x write Key Value\n", Status); #endif
a->IniFile->UpdateEndOffset = a->IniFile->EndOfFile; RtlFreeHeap( RtlProcessHeap(), 0, pStr ); if (AnsiSection.Buffer) { RtlFreeHeap(RtlProcessHeap(), 0, AnsiSection.Buffer); } return(Status); } *pfIniUpdated = TRUE; if (origbase != a->IniFile->BaseAddress) { a->TextCurrent = a->IniFile->BaseAddress; Status = BaseDllFindSection( a ); if (NT_SUCCESS(Status)) { pSection = a->TextCurrent; } else { pSection = NULL; } } } } }
} // end while(1)
}
/******************************************************************************
* * GetPerUserWindowsDirectory * * * *****************************************************************************/ ULONG GetPerUserWindowsDirectory(PWCHAR TermSrvWindowsPath, ULONG len) { WCHAR Buf[MAX_PATH+1]; UNICODE_STRING BaseHomePathVariableName, BaseHomeDriveVariableName; NTSTATUS Status; UNICODE_STRING Path;
if( !IsTSAppCompatEnabled() || IsSystemLUID() || (len < MAX_PATH) ) { return 0; }
/*
* Check for HOMEDRIVE and HOMEPATH */ RtlInitUnicodeString(&BaseHomeDriveVariableName,L"HOMEDRIVE"); RtlInitUnicodeString(&BaseHomePathVariableName,L"HOMEPATH");
Path.Buffer = Buf; Path.Length = 0; Path.MaximumLength = (MAX_PATH * sizeof(WCHAR)) - (9 * sizeof(WCHAR)); //MAX_PATH - wcslen(L"\\WINDOWS") + 1
if (NT_SUCCESS(Status = RtlQueryEnvironmentVariable_U( NULL, &BaseHomeDriveVariableName, &Path))) { Path.Buffer[Path.Length] = UNICODE_NULL; wcscpy(TermSrvWindowsPath,Path.Buffer);
Path.MaximumLength -= Path.Length;
if (NT_SUCCESS(Status = RtlQueryEnvironmentVariable_U( NULL, &BaseHomePathVariableName, &Path))) { Path.Buffer[Path.Length] = UNICODE_NULL; wcscat(TermSrvWindowsPath,Path.Buffer); }
}
if (!NT_SUCCESS(Status)) { #if DBG
DbgPrint("GetPerUserWindowsDirectory Failed with Status %lx\n", Status); #endif
return 0; }
/*
* Add a trailing backslash if one's not already there */
if (TermSrvWindowsPath[wcslen(TermSrvWindowsPath) -1 ] != L'\\') { wcscat(TermSrvWindowsPath,L"\\"); }
wcscat(TermSrvWindowsPath,L"WINDOWS");
return( wcslen(TermSrvWindowsPath) ); }
|