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.
 
 
 
 
 
 

447 lines
11 KiB

//
//
// 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);
}