//************************************************************* // // Utility functions // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1995 // All rights reserved // //************************************************************* #include "uenv.h" #include #include #include #include #include #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 // 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\$ // // 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; }