windows-nt/Source/XPSP1/NT/ds/security/gina/msgina/envvar.c
2020-09-26 16:20:57 +08:00

1662 lines
43 KiB
C

/****************************** 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);
}
}