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.
 
 
 
 
 
 

7819 lines
218 KiB

//*************************************************************
//
// Utility functions
//
// Microsoft Confidential
// Copyright (c) Microsoft Corporation 1995
// All rights reserved
//
//*************************************************************
#include "uenv.h"
#include <iphlpapi.h>
#include <winsock2.h>
#include <mswsock.h>
#include <Aclapi.h>
#include <windns.h>
#include "strsafe.h"
#define PCOMMON_IMPL
#include "pcommon.h"
#define NETWORK_PROVIDER L"System\\CurrentControlSet\\Services\\lanmanworkstation\\NetworkProvider"
#define PROVIDER_NAME L"Name"
INT g_iMachineRole = -1;
LPVOID g_lpTestData = NULL;
CRITICAL_SECTION *g_PingCritSec;
LPCTSTR c_szUNCFilePrefix = TEXT("\\\\?\\UNC\\");
LPCTSTR c_szLocalFilePrefix = TEXT("\\\\?\\");
const DWORD c_dwLocalFilePrefixLen = sizeof(c_szLocalFilePrefix) / sizeof(TCHAR); // Length of szLocalFilePrefix in unit of TCHAR.
//
// Local function proto-types
//
DWORD IsSlowLink (HKEY hKeyRoot, LPTSTR lpDCAddress, BOOL *bSlow, DWORD* pdwAdapterIndex );
DWORD GetNetworkProvider(NETRESOURCE *psNR);
#ifdef __cplusplus
extern "C" {
#endif
DWORD APIENTRY
NPAddConnection3ForCSCAgent(
HWND hwndOwner,
LPNETRESOURCE lpNetResource,
LPTSTR pszPassword,
LPTSTR pszUserName,
DWORD dwFlags,
BOOL *lpfIsDfsConnect
);
DWORD APIENTRY
NPCancelConnectionForCSCAgent (
LPCTSTR szName,
BOOL fForce
);
#ifdef __cplusplus
}
#endif
DWORD
GetGroupPolicyNetworkName( LPWSTR szNetworkName, LPDWORD pdwByteCount )
{
HKEY hKey;
DWORD dwError = ERROR_SUCCESS;
dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History",
0,
KEY_READ,
&hKey );
if ( dwError == ERROR_SUCCESS )
{
DWORD dwType = REG_SZ;
dwError = RegQueryValueEx( hKey,
L"NetworkName",
0,
&dwType,
(LPBYTE) szNetworkName,
pdwByteCount );
RegCloseKey (hKey);
}
return dwError;
}
int
GetNetworkName( LPWSTR* pszName, DWORD dwAdapterIndex )
{
int iError;
WSAQUERYSET restrictions;
GUID WsMobilityServiceClassGuid = NLA_SERVICE_CLASS_GUID;
WSADATA wsaData;
HANDLE hQuery;
PWSAQUERYSET pResult = 0;
DWORD length;
BOOL bFinish = FALSE;
PWS2_32_API pWS2_32 = Loadws2_32Api();
PIPHLPAPI_API pIpHlpApi = LoadIpHlpApi();
if ( !pWS2_32 )
{
return GetLastError();
}
if ( !pIpHlpApi )
{
return GetLastError();
}
//
// Initialize Winsock
//
iError = pWS2_32->pfnWSAStartup( MAKEWORD(2, 2), &wsaData );
if ( iError )
{
return iError;
}
//
// Initialize the query for network names
//
ZeroMemory(&restrictions, sizeof(restrictions));
restrictions.dwSize = sizeof(restrictions);
restrictions.lpServiceClassId = &WsMobilityServiceClassGuid;
restrictions.dwNameSpace = NS_NLA;
//
// Make sure we do not ask for the blobs that take a long time to get
//
if ( pWS2_32->pfnWSALookupServiceBegin( &restrictions, LUP_NOCONTAINERS, &hQuery ) )
{
iError = pWS2_32->pfnWSAGetLastError();
pWS2_32->pfnWSACleanup();
return iError;
}
//
// Start loop of getting network names
//
while ( !bFinish )
{
int error;
length = 0;
//
// Do call twice, first to get size of buffer for second call
//
error = pWS2_32->pfnWSALookupServiceNext( hQuery, 0, &length, 0 );
iError = pWS2_32->pfnWSAGetLastError();
if ( iError != WSAEFAULT && iError != WSA_E_NO_MORE )
{
break;
}
pResult = (PWSAQUERYSET) LocalAlloc( LPTR, length );
if ( !pResult )
{
iError = GetLastError();
break;
}
//
// Get a network name
//
if ( !pWS2_32->pfnWSALookupServiceNext( hQuery, 0, &length, pResult ) )
{
if ( pResult->lpBlob )
{
int next;
NLA_BLOB *blob = (NLA_BLOB *)pResult->lpBlob->pBlobData;
do {
//
// We are looking for the blob containing the network GUID
//
if ( blob->header.type == NLA_INTERFACE )
{
//
// "\\DEVICE\\TCPIP_" + "{GUID"
//
WCHAR szAdapter[64];
DWORD dwAdapter;
WCHAR* szEnd = NULL;
size_t cchRemain = 0;
HRESULT hr = E_FAIL;
//
// Convert guid to device name
//
StringCchCopyExW( szAdapter,
ARRAYSIZE(szAdapter),
L"\\DEVICE\\TCPIP_",
&szEnd,
&cchRemain,
0);
if (MultiByteToWideChar(CP_ACP,
0,
(LPCSTR)blob->data.interfaceData.adapterName,
-1,
szEnd,
cchRemain))
{
//
// Get the index for the network
//
if ( pIpHlpApi->pfnGetAdapterIndex( szAdapter, &dwAdapter ) == NO_ERROR )
{
//
// Is it the index we are after
//
if ( dwAdapterIndex == dwAdapter && pResult->lpszServiceInstanceName )
{
//
// Yes, copy the network name into the buffer
//
DWORD dwSize = sizeof( WCHAR ) * ( wcslen(pResult->lpszServiceInstanceName) + 1 );
*pszName = (LPWSTR) LocalAlloc( LPTR, dwSize );
if ( !*pszName )
{
iError = GetLastError();
}
else
{
StringCbCopyW( *pszName, dwSize, pResult->lpszServiceInstanceName );
bFinish = TRUE;
iError = 0;
}
}
}
}
else
{
iError = GetLastError();
}
}
//
// There maybe multiple blobs for each interface so make sure we find them all
//
next = blob->header.nextOffset;
blob = (NLA_BLOB *)(((char *)blob) + next);
} while ( next );
}
LocalFree( pResult );
}
else
{
iError = pWS2_32->pfnWSAGetLastError();
if ( iError == WSA_E_NO_MORE )
{
iError = 0;
}
LocalFree( pResult );
break;
}
}
//
// tidy up
//
pWS2_32->pfnWSALookupServiceEnd( hQuery );
pWS2_32->pfnWSACleanup();
return iError;
}
//*************************************************************
//
// ProduceWFromA()
//
// Purpose: Creates a buffer for a Unicode string and copies
// the ANSI text into it (converting in the process)
//
// Parameters: pszA - ANSI string
//
//
// Return: Unicode pointer if successful
// NULL if an error occurs
//
// Comments: The caller needs to free this pointer.
//
//
// History: Date Author Comment
// 5/24/95 ericflo Ported
//
//*************************************************************
LPWSTR ProduceWFromA(LPCSTR pszA)
{
LPWSTR pszW;
int cch;
if (!pszA)
return (LPWSTR)pszA;
cch = MultiByteToWideChar(CP_ACP, 0, pszA, -1, NULL, 0);
if (cch == 0)
cch = 1;
pszW = LocalAlloc(LPTR, cch * sizeof(WCHAR));
if (pszW) {
if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszA, -1, pszW, cch)) {
LocalFree(pszW);
pszW = NULL;
}
}
return pszW;
}
//*************************************************************
//
// ProduceAFromW()
//
// Purpose: Creates a buffer for an ANSI string and copies
// the Unicode text into it (converting in the process)
//
// Parameters: pszW - Unicode string
//
//
// Return: ANSI pointer if successful
// NULL if an error occurs
//
// Comments: The caller needs to free this pointer.
//
//
// History: Date Author Comment
// 5/24/95 ericflo Ported
//
//*************************************************************
LPSTR ProduceAFromW(LPCWSTR pszW)
{
LPSTR pszA;
int cch;
if (!pszW)
return (LPSTR)pszW;
cch = WideCharToMultiByte(CP_ACP, 0, pszW, -1, NULL, 0, NULL, NULL);
if (cch == 0)
cch = 1;
pszA = LocalAlloc(LPTR, cch * sizeof(char));
if (pszA) {
if (!WideCharToMultiByte(CP_ACP, 0, pszW, -1, pszA, cch, NULL, NULL)) {
LocalFree(pszA);
pszA = NULL;
}
}
return pszA;
}
//*************************************************************
//
// CheckSlash()
//
// Purpose: Checks for an ending slash and adds one if
// it is missing.
//
// Parameters: lpDir - directory
//
// Return: Pointer to the end of the string
//
// Comments:
//
// History: Date Author Comment
// 6/19/95 ericflo Created
//
//*************************************************************
LPTSTR CheckSlash (LPTSTR lpDir)
{
LPTSTR lpEnd;
lpEnd = lpDir + lstrlen(lpDir);
if (*(lpEnd - 1) != TEXT('\\')) {
*lpEnd = TEXT('\\');
lpEnd++;
*lpEnd = TEXT('\0');
}
return lpEnd;
}
//*************************************************************
//
// CheckSlashEx()
//
// Purpose: Checks for an ending slash and adds one if
// it is missing. It will take the buffer size
// to make it safe (not overflow the buffer).
//
// Parameters: lpDir - directory
// cchBuffer - buffer size
// pcchRemain - buffer remained after patch '\'
// can be NULL if not needed.
//
// Return: Pointer to the end of the string, NULL for
// overflowed buffer.
//
// Comments:
//
// History: Date Author Comment
// 06/19/95 ericflo Created
// 02/11/02 mingzhu Make it safe
//
//*************************************************************
LPTSTR CheckSlashEx(LPTSTR lpDir, UINT cchBuffer, UINT* pcchRemain )
{
LPTSTR lpEnd = NULL;
UINT cchLen = lstrlen(lpDir);
if (cchLen >= cchBuffer - 1) // Overflowed or full buffer
{
DmAssert(cchLen == cchBuffer - 1); // Should never happen
if (pcchRemain)
*pcchRemain = 0;
lpEnd = NULL;
}
else
{
lpEnd = lpDir + cchLen;
if (pcchRemain)
*pcchRemain = cchBuffer - 1 - cchLen;
if (*(lpEnd - 1) != TEXT('\\'))
{
*lpEnd = TEXT('\\');
lpEnd++;
*lpEnd = TEXT('\0');
if (pcchRemain)
(*pcchRemain) --;
}
}
return lpEnd;
}
//*************************************************************
//
// CheckSemicolon()
//
// Purpose: Checks for an ending slash and adds one if
// it is missing.
//
// Parameters: lpDir - directory
//
// Return: Pointer to the end of the string
//
// Comments:
//
// History: Date Author Comment
// 6/19/95 ericlfo Created
//
//*************************************************************
LPTSTR CheckSemicolon (LPTSTR lpDir)
{
LPTSTR lpEnd;
lpEnd = lpDir + lstrlen(lpDir);
if (*(lpEnd - 1) != TEXT(';')) {
*lpEnd = TEXT(';');
lpEnd++;
*lpEnd = TEXT('\0');
}
return lpEnd;
}
//*************************************************************
//
// Delnode_Recurse()
//
// Purpose: Recursive delete function for Delnode
//
// Parameters: lpDir - Full Directory Path.
// dwSize - Allocated size of the working buffer
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 8/10/95 ericflo Created
// 04/08/2002 mingzhu Added functionality to take ownership
//
// Notes:
// This function modifies the working buffer.
// This doesn't maintain the right error code. It ignores all
// errors and tries to delete as much as possible..
//
//*************************************************************
BOOL Delnode_Recurse (LPTSTR lpDir, DWORD dwSize)
{
BOOL bOwn = FALSE, bRetVal = FALSE;
LPTSTR lpEnd = NULL, lpWrkDir = NULL;
WIN32_FIND_DATA* pfd = NULL;
HANDLE hFile;
DWORD dwWrkDirSize;
DWORD cchEnd; // buffer size for lpEnd
HRESULT hr;
BOOL bDeleteSuccess;
//
// Verbose output
//
DebugMsg((DM_VERBOSE, TEXT("Delnode_Recurse: Entering, lpDir = <%s>"), lpDir));
//
// Each filename or a directory has to be less than MAX_PATH in the worst case.
// So make sure that we have at least MAX_PATH + 2 (for a slash and '\0'
// space left in the working buffer case.
//
// In the normal case, when we have a path of length ~MAX_PATH it will do only
// 1 allocation
//
if ((DWORD)(lstrlen(lpDir) + MAX_PATH+2) > (dwSize)) {
dwWrkDirSize = dwSize+2*MAX_PATH;
lpWrkDir = (LPTSTR)LocalAlloc(LPTR, dwWrkDirSize*sizeof(TCHAR));
if (!lpWrkDir) {
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Couldn't allocate memory for working buffer. Error - %d"), GetLastError()));
goto Exit;
}
StringCchCopy(lpWrkDir, dwWrkDirSize, lpDir);
bOwn = TRUE;
}
else {
lpWrkDir = lpDir;
dwWrkDirSize = dwSize;
}
//
// append "*.*" to the directory name
//
lpEnd = CheckSlashEx(lpWrkDir, dwWrkDirSize, &cchEnd);
StringCchCopy(lpEnd, cchEnd, c_szStarDotStar);
//
// Allocate fd in the heap, reduce stack usage
//
pfd = (WIN32_FIND_DATA*) LocalAlloc(LPTR, sizeof(WIN32_FIND_DATA));
if (!pfd)
{
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Couldn't allocate memory for WIN32_FIND_DATA. Error - %d"), GetLastError()));
goto Exit;
}
//
// Find the first file
//
hFile = FindFirstFile(lpWrkDir, pfd);
if (hFile == INVALID_HANDLE_VALUE) {
if ((GetLastError() == ERROR_FILE_NOT_FOUND) || (GetLastError() == ERROR_PATH_NOT_FOUND))
{
bRetVal = TRUE;
goto Exit;
}
else if ((GetLastError() == ERROR_ACCESS_DENIED))
{
//
// Now we got an access denied, we will try to take the ownership of the directory and
// add admin full access to it so that we can recurse into it and delete it.This only
// works when the caller is an admin.
//
*lpEnd = TEXT('\0'); // Restore the original name
hr = TakeOwnership(lpWrkDir);
if (FAILED(hr))
{
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: TakeOwnership failed. Error = 0x%08X"), hr));
goto Exit;
}
hr = AddAdminAccess(lpWrkDir);
if (FAILED(hr))
{
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: AddAdminAccess failed. Error = 0x%08X"), hr));
goto Exit;
}
// Append "*.*" and try again
StringCchCopy(lpEnd, cchEnd, c_szStarDotStar);
hFile = FindFirstFile(lpWrkDir, pfd);
if (hFile == INVALID_HANDLE_VALUE)
{
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: FindFirstFile failed. Error = %d"), GetLastError()));
goto Exit;
}
}
else {
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: FindFirstFile failed. Error = %d"), GetLastError()));
goto Exit;
}
}
do {
//
// Check for "." and ".."
//
if (!lstrcmpi(pfd->cFileName, c_szDot)) {
continue;
}
if (!lstrcmpi(pfd->cFileName, c_szDotDot)) {
continue;
}
//
// Verbose output
//
DebugMsg((DM_VERBOSE, TEXT("Delnode_Recurse: FindFile found: <%s>"), pfd->cFileName));
// Note that fd.cFileName will not exceed MAX_PATH, so the buffer is
// always large enough to hold it in this algorithm.
StringCchCopy(lpEnd, cchEnd, pfd->cFileName);
if (pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
//
// Found a directory.
//
if (pfd->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Found a reparse point <%s>, Will not recurse into it!"), lpWrkDir));
}
else
{
Delnode_Recurse(lpWrkDir, dwWrkDirSize);
// ignore errors and go ahead..
StringCchCopy(lpEnd, cchEnd, pfd->cFileName);
}
if (pfd->dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
pfd->dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
SetFileAttributes (lpWrkDir, pfd->dwFileAttributes);
}
if (!RemoveDirectory (lpWrkDir))
{
bDeleteSuccess = FALSE;
if (GetLastError() == ERROR_ACCESS_DENIED)
{
if ( SUCCEEDED(TakeOwnership(lpWrkDir)) &&
SUCCEEDED(AddAdminAccess(lpWrkDir)) &&
RemoveDirectory(lpWrkDir) )
{
bDeleteSuccess = TRUE;
}
}
if (!bDeleteSuccess)
{
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Failed to delete directory <%s>. Error = %d"),
lpWrkDir, GetLastError()));
}
}
} else {
//
// We found a file. Set the file attributes,
// and try to delete it.
//
if ((pfd->dwFileAttributes & FILE_ATTRIBUTE_READONLY) ||
(pfd->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) {
SetFileAttributes (lpWrkDir, FILE_ATTRIBUTE_NORMAL);
}
if (!DeleteFile (lpWrkDir))
{
bDeleteSuccess = FALSE;
if (GetLastError() == ERROR_ACCESS_DENIED)
{
if ( SUCCEEDED(TakeOwnership(lpWrkDir)) &&
SUCCEEDED(AddAdminAccess(lpWrkDir)) &&
DeleteFile(lpWrkDir) )
{
bDeleteSuccess = TRUE;
}
}
if (!bDeleteSuccess)
{
DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Failed to delete <%s>. Error = %d"),
pfd->cFileName, GetLastError()));
}
}
}
//
// Find the next entry
//
} while (FindNextFile(hFile, pfd));
//
// Close the search handle
//
FindClose(hFile);
//
// Success.
//
DebugMsg((DM_VERBOSE, TEXT("Delnode_Recurse: Leaving <%s>"), lpDir));
bRetVal = TRUE;
Exit:
if (bOwn)
LocalFree(lpWrkDir);
if (pfd)
LocalFree(pfd);
return bRetVal;
}
//*************************************************************
//
// Delnode()
//
// Purpose: Recursive function that deletes files and
// directories.
//
// Parameters: lpDir - Directory
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 6/23/95 ericflo Created
// 6/27/00 santanuc modified to allow deletion of file with path length > MAX_PATH
//
//*************************************************************
BOOL Delnode (LPTSTR lpDir)
{
LPTSTR lpWrkDir = NULL;
DWORD dwWrkDirSize;
BOOL bRetVal = FALSE;
lpWrkDir = SupportLongFileName(lpDir, &dwWrkDirSize);
if (!lpWrkDir) {
DebugMsg((DM_WARNING, TEXT("Delnode: Failed to Allocate memory. Error = %d"),
GetLastError()));
goto Exit;
}
if (!Delnode_Recurse (lpWrkDir, dwWrkDirSize)) {
DebugMsg((DM_WARNING, TEXT("Delnode: Delnode recurse failed with error %d"),
GetLastError()));
}
if (!RemoveDirectory (lpDir)) {
DWORD dwError;
dwError = GetLastError();
if ((dwError != ERROR_FILE_NOT_FOUND) &&
(dwError != ERROR_PATH_NOT_FOUND)) {
DebugMsg((DM_VERBOSE, TEXT("Delnode: Failed to delete directory <%s>. Error = %d"),
lpDir, dwError));
}
goto Exit;
}
bRetVal = TRUE;
DebugMsg((DM_VERBOSE, TEXT("Delnode: Deleted directory <%s> successfully."), lpDir));
Exit:
if (lpWrkDir) {
LocalFree(lpWrkDir);
}
return bRetVal;
}
//*************************************************************
//
// CreateSystemDirectory()
//
// Purpose: A directory with system bit turned on can be created using
// CreateSystemDirectory.
//
// This API causes a system directory with the specified pathname to be
// created. If the underlying file system supports security on files
// and directories, then the SecurityDescriptor argument is applied to
// the new directory.
//
// This call is similar to DOS (int 21h, function 39h) and OS/2's
// DosCreateDir.
//
//
// Parameters: lpPathName - Supplies the pathname of the system directory to be created.
// lpSecurityAttributes - An optional parameter that, if present, and
// supported on the target file system supplies a security
// descriptor for the new directory.
//
//
// Return: TRUE - The operation was successful.
// FALSE/NULL - The operation failed. Extended error status is available
// using GetLastError.
//
// Comments: This function is exactly same as CreateDirectory API with the exception
// that the directory is created using attribute FILE_ATTRIBUTE_SYSTEM.
// This allows newly created directory to not inherit the encryption property
// from parent directory if the parent directory is encrypted.
//
// History: Date Author Comments
// 07/18/00 santanuc To avoid deadlock situation when Documents and Settings
// directory is encrypted.
//
//*************************************************************
BOOL CreateSystemDirectory(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME_U RelativeName;
PVOID FreeBuffer;
ULONG dwErrorCode;
// Note : ANSI version may cause error calling the following
TranslationStatus = RtlDosPathNameToRelativeNtPathName_U( lpPathName,
&FileName,
NULL,
&RelativeName);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
//
// dont create a directory unless there is room in the directory for
// at least an 8.3 name. This way everyone will be able to delete all
// files in the directory by using del *.* which expands to path+\*.*
//
if ( FileName.Length > ((MAX_PATH-12)<<1) ) {
DWORD L;
LPWSTR lp;
if ( !(lpPathName[0] == TEXT('\\') && lpPathName[1] == TEXT('\\') &&
lpPathName[2] == TEXT('?') && lpPathName[3] == TEXT('\\')) ) {
L = GetFullPathNameW(lpPathName,0,NULL,&lp);
if ( !L || L+12 > MAX_PATH ) {
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0,FileName.Buffer);
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return FALSE;
}
}
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes( &Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL );
if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
}
// Creating the directory with attribute FILE_ATTRIBUTE_SYSTEM to avoid inheriting encryption
// property from parent directory
Status = NtCreateFile( &Handle,
FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_SYSTEM,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0L );
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
if ( NT_SUCCESS(Status) ) {
NtClose(Handle);
return TRUE;
}
else {
if ( RtlIsDosDeviceName_U((LPWSTR)lpPathName) ) {
Status = STATUS_NOT_A_DIRECTORY;
}
// Since RtlNtStatusToDosError function can't convert STATUS_TIMEOUT, we have to
// do it explicitly
if (Status == STATUS_TIMEOUT) {
SetLastError(ERROR_TIMEOUT);
}
else {
dwErrorCode = RtlNtStatusToDosError( Status );
SetLastError( dwErrorCode );
}
return FALSE;
}
}
//*************************************************************
//
// CreateNestedDirectory()
//
// Purpose: Creates a subdirectory and all it's parents
// if necessary using CreateNestedDirectoryEx.
//
// Parameters: lpDirectory - Directory name
// lpSecurityAttributes - Security Attributes
//
// Return: > 0 if successful
// 0 if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 7/18/00 santanuc Created
//
//*************************************************************
UINT CreateNestedDirectory(LPCTSTR lpDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
// Call CreateNestedDirectoryEx with inherit encryption property
return CreateNestedDirectoryEx(lpDirectory, lpSecurityAttributes, TRUE);
}
//*************************************************************
//
// CreateNestedDirectoryEx()
//
// Purpose: Creates a subdirectory and all it's parents
// if necessary.
//
// Parameters: lpDirectory - Directory name
// lpSecurityAttributes - Security Attributes
// bInheritEncryption - Flag indicating whether newly created directory should inherit
// encryption property from parent directory.
//
// Return: > 0 if successful
// 0 if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 8/08/95 ericflo Created
// 7/18/00 santanuc added a new flag bInheritEncryption to avoid deadlock when
// Documents and Settings directory is encrypted.
//
//*************************************************************
UINT CreateNestedDirectoryEx(LPCTSTR lpDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes, BOOL bInheritEncryption)
{
TCHAR szDirectory[2*MAX_PATH];
LPTSTR lpEnd;
WIN32_FILE_ATTRIBUTE_DATA fad;
//
// Check for NULL pointer
//
if (!lpDirectory || !(*lpDirectory)) {
DebugMsg((DM_WARNING, TEXT("CreateNestedDirectory: Received a NULL pointer.")));
return 0;
}
//
// Test if the directory exists already
//
if (GetFileAttributesEx (lpDirectory, GetFileExInfoStandard, &fad)) {
if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
return ERROR_ALREADY_EXISTS;
} else {
SetLastError(ERROR_ACCESS_DENIED);
return 0;
}
}
//
// First, see if we can create the directory without having
// to build parent directories.
//
if ( bInheritEncryption ) {
if (CreateDirectory (lpDirectory, lpSecurityAttributes))
return 1;
}
else {
if (CreateSystemDirectory (lpDirectory, lpSecurityAttributes)) {
SetFileAttributes(lpDirectory, FILE_ATTRIBUTE_NORMAL); // turn off the system attribute
return 1;
}
}
//
// No luck, copy the string to a buffer we can munge
//
StringCchCopy(szDirectory, ARRAYSIZE(szDirectory), lpDirectory);
//
// Find the first subdirectory name
//
lpEnd = szDirectory;
if (szDirectory[1] == TEXT(':')) {
lpEnd += 3;
} else if (szDirectory[1] == TEXT('\\')) {
//
// Skip the first two slashes
//
lpEnd += 2;
//
// Find the slash between the server name and
// the share name.
//
while (*lpEnd && *lpEnd != TEXT('\\')) {
lpEnd++;
}
if (!(*lpEnd)) {
return 0;
}
//
// Skip the slash, and find the slash between
// the share name and the directory name.
//
lpEnd++;
while (*lpEnd && *lpEnd != TEXT('\\')) {
lpEnd++;
}
if (!(*lpEnd)) {
return 0;
}
//
// Leave pointer at the beginning of the directory.
//
lpEnd++;
} else if (szDirectory[0] == TEXT('\\')) {
lpEnd++;
}
while (*lpEnd) {
while (*lpEnd && *lpEnd != TEXT('\\')) {
lpEnd++;
}
if (*lpEnd == TEXT('\\')) {
*lpEnd = TEXT('\0');
if (!GetFileAttributesEx (szDirectory, GetFileExInfoStandard, &fad)) {
if ( bInheritEncryption ) {
if (!CreateDirectory (szDirectory, lpSecurityAttributes)) {
DebugMsg((DM_WARNING, TEXT("CreateNestedDirectory: CreateDirectory failed with %d."), GetLastError()));
return 0;
}
}
else {
if (!CreateSystemDirectory (szDirectory, lpSecurityAttributes)) {
DebugMsg((DM_WARNING, TEXT("CreateNestedDirectory: CreateDirectory failed with %d."), GetLastError()));
return 0;
}
else
SetFileAttributes(szDirectory, FILE_ATTRIBUTE_NORMAL); // turn off the system attribute
}
}
*lpEnd = TEXT('\\');
lpEnd++;
}
}
//
// Create the final directory
//
if ( bInheritEncryption ) {
if (CreateDirectory (lpDirectory, lpSecurityAttributes))
return 1;
}
else {
if (CreateSystemDirectory (lpDirectory, lpSecurityAttributes)) {
SetFileAttributes(lpDirectory, FILE_ATTRIBUTE_NORMAL); // turn off the system attribute
return 1;
}
}
if (GetLastError() == ERROR_ALREADY_EXISTS) {
return ERROR_ALREADY_EXISTS;
}
//
// Failed
//
DebugMsg((DM_VERBOSE, TEXT("CreateNestedDirectory: Failed to create the directory with error %d."), GetLastError()));
return 0;
}
//*************************************************************
//
// GetProfilesDirectory()
//
// Purpose: Returns the location of the "profiles" directory
//
// Parameters: lpProfilesDir - Buffer to write result to
// lpcchSize - Size of the buffer in chars.
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments: If false is returned, lpcchSize holds the number of
// characters needed.
//
// History: Date Author Comment
// 9/18/95 ericflo Created
//
//*************************************************************
BOOL WINAPI GetProfilesDirectory(LPTSTR lpProfilesDir, LPDWORD lpcchSize)
{
return GetProfilesDirectoryEx (lpProfilesDir, lpcchSize, TRUE);
}
//*************************************************************
//
// GetProfilesDirectoryEx()
//
// Purpose: Returns the location of the "profiles" directory
//
// Parameters: lpProfilesDir - Buffer to write result to
// lpcchSize - Size of the buffer in chars.
// bExpand - Expand directory name
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments: If false is returned, lpcchSize holds the number of
// characters needed.
//
// History: Date Author Comment
// 12/15/97 ericflo Created
//
//*************************************************************
BOOL GetProfilesDirectoryEx(LPTSTR lpProfilesDir, LPDWORD lpcchSize, BOOL bExpand)
{
TCHAR szDirectory[MAX_PATH];
TCHAR szTemp[MAX_PATH];
DWORD dwLength;
HKEY hKey = INVALID_HANDLE_VALUE;
LONG lResult;
DWORD dwSize, dwType;
BOOL bRetVal = FALSE;
//
// Arg check
//
if (!lpcchSize) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
szDirectory[0] = TEXT('\0');
szTemp[0] = TEXT('\0');
lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, PROFILE_LIST_PATH, 0, KEY_READ,
&hKey);
if (lResult == ERROR_SUCCESS) {
dwSize = sizeof(szTemp);
lResult = RegQueryValueEx (hKey, PROFILES_DIRECTORY, NULL, &dwType,
(LPBYTE) szTemp, &dwSize);
if (lResult == ERROR_SUCCESS) {
if ((dwType == REG_EXPAND_SZ) || (dwType == REG_SZ)) {
if (bExpand && (dwType == REG_EXPAND_SZ)) {
if((dwLength = ExpandEnvironmentStrings(szTemp, szDirectory, MAX_PATH)) == 0) {
goto Exit;
}
else if(dwLength > MAX_PATH) {
SetLastError(ERROR_BAD_PATHNAME);
goto Exit;
}
} else {
StringCchCopy (szDirectory, ARRAYSIZE(szDirectory), szTemp);
}
}
}
RegCloseKey (hKey);
hKey = INVALID_HANDLE_VALUE;
}
if (szDirectory[0] == TEXT('\0')) {
LoadString (g_hDllInstance, IDS_PROFILES_ROOT, szTemp, ARRAYSIZE(szTemp));
if (bExpand) {
if((dwLength = ExpandEnvironmentStrings(szTemp, szDirectory, MAX_PATH)) == 0) {
goto Exit;
}
else if(dwLength > MAX_PATH) {
SetLastError(ERROR_BAD_PATHNAME);
goto Exit;
}
} else {
StringCchCopy (szDirectory, ARRAYSIZE(szDirectory), szTemp);
}
}
dwLength = lstrlen(szDirectory) + 1;
if (lpProfilesDir) {
if (*lpcchSize >= dwLength) {
StringCchCopy (lpProfilesDir, *lpcchSize, szDirectory);
bRetVal = TRUE;
} else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
} else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
*lpcchSize = dwLength;
Exit:
if(hKey != INVALID_HANDLE_VALUE) {
RegCloseKey(hKey);
}
return bRetVal;
}
//*************************************************************
//
// GetDefaultUserProfileDirectory()
//
// Purpose: Returns the location of the Default User's profile
//
// Parameters: lpProfileDir - Buffer to write result to
// lpcchSize - Size of the buffer in chars.
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments: If false is returned, lpcchSize holds the number of
// characters needed.
//
// History: Date Author Comment
// 12/8/97 ericflo Created
//
//*************************************************************
BOOL WINAPI GetDefaultUserProfileDirectory(LPTSTR lpProfileDir, LPDWORD lpcchSize)
{
return GetDefaultUserProfileDirectoryEx(lpProfileDir, lpcchSize, TRUE);
}
//*************************************************************
//
// GetDefaultUserProfileDirectoryEx()
//
// Purpose: Returns the location of the Default User's profile
//
// Parameters: lpProfileDir - Buffer to write result to
// lpcchSize - Size of the buffer in chars.
// bExpand - Expand the path or not
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments: If false is returned, lpcchSize holds the number of
// characters needed.
//
// History: Date Author Comment
// 12/8/97 ericflo Created
//
//*************************************************************
BOOL WINAPI GetDefaultUserProfileDirectoryEx(LPTSTR lpProfileDir,
LPDWORD lpcchSize, BOOL bExpand)
{
TCHAR szDirectory[MAX_PATH];
TCHAR szProfileName[MAX_PATH];
LPTSTR lpEnd;
int cchEnd;
DWORD dwSize, dwLength, dwType;
BOOL bRetVal = FALSE;
LONG lResult;
HKEY hKey;
//
// Arg check
//
if (!lpcchSize) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Get the profiles root
//
szDirectory[0] = TEXT('\0');
dwSize = ARRAYSIZE(szDirectory);
if (!GetProfilesDirectoryEx(szDirectory, &dwSize, bExpand)) {
DebugMsg((DM_WARNING, TEXT("GetDefaultUserProfileDirectory: Failed to get profiles root.")));
*lpcchSize = 0;
return FALSE;
}
//
// Query for the Default User profile name
//
lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, PROFILE_LIST_PATH,
0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetDefaultUserProfileDirectoryEx: Failed to open profile list key with %d."),
lResult));
SetLastError(lResult);
return FALSE;
}
dwSize = sizeof(szProfileName);
lResult = RegQueryValueEx (hKey, DEFAULT_USER_PROFILE, NULL, &dwType,
(LPBYTE) szProfileName, &dwSize);
if (lResult != ERROR_SUCCESS) {
StringCchCopy (szProfileName, ARRAYSIZE(szProfileName), DEFAULT_USER);
}
RegCloseKey (hKey);
//
// Put them together
//
lpEnd = CheckSlashEx (szDirectory, ARRAYSIZE(szDirectory), &cchEnd);
if (cchEnd < lstrlen(szProfileName) + 1)
{
DebugMsg((DM_WARNING, TEXT("GetDefaultUserProfileDirectory: path > MAX_PATH.")));
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
StringCchCopy (lpEnd, cchEnd, szProfileName);
//
// Save the result if possible
dwLength = lstrlen(szDirectory) + 1;
if (lpProfileDir) {
if (*lpcchSize >= dwLength) {
StringCchCopy (lpProfileDir, *lpcchSize, szDirectory);
bRetVal = TRUE;
} else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
} else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
*lpcchSize = dwLength;
return bRetVal;
}
//*************************************************************
//
// GetAllUsersProfileDirectory()
//
// Purpose: Returns the location of the All Users profile
//
// Parameters: lpProfileDir - Buffer to write result to
// lpcchSize - Size of the buffer in chars.
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments: If false is returned, lpcchSize holds the number of
// characters needed.
//
// History: Date Author Comment
// 12/8/97 ericflo Created
//
//*************************************************************
BOOL WINAPI GetAllUsersProfileDirectory(LPTSTR lpProfileDir, LPDWORD lpcchSize)
{
return GetAllUsersProfileDirectoryEx(lpProfileDir, lpcchSize, TRUE);
}
//*************************************************************
//
// GetAllUsersProfileDirectoryEx()
//
// Purpose: Returns the location of the All Users profile
//
// Parameters: lpProfileDir - Buffer to write result to
// lpcchSize - Size of the buffer in chars.
// bExpand - Expand the path or not
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments: If false is returned, lpcchSize holds the number of
// characters needed.
//
// History: Date Author Comment
// 12/8/97 ericflo Created
//
//*************************************************************
BOOL GetAllUsersProfileDirectoryEx (LPTSTR lpProfileDir,
LPDWORD lpcchSize, BOOL bExpand)
{
TCHAR szDirectory[MAX_PATH];
TCHAR szProfileName[MAX_PATH];
LPTSTR lpEnd;
int cchEnd;
DWORD dwSize, dwLength, dwType;
BOOL bRetVal = FALSE;
LONG lResult;
HKEY hKey;
//
// Arg check
//
if (!lpcchSize) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Get the profiles root
//
szDirectory[0] = TEXT('\0');
dwSize = ARRAYSIZE(szDirectory);
if (!GetProfilesDirectoryEx(szDirectory, &dwSize, bExpand)) {
DebugMsg((DM_WARNING, TEXT("GetAllUsersProfileDirectoryEx: Failed to get profiles root.")));
*lpcchSize = 0;
return FALSE;
}
//
// Query for the All Users profile name
//
lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, PROFILE_LIST_PATH,
0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetAllUsersProfileDirectoryEx: Failed to open profile list key with %d."),
lResult));
SetLastError(lResult);
return FALSE;
}
dwSize = sizeof(szProfileName);
lResult = RegQueryValueEx (hKey, ALL_USERS_PROFILE, NULL, &dwType,
(LPBYTE) szProfileName, &dwSize);
if (lResult != ERROR_SUCCESS) {
StringCchCopy(szProfileName, ARRAYSIZE(szProfileName), ALL_USERS);
}
RegCloseKey (hKey);
//
// Put them together
//
lpEnd = CheckSlashEx (szDirectory, ARRAYSIZE(szDirectory), &cchEnd);
if (cchEnd < lstrlen(szProfileName) + 1)
{
DebugMsg((DM_WARNING, TEXT("GetDefaultUserProfileDirectory: path > MAX_PATH.")));
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
StringCchCopy (lpEnd, cchEnd, szProfileName);
//
// Save the result if possible
dwLength = lstrlen(szDirectory) + 1;
if (lpProfileDir) {
if (*lpcchSize >= dwLength) {
StringCchCopy (lpProfileDir, *lpcchSize, szDirectory);
bRetVal = TRUE;
} else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
} else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
*lpcchSize = dwLength;
return bRetVal;
}
//*************************************************************
//
// GetProfileListKeyName()
//
// Purpose: Returns the key name for a specific user under ProfileList.
// Using safe string functions
//
// Parameters: szKeyName - Buffer of the returned name
// cchKeyName - size of the buffer
// szSidString - sid string for a specific user
//
// Return: S_OK if successful
// Error Code if an error occurs
//
// Comments: If error code is returned, content of szKeyName may
// change.
//
// History: Date Author Comment
// 02/21/2002 mingzhu Created
//
//*************************************************************
HRESULT GetProfileListKeyName(LPTSTR szKeyName, DWORD cchKeyName, LPTSTR szSidString)
{
HRESULT hr;
hr = StringCchCopy(szKeyName, cchKeyName, PROFILE_LIST_PATH);
if (SUCCEEDED(hr))
{
hr = StringCchCat(szKeyName, cchKeyName, TEXT("\\"));
if (SUCCEEDED(hr))
{
hr = StringCchCat(szKeyName, cchKeyName, szSidString);
}
}
return hr;
}
//*************************************************************
//
// GetKeyNameForUser()
//
// Purpose: Returns the user's key name in for specific user.
// Using safe string functions
//
// Parameters: szKeyName - Buffer of the returned name
// cchKeyName - size of the buffer
// szSidString - sid string for a specific user
// szSubKey - subkey name under the key's hive
//
// Return: S_OK if successful
// Error Code if an error occurs
//
// Comments: If error code is returned, content of szKeyName may
// change.
//
// History: Date Author Comment
// 02/21/2002 mingzhu Created
//
//*************************************************************
HRESULT GetKeyNameForUser(LPTSTR szKeyName, DWORD cchKeyName, LPTSTR szSidString, LPTSTR szSubKey)
{
HRESULT hr;
hr = StringCchCopy(szKeyName, cchKeyName, szSidString);
if (SUCCEEDED(hr))
{
hr = StringCchCat(szKeyName, cchKeyName, TEXT("\\"));
if (SUCCEEDED(hr))
{
hr = StringCchCat(szKeyName, cchKeyName, szSubKey);
}
}
return hr;
}
//*************************************************************
//
// SafeExpandEnvironmentStrings()
//
// Purpose: a wrapper of ExpandEnvironmentStrings() to
// handle small buffer errors more explictly.
//
// Parameters: lpSrc - Src string contains the env var
// lpDst - Output buffer
// nSize - Size of output buffer
//
// Return: S_OK if successful
// else if an error occurs
//
// History: Date Author Comment
// 02/21/2002 mingzhu Created
//
//*************************************************************
HRESULT SafeExpandEnvironmentStrings(LPCTSTR lpSrc, LPTSTR lpDst, DWORD nSize)
{
DWORD dwErr;
HRESULT hr;
dwErr = ExpandEnvironmentStrings(lpSrc, lpDst, nSize);
if (dwErr == 0)
hr = HRESULT_FROM_WIN32(GetLastError());
else if (dwErr > nSize)
hr = STRSAFE_E_INSUFFICIENT_BUFFER;
else
hr = S_OK;
return hr;
}
//*************************************************************
//
// AppendName()
//
// Purpose: append a file name to a folder name, or append a subkey name
// to a parent key name, add a slash if neccesory.
//
// Parameters: lpBuffer - output buffer to hold the appended path
// cchBuffer - size of the output buffer
// lpParent - path/parent key name to append to
// lpChild - file/subkey name to append
// lppEnd - optional returned pointer to the end of the slash of lpParent,
// can be used to further append other children to the same parent
// pcchEnd - optional returned pointer to the buffer size pointered by *lppEnd
//
// Return: S_OK if successful
// else if an error occurs
//
// History: Date Author Comment
// 03/05/2002 mingzhu Created
//
//*************************************************************
HRESULT AppendName(
LPTSTR lpBuffer,
UINT cchBuffer,
LPCTSTR lpParent,
LPCTSTR lpChild,
LPTSTR* lppEnd,
UINT* pcchEnd)
{
HRESULT hr;
LPTSTR lpEnd;
UINT cchEnd;
hr = StringCchCopy(lpBuffer, cchBuffer, lpParent);
if (SUCCEEDED(hr))
{
lpEnd = CheckSlashEx(lpBuffer, cchBuffer, &cchEnd);
if (!lpEnd)
{
hr = STRSAFE_E_INSUFFICIENT_BUFFER;
}
else
{
hr = StringCchCopy(lpEnd, cchEnd, lpChild);
}
}
if (SUCCEEDED(hr))
{
if (lppEnd)
*lppEnd = lpEnd;
if (pcchEnd)
*pcchEnd = cchEnd;
}
return hr;
}
//*************************************************************
//
// GetUserProfileDirectory()
//
// Purpose: Returns the root of the user's profile directory.
//
// Parameters: hToken - User's token
// lpProfileDir - Output buffer
// lpcchSize - Size of output buffer
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments: If false is returned, lpcchSize holds the number of
// characters needed.
//
// History: Date Author Comment
// 9/18/95 ericflo Created
//
//*************************************************************
BOOL WINAPI GetUserProfileDirectory(HANDLE hToken, LPTSTR lpProfileDir,
LPDWORD lpcchSize)
{
DWORD dwLength = MAX_PATH * sizeof(TCHAR);
DWORD dwType;
BOOL bRetVal = FALSE;
LPTSTR lpSidString;
TCHAR szBuffer[MAX_PATH];
TCHAR szDirectory[MAX_PATH];
HKEY hKey;
LONG lResult;
HRESULT hr;
//
// Parameter check
//
if (!hToken) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!lpcchSize) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Retrieve the user's sid string
//
lpSidString = GetSidString(hToken);
if (!lpSidString) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
//
// Check the registry
//
hr = GetProfileListKeyName(szBuffer, ARRAYSIZE(szBuffer), lpSidString);
if (FAILED(hr))
{
DeleteSidString(lpSidString);
SetLastError(HRESULT_CODE(hr));
return FALSE;
}
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS) {
DeleteSidString(lpSidString);
SetLastError(lResult);
return FALSE;
}
lResult = RegQueryValueEx(hKey,
PROFILE_IMAGE_VALUE_NAME,
NULL,
&dwType,
(LPBYTE) szBuffer,
&dwLength);
if (lResult != ERROR_SUCCESS) {
RegCloseKey (hKey);
DeleteSidString(lpSidString);
SetLastError(lResult);
return FALSE;
}
//
// Clean up
//
RegCloseKey(hKey);
DeleteSidString(lpSidString);
//
// Expand and get the length of string
//
hr = SafeExpandEnvironmentStrings(szBuffer, szDirectory, ARRAYSIZE(szDirectory));
if (FAILED(hr))
{
SetLastError(HRESULT_CODE(hr));
return FALSE;
}
dwLength = lstrlen(szDirectory) + 1;
//
// Save the string if appropriate
//
if (lpProfileDir) {
if (*lpcchSize >= dwLength) {
StringCchCopy (lpProfileDir, *lpcchSize, szDirectory);
bRetVal = TRUE;
} else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
}
else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
*lpcchSize = dwLength;
return bRetVal;
}
//*************************************************************
//
// GetUserProfileDirFromSid()
//
// Purpose: Returns the root of the user's profile directory.
//
// Parameters: pSid - User's SID
// lpProfileDir - Output buffer
// lpcchSize - Size of output buffer
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments: If false is returned, lpcchSize holds the number of
// characters needed.
//
// History: Date Author Comment
// 03/08/01 santanuc Created
//
//*************************************************************
BOOL WINAPI GetUserProfileDirFromSid(PSID pSid, LPTSTR lpProfileDir,
LPDWORD lpcchSize)
{
DWORD dwLength = MAX_PATH * sizeof(TCHAR);
DWORD dwType;
BOOL bRetVal = FALSE;
UNICODE_STRING UnicodeString;
TCHAR szBuffer[MAX_PATH];
TCHAR szDirectory[MAX_PATH];
HKEY hKey;
LONG lResult;
NTSTATUS NtStatus;
HRESULT hr;
//
// Parameter check
//
if (!pSid) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!lpcchSize) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Retrieve the user's sid string
//
NtStatus = RtlConvertSidToUnicodeString(
&UnicodeString,
pSid,
(BOOLEAN)TRUE // Allocate memory
);
//
// See if the conversion to a string worked
//
if (!NT_SUCCESS(NtStatus)) {
SetLastError(RtlNtStatusToDosError(NtStatus));
DebugMsg((DM_WARNING, TEXT("GetUserProfileDirFromSid: RtlConvertSidToUnicodeString failed, status = 0x%x"),
NtStatus));
return FALSE;
}
//
// Check the registry
//
hr = GetProfileListKeyName(szBuffer, ARRAYSIZE(szBuffer), UnicodeString.Buffer);
if (FAILED(hr))
{
RtlFreeUnicodeString(&UnicodeString);
SetLastError(HRESULT_CODE(hr));
return FALSE;
}
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, KEY_READ,
&hKey);
if (lResult != ERROR_SUCCESS) {
RtlFreeUnicodeString(&UnicodeString);
SetLastError(lResult);
return FALSE;
}
lResult = RegQueryValueEx(hKey,
PROFILE_IMAGE_VALUE_NAME,
NULL,
&dwType,
(LPBYTE) szBuffer,
&dwLength);
if (lResult != ERROR_SUCCESS) {
RegCloseKey (hKey);
RtlFreeUnicodeString(&UnicodeString);
SetLastError(lResult);
return FALSE;
}
//
// Clean up
//
RegCloseKey(hKey);
RtlFreeUnicodeString(&UnicodeString);
//
// Expand and get the length of string
//
hr = SafeExpandEnvironmentStrings(szBuffer, szDirectory, ARRAYSIZE(szDirectory));
if (FAILED(hr))
{
SetLastError(HRESULT_CODE(hr));
return FALSE;
}
dwLength = lstrlen(szDirectory) + 1;
//
// Save the string if appropriate
//
if (lpProfileDir) {
if (*lpcchSize >= dwLength) {
StringCchCopy (lpProfileDir, *lpcchSize, szDirectory);
bRetVal = TRUE;
} else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
}
else {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
*lpcchSize = dwLength;
return bRetVal;
}
//*************************************************************
//
// GetUserAppDataPath()
//
// Purpose: Returns the path for user's Appdata.
//
// Parameters: hToken - User's token
// lpFolderPath - Output buffer
//
// Return: ERROR_SUCCESS if successful
// otherwise the error code
//
// Comments: If error occurs then lpFolderPath set to empty.
// Used by Crypto guys to avoid calling SHGetFolderPath.
//
// History: Date Author Comment
//
//*************************************************************
DWORD WINAPI
GetUserAppDataPath(
HANDLE hToken,
BOOL fLocalAppData,
LPTSTR lpFolderPath
)
{
DWORD dwSize, dwType;
LPTSTR lpSidString = NULL;
DWORD dwError = ERROR_SUCCESS;
HKEY hKey = NULL;
TCHAR szBuffer[MAX_PATH];
HRESULT hr;
//
// Parameter check
//
if (!hToken) {
dwError = ERROR_INVALID_HANDLE;
goto Exit;
}
if (!lpFolderPath) {
dwError = ERROR_INVALID_PARAMETER;
goto Exit;
}
else {
*lpFolderPath = TEXT('\0');
}
//
// Retrieve the user's sid string
//
lpSidString = GetSidString(hToken);
if (!lpSidString) {
dwError = ERROR_INVALID_HANDLE;
goto Exit;
}
//
// Check the registry
//
hr = GetKeyNameForUser(szBuffer, ARRAYSIZE(szBuffer), lpSidString, USER_SHELL_FOLDERS);
if (FAILED(hr))
{
dwError = HRESULT_CODE(hr);
goto Exit;
}
dwError = RegOpenKeyEx(HKEY_USERS, szBuffer, 0, KEY_READ, &hKey);
if (dwError != ERROR_SUCCESS) {
goto Exit;
}
dwSize = MAX_PATH * sizeof(TCHAR);
dwError = RegQueryValueEx(hKey,
fLocalAppData ? TEXT("Local AppData") : TEXT("AppData"),
NULL,
&dwType,
(LPBYTE) szBuffer,
&dwSize);
if (ERROR_SUCCESS == dwError) {
dwSize = MAX_PATH;
if (!ExpandEnvironmentStringsForUser(hToken, szBuffer, lpFolderPath, dwSize)) {
dwError = GetLastError();
}
}
Exit:
//
// Clean up
//
if (lpSidString) {
DeleteSidString(lpSidString);
}
if (hKey) {
RegCloseKey(hKey);
}
SetLastError(dwError);
return dwError;
}
//*************************************************************
//
// StringToInt()
//
// Purpose: Converts a string to an integer
//
// Parameters: lpNum - Number to convert
//
// Return: The number
//
// Comments:
//
// History: Date Author Comment
// 10/3/95 ericflo Created
//
//*************************************************************
int StringToInt(LPTSTR lpNum)
{
int i = 0;
BOOL bNeg = FALSE;
if (*lpNum == TEXT('-')) {
bNeg = TRUE;
lpNum++;
}
while (*lpNum >= TEXT('0') && *lpNum <= TEXT('9')) {
i *= 10;
i += (int)(*lpNum-TEXT('0'));
lpNum++;
}
if (bNeg) {
i *= -1;
}
return(i);
}
//*************************************************************
//
// HexStringToInt()
//
// Purpose: Converts a hex string to an integer, stops
// on first invalid character
//
// Parameters: lpNum - Number to convert
//
// Return: The number
//
// Comments: Originally for use in "ExtractCSIDL" tested
// exclusively with 0x0000 numbers format
//
// History: Date Author Comment
// 6/9/98 stephstm Created
//
//*************************************************************
unsigned int HexStringToUInt(LPCTSTR lpcNum)
{
unsigned int i = 0;
while (1)
{
if(*lpcNum != TEXT('x') && *lpcNum != TEXT('X') )
{
if(*lpcNum >= TEXT('0') && *lpcNum <= TEXT('9'))
{
i *= 16;
i += (unsigned int)(*lpcNum-TEXT('0'));
}
else
{
if(*lpcNum >= TEXT('a') && *lpcNum <= TEXT('f'))
{
i *= 16;
i += (unsigned int)(*lpcNum-TEXT('a')) + 10;
}
else
{
if(*lpcNum >= TEXT('A') && *lpcNum <= TEXT('F'))
{
i *= 16;
i += (unsigned int)(*lpcNum-TEXT('A')) + 10;
}
else
break;
}
}
}
lpcNum++;
}
return(i);
}
//*************************************************************
//
// RegRenameKey()
//
// Purpose: Renames a registry key
//
// Parameters: hKeyRoot - Root key
// lpSubKey1 - SubKey to rename from
// lpSubKey2 - SubKey to rename to
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 20/9/99 ushaji created
// 05/02/2002 mingzhu Make this function support subkeys (recursive)
//
//*************************************************************
LONG RegRenameKey(HKEY hKeyRoot, LPTSTR lpSrcKey, LPTSTR lpDestKey)
{
HKEY hSrcKey=NULL, hDestKey=NULL;
LONG lResult;
DWORD dwDisposition;
DWORD dwValues, dwMaxValueNameLen, dwMaxValueLen, dwType;
DWORD dwMaxValueNameLenLocal, dwMaxValueLenLocal, i, dwSDSize;
DWORD dwSrcSubkeyLen, dwDestSubkeyLen, dwSubkeyLen;
DWORD dwSubkeys, dwMaxSubkeyNameLen, dwMaxSubkeyNameLenLocal;
LPTSTR lpSrcSubkey = NULL;
LPTSTR lpDestSubkey = NULL;
LPTSTR lpSubkey = NULL;
LPTSTR lpValueName=NULL;
LPBYTE lpData=NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
HRESULT hr;
//
// Verbose Debug Message
//
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: renaming %s to %s"), lpSrcKey, lpDestKey));
if (!lpSrcKey || !lpDestKey)
return ERROR_INVALID_PARAMETER;
lResult = RegOpenKeyEx(hKeyRoot, lpSrcKey, 0, KEY_ALL_ACCESS, &hSrcKey);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot open src key %s with error %d"), lpSrcKey, lResult));
goto Exit;
}
if (RegDelnode(hKeyRoot, lpDestKey) != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot delete dest key %s."), lpDestKey));
goto Exit;
}
lResult = RegQueryInfoKey(hSrcKey, NULL, NULL, NULL, &dwSubkeys, &dwMaxSubkeyNameLen, NULL,
&dwValues, &dwMaxValueNameLen, &dwMaxValueLen,
&dwSDSize, NULL);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot query src key %s with error %d"), lpSrcKey, lResult));
goto Exit;
}
pSD = LocalAlloc(LPTR, sizeof(BYTE)*dwSDSize);
if (!pSD) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot allocate memory error")));
lResult = GetLastError();
goto Exit;
}
lResult = RegGetKeySecurity(hSrcKey, DACL_SECURITY_INFORMATION, pSD, &dwSDSize);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot get sd with error %d"), lResult));
goto Exit;
}
lResult = RegCreateKeyEx(hKeyRoot, lpDestKey, 0, L"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hDestKey,
&dwDisposition);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot open dest key %s with error %d"), lpDestKey, lResult));
goto Exit;
}
lResult = RegSetKeySecurity(hDestKey, DACL_SECURITY_INFORMATION, pSD);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot get sd with error %d"), lResult));
goto Exit;
}
lpValueName = (LPTSTR) LocalAlloc(LPTR, sizeof(TCHAR)*(dwMaxValueNameLen+1));
if (!lpValueName) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot allocate memory for valuename")));
lResult = GetLastError();
goto Exit;
}
lpData = (LPBYTE) LocalAlloc(LPTR, sizeof(BYTE)*dwMaxValueLen);
if (!lpData) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot allocate memory for lpData")));
lResult = GetLastError();
goto Exit;
}
for (i = 0; i < dwValues; i++) {
dwMaxValueNameLenLocal = dwMaxValueNameLen+1;
dwMaxValueLenLocal = dwMaxValueLen;
lResult = RegEnumValue(hSrcKey, i, lpValueName, &dwMaxValueNameLenLocal, NULL, &dwType, lpData, &dwMaxValueLenLocal);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot enum src key value with error %d"), lResult));
goto Exit;
}
lResult = RegSetValueEx(hDestKey, lpValueName, 0, dwType, lpData, dwMaxValueLenLocal);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot set dest value %s with error %d"), lpValueName, lResult));
goto Exit;
}
}
//
// Allocate buffer for local, src and dest subkeys
//
lpSubkey = (LPTSTR) LocalAlloc(LPTR, sizeof(TCHAR)*(dwMaxSubkeyNameLen + 1));
if (!lpSubkey) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot allocate memory for subkey")));
lResult = GetLastError();
goto Exit;
}
dwSrcSubkeyLen = lstrlen(lpSrcKey) + dwMaxSubkeyNameLen + 2;
lpSrcSubkey = (LPTSTR) LocalAlloc(LPTR, sizeof(TCHAR)*(dwSrcSubkeyLen));
if (!lpSrcSubkey) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot allocate memory for src subkey")));
lResult = GetLastError();
goto Exit;
}
dwDestSubkeyLen = lstrlen(lpDestKey) + dwMaxSubkeyNameLen + 2;
lpDestSubkey = (LPTSTR) LocalAlloc(LPTR, sizeof(TCHAR)*(dwDestSubkeyLen));
if (!lpDestSubkey) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot allocate memory for dest subkey")));
lResult = GetLastError();
goto Exit;
}
//
// Enumerate subkeys and call this function recursively
//
for (i = 0; i < dwSubkeys; i++) {
// Enumerate local subkey
dwMaxSubkeyNameLenLocal = dwMaxSubkeyNameLen + 1;
lResult = RegEnumKeyEx(hSrcKey, i, lpSubkey, &dwMaxSubkeyNameLenLocal, NULL, NULL, NULL, NULL);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: Couldnot enum sub key value with error %d"), lResult));
goto Exit;
}
// Construct the src and dest subkey
hr = StringCchPrintf(lpSrcSubkey, dwSrcSubkeyLen, TEXT("%s\\%s"), lpSrcKey, lpSubkey);
if (FAILED(hr)) {
lResult = HRESULT_CODE(hr);
goto Exit;
}
hr = StringCchPrintf(lpDestSubkey, dwDestSubkeyLen, TEXT("%s\\%s"), lpDestKey, lpSubkey);
if (FAILED(hr)) {
lResult = HRESULT_CODE(hr);
goto Exit;
}
// Call this function recursively
lResult = RegRenameKey(hKeyRoot, lpSrcSubkey, lpDestSubkey);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_VERBOSE, TEXT("RegRenameKey: failed to rename %s to %s, error = %d"), lpSrcSubkey, lpDestSubkey, lResult));
goto Exit;
}
}
Exit:
if (lpSubkey)
LocalFree(lpSubkey);
if (lpSrcSubkey)
LocalFree(lpSrcSubkey);
if (lpDestSubkey)
LocalFree(lpDestSubkey);
if (hSrcKey)
RegCloseKey(hSrcKey);
if (hDestKey)
RegCloseKey(hDestKey);
if (lpData)
LocalFree(lpData);
if (lpValueName)
LocalFree(lpValueName);
if (pSD)
LocalFree(pSD);
if (lResult == ERROR_SUCCESS)
lResult = RegDelnode(hKeyRoot, lpSrcKey);
else
RegDelnode(hKeyRoot, lpDestKey);
return lResult;
}
//*************************************************************
//
// CreateSecureAdminDirectory()
//
// Purpose: Creates a secure directory that only the Administrator
// and system have access to.
//
// Parameters: lpDirectory - Directory Name
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 7/20/95 ericflo Created
//
//*************************************************************
BOOL CreateSecureAdminDirectory (LPTSTR lpDirectory, DWORD dwOtherSids)
{
//
// Attempt to create the directory
//
if (!CreateNestedDirectory(lpDirectory, NULL)) {
return FALSE;
}
//
// Set the security
//
if (!MakeFileSecure (lpDirectory, dwOtherSids)) {
RemoveDirectory(lpDirectory);
return FALSE;
}
return TRUE;
}
//*************************************************************
//
// DeleteAllValues ()
//
// Purpose: Deletes all values under specified key
//
// Parameters: hKey - Key to delete values from
//
// Return:
//
// Comments:
//
// History: Date Author Comment
// 9/14/95 ericflo Ported
//
//*************************************************************
BOOL DeleteAllValues(HKEY hKey)
{
TCHAR ValueName[MAX_PATH+1];
DWORD dwSize = MAX_PATH+1;
LONG lResult;
while (RegEnumValue(hKey, 0, ValueName, &dwSize,
NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
lResult = RegDeleteValue(hKey, ValueName);
if (lResult != ERROR_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("DeleteAllValues: Failed to delete value <%s> with %d."), ValueName, lResult));
return FALSE;
} else {
DebugMsg((DM_VERBOSE, TEXT("DeleteAllValues: Deleted <%s>"), ValueName));
}
dwSize = MAX_PATH+1;
}
return TRUE;
}
//*************************************************************
//
// MakeFileSecure()
//
// Purpose: Sets the attributes on the file so only Administrators
// and the OS can delete it. Authenticated Users have read
// permission only.
//
// Parameters: lpFile - File to set security on
//
// Return: (BOOL) TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 11/6/95 ericflo Created
// 2/16/99 ushaji Added everyone, pweruser
//
//*************************************************************
BOOL MakeFileSecure (LPTSTR lpFile, DWORD dwOtherSids)
{
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY authWORLD = SECURITY_WORLD_SID_AUTHORITY;
PACL pAcl = NULL;
PSID psidSystem = NULL, psidAdmin = NULL, psidUsers = NULL, psidPowerUsers = NULL;
PSID psidEveryOne = NULL;
DWORD cbAcl, aceIndex;
ACE_HEADER * lpAceHeader;
BOOL bRetVal = FALSE;
BOOL bAddPowerUsersAce=TRUE;
BOOL bAddEveryOneAce=FALSE;
DWORD dwAccMask;
//
// Get the system sid
//
if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to initialize system sid. Error = %d"), GetLastError()));
goto Exit;
}
//
// Get the Admin sid
//
if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0,
0, 0, 0, 0, &psidAdmin)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to initialize admin sid. Error = %d"), GetLastError()));
goto Exit;
}
//
// Get the users sid
//
if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_USERS,
0, 0, 0, 0, 0, 0, &psidUsers)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to initialize authenticated users sid. Error = %d"), GetLastError()));
goto Exit;
}
//
// Allocate space for the ACL
//
cbAcl = (2 * GetLengthSid (psidSystem)) +
(2 * GetLengthSid (psidAdmin)) +
(2 * GetLengthSid (psidUsers)) +
sizeof(ACL) +
(6 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
//
// Get the power users sid, if required.
// Don't fail if you don't get because it might not be available on DCs??
//
bAddPowerUsersAce = TRUE;
if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &psidPowerUsers)) {
DebugMsg((DM_WARNING, TEXT("AddPowerUserAce: Failed to initialize power users sid. Error = %d"), GetLastError()));
bAddPowerUsersAce = FALSE;
}
if (bAddPowerUsersAce)
cbAcl += (2 * GetLengthSid (psidPowerUsers)) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
//
// Get the EveryOne sid, if required.
//
if (dwOtherSids & OTHERSIDS_EVERYONE) {
bAddEveryOneAce = TRUE;
if (!AllocateAndInitializeSid(&authWORLD, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &psidEveryOne)) {
DebugMsg((DM_WARNING, TEXT("AddPowerUserAce: Failed to initialize everyone sid. Error = %d"), GetLastError()));
goto Exit;
}
}
if (bAddEveryOneAce)
cbAcl += (2 * GetLengthSid (psidEveryOne)) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl);
if (!pAcl) {
goto Exit;
}
if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to initialize acl. Error = %d"), GetLastError()));
goto Exit;
}
//
// Add Aces. Non-inheritable ACEs first
//
aceIndex = 0;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSystem)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidAdmin)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ | GENERIC_EXECUTE, psidUsers)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
if (bAddPowerUsersAce) {
//
// By default give read permissions, otherwise give modify permissions
//
dwAccMask = (dwOtherSids & OTHERSIDS_POWERUSERS) ? (FILE_ALL_ACCESS ^ (WRITE_DAC | WRITE_OWNER)):
(GENERIC_READ | GENERIC_EXECUTE);
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, dwAccMask, psidPowerUsers)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
}
if (bAddEveryOneAce) {
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ | GENERIC_EXECUTE, psidEveryOne)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
}
//
// Now the inheritable ACEs
//
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ | GENERIC_EXECUTE, psidUsers)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
if (bAddPowerUsersAce) {
aceIndex++;
dwAccMask = (dwOtherSids & OTHERSIDS_POWERUSERS) ? (FILE_ALL_ACCESS ^ (WRITE_DAC | WRITE_OWNER)):
(GENERIC_READ | GENERIC_EXECUTE);
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, dwAccMask, psidPowerUsers)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
}
if (bAddEveryOneAce) {
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ | GENERIC_EXECUTE, psidEveryOne)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError()));
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
}
//
// Put together the security descriptor
//
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to initialize security descriptor. Error = %d"), GetLastError()));
goto Exit;
}
if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to set security descriptor dacl. Error = %d"), GetLastError()));
goto Exit;
}
//
// Set the security
//
if (SetFileSecurity (lpFile, DACL_SECURITY_INFORMATION, &sd)) {
bRetVal = TRUE;
} else {
DebugMsg((DM_WARNING, TEXT("MakeFileSecure: SetFileSecurity failed. Error = %d"), GetLastError()));
}
Exit:
if (psidSystem) {
FreeSid(psidSystem);
}
if (psidAdmin) {
FreeSid(psidAdmin);
}
if (psidUsers) {
FreeSid(psidUsers);
}
if ((bAddPowerUsersAce) && (psidPowerUsers)) {
FreeSid(psidPowerUsers);
}
if ((bAddEveryOneAce) && (psidEveryOne)) {
FreeSid(psidEveryOne);
}
if (pAcl) {
GlobalFree (pAcl);
}
return bRetVal;
}
//*************************************************************
//
// GetSpecialFolderPath()
//
// Purpose: Gets the path to the requested special folder
//
// Parameters: csid - CSIDL of the special folder
// lpPath - Path to place result in
// assumed to be MAX_PATH in size
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL GetSpecialFolderPath (INT csidl, LPTSTR lpPath)
{
BOOL bResult = FALSE;
PSHELL32_API pShell32Api = NULL;
HRESULT hr = E_FAIL;
if (SUCCEEDED(hr = HRESULT_FROM_WIN32(LoadShell32Api( &pShell32Api ))))
{
//
// Ask the shell for the folder location
//
bResult = pShell32Api->pfnShGetSpecialFolderPath (NULL, lpPath, csidl, TRUE);
if (!bResult)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
if (!bResult)
{
DebugMsg((DM_WARNING, TEXT("GetSpecialFolderPath : ShGetSpecialFolderPath failed, hr = %08X\n"), hr));
}
return bResult;
}
//*************************************************************
//
// GetFolderPath()
//
// Purpose: Gets the path to the requested special folder
//
// Parameters: csidl - CSIDL of the special folder
// lpPath - Path to place result in
// assumed to be MAX_PATH in size
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL GetFolderPath (INT csidl, HANDLE hToken, LPTSTR lpPath)
{
BOOL bResult = FALSE;
PSHELL32_API pShell32Api = NULL;
HRESULT hr = E_FAIL;
if (SUCCEEDED(hr = HRESULT_FROM_WIN32(LoadShell32Api( &pShell32Api ))))
{
//
// Ask the shell for the folder location
//
hr = pShell32Api->pfnShGetFolderPath (NULL,
csidl | CSIDL_FLAG_CREATE,
hToken,
0,
lpPath);
bResult = SUCCEEDED ( hr );
}
if (!bResult)
{
DebugMsg((DM_WARNING, TEXT("GetFolderPath : ShGetFolderPath failed, hr = %08X\n"), hr));
}
return bResult;
}
//*************************************************************
//
// SetFolderPath()
//
// Purpose: Sets the path to the requested special folder
//
// Parameters: csidl - CSIDL of the special folder
// lpPath - Path
// assumed to be MAX_PATH in size
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL SetFolderPath (INT csidl, HANDLE hToken, LPTSTR lpPath)
{
BOOL bResult = FALSE;
PSHELL32_API pShell32Api = NULL;
HRESULT hr = E_FAIL;
if (SUCCEEDED(hr = HRESULT_FROM_WIN32(LoadShell32Api( &pShell32Api ))))
{
//
// Set the shell folder location
//
hr = pShell32Api->pfnShSetFolderPath (
csidl | CSIDL_FLAG_DONT_UNEXPAND,
hToken,
0,
lpPath);
bResult = SUCCEEDED ( hr );
}
if (!bResult)
{
DebugMsg((DM_WARNING, TEXT("SetFolderPath : ShSetFolderPath failed, hr = %08X\n"), hr));
}
return bResult;
}
//*************************************************************
//
// CenterWindow()
//
// Purpose: Centers a window on the screen
//
// Parameters: hwnd - window handle to center
//
// Return: void
//
// Comments:
//
// History: Date Author Comment
// 2/21/96 ericflo Ported
//
//*************************************************************
void CenterWindow (HWND hwnd)
{
RECT rect;
LONG dx, dy;
LONG dxParent, dyParent;
LONG Style;
// Get window rect
GetWindowRect(hwnd, &rect);
dx = rect.right - rect.left;
dy = rect.bottom - rect.top;
// Get parent rect
Style = GetWindowLong(hwnd, GWL_STYLE);
if ((Style & WS_CHILD) == 0) {
// Return the desktop windows size (size of main screen)
dxParent = GetSystemMetrics(SM_CXSCREEN);
dyParent = GetSystemMetrics(SM_CYSCREEN);
} else {
HWND hwndParent;
RECT rectParent;
hwndParent = GetParent(hwnd);
if (hwndParent == NULL) {
hwndParent = GetDesktopWindow();
}
GetWindowRect(hwndParent, &rectParent);
dxParent = rectParent.right - rectParent.left;
dyParent = rectParent.bottom - rectParent.top;
}
// Centre the child in the parent
rect.left = (dxParent - dx) / 2;
rect.top = (dyParent - dy) / 3;
// Move the child into position
SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, 0, 0, SWP_NOSIZE);
}
//*************************************************************
//
// UnExpandSysRoot()
//
// Purpose: Unexpands the given path/filename to have %systemroot%
// if appropriate
//
// Parameters: lpFile - File to check
// lpResult - Result buffer
// cchResult - Result buffer size
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 2/23/96 ericflo Created
//
//*************************************************************
BOOL UnExpandSysRoot(LPCTSTR lpFile, LPTSTR lpResult, DWORD cchResult)
{
TCHAR szSysRoot[MAX_PATH];
LPTSTR lpFileName;
DWORD dwSysLen;
HRESULT hr;
//
// Verbose Output
//
DebugMsg((DM_VERBOSE, TEXT("UnExpandSysRoot: Entering with <%s>"),
lpFile ? lpFile : TEXT("NULL")));
if (!lpFile || !*lpFile) {
DebugMsg((DM_VERBOSE, TEXT("UnExpandSysRoot: lpFile is NULL, setting lpResult to a null string")));
*lpResult = TEXT('\0');
return TRUE;
}
//
// If the first part of lpFile is the expanded value of %SystemRoot%
// then we want to un-expand the environment variable.
//
hr = SafeExpandEnvironmentStrings (TEXT("%SystemRoot%"), szSysRoot, ARRAYSIZE(szSysRoot));
if (FAILED(hr)) {
DebugMsg((DM_VERBOSE, TEXT("UnExpandSysRoot: ExpandEnvironmentString failed with error %d, setting szSysRoot to %systemroot% "), GetLastError()));
StringCchCopy(lpResult, cchResult, lpFile);
return FALSE;
}
dwSysLen = lstrlen(szSysRoot);
//
// Make sure the source is long enough
//
if ((DWORD)lstrlen(lpFile) < dwSysLen) {
StringCchCopy (lpResult, cchResult, lpFile);
return TRUE;
}
if (CompareString (LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
szSysRoot, dwSysLen,
lpFile, dwSysLen) == CSTR_EQUAL) {
//
// The szReturn buffer starts with %systemroot%.
// Actually insert %systemroot% in the result buffer.
//
StringCchCopy (lpResult, cchResult, TEXT("%SystemRoot%"));
StringCchCat (lpResult, cchResult, (lpFile + dwSysLen));
} else {
//
// The szReturn buffer does not start with %systemroot%
// just copy in the original string.
//
StringCchCopy (lpResult, cchResult, lpFile);
}
DebugMsg((DM_VERBOSE, TEXT("UnExpandSysRoot: Leaving with <%s>"), lpResult));
return TRUE;
}
//*************************************************************
//
// AllocAndExpandEnvironmentStrings()
//
// Purpose: Allocates memory for and returns pointer to buffer containing
// the passed string expanded.
//
// Parameters: lpszSrc - unexpanded string
//
// Return: Pointer to expanded string
// NULL if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 6/21/96 ericflo Ported
//
//*************************************************************
LPTSTR AllocAndExpandEnvironmentStrings(LPCTSTR lpszSrc)
{
LPTSTR String, Temp;
LONG LengthAllocated;
LONG LengthCopied;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
LengthAllocated = lstrlen(lpszSrc) + 60;
String = LocalAlloc(LPTR, LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugMsg((DM_WARNING, TEXT("AllocAndExpandEnvironmentStrings: Failed to allocate %d bytes for string"), LengthAllocated * sizeof(TCHAR)));
return(NULL);
}
while (TRUE) {
LengthCopied = ExpandEnvironmentStrings( lpszSrc,
String,
LengthAllocated
);
if (LengthCopied == 0) {
DebugMsg((DM_WARNING, TEXT("AllocAndExpandEnvironmentStrings: ExpandEnvironmentStrings failed, error = %d"), GetLastError()));
LocalFree(String);
String = NULL;
break;
}
//
// If the buffer was too small, make it bigger and try again
//
if (LengthCopied > LengthAllocated) {
Temp = LocalReAlloc(String, LengthCopied * sizeof(TCHAR), LMEM_MOVEABLE);
if (Temp == NULL) {
DebugMsg((DM_WARNING, TEXT("AllocAndExpandEnvironmentStrings: Failed to reallocate %d bytes for string"), LengthAllocated * sizeof(TCHAR)));
LocalFree(String);
String = NULL;
break;
}
LengthAllocated = LengthCopied;
String = Temp;
//
// Go back and try to expand the string again
//
} else {
//
// Success!
//
break;
}
}
return(String);
}
//*************************************************************
//
// IntToString
//
// Purpose: TCHAR version of itoa
//
// Parameters: INT i - integer to convert
// LPTSTR sz - pointer where to put the result
//
// Return: void
//
//*************************************************************
void IntToString( INT i, LPTSTR sz) {
TCHAR szTemp[CCH_MAX_DEC];
int iChr;
iChr = 0;
do {
szTemp[iChr++] = TEXT('0') + (i % 10);
i = i / 10;
} while (i != 0);
do {
iChr--;
*sz++ = szTemp[iChr];
} while (iChr != 0);
*sz++ = TEXT('\0');
}
//*************************************************************
//
// IsUserAGuest()
//
// Purpose: Determines if the user is a member of the guest group.
//
// Parameters: hToken - User's token
//
// Return: TRUE if user is a guest
// FALSE if not
// Comments:
//
// History: Date Author Comment
// 7/25/95 ericflo Created
//
//*************************************************************
BOOL IsUserAGuest(HANDLE hToken)
{
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
NTSTATUS Status;
BOOL FoundGuests=FALSE;
PSID pGuestSid=NULL, pDomainGuestSid=NULL, psidUser=NULL;
HANDLE hImpToken = NULL;
//
// Create Guests sid.
//
Status = RtlAllocateAndInitializeSid(
&authNT,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_GUESTS,
0, 0, 0, 0, 0, 0,
&pGuestSid
);
if (Status != STATUS_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("IsUserAGuest: RtlAllocateAndInitializeSid failed with error 0x%x"), Status));
goto Exit;
}
if (!DuplicateTokenEx(hToken, TOKEN_IMPERSONATE | TOKEN_QUERY,
NULL, SecurityImpersonation, TokenImpersonation,
&hImpToken)) {
DebugMsg((DM_WARNING, TEXT("IsUserAGuest: DuplicateTokenEx failed with error %d"), GetLastError()));
hImpToken = NULL;
goto Exit;
}
if (!CheckTokenMembership(hImpToken, pGuestSid, &FoundGuests)) {
DebugMsg((DM_WARNING, TEXT("IsUserAGuest: CheckTokenMembership failed for GuestSid with error %d"), GetLastError()));
}
if (!FoundGuests) {
//
// Get the user's sid
//
psidUser = GetUserSid(hToken);
if (!psidUser) {
DebugMsg((DM_WARNING, TEXT("MakeRegKeySecure: Failed to get user sid")));
goto Exit;
}
//
// Create Domain Guests sid.
//
Status = GetDomainSidFromDomainRid(
psidUser,
DOMAIN_GROUP_RID_GUESTS,
&pDomainGuestSid);
if (Status != STATUS_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("IsUserAGuest: GetDomainSidFromDomainRid failed with error 0x%x"), Status));
goto Exit;
}
if (!CheckTokenMembership(hImpToken, pDomainGuestSid, &FoundGuests)) {
DebugMsg((DM_WARNING, TEXT("IsUserAGuest: CheckTokenMembership failed for DomainGuestSid with error %d"), GetLastError()));
}
}
//
// Tidy up
//
Exit:
if (pGuestSid)
RtlFreeSid(pGuestSid);
if (pDomainGuestSid)
RtlFreeSid(pDomainGuestSid);
if (psidUser)
DeleteUserSid (psidUser);
if (hImpToken)
CloseHandle(hImpToken);
return(FoundGuests);
}
//*************************************************************
//
// IsUserAnAdminMember()
//
// Purpose: Determines if the user is a member of the administrators group.
//
// Parameters: hToken - User's token
//
// Return: TRUE if user is a admin
// FALSE if not
// Comments:
//
// History: Date Author Comment
// 7/25/95 ericflo Created
//
//*************************************************************
BOOL IsUserAnAdminMember(HANDLE hToken)
{
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
NTSTATUS Status;
BOOL FoundAdmins = FALSE;
PSID AdminsDomainSid=NULL;
HANDLE hImpToken = NULL;
//
// Create Admins domain sid.
//
Status = RtlAllocateAndInitializeSid(
&authNT,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdminsDomainSid
);
if (Status == STATUS_SUCCESS) {
//
// Test if user is in the Admins domain
//
if (!DuplicateTokenEx(hToken, TOKEN_IMPERSONATE | TOKEN_QUERY,
NULL, SecurityImpersonation, TokenImpersonation,
&hImpToken)) {
DebugMsg((DM_WARNING, TEXT("IsUserAnAdminMember: DuplicateTokenEx failed with error %d"), GetLastError()));
FoundAdmins = FALSE;
hImpToken = NULL;
goto Exit;
}
if (!CheckTokenMembership(hImpToken, AdminsDomainSid, &FoundAdmins)) {
DebugMsg((DM_WARNING, TEXT("IsUserAnAdminmember: CheckTokenMembership failed for AdminsDomainSid with error %d"), GetLastError()));
FoundAdmins = FALSE;
}
}
//
// Tidy up
//
Exit:
if (hImpToken)
CloseHandle(hImpToken);
if (AdminsDomainSid)
RtlFreeSid(AdminsDomainSid);
return(FoundAdmins);
}
//*************************************************************
//
// IsUserALocalSystemMember()
//
// Purpose: Determines if the user is a member of the Local system group.
//
// Parameters: hToken - User's token
//
// Return: TRUE if user is a local system
// FALSE if not
// Comments:
//
// History: Date Author Comment
// 9/22/00 santanuc created
//
//*************************************************************
BOOL IsUserALocalSystemMember(HANDLE hToken)
{
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
NTSTATUS Status;
BOOL FoundLocalSystem = FALSE;
PSID LocalSystemSid=NULL;
HANDLE hImpToken = NULL;
//
// Create Local system sid.
//
Status = RtlAllocateAndInitializeSid(
&authNT,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&LocalSystemSid
);
if (Status == STATUS_SUCCESS) {
//
// Test if user is in the Local system
//
if (!DuplicateTokenEx(hToken, TOKEN_IMPERSONATE | TOKEN_QUERY,
NULL, SecurityImpersonation, TokenImpersonation,
&hImpToken)) {
DebugMsg((DM_WARNING, TEXT("IsUserAGuest: DuplicateTokenEx failed with error %d"), GetLastError()));
FoundLocalSystem = FALSE;
hImpToken = NULL;
goto Exit;
}
if (!CheckTokenMembership(hImpToken, LocalSystemSid, &FoundLocalSystem)) {
DebugMsg((DM_WARNING, TEXT("IsUserAnAdminmember: CheckTokenMembership failed for LocalSystemSid with error %d"), GetLastError()));
FoundLocalSystem = FALSE;
}
}
//
// Tidy up
//
Exit:
if (hImpToken)
CloseHandle(hImpToken);
if (LocalSystemSid)
RtlFreeSid(LocalSystemSid);
return(FoundLocalSystem);
}
//*************************************************************
//
// IsUserAnInteractiveUser()
//
// Purpose: Determines if the user is interactively logged on.
//
// Parameters: hToken - User's token
//
// Return: TRUE if user is logged on interactively
// FALSE if not
// Comments:
//
//*************************************************************
BOOL IsUserAnInteractiveUser(HANDLE hToken)
{
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
BOOL bInteractive = FALSE;
PSID pInteractiveSid=NULL;
HANDLE hImpToken = NULL;
//
// Create Admins domain sid.
//
if (AllocateAndInitializeSid(&authNT, 1, SECURITY_INTERACTIVE_RID,
0, 0, 0, 0, 0, 0, 0, &pInteractiveSid)) {
//
// Test if user is interactive
//
if (!DuplicateTokenEx(hToken, TOKEN_IMPERSONATE | TOKEN_QUERY,
NULL, SecurityImpersonation, TokenImpersonation,
&hImpToken)) {
DebugMsg((DM_WARNING, TEXT("IsUserAnInteractiveUser: DuplicateTokenEx failed with error %d"), GetLastError()));
bInteractive = FALSE;
hImpToken = NULL;
goto Exit;
}
if (!CheckTokenMembership(hImpToken, pInteractiveSid, &bInteractive)) {
DebugMsg((DM_WARNING, TEXT("IsUserAnInteractiveUser: CheckTokenMembership failed for InteractiveSid with error %d"), GetLastError()));
bInteractive = FALSE;
}
}
else {
DebugMsg((DM_WARNING, TEXT("IsUserAnInteractiveUser: AllocateAndInitializeSid failed for InteractiveSid with error %d"), GetLastError()));
}
//
// Tidy up
//
Exit:
if (hImpToken)
CloseHandle(hImpToken);
if (pInteractiveSid)
FreeSid(pInteractiveSid);
return(bInteractive);
}
//*************************************************************
//
// CheckUserInMachineForest()
//
// Purpose: Determines if the user is from the same forest
// as the computer this code is running on.
//
// Parameters: hToken - User's token
//
// Return: ERROR_SUCCESS if successful
// <error> code if not.
// Comments:
//
//*************************************************************
DWORD CheckUserInMachineForest(HANDLE hToken, BOOL* pbInMachineForest)
{
DWORD dwResult = ERROR_SUCCESS;
HANDLE hOldToken = NULL;
LPWSTR szUserDomainName = NULL;
PDS_DOMAIN_TRUSTS pDomainTrusts = NULL;
ULONG ulDomainCount = 0;
ULONG ulCount = 0;
if ( (hToken == NULL) || (pbInMachineForest == NULL) )
{
return ERROR_INVALID_PARAMETER;
}
// Default to this
*pbInMachineForest = FALSE;
// Query for the user's domain name
if (!ImpersonateUser(hToken, &hOldToken))
{
dwResult = GetLastError();
DebugMsg((DM_WARNING, TEXT("CheckUserInMachineForest: Failed to impersonate user with %d."), dwResult));
goto Exit;
}
szUserDomainName = MyGetDomainDNSName ();
RevertToUser(&hOldToken);
if ( szUserDomainName == NULL )
{
dwResult = GetLastError();
DebugMsg((DM_WARNING, TEXT("CheckUserInMachineForest: MyGetDomainName failed with %d."), dwResult));
goto Exit;
}
// Now get the list of trusted domains for this machine
dwResult = DsEnumerateDomainTrusts( NULL, DS_DOMAIN_IN_FOREST, &pDomainTrusts, &ulDomainCount );
if ( dwResult != NO_ERROR )
{
pDomainTrusts = NULL;
DebugMsg((DM_WARNING, TEXT("CheckUserInMachineForest: Failed to enumerate forest domains with %d."), dwResult));
goto Exit;
}
dwResult = ERROR_SUCCESS;
for ( ulCount = 0; ulCount < ulDomainCount; ulCount++ )
{
if ( DnsNameCompare_W(szUserDomainName, pDomainTrusts[ulCount].DnsDomainName) )
{
*pbInMachineForest = TRUE;
goto Exit;
}
}
Exit:
if ( szUserDomainName != NULL )
{
LocalFree( szUserDomainName );
}
if ( pDomainTrusts != NULL )
{
NetApiBufferFree( pDomainTrusts );
}
return dwResult;
}
//*************************************************************
//
// MakeRegKeySecure()
//
// Purpose: Sets the security for the key give so that
// the admin and os having full control with the
// user having read / execute.
//
// Parameters: hToken - User's token or null for "everyone"
// hKeyRoot - Key to the root of the hive
// lpKeyName - Key to secure
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 5/7/97 ericflo Created
//
//*************************************************************
BOOL MakeRegKeySecure(HANDLE hToken, HKEY hKeyRoot, LPTSTR lpKeyName)
{
DWORD Error, dwDisp;
HKEY hSubKey;
SECURITY_DESCRIPTOR sd;
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
PACL pAcl = NULL;
PSID psidUser = NULL, psidSystem = NULL, psidAdmin = NULL;
DWORD cbAcl, AceIndex;
ACE_HEADER * lpAceHeader;
BOOL bRetVal = FALSE;
//
// Create the security descriptor that will be applied to the key
//
if (hToken) {
//
// Get the user's sid
//
psidUser = GetUserSid(hToken);
if (!psidUser) {
DebugMsg((DM_WARNING, TEXT("MakeRegKeySecure: Failed to get user sid")));
return FALSE;
}
} else {
//
// Get the authenticated users sid
//
if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_AUTHENTICATED_USER_RID,
0, 0, 0, 0, 0, 0, 0, &psidUser)) {
DebugMsg((DM_WARNING, TEXT("MakeRegKeySecure: Failed to initialize authenticated users sid. Error = %d"), GetLastError()));
return FALSE;
}
}
//
// Get the system sid
//
if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to initialize system sid. Error = %d"), GetLastError()));
goto Exit;
}
//
// Get the admin sid
//
if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0,
0, 0, 0, 0, &psidAdmin)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to initialize admin sid. Error = %d"), GetLastError()));
goto Exit;
}
//
// Allocate space for the ACL
//
cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) +
(2 * GetLengthSid (psidAdmin)) + sizeof(ACL) +
(6 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl);
if (!pAcl) {
goto Exit;
}
if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to initialize acl. Error = %d"), GetLastError()));
goto Exit;
}
//
// Add Aces for User, System, and Admin. Non-inheritable ACEs first
//
AceIndex = 0;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_READ, psidUser)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to add ace for user. Error = %d"), GetLastError()));
goto Exit;
}
AceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidSystem)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to add ace for system. Error = %d"), GetLastError()));
goto Exit;
}
AceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidAdmin)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to add ace for admin. Error = %d"), GetLastError()));
goto Exit;
}
//
// Now the inheritable ACEs
//
AceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ, psidUser)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to add ace for user. Error = %d"), GetLastError()));
goto Exit;
}
if (!GetAce(pAcl, AceIndex, &lpAceHeader)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError()));
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
AceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to add ace for system. Error = %d"), GetLastError()));
goto Exit;
}
if (!GetAce(pAcl, AceIndex, &lpAceHeader)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError()));
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
AceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to add ace for admin. Error = %d"), GetLastError()));
goto Exit;
}
if (!GetAce(pAcl, AceIndex, &lpAceHeader)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError()));
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
//
// Put together the security descriptor
//
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to initialize security descriptor. Error = %d"), GetLastError()));
goto Exit;
}
if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) {
DebugMsg((DM_VERBOSE, TEXT("MakeRegKeySecure: Failed to set security descriptor dacl. Error = %d"), GetLastError()));
goto Exit;
}
//
// Open the registry key
//
Error = RegCreateKeyEx(hKeyRoot,
lpKeyName,
0,
NULL,
REG_OPTION_NON_VOLATILE,
WRITE_DAC,
NULL,
&hSubKey,
&dwDisp);
if (Error == ERROR_SUCCESS) {
Error = RegSetKeySecurity (hSubKey, DACL_SECURITY_INFORMATION, &sd);
if (Error == ERROR_SUCCESS) {
bRetVal = TRUE;
} else {
DebugMsg((DM_WARNING, TEXT("MakeRegKeySecure: Failed to set security, error = %d"), Error));
}
RegCloseKey(hSubKey);
} else {
DebugMsg((DM_WARNING, TEXT("MakeRegKeySecure: Failed to open registry key, error = %d"), Error));
}
Exit:
//
// Free the sids and acl
//
if (psidUser) {
if (hToken) {
DeleteUserSid (psidUser);
} else {
FreeSid (psidUser);
}
}
if (psidSystem) {
FreeSid(psidSystem);
}
if (psidAdmin) {
FreeSid(psidAdmin);
}
if (pAcl) {
GlobalFree (pAcl);
}
return(bRetVal);
}
//*************************************************************
//
// FlushSpecialFolderCache()
//
// Purpose: Flushes the special folder cache in the shell
//
// Parameters: none
//
// Comments: Shell32.dll caches the special folder pidls
// but since winlogon never goes away, it is possible
// for one user's pidls to be used for another user
//
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
typedef VOID (*PFNSHFLUSHSFCACHE)(VOID);
BOOL FlushSpecialFolderCache (void)
{
HINSTANCE hInstDLL;
PFNSHFLUSHSFCACHE pfnSHFlushSFCache;
BOOL bResult = FALSE;
hInstDLL = LoadLibraryA ("shell32.dll");
if (hInstDLL) {
pfnSHFlushSFCache = (PFNSHFLUSHSFCACHE)GetProcAddress (hInstDLL,
MAKEINTRESOURCEA(526));
if (pfnSHFlushSFCache) {
pfnSHFlushSFCache();
bResult = TRUE;
}
FreeLibrary (hInstDLL);
}
return bResult;
}
//*************************************************************
//
// CheckForVerbosePolicy()
//
// Purpose: Checks if the user has requested verbose
// output of policy to the eventlog
//
// Parameters: None
//
// Return: TRUE if we should be verbose
// FALSE if not
//
//*************************************************************
BOOL CheckForVerbosePolicy (void)
{
DWORD dwSize, dwType;
BOOL bVerbose = FALSE;
HKEY hKey;
LONG lResult;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, DIAGNOSTICS_KEY,
0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
dwSize = sizeof(bVerbose);
if (RegQueryValueEx (hKey, DIAGNOSTICS_POLICY_VALUE, NULL,
&dwType, (LPBYTE) &bVerbose,
&dwSize) != ERROR_SUCCESS)
{
RegQueryValueEx (hKey, DIAGNOSTICS_GLOBAL_VALUE, NULL,
&dwType, (LPBYTE) &bVerbose, &dwSize);
}
RegCloseKey (hKey);
}
return bVerbose;
}
//*************************************************************
//
// int ExtractCSIDL()
//
// Purpose: Extract the CSIDL from the given string which
// should under the form ::0x0000::path1\path2\...\
// pathn\file.ext, where 0x0000 is any valid CSIDL
//
// Parameters: pcszPath - Path containing or not a CSIDL
// ppszUsualPath - pointer to first characvter of
// usual path
//
// Return: CSIDL if successful
// -1 if no CSIDL in path
//
// Comments: The ::0x0000:: must be at the beginning and not
// preceded by any other character and not followed
// by any either (other than the usual path)
//
// History: Date Author Comment
// 6/9/98 stephstm Created
//
//*************************************************************
int ExtractCSIDL(LPCTSTR pcszPath, LPTSTR* ppszUsualPath)
{
int nRV=-1;
if (NULL != ppszUsualPath)
{
if (TEXT(':') == *pcszPath && TEXT(':') == *(pcszPath+1) &&
TEXT(':') == *(pcszPath+8) && TEXT(':') == *(pcszPath+9))
{//looks good
//+4 to skip "::0x"
nRV = HexStringToUInt(pcszPath+4);
*ppszUsualPath = (LPTSTR)(pcszPath+10);
}
else
{//no CSIDL in this path
//the whole path is a usual path
*ppszUsualPath = (LPTSTR)pcszPath;
}
}
else
{
DebugMsg((DM_VERBOSE, TEXT("ExtractCSIDL: ppszUsualPath ptr is NULL.")));
}
return nRV;
}
//*************************************************************
//
// MyGetDomainDNSName()
//
// Purpose: Gets the user's domain dns name
//
// Parameters: void
//
// Return: lpDomain if successful
// NULL if an error occurs
//
//*************************************************************
LPTSTR MyGetDomainDNSName (VOID)
{
LPTSTR lpTemp, lpDomain;
//
// Get the username in DNS format. It will return it in
// dnsdomainname\username
//
lpDomain = MyGetUserName (NameDnsDomain);
if (!lpDomain) {
DebugMsg((DM_WARNING, TEXT("MyGetDomainName: MyGetUserName failed for dns domain name with %d"),
GetLastError()));
return NULL;
}
//
// Look for the \ between the domain and username and replace
// it with a NULL
//
lpTemp = lpDomain;
while (*lpTemp && ((*lpTemp) != TEXT('\\')))
lpTemp++;
if (*lpTemp != TEXT('\\')) {
DebugMsg((DM_WARNING, TEXT("GetUserAndDomainNames: Failed to find slash in dns style name: <%s>"),
lpDomain));
SetLastError(ERROR_INVALID_DATA);
LocalFree (lpDomain);
return NULL;
}
*lpTemp = TEXT('\0');
return lpDomain;
}
//*************************************************************
//
// MyGetUserName()
//
// Purpose: Gets the user name in the requested format
//
// Parameters: NameFormat - GetUserNameEx naming format
//
// Return: lpUserName if successful
// NULL if an error occurs
//
//*************************************************************
LPTSTR MyGetUserName (EXTENDED_NAME_FORMAT NameFormat)
{
DWORD dwCount = 0, dwError = ERROR_SUCCESS;
LPTSTR lpUserName = NULL, lpTemp;
ULONG ulUserNameSize;
PSECUR32_API pSecur32;
//
// Load secur32.dll
//
pSecur32 = LoadSecur32();
if (!pSecur32) {
DebugMsg((DM_WARNING, TEXT("MyGetUserName: Failed to load Secur32.")));
return NULL;
}
//
// Allocate a buffer for the user name
//
ulUserNameSize = 75;
if (NameFormat == NameFullyQualifiedDN) {
ulUserNameSize = 200;
}
lpUserName = LocalAlloc (LPTR, ulUserNameSize * sizeof(TCHAR));
if (!lpUserName) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("MyGetUserName: Failed to allocate memory with %d"),
dwError));
goto Exit;
}
//
// Get the username in the requested format
//
while (TRUE) {
if (pSecur32->pfnGetUserNameEx (NameFormat, lpUserName, &ulUserNameSize)) {
dwError = ERROR_SUCCESS;
goto Exit;
} else {
//
// Get the error code
//
dwError = GetLastError();
//
// If the call failed due to insufficient memory, realloc
// the buffer and try again. Otherwise, check the pass
// count and retry if appropriate.
//
if ((dwError == ERROR_INSUFFICIENT_BUFFER) ||
(dwError == ERROR_MORE_DATA)) {
lpTemp = LocalReAlloc (lpUserName, (ulUserNameSize * sizeof(TCHAR)),
LMEM_MOVEABLE);
if (!lpTemp) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("MyGetUserName: Failed to realloc memory with %d"),
dwError));
LocalFree (lpUserName);
lpUserName = NULL;
goto Exit;
}
lpUserName = lpTemp;
} else if ((dwError == ERROR_NONE_MAPPED) || (dwError == ERROR_NETWORK_UNREACHABLE)) {
LocalFree (lpUserName);
lpUserName = NULL;
goto Exit;
} else {
DebugMsg((DM_WARNING, TEXT("MyGetUserName: GetUserNameEx failed with %d."),
dwError));
dwCount++;
if (dwCount > 3) {
LocalFree (lpUserName);
lpUserName = NULL;
goto Exit;
}
DebugMsg((DM_VERBOSE, TEXT("MyGetUserName: Retrying call to GetUserNameEx in 1/2 second.")));
Sleep(500);
}
}
}
Exit:
SetLastError(dwError);
return lpUserName;
}
//*************************************************************
//
// MyGetUserNameEx()
//
// Purpose: Gets the user name in the requested format
//
// Parameters: NameFormat - GetUserNameEx naming format
//
// Return: lpUserName if successful
// NULL if an error occurs
//
//*************************************************************
LPTSTR MyGetUserNameEx (EXTENDED_NAME_FORMAT NameFormat)
{
DWORD dwCount = 0, dwError = ERROR_SUCCESS;
LPTSTR lpUserName = NULL, lpTemp;
ULONG ulUserNameSize;
PSECUR32_API pSecur32;
//
// Load secur32.dll
//
pSecur32 = LoadSecur32();
if (!pSecur32) {
DebugMsg((DM_WARNING, TEXT("MyGetUserNameEx: Failed to load Secur32.")));
return NULL;
}
//
// Allocate a buffer for the user name
//
ulUserNameSize = 75;
if (NameFormat == NameFullyQualifiedDN) {
ulUserNameSize = 200;
}
lpUserName = LocalAlloc (LPTR, ulUserNameSize * sizeof(TCHAR));
if (!lpUserName) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("MyGetUserNameEx: Failed to allocate memory with %d"),
dwError));
goto Exit;
}
//
// Get the username in the requested format
//
if (!pSecur32->pfnGetUserNameEx (NameFormat, lpUserName, &ulUserNameSize)) {
//
// If the call failed due to insufficient memory, realloc
// the buffer and try again. Otherwise, exit now.
//
dwError = GetLastError();
if ((dwError != ERROR_INSUFFICIENT_BUFFER) && (dwError != ERROR_MORE_DATA)) {
LocalFree (lpUserName);
lpUserName = NULL;
goto Exit;
}
lpTemp = LocalReAlloc (lpUserName, (ulUserNameSize * sizeof(TCHAR)),
LMEM_MOVEABLE);
if (!lpTemp) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("MyGetUserNameEx: Failed to realloc memory with %d"),
dwError));
LocalFree (lpUserName);
lpUserName = NULL;
goto Exit;
}
lpUserName = lpTemp;
if (!pSecur32->pfnGetUserNameEx (NameFormat, lpUserName, &ulUserNameSize)) {
dwError = GetLastError();
LocalFree (lpUserName);
lpUserName = NULL;
goto Exit;
}
dwError = ERROR_SUCCESS;
}
Exit:
SetLastError(dwError);
return lpUserName;
}
//*************************************************************
//
// MyGetComputerName()
//
// Purpose: Gets the computer name in the requested format
//
// Parameters: NameFormat - GetComputerObjectName naming format
//
// Return: lpComputerName if successful
// NULL if an error occurs
//
//*************************************************************
LPTSTR MyGetComputerName (EXTENDED_NAME_FORMAT NameFormat)
{
DWORD dwError = ERROR_SUCCESS;
LPTSTR lpComputerName = NULL, lpTemp;
ULONG ulComputerNameSize;
PSECUR32_API pSecur32;
//
// Load secur32.dll
//
pSecur32 = LoadSecur32();
if (!pSecur32) {
DebugMsg((DM_WARNING, TEXT("MyGetComputerName: Failed to load Secur32.")));
return NULL;
}
//
// Allocate a buffer for the computer name
//
ulComputerNameSize = 75;
if (NameFormat == NameFullyQualifiedDN) {
ulComputerNameSize = 200;
}
lpComputerName = LocalAlloc (LPTR, ulComputerNameSize * sizeof(TCHAR));
if (!lpComputerName) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("MyGetComputerName: Failed to allocate memory with %d"),
dwError));
goto Exit;
}
//
// Get the computer name in the requested format
//
if (!pSecur32->pfnGetComputerObjectName (NameFormat, lpComputerName, &ulComputerNameSize)) {
//
// If the call failed due to insufficient memory, realloc
// the buffer and try again. Otherwise, exit now.
//
dwError = GetLastError();
if (dwError != ERROR_INSUFFICIENT_BUFFER) {
LocalFree (lpComputerName);
lpComputerName = NULL;
goto Exit;
}
lpTemp = LocalReAlloc (lpComputerName, (ulComputerNameSize * sizeof(TCHAR)),
LMEM_MOVEABLE);
if (!lpTemp) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("MyGetComputerName: Failed to realloc memory with %d"),
dwError));
LocalFree (lpComputerName);
lpComputerName = NULL;
goto Exit;
}
lpComputerName = lpTemp;
if (!pSecur32->pfnGetComputerObjectName (NameFormat, lpComputerName, &ulComputerNameSize)) {
dwError = GetLastError();
LocalFree (lpComputerName);
lpComputerName = NULL;
goto Exit;
}
dwError = ERROR_SUCCESS;
}
Exit:
SetLastError(dwError);
return lpComputerName;
}
//*************************************************************
//
// ImpersonateUser()
//
// Purpose: Impersonates the specified user
//
// Parameters: hToken - user to impersonate
//
// Return: hToken if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL ImpersonateUser (HANDLE hNewUser, HANDLE *hOldUser)
{
DWORD dwErr;
if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_READ, TRUE, hOldUser))
{
*hOldUser = NULL;
dwErr = GetLastError();
if (dwErr != ERROR_NO_TOKEN)
{
DebugMsg((DM_VERBOSE, TEXT("ImpersonateUser: Failed to open thread token with %d."), dwErr));
return FALSE;
}
}
if (!ImpersonateLoggedOnUser(hNewUser))
{
if ( *hOldUser )
{
CloseHandle( *hOldUser );
*hOldUser = NULL;
}
DebugMsg((DM_VERBOSE, TEXT("ImpersonateUser: Failed to impersonate user with %d."), GetLastError()));
return FALSE;
}
return TRUE;
}
//*************************************************************
//
// RevertToUser()
//
// Purpose: Revert back to original user
//
// Parameters: hUser - original user token
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL RevertToUser (HANDLE *hUser)
{
BOOL bRetVal;
bRetVal = SetThreadToken(NULL, *hUser);
if (!bRetVal)
{
DebugMsg((DM_WARNING, TEXT("RevertToUser: SetThreadToken failed with %d."), GetLastError()));
}
if (*hUser)
{
CloseHandle (*hUser);
*hUser = NULL;
}
return bRetVal;
}
//*************************************************************
//
// GuidToString, StringToGuid, ValidateGuid, CompareGuid()
//
// Purpose: Guid utility functions
//
//*************************************************************
//
// Length in chars of string form of guid {44cffeec-79d0-11d2-a89d-00c04fbbcfa2}
//
#define GUID_LENGTH 38
void GuidToStringEx( const GUID *pGuid, TCHAR * szValue, UINT cchValue)
{
StringCchPrintf( szValue, cchValue,
TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
pGuid->Data1,
pGuid->Data2,
pGuid->Data3,
pGuid->Data4[0], pGuid->Data4[1],
pGuid->Data4[2], pGuid->Data4[3],
pGuid->Data4[4], pGuid->Data4[5],
pGuid->Data4[6], pGuid->Data4[7] );
}
void GuidToString( const GUID *pGuid, TCHAR * szValue)
{
//
// Assume the buffer is big enough (39 chars) to hold the string,
// try to use GuidToStringEx() instead!!!
//
StringCchPrintf( szValue, GUID_LENGTH + 1,
TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
pGuid->Data1,
pGuid->Data2,
pGuid->Data3,
pGuid->Data4[0], pGuid->Data4[1],
pGuid->Data4[2], pGuid->Data4[3],
pGuid->Data4[4], pGuid->Data4[5],
pGuid->Data4[6], pGuid->Data4[7] );
}
void StringToGuid( TCHAR * szValue, GUID * pGuid )
{
WCHAR wc;
INT i;
//
// If the first character is a '{', skip it
//
if ( szValue[0] == L'{' )
szValue++;
//
// Since szValue may be used again, no permanent modification to
// it is be made.
//
wc = szValue[8];
szValue[8] = 0;
pGuid->Data1 = wcstoul( &szValue[0], 0, 16 );
szValue[8] = wc;
wc = szValue[13];
szValue[13] = 0;
pGuid->Data2 = (USHORT)wcstoul( &szValue[9], 0, 16 );
szValue[13] = wc;
wc = szValue[18];
szValue[18] = 0;
pGuid->Data3 = (USHORT)wcstoul( &szValue[14], 0, 16 );
szValue[18] = wc;
wc = szValue[21];
szValue[21] = 0;
pGuid->Data4[0] = (unsigned char)wcstoul( &szValue[19], 0, 16 );
szValue[21] = wc;
wc = szValue[23];
szValue[23] = 0;
pGuid->Data4[1] = (unsigned char)wcstoul( &szValue[21], 0, 16 );
szValue[23] = wc;
for ( i = 0; i < 6; i++ )
{
wc = szValue[26+i*2];
szValue[26+i*2] = 0;
pGuid->Data4[2+i] = (unsigned char)wcstoul( &szValue[24+i*2], 0, 16 );
szValue[26+i*2] = wc;
}
}
BOOL ValidateGuidPrefix( TCHAR *szValue)
// This function is different from ValidateGuid in only one case. szValue is checked to be prefixed with Guid.
{
//
// Check if szValue is of form {19e02dd6-79d2-11d2-a89d-00c04fbbcfa2}
//
// Fixing bug 570352
DWORD i;
if ( lstrlen(szValue) < GUID_LENGTH ) // this function is different from ValidateGuid here.
return FALSE;
if ( szValue[0] != TEXT('{')
|| szValue[9] != TEXT('-')
|| szValue[14] != TEXT('-')
|| szValue[19] != TEXT('-')
|| szValue[24] != TEXT('-')
|| szValue[37] != TEXT('}') )
{
return FALSE;
}
for ( i = 0; (i <= 37); i++ )
{
if ( i != 0 && i != 9 && i != 14 && i != 19 && i != 24 && i != 37 )
{
// it shld be between 0-9 or A-F or a-f
if (szValue[i] >= L'0' && szValue[i] <= L'9')
continue;
if (szValue[i] >= L'a' && szValue[i] <= L'f')
continue;
if (szValue[i] >= L'A' && szValue[i] <= L'F')
continue;
return FALSE; // It is here because of invalid character in the string
}
}
return TRUE;
}
BOOL ValidateGuid( TCHAR *szValue )
{
//
// Check if szValue is of form {19e02dd6-79d2-11d2-a89d-00c04fbbcfa2}
//
// Fixing bug 570352
DWORD i;
if ( lstrlen(szValue) != GUID_LENGTH )
return FALSE;
return ValidateGuidPrefix(szValue);
}
INT CompareGuid( GUID * pGuid1, GUID * pGuid2 )
{
INT i;
if ( pGuid1->Data1 != pGuid2->Data1 )
return ( pGuid1->Data1 < pGuid2->Data1 ? -1 : 1 );
if ( pGuid1->Data2 != pGuid2->Data2 )
return ( pGuid1->Data2 < pGuid2->Data2 ? -1 : 1 );
if ( pGuid1->Data3 != pGuid2->Data3 )
return ( pGuid1->Data3 < pGuid2->Data3 ? -1 : 1 );
for ( i = 0; i < 8; i++ )
{
if ( pGuid1->Data4[i] != pGuid2->Data4[i] )
return ( pGuid1->Data4[i] < pGuid2->Data4[i] ? -1 : 1 );
}
return 0;
}
//*************************************************************
//
// RegCleanUpValue()
//
// Purpose: Removes the target value and if no more values / keys
// are present, removes the key. This function then
// works up the parent tree removing keys if they are
// also empty. If any parent key has a value / subkey,
// it won't be removed.
//
// Parameters: hKeyRoot - Root key
// lpSubKey - SubKey
// lpValueName - Value to remove
//
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL RegCleanUpValue (HKEY hKeyRoot, LPTSTR lpSubKey, LPTSTR lpValueName)
{
TCHAR szDelKey[2 * MAX_PATH];
LPTSTR lpEnd;
DWORD dwKeys, dwValues;
LONG lResult;
HKEY hKey;
//
// Make a copy of the subkey so we can write to it.
//
if (FAILED(StringCchCopy (szDelKey, ARRAYSIZE(szDelKey), lpSubKey)))
{
DebugMsg((DM_WARNING, TEXT("RegCleanUpKey: Failed to copy value name.")));
return FALSE;
}
//
// First delete the value
//
lResult = RegOpenKeyEx (hKeyRoot, szDelKey, 0, KEY_WRITE, &hKey);
if (lResult == ERROR_SUCCESS)
{
lResult = RegDeleteValue (hKey, lpValueName);
RegCloseKey (hKey);
if (lResult != ERROR_SUCCESS)
{
if (lResult != ERROR_FILE_NOT_FOUND)
{
DebugMsg((DM_WARNING, TEXT("RegCleanUpKey: Failed to delete value <%s> with %d."), lpValueName, lResult));
return FALSE;
}
}
}
//
// Now loop through each of the parents. If the parent is empty
// eg: no values and no other subkeys, then remove the parent and
// keep working up.
//
lpEnd = szDelKey + lstrlen(szDelKey) - 1;
while (lpEnd >= szDelKey)
{
//
// Find the parent key
//
while ((lpEnd > szDelKey) && (*lpEnd != TEXT('\\')))
lpEnd--;
//
// Open the key
//
lResult = RegOpenKeyEx (hKeyRoot, szDelKey, 0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS)
{
if (lResult == ERROR_FILE_NOT_FOUND)
{
goto LoopAgain;
}
else
{
DebugMsg((DM_WARNING, TEXT("RegCleanUpKey: Failed to open key <%s> with %d."), szDelKey, lResult));
return FALSE;
}
}
//
// See if there any any values / keys
//
lResult = RegQueryInfoKey (hKey, NULL, NULL, NULL, &dwKeys, NULL, NULL,
&dwValues, NULL, NULL, NULL, NULL);
RegCloseKey (hKey);
if (lResult != ERROR_SUCCESS)
{
DebugMsg((DM_WARNING, TEXT("RegCleanUpKey: Failed to query key <%s> with %d."), szDelKey, lResult));
return FALSE;
}
//
// Exit now if this key has values or keys
//
if ((dwKeys != 0) || (dwValues != 0))
{
return TRUE;
}
RegDeleteKey (hKeyRoot, szDelKey);
LoopAgain:
//
// If we are at the beginning of the subkey, we can leave now.
//
if (lpEnd == szDelKey)
{
return TRUE;
}
//
// There is a parent key. Remove the slash and loop again.
//
if (*lpEnd == TEXT('\\'))
{
*lpEnd = TEXT('\0');
}
}
return TRUE;
}
//*************************************************************
//
// InitializePingCritSec()
//
// Purpose: Initializes a CRITICAL_SECTION for pinging
// computers
//
// Parameters: none
//
//
// Return: ERROR_SUCCESS if successful
// An error if it fails.
//
//*************************************************************
DWORD InitializePingCritSec( void )
{
CRITICAL_SECTION *pCritSec = NULL;
DWORD result = ERROR_SUCCESS;
BOOL fInitialized = FALSE;
CRITICAL_SECTION *pInitial;
// If the critical section already exists, return.
if (g_PingCritSec != NULL)
return ERROR_SUCCESS;
// Allocate memory for the critial section.
pCritSec = (CRITICAL_SECTION *) LocalAlloc( LMEM_FIXED,
sizeof(CRITICAL_SECTION) );
if (pCritSec == NULL)
{
result = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}
// Initialize the critical section. Using the flag 0x80000000
// preallocates the event so that EnterCriticalSection can only
// throw timeout exceptions.
__try
{
if (!InitializeCriticalSectionAndSpinCount( pCritSec, 0x80000000 ))
result = GetLastError();
else
fInitialized = TRUE;
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
result = GetExceptionCode();
}
if (result != ERROR_SUCCESS)
goto Exit;
// Save the critical section.
pInitial = (CRITICAL_SECTION *) InterlockedCompareExchangePointer(
(void **) &g_PingCritSec, (void *) pCritSec, NULL );
// If the InterlockedCompareExchange succeeded, don't free the
// critical section just allocated.
if (pInitial == NULL)
pCritSec = NULL;
Exit:
if (pCritSec != NULL)
{
if (fInitialized)
DeleteCriticalSection( pCritSec );
LocalFree( pCritSec );
}
return result;
}
//*************************************************************
//
// ClosePingCritSec()
//
// Purpose: Closes the CRITICAL_SECTION for pinging
// computers
//
// Parameters: none
//
//
// Return: none
//
//*************************************************************
void ClosePingCritSec( void )
{
if (g_PingCritSec != NULL)
{
DeleteCriticalSection( g_PingCritSec );
LocalFree( g_PingCritSec );
g_PingCritSec = NULL;
}
}
#define PING_BUFFER_SIZE 2048
//*************************************************************
//
// PingComputerEx()
//
// Purpose: Pings the specified computer to determine
// what the data transfer rate is
//
// Parameters: ipaddr - IP address of computer
// ulSpeed - Data transfer rate (see Notes below)
// pdwAdapterIndex - index of the adapter that services
// calls to the DC
//
// Return: ERROR_SUCCESS if successful
// Error code otherwise
//
// Notes: For fast connections (eg: LAN), it isn't possible
// to get accurate transfer rates since the response
// time from the computer is less than 10ms. In
// this case, the function returns ERROR_SUCCESS and
// ulSpeed is set to maximum speed of network interface.
//
// This function will ping the computer 3 times with
// no data and 3 times with 4K of data. If the response
// time from any of the pings is less than 10ms, the
// function assumes this is a fast link (eg: LAN) and
// returns with ulSpeed set to maximum speed of network
// interface.
//
// If the pings respond in a time greater than 10ms,
// the time of the second ping is subtracted from
// the time of the first ping to determine the amount
// of time it takes to move just the data. This
// is repeated for the 3 sets of pings. Then the
// average time is computed from the 3 sets of pings.
// From the average time, the kbps is calculated.
//
//*************************************************************
DWORD WINAPI
PingComputerEx( ULONG ipaddr, ULONG *ulSpeed, DWORD* pdwAdapterIndex )
{
DWORD dwResult = ERROR_SUCCESS;
DWORD i;
DWORD dwReplySize;
HANDLE icmpHandle = NULL;
LPBYTE lpReply = NULL;
PICMP_ECHO_REPLY pReplyStruct;
ULONG ulFirst;
ULONG ulSecond;
ULONG ulDiff;
ULONG ulTotal = 0;
ULONG ulCount = 0;
PICMP_API pIcmp;
HRSRC hJPEG;
MIB_IFROW mibIfRow;
PIPHLPAPI_API pIpHlpApi;
HGLOBAL hGlobalJPEG;
dwResult = InitializePingCritSec();
if (dwResult != ERROR_SUCCESS)
return dwResult;
EnterCriticalSection( g_PingCritSec );
//
// Load iphlpapi.dll
//
pIpHlpApi = LoadIpHlpApi();
if ( !pIpHlpApi )
{
dwResult = GetLastError();
DebugMsg((DM_WARNING, TEXT("PingComputer: iphlpapi.dll is not loaded, %d"), dwResult ));
goto Exit;
}
//
// Load the icmp api
//
dwResult = LoadIcmp( &pIcmp );
if (dwResult != ERROR_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("PingComputer: Failed to load icmp api.")));
goto Exit;
}
//
// Load the slow link data if appropriate
//
if (!g_lpTestData) {
hJPEG = FindResource (g_hDllInstance, MAKEINTRESOURCE(IDB_SLOWLINK), TEXT("JPEG"));
if (hJPEG) {
hGlobalJPEG = LoadResource (g_hDllInstance, hJPEG);
if (hGlobalJPEG) {
g_lpTestData = LockResource (hGlobalJPEG);
}
}
}
if (!g_lpTestData) {
dwResult = GetLastError();
DebugMsg((DM_WARNING, TEXT("PingComputer: Failed to load slow link data.")));
goto Exit;
}
//
// Set default speed
//
ZeroMemory( &mibIfRow, sizeof( mibIfRow ) );
//
// get the interface index corr. to the interface that services traffic to ipaddr ( DC )
//
dwResult = pIpHlpApi->pfnGetBestInterface( ipaddr, &mibIfRow.dwIndex );
if ( dwResult != NO_ERROR )
{
DebugMsg((DM_WARNING, TEXT("PingComputer: GetBestInterface with %d"), dwResult));
}
else
{
//
// get information about the interface. We use the dwSpeed as the default speed of the link.
//
dwResult = pIpHlpApi->pfnGetIfEntry( &mibIfRow );
if ( dwResult != NO_ERROR )
{
DebugMsg((DM_WARNING, TEXT("PingComputer: GetIfEntry with %d"), dwResult));
}
else
{
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Adapter speed %d bps"), mibIfRow.dwSpeed));
}
}
if ( pdwAdapterIndex )
{
*pdwAdapterIndex = mibIfRow.dwIndex;
}
*ulSpeed = mibIfRow.dwSpeed/1024; // In kbps
//
// Allocate space for the receive buffer
//
dwReplySize = PING_BUFFER_SIZE + sizeof(ICMP_ECHO_REPLY) + 8;
lpReply = LocalAlloc (LPTR, dwReplySize);
if (!lpReply) {
dwResult = GetLastError();
DebugMsg((DM_WARNING, TEXT("PingComputer: Failed to allocate memory with %d"), dwResult));
goto Exit;
}
//
// Open the Icmp handle
//
icmpHandle = pIcmp->pfnIcmpCreateFile();
if (icmpHandle == INVALID_HANDLE_VALUE) {
dwResult = GetLastError();
DebugMsg((DM_WARNING, TEXT("PingComputer: Failed to open handle with %d"), dwResult));
goto Exit;
}
//
// Loop through the 3 sets of pings
//
for (i = 0; i < 3; i++) {
//
// Initialize the return value
//
dwResult = ERROR_SUCCESS;
//
// First ping with no data
//
if (pIcmp->pfnIcmpSendEcho (icmpHandle, ipaddr, g_lpTestData, 0, NULL, lpReply,
dwReplySize, 5000) == 0) {
dwResult = GetLastError();
if (dwResult == IP_DEST_HOST_UNREACHABLE) {
dwResult = ERROR_BAD_NETPATH;
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Target computer 0x%x not found"), (DWORD)ipaddr));
goto Exit;
} else {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: First send 0x%x failed with %d"), (DWORD)ipaddr, dwResult));
continue;
}
}
pReplyStruct = (PICMP_ECHO_REPLY) lpReply;
if (pReplyStruct->Status != IP_SUCCESS) {
if (pReplyStruct->Status == IP_DEST_HOST_UNREACHABLE) {
dwResult = ERROR_BAD_NETPATH;
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Target computer not found")));
goto Exit;
} else {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: First send has a reply buffer failure of %d"), pReplyStruct->Status));
continue;
}
}
ulFirst = pReplyStruct->RoundTripTime;
DebugMsg((DM_VERBOSE, TEXT("PingComputer: First time: %d"), ulFirst));
if (ulFirst < 10) {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Fast link. Exiting.")));
goto Exit;
}
//
// Second ping with dwSize data
//
if (pIcmp->pfnIcmpSendEcho (icmpHandle, ipaddr, g_lpTestData, PING_BUFFER_SIZE, NULL, lpReply,
dwReplySize, 5000) == 0) {
dwResult = GetLastError();
if (dwResult == IP_DEST_HOST_UNREACHABLE) {
dwResult = ERROR_BAD_NETPATH;
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Target computer not found")));
goto Exit;
} else {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Second send failed with %d"), dwResult));
continue;
}
}
pReplyStruct = (PICMP_ECHO_REPLY) lpReply;
if (pReplyStruct->Status != IP_SUCCESS) {
if (pReplyStruct->Status == IP_DEST_HOST_UNREACHABLE) {
dwResult = ERROR_BAD_NETPATH;
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Target computer not found")));
goto Exit;
} else {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Second send has a reply buffer failure of %d"), pReplyStruct->Status));
continue;
}
}
ulSecond = pReplyStruct->RoundTripTime;
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Second time: %d"), ulSecond));
if (ulSecond < 10) {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Fast link. Exiting.")));
goto Exit;
}
//
// Study the results
//
if (ulFirst > ulSecond) {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Second time less than first time.")));
} else if (ulFirst == ulSecond) {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: First and second times match.")));
} else {
ulTotal += (ulSecond - ulFirst);
ulCount++;
}
}
//
// Study the results
//
if (ulTotal > 0) {
ulTotal = (ulTotal / ulCount);
*ulSpeed = ((((PING_BUFFER_SIZE * 2) * 1000) / ulTotal) * 8) / 1024;
DebugMsg((DM_VERBOSE, TEXT("PingComputer: Transfer rate: %d Kbps Loop count: %d"),*ulSpeed, ulCount));
dwResult = ERROR_SUCCESS;
} else {
DebugMsg((DM_VERBOSE, TEXT("PingComputer: No data available")));
dwResult = ERROR_UNEXP_NET_ERR;
}
Exit:
if (icmpHandle) {
pIcmp->pfnIcmpCloseHandle (icmpHandle);
}
if (lpReply) {
LocalFree (lpReply);
}
LeaveCriticalSection( g_PingCritSec );
return dwResult;
}
DWORD WINAPI PingComputer (ULONG ipaddr, ULONG *ulSpeed)
{
return PingComputerEx( ipaddr, ulSpeed, 0 );
}
//*************************************************************
//
// GetDomainControllerInfo()
//
// Purpose: Wrapper for DsGetDcName().
//
// Parameters:
// pNetAPI32 - Net API entry points
// szDomainName - domain name
// ulFlags - flags, see DsGetDcName()
// ppInfo - see DOMAIN_CONTROLLER_INFO
// pfSlow - slow link?
//
// Comments:
//
//
// Return: NO_ERROR if successful
// Error code if an error occurs
//
//*************************************************************
DWORD GetDomainControllerInfo( PNETAPI32_API pNetAPI32,
LPTSTR szDomainName,
ULONG ulFlags,
HKEY hKeyRoot,
PDOMAIN_CONTROLLER_INFO* ppInfo,
BOOL* pfSlow,
DWORD* pdwAdapterIndex )
{
DWORD dwResult;
//
// get DC info.
//
dwResult = pNetAPI32->pfnDsGetDcName( 0,
szDomainName,
0,
0,
ulFlags,
ppInfo);
if ( dwResult == ERROR_SUCCESS ) {
//
// Check for slow link
//
dwResult = IsSlowLink( hKeyRoot,
(*ppInfo)->DomainControllerAddress,
pfSlow,
pdwAdapterIndex );
if ( dwResult != ERROR_SUCCESS ){
//
// force rediscovery to obtain a live DC
//
dwResult = pNetAPI32->pfnDsGetDcName( 0,
szDomainName,
0,
0,
ulFlags | DS_FORCE_REDISCOVERY,
ppInfo);
if ( dwResult == ERROR_SUCCESS ) {
//
// re-evaluate link speed
//
dwResult = IsSlowLink( hKeyRoot,
(*ppInfo)->DomainControllerAddress,
pfSlow,
pdwAdapterIndex );
}
}
}
return dwResult;
}
//***************************************************************************
//
// GetUserGuid
//
// Purpose: Allocates and returns a string representing the user guid of
// the current user.
//
// Parameters: hToken - user's token
//
// Return: szUserString is successful
// NULL if an error occurs
//
// Comments: Note, this only works for domain accounts. Local accounts
// do not have GUIDs.
//
// History: Date Author Comment
// 11/14/95 ushaji created
//***************************************************************************
LPTSTR GetUserGuid(HANDLE hToken)
{
LPTSTR szUserGuid=NULL;
HANDLE hOldToken;
PSID psidSystem = NULL, psidUser=NULL;
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
BOOL bImpersonated = FALSE;
//
// Get the system sid
//
if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
DebugMsg((DM_WARNING, TEXT("GetUserGuid: Failed to initialize system sid. Error = %d"), GetLastError()));
goto Exit;
}
psidUser = GetUserSid(hToken);
if (!psidUser) {
DebugMsg((DM_WARNING, TEXT("GetUserGuid: Couldn't get user sid, Error = %d"), GetLastError()));
goto Exit;
}
if (EqualSid(psidUser, psidSystem)) {
DebugMsg((DM_VERBOSE, TEXT("GetUserGuid: user sid matches local system, returning NULL"), GetLastError()));
goto Exit;
}
//
// impersonate the user and the get the user guid for this user.
//
if (!ImpersonateUser(hToken, &hOldToken)) {
DebugMsg((DM_WARNING, TEXT("GetUserGuid: Failed to impersonate user with %d."), GetLastError()));
goto Exit;
}
bImpersonated = TRUE;
szUserGuid = MyGetUserNameEx(NameUniqueId);
if (!szUserGuid) {
if ((GetLastError() != ERROR_CANT_ACCESS_DOMAIN_INFO) &&
(GetLastError() != ERROR_NONE_MAPPED)) {
DebugMsg((DM_WARNING, TEXT("GetUserGuid: Failed to get user guid with %d."), GetLastError()));
}
}
Exit:
if (bImpersonated)
RevertToUser(&hOldToken);
if (psidUser) {
DeleteUserSid (psidUser);
}
if (psidSystem)
FreeSid(psidSystem);
return szUserGuid;
}
//***************************************************************************
//
// GetOldSidString
//
// Purpose: Allocates and returns a string representing the old sid of
// the current user by looking at the profile guid in the registry.
//
// Parameters: hToken - user's token
// lpKeyName - key to read
//
// Return: SidString is successful
// NULL if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 11/14/95 ushaji created
//***************************************************************************
LPTSTR GetOldSidString(HANDLE hToken, LPTSTR lpKeyName)
{
TCHAR szBuffer[MAX_PATH], *lpEnd;
LPTSTR szUserGuid;
DWORD dwSize=0, dwType;
TCHAR *lpSidString = NULL;
HKEY hKey = NULL;
LONG lResult;
DWORD dwErr;
HRESULT hr;
DWORD cchEnd;
//
// get the prev last error
//
dwErr = GetLastError();
szUserGuid = GetUserGuid(hToken);
if (!szUserGuid) {
dwErr = GetLastError();
goto Exit;
}
//
// Open the guid->sid mapping
//
hr = StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), lpKeyName);
if (FAILED(hr))
{
dwErr = HRESULT_CODE(hr);
goto Exit;
}
lpEnd = CheckSlashEx (szBuffer, ARRAYSIZE(szBuffer), &cchEnd);
if (!lpEnd)
{
dwErr = ERROR_INSUFFICIENT_BUFFER;
goto Exit;
}
hr = StringCchCopy(lpEnd, cchEnd, szUserGuid);
if (FAILED(hr))
{
dwErr = HRESULT_CODE(hr);
goto Exit;
}
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS) {
dwErr = lResult;
DebugMsg((DM_VERBOSE, TEXT("GetOldSidString: Failed to open profile profile guid key with error %d"), lResult));
goto Exit;
}
//
// Query for the Sid String, (size first)
//
lResult = RegQueryValueEx (hKey,
PROFILE_SID_STRING,
NULL,
&dwType,
NULL,
&dwSize);
if (lResult != ERROR_SUCCESS) {
dwErr = lResult;
DebugMsg((DM_WARNING, TEXT("GetOldSidString: Failed to query size of SidString with error %d"), lResult));
goto Exit;
}
lpSidString = LocalAlloc(LPTR, dwSize);
if (!lpSidString) {
dwErr = lResult;
DebugMsg((DM_WARNING, TEXT("GetOldSidString: Failed to allocate memory for SidString"), lResult));
goto Exit;
}
lResult = RegQueryValueEx (hKey,
PROFILE_SID_STRING,
NULL,
&dwType,
(LPBYTE)lpSidString,
&dwSize);
if (lResult != ERROR_SUCCESS) {
dwErr = lResult;
DebugMsg((DM_WARNING, TEXT("GetOldSidString: Failed to query SidString with error %d"), lResult));
LocalFree(lpSidString);
lpSidString = NULL;
goto Exit;
}
Exit:
if (szUserGuid)
LocalFree(szUserGuid);
if (hKey)
RegCloseKey(hKey);
SetLastError(dwErr);
return lpSidString;
}
//***************************************************************************
//
// SetOldSidString
//
// Purpose: Sets the old sid string corresp. to a user for the next domain
// migration
//
// Parameters: hToken - user's token
// lpSidString - user's sid (in a string form)
// lpKeyName - key to store
//
// Return: SidString is successful
// NULL if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 11/14/95 ushaji created
//***************************************************************************
BOOL SetOldSidString(HANDLE hToken, LPTSTR lpSidString, LPTSTR lpKeyName)
{
TCHAR szBuffer[MAX_PATH+1], *lpEnd;
DWORD dwSize=0, dwDisp = 0;
HKEY hKey = NULL;
BOOL bRetVal = TRUE;
LONG lResult = 0;
LPTSTR szUserGuid;
DWORD dwErr;
HRESULT hr;
DWORD cchEnd;
//
// get the prev last error
//
dwErr = GetLastError();
szUserGuid = GetUserGuid(hToken);
if (!szUserGuid) {
dwErr = GetLastError();
goto Exit;
}
//
// Open the guid->sid mapping
//
hr = StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), lpKeyName);
if (FAILED(hr))
{
dwErr = HRESULT_CODE(hr);
goto Exit;
}
lpEnd = CheckSlashEx (szBuffer, ARRAYSIZE(szBuffer), &cchEnd);
if (!lpEnd)
{
dwErr = ERROR_INSUFFICIENT_BUFFER;
goto Exit;
}
hr = StringCchCopy(lpEnd, cchEnd, szUserGuid);
if (FAILED(hr))
{
dwErr = HRESULT_CODE(hr);
goto Exit;
}
lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, 0, 0, KEY_READ | KEY_WRITE, NULL,
&hKey, &dwDisp);
if (lResult != ERROR_SUCCESS) {
dwErr = GetLastError();
DebugMsg((DM_VERBOSE, TEXT("GetOldSidString: Failed to open profile profile guid key with error %d"), lResult));
goto Exit;
}
//
// Set the Sid String
//
lResult = RegSetValueEx (hKey,
PROFILE_SID_STRING,
0,
REG_SZ,
(LPBYTE) lpSidString,
(lstrlen(lpSidString) + 1) * sizeof(TCHAR));
if (lResult != ERROR_SUCCESS) {
dwErr = GetLastError();
DebugMsg((DM_WARNING, TEXT("SetOldSidString: Failed to set SidString with error %d"), lResult));
goto Exit;
}
bRetVal = TRUE;
Exit:
if (szUserGuid)
LocalFree(szUserGuid);
if (hKey)
RegCloseKey(hKey);
SetLastError(dwErr);
return bRetVal;
}
//***************************************************************************
//
// GetErrString
//
// Purpose: Calls FormatMessage to Get the error string corresp. to a error
// code
//
//
// Parameters: dwErr - Error Code
// szErr - Buffer to return the error string (MAX_PATH)
// is assumed.!!!
//
// Return: szErr
//
// History: Date Author Comment
// 4/28/99 ushaji created
//***************************************************************************
LPTSTR GetErrString(DWORD dwErr, LPTSTR szErr)
{
szErr[0] = TEXT('\0');
FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
szErr, MAX_PATH, NULL);
return szErr;
}
//*************************************************************
//
// GetMachineToken()
//
// Purpose: Gets the machine token
//
// Parameters: none
//
// Note: This must be called from the LocalSystem context
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
HANDLE GetMachineToken (void)
{
SECURITY_STATUS SecStatus;
SECURITY_STATUS InitStatus;
SECURITY_STATUS AcceptStatus;
HANDLE hToken = NULL;
PSecPkgInfo PackageInfo = NULL;
BOOLEAN AcquiredServerCred = FALSE;
BOOLEAN AcquiredClientCred = FALSE;
BOOLEAN AcquiredClientContext = FALSE;
BOOLEAN AcquiredServerContext = FALSE;
CredHandle CredentialHandle2;
CredHandle ServerCredHandleStorage;
CtxtHandle ClientContextHandle;
CtxtHandle ServerContextHandle;
PCtxtHandle pServerContextHandle = NULL;
PCtxtHandle pClientContextHandle = NULL;
PCredHandle ServerCredHandle = NULL;
TimeStamp Lifetime;
DWORD dwSize;
TCHAR szComputerName[MAX_PATH];
SecBufferDesc NegotiateDesc;
SecBuffer NegotiateBuffer;
SecBufferDesc ChallengeDesc;
PSecBufferDesc pChallengeDesc = NULL;
SecBuffer ChallengeBuffer;
LPBYTE pvBuffer = NULL;
LPBYTE pvBuffer2 = NULL;
ULONG ContextAttributes;
PSECUR32_API pSecur32;
HRESULT hr;
//
// Load pSecur32->dll
//
if ( !( pSecur32 = LoadSecur32 () ) ) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: Failed to load Secur32.")));
SecStatus = GetLastError();
return NULL;
}
//
// Get the computer name
//
dwSize = ARRAYSIZE(szComputerName);
if (!GetComputerName (szComputerName, &dwSize)) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: Failed to get the computer name with %d"), GetLastError()));
SecStatus = GetLastError();
goto Exit;
}
hr = StringCchCat(szComputerName, ARRAYSIZE(szComputerName), TEXT("$"));
if (FAILED(hr))
{
DebugMsg((DM_WARNING, TEXT("GetMachineToken: Failed to append a '$'. ")));
SecStatus = ERROR_INSUFFICIENT_BUFFER;
goto Exit;
}
//
// Get the kerberos security package
//
SecStatus = pSecur32->pfnQuerySecurityPackageInfo( L"kerberos", &PackageInfo );
if (SecStatus != STATUS_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: QuerySecurityPackageInfo failed with 0x%x"),
SecStatus));
goto Exit;
}
//
// Acquire a credential handle for the server side
//
ServerCredHandle = &ServerCredHandleStorage;
SecStatus = pSecur32->pfnAcquireCredentialsHandle(
NULL, // New principal
L"kerberos", // Package Name
SECPKG_CRED_INBOUND,
NULL,
NULL,
NULL,
NULL,
ServerCredHandle,
&Lifetime );
if (SecStatus != STATUS_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: AcquireCredentialsHandle for server failed with 0x%x"),
SecStatus));
goto Exit;
}
AcquiredServerCred = TRUE;
//
// Acquire a credential handle for the client side
//
SecStatus = pSecur32->pfnAcquireCredentialsHandle(
NULL, // New principal
L"kerberos", // Package Name
SECPKG_CRED_OUTBOUND,
NULL,
NULL,
NULL,
NULL,
&CredentialHandle2,
&Lifetime );
if (SecStatus != STATUS_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: AcquireCredentialsHandle for client failed with 0x%x"),
SecStatus));
goto Exit;
}
AcquiredClientCred = TRUE;
//
// Allocate buffers
//
pvBuffer = LocalAlloc( 0, PackageInfo->cbMaxToken);
if (!pvBuffer) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: LocalAlloc failed with %d"),
GetLastError()));
SecStatus = GetLastError();
goto Exit;
}
pvBuffer2 = LocalAlloc( 0, PackageInfo->cbMaxToken);
if (!pvBuffer2) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: LocalAlloc failed with %d"),
GetLastError()));
SecStatus = GetLastError();
goto Exit;
}
while (TRUE) {
//
// Initialize the security context (client side)
//
NegotiateDesc.ulVersion = 0;
NegotiateDesc.cBuffers = 1;
NegotiateDesc.pBuffers = &NegotiateBuffer;
NegotiateBuffer.cbBuffer = PackageInfo->cbMaxToken;
NegotiateBuffer.BufferType = SECBUFFER_TOKEN;
NegotiateBuffer.pvBuffer = pvBuffer;
InitStatus = pSecur32->pfnInitializeSecurityContext(
&CredentialHandle2,
pClientContextHandle,
szComputerName,
0,
0, // Reserved 1
SECURITY_NATIVE_DREP,
pChallengeDesc,
0, // Reserved 2
&ClientContextHandle,
&NegotiateDesc,
&ContextAttributes,
&Lifetime );
if ((InitStatus != SEC_E_OK) && (InitStatus != SEC_I_CONTINUE_NEEDED)) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: InitializeSecurityContext failed with 0x%x"),
InitStatus));
SecStatus = InitStatus;
goto Exit;
}
pClientContextHandle = &ClientContextHandle;
AcquiredClientContext = TRUE;
//
// Accept the server side context
//
NegotiateBuffer.BufferType |= SECBUFFER_READONLY;
ChallengeDesc.ulVersion = 0;
ChallengeDesc.cBuffers = 1;
ChallengeDesc.pBuffers = &ChallengeBuffer;
ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken;
ChallengeBuffer.BufferType = SECBUFFER_TOKEN;
ChallengeBuffer.pvBuffer = pvBuffer2;
AcceptStatus = pSecur32->pfnAcceptSecurityContext(
ServerCredHandle,
pServerContextHandle,
&NegotiateDesc,
0,
SECURITY_NATIVE_DREP,
&ServerContextHandle,
&ChallengeDesc,
&ContextAttributes,
&Lifetime );
if ((AcceptStatus != SEC_E_OK) && (AcceptStatus != SEC_I_CONTINUE_NEEDED)) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: AcceptSecurityContext failed with 0x%x"),
AcceptStatus));
SecStatus = AcceptStatus;
goto Exit;
}
AcquiredServerContext = TRUE;
if (AcceptStatus == SEC_E_OK) {
break;
}
pChallengeDesc = &ChallengeDesc;
pServerContextHandle = &ServerContextHandle;
DebugMsg((DM_VERBOSE, TEXT("GetMachineToken: Looping for authentication again.")));
}
//
// Get the server token
//
SecStatus = pSecur32->pfnQuerySecurityContextToken(&ServerContextHandle, &hToken);
if ( SecStatus != STATUS_SUCCESS ) {
DebugMsg((DM_WARNING, TEXT("GetMachineToken: QuerySecurityContextToken failed with 0x%x"),
SecStatus));
goto Exit;
}
Exit:
if (AcquiredClientContext) {
pSecur32->pfnDeleteSecurityContext( &ClientContextHandle );
}
if (AcquiredServerContext) {
pSecur32->pfnDeleteSecurityContext( &ServerContextHandle );
}
if (pvBuffer2) {
LocalFree (pvBuffer2);
}
if (pvBuffer) {
LocalFree (pvBuffer);
}
if (AcquiredClientCred) {
pSecur32->pfnFreeCredentialsHandle(&CredentialHandle2);
}
if (AcquiredServerCred)
{
pSecur32->pfnFreeCredentialsHandle(ServerCredHandle);
}
if (PackageInfo) {
pSecur32->pfnFreeContextBuffer(PackageInfo);
}
if (!hToken) {
SetLastError(SecStatus);
}
return hToken;
}
//*************************************************************
//
// IsNullGUID()
//
// Purpose: Determines if the passed in GUID is all zeros
//
// Parameters: pguid GUID to compare
//
// Return: TRUE if the GUID is all zeros
// FALSE if not
//
//*************************************************************
BOOL IsNullGUID (GUID *pguid)
{
return ( (pguid->Data1 == 0) &&
(pguid->Data2 == 0) &&
(pguid->Data3 == 0) &&
(pguid->Data4[0] == 0) &&
(pguid->Data4[1] == 0) &&
(pguid->Data4[2] == 0) &&
(pguid->Data4[3] == 0) &&
(pguid->Data4[4] == 0) &&
(pguid->Data4[5] == 0) &&
(pguid->Data4[6] == 0) &&
(pguid->Data4[7] == 0) );
}
//*************************************************************
//
// GetMachineRole()
//
// Purpose: Determines the role of the machine
// server vs workstation vs standalone
//
// Parameters: piRole - Receives the simple role number
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL GetMachineRole (LPINT piRole)
{
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pBasic;
DWORD dwResult;
PNETAPI32_API pNetAPI32;
//
// Check the cached value first
//
if (g_iMachineRole != -1) {
*piRole = g_iMachineRole;
return TRUE;
}
//
// Load netapi32
//
pNetAPI32 = LoadNetAPI32();
if (!pNetAPI32) {
DebugMsg((DM_WARNING, TEXT("GetMachineRole: Failed to load netapi32 with %d."),
GetLastError()));
return FALSE;
}
//
// Ask for the role of this machine
//
dwResult = pNetAPI32->pfnDsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic,
(PBYTE *)&pBasic);
if (dwResult != ERROR_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetMachineRole: DsRoleGetPrimaryDomainInformation failed with %d."),
dwResult));
return FALSE;
}
//
// Convert the role into a simple machine role
//
if ((pBasic->MachineRole == DsRole_RoleStandaloneWorkstation) ||
(pBasic->MachineRole == DsRole_RoleStandaloneServer)) {
*piRole = 0; // standalone machine not in a DS domain
} else {
if (pBasic->Flags & DSROLE_PRIMARY_DOMAIN_GUID_PRESENT) {
if (!IsNullGUID(&pBasic->DomainGuid)) {
*piRole = 2; // machine is a member of a domain with DS support
if ((pBasic->MachineRole == DsRole_RoleBackupDomainController) ||
(pBasic->MachineRole == DsRole_RolePrimaryDomainController)) {
*piRole = 3; // machine is a domain controller
}
} else {
*piRole = 1; // machine is a member of a NT4 domain
}
} else {
*piRole = 1; // machine is a member of a domain without DS support
}
}
pNetAPI32->pfnDsRoleFreeMemory (pBasic);
//
// Save this value in the cache for future use
//
g_iMachineRole = *piRole;
return TRUE;
}
//*************************************************************
//
// IsUNCPath()
//
// Purpose: Is the given path a UNC path
//
// Parameters: lpPath - Path to check
//
// Return: TRUE if the path is UNC
// FALSE if not
//
// Comments:
//
// History: Date Author Comment
// 6/21/96 ericflo Ported
//
//*************************************************************
BOOL IsUNCPath(LPCTSTR lpPath)
{
if ((!lpPath) || (!lpPath[0]) && (!lpPath[1]))
return FALSE;
if (lpPath[0] == TEXT('\\') && lpPath[1] == TEXT('\\')) {
return(TRUE);
}
return(FALSE);
}
//*************************************************************
//
// MakePathUNC()
//
// Purpose: Makes the given path UNC s.t. it can be accessed from a remote machine..
// if the path contains %systemroot% expanded then it substitutes
// \\machname\admin$ otherwise \\machname\<driveletter>$
//
// Parameters: lpPath - Input Path (needs to be absolute)
// szComputerName - Name of the computer on which this is the local path
//
// Return: Path if it was fone successfully
// NULL if not
//
// Comments:
//
//
//*************************************************************
LPTSTR MakePathUNC(LPTSTR pwszFile, LPTSTR szComputerName)
{
LPTSTR szUNCPath=NULL;
TCHAR szSysRoot[MAX_PATH];
DWORD dwSysLen;
LPTSTR lpEnd = NULL;
DWORD cchUNCPath;
DWORD cchEnd;
HRESULT hr;
DebugMsg((DM_VERBOSE, TEXT("MakePathUNC: Entering with <%s>"),
pwszFile ? pwszFile : TEXT("NULL")));
cchUNCPath = lstrlen(pwszFile)+lstrlen(szComputerName)+3+lstrlen(TEXT("admin$"))+1;
szUNCPath = LocalAlloc(LPTR, sizeof(TCHAR)*cchUNCPath);
if (!szUNCPath)
return NULL;
if (!pwszFile || !*pwszFile) {
DebugMsg((DM_VERBOSE, TEXT("MakePathUNC: lpFile is NULL, setting lpResult to a null string")));
*szUNCPath = TEXT('\0');
return szUNCPath;
}
if (IsUNCPath(pwszFile)) {
StringCchCopy(szUNCPath, cchUNCPath, pwszFile);
return szUNCPath;
}
StringCchCopy(szUNCPath, cchUNCPath, TEXT("\\\\"));
StringCchCat(szUNCPath, cchUNCPath, szComputerName);
//
// If the first part of lpFile is the expanded value of %SystemRoot%
//
if (FAILED(SafeExpandEnvironmentStrings (TEXT("%SystemRoot%"), szSysRoot, MAX_PATH))) {
DebugMsg((DM_WARNING, TEXT("MakePathUNC: ExpandEnvironmentString failed with error %d, setting szSysRoot to %systemroot% "), GetLastError()));
LocalFree(szUNCPath);
return NULL;
}
dwSysLen = lstrlen(szSysRoot);
lpEnd = CheckSlashEx(szUNCPath, cchUNCPath, &cchEnd);
//
// if the prefix is the same as expanded systemroot then..
//
if (((DWORD)lstrlen(pwszFile) > dwSysLen) &&
(CompareString (LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
szSysRoot, dwSysLen,
pwszFile, dwSysLen) == CSTR_EQUAL)) {
StringCchCat(szUNCPath, cchUNCPath, TEXT("admin$"));
StringCchCat(szUNCPath, cchUNCPath, pwszFile+dwSysLen);
}
else {
if (pwszFile[1] != TEXT(':')) {
DebugMsg((DM_WARNING, TEXT("MakePathUNC: Input path %s is not an absolute path"), pwszFile));
StringCchCat(szUNCPath, cchUNCPath, pwszFile);
return szUNCPath;
}
if (cchEnd > 2)
{
lpEnd[0] = pwszFile[0];
lpEnd[1] = TEXT('$');
lpEnd[2] = TEXT('\0');
StringCchCat(szUNCPath, cchUNCPath, pwszFile+2);
}
}
DebugMsg((DM_VERBOSE, TEXT("MakePathUNC: Returning a UNCPath of %s"), szUNCPath));
return szUNCPath;
}
//*************************************************************
//
// SupportLongFileName()
//
// Purpose: Prepends lpDir with \\?\UNC\ or \\?\ depending on
// whether lpDir is a UNC path or local path. Before
// prepending this function converts relative path or
// absolute path started with a slash to corresponding
// absolute path containing drive letter.
//
// Parameters: lpDir - Directory
// lpWrkDirSize - Size of the returned buffer in unit
// of TCHAR
//
// Return: LPTSTR pointing to prepended dir/file
// NULL if fail to allocate memory
//
// Comments: Prepending with \\?\UNC\ or \\?\ allows all file api's
// to handle file name > MAX_PATH.
//
// History: Date Author Comment
// 8/8/00 santanuc Created
//
//*************************************************************
LPTSTR SupportLongFileName (LPTSTR lpDir, LPDWORD lpWrkDirSize)
{
LPTSTR lpWrkDir = NULL;
*lpWrkDirSize = lstrlen(lpDir)+2*MAX_PATH;
lpWrkDir = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)**lpWrkDirSize);
if (!lpWrkDir) {
DebugMsg((DM_WARNING, TEXT("EnableLongFileNameDeletion: Failed to Allocate memory. Error = %d"),
GetLastError()));
return NULL;
}
if ( IsUNCPath(lpDir) ) {
// lpDir is of the form \\computername\...
StringCchCopy(lpWrkDir, *lpWrkDirSize, c_szUNCFilePrefix);
StringCchCat(lpWrkDir, *lpWrkDirSize, lpDir+2);
}
else if ( *CharNext(lpDir) == TEXT(':') ) {
// Local storage specified with drive name
StringCchCopy(lpWrkDir, *lpWrkDirSize, c_szLocalFilePrefix);
StringCchCat(lpWrkDir, *lpWrkDirSize, lpDir);
}
else if ( *lpDir == TEXT('\\') ) {
DWORD dwSize;
// Prepend lpDir with c_szLocalFilePrefix followed by current drive as DeleteFile function requires
// drive name to delete files from local storage with path name > MAX_PATH
StringCchCopy(lpWrkDir, *lpWrkDirSize, c_szLocalFilePrefix);
dwSize = GetCurrentDirectory(*lpWrkDirSize-c_dwLocalFilePrefixLen, lpWrkDir+c_dwLocalFilePrefixLen);
if (dwSize == 0) {
DebugMsg((DM_VERBOSE, TEXT("DelNode: GetCurrentDirectory failed with error %d"), GetLastError()));
// proceed to delete lpDir without long file name deletion feature
StringCchCopy(lpWrkDir, *lpWrkDirSize, lpDir);
}
else {
if (dwSize > *lpWrkDirSize-c_dwLocalFilePrefixLen) {
// Extend lpWrkDir to accomodate current directory name with drive
LocalFree(lpWrkDir);
*lpWrkDirSize = dwSize+c_dwLocalFilePrefixLen;
lpWrkDir = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)**lpWrkDirSize);
if (!lpWrkDir) {
DebugMsg((DM_WARNING, TEXT("Delnode: Failed to Allocate memory. Error = %d"), GetLastError()));
return NULL;
}
StringCchCopy(lpWrkDir, *lpWrkDirSize, c_szLocalFilePrefix);
dwSize = GetCurrentDirectory(*lpWrkDirSize-c_dwLocalFilePrefixLen, lpWrkDir+c_dwLocalFilePrefixLen);
if (dwSize == 0 || dwSize > *lpWrkDirSize-c_dwLocalFilePrefixLen) {
DebugMsg((DM_VERBOSE, TEXT("DelNode: GetCurrentDirectory 2nd call failed with error %d"), GetLastError()));
// proceed to delete lpDir without long file name deletion feature
StringCchCopy(lpWrkDir, *lpWrkDirSize, lpDir);
}
else {
// Copy lpDir after c_szLocalFilePrefix and drive name
StringCchCopy(lpWrkDir+c_dwLocalFilePrefixLen+2, *lpWrkDirSize-c_dwLocalFilePrefixLen-2, lpDir);
}
}
else {
// Copy lpDir after c_szLocalFilePrefix and drive name
StringCchCopy(lpWrkDir+c_dwLocalFilePrefixLen+2, *lpWrkDirSize-c_dwLocalFilePrefixLen-2, lpDir);
}
}
}
else {
LPTSTR szFileName;
DWORD dwSize;
// Relative path name specified. So Prepend lpDir with c_szLocalFilePrefix followed by the current directory
StringCchCopy(lpWrkDir, *lpWrkDirSize, c_szLocalFilePrefix);
dwSize = GetFullPathName(lpDir, *lpWrkDirSize-c_dwLocalFilePrefixLen, lpWrkDir+c_dwLocalFilePrefixLen, &szFileName);
if ( dwSize == 0 ) {
DebugMsg((DM_VERBOSE, TEXT("DelNode: GetFullPathName failed with error %d"), GetLastError()));
// proceed to delete lpDir without long file name deletion feature
StringCchCopy(lpWrkDir, *lpWrkDirSize, lpDir);
}
else {
if ( dwSize > *lpWrkDirSize-c_dwLocalFilePrefixLen ) {
// Extend lpWrkDir to accomodate absolute path name
LocalFree(lpWrkDir);
*lpWrkDirSize = dwSize+2*MAX_PATH;
lpWrkDir = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)**lpWrkDirSize);
if (!lpWrkDir) {
DebugMsg((DM_WARNING, TEXT("Delnode: Failed to Allocate memory. Error = %d"), GetLastError()));
return NULL;
}
StringCchCopy(lpWrkDir, *lpWrkDirSize, c_szLocalFilePrefix);
dwSize = GetFullPathName(lpDir, *lpWrkDirSize-c_dwLocalFilePrefixLen, lpWrkDir+c_dwLocalFilePrefixLen, &szFileName);
if (dwSize == 0 || dwSize > *lpWrkDirSize-c_dwLocalFilePrefixLen) {
DebugMsg((DM_VERBOSE, TEXT("DelNode: GetFullPathName 2nd call failed with error %d"), GetLastError()));
// proceed to delete lpDir without long file name deletion feature
StringCchCopy(lpWrkDir, *lpWrkDirSize, lpDir);
}
}
}
}
return lpWrkDir;
}
//*************************************************************
//
// SecureNestedDir_Recurse()
//
// Purpose: Recursive function for securing nested dirs/files
//
// Parameters: lpDir - Full Directory Path.
// dwSize - Allocated size of the working buffer
// pDirSd - Security descriptor to be applied with dirs
// pFileSd - Security descriptor to be applied with files
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
//
//
//*************************************************************
BOOL SecureNestedDir_Recurse (LPTSTR lpDir, DWORD dwSize, PSECURITY_DESCRIPTOR pDirSd, PSECURITY_DESCRIPTOR pFileSd)
{
BOOL bOwn = FALSE, bRetVal = FALSE;
LPTSTR lpEnd = NULL, lpWrkDir = NULL;
WIN32_FIND_DATA *pfd = NULL;
HANDLE hFile;
DWORD dwWrkDirSize;
DWORD cchEnd;
//
// Verbose output
//
DebugMsg((DM_VERBOSE, TEXT("SecureNestedDir_Recurse: Entering, lpDir = <%s>"), lpDir));
//
// Each filename or a directory has to be less than MAX_PATH in the worst case.
// So make sure that we have at least MAX_PATH + 2 (for a slash and '\0'
// space left in the working buffer case.
//
// In the normal case, when we have a path of length ~MAX_PATH it will do only
// 1 allocation
//
if ((DWORD)(lstrlen(lpDir) + MAX_PATH+2) > (dwSize)) {
dwWrkDirSize = dwSize+2*MAX_PATH;
lpWrkDir = (LPWSTR)LocalAlloc(LPTR, dwWrkDirSize*sizeof(TCHAR));
if (!lpWrkDir) {
DebugMsg((DM_WARNING, TEXT("SecureNestedDir_Recurse: Couldn't allocate memory for working buffer. Error - %d"), GetLastError()));
goto Exit;
}
StringCchCopy(lpWrkDir, dwWrkDirSize, lpDir);
bOwn = TRUE;
}
else {
lpWrkDir = lpDir;
dwWrkDirSize = dwSize;
}
//
// Allocate WIN32_FIND_DATA in the heap to save stack space
//
pfd = (WIN32_FIND_DATA*) LocalAlloc (LPTR, sizeof(WIN32_FIND_DATA));
if (!pfd)
{
DebugMsg((DM_WARNING, TEXT("SecureNestedDir_Recurse: Couldn't allocate memory for WIN32_FIND_DATA. Error - %d"), GetLastError()));
goto Exit;
}
//
// Attach a Slash the end if required
//
lpEnd = CheckSlashEx(lpWrkDir, dwWrkDirSize, &cchEnd);
StringCchCopy(lpEnd, cchEnd, c_szStarDotStar);
//
// Find the first file
//
hFile = FindFirstFile(lpWrkDir, pfd);
if (hFile == INVALID_HANDLE_VALUE) {
if ((GetLastError() == ERROR_FILE_NOT_FOUND) || (GetLastError() == ERROR_PATH_NOT_FOUND)) {
bRetVal = TRUE;
goto Exit;
} else {
DebugMsg((DM_WARNING, TEXT("SecureNestedDir_Recurse: FindFirstFile failed. Error = %d"),
GetLastError()));
goto Exit;
}
}
do {
//
// Verbose output
//
DebugMsg((DM_VERBOSE, TEXT("SecureNestedDir_Recurse: FindFile found: <%s>"), pfd->cFileName));
//
// Check for "." and ".."
//
if (!lstrcmpi(pfd->cFileName, c_szDot)) {
continue;
}
if (!lstrcmpi(pfd->cFileName, c_szDotDot)) {
continue;
}
StringCchCopy(lpEnd, cchEnd, pfd->cFileName);
if (pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
//
// Check for reparse point, don't recurse into it.
//
if (pfd->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
DebugMsg((DM_WARNING, TEXT("SecureNestedDir_Recurse: a reparse point was found: <%s>, will not recurse into it."), lpWrkDir));
}
else
{
SecureNestedDir_Recurse(lpWrkDir, dwWrkDirSize, pDirSd, pFileSd);
//
// ignore errors and go ahead..
//
StringCchCopy(lpEnd, cchEnd, pfd->cFileName);
}
if (!SetFileSecurity (lpWrkDir, DACL_SECURITY_INFORMATION, pDirSd)) {
DebugMsg((DM_WARNING, TEXT("SecureNestedDir_Recurse: Failed to secure directory <%s>. Error = %d"),
lpWrkDir, GetLastError()));
}
} else {
//
// We found a file. Try to secure it
//
if (!SetFileSecurity (lpWrkDir, DACL_SECURITY_INFORMATION, pFileSd)) {
DebugMsg((DM_WARNING, TEXT("SecureNestedDir_Recurse: Failed to secure file <%s>. Error = %d"),
pfd->cFileName, GetLastError()));
}
}
//
// Find the next entry
//
} while (FindNextFile(hFile, pfd));
//
// Close the search handle
//
FindClose(hFile);
//
// Success.
//
DebugMsg((DM_VERBOSE, TEXT("SecureNestedDir_Recurse: Leaving <%s>"), lpDir));
bRetVal = TRUE;
Exit:
if (pfd)
LocalFree(pfd);
if (bOwn)
LocalFree(lpWrkDir);
return bRetVal;
}
//*************************************************************
//
// SecureNestedDir()
//
// Purpose: Secure the dir and nested dirs(files) with input
// SECURITY_DESCRIPTOR.
//
// Parameters: lpDir - Directory
// pDirSd - Security descriptor to be applied with dirs.
// pFileSd - Security descriptor to be applied with files.
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// History: Date Author Comment
// 8/8/00 santanuc Created
//
//*************************************************************
BOOL SecureNestedDir (LPTSTR lpDir, PSECURITY_DESCRIPTOR pDirSd, PSECURITY_DESCRIPTOR pFileSd)
{
LPTSTR lpWrkDir = NULL;
DWORD dwWrkDirSize;
BOOL bRetVal = FALSE;
lpWrkDir = SupportLongFileName(lpDir, &dwWrkDirSize);
if (!lpWrkDir) {
DebugMsg((DM_WARNING, TEXT("SecureNestedDir: Failed to Allocate memory. Error = %d"),
GetLastError()));
goto Exit;
}
if (!SecureNestedDir_Recurse (lpWrkDir, dwWrkDirSize, pDirSd, pFileSd)) {
DebugMsg((DM_WARNING, TEXT("SecureNestedDir: SecureNestedDir recurse failed with error %d"),
GetLastError()));
}
if (!SetFileSecurity (lpDir, DACL_SECURITY_INFORMATION, pDirSd)) {
DebugMsg((DM_WARNING, TEXT("SecureNestedDir: SetFileSecurity failed. Error = %d"), GetLastError()));
goto Exit;
}
bRetVal = TRUE;
DebugMsg((DM_VERBOSE, TEXT("SecureNestedDir: Secure directory <%s> successfully."), lpDir));
Exit:
if (lpWrkDir) {
LocalFree(lpWrkDir);
}
return bRetVal;
}
//*************************************************************
//
// SetEnvironmentVariableInBlock()
//
// Purpose: Sets the environment variable in the given block
//
// Parameters: pEnv - Environment block
// lpVariable - Variables
// lpValue - Value
// bOverwrite - Overwrite
//
//
// Return: TRUE if successful
// FALSE if an error occurs
//
// Comments:
//
// History: Date Author Comment
// 6/21/96 ericflo Ported
//
//*************************************************************
BOOL SetEnvironmentVariableInBlock(PVOID *pEnv, LPTSTR lpVariable,
LPTSTR lpValue, BOOL bOverwrite)
{
NTSTATUS Status;
UNICODE_STRING Name, Value;
DWORD cb;
LPTSTR szValue = NULL;
if (!*pEnv || !lpVariable || !*lpVariable) {
return(FALSE);
}
RtlInitUnicodeString(&Name, lpVariable);
cb = 1025 * sizeof(WCHAR);
Value.Buffer = LocalAlloc(LPTR, cb);
if (Value.Buffer) {
Value.Length = 0;
Value.MaximumLength = (USHORT)cb;
Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value);
LocalFree(Value.Buffer);
if ( NT_SUCCESS(Status) && !bOverwrite) {
return(TRUE);
}
}
szValue = (LPTSTR)LocalAlloc(LPTR, 1024*sizeof(TCHAR));
if (!szValue) {
DebugMsg((DM_WARNING, TEXT("SetEnvironmentVariableInBlock: Out of memory")));
return FALSE;
}
if (lpValue && *lpValue) {
//
// Special case TEMP and TMP and shorten the path names
//
if ( CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpVariable, -1, TEXT("TEMP"), -1) == CSTR_EQUAL ||
CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpVariable, -1, TEXT("TMP") , -1) == CSTR_EQUAL ) {
DWORD dwLength = GetShortPathName (lpValue, szValue, 1024);
if (!dwLength || dwLength > 1024) {
StringCchCopy (szValue, 1024, lpValue);
}
} else {
StringCchCopy (szValue, 1024, lpValue);
}
RtlInitUnicodeString(&Value, szValue);
Status = RtlSetEnvironmentVariable(pEnv, &Name, &Value);
}
else {
Status = RtlSetEnvironmentVariable(pEnv, &Name, NULL);
}
LocalFree(szValue);
if (NT_SUCCESS(Status)) {
return(TRUE);
}
return(FALSE);
}
/***************************************************************************\
* ExpandUserEvironmentVariable
*
*
* History:
* 2-28-92 Johannec Created
*
\***************************************************************************/
DWORD
ExpandUserEnvironmentStrings(
PVOID pEnv,
LPCTSTR lpSrc,
LPTSTR lpDst,
DWORD nSize
)
{
NTSTATUS Status;
UNICODE_STRING Source, Destination;
ULONG Length;
RtlInitUnicodeString( &Source, lpSrc );
Destination.Buffer = lpDst;
Destination.Length = 0;
Destination.MaximumLength = (USHORT)(nSize*sizeof(WCHAR));
Length = 0;
Status = RtlExpandEnvironmentStrings_U( pEnv,
(PUNICODE_STRING)&Source,
(PUNICODE_STRING)&Destination,
&Length
);
if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_TOO_SMALL) {
return( Length / sizeof(WCHAR) );
}
else {
return( 0 );
}
}
//*************************************************************
//
// ConvertToShareName()
//
// Purpose: Convert the UNC path of a file\dir to a share
//
// Parameters: lpShare : Full UNC path of file\dir
//
// Return: None.
//
// Comments:
//
// History: Date Author Comment
// 8/21/00 santanuc Created
//
//*************************************************************
LPTSTR ConvertToShareName(LPTSTR lpShare)
{
BOOL bShareName = FALSE;
lpShare += 2; // Skip initial two slashes
while ((!bShareName || *lpShare != TEXT('\\')) && *lpShare != TEXT('\0')) {
if (*lpShare == TEXT('\\'))
bShareName = TRUE;
lpShare++;
}
if (*lpShare == TEXT('\\')) {
*lpShare = TEXT('\0');
return lpShare+1;
}
return NULL;
}
//*************************************************************
//
// AbleToBypassCSC()
//
// Purpose: Try to bypass CSC using a secret api.
//
// Parameters: hTokenUser - User's token
// lpDir - Roaming profile dir
// lppCscBypassedPath - Path name with mapped drive (OUT)
// cpDrive - Mapped drive (OUT)
//
// Return: ERROR_SUCCESS if successful
// Error code if an error occurs
//
// Comments: We will always bypass csc for roaming share.
// There are two reason behind this :
// o csc mark entire server offline even if only
// one share goes offline. This is a bad design
// from csc perspective and they need to fix it
// o If csc is turned on in the roaming share server
// then both csc and profile will try to sync files
// on top of one another and we will be in a inconsistent
// state
//
// History: Date Author Comment
// 10/29/00 santanuc Created
//
//*************************************************************
DWORD AbleToBypassCSC(HANDLE hTokenUser, LPCTSTR lpDir, LPTSTR *lppCscBypassedPath, TCHAR *cpDrive)
{
NETRESOURCE sNR;
LPTSTR lpShare = NULL;
BOOL bIsDfsConnect = FALSE, bRetValue = FALSE;
DWORD dwFlags = 0, dwError;
HANDLE hOldToken;
WIN32_FIND_DATA fd;
HANDLE hResult;
LPTSTR lpFileName;
BOOL bImpersonated = FALSE;
DWORD cchShare;
DWORD cchCscBypassedPath;
DebugMsg((DM_VERBOSE, TEXT("AbleToBypassCSC: Try to bypass CSC")));
if (!lpDir || !IsUNCPath(lpDir) || !lppCscBypassedPath || !cpDrive) {
return ERROR_INVALID_PARAMETER; // Invalid argument
}
// Initialize
*lppCscBypassedPath = NULL;
memset(&sNR, 0, sizeof(NETRESOURCE));
if (!ImpersonateUser(hTokenUser, &hOldToken)) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("AbleToBypassCSC: Failed to impersonate user with %d."), dwError));
goto Exit;
}
bImpersonated = TRUE;
//
// Construct the roaming share name
//
cchShare = lstrlen(lpDir) + 1;
lpShare = (LPTSTR)LocalAlloc(LPTR, cchShare * sizeof(TCHAR));
if (!lpShare) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("AbleToBypassCSC: Failed to allocate memory")));
goto Exit;
}
StringCchCopy(lpShare, cchShare, lpDir);
lpFileName = ConvertToShareName(lpShare);
cchCscBypassedPath = lstrlen(lpDir)+1;
*lppCscBypassedPath = (LPTSTR)LocalAlloc(LPTR, cchCscBypassedPath * sizeof(TCHAR));
if (!*lppCscBypassedPath) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("AbleToBypassCSC: Failed to allocate memory")));
goto Exit;
}
//
// Initialize NETRESOURCE structure
//
sNR.dwType = RESOURCETYPE_DISK;
sNR.lpRemoteName = lpShare;
sNR.lpLocalName = (LPTSTR)LocalAlloc(LPTR, 3 * sizeof(TCHAR));
if (!sNR.lpLocalName) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("AbleToBypassCSC: Failed to allocate memory")));
goto Exit;
}
sNR.lpLocalName[0] = TEXT('E');
sNR.lpLocalName[1] = TEXT(':');
sNR.lpLocalName[2] = TEXT('\0');
do{
__try {
dwError = NPAddConnection3ForCSCAgent(NULL, &sNR, NULL, NULL, dwFlags, &bIsDfsConnect);
DebugMsg((DM_VERBOSE, TEXT("AbleToBypassCSC: tried NPAddConnection3ForCSCAgent. Error %d"), dwError));
}
__except(EXCEPTION_EXECUTE_HANDLER) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("AbleToBypassCSC: Took exception in NPAddConnection3ForCSCAgent. Error %d"), dwError));
}
if (dwError == WN_SUCCESS || dwError == WN_CONNECTED_OTHER_PASSWORD ||
dwError == WN_CONNECTED_OTHER_PASSWORD_DEFAULT){
dwError = ERROR_SUCCESS;
break;
}
if (sNR.lpLocalName[0]==TEXT('Z')) {
goto Exit;
}
else if ((dwError == WN_BAD_LOCALNAME) || (dwError == WN_ALREADY_CONNECTED)){
++sNR.lpLocalName[0];
continue;
}
else{
if (GetNetworkProvider(&sNR) == ERROR_BAD_PROVIDER) {
dwError = ERROR_BAD_PROVIDER;
}
goto Exit;
}
}while (TRUE);
// Succesfully bypassed CSC. Do not modify dwError in this part.
bRetValue = TRUE;
*cpDrive = sNR.lpLocalName[0];
StringCchCopy(*lppCscBypassedPath, cchCscBypassedPath, sNR.lpLocalName);
StringCchCat(*lppCscBypassedPath, cchCscBypassedPath, TEXT("\\"));
if (lpFileName)
{
StringCchCat(*lppCscBypassedPath, cchCscBypassedPath, lpFileName);
}
DebugMsg((DM_VERBOSE, TEXT("AbleToBypassCSC: Share %s mapped to drive %c. Returned Path %s"), lpShare, sNR.lpLocalName[0], *lppCscBypassedPath));
Exit:
if (lpShare) {
LocalFree(lpShare);
}
if (!bRetValue && *lppCscBypassedPath) {
LocalFree(*lppCscBypassedPath);
*lppCscBypassedPath = NULL;
}
if (sNR.lpLocalName) {
LocalFree(sNR.lpLocalName);
}
if (bImpersonated) {
RevertToUser(&hOldToken);
}
return dwError;
}
//*************************************************************
//
// CancelCSCBypassedConnection()
//
// Purpose: Release the mapped drive.
//
// Parameters: hTokenUser - User's token
// cDrive - Drive letter to unmap
//
// Return: None
//
// Comments: We will always bypass csc for roaming share.
// There are two reason behind this :
// o csc mark entire server offline even if only
// one share goes offline. This is a bad design
// from csc perspective and they need to fix it
// o If csc is turned on in the roaming share server
// then both csc and profile will try to sync files
// on top of one another and we will be in a inconsistent
// state
//
// History: Date Author Comment
// 10/29/00 santanuc Created
//
//*************************************************************
void CancelCSCBypassedConnection(HANDLE hTokenUser, TCHAR cDrive)
{
DWORD dwError;
TCHAR szDrive[3];
HANDLE hOldToken;
if (!ImpersonateUser(hTokenUser, &hOldToken)) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("CancelCSCBypassedConnection: Failed to impersonate user with %d."), dwError));
return ;
}
szDrive[0] = cDrive;
szDrive[1] = TEXT(':');
szDrive[2] = TEXT('\0');
DebugMsg((DM_VERBOSE, TEXT("CancelCSCBypassedConnection: Cancelling connection of %s"), szDrive));
__try {
dwError = NPCancelConnectionForCSCAgent(szDrive, TRUE);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
dwError = GetLastError();
DebugMsg((DM_WARNING, TEXT("CancelCSCBypassedConnection: Took exception in NPCancelConnectionForCSCAgent. Error %d"), dwError));
}
if (dwError != WN_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("CancelCSCBypassedConnection: Fail to delete connection. Error returned %d"), dwError));
}
else {
DebugMsg((DM_VERBOSE, TEXT("CancelCSCBypassedConnection: Connection deleted.")));
}
RevertToUser(&hOldToken);
}
//*************************************************************
//
// GetNetworkProvider()
//
// Purpose: Determine network provider for a share
//
// Parameters:
//
// Return: DWORD
//
// Comments: Returns ERROR_BAD_PROVIDER if provider is other
// than microsoft SMB provider otherwise return
// NO_ERROR.
//
// History: Date Author Comment
// 03/08/01 santanuc Created
//
//*************************************************************
DWORD GetNetworkProvider(NETRESOURCE *psNR)
{
PFNWNETGETRESOURCEINFORMATION pfnWNetGetResourceInformation;
HMODULE hWNetLib = NULL;
NETRESOURCE dNR;
LPBYTE pbBuffer = (LPBYTE)&dNR;
DWORD cbBuffer = sizeof(dNR);
DWORD dwError = NO_ERROR;
LPTSTR lpSystem = NULL;
TCHAR szSMBProvider[100];
HKEY hKeyProvider = NULL;
DWORD dwSize, dwType;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_PROVIDER,
0, KEY_READ, &hKeyProvider) != ERROR_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetNetworkProvider: Failed to open network provider key. Error %d"), GetLastError()));
goto Exit;
}
dwSize = ARRAYSIZE(szSMBProvider);
if (RegQueryValueEx(hKeyProvider,
PROVIDER_NAME,
NULL,
&dwType,
(LPBYTE) szSMBProvider,
&dwSize) != ERROR_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetNetworkProvider: Failed to get network provider name. Error %d"), GetLastError()));
goto Exit;
}
if (!(hWNetLib = LoadLibrary(TEXT("mpr.dll")))) {
DebugMsg((DM_WARNING, TEXT("GetNetworkProvider: LoadLibrary failed with %d"), GetLastError()));
goto Exit;
}
pfnWNetGetResourceInformation = (PFNWNETGETRESOURCEINFORMATION)GetProcAddress(hWNetLib, "WNetGetResourceInformationW");
if (!pfnWNetGetResourceInformation) {
DebugMsg((DM_WARNING, TEXT("GetNetworkProvider: GetProcAddress failed with %d"), GetLastError()));
goto Exit;
}
dwError = (*pfnWNetGetResourceInformation)(psNR, pbBuffer, &cbBuffer, &lpSystem);
if (ERROR_MORE_DATA == dwError) {
pbBuffer = LocalAlloc(LPTR, cbBuffer);
if (!pbBuffer) {
DebugMsg((DM_WARNING, TEXT("AbleToBypassCSC: Failed to impersonate user with %d."), GetLastError()));
goto Exit;
}
dwError = (*pfnWNetGetResourceInformation)(psNR, pbBuffer, &cbBuffer, &lpSystem);
}
if (NO_ERROR == dwError) {
if (lstrcmpi(((NETRESOURCE *)pbBuffer)->lpProvider, szSMBProvider) != 0) {
dwError = ERROR_BAD_PROVIDER;
goto Exit;
}
}
dwError = NO_ERROR;
Exit:
if (hKeyProvider) {
RegCloseKey(hKeyProvider);
}
if (pbBuffer && (pbBuffer != (LPBYTE)&dNR)) {
LocalFree(pbBuffer);
}
if (hWNetLib) {
FreeLibrary(hWNetLib);
}
return dwError;
}
//*************************************************************
//
// GetUserNameFromSid()
//
// Purpose: Returns the user name in domain\user format
//
// Parameters: lpSidString - User's sid string
//
// Return: LPTSTR : domain\user name if succeeds
// lpSidString if fails
//
// Comments:
//
// History: Date Author Comment
// 10/31/00 santanuc Created
//
//*************************************************************
LPTSTR GetUserNameFromSid(LPTSTR lpSidString)
{
PSID pSidUser = NULL;
LPTSTR lpRetVal = lpSidString;
TCHAR szUserName[MAX_PATH], szDomainName[MAX_PATH];
DWORD dwUserSize = MAX_PATH, dwDomainSize = MAX_PATH;
SID_NAME_USE TypeOfAccount;
DWORD cchRetVal;
//
// Get the user sid
//
if (AllocateAndInitSidFromString(lpSidString, &pSidUser) != STATUS_SUCCESS) {
DebugMsg((DM_WARNING, TEXT("GetUserNameFromSid: Failed to create user sid.")));
goto Exit;
}
//
// Get the user and domain name
//
if (!LookupAccountSid(NULL, pSidUser, szUserName, &dwUserSize, szDomainName, &dwDomainSize, &TypeOfAccount)) {
DebugMsg((DM_WARNING, TEXT("GetUserNameFromSid: LookupAccountSid failed with error %d."), GetLastError()));
goto Exit;
}
cchRetVal = lstrlen(szUserName) + lstrlen(szDomainName) + 2;
lpRetVal = (LPTSTR)LocalAlloc(LPTR, cchRetVal * sizeof(TCHAR));
if (!lpRetVal) {
DebugMsg((DM_WARNING, TEXT("GetUserNameFromSid: Memory alloaction failure. error %d"), GetLastError()));
lpRetVal = lpSidString;
goto Exit;
}
// Construct the return string
StringCchCopy(lpRetVal, cchRetVal, szDomainName);
StringCchCat(lpRetVal, cchRetVal, TEXT("\\"));
StringCchCat(lpRetVal, cchRetVal, szUserName);
Exit:
if (pSidUser) {
LocalFree(pSidUser);
}
return lpRetVal;
}
//*************************************************************
//
// TakeOwnership()
//
// Purpose: Take ownership of a file or directory
//
// Parameters: lpFileName - file or directory name to work on
//
// Return: S_OK for success, else for error
//
// Comments:
//
// History: Date Author Comment
// 04/08/2002 mingzhu Created
//
//*************************************************************
HRESULT TakeOwnership(LPTSTR lpFileName)
{
HRESULT hr = E_FAIL;
DWORD dwErr;
PSID pSID = NULL;
NTSTATUS status;
BOOLEAN bTakeOwnerWasEnabled;
BOOL bTakeOwnerEnabled = FALSE;
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
//
// Output a debug message
//
DebugMsg((DM_VERBOSE, TEXT("TakeOwnership : Taking ownership of %s ..."), lpFileName));
//
// Enable SE_TAKE_OWNERSHIP_NAME priviledge
//
status = RtlAdjustPrivilege(SE_TAKE_OWNERSHIP_PRIVILEGE, TRUE, FALSE, &bTakeOwnerWasEnabled);
if(!NT_SUCCESS(status))
{
hr = HRESULT_FROM_WIN32(RtlNtStatusToDosError(status));
DebugMsg((DM_WARNING, TEXT("TakeOwnership: RtlAdjustPrivilege failed, error = %08x"), hr));
goto Exit;
}
//
// Create a SID for the BUILTIN\Administrators group.
//
if (!AllocateAndInitializeSid(&SIDAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &pSID))
{
hr = HRESULT_FROM_WIN32(GetLastError());
DebugMsg((DM_WARNING, TEXT("TakeOwnership: AllocateAndInitializeSid failed, error = %08x"), hr));
goto Exit;
}
//
// Set the owner in the object's security descriptor.
//
dwErr = SetNamedSecurityInfo(lpFileName, // name of the object
SE_FILE_OBJECT, // type of object
OWNER_SECURITY_INFORMATION, // change only the object's owner
pSID, // SID of Administrator group
NULL, NULL, NULL);
if (dwErr != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwErr);
DebugMsg((DM_WARNING, TEXT("TakeOwnership: SetNamedSecurityInfo failed, error = %08x"), hr));
goto Exit;
}
//
// We're done!
//
DebugMsg((DM_VERBOSE, TEXT("TakeOwnership : Success!")));
hr = S_OK;
Exit:
if (bTakeOwnerEnabled && !bTakeOwnerWasEnabled)
{
status = RtlAdjustPrivilege(SE_TAKE_OWNERSHIP_PRIVILEGE, FALSE, FALSE, &bTakeOwnerWasEnabled);
if(!NT_SUCCESS(status))
{
DebugMsg((DM_WARNING, TEXT("TakeOwnership: RtlAdjustPrivilege failed, error = %08x"), status));
}
}
if (pSID)
{
FreeSid(pSID);
}
return hr;
}
//*************************************************************
//
// AddAdminAccess()
//
// Purpose: Add administrators full access to a file or directory
//
// Parameters: lpFileName - file or directory name to work on
//
// Return: S_OK for success, else for error
//
// Comments:
//
// History: Date Author Comment
// 04/08/2002 mingzhu Created
//
//*************************************************************
HRESULT AddAdminAccess(LPTSTR lpFileName)
{
HRESULT hr = E_FAIL;
DWORD dwErr;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pOldDACL = NULL;
PACL pNewDACL = NULL;
EXPLICIT_ACCESS ea;
//
// Output a debug message
//
DebugMsg((DM_VERBOSE, TEXT("AddAdminAccess : Adding administrators access to %s."), lpFileName));
//
// Get the old DACL in the file.
//
dwErr = GetNamedSecurityInfo(lpFileName, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // change only the object's owner
NULL, NULL, &pOldDACL, NULL, // DACL to get
&pSD); // Security Descriptor of the file
if (dwErr != ERROR_SUCCESS)
{
DebugMsg((DM_WARNING, TEXT("AddAdminAccess : GetNamedSecurityInfo failed with %d"), dwErr));
hr = HRESULT_FROM_WIN32(dwErr);
goto Exit;
}
//
// Initialize an EXPLICIT_ACCESS structure for the new ACE (admin full access).
//
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = FILE_ALL_ACCESS;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT;
ea.Trustee.pMultipleTrustee = NULL;
ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea.Trustee.ptstrName = TEXT("Administrators");
//
// Create a new ACL that merges the new ACE into the existing DACL.
//
dwErr = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
if (ERROR_SUCCESS != dwErr)
{
DebugMsg((DM_WARNING, TEXT("AddAdminAccess : SetEntriesInAcl failed. Error = %d"), dwErr));
hr = HRESULT_FROM_WIN32(dwErr);
goto Exit;
}
//
// Set the owner in the object's security descriptor.
//
dwErr = SetNamedSecurityInfo(lpFileName, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // change only the object's owner
NULL, NULL, pNewDACL, NULL); // DACL to be set
if (dwErr != ERROR_SUCCESS)
{
DebugMsg((DM_WARNING, TEXT("AddAdminAccess : SetNamedSecurityInfo failed with %d"), dwErr));
hr = HRESULT_FROM_WIN32(dwErr);
goto Exit;
}
//
// We're done!
//
DebugMsg((DM_VERBOSE, TEXT("AddAdminAccess : Success!")));
hr = S_OK;
Exit:
if(pNewDACL != NULL)
LocalFree(pNewDACL);
if(pSD != NULL)
LocalFree(pSD);
return hr;
}
//*************************************************************
//
// Routine Description:
//
// This routine determines if we're doing a gui-mode setup.
//
// This value is retrieved from the following registry location:
//
// \HKLM\System\Setup\
//
// SystemSetupInProgress : REG_DWORD : 0x00 (where nonzero
// means we're doing a gui-setup)
//
// Arguments:
//
// None.
//
// Return Value:
//
// TRUE/FALSE
//
// Note:
//
// This function is courtesy of Andrew Ritz and the Setup API.
// It's copied over from base\pnp\setupapi\dll.c.
//
//***************************************************************
BOOL IsGuiSetupInProgress()
{
HKEY hKey;
DWORD Err, DataType, DataSize = sizeof(DWORD);
DWORD Value;
if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
0,
KEY_READ,
&hKey)) == ERROR_SUCCESS) {
//
// Attempt to read the the "DriverCachePath" value.
//
Err = RegQueryValueEx(
hKey,
TEXT("SystemSetupInProgress"),
NULL,
&DataType,
(LPBYTE)&Value,
&DataSize);
RegCloseKey(hKey);
}
if(Err == NO_ERROR) {
if(Value) {
return(TRUE);
}
}
return(FALSE);
}
//*************************************************************
//
// Description:
//
// This function will setup a new key under the ProfileList\{sid}
// entry and give the specified user write permittion to it in order
// to change his/her preference.
//
// Arguments:
//
// lpSidString - String format of the sid indicate which entry we will work on.
//
// Return Value:
//
// S_OK for success, else for failure
//
// Note:
//
// History: Date Author Comment
// 04/19/2002 mingzhu Created
//
//***************************************************************
HRESULT SetupPreferenceKey(LPCTSTR lpSidString)
{
HRESULT hr = E_FAIL;
LONG lResult;
DWORD dwResult;
TCHAR szKeyName[MAX_PATH];
HKEY hKey = NULL;
PSID psidUser = NULL;
PACL pOldDACL = NULL;
PACL pNewDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea;
DebugMsg((DM_VERBOSE, TEXT("SetupPreferenceKey: Setting up the preference key for <%s>"), lpSidString));
//
// Construct the key name
//
hr = StringCchPrintf(szKeyName,
ARRAYSIZE(szKeyName),
TEXT("%s\\%s\\%s"),
PROFILE_LIST_PATH,
lpSidString,
PREFERENCE_KEYNAME);
if (FAILED(hr))
{
DebugMsg((DM_WARNING, TEXT("SetupPreferenceKey: Failed to make key name, hr = %08X"), hr));
goto Exit;
}
//
// Create the "Preference" key, using default security (inherited)
//
lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
szKeyName,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL);
if (lResult != ERROR_SUCCESS)
{
DebugMsg((DM_WARNING, TEXT("SetupPreferenceKey: RegCreateKeyEx failed. Error = %d"), lResult));
hr = HRESULT_FROM_WIN32(lResult);
goto Exit;
}
//
// Get the user's sid from its string form
//
if (!ConvertStringSidToSid(lpSidString, &psidUser))
{
dwResult = GetLastError();
DebugMsg((DM_WARNING, TEXT("SetupPreferenceKey: ConvertStringSidToSid failed. Error = %d"), dwResult));
hr = HRESULT_FROM_WIN32(dwResult);
goto Exit;
}
//
// Get a pointer to the existing DACL and its SD
//
dwResult = GetSecurityInfo(hKey,
SE_REGISTRY_KEY,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&pOldDACL,
NULL,
&pSD);
if (dwResult != ERROR_SUCCESS)
{
DebugMsg((DM_WARNING, TEXT("SetupPreferenceKey: GetSecurityInfo failed. Error = %d"), dwResult));
hr = HRESULT_FROM_WIN32(dwResult);
goto Exit;
}
//
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
//
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = KEY_READ | KEY_SET_VALUE;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = psidUser;
//
// Create a new ACL that merges the new ACE into the existing DACL.
//
dwResult = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
if (dwResult != ERROR_SUCCESS)
{
DebugMsg((DM_WARNING, TEXT("SetupPreferenceKey: SetEntriesInAcl failed. Error = %d"), dwResult));
hr = HRESULT_FROM_WIN32(dwResult);
goto Exit;
}
//
// Attach the new ACL to the key
//
dwResult = SetSecurityInfo(hKey,
SE_REGISTRY_KEY,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
pNewDACL,
NULL);
if (dwResult != ERROR_SUCCESS)
{
DebugMsg((DM_WARNING, TEXT("SetupPreferenceKey: SetSecurityInfo failed. Error = %d"), dwResult));
hr = HRESULT_FROM_WIN32(dwResult);
goto Exit;
}
DebugMsg((DM_VERBOSE, TEXT("SetupPreferenceKey: Successfully setup the preference key for <%s>"), lpSidString));
hr = S_OK;
Exit:
if(pSD)
LocalFree(pSD);
if(pNewDACL)
LocalFree(pNewDACL);
if (psidUser)
LocalFree(psidUser);
if (hKey)
RegCloseKey(hKey);
return hr;
}