Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2850 lines
84 KiB

// Shell.cpp : This file contains the
// Created: Feb '98
// Author : a-rakeba
// History:
// Copyright (C) 1998 Microsoft Corporation
// All rights reserved.
// Microsoft Confidential
extern "C"
{
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntsam.h>
}
#include <cmnhdr.h>
#include <Windows.h>
#include <LmAccess.h>
#include <LmApiBuf.h>
#include <LmErr.h>
#include <LmWkSta.h>
#include <WinBase.h>
#include <IpTypes.h>
#include <shfolder.h>
#include <Debug.h>
#include <MsgFile.h>
#include <TlntUtils.h>
#include <Shell.h>
#include <LibFuncs.h>
#include <KillApps.h>
#include <Session.h>
#include <Telnetd.h>
#include <wincrypt.h>
#include <sddl.h>
#pragma warning(disable:4706)
#pragma warning(disable: 4127)
using namespace _Utils;
using CDebugLevel::TRACE_DEBUGGING;
using CDebugLevel::TRACE_HANDLE;
using CDebugLevel::TRACE_SOCKET;
extern HANDLE g_hSyncCloseHandle;
extern HCRYPTPROV g_hProv;
LPWSTR wideHomeDir = NULL;
BOOL create_desktop_for_this_session(
HANDLE client_token,
LPTSTR *desktop_name
)
{
#define NO_OF_SIDS 4
BOOL success = FALSE;
DWORD win32error = NO_ERROR;
PSID administrators_sid = NULL,
client_sid = NULL,
local_system_sid = NULL,
network_service_sid = NULL,
local_service_sid = NULL;
PACL new_acl = NULL;
SECURITY_DESCRIPTOR sd = { 0 };
SECURITY_INFORMATION sec_i = DACL_SECURITY_INFORMATION;
BYTE client_sid_buffer[256] = { 0 };
HDESK desktop = NULL;
/*
We are going to set the following entries for the Desktop
1. System Full Control
2. Administrators FullControl
3. client FullControl
4. Localservice full control
//5. Network service full control
*/
{
SID_IDENTIFIER_AUTHORITY local_system_authority = SECURITY_NT_AUTHORITY;
if (! AllocateAndInitializeSid(
&local_system_authority,
2, /* there are only two sub-authorities */
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,0,0,0,0,0, /* Don't care about the rest */
&administrators_sid
))
{
goto CLEANUP_AND_GET_OUT;
}
if (! AllocateAndInitializeSid(
&local_system_authority,
1, /* there is only two sub-authority */
SECURITY_LOCAL_SYSTEM_RID,
0,0,0,0,0,0,0, /* Don't care about the rest */
&local_system_sid
))
{
goto CLEANUP_AND_GET_OUT;
}
#ifndef SECURITY_LOCAL_SERVICE_RID
#define SECURITY_LOCAL_SERVICE_RID (0x00000013L)
//#define SECURITY_NETWORK_SERVICE_RID (0x00000014L)
#endif
//Build LocalLocal sid
if ( ! AllocateAndInitializeSid(
&local_system_authority,
1, /* there is only two sub-authority */
SECURITY_LOCAL_SERVICE_RID,
0,0,0,0,0,0,0, /* Don't care about the rest */
&local_service_sid
) )
{
goto CLEANUP_AND_GET_OUT;
}
/*
//Build LocalSystem sid
if ( ! AllocateAndInitializeSid(
&local_system_authority,
1, /* there is only two sub-authority /
SECURITY_NETWORK_SERVICE_RID,
0,0,0,0,0,0,0, /* Don't care about the rest /
&network_service_sid
) )
{
goto CLEANUP_AND_GET_OUT;
}
*/
}
{
DWORD required = 0;
if (! GetTokenInformation(
client_token,
TokenUser,
(LPVOID)client_sid_buffer,
sizeof(client_sid_buffer),
&required
))
{
goto CLEANUP_AND_GET_OUT;
}
client_sid = ((TOKEN_USER *)client_sid_buffer)->User.Sid;
}
{
DWORD aclSize;
// Add Identical settings both for desktop and for windowstation
aclSize = sizeof(ACL) +
(NO_OF_SIDS * sizeof(ACCESS_ALLOWED_ACE)) +
GetLengthSid(administrators_sid) +
GetLengthSid(client_sid)+
GetLengthSid(local_system_sid) +
GetLengthSid(local_service_sid) -
//GetLengthSid(network_service_sid) -
(NO_OF_SIDS * sizeof(DWORD));
new_acl = (PACL) new BYTE[aclSize];
if (NULL == new_acl)
{
goto CLEANUP_AND_GET_OUT;
}
if (!InitializeAcl(new_acl, aclSize, ACL_REVISION))
{
goto CLEANUP_AND_GET_OUT;
}
}
if (!AddAccessAllowedAce(
new_acl,
ACL_REVISION,
GENERIC_ALL,
local_system_sid
))
{
goto CLEANUP_AND_GET_OUT;
}
if (!AddAccessAllowedAce(
new_acl,
ACL_REVISION,
GENERIC_ALL,
administrators_sid
))
{
goto CLEANUP_AND_GET_OUT;
}
if (!AddAccessAllowedAce(
new_acl,
ACL_REVISION,
GENERIC_ALL,
client_sid
))
{
goto CLEANUP_AND_GET_OUT;
}
if(!AddAccessAllowedAce(
new_acl,
ACL_REVISION,
GENERIC_ALL,
local_service_sid
))
{
goto CLEANUP_AND_GET_OUT;
}
/*
if(!AddAccessAllowedAce(
new_acl,
ACL_REVISION,
GENERIC_ALL,
network_service_sid
))
{
goto CLEANUP_AND_GET_OUT;
}
*/
if ( !InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION ) )
{
goto CLEANUP_AND_GET_OUT;
}
if ( !SetSecurityDescriptorDacl(&sd, TRUE, new_acl, FALSE) )
{
goto CLEANUP_AND_GET_OUT;
}
{
SECURITY_ATTRIBUTES sa = { 0 };
if(!ConvertSidToStringSid(client_sid,&(*desktop_name)))
{
*desktop_name = NULL;
goto CLEANUP_AND_GET_OUT;
}
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
desktop = CreateDesktop(
*desktop_name,
NULL,
NULL,
0,
MAXIMUM_ALLOWED,
&sa);
if (NULL == desktop)
{
goto CLEANUP_AND_GET_OUT;
}
SetThreadDesktop(desktop);
CloseDesktop(desktop);
success = TRUE;
}
CLEANUP_AND_GET_OUT:
if (! success)
{
win32error = GetLastError();
_TRACE(TRACE_DEBUGGING,L"Creation and setting of windowstation/desktop failed with %d",win32error);
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_ERROR_CREATE_DESKTOP_FAILURE, win32error);
if(*desktop_name)
{
LocalFree(*desktop_name);
*desktop_name = NULL;
}
if(desktop)
{
CloseDesktop(desktop);
}
}
if ( administrators_sid != NULL )
{
FreeSid (administrators_sid );
}
if ( local_system_sid!= NULL )
{
FreeSid (local_system_sid);
}
if( local_service_sid != NULL )
{
FreeSid (local_service_sid);
}
/*
if( network_service_sid != NULL )
{
FreeSid (network_service_sid );
}
*/
if (new_acl)
delete [] new_acl;
return( success );
#undef NO_OF_SIDS
}
VOID CleanupClientToken(
HANDLE token
)
{
TOKEN_PRIVILEGES *tp = NULL;
DWORD needed_length = 0;
// DbgUserBreakPoint();
// Currently, we find that all the privileges enabled in the token obtained via ntlm logon so
// Disable everything except SeChangeNotifyPrivilege
if (GetTokenInformation(
token,
TokenPrivileges,
NULL,
0,
&needed_length
))
{
// No way this can be a success, so just return
DbgPrint("TLNTSESS: How did GetTokenInformation succeed?\n");
return;
}
tp = (TOKEN_PRIVILEGES *)GlobalAlloc(GPTR, needed_length);
if (tp)
{
if (GetTokenInformation(
token,
TokenPrivileges,
tp,
needed_length,
&needed_length
))
{
DWORD x;
LUID change_notify = RtlConvertUlongToLuid(SE_CHANGE_NOTIFY_PRIVILEGE);
for (x = 0; x < tp->PrivilegeCount; x ++)
{
if ((! RtlEqualLuid(&(tp->Privileges[x].Luid), &change_notify)) &&
(tp->Privileges[x].Attributes & SE_PRIVILEGE_ENABLED)
)
{
tp->Privileges[x].Attributes &= ~(SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED);
}
}
if (! AdjustTokenPrivileges(
token,
FALSE, // Don't disable all
tp,
needed_length,
NULL, // Don't need the prior state & length
NULL
))
{
DbgPrint("TLNTSESS: AdjustTokenPrivileges failed with %u\n", GetLastError());
}
}
else
{
DbgPrint("TLNTSESS: GetTokInfo failed with %u\n", GetLastError());
}
GlobalFree(tp);
}
}
CShell::CShell()
{
m_pSession = NULL;
m_bIsLocalHost = false;
m_hCurrUserKey = NULL;
m_lpEnv = NULL;
m_hProcess = NULL;
m_hTempProcess = NULL;
hUserEnvLib = NULL;
pHomeDir = NULL;
pHomeDrive = NULL;
pLogonScriptPath = NULL;
pProfilePath = NULL;
pServerName = NULL;
m_pwszAppDataDir = NULL;
m_pucDataFromCmd = NULL;
m_dwDataSizeFromCmd =0;
m_hReadFromCmd = NULL;
m_hWriteByCmd = NULL;
}
void
CShell::FreeInitialVariables()
{
delete[] pHomeDir;
delete[] pHomeDrive;
delete[] pLogonScriptPath;
delete[] pProfilePath;
delete[] pServerName;
delete[] m_pwszAppDataDir;
pHomeDir = NULL;
pHomeDrive = NULL;
pLogonScriptPath = NULL;
pProfilePath = NULL;
pServerName = NULL;
m_pwszAppDataDir = NULL;
}
CShell::~CShell()
{
if( m_pSession->m_bNtVersionGTE5 )
{
//Free libraries
FreeLibrary( hUserEnvLib );
}
FreeInitialVariables();
if( m_pSession->CSession::m_bIsStreamMode )
{
delete[] m_pucDataFromCmd;
TELNET_CLOSE_HANDLE( m_oReadFromCmd.hEvent );
TELNET_CLOSE_HANDLE( m_hReadFromCmd );
TELNET_CLOSE_HANDLE( m_hWriteByCmd );
}
}
void
CShell::Init ( CSession *pSession )
{
_chASSERT( pSession != 0 );
m_pSession = pSession;
}
bool
CShell::StartUserSession ( )
{
LoadLibNGetProc( );
LoadTheProfile();
//
// If Japanese NT then we need to set the console fonts to TrueType
//
DWORD dwCodePage = GetACP();
if(dwCodePage == 932||dwCodePage == 936||dwCodePage == 949||dwCodePage == 950)
{
DoFESpecificProcessing();
}
if( !StartProcess( ) )
{
return ( FALSE );
}
m_pSession->AddHandleToWaitOn( m_hProcess );
if( m_pSession->CSession::m_bIsStreamMode )
{
m_pSession->CSession::AddHandleToWaitOn( m_oReadFromCmd.hEvent );
if( !IssueReadFromCmd() )
{
return( FALSE );
}
}
//Start the scraper
if( !m_pSession->CScraper::InitSession() )
{
return ( FALSE );
}
return ( TRUE );
}
bool
CShell::CreateIOHandles()
{
BOOL dwStatus = 0;
_chVERIFY2( dwStatus = FreeConsole() );
if( !dwStatus )
{
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, 0, GetLastError() );
}
_chVERIFY2( dwStatus = AllocConsole() );
if( !dwStatus )
{
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, 0, GetLastError() );
}
//Fix for HANDLE LEAK
TELNET_CLOSE_HANDLE(m_pSession->CScraper::m_hConBufIn);
TELNET_CLOSE_HANDLE(m_pSession->CScraper::m_hConBufOut);
SECURITY_ATTRIBUTES sa;
INHERITABLE_NULL_DESCRIPTOR_ATTRIBUTE( sa );
_chVERIFY2( ( m_pSession->CScraper::m_hConBufIn =
CreateFileA( "CONIN$", GENERIC_READ | GENERIC_WRITE ,
0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) !=
INVALID_HANDLE_VALUE );
if( INVALID_HANDLE_VALUE == m_pSession->CScraper::m_hConBufIn)
{
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERRCONSOLE, GetLastError() );
goto ExitOnError;
}
_chVERIFY2( ( m_pSession->CScraper::m_hConBufOut =
CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) !=
INVALID_HANDLE_VALUE );
if( INVALID_HANDLE_VALUE == m_pSession->CScraper::m_hConBufOut )
{
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERRCONSOLE, GetLastError() );
goto ExitOnError;
}
return (TRUE);
ExitOnError :
TELNET_CLOSE_HANDLE(m_pSession->CScraper::m_hConBufIn);
TELNET_CLOSE_HANDLE(m_pSession->CScraper::m_hConBufOut);
return( FALSE );
}
void
CShell::DoFESpecificProcessing()
{
UCHAR InfoBuffer[ 1024 ];
DWORD cbInfoBuffer = 1024;
BOOL bSuccess = GetTokenInformation( m_pSession->CSession::m_hToken,
TokenUser, InfoBuffer, cbInfoBuffer, &cbInfoBuffer );
if(!bSuccess)
{
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
//
// Though we need to alloc buffer and try GetTokenInformation()
// again, actually it is highly unlikely; so we return false;
//
return;
}
else
{
_TRACE( TRACE_DEBUGGING, "Error: error getting token info");
return ;
}
}
CHAR szPathName[MAX_PATH] = { 0 };
LPSTR lpszKey = NULL;
DWORD dwFontSize = 0;
DWORD dwFaceNameSize = 0 ;
DWORD dwSize = 0;
DWORD dwVal = 54;
LPSTR szTextualSid = NULL; // allocated textual Sid
PSID_IDENTIFIER_AUTHORITY psia;
DWORD dwSubAuthorities;
DWORD dwCounter;
DWORD dwSidSize;
DWORD dwCodePage = GetACP();
LONG lRet=-1;
/*++
To support CHS, CHT, KOR alongwith JPN, we need to change the FaceName Value
to the True Type font for that particular language.
Copying the string directly into the variable doesn't work.
It copies high order ASCII characters in the string instead of the DBCS characters.
So we need to set the UNICODE byte values corresponding to the
DBCS characters for the TT Font Names.
These TT fonts are the ones which are present in Cmd.exe-Properties-Font.
For US locale, the TT font is Lucida Console.
But we don't need to set it on US locale. Raster Font works fine there.
For FE languages, the TT fonts need to be set.
--*/
const TCHAR szJAPFaceName[] = { 0xFF2D ,0xFF33 ,L' ' ,0x30B4 ,0x30B7 ,0x30C3 ,0x30AF ,L'\0' };
const TCHAR szCHTFaceName[] = { 0x7D30 ,0x660E ,0x9AD4 ,L'\0'};
const TCHAR szKORFaceName[] = { 0xAD74 ,0xB9BC ,0xCCB4 ,L'\0'};
const TCHAR szCHSFaceName[] = { 0x65B0 ,0x5B8B ,0x4F53 ,L'\0' };
TCHAR szFaceNameDef[MAX_STRING_LENGTH];
switch (dwCodePage)
{
case JAP_CODEPAGE:
_tcscpy(szFaceNameDef, szJAPFaceName); //On JAP, set the FaceName to "MS Gothic"
dwFontSize = JAP_FONTSIZE;
break;
case CHT_CODEPAGE:
_tcscpy(szFaceNameDef, szCHTFaceName); //On CHT, set the FaceName to "MingLiU"
dwFontSize = CHT_FONTSIZE;
break;
case KOR_CODEPAGE:
_tcscpy(szFaceNameDef, szKORFaceName);//On KOR, set the FaceName to "GulimChe"
dwFontSize = KOR_FONTSIZE;
break;
case CHS_CODEPAGE:
_tcscpy(szFaceNameDef, szCHSFaceName);//On CHS, set the FaceName to "NSimSun"
dwFontSize = CHS_FONTSIZE;
break;
default:
_tcscpy(szFaceNameDef,L"\0");
break;
}
dwFaceNameSize = ( _tcslen( szFaceNameDef ) + 1 ) * sizeof( TCHAR );
//
// Convert the SID to textual form, which is used to load
// the registry hive associated with that user
//
//
// Test if Sid is valid
//
if( !IsValidSid( ( ( PTOKEN_USER ) InfoBuffer )->User.Sid ) )
{
_TRACE( TRACE_DEBUGGING, "Error: IsValidSid()");
return;
}
//
// Get SidIdentifierAuthority
//
psia = GetSidIdentifierAuthority( ( ( PTOKEN_USER )InfoBuffer )->User.Sid );
//
// Get sidsubauthority count
//
dwSubAuthorities = *GetSidSubAuthorityCount( ( ( PTOKEN_USER ) InfoBuffer )->User.Sid );
//
// Compute buffer length
// S- + SID_REVISION- + identifierauthority- + subauthorities- + NULL
//
dwSidSize = ( 20 + 12 + ( 12 * dwSubAuthorities ) + 1 ) * sizeof( CHAR );
szTextualSid=( LPSTR ) new CHAR[dwSidSize];
if( szTextualSid == NULL )
{
return;
}
//
// Prepare S-SID_REVISION-
//
dwSidSize = sprintf( szTextualSid, "s-%lu-", SID_REVISION ); // NO Overflow, Baskar
//
// Prepare SidIdentifierAuthority
//
if( ( psia->Value[0] != 0 ) || ( psia->Value[1] != 0 ) )
{
dwSidSize += sprintf( szTextualSid + dwSidSize,
"0x%02lx%02lx%02lx%02lx%02lx%02lx",
( USHORT )psia->Value[0],
( USHORT )psia->Value[1],
( USHORT )psia->Value[2],
( USHORT )psia->Value[3],
( USHORT )psia->Value[4],
( USHORT )psia->Value[5] ); // NO Overflow, Baskar
}
else
{
dwSidSize += sprintf( szTextualSid + dwSidSize,
"%lu",
( ULONG )( psia->Value[5] ) +
( ULONG )( psia->Value[4] << 8 ) +
( ULONG )( psia->Value[3] << 16 ) +
( ULONG )( psia->Value[2] << 24 ) ); // NO Overflow, Baskar
}
//
// Copy each SidSubAuthority
//
for( dwCounter = 0 ; dwCounter < dwSubAuthorities ; dwCounter++ )
{
dwSidSize += sprintf( szTextualSid + dwSidSize, "-%lu",
*GetSidSubAuthority( ( ( PTOKEN_USER )InfoBuffer )->User.Sid, dwCounter ) ); // NO Overflow, Baskar
}
//
// Check to see if a hive for the specified user is already loaded
//
HKEY hK3 = NULL;
lRet = RegOpenKeyExA(
HKEY_USERS,
szTextualSid,
0,
KEY_QUERY_VALUE,
&hK3
);
//
// ERROR_ACCESS_DENIED probably means the user hive is already loaded
//
if( ( lRet != ERROR_SUCCESS ) && ( lRet != ERROR_ACCESS_DENIED ) )
{
if( hK3 != NULL )
{
RegCloseKey( hK3 );
}
//
// User hive is not loaded. Attempt to locate and load hive
//
LPCSTR szProfileList = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\";
LPSTR szSubKey = NULL;
HKEY hKey = NULL;
CHAR szPath[MAX_PATH];
DWORD cbPath = MAX_PATH;
CHAR szExpandedPath[MAX_PATH];
lRet = ERROR_SUCCESS;
//
// Allocate storage for ProfileList + TextualSid + NULL
//
szSubKey = (LPSTR) new CHAR[( strlen( szProfileList ) + strlen( szTextualSid ) + 1)];
if( szSubKey == NULL )
{
delete [] szTextualSid;
return;
}
//
// Prepare SubKey path by concatinating the fixed+variable paths
//
strcpy( szSubKey, szProfileList ); // Already correct size allocated based on strlen, no overflow/Attack.
strcat( szSubKey, szTextualSid );
lRet = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
szSubKey,
0,
KEY_QUERY_VALUE,
&hKey
);
if( lRet != ERROR_SUCCESS )
{
delete [] szTextualSid;
delete [] szSubKey;
return;
}
//
// Get ProfileImagePath
//
lRet = RegQueryValueExA(
hKey,
"ProfileImagePath",
NULL,
NULL,
( LPBYTE )szPath,
&cbPath
);
if( lRet != ERROR_SUCCESS )
{
delete [] szTextualSid;
delete [] szSubKey;
return;
}
//
// Expand ProfileImagePath
//
if( ExpandEnvironmentStringsA( szPath, szExpandedPath, MAX_PATH ) == 0 )
{
delete [] szTextualSid;
delete [] szSubKey;
RegCloseKey( hKey );
return;
}
//
// Enable SeRestorePrivilege for RegLoadKey
//
#if 0
SetCurrentPrivilege( SE_RESTORE_NAME, TRUE );
#endif
//
// Load the users registry hive
//
lRet = RegLoadKeyA( HKEY_USERS, szTextualSid, szExpandedPath );
if( lRet != ERROR_SUCCESS )
{
delete [] szTextualSid;
delete [] szSubKey;
RegCloseKey( hKey );
return;
}
//
// Disable SeRestorePrivilege
//
#if 0
SetCurrentPrivilege( SE_RESTORE_NAME, FALSE );
#endif
//
// Free resources
//
if( hKey != NULL )
{
RegCloseKey( hKey );
}
if( szSubKey != NULL )
{
delete [] szSubKey;
}
}
else
{
if( hK3 != NULL )
{
RegCloseKey( hK3 );
}
}
//
// Get path name to tlntsvr.exe
//
if( !GetModuleFileNameA( NULL, szPathName, MAX_PATH-1 ) )
{
delete [] szTextualSid;
return;
}
//
// Nuke the trailing "tlntsvr.exe"
//
LPSTR pSlash = strrchr( szPathName, '\\' );
if( pSlash == NULL )
{
delete [] szTextualSid;
return;
}
else
{
*pSlash = '\0';
}
LPSTR szTlntsess = "tlntsess.exe";
int ch = '\\';
LPSTR pBackSlash;
//
// Replace all '\\' with '_' This format is required for the console to
// interpret the key.
//
while ( 1 )
{
pBackSlash = strchr( szPathName, ch );
if( pBackSlash == NULL )
{
break;
}
else
{
*pBackSlash = '_';
}
}
//
// Append "tlntsess.exe" to the path
//
strcat( szPathName, "_" );
strcat( szPathName, szTlntsess );
HKEY hk2;
//
// The key we need to create is of the form:
// HKEY_USERS\S-1-5-21-2127521184-1604012920-1887927527-65937\Console\C:_SFU_Telnet_tlntsess.exe
//
unsigned int nBytes = ( strlen( szTextualSid ) + strlen( "Console" ) + strlen( szPathName ) + 3 ) * sizeof( CHAR );
lpszKey = (LPSTR) new CHAR[nBytes];
if( !lpszKey )
{
delete[] szTextualSid;
return;
}
SfuZeroMemory(lpszKey, nBytes);
strcpy( lpszKey, szTextualSid );
strcat( lpszKey, "\\" );
strcat( lpszKey, "Console" );
strcat( lpszKey, "\\" );
strcat( lpszKey, szPathName );
//
//
// Freeup TextualSid
delete [] szTextualSid;
//Need to set this in order to be able to display on Non-Jap FE machines
HKEY hk;
lRet = RegOpenKeyEx(
HKEY_USERS,
_T(".DEFAULT\\Console"),
0,
KEY_SET_VALUE,
&hk
);
if( lRet != ERROR_ACCESS_DENIED || lRet == ERROR_SUCCESS )
{
//
// Add STRING value "FaceName " under the key HKEY_USERS\.Default\Console
//
if( (lRet=RegSetValueEx( hk, _T("FaceName"), 0, REG_SZ, (LPBYTE) szFaceNameDef, dwFaceNameSize )) != ERROR_SUCCESS )
{
RegCloseKey( hk );
return;
}
RegCloseKey( hk );
}
//
// Attempt to create this key
//
if( !RegCreateKeyA( HKEY_USERS, lpszKey, &hk2 ) )
{
dwSize = sizeof( DWORD );
//
// Add DWORD value "FontFamily = 54" under the key
//
if( RegSetValueEx( hk2, _T("FontFamily"), 0, REG_DWORD, (LPBYTE) &dwVal, dwSize ) != ERROR_SUCCESS )
{
RegCloseKey( hk2 );
delete [] lpszKey;
return;
}
//
// Add DWORD value "CodePage " under the key
//
if( RegSetValueEx( hk2, _T("CodePage"), 0, REG_DWORD, (LPBYTE) &dwCodePage, dwSize ) != ERROR_SUCCESS )
{
RegCloseKey( hk2 );
delete [] lpszKey;
return;
}
//
// Add DWORD value "Font Size " under the key
//
if( RegSetValueEx( hk2, _T("FontSize"), 0, REG_DWORD, (LPBYTE) &dwFontSize, dwSize ) != ERROR_SUCCESS )
{
RegCloseKey( hk2 );
delete [] lpszKey;
return;
}
dwVal = 400;
//
// Add DWORD value "FontWeight = 400" under the key
//
if( RegSetValueEx( hk2, _T("FontWeight"), 0, REG_DWORD, (LPBYTE) &dwVal, dwSize ) != ERROR_SUCCESS )
{
RegCloseKey( hk2 );
delete [] lpszKey;
return;
}
dwVal = 0;
//
// Add DWORD value "HistoryNoDup = 0" under the key
//
if( RegSetValueEx( hk2, _T("HistoryNoDup"), 0, REG_DWORD, (LPBYTE) &dwVal, dwSize ) != ERROR_SUCCESS )
{
RegCloseKey( hk2 );
delete [] lpszKey;
return;
}
//
// Add STRING value "FaceName" under the key
//
if( RegSetValueEx( hk2, _T("FaceName"), 0, REG_SZ, (LPBYTE) szFaceNameDef, dwFaceNameSize ) != ERROR_SUCCESS )
{
RegCloseKey( hk2 );
delete [] lpszKey;
return;
}
RegCloseKey( hk2 );
}
if(lpszKey != NULL)
{
delete [] lpszKey;
}
return;
}
#ifdef ENABLE_LOGON_SCRIPT
void
CShell::GetUserScriptName( LPWSTR *szArgBuf, LPWSTR szUserScriptPath )
{
_chASSERT( szUserScriptPath != NULL );
_chASSERT( szArgBuf != NULL );
_chASSERT( pServerName != NULL );
DWORD dwSize = 0;
LPWSTR expandedScript = NULL;
LPWSTR shellName = NULL;
LPWSTR szTmp = NULL;
wcscpy( szUserScriptPath, L"" );
if( !AllocateNExpandEnvStrings( pLogonScriptPath, &expandedScript ) )
{
return;
}
dwSize = wcslen( pServerName ) + wcslen( DC_LOGON_SCRIPT_PATH) +
wcslen( LOCALHOST_LOGON_SCRIPT_PATH ) + wcslen( expandedScript ) +
+ 1;
*szArgBuf = new WCHAR[ dwSize ];
if( !*szArgBuf )
{
return;
}
SfuZeroMemory( *szArgBuf, dwSize );
if( m_bIsLocalHost && !IsThisMachineDC() )
{
LPWSTR szSysDir = NULL;
if( GetTheSystemDirectory( &szSysDir ) )
{
//logon script path
wsprintf( szUserScriptPath, L"%s%s", szSysDir, LOCALHOST_LOGON_SCRIPT_PATH ); // NO size info, Baskar. Attack ?
wsprintf( *szArgBuf, L"%s%s%s",
szSysDir, LOCALHOST_LOGON_SCRIPT_PATH, expandedScript ); // NO size info, Baskar. Attack ?
}
delete[] szSysDir;
}
else
{
//When NTLM authenticated, we are unable to access the logon script on the net share.
//This gives "access denied error" in the session. To avoid this, don't exec logon script....
if( !m_pSession->CIoHandler::m_bNTLMAuthenticated )
{
//logon script path
wsprintf( szUserScriptPath, L"%s%s", pServerName, DC_LOGON_SCRIPT_PATH ); // NO size info, Baskar. Attack ?
wsprintf( *szArgBuf, L"%s%s%s",
pServerName, DC_LOGON_SCRIPT_PATH, expandedScript ); // NO size info, Baskar. Attack ?
}
}
wcscat( szUserScriptPath, expandedScript );
szTmp = wcsrchr( szUserScriptPath, L'\\' );
if( szTmp )
{
*szTmp = L'\0';
}
else
{
szUserScriptPath[0] = 0;
}
delete[] expandedScript;
delete[] shellName;
}
#endif
void
CShell::GetScriptName( LPWSTR *szShell, LPWSTR *szArgBuf )
{
_chASSERT( szArgBuf );
_chASSERT( szShell );
TCHAR szUserScriptPath[ MAX_PATH + 1 ];
LPWSTR szUserScriptCmd = NULL;
DWORD dwSize = 0;
LPWSTR script1 = NULL;
*szShell = NULL;
*szArgBuf = NULL;
if( !AllocateNExpandEnvStrings( m_pSession->m_pszDefaultShell, szShell ) )
{
goto GetScriptNameAbort;
}
_TRACE(TRACE_DEBUGGING,L"szShell = %s",*szShell);
if( !AllocateNExpandEnvStrings( m_pSession->m_pszLoginScript, &script1 ) )
{
goto GetScriptNameAbort;
}
_TRACE(TRACE_DEBUGGING,L"script1l = %s",script1);
#ifdef ENABLE_LOGON_SCRIPT
if( pLogonScriptPath && ( wcscmp( pLogonScriptPath, L"" ) != 0 ) )
{
//User specific logon script is present. Execute this in a separate cmd.
//Get the shell, its commandline and also path for user script
GetUserScriptName( &szUserScriptCmd, szUserScriptPath );
if( !szUserScriptCmd )
{
goto GetScriptNameAbort;
}
_TRACE(TRACE_DEBUGGING,L"szUserScriptCmd = %s",szUserScriptCmd);
//This would update m_lpEnv if it is not null or the environment of current
//process for inheritance
if(FALSE == InjectUserScriptPathIntoPath( szUserScriptPath ))
{
goto GetScriptNameAbort;
}
dwSize += wcslen( AND ) +
wcslen( szUserScriptCmd );
}
#endif
if( m_pSession->CSession::m_pszDifferentShell && m_pSession->CSession::m_pszDifferentShell[0] != L'\0' )
{
dwSize += wcslen( AND ) +
wcslen( m_pSession->CSession::m_pszDifferentShell ) +
wcslen( AND ) +
wcslen( EXIT_CMD );
}
/* the arg is of the form :/q /k c:\sfu\telnet\userlogin.cmd *///&&c:\sfu\telnet\telnetlogin.cmd
dwSize += wcslen(m_pSession->CSession::m_pszSwitchToKeepShellRunning) +
wcslen(L" ") +
wcslen( script1 ) +
1;
*szArgBuf = new WCHAR[ dwSize ];
if( !*szArgBuf )
{
goto GetScriptNameAbort;
}
wsprintf(*szArgBuf,L"%s%s",m_pSession->CSession::m_pszSwitchToKeepShellRunning,L" "); // NO size info, Baskar. Attack ?
#ifdef ENABLE_LOGON_SCRIPT
if( pLogonScriptPath && ( wcscmp( pLogonScriptPath, L"" ) != 0 ) )
{
wcscat( *szArgBuf, szUserScriptCmd );
wcscat( *szArgBuf, AND );
}
#endif
_TRACE(TRACE_DEBUGGING,L"szArgBuf became = %s",*szArgBuf);
wcscat( *szArgBuf, script1 );
if( m_pSession->CSession::m_pszDifferentShell && m_pSession->CSession::m_pszDifferentShell[0] != L'\0' )
{
wcscat( *szArgBuf, AND );
wcscat( *szArgBuf, m_pSession->CSession::m_pszDifferentShell );
wcscat( *szArgBuf, AND );
wcscat( *szArgBuf, EXIT_CMD );
}
GetScriptNameAbort:
#ifdef ENABLE_LOGON_SCRIPT
if(szUserScriptCmd)
{
delete[] szUserScriptCmd;
}
#endif
if(script1)
{
delete[] script1;
}
_TRACE( TRACE_DEBUGGING, L"Argument for Shell: %s", *szArgBuf );
_TRACE( TRACE_DEBUGGING, L"Command Shell: %s", *szShell );
}
/*Mem allocated by the function; to be released by the caller */
bool
CShell::GetTheSystemDirectory( LPWSTR *szDir )
{
WORD wSize = MAX_PATH;
DWORD dwErr = 0;
DWORD dwStatus = 0;
retry:
*szDir = new WCHAR[ wSize ];
if( !*szDir )
{
return( FALSE );
}
dwStatus = GetSystemDirectory( *szDir, wSize );
if( !dwStatus )
{
delete[] ( *szDir );
dwErr = GetLastError();
if( dwErr != ERROR_INSUFFICIENT_BUFFER )
{
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, 0, dwErr );
return( FALSE );
}
wSize += MAX_PATH;
goto retry;
}
return ( TRUE );
}
bool
CShell::GetSystemDrive()
{
if( GetTheSystemDirectory( &wideHomeDir ) )
{
DWORD i=0;
while( wideHomeDir[ i ] != L'\0' && wideHomeDir[ i++ ] != L':' )
{
//Do nothing
}
wideHomeDir[ i++ ] = L'\\';
wideHomeDir[ i ] = L'\0';
return( TRUE );
}
return( FALSE );
}
bool
CShell::OnDataFromCmdPipe()
{
// Sendit over socket.
DWORD dwNumBytesRead = 0;
FinishIncompleteIo( m_hReadFromCmd, &m_oReadFromCmd, &dwNumBytesRead );
if( m_pSession->CScraper::m_dwTerm & TERMVTNT )
{
PUCHAR pVtntChars = NULL;
DWORD dwSize = 0;
m_pSession->CRFCProtocol::StrToVTNTResponse( ( CHAR * )m_pucDataFromCmd, dwNumBytesRead,
( VOID ** )&pVtntChars, &dwSize );
m_pSession->CScraper::SendBytes( pVtntChars, dwSize );
delete[] pVtntChars;
}
else
{
m_pSession->CScraper::SendBytes( m_pucDataFromCmd, dwNumBytesRead );
}
if( !IssueReadFromCmd() )
{
return( FALSE );
}
return( TRUE );
}
bool
CShell::IssueReadFromCmd()
{
DWORD dwRequestedIoSize = MAX_WRITE_SOCKET_BUFFER;
if( !ReadFile( m_hReadFromCmd, m_pucDataFromCmd,
dwRequestedIoSize, &m_dwDataSizeFromCmd, &m_oReadFromCmd ) )
{
DWORD dwError = GetLastError( );
if( ( dwError == ERROR_MORE_DATA ) || ( dwError != ERROR_IO_PENDING ) )
{
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READCMD, dwError );
_TRACE( TRACE_DEBUGGING, " Error: ReadFile -- 0x%1x ", dwError );
return ( FALSE );
}
}
return( TRUE );
}
bool
CShell::StartProcess ( )
{
DWORD dwStatus;
LPWSTR szArgBuf = NULL;
LPWSTR szShell = NULL;
PROCESS_INFORMATION pi, temp_pi;
STARTUPINFO si, temp_si;
bool bTryOnceAgain = true;
bool bRetVal = TRUE;
bool impersonating_client = FALSE;
HANDLE hStdError = NULL;
HANDLE hHandleToDuplicate = NULL;
DWORD dwExitCode = 0;
PSECURITY_DESCRIPTOR psd = NULL;
LPTSTR desktop_name = NULL;
LPTSTR winsta_name = NULL;
LPTSTR winsta_desktop = NULL;
HWINSTA winsta_service = NULL;
DWORD required = 0;
/*++
MSRC issue 567.
To generate random numbers, use Crypt...() functions. Acquire a crypt context at the beginning of
ListenerThread and release the context at the end of the thread. If acquiring the context fails,
the service fails to start since we do not want to continue with weak pipe names.
initialize the random number generator
--*/
if (!CryptAcquireContext(&g_hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT))
{
_TRACE(TRACE_DEBUGGING,L"Acquiring crypt context failed with error %d",GetLastError());
return FALSE;
}
if( !CreateIOHandles() )
{
return( FALSE );
}
if( m_pSession->CSession::m_bIsStreamMode )
{
TELNET_CLOSE_HANDLE( m_pSession->CScraper::m_hConBufOut );
InitializeOverlappedStruct( &m_oReadFromCmd );
m_pucDataFromCmd = new UCHAR[ MAX_WRITE_SOCKET_BUFFER ];
if( !m_pucDataFromCmd )
{
return( FALSE );
}
m_hReadFromCmd = NULL;
m_hWriteByCmd = NULL;
if(!TnCreateDefaultSecDesc(&psd, GENERIC_ALL&
~(WRITE_DAC | WRITE_OWNER | DELETE)))
{
return(FALSE);
}
if( !CreateReadOrWritePipe( &m_hReadFromCmd, &m_hWriteByCmd, (SECURITY_DESCRIPTOR *)psd, READ_PIPE ) )
{
if(psd)
{
free(psd);
}
return( FALSE );
}
//The following is for aesthetics
if( !m_pSession->CIoHandler::m_bNTLMAuthenticated )
{
DWORD dwNumWritten = 0;
UCHAR pBuf[] = { '\r', '\n', '\r', '\n' };
_chVERIFY2( WriteFile( m_hWriteByCmd, pBuf, sizeof( pBuf ), &dwNumWritten, NULL ) );
}
hHandleToDuplicate = m_hWriteByCmd;
}
else
{
hHandleToDuplicate = m_pSession->CScraper::m_hConBufOut;
}
if( !DuplicateHandle( GetCurrentProcess(), hHandleToDuplicate,
GetCurrentProcess(), &hStdError,0,
TRUE, DUPLICATE_SAME_ACCESS) )
{
hStdError = m_pSession->CScraper::m_hConBufOut;
}
if (!
create_desktop_for_this_session(m_pSession->CSession::m_hToken, &desktop_name))
{
bRetVal = FALSE;
goto ExitOnError;
}
winsta_service = GetProcessWindowStation();
if(winsta_service == NULL)
{
bRetVal = FALSE;
goto ExitOnError;
}
//bound to fail the first time. Get the size required by the winsta_name
GetUserObjectInformation( winsta_service,
UOI_NAME,
winsta_name,
0,
&required);
winsta_name = (LPTSTR) malloc (required);
if(winsta_name == NULL)
{
bRetVal = FALSE;
goto ExitOnError;
}
if(!GetUserObjectInformation( winsta_service,
UOI_NAME,
winsta_name,
required,
&required))
{
bRetVal = FALSE;
goto ExitOnError;
}
required = _tcslen(winsta_name)+_tcslen(desktop_name)+2; //+2 - 1 for '\\' and 1 for NULL
winsta_desktop = (LPTSTR) malloc(required*sizeof(TCHAR));
if(winsta_desktop == NULL)
{
bRetVal = FALSE;
goto ExitOnError;
}
_sntprintf(winsta_desktop,required,TEXT("%s\\%s"),winsta_name,desktop_name);
FillProcessStartupInfo( &si, m_pSession->CScraper::m_hConBufIn,
hHandleToDuplicate, hStdError, winsta_desktop );
SfuZeroMemory((void *)&temp_si, sizeof(temp_si));
temp_si.cb = sizeof( STARTUPINFO );
temp_si.lpDesktop = winsta_desktop;
temp_si.wShowWindow = SW_HIDE;
AllocNCpyWStr( &wideHomeDir, pHomeDir );
if( !wideHomeDir || wcscmp( wideHomeDir, L"" ) == 0 )
{
if ( wideHomeDir )
delete[] wideHomeDir;
GetSystemDrive( );
}
else
{
//Is it a network drive??
if( memcmp(L"\\\\", wideHomeDir, 4 ) == 0 )
{
GetUsersHomeDirectory( wideHomeDir );
}
}
m_lpEnv = NULL;
if( m_pSession-> m_bNtVersionGTE5 && fnP_CreateEnvironmentBlock )
{
if(!ImpersonateLoggedOnUser(m_pSession->CSession::m_hToken))
{
bRetVal = FALSE;
goto ExitOnError;
}
if( !fnP_CreateEnvironmentBlock( &( m_lpEnv ),
m_pSession->CSession::m_hToken, FALSE ) )
{
_TRACE( TRACE_DEBUGGING, "Error: CreateEnvironmentBlock()"
" - 0x%lx", GetLastError());
m_lpEnv = NULL;
}
if(!RevertToSelf())
{
bRetVal = FALSE;
goto ExitOnError;
}
}
//This function will insert some new variables in to the env
GetEnvVarData();
if( m_lpEnv )
{
ExportEnvVariables();
}
else
{
// Let the cmd inherit
SetEnvVariables();
}
GetScriptName( &szShell, &szArgBuf );
CleanupClientToken(m_pSession->CSession::m_hToken); // We don't care whether it succeeded or not
SetConsoleCtrlHandler( NULL, FALSE );
//call CreateProcessWithTokenW() CREATE_SUSPENDED on a dummy process. This will effectively load the profile for you.
//Save this process handle away
//service will use CreateProcessAsUser(), as it has in the past.
//call TerminateProcess() on the dummy process when the “real” process launched by
//CreateProcessAsUser() dies. This had to be done since
//CreateProcessWithTokenW() did not work as expected. There were some problems
//in associating the input output redirection handles with cmd.exe
if(!CreateProcessWithTokenW(m_pSession->CSession::m_hToken,
LOGON_WITH_PROFILE,
szShell,
szArgBuf,
CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED,
m_lpEnv,
NULL,
&temp_si,
&temp_pi)
)
{
DWORD dwLastError;
dwLastError = GetLastError();
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERRCMD, dwLastError );
_TRACE( TRACE_DEBUGGING, "Error: CreateProcessWithToken() - 0x%lx",
dwLastError );
_chASSERT( 0 );
bRetVal = FALSE;
SetConsoleCtrlHandler( NULL, TRUE );
goto ExitOnError;
}
else
{
m_hTempProcess = temp_pi.hProcess;
TELNET_CLOSE_HANDLE( temp_pi.hThread );
}
//You need to impersonate around CreateProcessAsUserA. Otherwise,
//if lpCurrentDir parameter is a network resource, the call will fail in the
//context of system account. Could not access the remote drive when the process
//is called with CreateProcessA alone. Don't know why??
if( !ImpersonateLoggedOnUser(m_pSession->CSession::m_hToken))
{
bRetVal = false;
goto ExitOnError;
}
impersonating_client = true;
try_again:
if( !CreateProcessAsUser( m_pSession->CSession::m_hToken, szShell,
szArgBuf,
NULL, NULL, TRUE,
CREATE_UNICODE_ENVIRONMENT | CREATE_SEPARATE_WOW_VDM,
m_lpEnv, NULL, &si, &pi ) )
{
DWORD dwLastError;
dwLastError = GetLastError();
if( dwLastError == ERROR_DIRECTORY && bTryOnceAgain )
{
bTryOnceAgain = false;
delete[] wideHomeDir;
GetSystemDrive( );
goto try_again;
}
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERRCMD, dwLastError );
_TRACE( TRACE_DEBUGGING, "Error: CreateProcessAsUserA() - 0x%lx",
dwLastError );
_chASSERT( 0 );
bRetVal = FALSE;
SetConsoleCtrlHandler( NULL, TRUE );
goto ExitOnError;
}
_chVERIFY2( GetExitCodeProcess( pi.hProcess, &dwExitCode ) );
if( dwExitCode != STILL_ACTIVE )
{
bRetVal = FALSE;
goto ExitOnError;
}
m_hProcess = pi.hProcess;
TELNET_CLOSE_HANDLE( pi.hThread );
SetConsoleCtrlHandler( NULL, TRUE );
ExitOnError:
TELNET_CLOSE_HANDLE( hStdError );
TELNET_CLOSE_HANDLE( m_pSession->CScraper::m_hConBufOut );
if(winsta_service)
{
CloseWindowStation(winsta_service);
}
if(impersonating_client && (! RevertToSelf()))
{
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_REVERTSELFFAIL, GetLastError());
bRetVal = false;
}
if(psd)
{
free(psd);
}
if(desktop_name)
{
LocalFree(desktop_name);
}
if(winsta_name)
{
free(winsta_name);
}
if(winsta_desktop)
{
free(winsta_desktop);
}
delete[] wideHomeDir;
delete[] szShell;
delete[] szArgBuf;
return ( bRetVal );
}
//Set "homedir" to the home directory of the user. Make a net connection if the //home directory is remote.
//System account can't access the network resources. You need to impersonate.
bool CShell::GetUsersHomeDirectory( LPWSTR homedir )
{
LPWSTR wsPathName = NULL;
LPWSTR wsNetName = NULL;
NETRESOURCE NetResource;
LPWSTR p;
int i, count, NthBackSlash;
bool result = true;
DWORD dwAddError = ERROR_SUCCESS;
LPWSTR szSaveHomeDir = NULL;
_TRACE( TRACE_DEBUGGING, "GetUsersHomeDirectory()");
_chASSERT( homedir != NULL );
// it is a network share
// mount it and return drive:path
if( !ImpersonateLoggedOnUser(m_pSession->CSession::m_hToken) )
{
wcscpy( homedir, L"C:\\" );
_TRACE( TRACE_DEBUGGING, "Error: ImpersonateLoggedonUser() --"
"0x%1x \n", GetLastError() );
return false;
}
if( !AllocNCpyWStr( &( wsPathName ), homedir) )
{
goto ExitOnError;
}
if( !AllocNCpyWStr( &( wsNetName ), homedir) )
{
goto ExitOnError;
}
if( !AllocNCpyWStr( &( szSaveHomeDir ), homedir) )
{
goto ExitOnError;
}
// find the fourth backslash - everything from there on is pathname
// This approach is sufficient for SMB. But, In NFS, \ is a valid char
// inside a share name. So, by trial and error, connect to the exact share
// name.
NthBackSlash = 4;
do
{
dwAddError = ERROR_SUCCESS;
for( i=0,count = 0, p =homedir; *p; ++p, ++i )
{
if( *p==L'\\' )
{
if( ++count == NthBackSlash )
break;
}
wsNetName[ i ] = homedir[ i ];
}
wsNetName[i] = L'\0';
i=0;
while( *p )
{
wsPathName[ i++ ] = *p++;
}
wsPathName[ i ] = L'\0';
if( count == NthBackSlash )
{
_snwprintf( homedir,(wcslen(pHomeDrive)+wcslen(wsPathName)),L"%s%s", pHomeDrive,
wsPathName ); // NO size info, Baskar. Attack ?
}
else
{
_snwprintf( homedir,wcslen(pHomeDrive),L"%s\\", pHomeDrive ); // NO size info, Baskar. Attack ?
}
NetResource.lpRemoteName = wsNetName;
NetResource.lpLocalName = pHomeDrive;
NetResource.lpProvider = NULL;
NetResource.dwType = RESOURCETYPE_DISK;
if( WNetAddConnection2( &NetResource, NULL, NULL, 0 ) != NO_ERROR )
{
dwAddError = GetLastError();
if( dwAddError == ERROR_ALREADY_ASSIGNED)
{
}
else
{
if( dwAddError == ERROR_BAD_NET_NAME && count == NthBackSlash )
{
wcscpy( homedir, szSaveHomeDir );
}
else
{
wcscpy( homedir, L"C:\\" );
_TRACE( TRACE_DEBUGGING, "Error: WNetAddConnection2() --"
" 0x%1x", dwAddError );
result = false;
dwAddError = ERROR_SUCCESS; //Get out of the loop
}
}
}
NthBackSlash++; // It may be NFS share and \ may be part of share name.
}
//ERROR_BAD_NET_NAME: The network name cannot be found
while( dwAddError == ERROR_BAD_NET_NAME);
ExitOnError:
if(! RevertToSelf())
{
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_REVERTSELFFAIL, GetLastError());
result = false;
_TRACE( TRACE_DEBUGGING, "Error: RevertToSelf() -- 0x%1x",
GetLastError() );
}
delete[] szSaveHomeDir;
delete[] wsPathName;
delete[] wsNetName;
return result;
}
//Get the user preference related info
bool CShell::GetNFillUserPref(LPWSTR serverName, LPWSTR user)
{
LPBYTE bufPtr = NULL;
LPUSER_INFO_3 userInfo3;
DWORD dwStatus = 0;
bool bRetVal = false;
BOOL bReturn = FALSE;
bReturn = ImpersonateLoggedOnUser( m_pSession->CSession::m_hToken );
if(!bReturn)
{
bRetVal = false;
goto Done;
}
if( ( dwStatus = NetUserGetInfo( serverName, user, 3, &bufPtr ) )== NERR_Success )
{
userInfo3 = ( LPUSER_INFO_3 ) bufPtr;
if( !AllocNCpyWStr( &pProfilePath, userInfo3->usri3_profile ) )
{
goto ExitOnError;
}
if( !AllocNCpyWStr( &pLogonScriptPath, userInfo3->usri3_script_path ) )
{
goto ExitOnError;
}
if( !AllocNCpyWStr( &pHomeDir, userInfo3->usri3_home_dir ) )
{
goto ExitOnError;
}
if( !AllocNCpyWStr( &pHomeDrive, userInfo3->usri3_home_dir_drive ) )
{
goto ExitOnError;
}
ExitOnError:
NetApiBufferFree( bufPtr );
bRetVal = true;
}
else if(dwStatus == ERROR_ACCESS_DENIED && m_pSession->CIoHandler::m_bNTLMAuthenticated)
{
bRetVal = true;
}
else
{
_TRACE( TRACE_DEBUGGING, "Error: NetUserGetInfo() code : %d",dwStatus);
}
if(!RevertToSelf())
{
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_REVERTSELFFAIL, GetLastError());
bRetVal = false;
}
Done:
return bRetVal;
}
bool
CShell::GetNameOfTheComputer()
{
LPWSTR lpBuffer = NULL;
bool bRetVal = false;
DWORD size = MAX_COMPUTERNAME_LENGTH + 3; //one for NULL and two for '\\'.
lpBuffer = new WCHAR[ size ];
if( !lpBuffer )
{
goto Done;
}
if( !GetComputerName( lpBuffer, &size ) )
{
_TRACE( TRACE_DEBUGGING, "Error: GetComputerName() -- 0x%1x",
GetLastError() );
goto Done;
}
else
{
size++;
size+= strlen("\\\\");
pServerName = new WCHAR[ size ];
if( NULL == pServerName)
{
goto Done;
}
SfuZeroMemory((void *)pServerName,size*sizeof(WCHAR));
_snwprintf( pServerName, size -1,L"%s%s", L"\\\\", lpBuffer ); // NO overflow, calculated size already.
}
bRetVal = true;
Done:
if(lpBuffer)
delete[] lpBuffer;
return( bRetVal );
}
/*
AreYouHostingTheDomain opens the local LSA and finds out the domain hosted.
It then checks that agains the domain passed and returns TRUE/FALSE as appropriate.
*/
BOOL CShell::AreYouHostingTheDomain(
LPTSTR lpDomain,
LPTSTR lpServer
)
{
OBJECT_ATTRIBUTES obj_attr = { 0 };
LSA_HANDLE policy;
NTSTATUS nStatus;
BOOL found = FALSE;
LSA_UNICODE_STRING name, *name_ptr = NULL;
obj_attr.Length = sizeof(obj_attr);
if (lpServer)
{
RtlInitUnicodeString(& name, lpServer);
name_ptr = & name;
}
nStatus = LsaOpenPolicy(
name_ptr,
&obj_attr,
POLICY_VIEW_LOCAL_INFORMATION | MAXIMUM_ALLOWED,
& policy
);
if (NT_SUCCESS(nStatus))
{
POLICY_ACCOUNT_DOMAIN_INFO *info;
nStatus = LsaQueryInformationPolicy(
policy,
PolicyAccountDomainInformation,
(PVOID *)&info
);
LsaClose(policy);
if (NT_SUCCESS(nStatus))
{
UNICODE_STRING ad_name;
RtlInitUnicodeString(& ad_name, lpDomain);
found = RtlEqualUnicodeString(& ad_name, & (info->DomainName), TRUE); // case insensitive check
LsaFreeMemory(info);
}
}
return found;
}
bool CShell::GetDomainController(LPTSTR lpDomain, LPTSTR lpServer)
{
NTSTATUS nStatus;
TCHAR *sz1stDCName = NULL;
TCHAR *sz2ndDCName = NULL;
bool bRetVal = false;
if(lpDomain == NULL || lpServer == NULL || lstrlenW(lpDomain) <= 0)
{
bRetVal = false;
goto Done;
}
// initialize the return parameter
lpServer[0] = _T('\0');
/*
Before we proceed any further check whether we are hosting the domain
*/
if (AreYouHostingTheDomain(lpDomain, NULL))
{
DWORD length = MAX_COMPUTERNAME_LENGTH + 3; //one for NULL and two for '\\'
/* Yes we are hosting the domain, so get computer name and get out */
if(!GetNameOfTheComputer())
{
lpServer[0] = _T('\0');
bRetVal = false;
goto Done;
}
if(pServerName)
_tcsncpy(lpServer,pServerName,length);
bRetVal = true;
goto Done;
}
/*
Get a domain controller for the domain we are joined to
*/
nStatus = NetGetAnyDCName( NULL, NULL, ( LPBYTE * )&sz1stDCName );
if(nStatus == NERR_Success )
{
/* The domain we want is that the one we are joined to ? */
if (AreYouHostingTheDomain(lpDomain, sz1stDCName) )
{
lstrcpy(lpServer, sz1stDCName); // No BO - BaskarK
NetApiBufferFree( sz1stDCName );
bRetVal = true;
goto Done;
}
/*
Since the domain we are joined to is not the one we want, let us find out whether it is in any
of the trusted list in the forest/enterprise
*/
nStatus = NetGetAnyDCName( sz1stDCName, lpDomain, ( LPBYTE * )&sz2ndDCName);
if(nStatus == NERR_Success )
{
lstrcpy(lpServer, sz2ndDCName ); // No BO - BaskarK
NetApiBufferFree( sz2ndDCName );
bRetVal = true;
}
NetApiBufferFree( sz1stDCName );
}
Done:
return bRetVal;
}
//Locate and get the user info needed to load his/her profile.
bool CShell::LoadTheProfile()
{
PROFILEINFO profile = { 0 };
bool result = true;
DWORD userPathSize = MAX_PATH+1, defPathSize = MAX_PATH+1;
LPWSTR lpWideDomain = NULL ;
PDOMAIN_CONTROLLER_INFO dcInfo = NULL;
BOOL fnResult = FALSE;
_TRACE( TRACE_DEBUGGING, "LoadTheProfile()");
profile.dwSize = sizeof( profile );
profile.dwFlags = PI_NOUI;
/*
* Fill the server name and the user name to pass to the
* GetNFillUserPref function
*/
ConvertSChartoWChar(m_pSession->CSession::m_pszUserName, &( profile.lpUserName ) );
profile.lpServerName = NULL;
if( !AllocNCpyWStr( &pServerName, L"") )
{
return false;
}
ConvertSChartoWChar(m_pSession->CSession::m_pszDomain, &lpWideDomain);
profile.lpServerName = new WCHAR[MAX_STRING_LENGTH];
if(profile.lpServerName == NULL)
{
result = false;
goto Done;
}
if( strcmp( m_pSession->CSession::m_pszDomain, "." ) != 0 )
{
if( GetDomainController( lpWideDomain, profile.lpServerName ) )
{
delete[] pServerName;
AllocNCpyWStr( &pServerName, profile.lpServerName );
}
}
else
{
m_bIsLocalHost = true;
GetNameOfTheComputer();
}
profile.lpProfilePath = NULL;
if(!GetNFillUserPref(profile.lpServerName, profile.lpUserName ))
{
result = false;
goto Done;
}
if( pProfilePath && wcscmp( pProfilePath, L"" ) != 0 )
{
AllocNCpyWStr( &( profile.lpProfilePath ), pProfilePath );
}
else
{
do
{
profile.lpProfilePath = new TCHAR[ userPathSize ];
if( !profile.lpProfilePath )
{
break;
}
if( !fnP_GetUserProfileDirectory )
{
break;
}
fnResult = fnP_GetUserProfileDirectory ( m_pSession->CSession::
m_hToken, profile.lpProfilePath, &userPathSize );
if (!fnResult)
{
DWORD err;
if ( ( err = GetLastError() ) != ERROR_INSUFFICIENT_BUFFER )
{
fnResult = TRUE;
_TRACE( TRACE_DEBUGGING, "Error: GetUserProfileDirecto"
"ry() -- 0x%1x", err );
}
delete[] profile.lpProfilePath;
profile.lpProfilePath = NULL;
}
} while ( !fnResult );
}
/*
* pHomeDir and pHomeDrive will be empty unless it is explicity set
* in the AD for domain users and Local User Manager for local users.
* So assign the profile directory as home directory if it is empty.
* Explorer does the same thing
*/
if (pHomeDir && wcscmp(pHomeDir, L"") == 0)
{
if (profile.lpProfilePath && wcscmp(profile.lpProfilePath, L"") != 0)
{
delete[] pHomeDir;
AllocNCpyWStr(&pHomeDir, profile.lpProfilePath);
}
}
do
{
profile.lpDefaultPath = new TCHAR[ defPathSize ];
if( profile.lpDefaultPath == NULL)
{
break;
}
if( !fnP_GetDefaultUserProfileDirectory )
{
break;
}
fnResult = fnP_GetDefaultUserProfileDirectory( profile.lpDefaultPath,
&defPathSize );
if (!fnResult)
{
DWORD err;
err = GetLastError();
if ( err != ERROR_INSUFFICIENT_BUFFER )
{
fnResult = TRUE;
_TRACE( TRACE_DEBUGGING, "Error: GetDefaultUserProfile"
"Directory() -- 0x%1x", err );
}
delete[] profile.lpDefaultPath;
profile.lpDefaultPath = NULL;
}
} while ( !fnResult );
profile.lpPolicyPath = NULL;
if( fnP_LoadUserProfile )
{
if( fnP_LoadUserProfile(m_pSession->CSession::m_hToken, &profile) )
{
//assign the handle to a member from the session structure
//so that it can be unloaded.
m_hCurrUserKey = profile.hProfile;
result = true;
}
else
{
_TRACE( TRACE_DEBUGGING, "Error: LoadUserProfile() -- 0x%1x",
GetLastError() );
result = false;
}
}
/*
* Read the APPDATA folder. We need to pass this onto the environment
* variables. For a user who is logged onto the system, this variable is
* available when environment is imported. Otherwise this has to be read
* and explicitly set. Are there more of this kind?? - Investigate.
* Use CSIDL_FLAG_CREATE to have the folder created in case of a user
* who logs onto the machine for the first time ever
*/
m_pwszAppDataDir = new TCHAR[MAX_PATH + 1];
if (!m_pwszAppDataDir)
{
result = false;
}
else
{
if (ImpersonateLoggedOnUser(m_pSession->CSession::m_hToken))
{
if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
m_pSession->m_bNtVersionGTE5 ? m_pSession->CSession::m_hToken : NULL,
// For systems earlier than Win2K this must be NULL, else you can
// pass the access token that can be used to represent a particular user
0, m_pwszAppDataDir)))
{
_TRACE(TRACE_DEBUGGING, "Error: Reading APPDATA path -- 0x%1x\n", GetLastError());
result = false;
}
if(!RevertToSelf())
{
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_REVERTSELFFAIL, GetLastError());
result = false;
_TRACE(TRACE_DEBUGGING, "Error: RevertToSelf() -- 0x%1x", GetLastError());
}
}
}
Done:
if(profile.lpUserName)
delete[] profile.lpUserName;
if(profile.lpServerName)
delete[] profile.lpServerName;
if(profile.lpDefaultPath)
delete[] profile.lpDefaultPath;
if(profile.lpProfilePath)
delete[] profile.lpProfilePath;
if(lpWideDomain)
delete[] lpWideDomain;
return result;
}
bool
CShell::CancelNetConnections ( )
{
DWORD dwRetVal;
if (NULL == m_pSession->CSession::m_hToken)
{
// Nothing to do here, perhaps the session was quit in an unauthenticated state
// or authentication failed
return true;
}
_chVERIFY2( dwRetVal = ImpersonateLoggedOnUser(
m_pSession->CSession::m_hToken ) );
if( !dwRetVal )
{
return ( false );
}
DWORD dwResult;
HANDLE hEnum;
DWORD cbBuffer = 16384;
DWORD cEntries = 0xFFFFFFFF;
LPNETRESOURCE lpnrDrv;
DWORD i;
dwResult = WNetOpenEnum( RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL,
&hEnum );
if(dwResult != NO_ERROR)
{
_TRACE( TRACE_DEBUGGING, "\nCannot enumerate network drives.\n" );
if(! RevertToSelf( ) )
{
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_REVERTSELFFAIL, GetLastError());
}
return ( false );
}
do{
lpnrDrv = (LPNETRESOURCE) GlobalAlloc( GPTR, cbBuffer );
if( !lpnrDrv )
{
if(! RevertToSelf( ) )
{
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_REVERTSELFFAIL, GetLastError());
}
return( false );
}
dwResult = WNetEnumResource( hEnum, &cEntries, lpnrDrv, &cbBuffer );
if (dwResult == NO_ERROR)
{
for( i = 0; i < cEntries; i++ )
{
if( lpnrDrv[i].lpLocalName != NULL )
{
//printf( "%s\t%s\n", lpnrDrv[i].lpLocalName,
// lpnrDrv[i].lpRemoteName );
WNetCancelConnection2( lpnrDrv[i].lpLocalName,
CONNECT_UPDATE_PROFILE, FALSE );
}
}
}
else if( dwResult != ERROR_NO_MORE_ITEMS )
{
_TRACE( TRACE_DEBUGGING, "Cannot complete network drive enumeration" );
GlobalFree( (HGLOBAL) lpnrDrv );
break;
}
GlobalFree( (HGLOBAL) lpnrDrv );
} while( dwResult != ERROR_NO_MORE_ITEMS );
WNetCloseEnum(hEnum);
if(! RevertToSelf( ) )
{
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_REVERTSELFFAIL, GetLastError());
return( false );
}
return ( true );
}
void
CShell::Shutdown ( )
{
_TRACE( TRACE_DEBUGGING, "0x%p CTelnetClient::Shutdown() \n", this );
if(g_hProv)
{
CryptReleaseContext(g_hProv,0);
g_hProv = NULL;
}
if( !CancelNetConnections())
{
_TRACE( TRACE_DEBUGGING, "Error: CancelNetConnections()" );
}
//expect a exception in debug builds.
//cmd is killed by now in general case.
//This should be before cleanup. Otherwise this is an open handle to cmd.
if ((m_hProcess != INVALID_HANDLE_VALUE) && (m_hProcess != NULL))
{
TerminateProcess(m_hProcess, 0); // Don't care whether it succeeded or not.
TELNET_CLOSE_HANDLE( m_hProcess );
}
if ((m_hTempProcess != INVALID_HANDLE_VALUE) && (m_hTempProcess != NULL))
{
TerminateProcess(m_hTempProcess , 0); // Don't care whether it succeeded or not.
TELNET_CLOSE_HANDLE( m_hTempProcess );
}
LUID id = m_pSession->CSession::m_AuthenticationId;
//clean up potentially abandoned proceses
//this slows down the thread a lot
if( ( id.HighPart !=0 ) || ( id.LowPart != 0 ) )
KillProcs( id );
if( fnP_UnloadUserProfile && m_hCurrUserKey )
{
if( !fnP_UnloadUserProfile(m_pSession->CSession::m_hToken, m_hCurrUserKey) )
{
_TRACE( TRACE_DEBUGGING, "Error: UnloadUserProfile() - %1x", GetLastError() );
}
}
if(m_lpEnv)
delete[] ( UCHAR * )m_lpEnv;
m_lpEnv = NULL;
FreeConsole();
}
void
CShell::LoadLibNGetProc( )
{
CHAR szDllPath[MAX_PATH*2] = { 0 };
UINT iRet = 0;
//Dynamicallly load userenv.lib
iRet = GetSystemDirectoryA(szDllPath,(MAX_PATH*2)-1);
if(iRet == 0 || iRet >= (MAX_PATH*2))
{
goto End;
}
strncpy(szDllPath+iRet,"\\userenv.dll",(MAX_PATH*2)-iRet-1);
_chVERIFY2( hUserEnvLib = LoadLibraryA( szDllPath ) );
if( hUserEnvLib )
{
_chVERIFY2( fnP_LoadUserProfile = ( LOADUSERPROFILE * ) GetProcAddress
( hUserEnvLib, "LoadUserProfileW" ) );
_chVERIFY2( fnP_UnloadUserProfile = ( UNLOADUSERPROFILE * )
GetProcAddress ( hUserEnvLib, "UnloadUserProfile" ) );
_chVERIFY2( fnP_CreateEnvironmentBlock = ( CREATEENVIRONMENTBLOCK * )
GetProcAddress( hUserEnvLib, "CreateEnvironmentBlock" ) );
_chVERIFY2( fnP_DestroyEnvironmentBlock = ( DESTROYENVIRONMENTBLOCK *)
GetProcAddress( hUserEnvLib, "DestroyEnvironmentBlock" ) );
_chVERIFY2( fnP_GetUserProfileDirectory = ( GETUSERPROFILEDIRECTORY * )
GetProcAddress( hUserEnvLib, "GetUserProfileDirectoryW" ) );
_chVERIFY2( fnP_GetDefaultUserProfileDirectory =
( GETDEFAULTUSERPROFILEDIRECTORY * )
GetProcAddress( hUserEnvLib, "GetDefaultUserProfileDirectoryW" ));
}
End:
return;
}
void CopyRestOfEnv( LPTSTR *lpSrcEnv, LPTSTR *lpDstEnv )
{
DWORD dwEnvSize = 0;
LPTSTR lpTmp = *lpSrcEnv;
DWORD dwStringLen = 0;
while( *( *lpSrcEnv ) )
{
dwStringLen = ( wcslen( *lpSrcEnv ) + 1 );
dwEnvSize += dwStringLen;
*lpSrcEnv += dwStringLen;
}
//Copy L'\0' at the end of the block also
memcpy( *lpDstEnv, lpTmp, (dwEnvSize+1 )*2 ); // NO size info for Dest, Attack ? - Baskar
}
void PutStringInEnv( LPTSTR lpStr, LPTSTR *lpSrcEnv, LPTSTR *lpDstEnv, bool bOverwrite)
{
DWORD dwEnvSize = 0;
LPTSTR lpTmp = *lpSrcEnv;
DWORD dwStringLen = 0;
LPTSTR lpSrcTmp = NULL;
wchar_t *wcCharPos = NULL;
wchar_t *wcCharPosSrc = NULL;
bool bCopyString = true;
int nOffset, nOffsetSrc,nOffsetTemp;
wcCharPos = wcschr(lpStr, L'=');
if (NULL == wcCharPos)
{
_TRACE(TRACE_DEBUGGING, "Error: TLNTSESS: The syntax of an env string is VAR=VALUE\n");
return;
}
nOffset = (int)(wcCharPos - lpStr);
wcCharPosSrc = wcschr(*lpSrcEnv, L'=');
if (NULL == wcCharPos)
{
_TRACE(TRACE_DEBUGGING, "Error: TLNTSESS: The syntax of an env string is VAR=VALUE\n");
return;
}
nOffsetTemp = (int)(wcCharPosSrc - (*lpSrcEnv));
nOffsetSrc = max(nOffset,nOffsetTemp);
while(*(*lpSrcEnv) && _wcsnicmp(*lpSrcEnv, lpStr, nOffsetSrc) < 0)
{
dwStringLen = wcslen(*lpSrcEnv) + 1;
dwEnvSize += dwStringLen;
*lpSrcEnv += dwStringLen;
wcCharPosSrc = wcschr(*lpSrcEnv, L'=');
if (NULL == wcCharPosSrc)
{
_TRACE(TRACE_DEBUGGING, "Error: TLNTSESS: The syntax of an env string is VAR=VALUE\n");
return;
}
nOffsetTemp = (int)(wcCharPosSrc - (*lpSrcEnv));
nOffsetSrc = max(nOffset,nOffsetTemp);
}
if (*(*lpSrcEnv) )
{
int iRet = -1;
iRet = _wcsnicmp(*lpSrcEnv, lpStr, nOffsetSrc);
if(iRet == 0)
{
dwStringLen = wcslen(*lpSrcEnv) + 1;
*lpSrcEnv += dwStringLen;
if (!bOverwrite)
{
dwEnvSize += dwStringLen; // Copy this env variable too, so offset the size
bCopyString = false; // Because we found a match and we shouldn't overwrite
}
}
}
memcpy( *lpDstEnv, lpTmp, dwEnvSize*2 ); // No size info ? - Baskar
*lpDstEnv += dwEnvSize;
if (!bCopyString)
{
return;
}
dwStringLen = wcslen ( lpStr ) + 1 ;
memcpy( *lpDstEnv, lpStr, dwStringLen*2 ); // No size info ? - Baskar
*lpDstEnv += dwStringLen;
}
//This will break an absolute path into drive and relative path.
//Relative path is returned through szHomePath
void GetRelativePath( LPWSTR *szHomePath )
{
_chASSERT( szHomePath );
_chASSERT( *szHomePath );
while( *( *szHomePath ) != L'\0' && *( *szHomePath ) != L':' )
{
( *szHomePath) ++;
}
if( *( *szHomePath ) == L':' )
{
( *szHomePath) ++;
}
*( *szHomePath ) = L'\0';
( *szHomePath)++;
}
//It returns the size in terms of WCHARS
void FindSizeOfEnvBlock( DWORD *dwEnvSize, LPVOID lpTmpEnv )
{
_chASSERT( dwEnvSize );
_chASSERT( lpTmpEnv );
//The Environment block has set of strings and ends with L'\0'
while( ( *( ( UCHAR * )lpTmpEnv ) ) )
{
DWORD dwStringLen = wcslen( ( LPTSTR )lpTmpEnv ) + 1;
*dwEnvSize += dwStringLen ;
lpTmpEnv = ( TCHAR * )lpTmpEnv + dwStringLen;
}
*dwEnvSize += 1; //Accounting for L'\0' at the end of block
}
// do this so that the cmd.exe
// gets the environment with following variables set
void
CShell::ExportEnvVariables()
{
TCHAR szHomeDirectoryPath[ MAX_PATH + 1 ];
TCHAR *szHomePath = NULL;
LPVOID lpTmpEnv = NULL;
LPVOID lpTmpOldEnv = NULL;
LPVOID lpNewEnv = NULL;
DWORD dwEnvSize = 0;
TCHAR szTmp[] = L"\\";
DWORD dwIndex = 0;
if(m_lpEnv == NULL)
return;
wcsncpy( szHomeDirectoryPath, wideHomeDir , MAX_PATH);
szHomePath = szHomeDirectoryPath;
GetRelativePath( &szHomePath );
TCHAR szHomeVar[ MAX_PATH + UNICODE_STR_SIZE(ENV_HOMEPATH) ] = { 0 };
TCHAR szHomeDirVar[ MAX_PATH + 1]= { 0 };
TCHAR szTermVar[ MAX_PATH + 1 ]= { 0 };
TCHAR szAppDataDirVar[MAX_PATH + UNICODE_STR_SIZE(ENV_APPDATA)]= { 0 };
TCHAR szUserName[MAX_PATH+1+ UNICODE_STR_SIZE(ENV_USERNAME)]= { 0 };
LPWSTR szUserDomain = NULL;
DWORD domainsize = wcslen(m_pSession->CSession::m_szDomain) +1 +UNICODE_STR_SIZE(ENV_USERDOMAIN);
LPWSTR szUserProfile = NULL;
DWORD profilesize = wcslen(pProfilePath)+1+UNICODE_STR_SIZE(ENV_USERPROFILE);
LPWSTR pszUserName = NULL;
TCHAR *szTempTerm = NULL;
TCHAR *szTerm = NULL;
szUserDomain = new WCHAR[domainsize];
if(szUserDomain == NULL)
{
lpTmpOldEnv = m_lpEnv;
m_lpEnv = NULL;
goto ExitOnError;
}
szUserProfile = new WCHAR[profilesize];
if(szUserProfile == NULL)
{
lpTmpOldEnv = m_lpEnv;
m_lpEnv = NULL;
goto ExitOnError;
}
wcscpy( szHomeVar, ENV_HOMEPATH );
wcscpy( szHomeDirVar, ENV_HOMEDRIVE );
wcscpy( szTermVar, ENV_TERM );
wcscpy( szAppDataDirVar, ENV_APPDATA );
wcscpy(szUserName, ENV_USERNAME);
wcscpy(szUserDomain, ENV_USERDOMAIN);
wcscpy(szUserProfile, ENV_USERPROFILE);
if(!ConvertSChartoWChar( m_pSession->CSession::m_pszTermType, &szTerm ))
{
lpTmpOldEnv = m_lpEnv;
m_lpEnv = NULL;
goto ExitOnError;
}
// Convert term type to lower case, so that UNIX programs can work...
for( szTempTerm = szTerm; *szTempTerm; szTempTerm++)
{
*szTempTerm = towlower(*szTempTerm);
}
while( ( dwIndex < MAX_PATH + 1 ) && szHomePath[ dwIndex ] )
{
if( szHomePath[ dwIndex ] == L'\\' || szHomePath[ dwIndex ] == L'/' )
{
szTmp[0] = szHomePath[ dwIndex ];
break;
}
dwIndex++;
}
if(!ConvertSChartoWChar(m_pSession->CSession::m_pszUserName, &pszUserName))
{
lpTmpOldEnv = m_lpEnv;
m_lpEnv = NULL;
goto ExitOnError;
}
wcsncat( szHomeVar, szTmp, 1 );
wcsncat( szHomeVar, szHomePath, MAX_PATH );
wcsncat( szHomeDirVar, szHomeDirectoryPath, MAX_PATH );
wcsncat( szTermVar, szTerm, MAX_PATH );
wcsncat( szAppDataDirVar, m_pwszAppDataDir, MAX_PATH );
wcsncat( szUserName, pszUserName, MAX_PATH);
wcsncat( szUserDomain,m_pSession->CSession::m_szDomain,domainsize -1);
wcsncat( szUserProfile,pProfilePath, profilesize -1);
szUserDomain[domainsize -1] = L'\0';
szUserProfile[profilesize -1] = L'\0';
FindSizeOfEnvBlock( &dwEnvSize, m_lpEnv );
dwEnvSize += ( wcslen( szHomeVar ) + 2 );
dwEnvSize += ( wcslen( szHomeDirVar ) + 2 );
dwEnvSize += ( wcslen( szTermVar ) + 2 );
dwEnvSize += ( wcslen( szAppDataDirVar ) + 2 );
dwEnvSize += ( wcslen( szUserName ) + 2 );
dwEnvSize += ( wcslen( szUserDomain ) + 2 );
dwEnvSize += ( wcslen( szUserProfile ) + 2 );
lpTmpEnv = m_lpEnv;
lpTmpOldEnv = m_lpEnv;
m_lpEnv = ( VOID * ) new UCHAR[ dwEnvSize * 2 ];
if( !m_lpEnv )
{
goto ExitOnError;
}
lpNewEnv = m_lpEnv;
/*
* Make calls to PutStringInEnv alphabetically. This function moves the lpTmpEnv
* variable and only searches forward. So if the calls aren't alphabetical, then
* you wouldn't find a match even if there is one
*/
PutStringInEnv( szAppDataDirVar, (LPTSTR *)&lpTmpEnv, ( LPTSTR * )&lpNewEnv, false);
PutStringInEnv( szHomeDirVar, ( LPTSTR * )&lpTmpEnv, ( LPTSTR * )&lpNewEnv, false);
PutStringInEnv( szHomeVar, ( LPTSTR * )&lpTmpEnv, ( LPTSTR * )&lpNewEnv, false);
PutStringInEnv( szTermVar, ( LPTSTR * )&lpTmpEnv, ( LPTSTR * )&lpNewEnv, true);
PutStringInEnv( szUserDomain, ( LPTSTR * )&lpTmpEnv, ( LPTSTR * )&lpNewEnv, true);
PutStringInEnv( szUserName, ( LPTSTR * )&lpTmpEnv, ( LPTSTR * )&lpNewEnv, true);
PutStringInEnv( szUserProfile, ( LPTSTR * )&lpTmpEnv, ( LPTSTR * )&lpNewEnv, true);
CopyRestOfEnv( ( LPTSTR * )&lpTmpEnv, ( LPTSTR * )&lpNewEnv );
ExitOnError:
delete[] szTerm;
if(pszUserName)
delete [] pszUserName;
if(szUserDomain)
delete [] szUserDomain;
if(szUserProfile)
delete [] szUserProfile;
if( fnP_DestroyEnvironmentBlock )
{
fnP_DestroyEnvironmentBlock( lpTmpOldEnv );
}
}
//Load the profile path for setting in the environment variable. Currently
//Telnet session exports APPDATA, HOMEDRIVE, HOMEPATH, USERNAME,
//USERDOMAIN,USERPROFILE env variables to the newly created cmd.exe
//If any more environment variables need to be exported, corresponding
//Global variables should be loaded in this function.
void
CShell::GetEnvVarData()
{
BOOL fnResult = FALSE;
LPTSTR szProfilePath = NULL;
DWORD userPathsize = MAX_PATH +1;
do
{
szProfilePath = new TCHAR[ userPathsize ];
if( !szProfilePath )
{
break;
}
if( !fnP_GetUserProfileDirectory )
{
break;
}
fnResult = fnP_GetUserProfileDirectory ( m_pSession->CSession::m_hToken,
szProfilePath, &userPathsize);
if (!fnResult)
{
DWORD err;
if ( ( err = GetLastError() ) != ERROR_INSUFFICIENT_BUFFER )
{
fnResult = TRUE;
_TRACE( TRACE_DEBUGGING, "Error: GetUserProfileDirecto"
"ry() -- 0x%1x", err );
}
delete[] szProfilePath;
szProfilePath = NULL;
}
else
{
if(pProfilePath)
{
delete [] pProfilePath;
}
AllocNCpyWStr(&pProfilePath, szProfilePath);
}
} while ( !fnResult );
if(szProfilePath)
delete [] szProfilePath;
}
//This is only on NT4 where there is no LoadUserProfile()
void
CShell::SetEnvVariables()
{
TCHAR szHomeDirectoryPath[ MAX_PATH + 1 ] = { 0 };
TCHAR *szHomePath = NULL;
UINT_PTR space_left;
DWORD dwIndex = 0;
WCHAR szTmp[] = L"\\";
TCHAR szHomeVar[ MAX_PATH + UNICODE_STR_SIZE(ENV_HOMEPATH) ] = { 0 };
TCHAR szHomeDirVar[ MAX_PATH + 1]= { 0 };
wcsncpy( szHomeDirectoryPath, wideHomeDir, MAX_PATH );
szHomePath = szHomeDirectoryPath;
GetRelativePath( &szHomePath );
_chVERIFY2( SetEnvironmentVariableW( L"HOMEDRIVE", szHomeDirectoryPath ) );
while( ( dwIndex < MAX_PATH + 1 ) && szHomePath[ dwIndex ] )
{
if( szHomePath[ dwIndex ] == L'\\' || szHomePath[ dwIndex ] == L'/' )
{
szTmp[0] = szHomePath[ dwIndex ];
break;
}
dwIndex++;
}
wcsncat( szHomeVar, szTmp, 1 );
space_left = MAX_PATH - (szHomePath - szHomeDirectoryPath);
wcsncat( szHomePath, L"\\", space_left );
wcsncat( szHomeVar, szHomePath, MAX_PATH );
_chVERIFY2( SetEnvironmentVariableW( L"HOMEPATH", szHomeVar ) );
_chVERIFY2( SetEnvironmentVariableA( "TERM", m_pSession->CSession::m_pszTermType ) );
SetEnvironmentVariableA("USERNAME",m_pSession->CSession::m_pszUserName);
SetEnvironmentVariableW(L"USERPROFILE",pProfilePath);
SetEnvironmentVariableW(L"USERDOMAIN",m_pSession->CSession::m_szDomain);
}
#ifdef ENABLE_LOGON_SCRIPT
BOOL
CShell::InjectUserScriptPathIntoPath( TCHAR szUserScriptPath[] )
{
DWORD dwSize = 0;
TCHAR *szNewPath = NULL;
DWORD dwRetVal = 0;
BOOL bRetVal = FALSE;
if (NULL == szUserScriptPath )
{
bRetVal = TRUE;
goto ExitOnError;
}
if( wcslen( szUserScriptPath ) == 0 )
{
bRetVal = TRUE;
goto ExitOnError;
}
if( m_lpEnv )
{
DWORD dwEnvSize = 0;
LPVOID lpTmpOldEnv = NULL;
LPVOID lpTmpEnv = NULL;
TCHAR *szVar = NULL;
FindSizeOfEnvBlock( &dwEnvSize, m_lpEnv );
dwSize = ( wcslen( szUserScriptPath ) + wcslen( L";" ) + 1);
lpTmpEnv = ( VOID * ) new TCHAR[ ( dwEnvSize + dwSize ) ];
if( lpTmpEnv )
{
bool bEndSearch = false;
lpTmpOldEnv = m_lpEnv;
memcpy( lpTmpEnv, m_lpEnv, dwEnvSize * sizeof(TCHAR) );
szVar = ( TCHAR * )lpTmpEnv;
m_lpEnv = lpTmpEnv;
do
{
if( _tcsnicmp( szVar, L"PATH=", LENGTH_OF_PATH_EQUALS ) == 0 )
{
TCHAR *szVarNextToPath = NULL;
bEndSearch = true;
szVarNextToPath = szVar + wcslen( szVar ) + 1; //points to variable next to path
szVar += LENGTH_OF_PATH_EQUALS; //Move past PATH=
wcscat( szVar, L";" );
wcscat( szVar, szUserScriptPath );
szVar += ( wcslen( szVar ) + 1 ); //Move past value of path
DWORD dwOffset = (DWORD)( szVarNextToPath - ( TCHAR *)m_lpEnv );
//copy restof the env block
memcpy( szVar, (( ( TCHAR * )lpTmpOldEnv )+ dwOffset) , (dwEnvSize*sizeof(szVar[0]) - dwOffset) );
break; //we are done with our job.
}
szVar = wcschr( ( TCHAR * )lpTmpEnv, L'\0' ) ; //look for L'\0'
if( szVar )
{
szVar++; //move past L'\0'
}
else
{
//Should not happen
_chASSERT( 0 );
break;
}
lpTmpEnv = szVar;
}
while( *szVar != L'\0' );
delete[] ( ( UCHAR * )lpTmpOldEnv );
}
}
else
{
dwSize = GetEnvironmentVariable( L"PATH", NULL, 0 );
dwSize += ( wcslen( szUserScriptPath ) + wcslen( L";" ) ); //find future length of path
szNewPath = new TCHAR[ dwSize + 1 ];
if( szNewPath )
{
dwRetVal = GetEnvironmentVariable( L"PATH", szNewPath, dwSize );
if(dwRetVal == 0 || dwRetVal > dwSize )
goto ExitOnError;
wcscat( szNewPath, L";" );
wcscat( szNewPath, szUserScriptPath );
if(!SetEnvironmentVariable( L"PATH", szNewPath ) )
goto ExitOnError;
}
else
{
goto ExitOnError;
}
}
bRetVal = TRUE;
ExitOnError:
if(szNewPath)
{
delete[] szNewPath;
}
return(bRetVal);
}
#endif