Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1660 lines
45 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: shell.c
//
// Contents: Microsoft Logon GUI DLL
//
// History: 7-14-94 RichardW Created
//
//----------------------------------------------------------------------------
#include "msgina.h"
#include "shtdnp.h"
#include <stdio.h>
#include <wchar.h>
#include <regapi.h>
#include <ginacomn.h>
HICON hNoDCIcon;
#if DBG
DWORD DebugAllowNoShell = 1;
#else
DWORD DebugAllowNoShell = 0;
#endif
//
// Parsing information for autoexec.bat
//
#define PARSE_AUTOEXEC_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
#define PARSE_AUTOEXEC_ENTRY TEXT("ParseAutoexec")
#define PARSE_AUTOEXEC_DEFAULT TEXT("1")
#define MAX_PARSE_AUTOEXEC_BUFFER 2
BOOL
SetLogonScriptVariables(
PGLOBALS pGlobals,
PVOID * pEnvironment
);
BOOL
SetAutoEnrollVariables(
PGLOBALS pGlobals,
PVOID * pEnvironment
);
VOID
DeleteLogonScriptVariables(
PGLOBALS pGlobals,
PVOID * pEnvironment
);
void CtxCreateMigrateEnv( PVOID );
void CtxDeleteMigrateEnv( VOID );
BOOL
DoAutoexecStuff(
PGLOBALS pGlobals,
PVOID * ppEnvironment,
LPTSTR pszPathVar)
{
HKEY hKey;
DWORD dwDisp, dwType, dwMaxBufferSize;
TCHAR szParseAutoexec[MAX_PARSE_AUTOEXEC_BUFFER];
//
// Set the default case
//
lstrcpy (szParseAutoexec, PARSE_AUTOEXEC_DEFAULT);
//
// Impersonate the user, and check the registry
//
if (OpenHKeyCurrentUser(pGlobals)) {
if (RegCreateKeyEx (pGlobals->UserProcessData.hCurrentUser, PARSE_AUTOEXEC_KEY, 0, 0,
REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
NULL, &hKey, &dwDisp) == ERROR_SUCCESS) {
//
// Query the current value. If it doesn't exist, then add
// the entry for next time.
//
dwMaxBufferSize = sizeof (TCHAR) * MAX_PARSE_AUTOEXEC_BUFFER;
if (RegQueryValueEx (hKey, PARSE_AUTOEXEC_ENTRY, NULL, &dwType,
(LPBYTE) szParseAutoexec, &dwMaxBufferSize)
!= ERROR_SUCCESS) {
//
// Set the default value
//
RegSetValueEx (hKey, PARSE_AUTOEXEC_ENTRY, 0, REG_SZ,
(LPBYTE) szParseAutoexec,
sizeof (TCHAR) * (lstrlen (szParseAutoexec) + 1));
}
//
// Close key
//
RegCloseKey (hKey);
}
//
// Close HKCU
//
CloseHKeyCurrentUser(pGlobals);
}
//
// Process the autoexec if appropriate
//
if (szParseAutoexec[0] == TEXT('1')) {
ProcessAutoexec(ppEnvironment, PATH_VARIABLE);
}
return(TRUE);
}
//+---------------------------------------------------------------------------
//
// Function: UpdateUserEnvironment
//
// Synopsis:
//
// Arguments: [pGlobals] --
// [ppEnvironment] --
//
// History: 11-01-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
UpdateUserEnvironment(
PGLOBALS pGlobals,
PVOID * ppEnvironment,
PWSTR pszOldDir
)
{
BOOL DeepShare;
TCHAR lpHomeShare[MAX_PATH] = TEXT("");
TCHAR lpHomePath[MAX_PATH] = TEXT("");
TCHAR lpHomeDrive[4] = TEXT("");
TCHAR lpHomeDirectory[MAX_PATH] = TEXT("");
BOOL TSHomeDir = FALSE;
TCHAR lpSmartcard[sizeof(pGlobals->Smartcard) + sizeof(pGlobals->SmartcardReader) + 1];
/*
* Initialize user's environment.
*/
SetUserEnvironmentVariable(ppEnvironment, USERNAME_VARIABLE, (LPTSTR)pGlobals->FlatUserName.Buffer, TRUE);
SetUserEnvironmentVariable(ppEnvironment, USERDOMAIN_VARIABLE, (LPTSTR)pGlobals->FlatDomain.Buffer, TRUE);
if (pGlobals->Smartcard[0] && pGlobals->SmartcardReader[0]) {
_snwprintf(
lpSmartcard,
sizeof(lpSmartcard) / sizeof(TCHAR),
TEXT("%s;%s"),
pGlobals->Smartcard,
pGlobals->SmartcardReader
);
SetUserEnvironmentVariable(ppEnvironment, SMARTCARD_VARIABLE, lpSmartcard, TRUE);
}
if ( !g_Console ) {
// See if the user specified a TerminalServer Home Directory.
// If so, we override the regular directory
if (lstrlen(pGlobals->MuGlobals.TSData.HomeDir) > 0) {
lstrcpy(lpHomeDirectory, pGlobals->MuGlobals.TSData.HomeDir);
TSHomeDir = TRUE;
}
if (lstrlen(pGlobals->MuGlobals.TSData.HomeDirDrive) > 0) {
lstrcpy(lpHomeDrive, pGlobals->MuGlobals.TSData.HomeDirDrive);
TSHomeDir = TRUE;
}
}
if (!TSHomeDir && pGlobals->Profile) {
if (pGlobals->Profile->HomeDirectoryDrive.Length &&
(pGlobals->Profile->HomeDirectoryDrive.Length + 1) < (MAX_PATH*sizeof(TCHAR))) {
lstrcpy(lpHomeDrive, pGlobals->Profile->HomeDirectoryDrive.Buffer);
}
if (pGlobals->Profile->HomeDirectory.Length &&
(pGlobals->Profile->HomeDirectory.Length + 1) < (MAX_PATH*sizeof(TCHAR))) {
lstrcpy(lpHomeDirectory, pGlobals->Profile->HomeDirectory.Buffer);
}
}
SetHomeDirectoryEnvVars(ppEnvironment,
lpHomeDirectory,
lpHomeDrive,
lpHomeShare,
lpHomePath,
&DeepShare);
ChangeToHomeDirectory( pGlobals,
ppEnvironment,
lpHomeDirectory,
lpHomeDrive,
lpHomeShare,
lpHomePath,
pszOldDir,
DeepShare
);
DoAutoexecStuff(pGlobals, ppEnvironment, PATH_VARIABLE);
SetEnvironmentVariables(pGlobals, USER_ENV_SUBKEY, ppEnvironment);
SetEnvironmentVariables(pGlobals, USER_VOLATILE_ENV_SUBKEY, ppEnvironment);
AppendNTPathWithAutoexecPath(ppEnvironment,
PATH_VARIABLE,
AUTOEXECPATH_VARIABLE);
if (!g_Console) {
HKEY Handle;
DWORD fPerSessionTempDir = 0;
DWORD dwValueData;
/*
* Open registry value set thru TSCC
*/
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
REG_CONTROL_TSERVER,
0,
KEY_READ,
&Handle ) == ERROR_SUCCESS )
{
DWORD ValueSize;
DWORD ValueType;
LONG rc;
ValueSize = sizeof(fPerSessionTempDir);
/*
* Read registry value
*/
rc = RegQueryValueExW( Handle,
REG_TERMSRV_PERSESSIONTEMPDIR,
NULL,
&ValueType,
(LPBYTE) &fPerSessionTempDir,
&ValueSize );
/*
* Close registry and key handle
*/
RegCloseKey( Handle );
}
/*
* Check the machine wide policy set thru Group Policy
*/
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
TS_POLICY_SUB_TREE,
0,
KEY_READ,
&Handle ) == ERROR_SUCCESS )
{
DWORD ValueSize;
DWORD ValueType;
LONG rc;
ValueSize = sizeof(fPerSessionTempDir);
/*
* Read registry value
*/
rc = RegQueryValueExW( Handle,
REG_TERMSRV_PERSESSIONTEMPDIR,
NULL,
&ValueType,
(LPBYTE) &dwValueData,
&ValueSize );
if (rc == ERROR_SUCCESS )
{
fPerSessionTempDir = dwValueData;
}
/*
* Close registry and key handle
*/
RegCloseKey( Handle );
}
if (fPerSessionTempDir) {
PTERMSRVCREATETEMPDIR pfnTermsrvCreateTempDir;
HANDLE dllHandle;
dllHandle = LoadLibrary(TEXT("wlnotify.dll"));
if (dllHandle) {
pfnTermsrvCreateTempDir = (PTERMSRVCREATETEMPDIR) GetProcAddress(
dllHandle,
"TermsrvCreateTempDir"
);
if (pfnTermsrvCreateTempDir) {
pfnTermsrvCreateTempDir( ppEnvironment,
pGlobals->UserProcessData.UserToken,
pGlobals->UserProcessData.NewThreadTokenSD);
}
FreeLibrary(dllHandle);
}
}
}
}
BOOL
ExecApplication(
IN LPTSTR pch,
IN LPTSTR Desktop,
IN PGLOBALS pGlobals,
IN PVOID pEnvironment,
IN DWORD Flags,
IN DWORD StartupFlags,
IN BOOL RestrictProcess,
OUT PPROCESS_INFORMATION ProcessInformation
)
{
STARTUPINFO si;
BOOL Result, IgnoreResult;
HANDLE ImpersonationHandle;
HANDLE ProcessToken;
//
// Initialize process startup info
//
si.cb = sizeof(STARTUPINFO);
si.lpReserved = pch;
si.lpTitle = pch;
si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
si.dwFlags = StartupFlags;
si.wShowWindow = SW_SHOW; // at least let the guy see it
si.lpReserved2 = NULL;
si.cbReserved2 = 0;
si.lpDesktop = Desktop;
//
// Impersonate the user so we get access checked correctly on
// the file we're trying to execute
//
ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
if (ImpersonationHandle == NULL) {
WLPrint(("ExecApplication failed to impersonate user"));
return(FALSE);
}
if (RestrictProcess &&
(pGlobals->UserProcessData.RestrictedToken != NULL) )
{
ProcessToken = pGlobals->UserProcessData.RestrictedToken;
}
else
{
ProcessToken = pGlobals->UserProcessData.UserToken;
}
//
// Create the app suspended
//
DebugLog((DEB_TRACE, "About to create process of %ws, on desktop %ws\n", pch, Desktop));
Result = CreateProcessAsUser(
ProcessToken,
NULL,
pch,
NULL,
NULL,
FALSE,
Flags | CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT,
pEnvironment,
NULL,
&si,
ProcessInformation);
IgnoreResult = StopImpersonating(ImpersonationHandle);
ASSERT(IgnoreResult);
return(Result);
}
BOOL
SetProcessQuotas(
PGLOBALS pGlobals,
PPROCESS_INFORMATION ProcessInformation,
PUSER_PROCESS_DATA UserProcessData
)
{
NTSTATUS Status = STATUS_SUCCESS;
BOOL Result;
QUOTA_LIMITS RequestedLimits;
UINT MessageId ;
RequestedLimits = UserProcessData->Quotas;
RequestedLimits.MinimumWorkingSetSize = 0;
RequestedLimits.MaximumWorkingSetSize = 0;
if (UserProcessData->Quotas.PagedPoolLimit != 0) {
Result = EnablePrivilege(SE_INCREASE_QUOTA_PRIVILEGE, TRUE);
if (!Result) {
WLPrint(("failed to enable increase_quota privilege"));
return(FALSE);
}
Status = NtSetInformationProcess(
ProcessInformation->hProcess,
ProcessQuotaLimits,
(PVOID)&RequestedLimits,
(ULONG)sizeof(QUOTA_LIMITS)
);
Result = EnablePrivilege(SE_INCREASE_QUOTA_PRIVILEGE, FALSE);
if (!Result) {
WLPrint(("failed to disable increase_quota privilege"));
}
}
if (STATUS_QUOTA_EXCEEDED == Status)
{
if ( TestTokenForAdmin( UserProcessData->UserToken ) )
{
MessageId = IDS_QUOTAEXHAUSTED ;
Status = STATUS_SUCCESS ;
}
else
{
MessageId = IDS_COULDNTSETQUOTAS ;
}
// Display a warning in this case
TimeoutMessageBox(pGlobals->hwndLogon,
pGlobals,
MessageId,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONERROR,
TIMEOUT_NONE);
}
#if DBG
if (!NT_SUCCESS(Status)) {
WLPrint(("SetProcessQuotas failed. Status: 0x%lx", Status));
}
#endif //DBG
return (NT_SUCCESS(Status));
}
DWORD
ExecProcesses(
PVOID pWlxContext,
IN LPTSTR Desktop,
IN PWSTR Processes,
PVOID *ppEnvironment,
DWORD Flags,
DWORD StartupFlags
)
{
PWCH pchData;
PROCESS_INFORMATION ProcessInformation;
DWORD dwExecuted = 0 ;
PWSTR pszTok;
PGLOBALS pGlobals = (PGLOBALS) pWlxContext;
WCHAR szCurrentDir[MAX_PATH];
pchData = Processes;
szCurrentDir[0] = L'\0';
if (*ppEnvironment) {
UpdateUserEnvironment(pGlobals, ppEnvironment, szCurrentDir);
}
SetLogonScriptVariables(pGlobals, ppEnvironment);
//we should not lauch autoenrollment in this case as it blocks the shell
//SetAutoEnrollVariables( pGlobals, ppEnvironment );
if (g_IsTerminalServer) {
CtxCreateMigrateEnv( *ppEnvironment );
pWlxFuncs->WlxWin31Migrate(pGlobals->hGlobalWlx);
CtxDeleteMigrateEnv( );
}
pszTok = wcstok(pchData, TEXT(","));
while (pszTok)
{
if (*pszTok == TEXT(' '))
{
while (*pszTok++ == TEXT(' '))
;
}
if (ExecApplication((LPTSTR)pszTok,
Desktop,
pGlobals,
*ppEnvironment,
Flags,
StartupFlags,
TRUE, // restrict application
&ProcessInformation)) {
dwExecuted++;
if (SetProcessQuotas(pGlobals,
&ProcessInformation,
&pGlobals->UserProcessData))
{
ResumeThread(ProcessInformation.hThread);
}
else
{
TerminateProcess(ProcessInformation.hProcess,
ERROR_ACCESS_DENIED);
}
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
} else {
DebugLog((DEB_WARN, "Cannot start %ws on %ws, error %d.", pszTok, Desktop, GetLastError()));
}
pszTok = wcstok(NULL, TEXT(","));
}
DeleteLogonScriptVariables(pGlobals, ppEnvironment);
if ( szCurrentDir[0] )
{
SetCurrentDirectory(szCurrentDir);
}
return dwExecuted ;
}
INT_PTR
NoDCDlgProc(
HWND hDlg,
UINT Message,
WPARAM wParam,
LPARAM lParam )
{
DWORD Button;
HWND hwnd;
switch (Message)
{
case WM_INITDIALOG:
CentreWindow( hDlg );
if ( !hNoDCIcon )
{
hNoDCIcon = LoadImage( hDllInstance,
MAKEINTRESOURCE( IDI_NODC_ICON ),
IMAGE_ICON,
64, 64,
LR_DEFAULTCOLOR );
}
SendMessage( GetDlgItem( hDlg, IDD_NODC_FRAME ),
STM_SETICON,
(WPARAM) hNoDCIcon,
0 );
if ( GetProfileInt( WINLOGON, TEXT("AllowDisableDCNotify"), 0 ) )
{
hwnd = GetDlgItem( hDlg, IDD_NODC_TEXT2 );
ShowWindow( hwnd, SW_HIDE );
EnableWindow( hwnd, FALSE );
}
else
{
hwnd = GetDlgItem( hDlg, IDD_NODC_CHECK );
CheckDlgButton( hDlg, IDD_NODC_CHECK, BST_UNCHECKED );
ShowWindow( hwnd, SW_HIDE );
EnableWindow( hwnd, FALSE );
}
return( TRUE );
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
{
Button = IsDlgButtonChecked( hDlg, IDD_NODC_CHECK );
EndDialog( hDlg, Button );
return( TRUE );
}
}
return( FALSE );
}
VOID
DoNoDCDialog(
PGLOBALS pGlobals )
{
HKEY hKey;
int err;
DWORD disp;
DWORD Flag;
DWORD dwType;
DWORD cbData;
BOOL MappedHKey;
PWSTR ReportControllerMissing;
Flag = 1;
hKey = NULL ;
if (OpenHKeyCurrentUser(pGlobals))
{
MappedHKey = TRUE;
err = RegCreateKeyEx( pGlobals->UserProcessData.hCurrentUser,
WINLOGON_USER_KEY,
0, NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&hKey,
&disp );
if (err == 0)
{
cbData = sizeof(DWORD);
err = RegQueryValueEx( hKey,
NODCMESSAGE,
NULL,
&dwType,
(LPBYTE) &Flag,
&cbData );
if (err != ERROR_SUCCESS || dwType != REG_DWORD)
{
Flag = 1;
}
}
else
{
hKey = NULL;
}
}
else
{
MappedHKey = FALSE;
}
if ( Flag )
{
ReportControllerMissing = AllocAndGetProfileString( APPLICATION_NAME,
REPORT_CONTROLLER_MISSING,
TEXT("FALSE")
);
if ( ReportControllerMissing )
{
if ( lstrcmp( ReportControllerMissing, TEXT("TRUE")) == 0 )
{
Flag = 1;
}
else
{
Flag = 0;
}
Free( ReportControllerMissing );
}
else
{
Flag = 1;
}
}
if (Flag)
{
pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, 120 );
Flag = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
hDllInstance,
(LPTSTR) IDD_NODC_DIALOG,
NULL,
NoDCDlgProc,
0 );
}
else
{
Flag = BST_CHECKED;
}
if (hKey)
{
if (Flag == BST_CHECKED)
{
Flag = 0;
}
else
{
Flag = 1;
}
RegSetValueEx( hKey,
NODCMESSAGE,
0,
REG_DWORD,
(LPBYTE) &Flag,
sizeof(DWORD) );
RegCloseKey( hKey );
}
if (MappedHKey)
{
CloseHKeyCurrentUser(pGlobals);
}
}
//+---------------------------------------------------------------------------
//
// Function: GetPasswordExpiryWarningPeriod
//
// Synopsis: Returns the password expiry warning period in days: either
// the value in the registry or the default value.
//
// Arguments: None
//
// Returns: Password expiry warning period in days.
//
// History: 10-09-01 CenkE Copied from ShouldPasswordExpiryWarningBeShown
//
//----------------------------------------------------------------------------
DWORD
GetPasswordExpiryWarningPeriod (
VOID
)
{
HKEY hKey;
DWORD dwSize;
DWORD dwType;
DWORD DaysToCheck;
DaysToCheck = PASSWORD_EXPIRY_WARNING_DAYS;
if (RegOpenKey(HKEY_LOCAL_MACHINE, WINLOGON_USER_KEY, &hKey) == 0)
{
dwSize = sizeof(DWORD);
if (RegQueryValueEx(hKey,
PASSWORD_EXPIRY_WARNING,
0,
&dwType,
(LPBYTE) &DaysToCheck,
&dwSize ) ||
(dwType != REG_DWORD) )
{
DaysToCheck = PASSWORD_EXPIRY_WARNING_DAYS;
}
RegCloseKey(hKey);
}
return DaysToCheck;
}
//+---------------------------------------------------------------------------
//
// Function: GetDaysToExpiry
//
// Synopsis: If the passed in times can be converted to seconds since 1980,
// returns how many days there are from CurrentTime to ExpiryTime
//
// Arguments: CurrentTime -- This can be the current time or the time of a
// logon etc. as FILETIME.
// ExpiryTime -- PasswordMustChange time from profile.
// DaysToExpiry -- If successful, days to password expiry is
// returned here.
//
// Returns: TRUE - DaysToExpiry could be calculated.
// FALSE - DaysToExpiry could not be calculated, or the password
// never expires.
//
// History: 10-09-01 CenkE Copied from ShouldPasswordExpiryWarningBeShown
//
//----------------------------------------------------------------------------
#define SECONDS_PER_DAY (60*60*24)
BOOL
GetDaysToExpiry (
IN PLARGE_INTEGER CurrentTime,
IN PLARGE_INTEGER ExpiryTime,
OUT PDWORD DaysToExpiry
)
{
ULONG ElapsedSecondsNow;
ULONG ElapsedSecondsPasswordExpires;
//
// Convert the expiry time to seconds.
//
if (!RtlTimeToSecondsSince1980(ExpiryTime, &ElapsedSecondsPasswordExpires))
{
//
// The time was not expressable in 32-bit seconds
// Set seconds to password expiry based on whether the expiry
// time is way in the past or way in the future.
//
// Never expires?
if (ExpiryTime->QuadPart > CurrentTime->QuadPart)
{
return FALSE;
}
ElapsedSecondsPasswordExpires = 0; // Already expired
}
//
// Convert the start time to seconds.
//
if (!RtlTimeToSecondsSince1980(CurrentTime, &ElapsedSecondsNow)) {
return FALSE;
}
if (ElapsedSecondsPasswordExpires < ElapsedSecondsNow)
{
(*DaysToExpiry) = 0;
}
else
{
(*DaysToExpiry) = (ElapsedSecondsPasswordExpires - ElapsedSecondsNow)/SECONDS_PER_DAY;
}
return TRUE;
}
BOOL
ShouldPasswordExpiryWarningBeShown(
IN PGLOBALS pGlobals,
IN BOOL LogonCheck,
OUT PDWORD pDaysToExpiry )
{
ULONG DaysToExpiry;
DWORD DaysToCheck;
LARGE_INTEGER Now;
LARGE_INTEGER Last;
PLARGE_INTEGER StartTime;
if (pGlobals->TransderedCredentials) {
// do not display password expiry in this case as it
// would otherwise display the password expiry twice
return FALSE;
}
Last.LowPart = pGlobals->LastNotification.dwLowDateTime;
Last.HighPart = pGlobals->LastNotification.dwHighDateTime;
GetSystemTimeAsFileTime((FILETIME*) &Now);
Last.QuadPart += (24 * 60 * 60 * 10000000I64);
//
// Only if last shown more than 24 hours ago
//
if (Now.QuadPart < Last.QuadPart)
{
return FALSE;
}
//
// Get password expiry warning period
//
DaysToCheck = GetPasswordExpiryWarningPeriod();
//
// Go get parameters from our user's profile
//
if (!pGlobals->Profile)
{
return FALSE;
}
if ( LogonCheck )
{
StartTime = &pGlobals->LogonTime;
}
else
{
StartTime = &Now;
}
//
// Determine number of days till the password expires.
//
if (!GetDaysToExpiry(StartTime,
&(pGlobals->Profile->PasswordMustChange),
&DaysToExpiry))
{
return FALSE;
}
// Not within warning period?
if (DaysToExpiry > DaysToCheck)
{
return FALSE;
}
// If return pointer... fill in
if ( pDaysToExpiry )
{
*pDaysToExpiry = DaysToExpiry;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: CheckPasswordExpiry
//
// Synopsis: Does the password expiration check on demand
//
// Arguments: [pGlobals] --
// [LogonCheck] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 8-13-96 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
INT_PTR
CheckPasswordExpiry(
PGLOBALS pGlobals,
BOOL LogonCheck)
{
LARGE_INTEGER Now;
ULONG DaysToExpiry;
TCHAR Buffer1[MAX_STRING_BYTES];
TCHAR Buffer2[MAX_STRING_BYTES];
INT_PTR Result = IDOK;
LPTSTR UserSidString;
// Get current time
GetSystemTimeAsFileTime((FILETIME*) &Now);
if (ShouldPasswordExpiryWarningBeShown(pGlobals, LogonCheck, &DaysToExpiry))
{
//
// Disable optimized logon for this user for next time if
// we are entering the password expiry warning period, so
// password expiry warning dialogs will be shown if the user
// does not change the password right now. Otherwise
// for cached logons password expiry time is invented to be
// forever in the future.
//
if (pGlobals->UserProcessData.UserToken)
{
UserSidString = GcGetSidString(pGlobals->UserProcessData.UserToken);
if (UserSidString)
{
GcSetNextLogonCacheable(UserSidString, FALSE);
GcDeleteSidString(UserSidString);
}
}
if (DaysToExpiry > 0)
{
LoadString(hDllInstance, IDS_PASSWORD_WILL_EXPIRE, Buffer1, sizeof(Buffer1) / sizeof( TCHAR ));
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, DaysToExpiry);
}
else
{
LoadString(hDllInstance, IDS_PASSWORD_EXPIRES_TODAY, Buffer2, sizeof(Buffer2) / sizeof( TCHAR ));
}
LoadString(hDllInstance, IDS_LOGON_MESSAGE, Buffer1, sizeof(Buffer1) / sizeof( TCHAR ) );
pGlobals->LastNotification.dwHighDateTime = Now.HighPart;
pGlobals->LastNotification.dwLowDateTime = Now.LowPart;
Result = TimeoutMessageBoxlpstr(NULL,
pGlobals,
Buffer2,
Buffer1,
MB_YESNO | MB_ICONEXCLAMATION,
(LogonCheck ? LOGON_TIMEOUT : 60));
if (Result == IDYES)
{
//
// Let the user change their password now
//
if ( LogonCheck && pGlobals->SmartCardLogon )
{
LogonCheck = FALSE ;
}
if ( LogonCheck )
{
RevealPassword( &pGlobals->PasswordString );
Result = ChangePasswordLogon(NULL,
pGlobals,
pGlobals->UserName,
pGlobals->Domain,
pGlobals->Password);
if ( Result == IDCANCEL )
{
//
// If we got cancelled, then the string won't get
// updated, so rehide it so that unlocks work later
//
HidePassword( &pGlobals->Seed,
&pGlobals->PasswordString );
}
}
else
{
Result = ChangePassword(
NULL,
pGlobals,
pGlobals->UserName,
pGlobals->Domain,
CHANGEPWD_OPTION_ALL );
}
}
if (DLG_INTERRUPTED(Result))
{
return(Result);
}
}
return MSGINA_DLG_SUCCESS;
}
/****************************************************************************\
*
* FUNCTION: DisplayPostShellLogonMessages
*
* PURPOSE: Displays any security warnings to the user after a successful logon
* The messages are displayed while the shell is starting up.
*
* RETURNS: DLG_SUCCESS - the dialogs were displayed successfully.
* DLG_INTERRUPTED() - a set defined in winlogon.h
*
* NOTE: Screen-saver timeouts are handled by our parent dialog so this
* routine should never return DLG_SCREEN_SAVER_TIMEOUT
*
* HISTORY:
*
* 12-09-91 Davidc Created.
*
\****************************************************************************/
INT_PTR
DisplayPostShellLogonMessages(
PGLOBALS pGlobals
)
{
INT_PTR Result = IDOK;
//
// Check to see if the system time is properly set
//
{
SYSTEMTIME Systime;
GetSystemTime(&Systime);
if ( Systime.wYear < 2000 ) {
Result = TimeoutMessageBox(
NULL,
pGlobals,
IDS_INVALID_TIME_MSG,
IDS_INVALID_TIME,
MB_OK | MB_ICONSTOP,
TIMEOUT_NONE
);
if (DLG_INTERRUPTED(Result)) {
return(Result);
}
}
}
pGlobals->LastNotification.dwHighDateTime = 0;
pGlobals->LastNotification.dwLowDateTime = 0;
if (!pGlobals->TransderedCredentials) {
// do not display password expiry in this case as it
// would otherwise display the password expiry twice
Result = CheckPasswordExpiry( pGlobals, TRUE );
}
if (pGlobals->Profile != NULL) {
//
// Logon cache used
//
if (pGlobals->Profile->UserFlags & LOGON_CACHED_ACCOUNT)
{
//
// Don't display any warning messages if we did an optimized logon.
//
if (pGlobals->OptimizedLogonStatus != OLS_LogonIsCached) {
DoNoDCDialog( pGlobals );
}
}
}
//
// Hash the password away, then destroy the text copy completely.
//
if (!pGlobals->TransderedCredentials) {
RevealPassword( &pGlobals->PasswordString );
if (pGlobals->SmartCardLogon)
{
// We don't want the SC PIN hash
// (prevents password unlocks using the PIN)
memset(pGlobals->PasswordHash, 0, sizeof(pGlobals->PasswordHash));
}
else
{
HashPassword( &pGlobals->PasswordString, pGlobals->PasswordHash );
}
ErasePassword( &pGlobals->PasswordString );
}
return(IDOK);
}
/***************************************************************************\
* FUNCTION: SetLogonScriptVariables
*
* PURPOSE: Sets the appropriate environment variables in the user
* process environment block so that the logon script information
* can be passed into the userinit app.
*
* RETURNS: TRUE on success, FALSE on failure
*
* HISTORY:
*
* 21-Aug-92 Davidc Created.
*
\***************************************************************************/
BOOL
SetLogonScriptVariables(
PGLOBALS pGlobals,
PVOID * pEnvironment
)
{
NTSTATUS Status;
LPWSTR EncodedMultiSz;
UNICODE_STRING Name, Value;
//
// Note whether we performed an optimized logon.
//
RtlInitUnicodeString(&Name, OPTIMIZED_LOGON_VARIABLE);
if (pGlobals->OptimizedLogonStatus == OLS_LogonIsCached) {
RtlInitUnicodeString(&Value, L"1");
} else {
RtlInitUnicodeString(&Value, L"0");
}
Status = RtlSetEnvironmentVariable(pEnvironment, &Name, &Value);
if (!NT_SUCCESS(Status)) {
WLPrint(("Failed to set environment variable <%Z> to value <%Z>", &Name, &Value));
goto CleanupAndExit;
}
//
// Set our primary authenticator logon script variables
//
if (pGlobals->Profile != NULL) {
//
// Set the server name variable
//
RtlInitUnicodeString(&Name, LOGON_SERVER_VARIABLE);
Status = RtlSetEnvironmentVariable(pEnvironment, &Name, &pGlobals->Profile->LogonServer);
if (!NT_SUCCESS(Status)) {
WLPrint(("Failed to set environment variable <%Z> to value <%Z>", &Name, &pGlobals->Profile->LogonServer));
goto CleanupAndExit;
}
//
// Set the script name variable
//
RtlInitUnicodeString(&Name, LOGON_SCRIPT_VARIABLE);
Status = RtlSetEnvironmentVariable(pEnvironment, &Name, &pGlobals->Profile->LogonScript);
if (!NT_SUCCESS(Status)) {
WLPrint(("Failed to set environment variable <%Z> to value <%Z>", &Name, &pGlobals->Profile->LogonScript));
goto CleanupAndExit;
}
}
//
// Set the multiple provider script name variable
//
if (pGlobals->MprLogonScripts != NULL) {
RtlInitUnicodeString(&Name, MPR_LOGON_SCRIPT_VARIABLE);
EncodedMultiSz = EncodeMultiSzW(pGlobals->MprLogonScripts);
if (EncodedMultiSz == NULL) {
WLPrint(("Failed to encode MPR logon scripts into a string"));
goto CleanupAndExit;
}
RtlInitUnicodeString(&Value, EncodedMultiSz);
Status = RtlSetEnvironmentVariable(pEnvironment, &Name, &Value);
Free(EncodedMultiSz);
if (!NT_SUCCESS(Status)) {
WLPrint(("Failed to set mpr scripts environment variable <%Z>", &Name));
goto CleanupAndExit;
}
}
return(TRUE);
CleanupAndExit:
DeleteLogonScriptVariables(pGlobals, pEnvironment);
return(FALSE);
}
BOOL
SetAutoEnrollVariables(
PGLOBALS pGlobals,
PVOID * pEnvironment
)
{
BOOL Result = FALSE ;
UNICODE_STRING Name, Value ;
// we should check for safe boot, domain member, and policy flag in registry
// but we will always spawn userinit, so instead of duplicationg code, let
// autoenrollment do those checks.
/*
if (OpenHKeyCurrentUser(pGlobals))
{
if ( RegOpenKeyEx( pGlobals->UserProcessData.hCurrentUser,
WINLOGON_POLICY_KEY,
0,
KEY_READ,
&hKey ) == 0 )
{
dwSize = sizeof( Result );
RegQueryValueEx( hKey,
DISABLE_AUTOENROLLMENT,
0,
&dwType,
(PBYTE) &Result,
&dwSize );
RegCloseKey( hKey );
}
CloseHKeyCurrentUser(pGlobals);
}
*/
//
// If the Disable flag hasn't been turned on, add the env var
//
if ( !Result )
{
RtlInitUnicodeString( &Name, USER_INIT_AUTOENROLL );
RtlInitUnicodeString( &Value, AUTOENROLL_NONEXCLUSIVE );
RtlSetEnvironmentVariable(pEnvironment, &Name, &Value);
RtlInitUnicodeString( &Name, USER_INIT_AUTOENROLLMODE );
RtlInitUnicodeString( &Value, AUTOENROLL_STARTUP );
RtlSetEnvironmentVariable(pEnvironment, &Name, &Value);
}
return TRUE ;
}
/***************************************************************************\
* FUNCTION: DeleteLogonScriptVariables
*
* PURPOSE: Deletes the environment variables in the user process
* environment block that we use to communicate logon script
* information to the userinit app
*
* RETURNS: Nothing
*
* HISTORY:
*
* 21-Aug-92 Davidc Created.
*
\***************************************************************************/
VOID
DeleteLogonScriptVariables(
PGLOBALS pGlobals,
PVOID * pEnvironment
)
{
NTSTATUS Status;
UNICODE_STRING Name;
RtlInitUnicodeString(&Name, OPTIMIZED_LOGON_VARIABLE);
Status = RtlSetEnvironmentVariable(pEnvironment, &Name, NULL);
if (!NT_SUCCESS(Status) && (Status != STATUS_UNSUCCESSFUL) ) {
WLPrint(("Failed to delete environment variable <%Z>, status = 0x%lx", &Name, Status));
}
RtlInitUnicodeString(&Name, LOGON_SERVER_VARIABLE);
Status = RtlSetEnvironmentVariable(pEnvironment, &Name, NULL);
if (!NT_SUCCESS(Status) && (Status != STATUS_UNSUCCESSFUL) ) {
WLPrint(("Failed to delete environment variable <%Z>, status = 0x%lx", &Name, Status));
}
RtlInitUnicodeString(&Name, LOGON_SCRIPT_VARIABLE);
Status = RtlSetEnvironmentVariable(pEnvironment, &Name, NULL);
if (!NT_SUCCESS(Status) && (Status != STATUS_UNSUCCESSFUL) ) {
WLPrint(("Failed to delete environment variable <%Z>, status = 0x%lx", &Name, Status));
}
if (pGlobals->MprLogonScripts != NULL) {
RtlInitUnicodeString(&Name, MPR_LOGON_SCRIPT_VARIABLE);
Status = RtlSetEnvironmentVariable(pEnvironment, &Name, NULL);
if (!NT_SUCCESS(Status) && (Status != STATUS_UNSUCCESSFUL) ) {
WLPrint(("Failed to delete environment variable <%Z>, status = 0x%lx", &Name, Status));
}
}
}
BOOL
WINAPI
WlxActivateUserShell(
PVOID pWlxContext,
PWSTR pszDesktop,
PWSTR pszMprLogonScript,
PVOID pEnvironment
)
{
BOOL bExec;
PGLOBALS pGlobals;
PWSTR pchData;
BOOL fReturn = FALSE;
_ShellReleaseLogonMutex(TRUE);
pchData = AllocAndGetPrivateProfileString(APPLICATION_NAME,
USERINIT_KEY,
TEXT("%SystemRoot%\\system32\\userinit.exe"),
NULL);
if ( !pchData )
{
if (pszMprLogonScript) {
LocalFree(pszMprLogonScript);
}
goto WlxAUSEnd;
}
pGlobals = (PGLOBALS) pWlxContext;
if (pGlobals->MprLogonScripts) {
LocalFree(pGlobals->MprLogonScripts);
}
pGlobals->MprLogonScripts = pszMprLogonScript;
bExec = ExecProcesses(pWlxContext, pszDesktop, pchData, &pEnvironment, 0, 0);
Free( pchData );
if (!bExec && (DebugAllowNoShell == 0))
{
goto WlxAUSEnd;
}
if ( pGlobals->ExtraApps )
{
ExecProcesses( pWlxContext, pszDesktop, pGlobals->ExtraApps, &pEnvironment, 0, 0 );
Free( pGlobals->ExtraApps );
pGlobals->ExtraApps = NULL;
}
pGlobals->UserProcessData.pEnvironment = pEnvironment;
// Write out the current user name to a place where shell logoff can read it
if (OpenHKeyCurrentUser(pGlobals))
{
HKEY hkeyExplorer = NULL;
if (ERROR_SUCCESS == RegOpenKeyEx(pGlobals->UserProcessData.hCurrentUser,
SHUTDOWN_SETTING_KEY, 0, KEY_SET_VALUE, &hkeyExplorer))
{
RegSetValueEx(hkeyExplorer, LOGON_USERNAME_SETTING, 0, REG_SZ,
(CONST BYTE *) pGlobals->UserName,
((lstrlen(pGlobals->UserName) + 1) * sizeof(WCHAR)));
RegCloseKey(hkeyExplorer);
}
CloseHKeyCurrentUser(pGlobals);
}
// Run the dirty dialog box.
if ( WinlogonDirtyDialog( NULL, pGlobals ) == WLX_SAS_ACTION_LOGOFF )
{
//
// If this returns logoff, it means that the dialog timed out and
// we need to force the user back off. Not the best user experience,
// but that's what the PMs want.
//
}
else
{
fReturn = TRUE ;
}
WlxAUSEnd:
return fReturn;
}
BOOL
WINAPI
WlxStartApplication(
PVOID pWlxContext,
PWSTR pszDesktop,
PVOID pEnvironment,
PWSTR pszCmdLine
)
{
PROCESS_INFORMATION ProcessInformation;
BOOL bExec;
PGLOBALS pGlobals = (PGLOBALS) pWlxContext;
WCHAR szCurrentDir[MAX_PATH];
WCHAR localApp[ MAX_PATH ];
szCurrentDir[0] = L'\0';
if (pEnvironment) {
UpdateUserEnvironment(pGlobals, &pEnvironment, szCurrentDir);
}
if ( (_wcsicmp(pszCmdLine, L"explorer.exe" ) == 0 ) ||
(_wcsicmp(pszCmdLine, L"explorer" ) == 0 ) ) {
//
// Avoid security problem since explorer is in SystemRoot,
// not SystemRoot\system32
//
if ( ExpandEnvironmentStrings(
L"%SystemRoot%\\explorer.exe",
localApp,
MAX_PATH ) != 0 ) {
pszCmdLine = localApp ;
}
}
bExec = ExecApplication (pszCmdLine,
pszDesktop,
pGlobals,
pEnvironment,
0,
STARTF_USESHOWWINDOW,
_wcsicmp(pszCmdLine, TEXT("taskmgr.exe")), // don't restrict application
&ProcessInformation);
if (pEnvironment)
{ // We don't need it anymore
VirtualFree(pEnvironment, 0, MEM_RELEASE);
}
if (!bExec) {
if ( szCurrentDir[0] )
{
SetCurrentDirectory(szCurrentDir);
}
return(FALSE);
}
if (SetProcessQuotas(pGlobals,
&ProcessInformation,
&pGlobals->UserProcessData))
{
ResumeThread(ProcessInformation.hThread);
}
else
{
TerminateProcess(ProcessInformation.hProcess,
ERROR_ACCESS_DENIED);
}
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
if ( szCurrentDir[0] )
{
SetCurrentDirectory(szCurrentDir);
}
return(TRUE);
}
void
CtxCreateMigrateEnv( PVOID pEnv )
{
NTSTATUS Status;
UNICODE_STRING Name, Value;
DWORD cb;
cb = 1024;
Value.Buffer = Alloc(sizeof(TCHAR)*cb);
if (!Value.Buffer)
return;
Value.Length = (USHORT)cb;
Value.MaximumLength = (USHORT)cb;
RtlInitUnicodeString( &Name, HOMEDRIVE_VARIABLE );
Status = RtlQueryEnvironmentVariable_U( pEnv, &Name, &Value );
if ( NT_SUCCESS(Status) )
SetEnvironmentVariable( HOMEDRIVE_VARIABLE, Value.Buffer );
Value.Length = (USHORT)cb;
Value.MaximumLength = (USHORT)cb;
RtlInitUnicodeString( &Name, HOMEPATH_VARIABLE );
Status = RtlQueryEnvironmentVariable_U( pEnv, &Name, &Value );
if ( NT_SUCCESS(Status) )
SetEnvironmentVariable( HOMEPATH_VARIABLE, Value.Buffer );
Value.Length = (USHORT)cb;
Value.MaximumLength = (USHORT)cb;
RtlInitUnicodeString( &Name, INIDRIVE_VARIABLE );
Status = RtlQueryEnvironmentVariable_U( pEnv, &Name, &Value );
if ( NT_SUCCESS(Status) )
SetEnvironmentVariable( INIDRIVE_VARIABLE, Value.Buffer );
Value.Length = (USHORT)cb;
Value.MaximumLength = (USHORT)cb;
RtlInitUnicodeString(&Name, INIPATH_VARIABLE);
Status = RtlQueryEnvironmentVariable_U( pEnv, &Name, &Value );
if ( NT_SUCCESS(Status) )
SetEnvironmentVariable( INIPATH_VARIABLE, Value.Buffer );
Free(Value.Buffer);
}
void
CtxDeleteMigrateEnv( )
{
SetEnvironmentVariable( HOMEDRIVE_VARIABLE, NULL);
SetEnvironmentVariable( HOMEPATH_VARIABLE, NULL);
SetEnvironmentVariable( INIDRIVE_VARIABLE, NULL);
SetEnvironmentVariable( INIPATH_VARIABLE, NULL);
}