diff options
Diffstat (limited to 'private/windows/gina/userenv')
45 files changed, 17899 insertions, 0 deletions
diff --git a/private/windows/gina/userenv/copydir.c b/private/windows/gina/userenv/copydir.c new file mode 100644 index 000000000..8d1965cc6 --- /dev/null +++ b/private/windows/gina/userenv/copydir.c @@ -0,0 +1,1241 @@ +//************************************************************* +// +// Functions to copy the profile directory +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + +// +// Local function proto-types +// + +BOOL RecurseDirectory (LPTSTR lpSrcDir, LPTSTR lpDestDir, DWORD dwFlags, + LPFILEINFO *llSrcDirs, LPFILEINFO *llSrcFiles); +BOOL AddFileInfoNode (LPFILEINFO *lpFileInfo, LPTSTR lpSrcFile, + LPTSTR lpDestFile, LPFILETIME ftFileTime, + DWORD dwFileSize, DWORD dwFileAttribs); +BOOL FreeFileInfoList (LPFILEINFO lpFileInfo); +BOOL SyncItems (LPFILEINFO lpSrcItems, LPFILEINFO lpDestItems, BOOL bFile); +void CopyFileFunc (LPTHREADINFO lpThreadInfo); + +//************************************************************* +// +// CopyProfileDirectory() +// +// Purpose: Copies the profile directory from the source +// to the destination +// +// +// Parameters: LPTSTR lpSourceDir - Source directory +// LPTSTR lpDestDir - Destination directory +// DWORD dwFlags - Flags +// +// +// Return: (BOOL) TRUE if successful +// FALSE if an error occurs +// +// +// Comments: +// +// +// History: Date Author Comment +// 5/24/95 ericflo Created +// +//************************************************************* + +BOOL CopyProfileDirectory (LPCTSTR lpSourceDir, LPCTSTR lpDestinationDir, + DWORD dwFlags) +{ + LPTSTR lpSrcDir = NULL, lpDestDir = NULL; + LPTSTR lpSrcEnd, lpDestEnd; + LPFILEINFO lpSrcFiles = NULL, lpDestFiles = NULL; + LPFILEINFO lpSrcDirs = NULL, lpDestDirs = NULL; + LPFILEINFO lpTemp; + CRITICAL_SECTION Crit; + THREADINFO ThreadInfo; + DWORD dwThreadId; + HANDLE hThreads[NUM_COPY_THREADS]; + DWORD dwThreadCount = 0; + HANDLE hFile; + WIN32_FIND_DATA fd; + BOOL bResult = FALSE; + BOOL bSynchronize = FALSE; + UINT uiResult; + UINT i; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: Entering, lpSourceDir = <%s>, lpDestinationDir = <%s>, dwFlags = 0x%x"), + lpSourceDir, lpDestinationDir, dwFlags)); + + + // + // Validate parameters + // + + if (!lpSourceDir || !lpDestinationDir) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: received NULL pointer"))); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + // + // Is this a full sync copy (delete extra files / directories in dest). + // + + if (dwFlags & CPD_SYNCHRONIZE) { + bSynchronize = TRUE; + } + + + // + // Test / Create the destination directory + // + + if (!CreateNestedDirectory(lpDestinationDir, NULL)) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: Failed to create the destination directory. Error = %d"), + GetLastError())); + return FALSE; + } + + + // + // Create and set up the directory buffers + // + + lpSrcDir = LocalAlloc(LPTR, (2 * MAX_PATH) * sizeof(TCHAR)); + lpDestDir = LocalAlloc(LPTR, (2 * MAX_PATH) * sizeof(TCHAR)); + + if (!lpSrcDir || !lpDestDir) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: Failed to allocate memory for working directories"))); + goto Exit; + } + + + lstrcpy (lpSrcDir, lpSourceDir); + lstrcpy (lpDestDir, lpDestinationDir); + + + // + // Setup ending pointers + // + + lpSrcEnd = CheckSlash (lpSrcDir); + lpDestEnd = CheckSlash (lpDestDir); + + + + // + // Step 1: Loop through the shell folders gathering info + // + + if (dwFlags & CPD_USESPECIALFOLDERS) { + + // + // If the caller wants to use the special folders + // only, then loop through all of the known special + // folders only coping those directories and files. + // + // Notes: + // 1) no files in the root will be copied + // 2) This does work for internation profiles + // since the directories names will be in one + // language and userenv.dll will be in another + // 3) Setup is the only known component using this + // flag (to upgrade Win95 machines). + // + + for (i=0; i < NUM_TIER1_FOLDERS; i++) { + + // + // Setup the source and dest pointers + // + + lstrcpy (lpSrcEnd, c_ShellFolders[i].lpFolderLocation); + lstrcpy (lpDestEnd, c_ShellFolders[i].lpFolderLocation); + + + // + // Test if the directory exists + // + + hFile = FindFirstFile(lpSrcDir, &fd); + + if (hFile != INVALID_HANDLE_VALUE) { + + + FindClose (hFile); + + + // + // Add to the list of directories + // + + if (!AddFileInfoNode (&lpSrcDirs, lpSrcDir, lpDestDir, NULL, 0, fd.dwFileAttributes)) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: AddFileInfoNode failed"))); + goto Exit; + } + + + // + // Recurse the source directory + // + + bResult = RecurseDirectory(lpSrcDir, lpDestDir, dwFlags, + &lpSrcDirs, &lpSrcFiles); + + if (!bResult) { + DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: RecurseDirectory returned FALSE"))); + } + + + if (bSynchronize) { + + // + // Recurse the destination directory + // + + bResult = RecurseDirectory(lpDestDir, lpSrcDir, dwFlags, + &lpDestDirs, &lpDestFiles); + + if (!bResult) { + DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: RecurseDirectory returned FALSE"))); + } + } + } + } + } else { + + // + // This version will copy every file / directory found + // in the profile directory except for ntuser.* files + // which will be handled below. + // + + // + // Setup the source and dest pointers + // + + lstrcpy (lpSrcEnd, c_szStarDotStar); + + + // + // Look for files/directories + // + + hFile = FindFirstFile(lpSrcDir, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + goto Exit; + } + + + do { + + // + // Append the file / directory name to the working buffers + // + + lstrcpy (lpSrcEnd, fd.cFileName); + lstrcpy (lpDestEnd, fd.cFileName); + + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + + + // + // Check for "." and ".." + // + + if (!lstrcmpi(fd.cFileName, c_szDot)) { + continue; + } + + if (!lstrcmpi(fd.cFileName, c_szDotDot)) { + continue; + } + + + // + // Add to the list of directories + // + + if (!AddFileInfoNode (&lpSrcDirs, lpSrcDir, lpDestDir, NULL, 0, fd.dwFileAttributes)) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: AddFileInfoNode failed"))); + FindClose (hFile); + goto Exit; + } + + + // + // Recurse the source directory + // + + bResult = RecurseDirectory(lpSrcDir, lpDestDir, dwFlags, + &lpSrcDirs, &lpSrcFiles); + + if (!bResult) { + DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: RecurseDirectory returned FALSE"))); + } + + + if (bSynchronize) { + + // + // Recurse the destination directory + // + + bResult = RecurseDirectory(lpDestDir, lpSrcDir, dwFlags, + &lpDestDirs, &lpDestFiles); + + if (!bResult) { + DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: RecurseDirectory returned FALSE"))); + } + } + } else { + + // + // If the filename found starts with "ntuser", then ignore + // it because the hive will be copied below (if appropriate). + // + + if (lstrlen(fd.cFileName) >= 6) { + if (CompareString (LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, + fd.cFileName, 6, + TEXT("ntuser"), 6) == 2) { + continue; + } + } + + + // + // We found a file. Add it to the list. + // + + if (!AddFileInfoNode (&lpSrcFiles, lpSrcDir, lpDestDir, + &fd.ftLastWriteTime, fd.nFileSizeLow, + fd.dwFileAttributes)) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirctory: AddFileInfoNode failed"))); + FindClose (hFile); + goto Exit; + } + + } + + // + // Find the next entry + // + + } while (FindNextFile(hFile, &fd)); + + FindClose (hFile); + } + + + + // + // Step 2: Create all the directories + // + + lpTemp = lpSrcDirs; + + while (lpTemp) { + + uiResult = CreateNestedDirectory(lpTemp->szDest, NULL); + + if (!uiResult) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: Failed to create the destination directory <%s>. Error = %d"), + lpTemp->szDest, GetLastError())); + goto Exit; + } + + + if (uiResult == ERROR_ALREADY_EXISTS) { + lpTemp->dwFlags |= FI_DIREXISTED; + + } else { + + // + // We created the directory. Set the attributes and security + // + + SetFileAttributes (lpTemp->szDest, lpTemp->dwFileAttribs); + + } + + + lpTemp = lpTemp->pNext; + } + + + // + // Step 3: Copy the files + // + + if (dwFlags & CPD_SLOWCOPY) { + + // + // Copy the files one at a time... + // + + lpTemp = lpSrcFiles; + + while (lpTemp) { + + if (!ReconcileFile (lpTemp->szSrc, lpTemp->szDest, dwFlags, + &lpTemp->ftSrc)) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: Failed to create the destination directory <%s>. Error = %d"), + lpTemp->szDest, GetLastError())); + goto Exit; + } + + lpTemp = lpTemp->pNext; + } + + } else { + + if (lpSrcFiles) { + + HANDLE hThreadToken; + + + if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE, + TRUE, &hThreadToken)) { + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_IMPERSONATE, + &hThreadToken)) { + goto Exit; + } + } + + + // + // Multi-threaded copy + // + + InitializeCriticalSection (&Crit); + + ThreadInfo.dwFlags = dwFlags; + ThreadInfo.lpCrit = &Crit; + ThreadInfo.lpSrcFiles = lpSrcFiles; + + // + // Create the file copy threads + // + + for (i = 0; i < NUM_COPY_THREADS; i++) { + if (hThreads[dwThreadCount] = CreateThread (NULL, + 0, + (LPTHREAD_START_ROUTINE) CopyFileFunc, + (LPVOID) &ThreadInfo, + CREATE_SUSPENDED, + &dwThreadId)) { + + SetThreadToken(&hThreads[dwThreadCount], hThreadToken); + ResumeThread (hThreads[dwThreadCount]); + dwThreadCount++; + } + } + + // + // Wait for the threads to finish + // + + if (WaitForMultipleObjects (dwThreadCount, hThreads, TRUE, INFINITE) == WAIT_FAILED) { + for (i = 0; i < dwThreadCount; i++) { + TerminateThread (hThreads[i], 1); + } + } + + // + // Clean up + // + + CloseHandle (hThreadToken); + + for (i = 0; i < dwThreadCount; i++) { + CloseHandle (hThreads[i]); + } + + DeleteCriticalSection (&Crit); + } + } + + + + // + // Step 4: Copy the actual hive and log file + // + + if (!(dwFlags & CPD_IGNOREHIVE)) { + + + // + // Search for all user hives + // + + if (dwFlags & CPD_WIN95HIVE) { + + lstrcpy (lpSrcEnd, c_szUserStar); + + } else { + + lstrcpy (lpSrcEnd, c_szNTUserStar); + + } + + + // + // Enumerate + // + + hFile = FindFirstFile(lpSrcDir, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: FindFirstFile failed to find a hive!. Error = %d"), + GetLastError())); + goto Exit; + } + + + do { + + // + // Setup the filename + // + + lstrcpy (lpSrcEnd, fd.cFileName); + lstrcpy (lpDestEnd, fd.cFileName); + + + // + // Copy the hive + // + + if (!ReconcileFile(lpSrcDir, lpDestDir, dwFlags, NULL)) { + DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: ReconcileFile failed with error = %d"), + GetLastError())); + if (!(dwFlags & CPD_IGNORECOPYERRORS)) { + FindClose(hFile); + goto Exit; + } + } + + + // + // Find the next entry + // + + } while (FindNextFile(hFile, &fd)); + + + FindClose(hFile); + } + + // + // Step 5: Synchronize the directories and files if appropriate + // + + if (bSynchronize) { + + // + // Files first... + // + + SyncItems (lpSrcFiles, lpDestFiles, TRUE); + + // + // Now the directories... + // + + SyncItems (lpSrcDirs, lpDestDirs, FALSE); + } + + + // + // Success + // + + bResult = TRUE; + + +Exit: + + + // + // Free the memory allocated above + // + + if (lpSrcDir) { + LocalFree(lpSrcDir); + } + + if (lpDestDir) { + LocalFree(lpDestDir); + } + + if (lpSrcFiles) { + FreeFileInfoList(lpSrcFiles); + } + + if (lpDestFiles) { + FreeFileInfoList(lpDestFiles); + } + + if (lpSrcDirs) { + FreeFileInfoList(lpSrcDirs); + } + + if (lpDestDirs) { + FreeFileInfoList(lpDestDirs); + } + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: Leaving with a return value of %d"), bResult)); + + return bResult; +} + +//************************************************************* +// +// RecurseDirectory() +// +// Purpose: Recurses through the subdirectory coping files. +// +// Parameters: lpSrcDir - Source directory working buffer +// lpDestDir - Destination directory working buffer +// dwFlags - dwFlags +// llSrcDirs - Link list of directories +// llSrcFiles - Link list of files +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: 1) The source and dest directories will already have +// the trailing backslash when entering this function. +// 2) The current working directory is the source directory. +// +// History: Date Author Comment +// 5/25/95 ericflo Created +// +//************************************************************* + +BOOL RecurseDirectory (LPTSTR lpSrcDir, LPTSTR lpDestDir, DWORD dwFlags, + LPFILEINFO *llSrcDirs, LPFILEINFO *llSrcFiles) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + WIN32_FIND_DATA fd; + LPTSTR lpSrcEnd, lpDestEnd; + BOOL bResult = TRUE; + + + // + // Setup the ending pointers + // + + lpSrcEnd = CheckSlash (lpSrcDir); + lpDestEnd = CheckSlash (lpDestDir); + + + // + // Append *.* to the source directory + // + + lstrcpy(lpSrcEnd, c_szStarDotStar); + + + + // + // Search through the source directory + // + + hFile = FindFirstFile(lpSrcDir, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + + if ( (GetLastError() == ERROR_FILE_NOT_FOUND) || + (GetLastError() == ERROR_PATH_NOT_FOUND) ) { + + // + // bResult is already initialized to TRUE, so + // just fall through. + // + + } else { + DebugMsg((DM_WARNING, TEXT("RecurseDirectory: FindFirstFile failed. Error = %d"), + GetLastError())); + + bResult = FALSE; + } + + goto RecurseDir_Exit; + } + + + do { + + // + // Append the file / directory name to the working buffers + // + + lstrcpy (lpSrcEnd, fd.cFileName); + lstrcpy (lpDestEnd, fd.cFileName); + + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + + // + // Check for "." and ".." + // + + if (!lstrcmpi(fd.cFileName, c_szDot)) { + continue; + } + + if (!lstrcmpi(fd.cFileName, c_szDotDot)) { + continue; + } + + + // + // Found a directory. + // + // 1) Change into that subdirectory on the source drive. + // 2) Recurse down that tree. + // 3) Back up one level. + // + + // + // Add to the list of directories + // + + if (!AddFileInfoNode (llSrcDirs, lpSrcDir, lpDestDir, NULL, 0, fd.dwFileAttributes)) { + DebugMsg((DM_WARNING, TEXT("RecurseDirectory: AddFileInfoNode failed"))); + goto RecurseDir_Exit; + } + + + // + // Recurse the subdirectory + // + + if (!RecurseDirectory(lpSrcDir, lpDestDir, dwFlags, + llSrcDirs, llSrcFiles)) { + DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: RecurseDirectory returned FALSE"))); + bResult = FALSE; + goto RecurseDir_Exit; + } + + } else { + + // + // We found a file. Add it to the list. + // + + if (!AddFileInfoNode (llSrcFiles, lpSrcDir, lpDestDir, + &fd.ftLastWriteTime, fd.nFileSizeLow, + fd.dwFileAttributes)) { + DebugMsg((DM_WARNING, TEXT("RecurseDirectory: AddFileInfoNode failed"))); + goto RecurseDir_Exit; + } + + } + + + // + // Find the next entry + // + + } while (FindNextFile(hFile, &fd)); + + +RecurseDir_Exit: + + // + // Remove the file / directory name appended above + // + + *lpSrcEnd = TEXT('\0'); + *lpDestEnd = TEXT('\0'); + + + // + // Close the search handle + // + + if (hFile != INVALID_HANDLE_VALUE) { + FindClose(hFile); + } + + return bResult; +} + +//************************************************************* +// +// ReconcileFile() +// +// Purpose: Compares the source and destination file. +// If the source is newer, then it is copied +// over the destination. +// +// Parameters: lpSrcFile - source filename +// lpDestFile - destination filename +// dwFlags - flags +// ftSrcTime - Src file time (can be NULL) +// +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 5/25/95 ericflo Created +// +//************************************************************* + +BOOL ReconcileFile (LPTSTR lpSrcFile, LPTSTR lpDestFile, + DWORD dwFlags, LPFILETIME ftSrcTime) +{ + HANDLE hFile; + FILETIME ftWriteSrc, ftWriteDest; + BOOL bCopyFile = FALSE; + + + + // + // If the flags have CPD_FORCECOPY, then skip to the + // copy file call without checking the timestamps. + // + + if (!(dwFlags & CPD_FORCECOPY)) { + + + // + // If we were given a source file time, use that + // + + if (ftSrcTime) { + ftWriteSrc.dwLowDateTime = ftSrcTime->dwLowDateTime; + ftWriteSrc.dwHighDateTime = ftSrcTime->dwHighDateTime; + + } else { + + + // + // Attempt to open the source file + // + + hFile = CreateFile(lpSrcFile, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) { + DebugMsg((DM_WARNING, TEXT("ReconcileFile: CreateFile on the source failed with error = %d"), + GetLastError())); + return FALSE; + } + + if (!GetFileTime(hFile, NULL, NULL, &ftWriteSrc)) { + DebugMsg((DM_WARNING, TEXT("ReconcileFile: GetFileTime on the source failed with error = %d"), + GetLastError())); + CloseHandle(hFile); + return FALSE; + } + + CloseHandle(hFile); + } + + + // + // Attempt to open the destination file + // + + hFile = CreateFile(lpDestFile, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) { + DWORD dwError; + + // + // CreateFile failed to open the destination + // file. If the last error is file not found + // then we automaticly will copy the file. + // + + dwError = GetLastError(); + + if (dwError == ERROR_FILE_NOT_FOUND) { + + bCopyFile = TRUE; + + } else { + + // + // CreateFile failed with some other error + // + + DebugMsg((DM_WARNING, TEXT("ReconcileFile: CreateFile on the destination failed with error = %d"), + dwError)); + return FALSE; + } + + } else { + + // + // The destination file exists. Query for the + // last write time. + // + + if (!GetFileTime(hFile, NULL, NULL, &ftWriteDest)) { + DebugMsg((DM_WARNING, TEXT("ReconcileFile: GetFileTime on the destination failed with error = %d"), + GetLastError())); + CloseHandle(hFile); + return FALSE; + } + + CloseHandle(hFile); + } + + } else { + + // + // The CPD_FORCECOPY flag is turned on, set bCopyFile to TRUE. + // + + bCopyFile = TRUE; + } + + + // + // If bCopyFile is still false, then we need to compare + // the last write time stamps. + // + + if (!bCopyFile) { + LONG lResult; + + // + // If the source is later than the destination + // we need to copy the file. + // + + lResult = CompareFileTime(&ftWriteSrc, &ftWriteDest); + + if (lResult == 1) { + bCopyFile = TRUE; + } + + if ( (dwFlags & CPD_COPYIFDIFFERENT) && (lResult == -1) ) { + bCopyFile = TRUE; + } + } + + + // + // Copy the file if appropriate + // + + if (bCopyFile) { + + SetFileAttributes (lpDestFile, FILE_ATTRIBUTE_NORMAL); + if (!CopyFile(lpSrcFile, lpDestFile, FALSE)) { + DebugMsg((DM_WARNING, TEXT("ReconcileFile: %s ==> %s [FAILED!!!]"), + lpSrcFile, lpDestFile)); + + DebugMsg((DM_WARNING, TEXT("ReconcileFile: CopyFile failed with error = %d"), + GetLastError())); + + if (!(dwFlags & CPD_IGNORECOPYERRORS)) { + return FALSE; + } + } else { + DebugMsg((DM_VERBOSE, TEXT("ReconcileFile: %s ==> %s [OK]"), + lpSrcFile, lpDestFile)); + } + } + + + return TRUE; +} + +//************************************************************* +// +// AddFileInfoNode() +// +// Purpose: Adds a node to the linklist of files +// +// Parameters: lpFileInfo - Link list to add to +// lpSrcFile - Source filename +// lpDestFile - Destination filename +// ftFileTime - Source time stamp +// dwFileSize - Size of the file +// dwFileAttribs - File attributes +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 9/28/95 ericflo Created +// +//************************************************************* + +BOOL AddFileInfoNode (LPFILEINFO *lpFileInfo, LPTSTR lpSrcFile, + LPTSTR lpDestFile, LPFILETIME ftFileTime, + DWORD dwFileSize, DWORD dwFileAttribs) +{ + LPFILEINFO lpNode; + + + lpNode = (LPFILEINFO) LocalAlloc(LPTR, sizeof(FILEINFO)); + + if (!lpNode) { + return FALSE; + } + + + lstrcpy (lpNode->szSrc, lpSrcFile); + lstrcpy (lpNode->szDest, lpDestFile); + + if (ftFileTime) { + lpNode->ftSrc.dwLowDateTime = ftFileTime->dwLowDateTime; + lpNode->ftSrc.dwHighDateTime = ftFileTime->dwHighDateTime; + } + + lpNode->dwFileSize = dwFileSize; + lpNode->dwFileAttribs = (dwFileAttribs & ~FILE_ATTRIBUTE_DIRECTORY); + + lpNode->pNext = *lpFileInfo; + + *lpFileInfo = lpNode; + + return TRUE; + +} + +//************************************************************* +// +// FreeFileInfoList() +// +// Purpose: Free's a file info link list +// +// Parameters: lpFileInfo - List to be freed +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 9/28/95 ericflo Created +// +//************************************************************* + +BOOL FreeFileInfoList (LPFILEINFO lpFileInfo) +{ + LPFILEINFO lpNext; + + + if (!lpFileInfo) { + return TRUE; + } + + + lpNext = lpFileInfo->pNext; + + while (lpFileInfo) { + LocalFree (lpFileInfo); + lpFileInfo = lpNext; + + if (lpFileInfo) { + lpNext = lpFileInfo->pNext; + } + } + + return TRUE; +} + +//************************************************************* +// +// SyncItems() +// +// Purpose: Removes unnecessary items from the destination +// directory tree +// +// Parameters: lpSrcItems - Link list of source items +// lpDestItems - Link list of dest items +// bFile - File or directory list +// +// Return: TRUE if successful +// FALSE if an error occurs +// Comments: +// +// History: Date Author Comment +// 9/28/95 ericflo Created +// +//************************************************************* + +BOOL SyncItems (LPFILEINFO lpSrcItems, LPFILEINFO lpDestItems, + BOOL bFile) +{ + LPFILEINFO lpTempSrc, lpTempDest; + + + // + // Check for NULL pointers + // + + if (!lpSrcItems || !lpDestItems) { + return TRUE; + } + + + // + // Loop through everyitem in lpDestItems to see if it + // is in lpSrcItems. If not, delete it. + // + + lpTempDest = lpDestItems; + + while (lpTempDest) { + + lpTempSrc = lpSrcItems; + + while (lpTempSrc) { + + if (lstrcmpi(lpTempDest->szSrc, lpTempSrc->szDest) == 0) { + break; + } + + lpTempSrc = lpTempSrc->pNext; + } + + // + // If lpTempSrc is NULL, then delete the extra file/directory + // + + if (!lpTempSrc) { + + DebugMsg((DM_VERBOSE, TEXT("SyncItems: removing <%s>"), + lpTempDest->szSrc)); + + + if (bFile) { + SetFileAttributes(lpTempDest->szSrc, FILE_ATTRIBUTE_NORMAL); + if (!DeleteFile (lpTempDest->szSrc)) { + DebugMsg((DM_WARNING, TEXT("SyncItems: Failed to delete <%s>. Error = %d."), + lpTempDest->szSrc, GetLastError())); + } + + } else { + SetFileAttributes(lpTempDest->szSrc, FILE_ATTRIBUTE_NORMAL); + if (!RemoveDirectory (lpTempDest->szSrc)) { + DebugMsg((DM_WARNING, TEXT("SyncItems: Failed to remove <%s>. Error = %d"), + lpTempDest->szSrc, GetLastError())); + } + + } + } + + lpTempDest = lpTempDest->pNext; + } + + return TRUE; + +} + +//************************************************************* +// +// CopyFileFunc() +// +// Purpose: Copies files +// +// Parameters: lpThreadInfo - Thread information +// +// Return: void +// +// Comments: +// +// History: Date Author Comment +// 2/23/96 ericflo Created +// +//************************************************************* + +void CopyFileFunc (LPTHREADINFO lpThreadInfo) +{ + HANDLE hInstDll; + LPFILEINFO lpSrcFile; + BOOL bRetVal = TRUE; + + + hInstDll = LoadLibrary (TEXT("userenv.dll")); + + + while (TRUE) { + + // + // Query for the next file to copy + // + + EnterCriticalSection(lpThreadInfo->lpCrit); + + lpSrcFile = lpThreadInfo->lpSrcFiles; + + if (lpSrcFile) { + lpThreadInfo->lpSrcFiles = lpThreadInfo->lpSrcFiles->pNext; + } + + LeaveCriticalSection(lpThreadInfo->lpCrit); + + + // + // If NULL, then we're finished. + // + + if (!lpSrcFile) { + break; + } + + + // + // Copy the file + // + + if (!ReconcileFile (lpSrcFile->szSrc, lpSrcFile->szDest, + lpThreadInfo->dwFlags, &lpSrcFile->ftSrc)) { + bRetVal = FALSE; + } + } + + + // + // Clean up + // + + if (hInstDll) { + FreeLibraryAndExitThread(hInstDll, bRetVal); + } else { + ExitThread (bRetVal); + } +} diff --git a/private/windows/gina/userenv/copydir.h b/private/windows/gina/userenv/copydir.h new file mode 100644 index 000000000..6d1b1fbab --- /dev/null +++ b/private/windows/gina/userenv/copydir.h @@ -0,0 +1,50 @@ +//************************************************************* +// +// Header file for copydir.c +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + + +// +// FILEINFO flags +// + +#define FI_DIREXISTED 0x00000001 + + +// +// File copy structure +// + +typedef struct _FILEINFO { + DWORD dwFlags; + TCHAR szSrc[MAX_PATH]; + TCHAR szDest[MAX_PATH]; + FILETIME ftSrc; + DWORD dwFileSize; + DWORD dwFileAttribs; + struct _FILEINFO *pNext; +} FILEINFO, * LPFILEINFO; + + +#define NUM_COPY_THREADS 7 + +// +// ThreadInfo structure +// + +typedef struct _THREADINFO { + DWORD dwFlags; + LPCRITICAL_SECTION lpCrit; + LPFILEINFO lpSrcFiles; +} THREADINFO, * LPTHREADINFO; + + + + +BOOL ReconcileFile (LPTSTR lpSrcFile, LPTSTR lpDestFile, + DWORD dwFlags, LPFILETIME ftSrcTime); diff --git a/private/windows/gina/userenv/debug.c b/private/windows/gina/userenv/debug.c new file mode 100644 index 000000000..a4207dcf4 --- /dev/null +++ b/private/windows/gina/userenv/debug.c @@ -0,0 +1,226 @@ +//************************************************************* +// +// Debugging functions +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + +#if DBG + +// +// Global Variable containing the debugging level. +// + +DWORD dwDebugLevel; + +// +// Debug strings +// + +const TCHAR c_szUserEnv[] = TEXT("USERENV: "); +const TCHAR c_szCRLF[] = TEXT("\r\n"); + + +// +// Registry debug information +// + +#define DEBUG_REG_LOCATION TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon") +#define DEBUG_KEY_NAME TEXT("UserEnvDebugLevel") + +//************************************************************* +// +// InitDebugSupport() +// +// Purpose: Sets the debugging level. +// Also checks the registry for a debugging level. +// +// Parameters: None +// +// Return: void +// +// Comments: +// +// +// History: Date Author Comment +// 5/25/95 ericflo Created +// +//************************************************************* + +void InitDebugSupport(void) +{ + LONG lResult; + HKEY hKey; + DWORD dwType, dwSize; + + // + // Initialize the debug level to normal + // + + dwDebugLevel = DL_NORMAL; + + + // + // Check the registry + // + + lResult = RegOpenKey (HKEY_LOCAL_MACHINE, DEBUG_REG_LOCATION, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + dwSize = sizeof(dwDebugLevel); + RegQueryValueEx(hKey, DEBUG_KEY_NAME, NULL, &dwType, + (LPBYTE)&dwDebugLevel, &dwSize); + + RegCloseKey(hKey); + } +} + +//************************************************************* +// +// DebugMsg() +// +// Purpose: Displays debug messages based on the debug level +// and type of debug message. +// +// Parameters: mask - debug message type +// pszMsg - debug message +// ... - variable number of parameters +// +// Return: void +// +// +// Comments: +// +// +// History: Date Author Comment +// 5/25/95 ericflo Created +// +//************************************************************* + +void _DebugMsg(UINT mask, LPCTSTR pszMsg, ...) +{ + BOOL bOutput; + TCHAR szDebugBuffer[2*MAX_PATH+40]; + va_list marker; + DWORD dwErrCode; + + + // + // Save the last error code (so the debug output doesn't change it). + // + + dwErrCode = GetLastError(); + + + // + // Detemerine the correct amount of debug output + // + + switch (LOWORD(dwDebugLevel)) { + + case DL_VERBOSE: + bOutput = TRUE; + break; + + case DL_NORMAL: + + // + // Normal debug output. Don't + // display verbose stuff, but + // do display warnings/asserts. + // + + if (mask != DM_VERBOSE) { + bOutput = TRUE; + } else { + bOutput = FALSE; + } + break; + + case DL_NONE: + default: + + // + // Only display asserts + // + + if (mask == DM_ASSERT) { + bOutput = TRUE; + } else { + bOutput = FALSE; + } + break; + } + + + // + // Display the error message if appropriate + // + + if (bOutput) { + va_start(marker, pszMsg); + wvsprintf(szDebugBuffer, pszMsg, marker); + OutputDebugString(c_szUserEnv); + OutputDebugString(szDebugBuffer); + OutputDebugString(c_szCRLF); + va_end(marker); + + if (dwDebugLevel & DL_LOGFILE) { + HANDLE hFile; + DWORD dwBytesWritten; + + hFile = CreateFile(TEXT("c:\\userenv.log"), + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile != INVALID_HANDLE_VALUE) { + + if (SetFilePointer (hFile, 0, NULL, FILE_END) != 0xFFFFFFFF) { + + WriteFile (hFile, (LPCVOID) szDebugBuffer, + lstrlen (szDebugBuffer) * sizeof(TCHAR), + &dwBytesWritten, + NULL); + + WriteFile (hFile, (LPCVOID) c_szCRLF, + lstrlen (c_szCRLF) * sizeof(TCHAR), + &dwBytesWritten, + NULL); + } + + CloseHandle (hFile); + } + + } + + } + + + // + // Restore the last error code + // + + SetLastError(dwErrCode); + + + // + // Break to the debugger if appropriate + // + + if (mask == DM_ASSERT) { + DebugBreak(); + } +} + +#endif // DBG diff --git a/private/windows/gina/userenv/debug.h b/private/windows/gina/userenv/debug.h new file mode 100644 index 000000000..32223782c --- /dev/null +++ b/private/windows/gina/userenv/debug.h @@ -0,0 +1,51 @@ +//************************************************************* +// +// Debugging functions header file +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#if DBG + +// +// Debug Levels +// + +#define DL_NONE 0x00000000 +#define DL_NORMAL 0x00000001 +#define DL_VERBOSE 0x00000002 +#define DL_LOGFILE 0x00010000 + + +// +// Debug message types +// + +#define DM_WARNING 0 +#define DM_ASSERT 1 +#define DM_VERBOSE 2 + + +// +// Debug macros +// + +#define DebugMsg(x) _DebugMsg x + + +// +// Debug function proto-types +// + +void _DebugMsg(UINT mask, LPCTSTR pszMsg, ...); +void InitDebugSupport(void); + +#else + +#define DebugMsg(x) + + +#endif // DBG diff --git a/private/windows/gina/userenv/envvar.c b/private/windows/gina/userenv/envvar.c new file mode 100644 index 000000000..5ce763f3a --- /dev/null +++ b/private/windows/gina/userenv/envvar.c @@ -0,0 +1,1404 @@ +//************************************************************* +// File name: envvar.c +// +// Description: Contains the environment variable functions +// +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1996 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + +// +// Max environment variable length +// + +#define MAX_VALUE_LEN 1024 + +// +// Environment variables +// + +#define COMPUTERNAME_VARIABLE TEXT("COMPUTERNAME") +#define HOMEDRIVE_VARIABLE TEXT("HOMEDRIVE") +#define HOMESHARE_VARIABLE TEXT("HOMESHARE") +#define HOMEPATH_VARIABLE TEXT("HOMEPATH") +#define SYSTEMDRIVE_VARIABLE TEXT("SystemDrive") +#define SYSTEMROOT_VARIABLE TEXT("SystemRoot") +#define USERNAME_VARIABLE TEXT("USERNAME") +#define USERDOMAIN_VARIABLE TEXT("USERDOMAIN") +#define USERPROFILE_VARIABLE TEXT("USERPROFILE") +#define PATH_VARIABLE TEXT("Path") +#define LIBPATH_VARIABLE TEXT("LibPath") +#define OS2LIBPATH_VARIABLE TEXT("Os2LibPath") +#define USER_ENV_SUBKEY TEXT("Environment") +#define USER_VOLATILE_ENV_SUBKEY TEXT("Volatile Environment") + +// +// Parsing information for autoexec.bat +// +#define AUTOEXECPATH_VARIABLE TEXT("AutoexecPath") +#define PARSE_AUTOEXEC_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon") +#define PARSE_AUTOEXEC_ENTRY TEXT("ParseAutoexec") +#define PARSE_AUTOEXEC_DEFAULT TEXT("1") +#define MAX_PARSE_AUTOEXEC_BUFFER 2 + + +#define SYS_ENVVARS TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Environment") + +BOOL UpdateSystemEnvironment(PVOID *pEnv); +BOOL SetEnvironmentVariableInBlock(PVOID *pEnv, LPTSTR lpVariable, LPTSTR lpValue, BOOL bOverwrite); +BOOL GetUserNameAndDomain(HANDLE hToken, LPTSTR *UserName, LPTSTR *UserDomain); +HKEY GetHKeyCU(HANDLE hToken); +BOOL ProcessAutoexec(PVOID *pEnv); +BOOL AppendNTPathWithAutoexecPath(PVOID *pEnv, LPTSTR lpPathVariable, LPTSTR lpAutoexecPath); +BOOL SetEnvironmentVariables(PVOID *pEnv, LPTSTR lpRegSubKey, HKEY hKeyCU); + + +//************************************************************* +// +// CreateEnvironmentBlock() +// +// Purpose: Creates the environment variables for the +// specificed hToken. If hToken is NULL, the +// environment block will only contain system +// variables. +// +// Parameters: pEnv - Receives the environment block +// hToken - User's token or NULL +// bInherit - Inherit the current process environment +// +// Return: TRUE if successful +// FALSE if not +// +// Comments: The pEnv value must be destroyed by +// calling DestroyEnvironmentBlock +// +// History: Date Author Comment +// 6/19/96 ericflo Created +// +//************************************************************* + +BOOL WINAPI CreateEnvironmentBlock (LPVOID *pEnv, HANDLE hToken, BOOL bInherit) +{ + TCHAR szBuffer[MAX_PATH+1]; + DWORD dwBufferSize = MAX_PATH+1; + NTSTATUS Status; + LPTSTR UserName = NULL; + LPTSTR UserDomain = NULL; + HKEY hKey, hKeyCU; + DWORD dwDisp, dwType; + TCHAR szParseAutoexec[MAX_PARSE_AUTOEXEC_BUFFER]; + + + Status = RtlCreateEnvironment((BOOLEAN)bInherit, pEnv); + if (!NT_SUCCESS(Status)) { + return FALSE; + } + + // + // First start by getting the systemroot and systemdrive values and + // setting it in the new environment. + // + + GetEnvironmentVariable(SYSTEMROOT_VARIABLE, szBuffer, dwBufferSize); + SetEnvironmentVariableInBlock(pEnv, SYSTEMROOT_VARIABLE, szBuffer, TRUE); + + GetEnvironmentVariable(SYSTEMDRIVE_VARIABLE, szBuffer, dwBufferSize); + SetEnvironmentVariableInBlock(pEnv, SYSTEMDRIVE_VARIABLE, szBuffer, TRUE); + + + // + // We must examine the registry directly to suck out + // the system environment variables, because they + // may have changed since the system was booted. + // + + if (!UpdateSystemEnvironment(pEnv)) { + RtlDestroyEnvironment(*pEnv); + return FALSE; + } + + + // + // Set the computername + // + + if (GetComputerName (szBuffer, &dwBufferSize)) { + SetEnvironmentVariableInBlock(pEnv, COMPUTERNAME_VARIABLE, szBuffer, TRUE); + } + + + // + // Set the default user profile location + // + + ExpandEnvironmentStrings (DEFAULT_PROFILE, szBuffer, MAX_PATH+1); + SetEnvironmentVariableInBlock(pEnv, USERPROFILE_VARIABLE, szBuffer, TRUE); + + + // + // If hToken is NULL, we can exit now since the caller only wants + // system environment variables. + // + + if (!hToken) { + return TRUE; + } + + + // + // Open the HKEY_CURRENT_USER for this token. + // + + hKeyCU = GetHKeyCU(hToken); + + if (!hKeyCU) { + RtlDestroyEnvironment(*pEnv); + DebugMsg((DM_WARNING, TEXT("CreateEnvironmentBlock: Failed to open HKEY_CURRENT_USER, error = %d"), + GetLastError())); + return FALSE; + } + + + // + // Set the user's name and domain. + // + + GetUserNameAndDomain(hToken, &UserName, &UserDomain); + SetEnvironmentVariableInBlock( pEnv, USERNAME_VARIABLE, UserName, TRUE); + SetEnvironmentVariableInBlock( pEnv, USERDOMAIN_VARIABLE, UserDomain, TRUE); + LocalFree(UserName); + LocalFree(UserDomain); + + + // + // Set the user's profile location. + // + + dwBufferSize = MAX_PATH + 1; + if (GetUserProfileDirectory(hToken, szBuffer, &dwBufferSize)) { + SetEnvironmentVariableInBlock(pEnv, USERPROFILE_VARIABLE, szBuffer, TRUE); + } + + + // + // Process autoexec.bat + // + + lstrcpy (szParseAutoexec, PARSE_AUTOEXEC_DEFAULT); + + if (RegCreateKeyEx (hKeyCU, PARSE_AUTOEXEC_KEY, 0, 0, + REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, + NULL, &hKey, &dwDisp) == ERROR_SUCCESS) { + + + // + // Query the current value. If it doesn't exist, then add + // the entry for next time. + // + + dwBufferSize = sizeof (TCHAR) * MAX_PARSE_AUTOEXEC_BUFFER; + if (RegQueryValueEx (hKey, PARSE_AUTOEXEC_ENTRY, NULL, &dwType, + (LPBYTE) szParseAutoexec, &dwBufferSize) + != ERROR_SUCCESS) { + + // + // Set the default value + // + + RegSetValueEx (hKey, PARSE_AUTOEXEC_ENTRY, 0, REG_SZ, + (LPBYTE) szParseAutoexec, + sizeof (TCHAR) * lstrlen (szParseAutoexec) + 1); + } + + // + // Close key + // + + RegCloseKey (hKey); + } + + + // + // Process autoexec if appropriate + // + + if (szParseAutoexec[0] == TEXT('1')) { + ProcessAutoexec(pEnv); + } + + + // + // Set User environment variables. + // + SetEnvironmentVariables(pEnv, USER_ENV_SUBKEY, hKeyCU); + + + // + // Set User volatile environment variables. + // + SetEnvironmentVariables(pEnv, USER_VOLATILE_ENV_SUBKEY, hKeyCU); + + + // + // Merge the paths + // + + AppendNTPathWithAutoexecPath(pEnv, PATH_VARIABLE, AUTOEXECPATH_VARIABLE); + + + RegCloseKey (hKeyCU); + + return TRUE; +} + + +//************************************************************* +// +// DestroyEnvironmentBlock() +// +// Purpose: Frees the environment block created by +// CreateEnvironmentBlock +// +// Parameters: lpEnvironment - Pointer to variables +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/19/96 ericflo Created +// +//************************************************************* + +BOOL WINAPI DestroyEnvironmentBlock (LPVOID lpEnvironment) +{ + + if (!lpEnvironment) { + return FALSE; + } + + RtlDestroyEnvironment(lpEnvironment); + + return TRUE; +} + + +//************************************************************* +// +// UpdateSystemEnvironment() +// +// Purpose: Reads the system environment variables from the +// registry. +// +// Parameters: pEnv - Environment block pointer +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/21/96 ericflo Ported +// +//************************************************************* + +BOOL UpdateSystemEnvironment(PVOID *pEnv) +{ + + HKEY KeyHandle; + DWORD Result; + DWORD ValueNameLength; + DWORD Type; + DWORD DataLength; + DWORD cValues; /* address of buffer for number of value identifiers */ + DWORD chMaxValueName; /* address of buffer for longest value name length */ + DWORD cbMaxValueData; /* address of buffer for longest value data length */ + DWORD junk; + FILETIME FileTime; + PTCHAR ValueName; + PTCHAR ValueData; + DWORD i; + BOOL Bool; + PTCHAR ExpandedValue; + BOOL rc = TRUE; + + DWORD ClassStringSize = MAX_PATH + 1; + TCHAR Class[MAX_PATH + 1]; + + Result = RegOpenKeyEx ( + HKEY_LOCAL_MACHINE, + SYS_ENVVARS, + 0, + KEY_QUERY_VALUE, + &KeyHandle + ); + + if ( Result != ERROR_SUCCESS ) { + + DebugMsg((DM_WARNING, TEXT("UpdateSystemEnvironment: RegOpenKeyEx failed, error = %d"),Result)); + return( FALSE ); + } + + Result = RegQueryInfoKey( + KeyHandle, + Class, /* address of buffer for class string */ + &ClassStringSize, /* address of size of class string buffer */ + NULL, /* reserved */ + &junk, /* address of buffer for number of subkeys */ + &junk, /* address of buffer for longest subkey */ + &junk, /* address of buffer for longest class string length */ + &cValues, /* address of buffer for number of value identifiers */ + &chMaxValueName, /* address of buffer for longest value name length */ + &cbMaxValueData, /* address of buffer for longest value data length */ + &junk, /* address of buffer for descriptor length */ + &FileTime /* address of buffer for last write time */ + ); + + if ( Result != NO_ERROR && Result != ERROR_MORE_DATA ) { + RegCloseKey(KeyHandle); + return( FALSE ); + } + + // + // No need to adjust the datalength for TCHAR issues + // + + ValueData = LocalAlloc(LPTR, cbMaxValueData); + + if ( ValueData == NULL ) { + RegCloseKey(KeyHandle); + return( FALSE ); + } + + // + // The maximum value name length comes back in characters, convert to bytes + // before allocating storage. Allow for trailing NULL also. + // + + ValueName = LocalAlloc(LPTR, (++chMaxValueName) * sizeof( TCHAR ) ); + + if ( ValueName == NULL ) { + + RegCloseKey(KeyHandle); + LocalFree( ValueData ); + return( FALSE ); + } + + // + // To exit from here on, set rc and jump to Cleanup + // + + for (i=0; i<cValues ; i++) { + + ValueNameLength = chMaxValueName; + DataLength = cbMaxValueData; + + Result = RegEnumValue ( + KeyHandle, + i, + ValueName, + &ValueNameLength, // Size in TCHARs + NULL, + &Type, + (LPBYTE)ValueData, + &DataLength // Size in bytes + ); + + if ( Result != ERROR_SUCCESS ) { + + // + // Problem getting the value. We can either try + // the rest or punt completely. + // + + rc = FALSE; + goto Cleanup; + } + + // + // If the buffer size is greater than the max allowed, + // terminate the string at MAX_VALUE_LEN - 1. + // + + if (DataLength >= (MAX_VALUE_LEN * sizeof(TCHAR))) { + ValueData[MAX_VALUE_LEN-1] = TEXT('\0'); + } + + switch ( Type ) { + case REG_SZ: + { + + Bool = SetEnvironmentVariableInBlock( + pEnv, + ValueName, + ValueData, + TRUE + ); + + if ( !Bool ) { + + // + // Not much to do here. + // + + rc = FALSE; + goto Cleanup; + } + + break; + } + default: + { + continue; + } + } + } + + // + // To exit from here on, set rc and jump to Cleanup + // + + for (i=0; i<cValues ; i++) { + + ValueNameLength = chMaxValueName; + DataLength = cbMaxValueData; + + Result = RegEnumValue ( + KeyHandle, + i, + ValueName, + &ValueNameLength, // Size in TCHARs + NULL, + &Type, + (LPBYTE)ValueData, + &DataLength // Size in bytes + ); + + if ( Result != ERROR_SUCCESS ) { + + // + // Problem getting the value. We can either try + // the rest or punt completely. + // + + rc = FALSE; + goto Cleanup; + } + + // + // If the buffer size is greater than the max allowed, + // terminate the string at MAX_VALUE_LEN - 1. + // + + if (DataLength >= (MAX_VALUE_LEN * sizeof(TCHAR))) { + ValueData[MAX_VALUE_LEN-1] = TEXT('\0'); + } + + switch ( Type ) { + case REG_EXPAND_SZ: + { + + ExpandedValue = AllocAndExpandEnvironmentStrings( ValueData ); + + Bool = SetEnvironmentVariableInBlock( + pEnv, + ValueName, + ExpandedValue, + TRUE + ); + + LocalFree( ExpandedValue ); + + if ( !Bool ) { + + // + // Not much to do here. + // + + rc = FALSE; + goto Cleanup; + } + + break; + } + default: + { + continue; + } + } + } + + +Cleanup: + + RegCloseKey(KeyHandle); + + LocalFree( ValueName ); + LocalFree( ValueData ); + + return( rc ); +} + +//************************************************************* +// +// 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; + DWORD cchValue = 1024; + + 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); + } + } + + if (lpValue && *lpValue) { + RtlInitUnicodeString(&Value, lpValue); + Status = RtlSetEnvironmentVariable(pEnv, &Name, &Value); + } + else { + Status = RtlSetEnvironmentVariable(pEnv, &Name, NULL); + } + if (NT_SUCCESS(Status)) { + return(TRUE); + } + return(FALSE); +} + +//************************************************************* +// +// 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(LPTSTR lpPath) +{ + if (lpPath[0] == TEXT('\\') && lpPath[1] == TEXT('\\')) { + return(TRUE); + } + return(FALSE); +} + +//************************************************************* +// +// GetUserNameAndDomain() +// +// Purpose: Gets the user's name and domain +// +// Parameters: hToken - User's token +// UserName - Receives pointer to user's name +// UserDomain - Receives pointer to user's domain +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/21/96 ericflo Ported +// +//************************************************************* + +BOOL GetUserNameAndDomain(HANDLE hToken, LPTSTR *UserName, LPTSTR *UserDomain) +{ + LPTSTR lpUserName = NULL; + LPTSTR lpUserDomain = NULL; + DWORD cbAccountName = 0; + DWORD cbUserDomain = 0; + SID_NAME_USE SidNameUse; + BOOL bRet = FALSE; + PSID pSid; + + + // + // Get the user's sid + // + + pSid = GetUserSid (hToken); + + if (!pSid) { + return FALSE; + } + + + // + // Get the space needed for the User name and the Domain name + // + if (!LookupAccountSid(NULL, + pSid, + NULL, &cbAccountName, + NULL, &cbUserDomain, + &SidNameUse + ) ) { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + goto Error; + } + } + + lpUserName = (LPTSTR)LocalAlloc(LPTR, cbAccountName*sizeof(TCHAR)); + if (!lpUserName) { + goto Error; + } + + lpUserDomain = (LPTSTR)LocalAlloc(LPTR, cbUserDomain*sizeof(WCHAR)); + if (!lpUserDomain) { + LocalFree(lpUserName); + goto Error; + } + + // + // Now get the user name and domain name + // + if (!LookupAccountSid(NULL, + pSid, + lpUserName, &cbAccountName, + lpUserDomain, &cbUserDomain, + &SidNameUse + ) ) { + + LocalFree(lpUserName); + LocalFree(lpUserDomain); + goto Error; + } + + *UserName = lpUserName; + *UserDomain = lpUserDomain; + bRet = TRUE; + +Error: + DeleteUserSid (pSid); + + return(bRet); +} + +//************************************************************* +// +// GetHKeyCU() +// +// Purpose: Get HKEY_CURRENT_USER for the given hToken +// +// Parameters: hToken - token handle +// +// Return: hKey if successful +// NULL if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/21/96 ericflo Created +// +//************************************************************* + +HKEY GetHKeyCU(HANDLE hToken) +{ + LPTSTR lpSidString; + HKEY hKey = NULL; + + + lpSidString = GetSidString (hToken); + + if (!lpSidString) { + return FALSE; + } + + RegOpenKeyEx (HKEY_USERS, lpSidString, 0, KEY_READ, &hKey); + + DeleteSidString(lpSidString); + + return hKey; +} + +/***************************************************************************\ +* ExpandUserEvironmentVariable +* +* +* History: +* 2-28-92 Johannec Created +* +\***************************************************************************/ +DWORD +ExpandUserEnvironmentStrings( + PVOID pEnv, + LPTSTR 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 ); + } + else { + return( 0 ); + } +} + +/***************************************************************************\ +* ProcessAutoexecPath +* +* Creates AutoexecPath environment variable using autoexec.bat +* LpValue may be freed by this routine. +* +* History: +* 06-02-92 Johannec Created. +* +\***************************************************************************/ +LPTSTR ProcessAutoexecPath(PVOID pEnv, LPTSTR lpValue, DWORD cb) +{ + LPTSTR lpt; + LPTSTR lpStart; + LPTSTR lpPath; + DWORD cbt; + UNICODE_STRING Name; + UNICODE_STRING Value; + BOOL bPrevAutoexecPath; + WCHAR ch; + DWORD dwTemp, dwCount = 0; + + cbt = 1024; + lpt = (LPTSTR)LocalAlloc(LPTR, cbt*sizeof(WCHAR)); + if (!lpt) { + return(lpValue); + } + *lpt = 0; + lpStart = lpValue; + + RtlInitUnicodeString(&Name, AUTOEXECPATH_VARIABLE); + Value.Buffer = (PWCHAR)LocalAlloc(LPTR, cbt*sizeof(WCHAR)); + if (!Value.Buffer) { + goto Fail; + } + + while (NULL != (lpPath = wcsstr (lpValue, TEXT("%")))) { + if (!_wcsnicmp(lpPath+1, TEXT("PATH%"), 5)) { + // + // check if we have an autoexecpath already set, if not just remove + // the %path% + // + Value.Length = (USHORT)cbt; + Value.MaximumLength = (USHORT)cbt; + bPrevAutoexecPath = (BOOL)!RtlQueryEnvironmentVariable_U(pEnv, &Name, &Value); + + *lpPath = 0; + dwTemp = dwCount + lstrlen (lpValue); + if (dwTemp < cbt) { + lstrcat(lpt, lpValue); + dwCount += dwTemp; + } + if (bPrevAutoexecPath) { + dwTemp = dwCount + lstrlen (Value.Buffer); + if (dwTemp < cbt) { + lstrcat(lpt, Value.Buffer); + dwCount += dwTemp; + } + } + + *lpPath++ = TEXT('%'); + lpPath += 5; // go passed %path% + lpValue = lpPath; + } + else { + lpPath = wcsstr(lpPath+1, TEXT("%")); + if (!lpPath) { + lpStart = NULL; + goto Fail; + } + lpPath++; + ch = *lpPath; + *lpPath = 0; + dwTemp = dwCount + lstrlen (lpValue); + if (dwTemp < cbt) { + lstrcat(lpt, lpValue); + dwCount += dwTemp; + } + *lpPath = ch; + lpValue = lpPath; + } + } + + if (*lpValue) { + dwTemp = dwCount + lstrlen (lpValue); + if (dwTemp < cbt) { + lstrcat(lpt, lpValue); + dwCount += dwTemp; + } + } + + LocalFree(Value.Buffer); + LocalFree(lpStart); + + return(lpt); +Fail: + LocalFree(lpt); + return(lpStart); +} + +/***************************************************************************\ +* ProcessCommand +* +* History: +* 01-24-92 Johannec Created. +* +\***************************************************************************/ +BOOL ProcessCommand(LPSTR lpStart, PVOID *pEnv) +{ + LPTSTR lpt, lptt; + LPTSTR lpVariable; + LPTSTR lpValue; + LPTSTR lpExpandedValue = NULL; + WCHAR c; + DWORD cb, cbNeeded; + LPTSTR lpu; + + // + // convert to Unicode + // + lpu = (LPTSTR)LocalAlloc(LPTR, (cb=lstrlenA(lpStart)+1)*sizeof(WCHAR)); + MultiByteToWideChar(CP_OEMCP, 0, lpStart, -1, lpu, cb); + + // + // Find environment variable. + // + for (lpt = lpu; *lpt && *lpt == TEXT(' '); lpt++) //skip spaces + ; + + if (!*lpt) + return(FALSE); + + lptt = lpt; + for (; *lpt && *lpt != TEXT(' ') && *lpt != TEXT('='); lpt++) //find end of variable name + ; + + c = *lpt; + *lpt = 0; + lpVariable = (LPTSTR)LocalAlloc(LPTR, (lstrlen(lptt) + 1)*sizeof(WCHAR)); + if (!lpVariable) + return(FALSE); + lstrcpy(lpVariable, lptt); + *lpt = c; + + // + // Find environment variable value. + // + for (; *lpt && (*lpt == TEXT(' ') || *lpt == TEXT('=')); lpt++) + ; + + if (!*lpt) { + // if we have a blank path statement in the autoexec file, + // then we don't want to pass "PATH" as the environment + // variable because it trashes the system's PATH. Instead + // we want to change the variable AutoexecPath. This would have + // be handled below if a value had been assigned to the + // environment variable. + if (lstrcmpi(lpVariable, PATH_VARIABLE) == 0) + { + SetEnvironmentVariableInBlock(pEnv, AUTOEXECPATH_VARIABLE, TEXT(""), TRUE); + } + else + { + SetEnvironmentVariableInBlock(pEnv, lpVariable, TEXT(""), TRUE); + } + return(FALSE); + } + + lptt = lpt; + for (; *lpt; lpt++) //find end of varaible value + ; + + c = *lpt; + *lpt = 0; + lpValue = (LPTSTR)LocalAlloc(LPTR, (lstrlen(lptt) + 1)*sizeof(WCHAR)); + if (!lpValue) { + LocalFree(lpVariable); + return(FALSE); + } + + lstrcpy(lpValue, lptt); + *lpt = c; + + cb = 1024; + lpExpandedValue = (LPTSTR)LocalAlloc(LPTR, cb*sizeof(WCHAR)); + if (lpExpandedValue) { + if (!lstrcmpi(lpVariable, PATH_VARIABLE)) { + lpValue = ProcessAutoexecPath(*pEnv, lpValue, (lstrlen(lpValue)+1)*sizeof(WCHAR)); + } + cbNeeded = ExpandUserEnvironmentStrings(*pEnv, lpValue, lpExpandedValue, cb); + if (cbNeeded > cb) { + LocalFree(lpExpandedValue); + cb = cbNeeded; + lpExpandedValue = (LPTSTR)LocalAlloc(LPTR, cb*sizeof(WCHAR)); + if (lpExpandedValue) { + ExpandUserEnvironmentStrings(*pEnv, lpValue, lpExpandedValue, cb); + } + } + } + + if (!lpExpandedValue) { + lpExpandedValue = lpValue; + } + if (lstrcmpi(lpVariable, PATH_VARIABLE)) { + SetEnvironmentVariableInBlock(pEnv, lpVariable, lpExpandedValue, FALSE); + } + else { + SetEnvironmentVariableInBlock(pEnv, AUTOEXECPATH_VARIABLE, lpExpandedValue, TRUE); + + } + + if (lpExpandedValue != lpValue) { + LocalFree(lpExpandedValue); + } + LocalFree(lpVariable); + LocalFree(lpValue); + + return(TRUE); +} + +/***************************************************************************\ +* ProcessSetCommand +* +* History: +* 01-24-92 Johannec Created. +* +\***************************************************************************/ +BOOL ProcessSetCommand(LPSTR lpStart, PVOID *pEnv) +{ + LPSTR lpt; + + // + // Find environment variable. + // + for (lpt = lpStart; *lpt && *lpt != TEXT(' '); lpt++) + ; + + if (!*lpt) + return(FALSE); + + return (ProcessCommand(lpt, pEnv)); + +} + +/***************************************************************************\ +* ProcessAutoexec +* +* History: +* 01-24-92 Johannec Created. +* +\***************************************************************************/ +BOOL +ProcessAutoexec( + PVOID *pEnv + ) +{ + HANDLE fh; + DWORD dwFileSize; + DWORD dwBytesRead; + CHAR *lpBuffer = NULL; + CHAR *token; + CHAR Seps[] = "&\n\r"; // Seperators for tokenizing autoexec.bat + BOOL Status = FALSE; + TCHAR szAutoExecBat [] = TEXT("c:\\autoexec.bat"); + UINT uiErrMode; + + + // There is a case where the OS might not be booting from drive + // C, so we can not assume that the autoexec.bat file is on c:\. + // Set the error mode so the user doesn't see the critical error + // popup and attempt to open the file on c:\. + + uiErrMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + + fh = CreateFile (szAutoExecBat, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + SetErrorMode (uiErrMode); + + if (fh == INVALID_HANDLE_VALUE) { + return(FALSE); //could not open autoexec.bat file, we're done. + } + dwFileSize = GetFileSize(fh, NULL); + if (dwFileSize == -1) { + goto Exit; // can't read the file size + } + + lpBuffer = (PCHAR)LocalAlloc(LPTR, dwFileSize+1); + if (!lpBuffer) { + goto Exit; + } + + Status = ReadFile(fh, lpBuffer, dwFileSize, &dwBytesRead, NULL); + if (!Status) { + goto Exit; // error reading file + } + + // + // Zero terminate the buffer so we don't walk off the end + // + + ASSERT(dwBytesRead <= dwFileSize); + lpBuffer[dwBytesRead] = 0; + + // + // Search for SET and PATH commands + // + + token = strtok(lpBuffer, Seps); + while (token != NULL) { + for (;*token && *token == ' ';token++) //skip spaces + ; + if (*token == TEXT('@')) + token++; + for (;*token && *token == ' ';token++) //skip spaces + ; + if (!_strnicmp(token, "Path", 4)) { + ProcessCommand(token, pEnv); + } + if (!_strnicmp(token, "SET", 3)) { + ProcessSetCommand(token, pEnv); + } + token = strtok(NULL, Seps); + } +Exit: + CloseHandle(fh); + if (lpBuffer) { + LocalFree(lpBuffer); + } + if (!Status) { + DebugMsg((DM_WARNING, TEXT("ProcessAutoexec: Cannot process autoexec.bat."))); + } + return(Status); +} + +/***************************************************************************\ +* BuildEnvironmentPath +* +* +* History: +* 2-28-92 Johannec Created +* +\***************************************************************************/ +BOOL BuildEnvironmentPath(PVOID *pEnv, + LPTSTR lpPathVariable, + LPTSTR lpPathValue) +{ + NTSTATUS Status; + UNICODE_STRING Name; + UNICODE_STRING Value; + WCHAR lpTemp[1024]; + DWORD cb; + + + if (!*pEnv) { + return(FALSE); + } + RtlInitUnicodeString(&Name, lpPathVariable); + cb = 1024; + Value.Buffer = (PWCHAR)LocalAlloc(LPTR, cb*sizeof(WCHAR)); + if (!Value.Buffer) { + return(FALSE); + } + Value.Length = (USHORT)cb; + Value.MaximumLength = (USHORT)cb; + Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value); + if (!NT_SUCCESS(Status)) { + LocalFree(Value.Buffer); + Value.Length = 0; + *lpTemp = 0; + } + if (Value.Length) { + lstrcpy(lpTemp, Value.Buffer); + if ( *( lpTemp + lstrlen(lpTemp) - 1) != TEXT(';') ) { + lstrcat(lpTemp, TEXT(";")); + } + LocalFree(Value.Buffer); + } + if (lpPathValue && + ((lstrlen(lpTemp)+lstrlen(lpPathValue)+1)*sizeof(WCHAR) < cb)) { + lstrcat(lpTemp, lpPathValue); + RtlInitUnicodeString(&Value, lpTemp); + Status = RtlSetEnvironmentVariable( pEnv, &Name, &Value); + } + if (NT_SUCCESS(Status)) { + return(TRUE); + } + return(FALSE); +} + +/***************************************************************************\ +* AppendNTPathWithAutoexecPath +* +* Gets the AutoexecPath created in ProcessAutoexec, and appends it to +* the NT path. +* +* History: +* 05-28-92 Johannec Created. +* +\***************************************************************************/ +BOOL +AppendNTPathWithAutoexecPath( + PVOID *pEnv, + LPTSTR lpPathVariable, + LPTSTR lpAutoexecPath + ) +{ + NTSTATUS Status; + UNICODE_STRING Name; + UNICODE_STRING Value; + WCHAR AutoexecPathValue[1024]; + DWORD cb; + BOOL Success; + + if (!*pEnv) { + return(FALSE); + } + + RtlInitUnicodeString(&Name, lpAutoexecPath); + cb = 1024; + Value.Buffer = (PWCHAR)LocalAlloc(LPTR, cb*sizeof(WCHAR)); + if (!Value.Buffer) { + return(FALSE); + } + + Value.Length = (USHORT)cb; + Value.MaximumLength = (USHORT)cb; + Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value); + if (!NT_SUCCESS(Status)) { + LocalFree(Value.Buffer); + return(FALSE); + } + + if (Value.Length) { + lstrcpy(AutoexecPathValue, Value.Buffer); + } + + LocalFree(Value.Buffer); + + Success = BuildEnvironmentPath(pEnv, lpPathVariable, AutoexecPathValue); + RtlSetEnvironmentVariable( pEnv, &Name, NULL); + + return(Success); +} + +/***************************************************************************\ +* SetEnvironmentVariables +* +* Reads the user-defined environment variables from the user registry +* and adds them to the environment block at pEnv. +* +* History: +* 2-28-92 Johannec Created +* +\***************************************************************************/ +BOOL +SetEnvironmentVariables( + PVOID *pEnv, + LPTSTR lpRegSubKey, + HKEY hKeyCU + ) +{ + WCHAR lpValueName[MAX_PATH]; + LPBYTE lpDataBuffer; + DWORD cbDataBuffer; + LPBYTE lpData; + LPTSTR lpExpandedValue = NULL; + DWORD cbValueName = MAX_PATH; + DWORD cbData; + DWORD dwType; + DWORD dwIndex = 0; + HKEY hkey; + BOOL bResult; + + if (RegOpenKeyExW(hKeyCU, lpRegSubKey, 0, KEY_READ, &hkey)) { + return(FALSE); + } + + cbDataBuffer = 4096; + lpDataBuffer = (LPBYTE)LocalAlloc(LPTR, cbDataBuffer*sizeof(WCHAR)); + if (lpDataBuffer == NULL) { + RegCloseKey(hkey); + return(FALSE); + } + lpData = lpDataBuffer; + cbData = cbDataBuffer; + bResult = TRUE; + while (!RegEnumValue(hkey, dwIndex, lpValueName, &cbValueName, 0, &dwType, + lpData, &cbData)) { + if (cbValueName) { + + // + // Limit environment variable length + // + + lpData[MAX_VALUE_LEN-1] = TEXT('\0'); + + + if (dwType == REG_SZ) { + // + // The path variables PATH, LIBPATH and OS2LIBPATH must have + // their values apppended to the system path. + // + + if ( !lstrcmpi(lpValueName, PATH_VARIABLE) || + !lstrcmpi(lpValueName, LIBPATH_VARIABLE) || + !lstrcmpi(lpValueName, OS2LIBPATH_VARIABLE) ) { + + BuildEnvironmentPath(pEnv, lpValueName, (LPTSTR)lpData); + } + else { + + // + // the other environment variables are just set. + // + + SetEnvironmentVariableInBlock(pEnv, lpValueName, (LPTSTR)lpData, TRUE); + } + } + } + dwIndex++; + cbData = cbDataBuffer; + cbValueName = MAX_PATH; + } + + dwIndex = 0; + cbData = cbDataBuffer; + cbValueName = MAX_PATH; + + + while (!RegEnumValue(hkey, dwIndex, lpValueName, &cbValueName, 0, &dwType, + lpData, &cbData)) { + if (cbValueName) { + + // + // Limit environment variable length + // + + lpData[MAX_VALUE_LEN-1] = TEXT('\0'); + + + if (dwType == REG_EXPAND_SZ) { + DWORD cb, cbNeeded; + + cb = 1024; + lpExpandedValue = (LPTSTR)LocalAlloc(LPTR, cb*sizeof(WCHAR)); + if (lpExpandedValue) { + cbNeeded = ExpandUserEnvironmentStrings(*pEnv, (LPTSTR)lpData, lpExpandedValue, cb); + if (cbNeeded > cb) { + LocalFree(lpExpandedValue); + cb = cbNeeded; + lpExpandedValue = (LPTSTR)LocalAlloc(LPTR, cb*sizeof(WCHAR)); + if (lpExpandedValue) { + ExpandUserEnvironmentStrings(*pEnv, (LPTSTR)lpData, lpExpandedValue, cb); + } + } + } + + if (lpExpandedValue == NULL) { + bResult = FALSE; + break; + } + + + // + // The path variables PATH, LIBPATH and OS2LIBPATH must have + // their values apppended to the system path. + // + + if ( !lstrcmpi(lpValueName, PATH_VARIABLE) || + !lstrcmpi(lpValueName, LIBPATH_VARIABLE) || + !lstrcmpi(lpValueName, OS2LIBPATH_VARIABLE) ) { + + BuildEnvironmentPath(pEnv, lpValueName, (LPTSTR)lpExpandedValue); + } + else { + + // + // the other environment variables are just set. + // + + SetEnvironmentVariableInBlock(pEnv, lpValueName, (LPTSTR)lpExpandedValue, TRUE); + } + + LocalFree(lpExpandedValue); + + } + + } + dwIndex++; + cbData = cbDataBuffer; + cbValueName = MAX_PATH; + } + + + + LocalFree(lpDataBuffer); + RegCloseKey(hkey); + + return(bResult); +} diff --git a/private/windows/gina/userenv/events.c b/private/windows/gina/userenv/events.c new file mode 100644 index 000000000..c0c1a3921 --- /dev/null +++ b/private/windows/gina/userenv/events.c @@ -0,0 +1,295 @@ +//************************************************************* +// +// Events.c - Routines to handle the event log +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" +#pragma hdrstop + +HANDLE hEventLog = INVALID_HANDLE_VALUE; +TCHAR EventSourceName[] = TEXT("Userenv"); + +typedef struct _ERRORSTRUCT { + DWORD dwTimeOut; + LPTSTR lpErrorText; +} ERRORSTRUCT, *LPERRORSTRUCT; + +BOOL APIENTRY ErrorDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +//************************************************************* +// +// InitializeEvents() +// +// Purpose: Opens the event log +// +// Parameters: void +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 7/17/95 ericflo Created +// +//************************************************************* + +BOOL InitializeEvents (void) +{ + + // + // Open the event source + // + + hEventLog = RegisterEventSource(NULL, EventSourceName); + + if (hEventLog) { + return TRUE; + } + + DebugMsg((DM_WARNING, TEXT("InitializeEvents: Could not open event log. Error = %d"), GetLastError())); + return FALSE; +} + + +//************************************************************* +// +// ReportError() +// +// Purpose: Displays an error message to the user and +// records it in the event log +// +// Parameters: dwFlags - Flags +// idMsg - Error message id +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 7/18/95 ericflo Created +// +//************************************************************* + +int ReportError (DWORD dwFlags, UINT idMsg, ...) +{ + TCHAR szMsg[MAX_PATH]; + TCHAR szErrorMsg[2*MAX_PATH+40]; + LPTSTR aStrings[2]; + va_list marker; + + + + // + // Check for the event log being open. + // + + if (hEventLog == INVALID_HANDLE_VALUE) { + if (!InitializeEvents()) { + DebugMsg((DM_WARNING, TEXT("RecordEvent: Cannot log event, no handle"))); + return -1; + } + } + + + + // + // Load the error message + // + + if (!LoadString (g_hDllInstance, idMsg, szMsg, MAX_PATH)) { + DebugMsg((DM_WARNING, TEXT("RecordEvent: LoadString failed (2). Error = %d"), GetLastError())); + return -1; + } + + + + // + // Plug in the arguments + // + + va_start(marker, idMsg); + wvsprintf(szErrorMsg, szMsg, marker); + va_end(marker); + + + + + if (!(dwFlags & PI_NOUI)) { + + ERRORSTRUCT es; + DWORD dwDlgTimeOut = PROFILE_DLG_TIMEOUT; + DWORD dwSize, dwType; + LONG lResult; + HKEY hKey; + + // + // Find the dialog box timeout + // + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + WINLOGON_KEY, + 0, + KEY_READ, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + dwSize = sizeof(DWORD); + RegQueryValueEx (hKey, + TEXT("ProfileDlgTimeOut"), + NULL, + &dwType, + (LPBYTE) &dwDlgTimeOut, + &dwSize); + + + RegCloseKey (hKey); + } + + + // + // Display the message + // + + es.dwTimeOut = dwDlgTimeOut; + es.lpErrorText = szErrorMsg; + + DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_ERROR), + NULL, ErrorDlgProc, (LPARAM)&es); + } + + + + // + // Report the event to the eventlog + // + + aStrings[0] = szErrorMsg; + + if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, 0, EVENT_PROFILE_ERROR, + NULL, 1, 0, aStrings, NULL) ) { + + DebugMsg((DM_WARNING, TEXT("ReportEvent failed. Error = %d"), GetLastError())); + } + + return 0; +} + +//************************************************************* +// +// ShutdownEvents() +// +// Purpose: Stops the event log +// +// Parameters: void +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 7/17/95 ericflo Created +// +//************************************************************* + +BOOL ShutdownEvents (void) +{ + BOOL bRetVal = TRUE; + + if (hEventLog != INVALID_HANDLE_VALUE) { + bRetVal = DeregisterEventSource(hEventLog); + } + + return bRetVal; +} + +//************************************************************* +// +// ErrorDlgProc() +// +// Purpose: Dialog box procedure for the error dialog +// +// Parameters: hDlg - handle to the dialog box +// uMsg - window message +// wParam - wParam +// lParam - lParam +// +// Return: TRUE if message was processed +// FALSE if not +// +// Comments: +// +// History: Date Author Comment +// 3/22/96 ericflo Created +// +//************************************************************* + +BOOL APIENTRY ErrorDlgProc (HWND hDlg, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + TCHAR szBuffer[10]; + static DWORD dwErrorTime; + + switch (uMsg) { + + case WM_INITDIALOG: + { + LPERRORSTRUCT lpES = (LPERRORSTRUCT) lParam; + + CenterWindow (hDlg); + SetDlgItemText (hDlg, IDC_ERRORTEXT, lpES->lpErrorText); + + dwErrorTime = lpES->dwTimeOut; + wsprintf (szBuffer, TEXT("%d"), dwErrorTime); + SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); + SetTimer (hDlg, 1, 1000, NULL); + return TRUE; + } + + case WM_TIMER: + + if (dwErrorTime >= 1) { + + dwErrorTime--; + wsprintf (szBuffer, TEXT("%d"), dwErrorTime); + SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); + + } else { + + // + // Time's up. Dismiss the dialog. + // + + PostMessage (hDlg, WM_COMMAND, IDOK, 0); + } + break; + + case WM_COMMAND: + + switch (LOWORD(wParam)) { + + case IDOK: + case IDCANCEL: + + KillTimer (hDlg, 1); + EndDialog(hDlg, TRUE); + break; + + default: + break; + + } + break; + + } + + return FALSE; +} diff --git a/private/windows/gina/userenv/events.h b/private/windows/gina/userenv/events.h new file mode 100644 index 000000000..80d6e25b9 --- /dev/null +++ b/private/windows/gina/userenv/events.h @@ -0,0 +1,13 @@ +//************************************************************* +// +// Events.h - header file for events.c +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +BOOL InitializeEvents (void); +int ReportError (DWORD dwFlags, UINT idMsg, ... ); +BOOL ShutdownEvents (void); diff --git a/private/windows/gina/userenv/globals.c b/private/windows/gina/userenv/globals.c new file mode 100644 index 000000000..a6de411b0 --- /dev/null +++ b/private/windows/gina/userenv/globals.c @@ -0,0 +1,325 @@ +//************************************************************* +// +// Global Variables +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + + +HINSTANCE g_hDllInstance; +DWORD g_dwBuildNumber; +TCHAR g_szCommon[MAX_COMMON_LEN]; +UINT g_cchCommon; +NTPRODUCTTYPE g_ProductType; + +const TCHAR c_szStarDotStar[] = TEXT("*.*"); +const TCHAR c_szSlash[] = TEXT("\\"); +const TCHAR c_szDot[] = TEXT("."); +const TCHAR c_szDotDot[] = TEXT(".."); +const TCHAR c_szMAN[] = TEXT(".man"); +const TCHAR c_szUSR[] = TEXT(".usr"); +const TCHAR c_szLog[] = TEXT(".log"); +const TCHAR c_szPDS[] = TEXT(".pds"); +const TCHAR c_szPDM[] = TEXT(".pdm"); +const TCHAR c_szLNK[] = TEXT(".lnk"); +const TCHAR c_szBAK[] = TEXT(".bak"); +const TCHAR c_szNTUserMan[] = TEXT("ntuser.man"); +const TCHAR c_szNTUserDat[] = TEXT("ntuser.dat"); +const TCHAR c_szNTConfigPol[] = TEXT("ntconfig.pol"); +const TCHAR c_szNTUserStar[] = TEXT("ntuser.*"); +const TCHAR c_szUserStar[] = TEXT("user.*"); +const TCHAR c_szSpace[] = TEXT(" "); +const TCHAR c_szDotPif[] = TEXT(".pif"); +const TCHAR c_szNULL[] = TEXT(""); +const TCHAR c_szCommonGroupsLocation[] = TEXT("Software\\Program Groups"); + + +// +// These are the shell folder names and locations +// relative to the root of of the local profile +// directory. NOTE: The folders that are +// below other folders are in tier 2. If you +// add a new folder to the root, be sure to fix +// the tier 1 define in globals.h!! +// + +FOLDER_INFO c_ShellFolders[NUM_SHELL_FOLDERS]; + +// +// These are the shell folder names and locations +// relative to the root of of the common profile +// directory. NOTE: The folders that are +// below other folders are in tier 2. If you +// add a new folder to the root, be sure to fix +// the tier 1 define in globals.h!! +// + +FOLDER_INFO c_CommonShellFolders[NUM_COMMON_SHELL_FOLDERS]; + + +//************************************************************* +// +// InitializeGlobals() +// +// Purpose: Initializes all the globals variables +// at DLL load time. +// +// Parameters: hInstance - DLL instance handle +// +// Return: void +// +// Comments: +// +// History: Date Author Comment +// 10/13/95 ericflo Created +// +//************************************************************* + +void InitializeGlobals (HINSTANCE hInstance) +{ + OSVERSIONINFO ver; + + + // + // Save the instance handle + // + + g_hDllInstance = hInstance; + + + // + // Query the build number + // + + ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&ver); + g_dwBuildNumber = (DWORD) LOWORD(ver.dwBuildNumber); + + + // + // Load the common string + // + + LoadString (hInstance, IDS_COMMON, g_szCommon, MAX_COMMON_LEN); + g_cchCommon = lstrlen (g_szCommon); + + + + // + // Now load the directory names that match + // the special folders + // + + + // AppData + c_ShellFolders[0].bHidden = FALSE; + c_ShellFolders[0].lpFolderName = TEXT("AppData"); + LoadString(hInstance, IDS_SH_APPDATA, + c_ShellFolders[0].lpFolderLocation, MAX_FOLDER_SIZE); + + // Desktop + c_ShellFolders[1].bHidden = FALSE; + c_ShellFolders[1].lpFolderName = TEXT("Desktop"); + LoadString(hInstance, IDS_SH_DESKTOP, + c_ShellFolders[1].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Favorites + c_ShellFolders[2].bHidden = FALSE; + c_ShellFolders[2].lpFolderName = TEXT("Favorites"); + LoadString(hInstance, IDS_SH_FAVORITES, + c_ShellFolders[2].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Nethood + c_ShellFolders[3].bHidden = TRUE; + c_ShellFolders[3].lpFolderName = TEXT("NetHood"); + LoadString(hInstance, IDS_SH_NETHOOD, + c_ShellFolders[3].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Personal + c_ShellFolders[4].bHidden = FALSE; + c_ShellFolders[4].lpFolderName = TEXT("Personal"); + LoadString(hInstance, IDS_SH_PERSONAL, + c_ShellFolders[4].lpFolderLocation, MAX_FOLDER_SIZE); + + + // PrintHood + c_ShellFolders[5].bHidden = TRUE; + c_ShellFolders[5].lpFolderName = TEXT("PrintHood"); + LoadString(hInstance, IDS_SH_PRINTHOOD, + c_ShellFolders[5].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Recent + c_ShellFolders[6].bHidden = TRUE; + c_ShellFolders[6].lpFolderName = TEXT("Recent"); + LoadString(hInstance, IDS_SH_RECENT, + c_ShellFolders[6].lpFolderLocation, MAX_FOLDER_SIZE); + + + // SendTo + c_ShellFolders[7].bHidden = FALSE; + c_ShellFolders[7].lpFolderName = TEXT("SendTo"); + LoadString(hInstance, IDS_SH_SENDTO, + c_ShellFolders[7].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Start Menu + c_ShellFolders[8].bHidden = FALSE; + c_ShellFolders[8].lpFolderName = TEXT("Start Menu"); + LoadString(hInstance, IDS_SH_STARTMENU, + c_ShellFolders[8].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Templates + c_ShellFolders[9].bHidden = TRUE; + c_ShellFolders[9].lpFolderName = TEXT("Templates"); + LoadString(hInstance, IDS_SH_TEMPLATES, + c_ShellFolders[9].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Programs + c_ShellFolders[10].bHidden = FALSE; + c_ShellFolders[10].lpFolderName = TEXT("Programs"); + LoadString(hInstance, IDS_SH_PROGRAMS, + c_ShellFolders[10].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Startup + c_ShellFolders[11].bHidden = FALSE; + c_ShellFolders[11].lpFolderName = TEXT("Startup"); + LoadString(hInstance, IDS_SH_STARTUP, + c_ShellFolders[11].lpFolderLocation, MAX_FOLDER_SIZE); + + + // + // Now load the directory names that match + // the common special folders + // + + // Common Desktop + c_CommonShellFolders[0].bHidden = FALSE; + c_CommonShellFolders[0].lpFolderName = TEXT("Common Desktop"); + LoadString(hInstance, IDS_SH_DESKTOP, + c_CommonShellFolders[0].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Common Start Menu + c_CommonShellFolders[1].bHidden = FALSE; + c_CommonShellFolders[1].lpFolderName = TEXT("Common Start Menu"); + LoadString(hInstance, IDS_SH_STARTMENU, + c_CommonShellFolders[1].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Common Programs + c_CommonShellFolders[2].bHidden = FALSE; + c_CommonShellFolders[2].lpFolderName = TEXT("Common Programs"); + LoadString(hInstance, IDS_SH_PROGRAMS, + c_CommonShellFolders[2].lpFolderLocation, MAX_FOLDER_SIZE); + + + // Common Startup + c_CommonShellFolders[3].bHidden = FALSE; + c_CommonShellFolders[3].lpFolderName = TEXT("Common Startup"); + LoadString(hInstance, IDS_SH_STARTUP, + c_CommonShellFolders[3].lpFolderLocation, MAX_FOLDER_SIZE); + +} + +//************************************************************* +// +// InitializeProductType() +// +// Purpose: Determines the current product type and +// sets the g_ProductType global variable. +// +// Parameters: void +// +// Return: void +// +// Comments: +// +// History: Date Author Comment +// 4/08/96 ericflo Created +// +//************************************************************* + +void InitializeProductType (void) +{ + HKEY hkey; + LONG lResult; + TCHAR szProductType[50]; + DWORD dwType, dwSize; + + + // + // Default product type is workstation. + // + + g_ProductType = PT_WORKSTATION; + + + // + // Query the registry for the product type. + // + + lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, + TEXT("System\\CurrentControlSet\\Control\\ProductOptions"), + 0, + KEY_READ, + &hkey); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("InitializeProductType: Failed to open registry (%d)"), lResult)); + goto Exit; + } + + + dwSize = 50; + szProductType[0] = TEXT('\0'); + + lResult = RegQueryValueEx (hkey, + TEXT("ProductType"), + NULL, + &dwType, + (LPBYTE) szProductType, + &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("InitializeProductType: Failed to query product type (%d)"), lResult)); + goto Exit; + } + + RegCloseKey (hkey); + + + // + // Map the product type string to the enumeration value. + // + + if (!lstrcmpi (szProductType, TEXT("WinNT"))) { + g_ProductType = PT_WORKSTATION; + + } else if (!lstrcmpi (szProductType, TEXT("ServerNT"))) { + g_ProductType = PT_SERVER; + + } else if (!lstrcmpi (szProductType, TEXT("LanmanNT"))) { + g_ProductType = PT_DC; + + } else { + DebugMsg((DM_WARNING, TEXT("InitializeProductType: Unknown product type! <%s>"), szProductType)); + } + + + +Exit: + DebugMsg((DM_VERBOSE, TEXT("InitializeProductType: Product Type: %d"), g_ProductType)); + +} diff --git a/private/windows/gina/userenv/globals.h b/private/windows/gina/userenv/globals.h new file mode 100644 index 000000000..bd74b2998 --- /dev/null +++ b/private/windows/gina/userenv/globals.h @@ -0,0 +1,106 @@ +//************************************************************* +// +// Global Variable Extern's +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + + +#define WINLOGON_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon") +#define POLICIES_KEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies") + +#define PROFILES_DIR TEXT("%SystemRoot%\\Profiles") +#define DEFAULT_PROFILE TEXT("%SystemRoot%\\Profiles\\Default User") +#define DEFAULT_NET_PROFILE TEXT("%SystemRoot%\\Profiles\\Default User (Network)") +#define COMMON_PROFILE TEXT("%SystemRoot%\\Profiles\\All Users") + + +extern HINSTANCE g_hDllInstance; +extern DWORD g_dwBuildNumber; +extern TCHAR g_szCommon[]; +extern UINT g_cchCommon; + + +extern const TCHAR c_szStarDotStar[]; +extern const TCHAR c_szSlash[]; +extern const TCHAR c_szDot[]; +extern const TCHAR c_szDotDot[]; +extern const TCHAR c_szMAN[]; +extern const TCHAR c_szUSR[]; +extern const TCHAR c_szLog[]; +extern const TCHAR c_szPDS[]; +extern const TCHAR c_szPDM[]; +extern const TCHAR c_szLNK[]; +extern const TCHAR c_szBAK[]; +extern const TCHAR c_szNTUserMan[]; +extern const TCHAR c_szNTUserDat[]; +extern const TCHAR c_szNTConfigPol[]; +extern const TCHAR c_szNTUserStar[]; +extern const TCHAR c_szUserStar[]; +extern const TCHAR c_szSpace[]; +extern const TCHAR c_szDotPif[]; +extern const TCHAR c_szNULL[]; +extern const TCHAR c_szCommonGroupsLocation[]; + +// +// Timeouts +// + +#define SLOW_LINK_TIMEOUT 2000 // ticks +#define PROFILE_DLG_TIMEOUT 30 // seconds + +// +// Folder sizes +// + +#define MAX_FOLDER_SIZE 80 +#define MAX_COMMON_LEN 30 + +// +// Personal profile folders +// + +#define NUM_SHELL_FOLDERS 12 +#define NUM_TIER1_FOLDERS 10 + + +// +// Common profile folders +// + +#define NUM_COMMON_SHELL_FOLDERS 4 +#define NUM_COMMON_TIER1_FOLDERS 2 + + +typedef struct _FOLDER_INFO { + BOOL bHidden; + LPTSTR lpFolderName; + TCHAR lpFolderLocation[MAX_FOLDER_SIZE]; +} FOLDER_INFO; + +extern FOLDER_INFO c_ShellFolders[]; +extern FOLDER_INFO c_CommonShellFolders[]; + + +// +// Product type +// + +typedef enum { + PT_WORKSTATION = 0x0001, // Workstation + PT_SERVER = 0x0002, // Server + PT_DC = 0x0004, // Domain controller +} NTPRODUCTTYPE; + +extern NTPRODUCTTYPE g_ProductType; + + +// +// Function proto-types +// + +void InitializeGlobals (HINSTANCE hInstance); +void InitializeProductType (void); diff --git a/private/windows/gina/userenv/makefile b/private/windows/gina/userenv/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/windows/gina/userenv/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/windows/gina/userenv/makefile.inc b/private/windows/gina/userenv/makefile.inc new file mode 100644 index 000000000..7923e99f9 --- /dev/null +++ b/private/windows/gina/userenv/makefile.inc @@ -0,0 +1,2 @@ +uevents.h msg00001.bin: uevents.mc + mc -v uevents.mc diff --git a/private/windows/gina/userenv/policy.c b/private/windows/gina/userenv/policy.c new file mode 100644 index 000000000..5df5179d1 --- /dev/null +++ b/private/windows/gina/userenv/policy.c @@ -0,0 +1,1415 @@ +//************************************************************* +// +// Functions to apply policy +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" +#include <regstr.h> +#include <winnetwk.h> +#include <lm.h> + +// +// Update mode constants +// + +#define UM_OFF 0 +#define UM_AUTOMATIC 1 +#define UM_MANUAL 2 + + +// +// Prefix constants for value names +// + +#define NUM_PREFIX 3 +#define PREFIX_UNKNOWN 0 +#define PREFIX_DELETE 1 +#define PREFIX_SOFT 2 +#define PREFIX_DELVALS 3 + + +// +// Max size of a value's data +// + +#define MAX_VALUE_DATA 4096 + +// +// Default group size +// + +#define DEFAULT_GROUP_SIZE 8192 + + +// +// Registry value names +// + +TCHAR g_szUpdateModeValue[] = TEXT("UpdateMode"); +TCHAR g_szNetPathValue[] = TEXT("NetworkPath"); +TCHAR g_szLogonKey[] = WINLOGON_KEY; +CHAR g_szPolicyHandler[] = "PolicyHandler"; // This needs to be ANSI +TCHAR g_szTmpKeyName[] = TEXT("AdminConfigData"); +TCHAR g_szPrefixDel[] = TEXT("**del."); +TCHAR g_szPrefixSoft[] = TEXT("**soft."); +TCHAR g_szPrefixDelvals[] = TEXT("**delvals."); + + +// +// Function proto-types +// + +HKEY OpenUserKey(HKEY hkeyRoot, LPCTSTR pszName, BOOL * pfFoundSpecific); +UINT MergeRegistryData(HKEY hkeySrc, HKEY hkeyDst, LPTSTR pszKeyNameBuffer, + UINT cbKeyNameBuffer); +UINT CopyKeyValues(HKEY hkeySrc,HKEY hkeyDst); +BOOL HasSpecialPrefix(LPTSTR szValueName, DWORD * pdwPrefix, + LPTSTR szStrippedValueName); +BOOL GetGroupProcessingOrder(HKEY hkeyHiveRoot,LPTSTR * pGroupBuffer, DWORD * pdwGroupSize); +BOOL FindGroupInList(LPTSTR pszGroupName, LPTSTR pszGroupList); +LPTSTR GetUserGroups (LPPROFILE lpProfile, DWORD * puEntriesRead); + + +//************************************************************* +// +// ApplyPolicy() +// +// Purpose: Applies policy +// +// Parameters: lpProfile - Profile information +// +// Return: TRUE if successful +// FALSE if an error occurs +// Comments: +// +// History: Date Author Comment +// 5/30/95 ericflo Created +// +//************************************************************* + +BOOL ApplyPolicy (LPPROFILE lpProfile) +{ + LONG lResult; + BOOL fFoundUser=FALSE; + HKEY hkeyMain=NULL, hkeyRoot=NULL, hkeyUser, hkeyLogon; + DWORD dwUpdateMode=UM_AUTOMATIC; + DWORD dwData, dwSize; + TCHAR szFilePath[MAX_PATH]; + TCHAR szLocalPath[MAX_PATH]; + TCHAR szTempDir[MAX_PATH]; + CHAR szHandler[MAX_PATH+50]; // This needs to be ANSI + TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1]; + TCHAR szKeyNameBuffer[MAX_PATH+1]; + LPTSTR lpEnd; + HANDLE hFile; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Entering"))); + + + + // + // Initialize szFilePath + // + + szFilePath[0] = TEXT('\0'); + + + // + // Check the registry to see if update is specified and get update path + // + + lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, + REGSTR_PATH_UPDATE, + 0, + KEY_READ, + &hkeyMain); + + + if (lResult == ERROR_SUCCESS) { + + + // + // Look for the update mode. + // + + dwSize=sizeof(dwUpdateMode); + if (RegQueryValueEx(hkeyMain,g_szUpdateModeValue,NULL,NULL, + (LPBYTE) &dwUpdateMode,&dwSize) != ERROR_SUCCESS) { + dwUpdateMode = UM_OFF; + } + + + // + // if manual update is specified, also get the path to update from + // (UNC path or path with drive letter) + // + + + if (dwUpdateMode==UM_MANUAL) { + + dwSize=MAX_PATH; + + lResult = RegQueryValueEx(hkeyMain, g_szNetPathValue, NULL, NULL, + (LPBYTE) szFilePath, &dwSize); + + if (lResult != ERROR_SUCCESS) { + RegCloseKey(hkeyMain); + ReportError(0, IDS_MISSINGPOLICYFILEENTRY, lResult); + return FALSE; + } + } + + RegCloseKey(hkeyMain); + } + + + // + // If this machine has policy turned off, then we can exit now. + // + + if (dwUpdateMode == UM_OFF) { + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Policy is turned off on this machine."))); + return TRUE; + } + + + // + // If we are running in automatic mode, use the supplied + // policy file. + // + + if (dwUpdateMode == UM_AUTOMATIC) { + + if (*lpProfile->szPolicyPath) { + lstrcpy (szFilePath, lpProfile->szPolicyPath); + } + } + + + // + // If we don't have a policy file, then we can exit now. + // + + if (szFilePath[0] == TEXT('\0')) { + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: No Policy file. Leaving."))); + return TRUE; + } + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: PolicyPath is: <%s>."), szFilePath)); + + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to impersonate user"))); + return FALSE; + } + + + // + // Test if the policy file exists + // + + hFile = CreateFile (szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); + + + if (hFile == INVALID_HANDLE_VALUE) { + lResult = GetLastError(); + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to revert to self"))); + } + + + if ( (lResult == ERROR_FILE_NOT_FOUND) || + (lResult = ERROR_PATH_NOT_FOUND) ) { + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: No policy file."))); + return TRUE; + + } else { + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Failed to open policy file with error %d."), GetLastError())); + return FALSE; + } + } + + CloseHandle (hFile); + + + // + // Create a temporary file name + // + + if (!GetTempPath (MAX_PATH, szTempDir)) { + lstrcpy (szTempDir, TEXT(".\\")); + } + + if (!GetTempFileName (szTempDir, TEXT("prf"), 0, szLocalPath)) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to create temporary filename with error %d."), GetLastError())); + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to revert to self"))); + } + return FALSE; + } + + + // + // Copy the policy hive + // + + if (!CopyFile(szFilePath, szLocalPath, FALSE)) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to copy policy file with error %d."), GetLastError())); + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to revert to self"))); + } + return FALSE; + } + + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to revert to self"))); + } + + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Local PolicyPath is: <%s>."), szLocalPath)); + + + // + // Query for the computer name + // + + dwSize = MAX_COMPUTERNAME_LENGTH + 1; + if (!GetComputerName(szComputerName, &dwSize)) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: GetComputerName failed."))); + return FALSE; + } + + + + // + // Check to see if an installable policy handler has been added. If + // so, call it and let it do the work. + // + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + g_szLogonKey, + 0, + KEY_READ, + &hkeyLogon); + + + if (lResult == ERROR_SUCCESS) { + HANDLE hDLL = NULL; + BOOL fRet; + PFNPROCESSPOLICIES pfn; + + + dwSize = ARRAYSIZE(szHandler); + lResult = RegQueryValueExA(hkeyLogon, + g_szPolicyHandler, + NULL, NULL, + (LPBYTE) szHandler, + &dwSize); + + + RegCloseKey(hkeyLogon); + + if (lResult == ERROR_SUCCESS) { + LPSTR lpEntryPoint = szHandler; + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Machine has a custom Policy Handler of: %s."), szHandler)); + + // + // Search for the , + // + + while (*lpEntryPoint && *lpEntryPoint != TEXT(',')) { + lpEntryPoint++; + } + + + // + // Check if we found the , + // + + if (*lpEntryPoint) { + + *lpEntryPoint = TEXT('\0'); + lpEntryPoint++; + + + hDLL = LoadLibraryA(szHandler); + + if (hDLL) { + + pfn = (PFNPROCESSPOLICIES) GetProcAddress(hDLL, lpEntryPoint); + + if (pfn != NULL) { + + // + // Map in HKEY_CURRENT_USER, and call the function. + // Note that the parameters are UNICODE. + // + + OpenHKeyCurrentUser(lpProfile); + + fRet = (*pfn) (NULL, + szLocalPath, + lpProfile->szUserName, + szComputerName, + 0); + + CloseHKeyCurrentUser(lpProfile); + + // + // if callout policy downloader returns FALSE, then we don't + // do any processing on our own. If it returns TRUE then we + // go ahead and process policies normally, in addition to whatever + // he may have done. + // + + if (!fRet) { + FreeLibrary(hDLL); + return TRUE; + } + + } else { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to find entry point %s in policy dll. Error %d."), + lpEntryPoint, GetLastError())); + } + + FreeLibrary(hDLL); + + } else { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to load %s with error %d."), + szHandler, GetLastError())); + } + } + } + } + + + // + // Load the policy hive into registry + // + + lResult = MyRegLoadKey(lpProfile, HKEY_USERS, + g_szTmpKeyName, szLocalPath); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to load policy hive. Error = %d"), lResult)); + return FALSE; + } + + + // + // Open the policy hive. + // + + lResult = RegOpenKeyEx (HKEY_USERS, + g_szTmpKeyName, + 0, + KEY_READ, + &hkeyMain); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to open policy hive. Error = %d"), lResult)); + MyRegUnLoadKey(HKEY_USERS, g_szTmpKeyName); + + return FALSE; + } + + + + // + // For user and machine policies, see if there is an appropriate entry + // in policy file (either a key with user/computer name, + // or a default user or workstation entry). If there is, then merge + // information under that key into registry. (If there isn't, it's + // not an error-- just nothing to do.) + // + + + // + // Merge user-specific policies if user name was specified + // + + if (RegOpenKeyEx(hkeyMain, + REGSTR_KEY_POL_USERS, + 0, + KEY_READ, + &hkeyRoot) == ERROR_SUCCESS) { + + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Looking for user specific policy."))); + + hkeyUser = OpenUserKey(hkeyRoot, lpProfile->szUserName, &fFoundUser); + + if (hkeyUser) { + MergeRegistryData(hkeyUser,lpProfile->hKeyCurrentUser,szKeyNameBuffer, ARRAYSIZE(szKeyNameBuffer)); + RegCloseKey(hkeyUser); + } + + RegCloseKey(hkeyRoot); + } + + + + // + // Merge group specific policies if user name specified, and we + // *didn't* find a specific user entry above + // + + if (!fFoundUser && *lpProfile->szServerName) { + HKEY hkeyGroups, hkeyGroup; + LPTSTR GroupBuffer, ApiBuf; + DWORD dwGroupSize = DEFAULT_GROUP_SIZE; + DWORD uEntriesRead; + + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Processing group(s) policy."))); + + GroupBuffer = GlobalAlloc(GPTR, DEFAULT_GROUP_SIZE * sizeof(TCHAR)); + + if (GroupBuffer) { + + // + // if there is a group processing order specified in policy hive, + // then process groups + // + + if (RegOpenKeyEx(hkeyMain, + REGSTR_KEY_POL_USERGROUPS, + 0, + KEY_READ, + &hkeyGroups) == ERROR_SUCCESS) { + + + if (GetGroupProcessingOrder(hkeyMain, &GroupBuffer, &dwGroupSize)) { + + // + // Enumerate the groups that this user belongs to + // + + ApiBuf = GetUserGroups (lpProfile, &uEntriesRead); + + + if (ApiBuf) { + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: User belongs to %d groups."), uEntriesRead)); + + if (uEntriesRead) { + + // + // Walk through the list of groups (ordered lowest priority + // to highest priority). for each group, if the user belongs + // to it then download policies for that group. + // + + LPTSTR pszGroup = GroupBuffer; + TCHAR szKeyNameBuffer[MAX_PATH+1]; + + while (*pszGroup) { + + // + // Does user belong to this group? + // + + if (FindGroupInList(pszGroup, ApiBuf)) { + + // + // Open the key in the hive for this group + // + + if (RegOpenKeyEx (hkeyGroups, + pszGroup, + 0, + KEY_READ, + &hkeyGroup) == ERROR_SUCCESS) { + + + // + // Merge group policies + // + + MergeRegistryData(hkeyGroup, + lpProfile->hKeyCurrentUser, + szKeyNameBuffer, + ARRAYSIZE(szKeyNameBuffer)); + + RegCloseKey (hkeyGroup); + } + } + + pszGroup += lstrlen(pszGroup) + 1; + } + } + + GlobalFree (ApiBuf); + + } else { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to get user's groups."))); + } + + } else { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to get group processing order."))); + } + + RegCloseKey(hkeyGroups); + + } else { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to allocate memory for group policy. Error = %d"), GetLastError())); + } + + GlobalFree (GroupBuffer); + + } else { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to allocate memory for group policy. Error = %d"), GetLastError())); + } + } + + + + // + // Merge machine-specific policies if computer name was specified + // + + if (RegOpenKeyEx(hkeyMain, + REGSTR_KEY_POL_COMPUTERS, + 0, + KEY_READ, + &hkeyRoot) == ERROR_SUCCESS) { + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Looking for machine specific policy."))); + + hkeyUser = OpenUserKey(hkeyRoot, szComputerName, &fFoundUser); + + if (hkeyUser) { + MergeRegistryData(hkeyUser, HKEY_LOCAL_MACHINE, szKeyNameBuffer, ARRAYSIZE(szKeyNameBuffer)); + RegCloseKey(hkeyUser); + } + + RegCloseKey(hkeyRoot); + } + + + + // + // Close the policy key + // + + RegCloseKey(hkeyMain); + + + // + // Unload the policy hive. + // + + if (!MyRegUnLoadKey(HKEY_USERS, g_szTmpKeyName)) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to unload policy hive. Error = %d"), lResult)); + return FALSE; + } + + + + // + // Delete the policy files + // + + if (!DeleteFile (szLocalPath)) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to delete policy file <%s>. Error %d"), + szLocalPath, GetLastError())); + } + + lstrcat (szLocalPath, c_szLog); + if (!DeleteFile (szLocalPath)) { + DebugMsg((DM_WARNING, TEXT("ApplyPolicy: Failed to delete policy log file <%s>. Error %d"), + szLocalPath, GetLastError())); + } + + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("ApplyPolicy: Leaving succesfully."))); + + return TRUE; +} + + +//************************************************************* +// +// OpenUserKey() +// +// Purpose: Attempts to open the user specific key, or the +// .default key. +// +// Parameters: hkeyRoot - Root key +// pszName - User name +// fFoundSpecific - Found the requested key +// +// Return: hkey if successful +// NULL if not +// +// Comments: +// +// History: Date Author Comment +// 9/13/95 ericflo Ported +// +//************************************************************* + +HKEY OpenUserKey(HKEY hkeyRoot,LPCTSTR pszName, BOOL *pfFoundSpecific) +{ + HKEY hkeyTest; + *pfFoundSpecific = FALSE; + + // + // See if there is a subkey under the specified key with the given + // user name + // + + if ((RegOpenKeyEx(hkeyRoot, + pszName, + 0, + KEY_READ, + &hkeyTest)) == ERROR_SUCCESS) { + + *pfFoundSpecific = TRUE; + DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: Found specific entry for %s ignoring .Default."), pszName)); + return hkeyTest; + } + + // + // If not, see if there is a default key + // + + if ((RegOpenKeyEx(hkeyRoot, + REGSTR_KEY_POL_DEFAULT, + 0, + KEY_READ, + &hkeyTest)) == ERROR_SUCCESS) { + + DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: No entry for %s, using .Default instead."), pszName)); + return hkeyTest; + } + + + // + // No entry for this name in policy file + // + + DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: No user/machine specific policy and no .Default policy."))); + return NULL; +} + + +//************************************************************* +// +// MergeRegistryData() +// +// Purpose: Merges hkeySrc and subkeys into hkeyDst. +// +// Parameters: hkeySrc - Source +// hkeyDst - Destination +// pszKeyNameBuffer - Key name +// cbKeyNameBuffer - Size of key name buffer +// +// +// Return: ERROR_SUCCESS if successful +// otherwise an error value +// +// Comments: +// +// History: Date Author Comment +// 9/13/95 ericflo Ported +// +//************************************************************* + +UINT MergeRegistryData(HKEY hkeySrc, HKEY hkeyDst, LPTSTR pszKeyNameBuffer, + UINT cbKeyNameBuffer) +{ + UINT nIndex = 0,uRet=ERROR_SUCCESS; + + // + // Look for any subkeys of the source key + // + + while ((uRet=RegEnumKey(hkeySrc,nIndex,pszKeyNameBuffer, + cbKeyNameBuffer)) == ERROR_SUCCESS) { + + HKEY hkeySubkeySrc,hkeySubkeyDst; + + + // + // Create the subkey under the destination key + // + + if ((uRet=RegCreateKey(hkeyDst,pszKeyNameBuffer, + &hkeySubkeyDst)) != ERROR_SUCCESS) + return uRet; + + if ((uRet=RegOpenKey(hkeySrc, pszKeyNameBuffer, + &hkeySubkeySrc)) != ERROR_SUCCESS) { + RegCloseKey(hkeySubkeyDst); + return uRet; + } + + + // + // Copy the key values from source subkey to destination subkey + // + + uRet=CopyKeyValues(hkeySubkeySrc,hkeySubkeyDst); + + if (uRet == ERROR_SUCCESS) { + + // + // Merge recursively on subkeys of these keys, if any + // + + uRet = MergeRegistryData(hkeySubkeySrc,hkeySubkeyDst,pszKeyNameBuffer, + cbKeyNameBuffer); + } + + RegCloseKey(hkeySubkeySrc); + RegCloseKey(hkeySubkeyDst); + + if (uRet != ERROR_SUCCESS) { + return uRet; + } + + nIndex ++; + } + + + if (uRet == ERROR_NO_MORE_ITEMS) { + uRet=ERROR_SUCCESS; + } + + return uRet; +} + +//************************************************************* +// +// CopyKeyValues() +// +// Purpose: Copies all key values from hkeySrc to hkeyDst +// +// Parameters: hkeySrc - Source +// hkeyDst - destination +// +// Return: Error code +// +// Comments: +// +// History: Date Author Comment +// 9/14/95 ericflo Ported +// +//************************************************************* + +UINT CopyKeyValues(HKEY hkeySrc, HKEY hkeyDst) +{ + DWORD dwSubkeyCount,dwMaxSubkeyNameLen,dwMaxClassNameLen,dwValueCount, + dwMaxValueNameLen,dwMaxValueDataLen,dwDescriptorLen,dwClassNameLen; + FILETIME ftLastWriteTime; + UINT uRet=ERROR_SUCCESS; + TCHAR szClassName[255]; + + // + // Do RegQueryInfoKey to find out if there are values for the source key, + // and the size of value name and value data buffes to alloc + // + + dwClassNameLen = ARRAYSIZE(szClassName); + + uRet=RegQueryInfoKey(hkeySrc,szClassName,&dwClassNameLen,NULL,&dwSubkeyCount, + &dwMaxSubkeyNameLen,&dwMaxClassNameLen,&dwValueCount,&dwMaxValueNameLen, + &dwMaxValueDataLen,&dwDescriptorLen,&ftLastWriteTime); + + if (uRet != ERROR_SUCCESS) { + return uRet; + } + + + // + // If there are values... + // + + + if (dwValueCount) { + TCHAR ValueName[MAX_PATH]; + LPBYTE ValueData; + DWORD dwType,dwValueNameSize,dwValueDataSize; + UINT nIndex = 0; + + + ValueData = GlobalAlloc (GPTR, MAX_VALUE_DATA); + + if (!ValueData) { + return GetLastError(); + } + + // + // the "**delvals" control code is special, must be processed + // first; look for it now and if it exists delete all existing + // values under this key in destination registry + // + + if (RegQueryValueEx(hkeySrc,g_szPrefixDelvals,NULL,NULL,NULL,NULL) == ERROR_SUCCESS) { + + DeleteAllValues(hkeyDst); + } + + // + // Enumerate the values of the source key, and create each value + // under the destination key + // + + do { + dwValueNameSize = MAX_PATH; + dwValueDataSize = MAX_VALUE_DATA; + + if ((uRet=RegEnumValue(hkeySrc,nIndex, ValueName, + &dwValueNameSize,NULL,&dwType, ValueData, + &dwValueDataSize)) == ERROR_SUCCESS) { + + DWORD dwPrefix; + + // + // Look for special prefixes which indicate we should treat + // these values specially + // + + if (HasSpecialPrefix(ValueName, &dwPrefix, ValueName)) { + + // + // ValueName now contains real value name stripped + // of prefix, filled in above by HasSpecialPrefix(). + // Adjust value name size, the value name will shorten + // because the prefix has been removed. + // + + dwValueNameSize = lstrlen (ValueName) + 1; + + switch (dwPrefix) { + + case PREFIX_DELETE: + + // + // Delete this value in destination + // + + RegDeleteValue(hkeyDst, ValueName); + uRet = ERROR_SUCCESS; + break; + + case PREFIX_SOFT: + + // + // "soft" value, only set this if it doesn't already + // exist in destination + // + + { + + TCHAR TmpValueData[MAX_PATH+1]; + DWORD dwSize=MAX_PATH+1; + + if (RegQueryValueEx(hkeyDst, ValueName, + NULL,NULL,(LPBYTE) TmpValueData, + &dwSize) != ERROR_SUCCESS) { + + // + // The value doesn't exist, set the value. + // + + uRet=RegSetValueEx(hkeyDst, ValueName, 0, + dwType, ValueData, + dwValueDataSize); + + } else { + + // + // Value already exists, nothing to do + // + + uRet = ERROR_SUCCESS; + } + + } + + break; + + case PREFIX_DELVALS: + // processed early on above, fall through and ignore + + default: + + // + // Got some prefix that we don't understand... presumably, + // from a future version. Ignore this value, rather than + // propagating it into the registry, prefix and all. + // This will give us less backward compatibility headaches + // down the road. + // + + uRet = ERROR_SUCCESS; // nothing to do + + break; + } + } else { + + // + // Copy the value normally to destination key + // + + uRet=RegSetValueEx(hkeyDst,ValueName,0, + dwType,ValueData,dwValueDataSize); + +#if DBG + if (uRet == ERROR_SUCCESS) { + + switch (dwType) { + case REG_SZ: + case REG_EXPAND_SZ: + DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s => %s [OK]"), + ValueName, (LPTSTR)ValueData)); + break; + + case REG_DWORD: + DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s => %d [OK]"), + ValueName, (DWORD)*ValueData)); + break; + + default: + DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s was set successfully"), + ValueName)); + } + + } else { + DebugMsg((DM_WARNING, TEXT("CopyKeyValues: Failed to set %s with error %d."), + ValueName, uRet)); + } +#endif + + } + } + + nIndex++; + + } while (uRet == ERROR_SUCCESS); + + + if (uRet == ERROR_NO_MORE_ITEMS) { + uRet=ERROR_SUCCESS; + } + + GlobalFree (ValueData); + } + + return uRet; +} + + +//************************************************************* +// +// HasSpecialPrefix() +// +// Purpose: Checks to see if szValueName has a special prefix (a la +// "**<something>." Returns TRUE if it does, FALSE otherwise. +// if TRUE, returns the numerical index of the prefix in *pdwPrefix, +// and copies the rest of value name (after the ".") into +// szStrippedValueName. Buffer for szStrippedValueName must be at +// least as large as szValueName. It is safe to pass the same +// buffer to szValueName and szStrippedValueName and have the name +// modified in place. +// +// Parameters: szValueName - Value Name +// pdwPrefix - Index of the prefix +// szStrippedValueName - Value name without the ** +// +// +// Return: TRUE if value name has a prefix +// FALSE if it does not +// +// Comments: +// +// History: Date Author Comment +// 9/14/95 ericflo Ported +// +//************************************************************* + +typedef struct tagPREFIXMAP { + const LPTSTR pszPrefix; + DWORD dwPrefixIndex; +} PREFIXMAP; + + + +BOOL HasSpecialPrefix(LPTSTR szValueName, DWORD * pdwPrefix, + LPTSTR szStrippedValueName) +{ + + PREFIXMAP PrefixMap[] = { + {g_szPrefixDel, PREFIX_DELETE}, + {g_szPrefixSoft, PREFIX_SOFT}, + {g_szPrefixDelvals, PREFIX_DELVALS} + }; + UINT nCount,nLen; + + + // + // Does the value name begin with "**"? + // + + if (!szValueName || (lstrlen(szValueName) < 2) || + szValueName[0] != TEXT('*') || szValueName[1] != TEXT('*')) + + return FALSE; // not a special prefix + + + // + // Try all the prefixes we know to try to find a match + // + + for (nCount = 0; nCount < ARRAYSIZE(PrefixMap); nCount++) { + nLen = lstrlen (PrefixMap[nCount].pszPrefix); + + if (CompareString (LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, + szValueName, nLen, + PrefixMap[nCount].pszPrefix, nLen) == 2) { + + *pdwPrefix = PrefixMap[nCount].dwPrefixIndex; + + // + // make a copy of the value name, sans prefix, into + // the stripped value name buffer + // + + lstrcpy (szStrippedValueName,szValueName + nLen); + return TRUE; + } + } + + // + // this is a prefix, but not one we know. + // + + *pdwPrefix = PREFIX_UNKNOWN; + lstrcpy (szStrippedValueName,szValueName); + return TRUE; +} + +//************************************************************* +// +// GetGroupProcessingOrder() +// +// Purpose: Gets the list of groups in order +// +// Parameters: hkeyHiveRoot - Registry key +// GroupBuffer - Pointer to group buffer +// pdwBufferSize - Buffer size +// +// Return: Number of entries if successful +// 0 if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 9/14/95 ericflo Ported +// +//************************************************************* + +BOOL GetGroupProcessingOrder(HKEY hkeyHiveRoot, LPTSTR * pGroupBuffer, + DWORD * pdwGroupSize) +{ + DWORD cEntries,cMaxValueName,cMaxData; + HKEY hkeyGroupData; + UINT uRet; + LPTSTR GroupBuffer = *pGroupBuffer; + DWORD dwGroupSize = *pdwGroupSize; + TCHAR szValueName[10], szGroupName[48+1]; // netware groups can be up to 48 chars + DWORD dwUsed = 0, dwSize; // amount of buffer used + UINT nLen,nRead=0; + + + // + // Open the group data key + // + + uRet = RegOpenKeyEx(hkeyHiveRoot, + REGSTR_KEY_POL_USERGROUPDATA, + 0, + KEY_READ, + &hkeyGroupData); + + if (uRet != ERROR_SUCCESS) { + + // + // Group data key doesn't exist (most likely), no downloading to do + // + + return FALSE; + } + + + // + // Find out the number of values in group data key + // + + if ((RegQueryInfoKey (hkeyGroupData,NULL,NULL,NULL,NULL,NULL, + NULL,&cEntries,&cMaxValueName,&cMaxData,NULL,NULL ) != ERROR_SUCCESS) || + !cEntries) { + + RegCloseKey(hkeyGroupData); + return FALSE; + } + + + // + // The values are stored as "1"="<group name>", "2"="<group name>", etc. + // where 1 is most important. we will pack the names into a buffer lowest + // priority to highest. So if we have n values, start with value name "<n>" + // and work down to "1". + // + + while (cEntries) { + + wsprintf(szValueName, TEXT("%lu"), cEntries); + + dwSize = ARRAYSIZE(szGroupName); + + if (RegQueryValueEx(hkeyGroupData,szValueName,NULL,NULL, + (LPBYTE) szGroupName,&dwSize) == ERROR_SUCCESS) { + + nLen = lstrlen(szGroupName) + 1; + + // + // Resize buffer if neccessary (add 1 for extra terminating null) + // + + if (nLen + dwUsed + 1 > dwGroupSize) { + + // + // add a little extra so we don't realloc on every item + // + + dwGroupSize = dwGroupSize + nLen + 256; + + GroupBuffer = GlobalReAlloc(GroupBuffer, + (dwGroupSize * sizeof(TCHAR)), + GMEM_MOVEABLE); + + if (!GroupBuffer) { + + RegCloseKey(hkeyGroupData); + return FALSE; + } + + + } + + lstrcpy(GroupBuffer + dwUsed, szGroupName); + dwUsed += nLen; + nRead++; + } + + cEntries --; + } + + // + // Doubly null-terminate buffer + // + + *(GroupBuffer + dwUsed) = TEXT('\0'); + + RegCloseKey(hkeyGroupData); + + *pGroupBuffer = GroupBuffer; + *pdwGroupSize = dwGroupSize; + + return (nRead > 0); +} + +//************************************************************* +// +// FindGroupInList() +// +// Purpose: Determines if the requested group +// is in the list of groups +// +// Parameters: pszGroupName - Group looking for +// pszGroupList - List of groups null seperated +// +// Return: TRUE if found +// FALSE if not +// +// Comments: +// +// History: Date Author Comment +// 9/15/95 ericflo Ported +// +//************************************************************* + +BOOL FindGroupInList(LPTSTR pszGroupName, LPTSTR pszGroupList) +{ + + while (*pszGroupList) { + + if (!lstrcmpi(pszGroupList,pszGroupName)) { + DebugMsg((DM_VERBOSE, TEXT("FindGroupInList: User is a member of the %s group."), pszGroupName)); + return TRUE; + } + + pszGroupList += lstrlen(pszGroupList) + 1; + } + + DebugMsg((DM_VERBOSE, TEXT("FindGroupInList: User is NOT a member of the %s group."), pszGroupName)); + return FALSE; +} + +//************************************************************* +// +// GetUserGroups() +// +// Purpose: Retrieves a list of groups this user belongs to +// +// Parameters: lpProfile - Profile information +// puEntriesRead - Number of groups +// +// Return: Pointer to list if successful +// Null if not +// +// Comments: +// +// History: Date Author Comment +// 9/15/95 ericflo Created +// +//************************************************************* + +LPTSTR GetUserGroups (LPPROFILE lpProfile, DWORD * puEntriesRead) +{ + UINT err, nIndex; + LPBYTE lpGroups; + PGROUP_INFO_0 pgi0; + DWORD dwSize = DEFAULT_GROUP_SIZE; + DWORD dwEntriesRead, dwTotalEntries; + DWORD cchSizeNeeded; + LPTSTR lpGroupNames, lpName; + + + // + // Query for the groups + // + + err = NetUserGetGroups (lpProfile->szServerName, + lpProfile->szUserName, + 0, + &lpGroups, + dwSize, + &dwEntriesRead, + &dwTotalEntries); + + + // + // Resize if default buffer is too small + // + + if (err == ERROR_MORE_DATA || err == NERR_BufTooSmall) { + + dwSize = dwTotalEntries; + + lpGroups = GlobalReAlloc (lpGroups, dwSize, GMEM_MOVEABLE); + + if (!lpGroups) + return NULL; + + err = NetUserGetGroups (lpProfile->szServerName, + lpProfile->szUserName, + 0, + &lpGroups, + dwSize, + &dwEntriesRead, + &dwTotalEntries); + + if (err != ERROR_SUCCESS) { + return NULL; + } + } + + + // + // NetUserGetGroups returns names packed in structures with fixed-length + // fields. Need to copy that into caller's buffer packed with the names + // packed end-to-end. + // + // Count the total buffer size we need, which will be smaller than the + // API buffer to NetUserGetGroups because we're not using fixed-length + // fields + // + + cchSizeNeeded = 1; + pgi0 = (PGROUP_INFO_0) lpGroups; + + for (nIndex=0; nIndex < dwEntriesRead; nIndex++) { + + cchSizeNeeded += lstrlen(pgi0->grpi0_name) + 1; + pgi0++; + } + + *puEntriesRead = dwEntriesRead; + + + // + // Build the list of group names + // + + lpGroupNames = GlobalAlloc (GPTR, cchSizeNeeded * sizeof (TCHAR)); + + if (!lpGroupNames) { + return NULL; + } + + + DebugMsg((DM_VERBOSE, TEXT("GetUserGroups: User is a member of the following global groups:"))); + + lpName = lpGroupNames; + pgi0 = (PGROUP_INFO_0) lpGroups; + + for (nIndex=0; nIndex < dwEntriesRead; nIndex++) { + + DebugMsg((DM_VERBOSE, TEXT("GetUserGroups: %s"), pgi0->grpi0_name)); + lstrcpy (lpName, pgi0->grpi0_name); + lpName += lstrlen(pgi0->grpi0_name) + 1; + pgi0++; + } + + + // + // Free the memory allocated by NetUserGetGroups + // + + GlobalFree (lpGroups); + + + return lpGroupNames; + +} diff --git a/private/windows/gina/userenv/policy.h b/private/windows/gina/userenv/policy.h new file mode 100644 index 000000000..fa0382eae --- /dev/null +++ b/private/windows/gina/userenv/policy.h @@ -0,0 +1,11 @@ +//************************************************************* +// +// Policy functions header file +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +BOOL ApplyPolicy (LPPROFILE lpProfile); diff --git a/private/windows/gina/userenv/profile.c b/private/windows/gina/userenv/profile.c new file mode 100644 index 000000000..d908e6485 --- /dev/null +++ b/private/windows/gina/userenv/profile.c @@ -0,0 +1,5851 @@ +//************************************************************* +// +// Profile management routines +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + +// +// Local function proto-types +// + +BOOL CheckNetDefaultProfile (LPPROFILE lpProfile); +BOOL ParseProfilePath(LPPROFILE lpProfile, LPTSTR lpProfilePath); +BOOL RestoreUserProfile(LPPROFILE lpProfile); +BOOL TestIfUserProfileLoaded(HANDLE hUserToken, LPPROFILEINFO lpProfileInfo); +BOOL GetTempProfileDir(LPPROFILE lpProfile, LPTSTR lpProfileImage); +BOOL ComputeLocalProfileName (LPPROFILE lpProfile, LPTSTR lpUserName, + LPTSTR lpProfileImage, DWORD cchMaxProfileImage, + LPTSTR lpExpProfileImage, DWORD cchMaxExpProfileImage); +BOOL CreateLocalProfileKey (LPPROFILE lpProfile, PHKEY phKey, BOOL *bKeyExists); +BOOL GetLocalProfileImage(LPPROFILE lpProfile, BOOL *bNewUser); +BOOL IsCentralProfileReachable(LPPROFILE lpProfile, BOOL *bCreateCentralProfile, + BOOL *bMandatory); +BOOL UpdateToLatestProfile(LPPROFILE lpProfile, LPTSTR lpCentralProfile, + LPTSTR lpLocalProfile, LPTSTR lpSidString); +BOOL IssueDefaultProfile (LPPROFILE lpProfile, LPTSTR lpDefaultProfile, + LPTSTR lpLocalProfile, LPTSTR lpSidString, + BOOL bMandatory); +BOOL UpgradeCentralProfile (LPPROFILE lpProfile, LPTSTR lpOldProfile); +BOOL UpgradeProfile (LPPROFILE lpProfile); +BOOL IsUserAGuest(LPPROFILE lpProfile); +BOOL IsUserAnAdminMember(LPPROFILE lpProfile); +BOOL SaveProfileInfo (LPPROFILE lpProfile); +LPPROFILE LoadProfileInfo(HANDLE hToken); +BOOL CheckForSlowLink(LPPROFILE lpProfile, DWORD dwTime); +BOOL APIENTRY SlowLinkDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +DWORD GetUserPreferenceValue(HANDLE hToken); +BOOL APIENTRY ChooseProfileDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +DWORD ApplySecurityToRegistryTree(HKEY RootKey, PSECURITY_DESCRIPTOR pSD); + +//************************************************************* +// +// LoadUserProfile() +// +// Purpose: Loads the user's profile, if unable to load +// use the cached profile or issue the default profile. +// +// Parameters: hToken - User's token +// lpProfileInfo - Profile Information +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/6/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI LoadUserProfile (HANDLE hToken, LPPROFILEINFO lpProfileInfo) +{ + LPPROFILE lpProfile; + BOOL bResult = FALSE; + HANDLE hEvent = NULL; + TCHAR szEventName[MAX_PATH]; + DWORD dwResult; + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + +#if DBG + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("========================================================="))); + + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Entering, hToken = <0x%x>, lpProfileInfo = 0x%x"), + hToken, lpProfileInfo)); + + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->dwFlags = <0x%x>"), + lpProfileInfo->dwFlags)); + + if (lpProfileInfo->lpUserName) { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpUserName = <%s>"), + lpProfileInfo->lpUserName)); + } else { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL user name!"))); + } + + if (lpProfileInfo->lpProfilePath) { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpProfilePath = <%s>"), + lpProfileInfo->lpProfilePath)); + } else { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL central profile path"))); + } + + if (lpProfileInfo->lpDefaultPath) { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpDefaultPath = <%s>"), + lpProfileInfo->lpDefaultPath)); + } else { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL default profile path"))); + } + + if (lpProfileInfo->lpServerName) { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpServerName = <%s>"), + lpProfileInfo->lpServerName)); + } else { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL server name"))); + } + + if (lpProfileInfo->dwFlags & PI_APPLYPOLICY) { + if (lpProfileInfo->lpPolicyPath) { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpPolicyPath = <%s>"), + lpProfileInfo->lpPolicyPath)); + } else { + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL policy path, but PI_APPLYPOLICY is set."))); + } + } + +#endif + + + // + // Check Parameters + // + + if (lpProfileInfo->dwSize != sizeof(PROFILEINFO)) { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: lpProfileInfo->dwSize != sizeof(PROFILEINFO)"))); + SetLastError(ERROR_INVALID_PARAMETER); + goto Exit; + } + + if (!lpProfileInfo->lpUserName || !(*lpProfileInfo->lpUserName)) { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: received a NULL pointer for lpUserName."))); + SetLastError(ERROR_INVALID_PARAMETER); + goto Exit; + } + + + // + // Create an event to prevent multiple threads/process from trying to + // load the profile at the same time. + // + + wsprintf (szEventName, TEXT("userenv: %s"), lpProfileInfo->lpUserName); + CharLower (szEventName); + + InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ); + + SetSecurityDescriptorDacl ( + &sd, + TRUE, // Dacl present + NULL, // NULL Dacl + FALSE // Not defaulted + ); + + sa.lpSecurityDescriptor = &sd; + sa.bInheritHandle = FALSE; + sa.nLength = sizeof( sa ); + + hEvent = CreateEvent ( &sa, TRUE, TRUE, szEventName); + + if (!hEvent) { + + if ( GetLastError() == ERROR_INVALID_HANDLE ) + { + hEvent = OpenEvent( EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, szEventName ); + } + + if ( !hEvent ) + { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to create event %s. Error = %d."), + szEventName, GetLastError())); + goto Exit; + + } + } + + + if ((WaitForSingleObject (hEvent, INFINITE) == WAIT_FAILED)) { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to wait on the event. Error = %d."), + GetLastError())); + goto Exit; + } + + // + // This will clear the event so other threads/process will have to + // wait in the WaitForSingleObject call. + // + + ResetEvent (hEvent); + + + // + // Check if the profile is loaded already. + // + + if (TestIfUserProfileLoaded(hToken, lpProfileInfo)) { + bResult = TRUE; + goto Exit; + } + + + // + // Allocate an internal Profile structure to work with. + // + + lpProfile = (LPPROFILE) LocalAlloc (LPTR, sizeof(PROFILE)); + + if (!lpProfile) { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to allocate memory"))); + goto Exit; + } + + + // + // Save the data passed in. + // + + lpProfile->dwFlags = lpProfileInfo->dwFlags; + lpProfile->dwUserPreference = GetUserPreferenceValue(hToken); + lpProfile->hToken = hToken; + lstrcpy (lpProfile->szUserName, lpProfileInfo->lpUserName); + + if (lpProfileInfo->lpDefaultPath) { + lstrcpy (lpProfile->szDefaultProfile, lpProfileInfo->lpDefaultPath); + } + + if (lpProfileInfo->lpServerName) { + lstrcpy (lpProfile->szServerName, lpProfileInfo->lpServerName); + } + + if (lpProfileInfo->dwFlags & PI_APPLYPOLICY) { + if (lpProfileInfo->lpPolicyPath) { + lstrcpy (lpProfile->szPolicyPath, lpProfileInfo->lpPolicyPath); + } + } + + // + // If there is a central profile, check for 3.x or 4.0 format. + // + + if (lpProfileInfo->lpProfilePath && (*lpProfileInfo->lpProfilePath)) { + + // + // Call ParseProfilePath to work some magic on it + // + + if (!ParseProfilePath(lpProfile, lpProfileInfo->lpProfilePath)) { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ParseProfilePath returned FALSE"))); + SetLastError(ERROR_INVALID_PARAMETER); + LocalFree (lpProfile); + goto Exit; + } + + // + // The real central profile directory is... + // + + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: ParseProfilePath returned a directory of <%s>"), + lpProfile->szCentralProfile)); + } + + + // + // Load the user's profile + // + + if (!RestoreUserProfile(lpProfile)) { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: RestoreUserProfile returned FALSE"))); + LocalFree (lpProfile); + goto Exit; + } + + + // + // Set the USERPROFILE environment variable into this process's + // environmnet. This allows ExpandEnvironmentStrings to be used + // in the userdiff processing. + // + + SetEnvironmentVariable (TEXT("USERPROFILE"), lpProfile->szLocalProfile); + + + // + // Upgrade the profile if appropriate. + // + + if (!UpgradeProfile(lpProfile)) { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: UpgradeProfile returned FALSE"))); + } + + + // + // Apply Policy + // + + if (lpProfile->dwFlags & PI_APPLYPOLICY) { + if (!ApplyPolicy(lpProfile)) { + DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ApplyPolicy returned FALSE"))); + } + } + + + // + // Save the outgoing parameters + // + + lpProfileInfo->hProfile = (HANDLE) lpProfile->hKeyCurrentUser; + + + // + // Save the profile information in the registry. + // + + SaveProfileInfo (lpProfile); + + + // + // Free the structure + // + + LocalFree (lpProfile); + + + // + // Success! + // + + bResult = TRUE; + +Exit: + + if (hEvent) { + + // + // This will set the event so other threads/process can continue. + // + + SetEvent (hEvent); + CloseHandle (hEvent); + } + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Leaving with a value of %d. hProfile = <0x%x>"), + bResult, lpProfileInfo->hProfile)); + + DebugMsg((DM_VERBOSE, TEXT("========================================================="))); + + return bResult; +} + +//************************************************************* +// +// CheckNetDefaultProfile() +// +// Purpose: Checks if a network profile exists and +// caches it locally if it is valid. +// +// Parameters: lpProfile - Profile information +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: This routine assumes we are working +// in the user's context. +// +// History: Date Author Comment +// 9/21/95 ericflo Created +// +//************************************************************* + +BOOL CheckNetDefaultProfile (LPPROFILE lpProfile) +{ + HANDLE hFile; + WIN32_FIND_DATA fd; + TCHAR szBuffer[MAX_PATH]; + TCHAR szLocalDir[MAX_PATH]; + LPTSTR lpEnd; + BOOL bRetVal = TRUE; + BOOL bProfileReady =FALSE; + BOOL bDeleteLocal = FALSE; + LPTSTR lpNetPath = lpProfile->szDefaultProfile; + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Entering, lpNetPath = <%s>"), + lpNetPath)); + + + // + // Expand the local profile directory + // + + ExpandEnvironmentStrings(DEFAULT_NET_PROFILE, szLocalDir, MAX_PATH); + + + + // + // See if network copy exists + // + + hFile = FindFirstFile (lpNetPath, &fd); + + if (hFile != INVALID_HANDLE_VALUE) { + + + // + // Close the find handle + // + + FindClose (hFile); + + + // + // We found something. Is it a directory? + // + + if ( !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { + + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: FindFirstFile found a file."))); + goto CheckLocal; + } + + + // + // Is there a ntuser.* file in this directory? + // + + lstrcpy (szBuffer, lpNetPath); + lpEnd = CheckSlash (szBuffer); + lstrcpy (lpEnd, c_szNTUserStar); + + + hFile = FindFirstFile (szBuffer, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: FindFirstFile found a directory, but no ntuser files."))); + goto CheckLocal; + } + + FindClose (hFile); + + + // + // We found a valid network profile. + // + + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Found a valid network profile."))); + + if (CopyProfileDirectory (lpNetPath, szLocalDir, + CPD_IGNORECOPYERRORS | + CPD_COPYIFDIFFERENT | + CPD_SYNCHRONIZE )) { + bProfileReady = TRUE; + goto Exit; + } + + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Failed to copy network profile to local cache."))); + + } else { + + // + // If the network default user profile does not + // exist, then we want to delete it off of local + // machines. + // + + if (GetLastError() == ERROR_FILE_NOT_FOUND) { + bDeleteLocal = TRUE; + } + + } + + +CheckLocal: + + // + // See if local network copy exists + // + + hFile = FindFirstFile (szLocalDir, &fd); + + if (hFile != INVALID_HANDLE_VALUE) { + + + // + // Close the find handle + // + + FindClose (hFile); + + + // + // We found something. Is it a directory? + // + + if ( !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { + + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: FindFirstFile found a file."))); + bRetVal = FALSE; + goto Exit; + } + + + // + // If the network copy has been deleted, then delete this + // local copy also and just use the normal Default User profile. + // + + if (bDeleteLocal) { + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Removing local copy of network default user profile."))); + Delnode (szLocalDir); + goto Exit; + } + + + // + // Is there a ntuser.* file in this directory? + // + + lstrcpy (szBuffer, szLocalDir); + lpEnd = CheckSlash (szBuffer); + lstrcpy (lpEnd, c_szNTUserStar); + + + hFile = FindFirstFile (szBuffer, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: FindFirstFile found a directory, but no ntuser files."))); + bRetVal = FALSE; + goto Exit; + } + + FindClose (hFile); + + + // + // We found a valid local profile. + // + + bProfileReady = TRUE; + } + + +Exit: + + // + // If we are leaving successfully, then + // save the local profile directory. + // + + if (bRetVal && bProfileReady) { + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: setting default profile to <%s>"), szLocalDir)); + + lstrcpy (lpProfile->szDefaultProfile, szLocalDir); + + } else { + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: setting default profile to NULL"))); + + *lpProfile->szDefaultProfile = TEXT('\0'); + } + + + // + // Tag the internal flags so we don't do this again. + // + + lpProfile->dwInternalFlags |= DEFAULT_NET_READY; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Leaving with a value of %d."), bRetVal)); + + + return bRetVal; + +} + + +//************************************************************* +// +// ParseProfilePath() +// +// Purpose: Parses the profile path to determine if +// it points at a directory or a filename. +// If the path points to a filename, a subdirectory +// of a similar name is created. +// +// Parameters: lpProfile - Profile Information +// lpProfilePath - Input path +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/6/95 ericflo Created +// +//************************************************************* + +BOOL ParseProfilePath(LPPROFILE lpProfile, LPTSTR lpProfilePath) +{ + WIN32_FIND_DATA fd; + HANDLE hResult; + DWORD dwError; + TCHAR szProfilePath[MAX_PATH]; + TCHAR szExt[5]; + LPTSTR lpEnd; + UINT uiExtCount; + BOOL bRetVal = FALSE; + BOOL bUpgradeCentral = FALSE; + BOOL bMandatory = FALSE; + DWORD dwStart, dwDelta; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Entering, lpProfilePath = <%s>"), + lpProfilePath)); + + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to impersonate user"))); + return FALSE; + } + + // + // Start by calling FindFirstFile so we have file attributes + // to work with. + // + + dwStart = GetTickCount(); + + hResult = FindFirstFile(lpProfilePath, &fd); + + dwDelta = GetTickCount() - dwStart; + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Tick Count = %d"), dwDelta)); + + // + // It's magic time... + // + + if (hResult != INVALID_HANDLE_VALUE) { + + // + // FindFirst File found something. + // First close the handle, then look at + // the file attributes. + // + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: FindFirstFile found something with attributes <0x%x>"), + fd.dwFileAttributes)); + + FindClose(hResult); + + + // + // If we found a directory, copy the path to + // the result buffer and exit. + // + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a directory"))); + CheckForSlowLink (lpProfile, dwDelta); + lstrcpy (lpProfile->szCentralProfile, lpProfilePath); + bRetVal = TRUE; + goto Exit; + } + + + // + // We found a file. + // Jump to the filename generation code. + // + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a file"))); + + + // + // We set this flag now, but it is only used if a new + // central directory is created. + // + + bUpgradeCentral = TRUE; + + goto GenerateDirectoryName; + } + + // + // FindFirstFile failed. Look at the error to determine why. + // + + dwError = GetLastError(); + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: FindFirstFile failed with error %d"), + dwError)); + + + if ( (dwError == ERROR_FILE_NOT_FOUND) || + (dwError == ERROR_PATH_NOT_FOUND) ) { + + DWORD dwStrLen; + + // + // Nothing found with this name. If the name + // does not end in .usr or .man, attempt to create + // the directory. + // + + dwStrLen = lstrlen (lpProfilePath); + + if (dwStrLen >= 4) { + + lpEnd = lpProfilePath + dwStrLen - 4; + + if ( (lstrcmpi(lpEnd, c_szUSR) != 0) && + (lstrcmpi(lpEnd, c_szMAN) != 0) ) { + + + if (CreateSecureDirectory(lpProfile, lpProfilePath, NULL)) { + + // + // Successfully created the directory. + // + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Succesfully created the sub-directory"))); + CheckForSlowLink (lpProfile, dwDelta); + lstrcpy (lpProfile->szCentralProfile, lpProfilePath); + bRetVal = TRUE; + goto Exit; + + } else { + + // + // Failed to create the subdirectory + // + + DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to create user sub-directory. Error = %d"), + GetLastError())); + } + } + } + } + + else if (dwError == ERROR_ACCESS_DENIED) { + DebugMsg((DM_WARNING, TEXT("ParseProfilePath: You don't have permission to your central profile server! Error = %d"), + dwError)); + + if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && + !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { + + ReportError(lpProfile->dwFlags, IDS_ACCESSDENIED, lpProfilePath); + } + goto DisableAndExit; + } + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Did not create the sub-directory. Generating a new name."))); + + +GenerateDirectoryName: + + // + // If we made it here, either: + // + // 1) a file exists with the same name + // 2) the directory couldn't be created + // 3) the profile path ends in .usr or .man + // + // Make a local copy of the path so we can munge it. + // + + lstrcpy (szProfilePath, lpProfilePath); + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Entering name generating code working with a path of <%s>."), + szProfilePath)); + + + // + // Does this path have a filename extension? + // + + lpEnd = szProfilePath + lstrlen (szProfilePath) - 1; + + while (*lpEnd && (lpEnd >= szProfilePath)) { + if (*lpEnd == TEXT('.')) + break; + + if (*lpEnd == TEXT('\\')) + break; + + lpEnd--; + } + + if (*lpEnd != TEXT('.')) { + + // + // The path does not have an extension. Append .pds + // + + lpEnd = szProfilePath + lstrlen (szProfilePath); + lstrcpy (lpEnd, c_szPDS); + + } else { + + // + // The path has an extension. Append the new + // directory extension (.pds or .pdm). + // + + if (lstrcmpi(lpEnd, c_szMAN) == 0) { + lstrcpy (lpEnd, c_szPDM); + bMandatory = TRUE; + + } else { + lstrcpy (lpEnd, c_szPDS); + } + + } + + + + // + // Call FindFirstFile to see if this directory exists. + // + + hResult = FindFirstFile(szProfilePath, &fd); + + + + if (hResult != INVALID_HANDLE_VALUE) { + + // + // FindFirst File found something. + // First close the handle, then look at + // the file attributes. + // + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: FindFirstFile(2) found something with attributes <0x%x>"), + fd.dwFileAttributes)); + + FindClose(hResult); + + + // + // If we found a directory, copy the path to + // the result buffer and exit. + // + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a directory"))); + if (bMandatory) { + lstrcpy (lpProfile->szCentralProfile, szProfilePath); + lpProfile->dwInternalFlags |= PROFILE_MANDATORY; + } else { + CheckForSlowLink (lpProfile, dwDelta); + lstrcpy (lpProfile->szCentralProfile, szProfilePath); + } + bRetVal = TRUE; + goto Exit; + } + + + // + // We found a file that matches the generated name. + // + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a file with the name we generated."))); + + if (!bMandatory) { + CheckForSlowLink (lpProfile, dwDelta); + } + + if (bMandatory || ((lpProfile->dwUserPreference != USERINFO_LOCAL) && + !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK))) { + + ReportError(lpProfile->dwFlags, IDS_FAILEDDIRCREATE, szProfilePath); + } + + goto DisableAndExit; + } + + + // + // FindFirstFile failed. Look at the error to determine why. + // + + dwError = GetLastError(); + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: FindFirstFile failed with error %d"), + dwError)); + + + // + // If we are working with a mandatory profile, + // disable the central profile and try to log + // on with a cache. + // + + if (bMandatory) { + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Central mandatory profile is unreachable to due error %d."), dwError)); + + if (IsUserAnAdminMember(lpProfile)) { + ReportError(lpProfile->dwFlags, IDS_MANDATORY_NOT_AVAILABLE, dwError); + + lpProfile->szCentralProfile[0] = TEXT('\0'); + lpProfile->dwInternalFlags |= PROFILE_MANDATORY; + bRetVal = TRUE; + } else { + ReportError(lpProfile->dwFlags, IDS_MANDATORY_NOT_AVAILABLE2, dwError); + } + goto Exit; + } + + + // + // The user has a roaming profile, so it is ok to call + // CheckForSlowLink now. + // + + CheckForSlowLink (lpProfile, dwDelta); + + if ( (dwError == ERROR_FILE_NOT_FOUND) || + (dwError == ERROR_PATH_NOT_FOUND) ) { + + // + // Attempt to create the directory. + // + + if (CreateSecureDirectory(lpProfile, szProfilePath, NULL)) { + + // + // Successfully created the directory. + // + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Succesfully created the sub-directory"))); + + lstrcpy (lpProfile->szCentralProfile, szProfilePath); + + + if (bUpgradeCentral) { + bRetVal = UpgradeCentralProfile (lpProfile, lpProfilePath); + + } else { + bRetVal = TRUE; + } + + if (bRetVal) { + + // + // Success + // + + CheckForSlowLink (lpProfile, dwDelta); + + goto Exit; + + } else { + + // + // Delete the directory we created above. + // + + Delnode (lpProfile->szCentralProfile); + } + + + } else { + + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Failed to create the sub-directory"))); + + if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && + !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { + + ReportError(lpProfile->dwFlags, IDS_FAILEDDIRCREATE2, szProfilePath, GetLastError()); + } + goto DisableAndExit; + } + } + + // + // The central profile isn't reachable, or failed to upgrade. + // Disable the central profile and try to log + // on with a cache. + // + + dwError = GetLastError(); + DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Central profile is unreachable to due error %d, switching to local profile only."), dwError)); + + if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && + !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { + + ReportError(lpProfile->dwFlags, IDS_CENTRAL_NOT_AVAILABLE2, dwError); + } + +DisableAndExit: + + lpProfile->szCentralProfile[0] = TEXT('\0'); + + bRetVal = TRUE; + + +Exit: + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to revert to self"))); + } + + return bRetVal; +} + +//************************************************************* +// +// RestoreUserProfile() +// +// Purpose: Downloads the user's profile if possible, +// otherwise use either cached profile or +// default profile. +// +// Parameters: lpProfile - Profile information +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/19/95 ericflo Created +// +//************************************************************* + +BOOL RestoreUserProfile(LPPROFILE lpProfile) +{ + BOOL IsCentralReachable = FALSE; + BOOL IsLocalReachable = FALSE; + BOOL IsMandatory = FALSE; + BOOL IsProfilePathNULL = FALSE; + BOOL bCreateCentralProfile = FALSE; + BOOL bDefaultUsed = FALSE; + LPTSTR lpCentralProfile; + LPTSTR lpLocalProfile; + BOOL bProfileLoaded = FALSE; + BOOL bNewUser = TRUE; + LPTSTR SidString; + LONG error = ERROR_SUCCESS; + TCHAR szProfile[MAX_PATH]; + LPTSTR lpEnd; + BOOL bRet; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Entering"))); + + + // + // Get the Sid string for the current user + // + + SidString = GetSidString(lpProfile->hToken); + if (!SidString) { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to get sid string for user"))); + return FALSE; + } + + + // + // Initialization + // + + lpCentralProfile = lpProfile->szCentralProfile; + + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Profile path = <%s>"), lpCentralProfile ? lpCentralProfile : TEXT(""))); + if (!lpCentralProfile || !(*lpCentralProfile)) { + IsProfilePathNULL = TRUE; + } + + + // + // Test if this user is a guest. + // + + if (IsUserAGuest(lpProfile)) { + lpProfile->dwInternalFlags |= PROFILE_GUEST_USER; + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: User is a Guest"))); + } + + // + // Test if this user is an admin. + // + + if (IsUserAnAdminMember(lpProfile)) { + lpProfile->dwInternalFlags |= PROFILE_ADMIN_USER; + lpProfile->dwInternalFlags &= ~PROFILE_GUEST_USER; + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: User is a Admin"))); + } + + + // + // Decide if the central profilemage is available. + // + + IsCentralReachable = IsCentralProfileReachable(lpProfile, + &bCreateCentralProfile, + &IsMandatory); + + if (IsCentralReachable) { + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Central Profile is reachable"))); + + if (IsMandatory) { + lpProfile->dwInternalFlags |= PROFILE_MANDATORY; + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Central Profile is mandatory"))); + + } else { + lpProfile->dwInternalFlags |= PROFILE_UPDATE_CENTRAL; + lpProfile->dwInternalFlags |= bCreateCentralProfile ? PROFILE_NEW_CENTRAL : 0; + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Central Profile is floating"))); + + if ((lpProfile->dwUserPreference == USERINFO_LOCAL) || + (lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Ignoring central profile due to User Preference of Local only (or slow link)."))); + IsProfilePathNULL = TRUE; + IsCentralReachable = FALSE; + } + } + + } else { + if (!IsProfilePathNULL) { + error = GetLastError(); + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: IsCentralProfileReachable returned FALSE. error = %d"), + error)); + + ReportError(lpProfile->dwFlags, IDS_CENTRAL_NOT_AVAILABLE, error); + } + } + + + // + // Determine if the local copy of the profilemage is available. + // + + IsLocalReachable = GetLocalProfileImage(lpProfile, &bNewUser); + + if (IsLocalReachable) { + lpProfile->dwInternalFlags |= PROFILE_USE_CACHE; + lpProfile->dwInternalFlags |= bNewUser ? PROFILE_NEW_LOCAL : 0; + + } else { + if (!GetTempProfileDir(lpProfile, lpProfile->szLocalProfile)) { + error = GetLastError(); + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: GetTempProfileDir failed with error %d. Unable to issue temporary profile!"), error)); + ReportError(lpProfile->dwFlags, IDS_TEMP_DIR_FAILED, lpProfile->szLocalProfile, error); + goto Exit; + } + } + + + lpLocalProfile = lpProfile->szLocalProfile; + + + DebugMsg((DM_VERBOSE, TEXT("Local profile %s reachable"), IsLocalReachable ? TEXT("is") : TEXT("is not"))); + DebugMsg((DM_VERBOSE, TEXT("Local profile name is <%s>"), lpLocalProfile)); + + + // + // We can do a couple of quick checks here to filter out + // new users. + // + + if (( (lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL) && + (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) ) || + (!IsCentralReachable && + (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) )) { + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Working with a new user. Go straight to issuing a default profile."))); + goto IssueDefault; + } + + + // + // If both central and local profileimages exist, reconcile them + // and load. + // + + if (IsCentralReachable && IsLocalReachable) { + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: About to call UpdateToLatestProfile"))); + bRet = UpdateToLatestProfile(lpProfile, lpCentralProfile, lpLocalProfile, SidString); + + if (!bRet) { + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: UpdatetoLatestProfile failed. Issuing default profile"))); + lpProfile->dwInternalFlags &= ~PROFILE_UPDATE_CENTRAL; + lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; + goto IssueDefault; + } + + lstrcpy (szProfile, lpLocalProfile); + lpEnd = CheckSlash(szProfile); + + if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { + lstrcpy (lpEnd, c_szNTUserMan); + } else { + lstrcpy (lpEnd, c_szNTUserDat); + } + + error = MyRegLoadKey(lpProfile, HKEY_USERS, SidString, szProfile); + bProfileLoaded = (error == ERROR_SUCCESS); + + + // + // If we failed to load the central profile for some + // reason, don't update it when we log off. + // + + if (bProfileLoaded) { + goto Exit; + + } else { + lpProfile->dwInternalFlags &= ~PROFILE_UPDATE_CENTRAL; + lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; + ReportError(lpProfile->dwFlags, IDS_FAILED_LOAD_LOCAL, error); + goto IssueDefault; + } + } + + + // + // Only a local profile exists so use it. + // + + if (!IsCentralReachable && IsLocalReachable) { + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: No central profile. Attempting to load local profile."))); + + lstrcpy (szProfile, lpLocalProfile); + lpEnd = CheckSlash(szProfile); + + if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { + lstrcpy (lpEnd, c_szNTUserMan); + } else { + lstrcpy (lpEnd, c_szNTUserDat); + } + + error = MyRegLoadKey(lpProfile, HKEY_USERS, SidString, szProfile); + bProfileLoaded = (error == ERROR_SUCCESS); + + if (!bProfileLoaded) { + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: MyRegLoadKey returned FALSE."))); + + ReportError(lpProfile->dwFlags, IDS_FAILED_LOAD_LOCAL, error); + } + + if (!bProfileLoaded && IsProfilePathNULL) { + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Failed to load local profile and profile path is NULL, going to overwrite local profile"))); + lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; + goto IssueDefault; + } + goto Exit; + } + + + // + // Last combination. Unable to access a local profile cache, + // but a central profile exists. Use the temporary profile. + // + + + if (IsCentralReachable) { + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Using temporary cache with central profile"))); + + + // + // Impersonate the user + // + + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to impersonate user"))); + goto Exit; + } + + + + bRet = CopyProfileDirectory (lpCentralProfile, + lpLocalProfile, + CPD_IGNORECOPYERRORS | + CPD_COPYIFDIFFERENT | + CPD_SYNCHRONIZE); + + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to revert to self"))); + } + + + // + // Check return value + // + + if (!bRet) { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); + goto Exit; + } + + lstrcpy (szProfile, lpLocalProfile); + lpEnd = CheckSlash(szProfile); + + if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { + lstrcpy (lpEnd, c_szNTUserMan); + } else { + lstrcpy (lpEnd, c_szNTUserDat); + } + + error = MyRegLoadKey(lpProfile,HKEY_USERS, + SidString, + szProfile); + + bProfileLoaded = (error == ERROR_SUCCESS); + + + if (bProfileLoaded) { + goto Exit; + } + + // + // If a temporary cache exists, delete it, since we will + // generate a new one below. + // + + if (!(lpProfile->dwInternalFlags & PROFILE_USE_CACHE)) { + + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Deleting temporary profile directory <%s>."), lpLocalProfile)); + + if (!DeleteProfile (NULL, lpLocalProfile, TRUE)) { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: DeleteProfile returned false. Error = %d"), GetLastError())); + } + } + } + + +IssueDefault: + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Issuing default profile"))); + + // + // If a cache exists, delete it, since we will + // generate a new one below. + // + + if (lpProfile->dwInternalFlags & PROFILE_DELETE_CACHE) { + + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Deleting cached profile directory <%s>."), lpLocalProfile)); + + lpProfile->dwInternalFlags &= ~PROFILE_DELETE_CACHE; + + if (!DeleteProfile (SidString, lpLocalProfile, TRUE)) { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: DeleteProfileDirectory returned false. Error = %d"), GetLastError())); + } + } + + + // + // Create a local profile to work with + // + + if (!(lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL)) { + + if (lpProfile->dwInternalFlags & PROFILE_USE_CACHE) { + + if (!GetLocalProfileImage(lpProfile, &bNewUser)) { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: GetLocalProfileImage failed."))); + ReportError(lpProfile->dwFlags, IDS_TEMP_DIR_FAILED, GetLastError()); + goto Exit; + } + + } else { + + lstrcpy (szProfile, CONFIG_FILE_PATH); + if (!ComputeLocalProfileName(lpProfile, lpProfile->szUserName, + szProfile, MAX_PATH, + lpLocalProfile, MAX_PATH)) { + + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: ComputeLocalProfileName failed."))); + goto Exit; + } + } + } + + + // + // If a default profile location was specified, try + // that first. + // + + if ( !(lpProfile->dwInternalFlags & DEFAULT_NET_READY) ) { + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to impersonate user"))); + goto IssueLocalDefault; + } + + + CheckNetDefaultProfile (lpProfile); + + + // + // Go back to system security context + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to revert to self"))); + } + } + + + if ( lpProfile->szDefaultProfile && *lpProfile->szDefaultProfile) { + + if (IssueDefaultProfile (lpProfile, lpProfile->szDefaultProfile, + lpLocalProfile, SidString, + (lpProfile->dwInternalFlags & PROFILE_MANDATORY))) { + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Successfully setup the specified default."))); + bProfileLoaded = TRUE; + goto IssueDefaultExit; + } + + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: IssueDefaultProfile failed with specified default."))); + } + +IssueLocalDefault: + + // + // Issue the local default profile. + // + + if (IssueDefaultProfile (lpProfile, DEFAULT_PROFILE, + lpLocalProfile, SidString, + (lpProfile->dwInternalFlags & PROFILE_MANDATORY))) { + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Successfully setup the local default."))); + bProfileLoaded = TRUE; + goto IssueDefaultExit; + } + + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: IssueDefaultProfile failed with local default."))); + + +IssueDefaultExit: + + // + // If the default profile was successfully issued, then + // we need to set the security on the hive. + // + + if (bProfileLoaded) { + if (!SetupNewHive(lpProfile, SidString, NULL)) { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: SetupNewHive failed"))); + bProfileLoaded = FALSE; + } + + + } + + +Exit: + + // + // If the profile was loaded, then save the profile type in the + // user's hive, and setup the "User Shell Folders" section for + // Explorer. + // + + if (bProfileLoaded) { + + // + // Open the Current User key. This will be closed in + // UnloadUserProfile. + // + + error = RegOpenKeyEx(HKEY_USERS, SidString, 0, KEY_ALL_ACCESS, + &lpProfile->hKeyCurrentUser); + + if (error != ERROR_SUCCESS) { + bProfileLoaded = FALSE; + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to open current user key. Error = %d"), error)); + } + } + + + if (!bProfileLoaded) { + + // + // If the user is an Admin, then let him/her log on with + // either the .default profile, or an empty profile. + // + + if (lpProfile->dwInternalFlags & PROFILE_ADMIN_USER) { + ReportError(lpProfile->dwFlags, IDS_ADMIN_OVERRIDE, GetLastError()); + bProfileLoaded = TRUE; + } else { + DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to save settings in user hive or failed to apply security. Error = %d"), GetLastError())); + ReportError(lpProfile->dwFlags, IDS_FAILED_LOAD_PROFILE, GetLastError()); + + if (lpProfile->hKeyCurrentUser) { + RegCloseKey (lpProfile->hKeyCurrentUser); + } + + MyRegUnLoadKey(HKEY_USERS, SidString); + } + } + + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: About to Leave. Final Information follows:"))); + DebugMsg((DM_VERBOSE, TEXT("Profile was %s loaded."), bProfileLoaded ? TEXT("successfully") : TEXT("NOT successfully"))); + DebugMsg((DM_VERBOSE, TEXT("lpProfile->szCentralProfile = <%s>"), lpProfile->szCentralProfile)); + DebugMsg((DM_VERBOSE, TEXT("lpProfile->szLocalProfile = <%s>"), lpProfile->szLocalProfile)); + DebugMsg((DM_VERBOSE, TEXT("lpProfile->dwInternalFlags = 0x%x"), lpProfile->dwInternalFlags)); + + + // + // Free up the user's sid string + // + + DeleteSidString(SidString); + + DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Leaving."))); + + return bProfileLoaded; +} + + +//************************************************************* +// +// TestIfUserProfileLoaded() +// +// Purpose: Test to see if this user's profile is loaded. +// +// Parameters: hToken - user's token +// lpProfileInfo - Profile information from app +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/19/95 ericflo Ported +// +//************************************************************* + +BOOL TestIfUserProfileLoaded(HANDLE hToken, LPPROFILEINFO lpProfileInfo) +{ + LPTSTR SidString; + DWORD error; + HKEY hSubKey; + + + // + // Get the Sid string for the user + // + + SidString = GetSidString(hToken); + if (!SidString) { + DebugMsg((DM_WARNING, TEXT("TestIfUserProfileLoaded: Failed to get sid string for user"))); + return FALSE; + } + + + + error = RegOpenKeyEx(HKEY_USERS, SidString, 0, KEY_ALL_ACCESS, &hSubKey); + + if (error == ERROR_SUCCESS) { + + DebugMsg((DM_VERBOSE, TEXT("TestIfUserProfileLoaded: Profile already loaded."))); + + // + // This key will be closed in UnloadUserProfile + // + + lpProfileInfo->hProfile = (HANDLE) hSubKey; + } + + DeleteSidString(SidString); + + return(error == ERROR_SUCCESS); +} + +//************************************************************* +// +// SecureUserKey() +// +// Purpose: Sets security on a key in the user's hive +// so only admin's can change it. +// +// Parameters: lpProfile - Profile Information +// lpKey - Key to secure +// pSid - Sid (used by CreateNewUser) +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/20/95 ericflo Created +// +//************************************************************* + +BOOL SecureUserKey(LPPROFILE lpProfile, LPTSTR lpKey, PSID pSid) +{ + DWORD Error, IgnoreError; + HKEY RootKey; + SECURITY_DESCRIPTOR sd; + SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; + PACL pAcl = NULL; + PSID psidUser = NULL, psidSystem = NULL, psidAdmin = NULL; + DWORD cbAcl, AceIndex, dwDisp; + ACE_HEADER * lpAceHeader; + BOOL bRetVal = FALSE; + BOOL bFreeSid = TRUE; + DWORD dwFlags = 0; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Entering"))); + + + // + // Create the security descriptor + // + + // + // Give the user access by their real sid so they still have access + // when they logoff and logon again + // + + if (pSid) { + psidUser = pSid; + bFreeSid = FALSE; + dwFlags = PI_NOUI; + } else { + psidUser = GetUserSid(lpProfile->hToken); + dwFlags = lpProfile->dwFlags; + } + + if (!psidUser) { + DebugMsg((DM_WARNING, TEXT("SecureUserKey: Failed to get user sid"))); + 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("SecureUserKey: 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("SecureUserKey: 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("SecureUserKey: 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("SecureUserKey: 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("SecureUserKey: 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("SecureUserKey: 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("SecureUserKey: Failed to add ace for user. Error = %d"), GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: 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("SecureUserKey: Failed to add ace for system. Error = %d"), GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: 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("SecureUserKey: Failed to add ace for admin. Error = %d"), GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: 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("SecureUserKey: Failed to initialize security descriptor. Error = %d"), GetLastError())); + goto Exit; + } + + + if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { + DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to set security descriptor dacl. Error = %d"), GetLastError())); + goto Exit; + } + + + // + // Open the root of the user's profile + // + + Error = RegCreateKeyEx(HKEY_USERS, + lpKey, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL, + NULL, + &RootKey, + &dwDisp); + + if (Error != ERROR_SUCCESS) { + + DebugMsg((DM_WARNING, TEXT("SecureUserKey: Failed to open root of user registry, error = %d"), Error)); + + } else { + + // + // Set the security descriptor on the key + // + + Error = ApplySecurityToRegistryTree(RootKey, &sd); + + + if (Error == ERROR_SUCCESS) { + bRetVal = TRUE; + + } else { + + DebugMsg((DM_WARNING, TEXT("SecureUserKey: Failed to apply security to registry key, error = %d"), Error)); + } + + RegCloseKey(RootKey); + } + + +Exit: + + // + // Free the sids and acl + // + + if (bFreeSid && psidUser) { + DeleteUserSid (psidUser); + } + + if (psidSystem) { + FreeSid(psidSystem); + } + + if (psidAdmin) { + FreeSid(psidAdmin); + } + + if (pAcl) { + GlobalFree (pAcl); + } + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Leaving with a return value of %d"), bRetVal)); + + + return(bRetVal); + +} + + + +//end +//************************************************************* +// +// ApplySecurityToRegistryTree() +// +// Purpose: Applies the passed security descriptor to the passed +// key and all its descendants. Only the parts of +// the descriptor inddicated in the security +// info value are actually applied to each registry key. +// +// Parameters: RootKey - Registry key +// pSD - Security Descriptor +// +// Return: ERROR_SUCCESS if successful +// +// Comments: +// +// History: Date Author Comment +// 7/19/95 ericflo Created +// +//************************************************************* + +DWORD ApplySecurityToRegistryTree(HKEY RootKey, PSECURITY_DESCRIPTOR pSD) + +{ + DWORD Error, IgnoreError; + DWORD SubKeyIndex; + LPTSTR SubKeyName; + HKEY SubKey; + DWORD cchSubKeySize = MAX_PATH + 1; + + + + // + // First apply security + // + + Error = RegSetKeySecurity(RootKey, DACL_SECURITY_INFORMATION, pSD); + + if (Error != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryTree: Failed to set security on registry key, error = %d"), Error)); + + return Error; + } + + + // + // Open each sub-key and apply security to its sub-tree + // + + SubKeyIndex = 0; + + SubKeyName = GlobalAlloc (GPTR, cchSubKeySize * sizeof(TCHAR)); + + if (!SubKeyName) { + DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryTree: Failed to allocate memory, error = %d"), GetLastError())); + return GetLastError(); + } + + while (TRUE) { + + // + // Get the next sub-key name + // + + Error = RegEnumKey(RootKey, SubKeyIndex, SubKeyName, cchSubKeySize); + + + if (Error != ERROR_SUCCESS) { + + if (Error == ERROR_NO_MORE_ITEMS) { + + // + // Successful end of enumeration + // + + Error = ERROR_SUCCESS; + + } else { + + DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryTree: Registry enumeration failed with error = %d"), Error)); + } + + break; + } + + + // + // Open the sub-key + // + + Error = RegOpenKeyEx(RootKey, + SubKeyName, + 0, + WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL, + &SubKey); + + if (Error != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryKey : Failed to open sub-key %s, error = %d"), SubKeyName, Error)); + break; + } + + // + // Apply security to the sub-tree + // + + Error = ApplySecurityToRegistryTree(SubKey, pSD); + + + // + // We're finished with the sub-key + // + + IgnoreError = RegCloseKey(SubKey); + if (IgnoreError != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryKey : Failed to close registry key, error = %d"), Error)); + } + + // + // See if we set the security on the sub-tree successfully. + // + + if (Error != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryKey : Failed to apply security to sub-key %s, error = %d"), SubKeyName, Error)); + break; + } + + // + // Go enumerate the next sub-key + // + + SubKeyIndex ++; + } + + + GlobalFree (SubKeyName); + + return Error; + +} + + + +//************************************************************* +// +// SetupNewHive() +// +// Purpose: Initializes the new user hive created by copying +// the default hive. +// +// Parameters: lpProfile - Profile Information +// lpSidString - Sid string +// pSid - Sid (used by CreateNewUser) +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 7/18/95 ericflo Created +// +//************************************************************* + +BOOL SetupNewHive(LPPROFILE lpProfile, LPTSTR lpSidString, PSID pSid) +{ + DWORD Error, IgnoreError; + HKEY RootKey; + 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; + BOOL bFreeSid = TRUE; + DWORD dwFlags = 0; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Entering"))); + + + // + // Create the security descriptor that will be applied to each key + // + + // + // Give the user access by their real sid so they still have access + // when they logoff and logon again + // + + if (pSid) { + psidUser = pSid; + bFreeSid = FALSE; + dwFlags = PI_NOUI; + } else { + psidUser = GetUserSid(lpProfile->hToken); + dwFlags = lpProfile->dwFlags; + } + + if (!psidUser) { + DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to get user sid"))); + 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("SetupNewHive: 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("SetupNewHive: 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("SetupNewHive: 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_ALL_ACCESS, psidUser)) { + DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: 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("SetupNewHive: 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("SetupNewHive: Failed to add ace for admin. Error = %d"), GetLastError())); + goto Exit; + } + + + // + // Now the inheritable ACEs + // + + AceIndex++; + if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidUser)) { + DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Failed to add ace for user. Error = %d"), GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: 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("SetupNewHive: Failed to add ace for system. Error = %d"), GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: 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("SetupNewHive: Failed to add ace for admin. Error = %d"), GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: 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("SetupNewHive: Failed to initialize security descriptor. Error = %d"), GetLastError())); + goto Exit; + } + + + if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { + DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Failed to set security descriptor dacl. Error = %d"), GetLastError())); + goto Exit; + } + + + // + // Open the root of the user's profile + // + + Error = RegOpenKeyEx(HKEY_USERS, + lpSidString, + 0, + WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL, + &RootKey); + + if (Error != ERROR_SUCCESS) { + + DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to open root of user registry, error = %d"), Error)); + + } else { + + // + // Set the security descriptor on the entire tree + // + + Error = ApplySecurityToRegistryTree(RootKey, &sd); + + + if (Error == ERROR_SUCCESS) { + + TCHAR szSubKey[MAX_PATH]; + + // + // Change the security on certain keys in the user's registry + // so that only Admin's and the OS have write access. + // + + lstrcpy (szSubKey, lpSidString); + lstrcat (szSubKey, TEXT("\\")); + lstrcat (szSubKey, POLICIES_KEY); + + if (!SecureUserKey(lpProfile, szSubKey, pSid)) { + DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to secure policies key"))); + } + + bRetVal = TRUE; + + } else { + + DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to apply security to user registry tree, error = %d"), Error)); + ReportError(dwFlags, IDS_SECURITY_FAILED, Error); + + } + + RegFlushKey (RootKey); + + IgnoreError = RegCloseKey(RootKey); + if (IgnoreError != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to close reg key, error = %d"), IgnoreError)); + } + } + + +Exit: + + // + // Free the sids and acl + // + + if (bFreeSid && psidUser) { + DeleteUserSid (psidUser); + } + + if (psidSystem) { + FreeSid(psidSystem); + } + + if (psidAdmin) { + FreeSid(psidAdmin); + } + + if (pAcl) { + GlobalFree (pAcl); + } + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Leaving with a return value of %d"), bRetVal)); + + + return(bRetVal); + +} + + +//************************************************************* +// +// IsCentralProfileReachable() +// +// Purpose: Checks to see if the user can access the +// central profile. +// +// Parameters: lpProfile - User's token +// bCreateCentralProfile - Should the central profile be created +// bMandatory - Is this a mandatory profile +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/20/95 ericflo Ported +// +//************************************************************* + +BOOL IsCentralProfileReachable(LPPROFILE lpProfile, BOOL *bCreateCentralProfile, + BOOL *bMandatory) +{ + WIN32_FIND_DATA fd; + HANDLE hFile; + TCHAR szProfile[MAX_PATH]; + LPTSTR lpProfilePath, lpEnd; + BOOL bRetVal = FALSE; + DWORD dwError; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Entering"))); + + + // + // Setup default values + // + + *bMandatory = FALSE; + *bCreateCentralProfile = FALSE; + + + // + // Check parameters + // + + if (lpProfile->szCentralProfile[0] == TEXT('\0')) { + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Null path. Leaving"))); + return FALSE; + } + + + lpProfilePath = lpProfile->szCentralProfile; + + + // + // Make sure we don't overrun our temporary buffer + // + + if ((lstrlen(lpProfilePath) + 1 + lstrlen(c_szNTUserMan + 1)) > MAX_PATH) { + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Failed because temporary buffer is too small."))); + return FALSE; + } + + + // + // Copy the profile path to a temporary buffer + // we can munge it. + // + + lstrcpy (szProfile, lpProfilePath); + + + // + // Add the slash if appropriate and then tack on + // ntuser.man. + // + + lpEnd = CheckSlash(szProfile); + lstrcpy(lpEnd, c_szNTUserMan); + + + // + // Impersonate the user + // + + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Failed to impersonate user"))); + return FALSE; + } + + + // + // See if this file exists + // + + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Testing <%s>"), szProfile)); + + hFile = CreateFile(szProfile, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + + if (hFile != INVALID_HANDLE_VALUE) { + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Found a mandatory profile."))); + CloseHandle(hFile); + *bMandatory = TRUE; + bRetVal = TRUE; + goto Exit; + } + + + dwError = GetLastError(); + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Profile is not reachable, error = %d"), + dwError)); + + + // + // If we received an error other than file not + // found, bail now because we won't be able to + // access this location. + // + + if (dwError != ERROR_FILE_NOT_FOUND) { + DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Profile path <%s> is not reachable, error = %d"), + szProfile, dwError)); + goto Exit; + } + + + // + // Now try ntuser.dat + // + + lstrcpy(lpEnd, c_szNTUserDat); + + + // + // See if this file exists. + // + + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Testing <%s>"), szProfile)); + + hFile = CreateFile(szProfile, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + + if (hFile != INVALID_HANDLE_VALUE) { + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Found a user profile."))); + CloseHandle(hFile); + bRetVal = TRUE; + goto Exit; + } + + + dwError = GetLastError(); + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Profile is not reachable, error = %d"), + dwError)); + + + if (dwError == ERROR_FILE_NOT_FOUND) { + DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Ok to create a user profile."))); + *bCreateCentralProfile = TRUE; + bRetVal = TRUE; + goto Exit; + } + + + DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Profile path <%s> is not reachable(2), error = %d"), + szProfile, dwError)); + +Exit: + + // + // Go back to system security context + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Failed to revert to self"))); + } + + return bRetVal; +} + +//************************************************************* +// +// MyRegLoadKey() +// +// Purpose: Loads a hive into the registry +// +// Parameters: lpProfile - Profile Info +// hKey - Key to load the hive into +// lpSubKey - Subkey name +// lpFile - hive filename +// +// Return: ERROR_SUCCESS if successful +// Error number if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/22/95 ericflo Created +// +//************************************************************* + +LONG MyRegLoadKey(LPPROFILE lpProfile, HKEY hKey, + LPTSTR lpSubKey, LPTSTR lpFile) +{ + NTSTATUS Status; + BOOLEAN WasEnabled; + int error; + + // + // Enable the restore privilege + // + + Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled); + + if (NT_SUCCESS(Status)) { + + error = RegLoadKey(hKey, lpSubKey, lpFile); + + // + // Restore the privilege to its previous state + // + + Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled); + if (!NT_SUCCESS(Status)) { + DebugMsg((DM_WARNING, TEXT("MyRegLoadKey: Failed to restore RESTORE privilege to previous enabled state"))); + } + + + // + // Check if the hive was loaded + // + + if (error != ERROR_SUCCESS) { + ReportError(PI_NOUI, IDS_REGLOADKEYFAILED, error, lpFile); + DebugMsg((DM_WARNING, TEXT("MyRegLoadKey: Failed to load subkey <%s>, error =%d"), lpSubKey, error)); + } + + } else { + error = GetLastError(); + DebugMsg((DM_WARNING, TEXT("MyRegLoadKey: Failed to enable restore privilege to load registry key"))); + } + + return error; +} + + +//************************************************************* +// +// MyRegUnLoadKey() +// +// Purpose: Unloads a registry key +// +// Parameters: hKey - Registry handle +// lpSubKey - Subkey to be unloaded +// +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/19/95 ericflo Ported +// +//************************************************************* + +BOOL MyRegUnLoadKey(HKEY hKey, LPTSTR lpSubKey) +{ + BOOL bResult = TRUE; + LONG error; + NTSTATUS Status; + BOOLEAN WasEnabled; + + + // + // Enable the restore privilege + // + + Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled); + + if (NT_SUCCESS(Status)) { + + error = RegUnLoadKey(hKey, lpSubKey); + + if ( error != ERROR_SUCCESS) { + bResult = FALSE; + } + + // + // Restore the privilege to its previous state + // + + Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled); + if (!NT_SUCCESS(Status)) { + DebugMsg((DM_WARNING, TEXT("MyRegUnLoadKey: Failed to restore RESTORE privilege to previous enabled state"))); + } + + } else { + DebugMsg((DM_WARNING, TEXT("MyRegUnloadKey: Failed to enable restore privilege to unload registry key"))); + bResult = FALSE; + } + + return bResult; +} + +//************************************************************* +// +// UpgradeLocalProfile() +// +// Purpose: Upgrades a local profile from a 3.x profile +// to a profile directory structure. +// +// Parameters: lpProfile - Profile Information +// lpOldProfile - Previous profile file +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 7/6/95 ericflo Created +// +//************************************************************* + +BOOL UpgradeLocalProfile (LPPROFILE lpProfile, LPTSTR lpOldProfile) +{ + TCHAR szSrc[MAX_PATH]; + TCHAR szDest[MAX_PATH]; + LPTSTR lpSrcEnd, lpDestEnd; + BOOL bRetVal = FALSE; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("UpgradeLocalProfile: Entering"))); + + + // + // Setup the temporary buffers + // + + lstrcpy (szSrc, lpOldProfile); + lstrcpy (szDest, lpProfile->szLocalProfile); + + lpDestEnd = CheckSlash (szDest); + lstrcpy (lpDestEnd, c_szNTUserDat); + + + // + // Copy the hive + // + + if (!CopyFile(szSrc, szDest, FALSE)) { + DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: CopyFile failed to copy hive with error = %d"), + GetLastError())); + return FALSE; + } + + + // + // Delete the old hive + // + + DeleteFile (szSrc); + + + + // + // Copy log file + // + + lstrcat (szSrc, c_szLog); + lstrcat (szDest, c_szLog); + + + if (!CopyFile(szSrc, szDest, FALSE)) { + DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: CopyFile failed to copy hive log with error = %d"), + GetLastError())); + } + + + // + // Delete the old hive log + // + + DeleteFile (szSrc); + + + // + // Copy in the new shell folders from the default + // + + if ( !(lpProfile->dwInternalFlags & DEFAULT_NET_READY) ) { + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to impersonate user"))); + goto IssueLocalDefault; + } + + + CheckNetDefaultProfile (lpProfile); + + + // + // Go back to system security context + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to revert to self"))); + } + + } + + if (lpProfile->szDefaultProfile && *lpProfile->szDefaultProfile) { + + ExpandEnvironmentStrings(lpProfile->szDefaultProfile, szSrc, MAX_PATH); + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to impersonate user"))); + goto IssueLocalDefault; + } + + if (CopyProfileDirectory (szSrc, lpProfile->szLocalProfile, + CPD_IGNOREHIVE | CPD_IGNORECOPYERRORS)) { + + bRetVal = TRUE; + } + + // + // Go back to system security context + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to revert to self"))); + } + } + + +IssueLocalDefault: + + if (!bRetVal) { + + ExpandEnvironmentStrings(DEFAULT_PROFILE, szSrc, MAX_PATH); + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to impersonate user"))); + goto Exit; + } + + bRetVal = CopyProfileDirectory (szSrc, lpProfile->szLocalProfile, + CPD_IGNOREHIVE | CPD_IGNORECOPYERRORS); + + // + // Go back to system security context + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to revert to self"))); + } + } + +Exit: + + if (bRetVal) { + lpProfile->dwInternalFlags |= PROFILE_RUN_SYNCAPP; + } + + return bRetVal; +} + +//************************************************************* +// +// UpgradeCentralProfile() +// +// Purpose: Upgrades a central profile from a 3.x profile +// to a profile directory structure. +// +// Parameters: lpProfile - Profile Information +// lpOldProfile - Previous profile file +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 7/6/95 ericflo Created +// +//************************************************************* + +BOOL UpgradeCentralProfile (LPPROFILE lpProfile, LPTSTR lpOldProfile) +{ + TCHAR szSrc[MAX_PATH]; + TCHAR szDest[MAX_PATH]; + LPTSTR lpSrcEnd, lpDestEnd, lpDot; + BOOL bRetVal = FALSE; + BOOL bMandatory = FALSE; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: Entering"))); + + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Failed to impersonate user"))); + return FALSE; + } + + + // + // Setup the source buffer + // + + lstrcpy (szSrc, lpOldProfile); + + + // + // Determine the profile type + // + + lpDot = szSrc + lstrlen(szSrc) - 4; + + if (*lpDot == TEXT('.')) { + if (!lstrcmpi (lpDot, c_szMAN)) { + bMandatory = TRUE; + } + } + + + // + // Setup the destination buffer + // + + lstrcpy (szDest, lpProfile->szCentralProfile); + + lpDestEnd = CheckSlash (szDest); + + if (bMandatory) { + lstrcpy (lpDestEnd, c_szNTUserMan); + } else { + lstrcpy (lpDestEnd, c_szNTUserDat); + } + + + // + // Copy the hive + // + + if (!CopyFile(szSrc, szDest, FALSE)) { + DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: CopyFile failed to copy hive with error = %d"), + GetLastError())); + DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Source = <%s>"), szSrc)); + DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Destination = <%s>"), szDest)); + + goto Exit; + } + + + + // + // Copy log file + // + + lstrcpy (lpDot, c_szLog); + lstrcat (szDest, c_szLog); + + + if (!CopyFile(szSrc, szDest, FALSE)) { + DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: CopyFile failed to copy hive log with error = %d"), + GetLastError())); + DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: Source = <%s>"), szSrc)); + DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: Destination = <%s>"), szDest)); + + } + + + // + // Copy in the new shell folders from the default + // + + if ( !(lpProfile->dwInternalFlags & DEFAULT_NET_READY) ) { + CheckNetDefaultProfile (lpProfile); + } + + + if (lpProfile->szDefaultProfile && *lpProfile->szDefaultProfile) { + + ExpandEnvironmentStrings(lpProfile->szDefaultProfile, szSrc, MAX_PATH); + + if (CopyProfileDirectory (szSrc, lpProfile->szCentralProfile, + CPD_IGNOREHIVE | CPD_IGNORECOPYERRORS)) { + + bRetVal = TRUE; + } + } + + + if (!bRetVal) { + + ExpandEnvironmentStrings(DEFAULT_PROFILE, szSrc, MAX_PATH); + + bRetVal = CopyProfileDirectory (szSrc, lpProfile->szCentralProfile, + CPD_IGNOREHIVE | CPD_IGNORECOPYERRORS); + } + + + if (bRetVal) { + lpProfile->dwInternalFlags |= PROFILE_RUN_SYNCAPP; + } + + +Exit: + + // + // Go back to system security context + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Failed to revert to self"))); + } + + + return bRetVal; +} + +//************************************************************* +// +// GetTempProfileDir() +// +// Purpose: Generates a temporary profile directory +// +// Parameters: lpProfile - Profile Information +// lpProfileImage - Receives the generated directory +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/20/95 ericflo Created +// +//************************************************************* + +BOOL GetTempProfileDir (LPPROFILE lpProfile, LPTSTR lpProfileImage) +{ + TCHAR szProfileImage[MAX_PATH]; + TCHAR szExpProfileImage[MAX_PATH]; + + + // + // Initialize the profile image + // + + lstrcpy (szProfileImage, CONFIG_FILE_PATH); + + + // + // Call the compute function to do the real work. + // + + if (ComputeLocalProfileName (lpProfile, TEMP_PROFILE_NAME_BASE, + szProfileImage, MAX_PATH, + szExpProfileImage, MAX_PATH)) { + + // + // Save the generated name. + // + + lstrcpy (lpProfileImage, szExpProfileImage); + + return TRUE; + } + + return FALSE; +} + +//************************************************************* +// +// CreateSecureDirectory() +// +// Purpose: Creates a secure directory that only the user, +// admin, and system have access to. +// +// Parameters: lpProfile - Profile Information +// lpDirectory - Directory Name +// pSid - Sid (used by CreateUserProfile) +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 7/20/95 ericflo Created +// +//************************************************************* + +BOOL CreateSecureDirectory (LPPROFILE lpProfile, LPTSTR lpDirectory, PSID pSid) +{ + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + 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; + BOOL bFreeSid = TRUE; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Entering with <%s>"), lpDirectory)); + + + + // + // Get the SIDs we'll need for the DACL + // + + if (pSid) { + psidUser = pSid; + bFreeSid = FALSE; + } else { + psidUser = GetUserSid(lpProfile->hToken); + } + + + + // + // Get the system sid + // + + if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID, + 0, 0, 0, 0, 0, 0, 0, &psidSystem)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: 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("SetupNewHive: 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("CreateSecureDirectory: 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, FILE_ALL_ACCESS, psidUser)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); + goto Exit; + } + + + + aceIndex++; + if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSystem)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); + goto Exit; + } + + + aceIndex++; + if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidAdmin)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); + goto Exit; + } + + + // + // Now the inheritable ACEs + // + + aceIndex++; + if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidUser)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, aceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: 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("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, aceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: 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("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); + goto Exit; + } + + if (!GetAce(pAcl, aceIndex, &lpAceHeader)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: 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("CreateSecureDirectory: Failed to initialize security descriptor. Error = %d"), GetLastError())); + goto Exit; + } + + + if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to set security descriptor dacl. Error = %d"), GetLastError())); + goto Exit; + } + + + // + // Add the security descriptor to the sa structure + // + + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = &sd; + sa.bInheritHandle = FALSE; + + + // + // Attempt to create the directory + // + + if (CreateNestedDirectory(lpDirectory, &sa)) { + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Created the directory <%s>"), lpDirectory)); + bRetVal = TRUE; + + } else { + + DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to created the directory <%s>"), lpDirectory)); + } + + + +Exit: + + if (bFreeSid && psidUser) { + DeleteUserSid (psidUser); + } + + if (psidSystem) { + FreeSid(psidSystem); + } + + if (psidAdmin) { + FreeSid(psidAdmin); + } + + if (pAcl) { + GlobalFree (pAcl); + } + + return bRetVal; + +} + + +//************************************************************* +// +// ComputeLocalProfileName() +// +// Purpose: Constructs the pathname of the local profile +// for this user. It will attempt to create +// a directory of the username, and then if +// unsccessful it will try the username.xxx +// where xxx is a three digit number +// +// Parameters: lpProfile - Profile Information +// lpUserName - UserName +// lpProfileImage - Profile directory (unexpanded) +// cchMaxProfileImage - lpProfileImage buffer size +// lpExpProfileImage - Expanded directory +// cchMaxExpProfileImage - lpExpProfileImage buffer size +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: lpProfileImage should be initialized with the +// root profile path and the trailing backslash. +// +// History: Date Author Comment +// 6/20/95 ericflo Created +// +//************************************************************* + +BOOL ComputeLocalProfileName (LPPROFILE lpProfile, LPTSTR lpUserName, + LPTSTR lpProfileImage, DWORD cchMaxProfileImage, + LPTSTR lpExpProfileImage, DWORD cchMaxExpProfileImage) +{ + int i = 0; + TCHAR szNumber[5]; + LPTSTR lpEnd; + DWORD dwProfileLen; + BOOL bRetVal = FALSE; + HANDLE hFile; + WIN32_FIND_DATA fd; + + + // + // Check buffer size + // + + dwProfileLen = lstrlen(lpProfileImage); + if ((dwProfileLen + lstrlen(lpUserName) + 4 + 1) > cchMaxProfileImage) { + DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: buffer too small"))); + return FALSE; + } + + // + // Place the username onto the end of the profile image + // + + lpEnd = lpProfileImage + dwProfileLen; + lstrcpy (lpEnd, lpUserName); + + + // + // Expand the profile path + // + + ExpandEnvironmentStrings(lpProfileImage, lpExpProfileImage, cchMaxExpProfileImage); + + + + // + // Does this directory exist? + // + + hFile = FindFirstFile (lpExpProfileImage, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + + // + // Attempt to create the directory + // + + if (CreateSecureDirectory(lpProfile, lpExpProfileImage, NULL)) { + DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: generated the profile directory <%s>"), lpExpProfileImage)); + bRetVal = TRUE; + goto Exit; + } + + } else { + + FindClose (hFile); + } + + + // + // Failed to create the directory for some reason. + // Now try username.000, username.001, etc + // + + lpEnd = lpProfileImage + lstrlen(lpProfileImage); + + for (i=0; i < 1000; i++) { + + // + // Convert the number to a string and attach it. + // + + wsprintf (szNumber, TEXT(".%.3d"), i); + lstrcpy (lpEnd, szNumber); + + + // + // Expand the profile path + // + + ExpandEnvironmentStrings(lpProfileImage, lpExpProfileImage, cchMaxExpProfileImage); + + + // + // Does this directory exist? + // + + hFile = FindFirstFile (lpExpProfileImage, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + + // + // Attempt to create the directory + // + + if (CreateSecureDirectory(lpProfile, lpExpProfileImage, NULL)) { + DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: generated the profile directory <%s>"), lpExpProfileImage)); + bRetVal = TRUE; + goto Exit; + } + + } else { + + FindClose (hFile); + } + } + + + DebugMsg((DM_WARNING, TEXT("ComputeLocalProfileName: Could not generate a profile directory. Error = %d"), GetLastError())); + +Exit: + + + return bRetVal; +} + +//************************************************************* +// +// CreateLocalProfileKey() +// +// Purpose: Creates a registry key pointing at the user profile +// +// Parameters: lpProfile - Profile information +// phKey - Handle to registry key if successful +// bKeyExists - TRUE if the registry key already existed +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/20/95 ericflo Ported +// +//************************************************************* + +BOOL CreateLocalProfileKey (LPPROFILE lpProfile, PHKEY phKey, BOOL *bKeyExists) +{ + TCHAR LocalProfileKey[MAX_PATH]; + DWORD Disposition; + DWORD RegErr = ERROR_SUCCESS + 1; + BOOL Result; + LPTSTR SidString; + + + SidString = GetSidString(lpProfile->hToken); + if (SidString != NULL) { + + // + // Call the RegCreateKey api in the user's context + // + + lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); + lstrcat(LocalProfileKey, TEXT("\\")); + lstrcat(LocalProfileKey, SidString); + + RegErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, 0, 0, + KEY_READ | KEY_WRITE, NULL, phKey, &Disposition); + if (RegErr == ERROR_SUCCESS) { + *bKeyExists = (BOOL)(Disposition & REG_OPENED_EXISTING_KEY); + } else { + DebugMsg((DM_WARNING, TEXT("CreateLocalProfileKey: Failed trying to create the local profile key <%s>, error = %d."), LocalProfileKey, RegErr)); + } + + DeleteSidString(SidString); + } + + + return(RegErr == ERROR_SUCCESS); +} + + +//************************************************************* +// +// GetLocalProfileImage() +// +// Purpose: Create/opens the profileimagepath +// +// Parameters: lpProfile - Profile information +// bNewUser - set to TRUE if the default profile was issued. +// +// Return: TRUE if the profile image is reachable +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/20/95 ericflo Ported +// +//************************************************************* +BOOL GetLocalProfileImage(LPPROFILE lpProfile, BOOL *bNewUser) +{ + HKEY hKey; + BOOL bKeyExists; + TCHAR lpProfileImage[MAX_PATH]; + TCHAR lpExpProfileImage[MAX_PATH]; + TCHAR lpOldProfileImage[MAX_PATH]; + LPTSTR lpExpandedPath, lpEnd; + DWORD cbExpProfileImage = sizeof(TCHAR)*MAX_PATH; + HANDLE hFile; + WIN32_FIND_DATA fd; + DWORD cb; + DWORD err; + DWORD dwType; + HANDLE fh; + PSID UserSid; + BOOL bRetVal = FALSE; + BOOL bUpgradeLocal = FALSE; + + lpProfile->szLocalProfile[0] = TEXT('\0'); + *bNewUser = TRUE; + + + if (!CreateLocalProfileKey(lpProfile, &hKey, &bKeyExists)) { + return FALSE; // not reachable and cannot keep a local copy + } + + if (bKeyExists) { + + // + // Check if the local profile image is valid. + // + + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Found entry in profile list for existing local profile"))); + + err = RegQueryValueEx(hKey, PROFILE_IMAGE_VALUE_NAME, 0, &dwType, + (LPBYTE)lpExpProfileImage, &cbExpProfileImage); + if (err == ERROR_SUCCESS && cbExpProfileImage) { + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Local profile image filename = <%s>"), lpExpProfileImage)); + + if (dwType == REG_EXPAND_SZ) { + + // + // Expand the profile image filename + // + + cb = sizeof(lpExpProfileImage); + lpExpandedPath = LocalAlloc(LPTR, cb); + if (lpExpandedPath) { + ExpandEnvironmentStrings(lpExpProfileImage, lpExpandedPath, cb); + lstrcpy(lpExpProfileImage, lpExpandedPath); + LocalFree(lpExpandedPath); + } + + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Expanded local profile image filename = <%s>"), lpExpProfileImage)); + } + + + // + // Call FindFirst to see if we need to migrate this profile + // + + hFile = FindFirstFile (lpExpProfileImage, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Local profile image filename we got from our profile list doesn't exit. Error = %d"), GetLastError())); + goto CreateLocal; + } + + FindClose(hFile); + + + // + // If this is a file, then we need to migrate it to + // + + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + lstrcpy (lpOldProfileImage, lpExpProfileImage); + bUpgradeLocal = TRUE; + goto CreateLocal; + } + + + // + // Test if a mandatory profile exists + // + + lpEnd = CheckSlash (lpExpProfileImage); + lstrcpy (lpEnd, c_szNTUserMan); + + fh = CreateFile(lpExpProfileImage, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fh != INVALID_HANDLE_VALUE) { + lpProfile->dwInternalFlags |= PROFILE_MANDATORY; + CloseHandle(fh); + + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Found local mandatory profile image file ok <%s>"), + lpExpProfileImage)); + + *(lpEnd - 1) = TEXT('\0'); + lstrcpy(lpProfile->szLocalProfile, lpExpProfileImage); + RegCloseKey(hKey); + *bNewUser = FALSE; + return TRUE; // local copy is valid and reachable + } else { + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: No local mandatory profile. Error = %d"), GetLastError())); + } + + + // + // Test if a normal profile exists + // + + lstrcpy (lpEnd, c_szNTUserDat); + + fh = CreateFile(lpExpProfileImage, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fh != INVALID_HANDLE_VALUE) { + CloseHandle(fh); + + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Found local profile image file ok <%s>"), + lpExpProfileImage)); + + *(lpEnd - 1) = TEXT('\0'); + lstrcpy(lpProfile->szLocalProfile, lpExpProfileImage); + RegCloseKey(hKey); + *bNewUser = FALSE; + return TRUE; // local copy is valid and reachable + } else { + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Local profile image filename we got from our profile list doesn't exit. <%s> Error = %d"), + lpExpProfileImage, GetLastError())); + } + } + } + + +CreateLocal: + + // + // No local copy found, try to create a new one. + // + + DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: One way or another we haven't got an existing local profile, try and create one"))); + + lstrcpy(lpProfileImage, CONFIG_FILE_PATH); + if (ComputeLocalProfileName(lpProfile, lpProfile->szUserName, + lpProfileImage, MAX_PATH, + lpExpProfileImage, MAX_PATH)) { + + + // + // Add this image file to our profile list for this user + // + + err = RegSetValueEx(hKey, + PROFILE_IMAGE_VALUE_NAME, + 0, + REG_EXPAND_SZ, + (LPBYTE)lpProfileImage, + sizeof(TCHAR)*(lstrlen(lpProfileImage) + 1)); + + if (err == ERROR_SUCCESS) { + + lstrcpy(lpProfile->szLocalProfile, lpExpProfileImage); + + // + // Get the sid of the logged on user + // + + UserSid = GetUserSid(lpProfile->hToken); + if (UserSid != NULL) { + + // + // Store the user sid under the Sid key of the local profile + // + + err = RegSetValueEx(hKey, + TEXT("Sid"), + 0, + REG_BINARY, + UserSid, + RtlLengthSid(UserSid)); + + + if (err != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("GetLocalProfileImage: Failed to set 'sid' value of user in profile list, error = %d"), err)); + } + + // + // We're finished with the user sid + // + + DeleteUserSid(UserSid); + + + // + // If we are upgrading a profile from a 3.5 machine + // do that now. + // + + if (bUpgradeLocal) { + if (UpgradeLocalProfile (lpProfile, lpOldProfileImage)) { + *bNewUser = FALSE; + } + } + + bRetVal = TRUE; + + } else { + DebugMsg((DM_WARNING, TEXT("GetLocalProfileImage: Failed to get sid of logged on user, so unable to update profile list"))); + } + } else { + DebugMsg((DM_WARNING, TEXT("GetLocalProfileImage: Failed to update profile list for user with local profile image filename, error = %d"), err)); + } + } + + + err = RegCloseKey(hKey); + + if (err != STATUS_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("GetLocalProfileImage: Failed to close registry key, error = %d"), err)); + } + + return bRetVal; +} + +//************************************************************* +// +// UpdateToLatestProfile() +// +// Purpose: Determines which profile is newer, and +// updates the local cache. +// +// Parameters: lpProfile - Profile info +// lpCentralProfile - Central profile +// lpLocalProfile - Local profile +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/21/95 ericflo Created +// +//************************************************************* + +BOOL UpdateToLatestProfile(LPPROFILE lpProfile, LPTSTR lpCentralProfile, + LPTSTR lpLocalProfile, LPTSTR lpSidString) +{ + HANDLE hLocal; + HANDLE hCentral; + FILETIME ftLocal; + FILETIME ftCentral; + BOOL FromCentralToLocal; + int DlgReturn; + LONG lTimeCompare; + TCHAR szProfile[MAX_PATH]; + LPTSTR lpEnd; + BOOL bRetVal; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Entering. Central = <%s> Local = <%s>"), + lpCentralProfile, lpLocalProfile)); + + + // + // Setup a temporary buffer to work with + // + + lstrcpy (szProfile, lpCentralProfile); + lpEnd = CheckSlash (szProfile); + + if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { + lstrcpy (lpEnd, c_szNTUserMan); + } else { + lstrcpy (lpEnd, c_szNTUserDat); + } + + + // + // Impersonate the user + // + + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to impersonate user"))); + return FALSE; + } + + + // + // Attempt to open the central profile + // + + hCentral = CreateFile(szProfile, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + + if (hCentral == INVALID_HANDLE_VALUE) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: couldn't open central profile, error = %d"), GetLastError())); + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to revert to self"))); + } + + return TRUE; + + } else { + + if (!GetFileTime(hCentral, NULL, NULL, &ftCentral)) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to query central profile file time. Error = %d"), + GetLastError())); + ftCentral.dwLowDateTime = 0; + ftCentral.dwHighDateTime = 0; + } + CloseHandle(hCentral); + } + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to revert to self"))); + } + + + + + // + // Re-initialize the temporary buffer to look + // at the local profile. + // + + lstrcpy (szProfile, lpLocalProfile); + lpEnd = CheckSlash (szProfile); + + if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { + lstrcpy (lpEnd, c_szNTUserMan); + } else { + lstrcpy (lpEnd, c_szNTUserDat); + } + + + // + // Attempt to open the local profile + // + + hLocal = CreateFile(szProfile, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + + if (hLocal == INVALID_HANDLE_VALUE) { + + DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: couldn't open local profile, error = %d"), GetLastError())); + ftLocal.dwLowDateTime = 0; + ftLocal.dwHighDateTime = 0; + + } else { + + if (!GetFileTime(hLocal, NULL, NULL, &ftLocal)) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to query local profile file time. Error = %d"), + GetLastError())); + ftLocal.dwLowDateTime = 0; + ftLocal.dwHighDateTime = 0; + } + + CloseHandle(hLocal); + } + + + if (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) { + DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: New local cach has been created. Forcing copy from central."))); + FromCentralToLocal = TRUE; + + } else { + // + // Decide which file is the most uptodate and use that as the source + // for the copy + // + + lTimeCompare = CompareFileTime(&ftCentral, &ftLocal); + if (lTimeCompare == -1) { + FromCentralToLocal = FALSE; + DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Local profile time stamp is newer than central time stamp."))); + } + else if (lTimeCompare == 1) { + FromCentralToLocal = TRUE; + DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Central profile time stamp is newer than local time stamp."))); + } + else { + DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Central and local profile times match."))); + return TRUE; + } + } + + + // + // If we have a mandatory profile and the cache is newer + // than the central, force the central to be downloaded again. + // We only want to use the cache if the central is not available. + // + + if ((lpProfile->dwInternalFlags & PROFILE_MANDATORY) && !FromCentralToLocal) { + + FromCentralToLocal = TRUE; + } + + + + if (!FromCentralToLocal && !(lpProfile->dwFlags & PI_NOUI)) { + HKEY hKey; + LONG lResult; + DWORD dwType, dwSize, dwDlgTimeOut; + + + // + // Ask the user if ok to overwrite the central profile with the + // the local profile. + // + // Get the dialog box timeout + // + + dwDlgTimeOut = PROFILE_DLG_TIMEOUT; + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + WINLOGON_KEY, + 0, + KEY_READ, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + dwSize = sizeof(DWORD); + RegQueryValueEx (hKey, + TEXT("ProfileDlgTimeOut"), + NULL, + &dwType, + (LPBYTE) &dwDlgTimeOut, + &dwSize); + + + RegCloseKey (hKey); + } + + + + if (dwDlgTimeOut > 0) { + + DlgReturn = DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_CHOOSE_PROFILE), + NULL, ChooseProfileDlgProc, dwDlgTimeOut); + + if (DlgReturn == IDNO) { + // + // The user doesn't want to overwrite the central profile. + // The central profile becomes the active profile and overwrites + // the local copy. + // + FromCentralToLocal = TRUE; + } + } + } + + + + // + // If FromCentralToLocal is false, we can exit now, + // since we are going to use the cache. + // + + if (!FromCentralToLocal) { + return TRUE; + } + + + // + // Impersonate the user + // + + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to impersonate user"))); + return FALSE; + } + + + + if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { + + bRetVal = CopyProfileDirectory (lpCentralProfile, lpLocalProfile, + CPD_IGNORECOPYERRORS | + CPD_COPYIFDIFFERENT | + CPD_SYNCHRONIZE); + + } else { + + bRetVal = CopyProfileDirectory (lpCentralProfile, lpLocalProfile, + CPD_IGNORECOPYERRORS | + CPD_COPYIFDIFFERENT | + CPD_SYNCHRONIZE); + } + + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to revert to self"))); + } + + + if (!bRetVal) { + + DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); + return FALSE; + + } + + + + + + DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Leaving successfully."))); + + return TRUE; +} + + +//************************************************************* +// +// IssueDefaultProfile() +// +// Purpose: Issues the specified default profile to a user +// +// Parameters: lpProfile - Profile Information +// lpDefaultProfile - Default profile location +// lpLocalProfile - Local profile location +// lpSidString - User's sid +// bMandatory - Issue mandatory profile +// +// Return: TRUE if profile was successfully setup +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/22/95 ericflo Created +// +//************************************************************* + +BOOL IssueDefaultProfile (LPPROFILE lpProfile, LPTSTR lpDefaultProfile, + LPTSTR lpLocalProfile, LPTSTR lpSidString, + BOOL bMandatory) +{ + LPTSTR lpEnd, lpTemp; + TCHAR szProfile[MAX_PATH]; + TCHAR szTempProfile[MAX_PATH]; + BOOL bProfileLoaded = FALSE; + WIN32_FIND_DATA fd; + HANDLE hFile; + LONG error; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Entering. lpDefaultProfile = <%s> lpLocalProfile = <%s>"), + lpDefaultProfile, lpLocalProfile)); + + + // + // First expand the default profile + // + + ExpandEnvironmentStrings(lpDefaultProfile, szProfile, MAX_PATH); + + + // + // Does the default profile directory exist? + // + + hFile = FindFirstFile (szProfile, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Default profile <%s> does not exist."), szProfile)); + return FALSE; + } + + FindClose(hFile); + + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: Failed to impersonate user"))); + return FALSE; + } + + // + // Copy profile to user profile + // + + if (!CopyProfileDirectory (szProfile, lpLocalProfile, CPD_FORCECOPY)) { + + DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); + return FALSE; + } + + // + // Rename the profile is a mandatory one was requested. + // + + lstrcpy (szProfile, lpLocalProfile); + lpEnd = CheckSlash (szProfile); + + if (bMandatory) { + + DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Mandatory profile was requested."))); + + lstrcpy (szTempProfile, szProfile); + lstrcpy (lpEnd, c_szNTUserMan); + + hFile = FindFirstFile (szProfile, &fd); + + if (hFile != INVALID_HANDLE_VALUE) { + DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Mandatory profile already exists."))); + FindClose(hFile); + + } else { + DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Renaming ntuser.dat to ntuser.man"))); + + lpTemp = CheckSlash(szTempProfile); + lstrcpy (lpTemp, c_szNTUserDat); + + if (!MoveFile(szTempProfile, szProfile)) { + DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: MoveFile returned false. Error = %d"), GetLastError())); + } + } + + } else { + lstrcpy (lpEnd, c_szNTUserDat); + } + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: Failed to revert to self"))); + } + + + // + // Try to load the new profile + // + + error = MyRegLoadKey(lpProfile,HKEY_USERS, + lpSidString, + szProfile); + + bProfileLoaded = (error == ERROR_SUCCESS); + + + if (!bProfileLoaded) { + DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: MyRegLoadKey failed with error %d"), + error)); + + return FALSE; + } + + + // + // Set the sync app flag + // + + lpProfile->dwInternalFlags |= PROFILE_RUN_SYNCAPP; + + + DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Leaving successfully"))); + + return TRUE; +} + + +//************************************************************* +// +// DeleteProfile() +// +// Purpose: Deletes the specified profile from the +// registry and disk. +// +// Parameters: lpSidString - Registry subkey +// lpProfileDir - Profile directory +// bBackup - Backup profile before deleting +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/23/95 ericflo Created +// +//************************************************************* + +BOOL DeleteProfile (LPTSTR lpSidString, LPTSTR lpLocalProfile, BOOL bBackup) +{ + LONG lResult; + TCHAR szTemp[MAX_PATH]; + + + // + // Cleanup the registry first. + // + + if (lpSidString && *lpSidString) { + + lstrcpy(szTemp, PROFILE_LIST_PATH); + lstrcat(szTemp, TEXT("\\")); + lstrcat(szTemp, lpSidString); + lResult = RegDeleteKey(HKEY_LOCAL_MACHINE, szTemp); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("DeleteProfile: Unable to delete registry entry. Error = %d"), lResult)); + return FALSE; + } + } + + if (bBackup) { + + // + // Generate the backup name + // + + lstrcpy (szTemp, lpLocalProfile); + lstrcat (szTemp, c_szBAK); + + // + // First delete any previous backup + // + + Delnode (szTemp); + + // + // Attempt to rename the directory + // + + if (!MoveFileEx(lpLocalProfile, szTemp, 0)) { + + DebugMsg((DM_VERBOSE, TEXT("DeleteProfile: Failed to rename the directory. Error = %d"), GetLastError())); + return FALSE; + } + + + } else { + + if (!Delnode (lpLocalProfile)) { + DebugMsg((DM_WARNING, TEXT("DeleteProfile: Delnode failed. Error = %d"), GetLastError())); + return FALSE; + } + } + + return TRUE; +} + +//************************************************************* +// +// UpgradeProfile() +// +// Purpose: Called after a profile is successfully loaded. +// Stamps build number into the profile, and if +// appropriate upgrades the per-user settings +// that NT setup wants done. +// +// Parameters: lpProfile - Profile Information +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 7/7/95 ericflo Created +// +//************************************************************* + +BOOL UpgradeProfile (LPPROFILE lpProfile) +{ + HKEY hKey; + DWORD dwDisp, dwType, dwSize, dwBuildNumber; + LONG lResult; + BOOL bUpgrade = FALSE; + BOOL bRunSyncApp = FALSE; + BOOL bDoUserdiff = TRUE; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Entering"))); + + + // + // Query for the build number + // + + lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser, WINLOGON_KEY, + 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, &hKey, &dwDisp); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("UpgradeProfile: Failed to open winlogon key. Error = %d"), lResult)); + return FALSE; + } + + + dwSize = sizeof(dwBuildNumber); + lResult = RegQueryValueEx (hKey, PROFILE_BUILD_NUMBER, + NULL, &dwType, (LPBYTE)&dwBuildNumber, + &dwSize); + + if (lResult == ERROR_SUCCESS) { + + // + // Found the build number. If they match, + // we don't want to process the userdiff hive + // + + if (dwBuildNumber == g_dwBuildNumber) { + DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Build numbers match"))); + bDoUserdiff = FALSE; + } + } else { + + dwBuildNumber = 0; + } + + + if (bDoUserdiff) { + + // + // Set the build number + // + + lResult = RegSetValueEx (hKey, PROFILE_BUILD_NUMBER, 0, REG_DWORD, + (LPBYTE) &g_dwBuildNumber, sizeof(g_dwBuildNumber)); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("UpgradeProfile: Failed to set build number. Error = %d"), lResult)); + } + } + + + // + // Set syncapp flag + // + + if (lpProfile->dwInternalFlags & PROFILE_RUN_SYNCAPP) { + + bRunSyncApp = TRUE; + + lResult = RegSetValueEx (hKey, SYNCAPP_REG_VALUE_NAME, 0, REG_DWORD, + (LPBYTE) &bRunSyncApp, sizeof(bRunSyncApp)); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("UpgradeProfile: Failed to set syncapp flag. Error = %d"), lResult)); + } + + DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Set syncapp flag to %d"), bRunSyncApp)); + } + + // + // Close the registry key + // + + RegCloseKey (hKey); + + + + if (bDoUserdiff) { + + // + // Apply changes to user's hive that NT setup needs. + // + + if (!ProcessUserDiff(lpProfile, dwBuildNumber)) { + DebugMsg((DM_WARNING, TEXT("UpgradeProfile: ProcessUserDiff failed"))); + } + } + + DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Leaving Successfully"))); + + return TRUE; + +} + +//************************************************************* +// +// IsUserAGuest() +// +// Purpose: Determines if the user is a member of the guest group. +// +// Parameters: lpProfile - Profile Information +// +// Return: TRUE if user is a guest +// FALSE if not +// Comments: +// +// History: Date Author Comment +// 7/25/95 ericflo Created +// +//************************************************************* + +BOOL IsUserAGuest(LPPROFILE lpProfile) +{ + SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; + NTSTATUS Status; + ULONG InfoLength; + PTOKEN_GROUPS TokenGroupList; + ULONG GroupIndex; + BOOL FoundGuests; + PSID GuestsDomainSid; + + + // + // Create Guests domain sid. + // + + + Status = RtlAllocateAndInitializeSid( + &authNT, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_GUESTS, + 0, 0, 0, 0, 0, 0, + &GuestsDomainSid + ); + + // + // Test if user is in the Guests domain + // + + // + // Get a list of groups in the token + // + + Status = NtQueryInformationToken( + lpProfile->hToken, // Handle + TokenGroups, // TokenInformationClass + NULL, // TokenInformation + 0, // TokenInformationLength + &InfoLength // ReturnLength + ); + + if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) { + + DebugMsg((DM_WARNING, TEXT("IsUserAGuest: Failed to get group info for guests token, status = 0x%x"), Status)); + RtlFreeSid(GuestsDomainSid); + return FALSE; + } + + + TokenGroupList = GlobalAlloc(GPTR, InfoLength); + + if (TokenGroupList == NULL) { + DebugMsg((DM_WARNING, TEXT("IsUserAGuest: Unable to allocate memory for token groups"))); + RtlFreeSid(GuestsDomainSid); + return FALSE; + } + + Status = NtQueryInformationToken( + lpProfile->hToken, // Handle + TokenGroups, // TokenInformationClass + TokenGroupList, // TokenInformation + InfoLength, // TokenInformationLength + &InfoLength // ReturnLength + ); + + if (!NT_SUCCESS(Status)) { + DebugMsg((DM_WARNING, TEXT("IsUserAGuest: Failed to query groups for guests token, status = 0x%x"), Status)); + GlobalFree(TokenGroupList); + RtlFreeSid(GuestsDomainSid); + return FALSE; + } + + + // + // Search group list for guests alias + // + + FoundGuests = FALSE; + + for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) { + + if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, GuestsDomainSid)) { + FoundGuests = TRUE; + break; + } + } + + // + // Tidy up + // + + GlobalFree(TokenGroupList); + RtlFreeSid(GuestsDomainSid); + + return(FoundGuests); +} + +//************************************************************* +// +// IsUserAnAdminMember() +// +// Purpose: Determines if the user is a member of the administrators group. +// +// Parameters: lpProfile - Profile Information +// +// Return: TRUE if user is a admin +// FALSE if not +// Comments: +// +// History: Date Author Comment +// 7/25/95 ericflo Created +// +//************************************************************* + +BOOL IsUserAnAdminMember(LPPROFILE lpProfile) +{ + SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; + NTSTATUS Status; + ULONG InfoLength; + PTOKEN_GROUPS TokenGroupList; + ULONG GroupIndex; + BOOL FoundAdmins; + PSID AdminsDomainSid; + + + // + // Create Admins domain sid. + // + + + Status = RtlAllocateAndInitializeSid( + &authNT, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdminsDomainSid + ); + + // + // Test if user is in the Admins domain + // + + // + // Get a list of groups in the token + // + + Status = NtQueryInformationToken( + lpProfile->hToken, // Handle + TokenGroups, // TokenInformationClass + NULL, // TokenInformation + 0, // TokenInformationLength + &InfoLength // ReturnLength + ); + + if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) { + + DebugMsg((DM_WARNING, TEXT("IsUserAnAdminMember: Failed to get group info for Admins token, status = 0x%x"), Status)); + RtlFreeSid(AdminsDomainSid); + return FALSE; + } + + + TokenGroupList = GlobalAlloc(GPTR, InfoLength); + + if (TokenGroupList == NULL) { + DebugMsg((DM_WARNING, TEXT("IsUserAnAdminMember: Unable to allocate memory for token groups"))); + RtlFreeSid(AdminsDomainSid); + return FALSE; + } + + Status = NtQueryInformationToken( + lpProfile->hToken, // Handle + TokenGroups, // TokenInformationClass + TokenGroupList, // TokenInformation + InfoLength, // TokenInformationLength + &InfoLength // ReturnLength + ); + + if (!NT_SUCCESS(Status)) { + DebugMsg((DM_WARNING, TEXT("IsUserAnAdminMember: Failed to query groups for Admins token, status = 0x%x"), Status)); + GlobalFree(TokenGroupList); + RtlFreeSid(AdminsDomainSid); + return FALSE; + } + + + // + // Search group list for Admins alias + // + + FoundAdmins = FALSE; + + for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) { + + if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, AdminsDomainSid)) { + FoundAdmins = TRUE; + break; + } + } + + // + // Tidy up + // + + GlobalFree(TokenGroupList); + RtlFreeSid(AdminsDomainSid); + + return(FoundAdmins); +} + +//************************************************************* +// +// SetProfileTime() +// +// Purpose: Sets the timestamp on the remote profile and +// local profile to be the same regardless of the +// file system type being used. +// +// Parameters: lpProfile - Profile Information +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 9/25/95 ericflo Ported +// +//************************************************************* + +BOOL SetProfileTime(LPPROFILE lpProfile) +{ + HANDLE hFileCentral; + HANDLE hFileLocal; + FILETIME ft; + TCHAR szProfile[MAX_PATH]; + LPTSTR lpEnd; + + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to impersonate user"))); + return FALSE; + } + + + // + // Create the central filename + // + + lstrcpy (szProfile, lpProfile->szCentralProfile); + lpEnd = CheckSlash (szProfile); + + if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { + lstrcpy (lpEnd, c_szNTUserMan); + } else { + lstrcpy (lpEnd, c_szNTUserDat); + } + + + hFileCentral = CreateFile(szProfile, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFileCentral == INVALID_HANDLE_VALUE) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't open central profile <%s>, error = %d"), + szProfile, GetLastError())); + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to revert to self"))); + } + return FALSE; + + } else { + + if (!GetFileTime(hFileCentral, NULL, NULL, &ft)) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't get time of central profile, error = %d"), GetLastError())); + } + } + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to revert to self"))); + } + + + // + // Create the local filename + // + + lstrcpy (szProfile, lpProfile->szLocalProfile); + lpEnd = CheckSlash (szProfile); + + if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { + lstrcpy (lpEnd, c_szNTUserMan); + } else { + lstrcpy (lpEnd, c_szNTUserDat); + } + + + hFileLocal = CreateFile(szProfile, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFileLocal == INVALID_HANDLE_VALUE) { + + DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't open local profile <%s>, error = %d"), + szProfile, GetLastError())); + + } else { + + if (!SetFileTime(hFileLocal, NULL, NULL, &ft)) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't set time on local profile, error = %d"), GetLastError())); + } + if (!GetFileTime(hFileLocal, NULL, NULL, &ft)) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't get time on local profile, error = %d"), GetLastError())); + } + CloseHandle(hFileLocal); + } + + // + // Reset time of central profile in case of discrepencies in + // times of different file systems. + // + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to impersonate user"))); + return FALSE; + } + + + // + // Set the time on the central profile + // + if (hFileCentral != INVALID_HANDLE_VALUE) { + if (!SetFileTime(hFileCentral, NULL, NULL, &ft)) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't set time on local profile, error = %d"), GetLastError())); + } + CloseHandle(hFileCentral); + } + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to revert to self"))); + } + + return TRUE; +} + +//************************************************************* +// +// IsCacheDeleted() +// +// Purpose: Determines if the locally cached copy of the +// roaming profile should be deleted. +// +// Parameters: void +// +// Return: TRUE if local cache should be deleted +// FALSE if not +// +// Comments: +// +// History: Date Author Comment +// 6/28/96 ericflo Created +// +//************************************************************* + +BOOL IsCacheDeleted (void) +{ + BOOL bRetVal = FALSE; + DWORD dwSize, dwType; + HKEY hKey; + + // + // Open the winlogon registry key + // + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + WINLOGON_KEY, + 0, + KEY_READ, + &hKey) == ERROR_SUCCESS) { + + // + // Check for the flag. + // + + dwSize = sizeof(BOOL); + RegQueryValueEx (hKey, + DELETE_ROAMING_CACHE, + NULL, + &dwType, + (LPBYTE) &bRetVal, + &dwSize); + + RegCloseKey (hKey); + } + + return bRetVal; +} + +//************************************************************* +// +// UnloadUserProfile() +// +// Purpose: Unloads the user's profile. +// +// Parameters: hToken - User's token +// hProfile - Profile handle created in LoadUserProfile +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 6/7/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI UnloadUserProfile (HANDLE hToken, HANDLE hProfile) +{ + LPPROFILE lpProfile = NULL; + LPTSTR lpSidString = NULL; + LONG err, IgnoreError; + BOOL bRet, bRetVal = FALSE; + HANDLE hEvent = NULL; + TCHAR szEventName[MAX_PATH]; + DWORD dwResult; + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Entering, hProfile = <0x%x>"), + hProfile)); + + + + // + // Check Parameters + // + + if (!hProfile) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: received a NULL hProfile."))); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + + // + // Load profile information + // + + lpProfile = LoadProfileInfo(hToken); + + if (!lpProfile) { + RegCloseKey((HKEY)hProfile); + goto Exit; + } + + + // + // Restore the hKeyCurrentUser parameter + // + + lpProfile->hKeyCurrentUser = (HKEY) hProfile; + + + // + // Get the Sid string for the current user + // + + lpSidString = GetSidString(lpProfile->hToken); + + if (!lpSidString) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to get sid string for user"))); + goto Exit; + } + + + // + // Create an event to prevent multiple threads/process from trying to + // unload the profile at the same time. + // + + wsprintf (szEventName, TEXT("userenv: %s"), lpSidString); + CharLower (szEventName); + + InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ); + + SetSecurityDescriptorDacl ( + &sd, + TRUE, // Dacl present + NULL, // NULL Dacl + FALSE // Not defaulted + ); + + sa.lpSecurityDescriptor = &sd; + sa.bInheritHandle = FALSE; + sa.nLength = sizeof( sa ); + + hEvent = CreateEvent ( &sa, TRUE, TRUE, szEventName); + + if (!hEvent) { + + if ( GetLastError() == ERROR_INVALID_HANDLE ) + { + hEvent = OpenEvent( EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, szEventName ); + } + + if ( !hEvent ) + { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to create event %s. Error = %d."), + szEventName, GetLastError())); + goto Exit; + + } + } + + + if ((WaitForSingleObject (hEvent, INFINITE) == WAIT_FAILED)) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to wait on the event. Error = %d."), + GetLastError())); + goto Exit; + } + + // + // This will clear the event so other threads/process will have to + // wait in the WaitForSingleObject call. + // + + ResetEvent (hEvent); + + + + // + // Flush out the profile which will also sync the log. + // + + err = RegFlushKey(lpProfile->hKeyCurrentUser); + if (err != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to flush the current user key, error = %d"), err)); + } + + + // + // Close the current user key that was opened in LoadUserProfile. + // + + err = RegCloseKey(lpProfile->hKeyCurrentUser); + if (err != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to close the current user key, error = %d"), err)); + } + + + // + // If this is a mandatory or a guest profile, unload it now. + // Guest profiles are always deleted so one guest can't see + // the profile of a previous guest. + // + + if ((lpProfile->dwInternalFlags & PROFILE_MANDATORY) || + (lpProfile->dwInternalFlags & PROFILE_GUEST_USER)) { + + err = MyRegUnLoadKey(HKEY_USERS, lpSidString); + + if (!err) { + DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Didn't unload the user profile because of error = %d"), GetLastError())); + bRetVal = TRUE; + goto Exit; + + } else { + DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Succesfully unloaded mandatory/guest profile"))); + } + + IgnoreError = RegFlushKey(HKEY_USERS); + if (IgnoreError != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to flush HKEY_USERS, error = %d"), IgnoreError)); + } + + if (IsCacheDeleted() || (lpProfile->dwInternalFlags & PROFILE_GUEST_USER)) { + + // + // Delete the profile + // + + if (!DeleteProfile (lpSidString, lpProfile->szLocalProfile, FALSE)) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: DeleteProfileDirectory returned false. Error = %d"), GetLastError())); + } + } + + if (err) { + bRetVal = TRUE; + } + + goto Exit; + } + + + + // + // Unload the profile + // + + err = MyRegUnLoadKey(HKEY_USERS, lpSidString); + + if (!err) { + DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Didn't unload user profile <err = %d>"), GetLastError())); + bRetVal = TRUE; + goto Exit; + + } else { + DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Succesfully unloaded profile"))); + } + + + + // + // Copy local profileimage to remote profilepath + // + + if ( ((lpProfile->dwInternalFlags & PROFILE_UPDATE_CENTRAL) || + (lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL)) ) { + + if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && + !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { + + DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Copying profile back to %s"), + lpProfile->szCentralProfile)); + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to impersonate user"))); + goto Exit; + } + + + bRet = CopyProfileDirectory (lpProfile->szLocalProfile, + lpProfile->szCentralProfile, + CPD_IGNORECOPYERRORS | + CPD_COPYIFDIFFERENT | + CPD_SYNCHRONIZE); + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to revert to self"))); + } + + + + // + // Check return value + // + + if (!bRet) { + + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); + ReportError(lpProfile->dwFlags, IDS_CENTRAL_UPDATE_FAILED, GetLastError()); + goto Exit; + } + + // + // The profile is copied, now we want to make sure the timestamp on + // both the remote profile and the local copy are the same, so we don't + // ask the user to update when it's not necessary. + // + + SetProfileTime(lpProfile); + + if (IsCacheDeleted()) { + if (!DeleteProfile (lpSidString, lpProfile->szLocalProfile, FALSE)) { + DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: DeleteProfileDirectory returned false (2). Error = %d"), GetLastError())); + } + } + } + } + + // + // Success + // + + bRetVal = TRUE; + + +Exit: + + + if (hEvent) { + + // + // This will set the event so other threads/process can continue. + // + + SetEvent (hEvent); + CloseHandle (hEvent); + } + + + if (lpSidString) { + DeleteSidString(lpSidString); + } + + + if (lpProfile) { + LocalFree (lpProfile); + } + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Leaving with a return value of %d"), bRetVal)); + + + return bRetVal; +} + + +//************************************************************* +// +// SaveProfileInfo() +// +// Purpose: Saves key parts of the lpProfile structure +// in the registry for UnloadUserProfile to use. +// +// Parameters: lpProfile - Profile information +// +// Return: (BOOL) TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 12/4/95 ericflo Created +// +//************************************************************* + +BOOL SaveProfileInfo(LPPROFILE lpProfile) +{ + LPTSTR SidString, lpEnd; + TCHAR LocalProfileKey[MAX_PATH]; + LONG lResult; + HKEY hKey; + DWORD dwType, dwSize, dwCount, dwDisp; + + + // + // Get the Sid string for the user + // + + SidString = GetSidString(lpProfile->hToken); + if (!SidString) { + DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to get sid string for user"))); + return FALSE; + } + + + // + // Open the profile mapping + // + + lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); + lpEnd = CheckSlash (LocalProfileKey); + lstrcpy(lpEnd, SidString); + + lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, 0, 0, + KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisp); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_VERBOSE, TEXT("SaveProfileInfo: Failed to open profile mapping key with error %d"), lResult)); + return FALSE; + } + + + // + // Save the flags + // + + lResult = RegSetValueEx (hKey, + PROFILE_FLAGS, + 0, + REG_DWORD, + (LPBYTE) &lpProfile->dwFlags, + sizeof(DWORD)); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_VERBOSE, TEXT("SaveProfileInfo: Failed to save flags with error %d"), lResult)); + } + + + // + // Save the internal flags + // + + lResult = RegSetValueEx (hKey, + PROFILE_STATE, + 0, + REG_DWORD, + (LPBYTE) &lpProfile->dwInternalFlags, + sizeof(DWORD)); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_VERBOSE, TEXT("SaveProfileInfo: Failed to save flags2 with error %d"), lResult)); + } + + + // + // Save the central profile path + // + + lResult = RegSetValueEx (hKey, + PROFILE_CENTRAL_PROFILE, + 0, + REG_SZ, + (LPBYTE) &lpProfile->szCentralProfile, + (lstrlen(lpProfile->szCentralProfile) + 1) * sizeof(TCHAR)); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_VERBOSE, TEXT("SaveProfileInfo: Failed to save central profile with error %d"), lResult)); + } + + + RegCloseKey (hKey); + + + DeleteSidString(SidString); + + + return(TRUE); +} + + +//************************************************************* +// +// LoadProfileInfo() +// +// Purpose: Loads key parts of the lpProfile structure +// in the registry for UnloadUserProfile to use. +// +// Parameters: hToken - User's token +// +// Return: pointer to lpProfile is successful +// NULL if not +// +// Comments: This function doesn't re-initialize all of the +// fields in the PROFILE structure. +// +// History: Date Author Comment +// 12/5/95 ericflo Created +// +//************************************************************* + +LPPROFILE LoadProfileInfo(HANDLE hToken) +{ + LPPROFILE lpProfile; + LPTSTR SidString, lpEnd; + TCHAR szBuffer[MAX_PATH]; + LONG lResult; + HKEY hKey; + DWORD dwType, dwSize; + + + // + // Allocate an internal Profile structure to work with. + // + + lpProfile = (LPPROFILE) LocalAlloc (LPTR, sizeof(PROFILE)); + + if (!lpProfile) { + DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to allocate memory"))); + return NULL; + } + + + // + // Save the data passed in. + // + + lpProfile->hToken = hToken; + + + + // + // Get the Sid string for the user + // + + SidString = GetSidString(hToken); + if (!SidString) { + DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to get sid string for user"))); + LocalFree (lpProfile); + return NULL; + } + + + // + // Open the profile mapping + // + + lstrcpy(szBuffer, PROFILE_LIST_PATH); + lpEnd = CheckSlash (szBuffer); + lstrcpy(lpEnd, SidString); + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, + KEY_READ, &hKey); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to open profile mapping key with error %d"), lResult)); + LocalFree (lpProfile); + return NULL; + } + + + // + // Query for the flags + // + + dwSize = sizeof(DWORD); + lResult = RegQueryValueEx (hKey, + PROFILE_FLAGS, + NULL, + &dwType, + (LPBYTE) &lpProfile->dwFlags, + &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query flags with error %d"), lResult)); + LocalFree (lpProfile); + return NULL; + } + + + // + // Query for the internal flags + // + + dwSize = sizeof(DWORD); + lResult = RegQueryValueEx (hKey, + PROFILE_STATE, + NULL, + &dwType, + (LPBYTE) &lpProfile->dwInternalFlags, + &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query internal flags with error %d"), lResult)); + LocalFree (lpProfile); + return NULL; + } + + + // + // Query for the user preference value + // + + + lpProfile->dwUserPreference = USERINFO_UNDEFINED; + dwSize = sizeof(DWORD); + + RegQueryValueEx (hKey, + USER_PREFERENCE, + NULL, + &dwType, + (LPBYTE) &lpProfile->dwUserPreference, + &dwSize); + + + + // + // Query for the central profile path + // + + dwSize = MAX_PATH * 2; + lResult = RegQueryValueEx (hKey, + PROFILE_CENTRAL_PROFILE, + NULL, + &dwType, + (LPBYTE) &lpProfile->szCentralProfile, + &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query central profile with error %d"), lResult)); + LocalFree (lpProfile); + return NULL; + } + + + // + // Query for the local profile path. The local profile path + // needs to be expanded so read it into the temporary buffer. + // + + dwSize = MAX_PATH * 2; + lResult = RegQueryValueEx (hKey, + PROFILE_IMAGE_VALUE_NAME, + NULL, + &dwType, + (LPBYTE) szBuffer, + &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query local profile with error %d"), lResult)); + LocalFree (lpProfile); + return NULL; + } + + + // + // Expand the local profile + // + + ExpandEnvironmentStrings(szBuffer, lpProfile->szLocalProfile, MAX_PATH); + + + + RegCloseKey (hKey); + + + DeleteSidString(SidString); + + return(lpProfile); +} + +//************************************************************* +// +// CheckForSlowLink() +// +// Purpose: Checks if the network connection is slow. +// +// Parameters: lpProfile - Profile Information +// dwTime - Time delta +// +// Return: TRUE if profile should be downloaded +// FALSE if not (use local) +// +// Comments: +// +// History: Date Author Comment +// 2/21/96 ericflo Created +// +//************************************************************* + +BOOL CheckForSlowLink(LPPROFILE lpProfile, DWORD dwTime) +{ + DWORD dwSlowTimeOut, dwSlowDlgTimeOut, dwSlowLinkDetectEnabled; + DWORD dwType, dwSize; + BOOL bRetVal; + HKEY hKey; + LONG lResult; + + + // + // If the user doesn't want pop-up's, then they always + // get their profile downloaded. + // + + if (lpProfile->dwFlags & PI_NOUI) { + return TRUE; + } + + // + // If the User Preferences states to always use the local + // profile then we can exit now with true. The profile + // won't actually be downloaded. In RestoreUserProfile, + // this will be filtered out, and only the local will be used. + // + + if (lpProfile->dwUserPreference == USERINFO_LOCAL) { + return TRUE; + } + + + // + // Get the slow link detection flag, slow link timeout, + // and dialog box timeout values. + // + + dwSlowTimeOut = SLOW_LINK_TIMEOUT; + dwSlowDlgTimeOut = PROFILE_DLG_TIMEOUT; + dwSlowLinkDetectEnabled = 1; + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + WINLOGON_KEY, + 0, + KEY_READ, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + dwSize = sizeof(DWORD); + RegQueryValueEx (hKey, + TEXT("SlowLinkDetectEnabled"), + NULL, + &dwType, + (LPBYTE) &dwSlowLinkDetectEnabled, + &dwSize); + + + dwSize = sizeof(DWORD); + RegQueryValueEx (hKey, + TEXT("SlowLinkTimeOut"), + NULL, + &dwType, + (LPBYTE) &dwSlowTimeOut, + &dwSize); + + dwSize = sizeof(DWORD); + RegQueryValueEx (hKey, + TEXT("ProfileDlgTimeOut"), + NULL, + &dwType, + (LPBYTE) &dwSlowDlgTimeOut, + &dwSize); + + + RegCloseKey (hKey); + } + + + // + // If slow link detection is disabled, then always download + // the profile. + // + + if (!dwSlowLinkDetectEnabled) { + return TRUE; + } + + + // + // If the delta time is less that the timeout time, then it + // is ok to download their profile (fast enough net connection). + // + + if (dwTime < dwSlowTimeOut) { + return TRUE; + } + + + // + // If the User Preferences states to always use the local + // profile on slow links, then we can exit now with false. + // + + if (lpProfile->dwUserPreference == USERINFO_LOCAL_SLOW_LINK) { + lpProfile->dwInternalFlags |= PROFILE_SLOW_LINK; + return FALSE; + } + + + // + // Display the slow link dialog + // + // If someone sets the dialog box timeout to 0, then we + // don't want to prompt the user. Just force the profile + // to download. + // + + if (dwSlowDlgTimeOut > 0) { + + bRetVal = DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_SLOW_LINK), + NULL, SlowLinkDlgProc, dwSlowDlgTimeOut); + + if (!bRetVal) { + lpProfile->dwInternalFlags |= PROFILE_SLOW_LINK; + } + + return bRetVal; + } + + return TRUE; +} + + +//************************************************************* +// +// SlowLinkDlgProc() +// +// Purpose: Dialog box procedure for the slow link dialog +// +// Parameters: hDlg - handle to the dialog box +// uMsg - window message +// wParam - wParam +// lParam - lParam +// +// Return: TRUE if message was processed +// FALSE if not +// +// Comments: +// +// History: Date Author Comment +// 2/13/96 ericflo Created +// +//************************************************************* + +BOOL APIENTRY SlowLinkDlgProc (HWND hDlg, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + TCHAR szBuffer[10]; + static DWORD dwSlowLinkTime; + + switch (uMsg) { + + case WM_INITDIALOG: + CenterWindow (hDlg); + dwSlowLinkTime = (DWORD) lParam; + wsprintf (szBuffer, TEXT("%d"), dwSlowLinkTime); + SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); + SetTimer (hDlg, 1, 1000, NULL); + return TRUE; + + case WM_TIMER: + + if (dwSlowLinkTime >= 1) { + + dwSlowLinkTime--; + wsprintf (szBuffer, TEXT("%d"), dwSlowLinkTime); + SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); + + } else { + + // + // Time's up. Download the profile. + // + + PostMessage (hDlg, WM_COMMAND, IDC_DOWNLOAD, 0); + } + break; + + case WM_COMMAND: + + switch (LOWORD(wParam)) { + + case IDC_DOWNLOAD: + case IDC_LOCAL: + case IDCANCEL: + + // + // Nothing to do. Save the state and return. + // + + KillTimer (hDlg, 1); + + // + // Return TRUE to download the profile, + // FALSE to use the local profile + // + + EndDialog(hDlg, ((LOWORD(wParam) == IDC_LOCAL) ? FALSE : TRUE)); + break; + + default: + break; + + } + break; + + } + + return FALSE; +} +//************************************************************* +// +// GetUserPreferenceValue() +// +// Purpose: Gets the User Preference flags +// +// Parameters: hToken - User's token +// +// Return: Value +// +// Comments: +// +// History: Date Author Comment +// 2/22/96 ericflo Created +// +//************************************************************* + +DWORD GetUserPreferenceValue(HANDLE hToken) +{ + TCHAR LocalProfileKey[MAX_PATH]; + DWORD RegErr, dwType, dwSize, dwRetVal = USERINFO_UNDEFINED; + LPTSTR lpEnd; + LPTSTR SidString; + HKEY hkeyProfile; + + + SidString = GetSidString(hToken); + if (SidString != NULL) { + + // + // Query for the UserPreference value + // + + lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); + lpEnd = CheckSlash (LocalProfileKey); + lstrcpy(lpEnd, SidString); + + RegErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + LocalProfileKey, + 0, + KEY_READ, + &hkeyProfile); + + + if (RegErr == ERROR_SUCCESS) { + + dwSize = sizeof(dwRetVal); + RegQueryValueEx(hkeyProfile, + USER_PREFERENCE, + NULL, + &dwType, + (LPBYTE) &dwRetVal, + &dwSize); + + RegCloseKey (hkeyProfile); + } + + DeleteSidString(SidString); + } + + return dwRetVal; +} + +//************************************************************* +// +// ChooseProfileDlgProc() +// +// Purpose: Dialog box procedure for the choose profile dialog +// +// Parameters: hDlg - handle to the dialog box +// uMsg - window message +// wParam - wParam +// lParam - lParam +// +// Return: TRUE if message was processed +// FALSE if not +// +// Comments: +// +// History: Date Author Comment +// 2/23/96 ericflo Created +// +//************************************************************* + +BOOL APIENTRY ChooseProfileDlgProc (HWND hDlg, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + TCHAR szBuffer[10]; + static DWORD dwChooseProfileTime; + + switch (uMsg) { + + case WM_INITDIALOG: + CenterWindow (hDlg); + dwChooseProfileTime = (DWORD) lParam; + wsprintf (szBuffer, TEXT("%d"), dwChooseProfileTime); + SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); + SetTimer (hDlg, 1, 1000, NULL); + return TRUE; + + case WM_TIMER: + + if (dwChooseProfileTime >= 1) { + + dwChooseProfileTime--; + wsprintf (szBuffer, TEXT("%d"), dwChooseProfileTime); + SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); + + } else { + + // + // Time's up. Use the local profile. + // + + PostMessage (hDlg, WM_COMMAND, IDC_CP_YES, 0); + } + break; + + case WM_COMMAND: + + switch (LOWORD(wParam)) { + + case IDC_CP_YES: + case IDC_CP_NO: + case IDCANCEL: + + // + // Nothing to do. Save the state and return. + // + + KillTimer (hDlg, 1); + + // + // Return IDYES to use the local profile + // IDNO to download the central profile + // + + EndDialog(hDlg, ((LOWORD(wParam) == IDC_CP_NO) ? IDNO : IDYES)); + break; + + default: + break; + + } + break; + + } + + return FALSE; +} diff --git a/private/windows/gina/userenv/profile.h b/private/windows/gina/userenv/profile.h new file mode 100644 index 000000000..e4262cc4c --- /dev/null +++ b/private/windows/gina/userenv/profile.h @@ -0,0 +1,71 @@ +//************************************************************* +// +// Header file for Profile.c +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +// +// Internal flags +// + +#define PROFILE_MANDATORY 0x00000001 +#define PROFILE_USE_CACHE 0x00000002 +#define PROFILE_NEW_LOCAL 0x00000004 +#define PROFILE_NEW_CENTRAL 0x00000008 +#define PROFILE_UPDATE_CENTRAL 0x00000010 +#define PROFILE_DELETE_CACHE 0x00000020 +#define PROFILE_RUN_SYNCAPP 0x00000040 +#define PROFILE_GUEST_USER 0x00000080 +#define PROFILE_ADMIN_USER 0x00000100 +#define DEFAULT_NET_READY 0x00000200 +#define PROFILE_SLOW_LINK 0x00000400 + +// +// User Preference values +// + +#define USERINFO_LOCAL 0 +#define USERINFO_FLOATING 1 +#define USERINFO_MANDATORY 2 +#define USERINFO_LOCAL_SLOW_LINK 3 +#define USERINFO_UNDEFINED 99 + + +typedef struct _PROFILE { + DWORD dwFlags; + DWORD dwInternalFlags; + DWORD dwUserPreference; + HANDLE hToken; + TCHAR szUserName[MAX_PATH]; + TCHAR szCentralProfile[MAX_PATH]; + TCHAR szDefaultProfile[MAX_PATH]; + TCHAR szLocalProfile[MAX_PATH]; + TCHAR szPolicyPath[MAX_PATH]; + TCHAR szServerName[MAX_COMPUTERNAME_LENGTH]; + HKEY hKeyCurrentUser; +} PROFILE, FAR * LPPROFILE; + + +#define USER_SHELL_FOLDER TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders") +#define PROFILE_LIST_PATH TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList") +#define PROFILE_FLAGS TEXT("Flags") +#define PROFILE_STATE TEXT("State") +#define PROFILE_IMAGE_VALUE_NAME TEXT("ProfileImagePath") +#define PROFILE_CENTRAL_PROFILE TEXT("CentralProfile") +#define CONFIG_FILE_PATH TEXT("%SystemRoot%\\Profiles\\") +#define USER_PREFERENCE TEXT("UserPreference") +#define PROFILE_BUILD_NUMBER TEXT("BuildNumber") +#define TEMP_PROFILE_NAME_BASE TEXT("TEMP") +#define SYNCAPP_REG_VALUE_NAME TEXT("RunSyncApp") +#define DELETE_ROAMING_CACHE TEXT("DeleteRoamingCache") + + +LONG MyRegLoadKey(LPPROFILE lpProfile, HKEY hKey, LPTSTR lpSubKey, LPTSTR lpFile); +BOOL MyRegUnLoadKey(HKEY hKey, LPTSTR lpSubKey); +BOOL SetupNewHive(LPPROFILE lpProfile, LPTSTR lpSidString, PSID pSid); +BOOL DeleteProfile (LPTSTR lpSidString, LPTSTR lpLocalProfile, BOOL bBackup); +BOOL CreateSecureDirectory (LPPROFILE lpProfile, LPTSTR lpDirectory, PSID pSid); diff --git a/private/windows/gina/userenv/profile.ico b/private/windows/gina/userenv/profile.ico Binary files differnew file mode 100644 index 000000000..2226f0db1 --- /dev/null +++ b/private/windows/gina/userenv/profile.ico diff --git a/private/windows/gina/userenv/resource.h b/private/windows/gina/userenv/resource.h new file mode 100644 index 000000000..39058d194 --- /dev/null +++ b/private/windows/gina/userenv/resource.h @@ -0,0 +1,77 @@ +//************************************************************* +// +// Resource.h - Header file for userenv.rc +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uevents.h" + +#define IDS_FAILED_LOAD_PROFILE 0 +#define IDS_ACCESSDENIED 1 +#define IDS_FAILEDDIRCREATE 2 +#define IDS_FAILEDDIRCREATE2 3 +#define IDS_CENTRAL_NOT_AVAILABLE 4 +#define IDS_TEMP_DIR_FAILED 5 +#define IDS_FAILED_LOAD_LOCAL 6 +#define IDS_SECURITY_FAILED 7 +#define IDS_CENTRAL_UPDATE_FAILED 8 +#define IDS_ADMIN_OVERRIDE 9 +#define IDS_CENTRAL_NOT_AVAILABLE2 10 +#define IDS_MANDATORY_NOT_AVAILABLE 11 +#define IDS_MANDATORY_NOT_AVAILABLE2 12 +#define IDS_MISSINGPOLICYFILEENTRY 13 +#define IDS_REGLOADKEYFAILED 14 +#define IDS_COMMON 15 + +#define IDS_SH_APPDATA 16 +#define IDS_SH_DESKTOP 17 +#define IDS_SH_FAVORITES 18 +#define IDS_SH_NETHOOD 19 +#define IDS_SH_PERSONAL 20 +#define IDS_SH_PRINTHOOD 21 +#define IDS_SH_RECENT 22 +#define IDS_SH_SENDTO 23 +#define IDS_SH_STARTMENU 24 +#define IDS_SH_TEMPLATES 25 +#define IDS_SH_PROGRAMS 26 +#define IDS_SH_STARTUP 27 + +#define IDS_COMMON_PROGRAMS 28 +#define IDS_DEFAULT_PROGRAMS 29 +#define IDS_COMMON_DESKTOP 30 +#define IDS_DEFAULT_DESKTOP 31 + +// +// Profile icon +// + +#define IDI_PROFILE 1 +// +// Slow link dialog +// + +#define IDD_SLOW_LINK 1000 +#define IDC_DOWNLOAD 1001 +#define IDC_LOCAL 1002 +#define IDC_TIMEOUT 1004 + + +// +// Choose profile dialog +// + +#define IDD_CHOOSE_PROFILE 2000 +#define IDC_CP_YES 2001 +#define IDC_CP_NO 2002 + + +// +// Error dialog +// + +#define IDD_ERROR 3000 +#define IDC_ERRORTEXT 1001 diff --git a/private/windows/gina/userenv/samples/copydir/generic.c b/private/windows/gina/userenv/samples/copydir/generic.c new file mode 100644 index 000000000..9a76e4607 --- /dev/null +++ b/private/windows/gina/userenv/samples/copydir/generic.c @@ -0,0 +1,423 @@ +/**************************************************************************** + + PROGRAM: Generic.c + + PURPOSE: Generic template for Windows applications + +****************************************************************************/ + +#include <windows.h> +#include <userenv.h> +#include "generic.h" + + +HINSTANCE hInst; +HWND hwndMain; +HANDLE hProfile, hUserToken; + +TCHAR szAppName[] = TEXT("Generic"); +#ifdef UNICODE +TCHAR szTitle[] = TEXT("UserEnv Profile Test App - UNICODE"); +#else +TCHAR szTitle[] = TEXT("UserEnv Profile Test App - ANSI"); +#endif + + +TCHAR szSrcDir[MAX_PATH]; +TCHAR szDestDir[MAX_PATH]; +TCHAR szProfilePath[MAX_PATH]; +TCHAR szDefaultPath[MAX_PATH]; +TCHAR szUserName[MAX_PATH]; +TCHAR szDomainName[MAX_PATH]; + +void ChangeMenuState (BOOL bLoggedOn); + +/**************************************************************************** + + FUNCTION: WinMain(HINSTANCE, HINSTANCE, LPSTR, int) + + PURPOSE: calls initialization function, processes message loop + +****************************************************************************/ +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, INT nCmdShow) +{ + MSG msg; + HANDLE hAccelTable; + + if (!hPrevInstance) + { + if (!InitApplication(hInstance)) + { + return (FALSE); + } + } + + + // Perform initializations that apply to a specific instance + if (!InitInstance(hInstance, nCmdShow)) + { + return (FALSE); + } + + hAccelTable = LoadAccelerators (hInstance, szAppName); + + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + + return (msg.wParam); + + lpCmdLine; +} + + +/**************************************************************************** + + FUNCTION: InitApplication(HINSTANCE) + + PURPOSE: Initializes window data and registers window class + +****************************************************************************/ + +BOOL InitApplication(HINSTANCE hInstance) +{ + WNDCLASS wc; + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = (WNDPROC)WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon (hInstance, szAppName); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = szAppName; + wc.lpszClassName = szAppName; + + return (RegisterClass(&wc)); +} + + +/**************************************************************************** + + FUNCTION: InitInstance(HINSTANCE, int) + + PURPOSE: Saves instance handle and creates main window + +****************************************************************************/ + +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; + hProfile = NULL; + + szSrcDir[0] = TEXT('\0'); + szDestDir[0] = TEXT('\0'); + szProfilePath[0] = TEXT('\0'); + szDefaultPath[0] = TEXT('\0'); + szUserName[0] = TEXT('\0'); + szDomainName[0] = TEXT('\0'); + + hWnd = CreateWindow(szAppName, + szTitle, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + NULL, + NULL, + hInstance, + NULL); + + if (!hWnd) + { + return (FALSE); + } + else + { + hwndMain = hWnd; + } + + ChangeMenuState(FALSE); + PostMessage (hWnd, WM_COMMAND, IDM_LOGON, 0); + + ShowWindow(hWnd, SW_SHOWDEFAULT); + UpdateWindow(hWnd); + + return (TRUE); + +} + +/**************************************************************************** + + FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) + + PURPOSE: Processes messages + +****************************************************************************/ + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + + switch (message) + { + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDM_LOGON: + if (DialogBox (hInst, TEXT("LOGONDLG"), hWnd, LogonDlgProc)) { + ChangeMenuState(TRUE); + } + break; + + case IDM_LOGOFF: + CloseHandle(hUserToken); + ChangeMenuState(FALSE); + break; + + case IDM_LUP: + DialogBox (hInst, TEXT("LUPDLG"), hWnd, LUPDlgProc); + break; + + case IDM_ULUP: + if (hProfile) { + if (UnloadUserProfile(hUserToken, hProfile)) { + hProfile = NULL; + } + } + break; + + case IDM_ABOUT: + DialogBox (hInst, TEXT("AboutBox"), hWnd, About); + break; + + case IDM_EXIT: + DestroyWindow (hwndMain); + break; + + + default: + return (DefWindowProc(hWnd, message, wParam, lParam)); + } + } + break; + + case WM_DESTROY: + if (hProfile) { + if (UnloadUserProfile(hUserToken, hProfile)) { + hProfile = NULL; + } + } + + PostQuitMessage(0); + break; + + default: + return (DefWindowProc(hWnd, message, wParam, lParam)); + } + + return FALSE; +} + +/**************************************************************************** + + FUNCTION: About(HWND, UINT, WPARAM, LPARAM) + + PURPOSE: Processes messages for "About" dialog box + +****************************************************************************/ + +LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + + switch (message) + { + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, TRUE); + return (TRUE); + } + break; + } + + return (FALSE); + + lParam; +} + + +/**************************************************************************** + + FUNCTION: LUPDlgProc(HWND, UINT, WPARAM, LPARAM) + +****************************************************************************/ + +LRESULT CALLBACK LUPDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + + switch (message) + { + case WM_INITDIALOG: + SetDlgItemText(hDlg, IDD_PROFILEPATH, szProfilePath); + SetDlgItemText(hDlg, IDD_DEFAULTPATH, szDefaultPath); + + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + PROFILEINFO pi; + DWORD dwStart, dwEnd, dwFlags = 0; + TCHAR szBuffer[200]; + HCURSOR hCursor; + BOOL bResult; + + SetDlgItemText(hDlg, IDD_RETVAL, NULL); + SetDlgItemText(hDlg, IDD_HKEY, NULL); + SetDlgItemText(hDlg, IDD_PROFILE, NULL); + + + GetDlgItemText(hDlg, IDD_PROFILEPATH, szProfilePath, MAX_PATH); + GetDlgItemText(hDlg, IDD_DEFAULTPATH, szDefaultPath, MAX_PATH); + + + pi.dwSize = sizeof(PROFILEINFO); + pi.dwFlags = dwFlags; + pi.lpUserName = szUserName; + pi.lpProfilePath = szProfilePath; + pi.lpDefaultPath = szDefaultPath; + pi.lpServerName = NULL; + + hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + + dwStart = GetTickCount(); + bResult = LoadUserProfile(hUserToken, &pi); + dwEnd = GetTickCount(); + + SetCursor(hCursor); + + //SetDlgItemInt(hDlg, IDD_EXTIME, dwEnd - dwStart, FALSE); + SetDlgItemInt(hDlg, IDD_RETVAL, bResult, FALSE); + + if (bResult) { + hProfile = pi.hProfile; + + wsprintf (szBuffer, TEXT("0x%x"), pi.hProfile); + SetDlgItemText(hDlg, IDD_PROFILE, szBuffer); + } + + } + + if (LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, TRUE); + return (TRUE); + } + + break; + } + + return (FALSE); +} + + +void ChangeMenuState (BOOL bLoggedOn) +{ + HMENU hMenu; + + + hMenu = GetMenu(hwndMain); + + if (bLoggedOn) { + + EnableMenuItem (hMenu, IDM_LOGON, MF_BYCOMMAND | MF_GRAYED); + + + EnableMenuItem (hMenu, IDM_LOGOFF, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem (hMenu, IDM_LUP, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem (hMenu, IDM_ULUP, MF_BYCOMMAND | MF_ENABLED); + + } else { + + EnableMenuItem (hMenu, IDM_LOGOFF, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem (hMenu, IDM_LUP, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem (hMenu, IDM_ULUP, MF_BYCOMMAND | MF_GRAYED); + + EnableMenuItem (hMenu, IDM_LOGON, MF_BYCOMMAND | MF_ENABLED); + } + +} + +/**************************************************************************** + + FUNCTION: LogonDlgProc(HWND, UINT, WPARAM, LPARAM) + +****************************************************************************/ + +LRESULT CALLBACK LogonDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + + switch (message) + { + case WM_INITDIALOG: + { + HBITMAP hBmp; + + hBmp = LoadBitmap (hInst, TEXT("Logo")); + + if (hBmp) { + SendDlgItemMessage (hDlg, IDD_ICON, STM_SETIMAGE, + IMAGE_BITMAP, (LPARAM) hBmp); + } + SetDlgItemText(hDlg, IDD_USERNAME, szUserName); + SetDlgItemText(hDlg, IDD_DOMAIN, szDomainName); + } + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + TCHAR szPassword[MAX_PATH]; + + GetDlgItemText(hDlg, IDD_USERNAME, szUserName, MAX_PATH); + GetDlgItemText(hDlg, IDD_DOMAIN, szDomainName, MAX_PATH); + GetDlgItemText(hDlg, IDD_PASSWORD, szPassword, MAX_PATH); + + if (LogonUser(szUserName, szDomainName, szPassword, + LOGON32_LOGON_INTERACTIVE, + LOGON32_PROVIDER_DEFAULT, + &hUserToken)) { + EndDialog(hDlg, TRUE); + return TRUE; + + } else { + TCHAR szBuffer[200]; + + wsprintf(szBuffer, TEXT("Logon Failed with Error %d"), + GetLastError()); + MessageBox (hDlg, szBuffer, TEXT("Logon"), MB_OK | MB_ICONEXCLAMATION); + return TRUE; + } + + } + + if (LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, FALSE); + return TRUE; + } + + break; + } + + return (FALSE); +} diff --git a/private/windows/gina/userenv/samples/copydir/generic.def b/private/windows/gina/userenv/samples/copydir/generic.def new file mode 100644 index 000000000..88b767ee8 --- /dev/null +++ b/private/windows/gina/userenv/samples/copydir/generic.def @@ -0,0 +1,21 @@ +NAME Generic +DESCRIPTION 'Sample Microsoft Windows Application' +EXETYPE WINDOWS +STUB 'WINSTUB.EXE' + + + +CODE PRELOAD MOVEABLE DISCARDABLE + + +DATA PRELOAD MOVEABLE MULTIPLE + +HEAPSIZE 1024 +STACKSIZE 5120 + + +EXPORTS + WndProc @1 + About @2 + LUPDlgProc @3 + LogonDlgProc @4 diff --git a/private/windows/gina/userenv/samples/copydir/generic.h b/private/windows/gina/userenv/samples/copydir/generic.h new file mode 100644 index 000000000..2085e7fe8 --- /dev/null +++ b/private/windows/gina/userenv/samples/copydir/generic.h @@ -0,0 +1,29 @@ +#define IDM_CPD 100 +#define IDM_EXIT 101 +#define IDM_ABOUT 102 +#define IDM_LUP 103 +#define IDM_ULUP 104 +#define IDM_LOGON 105 +#define IDM_LOGOFF 106 + +#define IDD_PROFILEPATH 601 +#define IDD_KEYNAMEBOX 602 +#define IDD_KEYNAME 603 +#define IDD_HKEY 605 +#define IDD_PROFILE 606 +#define IDD_HKEY_TEXT 607 +#define IDD_PROFILE_TEXT 608 +#define IDD_DEFAULTPATH 609 +#define IDD_RETVAL 610 + +#define IDD_USERNAME 700 +#define IDD_DOMAIN 701 +#define IDD_PASSWORD 702 +#define IDD_ICON 703 + +BOOL InitApplication(HANDLE); +BOOL InitInstance(HANDLE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK About (HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK LUPDlgProc (HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK LogonDlgProc(HWND, UINT, WPARAM, LPARAM); diff --git a/private/windows/gina/userenv/samples/copydir/generic.ico b/private/windows/gina/userenv/samples/copydir/generic.ico Binary files differnew file mode 100644 index 000000000..c127f57d0 --- /dev/null +++ b/private/windows/gina/userenv/samples/copydir/generic.ico diff --git a/private/windows/gina/userenv/samples/copydir/generic.rc b/private/windows/gina/userenv/samples/copydir/generic.rc new file mode 100644 index 000000000..f92e7b805 --- /dev/null +++ b/private/windows/gina/userenv/samples/copydir/generic.rc @@ -0,0 +1,86 @@ +#include "windows.h" +#include "generic.h" + +Generic ICON Generic.ICO +Logo BITMAP window.bmp + +Generic MENU +BEGIN + POPUP "&Test" + { + MENUITEM "&Log On...", IDM_LOGON + MENUITEM "Log &Off", IDM_LOGOFF + MENUITEM SEPARATOR + MENUITEM "LoadUser&Profile...", IDM_LUP + MENUITEM "&UnloadUserProfile", IDM_ULUP + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_EXIT + } + + POPUP "&Help" + { + MENUITEM "&About Generic...", IDM_ABOUT + } +END + +GENERIC ACCELERATORS +BEGIN + "?", IDM_ABOUT, ALT + "/", IDM_ABOUT, ALT +END + + +ABOUTBOX DIALOG 22, 17, 167, 64 +STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "About..." +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK", IDOK, 70, 40, 32, 14, WS_GROUP + CTEXT "LoadUserProfile Test App", -1, 10, 15, 150, 8 +END + + +LUPDLG DIALOG 6, 18, 235, 237 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "LoadUserProfile" +FONT 8, "MS Shell Dlg" +BEGIN + GROUPBOX "Flags", 101, 5, 5, 160, 76 + AUTOCHECKBOX "Reserved", 102, 15, 20, 75, 10, WS_DISABLED + AUTOCHECKBOX "Reserved", 103, 15, 40, 75, 10, WS_DISABLED + AUTOCHECKBOX "Reserved", 104, 15, 60, 75, 10, WS_DISABLED + AUTOCHECKBOX "Reserved", 105, 95, 20, 65, 10, WS_DISABLED + AUTOCHECKBOX "Reserved", 106, 95, 40, 65, 10, WS_DISABLED + AUTOCHECKBOX "Reserved", 107, 95, 60, 65, 10, WS_DISABLED + GROUPBOX "Profile Path", 108, 5, 87, 221, 35 + EDITTEXT IDD_PROFILEPATH, 15, 102, 201, 12, ES_AUTOHSCROLL + GROUPBOX "Default Profile Path", 138, 5, 130, 221, 35 + EDITTEXT IDD_DEFAULTPATH, 15, 145, 201, 12, ES_AUTOHSCROLL + CONTROL "", 113, "Static", SS_ETCHEDHORZ, 5, 177, 221, 1 + GROUPBOX "Results", 112, 5, 187, 221, 40 + CTEXT "Return Value:", 115, 15, 197, 50, 8 + CTEXT "hKey:", IDD_HKEY_TEXT, 90, 197, 50, 8 + CTEXT "hProfile:", IDD_PROFILE_TEXT, 170, 197, 50, 8 + EDITTEXT IDD_RETVAL, 15, 210, 49, 12, ES_AUTOHSCROLL + EDITTEXT IDD_HKEY, 90, 210, 49, 12, ES_AUTOHSCROLL + EDITTEXT IDD_PROFILE, 170, 210, 49, 12, ES_AUTOHSCROLL + DEFPUSHBUTTON "Execute", IDOK, 173, 8, 55, 14 + PUSHBUTTON "Close", IDCANCEL, 173, 27, 55, 14 +END + + +LOGONDLG DIALOG 62, 44, 223, 90 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Welcome" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "&Username:", 202, 53, 13, 40, 8 + EDITTEXT IDD_USERNAME, 95, 12, 122, 12, ES_AUTOHSCROLL + LTEXT "&From:", 203, 53, 29, 40, 8, NOT WS_GROUP + EDITTEXT IDD_DOMAIN, 95, 27, 122, 12, WS_TABSTOP | ES_AUTOHSCROLL + LTEXT "&Password:", 204, 53, 46, 39, 8, NOT WS_GROUP + EDITTEXT IDD_PASSWORD, 95, 44, 122, 12, ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK", IDOK, 63, 70, 40, 14, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, 119, 70, 40, 14 + CONTROL "", IDD_ICON, "Static", SS_BITMAP | WS_GROUP, 5, 11, 39, 45 +END diff --git a/private/windows/gina/userenv/samples/copydir/makefile b/private/windows/gina/userenv/samples/copydir/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/windows/gina/userenv/samples/copydir/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/windows/gina/userenv/samples/copydir/sources b/private/windows/gina/userenv/samples/copydir/sources new file mode 100644 index 000000000..689a2edaf --- /dev/null +++ b/private/windows/gina/userenv/samples/copydir/sources @@ -0,0 +1,41 @@ +!IF 0 + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + +!ENDIF + +MAJORCOMP=windows +MINORCOMP=shell + +TARGETNAME=generic +TARGETPATH=obj +TARGETTYPE=LIBRARY +TARGETLIBS= + +INCLUDES=$(BASEDIR)\private\windows\inc + +C_DEFINES= -DWIN32 -DWINVER=0x0400 + +SOURCES=generic.c \ + generic.rc + +UMTYPE=windows +UMENTRY=winmain +UMAPPL=generic + +UMLIBS=\ + $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \ + $(BASEDIR)\public\sdk\lib\*\userenv.lib \ + obj\*\generic.lib \ + obj\*\generic.res diff --git a/private/windows/gina/userenv/samples/copydir/window.bmp b/private/windows/gina/userenv/samples/copydir/window.bmp Binary files differnew file mode 100644 index 000000000..06758f8f8 --- /dev/null +++ b/private/windows/gina/userenv/samples/copydir/window.bmp diff --git a/private/windows/gina/userenv/samples/debug/debug.c b/private/windows/gina/userenv/samples/debug/debug.c new file mode 100644 index 000000000..c50bbe45a --- /dev/null +++ b/private/windows/gina/userenv/samples/debug/debug.c @@ -0,0 +1,221 @@ +//************************************************************* +// +// Debug.c - Debugging utility for User Environments +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <ntexapi.h> +#include "debug.h" + + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, INT nCmdShow) +{ + + DialogBox (hInstance, TEXT("DEBUG"), NULL, DebugDlgProc); + + return 0; + +} + +BOOL CALLBACK DebugDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + + switch (uMsg) { + + case WM_INITDIALOG: + { + HKEY hKey; + LONG lResult; + DWORD dwButton = IDD_NORMAL; + DWORD dwType, dwSize, dwValue; + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + WINLOGON_KEY, + 0, + KEY_READ, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + dwSize = sizeof(dwValue); + lResult = RegQueryValueEx(hKey, + USERENV_DEBUG_LEVEL, + NULL, + &dwType, + (LPBYTE)&dwValue, + &dwSize); + + if (lResult == ERROR_SUCCESS) { + + if (LOWORD(dwValue) == DL_NONE) { + dwButton = IDD_NONE; + } else if (LOWORD(dwValue) == DL_VERBOSE) { + dwButton = IDD_VERBOSE; + } + + } + + RegCloseKey(hKey); + } + + CheckRadioButton (hDlg, IDD_NONE, IDD_VERBOSE, dwButton); + + if (dwValue & DL_LOGFILE) { + CheckDlgButton (hDlg, IDD_LOGFILE, 1); + } + + + // + // Now check for winlogon + // + + dwButton = 0; + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + GLOBALFLAG_KEY, + 0, + KEY_READ, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + dwSize = sizeof(dwValue); + lResult = RegQueryValueEx(hKey, + GLOBAL_FLAG, + NULL, + &dwType, + (LPBYTE)&dwValue, + &dwSize); + + if (lResult == ERROR_SUCCESS) { + + if (dwValue & FLG_DEBUG_INITIAL_COMMAND) { + dwButton = 1; + } + + } + + RegCloseKey(hKey); + } + + CheckDlgButton (hDlg, IDD_WINLOGON, dwButton); + + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + { + HKEY hKey; + LONG lResult; + DWORD dwType, dwValue = DL_NORMAL; + DWORD dwButton, dwSize; + + if (IsDlgButtonChecked(hDlg, IDD_NONE)) { + dwValue = DL_NONE; + } else if (IsDlgButtonChecked(hDlg, IDD_VERBOSE)) { + dwValue = DL_VERBOSE; + } + + if (IsDlgButtonChecked(hDlg, IDD_LOGFILE)) { + dwValue |= DL_LOGFILE; + } + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + WINLOGON_KEY, + 0, + KEY_WRITE, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + lResult = RegSetValueEx(hKey, + USERENV_DEBUG_LEVEL, + 0, + REG_DWORD, + (LPBYTE)&dwValue, + sizeof(dwValue)); + + if (lResult != ERROR_SUCCESS) { + MessageBox(hDlg, TEXT("Failed to save settings."), NULL, MB_OK); + } + + RegCloseKey(hKey); + } + + + // + // Now check for winlogon + // + + if (IsDlgButtonChecked(hDlg, IDD_WINLOGON)) { + dwButton = 1; + } else { + dwButton = 0; + } + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + GLOBALFLAG_KEY, + 0, + KEY_ALL_ACCESS, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + dwSize = sizeof(dwValue); + lResult = RegQueryValueEx(hKey, + GLOBAL_FLAG, + NULL, + &dwType, + (LPBYTE)&dwValue, + &dwSize); + + if (lResult == ERROR_SUCCESS) { + + if (dwButton) { + dwValue |= FLG_DEBUG_INITIAL_COMMAND; + } else { + dwValue &= ~FLG_DEBUG_INITIAL_COMMAND; + } + + lResult = RegSetValueEx(hKey, + GLOBAL_FLAG, + 0, + REG_DWORD, + (LPBYTE)&dwValue, + sizeof(dwValue)); + if (lResult != ERROR_SUCCESS) { + MessageBox(hDlg, TEXT("Failed to save Global Flag settings."), NULL, MB_OK); + } + + } + + RegCloseKey(hKey); + } + + EndDialog(hDlg, FALSE); + return TRUE; + } + + case IDCANCEL: + EndDialog(hDlg, FALSE); + return TRUE; + + } + break; + + default: + break; + } + + return FALSE; +} diff --git a/private/windows/gina/userenv/samples/debug/debug.def b/private/windows/gina/userenv/samples/debug/debug.def new file mode 100644 index 000000000..f111d78ff --- /dev/null +++ b/private/windows/gina/userenv/samples/debug/debug.def @@ -0,0 +1,18 @@ +NAME Debug +DESCRIPTION 'Sample Microsoft Windows Application' +EXETYPE WINDOWS +STUB 'WINSTUB.EXE' + + + +CODE PRELOAD MOVEABLE DISCARDABLE + + +DATA PRELOAD MOVEABLE MULTIPLE + +HEAPSIZE 1024 +STACKSIZE 5120 + + +EXPORTS + DebugDlgProc @1 diff --git a/private/windows/gina/userenv/samples/debug/debug.h b/private/windows/gina/userenv/samples/debug/debug.h new file mode 100644 index 000000000..d9bd36ac6 --- /dev/null +++ b/private/windows/gina/userenv/samples/debug/debug.h @@ -0,0 +1,26 @@ +// +// Debug levels +// + +#define DL_NONE 0x00000000 +#define DL_NORMAL 0x00000001 +#define DL_VERBOSE 0x00000002 +#define DL_LOGFILE 0x00010000 + +// +// Winlogon location +// + +#define WINLOGON_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon") +#define GLOBALFLAG_KEY TEXT("System\\CurrentControlSet\\Control\\Session Manager") + +#define USERENV_DEBUG_LEVEL TEXT("UserEnvDebugLevel") +#define GLOBAL_FLAG TEXT("GlobalFlag") + +#define IDD_NONE 401 +#define IDD_NORMAL 402 +#define IDD_VERBOSE 403 +#define IDD_LOGFILE 404 +#define IDD_WINLOGON 405 + +BOOL CALLBACK DebugDlgProc (HWND, UINT, WPARAM, LPARAM); diff --git a/private/windows/gina/userenv/samples/debug/debug.rc b/private/windows/gina/userenv/samples/debug/debug.rc new file mode 100644 index 000000000..77929993c --- /dev/null +++ b/private/windows/gina/userenv/samples/debug/debug.rc @@ -0,0 +1,17 @@ +#include "windows.h" +#include "debug.h" + +DEBUG DIALOG 17, 26, 241, 117 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Debug User Environments" +FONT 8, "MS Shell Dlg" +BEGIN + GROUPBOX "Userenv Debug Output", -1, 10, 10, 160, 65 + AUTORADIOBUTTON "None", IDD_NONE, 25, 25, 68, 10, WS_TABSTOP | WS_GROUP + AUTORADIOBUTTON "Normal", IDD_NORMAL, 25, 40, 68, 10 + AUTORADIOBUTTON "Verbose", IDD_VERBOSE, 25, 55, 68, 10 + AUTOCHECKBOX "Create Log File (C:\USERENV.LOG)", IDD_LOGFILE, 10, 87, 161, 10, WS_TABSTOP | WS_GROUP + AUTOCHECKBOX "Debug Winlogon", IDD_WINLOGON, 10, 99, 161, 10, WS_TABSTOP | WS_GROUP + DEFPUSHBUTTON "OK", IDOK, 182, 10, 52, 17, WS_TABSTOP | WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, 182, 34, 52, 17, WS_TABSTOP | WS_GROUP +END diff --git a/private/windows/gina/userenv/samples/debug/makefile b/private/windows/gina/userenv/samples/debug/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/windows/gina/userenv/samples/debug/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/windows/gina/userenv/samples/debug/sources b/private/windows/gina/userenv/samples/debug/sources new file mode 100644 index 000000000..f5e7b3de0 --- /dev/null +++ b/private/windows/gina/userenv/samples/debug/sources @@ -0,0 +1,38 @@ +!IF 0 + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + +!ENDIF + +MAJORCOMP=windows +MINORCOMP=shell + +TARGETNAME=debug +TARGETPATH=obj +TARGETTYPE=LIBRARY +TARGETLIBS= + +INCLUDES= + +C_DEFINES= -DWIN32 -DUNICODE -D_UNICODE + +SOURCES=debug.c \ + debug.rc + +UMTYPE=windows +UMENTRY=winmain +UMAPPL=debug +UMLIBS=\ + obj\*\debug.lib \ + obj\*\debug.res diff --git a/private/windows/gina/userenv/setup.c b/private/windows/gina/userenv/setup.c new file mode 100644 index 000000000..0472ede70 --- /dev/null +++ b/private/windows/gina/userenv/setup.c @@ -0,0 +1,1494 @@ +//************************************************************* +// +// SETUP.C - API's used by setup to create groups/items +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include <uenv.h> + + +BOOL AppendCommonExtension(LPTSTR lpName); +BOOL PrependPath(LPCTSTR szFile, LPTSTR szResult); + +//************************************************************* +// +// CreateGroup() +// +// Purpose: Creates a program group (sub-directory) +// +// Parameters: lpGroupName - Name of group +// bCommonGroup - Common or Personal group +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 8/08/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI CreateGroup(LPCTSTR lpGroupName, BOOL bCommonGroup) +{ + TCHAR szDirectory[MAX_PATH]; + LPTSTR lpEnd; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("CreateGroup: Entering with <%s>."), lpGroupName)); + + + // + // Validate parameters + // + + if (!lpGroupName || !(*lpGroupName)) { + return TRUE; + } + + + // + // Get the profile directory + // + + if (!GetProgramsDirectory (bCommonGroup, szDirectory)) { + return FALSE; + } + + + // + // Now append the requested directory + // + + lpEnd = CheckSlash (szDirectory); + lstrcpy (lpEnd, lpGroupName); + + if (bCommonGroup) { + AppendCommonExtension(szDirectory); + } + + + // + // Create the group (directory) + // + + if (!CreateNestedDirectory(szDirectory, NULL)) { + DebugMsg((DM_VERBOSE, TEXT("CreateGroup: CreatedNestedDirectory failed."))); + return FALSE; + } + + + // + // Success + // + SHChangeNotify (SHCNE_MKDIR, SHCNF_PATH, szDirectory, NULL); + + DebugMsg((DM_VERBOSE, TEXT("CreateGroup: Leaving successfully."))); + + return TRUE; +} + + +//************************************************************* +// +// DeleteGroup() +// +// Purpose: Deletes a program group (sub-directory) +// +// Parameters: lpGroupName - Name of group +// bCommonGroup - Common or Personal group +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 8/10/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI DeleteGroup(LPCTSTR lpGroupName, BOOL bCommonGroup) +{ + TCHAR szDirectory[MAX_PATH]; + LPTSTR lpEnd; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("DeleteGroup: Entering with <%s>."), lpGroupName)); + + + // + // Validate parameters + // + + if (!lpGroupName || !(*lpGroupName)) { + return TRUE; + } + + + // + // Get the profile directory + // + + if (!GetProgramsDirectory (bCommonGroup, szDirectory)) { + return FALSE; + } + + + // + // Now append the requested directory + // + + lpEnd = CheckSlash (szDirectory); + lstrcpy (lpEnd, lpGroupName); + + if (bCommonGroup) { + AppendCommonExtension(szDirectory); + } + + + // + // Delete the group (directory) + // + + if (!Delnode(szDirectory)) { + DebugMsg((DM_VERBOSE, TEXT("DeleteGroup: Delnode failed."))); + return FALSE; + } + + + // + // Success + // + SHChangeNotify (SHCNE_RMDIR, SHCNF_PATH, szDirectory, NULL); + + DebugMsg((DM_VERBOSE, TEXT("DeleteGroup: Leaving successfully."))); + + return TRUE; +} + + +//************************************************************* +// +// AddItem() +// +// Purpose: Adds a item to the specified group +// +// Parameters: lpGroupName - Destination group +// bCommonGroup - Common vs Personal +// lpDescription - Description of the item +// lpCommandLine - Command line (including args) +// lpIconPath - Icon path (can be NULL) +// iIconIndex - Index of icon in icon path +// lpWorkingDir - Working directory +// wHotKey - Hot key +// iShowCmd - ShowWindow flag +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 8/09/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI AddItem(LPCTSTR lpGroupName, BOOL bCommonGroup, + LPCTSTR lpDescription, LPCTSTR lpCommandLine, + LPCTSTR lpIconPath, int iIconIndex, + LPCTSTR lpWorkingDirectory, WORD wHotKey, + int iShowCmd) + +{ + HANDLE hFile; + WIN32_FIND_DATA fd; + TCHAR szItem[MAX_PATH]; + TCHAR szArgs[MAX_PATH]; + TCHAR szLinkName[MAX_PATH]; + TCHAR szPath[MAX_PATH]; + LPTSTR lpArgs, lpEnd; + LPUNKNOWN pUnkOuter = NULL; + IShellLink *psl; + IPersistFile *ppf; + BOOL bRetVal = FALSE; + + + + // + // Verbose output + // + +#if DBG + DebugMsg((DM_VERBOSE, TEXT("AddItem: Entering."))); + if (lpGroupName && *lpGroupName) { + DebugMsg((DM_VERBOSE, TEXT("AddItem: lpGroupName = <%s>."), lpGroupName)); + DebugMsg((DM_VERBOSE, TEXT("AddItem: bCommonGroup = <%d>."), bCommonGroup)); + } + DebugMsg((DM_VERBOSE, TEXT("AddItem: lpDescription = <%s>."), lpDescription)); + DebugMsg((DM_VERBOSE, TEXT("AddItem: lpCommandLine = <%s>."), lpCommandLine)); + + if (lpIconPath) { + DebugMsg((DM_VERBOSE, TEXT("AddItem: lpIconPath = <%s>."), lpIconPath)); + DebugMsg((DM_VERBOSE, TEXT("AddItem: iIconIndex = <%d>."), iIconIndex)); + } + + if (lpWorkingDirectory) { + DebugMsg((DM_VERBOSE, TEXT("AddItem: lpWorkingDirectory = <%s>."), lpWorkingDirectory)); + } else { + DebugMsg((DM_VERBOSE, TEXT("AddItem: Null working directory. Setting to %%HOMEDRIVE%%%%HOMEPATH%%"))); + } + + DebugMsg((DM_VERBOSE, TEXT("AddItem: wHotKey = <%d>."), wHotKey)); + DebugMsg((DM_VERBOSE, TEXT("AddItem: iShowCmd = <%d>."), iShowCmd)); +#endif + + + // + // Get the profile directory + // + + if (!GetProgramsDirectory (bCommonGroup, szLinkName)) { + return FALSE; + } + + + if (lpGroupName && *lpGroupName) { + + lpEnd = CheckSlash (szLinkName); + lstrcpy (lpEnd, lpGroupName); + + if (bCommonGroup) { + AppendCommonExtension(szLinkName); + } + + + // + // Test if the program group (sub directory) exists. + // If not, create it. + // + + hFile = FindFirstFile (szLinkName, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + if (!CreateGroup (lpGroupName, bCommonGroup)) { + DebugMsg((DM_WARNING, TEXT("AddItem: CreateGroup failed."))); + return FALSE; + } + + } else { + FindClose (hFile); + } + } + + + // + // Now tack on the filename and extension. + // + + lpEnd = CheckSlash (szLinkName); + lstrcpy (lpEnd, lpDescription); + lstrcat (lpEnd, c_szLNK); + + + // + // Split the command line into the executable name + // and arguments. + // + + lstrcpy (szItem, lpCommandLine); + + lpArgs = PathGetArgs(szItem); + + if (*lpArgs) { + lstrcpy (szArgs, lpArgs); + + lpArgs--; + while (*lpArgs == TEXT(' ')) { + lpArgs--; + } + lpArgs++; + *lpArgs = TEXT('\0'); + } else { + szArgs[0] = TEXT('\0'); + } + + PathUnquoteSpaces (szItem); + + + // + // Create an IShellLink object + // + + if (FAILED(SHCoCreateInstance(NULL, &CLSID_ShellLink, pUnkOuter, + &IID_IShellLink, + (LPVOID)&psl))) + { + DebugMsg((DM_WARNING, TEXT("AddItem: Could not create instance of IShellLink ."))); + goto ExitNoFree; + } + + + // + // Query for IPersistFile + // + + if (FAILED(psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf))) + { + DebugMsg((DM_WARNING, TEXT("AddItem: QueryInterface of IShellLink failed."))); + goto ExitFreePSL; + } + + + + // + // Set the item information + // + + psl->lpVtbl->SetDescription(psl, lpDescription); + + PrependPath(szItem, szPath); + psl->lpVtbl->SetPath(psl, szPath); + + + psl->lpVtbl->SetArguments(psl, szArgs); + if (lpWorkingDirectory) { + psl->lpVtbl->SetWorkingDirectory(psl, lpWorkingDirectory); + } else { + psl->lpVtbl->SetWorkingDirectory(psl, TEXT("%HOMEDRIVE%%HOMEPATH%")); + } + + PrependPath(lpIconPath, szPath); + psl->lpVtbl->SetIconLocation(psl, szPath, iIconIndex); + + psl->lpVtbl->SetHotkey(psl, wHotKey); + psl->lpVtbl->SetShowCmd(psl, iShowCmd); + + + // + // Save the item to disk + // + + bRetVal = SUCCEEDED(ppf->lpVtbl->Save(ppf, szLinkName, TRUE)); + + if (bRetVal) { + SHChangeNotify (SHCNE_CREATE, SHCNF_PATH, szLinkName, NULL); + } + + // + // Release the IPersistFile object + // + + ppf->lpVtbl->Release(ppf); + + +ExitFreePSL: + + // + // Release the IShellLink object + // + + psl->lpVtbl->Release(psl); + +ExitNoFree: + + + // + // Finished. + // + + DebugMsg((DM_VERBOSE, TEXT("AddItem: Leaving with status of %d."), bRetVal)); + + return bRetVal; +} + + +//************************************************************* +// +// DeleteItem() +// +// Purpose: Deletes an item from the specified group +// +// Parameters: lpGroupName - Destination group +// bCommonGroup - Common vs Personal +// lpDescription - Description of the item +// bDeleteGroup - Delete the group if possible +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 8/10/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI DeleteItem(LPCTSTR lpGroupName, BOOL bCommonGroup, + LPCTSTR lpDescription, BOOL bDeleteGroup) +{ + TCHAR szLinkName[MAX_PATH]; + LPTSTR lpEnd; + + + + // + // Verbose output + // + +#if DBG + + DebugMsg((DM_VERBOSE, TEXT("DeleteItem: Entering."))); + if (lpGroupName && *lpGroupName) { + DebugMsg((DM_VERBOSE, TEXT("DeleteItem: lpGroupName = <%s>."), lpGroupName)); + DebugMsg((DM_VERBOSE, TEXT("DeleteItem: bCommonGroup = <%d>."), bCommonGroup)); + } + DebugMsg((DM_VERBOSE, TEXT("DeleteItem: lpDescription = <%s>."), lpDescription)); + +#endif + + // + // Get the profile directory + // + + if (!GetProgramsDirectory (bCommonGroup, szLinkName)) { + return FALSE; + } + + if (lpGroupName && *lpGroupName) { + lpEnd = CheckSlash (szLinkName); + lstrcpy (lpEnd, lpGroupName); + if (bCommonGroup) { + AppendCommonExtension(szLinkName); + } + } + // + // Now tack on the filename and extension. + // + + lpEnd = CheckSlash (szLinkName); + lstrcpy (lpEnd, lpDescription); + lstrcat (lpEnd, c_szLNK); + + + // + // Delete the file + // + + if (!DeleteFile (szLinkName)) { + DebugMsg((DM_VERBOSE, TEXT("DeleteItem: Failed to delete <%s>. Error = %d"), + szLinkName, GetLastError())); + return FALSE; + } + + SHChangeNotify (SHCNE_DELETE, SHCNF_PATH, szLinkName, NULL); + + + // + // Delete the group if appropriate (and possible). + // + + if (bDeleteGroup) { + *(lpEnd-1) = TEXT('\0'); + if (RemoveDirectory(szLinkName)) { + SHChangeNotify (SHCNE_RMDIR, SHCNF_PATH, szLinkName, NULL); + } + } + + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("DeleteItem: Leaving successfully."))); + + return TRUE; +} + +//************************************************************* +// +// PrependPath() +// +// Purpose: Expands the given filename to have %systemroot% +// if appropriate +// +// Parameters: lpFile - File to check +// lpResult - Result buffer (MAX_PATH chars in size) +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/11/95 ericflo Created +// +//************************************************************* + +BOOL PrependPath(LPCTSTR lpFile, LPTSTR lpResult) +{ + TCHAR szReturn [MAX_PATH]; + TCHAR szSysRoot[MAX_PATH]; + LPTSTR lpFileName; + DWORD dwSysLen; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("PrependPath: Entering with <%s>"), + lpFile ? lpFile : TEXT("NULL"))); + + + if (!lpFile || !*lpFile) { + DebugMsg((DM_VERBOSE, TEXT("PrependPath: lpFile is NULL, setting lpResult to a null string"))); + *lpResult = TEXT('\0'); + return TRUE; + } + + + // + // Call SearchPath to find the filename + // + + if (!SearchPath (NULL, lpFile, TEXT(".exe"), MAX_PATH, szReturn, &lpFileName)) { + DebugMsg((DM_VERBOSE, TEXT("PrependPath: SearchPath failed with error %d. Using input string"), GetLastError())); + lstrcpy (lpResult, lpFile); + return TRUE; + } + + + UnExpandSysRoot(szReturn, lpResult); + + DebugMsg((DM_VERBOSE, TEXT("PrependPath: Leaving with <%s>"), lpResult)); + + return TRUE; +} + +//************************************************************* +// +// AppendCommonExtension() +// +// Purpose: Appends " (Common)" to the directory name +// if it does not exist already. +// +// Parameters: lpName - Name to work with +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: lpName is assumed to be MAX_PATH chars long +// +// History: Date Author Comment +// 10/2/95 ericflo Created +// +//************************************************************* + +BOOL AppendCommonExtension(LPTSTR lpName) +{ + LPTSTR lpEnd; + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("AppendCommonExtension: Entering with <%s>"), lpName)); + + + lpEnd = lpName + lstrlen(lpName) - g_cchCommon; + + if (lstrcmpi(lpEnd, g_szCommon) == 0) { + return TRUE; + } + + + lstrcat (lpName, g_szCommon); + + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("AppendCommonExtension: Leaving successfully."))); + + return TRUE; +} + + + +//************************************************************* +// +// 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) +{ + + // + // Attempt to create the directory + // + + if (!CreateNestedDirectory(lpDirectory, NULL)) { + return FALSE; + } + + + // + // Set the security + // + + if (!MakeFileSecure (lpDirectory)) { + RemoveDirectory(lpDirectory); + return FALSE; + } + + return TRUE; +} + +//************************************************************* +// +// ConvertCommonGroups() +// +// Purpose: Calls grpconv.exe to convert progman common groups +// to Explorer common groups, and create floppy links. +// +// Parameters: none +// +// Return: TRUE if successful +// FALSE if an error occurs +// Comments: +// +// History: Date Author Comment +// 10/1/95 ericflo Created +// +//************************************************************* + +BOOL ConvertCommonGroups (void) +{ + STARTUPINFO si; + PROCESS_INFORMATION ProcessInformation; + BOOL Result; + TCHAR szCmdLine[MAX_PATH]; + DWORD dwType, dwSize, dwConvert; + BOOL bRunGrpConv = TRUE; + LONG lResult; + HKEY hKey; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("ConvertCommonGroups: Entering."))); + + + // + // Check if we have run grpconv before. + // + + lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, + TEXT("Software\\Program Groups"), + 0, + KEY_ALL_ACCESS, + &hKey); + + if (lResult == ERROR_SUCCESS) { + + dwSize = sizeof(dwConvert); + + lResult = RegQueryValueEx (hKey, + TEXT("ConvertedToLinks"), + NULL, + &dwType, + (LPBYTE)&dwConvert, + &dwSize); + + if (lResult == ERROR_SUCCESS) { + + // + // If dwConvert is 1, then grpconv has run before. + // Don't run it again. + // + + if (dwConvert) { + bRunGrpConv = FALSE; + } + } + + // + // Now set the value to prevent grpconv from running in the future + // + + dwConvert = 1; + RegSetValueEx (hKey, + TEXT("ConvertedToLinks"), + 0, + REG_DWORD, + (LPBYTE) &dwConvert, + sizeof(dwConvert)); + + + RegCloseKey (hKey); + } + + + if (bRunGrpConv) { + + // + // Initialize process startup info + // + + si.cb = sizeof(STARTUPINFO); + si.lpReserved = NULL; + si.lpDesktop = NULL; + si.lpTitle = NULL; + si.dwFlags = 0; + si.lpReserved2 = NULL; + si.cbReserved2 = 0; + + + // + // Spawn grpconv + // + + lstrcpy (szCmdLine, TEXT("grpconv -n")); + + Result = CreateProcess( + NULL, + szCmdLine, + NULL, + NULL, + FALSE, + NORMAL_PRIORITY_CLASS, + NULL, + NULL, + &si, + &ProcessInformation + ); + + if (!Result) { + DebugMsg((DM_WARNING, TEXT("ConvertCommonGroups: grpconv failed to start due to error %d."), GetLastError())); + return FALSE; + + } else { + + // + // Wait for up to 2 minutes + // + + WaitForSingleObject(ProcessInformation.hProcess, 120000); + + // + // Close our handles to the process and thread + // + + CloseHandle(ProcessInformation.hProcess); + CloseHandle(ProcessInformation.hThread); + + } + } + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("ConvertCommonGroups: Leaving Successfully."))); + + return TRUE; +} + +//************************************************************* +// +// InitializeProfiles() +// +// Purpose: Confirms / Creates the profile, Default User, +// and All Users directories, and converts any +// existing common groups. +// +// Parameters: +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: This should only be called by GUI mode setup! +// +// History: Date Author Comment +// 8/08/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI InitializeProfiles (void) +{ + TCHAR szDirectory[MAX_PATH]; + LPTSTR lpEnd; + INT i; + + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("InitializeProfiles: Entering."))); + + + + // + // Step 1: Check if the profiles directory exists. + // + + ExpandEnvironmentStrings(PROFILES_DIR, szDirectory, MAX_PATH); + + if (!CreateNestedDirectory(szDirectory, NULL)) { + DebugMsg((DM_WARNING, TEXT("InitializeProfiles: Failed to create profiles subdirectory <%s>. Error = %d."), + szDirectory, GetLastError())); + return FALSE; + } + + + + // + // Step 2: Check if the profiles\Default User directory exists. + // + + ExpandEnvironmentStrings(DEFAULT_PROFILE, szDirectory, MAX_PATH); + + if (!CreateSecureAdminDirectory (szDirectory)) { + DebugMsg((DM_WARNING, TEXT("InitializeProfiles: Failed to create Default User subdirectory <%s>. Error = %d."), + szDirectory, GetLastError())); + return FALSE; + } + + + // + // Step 3: Set the USERPROFILE environment variable + // + + SetEnvironmentVariable (TEXT("USERPROFILE"), szDirectory); + + + + // + // Step 4: Create all the folders (sub-directories) under Default User + // + + lpEnd = CheckSlash (szDirectory); + + + // + // Loop through the shell folders + // + + for (i=0; i < NUM_SHELL_FOLDERS; i++) { + + lstrcpy (lpEnd, c_ShellFolders[i].lpFolderLocation); + + if (!CreateNestedDirectory(szDirectory, NULL)) { + DebugMsg((DM_WARNING, TEXT("InitializeProfiles: Failed to create the destination directory <%s>. Error = %d"), + szDirectory, GetLastError())); + return FALSE; + } + + if (c_ShellFolders[i].bHidden) { + SetFileAttributes(szDirectory, FILE_ATTRIBUTE_HIDDEN); + } + + } + + + // + // Step 5: Check if the profiles\All Users directory exists. + // + + ExpandEnvironmentStrings(COMMON_PROFILE, szDirectory, MAX_PATH); + + if (!CreateSecureAdminDirectory (szDirectory)) { + DebugMsg((DM_WARNING, TEXT("InitializeProfiles: Failed to create All Users subdirectory <%s>. Error = %d."), + szDirectory, GetLastError())); + return FALSE; + } + + + // + // Step 6: Create all the folders (sub-directories) under All Users + // + + lpEnd = CheckSlash (szDirectory); + + + // + // Loop through the shell folders + // + + for (i=0; i < NUM_COMMON_SHELL_FOLDERS; i++) { + + lstrcpy (lpEnd, c_CommonShellFolders[i].lpFolderLocation); + + if (!CreateNestedDirectory(szDirectory, NULL)) { + DebugMsg((DM_WARNING, TEXT("InitializeProfiles: Failed to create the destination directory <%s>. Error = %d"), + szDirectory, GetLastError())); + return FALSE; + } + + if (c_CommonShellFolders[i].bHidden) { + SetFileAttributes(szDirectory, FILE_ATTRIBUTE_HIDDEN); + } + + } + + + // + // Step 7: Convert any common groups + // + + if (!ConvertCommonGroups()) { + DebugMsg((DM_WARNING, TEXT("InitializeProfiles: ConvertCommonGroups failed."))); + } + + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("InitializeProfiles: Leaving successfully."))); + + return TRUE; +} + +//************************************************************* +// +// CreateUserProfile() +// +// Purpose: Creates a new user profile, but does not load +// the hive. +// +// Parameters: pSid - SID pointer +// lpUserName - User name +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 9/12/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI CreateUserProfile (PSID pSid, LPCTSTR lpUserName) +{ + TCHAR szProfileDir[MAX_PATH]; + TCHAR szExpProfileDir[MAX_PATH]; + TCHAR szDefaultUser[MAX_PATH]; + TCHAR LocalProfileKey[MAX_PATH]; + UNICODE_STRING UnicodeString; + LPTSTR lpSidString, lpEnd, lpSave; + NTSTATUS NtStatus; + LONG lResult; + DWORD dwDisp; + HKEY hKey; + + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("CreateUserProfile: Entering with <%s>."), lpUserName)); + + + // + // Check parameters + // + + if (!lpUserName || !lpUserName[0]) { + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: Null username."))); + return FALSE; + } + + + // + // Make / Confirm the user's directory exists + // + + + lstrcpy (szProfileDir, CONFIG_FILE_PATH); + lstrcat (szProfileDir, lpUserName); + + ExpandEnvironmentStrings(szProfileDir, szExpProfileDir, MAX_PATH); + + + + if (!CreateSecureDirectory(NULL, szExpProfileDir, pSid)) { + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: Failed to create user directory <%s>."), szExpProfileDir)); + return FALSE; + } + + + + // + // Copy the default user profile into this directory + // + + ExpandEnvironmentStrings(DEFAULT_PROFILE, szDefaultUser, MAX_PATH); + + if (!CopyProfileDirectory (szDefaultUser, szExpProfileDir, CPD_IGNORECOPYERRORS)) { + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: CopyProfileDirectory failed with error %d."), GetLastError())); + return FALSE; + } + + + // + // Save the user's profile in the registry. + // First, convert the sid to a text string + // + + NtStatus = RtlConvertSidToUnicodeString(&UnicodeString, pSid, (BOOLEAN)TRUE); + + if (!NT_SUCCESS(NtStatus)) { + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: RtlConvertSidToUnicodeString failed, status = 0x%x"), + NtStatus)); + return FALSE; + } + + lpSidString = UnicodeString.Buffer; + + + + // + // Part B: Open the new registry key + // + + lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); + lstrcat(LocalProfileKey, TEXT("\\")); + lstrcat(LocalProfileKey, lpSidString); + + lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, 0, 0, + KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisp); + + if (lResult != ERROR_SUCCESS) { + + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: Failed trying to create the local profile key <%s>, error = %d."), LocalProfileKey, lResult)); + RtlFreeUnicodeString(&UnicodeString); + return FALSE; + } + + + + // + // Add the profile directory + // + + lResult = RegSetValueEx(hKey, PROFILE_IMAGE_VALUE_NAME, 0, + REG_EXPAND_SZ, + (LPBYTE)szProfileDir, + sizeof(TCHAR)*(lstrlen(szProfileDir) + 1)); + + + if (lResult != ERROR_SUCCESS) { + + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: First RegSetValueEx failed, error = %d."), lResult)); + RegCloseKey (hKey); + RtlFreeUnicodeString(&UnicodeString); + return FALSE; + } + + + // + // Add the users's SID + // + + lResult = RegSetValueEx(hKey, TEXT("Sid"), 0, + REG_BINARY, pSid, RtlLengthSid(pSid)); + + + if (lResult != ERROR_SUCCESS) { + + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: Second RegSetValueEx failed, error = %d."), lResult)); + } + + + // + // Close the registry key + // + + RegCloseKey (hKey); + + + + // + // Now load the hive temporary so the security can be fixed + // + + lpEnd = CheckSlash (szExpProfileDir); + lpSave = lpEnd - 1; + lstrcpy (lpEnd, c_szNTUserDat); + + lResult = MyRegLoadKey(NULL, HKEY_USERS, lpSidString, szExpProfileDir); + + + if (lResult != ERROR_SUCCESS) { + + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: Failed to load hive, error = %d."), lResult)); + + *lpSave = TEXT('\0'); + DeleteProfile (lpSidString, szExpProfileDir, FALSE); + RtlFreeUnicodeString(&UnicodeString); + return FALSE; + } + + if (!SetupNewHive(NULL, lpSidString, pSid)) { + + DebugMsg((DM_WARNING, TEXT("CreateUserProfile: SetupNewHive failed."))); + + *lpSave = TEXT('\0'); + MyRegUnLoadKey(HKEY_USERS, lpSidString); + DeleteProfile (lpSidString, szExpProfileDir, FALSE); + RtlFreeUnicodeString(&UnicodeString); + return FALSE; + + } + + + // + // Unload the hive + // + + MyRegUnLoadKey(HKEY_USERS, lpSidString); + + + // + // Free the sid string + // + + RtlFreeUnicodeString(&UnicodeString); + + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("CreateUserProfile: Leaving successfully."))); + + return TRUE; + +} + +//************************************************************* +// +// AddDesktopItem() +// +// Purpose: Adds a item to the desktop +// +// Parameters: bCommonItem - Common vs Personal +// lpDescription - Description of the item +// lpCommandLine - Command line (including args) +// lpIconPath - Icon path (can be NULL) +// iIconIndex - Index of icon in icon path +// lpWorkingDir - Working directory +// wHotKey - Hot key +// iShowCmd - ShowWindow flag +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 4/02/96 ericflo Created +// +//************************************************************* + +BOOL WINAPI AddDesktopItem(BOOL bCommonItem, + LPCTSTR lpDescription, LPCTSTR lpCommandLine, + LPCTSTR lpIconPath, int iIconIndex, + LPCTSTR lpWorkingDirectory, WORD wHotKey, + int iShowCmd) + +{ + HANDLE hFile; + WIN32_FIND_DATA fd; + TCHAR szItem[MAX_PATH]; + TCHAR szArgs[MAX_PATH]; + TCHAR szLinkName[MAX_PATH]; + TCHAR szPath[MAX_PATH]; + LPTSTR lpArgs, lpEnd; + LPUNKNOWN pUnkOuter = NULL; + IShellLink *psl; + IPersistFile *ppf; + BOOL bRetVal = FALSE; + + + + // + // Verbose output + // + +#if DBG + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: Entering."))); + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: bCommonItem = <%d>."), bCommonItem)); + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: lpDescription = <%s>."), lpDescription)); + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: lpCommandLine = <%s>."), lpCommandLine)); + + if (lpIconPath) { + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: lpIconPath = <%s>."), lpIconPath)); + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: iIconIndex = <%d>."), iIconIndex)); + } + + if (lpWorkingDirectory) { + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: lpWorkingDirectory = <%s>."), lpWorkingDirectory)); + } else { + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: Null working directory. Setting to %%HOMEDRIVE%%%%HOMEPATH%%"))); + } + + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: wHotKey = <%d>."), wHotKey)); + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: iShowCmd = <%d>."), iShowCmd)); +#endif + + + // + // Get the desktop directory + // + + if (!GetDesktopDirectory (bCommonItem, szLinkName)) { + return FALSE; + } + + + // + // Test if the sub directory exists. + // If not, create it. + // + + hFile = FindFirstFile (szLinkName, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + if (!CreateNestedDirectory(szLinkName, NULL)) { + DebugMsg((DM_WARNING, TEXT("AddDesktopItem: CreateNestedDirectory failed."))); + return FALSE; + } + + } else { + FindClose (hFile); + } + + + // + // Now tack on the filename and extension. + // + + lpEnd = CheckSlash (szLinkName); + lstrcpy (lpEnd, lpDescription); + lstrcat (lpEnd, c_szLNK); + + + // + // Split the command line into the executable name + // and arguments. + // + + lstrcpy (szItem, lpCommandLine); + + lpArgs = PathGetArgs(szItem); + + if (*lpArgs) { + lstrcpy (szArgs, lpArgs); + + lpArgs--; + while (*lpArgs == TEXT(' ')) { + lpArgs--; + } + lpArgs++; + *lpArgs = TEXT('\0'); + } else { + szArgs[0] = TEXT('\0'); + } + + + + + // + // Create an IShellLink object + // + + if (FAILED(SHCoCreateInstance(NULL, &CLSID_ShellLink, pUnkOuter, + &IID_IShellLink, + (LPVOID)&psl))) + { + DebugMsg((DM_WARNING, TEXT("AddDesktopItem: Could not create instance of IShellLink ."))); + goto ExitNoFree; + } + + + // + // Query for IPersistFile + // + + if (FAILED(psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf))) + { + DebugMsg((DM_WARNING, TEXT("AddDesktopItem: QueryInterface of IShellLink failed."))); + goto ExitFreePSL; + } + + + + // + // Set the item information + // + + psl->lpVtbl->SetDescription(psl, lpDescription); + + PrependPath(szItem, szPath); + psl->lpVtbl->SetPath(psl, szPath); + + + psl->lpVtbl->SetArguments(psl, szArgs); + if (lpWorkingDirectory) { + psl->lpVtbl->SetWorkingDirectory(psl, lpWorkingDirectory); + } else { + psl->lpVtbl->SetWorkingDirectory(psl, TEXT("%HOMEDRIVE%%HOMEPATH%")); + } + + PrependPath(lpIconPath, szPath); + psl->lpVtbl->SetIconLocation(psl, szPath, iIconIndex); + + psl->lpVtbl->SetHotkey(psl, wHotKey); + psl->lpVtbl->SetShowCmd(psl, iShowCmd); + + + // + // Save the item to disk + // + + bRetVal = SUCCEEDED(ppf->lpVtbl->Save(ppf, szLinkName, TRUE)); + + + // + // Release the IPersistFile object + // + + ppf->lpVtbl->Release(ppf); + + +ExitFreePSL: + + // + // Release the IShellLink object + // + + psl->lpVtbl->Release(psl); + +ExitNoFree: + + + // + // Finished. + // + + DebugMsg((DM_VERBOSE, TEXT("AddDesktopItem: Leaving with status of %d."), bRetVal)); + + return bRetVal; +} + + +//************************************************************* +// +// DeleteDesktopItem() +// +// Purpose: Deletes an item from the desktop +// +// Parameters: bCommonItem - Common vs Personal +// lpDescription - Description of the item +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 4/02/96 ericflo Created +// +//************************************************************* + +BOOL WINAPI DeleteDesktopItem(BOOL bCommonItem, LPCTSTR lpDescription) +{ + TCHAR szLinkName[MAX_PATH]; + LPTSTR lpEnd; + + + + // + // Verbose output + // + +#if DBG + + DebugMsg((DM_VERBOSE, TEXT("DeleteDesktopItem: Entering."))); + DebugMsg((DM_VERBOSE, TEXT("DeleteDesktopItem: bCommonItem = <%d>."), bCommonItem)); + DebugMsg((DM_VERBOSE, TEXT("DeleteDesktopItem: lpDescription = <%s>."), lpDescription)); + +#endif + + // + // Get the desktop directory + // + + if (!GetDesktopDirectory (bCommonItem, szLinkName)) { + return FALSE; + } + + // + // Now tack on the filename and extension. + // + + lpEnd = CheckSlash (szLinkName); + lstrcpy (lpEnd, lpDescription); + lstrcat (lpEnd, c_szLNK); + + + // + // Delete the file + // + + if (!DeleteFile (szLinkName)) { + DebugMsg((DM_VERBOSE, TEXT("DeleteDesktopItem: Failed to delete <%s>. Error = %d"), + szLinkName, GetLastError())); + return FALSE; + } + + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("DeleteDesktopItem: Leaving successfully."))); + + return TRUE; +} diff --git a/private/windows/gina/userenv/sid.c b/private/windows/gina/userenv/sid.c new file mode 100644 index 000000000..fef9ecdcb --- /dev/null +++ b/private/windows/gina/userenv/sid.c @@ -0,0 +1,249 @@ +//************************************************************* +// +// SID management functions. +// +// THESE FUNCTIONS ARE WINDOWS NT SPECIFIC!!!!! +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + +/***************************************************************************\ +* GetSidString +* +* Allocates and returns a string representing the sid of the current user +* The returned pointer should be freed using DeleteSidString(). +* +* Returns a pointer to the string or NULL on failure. +* +* History: +* 26-Aug-92 Davidc Created +* +\***************************************************************************/ +LPTSTR GetSidString(HANDLE UserToken) +{ + NTSTATUS NtStatus; + PSID UserSid; + UNICODE_STRING UnicodeString; + LPTSTR lpEnd; +#ifndef UNICODE + STRING String; +#endif + + // + // Get the user sid + // + + UserSid = GetUserSid(UserToken); + if (UserSid == NULL) { + DebugMsg((DM_WARNING, TEXT("GetSidString: GetUserSid returned NULL"))); + return NULL; + } + + // + // Convert user SID to a string. + // + + NtStatus = RtlConvertSidToUnicodeString( + &UnicodeString, + UserSid, + (BOOLEAN)TRUE // Allocate + ); + // + // We're finished with the user sid + // + + DeleteUserSid(UserSid); + + // + // See if the conversion to a string worked + // + + if (!NT_SUCCESS(NtStatus)) { + DebugMsg((DM_WARNING, TEXT("GetSidString: RtlConvertSidToUnicodeString failed, status = 0x%x"), + NtStatus)); + return NULL; + } + +#ifdef UNICODE + + + return(UnicodeString.Buffer); + +#else + + // + // Convert the string to ansi + // + + NtStatus = RtlUnicodeStringToAnsiString(&String, &UnicodeString, TRUE); + RtlFreeUnicodeString(&UnicodeString); + if (!NT_SUCCESS(NtStatus)) { + DebugMsg((DM_WARNING, TEXT("GetSidString: RtlUnicodeStringToAnsiString failed, status = 0x%x"), + status)); + return NULL; + } + + + return(String.Buffer); + +#endif + +} + + +/***************************************************************************\ +* DeleteSidString +* +* Frees up a sid string previously returned by GetSidString() +* +* Returns nothing. +* +* History: +* 26-Aug-92 Davidc Created +* +\***************************************************************************/ +VOID DeleteSidString(LPTSTR SidString) +{ + +#ifdef UNICODE + UNICODE_STRING String; + + RtlInitUnicodeString(&String, SidString); + + RtlFreeUnicodeString(&String); +#else + ANSI_STRING String; + + RtlInitAnsiString(&String, SidString); + + RtlFreeAnsiString(&String); +#endif + +} + + + +/***************************************************************************\ +* GetUserSid +* +* Allocs space for the user sid, fills it in and returns a pointer. Caller +* The sid should be freed by calling DeleteUserSid. +* +* Note the sid returned is the user's real sid, not the per-logon sid. +* +* Returns pointer to sid or NULL on failure. +* +* History: +* 26-Aug-92 Davidc Created. +\***************************************************************************/ +PSID GetUserSid (HANDLE UserToken) +{ + PTOKEN_USER pUser; + PSID pSid; + DWORD BytesRequired = 200; + NTSTATUS status; + + + // + // Allocate space for the user info + // + + pUser = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, BytesRequired); + + + if (pUser == NULL) { + DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"), + BytesRequired)); + return NULL; + } + + + // + // Read in the UserInfo + // + + status = NtQueryInformationToken( + UserToken, // Handle + TokenUser, // TokenInformationClass + pUser, // TokenInformation + BytesRequired, // TokenInformationLength + &BytesRequired // ReturnLength + ); + + if (status == STATUS_BUFFER_TOO_SMALL) { + + // + // Allocate a bigger buffer and try again. + // + + pUser = LocalReAlloc(pUser, BytesRequired, LMEM_MOVEABLE); + if (pUser == NULL) { + DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"), + BytesRequired)); + return NULL; + } + + status = NtQueryInformationToken( + UserToken, // Handle + TokenUser, // TokenInformationClass + pUser, // TokenInformation + BytesRequired, // TokenInformationLength + &BytesRequired // ReturnLength + ); + + } + + if (!NT_SUCCESS(status)) { + DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to query user info from user token, status = 0x%x"), + status)); + LocalFree(pUser); + return NULL; + } + + + BytesRequired = RtlLengthSid(pUser->User.Sid); + pSid = LocalAlloc(LMEM_FIXED, BytesRequired); + if (pSid == NULL) { + DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"), + BytesRequired)); + LocalFree(pUser); + return NULL; + } + + + status = RtlCopySid(BytesRequired, pSid, pUser->User.Sid); + + LocalFree(pUser); + + if (!NT_SUCCESS(status)) { + DebugMsg((DM_WARNING, TEXT("GetUserSid: RtlCopySid Failed. status = %d"), + status)); + LocalFree(pSid); + pSid = NULL; + } + + + return pSid; +} + + +/***************************************************************************\ +* DeleteUserSid +* +* Deletes a user sid previously returned by GetUserSid() +* +* Returns nothing. +* +* History: +* 26-Aug-92 Davidc Created +* +\***************************************************************************/ +VOID DeleteUserSid(PSID Sid) +{ + LocalFree(Sid); +} diff --git a/private/windows/gina/userenv/sid.h b/private/windows/gina/userenv/sid.h new file mode 100644 index 000000000..0ae6be416 --- /dev/null +++ b/private/windows/gina/userenv/sid.h @@ -0,0 +1,14 @@ +//************************************************************* +// +// Header file for Sid.c +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +LPTSTR GetSidString(HANDLE UserToken); +VOID DeleteSidString(LPTSTR SidString); +PSID GetUserSid (HANDLE UserToken); +VOID DeleteUserSid(PSID Sid); diff --git a/private/windows/gina/userenv/sources b/private/windows/gina/userenv/sources new file mode 100644 index 000000000..ec99224ab --- /dev/null +++ b/private/windows/gina/userenv/sources @@ -0,0 +1,50 @@ + +TARGETNAME=userenv +TARGETPATH=$(BASEDIR)\public\sdk\lib +TARGETTYPE=DYNLINK + +DLLDEF=userenv.def +DLLENTRY=LibMain + +UMTYPE=windows + +!IFNDEF MSC_WARNING_LEVEL +MSC_WARNING_LEVEL=/W3 +!ENDIF +MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX + +NTTARGETFILE0=uevents.h + +PRECOMPILED_INCLUDE=uenv.h +PRECOMPILED_PCH=precomp.pch +PRECOMPILED_OBJ=precomp.obj + +INCLUDES=.;..\..\inc;..\..\shell\inc;..\..\inc16 + +C_DEFINES=-DWIN32 -D_WIN32 -DUNICODE -D_USERENV_ + + +SOURCES= userenv.c \ + globals.c \ + util.c \ + stubs.c \ + copydir.c \ + debug.c \ + policy.c \ + profile.c \ + sid.c \ + setup.c \ + events.c \ + userdiff.c \ + envvar.c \ + userenv.rc + +TARGETLIBS= \ + $(BASEDIR)\public\sdk\lib\*\kernel32.lib \ + $(BASEDIR)\public\sdk\lib\*\advapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\user32.lib \ + $(BASEDIR)\public\sdk\lib\*\shell32.lib \ + $(BASEDIR)\public\sdk\lib\*\comctl32.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\mpr.lib \ + $(BASEDIR)\public\sdk\lib\*\uuid.lib diff --git a/private/windows/gina/userenv/stubs.c b/private/windows/gina/userenv/stubs.c new file mode 100644 index 000000000..1bbd4e4e1 --- /dev/null +++ b/private/windows/gina/userenv/stubs.c @@ -0,0 +1,599 @@ +//************************************************************* +// +// Contains the A/W api stubs +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI LoadUserProfileA (HANDLE hToken, LPPROFILEINFOA lpProfileInfoA) +{ + PROFILEINFOW ProfileInfoW; + BOOL bResult; + + + // + // Thunk ProfileInfoA to ProfileInfoW + // + + ProfileInfoW.dwSize = sizeof(PROFILEINFOW); + ProfileInfoW.dwFlags = lpProfileInfoA->dwFlags; + ProfileInfoW.lpUserName = ProduceWFromA(lpProfileInfoA->lpUserName); + ProfileInfoW.lpProfilePath = ProduceWFromA(lpProfileInfoA->lpProfilePath); + ProfileInfoW.lpDefaultPath = ProduceWFromA(lpProfileInfoA->lpDefaultPath); + ProfileInfoW.lpServerName = ProduceWFromA(lpProfileInfoA->lpServerName); + if (ProfileInfoW.dwFlags & PI_APPLYPOLICY) { + ProfileInfoW.lpPolicyPath = ProduceWFromA(lpProfileInfoA->lpPolicyPath); + } + + + // + // Now call the real LoadUserProfile function. + // + + bResult = LoadUserProfileW(hToken, &ProfileInfoW); + + + // + // Free memory allocated above and save the return + // values. + // + + FreeProducedString(ProfileInfoW.lpUserName); + FreeProducedString(ProfileInfoW.lpProfilePath); + FreeProducedString(ProfileInfoW.lpDefaultPath); + FreeProducedString(ProfileInfoW.lpServerName); + if (ProfileInfoW.dwFlags & PI_APPLYPOLICY) { + FreeProducedString(ProfileInfoW.lpPolicyPath); + } + + lpProfileInfoA->hProfile = ProfileInfoW.hProfile; + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI LoadUserProfileW (HANDLE hToken, LPPROFILEINFOW lpProfileInfoW) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI CreateGroupA(LPCSTR lpGroupName, BOOL bCommonGroup) +{ + LPWSTR lpGroupNameW; + BOOL bResult; + + // + // Convert the ANSI string to Unicode and call + // the real function. + // + + if (!(lpGroupNameW = ProduceWFromA(lpGroupName))) { + return FALSE; + } + + bResult = CreateGroupW(lpGroupNameW, bCommonGroup); + + FreeProducedString(lpGroupNameW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI CreateGroupW(LPCWSTR lpGroupName, BOOL bCommonGroup) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + +//************************************************************* + + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI DeleteGroupA(LPCSTR lpGroupName, BOOL bCommonGroup) +{ + LPWSTR lpGroupNameW; + BOOL bResult; + + // + // Convert the ANSI string to Unicode and call + // the real function. + // + + if (!(lpGroupNameW = ProduceWFromA(lpGroupName))) { + return FALSE; + } + + bResult = DeleteGroupW(lpGroupNameW, bCommonGroup); + + FreeProducedString(lpGroupNameW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI DeleteGroupW(LPCWSTR lpGroupName, BOOL bCommonGroup) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI AddItemA(LPCSTR lpGroupName, BOOL bCommonGroup, + LPCSTR lpDescription, LPCSTR lpCommandLine, + LPCSTR lpIconPath, int iIconIndex, + LPCSTR lpWorkingDirectory, WORD wHotKey, + int iShowCmd) + +{ + LPWSTR lpGroupNameW, lpDescriptionW, lpCommandLineW; + LPWSTR lpIconPathW, lpWorkingDirectoryW; + BOOL bResult; + + // + // Convert the ANSI strings to Unicode and call + // the real function. + // + + lpGroupNameW = ProduceWFromA(lpGroupName); + + if (!(lpDescriptionW = ProduceWFromA(lpDescription))) { + return FALSE; + } + + if (!(lpCommandLineW = ProduceWFromA(lpCommandLine))) { + return FALSE; + } + + lpIconPathW = ProduceWFromA(lpIconPath); + + lpWorkingDirectoryW = ProduceWFromA(lpWorkingDirectory); + + + bResult = AddItemW(lpGroupNameW, bCommonGroup, lpDescriptionW, + lpCommandLineW, lpIconPathW, iIconIndex, + lpWorkingDirectoryW, wHotKey, iShowCmd); + + + FreeProducedString(lpGroupNameW); + FreeProducedString(lpDescriptionW); + FreeProducedString(lpCommandLineW); + FreeProducedString(lpIconPathW); + FreeProducedString(lpWorkingDirectoryW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI AddItemW(LPCWSTR lpGroupName, BOOL bCommonGroup, + LPCWSTR lpDescription, LPCWSTR lpCommandLine, + LPCWSTR lpIconPath, int iIconIndex, + LPCWSTR lpWorkingDirectory, WORD wHotKey, + int iShowCmd) + +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI DeleteItemA(LPCSTR lpGroupName, BOOL bCommonGroup, + LPCSTR lpDescription, BOOL bDeleteGroup) +{ + LPWSTR lpGroupNameW, lpDescriptionW; + BOOL bResult; + + // + // Convert the ANSI strings to Unicode and call + // the real function. + // + + lpGroupNameW = ProduceWFromA(lpGroupName); + + if (!(lpDescriptionW = ProduceWFromA(lpDescription))) { + return FALSE; + } + + bResult = DeleteItemW(lpGroupNameW, bCommonGroup, lpDescriptionW, bDeleteGroup); + + + FreeProducedString(lpGroupNameW); + FreeProducedString(lpDescriptionW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI DeleteItemW(LPCWSTR lpGroupName, BOOL bCommonGroup, + LPCWSTR lpDescription, BOOL bDeleteGroup) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + + + +//************************************************************* + + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI CreateUserProfileA (PSID pSid, LPCSTR lpUserNameA) +{ + LPWSTR lpUserNameW; + BOOL bResult; + + // + // Convert the ANSI string to Unicode and call + // the real function. + // + + if (!(lpUserNameW = ProduceWFromA(lpUserNameA))) { + return FALSE; + } + + bResult = CreateUserProfileW(pSid, lpUserNameW); + + + FreeProducedString(lpUserNameW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI CreateUserProfileW (PSID pSid, LPCWSTR lpUserName) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + + + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI CopyProfileDirectoryA (LPCSTR lpSrcDirA, LPCSTR lpDstDirA, DWORD dwFlags) +{ + LPWSTR lpSrcDirW, lpDstDirW; + BOOL bResult; + + // + // Convert the ANSI strings to Unicode and call + // the real function. + // + + if (!(lpSrcDirW = ProduceWFromA(lpSrcDirA))) { + return FALSE; + } + + if (!(lpDstDirW = ProduceWFromA(lpDstDirA))) { + FreeProducedString(lpSrcDirW); + return FALSE; + } + + bResult = CopyProfileDirectoryW(lpSrcDirW, lpDstDirW, dwFlags); + + + FreeProducedString(lpSrcDirW); + FreeProducedString(lpDstDirW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI CopyProfileDirectoryW(LPCWSTR lpSrcDirW, LPCWSTR lpDstDirW, DWORD dwFlags) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI GetProfilesDirectoryA (LPSTR lpProfilesDirA, LPDWORD lpcchSize) +{ + LPWSTR lpProfilesDirW; + BOOL bResult; + + // + // Allocate a buffer to match the ANSI buffer + // + + if (!(lpProfilesDirW = GlobalAlloc(GPTR, (*lpcchSize) * sizeof(TCHAR)))) { + return FALSE; + } + + bResult = GetProfilesDirectoryW(lpProfilesDirW, lpcchSize); + + + if (bResult) { + WideCharToMultiByte(CP_ACP, 0, lpProfilesDirW, -1, lpProfilesDirA, + *lpcchSize, NULL, NULL); + } + + + GlobalFree(lpProfilesDirW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI GetProfilesDirectoryW(LPWSTR lpProfilesDirW, LPDWORD lpcchSize) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI GetUserProfileDirectoryA (HANDLE hToken, LPSTR lpProfileDirA, LPDWORD lpcchSize) +{ + LPWSTR lpProfileDirW; + BOOL bResult; + + // + // Allocate a buffer to match the ANSI buffer + // + + if (!(lpProfileDirW = GlobalAlloc(GPTR, (*lpcchSize) * sizeof(TCHAR)))) { + return FALSE; + } + + bResult = GetUserProfileDirectoryW(hToken, lpProfileDirW, lpcchSize); + + + if (bResult) { + WideCharToMultiByte(CP_ACP, 0, lpProfileDirW, -1, lpProfileDirA, + *lpcchSize, NULL, NULL); + } + + + GlobalFree(lpProfileDirW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI GetUserProfileDirectoryW(HANDLE hToken, LPWSTR lpProfileDirW, LPDWORD lpcchSize) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI AddDesktopItemA(BOOL bCommonItem, + LPCSTR lpDescription, LPCSTR lpCommandLine, + LPCSTR lpIconPath, int iIconIndex, + LPCSTR lpWorkingDirectory, WORD wHotKey, + int iShowCmd) + +{ + LPWSTR lpDescriptionW, lpCommandLineW; + LPWSTR lpIconPathW, lpWorkingDirectoryW; + BOOL bResult; + + // + // Convert the ANSI strings to Unicode and call + // the real function. + // + + if (!(lpDescriptionW = ProduceWFromA(lpDescription))) { + return FALSE; + } + + if (!(lpCommandLineW = ProduceWFromA(lpCommandLine))) { + return FALSE; + } + + lpIconPathW = ProduceWFromA(lpIconPath); + + lpWorkingDirectoryW = ProduceWFromA(lpWorkingDirectory); + + + bResult = AddDesktopItemW(bCommonItem, lpDescriptionW, + lpCommandLineW, lpIconPathW, iIconIndex, + lpWorkingDirectoryW, wHotKey, iShowCmd); + + + FreeProducedString(lpDescriptionW); + FreeProducedString(lpCommandLineW); + FreeProducedString(lpIconPathW); + FreeProducedString(lpWorkingDirectoryW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI AddDesktopItemW(BOOL bCommonGroup, + LPCWSTR lpDescription, LPCWSTR lpCommandLine, + LPCWSTR lpIconPath, int iIconIndex, + LPCWSTR lpWorkingDirectory, WORD wHotKey, + int iShowCmd) + +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE + +//************************************************************* + +#ifdef UNICODE + +// +// ANSI entry point when this module is compiled Unicode. +// + +BOOL WINAPI DeleteDesktopItemA(BOOL bCommonItem, LPCSTR lpDescription) +{ + LPWSTR lpDescriptionW; + BOOL bResult; + + // + // Convert the ANSI strings to Unicode and call + // the real function. + // + + if (!(lpDescriptionW = ProduceWFromA(lpDescription))) { + return FALSE; + } + + bResult = DeleteDesktopItemW(bCommonItem, lpDescriptionW); + + + FreeProducedString(lpDescriptionW); + + return bResult; +} + +#else + +// +// Unicode entry point when this module is compiled ANSI. +// + +BOOL WINAPI DeleteDesktopItemW(BOOL bCommonItem, LPCWSTR lpDescription) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif // UNICODE diff --git a/private/windows/gina/userenv/uenv.h b/private/windows/gina/userenv/uenv.h new file mode 100644 index 000000000..583153883 --- /dev/null +++ b/private/windows/gina/userenv/uenv.h @@ -0,0 +1,34 @@ +//************************************************************* +// +// Main header file for UserEnv project +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#ifndef RC_INVOKED +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#endif + +#include <windows.h> +#include <ole2.h> +#include <shlobj.h> +#include <userenv.h> +#include <userenvp.h> +#include "globals.h" +#include "debug.h" +#include "profile.h" +#include "util.h" +#include "sid.h" +#include "events.h" +#include "copydir.h" +#include "resource.h" +#include "userdiff.h" +#include "policy.h" + +#include <shell.h> +#include <shellp.h> diff --git a/private/windows/gina/userenv/uevents.mc b/private/windows/gina/userenv/uevents.mc new file mode 100644 index 000000000..ad02d56e9 --- /dev/null +++ b/private/windows/gina/userenv/uevents.mc @@ -0,0 +1,53 @@ +;/*++ BUILD Version: 0001 // Increment this if a change has global effects +; +;Copyright (c) 1992 Microsoft Corporation +; +;Module Name: +; +; uevents.h +; +;Abstract: +; +; Definitions for User Profiles Events +; +;Author: +; +; EricFlo +; +;Revision History: +; +;Notes: +; +; This file is generated by the MC tool from the uevents.mc file. +; +;--*/ +; +; +;#ifndef _USERENV_EVT_ +;#define _USERENV_EVT_ +; + + +SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS + Informational=0x1:STATUS_SEVERITY_INFORMATIONAL + Warning=0x2:STATUS_SEVERITY_WARNING + Error=0x3:STATUS_SEVERITY_ERROR + ) + +; +;///////////////////////////////////////////////////////////////////////// +;// +;// User Profile Events (1000 - 1999) +;// +;///////////////////////////////////////////////////////////////////////// +; + + +MessageId=1000 Severity=Error SymbolicName=EVENT_PROFILE_ERROR +Language=English +%1 +. + +; +;#endif // _USERENV_EVT_ +; diff --git a/private/windows/gina/userenv/userdiff.c b/private/windows/gina/userenv/userdiff.c new file mode 100644 index 000000000..967b8e6d6 --- /dev/null +++ b/private/windows/gina/userenv/userdiff.c @@ -0,0 +1,1392 @@ +//************************************************************* +// +// Userdiff.c +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + +#define MAX_KEY_NAME MAX_PATH + +BOOL AddUDNode (LPUDNODE *lpList, LPTSTR lpBuildNumber); +BOOL FreeUDList (LPUDNODE lpList); +BOOL ProcessBuild(LPPROFILE lpProfile, LPUDNODE lpItem); +BOOL ProcessHive(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey); +BOOL ProcessFiles(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey); +BOOL ProcessPrograms(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey); +BOOL OkToProcessItem(DWORD dwProductType); + +//************************************************************* +// +// ProcessUserDiff() +// +// Purpose: Processes the userdiff hive +// +// Parameters: lpProfile - Profile information +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/2/95 ericflo Created +// +//************************************************************* + +BOOL ProcessUserDiff (LPPROFILE lpProfile, DWORD dwBuildNumber) +{ + TCHAR szUserDiff[MAX_PATH]; + TCHAR szName[MAX_KEY_NAME]; + HANDLE hFile; + WIN32_FIND_DATA fd; + LPUDNODE lpList = NULL, lpItem; + LONG lResult; + HKEY hKeyUserDiff; + UINT Index = 0; + DWORD dwSize; + FILETIME ftWrite; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Entering."))); + + + // + // Determine which platform we are running on. + // + + InitializeProductType(); + + + // + // Test if the hive exists, first look for USERDIFR + // + + ExpandEnvironmentStrings(USERDIFR_LOCATION, szUserDiff, MAX_PATH); + hFile = FindFirstFile (szUserDiff, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: userdifr hive doesn't exist. Trying userdiff."))); + + ExpandEnvironmentStrings(USERDIFF_LOCATION, szUserDiff, MAX_PATH); + hFile = FindFirstFile (szUserDiff, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: userdiff hive doesn't exist. Leaving."))); + return TRUE; + } + } + + FindClose (hFile); + + + // + // Load the hive + // + + if (MyRegLoadKey(lpProfile, HKEY_USERS, USERDIFF, szUserDiff) != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: Failed to load userdiff."))); + return FALSE; + } + + + // + // Open the key + // + + lResult = RegOpenKeyEx(HKEY_USERS, USERDIFF, 0, KEY_READ, &hKeyUserDiff); + + if (lResult != ERROR_SUCCESS) { + MyRegUnLoadKey(HKEY_USERS, USERDIFF); + DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: failed to open registry root (%d)"), lResult)); + return FALSE; + } + + + + // + // Enumerate the build numbers + // + + dwSize = MAX_KEY_NAME; + lResult = RegEnumKeyEx(hKeyUserDiff, Index, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + if (lResult == ERROR_SUCCESS) { + + do { + + // + // Add the node + // + + if (!AddUDNode (&lpList, szName)) { + break; + } + + Index++; + dwSize = MAX_KEY_NAME; + + lResult = RegEnumKeyEx(hKeyUserDiff, Index, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + + } while (lResult == ERROR_SUCCESS); + } + + + // + // Close the open key + // + + RegCloseKey(hKeyUserDiff); + + + // + // Map HKCU + // + + if (OpenHKeyCurrentUser(lpProfile)) { + + // + // Process the builds + // + + lpItem = lpList; + + while (lpItem) { + + // + // Only want to apply changes that occurred in + // builds after the one the user is running. + // + + if ( (lpItem->dwBuildNumber > dwBuildNumber) && + (lpItem->dwBuildNumber <= g_dwBuildNumber) ) { + ProcessBuild(lpProfile, lpItem); + } + + lpItem = lpItem->pNext; + } + + + // + // Unmap HKCU + // + + CloseHKeyCurrentUser(lpProfile); + + } else { + DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: Failed to map HKCU"))); + } + + // + // Free the link list + // + + FreeUDList (lpList); + + + // + // Unload the hive + // + + MyRegUnLoadKey(HKEY_USERS, USERDIFF); + + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Leaving successfully."))); + + return TRUE; + +} + +//************************************************************* +// +// AddUDNode() +// +// Purpose: Adds a build node to the link listed +// sorted by build number +// +// Parameters: lpList - Link list of nodes +// lpBuildNumber - New node name +// +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/3/95 ericflo Created +// +//************************************************************* + +BOOL AddUDNode (LPUDNODE *lpList, LPTSTR lpBuildNumber) +{ + LPUDNODE lpNewItem; + LPUDNODE lpHead, lpPrev; + + if (!lpBuildNumber || !*lpBuildNumber) { + return TRUE; + } + + + // + // Setup the new node + // + + lpNewItem = (LPUDNODE) LocalAlloc(LPTR, sizeof(UDNODE)); + + if (!lpNewItem) { + return FALSE; + } + + lstrcpy (lpNewItem->szBuildNumber, lpBuildNumber); + lpNewItem->dwBuildNumber = StringToInt(lpBuildNumber); + lpNewItem->pNext = NULL; + + + // + // Now add it to the list sorted + // + + lpHead = *lpList; + lpPrev = NULL; + + + if (!lpHead) { + + // + // First item in the list + // + + *lpList = lpNewItem; + + return TRUE; + } + + + // + // If we made it here, there is one or more items in the list + // + + + while (lpHead) { + + if (lpNewItem->dwBuildNumber <= lpHead->dwBuildNumber) { + + if (lpPrev) { + + // + // Insert the item + // + + lpPrev->pNext = lpNewItem; + lpNewItem->pNext = lpHead; + return TRUE; + + } else { + + // + // Head of the list + // + + lpNewItem->pNext = lpHead; + *lpList = lpNewItem; + return TRUE; + + } + + } + + lpPrev = lpHead; + lpHead = lpHead->pNext; + } + + + // + // Add node to the end of the list + // + + lpPrev->pNext = lpNewItem; + + + return TRUE; +} + + +//************************************************************* +// +// FreeUDList() +// +// Purpose: Free's a UDNODE link list +// +// Parameters: lpList - List to be freed +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/3/95 ericflo Created +// +//************************************************************* + +BOOL FreeUDList (LPUDNODE lpList) +{ + LPUDNODE lpNext; + + + if (!lpList) { + return TRUE; + } + + + lpNext = lpList->pNext; + + while (lpList) { + LocalFree (lpList); + lpList = lpNext; + + if (lpList) { + lpNext = lpList->pNext; + } + } + + return TRUE; +} + +//************************************************************* +// +// ProcessBuild() +// +// Purpose: Processes the changes for a specific build +// +// Parameters: lpProfile - Profile information +// lpItem - Build item to process +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/3/95 ericflo Created +// +//************************************************************* + +BOOL ProcessBuild(LPPROFILE lpProfile, LPUDNODE lpItem) +{ + TCHAR szSubKey[MAX_PATH]; + LONG lResult; + HKEY hKey; + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("ProcessBuild: Entering with build <%s>."), + lpItem->szBuildNumber)); + + + // + // Open "Hive" subkey + // + + wsprintf (szSubKey, TEXT("%s\\%s\\Hive"), USERDIFF, lpItem->szBuildNumber); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey); + + if (lResult == ERROR_SUCCESS) { + ProcessHive(lpProfile, lpItem, hKey); + RegCloseKey (hKey); + } + + + // + // Open "Files" subkey + // + + wsprintf (szSubKey, TEXT("%s\\%s\\Files"), USERDIFF, lpItem->szBuildNumber); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey); + + if (lResult == ERROR_SUCCESS) { + ProcessFiles(lpProfile, lpItem, hKey); + RegCloseKey (hKey); + } + + + // + // Open "Execute" subkey + // + + wsprintf (szSubKey, TEXT("%s\\%s\\Execute"), USERDIFF, lpItem->szBuildNumber); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey); + + if (lResult == ERROR_SUCCESS) { + ProcessPrograms(lpProfile, lpItem, hKey); + RegCloseKey (hKey); + } + + // + // Success + // + + DebugMsg((DM_VERBOSE, TEXT("ProcessBuild: Leaving successfully."))); + + return TRUE; + +} + +//************************************************************* +// +// ProcessHive() +// +// Purpose: Processes the Hive entry for a build +// +// Parameters: lpProfile - Profile information +// lpItem - Build item +// hKey - Registry key to enumerate +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/3/95 ericflo Created +// +//************************************************************* + +BOOL ProcessHive(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey) +{ + TCHAR szSubKey[MAX_PATH]; + TCHAR szValueName[MAX_KEY_NAME]; + DWORD dwSize, dwType, dwAction, dwDisp, dwFlags, dwProductType; + LPBYTE lpValueData; + LONG lResult; + UINT Index = 1; + FILETIME ftWrite; + HKEY hKeyEntry, hKeyTemp; + LPTSTR lpName; + + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Entering."))); + + // + // Process the entry + // + + wsprintf (szSubKey, TEXT("%s\\%s\\Hive\\%d"), USERDIFF, lpItem->szBuildNumber, Index); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: No hive entries."))); + goto Exit; + } + + + do { + + // + // Query for the product type + // + + dwSize = sizeof(dwProductType); + lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType, + (LPBYTE)&dwProductType, &dwSize); + + + // + // It's ok to not have a product type listed in userdiff.ini. + // In this case, we always apply the change regardless of the + // platform. + // + + if (lResult == ERROR_SUCCESS) { + + // + // A specific product was listed. Check if + // we can process this entry. + // + + if (!OkToProcessItem(dwProductType)) { + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Skipping Item %d due to product type mismatch."), Index)); + goto LoopAgain; + } + } + + + // + // Query for the action type + // + + dwSize = sizeof(dwAction); + lResult = RegQueryValueEx(hKeyEntry, UD_ACTION, NULL, &dwType, + (LPBYTE)&dwAction, &dwSize); + + if (lResult == ERROR_SUCCESS) { + + switch (dwAction) { + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Item %d has an action of %d."), + Index, dwAction)); + + case 1: { + // + // Add New Key + // + // Get the key name + // + + dwSize = MAX_PATH * sizeof(TCHAR); + lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType, + (LPBYTE)szSubKey, &dwSize); + + if (lResult == ERROR_SUCCESS) { + + lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser, + szSubKey, 0, NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, + &hKeyTemp, &dwDisp); + + if (lResult == ERROR_SUCCESS) { + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Created subkey <%s>."), + szSubKey)); + + RegCloseKey(hKeyTemp); + } else { + + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create subkey <%s> with error %d."), + szSubKey, lResult)); + } + } + + } + break; + + case 2: { + // + // Delete a key and all it's subkeys + // + // Get the key name + // + + dwSize = MAX_PATH * sizeof(TCHAR); + lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType, + (LPBYTE)szSubKey, &dwSize); + + if (lResult == ERROR_SUCCESS) { + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Calling RegDelnode on <%s>."), + szSubKey)); + + RegDelnode (lpProfile->hKeyCurrentUser, szSubKey); + } + + } + break; + + case 3: { + // + // Add a new value + // + // Get the key name + // + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Adding a new value."))); + + dwSize = MAX_PATH * sizeof(TCHAR); + lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType, + (LPBYTE)szSubKey, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to get UD_KEYNAME with error %d."), lResult)); + goto LoopAgain; + } + + lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser, + szSubKey, 0, NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, + &hKeyTemp, &dwDisp); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create UD_KEYNAME with error %d."), lResult)); + goto LoopAgain; + } + + + // + // Query for the value name + // + + dwSize = MAX_KEY_NAME * sizeof(TCHAR); + lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAME, NULL, &dwType, + (LPBYTE)szValueName, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query UD_VALUENAME with error %d."), lResult)); + RegCloseKey(hKeyTemp); + goto LoopAgain; + } + + + // + // Query for the value data size + // + + dwSize = 0; + lResult = RegQueryValueEx(hKeyEntry, UD_VALUE, NULL, &dwType, + NULL, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query UD_VALUE with error %d."), lResult)); + RegCloseKey(hKeyTemp); + goto LoopAgain; + } + + + // + // Allocate space for the data + // + + lpValueData = LocalAlloc (LPTR, dwSize); + + if (!lpValueData) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: LocalAlloc failed (%d)."), GetLastError())); + RegCloseKey(hKeyTemp); + goto LoopAgain; + } + + + // + // Query for the value data + // + + lResult = RegQueryValueEx(hKeyEntry, UD_VALUE, NULL, &dwType, + lpValueData, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query value data with error %d."), lResult)); + LocalFree (lpValueData); + RegCloseKey(hKeyTemp); + goto LoopAgain; + } + + + // + // Set the new value + // + + RegSetValueEx(hKeyTemp, szValueName, 0, dwType, + lpValueData, dwSize); + + + // + // Clean up + // + + LocalFree (lpValueData); + + RegCloseKey(hKeyTemp); + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Finished adding value <%s>."), szValueName)); + } + break; + + case 4: { + // + // Delete value(s) + // + // Get the key name + // + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Entering delete a value."))); + + dwSize = ARRAYSIZE(szSubKey); + lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType, + (LPBYTE)szSubKey, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value to delete (%d)."), lResult)); + goto LoopAgain; + } + + lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser, + szSubKey, 0, NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, + &hKeyTemp, &dwDisp); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create key (%s) for value to delete (%d)."), szSubKey, lResult)); + goto LoopAgain; + } + + + // + // Query for the flags + // + + dwSize = sizeof(dwFlags); + lResult = RegQueryValueEx(hKeyEntry, UD_FLAGS, NULL, &dwType, + (LPBYTE)&dwFlags, &dwSize); + + if (lResult != ERROR_SUCCESS) { + dwFlags = 0; + } + + + // + // Process the flags + // + + if (dwFlags == 2) { + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Calling DeleteAllValues."))); + DeleteAllValues (hKeyTemp); + RegCloseKey(hKeyTemp); + goto LoopAgain; + } + + + // + // Query for the value names size + // + + dwSize = 0; + lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAMES, NULL, &dwType, + NULL, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value names to delete (%d)."), lResult)); + RegCloseKey(hKeyTemp); + goto LoopAgain; + } + + + // + // Allocate space for the data + // + + lpValueData = LocalAlloc (LPTR, dwSize); + + if (!lpValueData) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: LocalAlloc failed (%d)."), GetLastError())); + RegCloseKey(hKeyTemp); + goto LoopAgain; + } + + + // + // Query for the value data + // + + lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAMES, NULL, &dwType, + lpValueData, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value data to delete (%d)."), lResult)); + LocalFree (lpValueData); + RegCloseKey(hKeyTemp); + goto LoopAgain; + } + + + // + // Delete the values + // + + lpName = (LPTSTR) lpValueData; + + while (*lpName) { + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Deleting (%s)."), lpName)); + RegDeleteValue (hKeyTemp, lpName); + lpName += lstrlen(lpName) + 1; + } + + + // + // Delete the no-name value if appropriate + // + + if (dwFlags == 1) { + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Deleting no name value."))); + RegDeleteValue (hKeyTemp, NULL); + } + + + // + // Clean up + // + + LocalFree (lpValueData); + RegCloseKey(hKeyTemp); + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Leaving deletion code."))); + } + + break; + } + + } + +LoopAgain: + + // + // Close the registry key + // + + RegCloseKey(hKeyEntry); + + + // + // Enumerate again + // + + Index++; + + wsprintf (szSubKey, TEXT("%s\\%s\\Hive\\%d"), USERDIFF, lpItem->szBuildNumber, Index); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry); + + } while (lResult == ERROR_SUCCESS); + +Exit: + + DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Leaving."))); + + return TRUE; +} + +//************************************************************* +// +// ProcessFiles() +// +// Purpose: Processes the Files entry for a build +// +// Parameters: lpProfile - Profile information +// lpItem - Build item +// hKey - Registry key to enumerate +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/3/95 ericflo Created +// +//************************************************************* + +BOOL ProcessFiles(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey) +{ + TCHAR szSubKey[MAX_PATH]; + TCHAR szSrc[MAX_PATH]; + TCHAR szDest[MAX_PATH]; + TCHAR szItem[MAX_PATH]; + LPTSTR lpEnd, lpTemp; + DWORD dwSize, dwType, dwAction, dwProductType; + LONG lResult; + UINT Index = 1; + FILETIME ftWrite; + HKEY hKeyEntry; + + + // + // Verbose Output + // + + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Entering."))); + + + // + // Process the entry + // + + wsprintf (szSubKey, TEXT("%s\\%s\\Files\\%d"), USERDIFF, lpItem->szBuildNumber, Index); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: No Files entries."))); + goto Exit; + } + + + do { + + // + // Query for the product type + // + + dwSize = sizeof(dwProductType); + lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType, + (LPBYTE)&dwProductType, &dwSize); + + + // + // It's ok to not have a product type listed in userdiff.ini. + // In this case, we always apply the change regardless of the + // platform. + // + + if (lResult == ERROR_SUCCESS) { + + // + // A specific product was listed. Check if + // we can process this entry. + // + + if (!OkToProcessItem(dwProductType)) { + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Skipping Item %d due to product type mismatch."), Index)); + goto LoopAgain; + } + } + + + // + // Query for the action type + // + + dwSize = sizeof(dwAction); + lResult = RegQueryValueEx(hKeyEntry, UD_ACTION, NULL, &dwType, + (LPBYTE)&dwAction, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to query action type (%d)."), lResult)); + goto LoopAgain; + } + + + // + // Query for the item + // + + dwSize = ARRAYSIZE(szItem); + lResult = RegQueryValueEx(hKeyEntry, UD_ITEM, NULL, &dwType, + (LPBYTE)szItem, &dwSize); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to query UD_ITEM type (%d)."), lResult)); + goto LoopAgain; + } + + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Item %d has an action of %d."), + Index, dwAction)); + + switch (dwAction) { + + case 1: + + // + // Create new program group + // + + GetProgramsDirectory (FALSE, szDest); + lpEnd = CheckSlash(szDest); + lstrcpy (lpEnd, szItem); + + if (CreateNestedDirectory(szDest, NULL)) { + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Created new group (%s)."), szDest)); + } else { + DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to created new group (%s) with (%d)."), + szDest, GetLastError())); + } + + break; + + case 2: + // + // Delete a program group + // + + GetProgramsDirectory (FALSE, szDest); + lpEnd = CheckSlash(szDest); + lstrcpy (lpEnd, szItem); + + Delnode(szDest); + + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted group (%s)."), szDest)); + + break; + + case 3: + { + TCHAR szStartMenu [MAX_FOLDER_SIZE]; + + // + // Add a new item + // + + ExpandEnvironmentStrings (DEFAULT_PROFILE, szSrc, MAX_PATH); + lpEnd = CheckSlash(szSrc); + + if (LoadString (g_hDllInstance, IDS_SH_PROGRAMS, szStartMenu, + MAX_FOLDER_SIZE)) { + + lstrcpy (lpEnd, szStartMenu); + lpEnd = CheckSlash(szSrc); + lstrcpy (lpEnd, szItem); + + + GetProgramsDirectory (FALSE, szDest); + lpEnd = CheckSlash(szDest); + lstrcpy (lpEnd, szItem); + + if (CopyFile (szSrc, szDest, FALSE)) { + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: <%s> ==> <%s> [OK]."), + szSrc, szDest)); + } else { + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: <%s> ==> <%s> [FAILED %d]."), + szSrc, szDest, GetLastError())); + } + } + } + + break; + + case 4: + // + // Delete a program item + // + + GetProgramsDirectory (FALSE, szDest); + lpEnd = CheckSlash(szDest); + lstrcpy (lpEnd, szItem); + + if (DeleteFile(szDest)) { + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted <%s>"), szDest)); + } else { + DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to deleted <%s> with %d"), szDest, GetLastError())); + } + + + // + // Attempt to delete the directory + // + + lpTemp = szDest + lstrlen(szDest) - 1; + lpEnd--; + + while ((*lpTemp != TEXT('\\')) && lpTemp > lpEnd) { + lpTemp--; + } + + if (lpTemp == lpEnd) { + break; + } + + *lpTemp = TEXT('\0'); + + if (RemoveDirectory(szDest)) { + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted directory <%s>"), szDest)); + } else { + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Failed to delete directory <%s> with %d"), szDest, GetLastError())); + } + + break; + } + + +LoopAgain: + + // + // Close the registry key + // + + RegCloseKey(hKeyEntry); + + + // + // Enumerate again + // + + Index++; + + wsprintf (szSubKey, TEXT("%s\\%s\\Files\\%d"), USERDIFF, lpItem->szBuildNumber, Index); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry); + + } while (lResult == ERROR_SUCCESS); + +Exit: + + DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Leaving."))); + + return TRUE; +} + +//************************************************************* +// +// ProcessPrograms() +// +// Purpose: Processes the Execute entry for a build +// +// Parameters: lpProfile - Profile information +// lpItem - Build item +// hKey - Registry key to enumerate +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 11/16/95 ericflo Created +// +//************************************************************* + +BOOL ProcessPrograms (LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey) +{ + TCHAR szSubKey[MAX_PATH]; + TCHAR szCmdLine[MAX_PATH]; + TCHAR szFullPath[MAX_PATH]; + DWORD dwSize, dwType, dwProductType; + LONG lResult; + UINT Index = 1; + HKEY hKeyEntry; + STARTUPINFO si; + PROCESS_INFORMATION ProcessInformation; + BOOL Result; + + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Entering."))); + + + // + // Process the entry + // + + wsprintf (szSubKey, TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry); + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: No execute entries."))); + goto Exit; + } + + + do { + + // + // Query for the product type + // + + dwSize = sizeof(dwProductType); + lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType, + (LPBYTE)&dwProductType, &dwSize); + + + // + // It's ok to not have a product type listed in userdiff.ini. + // In this case, we always apply the change regardless of the + // platform. + // + + if (lResult == ERROR_SUCCESS) { + + // + // A specific product was listed. Check if + // we can process this entry. + // + + if (!OkToProcessItem(dwProductType)) { + DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Skipping Item %d due to product type mismatch."), Index)); + goto LoopAgain; + } + } + + + // + // Query for the command line + // + + + dwSize = MAX_PATH * sizeof(TCHAR); + lResult = RegQueryValueEx(hKeyEntry, UD_COMMANDLINE, NULL, &dwType, + (LPBYTE)szCmdLine, &dwSize); + + if (lResult != ERROR_SUCCESS) { + goto LoopAgain; + } + + + // + // If we have a NULL path, loop again. + // + + if (szCmdLine[0] == TEXT('\0')) { + goto LoopAgain; + } + + + // + // Expand the command line + // + + ExpandEnvironmentStrings (szCmdLine, szFullPath, MAX_PATH); + + + // + // Initialize process startup info + // + + si.cb = sizeof(STARTUPINFO); + si.lpReserved = NULL; + si.lpTitle = NULL; + si.lpDesktop = NULL; + si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L; + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_SHOWNORMAL; + si.lpReserved2 = NULL; + si.cbReserved2 = 0; + + + // + // Start the app + // + + Result = CreateProcessAsUser(lpProfile->hToken, NULL, szFullPath, + NULL, NULL, FALSE, + NORMAL_PRIORITY_CLASS, NULL, NULL, + &si, &ProcessInformation); + + if (Result) { + + DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Spawned <%s>. Waiting for it to complete."), + szFullPath)); + + // + // Wait for the app to complete (3 minutes max) + // + + WaitForSingleObject(ProcessInformation.hProcess, 180000); + + + DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Finished waiting for <%s>."), + szFullPath)); + + + // + // Close our handles to the process and thread + // + + CloseHandle(ProcessInformation.hProcess); + CloseHandle(ProcessInformation.hThread); + + } else { + DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Failed to execute <%s>, error = %d"), + szFullPath, GetLastError())); + } + +LoopAgain: + + // + // Close the registry key + // + + RegCloseKey(hKeyEntry); + + + // + // Enumerate again + // + + Index++; + + wsprintf (szSubKey, TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index); + lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry); + + } while (lResult == ERROR_SUCCESS); + +Exit: + + DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Leaving."))); + + return TRUE; +} + +//************************************************************* +// +// OkToProcessItem() +// +// Purpose: Determines if the platform currently running +// on should have the change in userdiff.ini applied. +// +// Parameters: dwProductType - ProductType for a specific entry +// in userdiff.ini +// +// Return: TRUE if change should be applied +// FALSE if not +// +// Comments: dwProductType can be one of these values: +// +// 0 = All platforms +// 1 = All server platforms +// 2 = Workstation +// 3 = Server +// 4 = Domain Controller +// +// History: Date Author Comment +// 4/08/96 ericflo Created +// +//************************************************************* + +BOOL OkToProcessItem(DWORD dwProductType) +{ + BOOL bRetVal = FALSE; + + + switch (g_ProductType) { + + case PT_WORKSTATION: + + if ( (dwProductType == 0) || + (dwProductType == 2) ) { + + bRetVal = TRUE; + } + + break; + + case PT_SERVER: + + if ( (dwProductType == 0) || + (dwProductType == 1) || + (dwProductType == 3) ) { + + bRetVal = TRUE; + } + + break; + + case PT_DC: + if ( (dwProductType == 0) || + (dwProductType == 1) || + (dwProductType == 4) ) { + + bRetVal = TRUE; + } + + break; + + } + + return bRetVal; +} diff --git a/private/windows/gina/userenv/userdiff.h b/private/windows/gina/userenv/userdiff.h new file mode 100644 index 000000000..aa7dbdc42 --- /dev/null +++ b/private/windows/gina/userenv/userdiff.h @@ -0,0 +1,42 @@ +//************************************************************* +// +// userdiff.h - Header file for userdiff.c +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + + +#define USERDIFF TEXT("UserDiff") +#define USERDIFR_LOCATION TEXT("%SystemRoot%\\system32\\config\\userdifr") +#define USERDIFF_LOCATION TEXT("%SystemRoot%\\system32\\config\\userdiff") + + +// +// Hive processing key words +// + +#define UD_ACTION TEXT("Action") +#define UD_KEYNAME TEXT("KeyName") +#define UD_VALUE TEXT("Value") +#define UD_VALUENAME TEXT("ValueName") +#define UD_VALUENAMES TEXT("ValueNames") +#define UD_FLAGS TEXT("Flags") +#define UD_ITEM TEXT("Item") +#define UD_COMMANDLINE TEXT("CommandLine") +#define UD_PRODUCTTYPE TEXT("Product") + + + +#define MAX_BUILD_NUMBER 30 + +typedef struct _UDNODE { + TCHAR szBuildNumber[MAX_BUILD_NUMBER]; + DWORD dwBuildNumber; + struct _UDNODE *pNext; +} UDNODE, * LPUDNODE; + + +BOOL ProcessUserDiff (LPPROFILE lpProfile, DWORD dwBuildNumber); diff --git a/private/windows/gina/userenv/userenv.c b/private/windows/gina/userenv/userenv.c new file mode 100644 index 000000000..b6aa3245e --- /dev/null +++ b/private/windows/gina/userenv/userenv.c @@ -0,0 +1,62 @@ +//************************************************************* +// +// Main entry point +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + + +//************************************************************* +// +// DllMain() +// +// Purpose: Main entry point +// +// Parameters: hInstance - Module instance +// dwReason - Way this function is being called +// lpReseved - Reserved +// +// +// Return: (BOOL) TRUE if successfully initialized +// FALSE if an error occurs +// +// +// Comments: +// +// +// History: Date Author Comment +// 5/24/95 ericflo Created +// +//************************************************************* + +BOOL WINAPI LibMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + { + + DisableThreadLibraryCalls (hInstance); + InitializeGlobals (hInstance); + +#if DBG + InitDebugSupport(); +#endif + + } + break; + + + case DLL_PROCESS_DETACH: + ShutdownEvents (); + break; + + } + + return TRUE; +} diff --git a/private/windows/gina/userenv/userenv.def b/private/windows/gina/userenv/userenv.def new file mode 100644 index 000000000..9ce340be5 --- /dev/null +++ b/private/windows/gina/userenv/userenv.def @@ -0,0 +1,37 @@ +LIBRARY USERENV + +DESCRIPTION 'Windows NT User Environment Manager' + +EXPORTS + LoadUserProfileA + LoadUserProfileW + UnloadUserProfile + GetProfilesDirectoryA + GetProfilesDirectoryW + GetUserProfileDirectoryA + GetUserProfileDirectoryW + CreateEnvironmentBlock + DestroyEnvironmentBlock + + +;;========================================================================= +;; Internal API's used by setup +;;========================================================================= + + InitializeProfiles @100 NONAME ;Internal + CreateGroupA @101 NONAME ;Internal + CreateGroupW @102 NONAME ;Internal + DeleteGroupA @103 NONAME ;Internal + DeleteGroupW @104 NONAME ;Internal + AddItemA @105 NONAME ;Internal + AddItemW @106 NONAME ;Internal + DeleteItemA @107 NONAME ;Internal + DeleteItemW @108 NONAME ;Internal + CreateUserProfileA @109 NONAME ;Internal + CreateUserProfileW @110 NONAME ;Internal + CopyProfileDirectoryA @111 NONAME ;Internal + CopyProfileDirectoryW @112 NONAME ;Internal + AddDesktopItemA @113 NONAME ;Internal + AddDesktopItemW @114 NONAME ;Internal + DeleteDesktopItemA @115 NONAME ;Internal + DeleteDesktopItemW @116 NONAME ;Internal diff --git a/private/windows/gina/userenv/userenv.rc b/private/windows/gina/userenv/userenv.rc new file mode 100644 index 000000000..c5b7eceae --- /dev/null +++ b/private/windows/gina/userenv/userenv.rc @@ -0,0 +1,124 @@ +//************************************************************* +// +// Userenv.rc - resource file +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include <windows.h> +#include "resource.h" + + +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Userenv" +#define VER_INTERNALNAME_STR "userenv\0" +#define VER_ORIGINALFILENAME_STR "userenv.dll" + +#include "common.ver" + +#include "uevents.rc" + +STRINGTABLE +BEGIN + IDS_FAILED_LOAD_PROFILE, "The operating system was unable to load your profile. Please contact your Network Administrator. (%d)" + IDS_ACCESSDENIED, "You do not have permission to access your central profile located at %s. The operating system is attempting to log you on with your local profile. \ + Please contact your Network Administrator." + IDS_FAILEDDIRCREATE, "The operating system was unable to create a profile directory %s. Another file exists with the same name. \ + You will be logged on with a local profile only. Please contact your Network Administrator." + IDS_FAILEDDIRCREATE2, "The operating system was unable to create profile directory %s. You will be logged on with a local profile only. \ + Please contact your Network Administrator. (%d)" + IDS_CENTRAL_NOT_AVAILABLE, "Your roaming profile is not available. You will be logged on with the locally stored profile. (%d)" + IDS_TEMP_DIR_FAILED, "The operating system was unable to create a temporary profile directory %s. Please contact your Network Administrator. (%d)" + IDS_FAILED_LOAD_LOCAL, "The operating system was unable to load the locally stored profile. A new local profile will be created. (%d)" + IDS_SECURITY_FAILED, "The operating system was unable to set security on your registry. Please contact your Network Administrator. (%d)" + IDS_CENTRAL_UPDATE_FAILED, "The update of your roaming profile failed. Please contact your Network Administrator. (%d)" + IDS_ADMIN_OVERRIDE, "Your profile was not successfully loaded, but you have been logged on with the default system profile. Please correct the problem and log off. (%d)" + IDS_CENTRAL_NOT_AVAILABLE2, "Your roaming profile is not available, the operating system is attempting to log you on with your local profile. (%d)" + IDS_MANDATORY_NOT_AVAILABLE ,"Your roaming mandatory profile is not available, the operating system is attempting to log you on with your local profile. (%d)" + IDS_MANDATORY_NOT_AVAILABLE2,"The operating system is unable to log you on because your roaming mandatory profile is not available. Please contact your Network Administrator. (%d)" + IDS_MISSINGPOLICYFILEENTRY, "This computer is in manual policy mode, but the policy file can not be found. You will be logged on without policy. (%d)" + IDS_REGLOADKEYFAILED, "RegLoadKey failed with error %d for %s" + IDS_COMMON, " (Common)" + + // + // Special Folder directory names + // + + IDS_SH_APPDATA, "Application Data" + IDS_SH_DESKTOP, "Desktop" + IDS_SH_FAVORITES, "Favorites" + IDS_SH_NETHOOD, "NetHood" + IDS_SH_PERSONAL, "Personal" + IDS_SH_PRINTHOOD, "PrintHood" + IDS_SH_RECENT, "Recent" + IDS_SH_SENDTO, "SendTo" + IDS_SH_STARTMENU, "Start Menu" + IDS_SH_TEMPLATES, "Templates" + IDS_SH_PROGRAMS, "Start Menu\\Programs" + IDS_SH_STARTUP, "Start Menu\\Programs\\Startup" + + // + // Default Start Menu locations + // + + IDS_COMMON_PROGRAMS, "%SystemRoot%\\Profiles\\All Users\\Start Menu\\Programs" + IDS_DEFAULT_PROGRAMS, "%SystemRoot%\\Profiles\\Default User\\Start Menu\\Programs" + + // + // Default Desktop locations + // + + IDS_COMMON_DESKTOP, "%SystemRoot%\\Profiles\\All Users\\Desktop" + IDS_DEFAULT_DESKTOP, "%SystemRoot%\\Profiles\\Default User\\Desktop" + +END + +IDI_PROFILE ICON profile.ico + +IDD_SLOW_LINK DIALOG 6, 18, 225, 75 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Slow Network Connection" +FONT 8, "MS Shell Dlg" +BEGIN + ICON IDI_PROFILE, 101, 10, 12, 18, 20 + LTEXT "A slow network connection has been detected. Would you like to download your profile or use the locally stored copy?", + -1, 45, 10, 114, 48 + DEFPUSHBUTTON "&Download", IDC_DOWNLOAD, 165, 10, 50, 14 + PUSHBUTTON "Use &Local", IDC_LOCAL, 165, 27, 50, 14 + RTEXT "Time remaining:", -1, 147, 60, 54, 8 + LTEXT "", IDC_TIMEOUT, 205, 60, 12, 8 +END + + +IDD_CHOOSE_PROFILE DIALOG 6, 18, 225, 75 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Choose Profile" +FONT 8, "MS Shell Dlg" +BEGIN + ICON IDI_PROFILE, 101, 10, 12, 18, 20 + LTEXT "Your locally stored profile is newer than your roaming profile. Would you like to use the locally stored profile?", + -1, 45, 10, 114, 48 + DEFPUSHBUTTON "&Yes", IDC_CP_YES, 165, 10, 50, 14 + PUSHBUTTON "&No", IDC_CP_NO, 165, 27, 50, 14 + RTEXT "Time remaining:", -1, 147, 60, 54, 8 + LTEXT "", IDC_TIMEOUT, 205, 60, 12, 8 +END + + +IDD_ERROR DIALOG 6, 18, 225, 85 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "User Environment" +FONT 8, "MS Shell Dlg" +BEGIN + ICON IDI_PROFILE, 101, 10, 12, 18, 20 + LTEXT "",IDC_ERRORTEXT, 45, 10, 110, 58 + DEFPUSHBUTTON "OK", IDOK, 165, 10, 50, 14 + RTEXT "Time remaining:", -1, 147, 70, 54, 8 + LTEXT "", IDC_TIMEOUT, 205, 70, 12, 8 +END diff --git a/private/windows/gina/userenv/util.c b/private/windows/gina/userenv/util.c new file mode 100644 index 000000000..fa9cc8d6f --- /dev/null +++ b/private/windows/gina/userenv/util.c @@ -0,0 +1,1645 @@ +//************************************************************* +// +// Utility functions +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#include "uenv.h" + +#define TYPICAL_STRING_LENGTH 60 + +//************************************************************* +// +// 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) +{ + DWORD dwStrLen; + 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 - Directory +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 8/10/95 ericflo Created +// +//************************************************************* + +BOOL Delnode_Recurse (LPTSTR lpDir) +{ + WIN32_FIND_DATA fd; + HANDLE hFile; + + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("Delnode_Recurse: Entering, lpDir = <%s>"), lpDir)); + + + // + // Setup the current working dir + // + + if (!SetCurrentDirectory (lpDir)) { + DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Failed to set current working directory. Error = %d"), GetLastError())); + return FALSE; + } + + + // + // Find the first file + // + + hFile = FindFirstFile(c_szStarDotStar, &fd); + + if (hFile == INVALID_HANDLE_VALUE) { + + if (GetLastError() == ERROR_FILE_NOT_FOUND) { + return TRUE; + } else { + DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: FindFirstFile failed. Error = %d"), + GetLastError())); + return FALSE; + } + } + + + do { + // + // Verbose output + // + + DebugMsg((DM_VERBOSE, TEXT("Delnode_Recurse: FindFile found: <%s>"), + fd.cFileName)); + + // + // Check for "." and ".." + // + + if (!lstrcmpi(fd.cFileName, c_szDot)) { + continue; + } + + if (!lstrcmpi(fd.cFileName, c_szDotDot)) { + continue; + } + + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + + // + // Found a directory. + // + + if (!Delnode_Recurse(fd.cFileName)) { + FindClose(hFile); + return FALSE; + } + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + fd.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY; + SetFileAttributes (fd.cFileName, fd.dwFileAttributes); + } + + + if (!RemoveDirectory (fd.cFileName)) { + DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Failed to delete directory <%s>. Error = %d"), + fd.cFileName, GetLastError())); + } + + } else { + + // + // We found a file. Set the file attributes, + // and try to delete it. + // + + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) || + (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) { + SetFileAttributes (fd.cFileName, FILE_ATTRIBUTE_NORMAL); + } + + if (!DeleteFile (fd.cFileName)) { + DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Failed to delete <%s>. Error = %d"), + fd.cFileName, GetLastError())); + } + + } + + + // + // Find the next entry + // + + } while (FindNextFile(hFile, &fd)); + + + // + // Close the search handle + // + + FindClose(hFile); + + + // + // Reset the working directory + // + + if (!SetCurrentDirectory (c_szDotDot)) { + DebugMsg((DM_WARNING, TEXT("Delnode_Recurse: Failed to reset current working directory. Error = %d"), GetLastError())); + return FALSE; + } + + + // + // Success. + // + + DebugMsg((DM_VERBOSE, TEXT("Delnode_Recurse: Leaving <%s>"), lpDir)); + + return TRUE; +} + + +//************************************************************* +// +// 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 +// +//************************************************************* + +BOOL Delnode (LPTSTR lpDir) +{ + TCHAR szCurWorkingDir[MAX_PATH]; + + if (GetCurrentDirectory(MAX_PATH, szCurWorkingDir)) { + + Delnode_Recurse (lpDir); + + SetCurrentDirectory (szCurWorkingDir); + + if (!RemoveDirectory (lpDir)) { + DebugMsg((DM_VERBOSE, TEXT("Delnode: Failed to delete directory <%s>. Error = %d"), + lpDir, GetLastError())); + return FALSE; + } + + + } else { + + DebugMsg((DM_WARNING, TEXT("Delnode: Failed to get current working directory. Error = %d"), GetLastError())); + return FALSE; + } + + return TRUE; + +} + +//************************************************************* +// +// CreateNestedDirectory() +// +// Purpose: Creates a subdirectory and all it's parents +// if necessary. +// +// Parameters: lpDirectory - Directory name +// lpSecurityAttributes - Security Attributes +// +// Return: > 0 if successful +// 0 if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 8/08/95 ericflo Created +// +//************************************************************* + +UINT CreateNestedDirectory(LPCTSTR lpDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes) +{ + TCHAR szDirectory[MAX_PATH]; + LPTSTR lpEnd; + + // + // Check for NULL pointer + // + + if (!lpDirectory || !(*lpDirectory)) { + DebugMsg((DM_WARNING, TEXT("CreateNestedDirectory: Received a NULL pointer."))); + return 0; + } + + + // + // First, see if we can create the directory without having + // to build parent directories. + // + + if (CreateDirectory (lpDirectory, lpSecurityAttributes)) { + return 1; + } + + // + // If this directory exists already, this is OK too. + // + + if (GetLastError() == ERROR_ALREADY_EXISTS) { + return ERROR_ALREADY_EXISTS; + } + + + // + // No luck, copy the string to a buffer we can munge + // + + lstrcpy (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 (!CreateDirectory (szDirectory, NULL)) { + + if (GetLastError() != ERROR_ALREADY_EXISTS) { + DebugMsg((DM_WARNING, TEXT("CreateNestedDirectory: CreateDirectory failed with %d."), GetLastError())); + return 0; + } + } + + *lpEnd = TEXT('\\'); + lpEnd++; + } + } + + + // + // Create the final directory + // + + if (CreateDirectory (szDirectory, lpSecurityAttributes)) { + 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) +{ + TCHAR szDirectory[MAX_PATH]; + DWORD dwLength; + BOOL bRetVal = FALSE; + + ExpandEnvironmentStrings(PROFILES_DIR, szDirectory, MAX_PATH); + dwLength = lstrlen(szDirectory) + 1; + + if (lpProfilesDir) { + + if (*lpcchSize >= dwLength) { + lstrcpy (lpProfilesDir, szDirectory); + bRetVal = TRUE; + + } else { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + } + } + + + *lpcchSize = dwLength; + + return bRetVal; +} + + +//************************************************************* +// +// 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; + + + // + // Parameter check + // + + if (!hToken) { + return FALSE; + } + + + // + // Retrieve the user's sid string + // + + lpSidString = GetSidString(hToken); + + if (!lpSidString) { + return FALSE; + } + + + // + // Check the registry + // + + lstrcpy(szBuffer, PROFILE_LIST_PATH); + lstrcat(szBuffer, TEXT("\\")); + lstrcat(szBuffer, lpSidString); + + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, KEY_READ, + &hKey); + + if (lResult != ERROR_SUCCESS) { + DeleteSidString(lpSidString); + return FALSE; + } + + lResult = RegQueryValueEx(hKey, + PROFILE_IMAGE_VALUE_NAME, + NULL, + &dwType, + (LPBYTE) szBuffer, + &dwLength); + + if (lResult != ERROR_SUCCESS) { + RegCloseKey (hKey); + DeleteSidString(lpSidString); + return FALSE; + } + + + // + // Clean up + // + + RegCloseKey(hKey); + DeleteSidString(lpSidString); + + + + // + // Expand and get the length of string + // + + ExpandEnvironmentStrings(szBuffer, szDirectory, MAX_PATH); + + dwLength = lstrlen(szDirectory) + 1; + + + // + // Save the string if appropriate + // + + if (lpProfileDir) { + + if (*lpcchSize >= dwLength) { + lstrcpy (lpProfileDir, szDirectory); + bRetVal = TRUE; + + } else { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + } + } + + + *lpcchSize = dwLength; + + return bRetVal; +} + +//************************************************************* +// +// 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); +} + +//************************************************************* +// +// RegDelnodeRecurse() +// +// Purpose: Deletes a registry key and all it's subkeys / values. +// Called by RegDelnode +// +// Parameters: hKeyRoot - Root key +// lpSubKey - SubKey to delete +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/3/95 ericflo Created +// +//************************************************************* + +BOOL RegDelnodeRecurse (HKEY hKeyRoot, LPTSTR lpSubKey) +{ + LPTSTR lpEnd; + LONG lResult; + DWORD dwSize; + TCHAR szName[MAX_PATH]; + HKEY hKey; + FILETIME ftWrite; + + // + // First, see if we can delete the key without having + // to recurse. + // + + + lResult = RegDeleteKey(hKeyRoot, lpSubKey); + + if (lResult == ERROR_SUCCESS) { + return TRUE; + } + + + lResult = RegOpenKeyEx (hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); + + if (lResult != ERROR_SUCCESS) { + return FALSE; + } + + + lpEnd = CheckSlash(lpSubKey); + + // + // Enumerate the keys + // + + dwSize = MAX_PATH; + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + if (lResult == ERROR_SUCCESS) { + + do { + + lstrcpy (lpEnd, szName); + + if (!RegDelnodeRecurse(hKeyRoot, lpSubKey)) { + break; + } + + // + // Enumerate again + // + + dwSize = MAX_PATH; + + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + + } while (lResult == ERROR_SUCCESS); + } + + lpEnd--; + *lpEnd = TEXT('\0'); + + + RegCloseKey (hKey); + + + // + // Try again to delete the key + // + + lResult = RegDeleteKey(hKeyRoot, lpSubKey); + + if (lResult == ERROR_SUCCESS) { + return TRUE; + } + + return FALSE; +} + +//************************************************************* +// +// RegDelnode() +// +// Purpose: Deletes a registry key and all it's subkeys / values +// +// Parameters: hKeyRoot - Root key +// lpSubKey - SubKey to delete +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/3/95 ericflo Created +// +//************************************************************* + +BOOL RegDelnode (HKEY hKeyRoot, LPTSTR lpSubKey) +{ + TCHAR szDelKey[2 * MAX_PATH]; + + + lstrcpy (szDelKey, lpSubKey); + + return RegDelnodeRecurse(hKeyRoot, szDelKey); + +} + +//************************************************************* +// +// 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 +// +//************************************************************* + +VOID DeleteAllValues(HKEY hKey) +{ + TCHAR ValueName[MAX_PATH+1]; + DWORD dwSize = MAX_PATH+1; + + while (RegEnumValue(hKey, 0, ValueName, &dwSize, + NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { + + if (RegDeleteValue(hKey, ValueName) != ERROR_SUCCESS) { + return; + } + + dwSize = MAX_PATH+1; + } +} + +//************************************************************* +// +// OpenHKeyCurrentUser() +// +// Purpose: Opens HKEY_CURRENT_USER to point at the current logged +// on user's profile. +// +// Parameters: lpProfile - Profile Information +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: +// +// History: Date Author Comment +// 10/13/95 ericflo Ported +// +//************************************************************* + +BOOL OpenHKeyCurrentUser(LPPROFILE lpProfile) +{ + + // + // Make sure HKEY_CURRENT_USER is closed before + // remapping it. + // + + try { + + RegCloseKey(HKEY_CURRENT_USER); + + } except(EXCEPTION_EXECUTE_HANDLER) {}; + + + // + // Impersonate the user + // + + if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { + DebugMsg((DM_WARNING, TEXT("OpenHKeyCurrentUser: Failed to impersonate user"))); + return FALSE; + } + + + // + // Access the registry to force HKEY_CURRENT_USER to be re-opened + // + + RegEnumKey(HKEY_CURRENT_USER, 0, NULL, 0); + + + // + // Revert to being 'ourself' + // + + if (!RevertToSelf()) { + DebugMsg((DM_WARNING, TEXT("OpenHKeyCurrentUser: Failed to revert to self"))); + } + + return TRUE; +} + +//************************************************************* +// +// CloseHKeyCurrentUser() +// +// Purpose: Closes HKEY_CURRENT_USER +// +// Parameters: lpProfile - Profile Information +// +// Return: void +// +// Comments: +// +// History: Date Author Comment +// 10/13/95 ericflo Ported +// +//************************************************************* + +VOID CloseHKeyCurrentUser(LPPROFILE lpProfile) +{ + RegCloseKey(HKEY_CURRENT_USER); +} + +//************************************************************* +// +// MakeFileSecure() +// +// Purpose: Sets the attributes on the file so only Administrators +// and the OS can delete it. Everyone else has 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 +// +//************************************************************* + +BOOL MakeFileSecure (LPTSTR lpFile) +{ + 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, psidEveryone = NULL; + DWORD cbAcl, aceIndex; + ACE_HEADER * lpAceHeader; + BOOL bRetVal = 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("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 World sid + // + + if (!AllocateAndInitializeSid(&authWorld, 1, SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, &psidEveryone)) { + + DebugMsg((DM_WARNING, TEXT("MakeFileSecure: Failed to initialize world sid. Error = %d"), GetLastError())); + goto Exit; + } + + + // + // Allocate space for the ACL + // + + cbAcl = (3 * GetLengthSid (psidSystem)) + + (3 * 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_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, 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, 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 (psidEveryone) { + FreeSid(psidEveryone); + } + + + if (pAcl) { + GlobalFree (pAcl); + } + + return bRetVal; +} + +//************************************************************* +// +// GetProgramsDirectory() +// +// Purpose: Retrieves the programs directory for the current +// user, or returns Default User's if not found. +// +// Parameters: bCommonGroup - Common or personal +// lpDirectory - Result +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: lpDirectory is assumed to be MAX_PATH chars long +// +// History: Date Author Comment +// 10/20/95 ericflo Created +// +//************************************************************* + +BOOL GetProgramsDirectory (BOOL bCommonGroup, LPTSTR lpDirectory) +{ + LONG lResult; + HKEY hKey; + DWORD dwType, dwSize; + TCHAR szDirectory[MAX_PATH]; + UINT uID; + BOOL bRetVal = FALSE; + + + // + // Open the User Shell Folders in the registry + // + + + lResult = RegOpenKeyEx (HKEY_CURRENT_USER, USER_SHELL_FOLDER, 0, + KEY_READ, &hKey); + + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("GetProgramsDirectory: Failed to open registry. %d"), lResult)); + goto Exit; + } + + + // + // Now query for the programs directory + // + + dwSize = MAX_PATH * sizeof(TCHAR); + szDirectory[0] = TEXT('\0'); + + if (bCommonGroup) { + + lResult = RegQueryValueEx (hKey, c_CommonShellFolders[2].lpFolderName, + NULL, &dwType, (LPBYTE) szDirectory, &dwSize); + } else { + + lResult = RegQueryValueEx (hKey, c_ShellFolders[10].lpFolderName, + NULL, &dwType, (LPBYTE) szDirectory, &dwSize); + } + + + RegCloseKey(hKey); + + + if (lResult != ERROR_SUCCESS) { + DebugMsg((DM_WARNING, TEXT("GetProgramsDirectory: Failed to query for registry value. %d"), lResult)); + goto Exit; + } + + + // + // Did we find anything? + // + + if (szDirectory[0] == TEXT('\0')) { + DebugMsg((DM_WARNING, TEXT("GetProgramsDirectory: NULL special folder name"))); + goto Exit; + } + + + // + // Save the result + // + + + if (ExpandEnvironmentStrings(szDirectory, lpDirectory, MAX_PATH)) { + bRetVal = TRUE; + } + + +Exit: + + if (!bRetVal) { + + // + // Load the default programs location + // + + if (bCommonGroup) { + uID = IDS_COMMON_PROGRAMS; + } else { + uID = IDS_DEFAULT_PROGRAMS; + } + + DebugMsg((DM_VERBOSE, TEXT("GetProgramsDirectory: Loading Default User programs dir !!!"))); + + if (LoadString(g_hDllInstance, uID, szDirectory, MAX_PATH)) { + + if (ExpandEnvironmentStrings(szDirectory, lpDirectory, MAX_PATH)) { + bRetVal = TRUE; + } + } + } + + + return bRetVal; + +} + +//************************************************************* +// +// GetDesktopDirectory() +// +// Purpose: Retrieves the Desktop directory for the current +// user, or returns Default User's if not found. +// +// Parameters: bCommonGroup - Common or personal +// lpDirectory - Result +// +// Return: TRUE if successful +// FALSE if an error occurs +// +// Comments: lpDirectory is assumed to be MAX_PATH chars long +// +// History: Date Author Comment +// 4/2/96 ericflo Created +// +//************************************************************* + +BOOL GetDesktopDirectory (BOOL bCommonGroup, LPTSTR lpDirectory) +{ + LONG lResult; + HKEY hKey; + DWORD dwType, dwSize; + TCHAR szDirectory[MAX_PATH]; + UINT uID; + BOOL bRetVal = FALSE; + + + // + // Open the User Shell Folders in the registry + // + + + lResult = RegOpenKeyEx (HKEY_CURRENT_USER, USER_SHELL_FOLDER, 0, + KEY_READ, &hKey); + + + if (lResult != ERROR_SUCCESS) { + goto Exit; + } + + + // + // Now query for the Desktop directory + // + + dwSize = MAX_PATH * sizeof(TCHAR); + szDirectory[0] = TEXT('\0'); + + if (bCommonGroup) { + + lResult = RegQueryValueEx (hKey, c_CommonShellFolders[0].lpFolderName, + NULL, &dwType, (LPBYTE) szDirectory, &dwSize); + } else { + + lResult = RegQueryValueEx (hKey, c_ShellFolders[1].lpFolderName, + NULL, &dwType, (LPBYTE) szDirectory, &dwSize); + } + + + RegCloseKey(hKey); + + + if (lResult != ERROR_SUCCESS) { + goto Exit; + } + + + // + // Did we find anything? + // + + if (szDirectory[0] == TEXT('\0')) { + goto Exit; + } + + + // + // Save the result + // + + + if (ExpandEnvironmentStrings(szDirectory, lpDirectory, MAX_PATH)) { + bRetVal = TRUE; + } + + +Exit: + + if (!bRetVal) { + + // + // Load the default Desktop location + // + + if (bCommonGroup) { + uID = IDS_COMMON_DESKTOP; + } else { + uID = IDS_DEFAULT_DESKTOP; + } + + if (LoadString(g_hDllInstance, uID, szDirectory, MAX_PATH)) { + + if (ExpandEnvironmentStrings(szDirectory, lpDirectory, MAX_PATH)) { + bRetVal = TRUE; + } + } + } + + + return bRetVal; + +} + + +//************************************************************* +// +// 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_TOPMOST, 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 (MAX_PATH chars in 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) +{ + TCHAR szSysRoot[MAX_PATH]; + LPTSTR lpFileName; + DWORD dwSysLen; + + + // + // 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. + // + + ExpandEnvironmentStrings (TEXT("%SystemRoot%"), szSysRoot, MAX_PATH); + dwSysLen = lstrlen(szSysRoot); + + + // + // Make sure the source is long enough + // + + if ((DWORD)lstrlen(lpFile) < dwSysLen) { + lstrcpy (lpResult, lpFile); + return TRUE; + } + + + if (CompareString (LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, + szSysRoot, dwSysLen, + lpFile, dwSysLen) == 2) { + + // + // The szReturn buffer starts with %systemroot%. + // Actually insert %systemroot% in the result buffer. + // + + lstrcpy (lpResult, TEXT("%SystemRoot%")); + lstrcat (lpResult, (lpFile + dwSysLen)); + + + } else { + + // + // The szReturn buffer does not start with %systemroot% + // just copy in the original string. + // + + lstrcpy (lpResult, 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; + 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) + TYPICAL_STRING_LENGTH; + + 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())); + Free(String); + String = NULL; + break; + } + + // + // If the buffer was too small, make it bigger and try again + // + + if (LengthCopied > LengthAllocated) { + + String = LocalReAlloc(String, LengthCopied * sizeof(TCHAR), LMEM_MOVEABLE); + LengthAllocated = LengthCopied; + if (String == NULL) { + DebugMsg((DM_WARNING, TEXT("AllocAndExpandEnvironmentStrings: Failed to reallocate %d bytes for string"), LengthAllocated * sizeof(TCHAR))); + break; + } + + // + // Go back and try to expand the string again + // + + } else { + + // + // Success! + // + + break; + } + + } + + return(String); +} diff --git a/private/windows/gina/userenv/util.h b/private/windows/gina/userenv/util.h new file mode 100644 index 000000000..514ddfd25 --- /dev/null +++ b/private/windows/gina/userenv/util.h @@ -0,0 +1,28 @@ +//************************************************************* +// +// Header file for Util.c +// +// Microsoft Confidential +// Copyright (c) Microsoft Corporation 1995 +// All rights reserved +// +//************************************************************* + +#define FreeProducedString(psz) if((psz) != NULL) {LocalFree(psz);} else + +LPWSTR ProduceWFromA(LPCSTR pszA); +LPSTR ProduceAFromW(LPCWSTR pszW); +LPTSTR CheckSlash (LPTSTR lpDir); +BOOL Delnode (LPTSTR lpDir); +UINT CreateNestedDirectory(LPCTSTR lpDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +int StringToInt(LPTSTR lpNum); +BOOL RegDelnode (HKEY hKeyRoot, LPTSTR lpSubKey); +VOID DeleteAllValues(HKEY hKey); +BOOL OpenHKeyCurrentUser(LPPROFILE lpProfile); +VOID CloseHKeyCurrentUser(LPPROFILE lpProfile); +BOOL MakeFileSecure (LPTSTR lpFile); +BOOL GetProgramsDirectory (BOOL bCommonGroup, LPTSTR lpDirectory); +BOOL GetDesktopDirectory (BOOL bCommonGroup, LPTSTR lpDirectory); +void CenterWindow (HWND hwnd); +BOOL UnExpandSysRoot(LPCTSTR lpFile, LPTSTR lpResult); +LPTSTR AllocAndExpandEnvironmentStrings(LPCTSTR lpszSrc); |