windows-nt/Source/XPSP1/NT/base/ntsetup/textmode/cmdcons/services.c
2020-09-26 16:20:57 +08:00

1444 lines
39 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
services.c
Abstract:
This module implements all access to the services db.
Author:
Wesley Witt (wesw) 21-Oct-1998
Revision History:
--*/
#include "cmdcons.h"
#pragma hdrstop
#include "ntregapi.h"
// forward-decl
BOOLEAN RcFindService(
IN LPCWSTR ServiceName,
OUT HANDLE* KeyHandle
);
BOOLEAN RcFindServiceByDisplayName(
IN HANDLE ServicesKey,
IN LPCWSTR ServiceName,
OUT HANDLE* KeyHandle
);
BOOLEAN RcGetStartType(
IN HANDLE hKey,
OUT DWORD *start_type
);
BOOLEAN RcSetStartType(
IN HANDLE hKey,
OUT DWORD start_type
);
BOOLEAN RcPrintStartType(
IN ULONG msg_id,
IN DWORD start_type
);
RcOpenHive(
PWSTR szHiveName,
PWSTR szHiveKey
);
BOOLEAN
RcCloseHive(
PWSTR szHiveKey
);
BOOLEAN RcOpenSystemHive();
BOOLEAN RcCloseSystemHive();
BOOLEAN RcDetermineCorrectControlKey(
OUT DWORD * pCorrectKey
);
ULONG
RcCmdEnableService(
IN PTOKENIZED_LINE TokenizedLine
)
/*++
Routine Description:
Top-level routine supporting the enable command in the setup diagnostic
command interpreter.
Arguments:
TokenizedLine - supplies structure built by the line parser describing
each string on the line as typed by the user.
Return Value:
None.
--*/
{
DWORD correctKey = 0;
DWORD new_start_type = 4;
DWORD start_type = 0;
HANDLE hkey = 0;
ASSERT(TokenizedLine->TokenCount >= 1);
// there should be three tokens,
// enable_service
// the name of the service/driver to be enabled
// the start_type of the service
if (RcCmdParseHelp( TokenizedLine, MSG_SERVICE_ENABLE_HELP )) {
return 1;
}
if(TokenizedLine->TokenCount == 2) {
// just display the current setting
RcOpenSystemHive();
if( RcFindService( TokenizedLine->Tokens->Next->String, &hkey ) ) {
RcMessageOut( MSG_SERVICE_FOUND, TokenizedLine->Tokens->Next->String );
if( RcGetStartType(hkey, &start_type ) ) {
RcPrintStartType( MSG_SERVICE_CURRENT_STATE, start_type );
RcMessageOut( MSG_START_TYPE_NOT_SPECIFIED );
}
} else {
RcMessageOut( MSG_SERVICE_NOT_FOUND, TokenizedLine->Tokens->Next->String );
}
NtClose( hkey );
RcCloseSystemHive();
} else if(TokenizedLine->TokenCount == 3) {
// change the setting
RcOpenSystemHive();
if( RcFindService( TokenizedLine->Tokens->Next->String, &hkey ) ) {
RcMessageOut( MSG_SERVICE_FOUND, TokenizedLine->Tokens->Next->String );
// we found it - open and retrieve the start type
if( RcGetStartType(hkey, &start_type ) ) {
if( !_wcsicmp( TokenizedLine->Tokens->Next->Next->String, L"SERVICE_BOOT_START" ) ) {
new_start_type = 0;
} else if( !_wcsicmp( TokenizedLine->Tokens->Next->Next->String, L"SERVICE_SYSTEM_START" ) ) {
new_start_type = 1;
} else if( !_wcsicmp( TokenizedLine->Tokens->Next->Next->String, L"SERVICE_AUTO_START" ) ) {
new_start_type = 2;
} else if( !_wcsicmp( TokenizedLine->Tokens->Next->Next->String, L"SERVICE_DEMAND_START" ) ) {
new_start_type = 3;
} else {
new_start_type = -1;
}
if( new_start_type == start_type ) {
// the service is already in the state
RcPrintStartType( MSG_SERVICE_SAME_STATE, start_type );
} else if( new_start_type != -1 ) {
// print the old start type
RcPrintStartType( MSG_SERVICE_CURRENT_STATE, start_type );
// setup the service
if( RcSetStartType( hkey, new_start_type ) ) {
RcPrintStartType( MSG_SERVICE_CHANGE_STATE, new_start_type );
}
} else {
RcMessageOut( MSG_SERVICE_ENABLE_SYNTAX_ERROR );
}
}
// close the key
NtClose( hkey );
} else {
// we couldn't find the service - report an error
RcMessageOut( MSG_SERVICE_NOT_FOUND, TokenizedLine->Tokens->Next->String );
}
RcCloseSystemHive();
} else {
// oops, we didn't get two or three parameters, print a help string.
RcMessageOut( MSG_SERVICE_ENABLE_HELP );
}
return 1;
}
ULONG
RcCmdDisableService(
IN PTOKENIZED_LINE TokenizedLine
)
/*++
Routine Description:
Top-level routine supporting the disable command in the setup diagnostic
command interpreter.
Arguments:
TokenizedLine - supplies structure built by the line parser describing
each string on the line as typed by the user.
Return Value:
None.
--*/
{
HANDLE hkey;
DWORD start_type;
WCHAR start_type_string[10];
PLINE_TOKEN Token;
BOOL syntaxError = FALSE;
BOOL doHelp = FALSE;
LPCWSTR Arg;
if (RcCmdParseHelp( TokenizedLine, MSG_SERVICE_DISABLE_HELP )) {
return 1;
}
RtlZeroMemory( (VOID *)&start_type_string, sizeof( WCHAR ) * 10 );
// the command will print the old start_type of the
// service before it asks for verification to disable it.
if(TokenizedLine->TokenCount == 2) {
// find the service key
RcOpenSystemHive();
if( RcFindService( TokenizedLine->Tokens->Next->String, &hkey ) ) {
RcMessageOut( MSG_SERVICE_FOUND, TokenizedLine->Tokens->Next->String );
// we found it - open and retrieve the start type
if( RcGetStartType(hkey, &start_type ) ) {
if( start_type != SERVICE_DISABLED ) {
// print the old start type
RcPrintStartType( MSG_SERVICE_CURRENT_STATE, start_type );
// disable the service
if( RcSetStartType( hkey, SERVICE_DISABLED ) ) {
RcPrintStartType( MSG_SERVICE_CHANGE_STATE, SERVICE_DISABLED );
}
} else {
RcMessageOut( MSG_SERVICE_ALREADY_DISABLED, TokenizedLine->Tokens->Next->String );
}
}
// close the key
NtClose( hkey );
} else {
// we couldn't find the service - report an error
RcMessageOut( MSG_SERVICE_NOT_FOUND, TokenizedLine->Tokens->Next->String );
}
RcCloseSystemHive();
} else {
// oops, we didn't get two parameters, print a help string.
RcMessageOut( MSG_SERVICE_DISABLE_HELP );
}
return 1;
}
BOOLEAN
RcFindService(
IN LPCWSTR ServiceName,
OUT PHANDLE KeyHandle
)
/*++
Routine Description:
Attempts to find and open the registry key for a particular
service by its key name in
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services.
If it fails, it will call RcFindServiceByDisplayName() to
locate the service by the DisplayName string value.
Arguments:
ServiceName - the name of the service as a wstring.
KeyHandle - pointer to a HANDLE where the function should
return the open registry handle.
this handle needs to be closed when the key is no
longer needed.
Return Value:
TRUE indicates sucess.
FALSE indicates that it couldn't find the service or failure.
--*/
{
NTSTATUS Status;
WCHAR RegPath[ MAX_PATH ];
OBJECT_ATTRIBUTES Obja;
DWORD correctKey;
UNICODE_STRING ServiceString;
HANDLE ServiceKeyHandle;
// zero out the buffer
RtlZeroMemory( (VOID * )&RegPath,
sizeof( WCHAR ) * MAX_PATH );
// find the correct controlset key
if( !RcDetermineCorrectControlKey( &correctKey ) ) {
return FALSE;
}
// prepend HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services to
// the supplied parameter
swprintf( RegPath, L"\\registry\\machine\\xSYSTEM\\ControlSet%03d\\Services\\", correctKey );
wcscat( RegPath, ServiceName );
// build the unicode string
RtlInitUnicodeString( &ServiceString, RegPath );
InitializeObjectAttributes( &Obja,&ServiceString,
OBJ_CASE_INSENSITIVE, NULL, NULL);
// attempt to open the key.
Status = ZwOpenKey( &ServiceKeyHandle, KEY_ALL_ACCESS, &Obja );
if( NT_SUCCESS( Status) ) {
// if we suceeded, set and return
// the handle.
*KeyHandle = ServiceKeyHandle;
} else {
// build the unicode string
swprintf( RegPath, L"\\registry\\machine\\xSYSTEM\\ControlSet%03d\\Services", correctKey );
RtlInitUnicodeString( &ServiceString, RegPath );
InitializeObjectAttributes( &Obja,&ServiceString,
OBJ_CASE_INSENSITIVE, NULL, NULL);
// open a handle to \\registry\\machine\\xSYSTEM\\ControlSet%03d\\Services
if( NT_SUCCESS( ZwOpenKey( &ServiceKeyHandle, KEY_ALL_ACCESS, &Obja ) ) ) {
if( !RcFindServiceByDisplayName( ServiceKeyHandle, ServiceName, KeyHandle ) ) {
// if we failed, NULL out KeyHandle, and return FALSE.
DEBUG_PRINTF(( "CMDCONS: failed to find key!\n" ));
*KeyHandle = INVALID_HANDLE_VALUE;
if( !NT_SUCCESS( NtClose( ServiceKeyHandle ) ) ) {
DEBUG_PRINTF(( "CMDCONS: failed to close service key handle\n" ));
}
return FALSE;
}
// we found the key!
// close the service key handle
if( !NT_SUCCESS( NtClose( ServiceKeyHandle ) ) ) {
DEBUG_PRINTF(( "CMDCONS: failed to close service key handle\n" ));
}
} else {
DEBUG_PRINTF(( "CMDCONS: failed to open service key handle\n" ));
RcMessageOut( MSG_SYSTEM_MISSING_CURRENT_CONTROLS );
}
}
// return true
return TRUE;
}
// buffersizes
#define sizeof_buffer1 sizeof( KEY_FULL_INFORMATION ) + (MAX_PATH+1) * sizeof( WCHAR )
#define sizeof_buffer2 sizeof( KEY_BASIC_INFORMATION ) + (MAX_PATH+1) * sizeof( WCHAR )
#define sizeof_buffer3 sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + (MAX_PATH+1) * sizeof( WCHAR )
BOOLEAN
RcFindServiceByDisplayName(
IN HANDLE ServicesKey,
IN LPCWSTR ServiceName,
OUT PHANDLE KeyHandle
)
/*++
Routine Description:
Attempts to find and open the registry key for a particular
service by the DisplayName string value.
Arguments:
SevicesKey - an open handle to the correct Services Key to search under
ServiceName - the name of the service as a wstring.
KeyHandle - pointer to a HANDLE where the function should
return the open registry handle.
this handle needs to be closed when the key is no
longer needed.
Return Value:
TRUE indicates sucess.
FALSE indicates that it couldn't find the service or failure.
--*/
{
WCHAR ValueName[] = L"DisplayName";
BYTE buffer1[ sizeof_buffer1 ];
BYTE buffer2[ sizeof_buffer2 ];
BYTE buffer3[ sizeof_buffer3 ];
KEY_FULL_INFORMATION * pKeyFullInfo;
KEY_BASIC_INFORMATION * pKeyBasicInfo;
KEY_VALUE_PARTIAL_INFORMATION * pKeyValuePartialInfo;
ULONG actualBytes;
ULONG loopCount;
ULONG keyCount;
OBJECT_ATTRIBUTES Obja;
HANDLE newHandle;
UNICODE_STRING unicodeString;
BOOL keyFound = FALSE;
// zero out the buffer
RtlZeroMemory( (VOID * ) &(buffer1[0]), sizeof_buffer1 );
pKeyFullInfo= (KEY_FULL_INFORMATION*) &( buffer1[0] );
pKeyBasicInfo = (KEY_BASIC_INFORMATION* ) &( buffer2[0] );
pKeyValuePartialInfo = (KEY_VALUE_PARTIAL_INFORMATION* ) &(buffer3[0]);
// do a ZwQueryKey() to find out the number of subkeys.
if( !NT_SUCCESS( ZwQueryKey( ServicesKey,
KeyFullInformation,
pKeyFullInfo,
sizeof_buffer1,
&actualBytes ) ) ) {
*KeyHandle = INVALID_HANDLE_VALUE;
DEBUG_PRINTF(( "FindServiceByDisplayName: failed to get number of keys!\n" ));
return FALSE;
}
keyCount = pKeyFullInfo->SubKeys;
// loop
for( loopCount = 0; loopCount < keyCount; loopCount++ ) {
// zero out the buffer
RtlZeroMemory( (VOID * ) &(buffer2[0]), sizeof_buffer2 );
// zero out the buffer
RtlZeroMemory( (VOID * ) &(buffer3[0]), sizeof_buffer3 );
// do an ZwEnumerateKey() to find the name of the subkey
ZwEnumerateKey( ServicesKey,
loopCount,
KeyBasicInformation,
pKeyBasicInfo,
sizeof_buffer2,
&actualBytes );
// setup the ZwOpenKey() with the name we just got back
RtlInitUnicodeString( &unicodeString, pKeyBasicInfo->Name );
InitializeObjectAttributes( &Obja, &unicodeString,
OBJ_CASE_INSENSITIVE, ServicesKey, NULL);
// do a ZwOpenKey() to open the key
if( !NT_SUCCESS( ZwOpenKey( &newHandle, KEY_ALL_ACCESS, &Obja ) ) ) {
DEBUG_PRINTF(( "FindServiceByDisplayName: failed to open the subkey?!\n" ));
}
// do a ZwQueryKeyValue() to find the key value DisplayName if it exists
RtlInitUnicodeString( &unicodeString, ValueName );
if( !NT_SUCCESS( ZwQueryValueKey( newHandle,
&unicodeString,
KeyValuePartialInformation,
pKeyValuePartialInfo,
sizeof_buffer3,
&actualBytes
)
)
) {
DEBUG_PRINTF(( "FindServiceByDisplayName: display name get failed\n" ));
} else {
// if the ZwQueryKeyValue() succeeded
if( pKeyValuePartialInfo->Type != REG_SZ ) {
DEBUG_PRINTF(( "FindServiceByDisplayName: paranoia!! mismatched key type?!\n" ));
} else {
// paranoia check SUCCEEDED
// if the value matches, break out of the loop
if( _wcsicmp( (WCHAR*)&(pKeyValuePartialInfo->Data[0]), ServiceName ) == 0 ) {
keyFound = TRUE;
break;
}
}
}
// close the key
if( !NT_SUCCESS( ZwClose( newHandle ) ) ) {
DEBUG_PRINTF(( "FindServiceByDisplayName: Failure closing the handle!!" ));
}
}
// return the handle to the opened key.
if( keyFound == TRUE ) {
*KeyHandle = newHandle;
return TRUE;
}
*KeyHandle = INVALID_HANDLE_VALUE;
return FALSE;
}
BOOLEAN
RcGetStartType(
IN HANDLE hKey,
OUT PULONG start_type
)
/*++
Routine Description:
Given an open service key, gets the start_type of the service.
Arguments:
hKey - a handle to the open service key
start_type - integer indicating the start type of the service
SERVICE_BOOT_START - 0x0
SERVICE_SYSTEM_START - 0x1
SERVICE_AUTO_START - 0x2
SERVUCE_DEMAMD_START - 0x3
SERVICE_DISABLED - 0x4
Return Value:
TRUE indicates sucess.
FALSE indicates failure.
--*/
{
BYTE buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 100 ]; // just grab a bunch of bytes
ULONG resultSize;
KEY_VALUE_PARTIAL_INFORMATION * keyPartialInfo;
UNICODE_STRING StartKey;
WCHAR KEY_NAME[] = L"Start";
RtlZeroMemory( (VOID * )&(buffer[0]),
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 100 );
keyPartialInfo = (KEY_VALUE_PARTIAL_INFORMATION*)&(buffer[0]);
ASSERT( keyPartialInfo );
RtlInitUnicodeString( &StartKey, KEY_NAME );
if( !NT_SUCCESS( ZwQueryValueKey( hKey,
&StartKey,
KeyValuePartialInformation,
keyPartialInfo,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 100,
&resultSize
)
)
) {
DEBUG_PRINTF(( "CMDCONS: start type get failed\n" ));
RcMessageOut( MSG_SERVICE_MISSING_START_KEY );
*start_type = -1;
return FALSE;
}
// paranoia check
if( keyPartialInfo->Type != REG_DWORD ) {
RcMessageOut( MSG_SERVICE_MISSING_START_KEY );
DEBUG_PRINTF(( "CMDCONS: mismatched key type?!\n" ));
*start_type = -1;
return FALSE;
}
*start_type = *( (DWORD*) &(keyPartialInfo->Data[0]) );
return TRUE;
}
BOOLEAN
RcSetStartType(
IN HANDLE hKey,
IN DWORD start_type
)
/*++
Routine Description:
Given an open service key, sets the start_type of the service.
Arguments:
hKey - a handle to the open service key
start_type - integer indicating the start type of the service
SERVICE_BOOT_START - 0x0
SERVICE_SYSTEM_START - 0x1
SERVICE_AUTO_START - 0x2
SERVUCE_DEMAMD_START - 0x3
SERVICE_DISABLED - 0x4
Return Value:
TRUE indicates sucess.
FALSE indicates failure.
--*/
{
UNICODE_STRING StartKey;
RtlInitUnicodeString( &StartKey, L"Start" );
if( NT_SUCCESS( ZwSetValueKey( hKey,
&StartKey,
0,
REG_DWORD,
&start_type,
sizeof( DWORD )
)
)
) {
return TRUE;
}
RcMessageOut( MSG_SERVICE_MISSING_START_KEY );
DEBUG_PRINTF(( "CMDCONS: start type get failed\n" ));
return FALSE;
}
BOOLEAN
RcPrintStartType(
ULONG msg_id,
DWORD start_type
)
/*++
Routine Description:
Prints the start_type.
Arguments:
start_type - integer indicating the start type of the service
SERVICE_BOOT_START - 0x0
SERVICE_SYSTEM_START - 0x1
SERVICE_AUTO_START - 0x2
SERVUCE_DEMAMD_START - 0x3
SERVICE_DISABLED - 0x4
Return Value:
TRUE - indicates sucess
FALSE - indicates failure
--*/
{
switch( start_type ) {
case 0:
RcMessageOut( msg_id, L"SERVICE_BOOT_START" );
break;
case 1:
RcMessageOut( msg_id, L"SERVICE_SYSTEM_START" );
break;
case 2:
RcMessageOut( msg_id, L"SERVICE_AUTO_START" );
break;
case 3:
RcMessageOut( msg_id, L"SERVICE_DEMAND_START" );
break;
case 4:
RcMessageOut( msg_id, L"SERVICE_DISABLED" );
break;
default:
break;
}
return TRUE;
}
BOOLEAN
RcOpenSystemHive(
VOID
)
/*++
Routine Description:
Opens the SYSTEM hive of the selected NT install.
Arguments:
None.
Return Value:
TRUE - indicates sucess
FALSE - indicates failure
--*/
{
PWSTR Hive = NULL;
PWSTR HiveKey = NULL;
PUCHAR buffer = NULL;
PWSTR PartitionPath = NULL;
NTSTATUS Status;
if (SelectedInstall == NULL) {
return FALSE;
}
//
// Allocate buffers.
//
Hive = SpMemAlloc(MAX_PATH * sizeof(WCHAR));
HiveKey = SpMemAlloc(MAX_PATH * sizeof(WCHAR));
buffer = SpMemAlloc(BUFFERSIZE);
//
// Get the name of the target patition.
//
SpNtNameFromRegion(
SelectedInstall->Region, // SelectedInstall is a global defined in cmdcons.h
_CmdConsBlock->TemporaryBuffer,
_CmdConsBlock->TemporaryBufferSize,
PartitionOrdinalCurrent
);
PartitionPath = SpDupStringW(_CmdConsBlock->TemporaryBuffer);
//
// Load the SYSTEM hive
//
wcscpy(Hive,PartitionPath);
SpConcatenatePaths(Hive,SelectedInstall->Path);
SpConcatenatePaths(Hive,L"system32\\config");
SpConcatenatePaths(Hive,L"system");
//
// Form the path of the key into which we will
// load the hive. We'll use the convention that
// a hive will be loaded into \registry\machine\x<hivename>.
//
wcscpy(HiveKey,L"\\registry\\machine\\xSYSTEM");
//
// Attempt to load the key.
//
Status = SpLoadUnloadKey(NULL,NULL,HiveKey,Hive);
if(!NT_SUCCESS(Status)) {
DEBUG_PRINTF(("CMDCONS: Unable to load hive %ws to key %ws (%lx)\n",Hive,HiveKey,Status));
SpMemFree( Hive );
SpMemFree( HiveKey );
SpMemFree( buffer );
return FALSE;
}
SpMemFree( Hive );
SpMemFree( HiveKey );
SpMemFree( buffer );
return TRUE;
}
BOOLEAN
RcCloseSystemHive(
VOID
)
/*++
Routine Description:
Closes the SYSTEM hive of the selected NT install.
Arguments:
none.
Return Value:
TRUE - indicates sucess
FALSE - indicates failure
--*/
{
PWSTR HiveKey = NULL;
NTSTATUS TmpStatus;
//
// Allocate buffers.
//
HiveKey = SpMemAlloc(MAX_PATH * sizeof(WCHAR));
wcscpy(HiveKey,L"\\registry\\machine\\xSYSTEM");
//
// Unload the SYSTEM hive
//
TmpStatus = SpLoadUnloadKey(NULL,NULL,HiveKey,NULL);
if(!NT_SUCCESS(TmpStatus)) {
KdPrint(("CMDCONS: warning: unable to unload key %ws (%lx)\n",HiveKey,TmpStatus));
SpMemFree( HiveKey );
return FALSE;
}
SpMemFree( HiveKey );
return TRUE;
}
BOOLEAN
RcDetermineCorrectControlKey(
OUT PULONG pCorrectKey
)
/*++
Routine Description:
Parses the select node and finds the correct ControlSetXXX to use.
Arguments:
pCorrectKey - pointer to a DWORD which will contain the number.
Return Value:
TRUE - indicates sucess
FALSE - indicates failure
--*/
{
NTSTATUS Status;
WCHAR RegPath[ MAX_PATH ];
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING SelectString;
HANDLE SelectKeyHandle;
BYTE buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 100 ]; // just grab a bunch of bytes
ULONG resultSize = 0;
KEY_VALUE_PARTIAL_INFORMATION * keyPartialInfo;
UNICODE_STRING SelectValue;
WCHAR VALUE_NAME[] = L"Current";
RtlZeroMemory( (VOID * )&(buffer[0]),
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 100 );
keyPartialInfo = (KEY_VALUE_PARTIAL_INFORMATION*)&(buffer[0]);
ASSERT( keyPartialInfo );
*pCorrectKey = -1;
// prepend HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services to
// the supplied parameter
wcscpy( RegPath, L"\\registry\\machine\\xSYSTEM\\Select" );
// build the unicode string
RtlInitUnicodeString( &SelectString, RegPath );
InitializeObjectAttributes( &Obja,&SelectString,
OBJ_CASE_INSENSITIVE, NULL, NULL);
// we need to determine the correct ControlSet to open
Status = ZwOpenKey( &SelectKeyHandle, KEY_ALL_ACCESS, &Obja );
if( NT_SUCCESS( Status ) ) {
RtlInitUnicodeString( &SelectValue, VALUE_NAME );
Status = ZwQueryValueKey( SelectKeyHandle,
&SelectValue,
KeyValuePartialInformation,
keyPartialInfo,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 100,
&resultSize
);
if( !NT_SUCCESS(Status) || Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
// couldn't find correct control value!
DEBUG_PRINTF(( "CMDCONS: failed to find correct control value!\n" ));
} else {
// we found a control value
// check if it's ok
if( keyPartialInfo->Type != REG_DWORD ) {
// paranoia check failed
DEBUG_PRINTF(( "CMDCONS: paranoia check failed?!\n" ));
DEBUG_PRINTF(( "CMDCONS: mismatched key type?!\n" ));
DEBUG_PRINTF(( "CMDCONS: key type of %d?!\n", keyPartialInfo->Type ));
DEBUG_PRINTF(( "CMDCONS: resultsize of %d?!\n", resultSize ));
} else {
// parnoia check sucess
*pCorrectKey = *( (DWORD*) &(keyPartialInfo->Data[0]) );
Status = NtClose( SelectKeyHandle );
if( !NT_SUCCESS ( Status ) ) {
DEBUG_PRINTF(( "CMDCONS: failure closing handle?!\n" ));
}
return TRUE;
}
}
}
// failed to find the Select node.
RcMessageOut( MSG_SYSTEM_MISSING_CURRENT_CONTROLS );
DEBUG_PRINTF(( "CMDCONS: failed to find select node!\n", *pCorrectKey ));
Status = NtClose( SelectKeyHandle );
if( !NT_SUCCESS ( Status ) ) {
DEBUG_PRINTF(( "CMDCONS: failure closing handle?!\n" ));
}
return FALSE;
}
ULONG
RcCmdListSvc(
IN PTOKENIZED_LINE TokenizedLine
)
{
#define DISPLAY_BUFFER_SIZE 512
NTSTATUS Status;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES Obja;
HANDLE ServiceKeyHandle = NULL;
ULONG ControlSetNumber;
ULONG cb;
ULONG KeyCount;
ULONG i;
HANDLE ValueHandle;
ULONG StartType;
PWSTR DisplayBuffer = NULL;
PKEY_BASIC_INFORMATION bi;
PKEY_VALUE_PARTIAL_INFORMATION pi;
WCHAR ServiceName[64];
PWSTR DisplayName;
static ULONG StartTypeIds[] = {
MSG_SVCTYPE_BOOT,
MSG_SVCTYPE_SYSTEM,
MSG_SVCTYPE_AUTO,
MSG_SVCTYPE_MANUAL,
MSG_SVCTYPE_DISABLED
};
static WCHAR *StartTypeStr[sizeof(StartTypeIds)/sizeof(ULONG)] = { 0 };
static WCHAR *DefaultSvcTypes[sizeof(StartTypeIds)/sizeof(ULONG)] =
{ L"Boot", L"System", L"Auto", L"Manual", L"Disabled" };
if (!StartTypeStr[0]) {
//
// load all the service type strings
//
ULONG Index;
for (Index = 0; Index < sizeof(StartTypeIds)/sizeof(ULONG); Index++) {
StartTypeStr[Index] = SpRetreiveMessageText(ImageBase, StartTypeIds[Index],
NULL, 0);
if (!StartTypeStr[Index])
StartTypeStr[Index] = DefaultSvcTypes[Index];
}
}
if (RcCmdParseHelp( TokenizedLine, MSG_LISTSVC_HELP )) {
return 1;
}
if (!RcOpenSystemHive()) {
return 1;
}
pRcEnableMoreMode();
if (!RcDetermineCorrectControlKey( &ControlSetNumber ) ) {
goto exit;
}
DisplayBuffer = (PWSTR) SpMemAlloc( DISPLAY_BUFFER_SIZE );
if (DisplayBuffer == NULL) {
goto exit;
}
swprintf( _CmdConsBlock->TemporaryBuffer, L"\\registry\\machine\\xSYSTEM\\ControlSet%03d\\Services\\", ControlSetNumber );
RtlInitUnicodeString( &UnicodeString, _CmdConsBlock->TemporaryBuffer );
InitializeObjectAttributes( &Obja, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = ZwOpenKey( &ServiceKeyHandle, KEY_ALL_ACCESS, &Obja );
if (!NT_SUCCESS(Status)) {
goto exit;
}
Status = ZwQueryKey(
ServiceKeyHandle,
KeyFullInformation,
_CmdConsBlock->TemporaryBuffer,
_CmdConsBlock->TemporaryBufferSize,
&cb
);
if (!NT_SUCCESS(Status)) {
goto exit;
}
KeyCount = ((KEY_FULL_INFORMATION*)_CmdConsBlock->TemporaryBuffer)->SubKeys;
bi = (PKEY_BASIC_INFORMATION)_CmdConsBlock->TemporaryBuffer;
pi = (PKEY_VALUE_PARTIAL_INFORMATION)_CmdConsBlock->TemporaryBuffer;
for (i=0; i<KeyCount; i++) {
RtlZeroMemory( DisplayBuffer, DISPLAY_BUFFER_SIZE );
RtlZeroMemory( _CmdConsBlock->TemporaryBuffer, _CmdConsBlock->TemporaryBufferSize );
Status = ZwEnumerateKey(
ServiceKeyHandle,
i,
KeyBasicInformation,
_CmdConsBlock->TemporaryBuffer,
_CmdConsBlock->TemporaryBufferSize,
&cb
);
if (!NT_SUCCESS(Status)) {
goto exit;
}
wcsncpy( ServiceName, bi->Name, (sizeof(ServiceName)/sizeof(WCHAR))-1 );
RtlInitUnicodeString( &UnicodeString, bi->Name );
InitializeObjectAttributes( &Obja, &UnicodeString, OBJ_CASE_INSENSITIVE, ServiceKeyHandle, NULL );
Status = ZwOpenKey( &ValueHandle, KEY_ALL_ACCESS, &Obja );
if (!NT_SUCCESS(Status)) {
goto exit;
}
RtlInitUnicodeString( &UnicodeString, L"Start" );
Status = ZwQueryValueKey(
ValueHandle,
&UnicodeString,
KeyValuePartialInformation,
_CmdConsBlock->TemporaryBuffer,
_CmdConsBlock->TemporaryBufferSize,
&cb
);
if (!NT_SUCCESS(Status)) {
ZwClose( ValueHandle );
continue;
}
if (pi->Type != REG_DWORD) {
StartType = 5;
} else {
StartType = *(PULONG)&(pi->Data[0]);
}
RtlInitUnicodeString( &UnicodeString, L"DisplayName" );
Status = ZwQueryValueKey(
ValueHandle,
&UnicodeString,
KeyValuePartialInformation,
_CmdConsBlock->TemporaryBuffer,
_CmdConsBlock->TemporaryBufferSize,
&cb
);
if (NT_SUCCESS(Status)) {
DisplayName = (PWSTR)&(pi->Data[0]);
} else {
DisplayName = NULL;
}
ZwClose( ValueHandle );
if (StartType != 5) {
swprintf( DisplayBuffer, L"%-15s %-8s %s\r\n",
ServiceName,
StartTypeStr[StartType],
DisplayName == NULL ? L"" : DisplayName
);
if (!RcTextOut( DisplayBuffer )){
goto exit;
}
}
}
exit:
if (ServiceKeyHandle) {
ZwClose( ServiceKeyHandle );
}
RcCloseSystemHive();
if (DisplayBuffer) {
SpMemFree(DisplayBuffer);
}
pRcDisableMoreMode();
return 1;
}
#define VERIFIER_DRV_LEVEL L"VerifyDriverLevel"
#define VERIFIER_DRIVERS L"VerifyDrivers"
#define VERIFIER_IO_LEVEL L"IoVerifierLevel"
#define VERIFIER_QUERY_INFO L"Flags = %ld; IO Level = %ld\r\nDrivers = %ws\r\n"
#define MEMMGR_PATH L"\\registry\\machine\\xSYSTEM\\ControlSet%03d\\Control\\Session Manager\\Memory Management"
#define IOSYS_PATH L"\\registry\\machine\\xSYSTEM\\ControlSet%03d\\Control\\Session Manager\\I/O System"
#define SYS_HIVE_NAME L"system"
#define SYS_HIVE_KEY L"\\registry\\machine\\xSYSTEM"
ULONG
RcCmdVerifier(
IN PTOKENIZED_LINE TokenizedLine
)
{
BOOLEAN ShowHelp = FALSE;
WCHAR *Args[128] = {0};
ULONG Index;
PLINE_TOKEN CurrToken = 0;
WCHAR Drivers[256] = {0};
DWORD Flags = -1;
DWORD IoLevel = -1;
BOOLEAN DisplaySettings = FALSE;
UNICODE_STRING UnicodeString;
ULONG NumArgs = 0;
BOOLEAN UseDefFlags = TRUE;
BOOLEAN UseDefIoLevel = TRUE;
BOOLEAN ResetSettings = FALSE;
if (RcCmdParseHelp(TokenizedLine, MSG_VERIFIER_HELP)) {
return 1;
}
//
// parse the arguments
//
Index = 0;
CurrToken = TokenizedLine->Tokens;
do {
Args[Index] = CurrToken->String;
CurrToken = CurrToken->Next;
Index++;
}
while ((Index < TokenizedLine->TokenCount) &&
(Index < sizeof(Args)/sizeof(PWCHAR)) && CurrToken);
NumArgs = min(TokenizedLine->TokenCount, Index);
if (TokenizedLine->TokenCount == 2) {
//
// should be one of /all, /reset, /query
//
if (!_wcsicmp(Args[1], L"/all")) {
wcscpy(Drivers, L"*");
Flags = 0;
IoLevel = 1;
} else if (!_wcsicmp(Args[1], L"/reset")) {
Drivers[0] = 0;
Flags = 0;
IoLevel = 1;
ResetSettings = TRUE;
} else if (!_wcsicmp(Args[1], L"/query")) {
DisplaySettings = TRUE;
} else {
ShowHelp = TRUE;
}
} else {
ULONG NextArg = 1;
if (!_wcsicmp(Args[NextArg], L"/flags")) {
RtlInitUnicodeString(&UnicodeString, Args[NextArg + 1]);
RtlUnicodeStringToInteger(&UnicodeString, 10, &Flags);
NextArg += 2;
UseDefFlags = FALSE;
}
if (!_wcsicmp(Args[NextArg], L"/iolevel")) {
RtlInitUnicodeString(&UnicodeString, Args[NextArg + 1]);
RtlUnicodeStringToInteger(&UnicodeString, 10, &IoLevel);
NextArg += 2;
UseDefIoLevel = FALSE;
}
if (!_wcsicmp(Args[NextArg], L"/driver")) {
ULONG Len = 0;
Drivers[0] = 0;
for (Index = NextArg + 1; Index < NumArgs; Index++) {
wcscat(Drivers, Args[Index]);
wcscat(Drivers, L" ");
}
if (!Drivers[0])
ShowHelp = TRUE; // need a driver name
} else if (!_wcsicmp(Args[NextArg], L"/all")) {
wcscpy(Drivers, L"*");
} else {
ShowHelp = TRUE;
}
}
//
// Verify the arguments
//
if (!ShowHelp) {
ShowHelp = !DisplaySettings && !ResetSettings &&
(Flags == -1) && (IoLevel == -1) && (!Drivers[0]);
}
if (ShowHelp) {
RcMessageOut(MSG_VERIFIER_HELP);
} else {
ULONG ControlSetNumber = 0;
HANDLE MemMgrKeyHandle = NULL;
HANDLE IOMgrKeyHandle = NULL;
OBJECT_ATTRIBUTES ObjAttrs;
BOOLEAN KeysOpened = FALSE;
PVOID TemporaryBuffer = _CmdConsBlock->TemporaryBuffer;
ULONG TemporaryBufferSize = _CmdConsBlock->TemporaryBufferSize;
NTSTATUS Status;
BOOLEAN SysHiveOpened;
//
// open the system hive & determine correct control set to use
//
SysHiveOpened = (BOOLEAN)RcOpenHive(SYS_HIVE_NAME, SYS_HIVE_KEY);
//
// get the control set which we are going to manipulate
//
if (SysHiveOpened && RcDetermineCorrectControlKey(&ControlSetNumber)) {
//
// open "Memory Management" subkey under "SM"
//
swprintf((PWSTR)TemporaryBuffer, MEMMGR_PATH, ControlSetNumber);
RtlInitUnicodeString(&UnicodeString, (PWSTR)TemporaryBuffer);
InitializeObjectAttributes(&ObjAttrs, &UnicodeString,
OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&MemMgrKeyHandle, KEY_ALL_ACCESS, &ObjAttrs);
if (NT_SUCCESS(Status)) {
//
// open "I/O System" subkey under "SM"
//
swprintf((PWSTR)TemporaryBuffer, IOSYS_PATH, ControlSetNumber);
RtlInitUnicodeString(&UnicodeString, (PWSTR)TemporaryBuffer);
InitializeObjectAttributes(&ObjAttrs, &UnicodeString,
OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&IOMgrKeyHandle, KEY_ALL_ACCESS, &ObjAttrs);
if (!NT_SUCCESS(Status)) {
ULONG Disposition = 0;
//
// Create "I/O System" subkey under "SM", if it does not exist
//
Status = ZwCreateKey(&IOMgrKeyHandle, KEY_ALL_ACCESS, &ObjAttrs,
0, NULL, REG_OPTION_NON_VOLATILE, NULL);
}
if (NT_SUCCESS(Status))
KeysOpened = TRUE;
}
}
if (KeysOpened) {
ULONG ByteCount = 0;
ULONG KeyCount = 0;
PKEY_VALUE_FULL_INFORMATION ValueFullInfo;
WCHAR ValueName[256];
ULONG Len;
if (DisplaySettings) {
//
// Query the Flags and Drivers
//
Flags = 0;
Drivers[0] = 0;
for(Index=0; ;Index++){
Status = ZwEnumerateValueKey(
MemMgrKeyHandle,
Index,
KeyValueFullInformation,
TemporaryBuffer,
TemporaryBufferSize,
&ByteCount
);
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_NO_MORE_ENTRIES)
Status = STATUS_SUCCESS;
break;
}
ValueFullInfo = (PKEY_VALUE_FULL_INFORMATION)TemporaryBuffer;
Len = ValueFullInfo->NameLength / sizeof(WCHAR);
wcsncpy(ValueName, ValueFullInfo->Name, Len);
ValueName[Len] = 0;
if ((!_wcsicmp(ValueName, VERIFIER_DRV_LEVEL)) &&
(ValueFullInfo->Type == REG_DWORD)) {
Flags = *(PDWORD)(((PUCHAR)ValueFullInfo) + ValueFullInfo->DataOffset);
} else if ((!_wcsicmp(ValueName, VERIFIER_DRIVERS)) &&
(ValueFullInfo->Type == REG_SZ)) {
Len = ValueFullInfo->DataLength / sizeof(WCHAR);
wcsncpy(Drivers, (PWSTR)(((PUCHAR)ValueFullInfo) + ValueFullInfo->DataOffset),
Len);
Drivers[Len] = 0;
}
}
//
// Query the IO level
//
for(Index=0; ;Index++){
Status = ZwEnumerateValueKey(
IOMgrKeyHandle,
Index,
KeyValueFullInformation,
TemporaryBuffer,
TemporaryBufferSize,
&ByteCount
);
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_NO_MORE_ENTRIES)
Status = STATUS_SUCCESS;
break;
}
ValueFullInfo = (PKEY_VALUE_FULL_INFORMATION)TemporaryBuffer;
Len = ValueFullInfo->NameLength / sizeof(WCHAR);
wcsncpy(ValueName, ValueFullInfo->Name, Len);
ValueName[Len] = 0;
if ((!_wcsicmp(ValueName, VERIFIER_IO_LEVEL)) &&
(ValueFullInfo->Type == REG_DWORD)) {
IoLevel = *(PDWORD)(((PUCHAR)ValueFullInfo) + ValueFullInfo->DataOffset);
}
}
if (IoLevel == 3)
IoLevel = 2;
else
IoLevel = 1;
//
// format the output and display it
//
swprintf((PWSTR)TemporaryBuffer, VERIFIER_QUERY_INFO,
Flags, IoLevel, Drivers);
RcTextOut((PWSTR)TemporaryBuffer);
} else {
//
// If IO verify bit is not set, then clear IoLevel
//
if (!(Flags & 0x10))
IoLevel = 0;
if (IoLevel == 2)
IoLevel = 3; // actual value stored in the registry
if (IoLevel != 3)
UseDefIoLevel = TRUE;
//
// set IO level
//
RtlInitUnicodeString(&UnicodeString, VERIFIER_IO_LEVEL);
if (UseDefIoLevel) {
Status = ZwDeleteValueKey(IOMgrKeyHandle, &UnicodeString);
} else {
Status = ZwSetValueKey(IOMgrKeyHandle, &UnicodeString, 0, REG_DWORD,
&IoLevel, sizeof(DWORD));
}
//
// set the DRV verification level
//
RtlInitUnicodeString(&UnicodeString, VERIFIER_DRV_LEVEL);
if (UseDefFlags) {
Status = ZwDeleteValueKey(MemMgrKeyHandle, &UnicodeString);
} else {
Status = ZwSetValueKey(MemMgrKeyHandle, &UnicodeString, 0, REG_DWORD,
&Flags, sizeof(DWORD));
}
//
// set the drivers to be verified
//
RtlInitUnicodeString(&UnicodeString, VERIFIER_DRIVERS);
if (Drivers[0]) {
Status = ZwSetValueKey(MemMgrKeyHandle, &UnicodeString, 0, REG_SZ,
Drivers, (wcslen(Drivers) + 1) * sizeof(WCHAR));
} else {
Status = ZwDeleteValueKey(MemMgrKeyHandle, &UnicodeString);
}
}
}
if (MemMgrKeyHandle)
ZwClose(MemMgrKeyHandle);
if (IOMgrKeyHandle)
ZwClose(IOMgrKeyHandle);
if (SysHiveOpened)
RcCloseHive(SYS_HIVE_KEY);
}
return 1;
}