mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
582 lines
13 KiB
582 lines
13 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|