summaryrefslogtreecommitdiffstats
path: root/private/windows/gina/userenv
diff options
context:
space:
mode:
Diffstat (limited to 'private/windows/gina/userenv')
-rw-r--r--private/windows/gina/userenv/copydir.c1241
-rw-r--r--private/windows/gina/userenv/copydir.h50
-rw-r--r--private/windows/gina/userenv/debug.c226
-rw-r--r--private/windows/gina/userenv/debug.h51
-rw-r--r--private/windows/gina/userenv/envvar.c1404
-rw-r--r--private/windows/gina/userenv/events.c295
-rw-r--r--private/windows/gina/userenv/events.h13
-rw-r--r--private/windows/gina/userenv/globals.c325
-rw-r--r--private/windows/gina/userenv/globals.h106
-rw-r--r--private/windows/gina/userenv/makefile6
-rw-r--r--private/windows/gina/userenv/makefile.inc2
-rw-r--r--private/windows/gina/userenv/policy.c1415
-rw-r--r--private/windows/gina/userenv/policy.h11
-rw-r--r--private/windows/gina/userenv/profile.c5851
-rw-r--r--private/windows/gina/userenv/profile.h71
-rw-r--r--private/windows/gina/userenv/profile.icobin0 -> 766 bytes
-rw-r--r--private/windows/gina/userenv/resource.h77
-rw-r--r--private/windows/gina/userenv/samples/copydir/generic.c423
-rw-r--r--private/windows/gina/userenv/samples/copydir/generic.def21
-rw-r--r--private/windows/gina/userenv/samples/copydir/generic.h29
-rw-r--r--private/windows/gina/userenv/samples/copydir/generic.icobin0 -> 766 bytes
-rw-r--r--private/windows/gina/userenv/samples/copydir/generic.rc86
-rw-r--r--private/windows/gina/userenv/samples/copydir/makefile6
-rw-r--r--private/windows/gina/userenv/samples/copydir/sources41
-rw-r--r--private/windows/gina/userenv/samples/copydir/window.bmpbin0 -> 2926 bytes
-rw-r--r--private/windows/gina/userenv/samples/debug/debug.c221
-rw-r--r--private/windows/gina/userenv/samples/debug/debug.def18
-rw-r--r--private/windows/gina/userenv/samples/debug/debug.h26
-rw-r--r--private/windows/gina/userenv/samples/debug/debug.rc17
-rw-r--r--private/windows/gina/userenv/samples/debug/makefile6
-rw-r--r--private/windows/gina/userenv/samples/debug/sources38
-rw-r--r--private/windows/gina/userenv/setup.c1494
-rw-r--r--private/windows/gina/userenv/sid.c249
-rw-r--r--private/windows/gina/userenv/sid.h14
-rw-r--r--private/windows/gina/userenv/sources50
-rw-r--r--private/windows/gina/userenv/stubs.c599
-rw-r--r--private/windows/gina/userenv/uenv.h34
-rw-r--r--private/windows/gina/userenv/uevents.mc53
-rw-r--r--private/windows/gina/userenv/userdiff.c1392
-rw-r--r--private/windows/gina/userenv/userdiff.h42
-rw-r--r--private/windows/gina/userenv/userenv.c62
-rw-r--r--private/windows/gina/userenv/userenv.def37
-rw-r--r--private/windows/gina/userenv/userenv.rc124
-rw-r--r--private/windows/gina/userenv/util.c1645
-rw-r--r--private/windows/gina/userenv/util.h28
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
new file mode 100644
index 000000000..2226f0db1
--- /dev/null
+++ b/private/windows/gina/userenv/profile.ico
Binary files differ
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
new file mode 100644
index 000000000..c127f57d0
--- /dev/null
+++ b/private/windows/gina/userenv/samples/copydir/generic.ico
Binary files differ
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
new file mode 100644
index 000000000..06758f8f8
--- /dev/null
+++ b/private/windows/gina/userenv/samples/copydir/window.bmp
Binary files differ
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);