text: /*++
  
  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.
                             if Message(comment) is longer than MAX_REASON_COMMENT_LEN
                             return FALSE.(ERROR_INVALID_PARAMETER)
                             
      dwTimeout -     Number of seconds to delay before shutting down
                             if dwTimeout is larger than MAX_SHUTDOWN_TIMEOUT,
                             return FALSE. (ERROR_INVALID_PARAMETER)
                             
      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);
  
      if ( ( Message.Length / sizeof(WCHAR) <  MAX_REASON_COMMENT_LEN ) &&
      	   ( dwTimeout < MAX_SHUTDOWN_TIMEOUT ) ){
  	    //
  	    // 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);
  	    }
      } 
      else{
      	 Result = ERROR_INVALID_PARAMETER;
      }    	
  
      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.
                             if Message(comment) is longer than MAX_REASON_COMMENT_LEN
                             return FALSE.(ERROR_INVALID_PARAMETER)
  
      dwTimeout -     Number of seconds to delay before shutting down
                             if dwTimeout is larger than MAX_SHUTDOWN_TIMEOUT,
                             return FALSE. (ERROR_INVALID_PARAMETER)
  
      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);
  
      if ( ( Message.Length / sizeof(WCHAR) < MAX_REASON_COMMENT_LEN ) &&
      	   ( dwTimeout < MAX_SHUTDOWN_TIMEOUT ) ) {
  	    	
  	    //
  	    // 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);
  	    }
      }
      else{
      	Result = ERROR_INVALID_PARAMETER;
     }
      	
  
      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);
  }
  
  
  