//---------------------------------------------------------------------------- // // Copyright (C) Intel Corporation, 2011 - 2014 All Rights Reserved. // // File: UserConsentApi.cs // // Contents: Api code for Intel(R) Active Management Technology // (Intel® AMT) User Consent. // // Notes: This sample application demonstrates various commands of user // consent flow for AMT 6.1 and above FW versions. // //---------------------------------------------------------------------------- using System; using Connection; using Intel.Management.Wsman; using System.Threading; using System.Collections.Generic; using Utils; using Common.Utils; namespace UserConsent { public class UserConsentApi : Connection_setup { #region ENUMS /// /// User input flags. /// public enum YesNoFlag { YES, NO }; /// /// System power states. /// public enum PowerState { Other = 1, On, LightSleep, DeepSleep, SoftPowerCycle, HardOff, Hibernate, SoftOff, HardPowerCycle, MasterBusReset, DiagnosticInterrupt }; /// /// Indicates the state of OptIn (User Consent). /// public enum OptInState { /// /// OptIn is required for sessions affected by OptInPolicy. /// NotStarted, /// /// A console has required an optIn code, but it was not displayed to the user yet. /// Requested, /// /// The optIn code was displayed to the user. /// Displayed, /// /// The optIn code was successfully entered by the IT. /// Received, /// /// Intel AMT had a KVM or Redirection open session. /// InSession }; /// /// Indicates the user consent policy. /// public enum OptInPolicy : uint { /// /// The optIn is not required for any of the features. /// NONE, /// /// The optIn is required only for KVM. /// KVM, /// /// The optIn is required for all operations. /// ALL = UInt32.MaxValue } /// /// Default screen values. /// public enum DefaultScreen { PrimaryScreen, SecondaryScreen //to do -- will need to include Third Screen option as well.. }; #endregion #region CONSTANTS private const uint MAX_NUMBER_OF_TRIALS = 3; private const uint PT_STATUS_SUCCESS = 0; private const uint PT_STATUS_UNSPECIFIED_ERROR = 2; private const string STR_UNSPECIFIED_ERROR = "Requested operation is not allowed in Intel AMT system's current state."; // OptInService Functions Statuses Dictionary StatusCodes = new Dictionary() { {0, "PT_STATUS_SUCCESS"}, {1, "PT_STATUS_INTERNAL_ERROR"}, {2, "PT_STATUS_INVALID_STATE"}, {3, "PT_STATUS_BLOCKED"}, {2066, "PT_STATUS_INVALID_CREDENTIALS"} }; // Yes No questions private string ASK_FOR_SWITCH_SCREEN = "Would you like to switch monitors?"; private string ASK_FOR_SAMPLE_REBOOT = "Would you like to reboot the system?"; #endregion #region PRIVATE_DATA_MEMBERS public static CmdLineArguments Params = new CmdLineArguments(); IWsmanItem returnValue; #endregion PRIVATE_DATA_MEMBERS #region CONSTRUCTORS // Creating the connection to the WSMan Client. // Inheriting Connection details from Connection_setup class. // Convert password to secure string to comply with wsman dll which supports passwords in SecureString // format only. public UserConsentApi(string ip, string username, string pwd, bool krb, MpsManager proxy, bool acceptSelfSignedCertificate = false) : base(ip, username, pwd.ConvertToSecureString(), krb, proxy, acceptSelfSignedCertificate) { } // Convert password to secure string to comply with wsman dll which supports passwords in SecureString // format only. public UserConsentApi(string ip, string username, string pwd, string clientCert, bool krb, MpsManager proxy, bool acceptSelfSignedCertificate = false) : base(ip, username, pwd.ConvertToSecureString(), clientCert, krb, proxy, acceptSelfSignedCertificate) { } #endregion CONSTRUCTORS #region PUBLIC_FUNCTIONS /// /// Get user consent policy. /// /// The current policy public OptInPolicy GetUserConsentPolicy() { // Get the IPS_OptInService using the Intel AMT as a reference. IManagedReference optInServiceRef = wsmanClient.NewReference("SELECT * FROM IPS_OptInService WHERE Name='Intel(r) AMT OptIn Service'"); IManagedInstance optInServiceInstance = optInServiceRef.Get(); IWsmanItem optInRequired = optInServiceInstance.GetProperty("OptInRequired"); OptInPolicy policy = OptInPolicy.NONE; // The optIn is not required for any of the features. (Property does not exist.) if (optInRequired != null)//service.ContainsField("OptInRequired")) { // Indicates the OptIn (User Consent) Policy for Redirection operations,including KVM and IDER, // or setting of boot options. // This value is Read Only if the system was configured in Client Control Mode and Read-Write // in Admin Control Mode and CanModifyOptInPolicy=true. // The allowed values in Admin Control Mode are: None (opt-in not required for any of the features), // KVM, or All (KVM+IDER+Boot options). Possible values in Client Control Mode: All. policy = (OptInPolicy)(Convert.ToUInt64(optInRequired.ToString())); } return policy; } /// /// Get user consent state - mainly examines OptInState. /// /// The current state public OptInState GetUserConsentState() { // Traversing the IPS_OptInService using the Intel AMT as a reference. IManagedReference optInServiceRef = wsmanClient.NewReference("SELECT * FROM IPS_OptInService WHERE Name='Intel(r) AMT OptIn Service'"); IManagedInstance optInServiceInstance = optInServiceRef.Get(); IWsmanItem optInState = optInServiceInstance.GetProperty("OptInState"); // Return the optIn state as enum parameter. OptInState state = (OptInState)(Convert.ToUInt64(optInState.ToString())); return state; } /// /// Get the system power state. /// /// The current power state public PowerState GetPowerState() { // Create a reference to the CIM_ComputerSystem instance. IManagedReference computerSysRef = wsmanClient.NewReference("SELECT * FROM CIM_ComputerSystem WHERE Name='ManagedSystem'"); IManagedReference associatedPowerMgmtRef = wsmanClient.NewReference("CIM_AssociatedPowerManagementService"); associatedPowerMgmtRef.AddSelector("UserOfService", computerSysRef); //Traverse to the CIM_AssociatedPowerManagementService instances that are connected to CIM_ComputerSystem instance. int powerState; foreach (IWsmanItem associatedPowerMgmtItem in associatedPowerMgmtRef.Enumerate("http://schemas.dmtf.org/wbem/wsman/1/wsman/SelectorFilter", null)) { // For each instance, check if it is associated to the CIM_PowerManagementService instance. if (associatedPowerMgmtItem.Object.GetProperty("ServiceProvided").IsA("CIM_PowerManagementService")) { IWsmanItem associatedPowerMgmtInstance = associatedPowerMgmtItem; powerState = Convert.ToInt16(associatedPowerMgmtInstance.Object.GetProperty("PowerState").ToString()); return (PowerState)(powerState); } } return 0; } /// /// Getting the user consent status. /// public IManagedInstance DisplayUserConsentStatus() { Console.WriteLine("Getting User Consent Status."); IManagedReference optInServiceRef = wsmanClient.NewReference("SELECT * FROM IPS_OptInService WHERE Name='Intel(r) AMT OptIn Service'"); IManagedInstance optInServiceInstance = optInServiceRef.Get(); IWsmanItem optInRequired = optInServiceInstance.GetProperty("OptInRequired"); IWsmanItem optInState = optInServiceInstance.GetProperty("OptInState"); IWsmanItem optInDisplayTimeout = optInServiceInstance.GetProperty("OptInDisplayTimeout"); IWsmanItem optInCodeTimeout = optInServiceInstance.GetProperty("OptInCodeTimeout"); Console.WriteLine("User Consent Policy is: " + (OptInPolicy)(Convert.ToUInt64(optInRequired.ToString()))); Console.WriteLine("User Consent State is: " + (OptInState)(Convert.ToUInt64(optInState.ToString()))); Console.WriteLine("User Consent code Timeout is : " + optInCodeTimeout.ToString()); Console.WriteLine("User Consent Display Timeout is : " + optInDisplayTimeout.ToString()); return optInServiceInstance; } /// /// Request an optIn code. (Intel AMT generates code internally.) /// public void StartUserConsent() { Console.WriteLine("Starting User Consent Process..."); IManagedReference optInServiceRef = wsmanClient.NewReference("SELECT * FROM IPS_OptInService WHERE Name='Intel(r) AMT OptIn Service'"); IManagedInstance optInServiceInstance = optInServiceRef.Get(); IWsmanItem optInState = optInServiceInstance.GetProperty("OptInState"); if (optInState.ToString().Equals("0")) // OptInState = 0 ==> NotStarted { // Starting the user consent service. // Intel AMT generates a random code and displays the consent form to the user. IManagedInstance inputObject = optInServiceRef.CreateMethodInput("StartOptIn"); IManagedInstance outputObject = optInServiceRef.InvokeMethod(inputObject); returnValue = outputObject.GetProperty("ReturnValue"); if (Convert.ToUInt64(returnValue.ToString()) != PT_STATUS_SUCCESS) { throw new Exception("Error occurred in StartUserConsent. Intel AMT status code: " + StatusCodes[Convert.ToUInt32(returnValue.ToString())]); } Params.MessageDisplay_Color("Success.", ConsoleColor.Green); } if (optInState.ToString().Equals("1")) // OptInState == 1 ==> Requested { Console.WriteLine("User Consent has been requested."); } if (optInState.ToString().Equals("3")) // OptInState == 3 ==> Received { Console.WriteLine("User Consent has been received."); } } /// /// Cancel a previous optIn code request. /// public void StopUserConsent() { Console.WriteLine("Canceling User Consent Process..."); // Getting the service instance. IManagedReference optInServiceRef = wsmanClient.NewReference("SELECT * FROM IPS_OptInService WHERE Name='Intel(r) AMT OptIn Service'"); IManagedInstance inputObject = optInServiceRef.CreateMethodInput("CancelOptIn"); IManagedInstance outputObject = optInServiceRef.InvokeMethod(inputObject); returnValue = outputObject.GetProperty("ReturnValue"); if (Convert.ToUInt64(returnValue.ToString()) != PT_STATUS_SUCCESS) { throw new Exception("Error occurred in StopUserConsent. Intel AMT status code: " + StatusCodes[Convert.ToUInt32(returnValue.ToString())]); } Params.MessageDisplay_Color("Success.", ConsoleColor.Green); } /// /// Send the consent code to Intel AMT. /// public void SendConsentCode() { // Count the number of trials to send the consent code. uint codeTrials = 0; while (codeTrials != MAX_NUMBER_OF_TRIALS) { uint optInCode; // Asking for user consent code to send - waiting for input. Console.WriteLine("Please enter user consent code:"); string strCode = Console.ReadLine(); // Parsing the user input to uint code (validate the input). uint.TryParse(strCode, out optInCode); if (optInCode != 0 || uint.Parse(strCode) == 0) { // When caller exceeded the number of allowed SendConsent retries, there is no indication that the // state machine has reset. Therefore we are checking the OptInState, after each SendConsent failure, // to figure out if it can send an additional retry. // Getting the service instance for getting the user consent state. IManagedReference optInServiceRef = wsmanClient.NewReference("SELECT * FROM IPS_OptInService WHERE Name='Intel(r) AMT OptIn Service'"); IManagedInstance optInServiceInstance = optInServiceRef.Get(); IWsmanItem OptIn_state = optInServiceInstance.GetProperty("OptInState"); if (OptIn_state.ToString().Equals("2")) // OptInState = 2 ==>Displayed { Console.WriteLine("Sending Consent Code.. "); IManagedInstance inputObject = optInServiceRef.CreateMethodInput("SendOptInCode"); inputObject.SetProperty("OptInCode", optInCode.ToString()); IManagedInstance outputObject = optInServiceRef.InvokeMethod(inputObject); returnValue = outputObject.GetProperty("ReturnValue"); if (Convert.ToUInt64(returnValue.ToString()) != PT_STATUS_SUCCESS) { Params.MessageDisplay_Color("Failed to send user consent code. Try again.", ConsoleColor.Red); codeTrials++; } else { Params.MessageDisplay_Color("Success.", ConsoleColor.Green); break; } } } else { throw new InvalidCastException("An illegal value was entered. Please provide a valid Code(six digits)."); } } if (Convert.ToUInt64(returnValue.ToString()) != PT_STATUS_SUCCESS) { Params.MessageDisplay_Color("Maximal number of trials was reached - code is expired.", ConsoleColor.Red); throw new Exception("Error occurred in SendConsentCode. Intel AMT status code: " + StatusCodes[Convert.ToUInt32(returnValue.ToString())]); } } /// /// Change the default monitor. /// public void SetDefaultMonitor() { Console.WriteLine("Setting Default Monitor..."); uint value; IManagedReference secIOServiceRef = wsmanClient.NewReference("SELECT * FROM IPS_SecIOService WHERE Name='SecIO'"); IManagedInstance secIOServiceInstance = secIOServiceRef.Get(); value = uint.Parse(secIOServiceInstance.GetProperty("DefaultScreen").ToString()); if (value == 0) { secIOServiceInstance.SetProperty("DefaultScreen", "1"); } else { // Starting with Release 8.0, Intel AMT supports up to three screens, so the value can be 0, 1, or 2. if (UtilitiesMethods.GetCoreVersion(wsmanClient).CompareTo("8.0.0.0") >= 0) { if (value == 1) secIOServiceInstance.SetProperty("DefaultScreen", "2"); if (value == 2) secIOServiceInstance.SetProperty("DefaultScreen", "0"); } else { secIOServiceInstance.SetProperty("DefaultScreen", "0"); } } secIOServiceRef.Put(secIOServiceInstance); Params.MessageDisplay_Color("Success.", ConsoleColor.Green); } /// /// Gets the current default monitor. /// public void GetDefaultMonitor() { IManagedReference secIOServiceRef = wsmanClient.NewReference("SELECT * FROM IPS_SecIOService WHERE Name='SecIO'"); IManagedInstance secIOServiceInstance = secIOServiceRef.Get(); Console.WriteLine("The current default monitor: " + secIOServiceInstance.GetProperty("DefaultScreen").ToString()); } /// /// Run full user consent flow. /// See the attached diagram (UserConsentFlowDiagram.bmp) that depicts the flow performed by the full user consent flow option. /// public void RunFullUserConsentFlow() { // ------------------------------------- // STEP 1: Check the system power state. // ------------------------------------- if (GetPowerState() != (PowerState.On)) { // If system state is Sx - close the program. Params.MessageDisplay_Color("This flow does not support the current power state.", ConsoleColor.Red); return; } // ------------------------------------- // STEP 2: Check the user consent state. // ------------------------------------- DisplayUserConsentStatus(); // Check the system policy: // Policy is "NONE" - indicates that user consent is not required. if (GetUserConsentPolicy() == OptInPolicy.NONE) { Params.MessageDisplay_Color("User consent is not required for any operation", ConsoleColor.Yellow); return; } // Get user consent state. OptInState state = GetUserConsentState(); // Check the system state: if (state != OptInState.NotStarted) { // The state is received - the code was entered successfully by the IT. if (state == OptInState.Received) { Params.MessageDisplay_Color("User consent was already obtained.", ConsoleColor.Yellow); return; } if (state == OptInState.InSession) { Params.MessageDisplay_Color("User Consent is not required. KVM or Redirection session is currently opened.", ConsoleColor.Yellow); return; } // The state should be displayed (The code was displayed to the user), or requested (The console required an opt-in code) else { string errorMessage = "Full flow cannot be executed in the current user-consent state. Resetting the state using cancel option."; Params.MessageDisplay_Color(errorMessage, ConsoleColor.Yellow); // Cancel the user consent (reset OptInState to "NotStarted"). StopUserConsent(); } } // ------- ------------------------------- // STEP 3: Start the user consent process. // --------------------------------------- StartUserConsent(); // The "Requested" state is ambiguous. SW cannot determine, based on this state alone, whether it should // initiate a reboot to display MEBx code, or keep waiting for Intel AMT to display Sprite screen. // A "Requested" state indicates to SW that a reboot is required for MEBx only after 15 seconds from StartConsent() // The Sleep of 15 seconds (15000 milliseconds) is required since Intel AMT FW will only determine // if it can use Sprite screen after a few seconds. Thread.Sleep(15000); // --------------------------- // STEP 4: Display the Sprite. // --------------------------- // Intel AMT FW detects whether integrated gfx can be used for consent and prioritizes it over MEBx method. // If the state is not "Displayed" - indicates that Discrete gfx are present in the platform // and displays the sprite over MEBx. // Check user consent state. if (GetUserConsentState() != OptInState.Displayed) { Console.WriteLine("User Consent form will be displayed via MEBx."); if ((YesNoFlag)Params.AskYesNo(ASK_FOR_SAMPLE_REBOOT) == YesNoFlag.YES) { BootSystem(PowerState.SoftPowerCycle); } } // The DefaultScreen property controls on which screen the Sprite message is displayed. // It is used by the IT to switch between screens if the local user does not see the Consent form. if ((YesNoFlag)Params.AskYesNo(ASK_FOR_SWITCH_SCREEN) == YesNoFlag.YES) { SetDefaultMonitor(); } // ----------------------------- // STEP 5: Send the consent code. // ------------------------------ // Get the user consent code and send it. SendConsentCode(); //Perform the task that required user consent...! //Stop the Consent Flow StopUserConsent(); } #endregion #region UTILS_FUNCTIONS /// /// Reboot the system. /// public void BootSystem(PowerState requestedPower) { Console.WriteLine("Booting the system... "); IManagedReference powerManagementRef = wsmanClient.NewReference("SELECT * FROM CIM_PowerManagementService WHERE Name='Intel(r) AMT Power Management Service'"); IManagedInstance inputObject = powerManagementRef.CreateMethodInput("RequestPowerStateChange"); inputObject.SetProperty("PowerState", (uint)requestedPower); // 5 = SoftPowerCycle - other options can also be set, based on the value that is being passed. /* * The supported PowerState values are: * 2 (Power Up), 5 (Power Cycle), 8 (Power Down), 10 (Master Bus Reset) * * ValueMap={2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} Values={Power On, Sleep - Light, Sleep - Deep, Power Cycle (Off Soft), Power Off - Hard, Hibernate, Power Off - Soft, * Power Cycle (Off Hard), Master Bus Reset, Diagnostic Interrupt (NMI), Power Off - Soft Graceful, Power Off - Hard Graceful, * Master Bus Reset Graceful, Power Cycle (Off - Soft Graceful), Power Cycle (Off - Hard Graceful)} */ IManagedReference computerSystemRef = wsmanClient.NewReference("SELECT * FROM CIM_ComputerSystem WHERE Name='ManagedSystem'"); inputObject.SetProperty("ManagedElement", computerSystemRef); IManagedInstance outputObject = powerManagementRef.InvokeMethod(inputObject); IWsmanItem return_value = outputObject.GetProperty("ReturnValue"); if (Convert.ToUInt64(return_value.ToString()) != PT_STATUS_SUCCESS) { throw new Exception("Failed to change power state. Intel AMT status code: " + StatusCodes[Convert.ToUInt32(return_value.ToString())]); } } #endregion } }