667 lines
15 KiB
C
667 lines
15 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Shutdown.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the client side wrappers for the Win32 remote
|
||
shutdown APIs, that is:
|
||
|
||
- InitiateSystemShutdownA
|
||
- InitiateSystemShutdownW
|
||
- AbortSystemShutdownA
|
||
- AbortSystemShutdownW
|
||
|
||
Author:
|
||
|
||
Dave Chalmers (davidc) 29-Apr-1992
|
||
|
||
Notes:
|
||
|
||
|
||
Revision History:
|
||
|
||
Dragos C. Sambotin (dragoss) 21-May-1999
|
||
Added support for the new winlogon's Shutdown interface
|
||
|
||
--*/
|
||
|
||
|
||
#define UNICODE
|
||
|
||
#include <rpc.h>
|
||
#include "regrpc.h"
|
||
#include "client.h"
|
||
#include "shutinit.h"
|
||
#include "..\regconn\regconn.h"
|
||
|
||
LONG
|
||
BaseBindToMachine(
|
||
IN LPCWSTR lpMachineName,
|
||
IN PBIND_CALLBACK BindCallback,
|
||
IN PVOID Context1,
|
||
IN PVOID Context2
|
||
);
|
||
|
||
LONG
|
||
ShutdownCallback(
|
||
IN RPC_BINDING_HANDLE *pbinding,
|
||
IN PUNICODE_STRING Message,
|
||
IN PVOID Context2
|
||
);
|
||
|
||
LONG
|
||
ShutdownCallbackEx(
|
||
IN RPC_BINDING_HANDLE *pbinding,
|
||
IN PUNICODE_STRING Message,
|
||
IN PVOID Context2
|
||
);
|
||
|
||
LONG
|
||
AbortShutdownCallback(
|
||
IN RPC_BINDING_HANDLE *pbinding,
|
||
IN PVOID Context1,
|
||
IN PVOID Context2
|
||
);
|
||
|
||
BOOL
|
||
APIENTRY
|
||
InitiateSystemShutdownW(
|
||
IN LPWSTR lpMachineName OPTIONAL,
|
||
IN LPWSTR lpMessage OPTIONAL,
|
||
IN DWORD dwTimeout,
|
||
IN BOOL bForceAppsClosed,
|
||
IN BOOL bRebootAfterShutdown
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Win32 Unicode API for initiating the shutdown of a (possibly remote) machine.
|
||
|
||
Arguments:
|
||
|
||
lpMachineName - Name of machine to shutdown.
|
||
|
||
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 flag is set, 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 TRUE on success, FALSE on failure (GetLastError() returns error code)
|
||
|
||
Possible errors :
|
||
|
||
ERROR_SHUTDOWN_IN_PROGRESS - a shutdown has already been started on
|
||
the specified machine.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Result;
|
||
UNICODE_STRING Message;
|
||
SHUTDOWN_CONTEXT ShutdownContext;
|
||
BOOL TryOld = TRUE;
|
||
|
||
//
|
||
// Explicitly bind to the given server.
|
||
//
|
||
if (!ARGUMENT_PRESENT(lpMachineName)) {
|
||
lpMachineName = L"";
|
||
TryOld = FALSE;
|
||
}
|
||
|
||
ShutdownContext.dwTimeout = dwTimeout;
|
||
ShutdownContext.bForceAppsClosed = (bForceAppsClosed != 0);
|
||
ShutdownContext.bRebootAfterShutdown = (bRebootAfterShutdown != 0);
|
||
RtlInitUnicodeString(&Message, lpMessage);
|
||
|
||
//
|
||
// Call the server
|
||
//
|
||
|
||
//
|
||
// First try to connect to the new InitShutdown interface
|
||
//
|
||
Result = BaseBindToMachineShutdownInterface(lpMachineName,
|
||
NewShutdownCallback,
|
||
&Message,
|
||
&ShutdownContext);
|
||
|
||
if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
|
||
//
|
||
// try the old one, maybe we are calling into a NT4 machine
|
||
// which doesn't know about the new interface
|
||
//
|
||
Result = BaseBindToMachine(lpMachineName,
|
||
ShutdownCallback,
|
||
&Message,
|
||
&ShutdownContext);
|
||
}
|
||
|
||
if (Result != ERROR_SUCCESS) {
|
||
SetLastError(Result);
|
||
}
|
||
|
||
return(Result == ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
BOOL
|
||
APIENTRY
|
||
InitiateSystemShutdownExW(
|
||
IN LPWSTR lpMachineName OPTIONAL,
|
||
IN LPWSTR lpMessage OPTIONAL,
|
||
IN DWORD dwTimeout,
|
||
IN BOOL bForceAppsClosed,
|
||
IN BOOL bRebootAfterShutdown,
|
||
IN DWORD dwReason
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Win32 Unicode API for initiating the shutdown of a (possibly remote) machine.
|
||
|
||
Arguments:
|
||
|
||
lpMachineName - Name of machine to shutdown.
|
||
|
||
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 flag is set, all applications are terminated
|
||
unconditionally.
|
||
|
||
bRebootAfterShutdown - TRUE if the system should reboot.
|
||
FALSE if it should be left in a shutdown state.
|
||
|
||
dwReason - Reason for initiating the shutdown. This reason is logged
|
||
in the eventlog #6006 event.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE on success, FALSE on failure (GetLastError() returns error code)
|
||
|
||
Possible errors :
|
||
|
||
ERROR_SHUTDOWN_IN_PROGRESS - a shutdown has already been started on
|
||
the specified machine.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Result;
|
||
UNICODE_STRING Message;
|
||
SHUTDOWN_CONTEXTEX ShutdownContext;
|
||
BOOL TryOld = TRUE;
|
||
|
||
//
|
||
// Explicitly bind to the given server.
|
||
//
|
||
if (!ARGUMENT_PRESENT(lpMachineName)) {
|
||
lpMachineName = L"";
|
||
TryOld = FALSE;
|
||
}
|
||
|
||
ShutdownContext.dwTimeout = dwTimeout;
|
||
ShutdownContext.bForceAppsClosed = (bForceAppsClosed != 0);
|
||
ShutdownContext.bRebootAfterShutdown = (bRebootAfterShutdown != 0);
|
||
ShutdownContext.dwReason = dwReason;
|
||
RtlInitUnicodeString(&Message, lpMessage);
|
||
|
||
//
|
||
// Call the server
|
||
//
|
||
|
||
//
|
||
// First try to connect to the new InitShutdown interface
|
||
//
|
||
Result = BaseBindToMachineShutdownInterface(lpMachineName,
|
||
NewShutdownCallbackEx,
|
||
&Message,
|
||
&ShutdownContext);
|
||
|
||
if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
|
||
//
|
||
// try the old one, maybe we are calling into a NT4 machine
|
||
// which doesn't know about the new interface
|
||
//
|
||
Result = BaseBindToMachine(lpMachineName,
|
||
ShutdownCallbackEx,
|
||
&Message,
|
||
&ShutdownContext);
|
||
}
|
||
|
||
if (Result != ERROR_SUCCESS) {
|
||
SetLastError(Result);
|
||
}
|
||
|
||
return(Result == ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
BOOL
|
||
APIENTRY
|
||
InitiateSystemShutdownA(
|
||
IN LPSTR lpMachineName OPTIONAL,
|
||
IN LPSTR lpMessage OPTIONAL,
|
||
IN DWORD dwTimeout,
|
||
IN BOOL bForceAppsClosed,
|
||
IN BOOL bRebootAfterShutdown
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
See InitiateSystemShutdownW
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING MachineName;
|
||
UNICODE_STRING Message;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
BOOL Result;
|
||
|
||
//
|
||
// Convert the ansi machinename to wide-character
|
||
//
|
||
|
||
RtlInitAnsiString( &AnsiString, lpMachineName );
|
||
Status = RtlAnsiStringToUnicodeString(
|
||
&MachineName,
|
||
&AnsiString,
|
||
TRUE
|
||
);
|
||
|
||
if( NT_SUCCESS( Status )) {
|
||
|
||
//
|
||
// Convert the ansi message to wide-character
|
||
//
|
||
|
||
RtlInitAnsiString( &AnsiString, lpMessage );
|
||
Status = RtlAnsiStringToUnicodeString(
|
||
&Message,
|
||
&AnsiString,
|
||
TRUE
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Call the wide-character api
|
||
//
|
||
|
||
Result = InitiateSystemShutdownW(
|
||
MachineName.Buffer,
|
||
Message.Buffer,
|
||
dwTimeout,
|
||
bForceAppsClosed,
|
||
bRebootAfterShutdown
|
||
);
|
||
|
||
RtlFreeUnicodeString(&Message);
|
||
}
|
||
|
||
RtlFreeUnicodeString(&MachineName);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
SetLastError(RtlNtStatusToDosError(Status));
|
||
Result = FALSE;
|
||
}
|
||
|
||
return(Result);
|
||
}
|
||
|
||
|
||
BOOL
|
||
APIENTRY
|
||
InitiateSystemShutdownExA(
|
||
IN LPSTR lpMachineName OPTIONAL,
|
||
IN LPSTR lpMessage OPTIONAL,
|
||
IN DWORD dwTimeout,
|
||
IN BOOL bForceAppsClosed,
|
||
IN BOOL bRebootAfterShutdown,
|
||
IN DWORD dwReason
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
See InitiateSystemShutdownW
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING MachineName;
|
||
UNICODE_STRING Message;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
BOOL Result;
|
||
|
||
//
|
||
// Convert the ansi machinename to wide-character
|
||
//
|
||
|
||
RtlInitAnsiString( &AnsiString, lpMachineName );
|
||
Status = RtlAnsiStringToUnicodeString(
|
||
&MachineName,
|
||
&AnsiString,
|
||
TRUE
|
||
);
|
||
|
||
if( NT_SUCCESS( Status )) {
|
||
|
||
//
|
||
// Convert the ansi message to wide-character
|
||
//
|
||
|
||
RtlInitAnsiString( &AnsiString, lpMessage );
|
||
Status = RtlAnsiStringToUnicodeString(
|
||
&Message,
|
||
&AnsiString,
|
||
TRUE
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Call the wide-character api
|
||
//
|
||
|
||
Result = InitiateSystemShutdownExW(
|
||
MachineName.Buffer,
|
||
Message.Buffer,
|
||
dwTimeout,
|
||
bForceAppsClosed,
|
||
bRebootAfterShutdown,
|
||
dwReason
|
||
);
|
||
|
||
RtlFreeUnicodeString(&Message);
|
||
}
|
||
|
||
RtlFreeUnicodeString(&MachineName);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
SetLastError(RtlNtStatusToDosError(Status));
|
||
Result = FALSE;
|
||
}
|
||
|
||
return(Result);
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
APIENTRY
|
||
AbortSystemShutdownW(
|
||
IN LPWSTR lpMachineName OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Win32 Unicode API for aborting the shutdown of a (possibly remote) machine.
|
||
|
||
Arguments:
|
||
|
||
lpMachineName - Name of target machine.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE on success, FALSE on failure (GetLastError() returns error code)
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Result;
|
||
RPC_BINDING_HANDLE binding;
|
||
BOOL TryOld = TRUE;
|
||
|
||
//
|
||
// Explicitly bind to the given server.
|
||
//
|
||
if (!ARGUMENT_PRESENT(lpMachineName)) {
|
||
lpMachineName = L"";
|
||
TryOld = FALSE;
|
||
}
|
||
|
||
//
|
||
// Call the server
|
||
//
|
||
|
||
//
|
||
// First try to connect to the new InitShutdown interface
|
||
//
|
||
Result = BaseBindToMachineShutdownInterface(lpMachineName,
|
||
NewAbortShutdownCallback,
|
||
NULL,
|
||
NULL);
|
||
|
||
if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
|
||
//
|
||
// try the old one, maybe we are calling into a NT4 machine
|
||
// which doesn't know about the new interface
|
||
Result = BaseBindToMachine(lpMachineName,
|
||
AbortShutdownCallback,
|
||
NULL,
|
||
NULL);
|
||
}
|
||
|
||
if (Result != ERROR_SUCCESS) {
|
||
SetLastError(Result);
|
||
}
|
||
|
||
return(Result == ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
APIENTRY
|
||
AbortSystemShutdownA(
|
||
IN LPSTR lpMachineName OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
See AbortSystemShutdownW
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING MachineName;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
BOOL Result;
|
||
|
||
//
|
||
// Convert the ansi machinename to wide-character
|
||
//
|
||
|
||
RtlInitAnsiString( &AnsiString, lpMachineName );
|
||
Status = RtlAnsiStringToUnicodeString(
|
||
&MachineName,
|
||
&AnsiString,
|
||
TRUE
|
||
);
|
||
|
||
if( NT_SUCCESS( Status )) {
|
||
|
||
//
|
||
// Call the wide-character api
|
||
//
|
||
|
||
Result = AbortSystemShutdownW(
|
||
MachineName.Buffer
|
||
);
|
||
|
||
RtlFreeUnicodeString(&MachineName);
|
||
}
|
||
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
SetLastError(RtlNtStatusToDosError(Status));
|
||
Result = FALSE;
|
||
}
|
||
|
||
return(Result);
|
||
}
|
||
|
||
LONG
|
||
ShutdownCallback(
|
||
IN RPC_BINDING_HANDLE *pbinding,
|
||
IN PUNICODE_STRING Message,
|
||
IN PSHUTDOWN_CONTEXT ShutdownContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Callback for binding to a machine to initiate a shutdown.
|
||
|
||
Arguments:
|
||
|
||
pbinding - Supplies a pointer to the RPC binding context
|
||
|
||
Message - Supplies message to display during shutdown timeout period.
|
||
|
||
ShutdownContext - Supplies remaining parameters for BaseInitiateSystemShutdown
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if no error.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Result;
|
||
|
||
RpcTryExcept {
|
||
Result = BaseInitiateSystemShutdown((PREGISTRY_SERVER_NAME)pbinding,
|
||
Message,
|
||
ShutdownContext->dwTimeout,
|
||
ShutdownContext->bForceAppsClosed,
|
||
ShutdownContext->bRebootAfterShutdown);
|
||
} RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
|
||
Result = RpcExceptionCode();
|
||
} RpcEndExcept;
|
||
|
||
if (Result != ERROR_SUCCESS) {
|
||
RpcBindingFree(pbinding);
|
||
}
|
||
return(Result);
|
||
}
|
||
|
||
LONG
|
||
ShutdownCallbackEx(
|
||
IN RPC_BINDING_HANDLE *pbinding,
|
||
IN PUNICODE_STRING Message,
|
||
IN PSHUTDOWN_CONTEXTEX ShutdownContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Callback for binding to a machine to initiate a shutdown.
|
||
|
||
Arguments:
|
||
|
||
pbinding - Supplies a pointer to the RPC binding context
|
||
|
||
Message - Supplies message to display during shutdown timeout period.
|
||
|
||
ShutdownContext - Supplies remaining parameters for BaseInitiateSystemShutdown
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if no error.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Result;
|
||
|
||
RpcTryExcept {
|
||
Result = BaseInitiateSystemShutdownEx((PREGISTRY_SERVER_NAME)pbinding,
|
||
Message,
|
||
ShutdownContext->dwTimeout,
|
||
ShutdownContext->bForceAppsClosed,
|
||
ShutdownContext->bRebootAfterShutdown,
|
||
ShutdownContext->dwReason);
|
||
} RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
|
||
Result = RpcExceptionCode();
|
||
} RpcEndExcept;
|
||
|
||
if (Result != ERROR_SUCCESS) {
|
||
RpcBindingFree(pbinding);
|
||
}
|
||
return(Result);
|
||
}
|
||
|
||
LONG
|
||
AbortShutdownCallback(
|
||
IN RPC_BINDING_HANDLE *pbinding,
|
||
IN PVOID Unused1,
|
||
IN PVOID Unused2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Callback for binding to a machine to abort a shutdown.
|
||
|
||
Arguments:
|
||
|
||
pbinding - Supplies a pointer to the RPC binding context
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if no error.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Result;
|
||
|
||
RpcTryExcept {
|
||
Result = BaseAbortSystemShutdown((PREGISTRY_SERVER_NAME)pbinding);
|
||
} RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
|
||
Result = RpcExceptionCode();
|
||
} RpcEndExcept;
|
||
|
||
if (Result != ERROR_SUCCESS) {
|
||
RpcBindingFree(pbinding);
|
||
}
|
||
return(Result);
|
||
}
|
||
|
||
|