/****************************** Module Header ******************************\ * Module Name: envvar.c * * Copyright (c) 1992, Microsoft Corporation * * Sets environment variables. * * History: * 2-25-92 JohanneC Created - * \***************************************************************************/ #include "msgina.h" #ifdef _X86_ #include "i386\oemhard.h" #endif #pragma hdrstop BOOL ProcessCommand(LPTSTR lpStart, PVOID *pEnv); BOOL ProcessSetCommand(LPTSTR lpStart, PVOID *pEnv); LPTSTR ProcessAutoexecPath(PVOID *pEnv, LPTSTR lpValue, DWORD cb); LONG AddNetworkConnection(PGLOBALS pGlobals, LPNETRESOURCE lpNetResource); BOOL UpdateUserEnvironmentVars( PVOID *pEnv ); #ifdef _X86_ BOOL IsPathIncludeRemovable(LPTSTR lpValue); #endif BOOL GetLUIDDeviceMapsEnabled( VOID ); #define KEY_NAME TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Environment") // // Max environment variable length // #define MAX_VALUE_LEN 1024 #define BSLASH TEXT('\\') #define COLON TEXT(':') // // These two globals implement ref counting on // pGlobals->UserProcessData->hCurrentUser (418628) // managed by OpenHKeyCurrentUser/CloseHKeyCurrentUser below // RTL_CRITICAL_SECTION g_csHKCU; ULONG g_ulHKCURef; BOOL InitHKeyCurrentUserSupport( ) { NTSTATUS Status ; Status = RtlInitializeCriticalSection( &g_csHKCU ); if ( !NT_SUCCESS( Status ) ) { DebugLog((DEB_ERROR, "InitHKeyCurrentUserSupport failed to init its lock, error = 0x%08X\n", Status)); return FALSE; } g_ulHKCURef = 0; return TRUE; } VOID CleanupHKeyCurrentUserSupport( ) { RtlDeleteCriticalSection( &g_csHKCU ); } /***************************************************************************\ * OpenHKeyCurrentUser * * Opens HKeyCurrentUser to point at the current logged on user's profile. * * Returns TRUE on success, FALSE on failure * * History: * 06-16-92 Davidc Created * \***************************************************************************/ BOOL OpenHKeyCurrentUser( PGLOBALS pGlobals ) { HANDLE ImpersonationHandle; BOOL Result; NTSTATUS Status ; // // Get in the correct context before we reference the registry // ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL); if (ImpersonationHandle == NULL) { DebugLog((DEB_ERROR, "OpenHKeyCurrentUser failed to impersonate user")); return(FALSE); } RtlEnterCriticalSection( &g_csHKCU ); if (g_ulHKCURef == 0) { Status = RtlOpenCurrentUser( MAXIMUM_ALLOWED, &pGlobals->UserProcessData.hCurrentUser ); } g_ulHKCURef++; RtlLeaveCriticalSection( &g_csHKCU ); // // Return to our own context // Result = StopImpersonating(ImpersonationHandle); ASSERT(Result); return(TRUE); } /***************************************************************************\ * CloseHKeyCurrentUser * * Closes HKEY_CURRENT_USER. * Any registry reference will automatically re-open it, so this is * only a token gesture - but it allows the registry hive to be unloaded. * * Returns nothing * * History: * 06-16-92 Davidc Created * \***************************************************************************/ VOID CloseHKeyCurrentUser( PGLOBALS pGlobals ) { RtlEnterCriticalSection( &g_csHKCU ); if (g_ulHKCURef > 0) { if (--g_ulHKCURef == 0) { NtClose( pGlobals->UserProcessData.hCurrentUser ); pGlobals->UserProcessData.hCurrentUser = NULL ; } } RtlLeaveCriticalSection( &g_csHKCU ); } /***************************************************************************\ * SetUserEnvironmentVariable * * * History: * 2-28-92 Johannec Created * \***************************************************************************/ BOOL SetUserEnvironmentVariable( PVOID *pEnv, LPTSTR lpVariable, LPTSTR lpValue, BOOL bOverwrite ) { NTSTATUS Status; UNICODE_STRING Name, Value; DWORD cb; TCHAR szValue[1024]; if (!*pEnv || !lpVariable || !*lpVariable) { return(FALSE); } RtlInitUnicodeString(&Name, lpVariable); cb = 1024; Value.Buffer = Alloc(sizeof(TCHAR)*cb); if (Value.Buffer) { Value.Length = (USHORT)cb; Value.MaximumLength = (USHORT)cb; Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value); Free(Value.Buffer); if ( NT_SUCCESS(Status) && !bOverwrite) { return(TRUE); } } if (lpValue && *lpValue) { // // Special case TEMP and TMP and shorten the path names // if ((!lstrcmpi(lpVariable, TEXT("TEMP"))) || (!lstrcmpi(lpVariable, TEXT("TMP")))) { if (!GetShortPathName (lpValue, szValue, 1024)) { lstrcpyn (szValue, lpValue, 1024); } } else { lstrcpyn (szValue, lpValue, 1024); } RtlInitUnicodeString(&Value, szValue); Status = RtlSetEnvironmentVariable(pEnv, &Name, &Value); } else { Status = RtlSetEnvironmentVariable(pEnv, &Name, NULL); } if (NT_SUCCESS(Status)) { return(TRUE); } return(FALSE); } /***************************************************************************\ * ExpandUserEnvironmentStrings * * 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; 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 ); } } /***************************************************************************\ * BuildEnvironmentPath * * * History: * 2-28-92 Johannec Created * \***************************************************************************/ BOOL BuildEnvironmentPath(PVOID *pEnv, LPTSTR lpPathVariable, LPTSTR lpPathValue) { NTSTATUS Status; UNICODE_STRING Name; UNICODE_STRING Value; TCHAR lpTemp[1025]; DWORD cb; if (!*pEnv) { return(FALSE); } RtlInitUnicodeString(&Name, lpPathVariable); cb = 1024; Value.Buffer = Alloc(sizeof(TCHAR)*cb); if (!Value.Buffer) { return(FALSE); } Value.Length = (USHORT)(sizeof(TCHAR) * cb); Value.MaximumLength = (USHORT)(sizeof(TCHAR) * cb); Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value); if (!NT_SUCCESS(Status)) { Free(Value.Buffer); Value.Length = 0; *lpTemp = 0; } if (Value.Length) { lstrcpy(lpTemp, Value.Buffer); if ( *( lpTemp + lstrlen(lpTemp) - 1) != TEXT(';') ) { lstrcat(lpTemp, TEXT(";")); } Free(Value.Buffer); } if (lpPathValue && ((lstrlen(lpTemp) + lstrlen(lpPathValue) + 1) < (INT)cb)) { lstrcat(lpTemp, lpPathValue); RtlInitUnicodeString(&Value, lpTemp); Status = RtlSetEnvironmentVariable(pEnv, &Name, &Value); } if (NT_SUCCESS(Status)) { return(TRUE); } return(FALSE); } /***************************************************************************\ * 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( PGLOBALS pGlobals, LPTSTR pEnvVarSubkey, PVOID *pEnv ) { TCHAR lpValueName[MAX_PATH]; PWCH lpDataBuffer; DWORD cbDataBuffer; PWCH lpData; LPTSTR lpExpandedValue = NULL; DWORD cbValueName = MAX_PATH; DWORD cbData; DWORD dwType; DWORD dwIndex = 0; HKEY hkey; BOOL bResult; /* * Open registry key to access USER environment variables. */ if (!OpenHKeyCurrentUser(pGlobals)) { DebugLog((DEB_ERROR, "SetEnvironmentVariables: Failed to open HKeyCurrentUser")); return(FALSE); } if (RegOpenKeyEx(pGlobals->UserProcessData.hCurrentUser, pEnvVarSubkey, 0, KEY_READ, &hkey)) { CloseHKeyCurrentUser(pGlobals); return(FALSE); } cbDataBuffer = 4096; lpDataBuffer = Alloc(sizeof(TCHAR)*cbDataBuffer); if (lpDataBuffer == NULL) { DebugLog((DEB_ERROR, "SetEnvironmentVariables: Failed to allocate %d bytes", cbDataBuffer)); CloseHKeyCurrentUser(pGlobals); RegCloseKey(hkey); return(FALSE); } lpData = lpDataBuffer; cbData = sizeof(TCHAR)*cbDataBuffer; bResult = TRUE; while (!RegEnumValue(hkey, dwIndex, lpValueName, &cbValueName, 0, &dwType, (LPBYTE)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, lpData); } else { // // the other environment variables are just set. // SetUserEnvironmentVariable(pEnv, lpValueName, lpData, TRUE); } } } dwIndex++; cbData = cbDataBuffer; cbValueName = MAX_PATH; } dwIndex = 0; cbData = cbDataBuffer; cbValueName = MAX_PATH; while (!RegEnumValue(hkey, dwIndex, lpValueName, &cbValueName, 0, &dwType, (LPBYTE)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 = Alloc(sizeof(TCHAR)*cb); if (lpExpandedValue) { cbNeeded = ExpandUserEnvironmentStrings(*pEnv, lpData, lpExpandedValue, cb); if (cbNeeded > cb) { Free(lpExpandedValue); cb = cbNeeded; lpExpandedValue = Alloc(sizeof(TCHAR)*cb); if (lpExpandedValue) { ExpandUserEnvironmentStrings(*pEnv, 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, lpExpandedValue); } else { // // the other environment variables are just set. // SetUserEnvironmentVariable(pEnv, lpValueName, lpExpandedValue, TRUE); } Free(lpExpandedValue); } } dwIndex++; cbData = cbDataBuffer; cbValueName = MAX_PATH; } Free(lpDataBuffer); RegCloseKey(hkey); CloseHKeyCurrentUser(pGlobals); return(bResult); } /***************************************************************************\ * IsUNCPath * * History: * 2-28-92 Johannec Created * \***************************************************************************/ BOOL IsUNCPath(LPTSTR lpPath) { if (lpPath[0] == BSLASH && lpPath[1] == BSLASH) { return(TRUE); } return(FALSE); } /***************************************************************************\ * SetHomeDirectoryEnvVars * * History: * 2-28-92 Johannec Created * \***************************************************************************/ BOOL SetHomeDirectoryEnvVars( PVOID *pEnv, LPTSTR lpHomeDirectory, LPTSTR lpHomeDrive, LPTSTR lpHomeShare, LPTSTR lpHomePath, BOOL * pfDeepShare ) { TCHAR cTmp; LPTSTR lpHomeTmp; BOOL bFoundFirstBSlash = FALSE; if (!*lpHomeDirectory) { return(FALSE); } *pfDeepShare = FALSE; if (IsUNCPath(lpHomeDirectory)) { lpHomeTmp = lpHomeDirectory + 2; while (*lpHomeTmp) { if (*lpHomeTmp == BSLASH) { if (bFoundFirstBSlash) { break; } bFoundFirstBSlash = TRUE; } lpHomeTmp++; } if (*lpHomeTmp) { lstrcpy(lpHomePath, lpHomeTmp); *pfDeepShare = TRUE; } else { *lpHomePath = BSLASH; *(lpHomePath+1) = 0; } cTmp = *lpHomeTmp; *lpHomeTmp = (TCHAR)0; lstrcpy(lpHomeShare, lpHomeDirectory); *lpHomeTmp = cTmp; // // If no home drive specified, than default to z: // if (!*lpHomeDrive) { lstrcpy(lpHomeDrive, TEXT("Z:")); } } else { // local home directory *lpHomeShare = 0; // no home share cTmp = lpHomeDirectory[2]; lpHomeDirectory[2] = (TCHAR)0; lstrcpy(lpHomeDrive, lpHomeDirectory); lpHomeDirectory[2] = cTmp; lstrcpy(lpHomePath, lpHomeDirectory + 2); } SetUserEnvironmentVariable(pEnv, HOMEDRIVE_VARIABLE, lpHomeDrive, TRUE); SetUserEnvironmentVariable(pEnv, HOMESHARE_VARIABLE, lpHomeShare, TRUE); SetUserEnvironmentVariable(pEnv, HOMEPATH_VARIABLE, lpHomePath, TRUE); return TRUE; } /***************************************************************************\ * UpdateHomeVarsInVolatileEnv * * Sets the HOMEDRIVE, HOMEPATH and HOMESHARE variables in the user's home * volatile environment so that SHGetFolderPath is able to expand these * variables * * History: * 6-5-2000 RahulTh Created * \***************************************************************************/ VOID UpdateHomeVarsInVolatileEnv ( PGLOBALS pGlobals, LPTSTR lpHomeDrive, LPTSTR lpHomeShare, LPTSTR lpHomePath ) { BOOL bOpenedHKCU; HANDLE ImpersonationHandle = NULL; HKEY hUserVolatileEnv = NULL; LONG lResult; bOpenedHKCU = OpenHKeyCurrentUser (pGlobals); ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL); if (ImpersonationHandle != NULL) { // // See the registry value to see whether we should really try to map // the whole directory or just map to the root.. // if ((pGlobals->UserProcessData).hCurrentUser) { lResult = RegOpenKeyEx((pGlobals->UserProcessData).hCurrentUser, L"Volatile Environment", 0, KEY_READ | KEY_WRITE, &hUserVolatileEnv); if (lResult == ERROR_SUCCESS) { RegSetValueEx (hUserVolatileEnv, HOMEDRIVE_VARIABLE, 0, REG_SZ, (LPBYTE) lpHomeDrive, (lstrlen (lpHomeDrive) + 1) * sizeof (TCHAR)); RegSetValueEx (hUserVolatileEnv, HOMESHARE_VARIABLE, 0, REG_SZ, (LPBYTE) lpHomeShare, (lstrlen (lpHomeShare) + 1) * sizeof (TCHAR)); RegSetValueEx (hUserVolatileEnv, HOMEPATH_VARIABLE, 0, REG_SZ, (LPBYTE) lpHomePath, (lstrlen (lpHomePath) + 1) * sizeof (TCHAR)); RegCloseKey(hUserVolatileEnv); } } // // Revert to being 'ourself' // if (!StopImpersonating(ImpersonationHandle)) { DebugLog((DEB_ERROR, "UpdateHomeVarsInVolatileEnv : Failed to revert to self")); } // // Set it to NULL // ImpersonationHandle = NULL; } else { DebugLog((DEB_ERROR, "UpdateHomeVarsInVolatileEnv : Failed to impersonate user")); } if (bOpenedHKCU) CloseHKeyCurrentUser (pGlobals); } /***************************************************************************\ * ChangeToHomeDirectory * * Sets the current directory to the user's home directory. If this fails * tries to set to the directory in the following order: * 1. home directory * 2. c:\users\default * 3. c:\users * 4. \ (root) * 5. leaves directory as is i.e. the present current directory * * History: * 2-28-92 Johannec Created * \***************************************************************************/ VOID ChangeToHomeDirectory( PGLOBALS pGlobals, PVOID *pEnv, LPTSTR lpHomeDir, LPTSTR lpHomeDrive, LPTSTR lpHomeShare, LPTSTR lpHomePath, LPTSTR lpOldDir, BOOL DeepShare ) { TCHAR lpCurDrive[4]; BOOL bNoHomeDir = FALSE; BOOL bTSHomeDir = FALSE; HANDLE ImpersonationHandle = NULL; DWORD error = ERROR_SUCCESS, dwSize, dwType; HKEY hUserPolicy=NULL; DWORD dwConnectHomeDirToRoot; LONG lResult; if (GetCurrentDirectory(MAX_PATH, lpOldDir)) { lpCurDrive[0] = lpOldDir[0]; lpCurDrive[1] = lpOldDir[1]; lpCurDrive[2] = (TCHAR)0; } else lpCurDrive[0] = (TCHAR)0; if (!*lpHomeDir) { bNoHomeDir = TRUE; DefaultDirectory: if (!bNoHomeDir) { #if 0 ReportWinlogonEvent(pGlobals, EVENTLOG_ERROR_TYPE, EVENT_SET_HOME_DIRECTORY_FAILED, sizeof(error), &error, 1, lpHomeDir); #endif } lstrcpy(lpHomeDir, lpCurDrive); if (g_IsTerminalServer) { TCHAR szProfileDir[MAX_PATH]; DWORD cbufSize = MAX_PATH; if ( GetUserProfileDirectory(pGlobals->UserProcessData.UserToken, szProfileDir, &cbufSize) && SetCurrentDirectory(szProfileDir) ) { lstrcpy(lpHomeDir, szProfileDir); bTSHomeDir = TRUE; } else { error = GetLastError(); DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to GetUserProfileDirectory '%ws', error = %d\n", lpHomeDir, error)); lstrcpy(lpHomeDir, NULL_STRING); } } if (!bTSHomeDir) { #if 0 if (SetCurrentDirectory(USERS_DEFAULT_DIRECTORY)) { lstrcat(lpHomeDir, USERS_DEFAULT_DIRECTORY); } else if (SetCurrentDirectory(USERS_DIRECTORY)) { lstrcat(lpHomeDir, USERS_DIRECTORY); } else #endif if (SetCurrentDirectory(ROOT_DIRECTORY)) { lstrcat(lpHomeDir, ROOT_DIRECTORY); } else { lstrcpy(lpHomeDir, NULL_STRING); } } if (bNoHomeDir || bTSHomeDir) { // Update the homedrive variable to reflect the correct value lstrcpy (lpHomeDrive, lpCurDrive); SetUserEnvironmentVariable(pEnv, HOMEDRIVE_VARIABLE, lpCurDrive, TRUE); *lpHomeShare = 0; // null string SetUserEnvironmentVariable(pEnv, HOMESHARE_VARIABLE, lpHomeShare, TRUE); if (*lpHomeDir) { lpHomeDir += 2; } // Update the homepath variable to reflect the correct value lstrcpy (lpHomePath, lpHomeDir); SetUserEnvironmentVariable(pEnv, HOMEPATH_VARIABLE, lpHomeDir, TRUE); } goto UpdateHomeVars; } /* * Test if homedir is a local directory.'?:\foo\bar' */ if (IsUNCPath(lpHomeDir)) { NETRESOURCE NetResource; BOOL bOpenedHKCU; /* * lpHomeDir is a UNC path, use lpHomedrive. */ // // First, try the (possibly) deep path: // ZeroMemory( &NetResource, sizeof( NetResource ) ); NetResource.lpLocalName = lpHomeDrive; NetResource.lpRemoteName = lpHomeDir; NetResource.lpProvider = NULL; NetResource.dwType = RESOURCETYPE_DISK; dwConnectHomeDirToRoot = 0; // default bOpenedHKCU = OpenHKeyCurrentUser(pGlobals); // // Impersonate the user // ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL); if (ImpersonationHandle != NULL) { // // See the registry value to see whether we should really try to map // the whole directory or just map to the root.. // if ((pGlobals->UserProcessData).hCurrentUser) { lResult = RegOpenKeyEx((pGlobals->UserProcessData).hCurrentUser, WINLOGON_POLICY_KEY, 0, KEY_READ, &hUserPolicy); if (lResult == ERROR_SUCCESS) { dwSize = sizeof(DWORD); RegQueryValueEx (hUserPolicy, TEXT("ConnectHomeDirToRoot"), NULL, &dwType, (LPBYTE) &dwConnectHomeDirToRoot, &dwSize); RegCloseKey(hUserPolicy); } } // // Revert to being 'ourself' // if (!StopImpersonating(ImpersonationHandle)) { DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to revert to self")); } // // Set it to NULL // ImpersonationHandle = NULL; } else { DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to impersonate user")); } if (bOpenedHKCU) CloseHKeyCurrentUser(pGlobals); if (!dwConnectHomeDirToRoot) { error = AddNetworkConnection( pGlobals, &NetResource ); if (error == ERROR_SUCCESS) { // // (possibly) deep path worked! // if ( DeepShare ) { // // Set homepath to just "\" // lstrcpy( lpHomePath, TEXT("\\") ); // Also update the value of homeshare to reflect the correct value lstrcpy (lpHomeShare, lpHomeDir); SetUserEnvironmentVariable(pEnv, HOMESHARE_VARIABLE, lpHomeShare, TRUE); SetUserEnvironmentVariable(pEnv, HOMEPATH_VARIABLE, lpHomePath, TRUE); } } else { dwConnectHomeDirToRoot = TRUE; } } if (dwConnectHomeDirToRoot) { NetResource.lpLocalName = lpHomeDrive; NetResource.lpRemoteName = lpHomeShare; NetResource.lpProvider = NULL; NetResource.dwType = RESOURCETYPE_DISK; error = AddNetworkConnection( pGlobals, &NetResource ); if ( error ) { goto DefaultDirectory; } } lstrcpy(lpHomeDir, lpHomeDrive); if ( lpHomePath && (*lpHomePath != TEXT('\\'))) { lstrcat(lpHomeDir, TEXT("\\")); } lstrcat(lpHomeDir, lpHomePath); // // Impersonate the user // ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL); if (ImpersonationHandle == NULL) { DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to impersonate user")); } if (!SetCurrentDirectory(lpHomeDir)) { error = GetLastError(); DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to SetCurrentDirectory '%ws', error = %d\n", lpHomeDir, error)); // // Revert to being 'ourself' // if (ImpersonationHandle && !StopImpersonating(ImpersonationHandle)) { DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to revert to self")); } goto DefaultDirectory; } } else { /* * lpHomeDir is a local path or absolute local path. */ // // Impersonate the user // ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL); if (ImpersonationHandle == NULL) { DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to impersonate user")); } if (!SetCurrentDirectory(lpHomeDir)) { error = GetLastError(); DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to SetCurrentDirectory '%ws', error = %d", lpHomeDir, error)); // // Revert to being 'ourself' // if (ImpersonationHandle && !StopImpersonating(ImpersonationHandle)) { DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to revert to self")); } goto DefaultDirectory; } } // // Revert to being 'ourself' // if (ImpersonationHandle && !StopImpersonating(ImpersonationHandle)) { DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to revert to self")); } UpdateHomeVars: // // Update the value of the home variables in the volatile environment // so that SHGetFolderPath expands these variables correctly // UpdateHomeVarsInVolatileEnv (pGlobals, lpHomeDrive, lpHomeShare, lpHomePath); return; } /***************************************************************************\ * ProcessAutoexec * * History: * 01-24-92 Johannec Created. * \***************************************************************************/ BOOL ProcessAutoexec( PVOID *pEnv, LPTSTR lpPathVariable ) { 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"); #ifdef _X86_ TCHAR szTemp[3]; #endif UINT uiErrMode; uiErrMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); #ifdef _X86_ if (IsNEC_98) { if (GetEnvironmentVariable (TEXT("SystemDrive"), szTemp, 3)) { szAutoExecBat[0] = szTemp[0]; } } #endif 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 = Alloc(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)) { STRING String; UNICODE_STRING UniString; RtlInitString(&String, (LPSTR)token); RtlAnsiStringToUnicodeString(&UniString, &String, TRUE); ProcessCommand(UniString.Buffer, pEnv); //ProcessCommand(token, pEnv); RtlFreeUnicodeString(&UniString); } if (!_strnicmp(token, "SET", 3)) { STRING String; UNICODE_STRING UniString; RtlInitString(&String, (LPSTR)token); RtlAnsiStringToUnicodeString(&UniString, &String, TRUE); ProcessSetCommand(UniString.Buffer, pEnv); //ProcessSetCommand(token, pEnv); RtlFreeUnicodeString(&UniString); } token = strtok(NULL, Seps); } Exit: CloseHandle(fh); if (lpBuffer) { Free(lpBuffer); } if (!Status) { DebugLog((DEB_ERROR, "Cannot process autoexec.bat.")); } return(Status); } /***************************************************************************\ * ProcessCommand * * History: * 01-24-92 Johannec Created. * \***************************************************************************/ BOOL ProcessCommand(LPTSTR lpStart, PVOID *pEnv) { LPTSTR lpt, lptt; LPTSTR lpVariable; LPTSTR lpValue; LPTSTR lpExpandedValue = NULL; TCHAR c; DWORD cb, cbNeeded; // // Find environment variable. // for (lpt = lpStart; *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 = Alloc(sizeof(TCHAR)*(lstrlen(lptt) + 1)); 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) { SetUserEnvironmentVariable(pEnv, AUTOEXECPATH_VARIABLE, TEXT(""), TRUE); } else { SetUserEnvironmentVariable(pEnv, lpVariable, TEXT(""), TRUE); } Free(lpVariable); return(FALSE); } lptt = lpt; for (; *lpt; lpt++) //find end of varaible value ; c = *lpt; *lpt = 0; lpValue = Alloc(sizeof(TCHAR)*(lstrlen(lptt) + 1)); if (!lpValue) { Free(lpVariable); return(FALSE); } lstrcpy(lpValue, lptt); *lpt = c; #ifdef _X86_ // NEC98 // // If the path includes removable drive, // it is assumed that the drive assignment has changed from DOS. // if (IsNEC_98 && (lstrcmpi(lpVariable, PATH_VARIABLE) == 0) && IsPathIncludeRemovable(lpValue)) { LocalFree(lpVariable); LocalFree(lpValue); return(FALSE); } #endif cb = 1024; lpExpandedValue = Alloc(sizeof(TCHAR)*cb); if (lpExpandedValue) { if (!lstrcmpi(lpVariable, PATH_VARIABLE)) { lpValue = ProcessAutoexecPath(pEnv, lpValue, lstrlen(lpValue)+1); } cbNeeded = ExpandUserEnvironmentStrings(*pEnv, lpValue, lpExpandedValue, cb); if (cbNeeded > cb) { Free(lpExpandedValue); cb = cbNeeded; lpExpandedValue = Alloc(sizeof(TCHAR)*cb); if (lpExpandedValue) { ExpandUserEnvironmentStrings(*pEnv, lpValue, lpExpandedValue, cb); } } } if (!lpExpandedValue) { lpExpandedValue = lpValue; } if (lstrcmpi(lpVariable, PATH_VARIABLE)) { SetUserEnvironmentVariable(pEnv, lpVariable, lpExpandedValue, FALSE); } else { SetUserEnvironmentVariable(pEnv, AUTOEXECPATH_VARIABLE, lpExpandedValue, TRUE); } if (lpExpandedValue != lpValue) { Free(lpExpandedValue); } Free(lpVariable); Free(lpValue); return(TRUE); } /***************************************************************************\ * ProcessSetCommand * * History: * 01-24-92 Johannec Created. * \***************************************************************************/ BOOL ProcessSetCommand(LPTSTR lpStart, PVOID *pEnv) { LPTSTR lpt; // // Find environment variable. // for (lpt = lpStart; *lpt && *lpt != TEXT(' '); lpt++) ; if (!*lpt || !_wcsnicmp(lpt,TEXT("COMSPEC"), 7)) return(FALSE); return (ProcessCommand(lpt, pEnv)); } /***************************************************************************\ * 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 = Alloc(sizeof(TCHAR)*cbt); if (!lpt) { return(lpValue); } *lpt = 0; lpStart = lpValue; RtlInitUnicodeString(&Name, AUTOEXECPATH_VARIABLE); Value.Buffer = Alloc(sizeof(TCHAR)*cbt); if (!Value.Buffer) { goto Fail; } while (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; } } Free(lpStart); Free(Value.Buffer); return(lpt); Fail: if ( Value.Buffer ) { Free(Value.Buffer); } Free(lpt); return(lpStart); } /***************************************************************************\ * 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; TCHAR AutoexecPathValue[1024]; DWORD cb; BOOL Success; if (!*pEnv) { return(FALSE); } RtlInitUnicodeString(&Name, lpAutoexecPath); cb = 1024; Value.Buffer = Alloc(sizeof(TCHAR)*cb); if (!Value.Buffer) { return(FALSE); } Value.Length = (USHORT)cb; Value.MaximumLength = (USHORT)cb; Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value); if (!NT_SUCCESS(Status)) { Free(Value.Buffer); return(FALSE); } if (Value.Length) { lstrcpy(AutoexecPathValue, Value.Buffer); } Free(Value.Buffer); Success = BuildEnvironmentPath(pEnv, lpPathVariable, AutoexecPathValue); RtlSetEnvironmentVariable(pEnv, &Name, NULL); return(Success); } /***************************************************************************\ * AddNetworkConnection * * calls WNetAddConnection in the user's context. * * History: * 6-26-92 Johannec Created * \***************************************************************************/ LONG AddNetworkConnection(PGLOBALS pGlobals, LPNETRESOURCE lpNetResource) { HANDLE ImpersonationHandle; TCHAR szMprDll[] = TEXT("mpr.dll"); CHAR szWNetAddConn[] = "WNetAddConnection2W"; CHAR szWNetCancelConn[] = "WNetCancelConnection2W"; DWORD (APIENTRY *lpfnWNetAddConn)(LPNETRESOURCE, LPTSTR, LPTSTR, DWORD); DWORD (APIENTRY *lpfnWNetCancelConn)(LPCTSTR, DWORD, BOOL); DWORD WNetResult; // // Impersonate the user // ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL); if (ImpersonationHandle == NULL) { DebugLog((DEB_ERROR, "AddNetworkConnection : Failed to impersonate user")); return(ERROR_ACCESS_DENIED); } // // Call the add connection api in the users context // if (!pGlobals->hMPR) { // wasn't loaded, try to load it now. pGlobals->hMPR = LoadLibrary(szMprDll); } if (pGlobals->hMPR) { if (lpfnWNetAddConn = (DWORD (APIENTRY *)(LPNETRESOURCE, LPTSTR, LPTSTR, DWORD)) GetProcAddress(pGlobals->hMPR, (LPSTR)szWNetAddConn)) { WNetResult = (*lpfnWNetAddConn)(lpNetResource, NULL, NULL, 0); // // When LUID DosDevices are disabled, // console users share the same DosDevices // With LUID DosDevices enabled, // users each get their own DosDevices // if ( (WNetResult == ERROR_ALREADY_ASSIGNED) || (WNetResult == ERROR_DEVICE_ALREADY_REMEMBERED) ) { // Drive is already assigned -- undo it and retry. This is to prevent a // user from subst-ing a drive to another user's home drive so the other // user's home drive points somewhere inappropriate on next logon. if (lpfnWNetCancelConn = (DWORD (APIENTRY *)(LPCTSTR, DWORD, BOOL)) GetProcAddress(pGlobals->hMPR, (LPSTR)szWNetCancelConn)) { WNetResult = lpfnWNetCancelConn(lpNetResource->lpLocalName, 0, TRUE); } if ( (WNetResult != NO_ERROR) && (WNetResult == ERROR_ALREADY_ASSIGNED) && (GetLUIDDeviceMapsEnabled() == FALSE) ) { // WNet didn't work -- try DefineDosDevice (as the user) // to undo any drive substitutions that aren't background // admin-level symlinks DefineDosDevice(DDD_REMOVE_DEFINITION, lpNetResource->lpLocalName, NULL); } // Retry the connection WNetResult = (*lpfnWNetAddConn)(lpNetResource, NULL, NULL, 0); } if (WNetResult != ERROR_SUCCESS) { DebugLog((DEB_ERROR, "WNetAddConnection2W to %ws failed, error = %d\n", lpNetResource->lpRemoteName, WNetResult)); FreeLibrary(pGlobals->hMPR); pGlobals->hMPR = NULL; SetLastError( WNetResult ); } if (!StopImpersonating(ImpersonationHandle)) { DebugLog((DEB_ERROR, "AddNetworkConnection : Failed to revert to self")); } return( WNetResult ); } else { DebugLog((DEB_ERROR, "Failed to get address of WNetAddConnection2W from mpr.dll")); } } else { DebugLog((DEB_ERROR, "Winlogon failed to load mpr.dll for add connection")); } // // Unload mpr.dll. Keeping it open messes up Novell and Banyan. // if ( pGlobals->hMPR ) { FreeLibrary(pGlobals->hMPR); pGlobals->hMPR = NULL; } // // Revert to being 'ourself' // if (!StopImpersonating(ImpersonationHandle)) { DebugLog((DEB_ERROR, "AddNetworkConnection : Failed to revert to self")); } // // This is the failure return. return( GetLastError() ); } #ifdef _X86_ BOOL IsPathIncludeRemovable(LPTSTR lpValue) { LPTSTR lpt, tmp; BOOL ret = FALSE; WCHAR c; tmp = LocalAlloc(LPTR, (lstrlen(lpValue) + 1) * sizeof(WCHAR)); if (!tmp) DebugLog((DEB_ERROR, "IsPathIncludeRemovable : Failed to LocalAlloc (%d)", GetLastError())); else { lstrcpy(tmp, lpValue); lpt = tmp; while (*lpt) { // skip spaces for ( ; *lpt && *lpt == TEXT(' '); lpt++) ; // check if the drive is removable if (lpt[0] && lpt[1] && lpt[1] == TEXT(':') && lpt[2]) { // ex) "A:\" c = lpt[3]; lpt[3] = 0; if (GetDriveType(lpt) == DRIVE_REMOVABLE) { lpt[3] = c; ret = TRUE; break; } lpt[3] = c; } // skip to the next path for ( ; *lpt && *lpt != TEXT(';'); lpt++) ; if (*lpt) lpt++; } LocalFree(tmp); } return(ret); } #endif /***************************************************************************\ * GetLUIDDeviceMapsEnabled * * This function calls NtQueryInformationProcess() to determine if * LUID device maps are enabled * * Return Value: * * TRUE - LUID device maps are enabled * * FALSE - LUID device maps are disabled * \***************************************************************************/ BOOL GetLUIDDeviceMapsEnabled( VOID ) { ULONG LUIDDeviceMapsEnabled; NTSTATUS Status; // // Check if LUID Device Maps are enabled // Status = NtQueryInformationProcess( NtCurrentProcess(), ProcessLUIDDeviceMapsEnabled, &LUIDDeviceMapsEnabled, sizeof(LUIDDeviceMapsEnabled), NULL ); if (!NT_SUCCESS( Status )) { return( FALSE ); } else { return (LUIDDeviceMapsEnabled != 0); } }