summaryrefslogtreecommitdiffstats
path: root/private/windows/gina/winlogon
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/windows/gina/winlogon
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/windows/gina/winlogon')
-rw-r--r--private/windows/gina/winlogon/debug.c306
-rw-r--r--private/windows/gina/winlogon/debug.h62
-rw-r--r--private/windows/gina/winlogon/dialogs.dlg48
-rw-r--r--private/windows/gina/winlogon/dialogs.h24
-rw-r--r--private/windows/gina/winlogon/doslog.c59
-rw-r--r--private/windows/gina/winlogon/doslog.h17
-rw-r--r--private/windows/gina/winlogon/envvar.c1458
-rw-r--r--private/windows/gina/winlogon/envvar.h73
-rw-r--r--private/windows/gina/winlogon/ginamgr.c220
-rw-r--r--private/windows/gina/winlogon/ginamgr.h159
-rw-r--r--private/windows/gina/winlogon/i386/os2ssmig.c2104
-rw-r--r--private/windows/gina/winlogon/i386/os2ssmig.h24
-rw-r--r--private/windows/gina/winlogon/i386/os2ssrtl.c1037
-rw-r--r--private/windows/gina/winlogon/i386/os2ssrtl.h121
-rw-r--r--private/windows/gina/winlogon/i386/sources2
-rw-r--r--private/windows/gina/winlogon/logfull.h22
-rw-r--r--private/windows/gina/winlogon/loggedon.h23
-rw-r--r--private/windows/gina/winlogon/logging.h31
-rw-r--r--private/windows/gina/winlogon/logoff.c1284
-rw-r--r--private/windows/gina/winlogon/logoff.h72
-rw-r--r--private/windows/gina/winlogon/logon.h23
-rw-r--r--private/windows/gina/winlogon/makefile6
-rw-r--r--private/windows/gina/winlogon/makefile.inc14
-rw-r--r--private/windows/gina/winlogon/misc.c143
-rw-r--r--private/windows/gina/winlogon/misc.h47
-rw-r--r--private/windows/gina/winlogon/monitor.c369
-rw-r--r--private/windows/gina/winlogon/monitor.h66
-rw-r--r--private/windows/gina/winlogon/msgalias.c171
-rw-r--r--private/windows/gina/winlogon/msgalias.h67
-rw-r--r--private/windows/gina/winlogon/precomp.h41
-rw-r--r--private/windows/gina/winlogon/provider.c1045
-rw-r--r--private/windows/gina/winlogon/provider.h45
-rw-r--r--private/windows/gina/winlogon/regini.c2527
-rw-r--r--private/windows/gina/winlogon/regini.h52
-rw-r--r--private/windows/gina/winlogon/removabl.c866
-rw-r--r--private/windows/gina/winlogon/removabl.h43
-rw-r--r--private/windows/gina/winlogon/res.rc35
-rw-r--r--private/windows/gina/winlogon/sas.c524
-rw-r--r--private/windows/gina/winlogon/sas.h24
-rw-r--r--private/windows/gina/winlogon/scrnsave.c981
-rw-r--r--private/windows/gina/winlogon/scrnsave.h27
-rw-r--r--private/windows/gina/winlogon/secutil.c2676
-rw-r--r--private/windows/gina/winlogon/secutil.h216
-rw-r--r--private/windows/gina/winlogon/setup.c582
-rw-r--r--private/windows/gina/winlogon/setup.h102
-rw-r--r--private/windows/gina/winlogon/shell.c170
-rw-r--r--private/windows/gina/winlogon/shutdown.h23
-rw-r--r--private/windows/gina/winlogon/shutdown.icobin0 -> 766 bytes
-rw-r--r--private/windows/gina/winlogon/sources88
-rw-r--r--private/windows/gina/winlogon/stringid.h44
-rw-r--r--private/windows/gina/winlogon/strings.h54
-rw-r--r--private/windows/gina/winlogon/strings.rc46
-rw-r--r--private/windows/gina/winlogon/sysinit.c969
-rw-r--r--private/windows/gina/winlogon/sysinit.h65
-rw-r--r--private/windows/gina/winlogon/sysshut.c1395
-rw-r--r--private/windows/gina/winlogon/sysshut.dlg15
-rw-r--r--private/windows/gina/winlogon/sysshut.h14
-rw-r--r--private/windows/gina/winlogon/timeout.c1248
-rw-r--r--private/windows/gina/winlogon/timeout.h129
-rw-r--r--private/windows/gina/winlogon/usrenv.c564
-rw-r--r--private/windows/gina/winlogon/usrenv.h96
-rw-r--r--private/windows/gina/winlogon/usrpro.c260
-rw-r--r--private/windows/gina/winlogon/usrpro.h29
-rw-r--r--private/windows/gina/winlogon/win31mig.c287
-rw-r--r--private/windows/gina/winlogon/win31mig.dlg19
-rw-r--r--private/windows/gina/winlogon/win31mig.h24
-rw-r--r--private/windows/gina/winlogon/winlogon.c378
-rw-r--r--private/windows/gina/winlogon/winlogon.h418
-rw-r--r--private/windows/gina/winlogon/winutil.c834
-rw-r--r--private/windows/gina/winlogon/winutil.h127
-rw-r--r--private/windows/gina/winlogon/wlevents.mc62
-rw-r--r--private/windows/gina/winlogon/wlx.c2126
-rw-r--r--private/windows/gina/winlogon/wlxutil.c1203
-rw-r--r--private/windows/gina/winlogon/wlxutil.h70
74 files changed, 28595 insertions, 0 deletions
diff --git a/private/windows/gina/winlogon/debug.c b/private/windows/gina/winlogon/debug.c
new file mode 100644
index 000000000..2e1f94e9e
--- /dev/null
+++ b/private/windows/gina/winlogon/debug.c
@@ -0,0 +1,306 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: debug.c
+//
+// Contents: Debugging support functions
+//
+// Classes:
+//
+// Functions:
+//
+// Note: This file is not compiled for retail builds
+//
+// History: 4-29-93 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+#if DBG // NOTE: This file not compiled for retail builds
+
+#include "precomp.h"
+#pragma hdrstop
+
+FILE * LogFile;
+DWORD WinlogonInfoLevel = 3;
+
+
+// Debugging support functions.
+
+// These two functions do not exist in Non-Debug builds. They are wrappers
+// to the commnot functions (maybe I should get rid of that as well...)
+// that echo the message to a log file.
+
+char * DebLevel[] = { "Winlogon-Error",
+ "Winlogon-Warn",
+ "Winlogon-Trace",
+ "Winlogon-Trace-Init",
+ "Winlogon-Trace-Timeout",
+ "Winlogon-Trace-SAS",
+ "Winlogon-Trace-State",
+ "Winlogon-Trace-MPR",
+ "Should-not-see",
+ "Winlogon-Trace-Profile",
+ "Should-not-see",
+ "Should-not-see",
+ "Should-not-see",
+ "Winlogon-Trace-Migrate",
+ "Should-not-see",
+ "Winlogon-Trace-Setup"
+ };
+
+typedef struct _DebugKeys {
+ char * Name;
+ DWORD Value;
+} DebugKeys, *PDebugKeys;
+
+DebugKeys DebugKeyNames[] = {
+ {"Error", DEB_ERROR},
+ {"Warning", DEB_WARN},
+ {"Trace", DEB_TRACE},
+ {"Init", DEB_TRACE_INIT},
+ {"Timeout", DEB_TRACE_TIMEOUT},
+ {"Sas", DEB_TRACE_SAS},
+ {"State", DEB_TRACE_STATE},
+ {"MPR", DEB_TRACE_MPR},
+ {"CoolSwitch", DEB_COOL_SWITCH},
+ {"Profile", DEB_TRACE_PROFILE},
+ {"DebugLsa", DEB_DEBUG_LSA},
+ {"DebugSpm", DEB_DEBUG_LSA},
+ {"DebugMpr", DEB_DEBUG_MPR},
+ {"DebugGo", DEB_DEBUG_NOWAIT},
+ {"Migrate", DEB_TRACE_MIGRATE},
+ {"DebugServices", DEB_DEBUG_SERVICES},
+ {"Setup", DEB_TRACE_SETUP},
+ };
+
+#define NUM_DEBUG_KEYS sizeof(DebugKeyNames) / sizeof(DebugKeys)
+#define NUM_BREAK_KEYS sizeof(BreakKeyNames) / sizeof(DebugKeys)
+
+//+---------------------------------------------------------------------------
+//
+// Function: LogEvent
+//
+// Synopsis: Logs an event to the console and, optionally, a file.
+//
+// Effects:
+//
+// Arguments: [Mask] --
+// [Format] --
+// [Format] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 4-29-93 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+void
+LogEvent( long Mask,
+ const char * Format,
+ ...)
+{
+ va_list ArgList;
+ int Level = 0;
+ int PrefixSize = 0;
+ char szOutString[256];
+ long OriWinlogonlMask = Mask;
+
+
+ if (Mask & WinlogonInfoLevel)
+ {
+ while (!(Mask & 1))
+ {
+ Level++;
+ Mask >>= 1;
+ }
+ if (Level >= (sizeof(DebLevel) / sizeof(char *)) )
+ {
+ Level = (sizeof(DebLevel) / sizeof(char *)) - 1;
+ }
+
+
+ //
+ // Make the prefix first: "Process.Thread> Winlogon-XXX"
+ //
+
+ PrefixSize = sprintf(szOutString, "%d.%d> %s: ",
+ GetCurrentProcessId(), GetCurrentThreadId(), DebLevel[Level]);
+
+
+ va_start(ArgList, Format);
+
+ if (_vsnprintf(&szOutString[PrefixSize], sizeof(szOutString) - PrefixSize,
+ Format, ArgList) < 0)
+ {
+ //
+ // Less than zero indicates that the string could not be
+ // fitted into the buffer. Output a special message indicating
+ // that:
+ //
+
+ OutputDebugStringA("Winlogon!LogEvent: Could not pack string into 256 bytes\n");
+
+ }
+ else
+ {
+ OutputDebugStringA(szOutString);
+ }
+
+
+ if (LogFile)
+ {
+ SYSTEMTIME stTime;
+ FILETIME ftTime;
+ FILETIME localtime;
+
+ NtQuerySystemTime((PLARGE_INTEGER) &ftTime);
+ FileTimeToLocalFileTime(&ftTime, &localtime);
+ FileTimeToSystemTime(&localtime, &stTime);
+ fprintf(LogFile, "%02d:%02d:%02d.%03d: %s\n",
+ stTime.wHour, stTime.wMinute, stTime.wSecond,
+ stTime.wMilliseconds, szOutString);
+
+ fflush(LogFile);
+ }
+
+ }
+
+}
+
+void
+OpenLogFile(LPSTR pszLogFile)
+{
+ LogFile = fopen(pszLogFile, "a");
+ if (!LogFile)
+ {
+ OutputDebugStringA("Winlogon: Could not open logfile for append");
+ OutputDebugStringA(pszLogFile);
+ }
+ DebugLog((DEB_TRACE, "Log file '%s' begins\n", pszLogFile));
+}
+
+
+DWORD
+GetDebugKeyValue(
+ PDebugKeys KeyTable,
+ int cKeys,
+ LPSTR pszKey)
+{
+ int i;
+
+ for (i = 0; i < cKeys ; i++ )
+ {
+ if (_strcmpi(KeyTable[i].Name, pszKey) == 0)
+ {
+ return(KeyTable[i].Value);
+ }
+ }
+ return(0);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: LoadDebugParameters
+//
+// Synopsis: Loads debug parameters from win.ini
+//
+// Effects:
+//
+// Arguments: (none)
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 4-29-93 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+
+void
+LoadDebugParameters(char * szSection)
+{
+ char szVal[128];
+ char * pszDebug;
+ int cbVal;
+
+ cbVal = GetProfileStringA(szSection, "DebugFlags", "Error,Warning", szVal, sizeof(szVal));
+
+ pszDebug = strtok(szVal, ", \t");
+ while (pszDebug)
+ {
+ WinlogonInfoLevel |= GetDebugKeyValue(DebugKeyNames, NUM_DEBUG_KEYS, pszDebug);
+ pszDebug = strtok(NULL, ", \t");
+ }
+
+ cbVal = GetProfileStringA(szSection, "LogFile", "", szVal, sizeof(szVal));
+ if (cbVal)
+ {
+ OpenLogFile(szVal);
+ }
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitDebugSupport
+//
+// Synopsis: Initializes debugging support for the Winlogon
+//
+// Effects:
+//
+// Arguments: (none)
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 4-29-93 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+
+void
+InitDebugSupport(void)
+{
+ LoadDebugParameters("WinlogonDebug");
+ LoadDebugParameters("Winlogon");
+
+}
+
+
+
+#else // DBG
+
+#pragma warning(disable:4206) // Disable the empty transation unit
+ // warning/error
+
+#endif // NOTE: This file not compiled for retail builds
diff --git a/private/windows/gina/winlogon/debug.h b/private/windows/gina/winlogon/debug.h
new file mode 100644
index 000000000..7da351b04
--- /dev/null
+++ b/private/windows/gina/winlogon/debug.h
@@ -0,0 +1,62 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: debug.h
+//
+// Contents:
+//
+// Classes:
+//
+// Functions:
+//
+// History: 8-02-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#if DBG
+
+extern DWORD WinlogonInfoLevel;
+extern DWORD GinaBreakFlags;
+
+#define DebugLog(x) LogEvent x
+
+
+void LogEvent(long, const char *, ...);
+void InitDebugSupport(void);
+
+#define DEB_ERROR 0x00000001
+#define DEB_WARN 0x00000002
+#define DEB_TRACE 0x00000004
+#define DEB_TRACE_INIT 0x00000008
+#define DEB_TRACE_TIMEOUT 0x00000010
+#define DEB_TRACE_SAS 0x00000020
+#define DEB_TRACE_STATE 0x00000040
+#define DEB_TRACE_MPR 0x00000080
+#define DEB_COOL_SWITCH 0x00000100
+#define DEB_TRACE_PROFILE 0x00000200
+#define DEB_DEBUG_LSA 0x00000400
+#define DEB_DEBUG_MPR 0x00000800
+#define DEB_DEBUG_NOWAIT 0x00001000
+#define DEB_TRACE_MIGRATE 0x00002000
+#define DEB_DEBUG_SERVICES 0x00004000
+#define DEB_TRACE_SETUP 0x00008000
+
+
+
+#else
+
+#define DebugLog(x)
+#define InitDebugSupport()
+
+
+#endif
+
+
+
+#endif // __DEBUG_H__
diff --git a/private/windows/gina/winlogon/dialogs.dlg b/private/windows/gina/winlogon/dialogs.dlg
new file mode 100644
index 000000000..6359c4301
--- /dev/null
+++ b/private/windows/gina/winlogon/dialogs.dlg
@@ -0,0 +1,48 @@
+1 DLGINCLUDE "dialogs.h"
+
+
+IDD_CONTROL DIALOG 70, 80, 144, 76
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Winlogon generic control dialog"
+FONT 8, "MS Shell Dlg"
+BEGIN
+END
+
+IDD_SHUTDOWN DIALOG 45, 22, 164, 52
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Shutdown Computer"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "It is now safe to turn off your computer.", 302, 31, 13,
+ 132, 8
+ ICON 4, IDD_ICON, 6, 7, 18, 20
+ DEFPUSHBUTTON "&Restart", 305, 62, 32, 40, 14
+END
+
+IDD_SHUTDOWN_WAIT DIALOG 69, 73, 132, 42
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Shutdown in Progress"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Please wait while the system writes unsaved data to the disk.",
+ 101, 11, 12, 112, 18
+END
+
+IDD_WAIT_NET_DRIVES_DISCONNECT DIALOG 111, 47, 120, 37
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Logoff in Progress"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CTEXT " Please wait while the network connections are being closed.", 101, 4, 8, 113,
+ 18
+END
+
+
+IDD_FORCED_LOGOFF_WAIT DIALOG 94, 47, 146, 42
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Workstation Locked"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Please wait while the current user is logged off.", 101,
+ 7, 12, 137, 19
+END
diff --git a/private/windows/gina/winlogon/dialogs.h b/private/windows/gina/winlogon/dialogs.h
new file mode 100644
index 000000000..b50a029be
--- /dev/null
+++ b/private/windows/gina/winlogon/dialogs.h
@@ -0,0 +1,24 @@
+/****************************** Module Header ******************************\
+* Module Name: dialogs.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define contants used by dialog edit when editting dialog.dlg
+*
+* NOTE - this file is maintained by dlgedit. Do not edit directly
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+
+#define IDD_SHUTDOWN 300
+#define IDD_FORCED_LOGOFF_WAIT 153
+#define IDD_SHUTDOWN_BUTTON 1011
+#define IDD_TEXT 1401
+#define IDD_SHUTDOWN_WAIT 600
+#define IDD_WAIT_DOMAIN_CACHE_VALID 800
+#define IDD_WAIT_NET_DRIVES_DISCONNECT 1600
+#define IDD_ICON 102
+#define IDD_CONTROL 1400
+#define IDD_FORCED_LOGOFF_WAIT 153
diff --git a/private/windows/gina/winlogon/doslog.c b/private/windows/gina/winlogon/doslog.c
new file mode 100644
index 000000000..6ce99cf71
--- /dev/null
+++ b/private/windows/gina/winlogon/doslog.c
@@ -0,0 +1,59 @@
+/****************************** Module Header ******************************\
+* Module Name: DosLog.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Contains implementations of Dos boot/shutdown support functions
+*
+* History:
+* 04-30-92 Sudeepb Created.
+*
+* 25-Nov-1992 Jonle, removed winlogon renaming, left BootDos\ShutdownDos
+* as stubs for future use.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+/***************************************************************************\
+* BootDOS
+*
+* Routine to be called at system boot for DOS support.
+*
+* Currently does nothing, left in place for future convenience
+*
+* Parameters - None
+*
+* Returns - Nothing
+*
+* History:
+* 04-30-92 Sudeepb Created.
+\***************************************************************************/
+
+void BootDOS ( void )
+{
+ return;
+}
+
+
+/***************************************************************************\
+* ShutdownDOS
+*
+* Routine to be called at system shutdown for DOS support.
+*
+* This routine saves away the config.sys and autoexec.bat of
+* DOS subsystem and restores the original ones.
+*
+* Parameters - None
+*
+* Returns - Nothing
+*
+* History:
+* 04-30-92 Sudeepb Created.
+\***************************************************************************/
+
+void ShutdownDOS ( void )
+{
+ return;
+}
diff --git a/private/windows/gina/winlogon/doslog.h b/private/windows/gina/winlogon/doslog.h
new file mode 100644
index 000000000..ab2fc755e
--- /dev/null
+++ b/private/windows/gina/winlogon/doslog.h
@@ -0,0 +1,17 @@
+/****************************** Module Header ******************************\
+* Module Name: DosLog.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Contains definitions of Dos boot/shutdown support functions
+*
+* Currently NONE
+*
+* History:
+* 04-30-92 Sudeepb Created.
+*
+* 25-Nov-1992 Jonle, removed winlogon renaming
+\***************************************************************************/
+
+void BootDOS ( void ) ;
+void ShutdownDOS ( void );
diff --git a/private/windows/gina/winlogon/envvar.c b/private/windows/gina/winlogon/envvar.c
new file mode 100644
index 000000000..6cc586fb7
--- /dev/null
+++ b/private/windows/gina/winlogon/envvar.c
@@ -0,0 +1,1458 @@
+/****************************** Module Header ******************************\
+* Module Name: envvar.c
+*
+* Copyright (c) 1992, Microsoft Corporation
+*
+* Sets environment variables.
+*
+* History:
+* 2-25-92 JohanneC Created -
+*
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+BOOL ProcessCommand(LPTSTR lpStart, PVOID *pEnv);
+BOOL ProcessSetCommand(LPTSTR lpStart, PVOID *pEnv);
+LPTSTR ProcessAutoexecPath(PVOID *pEnv, LPTSTR lpValue, DWORD cb);
+BOOL AddNetworkConnection(PGLOBALS pGlobals, LPNETRESOURCE lpNetResource);
+BOOL UpdateUserEnvironment( PVOID *pEnv );
+
+#define KEY_NAME TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Environment")
+
+//
+// Max environment variable length
+//
+
+#define MAX_VALUE_LEN 1024
+
+
+/***************************************************************************\
+* InitSystemParametersInfo
+*
+* Re-Initializes system parameters given the current user registry.
+*
+* History:
+*
+\***************************************************************************/
+
+VOID
+InitSystemParametersInfo(
+ PGLOBALS pGlobals,
+ BOOL bUserLoggedOn
+ )
+{
+ HANDLE ImpersonationHandle;
+ BOOL Result;
+
+ //
+ // Open the profile mapping for the logged on user
+ //
+
+ Result = OpenIniFileUserMapping(pGlobals);
+ if (!Result) {
+ DebugLog((DEB_ERROR, "InitSystemParametersInfo: Failed to open ini file mapping for user"));
+ return;
+ }
+ //
+ // Impersonate the user so if the user server side has to reference
+ // any ini files etc, it will do it in the correct place.
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "InitSystemParametersInfo : Failed to impersonate user"));
+ CloseIniFileUserMapping(pGlobals);
+ return;
+ }
+
+ UpdatePerUserSystemParameters(bUserLoggedOn);
+
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (!StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "InitSystemParametersInfo : Failed to revert to self"));
+ }
+
+ //
+ // Close the profile mapping
+ //
+
+ CloseIniFileUserMapping(pGlobals);
+}
+
+
+/***************************************************************************\
+* CreateUserEnvironment
+*
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+BOOL
+CreateUserEnvironment(
+ PVOID *pEnv
+ )
+{
+ NTSTATUS Status;
+
+ Status = RtlCreateEnvironment((BOOLEAN)TRUE, pEnv);
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // We must examine the registry directly to suck out
+ // the system environment variables, because they
+ // may have changed since the system was booted.
+ //
+
+ if ( UpdateUserEnvironment( pEnv )) {
+
+ return( TRUE );
+ }
+
+ RtlDestroyEnvironment(*pEnv);
+ }
+
+ return(FALSE);
+}
+
+
+/***************************************************************************\
+* SetUserEnvironmentVariable
+*
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+BOOL
+SetUserEnvironmentVariable(
+ PVOID *pEnv,
+ LPTSTR lpVariable,
+ LPTSTR lpValue,
+ BOOL bOverwrite
+ )
+{
+ NTSTATUS Status;
+ UNICODE_STRING Name, Value;
+ DWORD cb;
+ DWORD cchValue = 1024;
+
+ if (!*pEnv || !lpVariable || !*lpVariable) {
+ return(FALSE);
+ }
+ RtlInitUnicodeString(&Name, lpVariable);
+ cb = 1024;
+ Value.Buffer = Alloc(sizeof(TCHAR)*cb);
+ if (Value.Buffer) {
+ Value.Length = (USHORT)cb;
+ Value.MaximumLength = (USHORT)cb;
+ Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value);
+
+ Free(Value.Buffer);
+
+ if ( NT_SUCCESS(Status) && !bOverwrite) {
+ return(TRUE);
+ }
+ }
+ if (lpValue && *lpValue) {
+ RtlInitUnicodeString(&Value, lpValue);
+ Status = RtlSetEnvironmentVariable(pEnv, &Name, &Value);
+ }
+ else {
+ Status = RtlSetEnvironmentVariable(pEnv, &Name, NULL);
+ }
+ if (NT_SUCCESS(Status)) {
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+
+/***************************************************************************\
+* ExpandUserEnvironmentStrings
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+DWORD
+ExpandUserEnvironmentStrings(
+ PVOID pEnv,
+ LPTSTR lpSrc,
+ LPTSTR lpDst,
+ DWORD nSize
+ )
+{
+ NTSTATUS Status;
+ UNICODE_STRING Source, Destination;
+ ULONG Length;
+
+ RtlInitUnicodeString( &Source, lpSrc );
+ Destination.Buffer = lpDst;
+ Destination.Length = 0;
+ Destination.MaximumLength = (USHORT)nSize;
+ Length = 0;
+ Status = RtlExpandEnvironmentStrings_U( pEnv,
+ (PUNICODE_STRING)&Source,
+ (PUNICODE_STRING)&Destination,
+ &Length
+ );
+ if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_TOO_SMALL) {
+ return( Length );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+
+/***************************************************************************\
+* BuildEnvironmentPath
+*
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+BOOL BuildEnvironmentPath(PVOID *pEnv,
+ LPTSTR lpPathVariable,
+ LPTSTR lpPathValue)
+{
+ NTSTATUS Status;
+ UNICODE_STRING Name;
+ UNICODE_STRING Value;
+ TCHAR lpTemp[1024];
+ DWORD cch;
+
+
+ if (!*pEnv) {
+ return(FALSE);
+ }
+ RtlInitUnicodeString(&Name, lpPathVariable);
+ cch = 1024;
+ Value.Buffer = Alloc(sizeof(TCHAR)*cch);
+ if (!Value.Buffer) {
+ return(FALSE);
+ }
+ Value.Length = (USHORT)cch;
+ Value.MaximumLength = (USHORT)cch;
+ Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value);
+ if (!NT_SUCCESS(Status)) {
+ Free(Value.Buffer);
+ Value.Length = 0;
+ *lpTemp = 0;
+ }
+ if (Value.Length) {
+ lstrcpy(lpTemp, Value.Buffer);
+ if ( *( lpTemp + lstrlen(lpTemp) - 1) != TEXT(';') ) {
+ lstrcat(lpTemp, TEXT(";"));
+ }
+ Free(Value.Buffer);
+ }
+ if (lpPathValue && ((INT)(lstrlen(lpTemp) + lstrlen(lpPathValue) + 1) < (INT)cch)) {
+ lstrcat(lpTemp, lpPathValue);
+
+ RtlInitUnicodeString(&Value, lpTemp);
+
+ Status = RtlSetEnvironmentVariable(pEnv, &Name, &Value);
+ }
+ if (NT_SUCCESS(Status)) {
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+
+/***************************************************************************\
+* SetEnvironmentVariables
+*
+* Reads the user-defined environment variables from the user registry
+* and adds them to the environment block at pEnv.
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+BOOL
+SetEnvironmentVariables(
+ PGLOBALS pGlobals,
+ PVOID *pEnv
+ )
+{
+ TCHAR lpValueName[MAX_PATH];
+ PWCH lpDataBuffer;
+ DWORD cbDataBuffer;
+ PWCH lpData;
+ LPTSTR lpExpandedValue = NULL;
+ DWORD cbValueName = MAX_PATH;
+ DWORD cbData;
+ DWORD dwType;
+ DWORD dwIndex = 0;
+ HKEY hkey;
+ BOOL bResult;
+ NTSTATUS Status = 0;
+ TCHAR UserEnvVarSubkey[] = TEXT("Environment");
+
+ /*
+ * Open registry key to access USER environment variables.
+ */
+ if (!OpenHKeyCurrentUser(pGlobals)) {
+ DebugLog((DEB_ERROR, "SetEnvironmentVariables: Failed to open HKeyCurrentUser"));
+ return(FALSE);
+ }
+
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, UserEnvVarSubkey, 0, KEY_READ, &hkey)) {
+ CloseHKeyCurrentUser(pGlobals);
+ return(FALSE);
+ }
+
+ cbDataBuffer = 4096;
+ lpDataBuffer = Alloc(sizeof(TCHAR)*cbDataBuffer);
+ if (lpDataBuffer == NULL) {
+ DebugLog((DEB_ERROR, "SetEnvironmentVariables: Failed to allocate %d bytes", cbDataBuffer));
+ CloseHKeyCurrentUser(pGlobals);
+ RegCloseKey(hkey);
+ return(FALSE);
+ }
+ lpData = lpDataBuffer;
+ cbData = sizeof(TCHAR)*cbDataBuffer;
+ bResult = TRUE;
+ while (!RegEnumValue(hkey, dwIndex, lpValueName, &cbValueName, 0, &dwType,
+ (LPBYTE)lpData, &cbData)) {
+ if (cbValueName) {
+
+ //
+ // Limit environment variable length
+ //
+
+ lpData[MAX_VALUE_LEN-1] = TEXT('\0');
+
+
+ if (dwType == REG_SZ) {
+
+ //
+ // The path variables PATH, LIBPATH and OS2LIBPATH must have
+ // their values apppended to the system path.
+ //
+
+ if ( !lstrcmpi(lpValueName, PATH_VARIABLE) ||
+ !lstrcmpi(lpValueName, LIBPATH_VARIABLE) ||
+ !lstrcmpi(lpValueName, OS2LIBPATH_VARIABLE) ) {
+
+ BuildEnvironmentPath(pEnv, lpValueName, lpData);
+ }
+ else {
+
+ //
+ // the other environment variables are just set.
+ //
+ SetUserEnvironmentVariable(pEnv, lpValueName, lpData, TRUE);
+ }
+ }
+ }
+ dwIndex++;
+ cbData = cbDataBuffer;
+ cbValueName = MAX_PATH;
+ }
+
+ dwIndex = 0;
+ cbData = cbDataBuffer;
+ cbValueName = MAX_PATH;
+
+
+ while (!RegEnumValue(hkey, dwIndex, lpValueName, &cbValueName, 0, &dwType,
+ (LPBYTE)lpData, &cbData)) {
+ if (cbValueName) {
+
+ //
+ // Limit environment variable length
+ //
+
+ lpData[MAX_VALUE_LEN-1] = TEXT('\0');
+
+
+ if (dwType == REG_EXPAND_SZ) {
+ DWORD cb, cbNeeded;
+
+ cb = 1024;
+ lpExpandedValue = Alloc(sizeof(TCHAR)*cb);
+ if (lpExpandedValue) {
+ cbNeeded = ExpandUserEnvironmentStrings(*pEnv, lpData, lpExpandedValue, cb);
+ if (cbNeeded > cb) {
+ Free(lpExpandedValue);
+ cb = cbNeeded;
+ lpExpandedValue = Alloc(sizeof(TCHAR)*cb);
+ if (lpExpandedValue) {
+ ExpandUserEnvironmentStrings(*pEnv, lpData, lpExpandedValue, cb);
+ }
+ }
+ }
+
+ if (lpExpandedValue == NULL) {
+ bResult = FALSE;
+ break;
+ }
+
+
+ //
+ // The path variables PATH, LIBPATH and OS2LIBPATH must have
+ // their values apppended to the system path.
+ //
+
+ if ( !lstrcmpi(lpValueName, PATH_VARIABLE) ||
+ !lstrcmpi(lpValueName, LIBPATH_VARIABLE) ||
+ !lstrcmpi(lpValueName, OS2LIBPATH_VARIABLE) ) {
+
+ BuildEnvironmentPath(pEnv, lpValueName, lpExpandedValue);
+ }
+ else {
+
+ //
+ // the other environment variables are just set.
+ //
+ SetUserEnvironmentVariable(pEnv, lpValueName, lpExpandedValue, TRUE);
+ }
+
+ Free(lpExpandedValue);
+ }
+ }
+ dwIndex++;
+ cbData = cbDataBuffer;
+ cbValueName = MAX_PATH;
+ }
+
+
+ Free(lpDataBuffer);
+ RegCloseKey(hkey);
+ CloseHKeyCurrentUser(pGlobals);
+
+ return(bResult);
+}
+
+/***************************************************************************\
+* IsUNCPath
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+BOOL IsUNCPath(LPTSTR lpPath)
+{
+ if (lpPath[0] == BSLASH && lpPath[1] == BSLASH) {
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+/***************************************************************************\
+* SetHomeDirectoryEnvVars
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+BOOL
+SetHomeDirectoryEnvVars(
+ PVOID *pEnv,
+ LPTSTR lpHomeDirectory,
+ LPTSTR lpHomeDrive,
+ LPTSTR lpHomeShare,
+ LPTSTR lpHomePath
+ )
+{
+ TCHAR cTmp;
+ LPTSTR lpHomeTmp;
+ BOOL bFoundFirstBSlash = FALSE;
+
+ if (!*lpHomeDirectory) {
+ return(FALSE);
+ }
+ if (IsUNCPath(lpHomeDirectory)) {
+ lpHomeTmp = lpHomeDirectory + 2;
+ while (*lpHomeTmp) {
+ if (*lpHomeTmp == BSLASH) {
+ if (bFoundFirstBSlash) {
+ break;
+ }
+ bFoundFirstBSlash = TRUE;
+ }
+ lpHomeTmp++;
+ }
+ if (*lpHomeTmp) {
+ lstrcpy(lpHomePath, lpHomeTmp);
+ }
+ else {
+ *lpHomePath = BSLASH;
+ *(lpHomePath+1) = 0;
+ }
+
+ cTmp = *lpHomeTmp;
+ *lpHomeTmp = (TCHAR)0;
+ lstrcpy(lpHomeShare, lpHomeDirectory);
+ *lpHomeTmp = cTmp;
+
+ //
+ // If no home drive specified, than default to z:
+ //
+ if (!*lpHomeDrive) {
+ lstrcpy(lpHomeDrive, TEXT("Z:"));
+ }
+
+ }
+ else { // local home directory
+
+ *lpHomeShare = 0; // no home share
+
+ cTmp = lpHomeDirectory[2];
+ lpHomeDirectory[2] = (TCHAR)0;
+ lstrcpy(lpHomeDrive, lpHomeDirectory);
+ lpHomeDirectory[2] = cTmp;
+
+ lstrcpy(lpHomePath, lpHomeDirectory + 2);
+ }
+
+ SetUserEnvironmentVariable(pEnv, HOMEDRIVE_VARIABLE, lpHomeDrive, TRUE);
+ SetUserEnvironmentVariable(pEnv, HOMESHARE_VARIABLE, lpHomeShare, TRUE);
+ SetUserEnvironmentVariable(pEnv, HOMEPATH_VARIABLE, lpHomePath, TRUE);
+}
+
+/***************************************************************************\
+* ChangeToHomeDirectory
+*
+* Sets the current directory to the user's home directory. If this fails
+* tries to set to the directory in the following order:
+* 1. home directory
+* 2. c:\users\default
+* 3. c:\users
+* 4. \ (root)
+* 5. leaves directory as is i.e. the present current directory
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+VOID
+ChangeToHomeDirectory(
+ PGLOBALS pGlobals,
+ PVOID *pEnv,
+ LPTSTR lpHomeDir,
+ LPTSTR lpHomeDrive,
+ LPTSTR lpHomeShare,
+ LPTSTR lpHomePath
+ )
+{
+ TCHAR lpOldDir[MAX_PATH];
+ TCHAR lpCurDrive[4];
+ BOOL bNoHomeDir = FALSE;
+ HANDLE ImpersonationHandle = NULL;
+ DWORD error = ERROR_SUCCESS;
+
+ if (GetCurrentDirectory(MAX_PATH, lpOldDir)) {
+ lpCurDrive[0] = lpOldDir[0];
+ lpCurDrive[1] = lpOldDir[1];
+ lpCurDrive[2] = (TCHAR)0;
+ }
+ else
+ lpCurDrive[0] = (TCHAR)0;
+
+ if (!*lpHomeDir) {
+ bNoHomeDir = TRUE;
+
+DefaultDirectory:
+ if (!bNoHomeDir) {
+ ReportWinlogonEvent(pGlobals,
+ EVENTLOG_ERROR_TYPE,
+ EVENT_SET_HOME_DIRECTORY_FAILED,
+ sizeof(error),
+ &error,
+ 1,
+ lpHomeDir);
+
+ }
+ lstrcpy(lpHomeDir, lpCurDrive);
+ if (SetCurrentDirectory(USERS_DEFAULT_DIRECTORY)) {
+ lstrcat(lpHomeDir, USERS_DEFAULT_DIRECTORY);
+ }
+ else if (SetCurrentDirectory(USERS_DIRECTORY)) {
+ lstrcat(lpHomeDir, USERS_DIRECTORY);
+ }
+ else if (SetCurrentDirectory(ROOT_DIRECTORY)) {
+ lstrcat(lpHomeDir, ROOT_DIRECTORY);
+ }
+ else {
+ lstrcpy(lpHomeDir, NULL_STRING);
+ }
+ if (bNoHomeDir) {
+ SetUserEnvironmentVariable(pEnv, HOMEDRIVE_VARIABLE, lpCurDrive, TRUE);
+ *lpHomeShare = 0; // null string
+ SetUserEnvironmentVariable(pEnv, HOMESHARE_VARIABLE, lpHomeShare, TRUE);
+ if (*lpHomeDir) {
+ lpHomeDir += 2;
+ }
+ SetUserEnvironmentVariable(pEnv, HOMEPATH_VARIABLE, lpHomeDir, TRUE);
+ }
+
+ if (*lpOldDir) {
+ SetCurrentDirectory(lpOldDir);
+ }
+
+ return;
+ }
+ /*
+ * Test if homedir is a local directory.'?:\foo\bar'
+ */
+ if (IsUNCPath(lpHomeDir)) {
+ NETRESOURCE NetResource;
+
+ /*
+ * lpHomeDir is a UNC path, use lpHomedrive.
+ */
+
+ NetResource.lpLocalName = lpHomeDrive;
+ NetResource.lpRemoteName = lpHomeShare;
+ NetResource.lpProvider = NULL;
+ NetResource.dwType = RESOURCETYPE_DISK;
+
+ if (!AddNetworkConnection(pGlobals, &NetResource)) {
+ error = GetLastError();
+ goto DefaultDirectory;
+ }
+
+ lstrcpy(lpHomeDir, lpHomeDrive);
+ if (lpHomePath && *lpHomePath != TEXT('\\')) {
+ lstrcat(lpHomeDir, TEXT("\\"));
+ }
+ lstrcat(lpHomeDir, lpHomePath);
+
+ //
+ // Impersonate the user
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to impersonate user"));
+ }
+
+ if (!SetCurrentDirectory(lpHomeDir)) {
+ error = GetLastError();
+ DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to SetCurrentDirectory '%ws', error = %d",
+ lpHomeDir, error));
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (ImpersonationHandle && !StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to revert to self"));
+ }
+
+ goto DefaultDirectory;
+ }
+ }
+ else {
+ /*
+ * lpHomeDir is a local path or absolute local path.
+ */
+
+ //
+ // Impersonate the user
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to impersonate user"));
+ }
+
+ if (!SetCurrentDirectory(lpHomeDir)) {
+ error = GetLastError();
+ DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to SetCurrentDirectory '%ws', error = %d",
+ lpHomeDir, error));
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (ImpersonationHandle && !StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to revert to self"));
+ }
+
+ goto DefaultDirectory;
+ }
+ }
+
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (ImpersonationHandle && !StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "ChangeToHomeDirectory : Failed to revert to self"));
+ }
+
+ if (*lpOldDir) {
+ SetCurrentDirectory(lpOldDir);
+ }
+}
+
+/***************************************************************************\
+* ProcessAutoexec
+*
+* History:
+* 01-24-92 Johannec Created.
+*
+\***************************************************************************/
+BOOL
+ProcessAutoexec(
+ PVOID *pEnv,
+ LPTSTR lpPathVariable
+ )
+{
+ HANDLE fh;
+ DWORD dwFileSize;
+ DWORD dwBytesRead;
+ CHAR *lpBuffer = NULL;
+ CHAR *token;
+ CHAR Seps[] = "&\n\r"; // Seperators for tokenizing autoexec.bat
+ BOOL Status = FALSE;
+ TCHAR szAutoExecBat [] = TEXT("c:\\autoexec.bat");
+ UINT uiErrMode;
+
+
+ // There is a case where the OS might not be booting from drive
+ // C, so we can not assume that the autoexec.bat file is on c:\.
+ // Set the error mode so the user doesn't see the critical error
+ // popup and attempt to open the file on c:\.
+
+ uiErrMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+
+ fh = CreateFile (szAutoExecBat, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ SetErrorMode (uiErrMode);
+
+ if (fh == INVALID_HANDLE_VALUE) {
+ return(FALSE); //could not open autoexec.bat file, we're done.
+ }
+
+ dwFileSize = GetFileSize(fh, NULL);
+ if (dwFileSize == -1) {
+ goto Exit; // can't read the file size
+ }
+
+ lpBuffer = Alloc(dwFileSize+1);
+ if (!lpBuffer) {
+ goto Exit;
+ }
+
+ Status = ReadFile(fh, lpBuffer, dwFileSize, &dwBytesRead, NULL);
+ if (!Status) {
+ goto Exit; // error reading file
+ }
+
+ //
+ // Zero terminate the buffer so we don't walk off the end
+ //
+
+ ASSERT(dwBytesRead <= dwFileSize);
+ lpBuffer[dwBytesRead] = 0;
+
+ //
+ // Search for SET and PATH commands
+ //
+
+ token = strtok(lpBuffer, Seps);
+ while (token != NULL) {
+ for (;*token && *token == ' ';token++) //skip spaces
+ ;
+ if (*token == TEXT('@'))
+ token++;
+ for (;*token && *token == ' ';token++) //skip spaces
+ ;
+ if (!_strnicmp(token, "PATH", 4)) {
+ STRING String;
+ UNICODE_STRING UniString;
+
+ RtlInitString(&String, (LPSTR)token);
+ RtlAnsiStringToUnicodeString(&UniString, &String, TRUE);
+
+ if (UniString.Buffer)
+ {
+ ProcessCommand(UniString.Buffer, pEnv);
+ //ProcessCommand(token, pEnv);
+
+ RtlFreeUnicodeString(&UniString);
+ }
+ }
+ if (!_strnicmp(token, "SET", 3)) {
+ STRING String;
+ UNICODE_STRING UniString;
+
+ RtlInitString(&String, (LPSTR)token);
+ RtlAnsiStringToUnicodeString(&UniString, &String, TRUE);
+
+ if (UniString.Buffer)
+ {
+ ProcessSetCommand(UniString.Buffer, pEnv);
+ //ProcessSetCommand(token, pEnv);
+
+ RtlFreeUnicodeString(&UniString);
+ }
+ }
+ token = strtok(NULL, Seps);
+ }
+Exit:
+ CloseHandle(fh);
+ if (lpBuffer) {
+ Free(lpBuffer);
+ }
+ if (!Status) {
+ DebugLog((DEB_ERROR, "Cannot process autoexec.bat."));
+ }
+ return(Status);
+}
+
+/***************************************************************************\
+* ProcessCommand
+*
+* History:
+* 01-24-92 Johannec Created.
+*
+\***************************************************************************/
+BOOL ProcessCommand(LPTSTR lpStart, PVOID *pEnv)
+{
+ LPTSTR lpt, lptt;
+ LPTSTR lpVariable;
+ LPTSTR lpValue;
+ LPTSTR lpExpandedValue = NULL;
+ TCHAR c;
+ DWORD cb, cbNeeded;
+
+ //
+ // Find environment variable.
+ //
+ for (lpt = lpStart; *lpt && *lpt == TEXT(' '); lpt++) //skip spaces
+ ;
+
+ if (!*lpt)
+ return(FALSE);
+
+ lptt = lpt;
+ for (; *lpt && *lpt != TEXT(' ') && *lpt != TEXT('='); lpt++) //find end of variable name
+ ;
+
+ c = *lpt;
+ *lpt = 0;
+ lpVariable = Alloc(sizeof(TCHAR)*(lstrlen(lptt) + 1));
+ if (!lpVariable)
+ return(FALSE);
+ lstrcpy(lpVariable, lptt);
+ *lpt = c;
+
+ //
+ // Find environment variable value.
+ //
+ for (; *lpt && (*lpt == TEXT(' ') || *lpt == TEXT('=')); lpt++)
+ ;
+
+ if (!*lpt) {
+ // if we have a blank path statement in the autoexec file,
+ // then we don't want to pass "PATH" as the environment
+ // variable because it trashes the system's PATH. Instead
+ // we want to change the variable AutoexecPath. This would have
+ // be handled below if a value had been assigned to the
+ // environment variable.
+ if (lstrcmpi(lpVariable, PATH_VARIABLE) == 0)
+ {
+ SetUserEnvironmentVariable(pEnv, AUTOEXECPATH_VARIABLE, TEXT(""), TRUE);
+ }
+ else
+ {
+ SetUserEnvironmentVariable(pEnv, lpVariable, TEXT(""), TRUE);
+ }
+ Free(lpVariable);
+ return(FALSE);
+ }
+
+ lptt = lpt;
+ for (; *lpt; lpt++) //find end of varaible value
+ ;
+
+ c = *lpt;
+ *lpt = 0;
+ lpValue = Alloc(sizeof(TCHAR)*(lstrlen(lptt) + 1));
+ if (!lpValue) {
+ Free(lpVariable);
+ return(FALSE);
+ }
+
+ lstrcpy(lpValue, lptt);
+ *lpt = c;
+
+ cb = 1024;
+ lpExpandedValue = Alloc(sizeof(TCHAR)*cb);
+ if (lpExpandedValue) {
+ if (!lstrcmpi(lpVariable, PATH_VARIABLE)) {
+ lpValue = ProcessAutoexecPath(pEnv, lpValue, lstrlen(lpValue)+1);
+ }
+ cbNeeded = ExpandUserEnvironmentStrings(*pEnv, lpValue, lpExpandedValue, cb);
+ if (cbNeeded > cb) {
+ Free(lpExpandedValue);
+ cb = cbNeeded;
+ lpExpandedValue = Alloc(sizeof(TCHAR)*cb);
+ if (lpExpandedValue) {
+ ExpandUserEnvironmentStrings(*pEnv, lpValue, lpExpandedValue, cb);
+ }
+ }
+ }
+
+ if (!lpExpandedValue) {
+ lpExpandedValue = lpValue;
+ }
+ if (lstrcmpi(lpVariable, PATH_VARIABLE)) {
+ SetUserEnvironmentVariable(pEnv, lpVariable, lpExpandedValue, FALSE);
+ }
+ else {
+ SetUserEnvironmentVariable(pEnv, AUTOEXECPATH_VARIABLE, lpExpandedValue, TRUE);
+
+ }
+
+ if (lpExpandedValue != lpValue) {
+ Free(lpExpandedValue);
+ }
+ Free(lpVariable);
+ Free(lpValue);
+
+ return(TRUE);
+}
+
+/***************************************************************************\
+* ProcessSetCommand
+*
+* History:
+* 01-24-92 Johannec Created.
+*
+\***************************************************************************/
+BOOL ProcessSetCommand(LPTSTR lpStart, PVOID *pEnv)
+{
+ LPTSTR lpt;
+
+ //
+ // Find environment variable.
+ //
+ for (lpt = lpStart; *lpt && *lpt != TEXT(' '); lpt++)
+ ;
+
+ if (!*lpt || !_wcsnicmp(lpt,TEXT("COMSPEC"), 7))
+ return(FALSE);
+
+ return (ProcessCommand(lpt, pEnv));
+
+}
+
+/***************************************************************************\
+* ProcessAutoexecPath
+*
+* Creates AutoexecPath environment variable using autoexec.bat
+* LpValue may be freed by this routine.
+*
+* History:
+* 06-02-92 Johannec Created.
+*
+\***************************************************************************/
+LPTSTR ProcessAutoexecPath(PVOID *pEnv, LPTSTR lpValue, DWORD cb)
+{
+ LPTSTR lpt;
+ LPTSTR lpStart;
+ LPTSTR lpPath;
+ DWORD cbt;
+ UNICODE_STRING Name;
+ UNICODE_STRING Value;
+ BOOL bPrevAutoexecPath;
+ WCHAR ch;
+ DWORD dwTemp, dwCount = 0;
+
+ cbt = 1024;
+ lpt = Alloc(sizeof(TCHAR)*cbt);
+ if (!lpt) {
+ return(lpValue);
+ }
+ *lpt = 0;
+ lpStart = lpValue;
+
+ RtlInitUnicodeString(&Name, AUTOEXECPATH_VARIABLE);
+ Value.Buffer = Alloc(sizeof(TCHAR)*cbt);
+ if (!Value.Buffer) {
+ goto Fail;
+ }
+
+ while (lpPath = wcsstr (lpValue, TEXT("%"))) {
+ if (!_wcsnicmp(lpPath+1, TEXT("PATH%"), 5)) {
+ //
+ // check if we have an autoexecpath already set, if not just remove
+ // the %path%
+ //
+ Value.Length = (USHORT)cbt;
+ Value.MaximumLength = (USHORT)cbt;
+ bPrevAutoexecPath = (BOOL)!RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value);
+
+ *lpPath = 0;
+ dwTemp = dwCount + lstrlen (lpValue);
+ if (dwTemp < cbt) {
+ lstrcat(lpt, lpValue);
+ dwCount += dwTemp;
+ }
+ if (bPrevAutoexecPath) {
+ dwTemp = dwCount + lstrlen (Value.Buffer);
+ if (dwTemp < cbt) {
+ lstrcat(lpt, Value.Buffer);
+ dwCount += dwTemp;
+ }
+ }
+
+ *lpPath++ = TEXT('%');
+ lpPath += 5; // go passed %path%
+ lpValue = lpPath;
+ }
+ else {
+ lpPath = wcsstr(lpPath+1, TEXT("%"));
+ if (!lpPath) {
+ lpStart = NULL;
+ goto Fail;
+ }
+ lpPath++;
+ ch = *lpPath;
+ *lpPath = 0;
+ dwTemp = dwCount + lstrlen (lpValue);
+ if (dwTemp < cbt) {
+ lstrcat(lpt, lpValue);
+ dwCount += dwTemp;
+ }
+ *lpPath = ch;
+ lpValue = lpPath;
+ }
+ }
+
+ if (*lpValue) {
+ dwTemp = dwCount + lstrlen (lpValue);
+ if (dwTemp < cbt) {
+ lstrcat(lpt, lpValue);
+ dwCount += dwTemp;
+ }
+ }
+
+ Free(Value.Buffer);
+ Free(lpStart);
+
+ return(lpt);
+Fail:
+ Free(lpt);
+ return(lpStart);
+}
+
+
+/***************************************************************************\
+* AppendNTPathWithAutoexecPath
+*
+* Gets the AutoexecPath created in ProcessAutoexec, and appends it to
+* the NT path.
+*
+* History:
+* 05-28-92 Johannec Created.
+*
+\***************************************************************************/
+BOOL
+AppendNTPathWithAutoexecPath(
+ PVOID *pEnv,
+ LPTSTR lpPathVariable,
+ LPTSTR lpAutoexecPath
+ )
+{
+ NTSTATUS Status;
+ UNICODE_STRING Name;
+ UNICODE_STRING Value;
+ TCHAR AutoexecPathValue[1024];
+ DWORD cb;
+ BOOL Success;
+
+ if (!*pEnv) {
+ return(FALSE);
+ }
+
+ RtlInitUnicodeString(&Name, lpAutoexecPath);
+ cb = 1024;
+ Value.Buffer = Alloc(sizeof(TCHAR)*cb);
+ if (!Value.Buffer) {
+ return(FALSE);
+ }
+
+ Value.Length = (USHORT)cb;
+ Value.MaximumLength = (USHORT)cb;
+ Status = RtlQueryEnvironmentVariable_U(*pEnv, &Name, &Value);
+ if (!NT_SUCCESS(Status)) {
+ Free(Value.Buffer);
+ return(FALSE);
+ }
+
+ if (Value.Length) {
+ lstrcpy(AutoexecPathValue, Value.Buffer);
+ }
+
+ Free(Value.Buffer);
+
+ Success = BuildEnvironmentPath(pEnv, lpPathVariable, AutoexecPathValue);
+ RtlSetEnvironmentVariable(pEnv, &Name, NULL);
+ return(Success);
+}
+
+
+/***************************************************************************\
+* AddNetworkConnection
+*
+* calls WNetAddConnection in the user's context.
+*
+* History:
+* 6-26-92 Johannec Created
+*
+\***************************************************************************/
+BOOL AddNetworkConnection(PGLOBALS pGlobals, LPNETRESOURCE lpNetResource)
+{
+ HANDLE ImpersonationHandle;
+ TCHAR szMprDll[] = TEXT("mpr.dll");
+ CHAR szWNetAddConn[] = "WNetAddConnection2W";
+ DWORD (APIENTRY *lpfnWNetAddConn)(LPNETRESOURCE, LPTSTR, LPTSTR, DWORD);
+ DWORD WNetResult;
+ static BOOL fFirstLogon = TRUE;
+ BOOL Result = FALSE; // Failure is default
+
+ //
+ // Impersonate the user
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "AddNetworkConnection : Failed to impersonate user"));
+ return(FALSE);
+ }
+
+
+ //
+ // Call the add connection api in the users context
+ //
+
+ if (!pGlobals->hMPR) {
+ // wasn't loaded, try to load it now.
+ pGlobals->hMPR = LoadLibrary(szMprDll);
+ }
+
+ if (pGlobals->hMPR) {
+#if 0
+ if (lpfnWNetAddConn = (DWORD (APIENTRY *)(LPNETRESOURCE, LPTSTR, LPTSTR, DWORD))
+ GetProcAddress(pGlobals->hMPR, (LPSTR)szWNetAddConn)) {
+
+ RevealPassword(&pGlobals->PasswordString);
+
+ if (fFirstLogon) {
+ WNetResult = ERROR_NO_NETWORK;
+ if (WaitForNetworkToStart(SERVICE_WORKSTATION))
+ WNetResult = (*lpfnWNetAddConn)(lpNetResource,
+ pGlobals->Password,
+ pGlobals->UserName,
+ 0);
+ }
+ else {
+ WNetResult = (*lpfnWNetAddConn)(lpNetResource,
+ pGlobals->Password,
+ pGlobals->UserName,
+ 0);
+ }
+
+ HidePassword( &pGlobals->Seed, &pGlobals->PasswordString);
+
+ if (WNetResult != ERROR_SUCCESS) {
+ DebugLog((DEB_ERROR, "WNetAddConnection2W failed for home directory, error = %d", WNetResult));
+ }
+
+ Result = (WNetResult == ERROR_SUCCESS);
+
+ } else {
+ DebugLog((DEB_ERROR, "Failed to get address of WNetAddConnection2W from mpr.dll"));
+ }
+#endif
+ } else {
+ DebugLog((DEB_ERROR, "Winlogon failed to load mpr.dll for add connection"));
+ }
+
+ //
+ // Make sure we don't try to start the network again.
+ //
+
+ fFirstLogon = FALSE;
+
+ //
+ // Unload mpr.dll. Keeping it open messes up Novell and Banyan.
+ //
+
+ if ( pGlobals->hMPR ) {
+
+ FreeLibrary(pGlobals->hMPR);
+ pGlobals->hMPR = NULL;
+ }
+
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (!StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "AddNetworkConnection : Failed to revert to self"));
+ }
+
+ return(Result);
+}
+
+
+
+BOOL
+UpdateUserEnvironment(
+ PVOID *pEnv
+ )
+{
+
+ HKEY KeyHandle;
+ DWORD Result;
+ DWORD ValueNameLength;
+ DWORD Type;
+ DWORD DataLength;
+ DWORD cValues; /* address of buffer for number of value identifiers */
+ DWORD chMaxValueName; /* address of buffer for longest value name length */
+ DWORD cbMaxValueData; /* address of buffer for longest value data length */
+ DWORD junk;
+ FILETIME FileTime;
+ PTCHAR ValueName;
+ PTCHAR ValueData;
+ DWORD i;
+ BOOL Bool;
+ PTCHAR ExpandedValue;
+ BOOL rc = TRUE;
+
+ DWORD ClassStringSize = MAX_PATH + 1;
+ TCHAR Class[MAX_PATH + 1];
+
+ Result = RegOpenKeyEx (
+ HKEY_LOCAL_MACHINE,
+ KEY_NAME,
+ 0,
+ KEY_QUERY_VALUE,
+ &KeyHandle
+ );
+
+ if ( Result != ERROR_SUCCESS ) {
+
+ DebugLog((DEB_ERROR, "RegOpenKeyEx failed, error = %d\n",Result));
+ return( FALSE );
+ }
+
+ Result = RegQueryInfoKey(
+ KeyHandle,
+ Class, /* address of buffer for class string */
+ &ClassStringSize, /* address of size of class string buffer */
+ NULL, /* reserved */
+ &junk, /* address of buffer for number of subkeys */
+ &junk, /* address of buffer for longest subkey */
+ &junk, /* address of buffer for longest class string length */
+ &cValues, /* address of buffer for number of value identifiers */
+ &chMaxValueName, /* address of buffer for longest value name length */
+ &cbMaxValueData, /* address of buffer for longest value data length */
+ &junk, /* address of buffer for descriptor length */
+ &FileTime /* address of buffer for last write time */
+ );
+
+ if ( Result != NO_ERROR && Result != ERROR_MORE_DATA ) {
+ RegCloseKey(KeyHandle);
+ return( FALSE );
+ }
+
+ //
+ // No need to adjust the datalength for TCHAR issues
+ //
+
+ ValueData = Alloc( cbMaxValueData );
+
+ if ( ValueData == NULL ) {
+ RegCloseKey(KeyHandle);
+ return( FALSE );
+ }
+
+ //
+ // The maximum value name length comes back in characters, convert to bytes
+ // before allocating storage. Allow for trailing NULL also.
+ //
+
+ ValueName = Alloc( (++chMaxValueName) * sizeof( TCHAR ) );
+
+ if ( ValueName == NULL ) {
+
+ RegCloseKey(KeyHandle);
+ Free( ValueData );
+ return( FALSE );
+ }
+
+ //
+ // To exit from here on, set rc and jump to Cleanup
+ //
+
+ for (i=0; i<cValues ; i++) {
+
+ ValueNameLength = chMaxValueName;
+ DataLength = cbMaxValueData;
+
+ Result = RegEnumValue (
+ KeyHandle,
+ i,
+ ValueName,
+ &ValueNameLength, // Size in TCHARs
+ NULL,
+ &Type,
+ (LPBYTE)ValueData,
+ &DataLength // Size in bytes
+ );
+
+ if ( Result != ERROR_SUCCESS ) {
+
+ //
+ // Problem getting the value. We can either try
+ // the rest or punt completely.
+ //
+
+ rc = FALSE;
+ goto Cleanup;
+ }
+
+ //
+ // If the buffer size is greater than the max allowed,
+ // terminate the string at MAX_VALUE_LEN - 1.
+ //
+
+ if (DataLength >= (MAX_VALUE_LEN * sizeof(TCHAR))) {
+ ValueData[MAX_VALUE_LEN-1] = TEXT('\0');
+ }
+
+ switch ( Type ) {
+ case REG_SZ:
+ {
+
+ Bool = SetUserEnvironmentVariable(
+ pEnv,
+ ValueName,
+ ValueData,
+ TRUE
+ );
+
+ if ( !Bool ) {
+
+ //
+ // Not much to do here.
+ //
+
+ rc = FALSE;
+ goto Cleanup;
+ }
+
+ break;
+ }
+ default:
+ {
+ continue;
+ }
+ }
+ }
+
+ //
+ // To exit from here on, set rc and jump to Cleanup
+ //
+
+ for (i=0; i<cValues ; i++) {
+
+ ValueNameLength = chMaxValueName;
+ DataLength = cbMaxValueData;
+
+ Result = RegEnumValue (
+ KeyHandle,
+ i,
+ ValueName,
+ &ValueNameLength, // Size in TCHARs
+ NULL,
+ &Type,
+ (LPBYTE)ValueData,
+ &DataLength // Size in bytes
+ );
+
+ if ( Result != ERROR_SUCCESS ) {
+
+ //
+ // Problem getting the value. We can either try
+ // the rest or punt completely.
+ //
+
+ rc = FALSE;
+ goto Cleanup;
+ }
+
+ //
+ // If the buffer size is greater than the max allowed,
+ // terminate the string at MAX_VALUE_LEN - 1.
+ //
+
+ if (DataLength >= (MAX_VALUE_LEN * sizeof(TCHAR))) {
+ ValueData[MAX_VALUE_LEN-1] = TEXT('\0');
+ }
+
+ switch ( Type ) {
+ case REG_EXPAND_SZ:
+ {
+
+ ExpandedValue = AllocAndExpandEnvironmentStrings( ValueData );
+
+ Bool = SetUserEnvironmentVariable(
+ pEnv,
+ ValueName,
+ ExpandedValue,
+ TRUE
+ );
+
+ Free( ExpandedValue );
+
+ if ( !Bool ) {
+
+ //
+ // Not much to do here.
+ //
+
+ rc = FALSE;
+ goto Cleanup;
+ }
+
+ break;
+ }
+ default:
+ {
+ continue;
+ }
+ }
+ }
+
+
+Cleanup:
+
+ RegCloseKey(KeyHandle);
+
+ Free( ValueName );
+ Free( ValueData );
+
+ return( rc );
+}
diff --git a/private/windows/gina/winlogon/envvar.h b/private/windows/gina/winlogon/envvar.h
new file mode 100644
index 000000000..63c270f77
--- /dev/null
+++ b/private/windows/gina/winlogon/envvar.h
@@ -0,0 +1,73 @@
+/****************************** Module Header ******************************\
+* Module Name: envvar.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define apis in envvar.c
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+//
+// Prototypes
+//
+
+BOOL
+AppendNTPathWithAutoexecPath(
+ PVOID *pEnv,
+ LPTSTR lpPathVariable,
+ LPTSTR lpAutoexecPath
+ );
+
+BOOL
+CreateUserEnvironment(
+ PVOID *pEnv
+ );
+
+BOOL
+SetUserEnvironmentVariable(
+ PVOID *pEnv,
+ LPTSTR lpVariable,
+ LPTSTR lpValue,
+ BOOL bOverwrite
+ );
+
+DWORD
+ExpandUserEnvironmentStrings(
+ PVOID pEnv,
+ LPTSTR lpSrc,
+ LPTSTR lpDst,
+ DWORD nSize
+ );
+
+BOOL
+SetEnvironmentVariables(
+ PGLOBALS pGlobals,
+ PVOID *pEnv
+ );
+
+BOOL
+SetHomeDirectoryEnvVars(
+ PVOID *pEnv,
+ LPTSTR lpHomeDirectory,
+ LPTSTR lpHomeDrive,
+ LPTSTR lpHomeShare,
+ LPTSTR lpHomePath
+ );
+
+BOOL
+ProcessAutoexec(
+ PVOID *pEnv,
+ LPTSTR lpPathVariable
+ );
+
+VOID
+ChangeToHomeDirectory(
+ PGLOBALS pGlobals,
+ PVOID *pEnv,
+ LPTSTR lpHomeDir,
+ LPTSTR lpHomeDrive,
+ LPTSTR lpHomeShare,
+ LPTSTR lpHomePath
+ );
diff --git a/private/windows/gina/winlogon/ginamgr.c b/private/windows/gina/winlogon/ginamgr.c
new file mode 100644
index 000000000..176e08b2e
--- /dev/null
+++ b/private/windows/gina/winlogon/ginamgr.c
@@ -0,0 +1,220 @@
+/****************************** Module Header ******************************\
+* Module Name: ginamgr.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* GINA Management code
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+DWORD GinaBreakFlags;
+#endif
+
+PWLX_ISLOCKOK IsLockOkFn;
+
+BOOL
+WINAPI
+DummyWlxScreenSaverNotify(
+ PVOID pWlxContext,
+ BOOL * Secure)
+{
+ if ( *Secure && (IsLockOkFn != NULL ) )
+ {
+ *Secure = IsLockOkFn( pWlxContext );
+ }
+
+ return( TRUE );
+}
+
+PGINASESSION
+LoadGinaDll(PWSTR pszGinaDll)
+{
+ PGINASESSION pGinaSession;
+ HINSTANCE hDllInstance;
+
+ hDllInstance = LoadLibrary(pszGinaDll);
+
+ if (!hDllInstance)
+ {
+ DebugLog((DEB_ERROR, "Error %d loading Gina DLL %ws\n", GetLastError(), pszGinaDll));
+ return(NULL);
+ }
+
+ pGinaSession = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(GINASESSION));
+ if (!pGinaSession)
+ {
+ return(NULL);
+ }
+
+ pGinaSession->hInstance = hDllInstance;
+
+ pGinaSession->pWlxNegotiate = (PWLX_NEGOTIATE) GetProcAddress(hDllInstance, WLX_NEGOTIATE_NAME);
+ if (!pGinaSession->pWlxNegotiate)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxNegotiate entry point\n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxInitialize = (PWLX_INITIALIZE) GetProcAddress(hDllInstance, WLX_INITIALIZE_NAME);
+ if (!pGinaSession->pWlxInitialize)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxInitialize entry point\n"));
+ goto LoadGina_ErrorReturn;
+
+ }
+
+ pGinaSession->pWlxDisplaySASNotice = (PWLX_DISPLAYSASNOTICE) GetProcAddress(hDllInstance, WLX_DISPLAYSASNOTICE_NAME);
+ if (!pGinaSession->pWlxDisplaySASNotice)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxDisplaySASNotice entry point\n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxLoggedOutSAS = (PWLX_LOGGEDOUTSAS) GetProcAddress(hDllInstance, WLX_LOGGEDOUTSAS_NAME);
+ if (!pGinaSession->pWlxLoggedOutSAS)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxLoggedOutSAS entry point\n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxActivateUserShell = (PWLX_ACTIVATEUSERSHELL) GetProcAddress(hDllInstance, WLX_ACTIVATEUSERSHELL_NAME);
+ if (!pGinaSession->pWlxActivateUserShell)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxActivateUserShell entry point\n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxLoggedOnSAS = (PWLX_LOGGEDONSAS) GetProcAddress(hDllInstance, WLX_LOGGEDONSAS_NAME);
+ if (!pGinaSession->pWlxLoggedOnSAS)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxLoggedOnSAS entry point\n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxDisplayLockedNotice = (PWLX_DISPLAYLOCKEDNOTICE) GetProcAddress(hDllInstance, WLX_DISPLAYLOCKED_NAME);
+ if (!pGinaSession->pWlxDisplayLockedNotice)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxDisplayLockedNotice\n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxWkstaLockedSAS = (PWLX_WKSTALOCKEDSAS) GetProcAddress(hDllInstance, WLX_WKSTALOCKEDSAS_NAME);
+ if (!pGinaSession->pWlxWkstaLockedSAS)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxWkstaLockedSAS entry point \n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxIsLockOk = (PWLX_ISLOCKOK) GetProcAddress(hDllInstance, WLX_ISLOCKOK_NAME);
+ if (!pGinaSession->pWlxIsLockOk)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxIsLockOk entry point"));
+ goto LoadGina_ErrorReturn;
+ }
+ IsLockOkFn = pGinaSession->pWlxIsLockOk;
+
+ pGinaSession->pWlxIsLogoffOk = (PWLX_ISLOGOFFOK) GetProcAddress(hDllInstance, WLX_ISLOGOFFOK_NAME);
+ if (!pGinaSession->pWlxIsLogoffOk)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxIsLogoffOk entry point"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxLogoff = (PWLX_LOGOFF) GetProcAddress(hDllInstance, WLX_LOGOFF_NAME);
+ if (!pGinaSession->pWlxLogoff)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxLogoff entry point\n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+ pGinaSession->pWlxShutdown = (PWLX_SHUTDOWN) GetProcAddress(hDllInstance, WLX_SHUTDOWN_NAME);
+ if (!pGinaSession->pWlxShutdown)
+ {
+ DebugLog((DEB_ERROR, "Could not find WlxShutdown entry point \n"));
+ goto LoadGina_ErrorReturn;
+ }
+
+
+ //
+ // New interfaces
+ //
+
+ pGinaSession->pWlxStartApplication = (PWLX_STARTAPPLICATION) GetProcAddress(hDllInstance, WLX_STARTAPPLICATION_NAME);
+ if (!pGinaSession->pWlxStartApplication)
+ {
+ DebugLog((DEB_TRACE, "Could not find WlxStartApplication entry point \n"));
+ pGinaSession->pWlxStartApplication = WlxStartApplication;
+ }
+ pGinaSession->pWlxScreenSaverNotify = (PWLX_SSNOTIFY) GetProcAddress(hDllInstance, WLX_SSNOTIFY_NAME);
+ if (!pGinaSession->pWlxScreenSaverNotify)
+ {
+ pGinaSession->pWlxScreenSaverNotify = DummyWlxScreenSaverNotify;
+ }
+
+ return(pGinaSession);
+
+LoadGina_ErrorReturn:
+
+ LocalFree(pGinaSession);
+ return(NULL);
+}
+
+void
+GinaCatastrophicError(PGLOBALS pGlobals)
+{
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+ MessageBox( NULL,
+ TEXT("The GINA dll has created an unrecoverable error\nand Windows NT will reboot after this"),
+ TEXT("Error!"),
+ MB_ICONSTOP | MB_OK | MB_SYSTEMMODAL);
+ RtlRaiseStatus(STATUS_LOGON_FAILURE);
+}
+
+BOOL
+DetermineUserInterface(PGLOBALS pGlobals)
+{
+ WCHAR szGinaDll[MAX_PATH];
+ DWORD dwGinaLevel;
+
+ GetProfileString(APPLICATION_NAME, GINA_KEY, TEXT("msgina.dll"), szGinaDll, MAX_PATH);
+
+ pGlobals->pGina = LoadGinaDll(szGinaDll);
+
+ if (!pGlobals->pGina)
+ {
+ ExitProcess( EXIT_GINA_ERROR );
+ }
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_NEGOTIATE))
+ {
+ DebugBreak();
+ }
+ try
+ {
+#endif // Debug
+
+ pGlobals->pGina->pWlxNegotiate(WLX_CURRENT_VERSION, &dwGinaLevel);
+#if DBG
+ }
+ except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DebugLog((DEB_ERROR, "Exception in GINA dll\n"));
+ RtlRaiseStatus(GetExceptionCode());
+ }
+#endif
+
+ if (dwGinaLevel > WLX_CURRENT_VERSION)
+ {
+ DebugLog((DEB_ERROR, "%ws is at version %d, can't support\n", szGinaDll, dwGinaLevel));
+ ExitProcess( EXIT_GINA_ERROR );
+ }
+
+ return(TRUE);
+}
diff --git a/private/windows/gina/winlogon/ginamgr.h b/private/windows/gina/winlogon/ginamgr.h
new file mode 100644
index 000000000..87cbf3aa3
--- /dev/null
+++ b/private/windows/gina/winlogon/ginamgr.h
@@ -0,0 +1,159 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: ginamgr.h
+//
+// Contents:
+//
+// Classes:
+//
+// Functions:
+//
+// History: 10-24-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+
+
+#ifdef TYPES_ONLY
+
+typedef
+BOOL (WINAPI * PWLX_NEGOTIATE)(
+ DWORD, DWORD *);
+
+typedef
+BOOL (WINAPI * PWLX_INITIALIZE)(
+ LPWSTR, HANDLE, PVOID, PVOID, PVOID *);
+
+typedef
+VOID (WINAPI * PWLX_DISPLAYSASNOTICE)(
+ PVOID );
+
+typedef
+int (WINAPI * PWLX_LOGGEDOUTSAS)(
+ PVOID, DWORD, PLUID, PSID, PDWORD, PHANDLE, PWLX_MPR_NOTIFY_INFO, PVOID);
+
+typedef
+BOOL (WINAPI * PWLX_ACTIVATEUSERSHELL)(
+ PVOID, PWSTR, PWSTR, PVOID);
+
+typedef
+int (WINAPI * PWLX_LOGGEDONSAS)(
+ PVOID, DWORD, PVOID);
+
+typedef
+VOID (WINAPI * PWLX_DISPLAYLOCKEDNOTICE)(
+ PVOID );
+
+typedef
+int (WINAPI * PWLX_WKSTALOCKEDSAS)(
+ PVOID, DWORD );
+
+typedef
+BOOL (WINAPI * PWLX_ISLOCKOK)(
+ PVOID );
+
+typedef
+BOOL (WINAPI * PWLX_ISLOGOFFOK)(
+ PVOID );
+
+typedef
+VOID (WINAPI * PWLX_LOGOFF)(
+ PVOID );
+
+typedef
+VOID (WINAPI * PWLX_SHUTDOWN)(
+ PVOID, DWORD );
+
+typedef
+BOOL (WINAPI * PWLX_STARTAPPLICATION)(
+ PVOID, PWSTR, PVOID, PWSTR);
+
+typedef
+BOOL (WINAPI * PWLX_SSNOTIFY)(
+ PVOID, BOOL *);
+
+#define WLX_NEGOTIATE_NAME "WlxNegotiate"
+#define WLX_INITIALIZE_NAME "WlxInitialize"
+#define WLX_DISPLAYSASNOTICE_NAME "WlxDisplaySASNotice"
+#define WLX_LOGGEDOUTSAS_NAME "WlxLoggedOutSAS"
+#define WLX_ACTIVATEUSERSHELL_NAME "WlxActivateUserShell"
+#define WLX_LOGGEDONSAS_NAME "WlxLoggedOnSAS"
+#define WLX_DISPLAYLOCKED_NAME "WlxDisplayLockedNotice"
+#define WLX_WKSTALOCKEDSAS_NAME "WlxWkstaLockedSAS"
+#define WLX_ISLOCKOK_NAME "WlxIsLockOk"
+#define WLX_ISLOGOFFOK_NAME "WlxIsLogoffOk"
+#define WLX_LOGOFF_NAME "WlxLogoff"
+#define WLX_SHUTDOWN_NAME "WlxShutdown"
+#define WLX_STARTAPPLICATION_NAME "WlxStartApplication"
+#define WLX_SSNOTIFY_NAME "WlxScreenSaverNotify"
+
+
+typedef struct _GINASESSION {
+ struct _GINASESSION * pNext;
+ struct _GINASESSION * pPrev;
+ HANDLE hWlx; // Handle used by the DLL to call us
+ HANDLE hInstance; // Handle of the DLL
+ PVOID pGinaContext; // Pointer we store for them
+ DWORD cTimeout; // Current timeout, in sec.
+ PWLX_NEGOTIATE pWlxNegotiate; // WlxNegotiate function
+ PWLX_INITIALIZE pWlxInitialize; // WlxInitialize function
+ PWLX_DISPLAYSASNOTICE pWlxDisplaySASNotice;
+ PWLX_LOGGEDOUTSAS pWlxLoggedOutSAS;
+ PWLX_ACTIVATEUSERSHELL pWlxActivateUserShell;
+ PWLX_LOGGEDONSAS pWlxLoggedOnSAS;
+ PWLX_DISPLAYLOCKEDNOTICE pWlxDisplayLockedNotice;
+ PWLX_WKSTALOCKEDSAS pWlxWkstaLockedSAS;
+ PWLX_ISLOCKOK pWlxIsLockOk;
+ PWLX_ISLOGOFFOK pWlxIsLogoffOk;
+ PWLX_LOGOFF pWlxLogoff;
+ PWLX_SHUTDOWN pWlxShutdown;
+ PWLX_STARTAPPLICATION pWlxStartApplication;
+ PWLX_SSNOTIFY pWlxScreenSaverNotify;
+} GINASESSION, * PGINASESSION;
+
+
+#define BREAK_NEGOTIATE 0x00000001
+#define BREAK_INITIALIZE 0x00000002
+#define BREAK_DISPLAY 0x00000004
+#define BREAK_LOGGEDOUT 0x00000008
+#define BREAK_ACTIVATE 0x00000010
+#define BREAK_LOGGEDON 0x00000020
+#define BREAK_DISPLAYLOCKED 0x00000040
+#define BREAK_WKSTALOCKED 0x00000080
+#define BREAK_ISLOCKOK 0x00000100
+#define BREAK_ISLOGOFFOK 0x00000200
+#define BREAK_LOGOFF 0x00000400
+#define BREAK_SHUTDOWN 0x00000800
+
+#define FLAG_ON(dw, f) dw |= (f)
+#define FLAG_OFF(dw, f) dw &= (~(f))
+#define TEST_FLAG(dw, f) ((BOOL)(dw & (f)))
+
+#else // not TYPES_ONLY
+
+extern DWORD GinaBreakFlags;
+
+PGINASESSION
+LoadGinaDll(PWSTR pszGinaDll);
+
+
+BOOL
+DetermineUserInterface(PGLOBALS pGlobals);
+
+
+void
+GinaCatastrophicError(PGLOBALS pGlobals);
+
+void
+CADNotify(PGLOBALS pGlobals, DWORD SasType);
+
+#define IsShutdownReturn(Result) ((Result == WLX_SAS_ACTION_SHUTDOWN) || \
+ (Result == WLX_SAS_ACTION_SHUTDOWN_REBOOT) || \
+ (Result == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) )
+
+
+
+#endif
diff --git a/private/windows/gina/winlogon/i386/os2ssmig.c b/private/windows/gina/winlogon/i386/os2ssmig.c
new file mode 100644
index 000000000..6b6b2172b
--- /dev/null
+++ b/private/windows/gina/winlogon/i386/os2ssmig.c
@@ -0,0 +1,2104 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2ssmig.c
+
+Abstract:
+
+ This module contains the code necessary to initialize the
+ OS/2 SS entries in the registry. It migrates information
+ from os/2's config.sys file to the NT registry.
+
+Author:
+
+ Ofer Porat (oferp) 30-Mar-1993
+
+Environment:
+
+ User Mode only
+
+Revision History:
+
+ The code was originally in the os/2 subsystem, but was moved
+ to winlogon so the registry initialization can be done during
+ boot time. This way the registry info will be correct for the
+ first os/2 program to run.
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define IF_OS2_DEBUG(x) // permanently enables KdPrint()s
+static PVOID Os2Heap; // private heap used for allocs
+
+#define PATHLIST_MAX 1024 // max length of pathlists such as Os2LibPath (in characters)
+#define MAX_CONSYS_SIZE 16384 // max size of config.sys buffers (in bytes)
+#define DOS_DEV_LEN 12 // length of "\\DosDevices\\"
+
+//
+// The following constants define the meaning of the Flags value in
+// the config sys key entry:
+// bit CONFSYSON_DISK -- 1 = os/2 config.sys on drive c, 0 = no os/2 config.sys on drive c
+// bit DISABLEMIGTRATION -- if 1, migration from os/2 config.sys to NT registry is disabled.
+//
+
+#define FLAGS_CONFIGSYSONDISK 0x1L
+#define FLAGS_DISABLEMIGRATION 0x2L
+
+static WCHAR Os2SoftwareDirectory[] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft";
+static WCHAR Os2ProductDirectory[] = L"OS/2 Subsystem for NT";
+static WCHAR Os2VersionDirectory[] = L"1.0";
+static WCHAR Os2IniName[] = L"os2.ini";
+static WCHAR Os2ConfigSysName[] = L"config.sys";
+static WCHAR Os2ConfigFlagName[] = L"Flags";
+static WCHAR Os2ConfigStampName[] = L"FileTimeSizeStamp";
+static WCHAR Os2Class[] = L"OS2SS";
+static CHAR Os2ConfigSysDefaultValue[] =
+//
+// The '\a' in the following strings will be replaced by the SystemDirectory Value
+//
+"NTREM Here is a summary of what is allowed to appear in this registry entry:\0"
+"NTREM Comments starting with REM will be visible to the user when s/he opens\0"
+"NTREM c:\\config.sys.\0"
+"NTREM Comments starting with NTREM are only visible by direct access to the\0"
+"NTREM registry.\0"
+"NTREM The following OS/2 configuration commands are significant:\0"
+"NTREM COUNTRY=\0"
+"NTREM CODEPAGE=\0"
+"NTREM DEVINFO=KBD,\0"
+"NTREM Any other commands apart from the exceptions listed below will be\0"
+"NTREM visible to an OS/2 program that opens c:\\config.sys, however they are\0"
+"NTREM not used internally by the NT OS/2 SubSystem.\0"
+"NTREM Exceptions:\0"
+"NTREM The following commands are completely ignored. Their true values\0"
+"NTREM appear in the system environment and should be modified using the\0"
+"NTREM Control Panel System applet. Note that LIBPATH is called Os2LibPath\0"
+"NTREM in the NT system environment.\0"
+"SET PATH=<ignored>\0"
+"LIBPATH=<ignored>\0"
+"NTREM In addition, any \"SET=\" commands (except COMSPEC) will be\0"
+"NTREM completely ignored. You should set OS/2 environment variables just\0"
+"NTREM like any other Windows NT environment variables by using the Control\0"
+"NTREM Panel System applet.\0"
+"NTREM If you have an OS/2 editor available, it is highly recommended that you\0"
+"NTREM modify NT OS/2 config.sys configuration by editing c:\\config.sys with\0"
+"NTREM this editor. This is the documented way to make such modification, and\0"
+"NTREM is therefore less error-prone.\0"
+"NTREM Now comes the actual text.\0"
+"REM\0"
+"REM This is a fake OS/2 config.sys file used by the NT OS/2 SubSystem.\0"
+"REM The following information resides in the Registry and NOT in a disk file.\0"
+"REM OS/2 Apps that access c:\\config.sys actually manipulate this information.\0"
+"REM\0"
+"PROTSHELL=c:\\os2\\pmshell.exe c:\\os2\\os2.ini c:\\os2\\os2sys.ini \a\\cmd.exe\0"
+"SET COMSPEC=\a\\cmd.exe\0"
+;
+
+static WCHAR Os2ConfigSysKeyName[] =
+L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\config.sys";
+static WCHAR Os2EnvironmentDirectory[] =
+L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
+static HANDLE Os2EnvironmentKeyHandle = NULL;
+
+static WCHAR Os2OriginalCanonicalConfigSys[] = L"\\DosDevices\\C:\\CONFIG.SYS";
+
+static BOOLEAN Os2LibPathFound = FALSE;
+static WCHAR Os2LibPathValueName[] = L"Os2LibPath";
+static UNICODE_STRING Os2LibPathValueData_U;
+
+static PWSTR Os2PathString = NULL;
+
+static PWSTR pOs2ConfigSys = NULL;
+static ULONG Os2SizeOfConfigSys = 0;
+static PWSTR pOs2UpperCaseConfigSys = NULL;
+
+static WCHAR Os2SystemDirectory[MAX_PATH];
+
+
+VOID
+Os2RegSetFlags(
+ IN HANDLE ConfigSysKeyHandle,
+ IN ULONG FlagsValue
+ )
+
+/*++
+
+Routine Description:
+
+ Write the "Flags" value into the config.sys registry key.
+
+Arguments:
+
+ ConfigSysKeyHandle -- supplies read/write handle to config.sys reg key
+ FlagsValue -- supplies the value to write
+
+Return Value:
+
+ None.
+
+Note:
+
+ Errors are ignored
+
+--*/
+
+{
+ UNICODE_STRING String_U;
+ NTSTATUS Status;
+
+ RtlInitUnicodeString(&String_U, Os2ConfigFlagName);
+
+ Status = NtSetValueKey(
+ ConfigSysKeyHandle,
+ &String_U,
+ 0L,
+ REG_DWORD,
+ &FlagsValue,
+ sizeof(DWORD)
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Os2RegSetFlags: NetSetValueKey failed, Status = %lx\n", Status));
+#endif
+ }
+
+ // ignore errors
+}
+
+
+VOID
+Os2RegSetStamp(
+ IN HANDLE ConfigSysKeyHandle,
+ IN PLARGE_INTEGER pTimeStamp,
+ IN PLARGE_INTEGER pSizeStamp
+ )
+
+/*++
+
+Routine Description:
+
+ Write the "FileTimeSizeStamp" value into the config.sys registry key.
+
+Arguments:
+
+ ConfigSysKeyHandle -- supplies read/write handle to config.sys reg key
+ pTimeStamp, pSizeStamp -- supplies the value to write
+
+Return Value:
+
+ None.
+
+Note:
+
+ Errors are ignored
+
+--*/
+
+{
+ UNICODE_STRING String_U;
+ ULONG Buffer[4];
+ NTSTATUS Status;
+
+ Buffer[0] = pTimeStamp->LowPart;
+ Buffer[1] = (ULONG) pTimeStamp->HighPart;
+ Buffer[2] = pSizeStamp->LowPart;
+ Buffer[3] = (ULONG) pSizeStamp->HighPart;
+
+ RtlInitUnicodeString(&String_U, Os2ConfigStampName);
+
+ Status = NtSetValueKey(
+ ConfigSysKeyHandle,
+ &String_U,
+ 0L,
+ REG_BINARY,
+ (PVOID) Buffer,
+ sizeof(Buffer)
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Os2RegSetFlags: NetSetValueKey failed, Status = %lx\n", Status));
+#endif
+ }
+
+ // ignore errors
+}
+
+
+BOOLEAN
+Os2InitOriginalConfigSysProcessing(
+ IN HANDLE ConfigSysKeyHandle,
+ IN ULONG FlagsValue,
+ IN HANDLE ConfigSysFileHandle,
+ IN PLARGE_INTEGER pTimeStamp,
+ IN PLARGE_INTEGER pSizeStamp
+ )
+
+/*++
+
+Routine Description:
+
+ This function checks if there is an OS/2 config.sys configuration file on the
+ disk. If so, it opens it and reads it in. The file is converted to UNICODE,
+ and an upper case copy of it is made.
+
+Arguments:
+
+ ConfigSysKeyHandle -- supplies a read/write handle to the config.sys reg key
+ this is used to update the flags/stamp values
+ FlagsValue -- The previously existing "Flags" value that was read in from the
+ registry. If this is -1, then no previous Flags value existed.
+ ConfigSysFileHandle -- An optional handle to an already open config.sys file
+ pTimeStamp, pSizeStamp -- info about the open config.sys file.
+
+ Note: The parameters ConfigSysFileHandle + pTimeStamp + pSizeStamp are optional,
+ and come as a packet. If the config.sys file was previously opened, the handle
+ will be non-null, and all 3 params must be valid. If the config.sys file was
+ not previously opened (successfully), the handle should be NULL, and the other
+ 2 params need not be valid.
+
+Return Value:
+
+ TRUE if there's an OS/2 config.sys, and all the operations needed to prepare
+ it have succeeded. FALSE otherwise.
+
+Notes:
+ On success Sets global variables as follows:
+ pOs2ConfigSys - a null-terminated UNICODE copy of the OS/2 config.sys.
+ pOs2UpperCaseConfigSys - an upper case copy of pOs2ConfigSys.
+ Os2SizeOfConfigSys - the number of characters in the above strings.
+
+ ConfigSysFileHandle is closed before the function returns.
+
+ The flags/stamp values in the config.sys reg key are updated if necessary.
+
+--*/
+
+{
+ UNICODE_STRING CanonicalConfigDotSys_U;
+ UNICODE_STRING Tmp_U;
+ ANSI_STRING Tmp_MB;
+ OBJECT_ATTRIBUTES Obja;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ PSZ pTempOs2ConfigSys;
+ LARGE_INTEGER TimeStamp, SizeStamp;
+
+ if (FlagsValue != (ULONG)-1) {
+
+ if (FlagsValue & FLAGS_DISABLEMIGRATION) {
+
+ //
+ // ConfigSysFileHandle cannot be non-NULL at this point
+ // so there's no need to close it. Also, no need to
+ // update flags/stamp.
+ //
+
+ return(FALSE);
+ }
+
+ FlagsValue &= ~FLAGS_CONFIGSYSONDISK;
+
+ } else {
+ FlagsValue = 0;
+
+ //
+ // 1st time migration will always take place (after system setup)
+ // if you you want to disable post 1st-time migration, set FlagsValue
+ // to a default of FLAGS_DISABLEMIGRATION. If you don't any migration
+ // at all (not even 1st-time), then set the FlagsValue similarly, and
+ // also do a { Os2RegSetFlags(..), return FALSE }
+ //
+ }
+
+ if (ConfigSysFileHandle == NULL) {
+
+ // Try opening OS/2's config.sys file
+
+ RtlInitUnicodeString(&CanonicalConfigDotSys_U, Os2OriginalCanonicalConfigSys);
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalConfigDotSys_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&ConfigSysFileHandle,
+ FILE_GENERIC_READ,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ //
+ // Debug print removed, because this is a valid situation (no config.sys file)
+ //
+#if 0
+#if DBG
+ KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - NtOpenFile-1 %lx\n", Status));
+#endif
+#endif
+ Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
+ return (FALSE);
+ }
+
+ Status = Or2GetFileStamps(
+ ConfigSysFileHandle,
+ &TimeStamp,
+ &SizeStamp
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Os2InitOriginalConfigSysProcessing: Can't get config.sys time/size stamp, Status = %lx\n", Status));
+#endif
+
+ NtClose(ConfigSysFileHandle);
+ Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
+ return(FALSE);
+ }
+
+ pTimeStamp = &TimeStamp;
+ pSizeStamp = &SizeStamp;
+ }
+
+ // Get the file length
+
+ Os2SizeOfConfigSys = pSizeStamp->LowPart;
+
+ // Allocate space for reading it in
+
+ // the + 1 in following parameter is for inserting the NUL character
+
+ pTempOs2ConfigSys = (PSZ) RtlAllocateHeap(Os2Heap, 0, Os2SizeOfConfigSys + 1);
+
+ if (pTempOs2ConfigSys == NULL) {
+#if DBG
+ KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - RtlAllocateHeap pTempOs2ConfigSys\n"));
+#endif
+ Os2SizeOfConfigSys = 0;
+ NtClose(ConfigSysFileHandle);
+ Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
+ return (FALSE);
+ }
+
+ pOs2ConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+
+ if (pOs2ConfigSys == NULL) {
+#if DBG
+ KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - RtlAllocateHeap pOs2ConfigSys\n"));
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+ NtClose(ConfigSysFileHandle);
+ Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
+ return (FALSE);
+ }
+
+ // Read it in
+
+ Status = NtReadFile(ConfigSysFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ (PVOID)pTempOs2ConfigSys,
+ Os2SizeOfConfigSys,
+ NULL,
+ NULL
+ );
+ NtClose(ConfigSysFileHandle);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - NtReadFile %lx\n", Status));
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ pOs2ConfigSys = NULL;
+ Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
+ return (FALSE);
+ }
+
+ pTempOs2ConfigSys[Os2SizeOfConfigSys] = '\0';
+
+ // Convert to UNICODE
+
+ RtlInitAnsiString(&Tmp_MB, pTempOs2ConfigSys);
+
+ Tmp_U.Buffer = pOs2ConfigSys;
+ Tmp_U.MaximumLength = (USHORT) ((Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+
+ RtlOemStringToUnicodeString(&Tmp_U, (POEM_STRING)&Tmp_MB ,FALSE);
+
+ Os2SizeOfConfigSys = Tmp_U.Length / sizeof(WCHAR);
+
+ pOs2ConfigSys[Os2SizeOfConfigSys] = UNICODE_NULL;
+
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+
+ // Prepare the upper case copy
+
+ pOs2UpperCaseConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+ if (pOs2UpperCaseConfigSys == NULL) {
+#if DBG
+ KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - RtlAllocateHeap pOs2UpperConfigSys\n"));
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ pOs2ConfigSys = NULL;
+ Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
+ return (FALSE);
+ }
+
+ wcscpy(pOs2UpperCaseConfigSys, pOs2ConfigSys);
+ Or2UnicodeStrupr(pOs2UpperCaseConfigSys);
+
+ //
+ // Verify that the CONFIG.SYS file is really an OS/2 file and not a
+ // DOS file.
+ // Look for certain strings that MUST appear in an OS/2 CONFIG.SYS
+ // file and don't appear in DOS CONFIG.SYS files
+ //
+
+ if ((wcsstr(pOs2UpperCaseConfigSys, L"LIBPATH") == NULL) ||
+ (wcsstr(pOs2UpperCaseConfigSys, L"PROTSHELL") == NULL) ||
+ (wcsstr(pOs2UpperCaseConfigSys, L"PROTECTONLY") == NULL)
+ ) {
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2UpperCaseConfigSys);
+ pOs2UpperCaseConfigSys = pOs2ConfigSys = NULL;
+ Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
+ return (FALSE);
+ }
+
+ FlagsValue |= FLAGS_CONFIGSYSONDISK;
+
+ Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
+ Os2RegSetStamp(ConfigSysKeyHandle, pTimeStamp, pSizeStamp);
+
+ return (TRUE);
+}
+
+
+VOID
+Os2SetDirectiveProcessingDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This is a Dispatch Routine that is used to process SET directives in OS/2's config.sys
+ file. The directives are entered into the system environment.
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in os2ssrtl.c
+
+ UserParameter - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNICODE_STRING VarName_U; // for setting up variable name
+ UNICODE_STRING VarValue_U; // for setting up variable value
+ PWSTR Dest = *(PWSTR *) UserParameter;
+ NTSTATUS Status;
+// ULONG ResultLength;
+ WCHAR wch;
+// KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
+
+ // Set up variable name
+
+ VarName_U.Buffer = Value;
+ VarName_U.Length = 0;
+
+ while ((ValueLen > 0) && (*Value != L'=')) {
+ Value++;
+ VarName_U.Length += sizeof(WCHAR);
+ ValueLen--;
+ }
+
+ if (ValueLen == 0 || // End of line reached without finding '='
+ VarName_U.Length == 0) { // Empty name
+ return;
+ }
+
+ VarName_U.MaximumLength = VarName_U.Length;
+
+ // Following SET directives are ignored
+
+ if (Or2UnicodeEqualCI(VarName_U.Buffer, L"COMSPEC=", 8) ||
+// Or2UnicodeEqualCI(VarName_U.Buffer, L"PATH=", 5) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIDEO_DEVICES=", 14) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIO_IBMVGA=", 11) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIO_VGA=", 8) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"PROMPT=", 7)
+ ) {
+ return;
+ }
+
+ // Here, we have a valid name, followed by '='
+ Value++; // Skip the '='
+ ValueLen--;
+
+ // Set up variable value
+
+ VarValue_U.Buffer = Value;
+ VarValue_U.Length = (USHORT) (ValueLen * sizeof(WCHAR)); // what's left of the line
+ VarValue_U.MaximumLength = VarValue_U.Length;
+
+ //
+ // Update the information in the registry with the info
+ // in the file
+ //
+
+#if 0
+ // not in effect anymore
+ //
+ // The KEYS variable is handled in a special way.
+ // It's put in the registry config.sys in order to prevent possible
+ // conflict.
+ //
+
+ if (Or2UnicodeEqualCI(VarName_U.Buffer, L"KEYS=", 5)) {
+ RtlMoveMemory(Dest, L"SET ", 8);
+ Dest += 4;
+ RtlMoveMemory(Dest, VarName_U.Buffer, VarName_U.Length);
+ Dest += VarName_U.Length / sizeof(WCHAR);
+ *Dest++ = L'=';
+ RtlMoveMemory(Dest, VarValue_U.Buffer, VarValue_U.Length);
+ Dest += VarValue_U.Length / sizeof(WCHAR);
+ *Dest++ = UNICODE_NULL;
+ *(PWSTR *) UserParameter = Dest;
+ return;
+ }
+#endif
+
+ //
+ // If Os2EnvironmentKeyHandle is NULL, we don't have
+ // write access to the system environment, and we skip
+ // setting the variable.
+ //
+
+ if (Os2EnvironmentKeyHandle == NULL) {
+ return;
+ }
+
+ //
+ // Special handling for PATH -- retained in the global variable
+ // Os2PathString. Only the last occurence of PATH is retained.
+ // This is compatible with OS/2 which uses the last occurence.
+ //
+
+ if (Or2UnicodeEqualCI(VarName_U.Buffer, L"PATH=", 5)) {
+
+ if (Os2PathString != NULL) { // already found a path?
+
+ RtlFreeHeap(Os2Heap, 0, Os2PathString); // get rid of it
+ Os2PathString = NULL;
+ }
+
+ Os2PathString = (PWSTR) RtlAllocateHeap(Os2Heap, 0, VarValue_U.Length + sizeof(WCHAR));
+
+ if (Os2PathString == NULL) {
+#if DBG
+ KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Failed to allocate heap space for PATH\n"));
+#endif
+
+ return; // no space for storing the path -- skip it
+ }
+
+ // switch to the upper case copy...
+
+ VarValue_U.Buffer = pOs2UpperCaseConfigSys + (VarValue_U.Buffer - pOs2ConfigSys);
+
+ RtlMoveMemory(Os2PathString, VarValue_U.Buffer, VarValue_U.Length);
+ Os2PathString[VarValue_U.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ return;
+ }
+
+ //
+ // Otherwise, it's stored in the system environment
+ //
+
+ //
+ // If a value key of the same name already exists,
+ // don't replace it. This is done in order to prevent
+ // the OS/2 SS from overriding possible NT definitions
+ //
+
+ //
+ // !!! Modification 5/30/93 -- We decided to be a little more brave about this.
+ // On one hand there doesn't seem to be any conflict between any possible OS/2
+ // definitions, and NT definitions. On the other hand, since we now do re-migration
+ // on every config.sys change, if we don't update existing variables, the user's
+ // important OS/2 variables (e.g. DPATH) will not get remigrated. Therefore we
+ // always update. -- oferp
+ //
+
+#if 0
+
+ Status = NtQueryValueKey(Os2EnvironmentKeyHandle,
+ &VarName_U,
+ KeyValuePartialInformation,
+ &KeyValueInfo,
+ sizeof(KeyValueInfo),
+ &ResultLength
+ );
+#else
+
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+
+#endif
+
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
+
+ //
+ // Set the system wide variable to the value specified
+ // in the original OS/2 config.sys
+ //
+
+ wch = Value[ValueLen];
+ Value[ValueLen] = UNICODE_NULL;
+
+ Status = NtSetValueKey(Os2EnvironmentKeyHandle,
+ &VarName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ VarValue_U.Buffer,
+ VarValue_U.Length + sizeof(WCHAR)
+ );
+
+ Value[ValueLen] = wch;
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Unable to NtSetValueKey() system env, rc = %X\n",
+ Status));
+ }
+#endif
+ return;
+ }
+
+ } else {
+#if DBG
+ if (Status != STATUS_BUFFER_OVERFLOW) {
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Unable to NtQueryValueKey() system env, rc = %X\n",
+ Status));
+ }
+ }
+#endif
+ return;
+ }
+}
+
+
+VOID
+Os2CommaProcessingDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This is a Dispatch Routine that is used to process certain directives in OS/2's config.sys
+ file. The directives are copied into the config.sys registry entry we're building.
+ Some directives are truncated after a certain number of commas.
+
+ !!! Modification 5/30/93 -- Migration of the three NLS related statements has been disabled.
+ Reason: The intended default behavior is this: The registry config.sys entry has no
+ NLS entries, and the OS/2 subsystem picks up these values from NT's default values.
+ Supporting the registry config.sys values is only meant to be used if the user actually
+ wants to have separate OS/2 and NT NLS parameters. This is almost never the case. The
+ reason for allowing dual-NLS mode is because some NT languages may not be supported on
+ OS/2, and so the user may want to specify a different (existing) NLS setting for the
+ OS/2 subsystem. The usual setting is therefore to have no NLS directives in the registry
+ config.sys. That's why we shouldn't migrate. -- oferp
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in os2ssrtl.c
+
+ UserParameter - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+//
+// Lines passed to this dispatch function need to be copied to the output as are
+// except they should be truncated after a certain number of commas. The
+// following table lists the number of commas. 0 means no truncation.
+//
+
+#if 0
+ ULONG ItemTable[] = { 1, // COUNTRY
+ 0, // CODEPAGE
+ 2 // DEVINFO (only with KBD)
+ };
+ PWSTR Dest = *(PWSTR *) UserParameter;
+ ULONG CommaCtr;
+
+ if (DispatchTableIndex== 2 && !Or2UnicodeEqualCI(Value, L"KBD,", 4)) {
+ return;
+ }
+
+ // First, copy the Name
+
+ RtlMoveMemory(Dest, Name, NameLen * sizeof(WCHAR));
+ Dest += NameLen;
+ *Dest++ = L'=';
+
+ // Now, copy the value for the right number of commas
+
+ CommaCtr = 0;
+
+ while (ValueLen > 0) {
+ if (ItemTable[DispatchTableIndex] != 0 && *Value == L',') {
+ CommaCtr++;
+ if (CommaCtr == ItemTable[DispatchTableIndex]) {
+ break;
+ }
+ }
+
+ *Dest++ = *Value++;
+ ValueLen--;
+ }
+ *Dest++ = UNICODE_NULL;
+ *(PWSTR *) UserParameter = Dest;
+
+#else
+
+ return; // do nothing!
+
+#endif
+}
+
+
+VOID
+Os2ProcessOriginalConfigSys(
+ IN OUT PWSTR *DestPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This function processes OS/2's config.sys file after it has been properly initialized
+ by Os2InitOriginalConfigSysProcessing.
+
+Arguments:
+
+ DestPtr - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ static ENVIRONMENT_DISPATCH_TABLE_ENTRY DispatchTable[] =
+ {
+ { L"COUNTRY", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"CODEPAGE", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"DEVINFO", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"LIBPATH", L"=", Or2FillInSearchRecordDispatchFunction, NULL },
+ { L"SET", L" \t", Os2SetDirectiveProcessingDispatchFunction, NULL }
+ };
+ ENVIRONMENT_SEARCH_RECORD LibPathRecord;
+ ULONG i;
+ PWSTR p;
+ WCHAR ch;
+
+ //
+ // Most of the job is done by Or2IterateEnvironment which processes the file
+ // according to a dispatch table.
+ //
+ // LibPath needs to be handled a little differently. We need to process only
+ // the *last* occurence of LIBPATH= in the file (this is the same as OS/2).
+ // Therefore we only record the position of the LIBPATH= statments as we run
+ // into them. After we're finished we'll have the position of the last one,
+ // and we can process that line.
+ //
+
+ for (i = 0; i < 5; i++) {
+ DispatchTable[i].UserParameter = (PVOID) DestPtr;
+ }
+
+ DispatchTable[3].UserParameter = (PVOID)&LibPathRecord;
+ LibPathRecord.DispatchTableIndex = (ULONG)-1;
+
+ Or2IterateEnvironment(pOs2ConfigSys,
+ DispatchTable,
+ 5,
+ CRLF_DELIM);
+
+
+ if (Os2LibPathFound && LibPathRecord.DispatchTableIndex != (ULONG)-1) {
+
+ // handle LIBPATH if there was one
+
+ // get a pointer to the upper case version, so we can append it
+
+ p = pOs2UpperCaseConfigSys + (LibPathRecord.Value - pOs2ConfigSys);
+
+ ch = p[LibPathRecord.ValueLen];
+ p[LibPathRecord.ValueLen] = UNICODE_NULL;
+
+ Or2AppendPathToPath(Os2Heap,
+ p,
+ &Os2LibPathValueData_U,
+ TRUE);
+ p[LibPathRecord.ValueLen] = ch;
+ }
+}
+
+
+VOID
+Os2TerminateOriginalConfigSysProcessing(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Cleans up processing of OS/2's config.sys. Releases the storage used to store the
+ file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2UpperCaseConfigSys);
+ pOs2UpperCaseConfigSys = pOs2ConfigSys = NULL;
+ Os2SizeOfConfigSys = 0;
+}
+
+
+NTSTATUS
+Os2SbBuildSD(
+ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ PACL *pDacl
+ )
+
+/*++
+
+Routine Description:
+
+ Builds a security descriptor for creating our registry keys.
+
+ Administrators -- all access
+ everyone -- read access
+
+Arguments:
+
+ SecurityDescriptor -- supplies a pointer to a preallocated SD that will be built
+ pDacl -- returns a pointer to a dacl that should be released from Os2Heap after
+ we're finished using the security descriptor.
+
+Return Value:
+
+ NT error code.
+
+--*/
+
+{
+ PACL Dacl;
+ PACE_HEADER Pace;
+ PSID AdminAliasSid;
+ ULONG DaclSize;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
+ SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
+ PSID WorldSid;
+ NTSTATUS Status;
+
+ //
+ // Create the SIDs for local admin and World.
+ //
+
+ Status = RtlAllocateAndInitializeSid(
+ &NtAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &AdminAliasSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateAndInitializeSid(Admin), Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+ Status = RtlAllocateAndInitializeSid(
+ &WorldSidAuthority,
+ 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateAndInitializeSid(World), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeSid( AdminAliasSid );
+ return (Status);
+ }
+
+ Status = RtlCreateSecurityDescriptor( SecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlCreateSecurityDescriptor, Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeSid( AdminAliasSid );
+ RtlFreeSid( WorldSid );
+ return (Status);
+ }
+
+
+ //
+ // Compute the size of the buffer needed for the
+ // DACL.
+ //
+
+ DaclSize = sizeof( ACL ) +
+ 2 * (sizeof( ACCESS_ALLOWED_ACE ) - sizeof( ULONG ))
+ +
+ RtlLengthSid( AdminAliasSid ) +
+ RtlLengthSid( WorldSid );
+
+ Dacl = (PACL) RtlAllocateHeap(Os2Heap, 0, DaclSize);
+
+ if (Dacl == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateHeap failed\n"));
+ }
+#endif
+ RtlFreeSid( AdminAliasSid );
+ RtlFreeSid( WorldSid );
+ return(STATUS_NO_MEMORY);
+ }
+
+ //
+ // Build the ACL
+ //
+
+ Status = RtlCreateAcl ( Dacl, DaclSize, ACL_REVISION2 );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlCreateAcl, Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ RtlFreeSid( AdminAliasSid );
+ RtlFreeSid( WorldSid );
+ return (Status);
+ }
+
+ Status = RtlAddAccessAllowedAce (
+ Dacl,
+ ACL_REVISION2,
+ GENERIC_ALL,
+ AdminAliasSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAddAccessAllowedAce(Admin), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ RtlFreeSid( AdminAliasSid );
+ RtlFreeSid( WorldSid );
+ return (Status);
+ }
+
+ Status = RtlAddAccessAllowedAce (
+ Dacl,
+ ACL_REVISION2,
+ GENERIC_READ,
+ WorldSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAddAccessAllowedAce(World), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ RtlFreeSid( AdminAliasSid );
+ RtlFreeSid( WorldSid );
+ return (Status);
+ }
+
+ Status = RtlGetAce(
+ Dacl,
+ 0L,
+ &Pace
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlGetAce(Admin), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ RtlFreeSid( AdminAliasSid );
+ RtlFreeSid( WorldSid );
+ return (Status);
+ }
+
+ Pace->AceFlags |= CONTAINER_INHERIT_ACE;
+
+ Status = RtlGetAce(
+ Dacl,
+ 1L,
+ &Pace
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlGetAce(World), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ RtlFreeSid( AdminAliasSid );
+ RtlFreeSid( WorldSid );
+ return (Status);
+ }
+
+ Pace->AceFlags |= CONTAINER_INHERIT_ACE;
+
+ //
+ // Add the ACL to the security descriptor
+ //
+
+ Status = RtlSetDaclSecurityDescriptor(
+ SecurityDescriptor,
+ TRUE,
+ Dacl, // put (PACL) NULL to allow everyone all access
+ FALSE );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlSetDaclSecurityDescriptor, Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ RtlFreeSid( AdminAliasSid );
+ RtlFreeSid( WorldSid );
+ return (Status);
+ }
+
+ //
+ // These have been copied into the security descriptor, so
+ // we can free them.
+ //
+
+ RtlFreeSid( AdminAliasSid );
+
+ RtlFreeSid( WorldSid );
+
+ *pDacl = Dacl;
+
+ return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2SbInitializeRegistryKeys(
+ OUT PHANDLE phConfigSysKeyHandle,
+ OUT PHANDLE phEnvironmentKeyHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates the OS/2 subsystem key hierarchy in the registry. It also opens
+ the config.sys key, and opens the system environment key.
+
+Arguments:
+
+ phConfigSysKeyHandle - Returns a READ/WRITE handle to the config.sys key in the registry.
+
+ phEnvironmentKeyHandle - Returns a READ/WRITE handle to the system environment key.
+ If this key can't be opened due to access denied, NULL is returned and the
+ return value will be STATUS_SUCCESS.
+
+ Note --- If the return value is not a success return value, none of the above return
+ variables can be considered to be valid.
+
+Return Value:
+
+ The value is an NTSTATUS type that is returned when some failure occurs. It may
+ indicate any of several errors that occur during the APIs called in this function.
+ The return value should be tested with NT_SUCCESS().
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES Obja;
+ UNICODE_STRING Class_U;
+ UNICODE_STRING SoftwareDirectory_U;
+ UNICODE_STRING ProductDirectory_U;
+ UNICODE_STRING VersionDirectory_U;
+ UNICODE_STRING Os2IniName_U;
+ UNICODE_STRING ConfigSysName_U;
+ UNICODE_STRING EnvRegDir_U;
+ HANDLE SoftwareKeyHandle;
+ HANDLE ProductKeyHandle;
+ HANDLE VersionKeyHandle;
+ HANDLE Os2IniKeyHandle;
+ HANDLE ConfigSysKeyHandle;
+ HANDLE EnvironmentKeyHandle;
+ ULONG Disposition;
+ NTSTATUS Status;
+ SECURITY_DESCRIPTOR localSecurityDescriptor;
+ PSECURITY_DESCRIPTOR securityDescriptor;
+ PACL Dacl = NULL;
+
+
+ *phConfigSysKeyHandle = NULL;
+ *phEnvironmentKeyHandle = NULL;
+
+ // We start off by creating/opening the registry key hierarchy for our subsystem
+
+ securityDescriptor = &localSecurityDescriptor;
+
+ Status = Os2SbBuildSD(securityDescriptor,
+ &Dacl);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Os2SbBuildSD failed, Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&Class_U, Os2Class);
+
+ RtlInitUnicodeString(&SoftwareDirectory_U, Os2SoftwareDirectory);
+ InitializeObjectAttributes(&Obja,
+ &SoftwareDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&SoftwareKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't open software key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&ProductDirectory_U, Os2ProductDirectory);
+ InitializeObjectAttributes(&Obja,
+ &ProductDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ SoftwareKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&ProductKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ NtClose(SoftwareKeyHandle);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create product key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&VersionDirectory_U, Os2VersionDirectory);
+ InitializeObjectAttributes(&Obja,
+ &VersionDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ ProductKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&VersionKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ NtClose(ProductKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create version key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&Os2IniName_U, Os2IniName);
+ InitializeObjectAttributes(&Obja,
+ &Os2IniName_U,
+ OBJ_CASE_INSENSITIVE,
+ VersionKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&Os2IniKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create os2ini key, rc = %lx\n", Status));
+ }
+#endif
+ NtClose(VersionKeyHandle);
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+ NtClose(Os2IniKeyHandle);
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysName_U,
+ OBJ_CASE_INSENSITIVE,
+ VersionKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&ConfigSysKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ NtClose(VersionKeyHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create/open config.sys key, rc = %lx\n",
+ Status));
+ }
+#endif
+ return(Status);
+ }
+
+ // Open the environment.
+
+ RtlInitUnicodeString(&EnvRegDir_U, Os2EnvironmentDirectory);
+ InitializeObjectAttributes(&Obja,
+ &EnvRegDir_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&EnvironmentKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Unable to NtOpenKey() the system environment, rc = %lx\n",
+ Status));
+ }
+#endif
+ if (Status != STATUS_ACCESS_DENIED) {
+ NtClose(ConfigSysKeyHandle);
+ return(Status);
+ }
+
+ //
+ // on denied access, return with no error so we can at least create the
+ // config.sys value entry
+ // The caller will know this occured because the environment handle is null.
+ //
+
+ } else {
+ *phEnvironmentKeyHandle = EnvironmentKeyHandle;
+ }
+
+ *phConfigSysKeyHandle = ConfigSysKeyHandle;
+ return (STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2SbInitializeRegistry(
+ IN ULONG FlagsValue,
+ IN HANDLE ConfigSysFileHandle,
+ IN PLARGE_INTEGER pTimeStamp,
+ IN PLARGE_INTEGER pSizeStamp
+ )
+
+/*++
+
+Routine Description:
+
+ This function is responsible for initializing the entire Registry component of the
+ Subsystem. It generates the key hierarchy in the registry.
+
+ In the generation of the key hierarchy, it also generates a config.sys entry.
+ The information in this entry is taken from the following sources:
+
+ -- some default strings we put in (see Os2ConfigSysDefaultValue).
+ -- Information from OS/2's config.sys file is added as follows:
+
+ > SET commands are put in the system environment.
+ Some SET commands are ignored (see Os2SetDirectiveProcessingDispatchFunction)
+ > LIBPATH commands are merged to the Os2LibPath variable in the
+ system environment. A terminating semicolon is added if there
+ is only one path in the path list.
+ > SET PATH= is ignored, and the system path remains the same.
+
+Arguments:
+
+ FlagsValue -- The previously existing "Flags" value that was read in from the
+ registry. If this is -1, then no previous Flags value existed.
+ ConfigSysFileHandle -- An optional handle to an already open config.sys file
+ pTimeStamp, pSizeStamp -- info about the open config.sys file.
+
+ Note: The parameters ConfigSysFileHandle + pTimeStamp + pSizeStamp are optional,
+ and come as a packet. If the config.sys file was previously opened, the handle
+ will be non-null, and all 3 params must be valid. If the config.sys file was
+ not previously opened (successfully), the handle should be NULL, and the other
+ 2 params need not be valid.
+
+Return Value:
+
+ The value is an NTSTATUS type that is returned when some failure occurs. It may
+ indicate any of several errors that occur during the APIs called in this function.
+ The return value should be tested with NT_SUCCESS(). If an unsuccessful value
+ is returned, it means the registry component was not properly initialized.
+
+--*/
+
+{
+ UNICODE_STRING Os2LibPathValueName_U;
+ HANDLE ConfigSysKeyHandle;
+ NTSTATUS Status;
+ UNICODE_STRING ConfigSysName_U;
+ PWCHAR pInfo;
+ PUCHAR Src;
+ PWCHAR Src1;
+ PWCHAR Dest;
+ WCHAR ch, ch1;
+
+ // Create the key hierarchy
+
+ Status = Os2SbInitializeRegistryKeys(&ConfigSysKeyHandle,
+ &Os2EnvironmentKeyHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: failed Os2SbInitializeRegistryKeys, Status = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ //
+ // Create the config.sys entry
+ // and migrate information from os/2's config.sys file.
+ //
+
+ Os2LibPathFound = FALSE;
+ Os2LibPathValueData_U.Buffer = NULL;
+
+ if (Os2EnvironmentKeyHandle == NULL) { // we have no write access to the environment
+ goto Os2NoEnvAccess; // skip over the Os2LibPath stuff
+ }
+
+ // Get Os2LibPath from sys env so we can update it.
+
+ if (!Or2GetEnvPath(&Os2LibPathValueData_U,
+ Os2Heap,
+ PATHLIST_MAX,
+ Os2EnvironmentKeyHandle,
+ Os2LibPathValueName,
+ FALSE)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to fetch Os2LibPath from sys env\n"));
+ }
+#endif
+ } else {
+
+ // make sure there's at lease one semicolon
+
+ Or2CheckSemicolon(&Os2LibPathValueData_U);
+
+ Os2LibPathFound = TRUE;
+ }
+
+ if (Os2LibPathFound && Os2LibPathValueData_U.Length == 0) { // it's empty (or nonexistent)
+ // set up a default
+ UNICODE_STRING tmp;
+
+ RtlInitUnicodeString(&tmp, Os2SystemDirectory);
+
+ RtlCopyUnicodeString(&Os2LibPathValueData_U, &tmp);
+
+ RtlAppendUnicodeToString(&Os2LibPathValueData_U, L"\\os2\\dll;");
+
+ Os2LibPathValueData_U.Buffer[Os2LibPathValueData_U.Length/sizeof(WCHAR)] = UNICODE_NULL;
+ }
+
+Os2NoEnvAccess:
+
+ // Now set up the initial regisry config.sys entry.
+
+ // Allocate a buffer to build the config.sys entry in. (it's a multi-string)
+
+ pInfo = (PWCHAR) RtlAllocateHeap(Os2Heap, 0, MAX_CONSYS_SIZE);
+ if (pInfo == NULL)
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to RtlAllocateHeap() space for config.sys value buffer\n"));
+ }
+#endif
+ if (Os2LibPathValueData_U.Buffer != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Os2LibPathValueData_U.Buffer);
+ Os2LibPathValueData_U.Buffer = NULL;
+ Os2LibPathFound = FALSE;
+ }
+ if (Os2EnvironmentKeyHandle != NULL) {
+ NtClose(Os2EnvironmentKeyHandle);
+ Os2EnvironmentKeyHandle = NULL;
+ }
+ NtClose(ConfigSysKeyHandle);
+
+ return (STATUS_NO_MEMORY);
+ }
+
+ // Initially, copy our default value into the entry.
+
+ Src = (PUCHAR) Os2ConfigSysDefaultValue;
+ Dest = pInfo;
+ do
+ {
+ ch = (WCHAR) *Src++;
+ if (ch == L'\a')
+ {
+ Src1 = Os2SystemDirectory;
+ ch1 = *Src1++;
+ while (ch1 != UNICODE_NULL)
+ {
+ *Dest++ = ch1;
+ ch1 = *Src1++;
+ }
+ }
+ else
+ {
+ *Dest++ = ch;
+ }
+ } while (!((ch == UNICODE_NULL) && (*Src == '\0')));
+
+
+ // check if the an OS/2 CONFIG.SYS file already exists on
+ // the drive. Its name will be C:\CONFIG.SYS
+ // If it exists, process it for additional information
+ // The system env will also be updated
+
+ if (Os2InitOriginalConfigSysProcessing(
+ ConfigSysKeyHandle,
+ FlagsValue,
+ ConfigSysFileHandle,
+ pTimeStamp,
+ pSizeStamp
+ )) {
+
+ if (Os2EnvironmentKeyHandle == NULL) { // we have no write access to the environment
+
+ //
+ // We couldn't open a write key to the sys env for some reason, so we
+ // won't be able to migrate SET variables to NT from config.sys.
+ // Perhaps a popup should be generated to notify the user of this at
+ // this point.
+ // Anyway, we go on and only write the config.sys entry, skipping
+ // variable migration.
+ //
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Initializing registry without writing system env\n"));
+ }
+#endif
+ }
+
+ Os2ProcessOriginalConfigSys(&Dest);
+ Os2TerminateOriginalConfigSysProcessing();
+ }
+#if 0
+
+ //
+ // The code below is disabled. We'll add COUNTRY= when creating a fictive
+ // config.sys on the fly. If the code is reenabled in the future -- it
+ // should be fixed. It doesn't make sure there are at least three characters
+ // (with leading 0s) in the country code.
+ //
+
+ else {
+
+ WCHAR CountryCode[7];
+ ULONG CountryLength;
+ //
+ // add a default "COUNTRY=" line
+ //
+
+ CountryLength = GetLocaleInfoW(
+ GetSystemDefaultLCID(),
+ LOCALE_ICOUNTRY,
+ CountryCode,
+ 6);
+
+ if (CountryLength == 0) {
+#if DBG
+ KdPrint(("Os2SbInitializeRegistry: Cannot get locale country info, LastError = %lx\n",
+ GetLastError()));
+#endif
+ } else {
+
+ RtlMoveMemory(Dest, L"COUNTRY=", 16);
+ Dest += 8;
+
+ RtlMoveMemory(Dest, CountryCode, CountryLength * sizeof(WCHAR));
+ Dest += CountryLength;
+
+ *Dest++ = UNICODE_NULL;
+ }
+ }
+#endif
+
+ // Write the new Os2LibPath
+
+ if (Os2LibPathFound) {
+
+ RtlInitUnicodeString(&Os2LibPathValueName_U, Os2LibPathValueName);
+ Status = NtSetValueKey(Os2EnvironmentKeyHandle,
+ &Os2LibPathValueName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ Os2LibPathValueData_U.Buffer,
+ Os2LibPathValueData_U.Length + sizeof(WCHAR)
+ );
+
+#if DBG
+ if (!NT_SUCCESS(Status))
+ {
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() system environment, rc = %X\n",
+ Status));
+ }
+ }
+#endif
+
+ Os2LibPathFound = FALSE;
+ RtlFreeHeap(Os2Heap, 0, Os2LibPathValueData_U.Buffer);
+ Os2LibPathValueData_U.Buffer = NULL;
+ }
+
+ // handle a possible PATH value setting
+
+ if (Os2PathString != NULL) {
+
+ UNICODE_STRING Os2PathValueName_U;
+ UNICODE_STRING Os2PathValueData_U;
+
+ //
+ // Os2EnvironmentKeyHandle can't be NULL at this point because
+ // we wouldn't have set Os2PathString...
+ //
+
+ if (!Or2GetEnvPath(&Os2PathValueData_U,
+ Os2Heap,
+ PATHLIST_MAX,
+ Os2EnvironmentKeyHandle,
+ L"Path",
+ FALSE)) {
+#if DBG
+ KdPrint(("Os2SbInitializeRegistry: Unable to fetch Path from sys env\n"));
+#endif
+ //
+ // Can't get value, skip processing
+ //
+
+ } else {
+
+ if (Os2PathValueData_U.Length == 0) {
+
+ //
+ // If we couldn't get the value, or it's empty, don't process it
+ //
+
+#if DBG
+ KdPrint(("Os2SbInitializeRegistry: Path in sys env empty or not found\n"));
+#endif
+ } else {
+
+ //
+ // Append our string...
+ //
+
+ Or2AppendPathToPath(Os2Heap,
+ Os2PathString,
+ &Os2PathValueData_U,
+ TRUE);
+
+ //
+ // Put it back into the registry...
+ //
+
+ RtlInitUnicodeString(&Os2PathValueName_U, L"Path");
+ Status = NtSetValueKey(Os2EnvironmentKeyHandle,
+ &Os2PathValueName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ Os2PathValueData_U.Buffer,
+ Os2PathValueData_U.Length + sizeof(WCHAR)
+ );
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() system environment (2), rc = %X\n",
+ Status));
+ }
+#endif
+ // ignore error from setvaluekey
+ }
+
+ RtlFreeHeap(Os2Heap, 0, Os2PathValueData_U.Buffer);
+ }
+
+ RtlFreeHeap(Os2Heap, 0, Os2PathString);
+ Os2PathString = NULL;
+ }
+
+ if (Os2EnvironmentKeyHandle != NULL) {
+ NtClose(Os2EnvironmentKeyHandle);
+ Os2EnvironmentKeyHandle = NULL;
+ }
+
+ // set the REG_MULTI_SZ terminating NUL
+
+ *Dest++ = UNICODE_NULL;
+
+ // Finally, write the config.sys multi-string entry into the registry.
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ Status = NtSetValueKey(ConfigSysKeyHandle,
+ &ConfigSysName_U,
+ (ULONG)0,
+ REG_MULTI_SZ,
+ (PVOID)pInfo,
+ (PBYTE)Dest - (PBYTE)pInfo
+ );
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() registry config.sys, rc = %X\n",
+ Status));
+ }
+#endif
+ NtClose(ConfigSysKeyHandle);
+ return (Status);
+ }
+
+ NtClose(ConfigSysKeyHandle);
+ return (STATUS_SUCCESS);
+}
+
+
+VOID
+Os2MigrationProcedure(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine oversees the os/2 config.sys migration procedure. It's called from winlogon during
+ boot. It checks to see if the os/2ss config.sys-related registy entries are intact. If they
+ aren't, it rebuilds them. If they are intact, it checks if config.sys migration is enabled,
+ and if the os/2 config.sys file exists and has changed (size/lastwritetime) since the last migration.
+ If so, it remigrates the config.sys info. Note that SET variables are only added, never
+ removed. The same goes for LIBPATH. PATH is not migrated from os/2 config.sys to NT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BYTE RegBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4 * sizeof(ULONG)];
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ UNICODE_STRING String_U;
+ LARGE_INTEGER TimeStamp;
+ LARGE_INTEGER SizeStamp;
+ PKEY_VALUE_PARTIAL_INFORMATION pInfo = (PKEY_VALUE_PARTIAL_INFORMATION) RegBuffer;
+ PULONG RegVal;
+ HANDLE ConfigSysKeyHandle;
+ HANDLE ConfigSysFileHandle = NULL;
+ ULONG FlagsValue = (ULONG)-1;
+ ULONG ResultLength;
+ NTSTATUS Status;
+
+ RtlInitUnicodeString(&String_U, Os2ConfigSysKeyName);
+ InitializeObjectAttributes(&Obja,
+ &String_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&ConfigSysKeyHandle,
+ KEY_READ,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
+ Status != STATUS_OBJECT_NAME_NOT_FOUND &&
+ Status != STATUS_OBJECT_PATH_INVALID) {
+#if DBG
+ KdPrint(("Os2MigrationProcedure: Can't Open config.sys registry key, Status = %lx\n", Status));
+#endif
+ return;
+ }
+
+ goto BuildRegistry;
+ }
+
+ RtlInitUnicodeString(&String_U, Os2ConfigFlagName);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &String_U,
+ KeyValuePartialInformation,
+ pInfo,
+ sizeof(RegBuffer),
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ NtClose(ConfigSysKeyHandle);
+
+ if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
+ Status != STATUS_OBJECT_NAME_NOT_FOUND &&
+ Status != STATUS_OBJECT_PATH_INVALID) {
+#if DBG
+ KdPrint(("Os2MigrationProcedure: Can't Read config.sys flag value key, Status = %lx\n", Status));
+#endif
+ return;
+ }
+
+ goto BuildRegistry;
+ }
+
+ if (pInfo->Type != REG_DWORD ||
+ pInfo->DataLength != sizeof(DWORD)) {
+ NtClose(ConfigSysKeyHandle);
+ goto BuildRegistry;
+ }
+
+ FlagsValue = *(PULONG) (pInfo->Data);
+
+ RtlInitUnicodeString(&String_U, Os2ConfigSysName);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &String_U,
+ KeyValuePartialInformation,
+ NULL,
+ 0,
+ &ResultLength
+ );
+
+ //
+ // The 2 expected status results are:
+ //
+ // STATUS_OBJECT_NAME_NOT_FOUND - config.sys not yet defined
+ // STATUS_BUFFER_TOO_SMALL - config.sys already defined
+ //
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
+ Status == STATUS_OBJECT_PATH_NOT_FOUND ||
+ Status == STATUS_OBJECT_PATH_INVALID) {
+ NtClose(ConfigSysKeyHandle);
+ goto BuildRegistry;
+ }
+
+ if (Status != STATUS_BUFFER_TOO_SMALL) {
+#if DBG
+ KdPrint(("Os2MigrationProcedure: Can't Read config.sys registry value key, Status = %lx\n", Status));
+#endif
+ NtClose(ConfigSysKeyHandle);
+ return;
+ }
+
+ if ((FlagsValue & FLAGS_DISABLEMIGRATION) ||
+ !(FlagsValue & FLAGS_CONFIGSYSONDISK)) {
+
+ //
+ // os/2 config.sys migration disabled
+ // or no os/2 config.sys on disk
+ //
+
+ NtClose(ConfigSysKeyHandle);
+ return;
+ }
+
+ RtlInitUnicodeString(&String_U, Os2ConfigStampName);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &String_U,
+ KeyValuePartialInformation,
+ pInfo,
+ sizeof(RegBuffer),
+ &ResultLength
+ );
+
+ NtClose(ConfigSysKeyHandle);
+
+ if (!NT_SUCCESS(Status)) {
+
+ if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
+ Status != STATUS_OBJECT_NAME_NOT_FOUND &&
+ Status != STATUS_OBJECT_PATH_INVALID) {
+#if DBG
+ KdPrint(("Os2MigrationProcedure: Can't Read config.sys stamp value key, Status = %lx\n", Status));
+#endif
+ return;
+ }
+
+ goto BuildRegistry;
+ }
+
+ if (pInfo->Type != REG_BINARY ||
+ pInfo->DataLength != 4 * sizeof(DWORD)) {
+ goto BuildRegistry;
+ }
+
+ RegVal = (PULONG) (pInfo->Data);
+
+ RtlInitUnicodeString(&String_U, Os2OriginalCanonicalConfigSys);
+
+ InitializeObjectAttributes(&Obja,
+ &String_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&ConfigSysFileHandle,
+ FILE_GENERIC_READ,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ goto BuildRegistry;
+ }
+
+ Status = Or2GetFileStamps(
+ ConfigSysFileHandle,
+ &TimeStamp,
+ &SizeStamp
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Os2MigrationProcedure: Can't get config.sys time/size stamp, Status = %lx\n", Status));
+#endif
+
+ NtClose(ConfigSysFileHandle);
+ ConfigSysFileHandle = NULL;
+ goto BuildRegistry;
+ }
+
+ if (TimeStamp.LowPart == RegVal[0] &&
+ (ULONG) TimeStamp.HighPart == RegVal[1] &&
+ SizeStamp.LowPart == RegVal[2] &&
+ (ULONG) SizeStamp.HighPart == RegVal[3]) {
+
+ //
+ // os/2 config.sys hasn't changed, skip processing
+ //
+
+ NtClose(ConfigSysFileHandle);
+ return;
+ }
+
+ //
+ // We need to install the registry stuff
+ //
+
+BuildRegistry:
+
+ if (GetSystemDirectoryW(Os2SystemDirectory, MAX_PATH) == 0) {
+#if DBG
+ KdPrint(("Os2MigrationProcedure: Cannot obtain name of system directory, LastError = %lx\n",
+ GetLastError()));
+#endif
+ if (ConfigSysFileHandle != NULL) {
+ NtClose(ConfigSysFileHandle);
+ }
+ return;
+ }
+
+ //
+ // Create a heap to use for dynamic memory allocation.
+ //
+
+ Os2Heap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 0x10000L, // Initial size of heap is 64K
+ 0x1000L, // Commit an initial page
+ NULL,
+ NULL // Reserved
+ );
+ if (Os2Heap == NULL) {
+#if DBG
+ KdPrint(("Os2MigrationProcedure: Error at RtlCreateHeap of Os2Heap\n"));
+#endif
+ if (ConfigSysFileHandle != NULL) {
+ NtClose(ConfigSysFileHandle);
+ }
+ return;
+ }
+
+ Status = Os2SbInitializeRegistry(
+ FlagsValue,
+ ConfigSysFileHandle,
+ &TimeStamp,
+ &SizeStamp
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Os2MigrationProcedure: Os2SbInitializeRegistry() failed, Status = %lx\n", Status));
+#endif
+ }
+
+ //
+ // ConfigSysFileHandle is closed by Os2SbInitializeRegistry
+ //
+
+ RtlDestroyHeap(Os2Heap);
+}
diff --git a/private/windows/gina/winlogon/i386/os2ssmig.h b/private/windows/gina/winlogon/i386/os2ssmig.h
new file mode 100644
index 000000000..56a10edc0
--- /dev/null
+++ b/private/windows/gina/winlogon/i386/os2ssmig.h
@@ -0,0 +1,24 @@
+/****************************** Module Header ******************************\
+* Module Name: os2ssmig.h
+*
+* Copyright (c) 1993, Microsoft Corporation
+*
+* Import file for the OS/2 Subsystem migration code. Only applicable to x86 builds.
+*
+* History:
+* 03-30-93 OferP Created.
+\***************************************************************************/
+
+#ifndef __OS2SSMIG_H
+#define __OS2SSMIG_H
+
+#ifdef _X86_
+
+VOID
+Os2MigrationProcedure(
+ VOID
+ );
+
+#endif
+#endif
+
diff --git a/private/windows/gina/winlogon/i386/os2ssrtl.c b/private/windows/gina/winlogon/i386/os2ssrtl.c
new file mode 100644
index 000000000..eda1612de
--- /dev/null
+++ b/private/windows/gina/winlogon/i386/os2ssrtl.c
@@ -0,0 +1,1037 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2ssrtl.c
+
+Abstract:
+
+ This module contains CONFIG.SYS related parsing routines, and some other
+ routines needed to support os/2ss migration.
+
+Author:
+
+ Ofer Porat (oferp) 8-Nov-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define IF_OD2_DEBUG(x) // permanently enable debug prints
+
+#define WBLANK(ch) ((ch) == L' ' || (ch) == L'\t')
+
+//
+// used for text processing in Or2ReplacePathByPath()
+//
+typedef struct _INDEX_T {
+
+ UNICODE_STRING Src;
+ UNICODE_STRING Dest;
+
+} INDEX_T, *PINDEX_T;
+
+
+
+//
+// This routine skips over white space in a unicode string
+// either forward or backward.
+// Str -- address of pointer to string.
+// Direction -- either FWD or BWD.
+//
+
+VOID
+Or2SkipWWS(
+ IN OUT PWSTR *Str,
+ IN LONG Direction
+ )
+{
+ PWSTR q = *Str;
+
+ while (WBLANK(*q)) {
+ q += Direction;
+ }
+ *Str = q;
+}
+
+
+//
+// This routine converts a null terminated unicode string to upper case.
+// It is similar to wcsupr(). It exists because I'm not sure wcsupr()
+// actually uses the Unicode convention.
+//
+// Str -- string to convert.
+//
+
+VOID
+Or2UnicodeStrupr(
+ IN OUT PWSTR Str
+ )
+{
+ while (*Str != UNICODE_NULL) {
+ *Str = RtlUpcaseUnicodeChar(*Str);
+ Str++;
+ }
+}
+
+
+//
+// This routine compares 2 null-terminated unicode strings. The comparison
+// has a count limiting the number of chars compared, and the comparison is
+// case insensitive. It is similar to wcsnicmp(). It exists because I'm not
+// sure wcsnicmp() actually uses the Unicode convention.
+//
+// Str1, Str2 -- strings to compare.
+// Count -- max # of chars to compare.
+// return value -- TRUE if they're equal to within Count characters. FALSE otherwise.
+//
+
+BOOLEAN
+Or2UnicodeEqualCI(
+ IN PWSTR Str1,
+ IN PWSTR Str2,
+ IN ULONG Count
+ )
+{
+ while (Count != 0) {
+
+ if (*Str1 == UNICODE_NULL) {
+
+ if (*Str2 == UNICODE_NULL) {
+ return(TRUE);
+ }
+
+ return(FALSE);
+ }
+
+ if (RtlUpcaseUnicodeChar(*Str1) != RtlUpcaseUnicodeChar(*Str2)) {
+
+ return(FALSE);
+ }
+
+ Str1++; Str2++; Count--;
+ }
+ return(TRUE);
+}
+
+
+//
+// This routine appends a source path list to a destination path list. multiple occurences
+// of the same path are removed.
+//
+// HeapHandle -- a handle to a heap for temporary allocations
+// SrcPath -- a null terminated unicode string. It must be in uppercase for elimination of
+// multiple paths to occur. This path list is appended to DestPath.
+// DestPath -- an already existing counted unicode string containing the path list to be appended
+// to. The case is unimportant. The result is stored back in this string.
+// ExpandIt -- Should be TRUE in DestPath contains unexpanded %...% type strings. FALSE otherwise.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Does nothing, return value FALSE
+// can't expand the
+// DestPath Does nothing, return value FALSE
+// DestPath MaxLen
+// exceeded during
+// append Stop on the last path that fits, return value TRUE
+//
+
+BOOLEAN
+Or2AppendPathToPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath,
+ IN BOOLEAN ExpandIt
+ )
+{
+ WCHAR wch;
+ WCHAR wch1;
+ WCHAR wch2;
+ PWSTR p;
+ PWSTR q;
+ PWSTR r;
+ PWSTR t;
+ USHORT l;
+ USHORT addsemi;
+ UNICODE_STRING Expanded;
+ UNICODE_STRING Tmp;
+ BOOLEAN Found;
+ NTSTATUS Status;
+
+ Expanded.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, DestPath->MaximumLength + sizeof(WCHAR));
+
+ if (Expanded.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathPath: can't allocate Expanded from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ Expanded.MaximumLength = DestPath->MaximumLength;
+
+ if (ExpandIt) {
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ DestPath,
+ &Expanded,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathToPath: can't expand environment strings, rc = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Expanded.Buffer);
+ return(FALSE);
+ }
+
+ } else {
+
+ RtlCopyUnicodeString(&Expanded, DestPath);
+ }
+
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ Or2UnicodeStrupr(Expanded.Buffer);
+
+ addsemi = 2;
+
+ if (Expanded.Length == 0 ||
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR) - 1] == L';') {
+
+ addsemi = 0;
+ }
+
+ while (TRUE) {
+
+ Or2SkipWWS(&SrcPath, FWD);
+
+ wch = *SrcPath;
+
+ if (wch == UNICODE_NULL) {
+ break;
+ }
+
+ if (wch == L';') {
+ SrcPath++;
+ continue;
+ }
+
+ p = wcschr(SrcPath, L';');
+
+ if (p == NULL) {
+
+ p = SrcPath + wcslen(SrcPath);
+ q = p - 1;
+
+ } else {
+
+ q = p - 1;
+ p++;
+ }
+
+ Or2SkipWWS(&q, BWD);
+
+ l = q - SrcPath + 1;
+
+ wch = *(q+1);
+ *(q+1) = UNICODE_NULL;
+ t = Expanded.Buffer;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ r = wcsstr(t, SrcPath);
+
+ if (r == NULL) {
+ break;
+ }
+
+ if (r == Expanded.Buffer) {
+ wch1 = L';';
+ } else {
+ wch1 = *(r-1);
+ }
+
+ wch2 = r[l];
+
+ if ((wch1 == L';' || WBLANK(wch1)) &&
+ (wch2 == L';' || WBLANK(wch2) || wch2 == UNICODE_NULL)) {
+
+ Found = TRUE;
+ break;
+ }
+
+ t = r + l;
+ }
+
+ *(q+1) = wch;
+
+ if (Found) {
+ SrcPath = p;
+ continue;
+ }
+
+ Tmp.Buffer = SrcPath;
+ Tmp.Length = l * sizeof(WCHAR);
+ Tmp.MaximumLength = Tmp.Length;
+
+ if (Expanded.Length + addsemi + Tmp.Length > Expanded.MaximumLength ||
+ DestPath->Length + addsemi + Tmp.Length > DestPath->MaximumLength) {
+
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathToPath: Path buffer overflow\n"));
+ }
+#endif
+ break; // out of string space, terminate processing.
+ }
+
+ if (addsemi) {
+
+ RtlAppendUnicodeToString(&Expanded, L";");
+ RtlAppendUnicodeToString(DestPath, L";");
+
+ } else {
+
+ addsemi = 2;
+ }
+
+ RtlAppendUnicodeStringToString(&Expanded, &Tmp);
+ RtlAppendUnicodeStringToString(DestPath, &Tmp);
+
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ SrcPath = p;
+ }
+
+ DestPath->Buffer[DestPath->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+ RtlFreeHeap(HeapHandle, 0, Expanded.Buffer);
+ return(TRUE);
+}
+
+
+//
+// This routine takes a counted unicode string containing a path-list with %...% type strings in it.
+// It prepares a pool of characters containing the expansions of paths with %...% strings in them.
+// Also prepared is an index table. Each entry in the index table contains a counted string pointing
+// to the point in DestPath where the unexpanded path is, and a counted string pointing to the the pool
+// where the expanded path is.
+//
+// SrcPath -- a counted unicode string containing the path-list to generate an index for.
+// Pool -- a buffer containing space for SrcPath.MaximumLength wide characters. This is where
+// the expanded strings will be stored.
+// Ind -- a buffer containing enough space to allocate as many index entries as necessary to index
+// the path list. One way to know how many may be necessary is to count the # of semicolons in
+// SrcPath.
+// IndSize -- will contain the number of entries placed in Ind on exit.
+//
+// Possible Errors Effect
+// =============== ======
+// SrcPath.MaximumLength
+// characters are not
+// enough to store the
+// pool of expanded env
+// strings. Stops after the last expanded env string that fits in the pool.
+//
+
+static
+VOID
+Or2IndexPath(
+ IN PUNICODE_STRING SrcPath,
+ OUT PWSTR Pool,
+ OUT PINDEX_T Ind,
+ OUT PULONG IndSize
+ )
+{
+ PWSTR CurPool = Pool;
+ USHORT PoolQuota = SrcPath->MaximumLength;
+ ULONG IndEx = 0;
+ PWCHAR wp = SrcPath->Buffer;
+ PWCHAR wq, wr;
+ BOOLEAN HasPercent;
+ NTSTATUS Status;
+
+ for (; ; ) {
+
+ Or2SkipWWS(&wp, FWD);
+
+ if (*wp == UNICODE_NULL) {
+ break;
+ }
+
+ HasPercent = FALSE;
+
+ wq = wp;
+
+ while (*wq != L';' && *wq != UNICODE_NULL) {
+ if (*wq == L'%') {
+ HasPercent = TRUE;
+ }
+ wq++;
+ }
+
+ if (*wq == L';') {
+ wr = wq + 1;
+ } else {
+ wr = wq;
+ }
+
+ if (!HasPercent) {
+ wp = wr;
+ continue;
+ }
+
+ wq--;
+
+ Or2SkipWWS(&wq, BWD);
+
+ Ind[IndEx].Dest.Buffer = wp;
+ Ind[IndEx].Dest.Length = (wq - wp + 1) * sizeof(WCHAR);
+ Ind[IndEx].Dest.MaximumLength = Ind[IndEx].Dest.Length;
+
+ wp = wr;
+
+ Ind[IndEx].Src.Buffer = CurPool;
+ Ind[IndEx].Src.MaximumLength = PoolQuota;
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ &Ind[IndEx].Dest,
+ &Ind[IndEx].Src,
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2IndexPath: can't expand environment strings, rc = %lx\n", Status));
+ }
+#endif
+ break;
+ }
+
+ PoolQuota -= Ind[IndEx].Src.Length;
+ CurPool += Ind[IndEx].Src.Length / sizeof(WCHAR);
+
+ Ind[IndEx].Src.MaximumLength = Ind[IndEx].Src.Length;
+
+ IndEx++;
+ }
+
+ *IndSize = IndEx;
+}
+
+
+//
+// This routine takes a destination path-list and a source path list. The destination path-list
+// is completely replaced with the source path list. The destination list may contain %...% strings.
+// The source list is not expected to contain %...% strings. While the replacement is done, any
+// paths in the source which already exist in the destination in a form containing %...% strings, are
+// retained with their original %...% form.
+//
+// HeapHandle -- a handle to a heap for temporary allocations
+// SrcPath -- a null terminated unicode string containing the replacing path-list.
+// DestPath -- an already existing counted unicode string containing the path list to be replaced
+// to. The result is stored back in this string.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Does nothing, return value FALSE
+// DestPath MaxLen
+// exceeded during
+// replace Stop on the last path that fits, return value TRUE
+//
+
+BOOLEAN
+Or2ReplacePathByPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath
+ )
+{
+ PINDEX_T Ind;
+ PWSTR Pool;
+ PWSTR p;
+ PWSTR q;
+ WCHAR wch;
+ ULONG IndSize;
+ ULONG SemiCount;
+ ULONG i;
+ USHORT addsemi;
+ UNICODE_STRING Target;
+ UNICODE_STRING Tmp;
+
+ Target.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, DestPath->MaximumLength + sizeof(WCHAR));
+
+ if (Target.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Target from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ Target.MaximumLength = DestPath->MaximumLength;
+ Target.Length = 0;
+
+ Pool = (PWSTR) RtlAllocateHeap(HeapHandle, 0, (ULONG) DestPath->MaximumLength);
+
+ if (Pool == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Pool from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(FALSE);
+ }
+
+ SemiCount = 1;
+
+ for (i = 0; i < DestPath->Length/sizeof(WCHAR); i++) {
+ if (DestPath->Buffer[i] == L';') {
+ SemiCount++;
+ }
+ }
+
+ Ind = (PINDEX_T) RtlAllocateHeap(HeapHandle, 0, SemiCount * sizeof(INDEX_T));
+
+ if (Ind == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Ind from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Pool);
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(FALSE);
+ }
+
+ Or2IndexPath(DestPath, Pool, Ind, &IndSize);
+
+ addsemi = 0;
+
+ while (TRUE) {
+
+ Or2SkipWWS(&SrcPath, FWD);
+
+ wch = *SrcPath;
+
+ if (wch == UNICODE_NULL) {
+ break;
+ }
+
+ if (wch == L';') {
+ SrcPath++;
+ continue;
+ }
+
+ p = wcschr(SrcPath, L';');
+
+ if (p == NULL) {
+
+ p = SrcPath + wcslen(SrcPath);
+ q = p - 1;
+
+ } else {
+
+ q = p - 1;
+ p++;
+ }
+
+ Or2SkipWWS(&q, BWD);
+
+ Tmp.Buffer = SrcPath;
+ Tmp.Length = (q - SrcPath + 1) * sizeof(WCHAR);
+ Tmp.MaximumLength = Tmp.Length;
+
+ for (i = 0; i < IndSize; i++) {
+
+ if (RtlEqualUnicodeString(&Tmp, &Ind[i].Src, TRUE)) {
+
+ Tmp = Ind[i].Dest;
+ break;
+ }
+ }
+
+ if (Target.Length + addsemi + Tmp.Length > Target.MaximumLength) {
+
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: Path buffer overflow\n"));
+ }
+#endif
+ break; // out of string space, terminate processing.
+ }
+
+ if (addsemi) {
+
+ RtlAppendUnicodeToString(&Target, L";");
+
+ } else {
+
+ addsemi = 2;
+ }
+
+ RtlAppendUnicodeStringToString(&Target, &Tmp);
+
+ SrcPath = p;
+ }
+
+ RtlCopyUnicodeString(DestPath, &Target);
+
+ DestPath->Buffer[DestPath->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ RtlFreeHeap(HeapHandle, 0, Ind);
+ RtlFreeHeap(HeapHandle, 0, Pool);
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(TRUE);
+}
+
+
+//
+// This routine appends a terminating semicolon to a path list, if that path list
+// does not have a semicolon in it (in other words, if the path list contains only
+// one path).
+//
+// Str - The string to do semicolon processing on.
+//
+
+VOID
+Or2CheckSemicolon(
+ IN OUT PUNICODE_STRING Str
+ )
+{
+ USHORT i;
+ BOOLEAN flag;
+
+ if (Str->Length == 0 || Str->Length >= Str->MaximumLength) {
+ return;
+ }
+
+ flag = FALSE;
+
+ for(i = 0; i < Str->Length/ (USHORT) sizeof(WCHAR); i++) {
+ if (Str->Buffer[i] == L';') {
+ flag = TRUE;
+ break;
+ }
+ }
+
+ if (!flag) {
+ Str->Buffer[i++] = L';';
+ Str->Buffer[i] = UNICODE_NULL;
+ Str->Length += sizeof(WCHAR);
+ }
+}
+
+
+//
+// This routine fetches a path-list type environment variable from the registry.
+//
+// Data - an unallocated counted unicode string to hold the result.
+// HeapHandle -- a handle to a heap where we allocate from.
+// MaxSiz -- The MaximumLength Data should be given.
+// EnvKey -- a handle to the registry key in which the environment to be searched is.
+// ValueName -- a null-terminated unicode name of the registry value to fetch.
+// ExpandIt -- If TRUE, the registry value is expanded for %..% type strings before returning it.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Data.Buffer = NULL, return value FALSE
+// requested env variable
+// doesn't exist, or
+// can't query its value Data is allocated and given 0 length, return value TRUE
+// can't expand the
+// env variable Data is allocated and given 0 length, return value TRUE
+//
+
+BOOLEAN
+Or2GetEnvPath(
+ OUT PUNICODE_STRING Data,
+ IN PVOID HeapHandle,
+ IN USHORT MaxSiz,
+ IN HANDLE EnvKey,
+ IN PWSTR ValueName,
+ IN BOOLEAN ExpandIt
+ )
+{
+ PKEY_VALUE_PARTIAL_INFORMATION Buf;
+ UNICODE_STRING ExpBuf;
+ UNICODE_STRING ValueName_U;
+ UNICODE_STRING tmp;
+ ULONG ResultLength;
+ ULONG l1, l2;
+ NTSTATUS Status;
+
+ Data->Buffer = NULL;
+
+ l1 = ((ULONG) MaxSiz + 1) * sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
+
+ Buf = (PKEY_VALUE_PARTIAL_INFORMATION) RtlAllocateHeap(HeapHandle, 0, l1);
+
+ if (Buf == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2GetEnvPath: can't allocate Buf from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ if (ExpandIt) {
+
+ l2 = ((ULONG) MaxSiz + 1) * sizeof(WCHAR);
+
+ ExpBuf.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, l2);
+
+ if (ExpBuf.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2GetEnvPath: can't allocate ExpBuf from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Buf);
+ return(FALSE);
+ }
+
+ ExpBuf.MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ RtlInitUnicodeString(&ValueName_U, ValueName);
+ Status = NtQueryValueKey(EnvKey,
+ &ValueName_U,
+ KeyValuePartialInformation,
+ Buf,
+ l1,
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("OS2SSRTL(Or2GetEnvPath): FAILED - NtQueryValueKey %lx\n", Status));
+ }
+#endif
+ if (ExpandIt) {
+ RtlFreeHeap(HeapHandle, 0, Buf);
+ ExpBuf.Length = 0;
+ ExpBuf.Buffer[0] = UNICODE_NULL;
+ *Data = ExpBuf;
+ } else {
+ *((PWSTR) Buf) = UNICODE_NULL;
+ Data->Buffer = (PWSTR) Buf;
+ Data->Length = 0;
+ Data->MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ return(TRUE);
+ }
+
+ if (ExpandIt) {
+ RtlInitUnicodeString(&tmp, (PWSTR) Buf->Data);
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ &tmp,
+ &ExpBuf,
+ NULL);
+
+ RtlFreeHeap(HeapHandle, 0, Buf);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("OS2SSRTL(Or2GetEnvPath): FAILED - RtlExpandEnvironmentStrings_U %lx\n", Status));
+ }
+#endif
+ ExpBuf.Buffer[0] = UNICODE_NULL;
+ ExpBuf.Length = 0;
+ *Data = ExpBuf;
+ return(TRUE);
+ }
+
+ ExpBuf.Buffer[ExpBuf.Length/sizeof(WCHAR)] = UNICODE_NULL;
+ *Data = ExpBuf;
+
+ } else {
+
+ l2 = Buf->DataLength;
+ RtlMoveMemory(Buf, Buf->Data, l2);
+ Data->Buffer = (PWSTR) Buf;
+ Data->Length = (USHORT) (l2 - sizeof(WCHAR));
+ Data->MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ return(TRUE);
+}
+
+
+//
+// This is a general routine to parse an environment. It loops over the lines in the environment, and
+// identifies the variable in each line. For each variable, it searches a user dispatch table, and if
+// that dispatch table contains an entry for this variable, it calls the user supplied routine with the
+// name and value of the variable.
+//
+// Environment -- The environment to process. This is either in multi-string format, or a
+// (null|^Z)-terminated string consisting of lines separated by crlfs.
+// DispatchTable -- A dispatch table used to process the environment.
+// NumberOfDispatchItems -- Contains the number of entries in DispatchTable.
+// DelimOption -- specifies whether Environment is a multi-string (NULL_DELIM) or a string of crlf
+// separated lines (CRLF_DELIM).
+//
+// Description of the DispatchTable:
+// This is an array of structures of type ENVIRONMENT_DISPATCH_TABLE_ENTRY.
+// Each entry specifies a particular variable which should be handled.
+// an entry contains:
+// -- the name of the variable to operate on (this is case-insensitive).
+// -- a string of possible characters that serve as delimiters for the variable name (e.g. =, space, tab).
+// -- a DispatchFunction. This function is dispatched with 6 parameters:
+// -- the index in the dispatch table which triggered this call.
+// -- a user defined pointer, see below.
+// -- a pointer to the variable name in the environment.
+// -- length of the variable name (in chars).
+// -- a pointer to the variable value in the environment.
+// -- length of the variable value (in chars).
+// -- a user defined pointer that is passed to the dispatch function.
+//
+// The dispatch function may do anything it likes with the information it gets, and it
+// is not expected to return any value.
+//
+// A special value of "*" in the variable name field of an entry indicates that any variable name
+// is to be processed by the DispatchFunction. The DispatchFunction can figure out the name of
+// the variable it was called for by examining its parameters. If this option is used together
+// with a Delimeters value of NULL, no delimiter will be searched for, the line will be passed
+// as is with Name and Value both pointing to the beginning of the line (and ValueLen containing
+// its length)
+//
+
+VOID
+Or2IterateEnvironment(
+ IN PWSTR Environment,
+ IN ENVIRONMENT_DISPATCH_TABLE DispatchTable,
+ IN ULONG NumberOfDispatchItems,
+ IN ULONG DelimOption
+ )
+{
+ PWSTR Src;
+ PWSTR Tmp;
+ PWSTR Eol;
+ PWSTR NextLine;
+ ULONG i, m;
+ LONG l;
+ BOOLEAN Flag;
+
+ if (NumberOfDispatchItems == 0 || Environment == NULL || DispatchTable == NULL) {
+ return;
+ }
+
+ Src = Environment;
+ while (*Src != UNICODE_NULL) {
+ Or2SkipWWS(&Src, FWD);
+
+ if (DelimOption == CRLF_DELIM &&
+ *Src == L'\32') { // ^Z terminates file on CRLF delim texts
+ break;
+ }
+
+ for (i = 0; i < NumberOfDispatchItems; i++) {
+
+ if (DispatchTable[i].VarName[0] == L'*') {
+
+ if (DispatchTable[i].Delimiters == NULL) {
+
+ //
+ // No delimeter required. If the line is empty
+ // we don't process it.
+ //
+
+ if (*Src == UNICODE_NULL) {
+ continue;
+ }
+
+ if (DelimOption == CRLF_DELIM &&
+ (*Src == L'\r' || *Src == L'\n')) {
+ continue;
+ }
+
+ l = -1; // process the line from start
+ break;
+ }
+
+ Tmp = Src;
+ l = 0;
+ while (TRUE) {
+ if (*Tmp == UNICODE_NULL ||
+ (DelimOption == CRLF_DELIM && (*Tmp == L'\r' || *Tmp == L'\n' || *Tmp == L'\32'))) {
+ Flag = FALSE;
+ break;
+ }
+ if (wcschr(DispatchTable[i].Delimiters, RtlUpcaseUnicodeChar(*Tmp)) != NULL) {
+ Flag = TRUE;
+ break;
+ }
+ Tmp++;
+ l++;
+ }
+
+ if (Flag) {
+ break;
+ }
+ continue;
+ }
+
+ l = wcslen(DispatchTable[i].VarName);
+
+ if (Or2UnicodeEqualCI(Src, DispatchTable[i].VarName, (ULONG)l) &&
+ Src[l] != UNICODE_NULL &&
+ wcschr(DispatchTable[i].Delimiters, RtlUpcaseUnicodeChar(Src[l])) != NULL) {
+ break;
+ }
+ }
+
+ if (DelimOption == NULL_DELIM) {
+ Eol = Src + wcslen(Src);
+ NextLine = Eol + 1;
+ } else {
+ Eol = wcspbrk(Src, L"\r\n\32");
+ if (Eol == NULL) {
+ NextLine = Eol = Src + wcslen(Src);
+ } else {
+ NextLine = Eol;
+ if (*Eol != L'\32') {
+ while (*NextLine == L'\r' || *NextLine == L'\n') {
+ NextLine++;
+ }
+ }
+ }
+ }
+
+ if (i == NumberOfDispatchItems || DispatchTable[i].DispatchFunction == NULL) {
+ Src = NextLine;
+ continue;
+ }
+
+ Tmp = Src + l + 1;
+ Or2SkipWWS(&Tmp, FWD);
+ if (Eol != Tmp) {
+ Eol--;
+ Or2SkipWWS(&Eol, BWD);
+ m = (Eol - Tmp) + 1;
+ } else {
+ m = 0;
+ }
+
+ DispatchTable[i].DispatchFunction(i, DispatchTable[i].UserParameter, Src, l, Tmp, m);
+
+ Src = NextLine;
+ }
+}
+
+
+//
+// Following is useful Dispatch Function for use with Or2IterateEnvironment.
+// It copies the parameters passed to it into a structure of type
+// ENVIRONMENT_SEARCH_RECORD. A pointer to the structure to fill must be
+// passed through the UserParameter in the Dispatch Table.
+//
+
+VOID
+Or2FillInSearchRecordDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+{
+ PENVIRONMENT_SEARCH_RECORD p = (PENVIRONMENT_SEARCH_RECORD) UserParameter;
+
+ p->DispatchTableIndex = DispatchTableIndex;
+ p->Name = Name;
+ p->NameLen = NameLen;
+ p->Value = Value;
+ p->ValueLen = ValueLen;
+}
+
+
+NTSTATUS
+Or2GetFileStamps(
+ IN HANDLE hFile,
+ OUT PLARGE_INTEGER pTimeStamp,
+ OUT PLARGE_INTEGER pSizeStamp
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads a file's size and time of last write.
+
+Arguments:
+
+ hFile -- handle of file to read.
+ pTimeStamp -- returns file time of last write.
+ pSizeStamp -- returns file size.
+
+Return Value:
+
+ NT error code. The return parameters are valid only if this is
+ success.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_BASIC_INFORMATION BasicInfo;
+ FILE_STANDARD_INFORMATION StandardInfo;
+
+ Status = NtQueryInformationFile(hFile,
+ &IoStatus,
+ &BasicInfo,
+ sizeof(BasicInfo),
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Or2GetFileStamps: Unable to query file time, rc = %lx\n", Status));
+#endif
+ return(Status);
+ }
+
+ *pTimeStamp = BasicInfo.LastWriteTime;
+
+ Status = NtQueryInformationFile(hFile,
+ &IoStatus,
+ &StandardInfo,
+ sizeof(StandardInfo),
+ FileStandardInformation);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Or2GetFileStamps: Unable to query file size, rc = %lx\n", Status));
+#endif
+ return(Status);
+ }
+
+ *pSizeStamp = StandardInfo.EndOfFile;
+
+ return(STATUS_SUCCESS);
+}
+
diff --git a/private/windows/gina/winlogon/i386/os2ssrtl.h b/private/windows/gina/winlogon/i386/os2ssrtl.h
new file mode 100644
index 000000000..90d054fd4
--- /dev/null
+++ b/private/windows/gina/winlogon/i386/os2ssrtl.h
@@ -0,0 +1,121 @@
+/****************************** Module Header ******************************\
+* Module Name: os2ssrtl.h
+*
+* Copyright (c) 1993, Microsoft Corporation
+*
+* Import file for the OS/2 Subsystem migration code support module
+*
+* History:
+* 03-30-93 OferP Created.
+\***************************************************************************/
+
+#ifndef __OS2SSRTL_H
+#define __OS2SSRTL_H
+
+#define FWD +1L // these are used with
+#define BWD -1L // Or2SkipWWS
+
+#define NULL_DELIM 0 // these are used with
+#define CRLF_DELIM 1 // Or2IterateEnvironment
+
+typedef VOID (*PFN_ENVIRONMENT_PROCESSOR)(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ );
+
+typedef struct _ENVIRONMENT_DISPATCH_TABLE_ENTRY {
+ PWSTR VarName;
+ PWSTR Delimiters;
+ PFN_ENVIRONMENT_PROCESSOR DispatchFunction;
+ PVOID UserParameter;
+} ENVIRONMENT_DISPATCH_TABLE_ENTRY, *PENVIRONMENT_DISPATCH_TABLE_ENTRY;
+
+typedef PENVIRONMENT_DISPATCH_TABLE_ENTRY ENVIRONMENT_DISPATCH_TABLE;
+
+typedef struct _ENVIRONMENT_SEARCH_RECORD {
+ ULONG DispatchTableIndex;
+ PWSTR Name;
+ ULONG NameLen;
+ PWSTR Value;
+ ULONG ValueLen;
+} ENVIRONMENT_SEARCH_RECORD, *PENVIRONMENT_SEARCH_RECORD;
+
+VOID
+Or2SkipWWS(
+ IN OUT PWSTR *Str,
+ IN LONG Direction
+ );
+
+VOID
+Or2UnicodeStrupr(
+ IN OUT PWSTR Str
+ );
+
+BOOLEAN
+Or2UnicodeEqualCI(
+ IN PWSTR Str1,
+ IN PWSTR Str2,
+ IN ULONG Count
+ );
+
+BOOLEAN
+Or2AppendPathToPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath,
+ IN BOOLEAN ExpandIt
+ );
+
+BOOLEAN
+Or2ReplacePathByPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath
+ );
+
+VOID
+Or2CheckSemicolon(
+ IN OUT PUNICODE_STRING Str
+ );
+
+BOOLEAN
+Or2GetEnvPath(
+ OUT PUNICODE_STRING Data,
+ IN PVOID HeapHandle,
+ IN USHORT MaxSiz,
+ IN HANDLE EnvKey,
+ IN PWSTR ValueName,
+ IN BOOLEAN ExpandIt
+ );
+
+VOID
+Or2IterateEnvironment(
+ IN PWSTR Environment,
+ IN ENVIRONMENT_DISPATCH_TABLE DispatchTable,
+ IN ULONG NumberOfDispatchItems,
+ IN ULONG DelimOption
+ );
+
+VOID
+Or2FillInSearchRecordDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ );
+
+NTSTATUS
+Or2GetFileStamps(
+ IN HANDLE hFile,
+ OUT PLARGE_INTEGER pTimeStamp,
+ OUT PLARGE_INTEGER pSizeStamp
+ );
+
+#endif
+
diff --git a/private/windows/gina/winlogon/i386/sources b/private/windows/gina/winlogon/i386/sources
new file mode 100644
index 000000000..b7e8c42b7
--- /dev/null
+++ b/private/windows/gina/winlogon/i386/sources
@@ -0,0 +1,2 @@
+I386_SOURCES=os2ssmig.c \
+ os2ssrtl.c
diff --git a/private/windows/gina/winlogon/logfull.h b/private/windows/gina/winlogon/logfull.h
new file mode 100644
index 000000000..ff478cd08
--- /dev/null
+++ b/private/windows/gina/winlogon/logfull.h
@@ -0,0 +1,22 @@
+/****************************** Module Header ******************************\
+* Module Name: logfull.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define apis used to implement audit log full action dialog
+*
+* History:
+* 5-6-92 DaveHart Created.
+\***************************************************************************/
+
+
+//
+// Exported function prototypes
+//
+
+
+DLG_RETURN_TYPE
+LogFullAction(
+ HWND hwnd,
+ PGLOBALS pGlobals,
+ BOOL * bAuditingDisabled);
diff --git a/private/windows/gina/winlogon/loggedon.h b/private/windows/gina/winlogon/loggedon.h
new file mode 100644
index 000000000..ea837165b
--- /dev/null
+++ b/private/windows/gina/winlogon/loggedon.h
@@ -0,0 +1,23 @@
+/****************************** Module Header ******************************\
+* Module Name: loggedon.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define apis used to process input while a user is logged on.
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+
+//
+// Exported function prototypes
+//
+
+
+int
+Loggedon(
+ PGLOBALS
+ );
+
+
diff --git a/private/windows/gina/winlogon/logging.h b/private/windows/gina/winlogon/logging.h
new file mode 100644
index 000000000..acbeb7a1f
--- /dev/null
+++ b/private/windows/gina/winlogon/logging.h
@@ -0,0 +1,31 @@
+/****************************** Module Header ******************************\
+* Module Name: sas.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Defines apis to perform event logging in winlogon.
+*
+* History:
+* 03-19-93 Robertre Created.
+\***************************************************************************/
+
+#ifdef LOGGING
+
+BOOL
+WriteLog(
+ HANDLE FileHandle,
+ LPWSTR LogString
+ );
+
+BOOL
+OpenLogFile(
+ PHANDLE LogFileHandle
+ );
+
+BOOL SetLoggingFileVariables(PGLOBALS pGlobals);
+
+BOOL DeleteLoggingFileVariables(PGLOBALS pGlobals);
+
+extern HANDLE LogFileHandle;
+
+#endif
diff --git a/private/windows/gina/winlogon/logoff.c b/private/windows/gina/winlogon/logoff.c
new file mode 100644
index 000000000..995a49106
--- /dev/null
+++ b/private/windows/gina/winlogon/logoff.c
@@ -0,0 +1,1284 @@
+/****************************** Module Header ******************************\
+* Module Name: logoff.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Implements functions to allow a user to logoff the system.
+*
+* History:
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <ras.h>
+#include <raserror.h>
+
+//
+// Private prototypes
+//
+
+HANDLE
+ExecLogoffThread(
+ PGLOBALS pGlobals,
+ DWORD Flags
+ );
+
+DWORD
+LogoffThreadProc(
+ LPVOID Parameter
+ );
+
+BOOL WINAPI
+ShutdownWaitDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL WINAPI
+ShutdownDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+DeleteNetworkConnections(
+ PGLOBALS pGlobals
+ );
+
+BOOLEAN
+ShutdownThread(
+ VOID
+ );
+
+BOOL
+DeleteRasConnections(
+ PGLOBALS pGlobals
+ );
+
+BOOL WINAPI
+DeleteNetConnectionsDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+
+BOOL ExitWindowsInProgress = FALSE ;
+HMODULE hRasApi;
+
+//
+// Bugbug: move to winlogon.h
+//
+#define IsShutdown(x) ((x == WLX_SAS_ACTION_SHUTDOWN) || \
+ (x == WLX_SAS_ACTION_SHUTDOWN_REBOOT) || \
+ (x == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) )
+
+
+/***************************************************************************\
+* FUNCTION: InitiateLogOff
+*
+* PURPOSE: Starts the procedure of logging off the user.
+*
+* RETURNS: DLG_SUCCESS - logoff was initiated successfully.
+* DLG_FAILURE - failed to initiate logoff.
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+int
+InitiateLogoff(
+ PGLOBALS pGlobals,
+ LONG Flags
+ )
+{
+ BOOL IgnoreResult;
+ HANDLE ThreadHandle;
+ HANDLE Handle;
+ PUSER_PROCESS_DATA UserProcessData;
+ DWORD Result;
+
+ //
+ // If this is a shutdown operation, call ExitWindowsEx from
+ // another thread.
+ //
+
+ if (Flags & (EWX_SHUTDOWN | EWX_REBOOT | EWX_POWEROFF)) {
+
+ //
+ // Exec a user thread to call ExitWindows
+ //
+
+ ThreadHandle = ExecLogoffThread(pGlobals, Flags);
+
+ if (ThreadHandle == NULL) {
+
+ DebugLog((DEB_ERROR, "Unable to create logoff thread"));
+ return(DLG_FAILURE);
+
+ } else {
+
+ //
+ // We don't need the thread handle
+ //
+
+ IgnoreResult = CloseHandle(ThreadHandle);
+ ASSERT(IgnoreResult);
+ }
+ Result = DLG_SUCCESS;
+
+ } else {
+
+ //
+ // Switch the thread to user context. We don't want
+ // to start another thread to perform logoffs in
+ // case the system is out of memory and unable to
+ // create any more threads.
+ //
+
+ UserProcessData = &pGlobals->UserProcessData;
+ Handle = ImpersonateUser(UserProcessData, GetCurrentThread());
+
+ if (Handle == NULL) {
+
+ DebugLog((DEB_ERROR, "Failed to set user context on thread!"));
+
+ } else {
+
+ //
+ // Let the thread run
+ //
+
+ if ((pGlobals->UserLoggedOn) &&
+ (pGlobals->LastGinaRet != WLX_SAS_ACTION_FORCE_LOGOFF) )
+ {
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
+ }
+ Result = LogoffThreadProc((LPVOID)Flags);
+
+ }
+
+ RevertToSelf();
+
+ }
+
+ //
+ // ExitWindowsEx will cause one or more desktop switches to occur,
+ // so we must invalidate our current desktop.
+ //
+
+ if ( (Flags & EWX_WINLOGON_API_SHUTDOWN) == 0 )
+ {
+ pGlobals->WindowStation.PreviousDesktop = pGlobals->WindowStation.ActiveDesktop;
+ pGlobals->WindowStation.ActiveDesktop = -1;
+ }
+
+ //
+ // The reboot thread is off and running. We're finished.
+ //
+
+ return (Result);
+}
+
+
+/***************************************************************************\
+* FUNCTION: ExecLogoffThread
+*
+* PURPOSE: Creates a user thread that calls ExitWindowsEx with the
+* passed flags.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 05-05-92 Davidc Created.
+*
+\***************************************************************************/
+
+HANDLE
+ExecLogoffThread(
+ PGLOBALS pGlobals,
+ DWORD Flags
+ )
+{
+ HANDLE ThreadHandle;
+ DWORD ThreadId;
+
+ ThreadHandle = ExecUserThread(
+ pGlobals,
+ LogoffThreadProc,
+ (LPVOID)Flags,
+ 0, // Thread creation flags
+ &ThreadId);
+
+ if (ThreadHandle == NULL) {
+ DebugLog((DEB_ERROR, "Failed to exec a user logoff thread"));
+ }
+
+ return (ThreadHandle);
+}
+
+
+/***************************************************************************\
+* FUNCTION: LogoffThreadProc
+*
+* PURPOSE: The logoff thread procedure. Calls ExitWindowsEx with passed flags.
+*
+* RETURNS: Thread termination code is result of ExitWindowsEx call.
+*
+* HISTORY:
+*
+* 05-05-92 Davidc Created.
+*
+\***************************************************************************/
+
+DWORD
+LogoffThreadProc(
+ LPVOID Parameter
+ )
+{
+ DWORD LogoffFlags = (DWORD)Parameter;
+ BOOL Result = FALSE;
+
+
+ //
+ // If this logoff is a result of the InitiateSystemShutdown API,
+ // put up a dialog warning the user.
+ //
+
+ if ( LogoffFlags & EWX_WINLOGON_API_SHUTDOWN ) {
+ Result = ShutdownThread();
+ } else {
+ Result = TRUE;
+ }
+
+
+ if ( Result ) {
+
+ //
+ // Enable shutdown privilege if we need it
+ //
+
+ if (LogoffFlags & (EWX_SHUTDOWN | EWX_REBOOT | EWX_POWEROFF)) {
+ Result = EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);
+ if (!Result) {
+ DebugLog((DEB_ERROR, "Logoff thread failed to enable shutdown privilege!\n"));
+ }
+ }
+
+ //
+ // Call ExitWindowsEx with the passed flags
+ //
+
+ if (Result) {
+
+ DebugLog((DEB_TRACE, "Calling ExitWindowsEx(%#x, 0)\n", LogoffFlags));
+
+ //
+ // Set global flag indicating an ExitWindows is in progress.
+ //
+
+ ExitWindowsInProgress = TRUE ;
+
+ Result = ExitWindowsEx(LogoffFlags, 0);
+
+ ExitWindowsInProgress = FALSE ;
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "Logoff thread call to ExitWindowsEx failed, error = %d\n", GetLastError()));
+ }
+ }
+ }
+
+ return(Result ? DLG_SUCCESS : DLG_FAILURE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: RebootMachine
+*
+* PURPOSE: Calls NtShutdown(Reboot) in current user's context.
+*
+* RETURNS: Should never return
+*
+* HISTORY:
+*
+* 05-09-92 Davidc Created.
+*
+\***************************************************************************/
+
+VOID
+RebootMachine(
+ PGLOBALS pGlobals
+ )
+{
+ NTSTATUS Status;
+ BOOL EnableResult, IgnoreResult;
+ HANDLE UserHandle;
+
+ //
+ // Call windows to have it clear all data from video memory
+ //
+
+ // GdiEraseMemory();
+
+ DebugLog(( DEB_TRACE, "Rebooting machine\n" ));
+
+ //
+ // Impersonate the user for the shutdown call
+ //
+
+ UserHandle = ImpersonateUser( &pGlobals->UserProcessData, NULL );
+ ASSERT(UserHandle != NULL);
+
+ //
+ // Enable the shutdown privilege
+ // This should always succeed - we are either system or a user who
+ // successfully passed the privilege check in ExitWindowsEx.
+ //
+
+ EnableResult = EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);
+ ASSERT(EnableResult);
+
+
+ //
+ // Do the final system shutdown pass (reboot)
+ //
+
+ Status = NtShutdownSystem(ShutdownReboot);
+
+ DebugLog((DEB_ERROR, "NtShutdownSystem failed, status = 0x%lx", Status));
+ ASSERT(NT_SUCCESS(Status)); // Should never get here
+
+ //
+ // We may get here if system is screwed up.
+ // Try and clean up so they can at least log on again.
+ //
+
+ IgnoreResult = StopImpersonating(UserHandle);
+ ASSERT(IgnoreResult);
+}
+
+/***************************************************************************\
+* FUNCTION: PowerdownMachine
+*
+* PURPOSE: Calls NtShutdownSystem(ShutdownPowerOff) in current user's context.
+*
+* RETURNS: Should never return
+*
+* HISTORY:
+*
+* 08-09-93 TakaoK Created.
+*
+\***************************************************************************/
+
+VOID
+PowerdownMachine(
+ PGLOBALS pGlobals
+ )
+{
+ NTSTATUS Status;
+ BOOL EnableResult, IgnoreResult;
+ HANDLE UserHandle;
+
+ DebugLog(( DEB_TRACE, "Powering down machine\n" ));
+ //
+ // Impersonate the user for the shutdown call
+ //
+
+ UserHandle = ImpersonateUser( &pGlobals->UserProcessData, NULL );
+ ASSERT(UserHandle != NULL);
+
+ //
+ // Enable the shutdown privilege
+ // This should always succeed - we are either system or a user who
+ // successfully passed the privilege check in ExitWindowsEx.
+ //
+
+ EnableResult = EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);
+ ASSERT(EnableResult);
+
+ //
+ // Do the final system shutdown and powerdown pass
+ //
+
+ Status = NtShutdownSystem(ShutdownPowerOff);
+
+ DebugLog((DEB_ERROR, "NtPowerdownSystem failed, status = 0x%lx", Status));
+ ASSERT(NT_SUCCESS(Status)); // Should never get here
+
+ //
+ // We may get here if system is screwed up.
+ // Try and clean up so they can at least log on again.
+ //
+
+ IgnoreResult = StopImpersonating(UserHandle);
+ ASSERT(IgnoreResult);
+}
+
+
+/***************************************************************************\
+* FUNCTION: ShutdownMachine
+*
+* PURPOSE: Shutsdown and optionally reboots or powers off the machine.
+*
+* The shutdown is always done in the logged on user's context.
+* If no user is logged on then the shutdown happens in system context.
+*
+* RETURNS: FALSE if something went wrong, otherwise it never returns.
+*
+* HISTORY:
+*
+* 05-09-92 Davidc Created.
+* 10-04-93 Johannec Add poweroff option.
+*
+\***************************************************************************/
+
+BOOL
+ShutdownMachine(
+ PGLOBALS pGlobals,
+ int Flags
+ )
+{
+ int Result;
+ HANDLE FoundDialogHandle;
+ HANDLE LoadedDialogHandle = NULL;
+
+
+ //
+ // Preload the shutdown dialog so we don't have to fetch it after
+ // the filesystem has been shutdown
+ //
+
+ FoundDialogHandle = FindResource(NULL,
+ (LPTSTR) MAKEINTRESOURCE(IDD_SHUTDOWN),
+ (LPTSTR) MAKEINTRESOURCE(RT_DIALOG));
+ if (FoundDialogHandle == NULL) {
+ DebugLog((DEB_ERROR, "Failed to find shutdown dialog resource"));
+ } else {
+ LoadedDialogHandle = LoadResource(NULL, FoundDialogHandle);
+ if (LoadedDialogHandle == NULL) {
+ DebugLog((DEB_ERROR, "Ffailed to load shutdown dialog resource"));
+ }
+ }
+
+ //
+ // Notify the GINA of shutdown here.
+ //
+
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_SHUTDOWN))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxShutdown(%#x)\n",
+ pGlobals->pGina->pGinaContext));
+
+ DebugBreak();
+ }
+#endif
+
+ WlxSetTimeout(pGlobals, 120);
+
+ (void) pGlobals->pGina->pWlxShutdown(pGlobals->pGina->pGinaContext, Flags);
+
+ //
+ // If we haven't shut down already (via the Remote shutdown path), then
+ // we start it here, and wait for it to complete. Otherwise, skip straight
+ // down to the cool stuff.
+ //
+ if (pGlobals->WinlogonState != Winsta_Shutdown)
+ {
+ //
+ // Call windows to do the windows part of shutdown
+ // We make this a force operation so it is guaranteed to work
+ // and can not be interrupted.
+ //
+
+ DebugLog(( DEB_TRACE, "Starting shutdown\n" ));
+
+ Result = InitiateLogoff(pGlobals, EWX_SHUTDOWN | EWX_FORCE |
+ ((Flags == WLX_SAS_ACTION_SHUTDOWN_REBOOT) ? EWX_REBOOT : 0) |
+ ((Flags == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) ? EWX_POWEROFF : 0) );
+
+ ASSERT(Result == DLG_SUCCESS);
+
+
+
+ //
+ // Put up a dialog box to wait for the shutdown notification
+ // from windows and make the first NtShutdownSystem call.
+ //
+
+ WlxSetTimeout(pGlobals, TIMEOUT_NONE);
+
+ Result = WlxDialogBoxParam( pGlobals,
+ pGlobals->hInstance,
+ (LPTSTR)IDD_SHUTDOWN_WAIT,
+ NULL,
+ ShutdownWaitDlgProc,
+ (LONG)pGlobals);
+
+ }
+ else
+ {
+ //
+ // If we're here, it means that we were shut down from the remote path,
+ // so user has cleaned up, now we have to call NtShutdown to flush out
+ // mm, io, etc.
+ //
+
+ DebugLog(( DEB_TRACE, "Shutting down kernel\n" ));
+
+ EnablePrivilege( SE_SHUTDOWN_PRIVILEGE, TRUE );
+
+ NtShutdownSystem( ShutdownNoReboot );
+
+ EnablePrivilege( SE_SHUTDOWN_PRIVILEGE, FALSE );
+ }
+
+
+ //
+ // if machine has powerdown capability and user want to turn it off, then
+ // we down the system power.
+ //
+ if ( Flags == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF)
+ {
+ PowerdownMachine(pGlobals);
+
+ }
+
+
+ //
+ // If this is a shutdown request, then let the user know they can turn
+ // off the power. Otherwise drop straight through and reboot.
+ //
+
+ if ( Flags != WLX_SAS_ACTION_SHUTDOWN_REBOOT) {
+
+ DialogBoxIndirectParam(
+ pGlobals->hInstance,
+ (LPDLGTEMPLATE)LoadedDialogHandle,
+ NULL,
+ ShutdownDlgProc,
+ (LONG)pGlobals);
+ }
+
+
+ //
+ // If they got past that dialog it means they want to reboot
+ //
+
+ RebootMachine(pGlobals);
+
+ ASSERT(!"RebootMachine failed"); // Should never get here
+
+ return(FALSE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: ShutdownWaitDlgProc
+*
+* PURPOSE: Processes messages while we wait for windows to notify us of
+* a successful shutdown. When notification is received, do any
+* final processing and make the first call to NtShutdownSystem.
+*
+* RETURNS:
+* DLG_FAILURE - the dialog could not be displayed
+* DLG_SHUTDOWN() - the system has been shutdown, reboot wasn't requested
+*
+* HISTORY:
+*
+* 10-14-92 Davidc Created.
+* 10-04-93 Johannec Added Power off option.
+*
+\***************************************************************************/
+
+BOOL WINAPI
+ShutdownWaitDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
+ BOOL Success;
+ NTSTATUS Status;
+ HANDLE UserHandle;
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+ SetWindowLong(hDlg, GWL_USERDATA, lParam);
+ CentreWindow(hDlg);
+ return(TRUE);
+
+
+ case WLX_WM_SAS:
+ if (wParam != WLX_SAS_TYPE_USER_LOGOFF)
+ {
+ return(TRUE);
+ }
+
+ UpdateWindow(hDlg);
+
+ //
+ // Look at the public shutdown/reboot flags to determine what windows
+ // has actually done. We may receive other logoff notifications here
+ // but they will be only logoffs - the only place that winlogon actually
+ // calls ExitWindowsEx to do a shutdown/reboot is right here. So wait
+ // for the real shutdown/reboot notification.
+ //
+
+ if (pGlobals->LogoffFlags & (EWX_SHUTDOWN | EWX_REBOOT | EWX_POWEROFF)) {
+
+ //
+ // It's the notification we were waiting for.
+ // Do any final processing required and make the first
+ // call to NtShutdownSystem.
+ //
+
+
+ //
+ // Do any dos-specific clean-up
+ //
+
+ ShutdownDOS();
+
+
+ //
+ // Impersonate the user for the shutdown call
+ //
+
+ UserHandle = ImpersonateUser( &pGlobals->UserProcessData, NULL );
+ ASSERT(UserHandle != NULL);
+
+ //
+ // Enable the shutdown privilege
+ // This should always succeed - we are either system or a user who
+ // successfully passed the privilege check in ExitWindowsEx.
+ //
+
+ Success = EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);
+ ASSERT(Success);
+
+ //
+ // Do the first pass at system shutdown (no reboot yet)
+ //
+
+ WaitForSystemProcesses(pGlobals);
+
+ Status = NtShutdownSystem(ShutdownNoReboot);
+ ASSERT(NT_SUCCESS(Status));
+
+ //
+ // Revert to ourself
+ //
+
+ Success = StopImpersonating(UserHandle);
+ ASSERT(Success);
+
+ //
+ // We've finished system shutdown, we're done
+ //
+
+ EndDialog(hDlg, LogoffFlagsToWlxCode(pGlobals->LogoffFlags) );
+ }
+
+ return(TRUE);
+ }
+
+ // We didn't process this message
+ return FALSE;
+}
+
+
+/***************************************************************************\
+* FUNCTION: ShutdownDlgProc
+*
+* PURPOSE: Processes messages for the shutdown dialog - the one that says
+* it's safe to turn off the machine.
+*
+* RETURNS: DLG_SUCCESS if the user hits the restart button.
+*
+* HISTORY:
+*
+* 03-19-92 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL WINAPI
+ShutdownDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+ SetWindowLong(hDlg, GWL_USERDATA, lParam);
+ SetupSystemMenu(hDlg);
+ CentreWindow(hDlg);
+ return(TRUE);
+
+ case WM_COMMAND:
+ EndDialog(hDlg, DLG_SUCCESS);
+ return(TRUE);
+ }
+
+ // We didn't process this message
+ return FALSE;
+}
+
+
+/***************************************************************************\
+* FUNCTION: LogOff
+*
+* PURPOSE: Handles the post-user-application part of user logoff. This
+* routine is called after all the user apps have been closed down
+* It saves the user's profile, deletes network connections
+* and reboots/shutsdown the machine if that was requested.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+Logoff(
+ PGLOBALS pGlobals,
+ int LoggedOnResult
+ )
+{
+ NTSTATUS Status;
+ LUID luidNone = { 0, 0 };
+
+ DebugLog((DEB_TRACE, "In Logoff()\n"));
+
+ //
+ // We expect to be at the winlogon desktop in all cases
+ //
+
+ // ASSERT(OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED) == pGlobals->hdeskWinlogon);
+
+
+ //
+ // Delete the user's network connections
+ // Make sure we do this before deleting the user's profile
+ //
+
+ DeleteNetworkConnections(pGlobals);
+
+
+
+ //
+ // Remove any Messages Aliases added by the user.
+ //
+ DeleteMsgAliases();
+
+ //
+ // Play the user's logoff sound
+ //
+ if (pGlobals->PlaySound || pGlobals->MigrateSoundEvents) {
+ HANDLE uh;
+ BOOL fBeep;
+
+ // We AREN'T impersonating the user by default, so we MUST do so
+ // otherwise we end up playing the default rather than the user
+ // specified sound.
+
+ if (OpenIniFileUserMapping(pGlobals))
+ {
+ uh = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ //
+ // Whenever a user logs out, have WINMM.DLL check if there
+ // were any sound events added to the [SOUNDS] section of
+ // CONTROL.INI by a non-regstry-aware app. If there are,
+ // migrate those schemes to their new home. If there aren't,
+ // this is very quick.
+ //
+
+ if (pGlobals->MigrateSoundEvents) {
+ (*(pGlobals->MigrateSoundEvents))();
+ }
+
+ if (pGlobals->PlaySound) {
+ if (!SystemParametersInfo(SPI_GETBEEP, 0, &fBeep, FALSE)) {
+ // Failed to get hold of beep setting. Should we be
+ // noisy or quiet? We have to choose one value...
+ fBeep = TRUE;
+ }
+
+ if (fBeep) {
+
+ //
+ // Play synchronous
+ //
+ (*(pGlobals->PlaySound))((LPCSTR)SND_ALIAS_SYSTEMEXIT, NULL, SND_ALIAS_ID | SND_SYNC | SND_NODEFAULT);
+ }
+ }
+
+ StopImpersonating(uh);
+
+ CloseIniFileUserMapping(pGlobals);
+ }
+
+ }
+
+ //
+ // Call user to close the registry key for the NLS cache.
+ //
+
+ SetWindowStationUser(pGlobals->WindowStation.hwinsta, &luidNone, NULL, 0);
+
+ //
+ // Close the IniFileMapping that happened at logon time (LogonAttempt()).
+ //
+
+ CloseIniFileUserMapping(pGlobals);
+
+ //
+ // Save the user profile, this unloads the user's key in the registry
+ //
+
+ SaveUserProfile(pGlobals);
+
+ //
+ // Delete any remaining RAS connections. Make sure to do this after
+ // the user profile gets copied up to the
+ //
+
+ DeleteRasConnections( pGlobals );
+
+ //
+ // If the user logged off themselves (rather than a system logoff)
+ // and wanted to reboot then do it now.
+ //
+
+ if (IsShutdown(LoggedOnResult) && (!(pGlobals->LogoffFlags & EWX_WINLOGON_OLD_SYSTEM)))
+ {
+ ShutdownMachine(pGlobals, LoggedOnResult);
+
+ ASSERT(!"ShutdownMachine failed"); // Should never return
+ }
+
+
+ //
+ // Set up security info for new user (system) - this clears out
+ // the stuff for the old user.
+ //
+
+ SecurityChangeUser(pGlobals, NULL, NULL, pGlobals->WinlogonSid, FALSE);
+
+
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: DeleteNetworkConnections
+*
+* PURPOSE: Calls WNetNukeConnections in the client context to delete
+* any connections they may have had.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 04-15-92 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+DeleteNetworkConnections(
+ PGLOBALS pGlobals
+ )
+{
+ HANDLE ImpersonationHandle;
+ DWORD WNetResult;
+ BOOL Result = FALSE; // Default is failure
+ TCHAR szMprDll[] = TEXT("mpr.dll");
+ CHAR szWNetNukeConn[] = "WNetClearConnections";
+ CHAR szWNetOpenEnum[] = "WNetOpenEnumW";
+ CHAR szWNetEnumResource[] = "WNetEnumResourceW";
+ CHAR szWNetCloseEnum[] = "WNetCloseEnum";
+ PWNETNUKECONN lpfnWNetNukeConn = NULL;
+ PWNETOPENENUM lpfnWNetOpenEnum = NULL;
+ PWNETENUMRESOURCE lpfnWNetEnumResource = NULL;
+ PWNETCLOSEENUM lpfnWNetCloseEnum = NULL;
+ HWND hNetDelDlg;
+ HANDLE hEnum;
+ BOOL bConnectionsExist = TRUE;
+ NETRESOURCE NetRes;
+ DWORD dwNumEntries = 1;
+ DWORD dwEntrySize = sizeof (NETRESOURCE);
+
+ //
+ // Impersonate the user
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "DeleteNetworkConnections : Failed to impersonate user\n"));
+ return(FALSE);
+ }
+
+
+ //
+ // Load mpr if it wasn't already loaded.
+ //
+
+ if (!pGlobals->hMPR){
+ if (!(pGlobals->hMPR = LoadLibrary(szMprDll))) {
+ DebugLog((DEB_ERROR, "DeleteNetworkConnections : Failed to load mpr.dll\n"));
+ goto DNCExit;
+ }
+ }
+
+ //
+ // Get the function pointers
+ //
+
+ lpfnWNetOpenEnum = (PWNETOPENENUM) GetProcAddress(pGlobals->hMPR,
+ (LPSTR)szWNetOpenEnum);
+ lpfnWNetEnumResource = (PWNETENUMRESOURCE) GetProcAddress(pGlobals->hMPR,
+ (LPSTR)szWNetEnumResource);
+ lpfnWNetCloseEnum = (PWNETCLOSEENUM) GetProcAddress(pGlobals->hMPR,
+ (LPSTR)szWNetCloseEnum);
+ lpfnWNetNukeConn = (PWNETNUKECONN) GetProcAddress(pGlobals->hMPR,
+ (LPSTR)szWNetNukeConn);
+
+ //
+ // Check for NULL return values
+ //
+
+ if ( !lpfnWNetOpenEnum || !lpfnWNetEnumResource ||
+ !lpfnWNetCloseEnum || !lpfnWNetNukeConn ) {
+ DebugLog((DEB_ERROR, "DeleteNetworkConnections : Received a NULL pointer from GetProcAddress\n"));
+ goto DNCExit;
+ }
+
+ //
+ // Check for at least one network connection
+ //
+
+ if ( (*lpfnWNetOpenEnum)(RESOURCE_CONNECTED, RESOURCETYPE_ANY,
+ 0, NULL, &hEnum) == NO_ERROR) {
+
+ if ((*lpfnWNetEnumResource)(hEnum, &dwNumEntries, &NetRes,
+ &dwEntrySize) == ERROR_NO_MORE_ITEMS) {
+ bConnectionsExist = FALSE;
+ }
+
+ (*lpfnWNetCloseEnum)(hEnum);
+ }
+
+ //
+ // If we don't have any connections, then we can exit.
+ //
+
+ if (!bConnectionsExist) {
+ goto DNCExit;
+ }
+
+
+ //
+ // Display the status dialog box to the user
+ //
+
+ hNetDelDlg = CreateDialog (pGlobals->hInstance,
+ MAKEINTRESOURCE(IDD_WAIT_NET_DRIVES_DISCONNECT),
+ NULL,
+ DeleteNetConnectionsDlgProc);
+
+ //
+ // Delete the network connections.
+ //
+
+ WNetResult = 0;
+
+ WNetResult = (*lpfnWNetNukeConn)(NULL);
+
+ if (WNetResult != 0 && WNetResult != ERROR_CAN_NOT_COMPLETE) {
+ DebugLog((DEB_ERROR, "DeleteNetworkConnections : WNetNukeConnections failed, error = %d\n", WNetResult));
+ }
+
+ Result = (WNetResult == ERROR_SUCCESS);
+
+ //
+ // Close the dialog box
+ //
+
+ if (IsWindow (hNetDelDlg)) {
+ DestroyWindow (hNetDelDlg);
+ }
+
+
+DNCExit:
+
+ //
+ // Unload mpr.dll
+ //
+
+ if ( pGlobals->hMPR ) {
+ FreeLibrary(pGlobals->hMPR);
+ pGlobals->hMPR = NULL;
+ }
+
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (!StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "DeleteNetworkConnections : Failed to revert to self\n"));
+ }
+
+ return(Result);
+}
+
+/***************************************************************************\
+* FUNCTION: DeleteNetConnectionsDlgProc
+*
+* PURPOSE: Processes messages for the deleting net connections dialog
+*
+* RETURNS: Standard dialog box return values
+*
+* HISTORY:
+*
+* 04-26-92 EricFlo Created.
+*
+\***************************************************************************/
+
+BOOL WINAPI
+DeleteNetConnectionsDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+ CentreWindow(hDlg);
+ return(TRUE);
+
+ }
+
+ // We didn't process this message
+ return FALSE;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: DeleteRasConnections
+//
+// Synopsis: Delete RAS connections during logoff.
+//
+// Arguments: (none)
+//
+// History: 5-10-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+DeleteRasConnections(
+ PGLOBALS pGlobals
+ )
+{
+ HANDLE ImpersonationHandle;
+ SC_HANDLE hServiceMgr, hService;
+ SERVICE_STATUS status;
+ RASCONN rasconn;
+ LPRASCONN lprasconn = &rasconn;
+ DWORD i, dwErr, dwcb, dwc;
+ BOOL bRet;
+ PRASENUMCONNECTIONSW pRasEnumConnectionsW;
+ PRASHANGUPW pRasHangUpW;
+ BOOL FreeThatRasConn = FALSE;
+
+
+ if ( GetProfileInt( WINLOGON, KEEP_RAS_AFTER_LOGOFF, 0 ) )
+ {
+ return( TRUE );
+ }
+
+ //
+ // Determine whether the rasman service is running.
+ //
+
+ hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+
+ if ( hServiceMgr == NULL )
+ {
+ DebugLog((DEB_ERROR, "Unable to object service controller, %d\n", GetLastError()));
+ return( FALSE );
+ }
+
+ hService = OpenService(
+ hServiceMgr,
+ RASMAN_SERVICE_NAME,
+ SERVICE_QUERY_STATUS);
+
+ if (hService == NULL)
+ {
+ CloseServiceHandle(hServiceMgr);
+ DebugLog((DEB_TRACE, "rasman not started, nothing to tear down\n"));
+ return( TRUE );
+ }
+
+ bRet = QueryServiceStatus( hService, &status );
+
+ CloseServiceHandle(hService);
+
+ CloseServiceHandle(hServiceMgr);
+
+ if (! bRet )
+ {
+ //
+ // Service in bad state, get out of here...
+ //
+
+ return( TRUE );
+ }
+
+ if (status.dwCurrentState != SERVICE_RUNNING)
+ {
+ //
+ // Service is not running
+ //
+
+ return( TRUE );
+
+ }
+
+ //
+ // Load the RASAPI DLL so we can make it do stuff
+ //
+
+ if ( !hRasApi )
+ {
+ hRasApi = LoadLibrary( RASAPI32 );
+ if ( !hRasApi )
+ {
+ return( FALSE );
+ }
+ }
+
+ pRasEnumConnectionsW = (PRASENUMCONNECTIONSW) GetProcAddress(
+ hRasApi,
+ "RasEnumConnectionsW" );
+
+ pRasHangUpW = (PRASHANGUPW) GetProcAddress(
+ hRasApi,
+ "RasHangUpW" );
+
+ if ( (!pRasEnumConnectionsW) ||
+ (!pRasHangUpW) )
+ {
+ return( FALSE );
+ }
+
+
+
+ //
+ // Impersonate the user
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "DeleteNetworkConnections : Failed to impersonate user\n"));
+ return(FALSE);
+ }
+
+ //
+ // Enumerate the current RAS connections.
+ //
+
+
+ lprasconn->dwSize = sizeof (RASCONN);
+
+ dwcb = sizeof (RASCONN);
+
+ dwc = 1;
+
+ dwErr = pRasEnumConnectionsW(lprasconn, &dwcb, &dwc);
+
+ if (dwErr == ERROR_BUFFER_TOO_SMALL)
+ {
+ lprasconn = LocalAlloc(LPTR, dwcb);
+
+ FreeThatRasConn = TRUE;
+
+ if ( !lprasconn )
+ {
+ return( FALSE );
+ }
+
+ dwErr = pRasEnumConnectionsW(lprasconn, &dwcb, &dwc);
+ if (dwErr)
+ {
+ if ( FreeThatRasConn )
+ {
+ LocalFree( lprasconn );
+ }
+
+ return( FALSE );
+ }
+ }
+ else if (dwErr)
+ {
+ return( FALSE );
+ }
+
+ //
+ // cycle through the connections, and kill them
+ //
+
+
+ for (i = 0; i < dwc; i++)
+ {
+ DebugLog((DEB_TRACE, "Hanging up connection to %ws\n",
+ lprasconn[i].szEntryName));
+
+ (VOID) pRasHangUpW( lprasconn[i].hrasconn );
+ }
+
+ if ( FreeThatRasConn )
+ {
+ LocalFree( lprasconn );
+ }
+
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (!StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "DeleteNetworkConnections : Failed to revert to self\n"));
+ }
+
+ return( TRUE );
+}
diff --git a/private/windows/gina/winlogon/logoff.h b/private/windows/gina/winlogon/logoff.h
new file mode 100644
index 000000000..52fdded4a
--- /dev/null
+++ b/private/windows/gina/winlogon/logoff.h
@@ -0,0 +1,72 @@
+/****************************** Module Header ******************************\
+* Module Name: logoff.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define apis user to implement logoff functionality of winlogon
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+
+
+// Exported function prototypes
+//
+
+int
+InitiateLogoff(
+ PGLOBALS pGlobals,
+ LONG Flags
+ );
+
+BOOL
+Logoff(
+ PGLOBALS pGlobals,
+ int Result
+ );
+
+BOOL
+ShutdownMachine(
+ PGLOBALS pGlobals,
+ int Flags
+ );
+
+VOID
+RebootMachine(
+ PGLOBALS pGlobals
+ );
+
+VOID
+PowerdownMachine(
+ PGLOBALS pGlobals
+ );
+
+typedef DWORD (*PWNETNUKECONN) (
+ HWND
+ );
+
+typedef DWORD (*PWNETOPENENUM) (
+ DWORD,
+ DWORD,
+ DWORD,
+ LPNETRESOURCE,
+ LPHANDLE
+ );
+
+typedef DWORD (*PWNETENUMRESOURCE) (
+ HANDLE,
+ LPDWORD,
+ LPVOID,
+ LPDWORD
+ );
+
+typedef DWORD (*PWNETCLOSEENUM) (
+ HANDLE
+ );
+
+typedef DWORD
+(APIENTRY * PRASENUMCONNECTIONSW)( LPRASCONNW, LPDWORD, LPDWORD );
+
+typedef DWORD
+(APIENTRY * PRASHANGUPW) ( HRASCONN );
diff --git a/private/windows/gina/winlogon/logon.h b/private/windows/gina/winlogon/logon.h
new file mode 100644
index 000000000..79badac00
--- /dev/null
+++ b/private/windows/gina/winlogon/logon.h
@@ -0,0 +1,23 @@
+/****************************** Module Header ******************************\
+* Module Name: logon.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define apis user to implement logon functionality of winlogon
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+
+//
+// Exported function prototypes
+//
+
+
+int
+Logon(
+ PGLOBALS
+ );
+
+
diff --git a/private/windows/gina/winlogon/makefile b/private/windows/gina/winlogon/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/windows/gina/winlogon/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/windows/gina/winlogon/makefile.inc b/private/windows/gina/winlogon/makefile.inc
new file mode 100644
index 000000000..bba8bc651
--- /dev/null
+++ b/private/windows/gina/winlogon/makefile.inc
@@ -0,0 +1,14 @@
+!if exist($(TARGET_DIRECTORY).inc)
+!include $(TARGET_DIRECTORY).inc
+!endif
+
+res.rc: dialogs.dlg strings.rc win31mig.dlg wlevents.rc
+
+precomp.h: wlevents.h
+wlevents.rc: wlevents.h
+
+wlevents.h msg00001.bin: wlevents.mc
+ mc -v wlevents.mc
+
+
+
diff --git a/private/windows/gina/winlogon/misc.c b/private/windows/gina/winlogon/misc.c
new file mode 100644
index 000000000..364ea4000
--- /dev/null
+++ b/private/windows/gina/winlogon/misc.c
@@ -0,0 +1,143 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: misc.c
+//
+// Contents:
+//
+// Classes:
+//
+// Functions:
+//
+// History: 8-25-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+/***************************************************************************\
+* ReportWinlogonEvent
+*
+* Reports winlogon event by calling ReportEvent.
+*
+* History:
+* 10-Dec-93 JohanneC Created
+*
+\***************************************************************************/
+#define MAX_EVENT_STRINGS 8
+
+DWORD
+ReportWinlogonEvent(
+ IN PGLOBALS pGlobals,
+ IN WORD EventType,
+ IN DWORD EventId,
+ IN DWORD SizeOfRawData,
+ IN PVOID RawData,
+ IN DWORD NumberOfStrings,
+ ...
+ )
+{
+ va_list arglist;
+ ULONG i;
+ PWSTR Strings[ MAX_EVENT_STRINGS ];
+ DWORD rv;
+
+ va_start( arglist, NumberOfStrings );
+
+ if (NumberOfStrings > MAX_EVENT_STRINGS) {
+ NumberOfStrings = MAX_EVENT_STRINGS;
+ }
+
+ for (i=0; i<NumberOfStrings; i++) {
+ Strings[ i ] = va_arg( arglist, PWSTR );
+ }
+
+ if (pGlobals->hEventLog == NULL) {
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (pGlobals->hEventLog != INVALID_HANDLE_VALUE) {
+ if (!ReportEvent( pGlobals->hEventLog,
+ EventType,
+ 0, // event category
+ EventId,
+ pGlobals->UserProcessData.UserSid,
+ (WORD)NumberOfStrings,
+ SizeOfRawData,
+ Strings,
+ RawData) ) {
+ rv = GetLastError();
+ DebugLog((DEB_ERROR, "WINLOGON: ReportEvent( %u ) failed - %u\n", EventId, GetLastError() ));
+ } else {
+ rv = ERROR_SUCCESS;
+ }
+ } else {
+ rv = ERROR_INVALID_HANDLE;
+ }
+ return rv;
+}
+
+/***************************************************************************\
+* ClearUserProfileData
+*
+* Resets fields in user profile data. Should be used at startup when structure
+* contents are unknown.
+*
+* History:
+* 26-Aug-92 Davidc Created
+\***************************************************************************/
+VOID
+ClearUserProfileData(
+ PUSER_PROFILE_INFO UserProfileData
+ )
+{
+ UserProfileData->ProfilePath = NULL;
+ UserProfileData->ProfilePath = NULL;
+ UserProfileData->hProfile = NULL;
+ UserProfileData->PolicyPath = NULL;
+ UserProfileData->NetworkDefaultUserProfile = NULL;
+ UserProfileData->ServerName = NULL;
+ UserProfileData->Environment = NULL;
+
+}
+
+
+
+
+/***************************************************************************\
+* TimeoutMessageBox
+*
+* Same as a normal message box, but times out if there is no user input
+* for the specified number of seconds
+* For convenience, this api takes string resource ids rather than string
+* pointers as input. The resources are loaded from the .exe module
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+int
+TimeoutMessageBox(
+ PGLOBALS pGlobals,
+ HWND hwnd,
+ UINT IdText,
+ UINT IdCaption,
+ UINT wType)
+{
+ TCHAR CaptionBuffer[MAX_STRING_BYTES];
+ PTCHAR Caption = CaptionBuffer;
+ TCHAR Text[MAX_STRING_BYTES];
+
+ LoadString(NULL, IdText, Text, MAX_STRING_LENGTH);
+
+ if (IdCaption != 0) {
+ LoadString(NULL, IdCaption, Caption, MAX_STRING_LENGTH);
+ } else {
+ Caption = NULL;
+ }
+
+ return WlxMessageBox(pGlobals, hwnd, Text, Caption, wType);
+}
diff --git a/private/windows/gina/winlogon/misc.h b/private/windows/gina/winlogon/misc.h
new file mode 100644
index 000000000..a2ae79f33
--- /dev/null
+++ b/private/windows/gina/winlogon/misc.h
@@ -0,0 +1,47 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: misc.h
+//
+// Contents:
+//
+// Classes:
+//
+// Functions:
+//
+// History: 8-25-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+
+DWORD
+ReportWinlogonEvent(
+ IN PGLOBALS pGlobals,
+ IN WORD EventType,
+ IN DWORD EventId,
+ IN DWORD SizeOfRawData,
+ IN PVOID RawData,
+ IN DWORD NumberOfStrings,
+ ...
+ );
+
+
+VOID
+ClearUserProfileData(
+ PUSER_PROFILE_INFO UserProfileData
+ );
+
+
+int TimeoutMessageBox(
+ PGLOBALS pGlobals,
+ HWND hWnd,
+ UINT IdText,
+ UINT IdCaption,
+ UINT wType
+ );
+
+
+void
+MainLoop(PGLOBALS pGlobals);
diff --git a/private/windows/gina/winlogon/monitor.c b/private/windows/gina/winlogon/monitor.c
new file mode 100644
index 000000000..a07cf43c0
--- /dev/null
+++ b/private/windows/gina/winlogon/monitor.c
@@ -0,0 +1,369 @@
+/****************************** Module Header ******************************\
+* Module Name: monitor.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Implements functions that handle waiting for an object to be signalled
+* asynchronously.
+*
+* History:
+* 01-11-93 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Define this to enable verbose output for this module
+//
+
+// #define DEBUG_MONITOR
+
+#ifdef DEBUG_MONITOR
+#define VerbosePrint(s) WLPrint(s)
+#else
+#define VerbosePrint(s)
+#endif
+
+#define LockMonitor(Monitor) RtlEnterCriticalSection( &Monitor->CritSec )
+#define UnlockMonitor(Monitor) RtlLeaveCriticalSection( &Monitor->CritSec )
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: RefMonitor
+//
+// Synopsis: Safe Ref Count
+//
+// Arguments: [Monitor] --
+//
+// History: 7-12-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+VOID
+RefMonitor(
+ POBJECT_MONITOR Monitor)
+{
+ LockMonitor( Monitor );
+
+ Monitor->RefCount ++ ;
+
+ UnlockMonitor( Monitor );
+
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DerefMonitor
+//
+// Synopsis: Deref the monitor, cleaning up if refcount goes to zero
+//
+// Arguments: [Monitor] --
+//
+// History: 7-12-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+VOID
+DerefMonitor(
+ POBJECT_MONITOR Monitor )
+{
+ LockMonitor( Monitor );
+
+ DebugLog(( DEB_TRACE, "Deref of Monitor at %x\n", Monitor));
+
+ Monitor->RefCount -- ;
+
+ if ( Monitor->RefCount == 0 )
+ {
+ //
+ // Clean up time:
+ //
+
+ DebugLog(( DEB_TRACE, "Cleaning up Monitor at %x\n", Monitor ));
+
+ if ( Monitor->Thread )
+ {
+ CloseHandle( Monitor->Thread );
+ }
+
+ if ( Monitor->Flags & MONITOR_CLOSEOBJ )
+ {
+ if ( Monitor->Object != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle( Monitor->Object );
+ }
+ }
+
+ UnlockMonitor( Monitor );
+
+ RtlDeleteCriticalSection( &Monitor->CritSec );
+
+ Free( Monitor );
+
+ }
+ else
+ {
+ UnlockMonitor( Monitor );
+ }
+
+}
+
+/***************************************************************************\
+* FUNCTION: MonitorThread
+*
+* PURPOSE: Entry point for object monitor thread
+*
+* RETURNS: Windows error value
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+DWORD MonitorThread(
+ LPVOID lpThreadParameter
+ )
+{
+ POBJECT_MONITOR Monitor = (POBJECT_MONITOR)lpThreadParameter;
+ DWORD WaitResult;
+ NTSTATUS Status;
+ HANDLE Handle;
+
+ //
+ // Wait forever for object to be signalled
+ //
+
+ LockMonitor( Monitor );
+
+ Monitor->Flags |= MONITOR_ACTIVE ;
+
+ Handle = Monitor->Object ;
+
+ RefMonitor( Monitor );
+
+ UnlockMonitor( Monitor );
+
+ if ( Handle != INVALID_HANDLE_VALUE )
+ {
+
+ Status = NtWaitForSingleObject( Handle, TRUE, NULL);
+
+ if (!NT_SUCCESS(Status) && (Status != STATUS_ALERTED))
+ {
+ DebugLog((DEB_ERROR, "MonitorThread: NtWaitForSingleObject returned %x\n", Status));
+ }
+ }
+ else
+ {
+ Status = STATUS_SUCCESS ;
+ }
+
+ //
+ // Notify the appropriate window
+ //
+ if (Status != STATUS_ALERTED)
+ {
+ PostMessage( Monitor->hwndNotify,
+ WM_OBJECT_NOTIFY,
+ (WPARAM)Monitor,
+ (LPARAM)Monitor->CallerContext
+ );
+ }
+
+ LockMonitor( Monitor );
+
+ if ( Monitor->Flags & MONITOR_CLOSEOBJ )
+ {
+ CloseHandle( Handle );
+ }
+
+ Monitor->Object = INVALID_HANDLE_VALUE ;
+
+ Monitor->Flags = 0 ;
+
+ UnlockMonitor( Monitor );
+
+ DerefMonitor( Monitor );
+
+ return(ERROR_SUCCESS);
+}
+
+
+/***************************************************************************\
+* FUNCTION: CreateObjectMonitor
+*
+* PURPOSE: Creates a monitor object that will wait on the specified object
+* and post a message to the specifed window when the object is
+* signalled.
+*
+* NOTES: The object must have been opened for SYNCHRONIZE access.
+* The caller is responsible for closing the object handle
+* after the monitor object has been deleted.
+*
+* RETURNS: Handle to the monitor instance or NULL on failure.
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+POBJECT_MONITOR
+CreateObjectMonitor(
+ HANDLE Object,
+ HWND hwndNotify,
+ DWORD CallerContext
+ )
+{
+ POBJECT_MONITOR Monitor;
+ DWORD ThreadId;
+ NTSTATUS Status;
+
+ //
+ // Create monitor object
+ //
+
+ Monitor = Alloc(sizeof(OBJECT_MONITOR));
+ if (Monitor == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Initialize monitor fields
+ //
+
+ Status = RtlInitializeCriticalSection( &Monitor->CritSec );
+ if ( !NT_SUCCESS( Status ) )
+ {
+ Free( Monitor );
+ return( NULL );
+ }
+
+ LockMonitor( Monitor );
+
+ Monitor->hwndNotify = hwndNotify;
+ Monitor->Object = Object;
+ Monitor->CallerContext = CallerContext;
+ Monitor->RefCount = 1;
+ Monitor->Flags = 0 ;
+
+ //
+ // Create the monitor thread
+ //
+
+ Monitor->Thread = CreateThread(
+ NULL, // Use default ACL
+ 0, // Same stack size
+ MonitorThread, // Start address
+ (LPVOID)Monitor, // Parameter
+ 0, // Creation flags
+ &ThreadId // Get the id back here
+ );
+
+ if (Monitor->Thread == NULL) {
+
+ DebugLog((DEB_ERROR, "Failed to create monitor thread, error = %d\n", GetLastError()));
+
+ DerefMonitor( Monitor );
+
+ return(NULL);
+ }
+
+ UnlockMonitor( Monitor );
+
+ return(Monitor);
+}
+
+
+/***************************************************************************\
+* FUNCTION: DeleteObjectMonitor
+*
+* PURPOSE: Deletes an instance of a monitor object
+*
+* RETURNS: Nothing
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+VOID
+DeleteObjectMonitor(
+ POBJECT_MONITOR Monitor,
+ BOOLEAN fTerminate
+ )
+{
+ BOOL Result;
+
+ if ( fTerminate )
+ {
+ CancelObjectMonitor( Monitor );
+ }
+
+ DerefMonitor( Monitor );
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CancelObjectMonitor
+//
+// Synopsis: Interrupts a monitor thread safely.
+//
+// Arguments: [Monitor] --
+//
+// History: 7-12-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+VOID
+CancelObjectMonitor(
+ POBJECT_MONITOR Monitor )
+{
+ LockMonitor( Monitor );
+
+ if ( Monitor->Flags & MONITOR_ACTIVE )
+ {
+ NtAlertThread( Monitor->Thread );
+ }
+ else
+ {
+ Monitor->Object = INVALID_HANDLE_VALUE ;
+ }
+
+ UnlockMonitor( Monitor );
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CloseObjectMonitorObject
+//
+// Synopsis: Tags the handle to be closed when the monitor goes away
+//
+// Arguments: [Monitor] --
+//
+// History: 7-19-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+VOID
+CloseObjectMonitorObject(
+ POBJECT_MONITOR Monitor
+ )
+{
+ LockMonitor( Monitor );
+
+ Monitor->Flags |= MONITOR_CLOSEOBJ ;
+
+ UnlockMonitor( Monitor );
+}
diff --git a/private/windows/gina/winlogon/monitor.h b/private/windows/gina/winlogon/monitor.h
new file mode 100644
index 000000000..85cbabb8e
--- /dev/null
+++ b/private/windows/gina/winlogon/monitor.h
@@ -0,0 +1,66 @@
+/****************************** Module Header ******************************\
+* Module Name: monitor.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define object monitor interface
+*
+* History:
+* 01-23-91 Davidc Created.
+\***************************************************************************/
+
+//
+// Define a monitor object
+//
+
+typedef struct {
+ RTL_CRITICAL_SECTION CritSec;
+ HANDLE Object;
+ HWND hwndNotify;
+ DWORD CallerContext;
+ HANDLE Thread;
+ DWORD Flags;
+ DWORD RefCount;
+} OBJECT_MONITOR;
+typedef OBJECT_MONITOR *POBJECT_MONITOR;
+
+#define MONITOR_ACTIVE 0x00000001
+#define MONITOR_CLOSEOBJ 0x00000002
+
+//
+// Define notification message sent when object is signalled
+// wParam = monitor object handle
+// lParam = caller context
+//
+
+#define WM_OBJECT_NOTIFY (WM_USER + 800)
+
+
+//
+// Exported function prototypes
+//
+
+POBJECT_MONITOR
+CreateObjectMonitor(
+ HANDLE Object,
+ HWND hwndNotify,
+ DWORD CallerContext
+ );
+
+VOID
+DeleteObjectMonitor(
+ POBJECT_MONITOR Monitor,
+ BOOLEAN fTerminate
+ );
+
+VOID
+CancelObjectMonitor(
+ POBJECT_MONITOR Monitor );
+
+VOID
+CloseObjectMonitorObject(
+ POBJECT_MONITOR Monitor
+ );
+
+#define GetObjectMonitorCallerContext(Monitor) (Monitor->Context)
+#define GetObjectMonitorObject(Monitor) (Monitor->Object)
diff --git a/private/windows/gina/winlogon/msgalias.c b/private/windows/gina/winlogon/msgalias.c
new file mode 100644
index 000000000..fa8b25e58
--- /dev/null
+++ b/private/windows/gina/winlogon/msgalias.c
@@ -0,0 +1,171 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ msgalias.c
+
+Abstract:
+
+ This file contains routines for adding and deleting message aliases
+ when a user logs on/off.
+
+Author:
+
+ Dan Lafferty (danl) 21-Aug-1992
+
+Environment:
+
+ User Mode -Win32
+
+Revision History:
+
+ 21-Aug-1992 danl
+ created
+
+--*/
+#include "precomp.h"
+#pragma hdrstop
+
+#define LPTSTR LPWSTR
+
+
+
+
+VOID
+DeleteMsgAliases(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function removes all message aliases except the ComputerName.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+--*/
+{
+ DWORD status;
+ LPMSG_INFO_0 InfoStruct;
+ DWORD entriesRead;
+ DWORD totalEntries;
+ DWORD resumeHandle = 0;
+ DWORD i;
+ WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
+ LPWSTR NewServerName = NULL;
+ DWORD bufLen = MAX_COMPUTERNAME_LENGTH + 1;
+ HANDLE dllHandle;
+ PMSG_NAME_DEL NetMessageNameDel = NULL;
+ PMSG_NAME_ENUM NetMessageNameEnum = NULL;
+
+ //
+ // Get the computer name
+ //
+
+ if (!GetComputerNameW(ComputerName,&bufLen)) {
+ DebugLog((DEB_ERROR, "failed to obtain the computername"));
+ }
+
+ //
+ // Get the address of the functions we need from netapi32.dll
+ //
+ dllHandle = LoadLibraryW(L"netapi32.dll");
+ if (dllHandle == NULL) {
+ return;
+ }
+
+
+ NetMessageNameEnum = (PMSG_NAME_ENUM) GetProcAddress(
+ dllHandle,
+ "NetMessageNameEnum");
+
+ if (NetMessageNameEnum == NULL) {
+ FreeLibrary(dllHandle);
+ return;
+ }
+
+ NetMessageNameDel = (PMSG_NAME_DEL) GetProcAddress(
+ dllHandle,
+ "NetMessageNameDel");
+
+ if (NetMessageNameDel == NULL) {
+ FreeLibrary(dllHandle);
+ return;
+ }
+
+ //
+ // Enumerate all the Message Aliases
+ //
+
+ status = NetMessageNameEnum (
+ NULL, // ServerName - Local version
+ 0, // Level
+ (LPBYTE *)&InfoStruct, // return status buffer pointer
+ 0xffffffff, // preferred max length
+ &entriesRead, // entries read
+ &totalEntries, // total entries
+ &resumeHandle); // resume handle
+
+ if (status != NERR_Success) {
+ // DebugLog((DEB_ERROR, "NetMessageNameEnum failed %d",status));
+ FreeLibrary(dllHandle);
+ return;
+ }
+
+ //
+ // Remove the aliases that are not the computername.
+ //
+ for (i=0; i<entriesRead ;i++) {
+
+ if (_wcsicmp(InfoStruct->msgi0_name, ComputerName) != 0) {
+
+ status = NetMessageNameDel(
+ NULL,
+ InfoStruct->msgi0_name);
+ if (status != NERR_Success) {
+ DebugLog((DEB_ERROR, "DeleteMsgAliases: Name - %ws - delete failed",
+ InfoStruct->msgi0_name));
+ }
+ }
+ InfoStruct++;
+ }
+
+ FreeLibrary(dllHandle);
+}
+
+
+VOID
+TickleMessenger(VOID)
+{
+ HANDLE hDll;
+ PMSG_NAME_DEL NetMessageNameDel = NULL;
+
+ //
+ // Get the address of the functions we need from netapi32.dll
+ //
+ hDll = LoadLibraryW(L"netapi32.dll");
+ if (hDll == NULL) {
+ return;
+ }
+
+ NetMessageNameDel = (PMSG_NAME_DEL) GetProcAddress(
+ hDll,
+ "NetMessageNameDel");
+
+ if (NetMessageNameDel) {
+
+ NetMessageNameDel(NULL, TEXT(""));
+ }
+
+ FreeLibrary(hDll);
+
+}
diff --git a/private/windows/gina/winlogon/msgalias.h b/private/windows/gina/winlogon/msgalias.h
new file mode 100644
index 000000000..07622676c
--- /dev/null
+++ b/private/windows/gina/winlogon/msgalias.h
@@ -0,0 +1,67 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ msgalias.h
+
+Abstract:
+
+ Prototypes for functions that add/delete message aliases.
+
+Author:
+
+ Dan Lafferty (danl) 20-Mar-1991
+
+Environment:
+
+ User Mode -Win32
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ 20-Mar-1991 danl
+ created
+ .
+ .
+ least-recent-revision-date email-name
+ description
+
+--*/
+
+//
+// GetProcAddr Prototypes
+//
+
+typedef DWORD (*PMSG_NAME_ENUM) (
+ LPWSTR servername,
+ DWORD level,
+ LPBYTE *bufptr,
+ DWORD prefmaxlen,
+ LPDWORD entriesread,
+ LPDWORD totalentries,
+ LPDWORD resume_handle
+ );
+
+typedef DWORD (*PMSG_NAME_DEL) (
+ LPWSTR servername,
+ LPWSTR msgname
+ );
+
+
+//
+// Function Prototypes
+//
+
+VOID
+DeleteMsgAliases(
+ VOID
+ );
+
+
+VOID
+TickleMessenger(VOID);
diff --git a/private/windows/gina/winlogon/precomp.h b/private/windows/gina/winlogon/precomp.h
new file mode 100644
index 000000000..7615dd702
--- /dev/null
+++ b/private/windows/gina/winlogon/precomp.h
@@ -0,0 +1,41 @@
+#include "winlogon.h"
+#include <string.h>
+#include <stdio.h>
+#include <npapi.h>
+#include "doslog.h"
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <io.h>
+#include <fcntl.h>
+#include "mpr.h"
+#include <stddef.h>
+// #include "winp.h"
+// #include "winnls32.h"
+// #include "ime.h"
+// #include "winnls3p.h"
+#include <lmcons.h>
+#include <lmerr.h>
+#include <lmmsg.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include "sysshut.h"
+#include <winsvc.h>
+#include "crypt.h"
+#include <ntsam.h>
+#include <lmapibuf.h>
+#include <lmaccess.h>
+#include <wchar.h>
+
+#ifdef _X86_
+#include "os2ssrtl.h"
+#endif
+
+#include <stdarg.h>
+#include <errno.h>
+#include <ctype.h>
+#include "setup.h"
+// #include "regrpc.h"
+#include "ntrpcp.h"
+#include <rpc.h>
+#include <winreg.h>
+#include <userenv.h>
diff --git a/private/windows/gina/winlogon/provider.c b/private/windows/gina/winlogon/provider.c
new file mode 100644
index 000000000..566a6a7c2
--- /dev/null
+++ b/private/windows/gina/winlogon/provider.c
@@ -0,0 +1,1045 @@
+/****************************** Module Header ******************************\
+* Module Name: provider.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Implements functions that support multiple network providers.
+* Currently this involves notifying credential managers of logon and
+* password change operations.
+*
+* History:
+* 01-10-93 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Define this to enable verbose output for this module
+//
+
+// #define DEBUG_PROVIDER
+
+#ifdef DEBUG_PROVIDER
+#define VerbosePrint(s) WLPrint(s)
+#else
+#define VerbosePrint(s)
+#endif
+
+
+//
+// Define the key in the winlogon section of win.ini that
+// defines the the multiple provider notify app name.
+//
+
+#define NOTIFY_KEY_NAME TEXT("mpnotify")
+
+//
+// Define the default multiple provider notify app name.
+//
+
+#define DEFAULT_NOTIFY_APP_NAME TEXT("mpnotify.exe")
+
+
+//
+// Define environment variables used to pass information to multiple
+// provider notify process
+//
+
+#define MPR_STATION_NAME_VARIABLE TEXT("WlMprNotifyStationName")
+#define MPR_STATION_HANDLE_VARIABLE TEXT("WlMprNotifyStationHandle")
+#define MPR_WINLOGON_WINDOW_VARIABLE TEXT("WlMprNotifyWinlogonWindow")
+
+#define MPR_LOGON_FLAG_VARIABLE TEXT("WlMprNotifyLogonFlag")
+#define MPR_USERNAME_VARIABLE TEXT("WlMprNotifyUserName")
+#define MPR_DOMAIN_VARIABLE TEXT("WlMprNotifyDomain")
+#define MPR_PASSWORD_VARIABLE TEXT("WlMprNotifyPassword")
+#define MPR_OLD_PASSWORD_VARIABLE TEXT("WlMprNotifyOldPassword")
+#define MPR_OLD_PASSWORD_VALID_VARIABLE TEXT("WlMprNotifyOldPasswordValid")
+#define MPR_LOGONID_VARIABLE TEXT("WlMprNotifyLogonId")
+#define MPR_CHANGE_INFO_VARIABLE TEXT("WlMprNotifyChangeInfo")
+#define MPR_PASSTHROUGH_VARIABLE TEXT("WlMprNotifyPassThrough")
+#define MPR_PROVIDER_VARIABLE TEXT("WlMprNotifyProvider")
+
+
+// Message we send to ourselves so we can hide.
+#define WM_HIDEOURSELVES (WM_USER + 0)
+
+
+
+//
+// Define the structure used to pass data into the notify control dialog
+//
+
+typedef struct {
+ PGLOBALS pGlobals;
+ LPWSTR ReturnBuffer; // Returned from dialog
+ HANDLE hProcess;
+ POBJECT_MONITOR Monitor;
+ BOOL ProcessRunning;
+} NOTIFY_DATA;
+typedef NOTIFY_DATA *PNOTIFY_DATA;
+
+
+
+
+//
+// Private prototypes
+//
+
+BOOL
+MprNotifyDlgInit(
+ HWND hDlg
+ );
+
+BOOL
+StartNotifyProcessMonitor(
+ HWND hDlg
+ );
+
+VOID
+DeleteNotifyProcessMonitor(
+ HWND hDlg
+ );
+
+BOOL
+KillNotifyProcess(
+ PNOTIFY_DATA pNotifyData
+ );
+
+
+/***************************************************************************\
+* FUNCTION: DeleteNotifyVariables
+*
+* PURPOSE: Deletes all the notify data environment variables from the
+* current process's environment.
+*
+* RETURNS: Nothing
+*
+* HISTORY:
+*
+* 01-12-93 Davidc Created.
+*
+\***************************************************************************/
+
+VOID
+DeleteNotifyVariables(
+ VOID
+ )
+{
+ SetEnvironmentVariable(MPR_STATION_NAME_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_STATION_HANDLE_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_WINLOGON_WINDOW_VARIABLE, NULL);
+
+ SetEnvironmentVariable(MPR_LOGON_FLAG_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_USERNAME_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_DOMAIN_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_PASSWORD_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_OLD_PASSWORD_VALID_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_OLD_PASSWORD_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_LOGONID_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_CHANGE_INFO_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_PASSTHROUGH_VARIABLE, NULL);
+ SetEnvironmentVariable(MPR_PROVIDER_VARIABLE, NULL);
+}
+
+
+/***************************************************************************\
+* FUNCTION: SetWinlogonWindowVariable
+*
+* PURPOSE: Sets winlogon window environment variable in current process's
+* environment - this is inherited by notify process.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 01-12-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+SetWinlogonWindowVariable(
+ HWND hwnd
+ )
+{
+ BOOL Result;
+
+ Result = SetEnvironmentULong(MPR_WINLOGON_WINDOW_VARIABLE, (ULONG)hwnd);
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "SetWinlogonWindowVariable: Failed to set variable, error = %d\n", GetLastError()));
+ }
+
+ return(Result);
+}
+
+
+/***************************************************************************\
+* FUNCTION: SetCommonNotifyVariables
+*
+* PURPOSE: Sets environment variables to pass information to notify process
+* for data that is common to all notifications.
+* The variables are set in winlogon's environment - this is
+* inherited by the notify process.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* On failure return, all notify variables have been deleted
+*
+* HISTORY:
+*
+* 01-12-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+SetCommonNotifyVariables(
+ PGLOBALS pGlobals,
+ HWND hwndOwner,
+ LPTSTR Name OPTIONAL,
+ LPTSTR Domain OPTIONAL,
+ LPTSTR Password OPTIONAL,
+ LPTSTR OldPassword OPTIONAL
+ )
+{
+ BOOL Result = TRUE;
+
+ if (Result) {
+ Result = SetEnvironmentVariable(MPR_STATION_NAME_VARIABLE, WINDOW_STATION_NAME);
+ }
+ if (Result) {
+ Result = SetEnvironmentULong(MPR_STATION_HANDLE_VARIABLE, (ULONG)hwndOwner);
+ }
+
+ if (Result && ARGUMENT_PRESENT( Name )) {
+ Result = SetEnvironmentVariable(MPR_USERNAME_VARIABLE, Name);
+ }
+ if (Result && ARGUMENT_PRESENT( Domain )) {
+ Result = SetEnvironmentVariable(MPR_DOMAIN_VARIABLE, Domain);
+ }
+ if (Result && ARGUMENT_PRESENT( Password )) {
+ Result = SetEnvironmentVariable(MPR_PASSWORD_VARIABLE, Password);
+ }
+ if (Result) {
+ Result = SetEnvironmentULong(MPR_OLD_PASSWORD_VALID_VARIABLE,
+ (OldPassword != NULL) ? 1 : 0);
+ }
+ if (Result) {
+ Result = SetEnvironmentVariable(MPR_OLD_PASSWORD_VARIABLE, OldPassword);
+ if (OldPassword == NULL) {
+ Result = TRUE; // Ignore failure since deleting a variable that
+ // doesn't exist returns failure.
+ }
+ }
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "SetCommonNotifyVariables: Failed to set a variable, error = %d\n", GetLastError()));
+ DeleteNotifyVariables();
+ }
+
+ return(Result);
+}
+
+
+/***************************************************************************\
+* FUNCTION: SetLogonNotifyVariables
+*
+* PURPOSE: Sets environment variables to pass information to notify process
+* for data that is specific to logon notifications.
+* The variables are set in winlogon's environment - this is
+* inherited by the notify process.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* On failure return, all notify variables have been deleted
+*
+* HISTORY:
+*
+* 01-12-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+SetLogonNotifyVariables(
+ PLUID LogonId
+ )
+{
+ BOOL Result;
+ LARGE_INTEGER LargeInt;
+
+ LargeInt.LowPart = LogonId->LowPart;
+ LargeInt.HighPart = LogonId->HighPart;
+ Result = SetEnvironmentLargeInt(MPR_LOGONID_VARIABLE, LargeInt);
+ if (Result) {
+ Result = SetEnvironmentULong(MPR_LOGON_FLAG_VARIABLE, 1);
+ }
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "SetLogonNotifyVariables: Failed to set variable, error = %d\n", GetLastError()));
+ DeleteNotifyVariables();
+ }
+
+ return(Result);
+}
+
+
+/***************************************************************************\
+* FUNCTION: SetChangePasswordNotifyVariables
+*
+* PURPOSE: Sets environment variables to pass information to notify process
+* for data that is specific to change password notifications.
+* The variables are set in winlogon's environment - this is
+* inherited by the notify process.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* On failure return, all notify variables have been deleted
+*
+* HISTORY:
+*
+* 01-12-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+SetChangePasswordNotifyVariables(
+ DWORD ChangeInfo,
+ BOOL PassThrough,
+ PWSTR Provider OPTIONAL
+ )
+{
+ BOOL Result;
+
+ Result = SetEnvironmentULong(MPR_CHANGE_INFO_VARIABLE, ChangeInfo);
+ if (Result) {
+ Result = SetEnvironmentULong(MPR_LOGON_FLAG_VARIABLE, 0);
+ }
+
+ if (Result) {
+ Result = SetEnvironmentULong(MPR_PASSTHROUGH_VARIABLE, (PassThrough ? 1 : 0));
+ }
+
+ if (Result && ARGUMENT_PRESENT( Provider ) )
+ {
+ Result = SetEnvironmentVariable( MPR_PROVIDER_VARIABLE, Provider );
+ }
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "SetChangePasswordNotifyVariables: Failed to set variable, error = %d\n", GetLastError()));
+ DeleteNotifyVariables();
+ }
+
+ return(Result);
+}
+
+
+/***************************************************************************\
+* FUNCTION: MprNotifyDlgProc
+*
+* PURPOSE: Processes messages for the Mpr Notify dialog
+*
+* RETURNS: DLG_SUCCESS - the notification went without a hitch
+* - NotifyData->ReturnBuffer is valid.
+* DLG_FAILURE - something failed or there is no buffer to return.
+* - NotifyData->ReturnBuffer is invalid.
+*
+* DLG_INTERRUPTED() - a set defined in winlogon.h
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL WINAPI
+MprNotifyDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PNOTIFY_DATA pNotifyData = (PNOTIFY_DATA)GetWindowLong(hDlg, GWL_USERDATA);
+ PCOPYDATASTRUCT CopyData;
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+ SetWindowLong(hDlg, GWL_USERDATA, lParam);
+
+ if (!MprNotifyDlgInit(hDlg)) {
+ EndDialog(hDlg, DLG_FAILURE);
+ return(TRUE);
+ }
+
+ //
+ // Send ourselves a message so we can hide without the
+ // dialog code trying to force us to be visible
+ //
+
+ PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0);
+ return(TRUE);
+
+
+ case WM_HIDEOURSELVES:
+ ShowWindow(hDlg, SW_HIDE);
+ return(TRUE);
+
+
+ case WLX_WM_SAS:
+
+ if (wParam == WLX_SAS_TYPE_USER_LOGOFF)
+ {
+ DebugLog((DEB_TRACE_MPR, "Got a logoff notification\n"));
+ }
+ //
+ // Interrupt the notify process
+ // This gives us a way to terminate the notify process if it hangs up.
+ //
+
+ DebugLog((DEB_TRACE_MPR, "Got SAS message - interrupting notify process\n"));
+ EndDialog(hDlg, DLG_FAILURE);
+ return(TRUE);
+
+
+ case WM_COPYDATA:
+
+ //
+ // The notify process completed and is passing us the result
+ //
+
+ CopyData = (PCOPYDATASTRUCT)lParam;
+
+ DebugLog((DEB_TRACE_MPR, "Got WM_COPYDATA message from notify process\n"));
+ DebugLog((DEB_TRACE_MPR, "/tdwData = %d", CopyData->dwData));
+ DebugLog((DEB_TRACE_MPR, "/tcbData = %d", CopyData->cbData));
+
+ //
+ // End the screen-saver if it's running
+ // This assumes the screen-saver dialog terminates when it gets SAS.
+ // If it's not running this will come straight to us which is OK
+ //
+
+ DebugLog((DEB_TRACE_MPR, "Forwarding SAS message to top window\n"));
+ //ForwardMessage(pNotifyData->pGlobals, WM_SAS, 0, 0);
+
+
+ //
+ // Copy the passed data and quit this dialog
+ //
+
+ if (CopyData->dwData == 0) {
+ if (CopyData->cbData != 0) {
+ pNotifyData->ReturnBuffer = Alloc(CopyData->cbData);
+ if (pNotifyData->ReturnBuffer != NULL) {
+ CopyMemory(pNotifyData->ReturnBuffer, CopyData->lpData, CopyData->cbData);
+ } else {
+ DebugLog((DEB_ERROR, ("Failed to allocate memory for returned logon scripts")));
+ }
+ } else {
+ pNotifyData->ReturnBuffer = NULL;
+ }
+
+ } else {
+ DebugLog((DEB_TRACE_MPR, "Notify completed with an error: %d", CopyData->dwData));
+ }
+
+ EndDialog(hDlg, pNotifyData->ReturnBuffer ? DLG_SUCCESS : DLG_FAILURE);
+
+ return(TRUE); // We processed this message
+
+
+
+ case WM_OBJECT_NOTIFY:
+
+ //
+ // The notify process terminated for some reason
+ //
+
+ DebugLog((DEB_TRACE_MPR, "Notify process terminated - got monitor notification\n"));
+ EndDialog(hDlg, DLG_FAILURE);
+ return(TRUE);
+
+
+
+ case WM_DESTROY:
+
+ //
+ // Terminate the notify process and delete the monitor object.
+ //
+
+ if (pNotifyData->ProcessRunning) {
+
+ DebugLog((DEB_TRACE_MPR, "NotifyDlgProc: Deleting notify process and monitor\n"));
+
+ DeleteNotifyProcessMonitor(hDlg);
+ KillNotifyProcess(pNotifyData);
+ }
+
+ return(0);
+ }
+
+
+ // We didn't process the message
+ return(FALSE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: MprNotifyDlgInit
+*
+* PURPOSE: Handles initialization of Mpr notify dialog
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+#if DEVL
+BOOL bDebugMpNotify = FALSE;
+#endif
+
+BOOL
+MprNotifyDlgInit(
+ HWND hDlg
+ )
+{
+ PNOTIFY_DATA pNotifyData = (PNOTIFY_DATA)GetWindowLong(hDlg, GWL_USERDATA);
+ PGLOBALS pGlobals = pNotifyData->pGlobals;
+ USER_PROCESS_DATA SystemProcessData;
+ BOOL Success;
+ LPTSTR NotifyApp;
+ PROCESS_INFORMATION ProcessInformation;
+ PWSTR pchCmdLine;
+#if DEVL
+ WCHAR chDebugCmdLine[ MAX_PATH ];
+#endif
+
+ //
+ // Initialize flag to show we haven't created the notify process yet
+ //
+
+ pNotifyData->ProcessRunning = FALSE;
+
+ //
+ // Set our size to zero so we we don't appear
+ //
+
+ SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE |
+ SWP_NOREDRAW | SWP_NOZORDER);
+
+ //
+ // Set the winlogon window variable so the process knows who we are
+ //
+
+ SetWinlogonWindowVariable(hDlg);
+
+ //
+ // Start the notify process in system context
+ //
+
+ SystemProcessData.UserToken = NULL;
+ SystemProcessData.UserSid = pGlobals->WinlogonSid;
+ SystemProcessData.NewProcessSD = NULL;
+ SystemProcessData.NewProcessTokenSD = NULL;
+ SystemProcessData.NewThreadSD = NULL;
+ SystemProcessData.NewThreadTokenSD = NULL;
+ SystemProcessData.Quotas.PagedPoolLimit = 0;
+ SystemProcessData.CurrentDirectory = NULL;
+ SystemProcessData.pEnvironment = NULL; // Inherit our environment
+
+ //
+ // Get the name of the notify app
+ //
+
+ NotifyApp = AllocAndGetProfileString(WINLOGON, NOTIFY_KEY_NAME, DEFAULT_NOTIFY_APP_NAME);
+ if (NotifyApp == NULL) {
+ DebugLog((DEB_ERROR, "Failed to get name of provider notify app from registry\n"));
+ return(FALSE);
+ }
+
+ pchCmdLine = NotifyApp;
+
+ //
+ // Try and execute it
+ //
+#if DEVL
+ if (bDebugMpNotify) {
+ wsprintf( chDebugCmdLine, TEXT("ntsd -d %s%s"),
+ bDebugMpNotify == 2 ? TEXT("-g -G ") : TEXT(""),
+ pchCmdLine
+ );
+ pchCmdLine = chDebugCmdLine;
+ }
+#endif
+
+
+ Success = StartSystemProcess(pchCmdLine,
+ WINLOGON_DESKTOP_PATH,
+ 0,
+ 0,
+ NULL,
+ FALSE,
+ &pNotifyData->hProcess,
+ NULL);
+
+ Free(NotifyApp);
+
+ if (!Success) {
+ DebugLog((DEB_ERROR, "Failed to start multiple provider notifier\n"));
+ return(FALSE);
+ }
+
+ //
+ // Store the process id in our notify data for future reference
+ //
+
+
+
+ //
+ // Start the thread that will wait for the notify process to finish
+ //
+
+ if (!StartNotifyProcessMonitor(hDlg)) {
+
+ DebugLog((DEB_ERROR, "Failed to start notify process monitor thread\n"));
+ KillNotifyProcess(pNotifyData);
+ return(FALSE);
+ }
+
+ //
+ // Record the fact we started the notify process so we know
+ // to cleanup during WM_DESTROY
+ //
+
+ pNotifyData->ProcessRunning = TRUE;
+
+ // Success
+ return (TRUE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: StartNotifyProcessMonitor
+*
+* PURPOSE: Creates a thread that waits for the notify process to terminate
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+StartNotifyProcessMonitor(
+ HWND hDlg
+ )
+{
+ PNOTIFY_DATA NotifyData = (PNOTIFY_DATA)GetWindowLong(hDlg, GWL_USERDATA);
+
+ NotifyData->Monitor = CreateObjectMonitor(NotifyData->hProcess, hDlg, 0);
+
+ if (NotifyData->Monitor == NULL) {
+ DebugLog((DEB_ERROR, "Failed to create notify process monitor object\n"));
+ return(FALSE);
+ }
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+* FUNCTION: DeleteNotifyProcessMonitor
+*
+* PURPOSE: Cleans up resources used by notify process monitor
+*
+* RETURNS: Nothing
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+VOID
+DeleteNotifyProcessMonitor(
+ HWND hDlg
+ )
+{
+ PNOTIFY_DATA NotifyData = (PNOTIFY_DATA)GetWindowLong(hDlg, GWL_USERDATA);
+ POBJECT_MONITOR Monitor = NotifyData->Monitor;
+ HANDLE ProcessHandle = GetObjectMonitorObject(Monitor);
+
+ //
+ // Delete the object monitor
+ //
+
+ DeleteObjectMonitor(Monitor, TRUE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: KillNotifyProcess
+*
+* PURPOSE: Terminates the notify process
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+KillNotifyProcess(
+ PNOTIFY_DATA NotifyData
+ )
+{
+
+ if (!TerminateProcess(NotifyData->hProcess, STATUS_SUCCESS)) {
+ DebugLog((DEB_ERROR, "Failed to terminate notification process, error = %d\n", GetLastError()));
+ return(FALSE);
+ }
+
+ CloseHandle(NotifyData->hProcess);
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: NoNeedToNotify
+*
+* PURPOSE: Determines if it is necessary to call the notify apis.
+* It is not necessary if there is only one provider installed.
+*
+* We use this to save time in the common case where there is
+* only one provider. We can avoid the overhead of creating
+* the notify process in this case.
+*
+* RETURNS: TRUE if there is only one provider, otherwise FALSE
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+#define NET_PROVIDER_ORDER_KEY TEXT("system\\CurrentControlSet\\Control\\NetworkProvider\\Order")
+#define NET_PROVIDER_ORDER_VALUE TEXT("ProviderOrder")
+#define NET_ORDER_SEPARATOR TEXT(',')
+
+BOOL
+NoNeedToNotify(
+ VOID
+ )
+{
+ HKEY ProviderKey;
+ DWORD Error;
+ DWORD ValueType;
+ LPTSTR Value;
+ BOOL NeedToNotify = TRUE;
+
+ Error = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE, // hKey
+ NET_PROVIDER_ORDER_KEY, // lpSubKey
+ 0, // Must be 0
+ KEY_QUERY_VALUE, // Desired access
+ &ProviderKey // Newly Opened Key Handle
+ );
+
+ if (Error != ERROR_SUCCESS) {
+ DebugLog((DEB_ERROR, "NoNeedToNotify - failed to open provider key, assuming notification is necessary\n"));
+ return(!NeedToNotify);
+ }
+
+ Value = AllocAndRegQueryValueEx(
+ ProviderKey, // Key
+ NET_PROVIDER_ORDER_VALUE,// Value name
+ NULL, // Must be NULL
+ &ValueType // Type returned here
+ );
+
+ if (Value != NULL) {
+ if (ValueType == REG_SZ) {
+
+ LPTSTR p = Value;
+ while (*p) {
+ if (*p == NET_ORDER_SEPARATOR) {
+ break;
+ }
+ p = CharNext(p);
+ }
+
+ if (*p == 0) {
+
+ //
+ // We got to the end without finding a separator
+ // Only one provider is installed.
+ //
+
+ if (lstrcmpi(Value, SERVICE_WORKSTATION) == 0) {
+
+ //
+ // it's Lanman, don't notify
+ //
+
+ NeedToNotify = FALSE;
+
+
+ } else {
+
+ //
+ // it isn't Lanman, notify
+ //
+
+ NeedToNotify = TRUE;
+ }
+ }
+
+ } else {
+ DebugLog((DEB_ERROR, "NoNeedToNotify - provider order key unexpected type: %d, assuming notification is necessary", ValueType));
+ }
+
+ Free(Value);
+
+ } else {
+ DebugLog((DEB_ERROR, "NoNeedToNotify - failed to query provider order value, assuming notification is necessary\n"));
+ }
+
+ Error = RegCloseKey(ProviderKey);
+ ASSERT(Error == ERROR_SUCCESS);
+
+ return(!NeedToNotify);
+}
+
+
+
+/***************************************************************************\
+* MprLogonNotify
+*
+* Purpose : Notifies credential managers of a logon.
+*
+* RETURNS: DLG_SUCCESS - the notification went without a hitch
+* DLG_FAILURE - something failed.
+* DLG_INTERRUPTED() - a set of interruptions defined in winlogon.h
+*
+* On DLG_SUCCESS return MprLogonScripts contains a pointer to a
+* Multi-sz string or NULL if there is no data. i.e. multiple concatenated
+* zero terminated strings with a final terminator.
+* The memory should be freed by the caller (if pointer non-NULL) using Free().
+*
+* History:
+* 11-12-92 Davidc Created.
+\***************************************************************************/
+
+int
+MprLogonNotify(
+ PGLOBALS pGlobals,
+ HWND hwndOwner,
+ LPTSTR Name,
+ LPTSTR Domain,
+ LPTSTR Password,
+ LPTSTR OldPassword OPTIONAL,
+ PLUID LogonId,
+ LPWSTR *MprLogonScripts
+ )
+{
+ int Result;
+ NOTIFY_DATA NotifyData;
+
+ //
+ // Check if we really need to bother with this
+ //
+
+ if (NoNeedToNotify()) {
+ DebugLog((DEB_TRACE_MPR, "MprLogonNotify - skipping notification - only one provider\n"));
+ *MprLogonScripts = NULL;
+ return(DLG_SUCCESS);
+ }
+
+ //
+ // Set up the environment variables that we will use to pass
+ // information to notify process
+ //
+
+ if (!SetCommonNotifyVariables(pGlobals,
+ hwndOwner,
+ Name,
+ Domain,
+ Password,
+ OldPassword
+ )) {
+ return(DLG_FAILURE);
+ }
+
+ if (!SetLogonNotifyVariables(LogonId)) {
+ return(DLG_FAILURE);
+ }
+
+
+ //
+ // Initialize our notify data structure
+ //
+
+ NotifyData.pGlobals = pGlobals;
+ NotifyData.ReturnBuffer = NULL;
+
+ //
+ // Update windowstation lock so mpnotify can start.
+ //
+
+ UnlockWindowStation(pGlobals->WindowStation.hwinsta);
+ FastSetWinstaSecurity( &pGlobals->WindowStation,
+ FALSE );
+
+
+ //
+ // Create the dialog that will initiate the notify and wait
+ // for it to complete
+ //
+
+ Result = WlxDialogBoxParam( pGlobals,
+ pGlobals->hInstance,
+ (LPTSTR)IDD_CONTROL,
+ hwndOwner,
+ MprNotifyDlgProc,
+ (LONG)&NotifyData);
+
+ if (Result == DLG_SUCCESS) {
+ DebugLog((DEB_TRACE_MPR, "Logon notification return buffer (first string only) = <%ws>\n", NotifyData.ReturnBuffer));
+ *MprLogonScripts = NotifyData.ReturnBuffer;
+ } else {
+ DebugLog((DEB_TRACE_MPR, "Logon notification failed\n"));
+ }
+
+ //
+ // Re-lock the windowstation.
+ //
+
+ LockWindowStation(pGlobals->WindowStation.hwinsta);
+
+ DeleteNotifyVariables();
+
+ return(Result);
+}
+
+
+
+/***************************************************************************\
+* MprChangePasswordNotify
+*
+* Purpose : Notifies credential managers of a password change
+*
+* RETURNS: DLG_SUCCESS - the notification went without a hitch
+* DLG_FAILURE - something failed.
+* DLG_INTERRUPTED() - a set of interruptions defined in winlogon.h
+*
+* History:
+* 01-12-93 Davidc Created.
+\***************************************************************************/
+
+int
+MprChangePasswordNotify(
+ PGLOBALS pGlobals,
+ HWND hwndOwner,
+ PWSTR Provider,
+ LPTSTR Name,
+ LPTSTR Domain,
+ LPTSTR Password,
+ LPTSTR OldPassword,
+ DWORD ChangeInfo,
+ BOOL PassThrough
+ )
+{
+ int Result;
+ NOTIFY_DATA NotifyData;
+
+ //
+ // Check if we really need to bother with this
+ //
+
+ if (NoNeedToNotify()) {
+ DebugLog((DEB_TRACE_MPR, "MprChangePasswordNotify - skipping notification - only one provider\n"));
+ return(DLG_SUCCESS);
+ }
+
+ //
+ // Set up the environment variables that we will use to pass
+ // information to notify process
+ //
+
+ if (!SetCommonNotifyVariables(pGlobals,
+ hwndOwner,
+ Name,
+ Domain,
+ Password,
+ OldPassword
+ )) {
+ return(DLG_FAILURE);
+ }
+
+ if (!SetChangePasswordNotifyVariables(ChangeInfo,
+ PassThrough,
+ Provider ) )
+ {
+ return(DLG_FAILURE);
+ }
+
+
+ //
+ // Initialize our notify data structure
+ //
+
+ NotifyData.pGlobals = pGlobals;
+ NotifyData.ReturnBuffer = NULL;
+
+
+ //
+ // Update windowstation security so mpnotify can start.
+ //
+
+ FastSetWinstaSecurity( &pGlobals->WindowStation,
+ FALSE );
+
+ //
+ // Create the dialog that will initiate the notify and wait
+ // for it to complete
+ //
+
+ //
+ // Set timeout to 5 minutes, so the nwcs provider has time to run.
+ //
+
+ WlxSetTimeout( pGlobals, 5 * 60 );
+
+ Result = WlxDialogBoxParam( pGlobals,
+ pGlobals->hInstance,
+ (LPTSTR)IDD_CONTROL,
+ hwndOwner,
+ MprNotifyDlgProc,
+ (LONG)&NotifyData);
+ //
+ // Reset the windowstation security.
+ //
+
+ FastSetWinstaSecurity( &pGlobals->WindowStation,
+ TRUE );
+
+ if (Result == DLG_SUCCESS) {
+ Free(NotifyData.ReturnBuffer);
+ } else {
+ DebugLog((DEB_TRACE_MPR, "Change password notification failed\n"));
+ }
+
+ DeleteNotifyVariables();
+
+ return(Result);
+}
diff --git a/private/windows/gina/winlogon/provider.h b/private/windows/gina/winlogon/provider.h
new file mode 100644
index 000000000..0536d7b2f
--- /dev/null
+++ b/private/windows/gina/winlogon/provider.h
@@ -0,0 +1,45 @@
+/****************************** Module Header ******************************\
+* Module Name: provider.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define functions that support multiple network providers
+*
+* History:
+* 01-13-93 Davidc Created.
+\***************************************************************************/
+
+
+//
+// Exported function prototypes
+//
+
+int
+MprLogonNotify(
+ PGLOBALS pGlobals,
+ HWND hwndOwner,
+ LPTSTR Name,
+ LPTSTR Domain,
+ LPTSTR Password,
+ LPTSTR OldPassword OPTIONAL,
+ PLUID LogonId,
+ LPWSTR *MprLogonScripts
+ );
+
+int
+MprChangePasswordNotify(
+ PGLOBALS pGlobals,
+ HWND hwndOwner,
+ PWSTR Provider,
+ LPTSTR Name,
+ LPTSTR Domain,
+ LPTSTR Password,
+ LPTSTR OldPassword,
+ DWORD ChangeInfo,
+ BOOL PassThrough
+ );
+
+BOOL
+NoNeedToNotify(
+ VOID
+ );
diff --git a/private/windows/gina/winlogon/regini.c b/private/windows/gina/winlogon/regini.c
new file mode 100644
index 000000000..6c1c7183d
--- /dev/null
+++ b/private/windows/gina/winlogon/regini.c
@@ -0,0 +1,2527 @@
+#include "precomp.h"
+#pragma hdrstop
+
+
+#if INIT_REGISTRY
+
+VOID
+TmppSetUnsecureDefaultDacl( VOID );
+
+PGLOBALS pLocalGlobals;
+
+BOOL RunNetDetect = 0;
+BOOL ExtendedNetSetup = FALSE;
+BOOL NetSetupGoingToRun = FALSE;
+BOOL NetFound = FALSE;
+BOOL KeepScript = FALSE;
+char WinlogonSystemVariable[ 1024 ];
+PCHAR WinlogonShellVariable = NULL;
+
+char InputFileName[ MAX_PATH ];
+FILE *fh;
+char LineBuffer[ 1024 ];
+int LineIndent;
+int LineNumber;
+
+char MessageBuffer[ 512 ];
+char AnsiWinlogon[] = "Winlogon";
+WCHAR WideWinlogon[] = L"Winlogon";
+
+BOOL
+DeclareError(
+ char *Format,
+ ...
+ );
+
+BOOL
+DeclareError(
+ char *Format,
+ ...
+ )
+{
+ char *s;
+ size_t cb;
+ va_list arglist;
+
+ va_start(arglist, Format);
+
+ cb = _snprintf( MessageBuffer,
+ sizeof( MessageBuffer ),
+ "Winlogon: %s(%u)",
+ InputFileName,
+ LineNumber
+ );
+ s = MessageBuffer + cb;
+ *s++ = '\0';
+ cb = sizeof( MessageBuffer ) - cb;
+
+ _vsnprintf( s, cb, Format, arglist );
+
+#if DBG
+ DebugLog((DEB_TRACE_SETUP, "%s\n", s ));
+#endif
+
+ if (MessageBoxA( NULL, s, MessageBuffer, MB_OKCANCEL | MB_SETFOREGROUND )) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+BOOL
+GetLine( void )
+{
+ char *s, *s1;
+
+ while (TRUE) {
+ s = fgets( LineBuffer, sizeof( LineBuffer ), fh );
+ if (s == NULL) {
+ return FALSE;
+ }
+
+ LineNumber++;
+ if (s1 = strchr( s, '\r' )) {
+ *s1 = '\0';
+ }
+ else
+ if (s1 = strchr( s, '\n' )) {
+ *s1 = '\0';
+ }
+ else {
+ s1 = strchr( s, '\0' );
+ }
+ while (s1 > s && *--s1 <= ' ') {
+ *s1 = '\0';
+ }
+
+ while (*s && (*s <= ' ')) {
+ s++;
+ }
+
+ //
+ // If not a blank line or a comment line, then return to caller.
+ //
+
+ if (*s && *s != ';' && strncmp( s, "//", 2 )) {
+ LineIndent = s - LineBuffer;
+ strcpy( LineBuffer, s );
+// DebugLog((DEB_TRACE_SETUP, " (%u)'%s'\n", LineIndent, LineBuffer ));
+ return TRUE;
+ }
+ }
+}
+
+
+typedef BOOL (*PREG_INI_ROUTINE)(
+ struct _REG_INI_TABLE *TableEntry
+ );
+
+#define REG_INI_NONE 0
+#define REG_INI_VALUE 1
+#define REG_INI_MULTI_VALUE 2
+#define REG_INI_NAME_EQ_VALUE 3
+#define REG_INI_NAME_BOOLEAN 4
+#define REG_INI_DWORD 5
+#define REG_INI_NAME_EQ_MULTI 6
+
+#define REG_INI_FLAG_SKIP_FOR_NETSETUP (USHORT)0x0001
+#define REG_INI_FLAG_IGNORE_NOT_FOUND (USHORT)0x0002
+
+typedef struct _REG_INI_TABLE {
+ char *Name;
+ USHORT ValueType;
+ USHORT Flags;
+ PREG_INI_ROUTINE Routine;
+ char *RegistryPath;
+ char *RegistryValueName;
+} REG_INI_TABLE, *PREG_INI_TABLE;
+
+BOOL
+ProcessMachineType(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessDisabledDrivers(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessEnabledDrivers(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessProgramGroups(
+ PREG_INI_TABLE TableEntry,
+ BOOL PersonalGroups
+ );
+
+BOOL
+ProcessPersonalProgramGroups(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessCommonProgramGroups(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+SaveUserName(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+SaveMachineName(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+SavePassword(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+SaveTimeZone(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+SaveDomainName(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+SaveProductType(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+SaveScriptCommands(
+ PREG_INI_TABLE TableEntry
+ );
+
+REG_INI_TABLE RegistryIniTable[] = {
+ {"MachineType", REG_INI_NONE, 0, ProcessMachineType,
+ NULL, NULL
+ },
+
+ {"DisabledDrivers", REG_INI_NONE, 0, ProcessDisabledDrivers,
+ NULL, NULL
+ },
+
+ {"EnabledDrivers", REG_INI_NONE, 0, ProcessEnabledDrivers,
+ NULL, NULL
+ },
+
+ {"ProductType", REG_INI_VALUE, 0, SaveProductType,
+ "SYS:Control\\ProductOptions", "ProductType"
+ },
+
+ {"Domain", REG_INI_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, SaveDomainName,
+ "SYS:Services\\LanmanWorkstation\\Parameters", "Domain"
+ },
+
+ {"DomainId", REG_INI_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\LanmanWorkstation\\Parameters", "DomainId"
+ },
+
+ {"AccountDomainId", REG_INI_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\LanmanWorkstation\\Parameters", "AccountDomainId"
+ },
+
+ {"MachineName", REG_INI_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, SaveMachineName,
+ "SYS:Control\\ComputerName\\ComputerName", "ComputerName"
+ },
+
+ {"Password", REG_INI_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, SavePassword,
+ NULL, NULL
+ },
+
+ {"TimeZone", REG_INI_VALUE, 0, SaveTimeZone,
+ NULL, NULL
+ },
+
+ {"InsertScript", REG_INI_NONE, 0, SaveScriptCommands,
+ NULL, NULL
+ },
+
+ {"DosDevices", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Control\\Session Manager\\DOS Devices", NULL
+ },
+
+ {"Serial0", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial0", NULL
+ },
+
+ {"Serial1", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial1", NULL
+ },
+
+ {"Serial2", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial2", NULL
+ },
+
+ {"Serial3", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial3", NULL
+ },
+
+ {"Serial4", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial4", NULL
+ },
+
+ {"Serial5", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial5", NULL
+ },
+
+ {"Serial6", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial6", NULL
+ },
+
+ {"Serial7", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial7", NULL
+ },
+
+ {"Serial8", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial8", NULL
+ },
+
+ {"Serial9", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Services\\Serial\\Parameters\\Serial9", NULL
+ },
+
+ {"UserName", REG_INI_VALUE, 0, SaveUserName,
+ "SYS:Services", "CurrentUser"
+ },
+
+ {"DisablePasswordChange", REG_INI_DWORD, 0, NULL,
+ "SYS:Services\\NetLogon\\Parameters", "DisablePasswordChange"
+ },
+
+ {"GlobalFlags", REG_INI_DWORD, 0, NULL,
+ "SYS:Control\\Session Manager", "GlobalFlag"
+ },
+
+ {"ProtectionMode", REG_INI_DWORD, 0, NULL,
+ "SYS:Control\\Session Manager", "ProtectionMode"
+ },
+
+ {"CriticalSectionTimeout", REG_INI_DWORD, 0, NULL,
+ "SYS:Control\\Session Manager", "CriticalSectionTimeout"
+ },
+
+ {"ResourceTimeout", REG_INI_DWORD, 0, NULL,
+ "SYS:Control\\Session Manager", "ResourceTimeout"
+ },
+
+ {"WOW", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "SYS:Control\\WOW", NULL
+ },
+
+ {"PagingFiles", REG_INI_MULTI_VALUE, 0, NULL,
+ "SYS:Control\\Session Manager\\Memory Management", "PagingFiles"
+ },
+
+ {"InitialCommand", REG_INI_MULTI_VALUE, 0, NULL,
+ "SYS:Control\\Session Manager", "Execute"
+ },
+
+ {"SubSystems", REG_INI_MULTI_VALUE, 0, NULL,
+ "SYS:Control\\Session Manager\\SubSystems", "Optional"
+ },
+
+ {"ProgramGroups", REG_INI_NONE, 0, ProcessPersonalProgramGroups,
+ "USR:UNICODE Program Groups", NULL
+ },
+
+ {"CommonProgramGroups", REG_INI_NONE, 0, ProcessCommonProgramGroups,
+ "\\Registry\\Machine\\Software\\Program Groups", NULL
+ },
+
+ {"ProgramManager", REG_INI_NAME_BOOLEAN, 0, NULL,
+ "USR:Software\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager\\Settings", NULL
+ },
+
+ {"Environment", REG_INI_NAME_EQ_VALUE, 0, NULL,
+ "USR:Environment", NULL
+ },
+
+ {"Server", REG_INI_NAME_EQ_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\LanmanServer\\Parameters", NULL
+ },
+
+ {"ServerShares", REG_INI_NAME_EQ_MULTI, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\LanmanServer\\Shares", NULL
+ },
+
+ {"ServerLinkage", REG_INI_NAME_EQ_MULTI, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\LanmanServer\\Linkage", NULL
+ },
+
+ {"Nbf", REG_INI_NAME_EQ_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\Nbf\\Parameters", NULL
+ },
+
+ {"NbfLinkage", REG_INI_NAME_EQ_MULTI, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\Nbf\\Linkage", NULL
+ },
+
+ {"NetBios", REG_INI_NAME_EQ_MULTI, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\NetBiosInformation\\Parameters", NULL
+ },
+
+ {"NetBiosLinkage", REG_INI_NAME_EQ_MULTI, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\NetBios\\Linkage", NULL
+ },
+
+ {"Elnkii01", REG_INI_NAME_EQ_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\Elnkii01\\Parameters", NULL
+ },
+
+ {"ElnkMc01", REG_INI_NAME_EQ_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\ElnkMc01\\Parameters", NULL
+ },
+
+ {"UBAdapter", REG_INI_NAME_EQ_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\Xns\\Parameters", NULL
+ },
+
+ {"Lance01", REG_INI_NAME_EQ_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\Lance01\\Parameters", NULL
+ },
+
+ {"NE320001", REG_INI_NAME_EQ_VALUE, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\NE320001\\Parameters", NULL
+ },
+
+ {"WorkstationLinkage", REG_INI_NAME_EQ_MULTI, REG_INI_FLAG_SKIP_FOR_NETSETUP, NULL,
+ "SYS:Services\\LanmanWorkstation\\Linkage", NULL
+ },
+
+ {"Shell", REG_INI_VALUE, 0, NULL,
+ "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", "DefaultShell"
+ },
+
+ {NULL, REG_INI_NAME_EQ_VALUE, 0, NULL,
+ NULL, NULL
+ }
+};
+
+
+BOOL
+ProcessNone(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessValue(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessMultiValue(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessNameEqValue(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessNameBoolean(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessDWord(
+ PREG_INI_TABLE TableEntry
+ );
+
+BOOL
+ProcessNameEqMulti(
+ PREG_INI_TABLE TableEntry
+ );
+
+PREG_INI_ROUTINE RegistryIniRoutines[] = {
+ ProcessNone, // REG_INI_NONE
+ ProcessValue, // REG_INI_VALUE
+ ProcessMultiValue, // REG_INI_MULTI_VALUE
+ ProcessNameEqValue, // REG_INI_NAME_EQ_VALUE
+ ProcessNameBoolean, // REG_INI_NAME_BOOLEAN
+ ProcessDWord, // REG_INI_DWORD
+ ProcessNameEqMulti // REG_INI_NAME_EQ_MULTI
+};
+
+
+BOOL
+OpenRegistryKey(
+ PREG_INI_TABLE TableEntry,
+ PHANDLE Handle
+ );
+
+char CurrentIniFileName[ 256 ] = "win.ini";
+
+PREG_INI_TABLE
+FindTableEntry(
+ char *Name
+ )
+{
+ PREG_INI_TABLE TableEntry;
+
+ TableEntry = RegistryIniTable;
+ while (TableEntry->Name) {
+ if (!_stricmp( TableEntry->Name, Name )) {
+ break;
+ }
+ else {
+ TableEntry++;
+ }
+ }
+
+ return TableEntry;
+}
+
+BOOL
+WriteWinIni(
+ char *Section,
+ char *Key,
+ char *Value,
+ BOOL AppendToValue
+ )
+{
+ DWORD cbValue;
+ char *NewValue;
+ char *FileName;
+ BOOL Result;
+
+ FileName = CurrentIniFileName;
+ if (!_strnicmp( Value, "REG_DWORD ", 10 )) {
+ Value += 10;
+ }
+
+ if (AppendToValue) {
+ cbValue = 1024;
+ NewValue = (char *)LocalAlloc( LMEM_ZEROINIT, cbValue + strlen( Value ) + 1 );
+ if (NewValue) {
+ cbValue = GetPrivateProfileStringA( Section, Key, NULL, NewValue, cbValue, FileName );
+ if (cbValue) {
+ strcat( NewValue, Value );
+ }
+ }
+ }
+ else {
+ NewValue = Value;
+ }
+
+ Result = WritePrivateProfileStringA( Section, Key, NewValue, FileName );
+ if (!Result) {
+ DeclareError( "WritePrivateProfileString( %s, %s, %s, %s ) - failed (rc == %u)\n",
+ Section,
+ Key,
+ NewValue,
+ FileName ? FileName : "win.ini",
+ GetLastError()
+ );
+
+ }
+
+ if (NewValue != Value) {
+ LocalFree( NewValue );
+ }
+
+ return Result;
+}
+
+
+BOOL
+OpenRegistryKey(
+ PREG_INI_TABLE TableEntry,
+ PHANDLE Handle
+ )
+{
+ char *Path, FullPath[ 2 * MAX_PATH ];
+ ANSI_STRING AnsiPath;
+ UNICODE_STRING UnicodePath;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ Path = TableEntry->RegistryPath;
+ *Handle = NULL;
+ if (Path == NULL) {
+ return TRUE;
+ }
+ else
+ if (NetSetupGoingToRun && (TableEntry->Flags & REG_INI_FLAG_SKIP_FOR_NETSETUP)) {
+ return TRUE;
+ }
+
+ if (!_strnicmp( Path, "USR:", 4 )) {
+ strcpy( FullPath, "\\Registry\\User\\.Default\\" );
+ Path += 4;
+ }
+ else
+ if (!_strnicmp( Path, "SYS:", 4 )) {
+ strcpy( FullPath, "\\Registry\\Machine\\System\\CurrentControlSet\\" );
+ Path += 4;
+ }
+ else {
+ FullPath[ 0 ] = '\0';
+ }
+ strcat( FullPath, Path );
+ RtlInitAnsiString( &AnsiPath, FullPath );
+ RtlAnsiStringToUnicodeString( &UnicodePath, &AnsiPath, TRUE );
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodePath,
+ OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+ NULL,
+ NULL
+ );
+ Status = NtOpenKey( Handle,
+ MAXIMUM_ALLOWED,
+ &ObjectAttributes
+ );
+
+ RtlFreeUnicodeString( &UnicodePath );
+
+ if (NT_SUCCESS( Status )) {
+ return TRUE;
+ }
+ else {
+ if (!(TableEntry->Flags & REG_INI_FLAG_IGNORE_NOT_FOUND)) {
+ DeclareError( "NtOpenKey( %s ) failed (Status == %lx)\n",
+ FullPath,
+ Status
+ );
+ }
+
+ return FALSE;
+ }
+}
+
+BOOL
+WriteRegistryKey(
+ HANDLE KeyHandle,
+ char *ValueName,
+ DWORD ValueType,
+ char *ValueData,
+ DWORD ValueLength
+ )
+{
+ NTSTATUS Status;
+ ANSI_STRING AnsiString;
+ UNICODE_STRING UnicodeKeyName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE KeyHandle1;
+
+ RtlInitAnsiString( &AnsiString, ValueName );
+ RtlAnsiStringToUnicodeString( &UnicodeKeyName, &AnsiString, TRUE );
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeKeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+ KeyHandle,
+ NULL
+ );
+ Status = NtCreateKey( &KeyHandle1,
+ MAXIMUM_ALLOWED,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+ RtlFreeUnicodeString( &UnicodeKeyName );
+
+ if (NT_SUCCESS( Status )) {
+ Status = WriteRegistry( KeyHandle1,
+ NULL,
+ ValueType,
+ ValueData,
+ ValueLength
+ );
+ (void) NtClose( KeyHandle1 );
+
+ return( Status );
+
+ }
+ else {
+ DeclareError( "NtCreateKey( %s ) failed (Status == %lx)\n",
+ ValueName,
+ Status
+ );
+ return FALSE;
+ }
+}
+
+BOOL
+ProcessNone(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ return TRUE;
+}
+
+BOOL
+ProcessValue(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ HANDLE Handle;
+ BOOL Result;
+
+ if (!GetLine()) {
+ return FALSE;
+ }
+
+ if (!OpenRegistryKey( TableEntry, &Handle )) {
+ return FALSE;
+ }
+
+ Result = TRUE;
+ if (Handle) {
+ Result &= WriteRegistry( Handle,
+ TableEntry->RegistryValueName,
+ REG_SZ,
+ LineBuffer,
+ 0
+ );
+ NtClose( Handle );
+ }
+
+ return Result;
+}
+
+
+BOOL
+ProcessMultiValue(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ HANDLE Handle;
+ BOOL Result;
+ DWORD ValueLength, cb;
+ char *ValueData;
+
+ if (!OpenRegistryKey( TableEntry, &Handle )) {
+ return FALSE;
+ }
+
+ Result = TRUE;
+ ValueLength = 0;
+ ValueData = (char *)LocalAlloc( LMEM_ZEROINIT, ValueLength );
+ if (!ValueData)
+ {
+ NtClose( Handle );
+ return( FALSE );
+ }
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ if (Handle) {
+ cb = strlen( LineBuffer ) + 1;
+ ValueData = (char *)LocalReAlloc( ValueData, ValueLength + cb, LMEM_ZEROINIT | LMEM_MOVEABLE );
+ if (!ValueData)
+ {
+ NtClose( Handle );
+ return( FALSE );
+
+ }
+ strcpy( ValueData + ValueLength, LineBuffer );
+ ValueLength += cb;
+ }
+
+ }
+
+ if (Handle) {
+ cb = sizeof( '\0' );
+ ValueData = (char *)LocalReAlloc( ValueData, ValueLength + cb, LMEM_ZEROINIT | LMEM_MOVEABLE );
+ if (!ValueData)
+ {
+ NtClose( Handle );
+ return( FALSE );
+ }
+ ValueLength += cb;
+ Result &= WriteRegistry( Handle,
+ TableEntry->RegistryValueName,
+ REG_MULTI_SZ,
+ ValueData,
+ ValueLength
+ );
+ NtClose( Handle );
+ }
+
+ LocalFree( ValueData );
+
+ return Result;
+}
+
+
+BOOL
+ProcessNameEqValue(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ char MessageBuffer[ 128 ];
+ char SectionNameBuffer[ MAX_PATH ];
+ char *SectionName;
+ char *Equal, *Value;
+ HANDLE Handle;
+ BOOL AppendToValue;
+ BOOL Result;
+
+ if (!_strnicmp( LineBuffer, "-f ", 3)) {
+ Value = LineBuffer + 3;
+ while (*Value == ' ') {
+ Value++;
+ }
+
+ strcpy( CurrentIniFileName, Value );
+ return TRUE;
+ }
+
+ if (!OpenRegistryKey( TableEntry, &Handle )) {
+ return FALSE;
+ }
+
+ if (TableEntry->Name == NULL) {
+ SectionName = SectionNameBuffer;
+ strcpy( SectionName, LineBuffer );
+ }
+ else {
+ SectionName = NULL;
+ }
+ strcpy( MessageBuffer, LineBuffer );
+
+ Result = TRUE;
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ Equal = strchr( LineBuffer, '=' );
+ if (Equal == NULL) {
+ strcat( MessageBuffer, " - Expecting NAME=VALUE" );
+ DeclareError( MessageBuffer );
+ Result = FALSE;
+ break;
+ }
+ *Equal = '\0';
+ Value = Equal + 1;
+ if (Equal[ -1 ] == '+') {
+ AppendToValue = TRUE;
+ *--Equal = '\0';
+ }
+ else {
+ AppendToValue = FALSE;
+ }
+
+ while (Equal > LineBuffer && *--Equal <= ' ') {
+ *Equal = '\0';
+ }
+ while (*Value && *Value <= ' ') {
+ Value++;
+ }
+
+ if (Handle) {
+ Result &= WriteRegistry( Handle,
+ LineBuffer,
+ REG_SZ,
+ Value,
+ 0
+ );
+ }
+
+ if (SectionName) {
+ Result &= WriteWinIni( SectionName,
+ LineBuffer,
+ Value,
+ AppendToValue
+ );
+ }
+ }
+
+ if (Handle) {
+ NtClose( Handle );
+ }
+
+ return Result;
+}
+
+BOOL
+ProcessNameBoolean(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ HANDLE Handle;
+ BOOL Result;
+
+ if (!OpenRegistryKey( TableEntry, &Handle )) {
+ return FALSE;
+ }
+
+ Result = TRUE;
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ if (Handle) {
+ Result &= WriteRegistry( Handle,
+ LineBuffer,
+ REG_DWORD,
+ "1",
+ 0
+ );
+ }
+ }
+
+ if (Handle) {
+ NtClose( Handle );
+ }
+
+ return Result;
+}
+
+BOOL
+ProcessDWord(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ HANDLE Handle;
+ BOOL Result;
+
+ if (!GetLine()) {
+ return FALSE;
+ }
+
+ Result = TRUE;
+ if (!OpenRegistryKey( TableEntry, &Handle )) {
+ Result = FALSE;
+ }
+ else
+ if (Handle != NULL) {
+ Result &= WriteRegistry( Handle,
+ TableEntry->RegistryValueName,
+ REG_DWORD,
+ LineBuffer,
+ 0
+ );
+ NtClose( Handle );
+ }
+
+ return Result;
+}
+
+BOOL
+ProcessNameEqMulti(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ char *Equal, *Value;
+ char *Src, *Dst;
+ HANDLE Handle;
+ BOOL Result;
+
+ if (!TableEntry->RegistryPath) {
+ DeclareError( "RegistryPath must be specified for NAME_EQ_MULTI" );
+ return FALSE;
+ }
+ if (TableEntry->RegistryValueName) {
+ DeclareError( "RegistryValueName must be NULL for NAME_EQ_MULTI" );
+ return FALSE;
+ }
+
+ if (!OpenRegistryKey( TableEntry, &Handle )) {
+ return FALSE;
+ }
+
+ Result = TRUE;
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ Equal = strchr( LineBuffer, '=' );
+ if (Equal == NULL) {
+ DeclareError( "Expecting NAME=MULTI_SZ" );
+ Result = FALSE;
+ break;
+ }
+ *Equal = '\0';
+ Value = Equal + 1;
+ if (Equal[ -1 ] == '+') {
+ DeclareError( "+= not allowed for MULTI_SZ values" );
+ Result = FALSE;
+ break;
+ }
+
+ while (Equal > LineBuffer && *--Equal <= ' ') {
+ *Equal = '\0';
+ }
+ while (*Value && *Value <= ' ') {
+ Value++;
+ }
+
+ //
+ // Strip " from strings and put NULs in between.
+ //
+
+ Src = Dst = Value;
+ while (*Src) {
+ if (*Src++ != '"') {
+ DeclareError( "Expected '\"' to start MULTI_SZ string" );
+ Result = FALSE;
+ break;
+ }
+ while (*Src && (*Src != '"' || Src[1] == '"')) {
+ if ((*Dst++ = *Src++) == '"') {
+ Src++;
+ }
+ }
+ if (*Src++ != '"') {
+ DeclareError( "Missing '\"' at end of MULTI_SZ string" );
+ Result = FALSE;
+ break;
+ }
+ *Dst++ = '\0';
+ while (*Src && *Src <= ' ') {
+ Src++;
+ }
+ }
+ *Dst = '\0';
+
+ if (!Result) {
+ break;
+ }
+
+ if (Handle) {
+ Result &= WriteRegistry( Handle,
+ LineBuffer,
+ REG_MULTI_SZ,
+ Value,
+ 0
+ );
+ }
+ }
+
+ if (Handle) {
+ NtClose( Handle );
+ }
+
+ return Result;
+}
+
+
+BOOL
+ProcessPersonalProgramGroups(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ return ProcessProgramGroups( TableEntry, TRUE );
+}
+
+
+BOOL
+ProcessCommonProgramGroups(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ return ProcessProgramGroups( TableEntry, FALSE );
+}
+
+BOOL
+ProcessProgramGroups(
+ PREG_INI_TABLE TableEntry,
+ BOOL PersonalGroups
+ )
+{
+ HANDLE ProgramGroupsHandle;
+ HANDLE GroupsHandle;
+ HANDLE SettingsHandle;
+ REG_INI_TABLE TempEntry;
+ char *Equal, *Value, *ExpandedValue;
+ BOOL Result;
+ int GroupNumber;
+ int GroupFileHandle;
+ char GroupNumberKey[ MAX_PATH ];
+ char GroupOrderList[ MAX_PATH ] = " ";
+ char *GroupFileData;
+ struct _finddata_t GroupFileInfo;
+ long FindHandle;
+ DWORD cb;
+
+ OpenRegistryKey( TableEntry, &ProgramGroupsHandle );
+ if (ProgramGroupsHandle == NULL) {
+ return FALSE;
+ }
+
+ if (PersonalGroups) {
+ TempEntry.Flags = 0;
+ TempEntry.RegistryPath = "USR:Software\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager\\UNICODE Groups";
+ OpenRegistryKey( &TempEntry, &GroupsHandle );
+ if (GroupsHandle == NULL) {
+ NtClose( ProgramGroupsHandle );
+ return FALSE;
+ }
+
+ TempEntry.RegistryPath = "USR:Software\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager\\Settings";
+ OpenRegistryKey( &TempEntry, &SettingsHandle );
+ if (SettingsHandle == NULL) {
+ NtClose( GroupsHandle );
+ NtClose( ProgramGroupsHandle );
+ return FALSE;
+ }
+ }
+ else {
+ GroupsHandle = NULL;
+ SettingsHandle = NULL;
+ }
+
+ Result = TRUE;
+ GroupNumber = 0;
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ Equal = strchr( LineBuffer, '=' );
+ if (Equal == NULL) {
+ DeclareError( "Expecting NAME=VALUE" );
+ Result = FALSE;
+ break;
+ }
+ *Equal = '\0';
+ Value = Equal + 1;
+ while (Equal > LineBuffer && *--Equal <= ' ') {
+ *Equal = '\0';
+ }
+ while (*Value && *Value <= ' ') {
+ Value++;
+ }
+
+ if (strchr( Value, '%' )) {
+ cb = 4 * strlen( Value );
+ ExpandedValue = (char *)LocalAlloc( 0, cb );
+ ExpandEnvironmentStringsA( Value, ExpandedValue, cb );
+ Value = ExpandedValue;
+ }
+ else {
+ ExpandedValue = NULL;
+ }
+
+ cb = 0;
+ FindHandle = _findfirst( Value, &GroupFileInfo );
+ if (FindHandle != -1) {
+ GroupFileData = (char *)LocalAlloc( 0, GroupFileInfo.size );
+ _findclose( FindHandle );
+ GroupFileHandle = _open( Value, _O_BINARY | _O_RDONLY, _A_NORMAL );
+ if (GroupFileHandle != -1) {
+ cb = _read( GroupFileHandle, GroupFileData, GroupFileInfo.size );
+ if (cb != GroupFileInfo.size) {
+ cb = 0;
+ }
+ _close( GroupFileHandle );
+ }
+ }
+
+ if (ExpandedValue) {
+ LocalFree( ExpandedValue );
+ }
+
+ if (cb == 0) {
+ DeclareError( "Unable to open or access group file - %s", Value );
+ Result = FALSE;
+ }
+ else {
+ if (PersonalGroups) {
+ GroupNumber += 1;
+ sprintf( GroupNumberKey, "Group%u", GroupNumber );
+ Result &= WriteRegistry( GroupsHandle,
+ GroupNumberKey,
+ REG_SZ,
+ LineBuffer,
+ 0
+ );
+ }
+
+ Result &= WriteRegistryKey( ProgramGroupsHandle,
+ LineBuffer,
+ REG_BINARY,
+ GroupFileData,
+ cb
+ );
+
+
+ LocalFree( GroupFileData );
+ GroupFileData = NULL;
+ }
+ }
+
+ if (Result && PersonalGroups) {
+ char *s;
+ int i;
+
+ s = GroupOrderList;
+ for (i=0; i<GroupNumber; i++) {
+ if (i) {
+ *s++ = ' ' ;
+ }
+
+ s += sprintf( s, "%d", i+1 );
+ }
+
+ Result &= WriteRegistry( SettingsHandle,
+ "UNICODE Order",
+ REG_SZ,
+ GroupOrderList,
+ 0
+ );
+
+
+ Result &= WriteRegistry( SettingsHandle,
+ "Startup",
+ REG_SZ,
+ "Startup",
+ 0
+ );
+ }
+
+ if (PersonalGroups) {
+ NtClose( SettingsHandle );
+ NtClose( GroupsHandle );
+ }
+
+ NtClose( ProgramGroupsHandle );
+ return Result;
+}
+
+
+BOOL
+EnableDisableDriver(
+ char *ModuleName,
+ BOOL EnableLoad
+ );
+
+BOOL
+EnableDisableDriver(
+ char *ModuleName,
+ BOOL EnableLoad
+ )
+{
+ BOOL Result;
+ char RegistryPath[ MAX_PATH ];
+ HANDLE KeyHandle;
+ char StartValue[ 16 ];
+ REG_INI_TABLE TempEntry;
+
+
+ //
+ // Never ever disable VgaStart and VgaSave drivers.
+ //
+
+ if ( (_strnicmp(ModuleName, "Vga", 3) == 0) &&
+ !EnableLoad) {
+ return FALSE;
+ }
+
+ _snprintf( RegistryPath, sizeof( RegistryPath ), "SYS:Services\\%s", ModuleName );
+ TempEntry.RegistryPath = RegistryPath;
+ TempEntry.Flags = REG_INI_FLAG_IGNORE_NOT_FOUND;
+ OpenRegistryKey( &TempEntry, &KeyHandle );
+ if (KeyHandle != NULL) {
+ _snprintf( StartValue, sizeof( StartValue ), "%u",
+ EnableLoad ? SERVICE_SYSTEM_START : SERVICE_DISABLED
+ );
+ Result = WriteRegistry( KeyHandle,
+ "Start",
+ REG_DWORD,
+ StartValue,
+ 0
+ );
+ if (Result && EnableLoad) {
+ _snprintf( StartValue, sizeof( StartValue ), "%u", SERVICE_ERROR_IGNORE );
+ Result = WriteRegistry( KeyHandle,
+ "ErrorControl",
+ REG_DWORD,
+ StartValue,
+ 0
+ );
+ }
+
+ NtClose( KeyHandle );
+ Result = TRUE;
+ }
+ else {
+ Result = FALSE;
+ }
+
+ return Result;
+}
+
+
+BOOL
+ProcessREGINI(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ }
+
+ return TRUE;
+}
+
+BOOL
+ProcessMachineType(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ if (GetLine()) {
+ }
+
+ return TRUE;
+}
+
+BOOL
+ProcessDisabledDrivers(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ if (EnableDisableDriver( LineBuffer, FALSE )) {
+ DebugLog((DEB_TRACE_SETUP, " Disabled load of %s driver.\n", LineBuffer ));
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL
+ProcessEnabledDrivers(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ if (EnableDisableDriver( LineBuffer, TRUE )) {
+ DebugLog((DEB_TRACE_SETUP, " Enabled load of %s driver.\n", LineBuffer ));
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL
+DoFile( void )
+{
+ PREG_INI_TABLE TableEntry;
+ BOOL Result;
+
+ fh = fopen( InputFileName, "rb" );
+ if (fh == NULL) {
+ DeclareError( "Unable to open input file (rc == %u)\n", GetLastError() );
+ return FALSE;
+ }
+
+ Result = TRUE;
+ while (GetLine()) {
+ while (!LineIndent) {
+ TableEntry = FindTableEntry( LineBuffer );
+ LineIndent = 1;
+ if ((RegistryIniRoutines[ TableEntry->ValueType ])( TableEntry )) {
+ if (TableEntry->Routine) {
+ Result &= (TableEntry->Routine)( TableEntry );
+ }
+ }
+ else {
+ Result = FALSE;
+ }
+ }
+ }
+
+ return Result;
+}
+
+#if 0
+BOOL
+SaveDefaultProfile( void )
+{
+ char DefaultPath[ 2 * MAX_PATH ];
+ char ProfileKey[ 2 * MAX_PATH ];
+ ANSI_STRING AnsiPath;
+ UNICODE_STRING UnicodePath;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE KeyHandle;
+ HANDLE FileHandle;
+ IO_STATUS_BLOCK IoStatusBlock;
+ RTL_RELATIVE_NAME RelativeName;
+ UNICODE_STRING FileName;
+ PVOID FreeBuffer;
+ BOOLEAN ErrorFlag;
+
+ strcpy( ProfileKey, "\\Registry\\User\\The_User" );
+ RtlInitAnsiString( &AnsiPath, ProfileKey );
+ RtlAnsiStringToUnicodeString( &UnicodePath, &AnsiPath, TRUE );
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodePath,
+ OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+ NULL,
+ NULL
+ );
+ Status = NtOpenKey( &KeyHandle,
+ MAXIMUM_ALLOWED,
+ &ObjectAttributes
+ );
+
+ RtlFreeUnicodeString( &UnicodePath );
+
+ if (!NT_SUCCESS( Status )) {
+ DebugLog((DEB_ERROR, " Could not open key 'THE_USER' Status = 0x%lx\n\r", Status));
+ return FALSE;
+ }
+
+ ExpandEnvironmentStringsA("%systemRoot%\\system32\\config\\DEFAULT", DefaultPath, sizeof(DefaultPath));
+ RtlInitAnsiString( &AnsiPath, DefaultPath );
+ RtlAnsiStringToUnicodeString( &UnicodePath, &AnsiPath, TRUE );
+
+ //
+ // Convert the DOS path name to a canonical Nt path name.
+ //
+
+ ErrorFlag = RtlDosPathNameToNtPathName_U(
+ UnicodePath.Buffer,
+ &FileName,
+ NULL,
+ &RelativeName
+ );
+
+ RtlFreeUnicodeString( &UnicodePath );
+
+ //
+ // If the name was not succesfully converted assume it was invalid.
+ //
+ if( ! ErrorFlag ) {
+ DebugLog((DEB_ERROR, " Could not create default profile - RtlDosPathNameToNtPathName_U FAILED error = %d\n\r", ErrorFlag));
+ return FALSE;
+ }
+
+ //
+ // Remember the buffer allocatted by RtlDosPathNameToNtPathName_U.
+ //
+ FreeBuffer = FileName.Buffer;
+
+ //
+ // If a relative name and directory handle will work, use those.
+ //
+ if( RelativeName.RelativeName.Length ) {
+
+ //
+ // Replace the full path with the relative path.
+ //
+ FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
+
+ } else {
+
+ //
+ // Using the full path - no containing directory.
+ //
+ RelativeName.ContainingDirectory = NULL;
+ }
+
+ //
+ // Initialize the Obja structure for the save file.
+ //
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &FileName,
+ OBJ_CASE_INSENSITIVE,
+ RelativeName.ContainingDirectory,
+ NULL
+ );
+
+ //
+ // Create the file - fail if the file exists.
+ //
+ Status = NtCreateFile(
+ &FileHandle,
+ GENERIC_WRITE | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_CREATE,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+
+ //
+ // Free the buffer allocatted by RtlDosPathNameToNtPathName_U.
+ //
+ RtlFreeHeap( RtlProcessHeap(), 0, FreeBuffer );
+
+ //
+ // Check the results of the NtCreateFile.
+ //
+ if( ! NT_SUCCESS( Status )) {
+ DebugLog((DEB_ERROR, " Could not create default profile - Status == 0x%lx\n\r", Status));
+ return FALSE;
+ }
+
+ EnablePrivilege(SE_BACKUP_PRIVILEGE, TRUE);
+ EnablePrivilege(SE_RESTORE_PRIVILEGE, TRUE);
+
+ Status = NtSaveKey( KeyHandle, FileHandle );
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, " Could not save default profile - Status == 0x%lx\n\r", Status));
+ }
+ else {
+ DebugLog((DEB_ERROR, " Created the default profile DEFAULT\n\r"));
+ }
+
+ EnablePrivilege(SE_BACKUP_PRIVILEGE, FALSE);
+ EnablePrivilege(SE_RESTORE_PRIVILEGE, FALSE);
+
+ //
+ // Close the file.
+ //
+ NtClose( FileHandle );
+ return(NT_SUCCESS(Status));
+}
+#endif
+
+char SavedUserName[ MAX_COMPUTERNAME_LENGTH ];
+char SavedMachineName[ MAX_COMPUTERNAME_LENGTH ];
+char SavedDomainName[ MAX_COMPUTERNAME_LENGTH ];
+char SavedPassword[ 64 ];
+char SavedTimeZone[ 64 ];
+NT_PRODUCT_TYPE SavedProductType;
+char *CommandsToInsertAtBegOfScript;
+char *CommandsToInsertAtEndOfScript;
+
+BOOL
+SaveUserName(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ strcpy( SavedUserName, LineBuffer );
+ _strlwr( SavedUserName );
+ return TRUE;
+}
+
+BOOL
+SaveMachineName(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ strcpy( SavedMachineName, LineBuffer );
+ _strupr( SavedMachineName );
+ return TRUE;
+}
+
+BOOL
+SavePassword(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ strcpy( SavedPassword, LineBuffer );
+ return TRUE;
+}
+
+
+BOOL
+SaveTimeZone(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ strcpy( SavedTimeZone, LineBuffer );
+ return TRUE;
+}
+
+BOOL
+SaveDomainName(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ strcpy( SavedDomainName, LineBuffer );
+ _strupr( SavedDomainName );
+ return TRUE;
+}
+
+BOOL
+SaveProductType(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ TableEntry;
+
+ if (_strcmpi(LineBuffer, "LanmanNt") == 0) {
+ SavedProductType = NtProductLanManNt;
+ } else if (_strcmpi(LineBuffer, "ServerNt") == 0) {
+ SavedProductType = NtProductServer;
+ } else {
+ SavedProductType = NtProductWinNt;
+ }
+
+ return TRUE;
+}
+
+BOOL
+SaveScriptCommands(
+ PREG_INI_TABLE TableEntry
+ )
+{
+ char *s, **pp, *Src;
+ DWORD cb;
+
+ while (GetLine()) {
+ if (!LineIndent) {
+ break;
+ }
+
+ if (!_stricmp( LineBuffer, "KeepScript" )) {
+ KeepScript = TRUE;
+ }
+ else
+ if (!_stricmp( LineBuffer, "ExtendedNetSetup" )) {
+ ExtendedNetSetup = TRUE;
+ if (NetSetupGoingToRun) {
+ SetSetupType( SETUPTYPE_NETSRW );
+ }
+ }
+ else
+ if (!_stricmp( LineBuffer, "RunNetDetect" )) {
+ if (NetSetupGoingToRun) {
+ RunNetDetect = TRUE;
+ }
+ }
+ else {
+ Src = LineBuffer;
+ if (*Src == '!') {
+ pp = &CommandsToInsertAtEndOfScript;
+ Src++;
+ }
+ else {
+ pp = &CommandsToInsertAtBegOfScript;
+ }
+
+ if (*pp != NULL) {
+ cb = strlen( *pp );
+ }
+ else {
+ cb = 0;
+ }
+ cb += strlen( Src ) + 4;
+ s = RtlAllocateHeap( RtlProcessHeap(), 0, cb );
+ if (s == NULL) {
+ return FALSE;
+ }
+ sprintf( s, "%s%s\r\n", *pp != NULL ? *pp : "", Src );
+ if (*pp != NULL) {
+ RtlFreeHeap( RtlProcessHeap(), 0, *pp );
+ }
+ *pp = s;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOL
+GenerateInitialCommandScript( void )
+{
+ FILE *fh;
+ char ScriptFileName[ MAX_PATH ];
+ char SetupArguments[ 256];
+
+ GetEnvironmentVariableA( "SystemRoot", ScriptFileName, sizeof( ScriptFileName ) );
+ strcat( ScriptFileName, "\\winlogon.cmd" );
+ _unlink( ScriptFileName );
+
+ if (fh = fopen( ScriptFileName, "wb" )) {
+ fprintf( fh, "ini winlogon.Shell = \"progman.exe\"\r\n" );
+ fprintf( fh, "@ech ;\r\n" );
+ fprintf( fh, "@ech ;\r\n" );
+ fprintf( fh, "@ech This command will finish the initialization of your accounts database ;\r\n" );
+ fprintf( fh, "@ech and will not execute again the next time you boot. ;\r\n" );
+ fprintf( fh, "@ech ;\r\n" );
+ fprintf( fh, "@ech ;\r\n" );
+
+ if (CommandsToInsertAtBegOfScript != NULL) {
+ fprintf( fh, "%s", CommandsToInsertAtBegOfScript );
+ }
+
+ if (!NetSetupGoingToRun) {
+ if ( SavedTimeZone[0] ) {
+ fprintf( fh, "control main.cpl /INSTALL=%s\r\n", SavedTimeZone );
+ }
+ else {
+ fprintf( fh, "control main.cpl /INSTALL=Pacific\r\n");
+ }
+ }
+
+ fprintf( fh, "ini winlogon.DefaultUserName = %s\r\n", SavedUserName );
+ if ( NetFound ) {
+ if (SavedPassword[ 0 ]) {
+ fprintf( fh, "ini winlogon.AutoAdminLogon = 1\r\n" );
+ fprintf( fh, "ini winlogon.DefaultPassword = %s\r\n", SavedPassword );
+ }
+
+ if (SavedProductType != NtProductLanManNt) {
+ fprintf( fh, "ini winlogon.DefaultDomainName = %s\r\n", SavedDomainName );
+ if (!NetSetupGoingToRun) {
+ fprintf( fh, "netjoin\r\n" );
+ }
+ else {
+ fprintf( fh, "erase %%SystemRoot%%\\system32\\config\\userdef.*\r\n" );
+ }
+ fprintf( fh, "net localgroup Administrators %s\\%s /add\r\n", SavedDomainName, SavedUserName );
+ if (NetSetupGoingToRun) {
+ if (ExtendedNetSetup) {
+ sprintf( SetupArguments, " /t STF_COMPUTERNAME = %s", SavedMachineName );
+ AppendToSetupCommandLine( SetupArguments );
+ }
+
+ if (RunNetDetect) {
+ sprintf( SetupArguments, " /t STF_RUNNETDETECT = %u", RunNetDetect );
+ AppendToSetupCommandLine( SetupArguments );
+ }
+ }
+ }
+ }
+ else {
+ if (SavedPassword[ 0 ]) {
+ fprintf( fh, "ini winlogon.AutoAdminLogon = 1\r\n" );
+ fprintf( fh, "ini winlogon.DefaultPassword = %s\r\n", SavedPassword );
+ fprintf( fh, "adduser %s %s\r\n", SavedUserName, SavedPassword );
+ }
+ else {
+ fprintf( fh, "adduser %s localuser\r\n", SavedUserName );
+ }
+ }
+
+ if (!SavedPassword[ 0 ]) {
+ fprintf( fh, "@echo ;\r\n" );
+ fprintf( fh, "@echo Ready to reboot and logon as %s\r\n", SavedUserName );
+ fprintf( fh, "@echo ;\r\n" );
+ fprintf( fh, "@echo Pressing any key except Ctrl-C will reboot the machine.\r\n", SavedUserName );
+ fprintf( fh, "@pause\r\n" );
+ }
+
+ if (CommandsToInsertAtEndOfScript != NULL) {
+ fprintf( fh, "%s", CommandsToInsertAtEndOfScript );
+ }
+
+ if (!KeepScript) {
+ fprintf( fh, "erase %s && ", ScriptFileName );
+ }
+ fprintf( fh, "shutdown -r -f -t 0\r\n" );
+ fclose( fh );
+ WriteProfileStringA( AnsiWinlogon,
+ "Shell",
+ ScriptFileName
+ );
+ WriteProfileStringA( AnsiWinlogon, "AutoAdminLogon", "1" );
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+
+BOOL
+DisableFailedBuiltInDrivers(
+ PRTL_PROCESS_MODULES *ModuleList
+ )
+{
+ NTSTATUS Status;
+ RTL_PROCESS_MODULES ModuleInfoBuffer;
+ PRTL_PROCESS_MODULES ModuleInfo;
+ PRTL_PROCESS_MODULE_INFORMATION ModuleInfo1;
+ ULONG RequiredLength, ModuleNumber;
+
+ ModuleInfo = &ModuleInfoBuffer;
+ RequiredLength = sizeof( *ModuleInfo );
+ while (TRUE) {
+ Status = NtQuerySystemInformation( SystemModuleInformation,
+ ModuleInfo,
+ RequiredLength,
+ &RequiredLength
+ );
+ if (Status == STATUS_INFO_LENGTH_MISMATCH) {
+ if (ModuleInfo != &ModuleInfoBuffer) {
+ DebugLog((DEB_TRACE_SETUP, " QueryModuleInformation returned incorrect result.\n" ));
+ VirtualFree( ModuleInfo, 0, MEM_RELEASE );
+ return FALSE;
+ }
+
+ RequiredLength += 4096;
+ ModuleInfo = (PRTL_PROCESS_MODULES)VirtualAlloc( NULL,
+ RequiredLength,
+ MEM_COMMIT,
+ PAGE_READWRITE
+ );
+ if (ModuleInfo == NULL) {
+ DebugLog((DEB_TRACE_SETUP, " No memory for QueryModuleInformation (%lx).\n", RequiredLength ));
+ return FALSE;
+ }
+ }
+ else
+ if (!NT_SUCCESS( Status )) {
+ if (ModuleInfo != &ModuleInfoBuffer) {
+ VirtualFree( ModuleInfo, 0, MEM_RELEASE );
+ }
+
+ DebugLog((DEB_TRACE_SETUP, " QueryModuleInformation failed - %lx.\n", Status ));
+ return FALSE;
+ }
+ else {
+ break;
+ }
+ }
+
+ ModuleInfo1 = &ModuleInfo->Modules[ 0 ];
+ for (ModuleNumber=0; ModuleNumber<ModuleInfo->NumberOfModules; ModuleNumber++) {
+ if ((ModuleInfo1->Flags & LDRP_FAILED_BUILTIN_LOAD) &&
+ ModuleInfo1->LoadCount <= 1
+ ) {
+ char *ModuleName, *s;
+
+ ModuleName = &ModuleInfo1->FullPathName[ ModuleInfo1->OffsetToFileName ];
+ if (s = strchr( ModuleName, '.' )) {
+ *s = '\0';
+ }
+
+ if (EnableDisableDriver( ModuleName, FALSE )) {
+ DebugLog((DEB_TRACE_SETUP, " Disabled load of %s builtin driver.\n", ModuleName ));
+ }
+ }
+
+ ModuleInfo1++;
+ }
+
+ *ModuleList = ModuleInfo;
+ return TRUE;
+}
+
+BOOL
+LookupModuleName(
+ CHAR *DriverName,
+ PRTL_PROCESS_MODULES ModuleInfo
+ )
+{
+ PRTL_PROCESS_MODULE_INFORMATION moduleInfo1;
+ ULONG moduleNumber;
+
+ moduleInfo1 = &ModuleInfo->Modules[ 0 ];
+ for (moduleNumber=0; moduleNumber<ModuleInfo->NumberOfModules; moduleNumber++) {
+ if (!(moduleInfo1->Flags & LDRP_FAILED_BUILTIN_LOAD)) {
+
+ CHAR *moduleName, *s;
+
+ moduleName = &moduleInfo1->FullPathName[ moduleInfo1->OffsetToFileName ];
+ if (s = strchr( moduleName, '.' )) {
+ *s = '\0';
+ }
+
+ if (!_stricmp( moduleName, DriverName )) {
+ return TRUE;
+ }
+ }
+ moduleInfo1++;
+ }
+ return FALSE;
+}
+
+BOOL
+DisableFailedSysInitDrivers(
+ PRTL_PROCESS_MODULES ModuleInfo
+ )
+{
+ HANDLE keyHandle;
+ HANDLE subkeyHandle;
+ BOOL result;
+ CHAR registryPath[ MAX_PATH ];
+ ULONG subkey;
+ CHAR subkeyName[ MAX_PATH ];
+ ULONG subkeyNameLength;
+ FILETIME fileTime;
+ WCHAR startValue[ 16 ];
+ ULONG startValueLength;
+ ULONG status;
+ REG_INI_TABLE TempEntry;
+
+ //
+ // Get a handle to the Services entry in the registry to walk
+ // its tree.
+ //
+
+ TempEntry.RegistryPath = "SYS:Services";
+ TempEntry.Flags = 0;
+ OpenRegistryKey( &TempEntry, &keyHandle );
+ if (keyHandle != NULL) {
+ result = TRUE;
+ status = 0;
+ subkey = 0;
+ while (status == 0) {
+ subkeyNameLength = sizeof( subkeyName );
+ status = RegEnumKeyExA( keyHandle,
+ subkey,
+ subkeyName,
+ &subkeyNameLength,
+ NULL,
+ NULL,
+ NULL,
+ &fileTime );
+ if (status == 0) {
+ if (!(strstr( subkeyName, "_Rec" ))) {
+ _snprintf( registryPath, sizeof( registryPath ), "SYS:Services\\%s", subkeyName );
+ TempEntry.RegistryPath = registryPath;
+ OpenRegistryKey( &TempEntry, &subkeyHandle );
+ if (subkeyHandle != NULL) {
+ startValueLength = sizeof( startValue );
+ if (ReadRegistry( subkeyHandle,
+ L"Start",
+ REG_DWORD,
+ startValue,
+ &startValueLength )) {
+ NtClose( subkeyHandle );
+ if (startValueLength == SERVICE_SYSTEM_START ||
+ startValueLength == SERVICE_BOOT_START
+ ) {
+
+ //
+ // Driver located that should have been loaded at
+ // initialization time. Ensure in loaded module
+ // list.
+ //
+
+ if (!LookupModuleName( subkeyName, ModuleInfo )) {
+ if (EnableDisableDriver( subkeyName, FALSE )) {
+ DebugLog((DEB_TRACE_SETUP, " Disabled load of %s system init driver.\n", subkeyName ));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ subkey++;
+ }
+ NtClose( keyHandle );
+ }
+ else {
+ result = FALSE;
+ }
+
+ VirtualFree( ModuleInfo, 0, MEM_RELEASE );
+ return result;
+}
+
+
+BOOL bDebugCSRSS;
+
+BOOL
+InitializeDefaultRegistry(
+ PGLOBALS pGlobals
+ )
+{
+ DWORD cb;
+ CHAR cbuff[512];
+ PRTL_PROCESS_MODULES moduleInfo;
+
+
+ //
+ // See if we have done first boot of triple boot sequence.
+ //
+
+
+ cb = GetProfileStringA( AnsiWinlogon,
+ "DefaultSystem",
+ NULL,
+ WinlogonSystemVariable,
+ sizeof( WinlogonSystemVariable )
+ );
+
+ if (cb == 0) {
+
+ //
+ // Yes, see if we are doing second boot of triple boot
+ // sequence.
+ //
+
+ cbuff[ 0 ] = '\0';
+ cb = GetProfileStringA( AnsiWinlogon,
+ "Shell",
+ NULL,
+ cbuff,
+ sizeof( cbuff )
+ );
+
+ if (cb != 0 && !_stricmp( cbuff, "progman.exe" )) {
+
+ //
+ // No must be third or greater boot. See if they
+ // want to disable debugging the server.
+ //
+
+ cb = GetProfileStringA( AnsiWinlogon,
+ "DebugServerCommand",
+ "ntsd -p -1 -g -G",
+ cbuff,
+ sizeof( cbuff )
+ );
+
+ if (cb != 0 && (_stricmp( cbuff, "no" ) || bDebugCSRSS)) {
+ //
+ // No, start the debugger
+ //
+ UNICODE_STRING UniString;
+ STRING String;
+
+ if (bDebugCSRSS) {
+ strcpy( cbuff, "ntsd -p -1 -g -G" );
+ }
+
+ RtlInitAnsiString(&String,cbuff);
+ RtlAnsiStringToUnicodeString(&UniString,&String,TRUE);
+#if 0
+ ExecProcesses(L"DebugServerCommand",
+ UniString.Buffer,
+ APPLICATION_DESKTOP_NAME,
+ &pGlobals->UserProcessData,
+ HIGH_PRIORITY_CLASS,
+ STARTF_FORCEOFFFEEDBACK);
+#endif
+ RtlFreeUnicodeString(&UniString);
+ }
+ }
+ else
+ if (cb != 0 && strstr( cbuff, "winlogon.cmd" )) {
+ WriteProfileStringA( AnsiWinlogon, "AutoAdminLogon", "1" );
+
+ WriteProfileStringA( AnsiWinlogon,
+ "DefaultUserName",
+ "Administrator"
+ );
+
+ WriteProfileStringA( AnsiWinlogon,
+ "DefaultPassword",
+ ""
+ );
+
+ cb = sizeof( cbuff );
+ if (GetComputerNameA( cbuff, &cb )) {
+ WriteProfileStringA( AnsiWinlogon,
+ "DefaultDomainName",
+ cbuff
+ );
+ }
+ }
+
+ return FALSE;
+ }
+
+ TmppSetUnsecureDefaultDacl();
+ pLocalGlobals = pGlobals;
+ NetSetupGoingToRun = pGlobals->fExecuteSetup;
+
+ //
+ // Make sure we can see user (.default) portion of win.ini
+ //
+
+ if (!OpenProfileUserMapping()) {
+ DebugLog((DEB_TRACE_SETUP, " Unable to enable access to user specific portion of win.ini\n" ));
+ }
+
+ cb = SearchPathA(
+ NULL,
+ "net",
+ ".exe",
+ 512,
+ cbuff,
+ NULL
+ );
+ if ( cb && cb <= 512 ) {
+ NetFound = TRUE;
+ }
+ else {
+ NetFound = FALSE;
+ }
+
+ WriteProfileStringA( AnsiWinlogon,
+ "DefaultSystem",
+ NULL
+ );
+ WriteProfileStringA( AnsiWinlogon,
+ "System",
+ WinlogonSystemVariable
+ );
+
+ GetEnvironmentVariableA( "SystemRoot", InputFileName, sizeof( InputFileName ) );
+ strcat( InputFileName, "\\registry.ini" );
+
+ DebugLog((DEB_TRACE_SETUP, " Updating \\Registry and win.ini\n" ));
+ DebugLog((DEB_TRACE_SETUP, " with information from %s\n", InputFileName ));
+
+ if (!DisableFailedBuiltInDrivers( &moduleInfo )) {
+ DebugLog((DEB_TRACE_SETUP, " Failed to disable builtin drivers.\n" ));
+ }
+ else {
+ if (!DisableFailedSysInitDrivers( moduleInfo )) {
+ DebugLog((DEB_TRACE_SETUP, " Failed to disable system init drivers.\n" ));
+ }
+ }
+
+ DoFile();
+
+ //
+ // Set up the default username and domain so we logon as admin on next boot
+ //
+
+ WriteProfileStringA( AnsiWinlogon,
+ "DefaultUserName",
+ "Administrator"
+ );
+
+ WriteProfileStringA( AnsiWinlogon,
+ "DefaultDomainName",
+ SavedProductType == NtProductLanManNt ?
+ SavedDomainName : SavedMachineName
+ );
+
+ GenerateInitialCommandScript();
+
+ //
+ // All done accessing user (.default) portion of win.ini
+ //
+
+ CloseProfileUserMapping();
+
+ DebugLog((DEB_TRACE_SETUP, "Done updating. Rebooting to get changes.\n" ));
+ QuickReboot( pGlobals, FALSE );
+ return TRUE;
+}
+
+void
+QuickReboot(
+ PGLOBALS pGlobals,
+ BOOL RebootToAlternateOS
+ )
+{
+#ifdef i386
+ TCHAR szBuffer[ 64 ];
+
+ //
+ // Debug reboot facility to reboot directly into DOS by editing
+ // the users c:\boot.ini and changing the default boot OS to be
+ // whatever is in the root of C:, which is most likely DOS for
+ // people that are using NTLDR to dual boot. Only works for x86
+ // as MIPS uses ARCLOADER and it is not defined how to change its
+ // default operating system to load, other than through jzsetup.exe
+ //
+
+ if (RebootToAlternateOS) {
+ if (GetPrivateProfileString(TEXT("boot loader"),
+ TEXT("default"),
+ NULL,
+ szBuffer,
+ 64,
+ TEXT("c:\\boot.ini")
+ )
+ ) {
+ if (GetPrivateProfileString(WideWinlogon,
+ TEXT("DefaultAlternateOS"),
+ TEXT(""),
+ szBuffer,
+ 64,
+ NULL
+ )
+ ) {
+ WritePrivateProfileString(TEXT("boot loader"),
+ TEXT("default"),
+ szBuffer,
+ TEXT("c:\\boot.ini")
+ );
+ } else {
+#if DBG
+ DbgPrint( "WINLOGON: GetPrivateProfileString( %ws, %ws ) failed (%u)\n",
+ WideWinlogon,
+ TEXT("DefaultAlternateOS"),
+ GetLastError()
+ );
+#endif
+ }
+ }
+ else {
+#if DBG
+ DbgPrint( "WINLOGON: GetPrivateProfileString( %ws, %ws ) failed (%u)\n",
+ TEXT("boot loader"),
+ TEXT("default"),
+ GetLastError()
+ );
+#endif
+ }
+ }
+#endif // i386
+
+ WriteProfileStringW( NULL, NULL, NULL );
+ EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);
+ NtShutdownSystem(TRUE);
+ ASSERT(FALSE);
+}
+
+VOID
+TmppSetUnsecureDefaultDacl( VOID )
+
+{
+
+ NTSTATUS Status;
+ PSID WorldSid;
+ PACL Dacl;
+ HANDLE Token;
+
+ TOKEN_DEFAULT_DACL DefaultDacl;
+
+ SID_IDENTIFIER_AUTHORITY
+ WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
+
+
+
+
+
+ Status = RtlAllocateAndInitializeSid(
+ &WorldSidAuthority,
+ 1, //Sub authority count
+ SECURITY_WORLD_RID, //Sub authorities (up to 8)
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid
+ );
+
+
+ //
+ // Set our default protection so that regini won't protect
+ // registry keys it creates.
+ //
+
+ Dacl = RtlAllocateHeap( RtlProcessHeap(), 0, 256 );
+ ASSERT(Dacl != NULL);
+
+ Status = RtlCreateAcl( Dacl, 256, ACL_REVISION2);
+ ASSERT(NT_SUCCESS(Status));
+
+ Status = RtlAddAccessAllowedAce(
+ Dacl,
+ ACL_REVISION2,
+ (GENERIC_ALL ),
+ WorldSid
+ );
+ ASSERT(NT_SUCCESS(Status));
+
+
+ DefaultDacl.DefaultDacl = Dacl;
+
+
+ Status = NtOpenProcessToken(
+ NtCurrentProcess(),
+ (TOKEN_ADJUST_DEFAULT),
+ &Token
+ );
+ ASSERT(NT_SUCCESS(Status));
+
+
+ Status = NtSetInformationToken(
+ Token,
+ TokenDefaultDacl,
+ &DefaultDacl,
+ (ULONG)sizeof(TOKEN_DEFAULT_DACL)
+ );
+ ASSERT(NT_SUCCESS(Status));
+ Status = NtClose( Token );
+
+ RtlFreeHeap( RtlProcessHeap(), 0, Dacl );
+ RtlFreeSid( WorldSid );
+
+
+ return;
+
+}
+
+#endif // INIT_REGISTRY
+
+
+//
+// Open Registry key use base API. Same as OpenRegistryKey(),
+// but without error handling (since GUI may not be active).
+//
+
+HANDLE
+OpenNtRegKey(
+ WCHAR *UPath
+ )
+{
+ char *Path;
+ char FullPath[ 2 * MAX_PATH ];
+ ANSI_STRING AnsiPath;
+ UNICODE_STRING UnicodePath;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE Handle;
+ UNICODE_STRING UString;
+ ANSI_STRING AString;
+
+ RtlInitUnicodeString( &UString, UPath);
+ RtlUnicodeStringToAnsiString( &AString, &UString, TRUE);
+ Path = AString.Buffer;
+ if (!_strnicmp( Path, "USR:", 4 )) {
+ strcpy( FullPath, "\\Registry\\User\\.Default\\" );
+ Path += 4;
+ }
+ else
+ if (!_strnicmp( Path, "SYS:", 4 )) {
+ strcpy( FullPath, "\\Registry\\Machine\\System\\CurrentControlSet\\" );
+ Path += 4;
+ }
+ else {
+ FullPath[ 0 ] = '\0';
+ }
+ strcat( FullPath, Path );
+ RtlInitAnsiString( &AnsiPath, FullPath );
+ RtlAnsiStringToUnicodeString( &UnicodePath, &AnsiPath, TRUE );
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodePath,
+ OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+ NULL,
+ NULL
+ );
+ Status = NtOpenKey( &Handle,
+ MAXIMUM_ALLOWED,
+ &ObjectAttributes
+ );
+
+ RtlFreeUnicodeString( &UnicodePath );
+ RtlFreeAnsiString( &AString );
+
+ if (NT_SUCCESS( Status )) {
+ return Handle;
+ } else {
+ return NULL ;
+ }
+}
+
+
+BOOL
+ReadRegistry(
+ HANDLE KeyHandle, // Registry handle
+ WCHAR *ValueName, // Value to query
+ DWORD ValueType, // Value type expected
+ WCHAR *ValueData, // Value data if (multi-)string
+ DWORD *ValueLength // Length if string or value if REG_DWORD
+ )
+{
+ NTSTATUS Status;
+ UNICODE_STRING UnicodeString;
+ WCHAR ValueBuffer[ 512 ];
+ PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
+ ULONG ResultLength;
+
+ RtlInitUnicodeString( & UnicodeString, ValueName );
+ KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer ;
+ Status = NtQueryValueKey( KeyHandle,
+ &UnicodeString,
+ KeyValuePartialInformation,
+ KeyValueInformation,
+ sizeof ValueBuffer,
+ &ResultLength
+ );
+ if (!NT_SUCCESS( Status )) {
+ return FALSE;
+ }
+
+ if (KeyValueInformation->Type != ValueType) {
+ return FALSE ;
+ }
+
+ switch (KeyValueInformation->Type) {
+ case REG_MULTI_SZ:
+ case REG_SZ:
+ RtlMoveMemory( ValueData,
+ (PWSTR)KeyValueInformation->Data,
+ KeyValueInformation->DataLength
+ );
+ ValueData[ (KeyValueInformation->DataLength / sizeof( WCHAR )) - 1 ] = UNICODE_NULL;
+ *ValueLength = KeyValueInformation->DataLength;
+ break;
+
+ case REG_DWORD:
+ *ValueLength = *((DWORD *) KeyValueInformation->Data) ;
+ break;
+
+ default:
+ // We can't handle any other type.
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOL
+WriteRegistry(
+ HANDLE KeyHandle,
+ char *ValueName,
+ DWORD ValueType,
+ char *ValueData,
+ DWORD ValueLength
+ )
+{
+ char *s;
+ ANSI_STRING AnsiString;
+ UNICODE_STRING UnicodeString;
+ UNICODE_STRING UnicodeValueName;
+ DWORD ValueDword;
+ NTSTATUS Status;
+
+ if (ValueType == REG_SZ) {
+ if (!_strnicmp( ValueData, "REG_DWORD ", 10 )) {
+ Status = RtlCharToInteger( ValueData + 10, 0, &ValueDword );
+ if (!NT_SUCCESS( Status )) {
+ DeclareError( "Invalid integer\n" );
+ return FALSE;
+ }
+
+ ValueLength = sizeof( ValueDword );
+ ValueData = (char *)&ValueDword;
+ ValueType = REG_DWORD;
+ }
+ else {
+ if (strchr( ValueData, '%')) {
+ ValueType = REG_EXPAND_SZ;
+ }
+
+ RtlInitAnsiString( &AnsiString, ValueData );
+ ValueLength = 0;
+ }
+ }
+ else
+ if (ValueType == REG_MULTI_SZ) {
+ s = ValueData;
+ AnsiString.Buffer = ValueData;
+ while (*s) {
+ while (*s++) {
+ }
+ }
+
+ AnsiString.Length = (USHORT)(s - ValueData);
+ AnsiString.MaximumLength = (USHORT)(AnsiString.Length + 1);
+ ValueLength = 0;
+ }
+ else
+ if (ValueType == REG_BINARY) {
+ if (ValueLength == 0) {
+ DeclareError( "Invalid binary data\n" );
+ return FALSE;
+ }
+ }
+ else
+ if (ValueType == REG_DWORD) {
+ Status = RtlCharToInteger( ValueData, 0, &ValueDword );
+ if (!NT_SUCCESS( Status )) {
+ DeclareError( "Invalid integer\n" );
+ return FALSE;
+ }
+
+ ValueLength = sizeof( ValueDword );
+ ValueData = (char *)&ValueDword;
+ }
+ else {
+ DeclareError( "Invalid data type == %lx for %s\n",
+ ValueType,
+ ValueName ? ValueName : "(null)"
+ );
+
+ return FALSE;
+ }
+
+ if (ValueLength == 0) {
+ RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE );
+ ValueLength = UnicodeString.MaximumLength;
+ ValueData = (char *)UnicodeString.Buffer;
+ }
+ else {
+ UnicodeString.Buffer = NULL;
+ }
+
+ if (ValueName == NULL) {
+ RtlInitUnicodeString( &UnicodeValueName, NULL );
+ }
+ else {
+ RtlInitAnsiString( &AnsiString, ValueName );
+ RtlAnsiStringToUnicodeString( &UnicodeValueName, &AnsiString, TRUE );
+ }
+ Status = NtSetValueKey( KeyHandle,
+ &UnicodeValueName,
+ 0,
+ ValueType,
+ ValueData,
+ ValueLength
+ );
+
+ if (UnicodeValueName.Buffer != NULL) {
+ RtlFreeUnicodeString( &UnicodeValueName );
+ }
+
+ if (UnicodeString.Buffer != NULL) {
+ RtlFreeUnicodeString( &UnicodeString );
+ }
+
+ if (NT_SUCCESS( Status )) {
+ return TRUE;
+ }
+ else {
+ DeclareError( "NtSetValueKey( %wZ ) failed (Status == %lx)\n",
+ &UnicodeValueName,
+ Status
+ );
+
+ return FALSE;
+ }
+}
diff --git a/private/windows/gina/winlogon/regini.h b/private/windows/gina/winlogon/regini.h
new file mode 100644
index 000000000..a603a1abc
--- /dev/null
+++ b/private/windows/gina/winlogon/regini.h
@@ -0,0 +1,52 @@
+/****************************** Module Header ******************************\
+* Module Name: regini.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define apis user to implement default registry initialization
+*
+* History:
+* 05-01-92 Stevewo Created.
+\***************************************************************************/
+
+#if INIT_REGISTRY
+
+BOOL
+InitializeDefaultRegistry(
+ PGLOBALS pGlobals
+ );
+
+void
+QuickReboot(
+ PGLOBALS pGlobals,
+ BOOL RebootToAlternateOS
+ );
+
+#endif // INIT_REGISTRY
+
+ //
+ // Open Registry key use base API. Same as OpenRegistryKey(),
+ // but without error handling (since GUI may not be active).
+ //
+HANDLE
+OpenNtRegKey(
+ WCHAR *Path
+ );
+
+BOOL
+WriteRegistry(
+ HANDLE KeyHandle,
+ char *ValueName,
+ DWORD ValueType,
+ char *ValueData,
+ DWORD ValueLength
+ );
+
+BOOL
+ReadRegistry(
+ HANDLE KeyHandle, // Registry handle
+ WCHAR *ValueName, // Value to query
+ DWORD ValueType, // Value type expected
+ WCHAR *ValueData, // Value data if (multi-)string
+ DWORD *ValueLength // Length if string or value if REG_DWORD
+ );
diff --git a/private/windows/gina/winlogon/removabl.c b/private/windows/gina/winlogon/removabl.c
new file mode 100644
index 000000000..88450de45
--- /dev/null
+++ b/private/windows/gina/winlogon/removabl.c
@@ -0,0 +1,866 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ removabl.c
+
+Abstract:
+
+ Removable Media Services Module - This module contains services
+ related to the protection of removable media (e.g., floppies
+ and CD Roms) related to logon and logoff.
+
+
+Author:
+
+ Jim Kelly (JimK) Oct-19-1994
+
+Environment:
+
+ Part of Winlogon.
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+
+
+////////////////////////////////// Section ////////////////////////////////
+// //
+// Constants used in this module only. //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+#define RMVP_DRIVE_CD_ROM (1)
+#define RMVP_DRIVE_FLOPPY (2)
+
+//
+// Size of the buffer used to enumerate object directory
+// contents
+//
+
+#define RMVP_OBJDIR_ENUM_BUFFER_SIZE (1024)
+
+
+
+
+
+
+////////////////////////////////// Section ////////////////////////////////
+// //
+// Variables Global to this module. //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+PSID
+ RmvpLocalSystemSid,
+ RmvpAdministratorsSid;
+
+
+//
+// flags indicating whether or not we are configured to allocate
+// floppies and/or CDRoms.
+//
+
+BOOLEAN
+ RmvpAllocateFloppies = FALSE,
+ RmvpAllocateCDRoms = FALSE;
+
+
+
+
+
+////////////////////////////////// Section ////////////////////////////////
+// //
+// Prototypes of modules private to this module //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+VOID
+RmvpAllocateDevice(
+ IN HANDLE DeviceHandle,
+ IN PUNICODE_STRING DeviceName,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PUNICODE_STRING FsName,
+ IN OUT PHANDLE FsHandle
+ );
+
+BOOLEAN
+RmvpOpenDevice(
+ IN HANDLE Root,
+ IN POBJECT_DIRECTORY_INFORMATION Object,
+ IN ULONG DeviceType,
+ OUT PHANDLE Device
+ );
+
+
+
+
+
+////////////////////////////////// Section ////////////////////////////////
+// //
+// Services Exported By This Module //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+VOID
+RmvInitializeRemovableMediaSrvcs(
+ VOID
+ )
+/*++
+Routine Description:
+
+ Initialize RemovableMediaServices Module
+
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ NTSTATUS
+ Status;
+
+ SID_IDENTIFIER_AUTHORITY
+ NtAuthority = SECURITY_NT_AUTHORITY;
+
+
+ //
+ // See if we need to protect floppy and/or CDRom drives.
+ //
+
+ if (GetProfileInt( TEXT("Winlogon"), TEXT("AllocateFloppies"), 0) == 1) {
+ RmvpAllocateFloppies = TRUE;
+ }
+
+ if (GetProfileInt( TEXT("Winlogon"), TEXT("AllocateCDRoms"), 0) == 1) {
+ RmvpAllocateCDRoms = TRUE;
+ }
+
+
+ //
+ // Initialize needed well-known sids
+ //
+
+ Status = RtlAllocateAndInitializeSid( &NtAuthority,
+ 1,
+ SECURITY_LOCAL_SYSTEM_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &RmvpLocalSystemSid
+ );
+ ASSERT(NT_SUCCESS(Status));
+
+ Status = RtlAllocateAndInitializeSid( &NtAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &RmvpAdministratorsSid
+ );
+ ASSERT(NT_SUCCESS(Status));
+
+ return;
+}
+
+
+
+VOID
+RmvAllocateRemovableMedia(
+ IN PSID AllocatorId
+ )
+/*++
+Routine Description:
+
+ This routine must be called during the logon process.
+ Its purpose is to:
+
+ See if floppy and / or CD Rom allocation is enabled.
+ If so, then allocate the devices by:
+
+ Restricting TRAVERSE access to the devices, and
+
+ Forcing all handles to volumes open on those devices
+ to be made invalid.
+
+ Note that the work of finding and openning these devices must
+ be done at logon time rather than system initialization time
+ because of NT's ability to dynamically add devices while running.
+
+
+
+Arguments:
+
+ AllocatorId - Pointer to the SID to which the devices are
+ to be allocated.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ NTSTATUS
+ Status,
+ IgnoreStatus;
+
+ ACCESS_MASK
+ Access;
+
+ MYACE
+ Ace[3];
+
+ ACEINDEX
+ AceCount = 0;
+
+ PSECURITY_DESCRIPTOR
+ SecurityDescriptor;
+
+ ULONG
+ DriveType,
+ ReturnedLength,
+ Context = 0;
+
+ CHAR
+ Buffer[RMVP_OBJDIR_ENUM_BUFFER_SIZE];
+
+ HANDLE
+ DeviceHandle,
+ FatHandle = NULL,
+ CdfsHandle = NULL,
+ DirectoryHandle;
+
+
+ UNICODE_STRING
+ DirectoryName,
+ CdfsName,
+ FatfsName;
+
+ OBJECT_ATTRIBUTES
+ Attributes;
+
+ BOOLEAN
+ Opened;
+
+ POBJECT_DIRECTORY_INFORMATION
+ DirInfo;
+
+
+ RtlInitUnicodeString( &CdfsName, L"\\cdfs" );
+ RtlInitUnicodeString( &FatfsName, L"\\fat" );
+
+
+
+
+ //
+ // If there is nothing to allocate, then return.
+ //
+
+ if (!RmvpAllocateFloppies && !RmvpAllocateCDRoms) {
+ return;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // Technical Note:
+ //
+ // If I understand the way things work correctly, then there is
+ // a race condition that exists that we have to work around.
+ //
+ // The problem is that until a volume is mounted in a file-system
+ // that file system might not be loaded (and a corresponding device
+ // object may not exist). Therefore, we must not try to open a
+ // filesystem until we have opened a device object. For example,
+ // don't open FAT until we have opened \device\floppy0 AND PROTECTED
+ // IT AGAINST FUTURE TRAVERSE ACCESS.
+ //
+ // So, if you are looking at this routine and wondering why I don't
+ // open the FAT and CDFS file systems right away, it is in case they
+ // aren't loaded yet, but someone manages to squeek in a volume mount
+ // after I try to open the filesystems.
+ //
+ // What I believe will work is to open any floppy or cdrom devices
+ // I find, then change who has traverse access to them, then open
+ // the corresponding filesystem object IF IT HASN'T ALREADY BEEN
+ // OPENED. Once a filesystem object is opened, there is no need
+ // to close it and re-open it.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+
+
+
+ //
+ // Set up the protection to be applied to the removable device objects
+ //
+ // System: FILE_READ_ATTRIBUTES | READ_CONTROL | WRITE_DAC | SYNCHRONIZE
+ // AllocationId: RWE
+ //
+ // We apply the restrictive System access to the object so that network shares
+ // don't gain access (by nature of using a handle to the volume root
+ // that LM server keeps).
+ //
+
+ Access = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE;
+ SetMyAce( &(Ace[AceCount]), AllocatorId, Access, 0 );
+ AceCount++;
+ //Access &= ~FILE_TRAVERSE;
+ Access = (FILE_READ_ATTRIBUTES | READ_CONTROL | WRITE_DAC | SYNCHRONIZE);
+ SetMyAce( &(Ace[AceCount]), RmvpLocalSystemSid, Access, 0 );
+ AceCount++;
+
+#ifdef TRMV
+ {
+ //
+ // This is needed for our test program (an interactive program
+ // run in user mode) so that we don't set protection on the device
+ // preventing us from changing the protection.
+ //
+ // THIS CODE IS NOT INCLUDED WHEN THIS MODULE IS PART OF WINLOGON.
+ //
+
+ ACCESS_MASK
+ TestorAccess = (FILE_READ_ATTRIBUTES | READ_CONTROL | WRITE_DAC | SYNCHRONIZE);
+
+
+ SetMyAce( &(Ace[AceCount]), RmvpAdministratorsSid, TestorAccess, 0 );
+ AceCount++;
+ }
+#endif // TEST REMOVABLE
+
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor != NULL) {
+
+
+ //
+ // We find floppies and or CD Roms by enumerating the objects in
+ // the "\Device" object container and selecting the ones that
+ // start with "floppy" followed by a number or "cdrom" followed
+ // by a number. Even after finding such an object, we want to be
+ // sure it is a Device object and then open it and query it to
+ // make sure it is really a floppy or cdrom. The reason I say this
+ // is because you will find names like "floppyControllerEvent" in
+ // the \device container.
+ //
+
+ RtlInitUnicodeString( &DirectoryName, L"\\Device" );
+ InitializeObjectAttributes( &Attributes,
+ &DirectoryName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+
+ Status = NtOpenDirectoryObject( &DirectoryHandle,
+ STANDARD_RIGHTS_READ |
+ DIRECTORY_QUERY |
+ DIRECTORY_TRAVERSE,
+ &Attributes );
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "Failed to open \\Device object container. Status: %#x\n", Status ));
+ }
+#endif //DBG
+ ASSERT(NT_SUCCESS(Status));
+
+
+ //
+ // Loop through the directory querying device objects
+ //
+
+ Status = NtQueryDirectoryObject( DirectoryHandle,
+ Buffer,
+ sizeof(Buffer),
+ TRUE, // one entry at a time for now
+ TRUE,
+ &Context,
+ &ReturnedLength );
+
+#if DBG
+ if (!NT_SUCCESS( Status )) {
+ if (Status != STATUS_NO_MORE_ENTRIES) {
+ DebugLog((DEB_ERROR, "failed to query directory object, status: 0x%lx\n", Status));
+ }
+ }
+#endif //DBG
+
+ while ( NT_SUCCESS(Status) ) {
+
+ //
+ // Point to the first record in the buffer, we are guaranteed to have
+ // one otherwise Status would have been NO_MORE_ENTRIES
+ //
+
+ DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
+ while (DirInfo->Name.Length != 0) {
+
+ //
+ // For every record in the buffer compare it's name with the ones we're
+ // looking for
+ //
+
+ if (RmvpAllocateFloppies) {
+ Opened = RmvpOpenDevice( DirectoryHandle,
+ DirInfo,
+ RMVP_DRIVE_FLOPPY,
+ &DeviceHandle
+ );
+ if (Opened) {
+ RmvpAllocateDevice( DeviceHandle, &DirInfo->Name, SecurityDescriptor, &FatfsName, &FatHandle );
+ NtClose( DeviceHandle );
+ }
+ }
+
+ if (RmvpAllocateCDRoms) {
+ Opened = RmvpOpenDevice( DirectoryHandle,
+ DirInfo,
+ RMVP_DRIVE_CD_ROM,
+ &DeviceHandle
+ );
+ if (Opened) {
+ RmvpAllocateDevice( DeviceHandle, &DirInfo->Name, SecurityDescriptor, &CdfsName, &CdfsHandle );
+ NtClose( DeviceHandle );
+ }
+ }
+
+ //
+ // Advance DirInfo to the next entry
+ //
+
+ DirInfo ++;
+
+ } //end_while (more names in buffer)
+
+
+ //
+ // Get the next block of entries
+ //
+
+ Status = NtQueryDirectoryObject( DirectoryHandle,
+ Buffer,
+ sizeof(Buffer),
+ // LATER FALSE,
+ TRUE, // one entry at a time for now
+ FALSE,
+ &Context,
+ &ReturnedLength );
+
+ } //end_while (enumeration succeeded)
+
+ //
+ // We no longer need handles to FAT or CDFS (if they were opened).
+ //
+
+ if (FatHandle != NULL) {
+ IgnoreStatus = NtClose( FatHandle );
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+ }
+ if (CdfsHandle != NULL) {
+ IgnoreStatus = NtClose( CdfsHandle );
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+ }
+
+
+
+
+
+
+ //
+ // Free up the security descriptor
+ //
+
+ DeleteSecurityDescriptor(SecurityDescriptor);
+
+ } else {
+ DebugLog((DEB_ERROR, "failed to create removable media security descriptor"));
+ }
+
+
+ return;
+}
+
+
+
+
+////////////////////////////////// Section ////////////////////////////////
+// //
+// Services Private To This Module //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+VOID
+RmvpAllocateDevice(
+ IN HANDLE DeviceHandle,
+ IN PUNICODE_STRING DeviceName,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PUNICODE_STRING FsName,
+ IN OUT PHANDLE FsHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to allocate the device opened by DeviceHandle.
+
+ Allocation entails changing the protection on the device (the new
+ protection is passed in, but is expected to restrict TRAVERSE access),
+ and notifying the filesystem to invalidate all handles to the
+ volumes on the device.
+
+
+
+Arguments:
+
+ DeviceHandle - handle to the device being allocated. This must be opened
+ for WRITE_DAC access.
+
+ DeviceName - The name of the device being allocated.
+
+ SecurityDescriptor - New protection to assign to the device. Only the
+ Dacl of this security descriptor is used.
+
+ FsName - The name of the file system that owns responsibility for the
+ device. This is expected to be either "\\fat" or
+ "\\cdfs".
+
+ FsHandle - Pointer to a handle to the filesystem. If the handle
+ value is NULL, then it is assumed that the filesystem has not yet
+ been opened. In that case, this routine will attempt to open the
+ filesystem after assigning protection to the device.
+
+
+Return Value:
+
+ TRUE - indicates the device was successfully opened.
+
+ FALSE - indicates the device was NOT successfully opened.
+
+
+--*/
+{
+
+ NTSTATUS
+ Status;
+
+ OBJECT_ATTRIBUTES
+ Attributes;
+
+ IO_STATUS_BLOCK
+ IoStatusBlock;
+
+ BOOLEAN
+ WasEnabled;
+
+ //
+ // Change the protection on the device to restrict traverse access.
+ //
+
+ Status = NtSetSecurityObject( DeviceHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor);
+ ASSERT(NT_SUCCESS(Status));
+
+
+ //
+ // If the File system isn't yet open, then do so now.
+ //
+
+ if ((*FsHandle) == NULL) {
+
+ //
+ // Turn on the TCB privilege for our open to the filesystem to work.
+ //
+
+ Status = RtlAdjustPrivilege( SE_TCB_PRIVILEGE,
+ TRUE, // Enable
+ FALSE, // Client
+ &WasEnabled
+ );
+ ASSERT(NT_SUCCESS(Status));
+
+ if (NT_SUCCESS(Status)) {
+ InitializeObjectAttributes( &Attributes,
+ FsName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ Status = NtOpenFile( FsHandle,
+ (SYNCHRONIZE | FILE_READ_ATTRIBUTES),
+ &Attributes,
+ &IoStatusBlock,
+ (FILE_SHARE_READ | FILE_SHARE_WRITE),
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ //
+ // If no volumes have ever been mounted in the file system,
+ // then the file system may not be loaded. So, this error
+ // can not be considered serious.
+ //
+
+ (*FsHandle) = NULL; // In case garbage was put in our out parameter
+
+ if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+ DebugLog((DEB_ERROR, "Failed to open <%wZ>. Status: %#x\n", FsName, Status));
+ }
+ }
+
+
+ //
+ // Now restore the privilege (if necessary)
+ //
+
+ if (!WasEnabled) {
+ Status = RtlAdjustPrivilege( SE_TCB_PRIVILEGE,
+ FALSE, // Disable
+ FALSE, // Client
+ &WasEnabled
+ );
+ ASSERT(NT_SUCCESS(Status));
+ }
+ }
+ }
+
+ if ((*FsHandle) != NULL) {
+
+ //
+ // Notify the file system that it needs to invalidate the
+ // passed in volume.
+ //
+
+ Status = NtFsControlFile( (*FsHandle),
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_INVALIDATE_VOLUMES,
+ &DeviceHandle, //DavidGoe is going to define a real structure to pass here
+ sizeof(HANDLE),
+ NULL,
+ 0 );
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "Failed to remove handles from:\n"
+ " device: <%wZ>\n"
+ " file system: <%wZ>\n"
+ " Status: 0x%lx\n\n",
+ DeviceName, FsName, Status));
+ ASSERT(NT_SUCCESS(Status));
+ }
+#endif //DBG
+
+ }
+
+ return;
+}
+
+
+
+BOOLEAN
+RmvpOpenDevice(
+ IN HANDLE Root,
+ IN POBJECT_DIRECTORY_INFORMATION Object,
+ IN ULONG DeviceType,
+ OUT PHANDLE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to open a handle to a device whose name starts
+ with the string specified in the Prefix parameter.
+
+
+Arguments:
+
+ Root - handle to an object directory to be used as the root
+ when openning the device object. That is, the name specified
+ in the Object parameter is relative to the object this handle
+ refers to.
+
+ Object - Contains the name of the object and the name of the type
+ of the object. If the name of the type is not "device" and the
+ name of the object does not start with the string passed in
+ the Prefix parameter, then the open is not attempted.
+
+ DeviceType - specifies the type of device the object is expected to
+ be. Valid values are:
+
+ RMVP_DRIVE_CD_ROM
+ RMVP_DRIVE_FLOPPY
+
+ Device - Receives the handle to the device object (upon success).
+
+
+Return Value:
+
+ TRUE - indicates the device was successfully opened.
+
+ FALSE - indicates the device was NOT successfully opened.
+
+
+--*/
+{
+ NTSTATUS
+ IgnoreStatus,
+ Status;
+
+ OBJECT_ATTRIBUTES
+ ObjectAttributes;
+
+ IO_STATUS_BLOCK
+ IoStatusBlock;
+
+ UNICODE_STRING
+ Prefix,
+ DeviceName;
+
+ HANDLE
+ FileHandle;
+
+ FILE_FS_DEVICE_INFORMATION
+ DeviceInfo;
+
+
+
+ //RmvpPrint("Attempting to open Object<%wZ>, Type<%wZ>\n", &Object->Name, &Object->TypeName);
+
+
+ RtlInitUnicodeString( &DeviceName, L"Device" );
+
+ //
+ // If the type is not "Device" then we aren't interested in this object
+ //
+
+ if (!RtlEqualUnicodeString(&Object->TypeName, &DeviceName, TRUE)) {
+ return(FALSE);
+ }
+
+
+ //
+ // If the object name doesn't have the right prefix, then we aren't
+ // interested in this object
+ //
+
+ if (DeviceType == RMVP_DRIVE_CD_ROM) {
+
+ RtlInitUnicodeString( &Prefix, L"cdrom" );
+ if (!RtlPrefixUnicodeString( &Prefix, &Object->Name, TRUE)) {
+ return(FALSE);
+ }
+ } else {
+
+ ASSERT( DeviceType == RMVP_DRIVE_FLOPPY);
+ RtlInitUnicodeString( &Prefix, L"floppy" );
+ if (!RtlPrefixUnicodeString( &Prefix, &Object->Name, TRUE)) {
+ return(FALSE);
+ }
+ }
+
+
+
+ //
+ // Looks promising. Open the Device object
+ //
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &Object->Name,
+ OBJ_CASE_INSENSITIVE,
+ Root,
+ NULL
+ );
+
+ Status = NtOpenFile( &FileHandle,
+ (ACCESS_MASK)FILE_READ_ATTRIBUTES |
+ WRITE_DAC |
+ READ_CONTROL |
+ SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "Can't open for allocate: Object<%wZ> Type<%wZ>\n"
+ " Status: 0x%lx\n", &Object->Name, &Object->TypeName, Status));
+ }
+#endif //DBG
+
+ if (NT_SUCCESS( Status )) {
+
+ Status = NtQueryVolumeInformationFile( FileHandle,
+ &IoStatusBlock,
+ &DeviceInfo,
+ sizeof( DeviceInfo ),
+ FileFsDeviceInformation
+ );
+
+ if (NT_SUCCESS( Status )) {
+
+ //
+ // See if its the right kind of beast and has the right name prefix
+ //
+
+ if (DeviceType == RMVP_DRIVE_CD_ROM) {
+ if (DeviceInfo.DeviceType == FILE_DEVICE_CD_ROM) {
+ (*Device) = FileHandle;
+ DebugLog((DEB_TRACE, "Winlogon: Allocating CD Rom:\n"
+ " object: <%wZ>\n"
+ " type: <%wZ>\n",
+ &Object->Name, &Object->TypeName ));
+ return(TRUE);
+ }
+
+ } else {
+ ASSERT( DeviceType == RMVP_DRIVE_FLOPPY);
+ if ((DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE)) {
+ (*Device) = FileHandle;
+ DebugLog((DEB_TRACE, "Winlogon: Allocating floppy:\n"
+ " object: <%wZ>\n"
+ " type: <%wZ>\n",
+ &Object->Name, &Object->TypeName ));
+ return(TRUE);
+ }
+ }
+ }
+
+ IgnoreStatus = NtClose(FileHandle);
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+ }
+
+ return(FALSE);
+
+}
+
diff --git a/private/windows/gina/winlogon/removabl.h b/private/windows/gina/winlogon/removabl.h
new file mode 100644
index 000000000..5304d05a2
--- /dev/null
+++ b/private/windows/gina/winlogon/removabl.h
@@ -0,0 +1,43 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ removabl.h
+
+Abstract:
+
+ This file contains prototype definitions of services exported
+ from removabl.c
+
+
+Author:
+
+ Jim Kelly (JimK) Oct-19-1994
+
+Environment:
+
+ Part of Winlogon.
+
+Revision History:
+
+
+--*/
+
+#ifndef _REMOVABL_
+#define _REMOVABL_
+
+VOID
+RmvInitializeRemovableMediaSrvcs(
+ VOID
+ );
+
+VOID
+RmvAllocateRemovableMedia(
+ IN PSID AllocatorId
+ );
+
+
+
+#endif //_REMOVABL_
diff --git a/private/windows/gina/winlogon/res.rc b/private/windows/gina/winlogon/res.rc
new file mode 100644
index 000000000..890be2fd3
--- /dev/null
+++ b/private/windows/gina/winlogon/res.rc
@@ -0,0 +1,35 @@
+/****************************** Module Header ******************************\
+* Module Name: res.rc
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Main winlogon resource file.
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+
+#include "winlogon.h"
+
+#include "strings.rc"
+
+#include "sysshut.dlg"
+
+#include "dialogs.dlg"
+
+#include "win31mig.dlg"
+
+#include "wlevents.rc"
+
+IDD_SHUTDOWN_BITMAP ICON "shutdown.ico"
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows NT Logon Application"
+#define VER_INTERNALNAME_STR "winlogon\0"
+#define VER_ORIGINALFILENAME_STR "WINLOGON.EXE"
+
+#include "common.ver"
diff --git a/private/windows/gina/winlogon/sas.c b/private/windows/gina/winlogon/sas.c
new file mode 100644
index 000000000..f28bdd805
--- /dev/null
+++ b/private/windows/gina/winlogon/sas.c
@@ -0,0 +1,524 @@
+/****************************** Module Header ******************************\
+* Module Name: sas.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Support routines to implement processing of the secure attention sequence
+*
+* Users must always press the SAS key sequence before entering a password.
+* This module catches the key press and forwards a SAS message to the
+* correct winlogon window.
+*
+* History:
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Internal Prototypes
+LONG SASWndProc(
+ HWND hwnd,
+ UINT message,
+ DWORD wParam,
+ LONG lParam);
+
+BOOL SASCreate(
+ HWND hwnd);
+
+BOOL SASDestroy(
+ HWND hwnd);
+
+
+// Global used to hold the window handle of the SAS window.
+static HWND hwndSAS = NULL;
+// LATER this hwndSAS will have to go in instance data when we have multiple threads
+
+// Global for SAS window class name
+static PWCHAR szSASClass = TEXT("SAS window class");
+
+
+#if DBG
+#define DEFAULT_QUICK_REBOOT 1
+#else
+#define DEFAULT_QUICK_REBOOT 0
+#endif
+
+#define SHELL_RESTART_TIMER_ID 100
+
+/***************************************************************************\
+* SASInit
+*
+* Initialises this module.
+*
+* Creates a window to receive the SAS and registers the
+* key sequence as a hot key.
+*
+* Returns TRUE on success, FALSE on failure.
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL SASInit(
+ PGLOBALS pGlobals)
+{
+ WNDCLASS wc;
+
+ if (hwndSAS != NULL) {
+ DebugLog((DEB_ERROR, "SAS module already initialized !!"));
+ return(FALSE);
+ }
+
+ //
+ // Register the notification window class
+ //
+
+ wc.style = CS_SAVEBITS;
+ wc.lpfnWndProc = (WNDPROC)SASWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = pGlobals->hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = szSASClass;
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ hwndSAS = CreateWindowEx(0L, szSASClass, TEXT("SAS window"),
+ WS_OVERLAPPEDWINDOW,
+ 0, 0, 0, 0,
+ NULL, NULL, pGlobals->hInstance, NULL);
+
+ if (hwndSAS == NULL)
+ return FALSE;
+
+ //
+ // Store our globals pointer in the window user data
+ //
+
+ SetWindowLong(hwndSAS, GWL_USERDATA, (LONG)pGlobals);
+
+ //
+ // Register this window with windows so we get notified for
+ // screen-saver startup and user log-off
+ //
+ if (!SetLogonNotifyWindow(pGlobals->WindowStation.hwinsta, hwndSAS)) {
+ DebugLog((DEB_ERROR, "Failed to set logon notify window"));
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* SASTerminate
+*
+* Terminates this module.
+*
+* Unregisters the SAS and destroys the SAS windows
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+VOID SASTerminate(VOID)
+{
+ DestroyWindow(hwndSAS);
+
+ // Reset our globals
+ hwndSAS = NULL;
+}
+
+
+/***************************************************************************\
+* SASWndProc
+*
+* Window procedure for the SAS window.
+*
+* This window registers the SAS hotkey sequence, and forwards any hotkey
+* messages to the current winlogon window. It does this using a
+* timeout module function. i.e. every window should register a timeout
+* even if it's 0 if they want to get SAS messages.
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+LONG SASWndProc(
+ HWND hwnd,
+ UINT message,
+ DWORD wParam,
+ LONG lParam)
+{
+ PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hwnd, GWL_USERDATA);
+
+ switch (message)
+ {
+
+ case WM_CREATE:
+ if (!SASCreate(hwnd))
+ {
+ return(TRUE); // Fail creation
+ }
+ return(FALSE); // Continue creating window
+
+ case WM_DESTROY:
+ DebugLog(( DEB_TRACE, "SAS Window Shutting down?\n"));
+#if DBG
+ DebugBreak();
+#endif
+ SASDestroy(hwnd);
+ return(0);
+
+ case WM_HOTKEY:
+ if (wParam == 1)
+ {
+ QuickReboot(pGlobals, TRUE);
+ return(0);
+ }
+
+#if DBG
+ if (wParam == 2)
+ {
+ switch (pGlobals->WindowStation.ActiveDesktop)
+ {
+ case Desktop_Winlogon:
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
+ break;
+ case Desktop_Application:
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+ break;
+ }
+ return(0);
+ }
+ if (wParam == 3)
+ {
+ DebugBreak();
+ return(0);
+ }
+#endif
+
+ if (wParam == 4)
+ {
+ PGINASESSION pGina = pGlobals->pGina;
+ WCHAR szTaskMgr[] = L"taskmgr.exe";
+
+ DebugLog((DEB_TRACE, "Starting taskmgr.exe.\n"));
+
+ if (pGlobals->UserLoggedOn ) {
+ pGina->pWlxStartApplication(pGina->pGinaContext,
+ APPLICATION_DESKTOP_PATH,
+ pGlobals->UserProcessData.pEnvironment,
+ szTaskMgr);
+ }
+ return(0);
+ }
+
+ CADNotify(pGlobals, WLX_SAS_TYPE_CTRL_ALT_DEL);
+ return(0);
+
+ case WM_LOGONNOTIFY: // A private notification from Windows
+
+ DebugLog((DEB_TRACE_SAS, "LOGONNOTIFY message %d\n", wParam ));
+
+ switch (wParam)
+ {
+
+
+ case LOGON_LOGOFF:
+
+#if DBG
+ DebugLog((DEB_TRACE_SAS, "\tWINLOGON : %s\n", (lParam & EWX_WINLOGON_CALLER) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tSYSTEM : %s\n", (lParam & EWX_SYSTEM_CALLER) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tSHUTDOWN : %s\n", (lParam & EWX_SHUTDOWN) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tREBOOT : %s\n", (lParam & EWX_REBOOT) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tPOWEROFF : %s\n", (lParam & EWX_POWEROFF) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tFORCE : %s\n", (lParam & EWX_FORCE) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tOLD_SYSTEM : %s\n", (lParam & EWX_WINLOGON_OLD_SYSTEM) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tOLD_SHUTDOWN : %s\n", (lParam & EWX_WINLOGON_OLD_SHUTDOWN) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tOLD_REBOOT : %s\n", (lParam & EWX_WINLOGON_OLD_REBOOT) ? "True" : "False"));
+ DebugLog((DEB_TRACE_SAS, "\tOLD_POWEROFF : %s\n", (lParam & EWX_WINLOGON_OLD_POWEROFF) ? "True" : "False"));
+#endif
+
+ //
+ // If there is an exit windows in progress, reject this
+ // message if it is not our own call coming back. This
+ // prevents people from calling ExitWindowsEx repeatedly
+ //
+
+ if ( ExitWindowsInProgress &&
+ ( !( lParam & EWX_WINLOGON_CALLER ) ) )
+ {
+ break;
+
+ }
+ pGlobals->LogoffFlags = lParam;
+ CADNotify(pGlobals, WLX_SAS_TYPE_USER_LOGOFF);
+ break;
+
+ case LOGON_INPUT_TIMEOUT:
+ //
+ // Notify the current window
+ //
+ // ForwardMessage(pGlobals, WM_SCREEN_SAVER_TIMEOUT, 0, 0);
+ CADNotify(pGlobals, WLX_SAS_TYPE_SCRNSVR_TIMEOUT);
+ break;
+
+ case LOGON_RESTARTSHELL:
+ //
+ // Restart the shell after X seconds
+ //
+ // We don't restart the shell for the following conditions:
+ //
+ // 1) No one is logged on
+ // 2) We are in the process of logging off
+ // (logoffflags will be non-zero)
+ // 3) The shell exiting gracefully
+ // (Exit status is in lParam. 1 = graceful)
+ // 4) A new user has logged on after the request
+ // to restart the shell.
+ // (in the case of autoadminlogon, the new
+ // user could be logged on before the restart
+ // request comes through).
+ //
+
+ if (!pGlobals->UserLoggedOn ||
+ pGlobals->LogoffFlags ||
+ (lParam == 1) ||
+ (pGlobals->TickCount > (DWORD)GetMessageTime())) {
+
+ break;
+ }
+
+ SetTimer (hwnd, SHELL_RESTART_TIMER_ID, 2000, NULL);
+ break;
+ }
+
+ return(0);
+
+ case WM_TIMER:
+ {
+ PGINASESSION pGina;
+ LONG lResult;
+ HKEY hKey;
+ BOOL bRestart = TRUE;
+ DWORD dwType, dwSize;
+
+
+ //
+ // Restart the shell
+ //
+
+ if (wParam != SHELL_RESTART_TIMER_ID) {
+ break;
+ }
+
+ KillTimer (hwnd, SHELL_RESTART_TIMER_ID);
+
+
+ //
+ // Check if we should restart the shell
+ //
+
+ lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ WINLOGON_KEY,
+ 0,
+ KEY_READ,
+ &hKey);
+
+ if (lResult == ERROR_SUCCESS) {
+
+ dwSize = sizeof(bRestart);
+ RegQueryValueEx (hKey,
+ TEXT("AutoRestartShell"),
+ NULL,
+ &dwType,
+ (LPBYTE) &bRestart,
+ &dwSize);
+
+ RegCloseKey (hKey);
+ }
+
+
+ if (bRestart) {
+ PWCH pchData;
+ PWSTR pszTok;
+
+ DebugLog((DEB_TRACE, "Restarting user's shell.\n"));
+
+
+ pGina = pGlobals->pGina;
+
+ pchData = AllocAndGetPrivateProfileString(APPLICATION_NAME,
+ SHELL_KEY,
+ TEXT("explorer.exe"),
+ NULL);
+
+ if (!pchData) {
+ break;
+ }
+
+ pszTok = wcstok(pchData, TEXT(","));
+ while (pszTok)
+ {
+ if (*pszTok == TEXT(' '))
+ {
+ while (*pszTok++ == TEXT(' '))
+ ;
+ }
+
+
+ if (pGina->pWlxStartApplication(pGina->pGinaContext,
+ APPLICATION_DESKTOP_PATH,
+ pGlobals->UserProcessData.pEnvironment,
+ pszTok)) {
+
+ ReportWinlogonEvent(pGlobals,
+ EVENTLOG_INFORMATION_TYPE,
+ EVENT_SHELL_RESTARTED,
+ 0,
+ NULL,
+ 1,
+ pszTok);
+ }
+
+ pszTok = wcstok(NULL, TEXT(","));
+ }
+
+ Free(pchData);
+ }
+
+ }
+ break;
+
+ default:
+ return DefWindowProc(hwnd, message, wParam, lParam);
+
+ }
+
+ return 0L;
+}
+
+BOOL bRegisteredQuickReboot;
+BOOL bRegisteredDesktopSwitching;
+BOOL bRegisteredWinlogonBreakpoint;
+BOOL bRegisteredTaskmgr;
+
+
+/***************************************************************************\
+* SASCreate
+*
+* Does any processing required for WM_CREATE message.
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+BOOL SASCreate(
+ HWND hwnd)
+{
+ // Register the SAS unless we are told not to.
+
+
+ if (GetProfileInt( APPNAME_WINLOGON, VARNAME_AUTOLOGON, 0 ) != 2) {
+ if (!RegisterHotKey(hwnd, 0, MOD_CONTROL | MOD_ALT, VK_DELETE)) {
+ DebugLog((DEB_ERROR, "failed to register SAS"));
+ return(FALSE); // Fail creation
+ }
+ }
+
+
+ //
+ // (Ctrl+Alt+Shift+Del) hotkey to reboot into DOS directly
+ //
+
+ if (GetProfileInt( APPNAME_WINLOGON, VARNAME_ENABLEQUICKREBOOT, DEFAULT_QUICK_REBOOT) != 0) {
+ if (!RegisterHotKey(hwnd, 1, MOD_CONTROL | MOD_ALT | MOD_SHIFT, VK_DELETE)) {
+ DebugLog((DEB_ERROR, "failed to register quick reboot SAS"));
+ bRegisteredQuickReboot = FALSE;
+ } else {
+ bRegisteredQuickReboot = TRUE;
+ }
+ }
+
+#if DBG
+ //
+ // (Ctrl+Alt+Tab) will switch between desktops
+ //
+ if (GetProfileInt( APPNAME_WINLOGON, VARNAME_ENABLEDESKTOPSWITCHING, 0 ) != 0) {
+ if (!RegisterHotKey(hwnd, 2, MOD_CONTROL | MOD_ALT, VK_TAB)) {
+ DebugLog((DEB_ERROR, "failed to register desktop switch SAS"));
+ bRegisteredDesktopSwitching = FALSE;
+ } else {
+ bRegisteredDesktopSwitching = TRUE;
+ }
+ }
+
+
+ if (WinlogonInfoLevel & DEB_COOL_SWITCH) {
+ if (!RegisterHotKey(hwnd, 3, MOD_CONTROL | MOD_ALT | MOD_SHIFT, VK_TAB)) {
+ DebugLog((DEB_ERROR, "failed to register breakpoint SAS"));
+ bRegisteredWinlogonBreakpoint = FALSE;
+ } else {
+ bRegisteredWinlogonBreakpoint = TRUE;
+ }
+ }
+#endif
+
+ //
+ // (Ctrl+Shift+Esc) will start taskmgr
+ //
+
+ if (!RegisterHotKey(hwnd, 4, MOD_CONTROL | MOD_SHIFT, VK_ESCAPE)) {
+ DebugLog((DEB_ERROR, "failed to register taskmgr hotkey"));
+ bRegisteredTaskmgr = FALSE;
+ } else {
+ bRegisteredTaskmgr = TRUE;
+ }
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* SASDestroy
+*
+* Does any processing required for WM_DESTROY message.
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+BOOL SASDestroy(
+ HWND hwnd)
+{
+ // Unregister the SAS
+ UnregisterHotKey(hwnd, 0);
+
+ if (bRegisteredQuickReboot) {
+ UnregisterHotKey(hwnd, 1);
+ }
+ if (bRegisteredDesktopSwitching) {
+ UnregisterHotKey(hwnd, 2);
+ }
+
+#if DBG
+ if (bRegisteredWinlogonBreakpoint) {
+ UnregisterHotKey(hwnd, 3);
+ }
+#endif
+
+ if (bRegisteredTaskmgr) {
+ UnregisterHotKey(hwnd, 4);
+ }
+
+
+ return(TRUE);
+}
diff --git a/private/windows/gina/winlogon/sas.h b/private/windows/gina/winlogon/sas.h
new file mode 100644
index 000000000..979b3d875
--- /dev/null
+++ b/private/windows/gina/winlogon/sas.h
@@ -0,0 +1,24 @@
+/****************************** Module Header ******************************\
+* Module Name: sas.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Defines apis to handle Secure Attention Key Sequence
+*
+* History:
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+//
+// Exported function prototypes
+//
+
+
+BOOL SASInit(
+ PGLOBALS pGlobals
+ );
+
+VOID SASTerminate(
+ VOID
+ );
+
diff --git a/private/windows/gina/winlogon/scrnsave.c b/private/windows/gina/winlogon/scrnsave.c
new file mode 100644
index 000000000..0ce16f5c9
--- /dev/null
+++ b/private/windows/gina/winlogon/scrnsave.c
@@ -0,0 +1,981 @@
+/****************************** Module Header ******************************\
+* Module Name: scrnsave.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Support routines to implement screen-saver-invokation
+*
+* History:
+* 01-23-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define LPTSTR LPWSTR
+
+//
+// Define the structure used to pass data into the screen-saver control dialog
+//
+typedef struct {
+ PGLOBALS pGlobals;
+ BOOL fSecure;
+ BOOL fEnabled;
+ LPTSTR ScreenSaverName;
+ DWORD ProcessId; // Screen-saver process id
+ DWORD SasInterrupt; // Sas interrupt, if any
+ BOOL WeKilledIt;
+ HANDLE hProcess;
+ POBJECT_MONITOR Monitor;
+ int ReturnValue;
+} SCREEN_SAVER_DATA;
+typedef SCREEN_SAVER_DATA *PSCREEN_SAVER_DATA;
+
+// Parameters added to screen saver command line
+TCHAR Parameters[] = TEXT(" /s");
+
+//
+// Private prototypes
+//
+
+BOOL WINAPI
+ScreenSaverDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+ScreenSaverDlgInit(
+ HWND hDlg
+ );
+
+BOOL
+StartScreenSaver(
+ PSCREEN_SAVER_DATA ScreenSaverData
+ );
+
+BOOL
+KillScreenSaver(
+ PSCREEN_SAVER_DATA ScreenSaverData,
+ int ReturnValue
+ );
+
+BOOL
+StartScreenSaverMonitor(
+ HWND hDlg
+ );
+
+VOID
+DeleteScreenSaverMonitor(
+ HWND hDlg
+ );
+
+DWORD ScreenSaverMonitorThread(
+ LPVOID lpThreadParameter
+ );
+
+BOOL
+GetScreenSaverInfo(
+ PSCREEN_SAVER_DATA ScreenSaverData
+ );
+
+VOID
+DeleteScreenSaverInfo(
+ PSCREEN_SAVER_DATA ScreenSaverData
+ );
+
+// Message sent by the monitor thread to main thread window
+#define WM_SCREEN_SAVER_ENDED (WM_USER + 10)
+
+
+/***************************************************************************\
+* ScreenSaverEnabled
+*
+* Checks that a screen-saver is enabled for the current logged-on user.
+*
+* Returns : TRUE if the current user has an enabled screen-saver, otherwise FALSE
+*
+* 10-15-92 Davidc Created.
+\***************************************************************************/
+
+BOOL
+ScreenSaverEnabled(
+ PGLOBALS pGlobals)
+{
+ SCREEN_SAVER_DATA ScreenSaverData;
+ BOOL Enabled;
+
+ ScreenSaverData.pGlobals = pGlobals;
+ GetScreenSaverInfo(&ScreenSaverData);
+
+ Enabled = ScreenSaverData.fEnabled;
+
+ DeleteScreenSaverInfo(&ScreenSaverData);
+
+ return(Enabled);
+}
+
+/***************************************************************************\
+* ValidateScreenSaver
+*
+* Confirm that the screen saver executable exists and it enabled.
+*
+* Returns :
+* TRUE - the screen-saver is ready.
+* FALSE - the screen-saver does not exist or is not enabled.
+*
+* 01-23-91 ericflo Created.
+\***************************************************************************/
+BOOL
+ValidateScreenSaver(
+ PSCREEN_SAVER_DATA ssd)
+{
+ WIN32_FIND_DATA fd;
+ HANDLE hFile;
+ BOOL Enabled;
+ LPTSTR lpTempSS, lpEnd;
+ WCHAR szFake[2];
+ LPTSTR lpFake;
+
+
+ //
+ // Check if the screen saver enabled
+ //
+
+ Enabled = ssd->fEnabled;
+
+ //
+ // If the screen saver is enabled, confirm that the executable exists.
+ //
+
+ if (Enabled) {
+
+ //
+ // The screen save executable name contains some parameters after
+ // it. We need to allocate a temporary buffer, remove the arguments
+ // and test if the executable exists.
+ //
+
+ lpTempSS = (LPTSTR) GlobalAlloc (GPTR,
+ sizeof (TCHAR) * (lstrlen (ssd->ScreenSaverName) + 1));
+
+ if (!lpTempSS) {
+ return FALSE;
+ }
+
+ //
+ // Copy the filename to the temp buffer.
+ //
+
+ lstrcpy (lpTempSS, ssd->ScreenSaverName);
+
+
+ //
+ // Since we know how many arguments were added to the executable,
+ // we can get the string length, move that many characters in from
+ // the right and insert a NULL.
+ //
+
+ lpEnd = lpTempSS + lstrlen (lpTempSS);
+ *(lpEnd - lstrlen (Parameters)) = TEXT('\0');
+
+ //
+ // Test to see if the executable exists.
+ //
+
+ if (SearchPath(NULL, lpTempSS, NULL, 2, szFake, &lpFake) == 0)
+ {
+ Enabled = FALSE;
+
+ DebugLog((DEB_TRACE, "Screen Saver <%S> does not exist. Error is %d",
+ lpTempSS, GetLastError()));
+
+ }
+
+ //
+ // Clean up.
+ //
+
+ GlobalFree (lpTempSS);
+ }
+
+ return (Enabled);
+}
+
+/***************************************************************************\
+* RunScreenSaver
+*
+* Starts the appropriate screen-saver for the current user in the correct
+* context and waits for it to complete.
+* If the user presses the SAS, we kill the screen-saver and return.
+* If a logoff notification comes in, we kill the screen-saver and return.
+*
+* Returns :
+* DLG_SUCCESS - the screen-saver completed successfully.
+* DLG_FAILURE - unable to run the screen-saver
+* DLG_LOCK_WORKSTATION - the screen-saver completed successfully and
+* was designated secure.
+* DLG_LOGOFF - the screen-saver was interrupted by a user logoff notification
+*
+* Normally the original desktop is switched back to and the desktop lock
+* returned to its original state on exit.
+* If the return value is DLG_LOCK_WORKSTATION or DLG_LOGOFF - the winlogon
+* desktop has been switched to and the desktop lock retained.
+*
+* 01-23-91 Davidc Created.
+\***************************************************************************/
+
+int
+RunScreenSaver(
+ PGLOBALS pGlobals,
+ BOOL WindowStationLocked,
+ BOOL AllowFastUnlock)
+{
+ HDESK hdeskPrevious;
+ int Result;
+ SCREEN_SAVER_DATA ScreenSaverData;
+ BOOL Success;
+ WinstaState PriorState;
+ DWORD BeginTime;
+ DWORD EndTime;
+
+
+
+ //
+ // If no one is logged on, make SYSTEM the user.
+ //
+ if (!pGlobals->UserLoggedOn)
+ {
+
+
+ //
+ // Toggle the locks, in case the OPENLOCK is still set from
+ // a prior logoff.
+ //
+
+ UnlockWindowStation(pGlobals->WindowStation.hwinsta);
+ LockWindowStation(pGlobals->WindowStation.hwinsta);
+ }
+ //
+ // Create and open the app desktop.
+ //
+ if (!(pGlobals->WindowStation.hdeskScreenSaver =
+ CreateDesktop((LPTSTR)SCREENSAVER_DESKTOP_NAME,
+ NULL, NULL, 0, MAXIMUM_ALLOWED, NULL))) {
+ DebugLog((DEB_TRACE, "Failed to create screen saver desktop\n"));
+ return(DLG_FAILURE);
+ }
+
+ //
+ // Fill in screen-saver data structure
+ //
+ ZeroMemory( &ScreenSaverData, sizeof( ScreenSaverData ) );
+
+ ScreenSaverData.pGlobals = pGlobals;
+
+ if (GetScreenSaverInfo(&ScreenSaverData)) {
+ if (!ValidateScreenSaver(&ScreenSaverData)) {
+
+ DeleteScreenSaverInfo(&ScreenSaverData);
+
+ CloseDesktop(pGlobals->WindowStation.hdeskScreenSaver);
+
+ return (DLG_FAILURE);
+ }
+ }
+
+ //
+ // Update windowstation lock so screen saver can start
+ //
+
+ if (!pGlobals->pGina->pWlxScreenSaverNotify(
+ pGlobals->pGina->pGinaContext,
+ &ScreenSaverData.fSecure ))
+ {
+ DebugLog((DEB_TRACE, "GINA DLL rejected screen saver\n"));
+
+ DeleteScreenSaverInfo( &ScreenSaverData );
+ CloseDesktop( pGlobals->WindowStation.hdeskScreenSaver );
+
+ //
+ // If no one is logged on, remove SYSTEM as the user.
+ //
+ return(DLG_FAILURE);
+ }
+
+
+ pGlobals->ScreenSaverActive = TRUE;
+
+ if ( ScreenSaverData.fSecure )
+ {
+
+ PriorState = pGlobals->WinlogonState;
+ pGlobals->WinlogonState = Winsta_Locked;
+
+ DebugLog((DEB_TRACE_STATE, "RunScreenSaver: Setting state to %s\n",
+ GetState(Winsta_Locked)));
+ }
+
+ //
+ // Switch to screen-saver desktop
+ //
+ if (!SetActiveDesktop(&pGlobals->WindowStation, Desktop_ScreenSaver)) {
+
+ DebugLog((DEB_TRACE, "Failed to switch to screen saver desktop\n"));
+
+ pGlobals->ScreenSaverActive = FALSE;
+
+ DeleteScreenSaverInfo(&ScreenSaverData);
+ CloseDesktop(pGlobals->WindowStation.hdeskScreenSaver);
+
+ //
+ // If no one is logged on, remove SYSTEM as the user.
+ //
+ return(DLG_FAILURE);
+ }
+
+ //
+ // Stash begin time
+ //
+
+ BeginTime = GetTickCount();
+
+ //
+ // Start the screen-saver
+ //
+ if (!StartScreenSaver(&ScreenSaverData)) {
+
+ DebugLog((DEB_TRACE, "Failed to start screen-saver\n"));
+
+ if (ScreenSaverData.fSecure && pGlobals->UserLoggedOn)
+ {
+ Result = WLX_SAS_ACTION_LOCK_WKSTA;
+ }
+ else
+ {
+ Result = DLG_FAILURE;
+ }
+ DeleteScreenSaverInfo(&ScreenSaverData);
+ SetActiveDesktop(&pGlobals->WindowStation, pGlobals->WindowStation.PreviousDesktop);
+ pGlobals->ScreenSaverActive = FALSE;
+ CloseDesktop(pGlobals->WindowStation.hdeskScreenSaver);
+
+ //
+ // If no one is logged on, remove SYSTEM as the user.
+ //
+ return(Result);
+ }
+
+ //
+ // Initialize the sas type to report
+ //
+
+ ScreenSaverData.SasInterrupt = WLX_SAS_TYPE_SCRNSVR_ACTIVITY;
+
+ //
+ // Summon the dialog that monitors the screen-saver
+ //
+ Result = WlxSetTimeout( pGlobals, TIMEOUT_NONE);
+
+ Result = WlxDialogBoxParam( pGlobals,
+ pGlobals->hInstance,
+ (LPTSTR)IDD_CONTROL,
+ NULL, ScreenSaverDlgProc,
+ (LONG)&ScreenSaverData);
+
+ EndTime = GetTickCount();
+
+
+ if (EndTime <= BeginTime)
+ {
+ //
+ // TickCount must have wrapped around:
+ //
+
+ EndTime += (0xFFFFFFFF - BeginTime);
+ }
+ else
+ {
+ EndTime -= BeginTime;
+ }
+
+ //
+ // If the screen saver ran for less than the default period, don't enforce
+ // the lock.
+ //
+ if (ScreenSaverData.fSecure && pGlobals->UserLoggedOn)
+ {
+
+ if (AllowFastUnlock &&
+ (EndTime < (GetProfileInt( APPLICATION_NAME,
+ LOCK_GRACE_PERIOD_KEY,
+ LOCK_DEFAULT_VALUE) * 1000)))
+ {
+ Result = WLX_SAS_ACTION_NONE;
+ pGlobals->WinlogonState = PriorState;
+ }
+ else
+ {
+ Result = WLX_SAS_ACTION_LOCK_WKSTA;
+ }
+
+ }
+
+ DebugLog((DEB_TRACE, "Screensaver completed, SasInterrupt == %d\n",
+ ScreenSaverData.SasInterrupt));
+
+
+
+ //
+ // Set up desktop and windowstation lock appropriately. If we got a logoff,
+ // or we're supposed to lock the workstation, switch back to the winlogon
+ // desktop. Otherwise, go back to the users current desktop.
+ //
+
+ if ((ScreenSaverData.SasInterrupt == WLX_SAS_TYPE_USER_LOGOFF) ||
+ (Result == WLX_SAS_ACTION_LOCK_WKSTA) ) {
+
+ //
+ // Switch to the winlogon desktop and retain windowstation lock
+ //
+ Success = SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+
+ } else {
+
+ //
+ // Switch to previous desktop and retore lock to previous state
+ //
+ SetActiveDesktop(&pGlobals->WindowStation, pGlobals->WindowStation.PreviousDesktop);
+
+
+ //
+ // Tickle the messenger so it will display any queue'd messages.
+ // (This call is a kind of NoOp).
+ //
+ TickleMessenger();
+ }
+
+ //
+ // We are no longer active (our knowledge of the desktop state is correct),
+ // let SASRouter know, so any future SAS's will be sent correctly.
+ //
+
+ pGlobals->ScreenSaverActive = FALSE;
+ //
+ // If we killed it, it means we got a SAS and killed the screen saver.
+ // we need to repost the SAS so that whomever invoked the screen saver
+ // can catch it and pass it off to the gina. Note, we special case
+ // WLX_SAS_TYPE_USER_LOGOFF below, because WlxSasNotify filters it out,
+ // and we really need to return as the result code...
+ //
+ if ( ScreenSaverData.WeKilledIt &&
+ (ScreenSaverData.SasInterrupt != WLX_SAS_TYPE_SCRNSVR_ACTIVITY) )
+ {
+ if ( ScreenSaverData.SasInterrupt == WLX_SAS_TYPE_USER_LOGOFF )
+ {
+ //
+ // So HandleLoggedOn() will know what to do:
+ //
+
+ pGlobals->SasType = WLX_SAS_TYPE_USER_LOGOFF ;
+ Result = WLX_SAS_ACTION_LOGOFF ;
+ }
+ else
+ {
+ WlxSasNotify( pGlobals, ScreenSaverData.SasInterrupt );
+ }
+ }
+
+ DeleteScreenSaverInfo(&ScreenSaverData);
+
+ if (!CloseDesktop(pGlobals->WindowStation.hdeskScreenSaver)) {
+ DebugLog((DEB_TRACE, "Failed to close screen saver desktop!\n\n"));
+ } else
+ pGlobals->WindowStation.hdeskScreenSaver = NULL;
+
+ //
+ // Update windowstation locks to reflect correct state.
+ //
+
+
+ return(Result);
+}
+
+
+/***************************************************************************\
+* FUNCTION: ScreenSaverDlgProc
+*
+* PURPOSE: Processes messages for the screen-saver control dialog
+*
+* DIALOG RETURNS : DLG_FAILURE if dialog could not be created
+* DLG_SUCCESS if the screen-saver ran correctly and
+* has now completed.
+* DLG_LOGOFF() if the screen-saver was interrupted by
+* a logoff notification.
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL WINAPI
+ScreenSaverDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PSCREEN_SAVER_DATA pScreenSaverData = (PSCREEN_SAVER_DATA)GetWindowLong(hDlg, GWL_USERDATA);
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+ SetWindowLong(hDlg, GWL_USERDATA, lParam);
+
+ if (!ScreenSaverDlgInit(hDlg)) {
+ EndDialog(hDlg, DLG_FAILURE);
+
+ }
+
+ //
+ // Tell the mapping layer that we're a winlogon window, so we
+ // can handle our own timeouts.
+ //
+
+ SetMapperFlag(hDlg, MAPPERFLAG_WINLOGON);
+
+ EnableSasMessages( hDlg );
+
+ return(TRUE);
+
+ case WLX_WM_SAS:
+ //
+ // Just kill the screen-saver, the monitor thread will notice that
+ // the process has ended and send us a message
+ //
+
+ //
+ // Actually, stash the Sas code away, so that who ever invoked us
+ // can use it.
+
+
+ pScreenSaverData->SasInterrupt = wParam;
+ pScreenSaverData->WeKilledIt = TRUE;
+
+ KillScreenSaver(pScreenSaverData, DLG_SUCCESS);
+
+ DisableSasMessages();
+
+ return(TRUE);
+
+
+ case WM_OBJECT_NOTIFY:
+
+ DeleteScreenSaverMonitor(hDlg);
+
+ EndDialog(hDlg, pScreenSaverData->ReturnValue);
+ return(TRUE);
+ }
+
+ // We didn't process this message
+ return FALSE;
+}
+
+
+/***************************************************************************\
+* FUNCTION: ScreenSaverDlgInit
+*
+* PURPOSE: Handles initialization of screen-saver control dialog
+* Actually starts the screen-saver and puts the id of the
+* screen-saver process in the screen-saver data structure.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+ScreenSaverDlgInit(
+ HWND hDlg
+ )
+{
+ PSCREEN_SAVER_DATA ScreenSaverData = (PSCREEN_SAVER_DATA)GetWindowLong(hDlg, GWL_USERDATA);
+
+ //
+ // Initialize our return value
+ //
+ ScreenSaverData->ReturnValue = DLG_SUCCESS;
+
+
+ //
+ // Start the thread that will wait for the screen-saver to finish
+ //
+ if (!StartScreenSaverMonitor(hDlg)) {
+
+ DebugLog((DEB_TRACE, "Failed to start screen-saver monitor thread\n"));
+ KillScreenSaver(ScreenSaverData, DLG_FAILURE);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: StartScreenSaver
+*
+* PURPOSE: Creates the screen-saver process
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* On successful return, the ProcessId field in our global data structure
+* is set to the screen-saver process id
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+StartScreenSaver(
+ PSCREEN_SAVER_DATA ScreenSaverData
+ )
+{
+ HANDLE hThread;
+ HANDLE hProcess;
+
+
+ //
+ // Try and exec the screen-saver app
+ //
+ if (!StartSystemProcess(ScreenSaverData->ScreenSaverName,
+ SCREENSAVER_DESKTOP_PATH,
+ CREATE_SUSPENDED | CREATE_SEPARATE_WOW_VDM |
+ IDLE_PRIORITY_CLASS,
+ STARTF_SCREENSAVER,
+ ScreenSaverData->pGlobals->UserProcessData.pEnvironment,
+ FALSE,
+ &hProcess,
+ &hThread) )
+ {
+ DebugLog((DEB_ERROR, "Failed to start screen saver %ws, %d\n",
+ ScreenSaverData->ScreenSaverName, GetLastError()));
+ return(FALSE);
+ }
+
+ if (ScreenSaverData->pGlobals->UserLoggedOn)
+ {
+ WlxAssignShellProtection(
+ ScreenSaverData->pGlobals,
+ ScreenSaverData->pGlobals->UserProcessData.UserToken,
+ hProcess,
+ hThread);
+
+ }
+
+ ResumeThread(hThread);
+ CloseHandle(hThread);
+
+ ScreenSaverData->hProcess = hProcess;
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+* FUNCTION: KillScreenSaver
+*
+* PURPOSE: Terminates the screen-saver process
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+KillScreenSaver(
+ PSCREEN_SAVER_DATA ScreenSaverData,
+ int ReturnValue
+ )
+{
+ HANDLE hProcess;
+ BOOL bRet;
+
+ //
+ // Store the return value to be used by the dlg proc when the notification
+ // arrives from the monitor thread that the SS has ended.
+ //
+
+ ScreenSaverData->ReturnValue = ReturnValue;
+
+ if (ScreenSaverData->hProcess != INVALID_HANDLE_VALUE)
+ {
+ bRet = TerminateProcess(ScreenSaverData->hProcess, STATUS_SUCCESS);
+ if (!bRet)
+ {
+ DebugLog((DEB_TRACE, "Failed to terminate screen-saver process, error = %d\n", GetLastError()));
+ }
+
+ CloseObjectMonitorObject( ScreenSaverData->Monitor );
+
+ }
+
+// if (ScreenSaverData->Monitor)
+// {
+// DeleteObjectMonitor( ScreenSaverData->Monitor, FALSE );
+// }
+
+ ScreenSaverData->hProcess = INVALID_HANDLE_VALUE;
+
+ return(bRet);
+}
+
+
+/***************************************************************************\
+* FUNCTION: StartScreenSaverMonitor
+*
+* PURPOSE: Creates a thread that waits for the screen-saver to terminate
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+StartScreenSaverMonitor(
+ HWND hDlg
+ )
+{
+ PSCREEN_SAVER_DATA ScreenSaverData = (PSCREEN_SAVER_DATA)GetWindowLong(hDlg, GWL_USERDATA);
+
+ //
+ // Create a monitor object to watch the screen-saver process
+ //
+
+ ScreenSaverData->Monitor = CreateObjectMonitor(ScreenSaverData->hProcess,
+ hDlg, 0);
+
+ if (ScreenSaverData->Monitor == NULL) {
+ DebugLog((DEB_TRACE, "Failed to create screen-saver monitor object\n"));
+ return(FALSE);
+ }
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+* FUNCTION: DeleteScreenSaverMonitor
+*
+* PURPOSE: Cleans up resources used by screen-saver monitor
+*
+* RETURNS: Nothing
+*
+* HISTORY:
+*
+* 01-11-93 Davidc Created.
+*
+\***************************************************************************/
+
+VOID
+DeleteScreenSaverMonitor(
+ HWND hDlg
+ )
+{
+ PSCREEN_SAVER_DATA ScreenSaverData = (PSCREEN_SAVER_DATA)GetWindowLong(hDlg, GWL_USERDATA);
+ POBJECT_MONITOR Monitor = ScreenSaverData->Monitor;
+
+ //
+ // Delete the object monitor
+ //
+
+ CloseObjectMonitorObject( Monitor );
+
+ DeleteObjectMonitor(Monitor, FALSE);
+
+}
+
+
+/***************************************************************************\
+* FUNCTION: GetScreenSaverInfo
+*
+* PURPOSE: Gets the name of the screen-saver that should be run. Also whether
+* the user wanted the screen-saver to be secure. These values are
+* filled in in the ScreenSaver data structure on return.
+*
+* If there is no current user logged on or if we fail to get the
+* user's preferred screen-saver info, we default to the system
+* secure screen-saver.
+*
+* RETURNS: TRUE on success
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+GetScreenSaverInfo(
+ PSCREEN_SAVER_DATA ScreenSaverData
+ )
+{
+ BOOL Success = FALSE;
+ TCHAR SystemScreenSaverName[MAX_STRING_BYTES];
+ WCHAR ExpandedName[MAX_PATH];
+ DWORD ScreenSaverLength;
+ DWORD ExpandedSize;
+
+
+ //
+ // Get the default system screen-saver name
+ //
+ LoadString(NULL, IDS_SYSTEM_SCREEN_SAVER_NAME, SystemScreenSaverName, sizeof(SystemScreenSaverName));
+
+
+ //
+ // Open the ini file mapping layer in the current user's context
+ //
+
+ if (!OpenIniFileUserMapping(ScreenSaverData->pGlobals))
+ {
+ DebugLog((DEB_ERROR, "Failed to open user profile mapping!\n"));
+ }
+
+ //
+ // Try and get the user screen-saver program name
+ //
+
+ ScreenSaverData->ScreenSaverName = AllocAndGetPrivateProfileString(
+ SCREEN_SAVER_INI_SECTION,
+ SCREEN_SAVER_FILENAME_KEY,
+ SystemScreenSaverName, // default
+ SCREEN_SAVER_INI_FILE);
+
+ if (ScreenSaverData->ScreenSaverName == NULL) {
+ DebugLog((DEB_TRACE, "Failed to get screen-saver name\n"));
+ goto Exit;
+ }
+
+ ScreenSaverLength = lstrlen(ScreenSaverData->ScreenSaverName);
+
+ //
+ // Figure out how big based on the expanded environment variables, if any.
+ // subtract one, since Expand returns the # characters, plus the \0.
+ //
+ ExpandedSize = ExpandEnvironmentStrings(ScreenSaverData->ScreenSaverName,
+ ExpandedName,
+ MAX_PATH) - 1;
+
+ if (ExpandedSize != ScreenSaverLength )
+ {
+ //
+ // Well, we expanded to something other than what we had originally.
+ // So, alloc anew and do the parameter thing right now.
+ //
+
+ Free(ScreenSaverData->ScreenSaverName);
+ ScreenSaverData->ScreenSaverName = Alloc( (ExpandedSize +
+ lstrlen(Parameters) + 1) *
+ sizeof(WCHAR) );
+
+ if (!ScreenSaverData->ScreenSaverName)
+ {
+ DebugLog((DEB_WARN, "No memory for screensaver\n"));
+ goto Exit;
+ }
+
+ wcscpy( ScreenSaverData->ScreenSaverName,
+ ExpandedName);
+ wcscpy( &ScreenSaverData->ScreenSaverName[ExpandedSize],
+ Parameters);
+
+ }
+ else
+ {
+ //
+ // Always add some fixed screen-saver parameters
+ //
+
+ ScreenSaverData->ScreenSaverName = ReAlloc(
+ ScreenSaverData->ScreenSaverName,
+ (lstrlen(ScreenSaverData->ScreenSaverName) +
+ lstrlen(Parameters) + 1)
+ * sizeof(TCHAR));
+ if (ScreenSaverData->ScreenSaverName == NULL) {
+ DebugLog((DEB_TRACE, "Realloc of screen-saver name failed\n"));
+ goto Exit;
+ }
+
+ lstrcat(ScreenSaverData->ScreenSaverName, Parameters);
+
+ }
+
+ //
+ // Find out if the screen-saver should be secure
+ //
+
+ ScreenSaverData->fSecure = (GetPrivateProfileInt(
+ SCREEN_SAVER_INI_SECTION,
+ SCREEN_SAVER_SECURE_KEY,
+ (DWORD)FALSE, // default to non-secure
+ SCREEN_SAVER_INI_FILE) != 0);
+
+ //
+ // Find out if the screen-saver is enabled
+ //
+ ScreenSaverData->fEnabled = (GetProfileInt(
+ WINDOWS_INI_SECTION,
+ SCREEN_SAVER_ENABLED_KEY,
+ (DWORD)FALSE // default to not-enabled
+ ) != 0);
+
+ Success = TRUE;
+
+Exit:
+
+ //
+ // Close the ini file mapping - this closes the user registry key
+ //
+
+ (VOID)CloseIniFileUserMapping(ScreenSaverData->pGlobals);
+
+ return(Success);
+}
+
+
+/***************************************************************************\
+* FUNCTION: DeleteScreenSaverInfo
+*
+* PURPOSE: Frees up any space allocate by screen-saver data structure
+*
+* RETURNS: Nothing
+*
+* HISTORY:
+*
+* 11-17-92 Davidc Created.
+*
+\***************************************************************************/
+
+VOID
+DeleteScreenSaverInfo(
+ PSCREEN_SAVER_DATA ScreenSaverData
+ )
+{
+ if (ScreenSaverData->ScreenSaverName != NULL) {
+ Free(ScreenSaverData->ScreenSaverName);
+ }
+}
diff --git a/private/windows/gina/winlogon/scrnsave.h b/private/windows/gina/winlogon/scrnsave.h
new file mode 100644
index 000000000..3172b1a93
--- /dev/null
+++ b/private/windows/gina/winlogon/scrnsave.h
@@ -0,0 +1,27 @@
+/****************************** Module Header ******************************\
+* Module Name: scrnsave.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Secure Attention Key Sequence
+*
+* History:
+* 01-23-91 Davidc Created.
+\***************************************************************************/
+
+//
+// Exported function prototypes
+//
+
+BOOL
+ScreenSaverEnabled(
+ PGLOBALS pGlobals
+ );
+
+int
+RunScreenSaver(
+ PGLOBALS pGlobals,
+ BOOL WindowStationLocked,
+ BOOL AllowFastUnlock
+ );
+
diff --git a/private/windows/gina/winlogon/secutil.c b/private/windows/gina/winlogon/secutil.c
new file mode 100644
index 000000000..8189a8a2f
--- /dev/null
+++ b/private/windows/gina/winlogon/secutil.c
@@ -0,0 +1,2676 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: secutil.c
+//
+// Contents: Security Utilities
+//
+// Classes:
+//
+// Functions:
+//
+// History: 8-25-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// 'Constants' used in this module only.
+//
+SID_IDENTIFIER_AUTHORITY gSystemSidAuthority = SECURITY_NT_AUTHORITY;
+SID_IDENTIFIER_AUTHORITY gLocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
+PSID gLocalSid; // Initialized in 'InitializeSecurityGlobals'
+PSID gAdminSid; // Initialized in 'InitializeSecurityGlobals'
+PSID pWinlogonSid;
+
+typedef struct _MYACELIST {
+ DWORD Total;
+ DWORD Active;
+ DWORD WinlogonOnly;
+ MYACE * Aces;
+ DWORD TotalSids;
+ DWORD ActiveSids;
+ PSID * Sids;
+} MYACELIST, * PMYACELIST;
+
+
+//
+// Define all access to windows objects
+//
+
+#define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \
+ DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | \
+ DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | \
+ DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \
+ DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)
+
+#define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \
+ WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \
+ WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \
+ WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | \
+ WINSTA_READSCREEN | \
+ STANDARD_RIGHTS_REQUIRED)
+
+#define WINSTA_ATOMS (WINSTA_ACCESSGLOBALATOMS | \
+ WINSTA_ACCESSCLIPBOARD )
+
+//
+// Private prototypes
+//
+
+BOOL
+InitializeWindowsSecurity(
+ PGLOBALS pGlobals
+ );
+
+VOID
+InitializeSecurityGlobals(
+ VOID
+ );
+
+PVOID
+CreateAccessAllowedAce(
+ PSID Sid,
+ ACCESS_MASK AccessMask,
+ UCHAR AceFlags,
+ UCHAR InheritFlags
+ );
+
+VOID
+DestroyAce(
+ PVOID Ace
+ );
+
+PMYACELIST
+CreateAceList(
+ DWORD Count);
+
+BOOL
+InitializeWinstaSecurity(
+ PWinstaDescription pWinsta);
+
+/***************************************************************************\
+* InitializeSecurity
+*
+* Initializes the security module
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+BOOL
+InitializeSecurity(
+ PGLOBALS pGlobals
+ )
+{
+ //
+ // Set up our module globals
+ //
+ InitializeSecurityGlobals();
+
+ pWinlogonSid = pGlobals->WinlogonSid;
+
+
+ //
+ // Initialize the removable medial module
+ //
+
+ RmvInitializeRemovableMediaSrvcs();
+
+
+ //
+ // Initialize windows security aspects
+ //
+ if (!InitializeWindowsSecurity(pGlobals)) {
+ DebugLog((DEB_ERROR, "failed to initialize windows security\n"));
+ return(FALSE);
+ }
+
+ //
+ // Change user to 'system'
+ //
+ if (!SecurityChangeUser(pGlobals, NULL, NULL, pWinlogonSid, FALSE)) {
+ DebugLog((DEB_ERROR, "failed to set user to system\n"));
+ return(FALSE);
+ }
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+* InitializeWindowsSecurity
+*
+* Initializes windows specific parts of security module
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+BOOL
+InitializeWindowsSecurity(
+ PGLOBALS pGlobals
+ )
+{
+
+ //
+ // Register with windows so we can create windowstation etc.
+ //
+ if (!RegisterLogonProcess((DWORD)NtCurrentTeb()->ClientId.UniqueProcess, TRUE)) {
+ DebugLog((DEB_ERROR, "could not register itself as logon process\n"));
+ return(FALSE);
+ }
+
+ //
+ // Create and open the windowstation
+ //
+ if (!(pGlobals->WindowStation.hwinsta = CreateWindowStationW(WINDOW_STATION_NAME,
+ 0, MAXIMUM_ALLOWED, NULL))) {
+ DebugLog((DEB_ERROR, "could not create windowstation\n"));
+ return(FALSE);
+ }
+ pGlobals->WindowStation.pszWinsta = WINDOW_STATION_NAME;
+
+ //
+ // Associate winlogon with this window-station
+ //
+ if (!SetProcessWindowStation(pGlobals->WindowStation.hwinsta)) {
+ DebugLog((DEB_ERROR, "failed to set process window-station\n"));
+ return(FALSE);
+ }
+
+#if 0
+ //
+ // Set up window-station security (no user access yet)
+ //
+ if (!SetWindowStationSecurity(pGlobals, NULL)) {
+ DebugLog((DEB_ERROR, "failed to set window-station security\n"));
+ return(FALSE);
+ }
+#endif
+
+ if ( !InitializeWinstaSecurity( &pGlobals->WindowStation ) )
+ {
+ DebugLog((DEB_ERROR, "failed to init winsta security\n" ));
+ return( FALSE );
+ }
+
+#ifdef LATER // put the window-station lock back here when windows allows us to create desktops with the lock
+ //
+ // Lock the window-station now before we create any desktops
+ //
+ if (LockWindowStation(pGlobals->hwinsta) == WSS_ERROR) {
+ DebugLog((DEB_ERROR, "failed to lock window-station\n"));
+ return(FALSE);
+ }
+#endif
+ //
+ // Create and open the desktops.
+ // Pass in NULL for the default display
+ //
+
+ if (!(pGlobals->WindowStation.hdeskWinlogon = CreateDesktop((LPTSTR)WINLOGON_DESKTOP_NAME,
+ NULL, NULL, 0, MAXIMUM_ALLOWED, NULL))) {
+ DebugLog((DEB_ERROR, "Failed to create winlogon desktop\n"));
+ return(FALSE);
+ }
+
+ if (!(pGlobals->WindowStation.hdeskApplication = CreateDesktop((LPTSTR)APPLICATION_DESKTOP_NAME,
+ NULL, NULL, 0, MAXIMUM_ALLOWED, NULL))) {
+ DebugLog((DEB_ERROR, "Failed to create application desktop\n"));
+ return(FALSE);
+ }
+
+ //
+ // Make sure that this thread is started on the logon desktop. This
+ // is to ensure that apps will not be able to see its threadinfo
+ // data.
+ //
+
+ SetThreadDesktop(pGlobals->WindowStation.hdeskWinlogon);
+ GetDesktopWindow();
+
+ if (SetThreadDesktop(pGlobals->WindowStation.hdeskApplication))
+ {
+ pGlobals->WindowStation.hwndAppDesktop = GetDesktopWindow();
+ SetThreadDesktop(pGlobals->WindowStation.hdeskWinlogon);
+ }
+ else
+ {
+ DebugLog((DEB_WARN, "Could not set thread desktop to app desktop, %d\n", GetLastError()));
+ }
+
+ pGlobals->WindowStation.hdeskScreenSaver = NULL;
+
+ //
+ // Set desktop security (no user access yet)
+ //
+ if (!SetWinlogonDesktopSecurity(pGlobals->WindowStation.hdeskWinlogon, pWinlogonSid)) {
+ DebugLog((DEB_ERROR, "Failed to set winlogon desktop security\n"));
+ return(FALSE);
+ }
+ if (!SetUserDesktopSecurity(pGlobals->WindowStation.hdeskApplication, NULL, pWinlogonSid)) {
+ DebugLog((DEB_ERROR, "Failed to set application desktop security\n"));
+ return(FALSE);
+ }
+
+ //
+ // Associate winlogon with its desktop
+ //
+ if (!SetThreadDesktop(pGlobals->WindowStation.hdeskWinlogon)) {
+ DebugLog((DEB_ERROR, "Failed to associate winlogon with winlogon desktop\n"));
+ return(FALSE);
+ }
+
+
+ //
+ // Switch to the winlogon desktop
+ //
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+
+ return(TRUE);
+}
+
+
+
+
+
+/***************************************************************************\
+* SetMyAce
+*
+* Helper routine that fills in a MYACE structure.
+*
+* History:
+* 02-06-92 Davidc Created
+\***************************************************************************/
+VOID
+SetMyAce(
+ PMYACE MyAce,
+ PSID Sid,
+ ACCESS_MASK Mask,
+ UCHAR InheritFlags
+ )
+{
+ MyAce->Sid = Sid;
+ MyAce->AccessMask= Mask;
+ MyAce->InheritFlags = InheritFlags;
+}
+
+
+/***************************************************************************\
+* SetWindowStationSecurity
+*
+* Sets the security on the specified window station given the logon sid passed.
+*
+* If the UserSid = NULL, no access is given to anyone other than winlogon
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+BOOL
+SetWindowStationSecurity(
+ PGLOBALS pGlobals,
+ PSID UserSid
+ )
+{
+ MYACE Ace[9];
+ ACEINDEX AceCount = 0;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ SECURITY_INFORMATION si;
+ BOOL Result;
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ pWinlogonSid,
+ WINSTA_ALL,
+ NO_PROPAGATE_INHERIT_ACE
+ );
+ SetMyAce(&(Ace[AceCount++]),
+ pWinlogonSid,
+ GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
+ );
+
+ //
+ // Define the Admin ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ gAdminSid,
+ WINSTA_ENUMERATE | WINSTA_READATTRIBUTES,
+ NO_PROPAGATE_INHERIT_ACE
+ );
+ SetMyAce(&(Ace[AceCount++]),
+ gAdminSid,
+ DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS | DESKTOP_ENUMERATE |
+ DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
+ );
+
+ //
+ // Define the User ACEs
+ //
+
+ if (UserSid != NULL) {
+
+ SetMyAce(&(Ace[AceCount++]),
+ UserSid,
+ WINSTA_ALL,
+ NO_PROPAGATE_INHERIT_ACE
+ );
+ SetMyAce(&(Ace[AceCount++]),
+ UserSid,
+ GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
+ );
+
+ }
+
+ //
+ // If a user is logged in and UserSid is not the logged in user sid,
+ // add the logged in user's sid.
+ //
+
+ if (pGlobals->UserLoggedOn && UserSid != NULL &&
+ !RtlEqualSid(pGlobals->UserProcessData.UserSid, UserSid)) {
+
+ SetMyAce(&(Ace[AceCount++]),
+ pGlobals->UserProcessData.UserSid,
+ WINSTA_ALL,
+ NO_PROPAGATE_INHERIT_ACE
+ );
+ SetMyAce(&(Ace[AceCount++]),
+ pGlobals->UserProcessData.UserSid,
+ GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
+ );
+ }
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create winsta security descriptor\n"));
+ return(FALSE);
+ }
+
+ //
+ // Set the DACL on the object
+ //
+
+ si = DACL_SECURITY_INFORMATION;
+ Result = SetUserObjectSecurity(pGlobals->WindowStation.hwinsta, &si, SecurityDescriptor);
+
+ //
+ // Free up the security descriptor
+ //
+
+ DeleteSecurityDescriptor(SecurityDescriptor);
+
+ //
+ // Return success status
+ //
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "failed to set windowstation security\n"));
+ }
+ return(Result);
+}
+
+
+/***************************************************************************\
+* SetWinlogonDesktopSecurity
+*
+* Sets the security on the specified desktop so only winlogon can access it
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+BOOL
+SetWinlogonDesktopSecurity(
+ HDESK hdesktop,
+ PSID WinlogonSid
+ )
+{
+ MYACE Ace[2];
+ ACEINDEX AceCount = 0;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ SECURITY_INFORMATION si;
+ BOOL Result;
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ WinlogonSid,
+ DESKTOP_ALL,
+ 0
+ );
+
+ //
+ // Add enumerate access for administrators
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ gAdminSid,
+ DESKTOP_ENUMERATE | STANDARD_RIGHTS_REQUIRED,
+ NO_PROPAGATE_INHERIT_ACE
+ );
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create winlogon desktop security descriptor\n"));
+ return(FALSE);
+ }
+
+ //
+ // Set the DACL on the object
+ //
+
+ si = DACL_SECURITY_INFORMATION;
+ Result = SetUserObjectSecurity(hdesktop, &si, SecurityDescriptor);
+
+ //
+ // Free up the security descriptor
+ //
+
+ DeleteSecurityDescriptor(SecurityDescriptor);
+
+ //
+ // Return success status
+ //
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "failed to set winlogon desktop security\n"));
+ }
+ return(Result);
+}
+
+
+/***************************************************************************\
+* SetUserDesktopSecurity
+*
+* Sets the security on the specified desktop given the logon sid passed.
+*
+* If UserSid = NULL, access is given only to winlogon
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+BOOL
+SetUserDesktopSecurity(
+ HDESK hdesktop,
+ PSID UserSid,
+ PSID WinlogonSid
+ )
+{
+ MYACE Ace[3];
+ ACEINDEX AceCount = 0;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ SECURITY_INFORMATION si;
+ BOOL Result;
+ ACCESS_MASK DesktopAccess;
+ DWORD MiserlyAccess;
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ WinlogonSid,
+ DESKTOP_ALL,
+ 0
+ );
+
+ //
+ // Define the Admin ACEs
+ //
+
+ MiserlyAccess = GetProfileInt( WINLOGON, RESTRICT_NONINTERACTIVE_ACCESS, 0 );
+
+ if ( MiserlyAccess )
+ {
+ DesktopAccess = DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS |
+ DESKTOP_ENUMERATE |
+ DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU ;
+ }
+ else
+ {
+
+ DesktopAccess = DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS |
+ DESKTOP_ENUMERATE |
+ DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU |
+ GENERIC_EXECUTE ;
+ }
+
+ SetMyAce(&(Ace[AceCount++]),
+ gAdminSid,
+ DesktopAccess,
+ 0
+ );
+
+ //
+ // Define the User ACEs
+ //
+
+ if (UserSid != NULL) {
+
+ SetMyAce(&(Ace[AceCount++]),
+ UserSid,
+ DESKTOP_ALL,
+ 0
+ );
+ }
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create user desktop security descriptor\n"));
+ return(FALSE);
+ }
+
+ //
+ // Set the DACL on the object
+ //
+
+ si = DACL_SECURITY_INFORMATION;
+ Result = SetUserObjectSecurity(hdesktop, &si, SecurityDescriptor);
+
+ //
+ // Free up the security descriptor
+ //
+
+ DeleteSecurityDescriptor(SecurityDescriptor);
+
+ //
+ // Return success status
+ //
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "failed to set user desktop security\n"));
+ }
+ return(Result);
+}
+
+
+/***************************************************************************\
+* CreateLogonSid
+*
+* Creates a logon sid for a new logon.
+*
+* If LogonId is non NULL, on return the LUID that is part of the logon
+* sid is returned here.
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+PSID
+CreateLogonSid(
+ PLUID LogonId OPTIONAL
+ )
+{
+ NTSTATUS Status;
+ ULONG Length;
+ PSID Sid;
+ LUID Luid;
+
+ //
+ // Generate a locally unique id to include in the logon sid
+ //
+
+ Status = NtAllocateLocallyUniqueId(&Luid);
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "Failed to create LUID, status = 0x%lx", Status));
+ return(NULL);
+ }
+
+
+ //
+ // Allocate space for the sid and fill it in.
+ //
+
+ Length = RtlLengthRequiredSid(SECURITY_LOGON_IDS_RID_COUNT);
+
+ Sid = (PSID)Alloc(Length);
+ ASSERTMSG("Winlogon failed to allocate memory for logonsid", Sid != NULL);
+
+ if (Sid != NULL) {
+
+ RtlInitializeSid(Sid, &gSystemSidAuthority, SECURITY_LOGON_IDS_RID_COUNT);
+
+ ASSERT(SECURITY_LOGON_IDS_RID_COUNT == 3);
+
+ *(RtlSubAuthoritySid(Sid, 0)) = SECURITY_LOGON_IDS_RID;
+ *(RtlSubAuthoritySid(Sid, 1 )) = Luid.HighPart;
+ *(RtlSubAuthoritySid(Sid, 2 )) = Luid.LowPart;
+ }
+
+
+ //
+ // Return the logon LUID if required.
+ //
+
+ if (LogonId != NULL) {
+ *LogonId = Luid;
+ }
+
+ return(Sid);
+}
+
+
+/***************************************************************************\
+* DeleteLogonSid
+*
+* Frees up memory allocated for logon sid
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+VOID
+DeleteLogonSid(
+ PSID Sid
+ )
+{
+ Free(Sid);
+}
+
+
+/***************************************************************************\
+* InitializeSecurityGlobals
+*
+* Initializes the various global constants (mainly Sids used in this module.
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+VOID
+InitializeSecurityGlobals(
+ VOID
+ )
+{
+ NTSTATUS Status;
+
+ //
+ // Initialize the local sid for later
+ //
+
+ Status = RtlAllocateAndInitializeSid(
+ &gLocalSidAuthority,
+ 1,
+ SECURITY_LOCAL_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &gLocalSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "Failed to initialize local sid, status = 0x%lx", Status));
+ }
+
+ //
+ // Initialize the admin sid for later
+ //
+
+ Status = RtlAllocateAndInitializeSid(
+ &gSystemSidAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &gAdminSid
+ );
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "Failed to initialize admin alias sid, status = 0x%lx", Status));
+ }
+
+}
+
+
+/***************************************************************************\
+* EnablePrivilege
+*
+* Enables/disables the specified well-known privilege in the current thread
+* token if there is one, otherwise the current process token.
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+BOOL
+EnablePrivilege(
+ ULONG Privilege,
+ BOOL Enable
+ )
+{
+ NTSTATUS Status;
+ BOOLEAN WasEnabled;
+
+ //
+ // Try the thread token first
+ //
+
+ Status = RtlAdjustPrivilege(Privilege,
+ (BOOLEAN)Enable,
+ TRUE,
+ &WasEnabled);
+
+ if (Status == STATUS_NO_TOKEN) {
+
+ //
+ // No thread token, use the process token
+ //
+
+ Status = RtlAdjustPrivilege(Privilege,
+ (BOOLEAN)Enable,
+ FALSE,
+ &WasEnabled);
+ }
+
+
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "Failed to %ws privilege : 0x%lx, status = 0x%lx", Enable ? TEXT("enable") : TEXT("disable"), Privilege, Status));
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* ClearUserProcessData
+*
+* Resets fields in user process data. Should be used at startup when structure
+* contents are unknown.
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+VOID
+ClearUserProcessData(
+ PUSER_PROCESS_DATA UserProcessData
+ )
+{
+ UserProcessData->UserToken = NULL;
+ UserProcessData->UserSid = NULL;
+ UserProcessData->NewProcessSD = NULL;
+ UserProcessData->NewProcessTokenSD = NULL;
+ UserProcessData->NewThreadSD = NULL;
+ UserProcessData->NewThreadTokenSD = NULL;
+
+ //
+ // Use the PagedPoolLimit field as an indication as to whether
+ // any of the quota fields have been set. A zero PagedPoolLimit
+ // is not legit, and so makes for a greate indicator.
+ //
+
+ UserProcessData->Quotas.PagedPoolLimit = 0;
+
+ //
+ // the following two fields will be set by MOAP.
+ //
+
+ UserProcessData->CurrentDirectory = NULL;
+ UserProcessData->pEnvironment = NULL;
+}
+
+
+/***************************************************************************\
+* SetUserProcessData
+*
+* Sets up the user process data structure for a new user.
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+BOOL
+SetUserProcessData(
+ PUSER_PROCESS_DATA UserProcessData,
+ HANDLE UserToken,
+ PQUOTA_LIMITS Quotas OPTIONAL,
+ PSID UserSid,
+ PSID WinlogonSid
+ )
+{
+ NTSTATUS Status;
+
+ //
+ // Free an existing UserSid
+ //
+ if (UserProcessData->UserSid != NULL) {
+ //
+ // Don't free winlogon sid if this was a system logon (or no logon)
+ //
+ if (UserProcessData->UserSid != WinlogonSid) {
+ DeleteLogonSid(UserProcessData->UserSid);
+ }
+ UserProcessData->UserSid = NULL;
+ }
+
+ //
+ // Free up the logon token
+ //
+
+ if (UserProcessData->UserToken != NULL) {
+ Status = NtClose(UserProcessData->UserToken);
+ ASSERT(NT_SUCCESS(Status));
+ UserProcessData->UserToken = NULL;
+ }
+
+ //
+ // Free up any existing security descriptors
+ //
+ if (UserProcessData->NewProcessSD != NULL) {
+ DeleteSecurityDescriptor(UserProcessData->NewProcessSD);
+ }
+ if (UserProcessData->NewProcessTokenSD != NULL) {
+ DeleteSecurityDescriptor(UserProcessData->NewProcessTokenSD);
+ }
+ if (UserProcessData->NewThreadSD != NULL) {
+ DeleteSecurityDescriptor(UserProcessData->NewThreadSD);
+ }
+ if (UserProcessData->NewThreadTokenSD != NULL) {
+ DeleteSecurityDescriptor(UserProcessData->NewThreadTokenSD);
+ }
+
+ //
+ // Store the new user's token and sid
+ //
+
+ ASSERT(UserSid != NULL); // should always have a non-NULL user sid
+
+ UserProcessData->UserToken = UserToken;
+ UserProcessData->UserSid = UserSid;
+
+ //
+ // Save the user's quota limits
+ //
+
+ if (ARGUMENT_PRESENT(Quotas)) {
+ UserProcessData->Quotas = (*Quotas);
+ }
+
+
+ //
+ // Set up new security descriptors
+ //
+#if 0
+ UserProcessData->NewProcessSD = CreateUserProcessSD(
+ UserSid,
+ WinlogonSid);
+
+ ASSERT(UserProcessData->NewProcessSD != NULL);
+
+ UserProcessData->NewProcessTokenSD = CreateUserProcessTokenSD(
+ UserSid,
+ WinlogonSid);
+
+ ASSERT(UserProcessData->NewProcessTokenSD != NULL);
+#endif
+ UserProcessData->NewThreadSD = CreateUserThreadSD(
+ UserSid,
+ WinlogonSid);
+
+ ASSERT(UserProcessData->NewThreadSD != NULL);
+
+ UserProcessData->NewThreadTokenSD = CreateUserThreadTokenSD(
+ UserSid,
+ WinlogonSid);
+
+ ASSERT(UserProcessData->NewThreadTokenSD != NULL);
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: SecurityChangeUser
+*
+* PURPOSE: Sets up any security information for the new user.
+* This should be called whenever a user logs on or off.
+* UserLoggedOn should be set to indicate winlogon state, i.e.
+* TRUE if a real user is logged on, FALSE if this call is setting
+* our user back to system. (Note that UserToken and Sid may be
+* the winlogon token/sid on DBG machines where we allow system logon)
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+SecurityChangeUser(
+ PGLOBALS pGlobals,
+ HANDLE Token,
+ PQUOTA_LIMITS Quotas OPTIONAL,
+ PSID LogonSid,
+ BOOL UserLoggedOn
+ )
+{
+ LUID luidNone = { 0, 0 };
+
+ //
+ // Set appropriate protection on windows objects
+ //
+
+ if ( UserLoggedOn || pGlobals->fExecuteSetup )
+ {
+ AddUserToWinsta( &pGlobals->WindowStation,
+ LogonSid,
+ Token );
+
+ }
+ else
+ {
+ RemoveUserFromWinsta( &pGlobals->WindowStation,
+ pGlobals->UserProcessData.UserToken );
+ }
+
+#if 0
+ SetWindowStationSecurity(pGlobals,
+ (UserLoggedOn || pGlobals->fExecuteSetup) ? LogonSid : NULL);
+#endif
+
+ SetUserDesktopSecurity( pGlobals->WindowStation.hdeskApplication,
+ LogonSid,
+ pWinlogonSid);
+
+ //
+ // Setup new-process data
+ //
+
+ SetUserProcessData(&pGlobals->UserProcessData,
+ Token,
+ Quotas,
+ LogonSid,
+ pWinlogonSid);
+
+ //
+ // Setup the appropriate new environment
+ //
+
+ if (UserLoggedOn) {
+
+ //
+ // Do nothing to the profile or environment. Environment and profiles
+ // are all handled in wlx.c:LogonAttempt and DoStartShell
+ //
+
+ pGlobals->LogoffFlags = 0;
+ pGlobals->TickCount = GetTickCount();
+
+ } else {
+
+ //
+ // Restore the system environment
+ //
+
+ CloseIniFileUserMapping(pGlobals);
+
+ ResetEnvironment(pGlobals);
+
+ SetWindowStationUser(pGlobals->WindowStation.hwinsta, &luidNone, NULL, 0);
+
+ }
+
+
+ //
+ // Store whether there is a real user logged on or not
+ //
+
+ pGlobals->UserLoggedOn = UserLoggedOn;
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* CreateSecurityDescriptor
+*
+* Creates a security descriptor containing an ACL containing the specified ACEs
+*
+* A SD created with this routine should be destroyed using
+* DeleteSecurityDescriptor
+*
+* Returns a pointer to the security descriptor or NULL on failure.
+*
+* 02-06-92 Davidc Created.
+\***************************************************************************/
+
+PSECURITY_DESCRIPTOR
+CreateSecurityDescriptor(
+ PMYACE MyAce,
+ ACEINDEX AceCount
+ )
+{
+ NTSTATUS Status;
+ ACEINDEX AceIndex;
+ PACCESS_ALLOWED_ACE *Ace;
+ PACL Acl = NULL;
+ PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
+ ULONG LengthAces;
+ ULONG LengthAcl;
+ ULONG LengthSd;
+
+ //
+ // Allocate space for the ACE pointer array
+ //
+
+ Ace = (PACCESS_ALLOWED_ACE *)Alloc(sizeof(PACCESS_ALLOWED_ACE) * AceCount);
+ if (Ace == NULL) {
+ DebugLog((DEB_ERROR, "Failed to allocated ACE array\n"));
+ return(NULL);
+ }
+
+ //
+ // Create the ACEs and calculate total ACE size
+ //
+
+ LengthAces = 0;
+ for (AceIndex=0; AceIndex < AceCount; AceIndex ++) {
+ Ace[AceIndex] = CreateAccessAllowedAce(MyAce[AceIndex].Sid,
+ MyAce[AceIndex].AccessMask,
+ 0,
+ MyAce[AceIndex].InheritFlags);
+ if (Ace[AceIndex] == NULL) {
+ DebugLog((DEB_ERROR, "Failed to allocate ace\n"));
+ } else {
+ LengthAces += Ace[AceIndex]->Header.AceSize;
+ }
+ }
+
+ //
+ // Calculate ACL and SD sizes
+ //
+
+ LengthAcl = sizeof(ACL) + LengthAces;
+ LengthSd = SECURITY_DESCRIPTOR_MIN_LENGTH;
+
+ //
+ // Create the ACL
+ //
+
+ Acl = Alloc(LengthAcl);
+
+ if (Acl != NULL) {
+
+ Status = RtlCreateAcl(Acl, LengthAcl, ACL_REVISION);
+ ASSERT(NT_SUCCESS(Status));
+
+ //
+ // Add the ACES to the ACL and destroy the ACEs
+ //
+
+ for (AceIndex = 0; AceIndex < AceCount; AceIndex ++) {
+
+ if (Ace[AceIndex] != NULL) {
+
+ Status = RtlAddAce(Acl, ACL_REVISION, 0, Ace[AceIndex],
+ Ace[AceIndex]->Header.AceSize);
+
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "AddAce failed, status = 0x%lx", Status));
+ }
+
+ DestroyAce(Ace[AceIndex]);
+ }
+ }
+
+ } else {
+ DebugLog((DEB_ERROR, "Failed to allocate ACL\n"));
+ }
+
+ //
+ // Free the ACE pointer array
+ //
+ Free(Ace);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = Alloc(LengthSd);
+
+ if (SecurityDescriptor != NULL) {
+
+ Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
+ ASSERT(NT_SUCCESS(Status));
+
+ //
+ // Set the DACL on the security descriptor
+ //
+ Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Acl, FALSE);
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "SetDACLSD failed, status = 0x%lx", Status));
+ }
+ } else {
+ DebugLog((DEB_ERROR, "Failed to allocate security descriptor\n"));
+ }
+
+ //
+ // Return with our spoils
+ //
+ return(SecurityDescriptor);
+}
+
+
+/***************************************************************************\
+* DeleteSecurityDescriptor
+*
+* Deletes a security descriptor created using CreateSecurityDescriptor
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 02-06-92 Davidc Created.
+\***************************************************************************/
+
+BOOL
+DeleteSecurityDescriptor(
+ PSECURITY_DESCRIPTOR SecurityDescriptor
+ )
+{
+ NTSTATUS Status;
+ PACL Acl;
+ BOOLEAN Present;
+ BOOLEAN Defaulted;
+
+ ASSERT(SecurityDescriptor != NULL);
+
+ //
+ // Get the ACL
+ //
+ Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
+ &Present, &Acl, &Defaulted);
+ if (NT_SUCCESS(Status)) {
+
+ //
+ // Destroy the ACL
+ //
+ if (Present && (Acl != NULL)) {
+ Free(Acl);
+ }
+ } else {
+ DebugLog((DEB_ERROR, "Failed to get DACL from security descriptor being destroyed, Status = 0x%lx", Status));
+ }
+
+ //
+ // Destroy the Security Descriptor
+ //
+ Free(SecurityDescriptor);
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* CreateAccessAllowedAce
+*
+* Allocates memory for an ACCESS_ALLOWED_ACE and fills it in.
+* The memory should be freed by calling DestroyACE.
+*
+* Returns pointer to ACE on success, NULL on failure
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+PVOID
+CreateAccessAllowedAce(
+ PSID Sid,
+ ACCESS_MASK AccessMask,
+ UCHAR AceFlags,
+ UCHAR InheritFlags
+ )
+{
+ ULONG LengthSid = RtlLengthSid(Sid);
+ ULONG LengthACE = sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) + LengthSid;
+ PACCESS_ALLOWED_ACE Ace;
+
+ Ace = (PACCESS_ALLOWED_ACE)Alloc(LengthACE);
+ if (Ace == NULL) {
+ DebugLog((DEB_ERROR, "CreateAccessAllowedAce : Failed to allocate ace\n"));
+ return NULL;
+ }
+
+ Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+ Ace->Header.AceSize = (UCHAR)LengthACE;
+ Ace->Header.AceFlags = AceFlags | InheritFlags;
+ Ace->Mask = AccessMask;
+ RtlCopySid(LengthSid, (PSID)(&(Ace->SidStart)), Sid );
+
+ return(Ace);
+}
+
+
+/***************************************************************************\
+* DestroyAce
+*
+* Frees the memory allocate for an ACE
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+VOID
+DestroyAce(
+ PVOID Ace
+ )
+{
+ Free(Ace);
+}
+
+
+/***************************************************************************\
+* FUNCTION: ImpersonateUser
+*
+* PURPOSE: Impersonates the user by setting the users token
+* on the specified thread. If no thread is specified the token
+* is set on the current thread.
+*
+* RETURNS: Handle to be used on call to StopImpersonating() or NULL on failure
+* If a non-null thread handle was passed in, the handle returned will
+* be the one passed in. (See note)
+*
+* NOTES: Take care when passing in a thread handle and then calling
+* StopImpersonating() with the handle returned by this routine.
+* StopImpersonating() will close any thread handle passed to it -
+* even yours !
+*
+* HISTORY:
+*
+* 04-21-92 Davidc Created.
+*
+\***************************************************************************/
+
+HANDLE
+ImpersonateUser(
+ PUSER_PROCESS_DATA UserProcessData,
+ HANDLE ThreadHandle
+ )
+{
+ NTSTATUS Status, IgnoreStatus;
+ HANDLE UserToken = UserProcessData->UserToken;
+ SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE ImpersonationToken;
+ BOOL ThreadHandleOpened = FALSE;
+
+ if (ThreadHandle == NULL) {
+
+ //
+ // Get a handle to the current thread.
+ // Once we have this handle, we can set the user's impersonation
+ // token into the thread and remove it later even though we ARE
+ // the user for the removal operation. This is because the handle
+ // contains the access rights - the access is not re-evaluated
+ // at token removal time.
+ //
+
+ Status = NtDuplicateObject( NtCurrentProcess(), // Source process
+ NtCurrentThread(), // Source handle
+ NtCurrentProcess(), // Target process
+ &ThreadHandle, // Target handle
+ THREAD_SET_THREAD_TOKEN,// Access
+ 0L, // Attributes
+ DUPLICATE_SAME_ATTRIBUTES
+ );
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "ImpersonateUser : Failed to duplicate thread handle, status = 0x%lx", Status));
+ return(NULL);
+ }
+
+ ThreadHandleOpened = TRUE;
+ }
+
+
+ //
+ // If the usertoken is NULL, there's nothing to do
+ //
+
+ if (UserToken != NULL) {
+
+ //
+ // UserToken is a primary token - create an impersonation token version
+ // of it so we can set it on our thread
+ //
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ NULL,
+ 0L,
+ NULL,
+ UserProcessData->NewThreadTokenSD);
+
+ SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
+ SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ SecurityQualityOfService.EffectiveOnly = FALSE;
+
+ ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
+
+
+ Status = NtDuplicateToken( UserToken,
+ TOKEN_IMPERSONATE | TOKEN_READ,
+ &ObjectAttributes,
+ FALSE,
+ TokenImpersonation,
+ &ImpersonationToken
+ );
+ if (!NT_SUCCESS(Status)) {
+
+ DebugLog((DEB_ERROR, "Failed to duplicate users token to create impersonation thread, status = 0x%lx", Status));
+
+ if (ThreadHandleOpened) {
+ IgnoreStatus = NtClose(ThreadHandle);
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+ }
+
+ return(NULL);
+ }
+
+
+
+ //
+ // Set the impersonation token on this thread so we 'are' the user
+ //
+
+ Status = NtSetInformationThread( ThreadHandle,
+ ThreadImpersonationToken,
+ (PVOID)&ImpersonationToken,
+ sizeof(ImpersonationToken)
+ );
+ //
+ // We're finished with our handle to the impersonation token
+ //
+
+ IgnoreStatus = NtClose(ImpersonationToken);
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+
+ //
+ // Check we set the token on our thread ok
+ //
+
+ if (!NT_SUCCESS(Status)) {
+
+ DebugLog((DEB_ERROR, "Failed to set user impersonation token on winlogon thread, status = 0x%lx", Status));
+
+ if (ThreadHandleOpened) {
+ IgnoreStatus = NtClose(ThreadHandle);
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+ }
+
+ return(NULL);
+ }
+
+ }
+
+
+ return(ThreadHandle);
+
+}
+
+
+/***************************************************************************\
+* FUNCTION: StopImpersonating
+*
+* PURPOSE: Stops impersonating the client by removing the token on the
+* current thread.
+*
+* PARAMETERS: ThreadHandle - handle returned by ImpersonateUser() call.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* NOTES: If a thread handle was passed in to ImpersonateUser() then the
+* handle returned was one and the same. If this is passed to
+* StopImpersonating() the handle will be closed. Take care !
+*
+* HISTORY:
+*
+* 04-21-92 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+StopImpersonating(
+ HANDLE ThreadHandle
+ )
+{
+ NTSTATUS Status, IgnoreStatus;
+ HANDLE ImpersonationToken;
+
+
+ //
+ // Remove the user's token from our thread so we are 'ourself' again
+ //
+
+ ImpersonationToken = NULL;
+
+ Status = NtSetInformationThread( ThreadHandle,
+ ThreadImpersonationToken,
+ (PVOID)&ImpersonationToken,
+ sizeof(ImpersonationToken)
+ );
+ //
+ // We're finished with the thread handle
+ //
+
+ IgnoreStatus = NtClose(ThreadHandle);
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+
+
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "Failed to remove user impersonation token from winlogon thread, status = 0x%lx", Status));
+ }
+
+ return(NT_SUCCESS(Status));
+}
+
+
+/***************************************************************************\
+* ExecUserThread
+*
+* Creates a thread of the winlogon process running in the logged on user's
+* context.
+*
+* Returns thread handle on success, NULL on failure.
+*
+* Thread handle returned has all access to thread.
+*
+* 05-04-92 Davidc Created.
+\***************************************************************************/
+
+HANDLE ExecUserThread(
+ IN PGLOBALS pGlobals,
+ IN LPTHREAD_START_ROUTINE lpStartAddress,
+ IN LPVOID Parameter,
+ IN DWORD Flags,
+ OUT LPDWORD ThreadId
+ )
+{
+ SECURITY_ATTRIBUTES saThread;
+ PUSER_PROCESS_DATA UserProcessData = &pGlobals->UserProcessData;
+ HANDLE ThreadHandle, Handle;
+ BOOL Result = FALSE;
+ DWORD ResumeResult, IgnoreResult;
+
+ //
+ // Initialize thread security info
+ //
+
+ saThread.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saThread.lpSecurityDescriptor = UserProcessData->NewThreadSD;
+ saThread.bInheritHandle = FALSE;
+
+ //
+ // Create the thread suspended
+ //
+
+ ThreadHandle = CreateThread(
+ &saThread,
+ 0, // Default Stack size
+ lpStartAddress,
+ Parameter,
+ CREATE_SUSPENDED | Flags,
+ ThreadId);
+
+ if (ThreadHandle == NULL) {
+ DebugLog((DEB_ERROR, "User thread creation failed! Error = %d\n", GetLastError()));
+ return(NULL);
+ }
+
+
+ //
+ // Switch the thread to user context.
+ //
+
+ Handle = ImpersonateUser(UserProcessData, ThreadHandle);
+
+ if (Handle == NULL) {
+
+ DebugLog((DEB_ERROR, "Failed to set user context on thread!\n"));
+
+ } else {
+
+ //
+ // Should have got back the handle we passed in
+ //
+
+ ASSERT(Handle == ThreadHandle);
+
+ //
+ // Let the thread run
+ //
+
+ ResumeResult = ResumeThread(ThreadHandle);
+
+ if (ResumeResult == -1) {
+ DebugLog((DEB_ERROR, "failed to resume thread, error = %d", GetLastError()));
+
+ } else {
+
+ //
+ // Success
+ //
+
+ Result = TRUE;
+
+ }
+ }
+
+
+
+ if (!Result) {
+
+ //
+ // Terminate the thread
+ //
+
+ IgnoreResult = TerminateThread(ThreadHandle, 0);
+ ASSERT(IgnoreResult);
+
+ //
+ // Close the thread handle
+ //
+
+ IgnoreResult = CloseHandle(ThreadHandle);
+ ASSERT(IgnoreResult);
+
+ ThreadHandle = NULL;
+ }
+
+
+ return(ThreadHandle);
+}
+
+
+
+/***************************************************************************\
+* CreateUserProfileKeySD
+*
+* Creates a security descriptor to protect registry keys in the user profile
+*
+* History:
+* 22-Dec-92 Davidc Created
+* 04-May-93 Johannec added 3rd parameter for locked groups set in upedit.exe
+\***************************************************************************/
+PSECURITY_DESCRIPTOR
+CreateUserProfileKeySD(
+ PSID UserSid,
+ PSID WinlogonSid,
+ BOOL AllAccess
+ )
+{
+ MYACE Ace[3];
+ ACEINDEX AceCount = 0;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+
+ ASSERT(UserSid != NULL); // should always have a non-null user sid
+
+ //
+ // Define the User ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ UserSid,
+ AllAccess ? KEY_ALL_ACCESS :
+ KEY_ALL_ACCESS & ~(KEY_SET_VALUE | KEY_CREATE_SUB_KEY | DELETE),
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
+ );
+
+ //
+ // Define the Admin ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ gAdminSid,
+ KEY_ALL_ACCESS,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
+ );
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ WinlogonSid,
+ KEY_ALL_ACCESS,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
+ );
+
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create user process security descriptor\n\n"));
+ }
+
+ return(SecurityDescriptor);
+}
+
+/***************************************************************************\
+* CreateUserProcessTokenSD
+*
+* Creates a security descriptor to protect primary tokens on user processes
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+PSECURITY_DESCRIPTOR
+CreateUserProcessTokenSD(
+ PSID UserSid,
+ PSID WinlogonSid
+ )
+{
+ MYACE Ace[2];
+ ACEINDEX AceCount = 0;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ ASSERT(UserSid != NULL); // should always have a non-null user sid
+
+ //
+ // Define the User ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ UserSid,
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT | TOKEN_QUERY |
+ TOKEN_DUPLICATE | TOKEN_IMPERSONATE | READ_CONTROL,
+ 0
+ );
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ WinlogonSid,
+ TOKEN_READ,
+ 0
+ );
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create user process token security descriptor"));
+ }
+
+ return(SecurityDescriptor);
+
+ DBG_UNREFERENCED_PARAMETER(WinlogonSid);
+}
+
+/***************************************************************************\
+* CreateUserProcessSD
+*
+* Creates a security descriptor to protect user processes
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+PSECURITY_DESCRIPTOR
+CreateUserProcessSD(
+ PSID UserSid,
+ PSID WinlogonSid
+ )
+{
+ MYACE Ace[2];
+ ACEINDEX AceCount = 0;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ ASSERT(UserSid != NULL); // should always have a non-null user sid
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ WinlogonSid,
+ PROCESS_SET_INFORMATION | // Allow primary token to be set
+ PROCESS_TERMINATE | SYNCHRONIZE, // Allow screen-saver control
+ 0
+ );
+
+ //
+ // Define the User ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ UserSid,
+ PROCESS_ALL_ACCESS,
+ 0
+ );
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create user process security descriptor"));
+ }
+
+ return(SecurityDescriptor);
+}
+
+
+/***************************************************************************\
+* TestTokenForAdmin
+*
+* Returns TRUE if the token passed represents an admin user, otherwise FALSE
+*
+* The token handle passed must have TOKEN_QUERY access.
+*
+* History:
+* 05-06-92 Davidc Created
+\***************************************************************************/
+BOOL
+TestTokenForAdmin(
+ HANDLE Token
+ )
+{
+ NTSTATUS Status;
+ ULONG InfoLength;
+ PTOKEN_GROUPS TokenGroupList;
+ ULONG GroupIndex;
+ BOOL FoundAdmin;
+
+ //
+ // Get a list of groups in the token
+ //
+
+ Status = NtQueryInformationToken(
+ Token, // Handle
+ TokenGroups, // TokenInformationClass
+ NULL, // TokenInformation
+ 0, // TokenInformationLength
+ &InfoLength // ReturnLength
+ );
+
+ if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) {
+
+ DebugLog((DEB_ERROR, "failed to get group info for admin token, status = 0x%lx\n", Status));
+ return(FALSE);
+ }
+
+
+ TokenGroupList = Alloc(InfoLength);
+
+ if (TokenGroupList == NULL) {
+ DebugLog((DEB_ERROR, "unable to allocate memory for token groups\n"));
+ return(FALSE);
+ }
+
+ Status = NtQueryInformationToken(
+ Token, // Handle
+ TokenGroups, // TokenInformationClass
+ TokenGroupList, // TokenInformation
+ InfoLength, // TokenInformationLength
+ &InfoLength // ReturnLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "failed to query groups for admin token, status = 0x%lx\n", Status));
+ Free(TokenGroupList);
+ return(FALSE);
+ }
+
+
+ //
+ // Search group list for admin alias
+ //
+
+ FoundAdmin = FALSE;
+
+ for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) {
+
+ if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, gAdminSid)) {
+ FoundAdmin = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Tidy up
+ //
+
+ Free(TokenGroupList);
+
+
+
+ return(FoundAdmin);
+}
+
+
+/***************************************************************************\
+* SetProcessToken
+*
+* Set the primary token of the specified process
+* If the specified token is NULL, this routine does nothing.
+*
+* It assumed that the handles in ProcessInformation are the handles returned
+* on creation of the process and therefore have all access.
+*
+* Returns TRUE on success, FALSE on failure.
+*
+* 01-31-91 Davidc Created.
+\***************************************************************************/
+
+BOOL
+SetProcessToken(
+ PGLOBALS pGlobals,
+ HANDLE hProcess,
+ HANDLE hThread,
+ HANDLE hToken
+ )
+{
+ NTSTATUS Status, AdjustStatus;
+ PROCESS_ACCESS_TOKEN PrimaryTokenInfo;
+ HANDLE TokenToAssign;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ BOOLEAN WasEnabled;
+ PSECURITY_DESCRIPTOR psd;
+
+
+ //
+ // Check for a NULL token. (No need to do anything)
+ // The process will run in the parent process's context and inherit
+ // the default ACL from the parent process's token.
+ //
+ if (hToken == NULL)
+ {
+ return(TRUE);
+ }
+
+ psd = CreateUserProcessTokenSD( pGlobals->UserProcessData.UserSid,
+ pGlobals->WinlogonSid );
+
+ //
+ // A primary token can only be assigned to one process.
+ // Duplicate the logon token so we can assign one to the new
+ // process.
+ //
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ NULL,
+ 0,
+ NULL,
+ psd
+ );
+
+ Status = NtDuplicateToken(
+ hToken, // Duplicate this token
+ 0, // Same desired access
+ &ObjectAttributes,
+ FALSE, // EffectiveOnly
+ TokenPrimary, // TokenType
+ &TokenToAssign // Duplicate token handle stored here
+ );
+
+ DeleteSecurityDescriptor(psd);
+
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "SetProcessToken failed to duplicate primary token for new user process, status = 0x%lx\n", Status));
+ return(FALSE);
+ }
+
+ //
+ // Set the process's primary token
+ //
+
+
+ //
+ // Enable the required privilege
+ //
+
+ Status = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE,
+ FALSE, &WasEnabled);
+ if (NT_SUCCESS(Status)) {
+
+ PrimaryTokenInfo.Token = TokenToAssign;
+ PrimaryTokenInfo.Thread = hThread;
+
+ Status = NtSetInformationProcess(
+ hProcess,
+ ProcessAccessToken,
+ (PVOID)&PrimaryTokenInfo,
+ (ULONG)sizeof(PROCESS_ACCESS_TOKEN)
+ );
+ //
+ // Restore the privilege to its previous state
+ //
+
+ AdjustStatus = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
+ WasEnabled, FALSE, &WasEnabled);
+ if (!NT_SUCCESS(AdjustStatus)) {
+ DebugLog((DEB_ERROR, "failed to restore assign-primary-token privilege to previous enabled state\n"));
+ }
+
+ if (NT_SUCCESS(Status)) {
+ Status = AdjustStatus;
+ }
+ } else {
+ DebugLog((DEB_ERROR, "failed to enable assign-primary-token privilege\n"));
+ }
+
+ //
+ // We're finished with the token handle
+ //
+
+ CloseHandle(TokenToAssign);
+
+
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "SetProcessToken failed to set primary token for new user process, Status = 0x%lx\n", Status));
+ SetLastError(RtlNtStatusToDosError(Status));
+ }
+
+ return (NT_SUCCESS(Status));
+}
+
+
+/***************************************************************************\
+* CreateUserThreadSD
+*
+* Creates a security descriptor to protect user threads in the winlogon process
+*
+* History:
+* 05-04-92 Davidc Created
+\***************************************************************************/
+PSECURITY_DESCRIPTOR
+CreateUserThreadSD(
+ PSID UserSid,
+ PSID WinlogonSid
+ )
+{
+ MYACE Ace[2];
+ ACEINDEX AceCount = 0;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ ASSERT(UserSid != NULL); // should always have a non-null user sid
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ WinlogonSid,
+ THREAD_QUERY_INFORMATION |
+ THREAD_SET_THREAD_TOKEN |
+ THREAD_SUSPEND_RESUME |
+ THREAD_TERMINATE | SYNCHRONIZE,
+ 0
+ );
+
+ //
+ // Define the User ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ UserSid,
+ THREAD_GET_CONTEXT |
+ THREAD_QUERY_INFORMATION,
+ 0
+ );
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create user process security descriptor\n"));
+ }
+
+ return(SecurityDescriptor);
+}
+
+
+/***************************************************************************\
+* CreateUserThreadTokenSD
+*
+* Creates a security descriptor to protect tokens on user threads
+*
+* History:
+* 12-05-91 Davidc Created
+\***************************************************************************/
+PSECURITY_DESCRIPTOR
+CreateUserThreadTokenSD(
+ PSID UserSid,
+ PSID WinlogonSid
+ )
+{
+ MYACE Ace[2];
+ ACEINDEX AceCount = 0;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ ASSERT(UserSid != NULL); // should always have a non-null user sid
+
+ //
+ // Define the User ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ UserSid,
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT | TOKEN_QUERY |
+ TOKEN_DUPLICATE | TOKEN_IMPERSONATE | READ_CONTROL,
+ 0
+ );
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(&(Ace[AceCount++]),
+ WinlogonSid,
+ TOKEN_ALL_ACCESS,
+ 0
+ );
+
+ // Check we didn't goof
+ ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create user process token security descriptor\n"));
+ }
+
+ return(SecurityDescriptor);
+
+ DBG_UNREFERENCED_PARAMETER(WinlogonSid);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CreateAceList
+//
+// Synopsis: Create and initialize the ACELIST to track access to the winsta
+//
+// Arguments: [Count] --
+//
+// History: 6-24-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+PMYACELIST
+CreateAceList(
+ DWORD Count)
+{
+ PMYACELIST pList;
+
+ pList = LocalAlloc( LMEM_FIXED, sizeof( MYACELIST ) );
+
+ if ( pList )
+ {
+ pList->Aces = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
+ sizeof( MYACE ) * Count );
+
+ if ( pList->Aces )
+ {
+ pList->Total = Count;
+ pList->Active = 0;
+
+ pList->Sids = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
+ sizeof( PSID ) * Count );
+
+ if ( pList->Sids )
+ {
+ pList->TotalSids = Count;
+ pList->ActiveSids = 0;
+
+ return( pList );
+ }
+
+ return( pList );
+ }
+
+ LocalFree( pList );
+ }
+
+ return( NULL );
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: AceListAddSid
+//
+// Synopsis: Adds a SID to the list where the ace list is maintained.
+//
+// Arguments: [pList] --
+// [Sid] --
+//
+// History: 6-24-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+PSID
+AceListAddSid(
+ PMYACELIST pList,
+ PSID Sid )
+{
+ PVOID pCopy;
+ PSID SidCopy;
+ DWORD SidSize;
+
+ if ( pList->ActiveSids == pList->TotalSids )
+ {
+ pCopy = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
+ sizeof( PSID ) * (pList->TotalSids * 2 ) );
+
+ if ( pCopy )
+ {
+ CopyMemory( pCopy, pList->Sids, sizeof(PSID) * pList->ActiveSids );
+ LocalFree( pList->Sids );
+ pList->Sids = pCopy;
+ }
+ else
+ {
+ return( NULL );
+ }
+
+ }
+
+ SidSize = RtlLengthSid( Sid );
+
+ SidCopy = LocalAlloc( LMEM_FIXED, SidSize );
+
+ if ( SidCopy )
+ {
+ CopyMemory( SidCopy, Sid, SidSize );
+
+ pList->Sids[ pList->ActiveSids++ ] = SidCopy ;
+
+ return( SidCopy );
+ }
+
+ return( NULL );
+
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: AceListRemoveSid
+//
+// Synopsis: Removes and frees a SID from the list
+//
+// Arguments: [pList] -- List
+// [Sid] -- Sid to remove
+// [Absolute] -- TRUE -> pointer match, FALSE -> SID match
+//
+// History: 6-24-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+VOID
+AceListRemoveSid(
+ PMYACELIST pList,
+ PSID Sid,
+ BOOL Absolute )
+{
+ DWORD i;
+ PSID SidToDelete;
+
+ for ( i = 0 ; i < pList->ActiveSids ; i++ )
+ {
+ if ( Absolute )
+ {
+ if ( pList->Sids[ i ] == Sid )
+ {
+ break;
+ }
+ }
+ else
+ {
+ if ( RtlEqualSid( pList->Sids[i], Sid ) )
+ {
+ break;
+ }
+ }
+
+ }
+
+ if ( i == pList->ActiveSids )
+ {
+ return;
+ }
+
+ SidToDelete = pList->Sids[ i ];
+
+ pList->ActiveSids --;
+
+ pList->Sids[ i ] = pList->Sids[ pList->ActiveSids ];
+
+ LocalFree( SidToDelete );
+
+}
+//+---------------------------------------------------------------------------
+//
+// Function: AceListSetWinstaSecurity
+//
+// Synopsis: Applies the ACL in pList to the window station
+//
+// Arguments: [pList] --
+// [hWinsta] --
+//
+// History: 6-24-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+AceListSetWinstaSecurity(
+ PMYACELIST pList,
+ DWORD Count,
+ HWINSTA hWinsta )
+{
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ SECURITY_INFORMATION si;
+ BOOL Result;
+
+ //
+ // Create the security descriptor
+ //
+
+ SecurityDescriptor = CreateSecurityDescriptor(pList->Aces, Count );
+ if (SecurityDescriptor == NULL) {
+ DebugLog((DEB_ERROR, "failed to create winsta security descriptor\n"));
+ return(FALSE);
+ }
+
+ //
+ // Set the DACL on the object
+ //
+
+ si = DACL_SECURITY_INFORMATION;
+ Result = SetUserObjectSecurity(hWinsta, &si, SecurityDescriptor);
+
+ //
+ // Free up the security descriptor
+ //
+
+ DeleteSecurityDescriptor(SecurityDescriptor);
+
+ //
+ // Return success status
+ //
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "failed to set windowstation security\n"));
+ }
+ return(Result);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitializeWinstaSecurity
+//
+// Synopsis: Initializes the window station security to winlogon/admin only
+//
+// Arguments: [pWinsta] --
+//
+// History: 6-24-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+InitializeWinstaSecurity(
+ PWinstaDescription pWinsta)
+{
+ PMYACELIST pList;
+ DWORD MiserlyAccess;
+ ACCESS_MASK WinstaAccess, DesktopAccess;
+
+ pList = CreateAceList( 16 );
+
+ if ( !pList )
+ {
+ return( FALSE );
+ }
+
+ pWinsta->Acl = pList;
+
+ //
+ // Define the Winlogon ACEs
+ //
+
+ SetMyAce(& ( pList->Aces[ pList->Active ++ ]),
+ pWinlogonSid,
+ WINSTA_ALL,
+ NO_PROPAGATE_INHERIT_ACE
+ );
+
+ SetMyAce(& ( pList->Aces[ pList->Active ++ ]),
+ pWinlogonSid,
+ GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
+ );
+
+ //
+ // Define the Admin ACEs
+ //
+
+ MiserlyAccess = GetProfileInt( WINLOGON, RESTRICT_NONINTERACTIVE_ACCESS, 0 );
+
+ if ( MiserlyAccess )
+ {
+ WinstaAccess = WINSTA_ENUMERATE | WINSTA_READATTRIBUTES ;
+
+ DesktopAccess = DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS |
+ DESKTOP_ENUMERATE |
+ DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU ;
+ }
+ else
+ {
+ WinstaAccess = WINSTA_ENUMERATE | WINSTA_READATTRIBUTES |
+ WINSTA_ATOMS | STANDARD_RIGHTS_EXECUTE |
+ WINSTA_EXITWINDOWS ;
+
+ DesktopAccess = DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS |
+ DESKTOP_ENUMERATE |
+ DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU |
+ GENERIC_EXECUTE ;
+ }
+
+ SetMyAce(& ( pList->Aces[ pList->Active ++ ]),
+ gAdminSid,
+ WinstaAccess,
+ NO_PROPAGATE_INHERIT_ACE
+ );
+
+ SetMyAce(& ( pList->Aces[ pList->Active ++ ]),
+ gAdminSid,
+ DesktopAccess,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
+ );
+
+ pList->WinlogonOnly = pList->Active ;
+
+ return( AceListSetWinstaSecurity( pList, pList->Active, pWinsta->hwinsta ) );
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: AddUserToWinsta
+//
+// Synopsis: Adds the specified user to the window station
+//
+// Arguments: [pWinsta] --
+// [LogonSid] --
+// [Token] --
+//
+// History: 6-24-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+AddUserToWinsta(
+ PWinstaDescription pWinsta,
+ PSID LogonSid,
+ HANDLE Token )
+{
+ PTOKEN_USER pUser;
+ UCHAR Buffer[128];
+ PMYACELIST pList;
+ NTSTATUS Status;
+ ULONG Needed;
+ PSID LogonSidCopy;
+ PSID UserSidCopy;
+
+ pList = pWinsta->Acl;
+
+ pUser = (PTOKEN_USER) Buffer;
+
+ Status = NtQueryInformationToken( Token,
+ TokenUser,
+ pUser,
+ sizeof(Buffer),
+ &Needed );
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+ return( FALSE );
+ }
+
+
+ //
+ // Define the User ACEs
+ //
+
+ LogonSidCopy = AceListAddSid( pList, LogonSid );
+
+ if ( !LogonSidCopy )
+ {
+ return( FALSE );
+ }
+
+ UserSidCopy = AceListAddSid( pList, pUser->User.Sid );
+
+ if ( !UserSidCopy )
+ {
+ AceListRemoveSid( pList, LogonSidCopy, TRUE );
+
+ return( FALSE );
+ }
+
+ SetMyAce( &pList->Aces[ pList->Active ++ ],
+ LogonSidCopy,
+ WINSTA_ALL,
+ NO_PROPAGATE_INHERIT_ACE );
+
+ SetMyAce( &pList->Aces[ pList->Active ++ ],
+ LogonSidCopy,
+ GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL,
+ OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE );
+
+ SetMyAce( &pList->Aces[ pList->Active ++ ],
+ UserSidCopy,
+ WINSTA_ATOMS,
+ NO_PROPAGATE_INHERIT_ACE );
+
+
+ return( AceListSetWinstaSecurity( pList, pList->Active, pWinsta->hwinsta ) );
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: RemoveUserFromWinsta
+//
+// Synopsis: Removes a user from the window station
+//
+// Arguments: [pWinsta] --
+// [Token] --
+//
+// History: 6-24-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+RemoveUserFromWinsta(
+ PWinstaDescription pWinsta,
+ HANDLE Token )
+{
+ DWORD i;
+ PTOKEN_USER pUser;
+ UCHAR Buffer[128];
+ PMYACELIST pList;
+ NTSTATUS Status;
+ ULONG Needed;
+
+ pList = pWinsta->Acl;
+
+ if ( pList->Active == 0 )
+ {
+ return( FALSE );
+ }
+
+ pUser = (PTOKEN_USER) Buffer;
+
+ Status = NtQueryInformationToken( Token,
+ TokenUser,
+ pUser,
+ sizeof(Buffer),
+ &Needed );
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+ return( FALSE );
+ }
+
+
+ for ( i = pList->Active - 1 ; i >= pList->WinlogonOnly ; i-- )
+ {
+ if ( RtlEqualSid( pList->Aces[i].Sid, pUser->User.Sid ) )
+ {
+ break;
+ }
+ }
+
+ if ( i < pList->WinlogonOnly )
+ {
+ return( FALSE );
+ }
+
+ //
+ // We add users in blocks of three, usually LogonSid, LogonSid, UserSid.
+ // Thus, we delete them in threes
+ //
+
+ if ( i < 2 )
+ {
+ return( FALSE );
+ }
+
+ //
+ // Clean up SIDs
+ //
+
+ AceListRemoveSid( pList, pList->Aces[ i ].Sid, TRUE );
+
+ AceListRemoveSid( pList, pList->Aces[ i - 1 ].Sid, TRUE );
+
+ //
+ // If there are still more entries after this one,
+ // slide them down.
+ //
+
+ if ( pList->Active > i + 1 )
+ {
+ MoveMemory( &pList->Aces[ i - 2 ],
+ &pList->Aces[ i + 1 ],
+ (pList->Active - i - 1) * sizeof( MYACE ) );
+ }
+
+ pList->Active -= 3;
+
+ return( AceListSetWinstaSecurity( pList, pList->Active, pWinsta->hwinsta ) );
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: FastSetWinstaSecurity
+//
+// Synopsis: Allows fast toggling between "normal" and winlogon only access
+//
+// Arguments: [pWinsta] --
+// [FullAccess] --
+//
+// History: 6-24-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+FastSetWinstaSecurity(
+ PWinstaDescription pWinsta,
+ BOOL FullAccess)
+{
+ PMYACELIST pList;
+
+ pList = (PMYACELIST) pWinsta->Acl;
+
+ if ( FullAccess )
+ {
+ return( AceListSetWinstaSecurity( pList,
+ pList->Active,
+ pWinsta->hwinsta ) );
+
+ }
+ else
+ {
+ return( AceListSetWinstaSecurity( pList,
+ pList->WinlogonOnly,
+ pWinsta->hwinsta ) );
+ }
+
+}
diff --git a/private/windows/gina/winlogon/secutil.h b/private/windows/gina/winlogon/secutil.h
new file mode 100644
index 000000000..e49628bd2
--- /dev/null
+++ b/private/windows/gina/winlogon/secutil.h
@@ -0,0 +1,216 @@
+/****************************** Module Header ******************************\
+* Module Name: security.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define various winlogon security-related routines
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+
+extern PSID pWinlogonSid;
+
+//
+// Types used by security descriptor helper routines
+//
+
+typedef LONG ACEINDEX;
+typedef ACEINDEX *PACEINDEX;
+
+typedef struct _MYACE {
+ PSID Sid;
+ ACCESS_MASK AccessMask;
+ UCHAR InheritFlags;
+} MYACE;
+typedef MYACE *PMYACE;
+
+
+//
+// Exported function prototypes
+//
+
+
+VOID
+SetMyAce(
+ PMYACE MyAce,
+ PSID Sid,
+ ACCESS_MASK Mask,
+ UCHAR InheritFlags
+ );
+
+PSECURITY_DESCRIPTOR
+CreateSecurityDescriptor(
+ PMYACE MyAce,
+ ACEINDEX AceCount
+ );
+
+BOOL
+DeleteSecurityDescriptor(
+ PSECURITY_DESCRIPTOR SecurityDescriptor
+ );
+
+
+
+BOOL
+SetWindowStationSecurity(
+ IN PGLOBALS pGlobals,
+ IN PSID UserSid
+ );
+
+BOOL
+SetWinlogonDesktopSecurity(
+ IN HDESK hdesk,
+ IN PSID WinlogonSid
+ );
+
+BOOL
+SetUserDesktopSecurity(
+ IN HDESK hdesk,
+ IN PSID UserSid,
+ IN PSID WinlogonSid
+ );
+
+BOOL
+InitializeSecurity(
+ PGLOBALS pGlobals
+ );
+
+
+PSID
+CreateLogonSid(
+ PLUID LogonId OPTIONAL
+ );
+
+VOID
+DeleteLogonSid(
+ PSID Sid
+ );
+
+PSECURITY_DESCRIPTOR
+CreateUserProfileKeySD(
+ PSID UserSid,
+ PSID WinlogonSid,
+ BOOL AllAccess
+ );
+
+BOOL
+EnablePrivilege(
+ ULONG Privilege,
+ BOOL Enable
+ );
+
+VOID
+ClearUserProcessData(
+ PUSER_PROCESS_DATA UserProcessData
+ );
+
+BOOL
+SetUserProcessData(
+ PUSER_PROCESS_DATA UserProcessData,
+ HANDLE UserToken,
+ PQUOTA_LIMITS Quotas OPTIONAL,
+ PSID UserSid,
+ PSID WinlogonSid
+ );
+
+BOOL
+SecurityChangeUser(
+ PGLOBALS pGlobals,
+ HANDLE Token,
+ PQUOTA_LIMITS Quotas OPTIONAL,
+ PSID LogonSid,
+ BOOL UserLoggedOn
+ );
+
+BOOL
+TestTokenForAdmin(
+ HANDLE Token
+ );
+
+BOOL
+TestUserForAdmin(
+ PGLOBALS pGlobals,
+ IN PWCHAR UserName,
+ IN PWCHAR Domain,
+ IN PUNICODE_STRING PasswordString
+ );
+
+HANDLE
+ImpersonateUser(
+ PUSER_PROCESS_DATA UserProcessData,
+ HANDLE ThreadHandle OPTIONAL
+ );
+
+BOOL
+StopImpersonating(
+ HANDLE ThreadHandle
+ );
+
+BOOL
+TestUserPrivilege(
+ PGLOBALS pGlobals,
+ ULONG Privilege
+ );
+
+VOID
+HidePassword(
+ PUCHAR Seed OPTIONAL,
+ PUNICODE_STRING Password
+ );
+
+
+VOID
+RevealPassword(
+ PUNICODE_STRING HiddenPassword
+ );
+
+VOID
+ErasePassword(
+ PUNICODE_STRING Password
+ );
+
+BOOL
+SetProcessToken(
+ HANDLE hProcess,
+ HANDLE hThread,
+ PSECURITY_DESCRIPTOR psd,
+ HANDLE hToken
+ );
+
+PSECURITY_DESCRIPTOR
+CreateUserThreadSD(
+ PSID UserSid,
+ PSID WinlogonSid
+ );
+
+PSECURITY_DESCRIPTOR
+CreateUserThreadTokenSD(
+ PSID UserSid,
+ PSID WinlogonSid
+ );
+
+HANDLE ExecUserThread(
+ IN PGLOBALS pGlobals,
+ IN LPTHREAD_START_ROUTINE lpStartAddress,
+ IN LPVOID Parameter,
+ IN DWORD Flags,
+ OUT LPDWORD ThreadId
+ );
+
+BOOL
+RemoveUserFromWinsta(
+ PWinstaDescription pWinsta,
+ HANDLE Token );
+
+BOOL
+AddUserToWinsta(
+ PWinstaDescription pWinsta,
+ PSID LogonSid,
+ HANDLE Token );
+
+BOOL
+FastSetWinstaSecurity(
+ PWinstaDescription pWinsta,
+ BOOL FullAccess);
diff --git a/private/windows/gina/winlogon/setup.c b/private/windows/gina/winlogon/setup.c
new file mode 100644
index 000000000..c746d1413
--- /dev/null
+++ b/private/windows/gina/winlogon/setup.c
@@ -0,0 +1,582 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ setuplgn.c
+
+Abstract:
+
+ Routines for the special version of winlogon for Setup.
+
+Author:
+
+ Ted Miller (tedm) 4-May-1992
+
+Revision History:
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DEVL
+BOOL bDebugSetup;
+#endif
+
+//
+// Handle to the event used by lsa to stall security initialization.
+//
+
+HANDLE LsaStallEvent = NULL;
+
+//
+// Thread Id of the main thread of setuplgn.
+//
+
+DWORD MainThreadId;
+
+
+
+DWORD
+WaiterThread(
+ PVOID hProcess
+ );
+
+
+
+
+VOID
+CreateLsaStallEvent(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Create the event used by lsa to stall security initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES EventAttributes;
+ NTSTATUS Status;
+ UNICODE_STRING EventName;
+ HANDLE EventHandle;
+
+ RtlInitUnicodeString(&EventName,TEXT("\\INSTALLATION_SECURITY_HOLD"));
+ InitializeObjectAttributes(&EventAttributes,&EventName,0,0,NULL);
+
+ Status = NtCreateEvent( &EventHandle,
+ 0,
+ &EventAttributes,
+ NotificationEvent,
+ FALSE
+ );
+
+ if(NT_SUCCESS(Status)) {
+ LsaStallEvent = EventHandle;
+ } else {
+ DebugLog((DEB_ERROR, "Couldn't create lsa stall event (status = %lx)",Status));
+ }
+}
+
+
+DWORD
+CheckSetupType (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ See if the value "SetupType" exists under the Winlogon key in WIN.INI;
+ return its value. Return SETUPTYPE_NONE if not found.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ SETUPTYPE_xxxx (see SETUPLGN.H).
+
+--*/
+
+{
+ DWORD SetupType = SETUPTYPE_NONE ;
+ HANDLE KeyHandle = OpenNtRegKey(KEYNAME_SETUP) ;
+
+ if (KeyHandle) {
+ if ( ! ReadRegistry( KeyHandle,
+ VARNAME_SETUPTYPE,
+ REG_DWORD,
+ (TCHAR*) & SetupType,
+ & SetupType ) )
+ SetupType = SETUPTYPE_NONE ;
+ NtClose(KeyHandle);
+ }
+
+ return SetupType ;
+}
+
+BOOL
+SetSetupType (
+ DWORD type
+ )
+/*++
+
+Routine Description:
+
+ Set the "SetupType" value in the Registry.
+
+Arguments:
+
+ DWORD type (see SETUPLGN.H)
+
+Return Value:
+
+ TRUE if operation successful.
+
+--*/
+
+{
+ char buffer[20];
+ BOOL Result = FALSE ;
+
+ HANDLE KeyHandle = OpenNtRegKey(KEYNAME_SETUP) ;
+
+ if (KeyHandle) {
+ sprintf(buffer,"%ld", type);
+ Result = WriteRegistry( KeyHandle,
+ VARNAME_SETUPTYPE_A,
+ REG_DWORD, buffer,
+ sizeof type );
+ NtClose(KeyHandle);
+ }
+ return Result ;
+}
+
+
+BOOL
+AppendToSetupCommandLine(
+ LPSTR pszCommandArguments
+ )
+/*++
+
+Routine Description:
+
+ Append to the setup command line in the Registry.
+
+Arguments:
+
+ LPSTR pszCommandArguments (e.g. " /t STF_COMPUTERNAME = MACHINENAME")
+
+Return Value:
+
+ TRUE if operation successful.
+
+--*/
+
+{
+ TCHAR CmdLineBuffer[512];
+ DWORD DataSize;
+ BOOL Result = FALSE ;
+
+ HANDLE KeyHandle = OpenNtRegKey(KEYNAME_SETUP) ;
+
+ if (KeyHandle) {
+ DataSize = sizeof(CmdLineBuffer);
+ Result = ReadRegistry( KeyHandle,
+ VARNAME_SETUPCMD,
+ REG_SZ,
+ CmdLineBuffer,
+ &DataSize
+ );
+ if (Result) {
+ UNICODE_STRING UniString;
+ STRING String;
+ char szBuf[1024];
+
+ String.Buffer = szBuf;
+ String.MaximumLength = sizeof(szBuf);
+ RtlInitUnicodeString(&UniString, CmdLineBuffer);
+ RtlUnicodeStringToAnsiString(&String, &UniString, FALSE);
+
+ RtlAppendAsciizToString(&String, pszCommandArguments);
+ String.Buffer[ String.Length ] = '\0';
+ Result = WriteRegistry( KeyHandle,
+ VARNAME_SETUPCMD_A,
+ REG_SZ,
+ szBuf,
+ String.Length
+ );
+ }
+ NtClose(KeyHandle);
+ }
+ return Result ;
+}
+
+
+VOID
+ExecuteSetup(
+ PGLOBALS pGlobals
+ )
+
+/*++
+
+Routine Description:
+
+ Execute setup.exe. The command line to be passed to setup is obtained
+ from HKEY_LOCAL_MACHINE\system\setup:cmdline. Wait for setup to complete
+ before returning.
+
+Arguments:
+
+ pGlobals - global data structure
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TCHAR CmdLineBuffer[1024];
+ TCHAR DebugCmdLineBuffer[1024];
+ PWCHAR CmdLine;
+ USER_PROCESS_DATA UserProcessData;
+ PROCESS_INFORMATION ProcessInformation;
+ HANDLE hProcess;
+ HANDLE hThread;
+ ULONG ThreadId;
+ HKEY hKey;
+ ULONG Result;
+ ULONG DataSize;
+ ULONG ExitCode;
+ MSG Msg;
+ USEROBJECTFLAGS uof;
+
+ //
+ // See if this is normal SETUP or special Net IDW setup
+ // during 2nd phase of triple boot; if Net IDW, alter
+ // WIN.INI the same way the WINLOGON.CMD script would.
+ //
+ if ( pGlobals->SetupType == SETUPTYPE_NETIDW ) {
+
+ //
+ // Establish the proper shell for the first real user boot
+ //
+ // Until the new shell is fully integrated, read which shell is
+ // desired from the "DefaultShell" value, and copy it over.
+
+ GetProfileString( APPNAME_WINLOGON,
+ TEXT("DefaultShell"),
+ TEXT("progman.exe"),
+ CmdLineBuffer,
+ sizeof(CmdLineBuffer)/sizeof(WCHAR) );
+
+ WriteProfileString( APPNAME_WINLOGON,
+ TEXT("DefaultShell"),
+ NULL );
+
+ WriteProfileString( APPNAME_WINLOGON,
+ VARNAME_SHELL,
+ CmdLineBuffer );
+
+
+ }
+
+ //
+ // Get the Setup command line from the registry
+ //
+
+ if((Result = RegOpenKey( HKEY_LOCAL_MACHINE,
+ REGNAME_SETUP,
+ &hKey)) == NO_ERROR) {
+
+ DataSize = sizeof(CmdLineBuffer);
+
+ Result = RegQueryValueEx( hKey,
+ VARNAME_SETUPCMD,
+ NULL,
+ NULL,
+ (LPBYTE)CmdLineBuffer,
+ &DataSize
+ );
+
+ if(Result == NO_ERROR) {
+ // DebugLog((DEB_ERROR, "Setup cmd line is '%s'",CmdLineBuffer));
+ } else {
+ DebugLog((DEB_ERROR, "error %u querying CmdLine value from \\system\\setup",Result));
+ }
+ RegCloseKey(hKey);
+
+ } else {
+ DebugLog((DEB_ERROR, "error %u opening \\system\\setup key for CmdLine (2)",Result));
+ }
+
+ // Alter "SetupType" to indicate setup is no long in progress.
+
+ SetSetupType( SETUPTYPE_NONE ) ;
+
+#ifdef INIT_REGISTRY
+ //
+ // Dont do this if we want to boot an extra time as Administrator
+ // so we can run winlogon.cmd command script.
+
+ if ( pGlobals->SetupType == SETUPTYPE_NETSRW ) {
+ WriteProfileString( APPNAME_WINLOGON, VARNAME_AUTOLOGON, TEXT("1") );
+ } else {
+#endif
+ // Delete "AutoAdminLogon" from WIN.INI if present
+ // except in the retail upgrade case.
+
+ if(pGlobals->SetupType != SETUPTYPE_UPGRADE) {
+ WriteProfileString( APPNAME_WINLOGON, VARNAME_AUTOLOGON, NULL );
+ }
+
+#ifdef INIT_REGISTRY
+ }
+#endif
+
+
+ RtlZeroMemory(&UserProcessData,sizeof(UserProcessData));
+
+ //
+ // Make windowstation and desktop handles inheritable.
+ //
+ GetUserObjectInformation(pGlobals->WindowStation.hwinsta, UOI_FLAGS, &uof, sizeof(uof), NULL);
+ uof.fInherit = TRUE;
+ SetUserObjectInformation(pGlobals->WindowStation.hwinsta, UOI_FLAGS, &uof, sizeof(uof));
+ GetUserObjectInformation(pGlobals->WindowStation.hdeskApplication, UOI_FLAGS, &uof, sizeof(uof), NULL);
+ uof.fInherit = TRUE;
+ SetUserObjectInformation(pGlobals->WindowStation.hdeskApplication, UOI_FLAGS, &uof, sizeof(uof));
+
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
+
+ CmdLine = CmdLineBuffer;
+#if DEVL
+ if ( bDebugSetup ) {
+ wsprintf( DebugCmdLineBuffer, TEXT("ntsd -d %s%s"),
+ bDebugSetup == 2 ? TEXT("-g -G ") : TEXT(""),
+ CmdLine
+ );
+ CmdLine = DebugCmdLineBuffer;
+ }
+#endif
+
+ if(StartSystemProcess( CmdLine,
+ TEXT("winsta0\\Default"),
+ 0,
+ 0, // Normal startup feedback
+ NULL,
+ FALSE,
+ &hProcess,
+ NULL) )
+ {
+ if (hProcess)
+ {
+
+
+ //
+ // Create a second thread to wait on the setup process.
+ // When setup terminates, the second thread will send us
+ // a special message. When we receive the special message,
+ // exit the dispatch loop.
+ //
+ // Do this to allow us to respond to messages sent by the
+ // system, thus preventing the system from hanging.
+ //
+
+ MainThreadId = GetCurrentThreadId();
+
+ hThread = CreateThread( NULL,
+ 0,
+ WaiterThread,
+ (LPVOID)hProcess,
+ 0,
+ &ThreadId
+ );
+ if(hThread) {
+
+ while(GetMessage(&Msg,NULL,0,0)) {
+ DispatchMessage(&Msg);
+ }
+
+ CloseHandle(hThread);
+ GetExitCodeProcess(hProcess,&ExitCode);
+
+ // BUGBUG look at exit code; may have to restart machine.
+
+ } else {
+ DebugLog((DEB_ERROR, "couldn't start waiter thread"));
+ }
+
+ CloseHandle(hProcess);
+
+ } else {
+ DebugLog((DEB_ERROR, "couldn't get handle to setup process, error = %u",GetLastError()));
+ }
+ } else {
+ DebugLog((DEB_ERROR, "couldn't exec '%ws'",CmdLine));
+ }
+
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+
+}
+
+
+DWORD
+WaiterThread(
+ PVOID hProcess
+ )
+{
+ WaitForSingleObject(hProcess,(DWORD)(-1));
+
+ PostThreadMessage(MainThreadId,WM_QUIT,0,0);
+
+ ExitThread(0);
+
+ return(0); // prevent compiler warning
+}
+
+
+
+VOID
+CheckForIncompleteSetup (
+ PGLOBALS pGlobals
+ )
+/*++
+
+Routine Description:
+
+ Checks to see if setup started but never completed.
+ Do this by checking to see if the SetupInProgress value has been
+ reset to 0. This value is set to 1 in the default hives that run setup.
+ Setup.exe resets it to 0 on successful completion.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD SetupInProgress = 0 ;
+ HANDLE KeyHandle = OpenNtRegKey(KEYNAME_SETUP) ;
+
+ if (KeyHandle) {
+ if ( ! ReadRegistry( KeyHandle,
+ VARNAME_SETUPINPROGRESS,
+ REG_DWORD,
+ (TCHAR*) & SetupInProgress,
+ & SetupInProgress ) ) {
+
+ SetupInProgress = 0;
+ }
+
+ NtClose(KeyHandle);
+ }
+
+
+ //
+ // If setup did not complete then make them reboot
+ //
+
+ if (SetupInProgress) {
+
+ TimeoutMessageBox(pGlobals,
+ NULL,
+ IDS_SETUP_INCOMPLETE,
+ IDS_WINDOWS_MESSAGE,
+ MB_ICONSTOP | MB_OK
+ );
+
+#if DBG
+ //
+ // On debug builds let them continue if they hold down Ctrl
+ //
+
+ if ((GetKeyState(VK_LCONTROL) < 0) ||
+ (GetKeyState(VK_RCONTROL) < 0)) {
+
+ return;
+ }
+#endif
+
+ //
+ // Reboot time
+ //
+
+ RebootMachine(pGlobals);
+
+ }
+}
+
+
+//
+// This function checks if the "Repair" value is set. If so, then
+// it loads syssetup.dll and calls RepairStartMenuItems
+//
+
+VOID
+CheckForRepairRequest (void)
+{
+ HKEY hkeyWinlogon;
+ LONG lResult;
+ DWORD dwSize, dwType;
+ BOOL bRunRepair = FALSE;
+ HINSTANCE hSysSetup;
+ REPAIRSTARTMENUITEMS RepairStartMenuItems;
+
+
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY,
+ 0, KEY_READ | KEY_WRITE, &hkeyWinlogon) == ERROR_SUCCESS) {
+
+ dwSize = sizeof(bRunRepair);
+
+ if (RegQueryValueEx (hkeyWinlogon, L"Repair",
+ NULL, &dwType, (LPBYTE) &bRunRepair,
+ &dwSize) == ERROR_SUCCESS) {
+
+ RegDeleteValue (hkeyWinlogon, L"Repair");
+ }
+
+ RegCloseKey (hkeyWinlogon);
+ }
+
+
+ if (bRunRepair) {
+
+ hSysSetup = LoadLibrary (L"syssetup.dll");
+
+ if (hSysSetup) {
+
+ RepairStartMenuItems = (REPAIRSTARTMENUITEMS)GetProcAddress(hSysSetup,
+ "RepairStartMenuItems");
+
+ if (RepairStartMenuItems) {
+ RepairStartMenuItems();
+ }
+
+ FreeLibrary (hSysSetup);
+ }
+ }
+
+}
diff --git a/private/windows/gina/winlogon/setup.h b/private/windows/gina/winlogon/setup.h
new file mode 100644
index 000000000..a13379c8d
--- /dev/null
+++ b/private/windows/gina/winlogon/setup.h
@@ -0,0 +1,102 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ setuplgn.h
+
+Abstract:
+
+ Private header file for the special version of winlogon for Setup.
+
+Author:
+
+ Ted Miller (tedm) 4-May-1992
+
+Revision History:
+
+--*/
+
+//
+// Scalars and functions to test and set the "SetupType" value item
+//
+
+#define SETUPTYPE_NONE 0
+#define SETUPTYPE_FULL 1
+#define SETUPTYPE_NETIDW 2
+#ifdef INIT_REGISTRY
+#define SETUPTYPE_NETSRW 3
+#endif
+#define SETUPTYPE_UPGRADE 4
+
+#define APPNAME_WINLOGON TEXT("Winlogon")
+#define VARNAME_SETUPTYPE TEXT("SetupType")
+#define VARNAME_SETUPTYPE_A "SetupType"
+#define VARNAME_SETUPCMD TEXT("Cmdline")
+#define VARNAME_SETUPCMD_A "Cmdline"
+#define VARNAME_AUTOLOGON TEXT("AutoAdminLogon")
+#define VARNAME_ENABLEQUICKREBOOT TEXT("EnableQuickReboot")
+#define VARNAME_ENABLEDESKTOPSWITCHING TEXT("EnableDesktopSwitching")
+#define VARNAME_SHELL TEXT("Shell")
+#define VARNAME_SETUPINPROGRESS TEXT("SystemSetupInProgress")
+#define VARNAME_SETUPINPROGRESS_A "SystemSetupInProgress"
+#define KEYNAME_SETUP TEXT("\\Registry\\Machine\\System\\Setup")
+#define REGNAME_SETUP TEXT("SYSTEM\\setup")
+
+DWORD
+CheckSetupType (
+ VOID
+ );
+
+BOOL
+SetSetupType (
+ DWORD type
+ );
+
+BOOL
+AppendToSetupCommandLine(
+ LPSTR pszCommandArguments
+ );
+
+//
+// Function to execute setup.exe and wait for it to complete.
+//
+
+VOID
+ExecuteSetup(
+ PGLOBALS pGlobals
+ );
+
+
+//
+// Handle to the event used by lsa to stall security initialization.
+//
+
+HANDLE LsaStallEvent;
+
+
+//
+// Function to create an event used by LSA to stall security initialization.
+//
+
+VOID
+CreateLsaStallEvent(
+ VOID
+ );
+
+
+
+VOID
+CheckForIncompleteSetup (
+ PGLOBALS pGlobals
+ );
+
+
+typedef
+VOID (WINAPI * REPAIRSTARTMENUITEMS)(
+ VOID
+ );
+
+VOID
+CheckForRepairRequest (void);
diff --git a/private/windows/gina/winlogon/shell.c b/private/windows/gina/winlogon/shell.c
new file mode 100644
index 000000000..713e7a38b
--- /dev/null
+++ b/private/windows/gina/winlogon/shell.c
@@ -0,0 +1,170 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: shell.c
+//
+// Contents: Microsoft Logon GUI DLL
+//
+// History: 7-14-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+BOOL
+SetProcessQuotas(
+ PPROCESS_INFORMATION ProcessInformation,
+ PUSER_PROCESS_DATA UserProcessData
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL Result;
+ QUOTA_LIMITS RequestedLimits;
+
+ RequestedLimits = UserProcessData->Quotas;
+ RequestedLimits.MinimumWorkingSetSize = 0;
+ RequestedLimits.MaximumWorkingSetSize = 0;
+
+ if (UserProcessData->Quotas.PagedPoolLimit != 0) {
+
+ Result = EnablePrivilege(SE_INCREASE_QUOTA_PRIVILEGE, TRUE);
+ if (!Result) {
+ DebugLog((DEB_ERROR, "failed to enable increase_quota privilege\n"));
+ return(FALSE);
+ }
+
+ Status = NtSetInformationProcess(
+ ProcessInformation->hProcess,
+ ProcessQuotaLimits,
+ (PVOID)&RequestedLimits,
+ (ULONG)sizeof(QUOTA_LIMITS)
+ );
+
+ Result = EnablePrivilege(SE_INCREASE_QUOTA_PRIVILEGE, FALSE);
+ if (!Result) {
+ DebugLog((DEB_ERROR, "failed to disable increase_quota privilege\n"));
+ }
+ }
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "SetProcessQuotas failed. Status: 0x%lx\n", Status));
+ }
+#endif //DBG
+
+ return (NT_SUCCESS(Status));
+}
+
+
+BOOL
+ExecApplication(
+ IN LPTSTR pch,
+ IN LPTSTR Desktop,
+ IN PGLOBALS pGlobals,
+ IN PVOID pEnvironment,
+ IN DWORD Flags,
+ IN DWORD StartupFlags,
+ OUT PPROCESS_INFORMATION ProcessInformation
+ )
+{
+ STARTUPINFO si;
+ BOOL Result, IgnoreResult;
+ HANDLE ImpersonationHandle;
+
+
+ //
+ // 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) {
+ DebugLog((DEB_ERROR, "ExecApplication failed to impersonate user\n"));
+ return(FALSE);
+ }
+
+
+ //
+ // Create the app suspended
+ //
+ DebugLog((DEB_TRACE, "About to create process of %ws, on desktop %ws\n", pch, Desktop));
+ Result = CreateProcessAsUser(
+ pGlobals->UserProcessData.UserToken,
+ NULL,
+ pch,
+ NULL,
+ NULL,
+ FALSE,
+ Flags | CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT,
+ pEnvironment,
+ NULL,
+ &si,
+ ProcessInformation);
+
+
+ IgnoreResult = StopImpersonating(ImpersonationHandle);
+ ASSERT(IgnoreResult);
+
+ return(Result);
+
+}
+
+
+
+BOOL
+WINAPI
+WlxStartApplication(
+ PVOID pWlxContext,
+ PWSTR pszDesktop,
+ PVOID pEnvironment,
+ PWSTR pszCmdLine
+ )
+{
+ PROCESS_INFORMATION ProcessInformation;
+ BOOL bExec;
+
+ bExec = ExecApplication (pszCmdLine,
+ pszDesktop,
+ g_pGlobals,
+ pEnvironment,
+ 0,
+ STARTF_USESHOWWINDOW,
+ &ProcessInformation);
+
+ if (!bExec) {
+ return(FALSE);
+ }
+
+ if (SetProcessQuotas(&ProcessInformation,
+ &g_pGlobals->UserProcessData)) {
+ ResumeThread(ProcessInformation.hThread);
+
+ } else {
+ TerminateProcess(ProcessInformation.hProcess,
+ ERROR_ACCESS_DENIED);
+ }
+
+
+ CloseHandle(ProcessInformation.hThread);
+ CloseHandle(ProcessInformation.hProcess);
+
+ return(TRUE);
+}
diff --git a/private/windows/gina/winlogon/shutdown.h b/private/windows/gina/winlogon/shutdown.h
new file mode 100644
index 000000000..9c7579aea
--- /dev/null
+++ b/private/windows/gina/winlogon/shutdown.h
@@ -0,0 +1,23 @@
+//
+// The Shutdown Query dialog and Logoff Windows NT dialog
+// are shared by Progman (included in windows\shell\progman\progman.dlg),
+// and therefore changes to them or the filename should not be made
+// unless tested with Progman first.
+// This header file is included in windows\shell\progman\pmdlg.h
+//
+// 11/10/92 johannec
+//
+
+#define IDD_SHUTDOWN_QUERY 1200
+#define IDD_CLOSEAPPS 1201
+#define IDD_RESTART 1202
+#define IDD_END_WINDOWS_SESSION 1203
+#define IDD_POWEROFF 1204
+
+#define DLGSEL_LOGOFF 0
+#define DLGSEL_SHUTDOWN 1
+#define DLGSEL_SHUTDOWN_AND_RESTART 2
+#define DLGSEL_SHUTDOWN_AND_POWEROFF 3
+
+#define SHUTDOWN_SETTING_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Shutdown"
+#define SHUTDOWN_SETTING L"Shutdown Setting"
diff --git a/private/windows/gina/winlogon/shutdown.ico b/private/windows/gina/winlogon/shutdown.ico
new file mode 100644
index 000000000..2512943dd
--- /dev/null
+++ b/private/windows/gina/winlogon/shutdown.ico
Binary files differ
diff --git a/private/windows/gina/winlogon/sources b/private/windows/gina/winlogon/sources
new file mode 100644
index 000000000..3080168ff
--- /dev/null
+++ b/private/windows/gina/winlogon/sources
@@ -0,0 +1,88 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+
+MAJORCOMP=windows
+MINORCOMP=winlogon
+
+TARGETNAME=winlogon
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+INCLUDES=.;$(TARGET_DIRECTORY);..\..\inc;..\..\..\inc;..\..\screg\winreg
+C_DEFINES=-DUNICODE
+
+!ifndef MSC_WARNING_LEVEL
+MSC_WARNING_LEVEL=-W3 -WX
+!endif
+
+BACKGROUND_USE=1
+
+SOURCES= \
+ debug.c \
+ doslog.c \
+ envvar.c \
+ ginamgr.c \
+ logoff.c \
+ misc.c \
+ monitor.c \
+ msgalias.c \
+ provider.c \
+ regini.c \
+ removabl.c \
+ res.rc \
+ sas.c \
+ scrnsave.c \
+ secutil.c \
+ setup.c \
+ shell.c \
+ sysinit.c \
+ sysshut.c \
+ timeout.c \
+ usrenv.c \
+ usrpro.c \
+ win31mig.c \
+ winlogon.c \
+ winutil.c \
+ wlx.c \
+ wlxutil.c
+
+USE_CRTDLL=1
+
+UMTYPE=windows
+UMENTRY=winmain
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\rpcutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\lsadll.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32p.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\userenv.lib \
+ ..\..\screg\winreg\server\obj\*\winreg.lib \
+ ..\..\screg\winreg\perflib\obj\*\perflib.lib \
+ ..\..\screg\winreg\lib\obj\*\wrlib.lib
+
+NTTARGETFILE0=wlevents.h
diff --git a/private/windows/gina/winlogon/stringid.h b/private/windows/gina/winlogon/stringid.h
new file mode 100644
index 000000000..d091e553f
--- /dev/null
+++ b/private/windows/gina/winlogon/stringid.h
@@ -0,0 +1,44 @@
+/****************************** Module Header ******************************\
+* Module Name: stringid.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Defines resource ids for resources other than dialogs
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+//
+// Strings
+//
+#define IDS_RESTART_SYSTEM 1520
+#define IDS_WINDOWS_MESSAGE 1524
+#define IDS_SAFE_TO_TURN_OFF 1526
+#define IDS_SHUTDOWN_MESSAGE 1527
+
+
+
+#define IDS_SYSTEM_SCREEN_SAVER_NAME 1564
+
+
+#define IDS_SOUND_DLL 1570
+#define IDS_WAVEOUTGETNUMDEVS 1571
+#define IDS_PLAYSOUND 1572
+#define IDS_MIGRATESOUNDEVENTS 1573
+#define IDS_MIDI_DLL 1574
+#define IDS_MIGRATEMIDIUSER 1575
+
+#define IDS_NO_PAGING_FILE 1580
+#define IDS_LIMITED_RESOURCES 1581
+
+#define IDS_INVALID_TIME 1582
+#define IDS_INVALID_TIME_MSG 1583
+
+#define IDS_SETUP_INCOMPLETE 1590
+
+#define IDS_ACCOUNT_LOCKED 1603
+
+#define IDS_ADMIN_ACCOUNT_NAME 1700
+
+#define IDD_SHUTDOWN_BITMAP 4
diff --git a/private/windows/gina/winlogon/strings.h b/private/windows/gina/winlogon/strings.h
new file mode 100644
index 000000000..3cc268148
--- /dev/null
+++ b/private/windows/gina/winlogon/strings.h
@@ -0,0 +1,54 @@
+/****************************** Module Header ******************************\
+* Module Name: strings.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Defines strings that do not need to be localized.
+*
+* History:
+* 11-17-92 Davidc Created.
+\***************************************************************************/
+
+//
+// App name strings
+//
+
+#define WINLOGON TEXT("WINLOGON")
+
+
+//
+// Define where we store the most recent logon information
+//
+
+#define APPLICATION_NAME WINLOGON
+
+//
+// Define where we get screen-saver information
+//
+
+#define SCREEN_SAVER_INI_FILE TEXT("system.ini")
+#define SCREEN_SAVER_INI_SECTION TEXT("boot")
+#define SCREEN_SAVER_FILENAME_KEY TEXT("SCRNSAVE.EXE")
+#define SCREEN_SAVER_SECURE_KEY TEXT("ScreenSaverIsSecure")
+
+#define WINDOWS_INI_SECTION TEXT("Windows")
+#define SCREEN_SAVER_ENABLED_KEY TEXT("ScreenSaveActive")
+
+//
+// Gina is loaded from:
+//
+
+#define GINA_KEY TEXT("GinaDll")
+#define LOCK_GRACE_PERIOD_KEY TEXT("ScreenSaverGracePeriod")
+#define LOCK_DEFAULT_VALUE 5
+#define KEEP_RAS_AFTER_LOGOFF TEXT("KeepRasConnections")
+#define RESTRICT_NONINTERACTIVE_ACCESS TEXT("RestrictNonInteractiveAccess")
+
+
+//
+// Shell= line in the registry
+//
+
+#define SHELL_KEY TEXT("Shell")
+#define RASAPI32 TEXT("rasapi32.dll")
+#define RASMAN_SERVICE_NAME TEXT("RASMAN")
diff --git a/private/windows/gina/winlogon/strings.rc b/private/windows/gina/winlogon/strings.rc
new file mode 100644
index 000000000..3b9fad652
--- /dev/null
+++ b/private/windows/gina/winlogon/strings.rc
@@ -0,0 +1,46 @@
+/****************************** Module Header ******************************\
+* Module Name: strings.rc
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Defines string resources
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+STRINGTABLE
+BEGIN
+
+IDS_RESTART_SYSTEM "Restart system"
+IDS_WINDOWS_MESSAGE "Windows Message"
+IDS_SAFE_TO_TURN_OFF "It is now safe to turn off the computer."
+IDS_SHUTDOWN_MESSAGE "Shutdown Message"
+IDS_NO_PAGING_FILE "Your system is running without a properly sized paging file. Please use the virtual memory option of the System applet in the Control Panel to create a paging file, or to increase the initial size of your paging file."
+IDS_LIMITED_RESOURCES "Limited Virtual Memory"
+IDS_INVALID_TIME_MSG "The time or date on your system is invalid. Please use the date/time applet in the Control Panel to properly set your system time and date."
+IDS_INVALID_TIME "Invalid System Time"
+IDS_SETUP_INCOMPLETE "The system is not fully installed. Please run setup again."
+IDS_ACCOUNT_LOCKED "Unable to log you on because your account has been locked out, please contact your administrator."
+
+
+//
+// Screen saver strings
+//
+
+IDS_SYSTEM_SCREEN_SAVER_NAME "system.scr"
+
+IDS_ADMIN_ACCOUNT_NAME "Administrator"
+
+//
+// Define multimedia strings
+//
+
+IDS_SOUND_DLL "WINMM"
+IDS_WAVEOUTGETNUMDEVS "waveOutGetNumDevs"
+IDS_PLAYSOUND "PlaySound"
+IDS_MIGRATESOUNDEVENTS "MigrateSoundEvents"
+IDS_MIDI_DLL "WINMM"
+IDS_MIGRATEMIDIUSER "MigrateMidiUser"
+
+END
diff --git a/private/windows/gina/winlogon/sysinit.c b/private/windows/gina/winlogon/sysinit.c
new file mode 100644
index 000000000..fb6ceee9b
--- /dev/null
+++ b/private/windows/gina/winlogon/sysinit.c
@@ -0,0 +1,969 @@
+/****************************** Module Header ******************************\
+* Module Name: sysinit.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Winlogon main module
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+BOOLEAN PageFilePopup = FALSE;
+
+TCHAR szMemMan[] =
+ TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
+
+TCHAR szNoPageFile[] = TEXT("TempPageFile");
+
+HANDLE hSystemProcesses[MAXIMUM_WAIT_OBJECTS];
+DWORD cSystemProcesses;
+
+#define DEBUG_COMMAND TEXT("ntsd -d ")
+#define DEBUG_COMMAND_NO_WAIT TEXT("ntsd -d -g ")
+#define SELECT_DEBUG_COMMAND(x) (x & DEB_DEBUG_NOWAIT ? DEBUG_COMMAND_NO_WAIT : DEBUG_COMMAND)
+
+
+//
+// Bogus #2: InitializeWinreg is defined in regrpc.h, but we can't include
+// it in any file that uses RegXxx APIs. So, rather than add yet another
+// source file, this is explicitly prototyped here, and any change there has
+// to be reflected here.
+//
+
+BOOL
+InitializeWinreg(void);
+
+
+//
+// Look for autocheck logs, and log them
+//
+
+VOID
+DealWithAutochkLogs(
+ VOID
+ )
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE Handle;
+ HANDLE DirectoryHandle;
+
+ POBJECT_DIRECTORY_INFORMATION DirInfo;
+ CHAR DirInfoBuffer[ 256 ];
+ ULONG Context, Length;
+ BOOLEAN RestartScan;
+ GLOBALS LocalGlobals;
+
+ UNICODE_STRING UnicodeString;
+ UNICODE_STRING LinkTarget;
+ UNICODE_STRING LinkTypeName;
+ UNICODE_STRING LinkTargetPrefix;
+ WCHAR LinkTargetBuffer[ MAXIMUM_FILENAME_LENGTH ];
+ WCHAR LogFile[MAX_PATH];
+ HANDLE LogFileHandle;
+ DWORD FileSize,BytesRead;
+ WCHAR *FileBuffer;
+ DWORD ServerRetryCount;
+ DWORD rv;
+ DWORD gle;
+ UINT OldMode;
+
+
+ ZeroMemory(&LocalGlobals,sizeof(LocalGlobals));
+ LinkTarget.Buffer = LinkTargetBuffer;
+
+ DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer;
+ RestartScan = TRUE;
+ RtlInitUnicodeString( &LinkTypeName, L"SymbolicLink" );
+ RtlInitUnicodeString( &LinkTargetPrefix, L"\\Device\\Harddisk" );
+
+ RtlInitUnicodeString( &UnicodeString, L"\\DosDevices" );
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+ Status = NtOpenDirectoryObject( &DirectoryHandle,
+ DIRECTORY_QUERY,
+ &ObjectAttributes
+ );
+ if (!NT_SUCCESS( Status )) {
+ return;
+ }
+
+ while (TRUE) {
+ Status = NtQueryDirectoryObject( DirectoryHandle,
+ (PVOID)DirInfo,
+ sizeof( DirInfoBuffer ),
+ TRUE,
+ RestartScan,
+ &Context,
+ &Length
+ );
+ if (!NT_SUCCESS( Status )) {
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ if (RtlEqualUnicodeString( &DirInfo->TypeName, &LinkTypeName, TRUE ) &&
+ DirInfo->Name.Buffer[(DirInfo->Name.Length>>1)-1] == L':') {
+ InitializeObjectAttributes( &ObjectAttributes,
+ &DirInfo->Name,
+ OBJ_CASE_INSENSITIVE,
+ DirectoryHandle,
+ NULL
+ );
+ Status = NtOpenSymbolicLinkObject( &Handle,
+ SYMBOLIC_LINK_QUERY,
+ &ObjectAttributes
+ );
+ if (NT_SUCCESS( Status )) {
+ LinkTarget.Length = 0;
+ LinkTarget.MaximumLength = sizeof( LinkTargetBuffer );
+ Status = NtQuerySymbolicLinkObject( Handle,
+ &LinkTarget,
+ NULL
+ );
+ NtClose( Handle );
+ if (NT_SUCCESS( Status ) &&
+ RtlPrefixUnicodeString( &LinkTargetPrefix, &LinkTarget, TRUE )
+ ) {
+
+ CopyMemory(LogFile,DirInfo->Name.Buffer,DirInfo->Name.Length);
+ LogFile[DirInfo->Name.Length >> 1] = (WCHAR)0;
+ wcscat(LogFile,L"\\bootex.log");
+
+ OldMode = SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS );
+
+ LogFileHandle = CreateFileW(
+ LogFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ (VOID )SetErrorMode( OldMode );
+
+ if ( LogFileHandle != INVALID_HANDLE_VALUE ) {
+ FileSize = GetFileSize(LogFileHandle,NULL);
+ if ( FileSize != 0xffffffff ) {
+
+ //
+ // truncate the file data if necessary
+ //
+ if ( FileSize > 32000 ) {
+ FileSize = 32000;
+ }
+ FileBuffer = LocalAlloc(LMEM_FIXED,FileSize+sizeof(WCHAR));
+ if ( FileBuffer ) {
+ FileBuffer[FileSize>>1] = (WCHAR)'\0';
+ if ( ReadFile(LogFileHandle,FileBuffer,FileSize,&BytesRead,NULL) ) {
+ FileBuffer[BytesRead>>1] = (WCHAR)'\0';
+
+ ServerRetryCount = 0;
+tryagain:
+ LocalGlobals.hEventLog = RegisterEventSource(
+ NULL,
+ TEXT("Autochk")
+ );
+ if ( LocalGlobals.hEventLog ) {
+ rv = ReportWinlogonEvent(
+ &LocalGlobals,
+ EVENTLOG_INFORMATION_TYPE,
+ EVENT_AUTOCHK_DATA,
+ 0,
+ NULL,
+ 1,
+ FileBuffer
+ );
+ DeregisterEventSource(LocalGlobals.hEventLog);
+ LocalGlobals.hEventLog = NULL;
+ NtClose(LogFileHandle);
+ LogFileHandle = INVALID_HANDLE_VALUE;
+ if ( rv == ERROR_SUCCESS ) {
+ DeleteFile(LogFile);
+ }
+ }
+ else {
+ gle = GetLastError();
+ if ( (gle == RPC_S_SERVER_UNAVAILABLE ||
+ gle == RPC_S_UNKNOWN_IF)
+ && ServerRetryCount < 10 ) {
+ Sleep(1000);
+ ServerRetryCount++;
+ goto tryagain;
+ }
+ }
+
+ }
+ }
+ }
+ if (LogFileHandle != INVALID_HANDLE_VALUE ) {
+ NtClose(LogFileHandle);
+ }
+ }
+
+ }
+ }
+ }
+
+ RestartScan = FALSE;
+ if (!NT_SUCCESS( Status )) {
+ break;
+ }
+ }
+ NtClose(DirectoryHandle);
+ return;
+}
+
+
+DWORD FontLoaderThread( void )
+{
+ LoadLocalFonts();
+ ExitThread(0);
+ return(0); // prevent compiler warning
+}
+
+HANDLE
+StartLoadingFonts(void)
+{
+ HANDLE hThread;
+ DWORD ThreadId = 0;
+
+ hThread = CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE) FontLoaderThread,
+ 0,
+ 0,
+ &ThreadId
+ );
+
+ //
+ // We don't need this handle (we're not going to wait), so get rid of
+ // it now, rather than later.
+ //
+
+ return( hThread );
+}
+
+
+BOOL InitSystemFontInfo(
+ PGLOBALS pGlobals
+ )
+{
+ TCHAR *FontNames, *FontName;
+ TCHAR FontPath[ MAX_PATH ];
+ ULONG cb = 63 * 1024;
+
+
+ FontNames = Alloc( cb );
+ ASSERTMSG("Winlogon failed to allocate memory for reading font information", FontNames != NULL);
+ if (FontNames == NULL) {
+ return FALSE;
+ }
+
+ if (GetProfileString( TEXT("Fonts"), NULL, TEXT(""), FontNames, cb )) {
+ FontName = FontNames;
+ while (*FontName) {
+ if (GetProfileString( TEXT("Fonts"), FontName, TEXT(""), FontPath, sizeof( FontPath ) )) {
+ switch (AddFontResource( FontPath )) {
+ case 0:
+ KdPrint(("WINLOGON: Unable to add new font path: %ws\n", FontPath ));
+ break;
+
+ case 1:
+ KdPrint(("WINLOGON: Found new font path: %ws\n", FontPath ));
+ break;
+
+ default:
+ KdPrint(("WINLOGON: Found existing font path: %ws\n", FontPath ));
+ RemoveFontResource( FontPath );
+ break;
+ }
+ }
+ while (*FontName++) ;
+ }
+ } else {
+ KdPrint(("WINLOGON: Unable to read font info from win.ini - %u\n", GetLastError()));
+ }
+
+ Free( FontNames );
+ return TRUE;
+}
+
+
+/***************************************************************************\
+* SetProcessPriority
+*
+* Sets the priority of the winlogon process.
+*
+* History:
+* 18-May-1992 Davidc Created.
+\***************************************************************************/
+BOOL SetProcessPriority(
+ VOID
+ )
+{
+ //
+ // Bump us up to the high priority class
+ //
+
+ if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
+ DebugLog((DEB_ERROR, "Failed to raise it's own process priority, error = %d", GetLastError()));
+ return(FALSE);
+ }
+
+ //
+ // Set this thread to high priority since we'll be handling all input
+ //
+
+ if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
+ DebugLog((DEB_ERROR, "Failed to raise main thread priority, error = %d", GetLastError()));
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+VOID
+CreateTemporaryPageFile()
+{
+ LONG FileSizeInMegabytes;
+ UNICODE_STRING PagingFileName;
+ NTSTATUS st;
+ LARGE_INTEGER MinPagingFileSize;
+ LARGE_INTEGER MaxPagingFileSize;
+ UNICODE_STRING FileName;
+ BOOLEAN TranslationStatus;
+ TCHAR TemporaryPageFile[MAX_PATH+1];
+ NTSTATUS PfiStatus,PiStatus;
+ ULONG ReturnLength;
+ SYSTEM_PAGEFILE_INFORMATION pfi;
+ SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
+ HKEY hkeyMM;
+ DWORD dwRegData = 0;
+
+
+ GetSystemDirectory(TemporaryPageFile,sizeof(TemporaryPageFile));
+ wcscat(TemporaryPageFile,TEXT("\\temppf.sys"));
+ DeleteFile(TemporaryPageFile);
+
+ //
+ // Check to see if we have a pagefile, warn the user if we don't
+ //
+
+ PfiStatus = NtQuerySystemInformation(
+ SystemPageFileInformation,
+ &pfi,
+ sizeof(pfi),
+ &ReturnLength
+ );
+
+ PiStatus = NtQuerySystemInformation(
+ SystemPerformanceInformation,
+ &PerfInfo,
+ sizeof(PerfInfo),
+ NULL
+ );
+ //
+ // if you have no page file, or your total commit limit is at it's minimum,
+ // then create an additional pagefile and tel the user to do something...
+ //
+
+ if ( (NT_SUCCESS(PfiStatus) && (ReturnLength == 0)) ||
+ (NT_SUCCESS(PiStatus) && PerfInfo.CommitLimit <= 5500 ) ) {
+
+ //
+ // Set a flag in registry so USERINIT knows to run VMApp.
+ //
+ dwRegData = 1;
+
+ PageFilePopup = TRUE;
+
+ //
+ // create a temporary pagefile to get us through logon/control
+ // panel activation
+ //
+ //
+
+ GetSystemDirectory(TemporaryPageFile,sizeof(TemporaryPageFile));
+ lstrcat(TemporaryPageFile,TEXT("\\temppf.sys"));
+
+
+ //
+ // Start with a 20mb pagefile
+ //
+
+ FileSizeInMegabytes = 20;
+
+ RtlInitUnicodeString(&PagingFileName, TemporaryPageFile);
+
+ MinPagingFileSize = RtlEnlargedIntegerMultiply(FileSizeInMegabytes,0x100000);
+ MaxPagingFileSize = MinPagingFileSize;
+
+
+ TranslationStatus = RtlDosPathNameToNtPathName_U(
+ PagingFileName.Buffer,
+ &FileName,
+ NULL,
+ NULL
+ );
+
+ if ( TranslationStatus ) {
+
+retry:
+ st = NtCreatePagingFile(
+ (PUNICODE_STRING)&FileName,
+ &MinPagingFileSize,
+ &MaxPagingFileSize,
+ 0
+ );
+
+ if (!NT_SUCCESS( st )) {
+
+ if ( FileSizeInMegabytes > 0 ) {
+ FileSizeInMegabytes -= 2;
+ MinPagingFileSize = RtlEnlargedIntegerMultiply(FileSizeInMegabytes,0x100000);
+ MaxPagingFileSize = MinPagingFileSize;
+ goto retry;
+ }
+ } else {
+ MoveFileExW(PagingFileName.Buffer,NULL,MOVEFILE_DELAY_UNTIL_REBOOT);
+
+ }
+
+ RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
+
+ }
+ }
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMemMan, 0,
+ KEY_WRITE, &hkeyMM) == ERROR_SUCCESS) {
+ if (dwRegData == 1) {
+ RegSetValueEx (hkeyMM, szNoPageFile, 0, REG_DWORD,
+ (LPBYTE)&dwRegData, sizeof(dwRegData));
+ } else
+ RegDeleteValue(hkeyMM, (LPTSTR)szNoPageFile);
+ RegCloseKey(hkeyMM);
+ }
+}
+
+
+BOOL
+StartSystemProcess(
+ PWSTR pszCommandLine,
+ PWSTR pszDesktop,
+ DWORD Flags,
+ DWORD StartupFlags,
+ PVOID pEnvironment,
+ BOOLEAN fSaveHandle,
+ HANDLE *phProcess,
+ HANDLE *phThread
+ )
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ BOOL Result;
+#if DBG
+ WCHAR szExtra[MAX_PATH];
+#endif
+
+ //
+ // Initialize process startup info
+ //
+ ZeroMemory(&si, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+ si.lpReserved = pszCommandLine;
+ si.lpTitle = pszCommandLine;
+ si.dwFlags = StartupFlags;
+ si.wShowWindow = SW_SHOW; // at least let the guy see it
+ si.lpDesktop = pszDesktop;
+
+ //
+ // Special debug helpers for our friends
+ //
+#if DBG
+ if ((WinlogonInfoLevel & DEB_DEBUG_LSA) &&
+ ((wcsncmp(pszCommandLine, TEXT("lsass"), 5) == 0) ||
+ (wcsncmp(pszCommandLine, TEXT("spmgr"), 5) == 0) ))
+ {
+ wcscpy(szExtra, SELECT_DEBUG_COMMAND(WinlogonInfoLevel));
+ wcscat(szExtra, pszCommandLine);
+ pszCommandLine = szExtra;
+ }
+ if ((WinlogonInfoLevel & DEB_DEBUG_MPR) &&
+ (wcsncmp(pszCommandLine, TEXT("mpnotify"), 8) == 0))
+ {
+ wcscpy(szExtra, SELECT_DEBUG_COMMAND(WinlogonInfoLevel));
+ wcscat(szExtra, pszCommandLine);
+ pszCommandLine = szExtra;
+ }
+ if ((WinlogonInfoLevel & DEB_DEBUG_SERVICES) &&
+ (wcsncmp(pszCommandLine, TEXT("services"), 8) == 0))
+ {
+ wcscpy(szExtra, SELECT_DEBUG_COMMAND(WinlogonInfoLevel));
+ wcscat(szExtra, pszCommandLine);
+ pszCommandLine = szExtra;
+ }
+#endif
+
+
+ //
+ // Create the app suspended
+ //
+ Result = CreateProcess(NULL,
+ pszCommandLine,
+ NULL,
+ NULL,
+ FALSE,
+ Flags | CREATE_UNICODE_ENVIRONMENT,
+ pEnvironment,
+ NULL,
+ &si,
+ &pi);
+
+
+ if (Result)
+ {
+ if (!phProcess)
+ {
+ if (fSaveHandle)
+ {
+ if (cSystemProcesses < MAXIMUM_WAIT_OBJECTS)
+ {
+ hSystemProcesses[cSystemProcesses++] = pi.hProcess;
+ }
+ }
+ else
+ {
+ CloseHandle(pi.hProcess);
+ }
+ }
+ else
+ {
+ *phProcess = pi.hProcess;
+ }
+ if (!phThread)
+ {
+ CloseHandle(pi.hThread);
+ }
+ else
+ {
+ *phThread = pi.hThread;
+ }
+ }
+
+ return(Result);
+}
+
+
+BOOL
+ExecSystemProcesses(
+ PGLOBALS pGlobals
+ )
+{
+ BOOL SystemStarted = FALSE ;
+ SYSTEM_CRASH_STATE_INFORMATION CrashState;
+ PWSTR pszStartLine;
+ PWSTR pszTok;
+ DWORD dwStarted = 0;
+ PVOID pEnvironment;
+
+ //
+ // Initialize the shutdown server
+ //
+
+ RpcpInitRpcServer();
+ if ( !InitializeShutdownModule( pGlobals ) ) {
+ ASSERT( FALSE );
+ DebugLog((DEB_ERROR, "Cannot InitializeShutdownModule."));
+ }
+
+ //
+ // Initialize the registry server
+ //
+ // NB: This is prototyped local to this file. Any change must be
+ // reflected above.
+ //
+
+ if ( !InitializeWinreg() ) {
+ ASSERT( FALSE );
+ DebugLog((DEB_ERROR, "Cannot InitializeWinreg."));
+ }
+
+
+
+ //
+ // must start services.exe server before anything else. If there is an
+ // entry ServiceControllerStart in win.ini, use it as the command.
+ //
+ pszStartLine = AllocAndGetProfileString(APPLICATION_NAME,
+ TEXT("ServiceControllerStart"),
+ TEXT("services.exe"));
+
+ if (!pszStartLine)
+ {
+ DebugLog((DEB_ERROR, "Can't allocate space, so this exec probably won't work\n"));
+ pszStartLine = TEXT("services.exe");
+ }
+
+ if (CreateUserEnvironment(&pEnvironment))
+ {
+ SetupBasicEnvironment(&pEnvironment);
+ }
+ else
+ {
+ DebugLog((DEB_ERROR, "Failed to create initial environment\n"));
+
+ //
+ // Set this to NULL, and let CreateProcess deal with any
+ // memory constraints.
+ //
+ pEnvironment = NULL;
+ }
+
+ if (!StartSystemProcess(pszStartLine,
+ APPLICATION_DESKTOP_NAME,
+ 0,
+ STARTF_FORCEOFFFEEDBACK,
+ pEnvironment,
+ FALSE, // Don't stash this handle away
+ NULL, NULL))
+ {
+ DebugLog((DEB_ERROR, "Couldn't start %ws, %d\n", pszStartLine, GetLastError()));
+ }
+
+ else
+ {
+ HANDLE hRPCRegServer;
+ int error,
+ i = 0 ;
+
+ while(i < 20000) {
+ Sleep(1000); i+=1000;
+ if (hRPCRegServer = OpenEventA(SYNCHRONIZE, FALSE, "Microsoft.RPC_Registry_Server")) {
+ //WLPrint(("RPC_Registry_Server event openned"));
+ error = WaitForSingleObject(hRPCRegServer, 100);
+ CloseHandle(hRPCRegServer);
+ break;
+ }
+ }
+ }
+
+ Free(pszStartLine);
+
+ //
+ // If this is standard installation or network installation, we need to
+ // create an event to stall lsa security initialization. In the case of
+ // WINNT -> WINNT and AS -> AS upgrade we shouldn't stall LSA.
+ //
+ if (pGlobals->fExecuteSetup && (pGlobals->SetupType != SETUPTYPE_UPGRADE)) {
+ CreateLsaStallEvent();
+ }
+
+ //
+ // If there is a system dump available, start up the save dump process to
+ // capture it so that it doesn't use as much paging file so that it is
+ // available for system use.
+ //
+
+ NtQuerySystemInformation( SystemCrashDumpStateInformation,
+ &CrashState,
+ sizeof( CrashState ),
+ (PULONG) NULL );
+ if (CrashState.ValidCrashDump) {
+ pszStartLine = AllocAndGetProfileString(APPLICATION_NAME,
+ TEXT("SaveDumpStart"),
+ TEXT("savedump.exe"));
+
+
+ if (!StartSystemProcess(pszStartLine,
+ APPLICATION_DESKTOP_NAME,
+ 0,
+ STARTF_FORCEOFFFEEDBACK,
+ pEnvironment,
+ FALSE, // Don't care about syncing later
+ NULL, NULL))
+ {
+ DebugLog((DEB_ERROR, "Couldn't start %ws, %d\n", pszStartLine, GetLastError()));
+ }
+ Free(pszStartLine);
+ }
+
+ //
+ // Startup system processes
+ // These must be started for authentication initialization to succeed
+ // because one of the system processes is the LSA server.
+ //
+ pszStartLine = AllocAndGetProfileString(APPLICATION_NAME,
+ TEXT("System"),
+ NULL);
+
+ pszTok = wcstok(pszStartLine, TEXT(","));
+ while (pszTok)
+ {
+ //
+ // Skip any blanks...
+ //
+ if (*pszTok == TEXT(' '))
+ {
+ while (*pszTok++ == TEXT(' '))
+ ;
+ }
+
+ if (StartSystemProcess( pszTok,
+ APPLICATION_DESKTOP_NAME,
+ 0,
+ STARTF_FORCEOFFFEEDBACK,
+ pEnvironment,
+ TRUE, // Save this handle to sync with
+ NULL, NULL))
+ {
+ dwStarted++;
+ }
+ pszTok = wcstok(NULL, TEXT(","));
+
+ }
+
+ Free(pszStartLine);
+
+ RtlDestroyEnvironment(pEnvironment);
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+* InitializeSound
+*
+* Set up a global function variable to address the sound playing routine.
+* If no wave devices are present, this variable will remain 0 and no sound
+* will be made by WinLogon.
+*
+* History:
+* 6-May-1992 SteveDav Created
+\***************************************************************************/
+void InitializeSound(
+ PGLOBALS pGlobals)
+{
+ //
+ // Load the sound playing module. If no wave devices are available
+ // free the library, and set the address of the sound function to 0
+ //
+
+ CHAR ResourceString[MAX_STRING_BYTES];
+ HANDLE hLib;
+
+ // Set the initial value (should not be necessary)
+ pGlobals->PlaySound = NULL;
+ pGlobals->MigrateSoundEvents = NULL;
+
+ //
+ // Get name of sound library
+ //
+ if (!LoadStringA(NULL, IDS_SOUND_DLL, ResourceString, sizeof(ResourceString))) {
+ // Cannot get the name of the sound library
+ return;
+ }
+
+ hLib = LoadLibraryA(ResourceString);
+
+ if (hLib) {
+
+ /* We must use the Ascii version of LoadString as GetProcAddress */
+ /* takes an Ascii string only... */
+
+ /* Whenever a user logs in, have WINMM.DLL check if there are any */
+ /* sound events within the [SOUNDS] section of CONTROL.INI that */
+ /* haven't been ported into HKCU/AppEvents. Here, we find the */
+ /* relevant routine within WINMM.DLL so it can be called when */
+ /* appropriate. */
+
+ if (!LoadStringA(NULL, IDS_MIGRATESOUNDEVENTS, ResourceString, sizeof(ResourceString))) {
+ /* we do not know the name of the routine to call */
+ pGlobals->MigrateSoundEvents = NULL;
+ } else {
+ pGlobals->MigrateSoundEvents = (SOUNDPROC)GetProcAddress(hLib, ResourceString);
+ }
+
+ if (!LoadStringA(NULL, IDS_WAVEOUTGETNUMDEVS, ResourceString, sizeof(ResourceString))) {
+ /* we do not know the name of the routine to call */
+ //return; We must free the library...
+ } else {
+ pGlobals->PlaySound = (SOUNDPROC)GetProcAddress(hLib, ResourceString);
+ }
+
+ if (pGlobals->PlaySound) {
+ /* See how many wave devices there are - if none, or we fail
+ * to load the name of PlaySound, then unload WINMM and never
+ * try and call it again.
+ */
+ UINT n;
+ n = (UINT)(*(pGlobals->PlaySound))();
+ if (n &&
+ LoadStringA(NULL, IDS_PLAYSOUND, ResourceString, sizeof(ResourceString))) {
+ pGlobals->PlaySound = (SOUNDPROC)GetProcAddress(hLib, ResourceString);
+ } else {
+ pGlobals->PlaySound = NULL;
+ //DebugLog((DEB_ERROR, "Winlogon: NO WAVE devices"));
+ }
+ }
+
+ if (!pGlobals->PlaySound && !pGlobals->MigrateSoundEvents) {
+ //DebugLog((DEB_ERROR, "Winlogon: Unloading WINMM"));
+ FreeLibrary(hLib);
+ }
+
+ }
+#if DBG
+ else { /* Could not load WINMM */
+ DebugLog((DEB_ERROR, "Could not load WINMM")); // Keep this debug message. It's an error
+ }
+#endif
+}
+
+
+
+/***************************************************************************\
+* InitializeMidi
+*
+* Set up a global function variable to address the Midi Migrate User routine.
+*
+* History:
+* 1-3-96 ShawnB Created
+\***************************************************************************/
+void InitializeMidi(
+ PGLOBALS pGlobals)
+{
+ //
+ // Load the Midi Migration module.
+ //
+
+ CHAR ResourceString[MAX_STRING_BYTES];
+ HMODULE hModule;
+ BOOL fFreeLib;
+
+ // Set the initial value (should not be necessary)
+ pGlobals->MigrateMidiUser = NULL;
+
+ //
+ // Get name of Midi library
+ //
+ if (!LoadStringA(NULL, IDS_MIDI_DLL, ResourceString, sizeof(ResourceString))) {
+ // Cannot get the name of the Midi library
+ return;
+ }
+
+ // Check if Already loaded (by InitializeSound)
+ hModule = GetModuleHandleA(ResourceString);
+ if (!hModule)
+ {
+ // Load it ourselves
+ hModule = (HMODULE)LoadLibraryA(ResourceString);
+ fFreeLib = TRUE;
+ }
+ else
+ {
+ fFreeLib = FALSE;
+ }
+
+ if (hModule) {
+
+ /* We must use the Ascii version of LoadString as GetProcAddress */
+ /* takes an Ascii string only... */
+
+ /* Whenever a user logs in, have WINMM.DLL check if the user needs */
+ /* their MIDI registry info updated. Here, we find the */
+ /* relevant routine within WINMM.DLL so it can be called when */
+ /* appropriate. */
+
+ if (!LoadStringA(NULL, IDS_MIGRATEMIDIUSER, ResourceString, sizeof(ResourceString))) {
+ /* we do not know the name of the routine to call */
+ pGlobals->MigrateMidiUser = NULL;
+ } else {
+ pGlobals->MigrateMidiUser = (MIDIPROC)GetProcAddress(hModule, ResourceString);
+ }
+
+
+ if (!pGlobals->MigrateMidiUser) {
+ //DebugLog((DEB_ERROR, "Winlogon: Unloading WINMM"));
+ if (fFreeLib)
+ {
+ FreeLibrary(hModule);
+ }
+ }
+
+ }
+#if DBG
+ else { /* Could not load WINMM */
+ DebugLog((DEB_ERROR, "Could not load WINMM")); // Keep this debug message. It's an error
+ }
+#endif
+} // End InitializeMidi
+
+BOOL
+WaitForSystemProcesses(
+ PGLOBALS pGlobals)
+{
+ DWORD i;
+ DWORD Exit;
+
+ //
+ // First, verify all handles:
+ //
+
+ for (i = 0; i < cSystemProcesses ; i++ )
+ {
+
+WaitLoopTop:
+
+ if (GetExitCodeProcess(hSystemProcesses[i], &Exit))
+ {
+ if (Exit == STILL_ACTIVE)
+ {
+ //
+ // Ooh, a good one. Keep it.
+ //
+
+ continue;
+ }
+
+ }
+
+ //
+ // Bad handle, one way or another
+ //
+
+ CloseHandle(hSystemProcesses[i]);
+ hSystemProcesses[i] = hSystemProcesses[--cSystemProcesses];
+
+ if (i != cSystemProcesses)
+ {
+ goto WaitLoopTop; // Retry same index, but do not increment
+ }
+
+ }
+
+ if (!cSystemProcesses)
+ {
+ return(TRUE);
+ }
+
+ Exit = WaitForMultipleObjectsEx( cSystemProcesses,
+ hSystemProcesses,
+ FALSE,
+ 4000,
+ FALSE );
+
+
+ return(Exit != WAIT_TIMEOUT);
+}
diff --git a/private/windows/gina/winlogon/sysinit.h b/private/windows/gina/winlogon/sysinit.h
new file mode 100644
index 000000000..f567f6fad
--- /dev/null
+++ b/private/windows/gina/winlogon/sysinit.h
@@ -0,0 +1,65 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: sysinit.h
+//
+// Contents:
+//
+// Classes:
+//
+// Functions:
+//
+// History: 12-05-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DealWithAutochkLogs(
+ VOID
+ );
+
+HANDLE
+StartLoadingFonts(void);
+
+BOOL InitSystemFontInfo(
+ PGLOBALS pGlobals
+ );
+
+BOOL SetProcessPriority(
+ VOID
+ );
+
+void
+InitializeSound(PGLOBALS pGlobals);
+
+void
+InitializeMidi(PGLOBALS pGlobals);
+
+VOID CreateTemporaryPageFile();
+
+
+BOOL
+StartSystemProcess(
+ PWSTR pszCommandLine,
+ PWSTR pszDesktop,
+ DWORD Flags,
+ DWORD StartupFlags,
+ PVOID pEnvironment,
+ BOOLEAN fSaveHandle,
+ HANDLE *phProcess,
+ HANDLE *phThread
+ );
+
+
+BOOL
+ExecSystemProcesses(
+ PGLOBALS pGlobals
+ );
+
+BOOL
+WaitForSystemProcesses(
+ PGLOBALS pGlobals);
+
+extern BOOLEAN PageFilePopup;
diff --git a/private/windows/gina/winlogon/sysshut.c b/private/windows/gina/winlogon/sysshut.c
new file mode 100644
index 000000000..65ff4c55f
--- /dev/null
+++ b/private/windows/gina/winlogon/sysshut.c
@@ -0,0 +1,1395 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Shutdown.c
+
+Abstract:
+
+ This module contains the server side implementation for the Win32 remote
+ shutdown APIs, that is:
+
+ - BaseInitiateSystemShutdown
+ - BaseAbortSystemShutdown
+
+Author:
+
+ Dave Chalmers (davidc) 29-Apr-1992
+
+Notes:
+
+
+Revision History:
+
+ 19-Oct-1993 Danl
+ Removed HackExtraThread which was only here to work around a bug in
+ the UserSrv. The text describing the reason for this workaround is
+ as follows:
+ HACKHACK - Work around bug in UserSrv that causes ExitWindowsEx to
+ fail (error 5) when called by a process which doesn't
+ have any threads which have called User APIs. Remove
+ after UserSrv is fixed. See NTBUG 11601.
+ Workaround is to create a thread which will make one
+ API call then sleep forever.
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define RPC_NO_WINDOWS_H
+#include "regrpc.h"
+#include "ntrpcp.h"
+#include <rpc.h>
+
+// // // // // //
+
+//
+// Shutdown Dialog Return Codes:
+//
+
+#define SHUTDOWN_SUCCESS 0
+#define SHUTDOWN_USER_LOGOFF 1
+#define SHUTDOWN_DESKTOP_SWITCH 2
+#define SHUTDOWN_CANCELLED 3
+
+//
+// System Shutdown globals
+//
+
+RTL_CRITICAL_SECTION ShutdownCriticalSection; // Protect global shutdown data
+
+//
+// Set when a thread has a shutdown 'in progress'
+// (Protected by critical section)
+//
+
+BOOL ShutdownInProgress;
+
+//
+// Set when a thread wants to interrupt the shutdown
+// (Protected by critical section)
+//
+
+BOOL AbortShutdown;
+
+
+//
+// Data for shutdown UI - this is protected by the ShutdownInProgress flag.
+// i.e. only the current shutdown thread manipulates this data.
+//
+
+LARGE_INTEGER ShutdownTime;
+DWORD ShutdownDelayInSeconds;
+PTCH ShutdownMessage;
+DWORD ExitWindowsFlags;
+DWORD GinaCode;
+PTSTR UserName;
+PTSTR UserDomain;
+BOOL AllowLogonDuringShutdown = TRUE ;
+ActiveDesktops ShutdownDesktop;
+WINDOWPLACEMENT ShutdownWindowPlacement;
+BOOL ShutdownGetPlacement = FALSE;
+BOOL ShutdownHasBegun = FALSE;
+
+//
+// Data captured during initialization
+//
+
+PGLOBALS GlobalWinMainData;
+
+
+
+
+
+//
+// Private prototypes
+//
+
+
+DWORD
+InitializeShutdownData(
+ PUNICODE_STRING lpMessage,
+ DWORD dwTimeout,
+ BOOL bForceAppsClosed,
+ BOOL bRebootAfterShutdown
+ );
+
+VOID
+FreeShutdownData(
+ VOID
+ );
+
+BOOL WINAPI
+ShutdownApiDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+UpdateTimeToShutdown(
+ HWND hDlg
+ );
+
+VOID
+CentreWindow(
+ HWND hwnd
+ );
+
+DWORD
+TestClientPrivilege(
+ VOID
+ );
+
+DWORD
+GetClientId(
+ PTSTR *UserName,
+ PTSTR *UserDomain
+ );
+
+VOID
+DeleteClientId(
+ PTSTR UserName,
+ PTSTR UserDomain
+ );
+
+BOOL
+InsertClientId(
+ HWND hDlg,
+ int ControlId,
+ PTSTR UserName,
+ PTSTR UserDomain
+ );
+
+
+
+
+
+BOOL
+InitializeShutdownModule(
+ PGLOBALS pGlobals
+ )
+/*++
+
+Routine Description:
+
+ Does any initializtion required for this module.
+
+Arguments:
+
+ pGlobals - Pointer to global data defined in WinMain
+
+Return Value:
+
+ Returns TRUE on success, FALSE on failure.
+
+--*/
+{
+ NTSTATUS Status;
+
+ //
+ // Initialize global variables
+ //
+
+ ShutdownInProgress = FALSE;
+
+ //
+ // Initialize critical section to protect globals
+ //
+
+ Status = RtlInitializeCriticalSection(&ShutdownCriticalSection);
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("Registry Server : Shutdown : Failed to initialize critical section\n");
+ }
+#endif
+
+ GlobalWinMainData = pGlobals;
+ return(NT_SUCCESS(Status));
+}
+
+ULONG
+BaseInitiateSystemShutdown(
+ IN PREGISTRY_SERVER_NAME ServerName,
+ IN PUNICODE_STRING lpMessage OPTIONAL,
+ IN DWORD dwTimeout,
+ IN BOOLEAN bForceAppsClosed,
+ IN BOOLEAN bRebootAfterShutdown
+ )
+/*++
+
+Routine Description:
+
+ Initiates the shutdown of this machine.
+
+Arguments:
+
+ ServerName - Name of machine this server code is running on. (Ignored)
+
+ lpMessage - message to display during shutdown timeout period.
+
+ dwTimeout - number of seconds to delay before shutting down
+
+ bForceAppsClosed - Normally applications may prevent system shutdown.
+ - If this true, all applications are terminated unconditionally.
+
+ bRebootAfterShutdown - TRUE if the system should reboot. FALSE if it should
+ - be left in a shutdown state.
+
+Return Value:
+
+ Returns ERROR_SUCCESS (0) for success; error-code for failure.
+
+--*/
+
+{
+ NTSTATUS Status;
+ DWORD Error;
+
+ //
+ // Check the caller has the appropriate privilege
+ //
+
+ Error = TestClientPrivilege();
+ if (Error != ERROR_SUCCESS) {
+ return(Error);
+ }
+
+ //
+ // Enter the critical section so we can look at our globals
+ //
+
+ Status = RtlEnterCriticalSection(&ShutdownCriticalSection);
+ if (!NT_SUCCESS(Status)) {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+ //
+ // Set up our global shutdown data.
+ // Fail if a shutdown is already in progress
+ //
+
+ if (ShutdownInProgress) {
+ Error = ERROR_SHUTDOWN_IN_PROGRESS;
+ } else {
+
+ //
+ // Set up our globals for the shutdown thread to use.
+ //
+
+ Error = InitializeShutdownData(lpMessage,
+ dwTimeout,
+ bForceAppsClosed,
+ bRebootAfterShutdown
+ );
+ if (Error == ERROR_SUCCESS) {
+ ShutdownInProgress = TRUE;
+ AbortShutdown = FALSE;
+ }
+ }
+
+ //
+ // Leave the critical section
+ //
+
+ Status = RtlLeaveCriticalSection(&ShutdownCriticalSection);
+ if (Error == ERROR_SUCCESS) {
+ if (!NT_SUCCESS(Status)) {
+ Error = RtlNtStatusToDosError(Status);
+ }
+ } else {
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+
+
+ //
+ // Create a thread to handle the shutdown (UI and calling ExitWindows)
+ // The thread will handle resetting our shutdown data and globals.
+ //
+
+ if (Error == ERROR_SUCCESS) {
+ int Result;
+
+ //
+ // Have winlogon create us a thread running on the user's desktop.
+ //
+ // The thread will do a call back to ShutdownThread()
+ //
+
+ GlobalWinMainData->LogoffFlags = EWX_WINLOGON_API_SHUTDOWN | ExitWindowsFlags;
+ Result = InitiateLogoff( GlobalWinMainData,
+ EWX_WINLOGON_API_SHUTDOWN | ExitWindowsFlags );
+
+
+ if (Result != DLG_SUCCESS ) {
+ Error = GetLastError();
+ KdPrint(("InitiateSystemShutdown : Failed to create shutdown thread. Error = %d\n", Error));
+ FreeShutdownData();
+ ShutdownInProgress = FALSE; // Atomic operation
+ }
+ }
+
+ return(Error);
+
+ UNREFERENCED_PARAMETER(ServerName);
+}
+
+
+
+DWORD
+InitializeShutdownData(
+ PUNICODE_STRING lpMessage,
+ DWORD dwTimeout,
+ BOOL bForceAppsClosed,
+ BOOL bRebootAfterShutdown
+ )
+/*++
+
+Routine Description:
+
+ Stores the passed shutdown parameters in our global data.
+
+Return Value:
+
+ Returns ERROR_SUCCESS (0) for success; error-code for failure.
+
+--*/
+
+{
+ NTSTATUS Status;
+ LARGE_INTEGER TimeNow;
+ LARGE_INTEGER Delay;
+ DWORD Error;
+
+ //
+ // Set the shutdown time
+ //
+
+ ShutdownDelayInSeconds = dwTimeout;
+
+ Status = NtQuerySystemTime(&TimeNow);
+ if (!NT_SUCCESS(Status)) {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+ Delay = RtlEnlargedUnsignedMultiply(dwTimeout, 10000000); // Delay in 100ns
+
+ ShutdownTime.QuadPart = TimeNow.QuadPart + Delay.QuadPart;
+
+
+ //
+ // Set the shutdown flags
+ //
+ // We set the EWX_WINLOGON_OLD_xxx and EWX_xxx both since this message
+ // originates from the winlogon process. When these flags actually bubble
+ // back to the active dialog box, winlogon expects the EWX_WINLOGON_OLD_xxx
+ // to indicate the 'real' request.
+ //
+
+ ExitWindowsFlags = EWX_LOGOFF | EWX_SHUTDOWN | EWX_WINLOGON_OLD_SHUTDOWN;
+ ExitWindowsFlags |= bForceAppsClosed ? EWX_FORCE : 0;
+ ExitWindowsFlags |= bRebootAfterShutdown ?
+ (EWX_REBOOT | EWX_WINLOGON_OLD_REBOOT) : 0;
+
+ if (bRebootAfterShutdown)
+ {
+ GinaCode = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
+ }
+ else
+ {
+ GinaCode = WLX_SAS_ACTION_SHUTDOWN;
+ }
+
+
+ //
+ // Store the caller's username and domain.
+ //
+
+ Error = GetClientId(&UserName, &UserDomain);
+ if (Error != ERROR_SUCCESS) {
+ return(Error);
+ }
+
+
+ //
+ // Set the shutdown message
+ //
+
+ if (lpMessage != NULL) {
+
+ //
+ // Copy the message into a global buffer
+ //
+
+ USHORT Bytes = lpMessage->Length + (USHORT)sizeof(UNICODE_NULL);
+
+ ShutdownMessage = (PTCH)LocalAlloc(LPTR, Bytes);
+ if (ShutdownMessage == NULL) {
+ DeleteClientId(UserName, UserDomain);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ RtlMoveMemory(ShutdownMessage, lpMessage->Buffer, lpMessage->Length);
+ ShutdownMessage[lpMessage->Length / sizeof(WCHAR)] = 0; // Null terminate
+
+ } else {
+ ShutdownMessage = NULL;
+ }
+
+
+ return(ERROR_SUCCESS);
+}
+
+
+
+VOID
+FreeShutdownData(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Frees up any memory allocated to store the shutdown data
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (ShutdownMessage != NULL) {
+ LocalFree(ShutdownMessage);
+ ShutdownMessage = NULL;
+ }
+
+ DeleteClientId(UserName, UserDomain);
+ UserName = NULL;
+ UserDomain = NULL;
+}
+
+
+
+BOOLEAN
+ShutdownThread(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Handles the display of a shutdown dialog and coordinating with the
+ AbortShutdown API.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE - system should be shut down
+ FALSE - shutdown was aborted
+
+--*/
+{
+ NTSTATUS Status;
+ DWORD Error;
+ BOOL DoShutdown = TRUE;
+ HDESK hdesk;
+ BOOL CloseDesktopHandle;
+ DWORD Result;
+ BOOL Locked;
+ BOOL Success;
+
+ //
+ // Quick check so we don't get into thorny race conditions.
+ //
+
+ if ( ShutdownDelayInSeconds == 0 )
+ {
+
+ FreeShutdownData();
+
+ RtlEnterCriticalSection( &ShutdownCriticalSection );
+
+ ShutdownInProgress = FALSE ;
+
+ RtlLeaveCriticalSection( &ShutdownCriticalSection );
+
+ GlobalWinMainData->LastGinaRet = GinaCode;
+
+ ShutdownHasBegun = TRUE;
+
+ return( TRUE );
+
+ }
+
+
+ hdesk = GetActiveDesktop(&GlobalWinMainData->WindowStation,
+ &CloseDesktopHandle,
+ &Locked);
+
+ while (hdesk != NULL)
+ {
+ DebugLog((DEB_TRACE, "Starting shutdown dialog on desktop %x\n", hdesk));
+
+ if (Locked)
+ {
+ UnlockWindowStation(GlobalWinMainData->WindowStation.hwinsta);
+ }
+
+ Success = SetThreadDesktop(hdesk);
+ if (!Success)
+ {
+ DebugLog((DEB_TRACE, "Unable to set desktop, %d\n", GetLastError()));
+ }
+
+ if (Locked)
+ {
+ LockWindowStation(GlobalWinMainData->WindowStation.hwinsta);
+ }
+
+ ShutdownDesktop = GlobalWinMainData->WindowStation.ActiveDesktop;
+
+
+ //
+ // Push the timeout past the shutdown delay, so that we can
+ // catch the messages we want, without stomping on the timeout
+ // structures.
+ //
+ Result = DialogBoxParam( GetModuleHandle(NULL),
+ MAKEINTRESOURCE( IDD_SYSTEM_SHUTDOWN ),
+ NULL,
+ ShutdownApiDlgProc,
+ (LPARAM) 0 );
+
+ DebugLog((DEB_TRACE, "Shutdown Dialog Returned %d\n", Result ));
+
+
+
+ if (CloseDesktopHandle)
+ {
+ CloseDesktop( hdesk );
+ }
+
+ if ((Result == SHUTDOWN_SUCCESS) ||
+ (Result == SHUTDOWN_CANCELLED) )
+ {
+ break;
+ }
+
+ //
+ // Trickier ones:
+ //
+
+ if (Result == SHUTDOWN_USER_LOGOFF)
+ {
+ if (!AllowLogonDuringShutdown)
+ {
+ break;
+ }
+
+ }
+
+ ShutdownGetPlacement = TRUE;
+
+ hdesk = GetActiveDesktop(&GlobalWinMainData->WindowStation,
+ &CloseDesktopHandle,
+ &Locked);
+
+ DebugLog((DEB_TRACE, "Switching to current desktop and restarting dialog\n"));
+
+ }
+
+ //
+ // The shutdown has either completed or been cancelled
+ // Reset our globals.
+ //
+ // Note we need to reset the shutdown-in-progress flag before
+ // entering the non-abortable part of shutdown so that anyone
+ // trying to abort from here on in will get a failure return code.
+ //
+
+ FreeShutdownData();
+
+
+ Status = RtlEnterCriticalSection(&ShutdownCriticalSection);
+ Error = RtlNtStatusToDosError(Status);
+
+ if (Error == ERROR_SUCCESS) {
+
+ //
+ // Reset the global shutdown-in-progress flag
+ // and check for an abort request.
+ //
+
+ if (AbortShutdown) {
+ DoShutdown = FALSE;
+ }
+
+ ShutdownInProgress = FALSE;
+
+ //
+ // Leave the critical section
+ //
+
+ Status = RtlLeaveCriticalSection(&ShutdownCriticalSection);
+ if (!NT_SUCCESS(Status)) {
+ Error = RtlNtStatusToDosError(Status);
+ }
+ }
+
+ //
+ // If DoShutdown, update the last gina ret so that
+ // the shutdown code will know what to do:
+ //
+
+ if ( DoShutdown )
+ {
+ GlobalWinMainData->LastGinaRet = GinaCode;
+
+ ShutdownHasBegun = TRUE;
+ }
+
+
+
+ //
+ // Tell the caller if he should shut down.
+ //
+
+ return DoShutdown;
+
+}
+
+
+
+BOOL WINAPI
+ShutdownApiDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+/*++
+
+Routine Description:
+
+ Processes messages for the shutdown dialog
+
+ Dialog returns ERROR_SUCCESS if shutdown should proceed,
+ ERROR_OPERATION_ABORTED if shutdown should be cancelled.
+
+--*/
+{
+ HMENU hMenu;
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+
+ //
+ // Add the caller's id to the main message text
+ //
+
+ InsertClientId(hDlg, IDD_SYSTEM_MESSAGE, UserName, UserDomain);
+
+ //
+ // Setup the client's message
+ //
+
+ SetDlgItemText(hDlg, IDD_MESSAGE, ShutdownMessage);
+
+ //
+ // Remove the close item from the system menu
+ //
+
+ hMenu = GetSystemMenu(hDlg, FALSE);
+ DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
+
+ //
+ // Position ourselves
+ //
+
+ if ( ShutdownGetPlacement )
+ {
+ SetWindowPlacement( hDlg, &ShutdownWindowPlacement );
+ }
+ else
+ {
+ CentreWindow(hDlg);
+ }
+
+ SetWindowPos( hDlg, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
+
+
+ //
+ // Start the timer
+ //
+
+ SetTimer(hDlg, 0, 1000, NULL); // 1 second timer
+
+ //
+ // Check if it's over before we've even started
+ //
+
+ if (UpdateTimeToShutdown(hDlg)) {
+
+ // It's already time to shutdown
+ EndDialog(hDlg, SHUTDOWN_SUCCESS);
+ }
+
+ //
+ // Let everyone know what state we're in
+ //
+
+ GlobalWinMainData->PreviousWinlogonState = GlobalWinMainData->WinlogonState;
+ GlobalWinMainData->WinlogonState = Winsta_InShutdownDlg;
+
+// GlobalWinMainData->ShutdownStarted = TRUE;
+
+ return(TRUE);
+
+
+ case WM_TIMER:
+
+ //
+ // Check for abort flag
+ //
+
+ if (AbortShutdown) {
+ if (GlobalWinMainData->WinlogonState == Winsta_InShutdownDlg) {
+ GlobalWinMainData->WinlogonState = GlobalWinMainData->PreviousWinlogonState;
+ }
+// GlobalWinMainData->ShutdownStarted = FALSE;
+ EndDialog(hDlg, SHUTDOWN_CANCELLED);
+ return(TRUE);
+ }
+
+ if ( GlobalWinMainData->WindowStation.ActiveDesktop != ShutdownDesktop )
+ {
+ GetWindowPlacement( hDlg, &ShutdownWindowPlacement );
+ EndDialog( hDlg, SHUTDOWN_DESKTOP_SWITCH );
+ return( TRUE );
+ }
+
+ //
+ // Update the time delay and check if our time's up
+ //
+
+ if (!UpdateTimeToShutdown(hDlg)) {
+
+ //
+ // Keep waiting
+ //
+
+ return(TRUE);
+ }
+
+ //
+ // Shutdown time has arrived. Drop through...
+ //
+
+ case WLX_WM_SAS:
+
+
+ DebugLog((DEB_TRACE, "Sas message received? wParam = %d\n", wParam ));
+ if ((wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) &&
+ (message == WLX_WM_SAS)) {
+
+ //
+ // Don't end the dialog if it's just a screen saver timeout
+ //
+
+ return(TRUE);
+
+ } else if ((wParam == WLX_SAS_TYPE_CTRL_ALT_DEL) &&
+ (message == WLX_WM_SAS)) {
+
+ //
+ // Also don't end the dialog if it's a Ctrl-Alt-Del
+ //
+
+ Sleep (1000);
+ return(TRUE);
+
+ } else {
+
+ //
+ // If the user logs off, preempt the timeout, restore the state
+ //
+
+ if (GlobalWinMainData->WinlogonState == Winsta_InShutdownDlg) {
+ GlobalWinMainData->WinlogonState = GlobalWinMainData->PreviousWinlogonState;
+ }
+
+ EndDialog(hDlg, SHUTDOWN_SUCCESS);
+
+ return(TRUE);
+
+ }
+
+ }
+
+ // We didn't process this message
+ return FALSE;
+
+ UNREFERENCED_PARAMETER(lParam);
+}
+
+
+
+
+BOOL
+UpdateTimeToShutdown(
+ HWND hDlg
+ )
+/*++
+
+Routine Description:
+
+ Updates the display of the time to system shutdown.
+
+Returns:
+
+ TRUE if shutdown time has arrived, otherwise FALSE
+
+--*/
+{
+ NTSTATUS Status;
+ BOOLEAN Success;
+ LARGE_INTEGER TimeNow;
+ ULONG ElapsedSecondsNow;
+ ULONG ElapsedSecondsAtShutdown;
+ ULONG SecondsRemaining;
+ ULONG DaysRemaining;
+ ULONG HoursRemaining;
+ ULONG MinutesRemaining;
+ TCHAR Message[40];
+
+ //
+ // Set the shutdown time
+ //
+
+ Status = NtQuerySystemTime(&TimeNow);
+ ASSERT(NT_SUCCESS(Status));
+
+ if (TimeNow.QuadPart >= ShutdownTime.QuadPart)
+ {
+ return(TRUE);
+ }
+
+ Success = RtlTimeToSecondsSince1980(&TimeNow, &ElapsedSecondsNow);
+ ASSERT(Success);
+
+ Success = RtlTimeToSecondsSince1980(&ShutdownTime, &ElapsedSecondsAtShutdown);
+ ASSERT(Success);
+
+ SecondsRemaining = ElapsedSecondsAtShutdown - ElapsedSecondsNow;
+
+ //
+ // Convert the seconds remaining to a string
+ //
+
+ MinutesRemaining = SecondsRemaining / 60;
+ HoursRemaining = MinutesRemaining / 60;
+ DaysRemaining = HoursRemaining / 24;
+
+ SecondsRemaining = SecondsRemaining % 60;
+ MinutesRemaining = MinutesRemaining % 60;
+ HoursRemaining = HoursRemaining % 24;
+
+ if (DaysRemaining > 0) {
+ wsprintf(Message, TEXT("%d days"), DaysRemaining);
+ } else {
+ wsprintf(Message, TEXT("%02d:%02d:%02d"), HoursRemaining, MinutesRemaining, SecondsRemaining);
+ }
+
+ SetDlgItemText(hDlg, IDD_TIMER, Message);
+
+ return(FALSE);
+}
+
+
+
+ULONG
+BaseAbortSystemShutdown(
+ IN PREGISTRY_SERVER_NAME ServerName
+ )
+/*++
+
+Routine Description:
+
+ Aborts a pending shutdown of this machine.
+
+Arguments:
+
+ ServerName - Name of machine this server code is running on. (Ignored)
+
+Return Value:
+
+ Returns ERROR_SUCCESS (0) for success; error-code for failure.
+
+--*/
+
+{
+ NTSTATUS Status;
+ DWORD Error;
+
+ //
+ // Check the caller has the appropriate privilege
+ //
+
+ Error = TestClientPrivilege();
+ if (Error != ERROR_SUCCESS) {
+ return(Error);
+ }
+
+ //
+ // Enter the critical section so we can look at our globals
+ //
+
+ Status = RtlEnterCriticalSection(&ShutdownCriticalSection);
+ if (!NT_SUCCESS(Status)) {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+
+ //
+ // If a shutdown is in progress, set the abort flag
+ //
+
+ if (ShutdownInProgress) {
+ AbortShutdown = TRUE;
+ Error = ERROR_SUCCESS;
+ } else
+ {
+ if ( ShutdownHasBegun )
+ {
+ Error = ERROR_SHUTDOWN_IN_PROGRESS;
+ }
+ else
+ {
+ Error = ERROR_NO_SHUTDOWN_IN_PROGRESS;
+ }
+ }
+
+ //
+ // Leave the critical section
+ //
+
+ Status = RtlLeaveCriticalSection(&ShutdownCriticalSection);
+ if (Error == ERROR_SUCCESS) {
+ if (!NT_SUCCESS(Status)) {
+ Error = RtlNtStatusToDosError(Status);
+ }
+ } else {
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ return(Error);
+
+ UNREFERENCED_PARAMETER(ServerName);
+}
+
+
+
+DWORD
+TestClientPrivilege(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Checks if the client has the privilege to perform the requested shutdown.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ ERROR_SUCCESS if the client has the appropriate privilege.
+
+ ERROR_ACCESS_DENIED - client does not have the required privilege
+
+--*/
+{
+ NTSTATUS Status, IgnoreStatus;
+ BOOL LocalConnection;
+ LUID PrivilegeRequired;
+ PRIVILEGE_SET PrivilegeSet;
+ BOOLEAN Privileged;
+ USER_SESSION_KEY SessionKey;
+ HANDLE Token;
+
+ UNICODE_STRING SubSystemName; // LATER this should be global
+ RtlInitUnicodeString(&SubSystemName, L"Win32 Registry/SystemShutdown module");
+
+ //
+ // Find out if this is a local connection
+ //
+
+ Status = RtlGetUserSessionKeyServer(NULL, &SessionKey);
+ if (NT_SUCCESS(Status)) {
+
+ LocalConnection = (Status == STATUS_LOCAL_USER_SESSION_KEY);
+
+ if (LocalConnection) {
+ PrivilegeRequired = RtlConvertLongToLuid(SE_SHUTDOWN_PRIVILEGE);
+ } else {
+ PrivilegeRequired = RtlConvertLongToLuid(SE_REMOTE_SHUTDOWN_PRIVILEGE);
+ }
+
+
+ //
+ // See if the client has the required privilege
+ //
+
+ Status = I_RpcMapWin32Status(RpcImpersonateClient( NULL ));
+ if (NT_SUCCESS(Status)) {
+
+ PrivilegeSet.PrivilegeCount = 1;
+ PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
+ PrivilegeSet.Privilege[0].Luid = PrivilegeRequired;
+ PrivilegeSet.Privilege[0].Attributes = 0;
+
+ Status = NtOpenThreadToken( NtCurrentThread(),
+ TOKEN_QUERY,
+ TRUE,
+ &Token);
+ if (NT_SUCCESS(Status)) {
+
+ Status = NtPrivilegeCheck(Token,
+ &PrivilegeSet,
+ &Privileged);
+
+ if (NT_SUCCESS(Status) || (Status == STATUS_PRIVILEGE_NOT_HELD)) {
+
+ Status = NtPrivilegeObjectAuditAlarm(
+ &SubSystemName,
+ NULL,
+ Token,
+ 0,
+ &PrivilegeSet,
+ Privileged);
+ }
+
+ IgnoreStatus = NtClose(Token);
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+ }
+
+ }
+
+ IgnoreStatus = I_RpcMapWin32Status(RpcRevertToSelf());
+ ASSERT( NT_SUCCESS(IgnoreStatus) );
+ }
+
+
+ //
+ // Handle unexpected errors
+ //
+
+ if (!NT_SUCCESS(Status)) {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+
+ //
+ // If they failed the privilege check, return an error
+ //
+
+ if (!Privileged) {
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ //
+ // They passed muster
+ //
+
+ return(ERROR_SUCCESS);
+}
+
+
+
+
+DWORD
+GetClientId(
+ PTSTR *UserName,
+ PTSTR *UserDomain
+ )
+/*++
+
+Routine Description:
+
+ Gets the name and domain of the caller, allocates and returns pointers
+ to the information.
+
+ Note we have RPC impersonate the client to discover their ID.
+
+Arguments:
+
+ UserName - a pointer to a NULL terminated string containing the client's
+ user name is returned here.
+
+ DomainName - a pointer to a NULL terminated string containing the client's
+ domain name is returned here.
+
+ The caller should free UserName and DomainName by calling DeleteClientId
+
+Return Value:
+
+ ERROR_SUCCESS - UserName and UserDomain contain valid pointers
+
+ Other - UserName and UserDomain are invalid
+
+--*/
+{
+ HANDLE TokenHandle;
+ DWORD cbNeeded;
+ PTOKEN_USER pUserToken;
+ BOOL ReturnValue=FALSE;
+ DWORD cbDomain;
+ DWORD cbName;
+ SID_NAME_USE SidNameUse;
+ DWORD Error;
+ DWORD IgnoreError;
+
+ //
+ // Prepare for failure
+ //
+
+ *UserName = NULL;
+ *UserDomain = NULL;
+
+
+ Error = RpcImpersonateClient(NULL);
+ if (Error != ERROR_SUCCESS) {
+ return(Error);
+ }
+
+ if (OpenThreadToken(GetCurrentThread(),
+ TOKEN_QUERY,
+ FALSE,
+ &TokenHandle)) {
+ //
+ // Get the user Sid
+ //
+
+ if (!GetTokenInformation(TokenHandle, TokenUser, (PVOID)NULL, 0, &cbNeeded)) {
+
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+
+ pUserToken = (PTOKEN_USER)LocalAlloc(LPTR, cbNeeded);
+
+ if (pUserToken != NULL) {
+
+ if (GetTokenInformation(TokenHandle, TokenUser, pUserToken,
+ cbNeeded, &cbNeeded)) {
+
+ //
+ // Convert User Sid to name/domain
+ //
+
+ cbName = 0;
+ cbDomain = 0;
+
+ if (!LookupAccountSid(NULL,
+ pUserToken->User.Sid,
+ NULL, &cbName,
+ NULL, &cbDomain,
+ &SidNameUse)) {
+
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+
+ *UserDomain = (PTSTR)LocalAlloc(LPTR, cbDomain*sizeof(TCHAR));
+ *UserName = (PTSTR)LocalAlloc(LPTR, cbName*sizeof(TCHAR));
+
+ if ((*UserDomain != NULL) && (*UserName != NULL)) {
+
+ ReturnValue = LookupAccountSid(
+ NULL,
+ pUserToken->User.Sid,
+ *UserName, &cbName,
+ *UserDomain, &cbDomain,
+ &SidNameUse);
+ }
+ }
+
+ }
+ }
+
+ LocalFree(pUserToken);
+ }
+ }
+ }
+
+ CloseHandle(TokenHandle);
+ }
+
+
+ IgnoreError = RpcRevertToSelf();
+ ASSERT(IgnoreError == ERROR_SUCCESS);
+
+
+ //
+ // Clean up on failure
+ //
+
+ if (ReturnValue) {
+ Error = ERROR_SUCCESS;
+ } else {
+
+ Error = GetLastError();
+
+ DeleteClientId(*UserName, *UserDomain);
+
+ *UserName = NULL;
+ *UserDomain = NULL;
+ }
+
+
+ return(Error);
+}
+
+
+
+
+VOID
+DeleteClientId(
+ PTSTR UserName,
+ PTSTR UserDomain
+ )
+/*++
+
+Routine Description:
+
+ Frees the client id returned previously by GetClientId
+
+Arguments:
+
+ UserName - a pointer to the username returned by GetClientId.
+
+ DomainName - a pointer to the domain name eturned by GetClientId
+
+Return Value:
+
+ None
+
+--*/
+{
+ if (UserName != NULL) {
+ LocalFree(UserName);
+ }
+
+ if (UserDomain != NULL) {
+ LocalFree(UserDomain);
+ }
+
+}
+
+
+
+
+BOOL
+InsertClientId(
+ HWND hDlg,
+ int ControlId,
+ PTSTR UserName,
+ PTSTR UserDomain
+ )
+/*++
+
+Routine Description:
+
+ Takes the text from the specified dialog control, treats it as a printf
+ formatting string and inserts the user name and domain as the first 2
+ string identifiers (%s)
+
+Arguments:
+
+ UserName - a pointer to the username returned by GetClientId.
+
+ DomainName - a pointer to the domain name eturned by GetClientId
+
+Return Value:
+
+ TRUE on success, FALSE on failure
+
+--*/
+{
+ DWORD StringLength;
+ DWORD StringBytes;
+ PTSTR FormatBuffer;
+ PTSTR Buffer;
+
+ //
+ // Allocate space for the formatting string out of the control
+ //
+
+ StringLength = (DWORD)SendMessage(GetDlgItem(hDlg, ControlId), WM_GETTEXTLENGTH, 0, 0);
+ StringBytes = (StringLength + 1) * sizeof(TCHAR); // Allow for terminator
+
+ FormatBuffer = (PTSTR)LocalAlloc(LPTR, StringBytes);
+ if (FormatBuffer == NULL) {
+ return(FALSE);
+ }
+
+ //
+ // Read the format string into the buffer
+ //
+
+ GetDlgItemText(hDlg, ControlId, FormatBuffer, StringLength);
+
+ //
+ // Calculate the maximum size of the string we'll create
+ // i.e. Formatting string + username + userdomain
+ //
+
+ StringLength += lstrlen(UserName);
+ StringLength += lstrlen(UserDomain);
+
+ //
+ // Allocate space for formatted string
+ //
+
+ StringBytes = (StringLength + 1) * sizeof(TCHAR); // Allow for terminator
+
+ Buffer = (PTSTR)LocalAlloc(LPTR, StringBytes);
+ if (Buffer == NULL) {
+ LocalFree(FormatBuffer);
+ return(FALSE);
+ }
+
+ //
+ // Insert the user id into the format string
+ //
+
+ wsprintf(Buffer, FormatBuffer, UserDomain, UserName);
+ ASSERT((lstrlen(Buffer) * sizeof(TCHAR)) < StringBytes);
+
+ //
+ // Replace the control text with our formatted result
+ //
+
+ SetDlgItemText(hDlg, ControlId, Buffer);
+
+ //
+ // Tidy up
+ //
+
+ LocalFree(FormatBuffer);
+ LocalFree(Buffer);
+
+
+ return(TRUE);
+}
diff --git a/private/windows/gina/winlogon/sysshut.dlg b/private/windows/gina/winlogon/sysshut.dlg
new file mode 100644
index 000000000..9c1ff7e24
--- /dev/null
+++ b/private/windows/gina/winlogon/sysshut.dlg
@@ -0,0 +1,15 @@
+#include "sysshut.h"
+
+IDD_SYSTEM_SHUTDOWN DIALOG 35, 46, 184, 119
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "System Shutdown"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "This system is shutting down. Please save all work in progress and log off. Any unsaved changes will be lost. This shutdown was initiated by %s\\%s.",
+ IDD_SYSTEM_MESSAGE, 33, 11, 147, 42
+ RTEXT "Time before shutdown :", 102, 21, 59, 85, 8
+ GROUPBOX "Message", 104, 30, 73, 146, 38
+ LTEXT "Text", IDD_MESSAGE, 36, 83, 137, 25
+ LTEXT "00:00:00", IDD_TIMER, 114, 59, 41, 8
+ ICON 32513, -1, 7, 12, 18, 20
+END
diff --git a/private/windows/gina/winlogon/sysshut.h b/private/windows/gina/winlogon/sysshut.h
new file mode 100644
index 000000000..493c05f9c
--- /dev/null
+++ b/private/windows/gina/winlogon/sysshut.h
@@ -0,0 +1,14 @@
+#define IDD_SYSTEM_SHUTDOWN 1300
+#define IDD_TIMER 1303
+#define IDD_MESSAGE 1305
+#define IDD_SYSTEM_MESSAGE 1306
+
+BOOLEAN
+ShutdownThread(
+ VOID
+ );
+
+BOOL
+InitializeShutdownModule(
+ PGLOBALS pGlobals
+ );
diff --git a/private/windows/gina/winlogon/timeout.c b/private/windows/gina/winlogon/timeout.c
new file mode 100644
index 000000000..a03daa3c6
--- /dev/null
+++ b/private/windows/gina/winlogon/timeout.c
@@ -0,0 +1,1248 @@
+/****************************** Module Header ******************************\
+* Module Name: timeout.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Support routines to implement dialog input timeouts
+*
+* History:
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Define private notification message sent to dialogs on an interrupt
+//
+
+#define WM_DLG_INTERRUPT (WM_USER+600)
+
+//
+// Define value returned by a message box or dialog box when interrupted
+// This value must be interpreted using the InterrruptType variable
+//
+
+#define DLG_INTERRUPT 0 // Must be 0 so we can return it from message boxes
+
+//
+// Define the maximum number of nested dialogs we can handle
+//
+
+#define MAX_NESTED_TIMEOUTS 5
+#define TIMEOUT_DEFAULT 120
+
+//
+// Globals - these will need to put in an instance data structure
+// when we have multiple logon threads
+//
+
+//
+// Define array used to store window handles who ask for timeout service.
+// This array is used as a push down stack to suppport nested timeouts
+//
+
+HWND hwndArray[MAX_NESTED_TIMEOUTS];
+TIMEOUT TimeoutArray[MAX_NESTED_TIMEOUTS];
+PGLOBALS GlobalsArray[MAX_NESTED_TIMEOUTS];
+LONG NestedIndex = 0;
+
+
+//
+// Variable that stores the required return code for the top dialog.
+// This is only used if we force a dialog to return DLG_INTERRUPT.
+// We have to use this mechanism because message boxes will not allow
+// you to return any random value. DLG_INTERRUPT is 0 which message
+// boxes let through.
+//
+
+int TopDialogReturnCode = DLG_INTERRUPT;
+
+
+
+HWND hwndMessageOwner = NULL;// Store the owner of the message box
+ // we want to find
+LPTSTR TimeoutTitle = NULL; // Stores the title of the message box we
+ // are going to timeout on.
+BOOL InputHooksInstalled = FALSE;
+BOOL TimeoutOccurred = FALSE;
+BOOL DialogActive = FALSE;
+
+//
+// Variables that support the input timeout
+//
+
+int TimerID = 0;
+HHOOK hhkMouse;
+HHOOK hhkKeyboard;
+
+
+//
+// Internal Prototypes
+//
+
+BOOL PushMessageTimeout(HWND hwndOwner, TIMEOUT TimeDelay, LPTSTR Title, PGLOBALS pGlobals);
+BOOL PopMessageTimeout(VOID);
+BOOL PushTimeout(HWND hwnd, TIMEOUT TimeDelay, PGLOBALS pGlobals);
+BOOL PopTimeout(VOID);
+BOOL StartTopTimeout(VOID);
+HWND GetTopTimeout(PTIMEOUT pTimeDelay);
+BOOL SetTopTimeout(HWND hwnd);
+BOOL SetTimeout(TIMEOUT TimeDelay);
+BOOL CheckTimeout(HWND hwnd);
+BOOL SetInputHooks(VOID);
+BOOL ReleaseInputHooks(VOID);
+LRESULT WINAPI MouseHookfn(int nCode, WPARAM wParam, LPARAM lParam);
+LRESULT WINAPI KeyboardHookfn(int nCode, WPARAM wParam, LPARAM lParam);
+BOOL StartTimer(TIMEOUT TimeDelay);
+WORD WINAPI Timerfn(HWND hwnd, WORD Message, int IDEvent, DWORD dwTime);
+BOOL StopTimer(VOID);
+BOOL FindMessageBox(VOID);
+BOOL WINAPI FindEnumfn(HWND, LPARAM);
+TIMEOUT InheritTimeout(TIMEOUT TimeDelay);
+BOOL HandleScreenSaverTimeout(HWND hwndTop, TIMEOUT Timeout);
+BOOL HandleUserLogoff(PGLOBALS pGlobals, HWND hwndTop, TIMEOUT Timeout, LONG Flags);
+
+
+/***************************************************************************\
+* ForwardMessage
+*
+* Sends a message to the window on top of the timeout stack
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+#if 0
+
+LONG
+ForwardMessage(
+ PGLOBALS pGlobals,
+ UINT Message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ TIMEOUT Timeout;
+ HWND hwndTop = GetTopTimeout(&Timeout);
+
+ // If there is nothing on the stack, dump the message
+ if (hwndTop == NULL) {
+ DebugLog((DEB_ERROR, "No-one on the stack to forward message to !"));
+ ASSERT(FALSE);
+ return(0);
+ }
+
+ switch (Message) {
+
+ case WM_SAS:
+ SendMessage(hwndTop, Message, wParam, lParam);
+ break;
+
+ case WM_INPUT_TIMEOUT:
+
+ // Check the timeout condition still exists and exit the dialog
+ if (CheckTimeout(hwndTop)) {
+
+ EndTopDialog(hwndTop, DLG_INPUT_TIMEOUT);
+
+ }
+ break;
+
+ case WM_SCREEN_SAVER_TIMEOUT:
+
+ //
+ // Ignore if the current user doesn't have an enabled screen-saver.
+ // The timeout notification may have been in the message queue when
+ // we changed user - the new user may not have a screen-saver.
+ //
+
+ if (ScreenSaverEnabled(pGlobals)) {
+ HandleScreenSaverTimeout(hwndTop, Timeout);
+ }
+
+ break;
+
+ case WM_USER_LOGOFF:
+
+ HandleUserLogoff(pGlobals, hwndTop, Timeout, lParam);
+
+ break;
+
+ default:
+ DebugLog((DEB_ERROR, "Unexpected message supplied to ForwardMessage"));
+ ASSERT(FALSE);
+ break;
+ }
+
+ return(0);
+}
+
+
+/***************************************************************************\
+* HandleScreenSaverTimeout
+*
+* Deal with a screen-saver timeout notification from windows.
+*
+* If the topmost window has a timeout, the screen-saver timeout simply
+* interrupts the dialog and causes it to return DLG_SCREEN_SAVER_TIMEOUT.
+*
+* If the topmost window has no timeout, the window stack is searched from
+* the top for the first window to have the TIMEOUT_SS_NOTIFY bit set.
+* This window is then sent a WM_SCREEN_SAVER_TIMEOUT message.
+* This allows a non-timeout window to take responsibility for starting
+* the screen-saver from any-non timeout windows above it.
+*
+* Returns TRUE
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+BOOL
+HandleScreenSaverTimeout(
+ HWND hwndTop,
+ TIMEOUT Timeout
+ )
+{
+ HWND hwndNotify;
+ LONG Index;
+
+ //
+ // If top top window has a timeout, it should be interrupted
+ //
+
+ if (TIMEOUT_VALUE(Timeout) != TIMEOUT_NONE) {
+
+ EndTopDialog(hwndTop, DLG_SCREEN_SAVER_TIMEOUT);
+
+ return(TRUE); // We're done
+ }
+
+
+ //
+ // The top window has no timeout, search for window with notify bit set
+ //
+
+ for (Index = NestedIndex - 1; Index >= 0; Index --) {
+ if (TIMEOUT_NOTIFY(TimeoutArray[Index])) {
+ // Found a window with the notify bit set
+ break;
+ }
+ }
+
+ // Q.A.
+ ASSERTMSG("Notify window not found on timeout stack", Index >= 0);
+ ASSERTMSG("Found notify window with a non-zero timeout !!",
+ TIMEOUT_VALUE(TimeoutArray[Index]) == TIMEOUT_NONE);
+
+ hwndNotify = hwndArray[Index];
+
+ ASSERTMSG("Found notify window with a NULL hwnd !!", hwndNotify != NULL);
+
+ //
+ // Forward the message to the notify window
+ //
+
+ SendMessage(hwndNotify, WM_SCREEN_SAVER_TIMEOUT, 0, 0);
+
+ return(TRUE); // We've dealt with it
+}
+
+#endif
+
+/***************************************************************************\
+* MapResultCode
+*
+* Maps the DLG_INTERRUPT message to the appropriate return code stored
+* in TopDialogReturnCode
+*
+* 03-17-92 Davidc Created.
+\***************************************************************************/
+
+int
+MapResultCode(
+ int Result,
+ int TopDialogReturnCode
+ )
+{
+ if (Result == DLG_INTERRUPT) {
+
+ ASSERT(TopDialogReturnCode != DLG_INTERRUPT);
+
+ Result = TopDialogReturnCode;
+
+#if DBG
+ //
+ // Reset the stored return code so we can detect if an interrupt is
+ // generated without the code being set correctly.
+ //
+
+ TopDialogReturnCode = DLG_INTERRUPT;
+#endif
+ }
+
+ if (Result == -1) {
+ DebugLog((DEB_ERROR, "Failed to create dialog or message box"));
+ }
+
+ return(Result);
+}
+
+
+/***************************************************************************\
+* ProcessDialogTimeout
+*
+* Called as first part of dialog routine that wants to timeout after
+* there is no input for a specified time. Simply sets up the hwnd on top
+* of our stack.
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+VOID ProcessDialogTimeout(
+ HWND hwnd,
+ UINT Message,
+ DWORD wParam,
+ LONG lParam)
+{
+ switch (Message) {
+
+ case WM_INITDIALOG:
+ if (!SetTopTimeout(hwnd)) {
+ DebugLog((DEB_ERROR, "ProcessDialogTimeout failed to set the hwnd on top of the timeout stack"));
+ }
+ }
+ DBG_UNREFERENCED_PARAMETER(Message);
+ DBG_UNREFERENCED_PARAMETER(wParam);
+ DBG_UNREFERENCED_PARAMETER(lParam);
+}
+
+
+/***************************************************************************\
+* PushDialogTimeout
+*
+* Sets up an input timeout for the dialog box that is just about to be created
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL PushDialogTimeout(
+ TIMEOUT TimeDelay,
+ PGLOBALS pGlobals)
+{
+ TimeDelay = InheritTimeout(TimeDelay);
+
+ // Push the timeout with a NULL hwnd (to be filled in later)
+ PushTimeout(NULL, TimeDelay, pGlobals);
+
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* PushMessageTimeout
+*
+* Sets up an input timeout for the message box that is just about to be created
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL PushMessageTimeout(
+ HWND hwndOwner,
+ TIMEOUT TimeDelay,
+ LPTSTR Title,
+ PGLOBALS pGlobals)
+{
+ TimeDelay = InheritTimeout(TimeDelay);
+
+ // Check the last message box has been dealt with
+ ASSERTMSG("Last timeout message box not identified yet !", TimeoutTitle == NULL);
+
+ // Push the timeout with a NULL hwnd (to be filled in later)
+ PushTimeout(NULL, TimeDelay, pGlobals);
+
+ // Store the message box title so that when we need to operate on the
+ // message box, we can go and search for it by title.
+
+ TimeoutTitle = Title;
+ hwndMessageOwner = hwndOwner;
+ DialogActive = TRUE;
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* PopMessageTimeout
+*
+* Pops the top timeout from the stack and reenables the timeout for the
+* next guy on the stack
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL PopMessageTimeout(VOID)
+{
+ PopTimeout();
+
+ // Reset our global in case we never went off to search for the
+ // message box 'cos we never had to
+
+ TimeoutTitle = NULL;
+ DialogActive = FALSE;
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* FindMessageBox
+*
+* Searches for the message box that our globals tell us we're looking for.
+*
+* Returns TRUE if found, otherwise FALSE
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL FindMessageBox(VOID)
+{
+ BOOL Found;
+
+ Found = !EnumTaskWindows(GetCurrentThreadId(), FindEnumfn, 0);
+
+ if (!Found) {
+ DebugLog((DEB_ERROR, "Message box window <%s> not found !!!", TimeoutTitle));
+ }
+
+ return(Found);
+}
+
+
+/***************************************************************************\
+* FindEnumfn
+*
+* Enumeration function used by FindMessageBox()
+*
+* Returns FALSE if message box is found, otherwise TRUE
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL WINAPI
+FindEnumfn(
+ HWND hwnd,
+ LPARAM lParam)
+{
+ TCHAR Title[MAX_STRING_BYTES];
+
+ // See if this hwnd is the one
+
+ GetWindowText(hwnd, Title, sizeof(Title));
+
+ if (lstrcmp(Title, TimeoutTitle) == 0) {
+
+ // Found it
+
+ if (!SetTopTimeout(hwnd)) {
+ DebugLog((DEB_ERROR, "failed to set top timeout for message box !!"));
+ }
+
+ // Reset our global
+ TimeoutTitle = NULL;
+
+ return(FALSE); // Stop enumeration
+ }
+
+ return(TRUE); // Continue enumeration
+
+ DBG_UNREFERENCED_PARAMETER(lParam);
+}
+
+
+/***************************************************************************\
+* InheritTimeout
+*
+* Converts a timedelay value that is potentially TIMEOUT_CURRENT to
+* an independent timedelay value.
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+TIMEOUT InheritTimeout(
+ TIMEOUT TimeDelay
+ )
+{
+ TIMEOUT ResultantTimeDelay;
+
+ if (TIMEOUT_VALUE(TimeDelay) == TIMEOUT_CURRENT) {
+ //
+ // Inherit timedelay from previous window
+ //
+ HWND hwndTop = GetTopTimeout(&ResultantTimeDelay);
+
+ if (!hwndTop)
+ {
+ DebugLog((DEB_WARN, "Tried to use TIMEOUT_CURRENT with no current timeout\n"));
+ ResultantTimeDelay = TIMEOUT_DEFAULT;
+ }
+
+ // Don't inherit the TIMEOUT_SS_NOTIFY bit
+ ResultantTimeDelay &= TIMEOUT_VALUE_MASK;
+
+ // Set the notify bit to match the one passed in
+ ResultantTimeDelay |= TIMEOUT_NOTIFY(TimeDelay);
+
+ } else {
+ //
+ // No inheritance
+ //
+ ResultantTimeDelay = TimeDelay;
+ }
+
+ return(ResultantTimeDelay);
+}
+
+
+/***************************************************************************\
+* PushTimeout
+*
+* Internal routine to push the timeout information onto a stack
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL PushTimeout(
+ HWND hwnd,
+ TIMEOUT TimeDelay,
+ PGLOBALS pGlobals)
+{
+ // Check we don't have an outstanding unidentified message box
+ ASSERTMSG("Last timeout message box not identified yet !", TimeoutTitle == NULL);
+
+ if (NestedIndex < MAX_NESTED_TIMEOUTS) {
+
+#if DBG
+ // Check we never push a TIMEOUT_NONE dialog when there's
+ // a timeout window already on the stack.
+ // This would be unusual.
+
+ if (TIMEOUT_VALUE(TimeDelay) == TIMEOUT_NONE) {
+ if (NestedIndex > 0) {
+ if (TIMEOUT_VALUE(TimeoutArray[NestedIndex-1]) != TIMEOUT_NONE) {
+ ASSERTMSG("Non-timeout window pushed on top of timeout window !!!", FALSE);
+ }
+ }
+ }
+#endif
+ hwndArray[NestedIndex] = hwnd;
+ GlobalsArray[NestedIndex] = pGlobals;
+ TimeoutArray[NestedIndex++] = TimeDelay;
+
+ StartTopTimeout();
+
+ return(TRUE);
+
+ } else {
+
+ DebugLog((DEB_ERROR, "PushTimeout - Out of input timeout slots !!"));
+ return(FALSE);
+ }
+
+}
+
+
+/***************************************************************************\
+* PopTimeout
+*
+* Pops the top timeout from the stack and reenables the timeout for the
+* next guy on the stack
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL PopTimeout(VOID)
+{
+ if (NestedIndex <= 0) {
+ DebugLog((DEB_ERROR, "PopTimeout called with an empty timeout stack !!"));
+ return(FALSE);
+ }
+
+ NestedIndex --;
+
+ // This call will disable timeouts on an empty stack
+ StartTopTimeout();
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* StartTopTimeout
+*
+* Starts (or restarts) the timeout on the top of the stack.
+* If the stack is empty, timeouts are disabled.
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL StartTopTimeout(VOID)
+{
+ TIMEOUT TimeDelay;
+
+ if (NestedIndex > 0) {
+ TimeDelay = TimeoutArray[NestedIndex - 1];
+ DebugLog((DEB_TRACE_TIMEOUT, "Enabling timeout after %d seconds\n", TIMEOUT_VALUE(TimeDelay)));
+ } else {
+ DebugLog((DEB_TRACE_TIMEOUT, "Disabling timeouts\n"));
+ TimeDelay = TIMEOUT_NONE; // Disable timeouts
+ }
+
+ SetTimeout(TIMEOUT_VALUE(TimeDelay));
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* GetTopTimeout
+*
+* Returns the timeout on the top of the stack.
+*
+* Returns top hwnd and time-delay or NULL on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+HWND GetTopTimeout(
+ PTIMEOUT pTimeDelay)
+{
+ HWND hwndTop = NULL;
+ TIMEOUT TimeDelay = 0;
+
+ if (TimeoutTitle != NULL) {
+ // Go search for message box before getting the top hwnd
+ FindMessageBox();
+ }
+
+ if (NestedIndex > 0) {
+ hwndTop = hwndArray[NestedIndex - 1];
+ TimeDelay = TimeoutArray[NestedIndex - 1];
+ }
+
+ if (pTimeDelay != NULL) {
+ *pTimeDelay = TimeDelay;
+ }
+
+ return(hwndTop);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: TimeoutUpdateTopTimeout
+//
+// Synopsis: Updates the current timeout, returns FALSE if no window
+// active, TRUE if it was updated.
+//
+// Arguments: [Timeout] --
+//
+// History: 3-05-96 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+TimeoutUpdateTopTimeout(
+ DWORD Timeout)
+{
+ if ( DialogActive )
+ {
+ if ( TimeoutTitle != NULL )
+ {
+ FindMessageBox();
+ }
+
+ if ( NestedIndex > 0 )
+ {
+ TimeoutArray[ NestedIndex - 1 ] = Timeout;
+ return( TRUE );
+ }
+
+ }
+
+ return( FALSE );
+}
+
+
+
+/***************************************************************************\
+* SetTopTimeout
+*
+* Sets the hwnd on top of the timeout stack to the one specified.
+* The top timeout value is left unchanged.
+*
+* Checks if the existing hwnd is NULL, if not this call fails.
+*
+* Returns TRUE on success, FALSE on failure.
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL SetTopTimeout(
+ HWND hwnd)
+{
+ if (NestedIndex <= 0) {
+ DebugLog((DEB_ERROR, "SetTopTimeout : Tried to set the top hwnd on an empty stack !!"));
+ return(FALSE);
+ }
+
+ if (hwndArray[NestedIndex - 1] != NULL) {
+ DebugLog((DEB_ERROR, "SetTopTimeout : hwnd at top of stack is not NULL !!"));
+ return(FALSE);
+ }
+
+ hwndArray[NestedIndex - 1] = hwnd;
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* SetTimeout
+*
+* Sets an input timeout for the specified window using the specified delay.
+*
+* If TimeDelay = 0, no timeout is enabled for this window.
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL SetTimeout(
+ TIMEOUT TimeDelay)
+{
+ if (TimeDelay != 0) {
+
+ if (!InputHooksInstalled) {
+ SetInputHooks();
+ }
+ StartTimer(TimeDelay);
+
+ } else {
+
+ if (InputHooksInstalled) {
+ ReleaseInputHooks();
+ }
+
+ StopTimer();
+ }
+
+ return (TRUE);
+}
+
+
+/***************************************************************************\
+* CheckTimeout
+*
+* Returns TRUE if a timeout is still occurring for this window, otherwise FALSE
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL CheckTimeout(
+ HWND hwnd)
+{
+ if (GetTopTimeout(NULL) != hwnd) {
+ return(FALSE);
+ }
+
+ return (TimeoutOccurred);
+}
+
+
+/***************************************************************************\
+* StartTimer
+*
+* Starts (or restarts) the input timer with the specified delay
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL StartTimer(
+ TIMEOUT TimeDelay)
+{
+ StopTimer();
+
+ TimerID = SetTimer(NULL, TimerID, TimeDelay * 1000, (TIMERPROC)Timerfn);
+
+ return(TimerID != 0);
+}
+
+
+/***************************************************************************\
+* StopTimer
+*
+* Stops the input timer and resets the timeout flag
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL StopTimer(VOID)
+{
+ if (TimerID != 0) {
+ KillTimer(NULL, TimerID);
+ TimerID = 0;
+ }
+
+ TimeoutOccurred = FALSE;
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* Timerfn
+*
+* Called when the timer goes off.
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+WORD WINAPI Timerfn(
+ HWND hwnd,
+ WORD Message,
+ int IDEvent,
+ DWORD dwTime)
+{
+ // Set the timeout flag and stop any more timeouts
+
+ TimeoutOccurred = TRUE;
+
+ KillTimer(NULL, TimerID);
+ TimerID = 0;
+
+ if (GetTopTimeout(NULL) == NULL) {
+ DebugLog((DEB_ERROR, "Input timer went off, but top timeout has NULL hwnd"));
+ }
+
+ // Send a message to the window who owns the timeout
+ // ForwardMessage(NULL, WM_INPUT_TIMEOUT, FALSE, 0);
+
+ DebugLog((DEB_TRACE_TIMEOUT, "Input timer went off, sending TIMEOUT\n"));
+ if (DialogActive)
+ {
+ EndTopDialog(NULL, WLX_DLG_INPUT_TIMEOUT);
+ }
+ else
+ SASRouter(GlobalsArray[NestedIndex - 1], WLX_SAS_TYPE_TIMEOUT);
+
+ return(0);
+
+ DBG_UNREFERENCED_PARAMETER(hwnd);
+ DBG_UNREFERENCED_PARAMETER(Message);
+ DBG_UNREFERENCED_PARAMETER(IDEvent);
+ DBG_UNREFERENCED_PARAMETER(dwTime);
+}
+
+
+/***************************************************************************\
+* SetInputHooks
+*
+* Installs input hooks
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL SetInputHooks(VOID)
+{
+ InputHooksInstalled = TRUE;
+
+
+ hhkMouse = SetWindowsHook(WH_MOUSE, MouseHookfn);
+ hhkKeyboard = SetWindowsHook(WH_KEYBOARD, KeyboardHookfn);
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* ReleaseInputHooks
+*
+* Uninstalls input hooks
+*
+* Returns TRUE on success, FALSE on failure
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL ReleaseInputHooks(VOID)
+{
+ UnhookWindowsHook(WH_MOUSE, MouseHookfn);
+ UnhookWindowsHook(WH_KEYBOARD, KeyboardHookfn);
+
+ InputHooksInstalled = FALSE;
+
+ return(TRUE);
+}
+
+
+/***************************************************************************\
+* MouseHookfn
+*
+* Called when there is mouse input for this app
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+LRESULT WINAPI
+MouseHookfn(
+ int nCode,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ if (nCode >= 0) {
+ if (!TimeoutOccurred) {
+ StartTopTimeout();
+ }
+ }
+
+ return(DefHookProc(nCode, wParam, lParam, &hhkMouse));
+}
+
+
+/***************************************************************************\
+* KeyboardHookfn
+*
+* Called when there is keyboard input for this app
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+LRESULT WINAPI
+KeyboardHookfn(
+ int nCode,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ if (nCode >= 0) {
+ if (!TimeoutOccurred) {
+ StartTopTimeout();
+ }
+ }
+
+ return(DefHookProc(nCode, wParam, lParam, &hhkKeyboard));
+}
+
+
+/***************************************************************************\
+* TimeoutMessageBox
+*
+* Same as a normal message box, but times out if there is no user input
+* for the specified number of seconds
+* For convenience, this api takes string resource ids rather than string
+* pointers as input. The resources are loaded from the .exe module
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+int TimeoutMessageBoxEx(
+ PGLOBALS pGlobals,
+ HWND hwnd,
+ UINT IdText,
+ UINT IdCaption,
+ UINT wType,
+ TIMEOUT Timeout)
+{
+ TCHAR CaptionBuffer[MAX_STRING_BYTES];
+ PTCHAR Caption = CaptionBuffer;
+ TCHAR Text[MAX_STRING_BYTES];
+
+ LoadString(NULL, IdText, Text, MAX_STRING_LENGTH);
+
+ if (IdCaption != 0) {
+ LoadString(NULL, IdCaption, Caption, MAX_STRING_LENGTH);
+ } else {
+ Caption = NULL;
+ }
+
+ return TimeoutMessageBoxlpstr(pGlobals, hwnd, Text, Caption, wType, Timeout);
+}
+
+
+/***************************************************************************\
+* TimeoutMessageBoxlpstr
+*
+* Same as a normal message box, but times out if there is no user input
+* for the specified number of seconds
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+int TimeoutMessageBoxlpstr(
+ PGLOBALS pGlobals,
+ HWND hwnd,
+ LPTSTR Text,
+ LPTSTR Caption,
+ UINT wType,
+ TIMEOUT Timeout)
+{
+ int Result;
+ int DlgResult;
+
+#if DBG
+ //
+ // Reset the return code so if we forget to set if before returning
+ // an interrupt MapResultCode will detect it.
+ // Also this allows us to check the interrupt type is not overwritten
+ // by a second interrupt before we clear it.
+ //
+ TopDialogReturnCode = DLG_INTERRUPT;
+#endif
+
+ // Set up input timeout
+ PushMessageTimeout(hwnd, Timeout, Caption, pGlobals);
+
+ Result = MessageBox(hwnd, Text, Caption, wType);
+
+ // Re-enable previous timeout
+ PopMessageTimeout();
+
+ DlgResult = MapResultCode(Result, TopDialogReturnCode);
+
+#if DBG
+ //
+ // Reset the stored return code so we can detect if an interrupt is
+ // generated without the code being set.
+ //
+
+ TopDialogReturnCode = DLG_INTERRUPT;
+#endif
+
+ return(DlgResult);
+}
+
+
+/***************************************************************************\
+* TimeoutDialogBoxParam
+*
+* Same as a normal dialog box, but times out if there is no user input
+* for the specified number of seconds
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+int
+TimeoutDialogBoxParam(
+ PGLOBALS pGlobals,
+ HANDLE hInstance,
+ LPTSTR lpTemplateName,
+ HWND hwndParent,
+ DLGPROC lpDialogFunc,
+ LONG dwInitParam,
+ TIMEOUT Timeout)
+{
+ int Result;
+ MSG msg;
+
+#if DBG
+ //
+ // Reset the return code so if we forget to set if before returning
+ // an interrupt MapResultCode will detect it.
+ // Also this allows us to check the interrupt type is not overwritten
+ // by a second interrupt before we clear it.
+ //
+ TopDialogReturnCode = DLG_INTERRUPT;
+#endif
+
+ while (TRUE) {
+ PushDialogTimeout(Timeout, pGlobals);
+
+ Result = DialogBoxParam(hInstance,
+ lpTemplateName,
+ hwndParent,
+ lpDialogFunc,
+ dwInitParam
+ );
+#if DBG
+ if (Result < 0)
+ {
+ if ((DWORD) lpTemplateName > 0x00010000)
+ {
+ DebugLog((DEB_WARN, "DialogBoxParam(%#x, %ws, %#x, %#x, %#x) failed, error %d\n",
+ hInstance, lpTemplateName, hwndParent, lpDialogFunc,
+ dwInitParam, GetLastError() ));
+ }
+ else
+ {
+ DebugLog((DEB_WARN, "DialogBoxParam(%#x, %#x, %#x, %#x, %#x) failed, error %d\n",
+ hInstance, lpTemplateName, hwndParent, lpDialogFunc,
+ dwInitParam, GetLastError() ));
+
+ }
+ }
+#endif
+
+ // Re-enable previous timeout
+ PopTimeout();
+
+ //
+ // If the dialog returned due to WM_QUIT, eat the message
+ // and do the dialog again.
+ //
+
+ if (!PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE)) {
+ break;
+ }
+ }
+
+ return(Result);
+}
+
+
+/***************************************************************************\
+* TimeoutDialogBoxIndirectParam
+*
+* Same as a normal dialog box, but times out if there is no user input
+* for the specified number of seconds
+*
+* 05-15-92 Davidc Created.
+\***************************************************************************/
+
+int
+TimeoutDialogBoxIndirectParam(
+ PGLOBALS pGlobals,
+ HANDLE hInstance,
+ LPDLGTEMPLATE Template,
+ HWND hwndParent,
+ DLGPROC lpDialogFunc,
+ LONG dwInitParam,
+ TIMEOUT Timeout)
+{
+ int Result;
+ MSG msg;
+
+
+ while (TRUE) {
+ PushDialogTimeout(Timeout, pGlobals);
+
+ Result = DialogBoxIndirectParam(hInstance,
+ Template,
+ hwndParent,
+ lpDialogFunc,
+ dwInitParam
+ );
+
+ // Re-enable previous timeout
+ PopTimeout();
+
+ //
+ // If the dialog returned due to WM_QUIT, eat the message
+ // and do the dialog again.
+ //
+
+ if (!PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE)) {
+ break;
+ }
+ }
+
+ return(Result);
+}
+
+
+
+/***************************************************************************\
+* EndTopDialog
+*
+* Interrupts the dialog on top of the timeout stack and causes it to return
+* the code specified.
+*
+* The passed hwnd is that of the caller. This is not used other than as
+* a debugging aid.
+*
+* The dlgresult passed must be one of the interrupt types.
+*
+* Returns TRUE on success, FALSE on failure.
+*
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+BOOL EndTopDialog(
+ HWND hwnd,
+ int DlgResult
+ )
+{
+ HWND hwndTop = GetTopTimeout(NULL);
+
+ if (hwndTop == NULL) {
+ DebugLog((DEB_ERROR, "EndTopDialog called with no dialogs on the stack!"));
+ ASSERT(FALSE);
+ return(FALSE);
+ }
+
+#ifdef WINLOGON_TEST
+ if (hwndTop != hwnd) {
+ DebugLog((DEB_ERROR, "Ending top dialog from lower-level dialog!"));
+ }
+#endif
+
+ //
+ // Check the value has not already been set
+ //
+
+ ASSERT(TopDialogReturnCode == DLG_INTERRUPT);
+
+ TopDialogReturnCode = DlgResult;
+
+ return (EndDialog(hwndTop, DLG_INTERRUPT));
+}
+
+BOOL
+KillMessageBox( DWORD SasCode )
+{
+ DWORD EndCode;
+
+ //
+ // This will kill any outstanding message boxes due to an incoming
+ // SAS event. This is used by SendSasToTopWindow when it is forwarding
+ // along an GINA specific SAS. This kills pending message boxes so that
+ // the dialog regains control.
+ //
+
+ if (DialogActive)
+ {
+ switch ( SasCode )
+ {
+ case WLX_SAS_TYPE_TIMEOUT:
+ EndCode = WLX_DLG_INPUT_TIMEOUT ;
+ break;
+
+ case WLX_SAS_TYPE_SCRNSVR_TIMEOUT:
+ EndCode = WLX_DLG_SCREEN_SAVER_TIMEOUT ;
+ break;
+
+ default:
+ EndCode = WLX_DLG_SAS;
+ break;
+ }
+
+ EndTopDialog(NULL, EndCode);
+ return(TRUE);
+ }
+ return(FALSE);
+}
diff --git a/private/windows/gina/winlogon/timeout.h b/private/windows/gina/winlogon/timeout.h
new file mode 100644
index 000000000..8f679d671
--- /dev/null
+++ b/private/windows/gina/winlogon/timeout.h
@@ -0,0 +1,129 @@
+/****************************** Module Header ******************************\
+* Module Name: timeout.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Defines apis to support dialog and message-box input timeouts
+*
+* History:
+* 12-05-91 Davidc Created.
+\***************************************************************************/
+
+
+//
+// Define timeout type - represents timeout value in seconds
+//
+typedef ULONG TIMEOUT;
+typedef TIMEOUT * PTIMEOUT;
+
+
+//
+// Define special timeout values
+//
+// The top bit of the timeout value is the 'notify bit'.
+// This bit is only used when the timeout value = TIMEOUT_NONE
+//
+// When a screen-saver timeout occurs, the timeout stack is searched
+// from the top down for the first occurrence of
+// 1) A window with a timeout OR
+// 2) The first TIMEOUT_NONE window with the notify-bit set.
+//
+// In case 1), the window is timed-out and returns DLG_SCREEN_SAVER_TIMEOUT.
+//
+// In case 2), a WM_SCREEN_SAVER_TIMEOUT message is posted to the window.
+//
+// The notify bit is never inherited. If required, it must be specified in
+// addition to TIMEOUT_CURRENT.
+//
+// NOTE SAS messages are always sent to the topmost timeout window
+//
+// NOTE User logoff messages cause the top window to return DLG_USER_LOGOFF
+// if it has a non-0 timeout, otherwise the window receives a WM_USER_LOGOFF
+// message.
+//
+
+#define TIMEOUT_VALUE_MASK (0x0fffffff)
+#define TIMEOUT_NOTIFY_MASK (0x10000000)
+
+#define TIMEOUT_VALUE(t) (t & TIMEOUT_VALUE_MASK)
+#define TIMEOUT_NOTIFY(t) (t & TIMEOUT_NOTIFY_MASK)
+
+#define TIMEOUT_SS_NOTIFY (TIMEOUT_NOTIFY_MASK)
+#define TIMEOUT_CURRENT (TIMEOUT_VALUE_MASK) // Use existing timeout
+#define TIMEOUT_NONE (0) // Disable input timeout
+
+
+
+
+
+
+//
+// Exported function prototypes
+//
+
+
+LONG ForwardMessage(
+ PGLOBALS pGlobals,
+ UINT Message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+VOID ProcessDialogTimeout(
+ HWND hwnd,
+ UINT Message,
+ DWORD wParam,
+ LONG lParam
+ );
+
+int TimeoutMessageBoxEx(
+ PGLOBALS pGlobals,
+ HWND hWnd,
+ UINT IdText,
+ UINT IdCaption,
+ UINT wType,
+ TIMEOUT Timeout
+ );
+
+int TimeoutMessageBoxlpstr(
+ PGLOBALS pGlobals,
+ HWND hWnd,
+ LPTSTR Text,
+ LPTSTR Caption,
+ UINT wType,
+ TIMEOUT Timeout
+ );
+
+int
+TimeoutDialogBoxParam(
+ PGLOBALS pGlobals,
+ HANDLE hInstance,
+ LPTSTR lpTemplateName,
+ HWND hWndParent,
+ DLGPROC lpDialogFunc,
+ LONG dwInitParam,
+ TIMEOUT Timeout
+ );
+
+int
+TimeoutDialogBoxIndirectParam(
+ PGLOBALS pGlobals,
+ HANDLE hInstance,
+ LPDLGTEMPLATE Template,
+ HWND hwndParent,
+ DLGPROC lpDialogFunc,
+ LONG dwInitParam,
+ TIMEOUT Timeout
+ );
+
+BOOL EndTopDialog(
+ HWND hwnd,
+ int DlgResult
+ );
+
+BOOL SetTopTimeout(HWND hwnd);
+
+
+BOOL
+TimeoutUpdateTopTimeout(
+ DWORD Timeout);
diff --git a/private/windows/gina/winlogon/usrenv.c b/private/windows/gina/winlogon/usrenv.c
new file mode 100644
index 000000000..41f7e6d1d
--- /dev/null
+++ b/private/windows/gina/winlogon/usrenv.c
@@ -0,0 +1,564 @@
+/****************************** Module Header ******************************\
+* Module Name: logon.c
+*
+* Copyright (c) 1992, Microsoft Corporation
+*
+* Handles logoff dialog.
+*
+* History:
+* 2-25-92 JohanneC Created -
+*
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+BOOL
+SetGINAEnvVars (
+ PGLOBALS pGlobals
+ );
+
+
+
+BOOL
+SetupBasicEnvironment(
+ PVOID * ppEnv
+ )
+{
+ TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
+ DWORD dwComputerNameSize = MAX_COMPUTERNAME_LENGTH+1;
+
+ if (GetComputerName (szComputerName, &dwComputerNameSize)) {
+ SetUserEnvironmentVariable(ppEnv, COMPUTERNAME_VARIABLE, (LPTSTR) szComputerName, TRUE);
+ }
+
+ return(TRUE);
+}
+
+/***************************************************************************\
+* SetupUserEnvironment
+*
+* Initializes all system and user environment variables, retrieves the user's
+* profile, sets current directory...
+*
+* Returns TRUE on success, FALSE on failure.
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+BOOL
+SetupUserEnvironment(
+ PGLOBALS pGlobals
+ )
+{
+ PVOID pEnv = NULL;
+ TCHAR lpHomeShare[MAX_PATH] = TEXT("");
+ TCHAR lpHomePath[MAX_PATH] = TEXT("");
+ TCHAR lpHomeDrive[4] = TEXT("");
+ TCHAR lpHomeDirectory[MAX_PATH] = TEXT("");
+ TCHAR lpUserProfile[MAX_PATH];
+ DWORD dwSize = MAX_PATH;
+ NTSTATUS Status;
+
+ if (!pGlobals->hEventLog) {
+ //
+ // Register the event source for winlogon events.
+ //
+ pGlobals->hEventLog = RegisterEventSource(NULL, EVENTLOG_SOURCE);
+ }
+
+ /*
+ * Create a new environment for the user.
+ */
+
+ if (!CreateUserEnvironment(&pEnv))
+ {
+ return(FALSE);
+ }
+
+ SetupBasicEnvironment(&pEnv);
+
+ /*
+ * Initialize user's environment.
+ */
+
+#if 0
+ SetUserEnvironmentVariable(&pEnv, USERNAME_VARIABLE, (LPTSTR)pGlobals->UserName, TRUE);
+ SetUserEnvironmentVariable(&pEnv, USERDOMAIN_VARIABLE, (LPTSTR)pGlobals->Domain, TRUE);
+
+ if (pGlobals->Profile->HomeDirectoryDrive.Length &&
+ (pGlobals->Profile->HomeDirectoryDrive.Length + 1) < MAX_PATH) {
+ lstrcpy(lpHomeDrive, pGlobals->Profile->HomeDirectoryDrive.Buffer);
+ }
+
+ if (pGlobals->Profile->HomeDirectory.Length &&
+ (pGlobals->Profile->HomeDirectory.Length + 1) < MAX_PATH) {
+ lstrcpy(lpHomeDirectory, pGlobals->Profile->HomeDirectory.Buffer);
+ }
+#endif
+ SetHomeDirectoryEnvVars(&pEnv, lpHomeDirectory,
+ lpHomeDrive, lpHomeShare, lpHomePath);
+#if 0
+ if (pGlobals->Profile->ProfilePath.Length) {
+ pGlobals->UserProfile.ProfilePath =
+ AllocAndExpandEnvironmentStrings(pGlobals->Profile->ProfilePath.Buffer);
+ } else {
+ pGlobals->UserProfile.ProfilePath = NULL;
+ }
+#endif
+
+ //
+ // Load the user's profile into the registry
+ //
+
+ Status = RestoreUserProfile(pGlobals);
+ if (Status != STATUS_SUCCESS) {
+ DebugLog((DEB_ERROR, "restoring the user profile failed"));
+ return(FALSE);
+ }
+
+
+ //
+ // Set USERPROFILE environment variable
+ //
+
+ if (GetUserProfileDirectory (pGlobals->UserProcessData.UserToken,
+ lpUserProfile, &dwSize)) {
+
+ SetUserEnvironmentVariable(&pEnv, USERPROFILE_VARIABLE, lpUserProfile, TRUE);
+ }
+
+
+ pGlobals->UserProcessData.pEnvironment = pEnv;
+
+ if (pGlobals->UserProcessData.CurrentDirectory = (LPTSTR)Alloc(
+ sizeof(TCHAR)*(lstrlen(lpHomeDirectory)+1)))
+ lstrcpy(pGlobals->UserProcessData.CurrentDirectory, lpHomeDirectory);
+
+ //
+ // Set the GINA environment variables in the registry
+ //
+
+ SetGINAEnvVars (pGlobals);
+
+
+ /*
+ * Set all windows controls to be the user's settings.
+ */
+ InitSystemParametersInfo(pGlobals, TRUE);
+
+ return(TRUE);
+
+}
+
+/***************************************************************************\
+* ResetEnvironment
+*
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+VOID
+ResetEnvironment(
+ PGLOBALS pGlobals
+ )
+{
+
+ //
+ // If they were logged on as system, all these values will be NULL
+ //
+
+ if (pGlobals->UserProcessData.CurrentDirectory) {
+ Free(pGlobals->UserProcessData.CurrentDirectory);
+ pGlobals->UserProcessData.CurrentDirectory = NULL;
+ }
+ if (pGlobals->UserProcessData.pEnvironment) {
+ RtlDestroyEnvironment(pGlobals->UserProcessData.pEnvironment);
+ pGlobals->UserProcessData.pEnvironment = NULL;
+ }
+ if (pGlobals->UserProfile.ProfilePath) {
+ Free(pGlobals->UserProfile.ProfilePath);
+ pGlobals->UserProfile.ProfilePath = NULL;
+ }
+ if (pGlobals->UserProfile.PolicyPath) {
+ Free(pGlobals->UserProfile.PolicyPath);
+ pGlobals->UserProfile.PolicyPath = NULL;
+ }
+ if (pGlobals->UserProfile.NetworkDefaultUserProfile) {
+ Free(pGlobals->UserProfile.NetworkDefaultUserProfile);
+ pGlobals->UserProfile.NetworkDefaultUserProfile = NULL;
+ }
+ if (pGlobals->UserProfile.ServerName) {
+ Free(pGlobals->UserProfile.ServerName);
+ pGlobals->UserProfile.ServerName = NULL;
+ }
+ if (pGlobals->UserProfile.Environment) {
+ Free(pGlobals->UserProfile.Environment);
+ pGlobals->UserProfile.Environment = NULL;
+ }
+
+ //
+ // Reset all windows controls to be the default settings
+ //
+
+ InitSystemParametersInfo(pGlobals, FALSE);
+}
+
+
+
+
+
+/***************************************************************************\
+* OpenHKeyCurrentUser
+*
+* Opens HKeyCurrentUser to point at the current logged on user's profile.
+*
+* Returns TRUE on success, FALSE on failure
+*
+* History:
+* 06-16-92 Davidc Created
+*
+\***************************************************************************/
+BOOL
+OpenHKeyCurrentUser(
+ PGLOBALS pGlobals
+ )
+{
+ DWORD err;
+ HANDLE ImpersonationHandle;
+ BOOL Result;
+
+ //
+ // Make sure HKEY_CURRENT_USER is closed before
+ // remapping it.
+ //
+
+ try {
+
+ RegCloseKey(HKEY_CURRENT_USER);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {};
+
+
+ //
+ // Get in the correct context before we reference the registry
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "OpenHKeyCurrentUser failed to impersonate user"));
+ return(FALSE);
+ }
+
+
+ //
+ // Access the registry to force HKEY_CURRENT_USER to be re-opened
+ //
+
+ err = RegEnumKey(HKEY_CURRENT_USER, 0, NULL, 0);
+
+ //
+ // Return to our own context
+ //
+
+ Result = StopImpersonating(ImpersonationHandle);
+ ASSERT(Result);
+
+
+ return(TRUE);
+}
+
+
+
+/***************************************************************************\
+* CloseHKeyCurrentUser
+*
+* Closes HKEY_CURRENT_USER.
+* Any registry reference will automatically re-open it, so this is
+* only a token gesture - but it allows the registry hive to be unloaded.
+*
+* Returns nothing
+*
+* History:
+* 06-16-92 Davidc Created
+*
+\***************************************************************************/
+VOID
+CloseHKeyCurrentUser(
+ PGLOBALS pGlobals
+ )
+{
+ DWORD err;
+
+ err = RegCloseKey(HKEY_CURRENT_USER);
+ ASSERT(err == ERROR_SUCCESS);
+}
+
+
+/***************************************************************************\
+* FUNCTION: SetEnvironmentULong
+*
+* PURPOSE: Sets the value of an environment variable to the string
+* representation of the passed data.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 01-12-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+SetEnvironmentULong(
+ LPTSTR Variable,
+ ULONG Value
+ )
+{
+ TCHAR Buffer[10];
+ int Result;
+
+ Result = _snwprintf(Buffer, sizeof(Buffer)/sizeof(TCHAR), TEXT("%x"), Value);
+ ASSERT(Result < sizeof(Buffer));
+
+ return (SetEnvironmentVariable(Variable, Buffer));
+}
+
+
+/***************************************************************************\
+* FUNCTION: SetEnvironmentLargeInt
+*
+* PURPOSE: Sets the value of an environment variable to the string
+* representation of the passed data.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 01-12-93 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+SetEnvironmentLargeInt(
+ LPTSTR Variable,
+ LARGE_INTEGER Value
+ )
+{
+ TCHAR Buffer[20];
+ int Result;
+
+ Result = _snwprintf(Buffer, sizeof(Buffer)/sizeof(TCHAR), TEXT("%x:%x"), Value.HighPart, Value.LowPart);
+ ASSERT(Result < sizeof(Buffer));
+
+ return (SetEnvironmentVariable(Variable, Buffer));
+}
+
+/***************************************************************************\
+* FUNCTION: SetGINAEnvVars
+*
+* PURPOSE: Sets the environment variables GINA passed back to the
+* volatile environment in the user's profile
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 09-26-95 EricFlo Created.
+*
+\***************************************************************************/
+
+#define MAX_VALUE_LEN 1024
+
+BOOL
+SetGINAEnvVars (
+ PGLOBALS pGlobals
+ )
+{
+
+ TCHAR szValueName[MAX_VALUE_LEN + 1];
+ TCHAR szValue[MAX_VALUE_LEN + 1];
+ LPTSTR lpEnv = pGlobals->UserProfile.Environment;
+ LPTSTR lpEnd, lpBegin, lpTemp;
+ HKEY hKey = NULL;
+ DWORD dwDisp;
+ BOOL bRetVal = FALSE;
+ DWORD cPercent, len, i;
+
+
+
+ if (!lpEnv) {
+ return TRUE;
+ }
+
+
+ if (!OpenHKeyCurrentUser(pGlobals)) {
+ DebugLog((DEB_ERROR, "SetGINAEnvVars: Failed to open HKeyCurrentUser"));
+ return FALSE;
+ }
+
+
+ if (RegCreateKeyEx(HKEY_CURRENT_USER,
+ TEXT("Volatile Environment"),
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ KEY_WRITE,
+ NULL,
+ &hKey,
+ &dwDisp) != ERROR_SUCCESS) {
+ goto Exit;
+ }
+
+
+
+ lpEnd = lpBegin = lpEnv;
+
+ for (;;) {
+
+ //
+ // Skip leading blanks
+ //
+
+ while (*lpEnd == TEXT(' ')) {
+ lpEnd++;
+ }
+
+ lpBegin = lpEnd;
+
+
+
+ //
+ // Search for the = sign
+ //
+
+ while (*lpEnd && *lpEnd != TEXT('=')) {
+ lpEnd++;
+ }
+
+ if (!*lpEnd) {
+ goto Exit;
+ }
+
+ //
+ // Null terminate and copy to value name buffer
+ //
+
+ *lpEnd = TEXT('\0');
+
+ if (lstrlen(lpBegin) + 1 > MAX_VALUE_LEN) {
+ goto Exit;
+ }
+
+ lstrcpy (szValueName, lpBegin);
+
+
+ *lpEnd++ = TEXT('=');
+
+
+ //
+ // Trim off any trailing spaces
+ //
+
+ lpTemp = szValueName + (lstrlen (szValueName) - 1);
+
+ while (*lpTemp && (*lpTemp == TEXT(' ')) ) {
+ lpTemp--;
+ }
+
+ lpTemp++;
+ *lpTemp = TEXT('\0');
+
+
+
+ //
+ // Skip leading blanks before value data
+ //
+
+ while (*lpEnd == TEXT(' ')) {
+ lpEnd++;
+ }
+
+ lpBegin = lpEnd;
+
+
+ //
+ // Search for the null terminator
+ //
+
+ while (*lpEnd) {
+ lpEnd++;
+ }
+
+ if (lstrlen(lpBegin) + 1 > MAX_VALUE_LEN) {
+ goto Exit;
+ }
+
+ lstrcpy (szValue, lpBegin);
+
+
+ //
+ // Trim off any trailing spaces
+ //
+
+ lpTemp = szValue + (lstrlen (szValue) - 1);
+
+ while (*lpTemp && (*lpTemp == TEXT(' ')) ) {
+ lpTemp--;
+ }
+
+ lpTemp++;
+ *lpTemp = TEXT('\0');
+
+
+
+ //
+ // Scan the value data to see if a 2 % signs exist.
+ // If so, then this is an expand_sz type.
+ //
+
+ cPercent = 0;
+ len = lstrlen (szValue);
+
+ for (i = 0; i < len; i++) {
+ if (szValue[i] == TEXT('%')) {
+ cPercent++;
+ }
+ }
+
+
+ //
+ // Set it in the user profile
+ //
+
+ RegSetValueEx (hKey,
+ szValueName,
+ 0,
+ (cPercent >= 2) ? REG_EXPAND_SZ : REG_SZ,
+ (LPBYTE) szValue,
+ (len + 1) * sizeof(TCHAR));
+
+ lpEnd++;
+
+ if (!*lpEnd) {
+ break;
+ }
+
+ lpBegin = lpEnd;
+ }
+
+ bRetVal = TRUE;
+
+Exit:
+
+ if (hKey) {
+ RegCloseKey (hKey);
+ }
+
+ CloseHKeyCurrentUser(pGlobals);
+
+ return bRetVal;
+
+}
diff --git a/private/windows/gina/winlogon/usrenv.h b/private/windows/gina/winlogon/usrenv.h
new file mode 100644
index 000000000..6891a689d
--- /dev/null
+++ b/private/windows/gina/winlogon/usrenv.h
@@ -0,0 +1,96 @@
+/****************************** Module Header ******************************\
+* Module Name: usrenv.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define constants user by and apis in usrenv.c
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+#define COLON TEXT(':')
+#define BSLASH TEXT('\\')
+
+//
+// Define the source for the event log handle used to log profile failures.
+//
+#define EVENTLOG_SOURCE TEXT("Winlogon")
+
+
+//
+// Value names for for different environment variables
+//
+
+#define PATH_VARIABLE TEXT("PATH")
+#define LIBPATH_VARIABLE TEXT("LibPath")
+#define OS2LIBPATH_VARIABLE TEXT("Os2LibPath")
+#define AUTOEXECPATH_VARIABLE TEXT("AutoexecPath")
+
+#define HOMEDRIVE_VARIABLE TEXT("HOMEDRIVE")
+#define HOMESHARE_VARIABLE TEXT("HOMESHARE")
+#define HOMEPATH_VARIABLE TEXT("HOMEPATH")
+
+#define COMPUTERNAME_VARIABLE TEXT("COMPUTERNAME")
+#define USERNAME_VARIABLE TEXT("USERNAME")
+#define USERDOMAIN_VARIABLE TEXT("USERDOMAIN")
+#define USERPROFILE_VARIABLE TEXT("USERPROFILE")
+
+//
+// Default directories used when the user's home directory does not exist
+// or is invalid.
+//
+
+#define ROOT_DIRECTORY TEXT("\\")
+#define USERS_DIRECTORY TEXT("\\users")
+#define USERS_DEFAULT_DIRECTORY TEXT("\\users\\default")
+
+#define NULL_STRING TEXT("")
+
+//
+// Defines for Logon script paths.
+//
+
+#define SERVER_SCRIPT_PATH TEXT("\\NETLOGON\\")
+#define LOCAL_SCRIPT_PATH TEXT("\\repl\\import\\scripts\\")
+
+
+//
+// Prototypes
+//
+
+
+BOOL
+SetupUserEnvironment(
+ PGLOBALS pGlobals
+ );
+
+VOID
+ResetEnvironment(
+ PGLOBALS pGlobals
+ );
+
+BOOL
+SetupBasicEnvironment(
+ PVOID * ppEnv
+ );
+
+VOID InitSystemParametersInfo(
+ PGLOBALS pGlobals,
+ BOOL bUserLoggedOn
+ );
+
+BOOL
+OpenHKeyCurrentUser(
+ PGLOBALS pGlobals
+ );
+
+VOID
+CloseHKeyCurrentUser(
+ PGLOBALS pGlobals
+ );
+
+VOID
+ClearUserProfileData(
+ PUSER_PROFILE_INFO UserProfileData
+ );
diff --git a/private/windows/gina/winlogon/usrpro.c b/private/windows/gina/winlogon/usrpro.c
new file mode 100644
index 000000000..5f9c4ba7e
--- /dev/null
+++ b/private/windows/gina/winlogon/usrpro.c
@@ -0,0 +1,260 @@
+/****************************** Module Header ******************************\
+* Module Name: logon.c
+*
+* Copyright (c) 1992, Microsoft Corporation
+*
+* Handles loading and unloading user profiles.
+*
+* History:
+* 2-25-92 JohanneC Created -
+*
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+/////////////////////////////////////////////////////////////////////////
+//
+// Global variables for this module.
+//
+/////////////////////////////////////////////////////////////////////////
+PSID gGuestsDomainSid = NULL;
+SID_IDENTIFIER_AUTHORITY gNtAuthority = SECURITY_NT_AUTHORITY;
+
+
+
+/***************************************************************************\
+* IsUserAGuest
+*
+* returns TRUE if the user is a member of the Guests domain. If so, no
+* cached profile should be created and when the profile is not available
+* use the user default profile.
+*
+* History:
+* 04-30-93 Johannec Created
+*
+\***************************************************************************/
+BOOL IsUserAGuest(PGLOBALS pGlobals)
+{
+ NTSTATUS Status;
+ ULONG InfoLength;
+ PTOKEN_GROUPS TokenGroupList;
+ ULONG GroupIndex;
+ BOOL FoundGuests;
+
+
+ if (TestTokenForAdmin(pGlobals->UserProcessData.UserToken)) {
+ //
+ // The user is an admin, ignore the fact that the user could be a
+ // guest too.
+ //
+ return(FALSE);
+ }
+ if (!gGuestsDomainSid) {
+
+ //
+ // Create Guests domain sid.
+ //
+ Status = RtlAllocateAndInitializeSid(
+ &gNtAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_GUESTS,
+ 0, 0, 0, 0, 0, 0,
+ &gGuestsDomainSid
+ );
+ }
+
+ //
+ // Test if user is in the Guests domain
+ //
+
+ //
+ // Get a list of groups in the token
+ //
+
+ Status = NtQueryInformationToken(
+ pGlobals->UserProcessData.UserToken, // Handle
+ TokenGroups, // TokenInformationClass
+ NULL, // TokenInformation
+ 0, // TokenInformationLength
+ &InfoLength // ReturnLength
+ );
+
+ if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) {
+
+ DebugLog((DEB_ERROR, "failed to get group info for guests token, status = 0x%lx", Status));
+ return(FALSE);
+ }
+
+
+ TokenGroupList = Alloc(InfoLength);
+
+ if (TokenGroupList == NULL) {
+ DebugLog((DEB_ERROR, "unable to allocate memory for token groups\n"));
+ return(FALSE);
+ }
+
+ Status = NtQueryInformationToken(
+ pGlobals->UserProcessData.UserToken, // Handle
+ TokenGroups, // TokenInformationClass
+ TokenGroupList, // TokenInformation
+ InfoLength, // TokenInformationLength
+ &InfoLength // ReturnLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ DebugLog((DEB_ERROR, "failed to query groups for guests token, status = 0x%lx", Status));
+ Free(TokenGroupList);
+ return(FALSE);
+ }
+
+
+ //
+ // Search group list for guests alias
+ //
+
+ FoundGuests = FALSE;
+
+ for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) {
+
+ if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, gGuestsDomainSid)) {
+ FoundGuests = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Tidy up
+ //
+
+ Free(TokenGroupList);
+
+ return(FoundGuests);
+}
+
+/***************************************************************************\
+* RestoreUserProfile
+*
+* Downloads the user's profile if possible, otherwise use either cached
+* profile or default Windows profile.
+*
+* Returns TRUE on success, FALSE on failure.
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+NTSTATUS
+RestoreUserProfile(
+ PGLOBALS pGlobals
+ )
+{
+ PROFILEINFO pi;
+ BOOL bSilent = FALSE;
+ HKEY hKey;
+ LONG lResult;
+ DWORD dwType, dwSize;
+
+
+ //
+ // Check if the "NoPopups" flag is set.
+ //
+
+ lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Windows"),
+ 0,
+ KEY_READ,
+ &hKey);
+
+ if (lResult == ERROR_SUCCESS) {
+
+ dwSize = sizeof (bSilent);
+
+ RegQueryValueEx(hKey,
+ TEXT("NoPopupsOnBoot"),
+ NULL,
+ &dwType,
+ (LPBYTE) &bSilent,
+ &dwSize);
+
+ RegCloseKey (hKey);
+ }
+
+
+ //
+ // Load the profile
+ //
+
+ pi.dwSize = sizeof(PROFILEINFO);
+ pi.dwFlags = PI_APPLYPOLICY | (bSilent ? PI_NOUI : 0);
+ pi.lpUserName = pGlobals->UserName;
+ pi.lpProfilePath = pGlobals->UserProfile.ProfilePath;
+ pi.lpDefaultPath = pGlobals->UserProfile.NetworkDefaultUserProfile;
+ pi.lpServerName = pGlobals->UserProfile.ServerName;
+ pi.lpPolicyPath = pGlobals->UserProfile.PolicyPath;
+
+ if (LoadUserProfile(pGlobals->UserProcessData.UserToken, &pi)) {
+ pGlobals->UserProfile.hProfile = pi.hProfile;
+ return ERROR_SUCCESS;
+ } else {
+ pGlobals->UserProfile.hProfile = NULL;
+ }
+
+ //
+ // Failure
+ //
+
+ return GetLastError();
+
+}
+
+/***************************************************************************\
+* SaveUserProfile
+*
+* Saves the user's profile changes.
+*
+*
+* History:
+* 2-28-92 Johannec Created
+*
+\***************************************************************************/
+BOOL
+SaveUserProfile(
+ PGLOBALS pGlobals
+ )
+{
+ HANDLE hEventStart, hEventDone;
+
+ //
+ // Notify RAS Autodial service that the
+ // user has is logging off.
+ //
+ hEventStart = OpenEvent(EVENT_ALL_ACCESS, FALSE, L"RasAutodialLogoffUser");
+ hEventDone = OpenEvent(EVENT_ALL_ACCESS, FALSE, L"RasAutodialLogoffUserDone");
+
+ if (hEventStart != NULL && hEventDone != NULL) {
+
+ //
+ // Toggle the event so RAS can save it's settings and
+ // close it's HKEY_CURRENT_USER key.
+ //
+
+ SetEvent(hEventStart);
+
+ //
+ // Autodial will toggle the event again when it's finished.
+ //
+
+ WaitForSingleObject (hEventDone, 20000);
+
+ CloseHandle(hEventStart);
+ CloseHandle(hEventDone);
+ }
+
+
+
+ return UnloadUserProfile (pGlobals->UserProcessData.UserToken,
+ pGlobals->UserProfile.hProfile);
+
+}
diff --git a/private/windows/gina/winlogon/usrpro.h b/private/windows/gina/winlogon/usrpro.h
new file mode 100644
index 000000000..4296fd9dc
--- /dev/null
+++ b/private/windows/gina/winlogon/usrpro.h
@@ -0,0 +1,29 @@
+/****************************** Module Header ******************************\
+* Module Name: usrpro.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define apis in usrpro.c
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+//
+// Prototypes
+//
+
+BOOL
+SaveUserProfile(
+ PGLOBALS pGlobals
+ );
+
+NTSTATUS
+RestoreUserProfile(
+ PGLOBALS pGlobals
+ );
+
+BOOL
+IsUserAGuest(
+ PGLOBALS pGlobals
+ );
diff --git a/private/windows/gina/winlogon/win31mig.c b/private/windows/gina/winlogon/win31mig.c
new file mode 100644
index 000000000..d310d5350
--- /dev/null
+++ b/private/windows/gina/winlogon/win31mig.c
@@ -0,0 +1,287 @@
+/****************************** Module Header ******************************\
+* Module Name: logon.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Implements functions to allow a user to control migration of
+* Windows 3.1 configuration information from the .INI, .GRP and REG.DAT
+* files into the Windows/NT when the logon for the first time.
+*
+* History:
+* 02-23-93 Stevewo Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+typedef struct _WIN31_MIGRATION_DIALOG {
+ PGLOBALS pGlobals;
+ DWORD Win31MigrationFlags;
+} WIN31_MIGRATION_DIALOG, * PWIN31_MIGRATION_DIALOG;
+
+//
+// Private prototypes
+//
+
+BOOL WINAPI
+Win31MigrationDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+/***************************************************************************\
+* FUNCTION: Windows31Migration
+*
+* PURPOSE: Checks to see if there is any Windows 3.1 data to
+* migrate to the Windows/NT registry, and if so,
+* puts up a dialog box for the user to control the
+* process and watch it happen.
+*
+* RETURNS: TRUE/FALSE
+*
+* HISTORY:
+*
+* 02-23-93 Stevewo Created.
+*
+\***************************************************************************/
+
+BOOL
+Windows31Migration(
+ PGLOBALS pGlobals
+ )
+{
+ HANDLE ImpersonationHandle;
+ WIN31_MIGRATION_DIALOG DialogInfo;
+ DWORD Win31MigrationFlags;
+ BOOL bDisplayDialog = TRUE;
+ HKEY hkeyWinlogon;
+ DWORD dwResult, dwType, dwSize;
+
+
+ //
+ // Get in the correct context before we reference the registry
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "Win31Migration failed to impersonate user for query\n"));
+ return(TRUE);
+ }
+
+ Win31MigrationFlags = QueryWindows31FilesMigration( Win31LogonEvent );
+
+ StopImpersonating(ImpersonationHandle);
+
+ if (Win31MigrationFlags == 0) {
+ return(TRUE);
+ }
+
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY,
+ 0, KEY_READ, &hkeyWinlogon) == ERROR_SUCCESS) {
+
+ dwSize = sizeof(dwResult);
+
+ if (RegQueryValueEx (hkeyWinlogon, TEXT("win9xupg"),
+ NULL, &dwType, (LPBYTE) &dwResult,
+ &dwSize) == ERROR_SUCCESS) {
+
+ if (dwResult) {
+ bDisplayDialog = FALSE;
+ }
+ }
+
+ RegCloseKey (hkeyWinlogon);
+ }
+
+
+ if (!bDisplayDialog) {
+ return(TRUE);
+ }
+
+
+ DialogInfo.pGlobals = pGlobals;
+ DialogInfo.Win31MigrationFlags = Win31MigrationFlags;
+
+ return WlxDialogBoxParam(pGlobals,
+ pGlobals->hInstance,
+ (LPTSTR) MAKEINTRESOURCE(IDD_WIN31MIG),
+ NULL,
+ Win31MigrationDlgProc,
+ (LPARAM)&DialogInfo
+ );
+}
+
+
+BOOL WINAPI
+Win31MigrationStatusCallback(
+ IN PWSTR Status,
+ IN PVOID CallbackParameter
+ )
+{
+ HWND hDlg = (HWND)CallbackParameter;
+
+ return SetDlgItemTextW(hDlg, IDD_WIN31MIG_STATUS, Status);
+}
+
+
+
+/***************************************************************************\
+* FUNCTION: Win31MigrationDlgProc
+*
+* PURPOSE: Processes messages for Windows 3.1 Migration dialog
+*
+* RETURNS: TRUE/FALSE
+*
+* HISTORY:
+*
+* 02-23-93 Stevewo Created.
+*
+\***************************************************************************/
+
+BOOL WINAPI
+Win31MigrationDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PWIN31_MIGRATION_DIALOG pDialogInfo = (PWIN31_MIGRATION_DIALOG) GetWindowLong(hDlg, GWL_USERDATA);
+ HANDLE ImpersonationHandle;
+ UINT idFocus;
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+
+ //
+ // Make sure that we don't get killed by a stray SAS
+ //
+ SetMapperFlag(hDlg, MAPPERFLAG_WINLOGON);
+
+ pDialogInfo = (PWIN31_MIGRATION_DIALOG) lParam;
+ SetWindowLong(hDlg, GWL_USERDATA, lParam);
+
+
+ if (pDialogInfo->Win31MigrationFlags & WIN31_MIGRATE_INIFILES) {
+ CheckDlgButton(hDlg, idFocus = IDD_WIN31MIG_INIFILES, 1 );
+ } else {
+ CheckDlgButton(hDlg, IDD_WIN31MIG_INIFILES, 0 );
+ }
+
+ if (pDialogInfo->Win31MigrationFlags & WIN31_MIGRATE_GROUPS) {
+ CheckDlgButton(hDlg, idFocus = IDD_WIN31MIG_GROUPS, 1 );
+ } else {
+ CheckDlgButton(hDlg, IDD_WIN31MIG_GROUPS, 0 );
+ }
+
+ CentreWindow(hDlg);
+ SetFocus(GetDlgItem(hDlg, idFocus));
+
+
+ return(TRUE);
+
+ case WM_COMMAND:
+
+ switch (HIWORD(wParam)) {
+
+ default:
+
+ switch (LOWORD(wParam)) {
+
+ case IDOK:
+ pDialogInfo->Win31MigrationFlags = 0;
+ if (IsDlgButtonChecked(hDlg, IDD_WIN31MIG_INIFILES) == 1) {
+ pDialogInfo->Win31MigrationFlags |= WIN31_MIGRATE_INIFILES;
+ }
+
+ if (IsDlgButtonChecked(hDlg, IDD_WIN31MIG_GROUPS) == 1) {
+ pDialogInfo->Win31MigrationFlags |= WIN31_MIGRATE_GROUPS;
+ }
+
+ if (pDialogInfo->Win31MigrationFlags != 0) {
+ SetCursor( LoadCursor( NULL, IDC_WAIT ) );
+ //
+ // Get in the correct context before we reference the registry
+ //
+
+ ImpersonationHandle = ImpersonateUser(&pDialogInfo->pGlobals->UserProcessData, NULL);
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "Win31MigrationDlgProc failed to impersonate user for update\n"));
+ EndDialog(hDlg, DLG_FAILURE);
+ return(TRUE);
+ }
+
+ OpenProfileUserMapping();
+
+ SynchronizeWindows31FilesAndWindowsNTRegistry( Win31LogonEvent,
+ pDialogInfo->Win31MigrationFlags,
+ Win31MigrationStatusCallback,
+ hDlg
+ );
+
+
+ //
+ // If they migrated the groups, then we need to set
+ // the group convert flag so links are created.
+ //
+
+
+ if (pDialogInfo->Win31MigrationFlags & WIN31_MIGRATE_GROUPS) {
+ HKEY hKey;
+ DWORD dwDisp;
+ BOOL bRunGrpConv;
+
+ if (RegCreateKeyEx (HKEY_CURRENT_USER, WINLOGON_KEY,
+ 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL, &hKey, &dwDisp) ==
+ ERROR_SUCCESS) {
+
+
+ bRunGrpConv = TRUE;
+
+ RegSetValueEx (hKey, TEXT("RunGrpConv"), 0, REG_DWORD,
+ (LPBYTE) &bRunGrpConv, sizeof(bRunGrpConv));
+
+ RegCloseKey (hKey);
+ }
+
+ }
+
+ CloseProfileUserMapping();
+ StopImpersonating(ImpersonationHandle);
+ SetCursor( LoadCursor( NULL, IDC_ARROW ) );
+ }
+
+ EndDialog(hDlg, DLG_SUCCESS);
+
+ if (pDialogInfo->Win31MigrationFlags & WIN31_MIGRATE_INIFILES) {
+ InitSystemParametersInfo(pDialogInfo->pGlobals, TRUE);
+ }
+
+ return(TRUE);
+
+ case IDCANCEL:
+ EndDialog(hDlg, DLG_FAILURE);
+ return(TRUE);
+
+ }
+ break;
+
+ }
+ break;
+
+ case WLX_WM_SAS:
+ // Ignore it
+ return(TRUE);
+
+ case WM_PAINT:
+ break; // Fall through to do default processing
+ // We may have validated part of the window.
+ }
+
+ // We didn't process the message
+ return(FALSE);
+}
diff --git a/private/windows/gina/winlogon/win31mig.dlg b/private/windows/gina/winlogon/win31mig.dlg
new file mode 100644
index 000000000..d7c7bab49
--- /dev/null
+++ b/private/windows/gina/winlogon/win31mig.dlg
@@ -0,0 +1,19 @@
+1 DLGINCLUDE "win31mig.H"
+
+IDD_WIN31MIG DIALOG 170, 22, 231, 186
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Windows 3.x Migration"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "You have installed Windows NT into an existing Windows 3.x directory. You have the option of migrating portions of your Windows 3.x environment into the Windows NT environment.",
+ 807, 7, 17, 217, 29
+ AUTOCHECKBOX "Migrate Windows 3.x &WIN.INI and CONTROL.INI",
+ IDD_WIN31MIG_INIFILES, 16, 77, 172, 10
+ AUTOCHECKBOX "Migrate Windows 3.x &Program Manager group files",
+ IDD_WIN31MIG_GROUPS, 16, 103, 176, 10
+ DEFPUSHBUTTON "OK", IDOK, 65, 158, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 121, 158, 40, 14
+ LTEXT "Please select below the parts you wish to migrate into the Windows NT environment.",
+ 806, 7, 45, 214, 18
+ CTEXT "", IDD_WIN31MIG_STATUS, 16, 126, 174, 13
+END
diff --git a/private/windows/gina/winlogon/win31mig.h b/private/windows/gina/winlogon/win31mig.h
new file mode 100644
index 000000000..90545c6f4
--- /dev/null
+++ b/private/windows/gina/winlogon/win31mig.h
@@ -0,0 +1,24 @@
+/****************************** Module Header ******************************\
+* Module Name: win31mig.h
+*
+* Copyright (c) 1993, Microsoft Corporation
+*
+* Constants for the Windows 3.1 Migration dialog
+*
+* NOTE - this file is maintained by dlgedit. Do not edit directly
+*
+* History:
+* 01-08-93 Stevewo Created.
+\***************************************************************************/
+
+#ifndef RC_INVOKED
+BOOL
+Windows31Migration(
+ PGLOBALS pGlobals
+ );
+#endif /* !RC_INVOKED */
+
+#define IDD_WIN31MIG 801
+#define IDD_WIN31MIG_INIFILES 802
+#define IDD_WIN31MIG_GROUPS 803
+#define IDD_WIN31MIG_STATUS 804
diff --git a/private/windows/gina/winlogon/winlogon.c b/private/windows/gina/winlogon/winlogon.c
new file mode 100644
index 000000000..bf2e87b75
--- /dev/null
+++ b/private/windows/gina/winlogon/winlogon.c
@@ -0,0 +1,378 @@
+/****************************** Module Header ******************************\
+* Module Name: winlogon.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Winlogon main module
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Global pointer to the pGlobals structure
+//
+
+PGLOBALS g_pGlobals = NULL;
+HANDLE hFontThread = NULL; // Handle to the fontloader
+
+/***************************************************************************\
+* InitializeGlobals
+*
+*
+* History:
+* 12-09-91 Davidc Created.
+* 6-May-1992 SteveDav Added MM sound initialisation
+* 1-03-96 ShawnB Added MM Midi initalisation
+\***************************************************************************/
+BOOL InitializeGlobals(
+ PGLOBALS pGlobals,
+ HANDLE hInstance)
+{
+ SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
+ ULONG SidLength;
+ BOOL Result;
+ TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
+ DWORD dwComputerNameSize = MAX_COMPUTERNAME_LENGTH+1;
+ TCHAR szDefaultUser[MAX_PATH];
+
+
+ //
+ // Get a copy of the computer name in *my* environment, so that we
+ // can look at it later.
+ //
+
+ if (GetComputerName (szComputerName, &dwComputerNameSize)) {
+ SetEnvironmentVariable(COMPUTERNAME_VARIABLE, (LPTSTR) szComputerName);
+ }
+
+
+ //
+ // Set the default USERPROFILE location
+ //
+
+ ExpandEnvironmentStrings (TEXT("%SystemRoot%\\Profiles\\Default User"),
+ szDefaultUser, MAX_PATH);
+ SetEnvironmentVariable(TEXT("USERPROFILE"), szDefaultUser);
+
+
+ //
+ // Save pGlobals in the global pointer
+ //
+
+ g_pGlobals = pGlobals;
+
+
+ //
+ // Zero init the structure just to be safe.
+ //
+
+ RtlZeroMemory(pGlobals, sizeof(GLOBALS));
+
+ pGlobals->CheckMark = GLOBALS_CHECKMARK;
+
+ //
+ // Store away our instance handle
+ //
+
+ pGlobals->hInstance = hInstance;
+
+ //
+ // Get our sid so it can be put on object ACLs
+ //
+
+ SidLength = RtlLengthRequiredSid(1);
+ pGlobals->WinlogonSid = (PSID)Alloc(SidLength);
+ ASSERTMSG("Winlogon failed to allocate memory for system sid", pGlobals->WinlogonSid != NULL);
+
+ RtlInitializeSid(pGlobals->WinlogonSid, &SystemSidAuthority, 1);
+ *(RtlSubAuthoritySid(pGlobals->WinlogonSid, 0)) = SECURITY_LOCAL_SYSTEM_RID;
+
+ //
+ // Initialize (clear) the user process data.
+ // It will be setup correctly in the first SecurityChangeUser() call
+ //
+
+ ClearUserProcessData(&pGlobals->UserProcessData);
+
+ //
+ // Initialize (clear) the user profile data
+ // It will be setup correctly in the first SecurityChangeUser() call
+ //
+
+ ClearUserProfileData(&pGlobals->UserProfile);
+
+
+ //
+ // Initialize the multi-media stuff
+ //
+
+ InitializeSound(pGlobals);
+ InitializeMidi(pGlobals);
+
+ //
+ // Initialize the handle to MPR.DLL. This dll must be loaded in the
+ // user's context because of calls to winreg apis. It is therefore
+ // loaded after the user has logged on, in SetupUserEnvironment.
+ // It is used to restore and nuke the user's network connections.
+ //
+
+ pGlobals->hMPR = NULL;
+
+ //
+ // Initialize the handle to the eventlog to NULL. This will be initialize
+ // the first time a user logs on. All profile event logging will use
+ // this handle.
+ //
+ pGlobals->hEventLog = NULL;
+
+ //
+ // Set the SETUP Booleans
+ //
+ pGlobals->SetupType = CheckSetupType() ;
+ pGlobals->fExecuteSetup = pGlobals->SetupType == SETUPTYPE_FULL
+#ifdef INIT_REGISTRY
+ || pGlobals->SetupType == SETUPTYPE_NETSRW
+#endif
+ || pGlobals->SetupType == SETUPTYPE_NETIDW
+ || pGlobals->SetupType == SETUPTYPE_UPGRADE;
+
+
+ //
+ // Close the ini file mapping so we get an error if we try
+ // to use ini apis without explicitly opening a new mapping.
+ //
+
+ CloseIniFileUserMapping(pGlobals);
+
+
+ return TRUE;
+}
+
+
+
+void
+DoSetup(PGLOBALS pGlobals)
+{
+ BOOL EnableResult;
+
+ ExecuteSetup(pGlobals);
+
+ //
+ // Enable the shutdown privilege
+ // This should always succeed - we are either system or a user who
+ // successfully passed the privilege check in ExitWindowsEx.
+ //
+
+ EnableResult = EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);
+ ASSERT(EnableResult);
+
+ NtShutdownSystem(ShutdownReboot);
+
+}
+
+/***************************************************************************\
+* WinMain
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpszCmdParam,
+ int nCmdShow)
+{
+ GLOBALS Globals;
+ int Result;
+ DWORD Win31MigrationFlags;
+
+ //
+ // Initialize debug support and logging
+ //
+
+ InitDebugSupport();
+
+ //
+ // Make ourselves more important
+ //
+
+ if (!SetProcessPriority())
+ {
+ ExitProcess( EXIT_INITIALIZATION_ERROR );
+ }
+
+ //
+ // Initialize the globals
+ //
+
+ InitializeGlobals(&Globals, (HANDLE)hInstance);
+
+ //
+ // If we are supposed to run setup, then we probably don't
+ // have a paging file yet.
+ //
+
+ if (!Globals.fExecuteSetup)
+ {
+ CreateTemporaryPageFile();
+ }
+
+ //
+ // Do any DOS-specific initialization:
+ //
+
+ BootDOS();
+
+
+ //
+ // Initialize the rest of security
+ //
+
+ if ( !InitializeSecurity(&Globals) )
+ {
+ ExitProcess( EXIT_SECURITY_INIT_ERROR );
+ }
+
+ //
+ // Determine and load the GINA DLL to use
+ //
+
+ if ( ! DetermineUserInterface(&Globals) )
+ {
+ ExitProcess( EXIT_GINA_ERROR );
+ }
+
+
+
+ DebugLog((DEB_TRACE_INIT, "Execute system processes:\n"));
+
+ if ( ! ExecSystemProcesses(&Globals) )
+ {
+ ExitProcess( EXIT_SYSTEM_PROCESS_ERROR );
+ }
+
+ DebugLog((DEB_TRACE_INIT, "Done with system processes:\n"));
+
+
+ // BUGBUG: This can probably go in front of ExecSystemProcesses().
+
+#ifdef INIT_REGISTRY
+ InitializeDefaultRegistry(&Globals);
+#endif
+
+
+
+ //
+ // Decide what to do about setup.
+ //
+
+ if (Globals.fExecuteSetup)
+ {
+ //
+ // Run setup, then reboot: This never returns.
+ //
+
+ DoSetup(&Globals);
+ }
+ else
+ {
+ //
+ // Don't go any further if setup didn't complete fully. If this
+ // machine has not completed setup correctly, this will not return.
+ //
+
+ CheckForIncompleteSetup(&Globals);
+
+ }
+
+
+
+
+ //
+ // Initialize the secure attention sequence
+ //
+
+ if (!SASInit(&Globals))
+ {
+ ExitProcess( EXIT_NO_SAS_ERROR );
+ }
+
+ //
+ // Check to see if there is any WIN.INI or REG.DAT to migrate into
+ // Windows/NT registry.
+ //
+
+ Win31MigrationFlags = QueryWindows31FilesMigration( Win31SystemStartEvent );
+ if (Win31MigrationFlags != 0) {
+ SynchronizeWindows31FilesAndWindowsNTRegistry( Win31SystemStartEvent,
+ Win31MigrationFlags,
+ NULL,
+ NULL
+ );
+ InitSystemFontInfo(&Globals);
+ }
+
+#ifdef _X86_
+
+ //
+ // Do OS/2 Subsystem boot-time migration.
+ // Only applicable to x86 builds.
+ //
+
+ Os2MigrationProcedure();
+
+#endif
+
+
+ //
+ // Load those pesky fonts:
+ //
+
+ hFontThread = StartLoadingFonts();
+
+
+ //
+ // Check if we need to run setup's GUI repair code
+ //
+
+ CheckForRepairRequest ();
+
+
+
+ //
+ // Main logon/logoff loop
+ //
+
+
+ MainLoop(&Globals);
+
+
+
+ //
+ // Shutdown the machine
+ //
+
+ ShutdownMachine(&Globals, Globals.LastGinaRet);
+
+
+ //
+ // Should never get here
+ //
+
+ DebugLog((DEB_ERROR, "ShutdownMachine failed!\n"));
+ ASSERT(!"ShutdownMachine failed!");
+
+ SASTerminate();
+
+ ExitProcess( EXIT_SHUTDOWN_FAILURE );
+
+ return( 0 );
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpszCmdParam);
+ UNREFERENCED_PARAMETER(nCmdShow);
+}
diff --git a/private/windows/gina/winlogon/winlogon.h b/private/windows/gina/winlogon/winlogon.h
new file mode 100644
index 000000000..581b343ab
--- /dev/null
+++ b/private/windows/gina/winlogon/winlogon.h
@@ -0,0 +1,418 @@
+/****************************** Module Header ******************************\
+* Module Name: winlogon.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Main header file for winlogon
+*
+* History:
+* 12-09-91 Davidc Created.
+* 6-May-1992 SteveDav Added space for WINMM sound function
+\***************************************************************************/
+
+
+#ifndef RC_INVOKED
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntlsa.h>
+#include <ntmsv1_0.h>
+#include <lmsname.h>
+#endif
+
+
+#include <windows.h>
+#include <winbasep.h>
+#include <winuserp.h>
+#include <winsecp.h>
+#include <mmsystem.h>
+#include <winwlx.h>
+
+#ifndef RC_INVOKED
+
+//
+// Exit Codes, that will show up the bugcheck:
+//
+
+#define EXIT_INITIALIZATION_ERROR 1024
+#define EXIT_SECURITY_INIT_ERROR 1025
+#define EXIT_GINA_ERROR 1026
+#define EXIT_SYSTEM_PROCESS_ERROR 1027
+#define EXIT_NO_SAS_ERROR 1028
+#define EXIT_SHUTDOWN_FAILURE 1029
+#define EXIT_GINA_INIT_ERROR 1030
+
+//
+// Tempoary development aid - system logon capability
+//
+
+#if DBG
+#define SYSTEM_LOGON
+#endif
+
+#if DEVL
+#define INIT_REGISTRY 1
+#endif
+
+//
+// Temporary development aid - Ctrl-Tasklist starts cmd shell
+//
+#if DBG
+#define CTRL_TASKLIST_SHELL
+#endif
+
+
+//
+// Define the input timeout delay for logon dialogs (seconds)
+//
+
+#define LOGON_TIMEOUT 120
+
+
+//
+// Define the input timeout delay for the security options dialog (seconds)
+//
+
+#define OPTIONS_TIMEOUT 120
+
+
+//
+// Define the number of days warning we give the user before their password expires
+//
+
+#define PASSWORD_EXPIRY_WARNING_DAYS 14
+
+
+//
+// Define the maximum time we display the 'wait for user to be logged off'
+// dialog. This dialog should be interrupted by the user being logged off.
+// This timeout is a safety measure in case that doesn't happen because
+// of some system error.
+//
+
+#define WAIT_FOR_USER_LOGOFF_DLG_TIMEOUT 120 // seconds
+
+
+//
+// Define the account lockout limits
+//
+// A delay of LOCKOUT_BAD_LOGON_DELAY seconds will be added to
+// each failed logon if more than LOCKOUT_BAD_LOGON_COUNT failed logons
+// have occurred in the last LOCKOUT_BAD_LOGON_PERIOD seconds.
+//
+
+#define LOCKOUT_BAD_LOGON_COUNT 5
+#define LOCKOUT_BAD_LOGON_PERIOD 60 // seconds
+#define LOCKOUT_BAD_LOGON_DELAY 30 // seconds
+
+
+
+//
+// Define the maximum length of strings we'll use in winlogon
+//
+
+#define MAX_STRING_LENGTH 255
+#define MAX_STRING_BYTES (MAX_STRING_LENGTH + 1)
+
+
+//
+// Define the typical length of a string
+// This is used as an initial allocation size for most string routines.
+// If this is insufficient, the block is reallocated larger and
+// the operation retried. i.e. Make this big enough for most strings
+// to fit first time.
+//
+
+#define TYPICAL_STRING_LENGTH 60
+
+
+
+//
+// Windows object names
+//
+
+#define WINDOW_STATION_NAME TEXT("WinSta0")
+#define APPLICATION_DESKTOP_NAME TEXT("Default")
+#define WINLOGON_DESKTOP_NAME TEXT("Winlogon")
+#define SCREENSAVER_DESKTOP_NAME TEXT("Screen-saver")
+
+#define APPLICATION_DESKTOP_PATH TEXT("WinSta0\\Default")
+#define WINLOGON_DESKTOP_PATH TEXT("WinSta0\\Winlogon")
+#define SCREENSAVER_DESKTOP_PATH TEXT("WinSta0\\Screen-saver")
+
+
+//
+// Winlogon's registry location
+//
+
+#define WINLOGON_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
+
+
+//
+// Define the structure that contains information used when starting
+// user processes.
+// This structure should only be modified by SetUserProcessData()
+//
+
+typedef struct {
+ HANDLE UserToken; // NULL if no user logged on
+ PSID UserSid; // == WinlogonSid if no user logged on
+ PSECURITY_DESCRIPTOR NewProcessSD;
+ PSECURITY_DESCRIPTOR NewProcessTokenSD;
+ PSECURITY_DESCRIPTOR NewThreadSD;
+ PSECURITY_DESCRIPTOR NewThreadTokenSD;
+ QUOTA_LIMITS Quotas;
+ LPTSTR CurrentDirectory;
+ PVOID pEnvironment;
+} USER_PROCESS_DATA;
+typedef USER_PROCESS_DATA *PUSER_PROCESS_DATA;
+
+//
+// Define the structure that contains information about the user's profile.
+// This is used in SetupUserEnvironment and ResetEnvironment (in usrenv.c)
+// This data is only valid while a user is logged on.
+//
+
+typedef struct {
+ LPTSTR ProfilePath;
+ HANDLE hProfile;
+ LPTSTR PolicyPath;
+ LPTSTR NetworkDefaultUserProfile;
+ LPTSTR ServerName;
+ LPTSTR Environment;
+} USER_PROFILE_INFO;
+typedef USER_PROFILE_INFO *PUSER_PROFILE_INFO;
+
+
+
+//
+// Get any data types defined in module headers and used in GLOBALS
+//
+#define TYPES_ONLY
+#include "ginamgr.h"
+#undef TYPES_ONLY
+
+
+typedef enum _WinstaState {
+ Winsta_PreLoad,
+ Winsta_Initialize,
+ Winsta_NoOne,
+ Winsta_NoOne_Display,
+ Winsta_NoOne_SAS,
+ Winsta_LoggedOnUser_StartShell,
+ Winsta_LoggedOnUser,
+ Winsta_LoggedOn_SAS,
+ Winsta_Locked,
+ Winsta_Locked_Display,
+ Winsta_Locked_SAS,
+ Winsta_WaitForLogoff,
+ Winsta_WaitForShutdown,
+ Winsta_Shutdown,
+ Winsta_InShutdownDlg,
+ Winsta_StateMax
+} WinstaState;
+
+#define IsSASState(State) ((State == Winsta_NoOne_SAS) || \
+ (State == Winsta_LoggedOn_SAS) || \
+ (State == Winsta_Locked_SAS) )
+
+#define IsDisplayState(State) ((State == Winsta_NoOne_Display) || \
+ (State == Winsta_Locked_Display) || \
+ (State == Winsta_WaitForLogoff) )
+
+#if DBG
+extern char * StateNames[Winsta_StateMax];
+
+#define GetState(x) ( x < (sizeof(StateNames) / sizeof(char *)) ? StateNames[x] : "Invalid")
+#endif
+
+extern BOOLEAN SasMessages;
+#define DisableSasMessages() SasMessages = FALSE;
+#define TestSasMessages() (SasMessages)
+VOID
+EnableSasMessages(HWND hWnd);
+
+BOOL
+QueueSasEvent(
+ DWORD dwSasType);
+
+BOOL
+FetchPendingSas(
+ PDWORD pSasType);
+
+BOOL
+TestPendingSas(VOID);
+
+BOOL
+KillMessageBox( DWORD SasCode );
+
+typedef enum _ActiveDesktops {
+ Desktop_Winlogon,
+ Desktop_ScreenSaver,
+ Desktop_Application,
+ Desktop_Previous
+} ActiveDesktops;
+
+typedef struct _WinstaDescription {
+ HWINSTA hwinsta; // Handle to window station
+ HDESK hdeskWinlogon; // Desktop handles
+ HDESK hdeskApplication; // ""
+ HWND hwndAppDesktop; // "
+ HDESK hdeskScreenSaver; // "
+ HDESK hdeskPrevious; // Previous
+ ActiveDesktops ActiveDesktop; // Current, active desktop
+ ActiveDesktops PreviousDesktop; // Previous desktop
+ PWSTR pszWinsta; // Name of window station.
+ PWSTR pszDesktop; // Name of current desktop.
+ DWORD DesktopLength; // Length of name.
+ BOOL Locked; // Do I think it's locked?
+ PVOID Acl; // Stored ACL
+} WinstaDescription, * PWinstaDescription;
+
+
+typedef UINT (FAR WINAPI *SOUNDPROC)();
+typedef BOOL (FAR WINAPI *MIDIPROC)();
+
+
+//
+// Define the winlogon global structure.
+//
+
+typedef struct {
+ DWORD CheckMark;
+
+ // Filled in by InitializeGlobals at startup
+ HANDLE hInstance;
+ PSID WinlogonSid;
+ SOUNDPROC PlaySound;
+ SOUNDPROC MigrateSoundEvents;
+ MIDIPROC MigrateMidiUser;
+ HANDLE hMPR; // handle to MPR.DLL
+ // Needed to call WNetRestoreConnection when logging
+ // on the user (in SetupUserEnviron), and to call
+ // WNetNukeConnections when logging of the user.
+ // Cannot be called directly beacuse it uses the
+ // winreg apis, and thus it has to be loaded
+ // after the profiles are loaded (SetupUserEnvironment).
+ // Has to be loaded in the user context.
+
+ HANDLE hEventLog;
+
+ // Filled in by InitializeSecurity() at startup
+ WinstaDescription WindowStation;
+ PGINASESSION pGina;
+ WinstaState WinlogonState;
+ WinstaState PreviousWinlogonState;
+ BOOL ForwardCAD;
+ DWORD SasType;
+ DWORD LastGinaRet;
+ DWORD LogoffFlags;
+ BOOL ScreenSaverActive;
+ BOOL ShutdownStarted;
+
+ // Filled in during startup
+ BOOL AuditLogFull;
+ BOOL AuditLogNearFull;
+
+ // Always valid, indicates if we have a user logged on
+ BOOL UserLoggedOn;
+ DWORD IniRef;
+ DWORD TickCount;
+
+ // Always valid - used to start new processes and screen-saver
+ USER_PROCESS_DATA UserProcessData;
+ LUID LogonId;
+
+ // Filled in during SetupUserEnvironment, and used in ResetEnvironment.
+ // Valid only when a user is logged on.
+
+ PWSTR LogonScripts;
+ PWSTR UserName;
+ PWSTR Domain;
+ USER_PROFILE_INFO UserProfile;
+
+
+ //
+ // Value of SetupType from registry
+ //
+
+ ULONG SetupType ;
+
+ //
+ // Boolean flag indicating whether SETUP is to be run
+ //
+ BOOL fExecuteSetup ;
+
+ WCHAR DesktopName[ TYPICAL_STRING_LENGTH ];
+ DWORD DesktopNameLength;
+
+} GLOBALS;
+typedef GLOBALS *PGLOBALS;
+
+#define GLOBALS_CHECKMARK 0x616f6947
+#define VerifyHandle(h) ((PGLOBALS) (((PGLOBALS)h)->CheckMark == GLOBALS_CHECKMARK) ? h : NULL)
+
+//
+// Global pointer to the pGlobals structure
+//
+
+extern PGLOBALS g_pGlobals;
+extern HANDLE hFontThread;
+extern BOOL ExitWindowsInProgress ;
+
+
+//
+// Define a macro to determine if we're a workstation or not
+// This allows easy changes as new product types are added.
+//
+
+#define IsWorkstation(prodtype) (((prodtype) == NtProductWinNt) \
+ || ((prodtype) == NtProductServer))
+
+
+#define DLG_SUCCESS IDOK
+#define DLG_FAILURE IDCANCEL
+
+//
+// Include individual module header files
+//
+#include "wlxutil.h"
+#include "regini.h"
+#include "logon.h"
+#include "loggedon.h"
+#include "sas.h"
+#include "winutil.h"
+#include "sysinit.h"
+#include "ginamgr.h"
+#include "debug.h"
+#include "strings.h"
+#include "wlxutil.h"
+#include "doslog.h"
+#include "regini.h"
+#include "secutil.h"
+#include "logoff.h"
+#include "misc.h"
+#include "msgalias.h"
+#include "usrpro.h"
+#include "usrenv.h"
+#include "envvar.h"
+#include "monitor.h"
+#include "scrnsave.h"
+#include "timeout.h"
+#include "provider.h"
+#include "removabl.h"
+
+
+#ifdef _X86_
+#include "os2ssmig.h"
+#endif
+
+#endif /* !RC_INVOKED */
+
+//
+// Include resource header files
+//
+#include "win31mig.h"
+#include "wlevents.h"
+#include "stringid.h"
+#include "dialogs.h"
diff --git a/private/windows/gina/winlogon/winutil.c b/private/windows/gina/winlogon/winutil.c
new file mode 100644
index 000000000..b9a63bd25
--- /dev/null
+++ b/private/windows/gina/winlogon/winutil.c
@@ -0,0 +1,834 @@
+/****************************** Module Header ******************************\
+* Module Name: winutil.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Implements windows specific utility functions
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+
+#if DBG
+char * DesktopNames[] = {"Winlogon", "ScreenSaver", "Application", "[Previous]"};
+#define DbgGetDesktopName(x) (x < (sizeof(DesktopNames) / sizeof(char *)) ? DesktopNames[x] : "Unknown!")
+#endif
+
+
+HDESK
+GetActiveDesktop(
+ PWinstaDescription pWindowStation,
+ BOOL * pCloseWhenDone,
+ BOOL * pLocked)
+{
+ HDESK hDesk;
+ ActiveDesktops Desktop;
+
+ Desktop = pWindowStation->ActiveDesktop;
+ if (Desktop == -1)
+ {
+ Desktop = pWindowStation->PreviousDesktop;
+ }
+
+ switch ( Desktop )
+ {
+ case Desktop_Application:
+ hDesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
+ *pCloseWhenDone = TRUE;
+ *pLocked = FALSE;
+ break;
+
+ case Desktop_Winlogon:
+ hDesk = pWindowStation->hdeskWinlogon;
+ *pCloseWhenDone = FALSE;
+ *pLocked = TRUE;
+ break;
+
+ case Desktop_ScreenSaver:
+ hDesk = pWindowStation->hdeskScreenSaver;
+ *pCloseWhenDone = FALSE;
+ *pLocked = FALSE;
+ break;
+
+ default:
+ DebugLog((DEB_TRACE, "Unknown desktop: %d\n", Desktop));
+ *pCloseWhenDone = FALSE;
+ hDesk = NULL;
+ *pLocked = FALSE;
+ break;
+
+ }
+
+ return(hDesk);
+}
+
+BOOL
+ToggleDesktopLock(
+ PWinstaDescription pWindowStation)
+{
+ BOOL bRet;
+
+ if (pWindowStation->Locked)
+ {
+ bRet = UnlockWindowStation( pWindowStation->hwinsta );
+ pWindowStation->Locked = FALSE;
+ }
+ else
+ {
+ bRet = LockWindowStation( pWindowStation->hwinsta );
+ pWindowStation->Locked = TRUE;
+ }
+
+ return( bRet );
+}
+
+BOOL
+SetReturnDesktop(
+ PWinstaDescription pWindowStation,
+ PWLX_DESKTOP pDesktop)
+{
+ WCHAR DesktopName[TYPICAL_STRING_LENGTH];
+ DWORD Needed;
+ PWSTR pszDesktop;
+ BOOL FreeDesktopString = FALSE;
+ HDESK hDesk;
+
+ if ( pWindowStation->ActiveDesktop == Desktop_Application )
+ {
+ return( FALSE );
+ }
+
+ if ( (pDesktop->Flags & WLX_DESKTOP_NAME) == 0 )
+ {
+ if (!GetUserObjectInformation( pDesktop->hDesktop,
+ UOI_NAME,
+ DesktopName,
+ TYPICAL_STRING_LENGTH,
+ &Needed ) )
+ {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER )
+ {
+ return( FALSE );
+ }
+
+ pszDesktop = LocalAlloc( LMEM_FIXED, Needed );
+
+ if ( !pszDesktop )
+ {
+ return( FALSE );
+ }
+
+ GetUserObjectInformation( pDesktop->hDesktop,
+ UOI_NAME,
+ pszDesktop,
+ Needed,
+ &Needed );
+
+ FreeDesktopString = TRUE;
+
+ }
+ else
+ {
+ pszDesktop = DesktopName;
+
+ FreeDesktopString = FALSE;
+ }
+
+ }
+ else
+ {
+ pszDesktop = pDesktop->pszDesktopName;
+
+ FreeDesktopString = FALSE;
+
+ }
+
+ hDesk = OpenDesktop( pszDesktop, 0, FALSE, MAXIMUM_ALLOWED );
+
+ if (!hDesk)
+ {
+ if (FreeDesktopString)
+ {
+ LocalFree( pszDesktop );
+ }
+ return( FALSE );
+ }
+
+ CloseDesktop( pWindowStation->hdeskPrevious );
+ pWindowStation->hdeskPrevious = hDesk;
+
+ if (FreeDesktopString)
+ {
+ LocalFree( pszDesktop );
+ }
+
+ return( TRUE );
+
+}
+
+BOOL
+SetActiveDesktop(
+ PWinstaDescription pWindowStation,
+ ActiveDesktops Desktop)
+{
+ HDESK hDesk;
+ HDESK hPrevious;
+ DWORD LengthNeeded;
+
+ if (Desktop == pWindowStation->ActiveDesktop)
+ {
+ return(TRUE);
+ }
+
+ if (pWindowStation->ActiveDesktop == Desktop_Application)
+ {
+ LockWindowStation(pWindowStation->hwinsta);
+ pWindowStation->hdeskPrevious = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
+
+ if (!GetUserObjectInformation( pWindowStation->hdeskPrevious,
+ UOI_NAME,
+ pWindowStation->pszDesktop,
+ pWindowStation->DesktopLength,
+ &LengthNeeded) )
+ {
+ if (pWindowStation->DesktopLength != TYPICAL_STRING_LENGTH)
+ {
+ LocalFree( pWindowStation->pszDesktop );
+ }
+ pWindowStation->pszDesktop = LocalAlloc( LMEM_FIXED, LengthNeeded );
+ if (pWindowStation->pszDesktop)
+ {
+ pWindowStation->DesktopLength = LengthNeeded;
+
+ if (!GetUserObjectInformation( pWindowStation->hdeskPrevious,
+ UOI_NAME,
+ pWindowStation->pszDesktop,
+ pWindowStation->DesktopLength,
+ &LengthNeeded))
+ {
+ pWindowStation->pszDesktop[0] = 0;
+ }
+ }
+ else
+ {
+ pWindowStation->DesktopLength = 0;
+ }
+ }
+
+ DebugLog((DEB_TRACE, "Source desktop was %ws\n", pWindowStation->pszDesktop));
+ }
+
+ switch (Desktop)
+ {
+ case Desktop_Winlogon:
+ hDesk = pWindowStation->hdeskWinlogon;
+ break;
+ case Desktop_ScreenSaver:
+ hDesk = pWindowStation->hdeskScreenSaver;
+ break;
+ case Desktop_Application:
+ if (pWindowStation->hdeskPrevious)
+ {
+ hDesk = pWindowStation->hdeskPrevious;
+ }
+ else
+ {
+ hDesk = pWindowStation->hdeskApplication;
+ }
+ break;
+ default:
+ DebugLog((DEB_ERROR, "Error: Invalid desktop specified %d\n", Desktop));
+ return(FALSE);
+ }
+ if (SwitchDesktop(hDesk))
+ {
+ DebugLog((DEB_TRACE, "Switching desktop from %s to %s\n",
+ DbgGetDesktopName(pWindowStation->ActiveDesktop),
+ DbgGetDesktopName(Desktop) ));
+
+ pWindowStation->PreviousDesktop = pWindowStation->ActiveDesktop;
+ pWindowStation->ActiveDesktop = Desktop;
+
+ //
+ // If we're switching back to the user's desktop, then unlock the
+ // window station, so that the user can switch desktops again. Also,
+ // close our handle to the desktop. Note! Unlock before close, so
+ // that if this is the last handle to the desktop, cleanup can occur
+ // correctly.
+ //
+
+ if (pWindowStation->ActiveDesktop == Desktop_Application)
+ {
+ UnlockWindowStation(pWindowStation->hwinsta);
+ if (pWindowStation->hdeskPrevious)
+ {
+ DebugLog((DEB_TRACE, "Closing handle %x to users desktop\n", pWindowStation->hdeskPrevious));
+ CloseDesktop(pWindowStation->hdeskPrevious);
+ pWindowStation->hdeskPrevious = NULL;
+ }
+ }
+
+
+ return(TRUE);
+ }
+ DebugLog((DEB_WARN, "Could not switch desktop!\n"));
+ return(FALSE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: AllocAndGetPrivateProfileString
+*
+* PURPOSE: Allocates memory for and returns pointer to a copy of the
+* specified profile string
+* The returned string should be freed using Free()
+*
+* RETURNS: Pointer to copy of profile string or NULL on failure.
+*
+* HISTORY:
+*
+* 12-Nov-92 Davidc Created.
+*
+\***************************************************************************/
+
+LPTSTR
+AllocAndGetPrivateProfileString(
+ LPCTSTR lpAppName,
+ LPCTSTR lpKeyName,
+ LPCTSTR lpDefault,
+ LPCTSTR lpFileName
+ )
+{
+ LPTSTR String;
+ LONG LengthAllocated;
+ LONG LengthCopied;
+
+ //
+ // Pick a random buffer length, if it's not big enough reallocate
+ // it and try again until it is.
+ //
+
+ LengthAllocated = TYPICAL_STRING_LENGTH;
+
+ String = Alloc(LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ return(NULL);
+ }
+
+ while (TRUE) {
+
+ LengthCopied = GetPrivateProfileString( lpAppName,
+ lpKeyName,
+ lpDefault,
+ String,
+ LengthAllocated,
+ lpFileName
+ );
+ //
+ // If the returned value is our passed size - 1 (weird way for error)
+ // then our buffer is too small. Make it bigger and start over again.
+ //
+
+ if (LengthCopied == (LengthAllocated - 1)) {
+
+ DebugLog((DEB_TRACE, "AllocAndGetPrivateProfileString: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
+
+ LengthAllocated *= 2;
+ String = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ break;
+ }
+
+ //
+ // Go back and try to read it again
+ //
+
+ } else {
+
+ //
+ // Success!
+ //
+
+ break;
+ }
+
+ }
+
+ return(String);
+}
+
+
+/***************************************************************************\
+* FUNCTION: WritePrivateProfileInt
+*
+* PURPOSE: Writes out an integer to a profile file
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 12-Nov-92 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+WritePrivateProfileInt(
+ LPCTSTR lpAppName,
+ LPCTSTR lpKeyName,
+ UINT Value,
+ LPCTSTR lpFileName
+ )
+{
+ NTSTATUS Status;
+ TCHAR String[30];
+ UNICODE_STRING UniString;
+
+ UniString.MaximumLength = 30;
+ UniString.Buffer = String;
+
+ Status = RtlIntegerToUnicodeString(Value,10,&UniString);
+
+ if (!NT_SUCCESS(Status)) {
+ return(FALSE);
+ }
+
+ return (WritePrivateProfileString(lpAppName, lpKeyName, UniString.Buffer, lpFileName));
+
+}
+
+
+/***************************************************************************\
+* FUNCTION: AllocAndExpandEnvironmentStrings
+*
+* PURPOSE: Allocates memory for and returns pointer to buffer containing
+* the passed string expanded to include environment strings
+* The returned buffer should be freed using Free()
+*
+* RETURNS: Pointer to expanded string or NULL on failure.
+*
+* HISTORY:
+*
+* 21-Dec-92 Davidc Created.
+*
+\***************************************************************************/
+
+LPTSTR
+AllocAndExpandEnvironmentStrings(
+ LPCTSTR lpszSrc
+ )
+{
+ LPTSTR String;
+ LONG LengthAllocated;
+ LONG LengthCopied;
+
+ //
+ // Pick a random buffer length, if it's not big enough reallocate
+ // it and try again until it is.
+ //
+
+ LengthAllocated = lstrlen(lpszSrc) + TYPICAL_STRING_LENGTH;
+
+ String = Alloc(LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to allocate %d bytes for string\n", LengthAllocated * sizeof(TCHAR)));
+ return(NULL);
+ }
+
+ while (TRUE) {
+
+ LengthCopied = ExpandEnvironmentStrings( lpszSrc,
+ String,
+ LengthAllocated
+ );
+ if (LengthCopied == 0) {
+ DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : ExpandEnvironmentStrings failed, error = %d\n", GetLastError()));
+ Free(String);
+ String = NULL;
+ break;
+ }
+
+ //
+ // If the buffer was too small, make it bigger and try again
+ //
+
+ if (LengthCopied > LengthAllocated) {
+
+ DebugLog((DEB_TRACE, "AllocAndExpandEnvironmentStrings: Failed with buffer length = %d, reallocating to %d and retrying (retry should succeed)\n", LengthAllocated, LengthCopied));
+
+ String = ReAlloc(String, LengthCopied * sizeof(TCHAR));
+ LengthAllocated = LengthCopied;
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ break;
+ }
+
+ //
+ // Go back and try to expand the string again
+ //
+
+ } else {
+
+ //
+ // Success!
+ //
+
+ break;
+ }
+
+ }
+
+ return(String);
+}
+
+
+/***************************************************************************\
+* FUNCTION: AllocAndRegEnumKey
+*
+* PURPOSE: Allocates memory for and returns pointer to buffer containing
+* the next registry sub-key name under the specified key
+* The returned buffer should be freed using Free()
+*
+* RETURNS: Pointer to sub-key name or NULL on failure. The reason for the
+* error can be obtains using GetLastError()
+*
+* HISTORY:
+*
+* 21-Dec-92 Davidc Created.
+*
+\***************************************************************************/
+
+LPTSTR
+AllocAndRegEnumKey(
+ HKEY hKey,
+ DWORD iSubKey
+ )
+{
+ LPTSTR String;
+ LONG LengthAllocated;
+
+ //
+ // Pick a random buffer length, if it's not big enough reallocate
+ // it and try again until it is.
+ //
+
+ LengthAllocated = TYPICAL_STRING_LENGTH;
+
+ String = Alloc(LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ return(NULL);
+ }
+
+ while (TRUE) {
+
+ DWORD Error = RegEnumKey(hKey, iSubKey, String, LengthAllocated);
+ if (Error == ERROR_SUCCESS) {
+ break;
+ }
+
+ if (Error != ERROR_MORE_DATA) {
+
+ if (Error != ERROR_NO_MORE_ITEMS) {
+ DebugLog((DEB_ERROR, "AllocAndRegEnumKey : RegEnumKey failed, error = %d", Error));
+ }
+
+ Free(String);
+ String = NULL;
+ SetLastError(Error);
+ break;
+ }
+
+ //
+ // The buffer was too small, make it bigger and try again
+ //
+
+ DebugLog((DEB_TRACE, "AllocAndRegEnumKey: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
+
+ LengthAllocated *= 2;
+ String = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ break;
+ }
+ }
+
+ return(String);
+}
+
+
+/***************************************************************************\
+* FUNCTION: AllocAndRegQueryValueEx
+*
+* PURPOSE: Version of RegQueryValueEx that returns value in allocated buffer.
+* The returned buffer should be freed using Free()
+*
+* RETURNS: Pointer to key value or NULL on failure. The reason for the
+* error can be obtains using GetLastError()
+*
+* HISTORY:
+*
+* 15-Jan-93 Davidc Created.
+*
+\***************************************************************************/
+
+LPTSTR
+AllocAndRegQueryValueEx(
+ HKEY hKey,
+ LPTSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType
+ )
+{
+ LPTSTR String;
+ DWORD BytesAllocated;
+
+ //
+ // Pick a random buffer length, if it's not big enough reallocate
+ // it and try again until it is.
+ //
+
+ BytesAllocated = TYPICAL_STRING_LENGTH * sizeof(TCHAR);
+
+ String = Alloc(BytesAllocated);
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to allocate %d bytes for string", BytesAllocated));
+ return(NULL);
+ }
+
+ while (TRUE) {
+
+ DWORD Error;
+ DWORD BytesReturned = BytesAllocated;
+
+ Error = RegQueryValueEx(hKey,
+ lpValueName,
+ lpReserved,
+ lpType,
+ (LPBYTE)String,
+ &BytesReturned);
+ if (Error == ERROR_SUCCESS) {
+ break;
+ }
+
+ if (Error != ERROR_MORE_DATA) {
+
+ DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : RegQueryValueEx failed, error = %d", Error));
+ Free(String);
+ String = NULL;
+ SetLastError(Error);
+ break;
+ }
+
+ //
+ // The buffer was too small, make it bigger and try again
+ //
+
+ DebugLog((DEB_TRACE, "AllocAndRegQueryValueEx: Failed with buffer length = %d bytes, reallocating and retrying", BytesAllocated));
+
+ BytesAllocated *= 2;
+ String = ReAlloc(String, BytesAllocated);
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to reallocate %d bytes for string", BytesAllocated));
+ break;
+ }
+ }
+
+ return(String);
+}
+
+
+/***************************************************************************\
+* CentreWindow
+*
+* Purpose : Positions a window so that it is centred in its parent
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+VOID
+CentreWindow(
+ HWND hwnd
+ )
+{
+ RECT rect;
+ LONG dx, dy;
+ LONG dxParent, dyParent;
+ LONG Style;
+
+ // Get window rect
+ GetWindowRect(hwnd, &rect);
+
+ dx = rect.right - rect.left;
+ dy = rect.bottom - rect.top;
+
+ // Get parent rect
+ Style = GetWindowLong(hwnd, GWL_STYLE);
+ if ((Style & WS_CHILD) == 0) {
+
+ // Return the desktop windows size (size of main screen)
+ dxParent = GetSystemMetrics(SM_CXSCREEN);
+ dyParent = GetSystemMetrics(SM_CYSCREEN);
+ } else {
+ HWND hwndParent;
+ RECT rectParent;
+
+ hwndParent = GetParent(hwnd);
+ if (hwndParent == NULL) {
+ hwndParent = GetDesktopWindow();
+ }
+
+ GetWindowRect(hwndParent, &rectParent);
+
+ dxParent = rectParent.right - rectParent.left;
+ dyParent = rectParent.bottom - rectParent.top;
+ }
+
+ // Centre the child in the parent
+ rect.left = (dxParent - dx) / 2;
+ rect.top = (dyParent - dy) / 3;
+
+ // Move the child into position
+ SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, 0, 0, SWP_NOSIZE);
+
+ SetForegroundWindow(hwnd);
+}
+
+
+/***************************************************************************\
+* SetupSystemMenu
+*
+* Purpose : Does any manipulation required for a dialog system menu.
+* Should be called during WM_INITDIALOG processing for a dialog
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+VOID
+SetupSystemMenu(
+ HWND hDlg
+ )
+{
+ // Remove the Close item from the system menu if we don't
+ // have a CANCEL button
+
+ if (GetDlgItem(hDlg, IDCANCEL) == NULL) {
+
+ HMENU hMenu = GetSystemMenu(hDlg, FALSE);
+
+ DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
+ }
+
+}
+
+/***************************************************************************\
+* FUNCTION: OpenIniFileUserMapping
+*
+* PURPOSE: Forces the ini file mapping apis to reference the current user's
+* registry.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 24-Aug-92 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+OpenIniFileUserMapping(
+ PGLOBALS pGlobals
+ )
+{
+ BOOL Result;
+ HANDLE ImpersonationHandle;
+
+ //
+ // Impersonate the user
+ //
+
+ if (pGlobals->IniRef == 0)
+ {
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to impersonate user"));
+ return(FALSE);
+ }
+
+ DebugLog((DEB_TRACE, "Actually opening user mapping. User %s logged on\n",
+ pGlobals->UserLoggedOn ? "is" : "is not"));
+
+ Result = OpenProfileUserMapping();
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "OpenProfileUserMapping failed, error = %d", GetLastError()));
+ }
+
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (!StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to revert to self"));
+ }
+
+
+ }
+ else
+ {
+ Result = TRUE;
+ }
+
+ pGlobals->IniRef++;
+
+ DebugLog((DEB_TRACE, "ProfileUserMapping Refs = %d\n", pGlobals->IniRef));
+
+ return(Result);
+}
+
+/***************************************************************************\
+* FUNCTION: CloseIniFileUserMapping
+*
+* PURPOSE: Closes the ini file mapping to the user's registry such
+* that future use of the ini apis will fail if they reference
+* the user's registry.
+*
+* RETURNS: Nothing
+*
+* HISTORY:
+*
+* 24-Aug-92 Davidc Created.
+*
+\***************************************************************************/
+
+VOID
+CloseIniFileUserMapping(
+ PGLOBALS pGlobals
+ )
+{
+ BOOL Result;
+
+ if (pGlobals->IniRef)
+ {
+ if (--pGlobals->IniRef == 0)
+ {
+
+ DebugLog((DEB_TRACE, "Actually closing user mapping\n"));
+
+ Result = CloseProfileUserMapping();
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "CloseProfileUserMapping failed, error = %d", GetLastError()));
+ }
+
+ }
+
+ }
+
+ DebugLog((DEB_TRACE, "ProfileUserMapping Refs = %d\n", pGlobals->IniRef));
+}
diff --git a/private/windows/gina/winlogon/winutil.h b/private/windows/gina/winlogon/winutil.h
new file mode 100644
index 000000000..62f8b76b6
--- /dev/null
+++ b/private/windows/gina/winlogon/winutil.h
@@ -0,0 +1,127 @@
+/****************************** Module Header ******************************\
+* Module Name: winutil.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Define windows utility functions
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+
+//
+// Exported function prototypes
+//
+
+
+BOOL
+SetActiveDesktop(
+ PWinstaDescription pWindowStation,
+ ActiveDesktops Desktop);
+
+BOOL
+SetReturnDesktop(
+ PWinstaDescription pWindowStation,
+ PWLX_DESKTOP pDesktop);
+
+HDESK
+GetActiveDesktop(
+ PWinstaDescription pWindowStation,
+ BOOL * pCloseWhenDone,
+ BOOL * pLocked);
+
+BOOL
+ToggleDesktopLock(
+ PWinstaDescription pWindowStation);
+
+BOOL
+OpenIniFileUserMapping(
+ PGLOBALS pGlobals
+ );
+
+VOID
+CloseIniFileUserMapping(
+ PGLOBALS pGlobals
+ );
+
+LPTSTR
+AllocAndGetPrivateProfileString(
+ LPCTSTR lpAppName,
+ LPCTSTR lpKeyName,
+ LPCTSTR lpDefault,
+ LPCTSTR lpFileName
+ );
+
+#define AllocAndGetProfileString(App, Key, Def) \
+ AllocAndGetPrivateProfileString(App, Key, Def, NULL)
+
+
+BOOL
+WritePrivateProfileInt(
+ LPCTSTR lpAppName,
+ LPCTSTR lpKeyName,
+ UINT Value,
+ LPCTSTR lpFileName
+ );
+
+#define WriteProfileInt(App, Key, Value) \
+ WritePrivateProfileInt(App, Key, Value, NULL)
+
+
+LPTSTR
+AllocAndExpandEnvironmentStrings(
+ LPCTSTR lpszSrc
+ );
+
+LPTSTR
+AllocAndRegEnumKey(
+ HKEY hKey,
+ DWORD iSubKey
+ );
+
+LPTSTR
+AllocAndRegQueryValueEx(
+ HKEY hKey,
+ LPTSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType
+ );
+
+BOOL
+SetEnvironmentULong(
+ LPTSTR Variable,
+ ULONG Value
+ );
+
+BOOL
+SetEnvironmentLargeInt(
+ LPTSTR Variable,
+ LARGE_INTEGER Value
+ );
+
+LPWSTR
+EncodeMultiSzW(
+ IN LPWSTR MultiSz
+ );
+
+VOID
+CentreWindow(
+ HWND hwnd
+ );
+
+VOID
+SetupSystemMenu(
+ HWND hDlg
+ );
+
+
+//
+// Memory macros
+//
+
+#define Alloc(c) ((PVOID)LocalAlloc(LPTR, c))
+#define ReAlloc(p, c) ((PVOID)LocalReAlloc(p, c, LPTR | LMEM_MOVEABLE))
+#define Free(p) ((VOID)LocalFree(p))
+
+
diff --git a/private/windows/gina/winlogon/wlevents.mc b/private/windows/gina/winlogon/wlevents.mc
new file mode 100644
index 000000000..ff4a2f29d
--- /dev/null
+++ b/private/windows/gina/winlogon/wlevents.mc
@@ -0,0 +1,62 @@
+;/*++ BUILD Version: 0001 // Increment this if a change has global effects
+;
+;Copyright (c) 1992 Microsoft Corporation
+;
+;Module Name:
+;
+; wlevents.h
+;
+;Abstract:
+;
+; Definitions for User Profiles Events
+;
+;Author:
+;
+; Johannec 12-08-93
+;
+;Revision History:
+;
+;Notes:
+;
+; This file is generated by the MC tool from the wlevents.mc file.
+;
+;--*/
+;
+;
+;#ifndef _PROFEVT_
+;#define _PROFEVT_
+;
+
+
+SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
+ Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
+ Warning=0x2:STATUS_SEVERITY_WARNING
+ Error=0x3:STATUS_SEVERITY_ERROR
+ )
+
+;
+;/////////////////////////////////////////////////////////////////////////
+;//
+;// Winlogon Events (1000 - 1999)
+;//
+;/////////////////////////////////////////////////////////////////////////
+;
+
+MessageId=1000 Severity=Error SymbolicName=EVENT_SET_HOME_DIRECTORY_FAILED
+Language=English
+Failed to set the user's home directory %1.
+.
+
+MessageId=1001 Severity=Informational SymbolicName=EVENT_AUTOCHK_DATA
+Language=English
+%1
+.
+
+MessageId=1002 Severity=Informational SymbolicName=EVENT_SHELL_RESTARTED
+Language=English
+The shell stopped unexpectedly and %1 was restarted.
+.
+
+;
+;#endif // _PROFEVT_
+;
diff --git a/private/windows/gina/winlogon/wlx.c b/private/windows/gina/winlogon/wlx.c
new file mode 100644
index 000000000..1fe4f2ea5
--- /dev/null
+++ b/private/windows/gina/winlogon/wlx.c
@@ -0,0 +1,2126 @@
+/****************************** Module Header ******************************\
+* Module Name: wlx.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Winlogon main module
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define WM_HIDEOURSELVES WM_USER + 600
+
+
+#if DBG
+char * SASTypes[] = { "Timeout", "Ctrl-Alt-Del", "ScreenSaver Timeout",
+ "ScreenSaver Activity", "User Logoff" };
+#define SASName(x) (x < (sizeof(SASTypes) / sizeof(char *)) ? SASTypes[x] : "User Defined")
+
+char * WlxRets[] = { "invalid", "Logon", "None", "LockWksta", "Logoff", "Shutdown",
+ "Pwd Changed", "TaskList", "UnlockWksta", "ForceLogoff",
+ "Shutdown-PowerOff", "Shutdown-Reboot" };
+#define WlxName(x) (x < (sizeof(WlxRets) / sizeof(char *)) ? WlxRets[x] : "Invalid")
+#endif
+
+#define IsShutdown(x) ((x == WLX_SAS_ACTION_SHUTDOWN) || \
+ (x == WLX_SAS_ACTION_SHUTDOWN_REBOOT) || \
+ (x == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) )
+
+#define RealFlagsFromStoredFlags(Flags) \
+ EWX_LOGOFF | \
+ ((Flags & EWX_WINLOGON_OLD_SYSTEM) ? EWX_SYSTEM_CALLER : 0) | \
+ ((Flags & EWX_WINLOGON_OLD_SHUTDOWN) ? EWX_SHUTDOWN : 0) | \
+ ((Flags & EWX_WINLOGON_OLD_REBOOT) ? EWX_REBOOT : 0) | \
+ ((Flags & EWX_WINLOGON_OLD_POWEROFF) ? EWX_POWEROFF : 0)
+
+#define StoredFlagsFromRealFlags(Flags) \
+ EWX_LOGOFF | \
+ ((Flags & EWX_SYSTEM_CALLER) ? EWX_WINLOGON_OLD_SYSTEM : 0) | \
+ ((Flags & EWX_SHUTDOWN) ? EWX_WINLOGON_OLD_SHUTDOWN : 0) | \
+ ((Flags & EWX_REBOOT) ? EWX_WINLOGON_OLD_REBOOT : 0) | \
+ ((Flags & EWX_POWEROFF) ? EWX_WINLOGON_OLD_POWEROFF : 0)
+
+
+BOOLEAN SasMessages = TRUE;
+
+//
+// For checking page file
+//
+
+extern TCHAR szMemMan[];
+
+extern TCHAR szNoPageFile[];
+
+//
+// For migration
+//
+
+TCHAR szAdminName[ MAX_STRING_BYTES ];
+
+//
+// Local Prototypes
+//
+
+int
+DoLockWksta(
+ PGLOBALS pGlobals,
+ BOOL ScreenSaverInvoked);
+
+int
+DoScreenSaver(
+ PGLOBALS pGlobals,
+ BOOL WkstaLocked);
+
+void
+WinsrvNotify(
+ PGLOBALS pGlobals,
+ DWORD SasType);
+
+BOOL
+LoggedonDlgInit(
+ HWND hDlg
+ );
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DropWorkingSet
+//
+// Synopsis: Reduce working set when we're
+//
+// Arguments: (none)
+//
+// History: 11-04-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+void
+DropWorkingSet(void)
+{
+ NTSTATUS Status;
+ QUOTA_LIMITS Quota;
+
+ Status = NtQueryInformationProcess( NtCurrentProcess(),
+ ProcessQuotaLimits,
+ &Quota,
+ sizeof(QUOTA_LIMITS),
+ NULL );
+
+ if (NT_SUCCESS(Status))
+ {
+ Quota.MinimumWorkingSetSize = 0xFFFFFFFF;
+ Quota.MaximumWorkingSetSize = 0xFFFFFFFF;
+
+ NtSetInformationProcess(NtCurrentProcess(),
+ ProcessQuotaLimits,
+ &Quota,
+ sizeof(QUOTA_LIMITS) );
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitializeGinaDll
+//
+// Synopsis: Initializes the gina
+//
+// Arguments: [pGlobals] --
+//
+// History: 10-17-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+InitializeGinaDll(PGLOBALS pGlobals)
+{
+ PGINASESSION pGina;
+
+ pGina = pGlobals->pGina;
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_INITIALIZE))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxInitialize(%ws, 1, NULL, @%#x, @%#x)\n",
+ pGlobals->WindowStation.pszWinsta,
+ &WlxDispatchTable, &pGina->pGinaContext));
+
+ DebugBreak();
+ }
+#endif
+
+
+ //
+ // Perversely, this may not return. The GINA may in fact call SASNotify
+ // immediately, so update the state before we go in:
+ //
+
+ pGlobals->WinlogonState = Winsta_NoOne;
+ DebugLog((DEB_TRACE_STATE, "InitGina: State is %d %s\n", Winsta_NoOne, GetState(Winsta_NoOne)));
+
+ if (!pGina->pWlxInitialize( pGlobals->WindowStation.pszWinsta,
+ pGlobals,
+ NULL,
+ (PVOID) &WlxDispatchTable,
+ &pGina->pGinaContext))
+ {
+ //
+ // If the GINA failed to init, we're dead. bugcheck time:
+ //
+
+ ExitProcess( EXIT_GINA_INIT_ERROR );
+ }
+ return(TRUE);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SASRouter
+//
+// Synopsis: Routes an SAS event to the appropriate recipient
+//
+// Arguments: [pGlobals] --
+// [SasType] --
+//
+// History: 8-24-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+void
+SASRouter( PGLOBALS pGlobals,
+ DWORD SasType )
+{
+
+
+ if (!TestSasMessages())
+ {
+ QueueSasEvent(SasType);
+ return;
+ }
+
+ pGlobals->SasType = SasType;
+
+ if (!IsSASState(pGlobals->WinlogonState))
+ {
+ if (IsDisplayState(pGlobals->WinlogonState) ||
+ (pGlobals->WinlogonState == Winsta_WaitForShutdown) ||
+ (pGlobals->WinlogonState == Winsta_InShutdownDlg) ||
+ (pGlobals->WinlogonState == Winsta_Locked))
+ {
+ DebugLog((DEB_TRACE, "In state %s, sending kill message to window\n",
+ GetState(pGlobals->WinlogonState)));
+
+ if (!SendSasToTopWindow(pGlobals, SasType))
+ DebugLog((DEB_WARN, "No window to send SAS notice to?\n"));
+ }
+
+ //
+ // If this was a timeout message,
+ if ((SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) ||
+ (SasType == WLX_SAS_TYPE_TIMEOUT) )
+ {
+ //
+ // We do *not* change state on a timeout!
+ //
+ return;
+ }
+
+ ChangeStateForSAS(pGlobals);
+
+
+ if (!pGlobals->ScreenSaverActive)
+ {
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+ }
+
+ //
+ // We should be in one of the three base states now:
+ //
+
+ DebugLog((DEB_TRACE_STATE, "SASRouter: In state %s\n", GetState(pGlobals->WinlogonState)));
+ switch (pGlobals->WinlogonState)
+ {
+ case Winsta_NoOne_SAS:
+ case Winsta_LoggedOn_SAS:
+ case Winsta_Locked_SAS:
+ case Winsta_WaitForLogoff:
+ case Winsta_WaitForShutdown:
+ case Winsta_InShutdownDlg:
+ DisableSasMessages();
+ break;
+
+
+ default:
+ DebugLog((DEB_ERROR, "SASRouter: Incorrect state %d, %s.\n",
+ pGlobals->WinlogonState, GetState(pGlobals->WinlogonState)));
+ break;
+
+ }
+ }
+ else
+ {
+ //
+ // We are already handling an SAS attempt.
+ //
+ // Note: This may fail. There may not be a window currently to
+ // receive the message. Life is tough that way. The SAS will be
+ // *dropped*.
+ //
+
+ DebugLog((DEB_TRACE, "Sending SAS %s to top window\n", SASName(SasType)));
+
+ SendSasToTopWindow(pGlobals, SasType);
+ }
+
+
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CADNotify
+//
+// Synopsis: Called by sas.c, this is the entrypoint for a Ctrl-Alt-Del
+// call. Expanded to handle all notification from winsrv.
+//
+// Arguments: [pGlobals] --
+// [SasType] --
+//
+// Algorithm:
+//
+// History: 10-17-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+void
+CADNotify(
+ PGLOBALS pGlobals,
+ DWORD SasType)
+{
+ DebugLog((DEB_TRACE, "Received SAS from winsrv, code %d (%s)\n", SasType, SASName(SasType)));
+ if (SasType == WLX_SAS_TYPE_USER_LOGOFF)
+ {
+ WinsrvNotify(pGlobals, SasType);
+ }
+ else if (pGlobals->ForwardCAD)
+ {
+ SASRouter(pGlobals, SasType);
+ }
+}
+
+PWSTR
+AllocAndDuplicateString(
+ PWSTR pszString)
+{
+ int len;
+ PWSTR pszNewString;
+
+ if (!pszString)
+ {
+ return(NULL);
+ }
+
+ len = (wcslen(pszString) + 1) * sizeof(WCHAR);
+
+ pszNewString = LocalAlloc(LMEM_FIXED, len);
+ if (pszNewString)
+ {
+ CopyMemory(pszNewString, pszString, len);
+ }
+
+ return(pszNewString);
+
+}
+
+PWSTR
+AllocAndDuplicateStrings(
+ PWSTR pszStrings)
+{
+ DWORD len;
+ PWSTR pszNewStrings;
+
+ if (!pszStrings)
+ {
+ return(NULL);
+ }
+
+
+ len = LocalSize (pszStrings);
+
+ pszNewStrings = LocalAlloc(LPTR, len);
+ if (pszNewStrings)
+ {
+ CopyMemory(pszNewStrings, pszStrings, len);
+ }
+
+ return(pszNewStrings);
+
+}
+
+
+PVOID
+CopyEnvironment(
+ PVOID pEnv)
+{
+ MEMORY_BASIC_INFORMATION mbi;
+ PVOID pNew;
+
+ if (VirtualQueryEx(
+ GetCurrentProcess(),
+ pEnv,
+ &mbi,
+ sizeof(mbi) ) )
+ {
+ pNew = VirtualAlloc(NULL,
+ mbi.RegionSize,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if (pNew)
+ {
+ CopyMemory(pNew, pEnv, mbi.RegionSize);
+ return(pNew);
+ }
+ }
+
+ return(NULL);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LogonAttempt
+//
+// Synopsis: Handles a logon attempt.
+//
+// Arguments: [pGlobals] --
+//
+// History: 10-17-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+int
+LogonAttempt(
+ PGLOBALS pGlobals)
+{
+ DWORD WlxResult;
+ PGINASESSION pGina;
+ WLX_MPR_NOTIFY_INFO MprInfo;
+ PWLX_PROFILE_V2_0 pProfileInfo;
+ PSID pLogonSid;
+ DWORD Options;
+ HANDLE hToken;
+ HANDLE uh;
+ int MprRet;
+
+
+ pGina = pGlobals->pGina;
+
+ pLogonSid = CreateLogonSid(NULL);
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_LOGGEDOUT))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxLoggedOutSAS(%#x, %d, @%#x, @%x,\n",
+ pGina->pGinaContext, pGlobals->SasType, &pGlobals->LogonId, pLogonSid));
+ DebugLog((DEB_TRACE, " @%#x, @%#x, @%#x, @%#x)\n", &Options, &hToken,
+ &MprInfo, &pProfileInfo));
+
+ DebugBreak();
+ }
+#endif
+
+ WlxSetTimeout(pGlobals, 120);
+
+ WlxResult = pGina->pWlxLoggedOutSAS(pGina->pGinaContext,
+ pGlobals->SasType,
+ &pGlobals->LogonId,
+ pLogonSid,
+ &Options,
+ &hToken,
+ &MprInfo,
+ &pProfileInfo );
+
+ DebugLog((DEB_TRACE, "WlxLoggedOutSAS returned %d, %s\n", WlxResult, WlxName(WlxResult)));
+
+ if (WlxResult != WLX_SAS_ACTION_LOGON )
+ {
+ DebugLog((DEB_TRACE_STATE, "LogonAttempt: Resetting state to %s\n", GetState(Winsta_NoOne)));
+
+ pGlobals->WinlogonState = Winsta_NoOne;
+
+ DeleteLogonSid(pLogonSid);
+
+ return(WlxResult);
+ }
+
+ //
+ // Okay, someone logged on. This, this is interesting.
+ //
+
+ if (MprInfo.pszUserName)
+ {
+ pGlobals->UserName = AllocAndDuplicateString(MprInfo.pszUserName);
+ }
+
+
+ MprRet = MprLogonNotify(
+ pGlobals,
+ NULL,
+ MprInfo.pszUserName,
+ MprInfo.pszDomain,
+ MprInfo.pszPassword,
+ MprInfo.pszOldPassword,
+ &pGlobals->LogonId,
+ &pGlobals->LogonScripts);
+
+ DestroyMprInfo(&MprInfo);
+
+ //
+ // Wait on the font loading thread here, so we don't inadvertantly re-enter
+ // the stuff in user that gets confused.
+ //
+
+ if ( hFontThread )
+ {
+ WaitForSingleObject( hFontThread, INFINITE );
+
+ CloseHandle( hFontThread );
+
+ hFontThread = NULL;
+
+ }
+
+ SecurityChangeUser(pGlobals, hToken, NULL, pLogonSid, TRUE);
+
+ if (!TEST_FLAG(Options, WLX_LOGON_OPT_NO_PROFILE))
+ {
+ if (pProfileInfo) {
+
+ if (pProfileInfo->pszProfile)
+ {
+ pGlobals->UserProfile.ProfilePath =
+ AllocAndExpandEnvironmentStrings(pProfileInfo->pszProfile);
+ LocalFree(pProfileInfo->pszProfile);
+ }
+ else
+ {
+ pGlobals->UserProfile.ProfilePath = NULL;
+ }
+
+ if (pProfileInfo->dwType >= WLX_PROFILE_TYPE_V2_0) {
+ if (pProfileInfo->pszPolicy)
+ {
+ pGlobals->UserProfile.PolicyPath =
+ AllocAndDuplicateString(pProfileInfo->pszPolicy);
+
+ LocalFree(pProfileInfo->pszPolicy);
+ }
+ else
+ {
+ pGlobals->UserProfile.PolicyPath = NULL;
+ }
+
+ if (pProfileInfo->pszNetworkDefaultUserProfile)
+ {
+ pGlobals->UserProfile.NetworkDefaultUserProfile =
+ AllocAndDuplicateString(pProfileInfo->pszNetworkDefaultUserProfile);
+
+ LocalFree(pProfileInfo->pszNetworkDefaultUserProfile);
+ }
+ else
+ {
+ pGlobals->UserProfile.NetworkDefaultUserProfile = NULL;
+ }
+
+ if (pProfileInfo->pszServerName)
+ {
+ pGlobals->UserProfile.ServerName =
+ AllocAndDuplicateString(pProfileInfo->pszServerName);
+
+ LocalFree(pProfileInfo->pszServerName);
+ }
+ else
+ {
+ pGlobals->UserProfile.ServerName = NULL;
+ }
+
+ if (pProfileInfo->pszEnvironment)
+ {
+ pGlobals->UserProfile.Environment =
+ AllocAndDuplicateStrings(pProfileInfo->pszEnvironment);
+
+ LocalFree(pProfileInfo->pszEnvironment);
+ }
+ else
+ {
+ pGlobals->UserProfile.Environment = NULL;
+ }
+
+
+ } else {
+
+ pGlobals->UserProfile.PolicyPath = NULL;
+ pGlobals->UserProfile.NetworkDefaultUserProfile = NULL;
+ pGlobals->UserProfile.ServerName = NULL;
+ pGlobals->UserProfile.Environment = NULL;
+ }
+
+ }
+
+ DebugLog((DEB_TRACE_PROFILE, "Using initial profile path of %ws\n", pGlobals->UserProfile.ProfilePath));
+
+ LocalFree(pProfileInfo);
+
+ //
+ // Load profile, set environment variables, etc.
+ //
+
+ if (SetupUserEnvironment(pGlobals))
+ {
+ OpenIniFileUserMapping(pGlobals);
+
+ uh = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ SetWindowStationUser(pGlobals->WindowStation.hwinsta, &pGlobals->LogonId,
+ pGlobals->UserProcessData.UserSid,
+ RtlLengthSid(pGlobals->UserProcessData.UserSid));
+
+ StopImpersonating(uh);
+
+ //
+ // Update the window station lock so that apps can start.
+ //
+
+ UnlockWindowStation(pGlobals->WindowStation.hwinsta);
+ LockWindowStation(pGlobals->WindowStation.hwinsta);
+
+ //
+ // allocate floppies and CDRoms (if so configured)
+ //
+
+ RmvAllocateRemovableMedia( pLogonSid );
+ }
+ else
+ {
+ //
+ // Whoops, something went wrong. we *must* log the user
+ // out. We do this by passing LOGOFF back to mainloop.
+ //
+
+ WlxResult = WLX_SAS_ACTION_LOGOFF;
+ }
+
+
+ }
+
+ return(WlxResult);
+
+}
+
+/****************************************************************************\
+*
+* FUNCTION: DisplayPreShellLogonMessages
+*
+* PURPOSE: Displays any security warnings to the user after a successful logon
+* The messages are displayed before the shell starts
+*
+* 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
+DisplayPreShellLogonMessages(
+ PGLOBALS pGlobals
+ )
+{
+ int Result;
+
+ if (PageFilePopup) {
+ HKEY hkeyMM;
+ DWORD dwTempFile, cbTempFile, dwType;
+
+ //
+ // WinLogon created a temp page file. If a previous user has not
+ // created a real one already, then inform this user to do so.
+ //
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMemMan, 0, KEY_READ,
+ &hkeyMM) == ERROR_SUCCESS) {
+
+ cbTempFile = sizeof(dwTempFile);
+ if (RegQueryValueEx (hkeyMM, szNoPageFile, NULL, &dwType,
+ (LPBYTE) &dwTempFile, &cbTempFile) != ERROR_SUCCESS ||
+ dwType != REG_DWORD || cbTempFile != sizeof(dwTempFile)) {
+ dwTempFile = 0;
+ }
+
+ RegCloseKey(hkeyMM);
+ } else
+ dwTempFile = 0;
+
+ if (dwTempFile == 1) {
+
+ WlxSetTimeout(pGlobals, TIMEOUT_NONE);
+
+ Result = TimeoutMessageBox(
+ pGlobals,
+ NULL,
+ IDS_NO_PAGING_FILE,
+ IDS_LIMITED_RESOURCES,
+ MB_OK | MB_ICONSTOP
+ );
+
+ if (Result == WLX_DLG_INPUT_TIMEOUT) {
+ return(Result);
+ }
+ }
+ }
+
+ return(DLG_SUCCESS);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoStartShell
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: [pGlobals] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 9-30-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+DoStartShell(
+ PGLOBALS pGlobals
+ )
+{
+ PGINASESSION pGina;
+ HANDLE hImp;
+ PVOID pNewEnvironment;
+
+ (void) DisplayPreShellLogonMessages(pGlobals);
+
+ //
+ // If not logging in as Guest, System or Administrator then check for
+ // migration of Windows 3.1 configuration inforation.
+ //
+
+ if (szAdminName[ 0 ] == TEXT('\0'))
+ {
+ LoadString(NULL, IDS_ADMIN_ACCOUNT_NAME, szAdminName, sizeof(szAdminName));
+ }
+
+
+ if (!IsUserAGuest(pGlobals) &&
+ _wcsicmp(pGlobals->UserName, szAdminName)
+ )
+ {
+ Windows31Migration(pGlobals);
+ }
+
+
+ pGina = pGlobals->pGina;
+
+
+ //
+ // Play the user's logon sound
+ //
+
+ if (pGlobals->PlaySound ||
+ pGlobals->MigrateSoundEvents ||
+ pGlobals->MigrateMidiUser)
+ {
+ BOOL fBeep;
+
+ if (OpenIniFileUserMapping(pGlobals))
+ {
+ hImp = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ //
+ // Migrate Users MIDI settings
+ //
+
+ if (pGlobals->MigrateMidiUser) {
+ (*(pGlobals->MigrateMidiUser))();
+ }
+
+ if (pGlobals->MigrateSoundEvents) {
+ (*(pGlobals->MigrateSoundEvents))();
+ }
+
+ if (pGlobals->PlaySound) {
+
+ //
+ // Whenever a user logs in, have WINMM.DLL check if there
+ // are any sound events within the [SOUNDS] section of
+ // CONTROL.INI that haven't been ported into HKCU/AppEvents.
+ // If there are, migrate those schemes to their new home.
+ // This must be done before the upcoming PlaySound() call,
+ // as PlaySound() uses the HKCU/AppEvents schemes-listing
+ // to resolve an SND_ALIAS_ID request.
+ //
+
+ if (!SystemParametersInfo(SPI_GETBEEP, 0, &fBeep, FALSE)) {
+ // Failed to get hold of beep setting. Should we be
+ // noisy or quiet? We have to choose one value...
+ fBeep = TRUE;
+ }
+
+ if (fBeep) {
+ (*(pGlobals->PlaySound))((LPCSTR)SND_ALIAS_SYSTEMSTART,
+ NULL,
+ SND_ALIAS_ID | SND_ASYNC | SND_NODEFAULT);
+ }
+ }
+
+ StopImpersonating(hImp);
+
+ CloseIniFileUserMapping(pGlobals);
+ }
+
+ }
+
+ WlxSetTimeout(pGlobals, 120);
+
+ pNewEnvironment = CopyEnvironment(pGlobals->UserProcessData.pEnvironment);
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_ACTIVATE))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxActivateUserShell(%#x, %ws, %ws, %#x)\n",
+ pGina->pGinaContext, APPLICATION_DESKTOP_PATH,
+ pGlobals->LogonScripts, NULL));
+ DebugBreak();
+ }
+#endif
+ return( pGina->pWlxActivateUserShell( pGina->pGinaContext,
+ APPLICATION_DESKTOP_PATH,
+ pGlobals->LogonScripts,
+ pNewEnvironment) );
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: HandleLoggedOn
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: [pGlobals] --
+// [SasType] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 9-30-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+HandleLoggedOn(
+ PGLOBALS pGlobals,
+ DWORD SasType)
+{
+ DWORD Result;
+ WLX_MPR_NOTIFY_INFO MprInfo;
+ PGINASESSION pGina;
+ int Flags;
+ int MprRet;
+ int LogoffResult;
+
+ pGina = pGlobals->pGina;
+
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+
+ ZeroMemory(&MprInfo, sizeof(MprInfo));
+
+ WlxSetTimeout(pGlobals, 120);
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_LOGGEDON))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxLoggedOnSAS( %#x, %d, NULL)\n",
+ pGina->pGinaContext, pGlobals->SasType));
+ DebugBreak();
+ }
+#endif
+
+ Result = pGina->pWlxLoggedOnSAS( pGina->pGinaContext,
+ SasType,
+ NULL );
+
+ WlxSetTimeout(pGlobals, TIMEOUT_NONE);
+
+ DebugLog((DEB_TRACE, "WlxLoggedOnSAS returned %d, %s\n", Result, WlxName(Result)));
+ pGlobals->LastGinaRet = Result;
+
+ //
+ // if a new SAS has come in while we were processing that one, repost it and
+ // pick it up in LoggedOnDlgProc.
+ //
+
+ if ( pGlobals->SasType != SasType )
+ {
+ DebugLog((DEB_TRACE, "New SAS (%d: %s) came in while handling (%d: %s). Routing it now\n",
+ pGlobals->SasType, SASName(pGlobals->SasType),
+ SasType, SASName(SasType) ));
+
+ SASRouter( pGlobals, pGlobals->SasType );
+
+ }
+
+ if (Result == WLX_SAS_ACTION_LOCK_WKSTA)
+ {
+ return (DoLockWksta(pGlobals, FALSE));
+ }
+
+ if ((Result == WLX_SAS_ACTION_TASKLIST) ||
+ (Result == WLX_SAS_ACTION_NONE))
+ {
+ if ((pGlobals->WinlogonState != Winsta_WaitForLogoff) &&
+ (pGlobals->WinlogonState != Winsta_WaitForShutdown) &&
+ (pGlobals->WinlogonState != Winsta_InShutdownDlg) )
+ {
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
+ }
+ if (Result == WLX_SAS_ACTION_TASKLIST)
+ {
+ WCHAR szTaskMgr[] = L"taskmgr.exe";
+
+ DebugLog((DEB_TRACE, "Starting taskmgr.exe.\n"));
+
+ if (pGlobals->UserLoggedOn ) {
+ pGina->pWlxStartApplication(pGina->pGinaContext,
+ APPLICATION_DESKTOP_PATH,
+ pGlobals->UserProcessData.pEnvironment,
+ szTaskMgr);
+ }
+ }
+
+ TickleMessenger();
+
+ return(Result);
+
+ }
+
+ switch (Result)
+ {
+ case WLX_SAS_ACTION_LOGOFF:
+ Flags = EWX_LOGOFF;
+ break;
+
+ case WLX_SAS_ACTION_FORCE_LOGOFF:
+ Flags = EWX_LOGOFF | EWX_FORCE;
+ break;
+
+ case WLX_SAS_ACTION_SHUTDOWN:
+ Flags = EWX_LOGOFF | EWX_WINLOGON_OLD_SHUTDOWN;
+ break;
+
+ case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
+ Flags = EWX_LOGOFF | EWX_WINLOGON_OLD_SHUTDOWN | EWX_WINLOGON_OLD_REBOOT;
+ break;
+
+ case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
+ Flags = EWX_LOGOFF | EWX_WINLOGON_OLD_SHUTDOWN | EWX_WINLOGON_OLD_POWEROFF;
+ break;
+
+ default:
+ DebugLog((DEB_ERROR, "Incorrect result (%d) from WlxLoggedOnSAS\n", Result));
+ return(0);
+ }
+
+
+ LogoffResult = InitiateLogoff(pGlobals, Flags);
+ if (LogoffResult == DLG_FAILURE)
+ {
+ return(WLX_SAS_ACTION_NONE);
+ }
+
+ return(Result);
+
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoLockWksta
+//
+// Synopsis:
+//
+// Arguments: [pGlobals] --
+//
+// History: 9-16-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+int
+DoLockWksta(
+ PGLOBALS pGlobals,
+ BOOL ScreenSaverInvoked)
+{
+ int Result;
+ PGINASESSION pGina;
+
+ pGlobals->WinlogonState = Winsta_Locked;
+ DebugLog((DEB_TRACE_STATE, "DoLockWksta: Setting state to %s\n", GetState(Winsta_Locked)));
+
+ pGina = pGlobals->pGina;
+
+ LockWindowStation(pGlobals->WindowStation.hwinsta);
+
+ do
+ {
+
+ pGlobals->WinlogonState = Winsta_Locked_Display;
+ DebugLog((DEB_TRACE_STATE, "DoLockWksta: Setting state to %s\n",
+ GetState(Winsta_Locked_Display)));
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_DISPLAYLOCKED))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxDisplayLockedNotice( %#x )\n",
+ pGina->pGinaContext ));
+ DebugBreak();
+ }
+#endif
+ //
+ // No input timeout
+ //
+
+ WlxSetTimeout(pGlobals, TIMEOUT_NONE);
+
+ pGina->pWlxDisplayLockedNotice( pGina->pGinaContext );
+
+ DebugLog((DEB_TRACE, "Out of DisplayLockedNotice, SAS = %s\n",
+ SASName(pGlobals->SasType)));
+
+ if (pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
+ {
+ //
+ // If we were invoked as part of a secure screen saver,
+ // then this timeout means that we should return to it
+ // and let it cycle.
+ //
+ if (ScreenSaverInvoked)
+ {
+ return(WLX_SAS_ACTION_NONE);
+ }
+
+ //
+ // Invoke the screen saver:
+ //
+
+ if (DoScreenSaver(pGlobals, TRUE) >= 0)
+ {
+
+ //
+ // Jump right back to the top.
+ //
+
+ Result = WLX_SAS_ACTION_NONE;
+
+ continue;
+ }
+
+ //
+ // A return of -1 indicates that some other SAS occurred,
+ // e.g. a Logoff, or a GINA specific SAS. Fall through to
+ // the default handling.
+ //
+
+ }
+
+ //
+ // An unfortunate label, but things get awfully convoluted switching
+ // between the screen saver and the locked state. The screen saver
+ // has stopped due to a SAS, and here is where we figure out what to
+ // do. This is jumped to from below, if the WkstaLocked dialog
+ // ended with a screen saver timeout.
+ //
+
+
+ResetLockCall:
+
+ if (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF)
+ {
+ if (pGlobals->LogoffFlags & EWX_WINLOGON_API_SHUTDOWN)
+ {
+ pGlobals->WinlogonState = Winsta_Shutdown;
+ }
+ return(WLX_SAS_ACTION_LOGOFF);
+ }
+
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_WKSTALOCKED))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxWkstaLockedSAS( %#x, %d )\n",
+ pGina->pGinaContext, pGlobals->SasType ));
+ DebugBreak();
+ }
+#endif
+ WlxSetTimeout(pGlobals, 120);
+
+ Result = pGina->pWlxWkstaLockedSAS( pGina->pGinaContext, pGlobals->SasType );
+
+ WlxSetTimeout(pGlobals, TIMEOUT_NONE);
+
+ DebugLog((DEB_TRACE, "WlxWkstaLockedSAS returned %d, %s\n", Result, WlxName(Result)));
+
+ pGlobals->LastGinaRet = Result;
+
+ if ( (Result == WLX_SAS_ACTION_NONE) &&
+ (pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT ) )
+ {
+ //
+ // The GINA was interrupted by a screen saver timeout. If
+ // we were invoked by a screen saver, we should return immediately,
+ // otherwise, run the screen saver. Same as before when the display
+ // call timed out.
+ //
+
+ if (ScreenSaverInvoked)
+ {
+ return(WLX_SAS_ACTION_NONE);
+ }
+
+ //
+ // A return of -1 indicates that the screen saver terminated
+ // due to some other SAS. Jump back up to the point where we
+ // handle that, so that we have one point where we do things
+ // correctly.
+ //
+
+ if ( DoScreenSaver( pGlobals, TRUE ) < 0 )
+ {
+ goto ResetLockCall;
+
+ }
+
+ //
+ // Otherwise, fall through, and loop again.
+ //
+
+
+ }
+
+ } while (Result == WLX_SAS_ACTION_NONE);
+
+
+ if (Result == WLX_SAS_ACTION_FORCE_LOGOFF)
+ {
+ InitiateLogoff(pGlobals, EWX_LOGOFF | EWX_FORCE);
+ }
+ else
+ {
+ SetActiveDesktop( &pGlobals->WindowStation, Desktop_Application );
+
+ TickleMessenger();
+ }
+
+ return(Result);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoScreenSaver
+//
+// Synopsis: Starts up the screen saver
+//
+// Effects:
+//
+// Arguments: [pGlobals] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 10-13-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+int
+DoScreenSaver(
+ PGLOBALS pGlobals,
+ BOOL WkstaLocked)
+{
+ int Result;
+ BOOL FastUnlock;
+
+
+ //
+ // WkstaLocked indicates that we were called by the DoLockWksta
+ // path. This means that we should not recursively call them, since
+ // there is no stopping case and we could chew up a lot of stack.
+ // So, we loop here, but we can break out if RunScreenSaver doesn't
+ // return Wksta locked.
+ //
+
+ //
+ // FastUnlock determines if we allow a grace period or not. If the
+ // wksta is locked coming in, then it is not allowed at all. If it is
+ // not locked on entry, then we allow it once.
+ //
+
+ FastUnlock = !WkstaLocked;
+
+ do
+ {
+ Result = RunScreenSaver(pGlobals, FALSE, FastUnlock);
+
+ FastUnlock = FALSE;
+
+ if (Result == WLX_SAS_ACTION_LOCK_WKSTA)
+ {
+ //
+ // Ok, it's a secure screen saver. If we are already locked,
+ // break and return
+ //
+ if (WkstaLocked)
+ {
+ break;
+ }
+
+ //
+ // Ok, it's not. Invoke the lock code ourselves, but tell it
+ // that it's being called from the screen saver path.
+ //
+
+ Result = DoLockWksta(pGlobals, TRUE);
+
+ }
+ else
+ {
+ break;
+ }
+
+ //
+ // Loop clause: we only get here if we have invoked DoLockWksta.
+ // Loop only if it return WLX_SAS_ACTION_NONE, not unlock or force
+ // logoff.
+ //
+
+ } while (Result == WLX_SAS_ACTION_NONE);
+
+ if ( (Result == -1) || (Result == WLX_SAS_ACTION_LOGOFF) )
+ {
+ return( Result );
+ }
+ else if (Result == WLX_SAS_ACTION_FORCE_LOGOFF)
+ {
+ return(Result);
+ }
+ return(0);
+
+}
+
+
+
+/***************************************************************************\
+* FUNCTION: LogoffWaitDlgProc
+*
+* PURPOSE: Processes messages for the forced logoff wait dialog
+*
+* RETURNS:
+* DLG_FAILURE - the dialog could not be displayed
+* DLG_INTERRUPTED() - this is a set of possible interruptions (see winlogon.h)
+*
+* HISTORY:
+*
+* 05-09-92 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+CALLBACK
+LogoffWaitDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ switch (message) {
+
+ case WM_INITDIALOG:
+
+ EnableSasMessages(hDlg);
+
+ SetWindowLong(hDlg, GWL_USERDATA, lParam);
+
+ CentreWindow(hDlg);
+
+ return(TRUE);
+
+ }
+
+ // We didn't process this message
+ return FALSE;
+}
+
+
+BOOL
+WaitForForceLogoff(
+ HWND hWnd,
+ PGLOBALS pGlobals)
+{
+ int Result;
+
+ do
+ {
+ SetActiveDesktop( &pGlobals->WindowStation, Desktop_Winlogon );
+
+ WlxSetTimeout(pGlobals, TIMEOUT_NONE);
+
+ Result = WlxDialogBoxParam( pGlobals,
+ pGlobals->hInstance,
+ MAKEINTRESOURCE(IDD_FORCED_LOGOFF_WAIT),
+ hWnd,
+ LogoffWaitDlgProc,
+ (LONG) pGlobals);
+
+ } while ( (Result == WLX_DLG_INPUT_TIMEOUT) ||
+ (Result == WLX_DLG_SCREEN_SAVER_TIMEOUT) );
+
+
+ return(TRUE);
+
+}
+
+/***************************************************************************\
+* FUNCTION: LoggedOnDlgProc
+*
+* PURPOSE: Processes messages for the logged-on control dialog
+*
+* DIALOG RETURNS:
+*
+* DLG_FAILURE - Couldn't bring up the dialog
+* DLG_LOGOFF() - The user logged off
+*
+* NOTES:
+*
+* On entry, it assumed that the winlogon desktop is switched to and the
+* desktop lock is held. This same state exists on exit.
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL WINAPI
+LoggedonDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
+ int Result;
+
+
+ switch (message)
+ {
+
+ case WM_INITDIALOG:
+ SetWindowLong(hDlg, GWL_USERDATA, lParam);
+ pGlobals = (PGLOBALS)lParam;
+
+ if (!LoggedonDlgInit(hDlg)) {
+ EndDialog(hDlg, DLG_FAILURE);
+ return(TRUE);
+ }
+
+ // Send ourselves a message so we can hide ourselves without the
+ // dialog code trying to force us to be visible
+ PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0);
+
+ //
+ //
+ // Switch to app desktop and release lock
+ //
+
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
+
+ //
+ // Tickle the messenger so it will display any queue'd messages.
+ // (This call is a kind of NoOp).
+ //
+ TickleMessenger();
+
+ return(TRUE);
+
+ case WM_HIDEOURSELVES:
+ ShowWindow(hDlg, SW_HIDE);
+
+ DropWorkingSet();
+
+ return(TRUE);
+
+ case WLX_WM_SAS:
+
+ //
+ // Disable further SAS events until we decide what to do. If
+ // we start another window, they will automagically be forwarded
+ // to it. This lets us call right into the individual cases.
+ //
+
+ DisableSasMessages();
+
+ if (wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
+ {
+ Result = DoScreenSaver(pGlobals, FALSE);
+
+ if ( (Result < 0) || (Result == WLX_SAS_ACTION_LOGOFF) )
+ {
+ //
+ // Ugly case: the screen saver received a SAS event
+ // which has interrupted it. So, that SAS is now stored
+ // in the globals. We snag it, stuff it in wParam, and
+ // FALL THROUGH to the rest of this code.
+ //
+
+ wParam = pGlobals->SasType;
+ }
+ else if (Result == WLX_SAS_ACTION_FORCE_LOGOFF)
+ {
+ EndDialog(hDlg, WLX_SAS_ACTION_FORCE_LOGOFF);
+ return(TRUE);
+
+ }
+ else
+ {
+ EnableSasMessages(hDlg);
+ return(TRUE);
+ }
+ }
+
+ //
+ // Ok, more ugly cases. The user could asynchronously log off
+ // while we're in HandleLoggedOn(), in which case we would get
+ // the logoff notify in some other dialog, and returned to us
+ // here. But, we also have some logoff cases coming through
+ // here if we are waiting for the logoff, so if this is not
+ // winsrv telling us it's logged the guy off, ask the gina
+ // what to do.
+ //
+
+ if ((wParam != WLX_SAS_TYPE_USER_LOGOFF) &&
+ (wParam != WLX_SAS_TYPE_TIMEOUT) )
+ {
+ Result = HandleLoggedOn(pGlobals, (DWORD) wParam);
+ }
+ else
+ {
+ Result = -1;
+ }
+
+
+ if ((wParam == WLX_SAS_TYPE_USER_LOGOFF ) ||
+ (Result == WLX_SAS_ACTION_LOGOFF ) ||
+ (Result == WLX_SAS_ACTION_FORCE_LOGOFF ) )
+ {
+ //
+ // If we were shut down by the remote guy, handle that
+ //
+ if (pGlobals->WinlogonState == Winsta_Shutdown)
+ {
+ EndDialog(hDlg, pGlobals->LastGinaRet);
+ return(TRUE);
+ }
+ if ((pGlobals->WinlogonState == Winsta_WaitForLogoff) ||
+ (wParam == WLX_SAS_TYPE_USER_LOGOFF) )
+ {
+ if (IsShutdown(pGlobals->LastGinaRet))
+ {
+ pGlobals->WinlogonState = Winsta_WaitForShutdown;
+ }
+ else
+ pGlobals->WinlogonState = Winsta_NoOne;
+
+ DebugLog((DEB_TRACE_STATE, "LoggedOnDlg: setting state to %s\n",
+ GetState(pGlobals->WinlogonState)));
+
+ EndDialog(hDlg, pGlobals->LastGinaRet);
+ return(TRUE);
+
+ }
+ else
+ {
+ DebugLog((DEB_TRACE_STATE, "LoggedOnDlg: setting state to WaitForLogoff\n"));
+ pGlobals->WinlogonState = Winsta_WaitForLogoff;
+
+ //
+ // If this is a force-logoff, end now, so that we fall
+ // through to the special dialog (WaitForForceLogoff())
+ //
+
+ if (Result == WLX_SAS_ACTION_FORCE_LOGOFF)
+ {
+ EndDialog(hDlg, Result);
+ return(TRUE);
+ }
+ }
+ }
+ else
+ {
+ //
+ // Now it is perverse. If the user logged off *while the
+ // options dialog was up*, they will return NONE, expecting
+ // us to deal with it correctly.
+ //
+
+ if (pGlobals->WinlogonState == Winsta_WaitForLogoff)
+ {
+ if (IsShutdown(pGlobals->LastGinaRet))
+ {
+ pGlobals->WinlogonState = Winsta_WaitForShutdown;
+ }
+ else
+ pGlobals->WinlogonState = Winsta_NoOne;
+
+ DebugLog((DEB_TRACE_STATE, "LoggedOnDlg: setting state to %s\n",
+ GetState(pGlobals->WinlogonState)));
+
+ EndDialog(hDlg, pGlobals->LastGinaRet);
+ return(TRUE);
+
+ }
+ }
+
+ EnableSasMessages(hDlg);
+
+ DropWorkingSet();
+
+ return(TRUE);
+ }
+
+ // We didn't process this message
+ return(FALSE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: LoggedonDlgInit
+*
+* PURPOSE: Handles initialization of logged-on dialog
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 12-09-91 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+LoggedonDlgInit(
+ HWND hDlg
+ )
+{
+ PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
+
+ // Set our size to zero so we we don't appear
+ SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE |
+ SWP_NOREDRAW | SWP_NOZORDER);
+
+ SetMapperFlag(hDlg, MAPPERFLAG_WINLOGON);
+
+ return(TRUE);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: BlockWaitForUserAction
+//
+// Synopsis: Blocks, waiting for the interactive user to do something, or
+// a SAS to come in from the gina.
+//
+// Effects:
+//
+// Arguments: [pGlobals] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 10-17-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+
+int
+BlockWaitForUserAction(PGLOBALS pGlobals)
+{
+ int res;
+
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
+ WlxSetTimeout(pGlobals, TIMEOUT_NONE);
+ res = WlxDialogBoxParam( pGlobals, pGlobals->hInstance,
+ MAKEINTRESOURCE(IDD_CONTROL),
+ NULL,
+ LoggedonDlgProc,
+ (LONG) pGlobals) ;
+#if DBG
+ if (res == -1)
+ {
+ DebugLog((DEB_ERROR, "Failed to start LoggedOnDlgProc, %d\n", GetLastError()));
+ }
+#endif
+
+ return(res);
+
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MainLoop
+//
+// Synopsis: Main winlogon loop.
+//
+// Arguments: [pGlobals] --
+//
+// History: 10-17-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+void
+MainLoop(PGLOBALS pGlobals)
+{
+ DWORD WlxResult;
+ PGINASESSION pGina;
+ int ScreenSaverResult;
+
+ WlxResult = WLX_SAS_ACTION_NONE;
+ pGina = pGlobals->pGina;
+
+ //
+ // Initialize the gina dll
+ //
+
+ if (!InitializeGinaDll(pGlobals))
+ {
+ return;
+ }
+
+ //
+ // So long as action is none, loop here:
+ //
+
+ while (WlxResult == WLX_SAS_ACTION_NONE)
+ {
+ DealWithAutochkLogs();
+
+ //
+ // If no one is logged on, switch to the display state, and call
+ // the gina to display a message. This is structured this way so
+ // that a gina can call us immediately during Initialize, and we
+ // can fall into the loop in the correct state.
+ //
+ if (pGlobals->WinlogonState == Winsta_NoOne)
+ {
+ pGlobals->WinlogonState = Winsta_NoOne_Display;
+ DebugLog((DEB_TRACE_STATE, "Setting state to %s\n",
+ GetState(Winsta_NoOne_Display)));
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_DISPLAY))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxDisplaySASNotice(%x)\n",
+ pGina->pGinaContext));
+ DebugBreak();
+ }
+#endif
+ WlxSetTimeout(pGlobals, TIMEOUT_NONE);
+
+ pGina->pWlxDisplaySASNotice(pGina->pGinaContext);
+
+ //
+ // If we got a user logoff notify, that means that WE HAVE ALREADY
+ // SHUT DOWN. A remote shutdown has taken place, and it has been
+ // started by sysshut.c.
+ //
+ if (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF)
+ {
+ //
+ // We are *done*
+ //
+
+ DebugLog(( DEB_TRACE_STATE, "Received Logoff, setting state to %s\n",
+ GetState(Winsta_Shutdown) ));
+
+ pGlobals->WinlogonState = Winsta_Shutdown;
+
+ break;
+ }
+
+ //
+ // If we got a time out,
+ //
+ if (pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
+ {
+ //
+ // run the screen saver
+ //
+
+ ScreenSaverResult = DoScreenSaver( pGlobals, FALSE );
+
+ if (ScreenSaverResult < 0)
+ {
+ //
+ // This means that a SAS other than activity cancelled
+ // the screen saver, such as a GINA specific one.
+ // In this case, drop on through to the logonattempt,
+ // since the current sas is in pGlobals.
+ //
+
+ NOTHING ;
+
+ }
+ else
+ {
+ if ( ( (ScreenSaverResult == 0) &&
+ (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF) ) ||
+ (ScreenSaverResult == WLX_SAS_ACTION_LOGOFF) )
+ {
+ //
+ // Shutdown during the screen saver.
+ //
+
+ DebugLog(( DEB_TRACE_STATE, "Received Logoff during screensaver, setting state to %s\n",
+ GetState(Winsta_Shutdown) ));
+
+ pGlobals->WinlogonState = Winsta_Shutdown;
+
+ break;
+
+ }
+
+ //
+ // And start the loop over again.
+ //
+ WlxResult = WLX_SAS_ACTION_NONE;
+
+ //
+ // Remember, we're in Winsta_NoOne_Display right now, so we
+ // reset this so that we'll drop back into this at the top of
+ // the loop.
+ //
+
+ DebugLog((DEB_TRACE_STATE, "Resetting to %s\n",
+ GetState(Winsta_NoOne) ));
+
+ pGlobals->WinlogonState = Winsta_NoOne;
+
+ continue;
+ }
+
+ //
+ // If we got a user logoff notify, that means that WE HAVE ALREADY
+ // SHUT DOWN. A remote shutdown has taken place, and it has been
+ // started by sysshut.c.
+ //
+ if (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF)
+ {
+ //
+ // We are *done*
+ //
+ DebugLog(( DEB_TRACE_STATE, "Received Logoff during no-one screensaver, setting state to %s\n",
+ GetState(Winsta_Shutdown) ));
+
+ pGlobals->WinlogonState = Winsta_Shutdown;
+ break;
+ }
+ }
+
+ }
+
+ WlxResult = LogonAttempt(pGlobals);
+
+ if (WlxResult == WLX_SAS_ACTION_NONE)
+ {
+ //
+ // If we got a user logoff notify, that means that WE HAVE ALREADY
+ // SHUT DOWN. A remote shutdown has taken place, and it has been
+ // started by sysshut.c.
+ //
+ if (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF)
+ {
+ //
+ // We are *done*
+ //
+
+ DebugLog(( DEB_TRACE_STATE, "Got logoff during logon, setting to %s\n",
+ GetState(Winsta_Shutdown) ));
+
+ pGlobals->WinlogonState = Winsta_Shutdown;
+
+ break;
+ }
+ //
+ // If we got a time out (meaning a screensaver timeout
+ // occurred during the logon prompt, then the prompt should be dead,
+ // but we'll hit here
+ //
+ if (pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
+ {
+ //
+ // run the screen saver
+ //
+ ScreenSaverResult = DoScreenSaver(pGlobals, FALSE);
+
+ if (ScreenSaverResult < 0)
+ {
+ //
+ // This means that a SAS other than activity cancelled
+ // the screen saver, such as a GINA specific one.
+ // In this case, drop on through to the logonattempt,
+ // since the current sas is in pGlobals.
+ //
+
+ NOTHING ;
+
+ }
+ else
+ {
+ if ( (ScreenSaverResult == 0) &&
+ (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF) )
+ {
+ //
+ // Shutdown during the screen saver.
+ //
+
+ DebugLog(( DEB_TRACE_STATE, "Received Logoff during screensaver, setting state to %s\n",
+ GetState(Winsta_Shutdown) ));
+
+ pGlobals->WinlogonState = Winsta_Shutdown;
+
+ break;
+
+ }
+
+ }
+
+ //
+ // We're already at WlxResult == NONE, and State == NoOne,
+ // so we can just continue
+ //
+
+ }
+
+ //
+ // Make sure that we're back to NoOne:
+ //
+
+ pGlobals->WinlogonState = Winsta_NoOne;
+
+ continue;
+ }
+
+ if (IsShutdownReturn(WlxResult))
+ {
+ pGlobals->LastGinaRet = WlxResult;
+ DebugLog((DEB_TRACE_STATE, "Setting state to %d (%s)\n",
+ Winsta_WaitForShutdown, GetState(Winsta_WaitForShutdown)));
+ pGlobals->WinlogonState = Winsta_WaitForShutdown;
+ break;
+ }
+
+ //
+ // Because profile or something else could have gone wrong, the gina
+ // could have returned LOGON, but it was changed to LOGOFF in
+ // LogonAttempt(). In that case, we don't try and start the shell,
+ // we just go straight to logoff processing.
+ //
+
+ if (WlxResult == WLX_SAS_ACTION_LOGON)
+ {
+ if (DoStartShell(pGlobals))
+ {
+ WlxResult = BlockWaitForUserAction(pGlobals);
+
+ if (WlxResult == WLX_SAS_ACTION_FORCE_LOGOFF)
+ {
+ WaitForForceLogoff(NULL, pGlobals);
+
+ WlxResult = WLX_SAS_ACTION_LOGOFF;
+
+ }
+ }
+ else
+ {
+ WlxResult = WLX_SAS_ACTION_LOGOFF;
+ }
+ }
+
+ EnableSasMessages(NULL);
+
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+
+ if (pGlobals->WinlogonState == Winsta_Shutdown)
+ {
+ break;
+ }
+
+ Logoff(pGlobals, WlxResult);
+
+ SecurityChangeUser(pGlobals, NULL, NULL, pGlobals->WinlogonSid, FALSE);
+
+ if (WlxResult == WLX_SAS_ACTION_LOGOFF)
+ {
+ pGlobals->WinlogonState = Winsta_NoOne;
+ DebugLog((DEB_TRACE, "WlxResult was logoff, so beginning loop again\n"));
+ DebugLog((DEB_TRACE_STATE, "State set to %s\n", GetState(Winsta_NoOne)));
+ WlxResult = WLX_SAS_ACTION_NONE;
+ }
+
+ //
+ // Notify the GINA that the user is logged off
+ //
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_LOGOFF))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxLogoff(%x)\n", pGina->pGinaContext));
+ DebugBreak();
+ }
+#endif
+ pGina->pWlxLogoff(pGina->pGinaContext);
+
+ //
+ // Toggle the winsta lock on and off. This clears the openlock, and
+ // sets the switchlock, allowing services to start, but no one can
+ // switch the active desktop.
+ //
+
+ UnlockWindowStation(pGlobals->WindowStation.hwinsta);
+ LockWindowStation(pGlobals->WindowStation.hwinsta);
+
+#if DBG
+ if ((WlxResult == WLX_SAS_ACTION_NONE) ||
+ (WlxResult == WLX_SAS_ACTION_LOGON) ||
+ (WlxResult == WLX_SAS_ACTION_SHUTDOWN) ||
+ (WlxResult == WLX_SAS_ACTION_SHUTDOWN_REBOOT) ||
+ (WlxResult == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) )
+ {
+ continue;
+ }
+
+ DebugLog((DEB_TRACE, "WlxResult not acceptible value: %d\n", WlxResult));
+ DebugLog((DEB_TRACE, "Resetting to WLX_SAS_ACTION_NONE\n"));
+ WlxResult = WLX_SAS_ACTION_NONE;
+#endif
+
+ }
+
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LogoffFlagsToWlxCode
+//
+// Synopsis: Translates a winsrv USER_LOGOFF message flags to a
+// wlx return code.
+//
+// Arguments: [Flags] --
+//
+// History: 10-17-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+DWORD
+LogoffFlagsToWlxCode(DWORD Flags)
+{
+ if (Flags & EWX_POWEROFF)
+ {
+ return(WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
+ }
+ if (Flags & EWX_REBOOT)
+ {
+ return(WLX_SAS_ACTION_SHUTDOWN_REBOOT);
+ }
+ if (Flags & EWX_SHUTDOWN)
+ {
+ return(WLX_SAS_ACTION_SHUTDOWN);
+ }
+
+ return(WLX_SAS_ACTION_LOGOFF);
+
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: WinsrvNotify
+//
+// Synopsis: Handles when winsrv talks to us
+//
+// Arguments: [pGlobals] --
+// [SasType] --
+//
+// Algorithm:
+//
+// History: 10-17-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+void
+WinsrvNotify(
+ PGLOBALS pGlobals,
+ DWORD SasType)
+{
+ DWORD RealFlags;
+ DWORD LogoffResult;
+ WinstaState PriorState;
+ //
+ // If the caller isn't system, and no-one is logged on, discard this message.
+ //
+
+ if (!(pGlobals->LogoffFlags & EWX_SYSTEM_CALLER) && !pGlobals->UserLoggedOn)
+ {
+ DebugLog((DEB_TRACE, "Discarding notice from winsrv!\n"));
+ return;
+ }
+
+ //
+ // If this indicates that winlogon initiated this message (by calling
+ // InitiateLogoff() somewhere else, or we're in a wait state, then pass
+ // the message along. This is what will kill our LoggedOnDlg.
+ //
+
+ if ((pGlobals->LogoffFlags & EWX_WINLOGON_CALLER) ||
+ (pGlobals->WinlogonState == Winsta_WaitForLogoff) ||
+ (pGlobals->WinlogonState == Winsta_WaitForShutdown) ||
+ (pGlobals->WinlogonState == Winsta_InShutdownDlg) )
+ {
+ SASRouter(pGlobals, SasType);
+ RealFlags = RealFlagsFromStoredFlags(pGlobals->LogoffFlags);
+ pGlobals->LastGinaRet = LogoffFlagsToWlxCode(RealFlags);
+ return;
+ }
+
+ //
+ // Well, this means that the user has called ExitWindowsEx(), and winsrv
+ // has passed the ball to us. We have to turn around and ask the gina if
+ // logoff is ok. This is convenient for some security architectures. I
+ // guess.
+ //
+
+#if DBG
+ if (TEST_FLAG(GinaBreakFlags, BREAK_ISLOGOFFOK))
+ {
+ DebugLog((DEB_TRACE, "About to call WlxIsLogoffOk(%#x)\n", pGlobals->pGina->pGinaContext));
+ DebugBreak();
+ }
+#endif
+ if (!pGlobals->pGina->pWlxIsLogoffOk(pGlobals->pGina->pGinaContext))
+ {
+ DebugLog((DEB_TRACE, "Gina said no logoff...\n"));
+ return;
+ }
+
+
+ //
+ // Well, if we're not in a wait state, then initiate logoff and possibly
+ // shutdown. Convoluted, right?
+ //
+
+ if ((pGlobals->WinlogonState != Winsta_WaitForLogoff) &&
+ (pGlobals->WinlogonState != Winsta_WaitForShutdown) &&
+ (pGlobals->WinlogonState != Winsta_InShutdownDlg) )
+ {
+ PriorState = pGlobals->WinlogonState;
+ pGlobals->WinlogonState = Winsta_WaitForLogoff;
+ DebugLog((DEB_TRACE_STATE, "WinsrvNotify: Setting state to %s\n",
+ GetState(Winsta_WaitForLogoff)));
+
+ pGlobals->LastGinaRet = LogoffFlagsToWlxCode(pGlobals->LogoffFlags);
+ DebugLog((DEB_TRACE, "Setting lastginaret to %s\n",
+ WlxName(pGlobals->LastGinaRet)));
+
+ LogoffResult = InitiateLogoff( pGlobals,
+ (pGlobals->LogoffFlags & EWX_FORCE) |
+ StoredFlagsFromRealFlags(pGlobals->LogoffFlags)
+ );
+
+ if (LogoffResult == DLG_FAILURE)
+ {
+ DebugLog((DEB_TRACE, "Logoff refused, resetting\n"));
+ pGlobals->WinlogonState = PriorState;
+ DebugLog((DEB_TRACE_STATE, "WinsrvNotify: resetting state back to %s\n",
+ GetState(PriorState)));
+ }
+ }
+
+}
diff --git a/private/windows/gina/winlogon/wlxutil.c b/private/windows/gina/winlogon/wlxutil.c
new file mode 100644
index 000000000..f2bb9f72e
--- /dev/null
+++ b/private/windows/gina/winlogon/wlxutil.c
@@ -0,0 +1,1203 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: wlxutil.c
+//
+// Contents: WLX helper functions
+//
+// Classes:
+//
+// Functions:
+//
+// History: 8-24-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+char * StateNames[] = {"Preload", "Initialize", "NoOne", "NoOne_Display",
+ "NoOne_SAS", "LoggedOnUser_StartShell", "LoggedOnUser",
+ "LoggedOn_SAS", "Locked", "Locked_Display", "Locked_SAS",
+ "WaitForLogoff", "WaitForShutdown", "Shutdown" };
+#endif
+
+
+WLX_DISPATCH_VERSION_1_1 WlxDispatchTable = {
+ WlxUseCtrlAltDel,
+ WlxSetContextPointer,
+ WlxSasNotify,
+ WlxSetTimeout,
+ WlxAssignShellProtection,
+ WlxMessageBox,
+ WlxDialogBox,
+ WlxDialogBoxParam,
+ WlxDialogBoxIndirect,
+ WlxDialogBoxIndirectParam,
+ WlxSwitchDesktopToUser,
+ WlxSwitchDesktopToWinlogon,
+ WlxChangePasswordNotify,
+ WlxGetSourceDesktop,
+ WlxSetReturnDesktop,
+ WlxCreateUserDesktop,
+ WlxChangePasswordNotifyEx };
+
+
+
+typedef struct _WindowMapper {
+ DWORD fMapper;
+ HWND hWnd;
+ DLGPROC DlgProc;
+ struct _WindowMapper * pPrev;
+ LPARAM InitialParameter;
+} WindowMapper, * PWindowMapper;
+#define MAPPERFLAG_ACTIVE 1
+#define MAPPERFLAG_DIALOG 2
+#define MAPPERFLAG_SAS 4
+#define MAPPERFLAG_WINLOGON 8
+
+#define MAX_WINDOW_MAPPERS 32
+
+WindowMapper Mappers[MAX_WINDOW_MAPPERS];
+DWORD cActiveWindow;
+DWORD PendingSasEvents[MAX_WINDOW_MAPPERS];
+DWORD PendingSasHead;
+DWORD PendingSasTail;
+
+void
+InitWindowMappers()
+{
+ ZeroMemory(Mappers, sizeof(WindowMapper) * MAX_WINDOW_MAPPERS);
+ cActiveWindow = 0;
+ PendingSasHead = 0;
+ PendingSasTail = 0;
+}
+
+PWindowMapper
+LocateTopMappedWindow(void)
+{
+ int i;
+ for (i = 0; i < MAX_WINDOW_MAPPERS ; i++ )
+ {
+ if (Mappers[i].fMapper & MAPPERFLAG_SAS)
+ {
+ return(&Mappers[i]);
+ }
+ }
+
+ return(NULL);
+
+}
+
+PWindowMapper
+AllocWindowMapper(void)
+{
+ int i;
+ PWindowMapper pMap;
+
+ for (i = 0 ; i < MAX_WINDOW_MAPPERS ; i++ )
+ {
+ if ((Mappers[i].fMapper & MAPPERFLAG_ACTIVE) == 0)
+ {
+ cActiveWindow ++;
+ pMap = LocateTopMappedWindow();
+ if (pMap)
+ {
+ FLAG_OFF(pMap->fMapper, MAPPERFLAG_SAS);
+ }
+
+ Mappers[i].hWnd = NULL;
+ FLAG_ON(Mappers[i].fMapper, MAPPERFLAG_ACTIVE | MAPPERFLAG_SAS);
+ Mappers[i].pPrev = pMap;
+
+ return(&Mappers[i]);
+ }
+ }
+ return(NULL);
+}
+
+PWindowMapper
+LocateWindowMapper(HWND hWnd)
+{
+ int i;
+
+ for (i = 0; i < MAX_WINDOW_MAPPERS ; i++ )
+ {
+ if (Mappers[i].hWnd == hWnd)
+ {
+ return(&Mappers[i]);
+ }
+ }
+
+ return(NULL);
+}
+
+void
+FreeWindowMapper(PWindowMapper pMap)
+{
+ pMap->hWnd = NULL;
+ pMap->DlgProc = NULL;
+ if (pMap->fMapper & MAPPERFLAG_SAS)
+ {
+ if (pMap->pPrev)
+ {
+ FLAG_ON(pMap->pPrev->fMapper, MAPPERFLAG_SAS);
+ }
+ }
+ pMap->fMapper = 0;
+ pMap->pPrev = NULL;
+ cActiveWindow--;
+}
+
+HWND
+LocateTopWindow(VOID)
+{
+ PWindowMapper pMap;
+
+ pMap = LocateTopMappedWindow();
+ if (pMap)
+ {
+ return(pMap->hWnd);
+ }
+ return(NULL);
+}
+
+BOOL
+SetMapperFlag(
+ HWND hWnd,
+ DWORD Flag
+ )
+{
+ PWindowMapper pMap;
+
+ pMap = LocateWindowMapper(hWnd);
+ if (!pMap)
+ {
+ return(FALSE);
+ }
+
+ pMap->fMapper |= Flag;
+
+ return(TRUE);
+
+}
+
+
+BOOL
+QueueSasEvent(
+ DWORD dwSasType)
+{
+ if (((PendingSasTail + 1) % MAX_WINDOW_MAPPERS) == PendingSasHead)
+ {
+ return(FALSE);
+ }
+
+ PendingSasEvents[PendingSasTail] = dwSasType;
+ PendingSasTail ++;
+ PendingSasTail %= MAX_WINDOW_MAPPERS;
+
+ return(TRUE);
+}
+
+BOOL
+FetchPendingSas(
+ PDWORD pSasType)
+{
+ if (PendingSasHead == PendingSasTail)
+ {
+ return(FALSE);
+ }
+ *pSasType = PendingSasEvents[PendingSasHead++];
+ PendingSasHead %= MAX_WINDOW_MAPPERS;
+ return(TRUE);
+}
+
+BOOL
+TestPendingSas(VOID)
+{
+ return (PendingSasHead == PendingSasTail);
+}
+
+VOID
+EnableSasMessages(HWND hWnd)
+{
+ DWORD SasType;
+
+ SasMessages = TRUE;
+ while (FetchPendingSas(&SasType))
+ {
+ if (hWnd)
+ {
+#if DBG
+ DebugLog((DEB_TRACE, "Posting queued Sas %d to window %x\n",
+ SasType, hWnd ));
+#endif
+
+ PostMessage(hWnd, WLX_WM_SAS, (WPARAM) SasType, 0);
+ }
+ }
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: RootWndProc
+//
+// Synopsis: This is the base window proc for all testgina windows.
+//
+// Arguments: [hWnd] --
+// [Message] --
+// [wParam] --
+// [lParam] --
+//
+// History: 7-18-94 RichardW Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+CALLBACK
+RootDlgProc(
+ HWND hWnd,
+ UINT Message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ PWindowMapper pMap;
+ int res;
+ BOOLEAN bRet;
+
+ //
+ // If this is a WM_INITDIALOG message, then the parameter is the mapping,
+ // which needs to have a hwnd associated with it. Otherwise, do the normal
+ // preprocessing.
+ //
+ if (Message == WM_INITDIALOG)
+ {
+ pMap = (PWindowMapper) lParam;
+ pMap->hWnd = hWnd;
+ SetTopTimeout(hWnd);
+ lParam = pMap->InitialParameter;
+ //
+ // Now that everything is done, enable sas messages again. This
+ // protects us from people pounding on the c-a-d keys, when our response
+ // time is slow, e.g. due to stress. We also drain the queue of pending
+ // SAS events.
+ //
+ EnableSasMessages(hWnd);
+ }
+ else
+ {
+ pMap = LocateWindowMapper(hWnd);
+ if (!pMap)
+ {
+ return(FALSE);
+ }
+ }
+
+ if (Message == WLX_WM_SAS &&
+ ((pMap->fMapper & MAPPERFLAG_WINLOGON) == 0))
+ {
+ if ((wParam == WLX_SAS_TYPE_TIMEOUT) ||
+ (wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) )
+ {
+ DebugLog((DEB_TRACE, "Sending timeout to top window.\n"));
+ }
+ }
+
+ bRet = pMap->DlgProc(hWnd, Message, wParam, lParam);
+ if (!bRet)
+ {
+ if (Message == WM_INITDIALOG)
+ {
+ return(bRet);
+ }
+ if (Message == WLX_WM_SAS)
+ {
+ if ((pMap->fMapper & MAPPERFLAG_WINLOGON) == 0)
+ {
+ //
+ // Re-enable the messages
+ EnableSasMessages(pMap->hWnd);
+
+ }
+ switch (wParam)
+ {
+ case WLX_SAS_TYPE_CTRL_ALT_DEL:
+ default:
+ res = WLX_DLG_SAS;
+ break;
+
+ case WLX_SAS_TYPE_TIMEOUT:
+ res = WLX_DLG_INPUT_TIMEOUT;
+ break;
+ case WLX_SAS_TYPE_SCRNSVR_TIMEOUT:
+ res = WLX_DLG_SCREEN_SAVER_TIMEOUT;
+ break;
+ case WLX_SAS_TYPE_USER_LOGOFF:
+ res = WLX_DLG_USER_LOGOFF;
+ break;
+ }
+ if (res)
+ {
+ EndDialog(hWnd, res);
+ bRet = TRUE;
+ }
+ }
+ }
+ else
+ {
+ if (Message == WLX_WM_SAS &&
+ ((pMap->fMapper & MAPPERFLAG_WINLOGON) == 0))
+ {
+ //
+ // Re-enable the messages
+ //
+ EnableSasMessages(pMap->hWnd);
+
+ switch (wParam)
+ {
+ case WLX_SAS_TYPE_TIMEOUT:
+ res = WLX_DLG_INPUT_TIMEOUT;
+ break;
+
+ case WLX_SAS_TYPE_SCRNSVR_TIMEOUT:
+ res = WLX_DLG_SCREEN_SAVER_TIMEOUT;
+ break;
+
+ case WLX_SAS_TYPE_USER_LOGOFF:
+ res = WLX_DLG_USER_LOGOFF;
+ break;
+
+ default:
+ res = 0;
+ break;
+ }
+
+ if (res)
+ {
+ DebugLog((DEB_TRACE, "Gina ate the SAS (%d) message, but ending it anyway.\n", wParam));
+ EndDialog(hWnd, res);
+ }
+
+ }
+ }
+
+ return(bRet);
+
+}
+
+VOID
+ChangeStateForSAS(PGLOBALS pGlobals)
+{
+#if DBG
+ WinstaState State = pGlobals->WinlogonState;
+#endif
+ if ((pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) &&
+ (pGlobals->SasType == WLX_SAS_TYPE_TIMEOUT) )
+ {
+ DebugLog((DEB_TRACE, "SAS was a timeout, no state change\n"));
+ return;
+ }
+ switch (pGlobals->WinlogonState)
+ {
+ case Winsta_NoOne:
+ case Winsta_NoOne_Display:
+ pGlobals->WinlogonState = Winsta_NoOne_SAS;
+ break;
+
+ case Winsta_Locked:
+ case Winsta_Locked_Display:
+ pGlobals->WinlogonState = Winsta_Locked_SAS;
+ break;
+
+ case Winsta_LoggedOnUser:
+ case Winsta_LoggedOnUser_StartShell:
+ pGlobals->WinlogonState = Winsta_LoggedOn_SAS;
+ break;
+
+ case Winsta_WaitForLogoff:
+ case Winsta_WaitForShutdown:
+ case Winsta_InShutdownDlg:
+ break;
+
+ default:
+ DebugLog((DEB_ERROR, "Don't know how to get to next state from %d, %s\n",
+ pGlobals->WinlogonState, GetState(pGlobals->WinlogonState)));
+ }
+#if DBG
+ DebugLog((DEB_TRACE, "ChangeStateForSAS: Went from %d (%s) to %d (%s)\n",
+ State, GetState(State), pGlobals->WinlogonState,
+ GetState(pGlobals->WinlogonState) ));
+#endif
+}
+
+
+BOOL
+SendSasToTopWindow(
+ PGLOBALS pGlobals,
+ DWORD SasType)
+{
+ PWindowMapper pMap;
+#if DBG
+ WCHAR WindowName[32];
+#endif
+
+ if (cActiveWindow)
+ {
+ if ((pGlobals->WinlogonState == Winsta_InShutdownDlg) &&
+ (SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT))
+ {
+ return(TRUE);
+ }
+
+ pMap = LocateTopMappedWindow();
+
+ if (!pMap)
+ {
+ return(FALSE);
+ }
+
+ if ( ( SasType > WLX_SAS_TYPE_MAX_MSFT_VALUE) ||
+ ( SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) ||
+ ( SasType == WLX_SAS_TYPE_TIMEOUT) )
+ {
+ //
+ // Either a timeout (which we have to forward), or a private
+ // which we have to forward. Kill any message boxes
+ //
+ if (KillMessageBox( SasType ))
+ {
+ DebugLog((DEB_TRACE, "Killed a pending message box\n"));
+ }
+ }
+
+#if DBG
+ GetWindowText( pMap->hWnd, WindowName, 32 );
+ DebugLog((DEB_TRACE, "Sending SAS code %d to window %x (%ws) \n", SasType, pMap->hWnd, WindowName ));
+
+#endif
+
+
+ PostMessage(pMap->hWnd, WLX_WM_SAS, (WPARAM) SasType, 0);
+
+ //
+ // This will cause them to be queued, and then handled later.
+ //
+ DisableSasMessages();
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+
+
+
+VOID
+DestroyMprInfo(
+ PWLX_MPR_NOTIFY_INFO pMprInfo)
+{
+ if (pMprInfo->pszUserName)
+ {
+ LocalFree(pMprInfo->pszUserName);
+ }
+
+ if (pMprInfo->pszDomain)
+ {
+ LocalFree(pMprInfo->pszDomain);
+ }
+
+ if (pMprInfo->pszPassword)
+ {
+ ZeroMemory(pMprInfo->pszPassword, wcslen(pMprInfo->pszPassword) * 2);
+ LocalFree(pMprInfo->pszPassword);
+ }
+
+ if (pMprInfo->pszOldPassword)
+ {
+ ZeroMemory(pMprInfo->pszOldPassword, wcslen(pMprInfo->pszOldPassword) * 2);
+ LocalFree(pMprInfo->pszOldPassword);
+ }
+}
+
+
+
+
+
+
+
+
+
+VOID
+WINAPI
+WlxUseCtrlAltDel(
+ HANDLE hWlx)
+{
+ PGLOBALS pGlobals;
+
+ if (pGlobals = VerifyHandle(hWlx))
+ {
+ pGlobals->ForwardCAD = TRUE;
+ }
+}
+
+VOID
+WINAPI
+WlxSetContextPointer(
+ HANDLE hWlx,
+ PVOID pWlxContext
+ )
+{
+ PGLOBALS pGlobals;
+
+ if (pGlobals = VerifyHandle(hWlx))
+ {
+ pGlobals->pGina->pGinaContext = pWlxContext;
+ }
+
+}
+
+VOID
+WINAPI
+WlxSasNotify(
+ HANDLE hWlx,
+ DWORD SasType
+ )
+{
+ PGLOBALS pGlobals;
+
+ if (pGlobals = VerifyHandle(hWlx))
+ {
+ switch (SasType)
+ {
+ case WLX_SAS_TYPE_USER_LOGOFF:
+ case WLX_SAS_TYPE_TIMEOUT:
+ case WLX_SAS_TYPE_SCRNSVR_TIMEOUT:
+ DebugLog((DEB_ERROR, "Illegal SAS Type (%d) passed to WlxSasNotify\n", SasType ));
+ return;
+
+ default:
+ SASRouter(pGlobals, SasType);
+ }
+ }
+}
+
+BOOL
+WINAPI
+WlxSetTimeout(
+ HANDLE hWlx,
+ DWORD Timeout
+ )
+{
+ PGLOBALS pGlobals;
+
+ if (pGlobals = VerifyHandle(hWlx))
+ {
+ if ((pGlobals->WinlogonState == Winsta_NoOne_Display) ||
+ (pGlobals->WinlogonState == Winsta_Locked_Display) )
+ {
+ if (Timeout)
+ {
+ SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);
+ return(FALSE);
+ }
+ }
+ pGlobals->pGina->cTimeout = Timeout;
+ TimeoutUpdateTopTimeout( Timeout );
+ return(TRUE);
+ }
+
+ SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);
+ return(FALSE);
+
+}
+
+int
+WINAPI
+WlxAssignShellProtection(
+ HANDLE hWlx,
+ HANDLE hToken,
+ HANDLE hProcess,
+ HANDLE hThread
+ )
+{
+ PGLOBALS pGlobals;
+ PTOKEN_DEFAULT_DACL pDefDacl;
+ DWORD cDefDacl = 0;
+ NTSTATUS Status;
+ PSECURITY_DESCRIPTOR psd;
+ unsigned char buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ BOOL Success;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ Status = NtQueryInformationToken(hToken, TokenDefaultDacl, NULL, 0, &cDefDacl);
+ if (!NT_SUCCESS(Status) && ( Status != STATUS_BUFFER_TOO_SMALL ))
+ {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+
+ pDefDacl = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cDefDacl);
+ if (!pDefDacl)
+ {
+ return(ERROR_OUTOFMEMORY);
+ }
+
+ Status = NtQueryInformationToken(hToken, TokenDefaultDacl,
+ pDefDacl, cDefDacl, &cDefDacl);
+
+ if (!NT_SUCCESS(Status))
+ {
+ LocalFree(pDefDacl);
+ return(RtlNtStatusToDosError(Status));
+ }
+
+ psd = (PSECURITY_DESCRIPTOR) buf;
+ InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(psd, TRUE, pDefDacl->DefaultDacl, FALSE);
+
+ Success = SetKernelObjectSecurity(hProcess, DACL_SECURITY_INFORMATION, psd);
+
+ LocalFree(pDefDacl);
+
+ if (Success)
+ {
+ if (SetProcessToken(pGlobals, hProcess, hThread, hToken))
+ return(0);
+ }
+
+ return(GetLastError());
+
+}
+
+
+int WINAPI
+WlxMessageBox(
+ HANDLE hWlx,
+ HWND hWnd,
+ LPWSTR lpsz1,
+ LPWSTR lpsz2,
+ UINT fmb)
+{
+ PGLOBALS pGlobals;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);
+ return(-1);
+ }
+ return(TimeoutMessageBoxlpstr(pGlobals, hWnd, lpsz1, lpsz2, fmb,
+ pGlobals->pGina->cTimeout | TIMEOUT_SS_NOTIFY ) );
+}
+
+int WINAPI
+WlxDialogBox(
+ HANDLE hWlx,
+ HANDLE hInstance,
+ LPWSTR lpsz1,
+ HWND hWnd,
+ DLGPROC dlgproc)
+{
+ return(WlxDialogBoxParam(hWlx, hInstance, lpsz1, hWnd, dlgproc, 0));
+}
+
+int WINAPI
+WlxDialogBoxIndirect(
+ HANDLE hWlx,
+ HANDLE hInstance,
+ LPCDLGTEMPLATE lpTemplate,
+ HWND hWnd,
+ DLGPROC dlgproc)
+{
+ return(WlxDialogBoxIndirectParam(hWlx, hInstance, lpTemplate, hWnd, dlgproc, 0));
+}
+
+
+
+int WINAPI
+WlxDialogBoxParam(
+ HANDLE hWlx,
+ HANDLE hInstance,
+ LPWSTR lpsz1,
+ HWND hWnd,
+ DLGPROC dlgproc,
+ LPARAM lParam)
+{
+ PWindowMapper pMap;
+ PGLOBALS pGlobals;
+ int res;
+
+
+ pMap = AllocWindowMapper();
+ if (!pMap)
+ {
+ ASSERTMSG("Too many nested windows? send mail to richardw", pMap);
+ DebugLog((DEB_ERROR, "Too many nested windows?!?\n"));
+ SetLastError(ERROR_OUTOFMEMORY);
+ return(-1);
+ }
+
+ pMap->InitialParameter = lParam;
+ pMap->DlgProc = dlgproc;
+ pMap->fMapper |= MAPPERFLAG_DIALOG;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);
+ return(-1);
+ }
+
+ //res = DialogBoxParam(hInstance, lpsz1, hWnd, RootDlgProc, (LPARAM) pMap);
+ res = TimeoutDialogBoxParam(pGlobals, hInstance, lpsz1, hWnd,
+ RootDlgProc, (LPARAM) pMap,
+ pGlobals->pGina->cTimeout | TIMEOUT_SS_NOTIFY);
+
+ FreeWindowMapper(pMap);
+
+ return(res);
+}
+
+int WINAPI
+WlxDialogBoxIndirectParam(
+ HANDLE hWlx,
+ HANDLE hInstance,
+ LPCDLGTEMPLATE lpTemplate,
+ HWND hWnd,
+ DLGPROC dlgproc,
+ LPARAM lParam)
+{
+ PWindowMapper pMap;
+ int res;
+
+
+ pMap = AllocWindowMapper();
+ if (!pMap)
+ {
+ ASSERTMSG("Too many nested windows? send mail to richardw", pMap);
+ DebugLog((DEB_ERROR, "Too many nested windows?!?\n"));
+ SetLastError(ERROR_OUTOFMEMORY);
+ return(-1);
+ }
+
+ pMap->InitialParameter = lParam;
+ pMap->DlgProc = dlgproc;
+ pMap->fMapper |= MAPPERFLAG_DIALOG;
+
+ res = DialogBoxIndirectParam(hInstance, lpTemplate, hWnd, RootDlgProc, (LPARAM) pMap);
+
+ FreeWindowMapper(pMap);
+
+ return(res);
+}
+
+int WINAPI
+WlxSwitchDesktopToUser(
+ HANDLE hWlx)
+{
+ PGLOBALS pGlobals;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
+ SetThreadDesktop(pGlobals->WindowStation.hdeskApplication);
+
+ return(0);
+
+}
+
+int WINAPI
+WlxSwitchDesktopToWinlogon(
+ HANDLE hWlx)
+{
+ PGLOBALS pGlobals;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
+ SetThreadDesktop(pGlobals->WindowStation.hdeskWinlogon);
+
+ return(0);
+
+}
+
+int WINAPI
+WlxChangePasswordNotify(
+ HANDLE hWlx,
+ PWLX_MPR_NOTIFY_INFO pMprInfo,
+ DWORD dwChangeInfo)
+{
+ PGLOBALS pGlobals;
+ int Result;
+
+ return WlxChangePasswordNotifyEx( hWlx, pMprInfo, dwChangeInfo, NULL, NULL );
+
+
+}
+
+int WINAPI
+WlxChangePasswordNotifyEx(
+ HANDLE hWlx,
+ PWLX_MPR_NOTIFY_INFO pMprInfo,
+ DWORD dwChangeInfo,
+ PWSTR pszProvider,
+ PVOID pvReserved)
+{
+ PGLOBALS pGlobals;
+ int Result;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ Result = MprChangePasswordNotify(
+ pGlobals,
+ LocateTopWindow(),
+ pszProvider,
+ pMprInfo->pszUserName,
+ pMprInfo->pszDomain,
+ pMprInfo->pszPassword,
+ pMprInfo->pszOldPassword,
+ dwChangeInfo,
+ FALSE);
+
+ DestroyMprInfo(pMprInfo);
+
+ if (Result == DLG_SUCCESS)
+ {
+ return(0);
+ }
+ else
+ return(ERROR_INVALID_PARAMETER);
+
+}
+
+BOOL
+WINAPI
+WlxGetSourceDesktop(
+ HANDLE hWlx,
+ PWLX_DESKTOP * ppDesktop)
+{
+ PGLOBALS pGlobals;
+ DWORD len;
+ PWLX_DESKTOP pDesktop;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ SetLastError(ERROR_INVALID_HANDLE);
+ return( FALSE );
+ }
+
+ if (pGlobals->WindowStation.pszDesktop)
+ {
+ len = (wcslen(pGlobals->WindowStation.pszDesktop) + 1) * sizeof(WCHAR);
+ }
+ else
+ {
+ len = 0;
+ }
+
+ pDesktop = LocalAlloc( LMEM_FIXED, sizeof(WLX_DESKTOP) + len );
+
+ if (!pDesktop)
+ {
+ return( FALSE );
+ }
+
+ pDesktop->Size = sizeof(WLX_DESKTOP);
+ pDesktop->Flags = WLX_DESKTOP_NAME;
+ pDesktop->hDesktop = NULL;
+ pDesktop->pszDesktopName = (PWSTR) (pDesktop + 1);
+ if (len)
+ {
+ wcscpy( pDesktop->pszDesktopName, pGlobals->WindowStation.pszDesktop );
+ }
+
+ *ppDesktop = pDesktop;
+
+ return( TRUE );
+}
+
+BOOL
+WINAPI
+WlxSetReturnDesktop(
+ HANDLE hWlx,
+ PWLX_DESKTOP pDesktop)
+{
+ PGLOBALS pGlobals;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ SetLastError(ERROR_INVALID_HANDLE);
+ return( FALSE );
+ }
+
+ if ((pDesktop->Size != sizeof(WLX_DESKTOP)) ||
+ ((pDesktop->Flags & (WLX_DESKTOP_HANDLE | WLX_DESKTOP_NAME)) == 0) )
+ {
+ DebugLog((DEB_ERROR, "Invalid desktop\n"));
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return( FALSE );
+ }
+
+
+ return( SetReturnDesktop( &pGlobals->WindowStation, pDesktop ) );
+
+}
+
+BOOL
+WINAPI
+WlxCreateUserDesktop(
+ HANDLE hWlx,
+ HANDLE hToken,
+ DWORD Flags,
+ PWSTR pszDesktopName,
+ PWLX_DESKTOP * ppDesktop)
+{
+ PGLOBALS pGlobals;
+ PTOKEN_GROUPS pGroups;
+ PTOKEN_USER pUser;
+ DWORD Needed;
+ NTSTATUS Status;
+ DWORD i;
+ PSID pSid;
+ PWLX_DESKTOP pDesktop;
+
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ SetLastError(ERROR_INVALID_HANDLE);
+ return( FALSE );
+ }
+
+ if (((Flags & (WLX_CREATE_INSTANCE_ONLY | WLX_CREATE_USER)) == 0 ) ||
+ ((Flags & (WLX_CREATE_INSTANCE_ONLY | WLX_CREATE_USER)) ==
+ (WLX_CREATE_INSTANCE_ONLY | WLX_CREATE_USER) ) )
+ {
+ DebugLog((DEB_ERROR, "Invalid flags\n"));
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return( FALSE );
+ }
+
+ pGroups = NULL;
+ pUser = NULL;
+ pSid = NULL;
+
+ if ( Flags & WLX_CREATE_INSTANCE_ONLY )
+ {
+ Status = NtQueryInformationToken( hToken,
+ TokenGroups,
+ NULL,
+ 0,
+ &Needed );
+
+ if ( Status != STATUS_BUFFER_TOO_SMALL )
+ {
+ SetLastError( RtlNtStatusToDosError( Status ) );
+ return( FALSE );
+ }
+
+ pGroups = (PTOKEN_GROUPS) LocalAlloc( LMEM_FIXED, Needed );
+
+ if ( !pGroups )
+ {
+ return( FALSE );
+ }
+
+ Status = NtQueryInformationToken( hToken,
+ TokenGroups,
+ pGroups,
+ Needed,
+ &Needed );
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+ LocalFree( pGroups );
+ SetLastError( RtlNtStatusToDosError( Status ) );
+ return( FALSE );
+ }
+
+ for (i = 0 ; i < pGroups->GroupCount ; i++ )
+ {
+ if ( pGroups->Groups[i].Attributes & SE_GROUP_LOGON_ID )
+ {
+ pSid = pGroups->Groups[i].Sid;
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ Status = NtQueryInformationToken( hToken,
+ TokenUser,
+ NULL,
+ 0,
+ &Needed );
+
+ if ( Status != STATUS_BUFFER_TOO_SMALL )
+ {
+ SetLastError( RtlNtStatusToDosError( Status ) );
+ return( FALSE );
+ }
+
+ pUser = (PTOKEN_USER) LocalAlloc( LMEM_FIXED, Needed );
+
+ if ( !pUser )
+ {
+ return( FALSE );
+ }
+
+ Status = NtQueryInformationToken( hToken,
+ TokenUser,
+ pUser,
+ Needed,
+ &Needed );
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+ LocalFree( pUser );
+ SetLastError( RtlNtStatusToDosError( Status ) );
+ return( FALSE );
+ }
+
+ pSid = pUser->User.Sid;
+
+ }
+
+ if ( !pSid )
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto CleanUp;
+ }
+
+ //
+ // Okay, we have the right SID now, so create the desktop.
+ //
+
+ Needed = sizeof( WLX_DESKTOP ) + (wcslen( pszDesktopName ) + 1 ) * sizeof(WCHAR);
+
+ pDesktop = (PWLX_DESKTOP) LocalAlloc( LMEM_FIXED, Needed );
+
+ if ( !pDesktop )
+ {
+ goto CleanUp;
+ }
+
+ pDesktop->Size = sizeof( WLX_DESKTOP );
+ pDesktop->Flags = WLX_DESKTOP_NAME;
+ pDesktop->hDesktop = NULL;
+ pDesktop->pszDesktopName = (PWSTR) (pDesktop + 1);
+
+ wcscpy( pDesktop->pszDesktopName, pszDesktopName );
+
+ pDesktop->hDesktop = CreateDesktop( pszDesktopName,
+ NULL, NULL, 0, MAXIMUM_ALLOWED, NULL);
+
+ if ( !pDesktop->hDesktop )
+ {
+ goto CleanUp;
+ }
+
+ if (!SetUserDesktopSecurity(pDesktop->hDesktop,
+ pSid, pWinlogonSid ) )
+ {
+ goto CleanUp;
+ }
+
+ if (!AddUserToWinsta( &pGlobals->WindowStation,
+ pSid,
+ hToken ) )
+ {
+ goto CleanUp;
+ }
+
+ *ppDesktop = pDesktop;
+ pDesktop->Flags |= WLX_DESKTOP_HANDLE;
+
+ if ( pGroups )
+ {
+ LocalFree( pGroups );
+ }
+
+ if ( pUser )
+ {
+ LocalFree( pUser );
+ }
+
+ return( TRUE );
+
+
+CleanUp:
+
+ if ( pDesktop )
+ {
+ if ( pDesktop->hDesktop )
+ {
+ CloseDesktop( pDesktop->hDesktop );
+ }
+
+ LocalFree( pDesktop );
+ }
+
+ if ( pGroups )
+ {
+ LocalFree( pGroups );
+ }
+
+ if ( pUser )
+ {
+ LocalFree( pUser );
+ }
+
+ return( FALSE );
+
+}
+
+BOOL
+WINAPI
+WlxCloseUserDesktop(
+ HANDLE hWlx,
+ PWLX_DESKTOP pDesktop,
+ HANDLE hToken )
+{
+ PGLOBALS pGlobals;
+
+ if (!(pGlobals = VerifyHandle(hWlx)))
+ {
+ DebugLog((DEB_ERROR, "Invalid hWlx handle\n"));
+ SetLastError(ERROR_INVALID_HANDLE);
+ return( FALSE );
+ }
+
+ if ( RemoveUserFromWinsta( &pGlobals->WindowStation, hToken ) )
+ {
+ return( CloseDesktop( pDesktop->hDesktop ) );
+ }
+
+ return( FALSE );
+}
diff --git a/private/windows/gina/winlogon/wlxutil.h b/private/windows/gina/winlogon/wlxutil.h
new file mode 100644
index 000000000..212a3973a
--- /dev/null
+++ b/private/windows/gina/winlogon/wlxutil.h
@@ -0,0 +1,70 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: wlxutil.h
+//
+// Contents:
+//
+// Classes:
+//
+// Functions:
+//
+// History: 8-24-94 RichardW Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef _WLXUTIL_H_
+#define _WLXUTIL_H_
+
+
+VOID WINAPI WlxUseCtrlAltDel(HANDLE);
+VOID WINAPI WlxSasNotify(HANDLE, DWORD);
+VOID WINAPI WlxSetContextPointer(HANDLE, PVOID);
+BOOL WINAPI WlxSetTimeout(HANDLE, DWORD);
+int WINAPI WlxAssignShellProtection(HANDLE, HANDLE, HANDLE, HANDLE);
+int WINAPI WlxMessageBox(HANDLE, HWND, LPWSTR, LPWSTR, UINT);
+int WINAPI WlxDialogBox(HANDLE, HANDLE, LPWSTR, HWND, DLGPROC);
+int WINAPI WlxDialogBoxIndirect(HANDLE, HANDLE, LPCDLGTEMPLATE, HWND, DLGPROC);
+int WINAPI WlxDialogBoxParam(HANDLE, HANDLE, LPWSTR, HWND, DLGPROC, LPARAM);
+int WINAPI WlxDialogBoxIndirectParam(HANDLE, HANDLE, LPCDLGTEMPLATE, HWND, DLGPROC, LPARAM);
+int WINAPI WlxSwitchDesktopToUser(HANDLE);
+int WINAPI WlxSwitchDesktopToWinlogon(HANDLE);
+int WINAPI WlxChangePasswordNotify(HANDLE, PWLX_MPR_NOTIFY_INFO, DWORD);
+BOOL WINAPI WlxGetSourceDesktop(HANDLE, PWLX_DESKTOP *);
+BOOL WINAPI WlxSetReturnDesktop(HANDLE, PWLX_DESKTOP);
+BOOL WINAPI WlxCreateUserDesktop(HANDLE, HANDLE, DWORD, PWSTR, PWLX_DESKTOP *);
+int WINAPI WlxChangePasswordNotifyEx( HANDLE, PWLX_MPR_NOTIFY_INFO, DWORD, PWSTR, PVOID);
+
+extern WLX_DISPATCH_VERSION_1_0 OldWlxDispatchTable;
+extern WLX_DISPATCH_VERSION_1_1 WlxDispatchTable;
+
+
+void
+SASRouter( PGLOBALS pGlobals,
+ DWORD SasType );
+
+BOOL
+SendSasToTopWindow(
+ PGLOBALS pGlobals,
+ DWORD SasType);
+
+VOID
+ChangeStateForSAS(PGLOBALS pGlobals);
+
+#define MAPPERFLAG_WINLOGON 8
+BOOL
+SetMapperFlag(
+ HWND hWnd,
+ DWORD Flag
+ );
+
+VOID
+DestroyMprInfo(
+ PWLX_MPR_NOTIFY_INFO pMprInfo);
+
+DWORD
+LogoffFlagsToWlxCode(DWORD Flags);
+
+#endif