|
|
//
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-1999
//
// Author: AdamEd
// Date: October 1998
//
// Class Store path query / persistence
//
//
//---------------------------------------------------------------------
#include "cstore.hxx"
#include "cspath.hxx"
HRESULT GetAppmgmtIniFilePath( PSID pSid, LPWSTR* ppwszPath ) { UNICODE_STRING SidString; PTOKEN_USER pTokenUser; WCHAR wszPath[MAX_PATH]; WCHAR * pwszSystemDir = NULL; DWORD AllocLength; DWORD Length; DWORD Size; BOOL bStatus; ULONG ulSize;
*ppwszPath = 0;
pwszSystemDir = wszPath; AllocLength = sizeof(wszPath) / sizeof(WCHAR);
for (;;) { Length = GetSystemDirectory( pwszSystemDir, AllocLength );
if ( 0 == Length ) return HRESULT_FROM_WIN32(GetLastError());
if ( Length >= AllocLength ) { AllocLength = Length + 1; if (pwszSystemDir != wszPath) { LocalFree(pwszSystemDir); } pwszSystemDir = (WCHAR *) LocalAlloc( LPTR, AllocLength * sizeof(WCHAR) ); if (NULL == pwszSystemDir) { return E_OUTOFMEMORY; }
continue; }
break; }
if ( pSid ) { NTSTATUS ntStatus; DWORD dwStatus;
ntStatus = RtlConvertSidToUnicodeString( &SidString, pSid, TRUE ); if (!NT_SUCCESS(ntStatus)) { if (pwszSystemDir != wszPath) { LocalFree(pwszSystemDir); }
dwStatus = RtlNtStatusToDosError(ntStatus); return HRESULT_FROM_WIN32(dwStatus); }
} else { RtlInitUnicodeString( &SidString, L"MACHINE" ); }
HRESULT hr;
// System dir + \appmgmt\ + Sid \ + inifilename \ + null
ulSize = Length + 11 + (SidString.Length / 2) + (sizeof(APPMGMT_INI_FILENAME) / sizeof(WCHAR)); *ppwszPath = new WCHAR[ulSize];
if ( *ppwszPath ) { hr = StringCchCopy( *ppwszPath, ulSize, pwszSystemDir ); if (SUCCEEDED(hr)) { if ( pwszSystemDir[lstrlen(pwszSystemDir)-1] != L'\\' ) { hr = StringCchCat( *ppwszPath, ulSize, L"\\" ); } if (SUCCEEDED(hr)) { hr = StringCchCat( *ppwszPath, ulSize, L"appmgmt\\" ); if (SUCCEEDED(hr)) { hr = StringCchCat( *ppwszPath, ulSize, SidString.Buffer ); if (SUCCEEDED(hr)) { hr = StringCchCat( *ppwszPath, ulSize, APPMGMT_INI_FILENAME ); }
} }
} if (FAILED(hr)) { if ( pSid ) RtlFreeUnicodeString( &SidString ); if (pwszSystemDir != wszPath) { LocalFree(pwszSystemDir); } return hr; } } else { hr = E_OUTOFMEMORY; }
if ( pSid ) RtlFreeUnicodeString( &SidString ); if (pwszSystemDir != wszPath) { LocalFree(pwszSystemDir); }
return hr; }
LONG GetClassStorePathSize( HANDLE hFile, DWORD* pdwSize) { BOOL bStatus; DWORD cbSizeHigh;
//
// Initialize the size to the length of an empty path -- this way
// if no file is passed in we will treat that as a class store path
// of zero length (excluding the terminator). This length must include
// the terminator, so we set our initial size to that of an empty string
//
*pdwSize = sizeof(L'\0');
//
// If we have an open file with data, determine the size of the data
//
if ( hFile ) { //
// GetFileSize returns the logical size of the file, regardless
// of whether the logical size is the same as the physical
// size due to the vagaries of different file systems or compression
//
*pdwSize = GetFileSize( hFile, &cbSizeHigh);
//
// Check for a failure from the api
//
if ( -1 == *pdwSize ) { return GetLastError(); }
//
// Check the size for validity -- a file of ridiculous
// size will be rejected
//
if ( cbSizeHigh ) { //
// If the high dword is set, clearly this file
// contains an unreasonable amount of data
//
return ERROR_INSUFFICIENT_BUFFER; } else if ( *pdwSize > MAX_CSPATH_SIZE ) { //
// Again, the size should be within reasonable limits
//
return ERROR_INSUFFICIENT_BUFFER; } }
return ERROR_SUCCESS; }
LONG ReadClassStorePathFromFile( HANDLE hFile, WCHAR* wszDestination, DWORD cbSize) { DWORD cbRead; BOOL bStatus;
//
// The format of the file is simple -- it is simply the stream of bytes
// that represent a unicode string terminated by a null unicode character --
// we can just read the data directly and copy it to a buffer referenced by
// a WCHAR* -- it will be legitimate unicode string once we read it in -- it includes
// the null unicode char as the last byte read
//
//
// Note that we've read nothing so far
//
cbRead = 0;
//
// If the file has data, read it
//
if ( cbSize ) { //
// Read the data from the file into the buffer
//
bStatus = ReadFile( hFile, wszDestination, cbSize, &cbRead, NULL);
if (!bStatus) { return GetLastError(); }
//
// Verify that the last character read was a null unicode character.
// If it wasn't, the file is corrupt -- return an error so we don't
// try to use the corrupt data and cause repeated errors or even crashes
//
if ( wszDestination[ cbRead / sizeof(*wszDestination) - 1 ] != L'\0' ) { return ERROR_FILE_CORRUPT; } } else { //
// For empty files, we simply return an empty unicode string
//
wszDestination[ 0 ] = L'\0'; }
return ERROR_SUCCESS; }
HRESULT ReadClassStorePath(PSID pSid, LPWSTR* ppwszClassStorePath) { HRESULT hr; LPWSTR wszIniFilePath; DWORD cbSize; WCHAR* wszClassStorePath; LONG Status; HANDLE hFile;
cbSize = 0;
//
// Notes: The file being read by this function was originally an
// ini file as generated by the WritePrivateProfileSection api.
// Unfortunately, the corresponding GetPrivateProfileString was horribly
// broken in the sense that it had a 32k limit on the size of values. This
// was not acceptable for our design, so we read the file directly
//
hr = GetAppmgmtIniFilePath( pSid, &wszIniFilePath);
if (FAILED(hr)) { return hr; }
//
// Initialize our reference to conditionally freed data
//
wszClassStorePath = NULL;
//
// First, attempt to open the file, which should already exist. We
// generally do not expect concurrent readers, as there
// are only two processes from which this file is read: services
// and winlogon. Neither should be reading it at the same time, though
// a terminal server case where the same user was logged in to the machine
// twice could cause it
//
hFile = CreateFile( wszIniFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
//
// Handle the failure cases
//
if ( INVALID_HANDLE_VALUE == hFile ) { //
// We want to use NULL to indicate the absence of the file
//
hFile = NULL;
Status = GetLastError();
//
// If the file did not exist, that's ok -- we interpret the
// absence of the file as a blank class store path -- we
// will not exit if the file didn't exist
//
if (ERROR_FILE_NOT_FOUND != Status) { goto cleanup_and_exit; } } else { //
// If we don't have a file in existence, this means a zero length
// class store path
//
cbSize = 0; }
//
// Now that we have access to the file or know that the file does
// not exist, we can calculate the size of the class store path
// from the file's size, as they have a 1-1 relationship. Note that if the
// file does not exist, then hFile will be NULL
//
if ( hFile ) { Status = GetClassStorePathSize( hFile, &cbSize);
if ( ERROR_SUCCESS != Status ) { goto cleanup_and_exit; } }
//
// We know the size, so allocate space, treating the size
// as the length (in bytes) of the string including the terminator --
// to handle the case where cbSize is zero because of a nonexistent
// cs path, we will also add a terminating NULL since zero length
// strings are still 1 character in size
//
wszClassStorePath = new WCHAR [ cbSize / sizeof(*wszClassStorePath) + 1 ];
if ( wszClassStorePath ) { //
// We have a buffer, so read the unicode string into
// the buffer
//
Status = ReadClassStorePathFromFile( hFile, wszClassStorePath, cbSize); } else { Status = ERROR_NOT_ENOUGH_MEMORY; }
cleanup_and_exit:
//
// We no longer need the path to the ini file -- free it
//
delete [] wszIniFilePath;
//
// Close the file if it's open
//
if ( hFile ) { CloseHandle( hFile ); }
//
// On success, set the out param. On failure,
// free any buffer we allocated for the class store path
//
if (ERROR_SUCCESS == Status) { *ppwszClassStorePath = wszClassStorePath; } else { delete [] wszClassStorePath; }
return HRESULT_FROM_WIN32(Status); }
|