2020-03-24 11:08:37 -07:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
2018-02-13 09:23:53 -08:00
|
|
|
// Licensed under the MIT License.
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Management.Automation.Host;
|
2019-04-30 10:25:11 +05:00
|
|
|
using System.Reflection;
|
|
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
using Dbg = System.Management.Automation.Diagnostics;
|
|
|
|
|
using InternalHostUserInterface = System.Management.Automation.Internal.Host.InternalHostUserInterface;
|
|
|
|
|
|
|
|
|
|
namespace System.Management.Automation.Remoting
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Executes methods; can be encoded and decoded for transmission over the
|
|
|
|
|
/// wire.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal class RemoteHostCall
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Method name.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal string MethodName
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _methodInfo.Name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Method id.
|
|
|
|
|
/// </summary>
|
2016-08-02 13:29:09 -07:00
|
|
|
internal RemoteHostMethodId MethodId { get; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parameters.
|
|
|
|
|
/// </summary>
|
2016-08-02 13:29:09 -07:00
|
|
|
internal object[] Parameters { get; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Method info.
|
|
|
|
|
/// </summary>
|
2020-11-07 11:36:04 +00:00
|
|
|
private readonly RemoteHostMethodInfo _methodInfo;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Call id.
|
|
|
|
|
/// </summary>
|
2020-11-07 11:36:04 +00:00
|
|
|
private readonly long _callId;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Call id.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal long CallId
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _callId;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-01-06 04:40:24 +05:00
|
|
|
/// Computer name to be used in messages.
|
2016-03-30 14:20:52 -07:00
|
|
|
/// </summary>
|
|
|
|
|
private string _computerName;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor for RemoteHostCall.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal RemoteHostCall(long callId, RemoteHostMethodId methodId, object[] parameters)
|
|
|
|
|
{
|
|
|
|
|
Dbg.Assert(parameters != null, "Expected parameters != null");
|
|
|
|
|
_callId = callId;
|
2016-08-02 13:29:09 -07:00
|
|
|
MethodId = methodId;
|
|
|
|
|
Parameters = parameters;
|
2016-03-30 14:20:52 -07:00
|
|
|
_methodInfo = RemoteHostMethodInfo.LookUp(methodId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Encode parameters.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static PSObject EncodeParameters(object[] parameters)
|
|
|
|
|
{
|
|
|
|
|
// Encode the parameters and wrap the array into an ArrayList and then into a PSObject.
|
|
|
|
|
ArrayList parameterList = new ArrayList();
|
2016-07-29 13:02:49 -07:00
|
|
|
for (int i = 0; i < parameters.Length; ++i)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2020-07-30 16:06:38 -07:00
|
|
|
object parameter = parameters[i] == null ? null : RemoteHostEncoder.EncodeObject(parameters[i]);
|
2016-03-30 14:20:52 -07:00
|
|
|
parameterList.Add(parameter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new PSObject(parameterList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Decode parameters.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static object[] DecodeParameters(PSObject parametersPSObject, Type[] parameterTypes)
|
|
|
|
|
{
|
|
|
|
|
// Extract the ArrayList and decode the parameters.
|
2016-07-29 13:02:49 -07:00
|
|
|
ArrayList parameters = (ArrayList)parametersPSObject.BaseObject;
|
2016-03-30 14:20:52 -07:00
|
|
|
List<object> decodedParameters = new List<object>();
|
|
|
|
|
Dbg.Assert(parameters.Count == parameterTypes.Length, "Expected parameters.Count == parameterTypes.Length");
|
2016-07-29 13:02:49 -07:00
|
|
|
for (int i = 0; i < parameters.Count; ++i)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2020-07-30 16:06:38 -07:00
|
|
|
object parameter = parameters[i] == null ? null : RemoteHostEncoder.DecodeObject(parameters[i], parameterTypes[i]);
|
2016-03-30 14:20:52 -07:00
|
|
|
decodedParameters.Add(parameter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return decodedParameters.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Encode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal PSObject Encode()
|
|
|
|
|
{
|
|
|
|
|
// Add all host information as data.
|
|
|
|
|
PSObject data = RemotingEncoder.CreateEmptyPSObject();
|
|
|
|
|
|
|
|
|
|
// Encode the parameters for transport.
|
2016-08-02 13:29:09 -07:00
|
|
|
PSObject parametersPSObject = EncodeParameters(Parameters);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// Embed everything into the main PSobject.
|
|
|
|
|
data.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.CallId, _callId));
|
2016-08-02 13:29:09 -07:00
|
|
|
data.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.MethodId, MethodId));
|
2016-03-30 14:20:52 -07:00
|
|
|
data.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.MethodParameters, parametersPSObject));
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Decode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static RemoteHostCall Decode(PSObject data)
|
|
|
|
|
{
|
|
|
|
|
Dbg.Assert(data != null, "Expected data != null");
|
|
|
|
|
|
|
|
|
|
// Extract all the fields from data.
|
|
|
|
|
long callId = RemotingDecoder.GetPropertyValue<long>(data, RemoteDataNameStrings.CallId);
|
|
|
|
|
PSObject parametersPSObject = RemotingDecoder.GetPropertyValue<PSObject>(data, RemoteDataNameStrings.MethodParameters);
|
|
|
|
|
RemoteHostMethodId methodId = RemotingDecoder.GetPropertyValue<RemoteHostMethodId>(data, RemoteDataNameStrings.MethodId);
|
|
|
|
|
|
|
|
|
|
// Look up all the info related to the method.
|
|
|
|
|
RemoteHostMethodInfo methodInfo = RemoteHostMethodInfo.LookUp(methodId);
|
|
|
|
|
|
|
|
|
|
// Decode the parameters.
|
|
|
|
|
object[] parameters = DecodeParameters(parametersPSObject, methodInfo.ParameterTypes);
|
|
|
|
|
|
|
|
|
|
// Create and return the RemoteHostCall.
|
|
|
|
|
return new RemoteHostCall(callId, methodId, parameters);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Is void method.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal bool IsVoidMethod
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _methodInfo.ReturnType == typeof(void);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Execute void method.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal void ExecuteVoidMethod(PSHost clientHost)
|
|
|
|
|
{
|
|
|
|
|
// The clientHost can be null if the user creates a runspace object without providing
|
|
|
|
|
// a host parameter.
|
2020-07-30 16:06:38 -07:00
|
|
|
if (clientHost == null)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RemoteRunspace remoteRunspaceToClose = null;
|
|
|
|
|
if (this.IsSetShouldExitOrPopRunspace)
|
|
|
|
|
{
|
|
|
|
|
remoteRunspaceToClose = GetRemoteRunspaceToClose(clientHost);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
object targetObject = this.SelectTargetObject(clientHost);
|
2016-08-02 13:29:09 -07:00
|
|
|
MyMethodBase.Invoke(targetObject, Parameters);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (remoteRunspaceToClose != null)
|
|
|
|
|
{
|
|
|
|
|
remoteRunspaceToClose.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get remote runspace to close.
|
|
|
|
|
/// </summary>
|
2020-11-24 10:12:11 +00:00
|
|
|
private static RemoteRunspace GetRemoteRunspaceToClose(PSHost clientHost)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// Figure out if we need to close the remote runspace. Return null if we don't.
|
|
|
|
|
|
|
|
|
|
// Are we a Start-PSSession enabled host?
|
|
|
|
|
IHostSupportsInteractiveSession host = clientHost as IHostSupportsInteractiveSession;
|
2020-07-30 16:06:38 -07:00
|
|
|
if (host == null || !host.IsRunspacePushed)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now inspect the runspace.
|
|
|
|
|
RemoteRunspace remoteRunspace = host.Runspace as RemoteRunspace;
|
2020-07-30 16:06:38 -07:00
|
|
|
if (remoteRunspace == null || !remoteRunspace.ShouldCloseOnPop)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// At this point it is clear we have to close the remote runspace, so return it.
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// My method base.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private MethodBase MyMethodBase
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
return (MethodBase)_methodInfo.InterfaceType.GetMethod(_methodInfo.Name, _methodInfo.ParameterTypes);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Execute non void method.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal RemoteHostResponse ExecuteNonVoidMethod(PSHost clientHost)
|
|
|
|
|
{
|
|
|
|
|
// The clientHost can be null if the user creates a runspace object without providing
|
|
|
|
|
// a host parameter.
|
2020-07-30 16:06:38 -07:00
|
|
|
if (clientHost == null)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
throw RemoteHostExceptions.NewNullClientHostException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object targetObject = this.SelectTargetObject(clientHost);
|
|
|
|
|
RemoteHostResponse remoteHostResponse = this.ExecuteNonVoidMethodOnObject(targetObject);
|
|
|
|
|
return remoteHostResponse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Execute non void method on object.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteHostResponse ExecuteNonVoidMethodOnObject(object instance)
|
|
|
|
|
{
|
|
|
|
|
// Create variables to store result of execution.
|
|
|
|
|
Exception exception = null;
|
|
|
|
|
object returnValue = null;
|
|
|
|
|
|
|
|
|
|
// Invoke the method and store its return values.
|
|
|
|
|
try
|
|
|
|
|
{
|
2016-08-02 13:29:09 -07:00
|
|
|
if (MethodId == RemoteHostMethodId.GetBufferContents)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
throw new PSRemotingDataStructureException(RemotingErrorIdStrings.RemoteHostGetBufferContents,
|
|
|
|
|
_computerName.ToUpper());
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-02 13:29:09 -07:00
|
|
|
returnValue = MyMethodBase.Invoke(instance, Parameters);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
// Catch-all OK, 3rd party callout.
|
|
|
|
|
exception = e.InnerException;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a RemoteHostResponse object to store the return value and exceptions.
|
2016-08-02 13:29:09 -07:00
|
|
|
return new RemoteHostResponse(_callId, MethodId, returnValue, exception);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get the object that this method should be invoked on.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private object SelectTargetObject(PSHost host)
|
|
|
|
|
{
|
2020-07-30 16:06:38 -07:00
|
|
|
if (host == null || host.UI == null) { return null; }
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
if (_methodInfo.InterfaceType == typeof(PSHost)) { return host; }
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
if (_methodInfo.InterfaceType == typeof(IHostSupportsInteractiveSession)) { return host; }
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
if (_methodInfo.InterfaceType == typeof(PSHostUserInterface)) { return host.UI; }
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
if (_methodInfo.InterfaceType == typeof(IHostUISupportsMultipleChoiceSelection)) { return host.UI; }
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
if (_methodInfo.InterfaceType == typeof(PSHostRawUserInterface)) { return host.UI.RawUI; }
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
throw RemoteHostExceptions.NewUnknownTargetClassException(_methodInfo.InterfaceType.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Is set should exit.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal bool IsSetShouldExit
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2016-08-02 13:29:09 -07:00
|
|
|
return MethodId == RemoteHostMethodId.SetShouldExit;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Is set should exit or pop runspace.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal bool IsSetShouldExitOrPopRunspace
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return
|
2016-08-02 13:29:09 -07:00
|
|
|
MethodId == RemoteHostMethodId.SetShouldExit ||
|
|
|
|
|
MethodId == RemoteHostMethodId.PopRunspace;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This message performs various security checks on the
|
|
|
|
|
/// remote host call message. If there is a need to modify
|
|
|
|
|
/// the message or discard it for security reasons then
|
2019-01-06 04:40:24 +05:00
|
|
|
/// such modifications will be made here.
|
2016-03-30 14:20:52 -07:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="computerName">computer name to use in
|
|
|
|
|
/// warning messages</param>
|
2018-12-25 21:43:03 +05:00
|
|
|
/// <returns>A collection of remote host calls which will
|
2016-03-30 14:20:52 -07:00
|
|
|
/// have to be executed before this host call can be
|
2018-12-25 21:43:03 +05:00
|
|
|
/// executed.</returns>
|
2018-12-22 01:26:06 -08:00
|
|
|
internal Collection<RemoteHostCall> PerformSecurityChecksOnHostMessage(string computerName)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2018-12-31 15:10:15 +05:00
|
|
|
Dbg.Assert(!string.IsNullOrEmpty(computerName),
|
2016-03-30 14:20:52 -07:00
|
|
|
"Computer Name must be passed for use in warning messages");
|
|
|
|
|
_computerName = computerName;
|
|
|
|
|
Collection<RemoteHostCall> prerequisiteCalls = new Collection<RemoteHostCall>();
|
|
|
|
|
|
|
|
|
|
// check if the incoming message is a PromptForCredential message
|
|
|
|
|
// if so, do the following:
|
2019-05-03 03:38:06 -07:00
|
|
|
// (a) prepend "PowerShell Credential Request" in the title
|
2016-03-30 14:20:52 -07:00
|
|
|
// (b) prepend "Message from Server XXXXX" to the text message
|
2016-08-02 13:29:09 -07:00
|
|
|
if (MethodId == RemoteHostMethodId.PromptForCredential1 ||
|
|
|
|
|
MethodId == RemoteHostMethodId.PromptForCredential2)
|
2016-07-29 13:02:49 -07:00
|
|
|
{
|
2016-03-30 14:20:52 -07:00
|
|
|
// modify the caption which is _parameters[0]
|
2016-08-02 13:29:09 -07:00
|
|
|
string modifiedCaption = ModifyCaption((string)Parameters[0]);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// modify the message which is _parameters[1]
|
2016-08-02 13:29:09 -07:00
|
|
|
string modifiedMessage = ModifyMessage((string)Parameters[1], computerName);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-08-02 13:29:09 -07:00
|
|
|
Parameters[0] = modifiedCaption;
|
|
|
|
|
Parameters[1] = modifiedMessage;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if the incoming message is a Prompt message
|
|
|
|
|
// if so, then do the following:
|
|
|
|
|
// (a) check if any of the field descriptions
|
|
|
|
|
// correspond to PSCredential
|
2017-01-16 13:31:14 -08:00
|
|
|
// (b) if field descriptions correspond to
|
|
|
|
|
// PSCredential modify the caption and
|
2016-03-30 14:20:52 -07:00
|
|
|
// message as in the previous case above
|
2016-08-02 13:29:09 -07:00
|
|
|
else if (MethodId == RemoteHostMethodId.Prompt)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// check if any of the field descriptions is for type
|
|
|
|
|
// PSCredential
|
2016-08-02 13:29:09 -07:00
|
|
|
if (Parameters.Length == 3)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
Collection<FieldDescription> fieldDescs =
|
2016-08-02 13:29:09 -07:00
|
|
|
(Collection<FieldDescription>)Parameters[2];
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
bool havePSCredential = false;
|
|
|
|
|
|
|
|
|
|
foreach (FieldDescription fieldDesc in fieldDescs)
|
|
|
|
|
{
|
|
|
|
|
fieldDesc.IsFromRemoteHost = true;
|
|
|
|
|
|
|
|
|
|
Type fieldType = InternalHostUserInterface.GetFieldType(fieldDesc);
|
|
|
|
|
if (fieldType != null)
|
|
|
|
|
{
|
|
|
|
|
if (fieldType == typeof(PSCredential))
|
|
|
|
|
{
|
|
|
|
|
havePSCredential = true;
|
|
|
|
|
fieldDesc.ModifiedByRemotingProtocol = true;
|
|
|
|
|
}
|
|
|
|
|
else if (fieldType == typeof(System.Security.SecureString))
|
|
|
|
|
{
|
|
|
|
|
prerequisiteCalls.Add(ConstructWarningMessageForSecureString(
|
|
|
|
|
computerName, RemotingErrorIdStrings.RemoteHostPromptSecureStringPrompt));
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-20 22:54:10 -08:00
|
|
|
}
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
if (havePSCredential)
|
|
|
|
|
{
|
|
|
|
|
// modify the caption which is parameter[0]
|
2016-08-02 13:29:09 -07:00
|
|
|
string modifiedCaption = ModifyCaption((string)Parameters[0]);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// modify the message which is parameter[1]
|
2016-08-02 13:29:09 -07:00
|
|
|
string modifiedMessage = ModifyMessage((string)Parameters[1], computerName);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-08-02 13:29:09 -07:00
|
|
|
Parameters[0] = modifiedCaption;
|
|
|
|
|
Parameters[1] = modifiedMessage;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
2018-12-20 22:54:10 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// Check if the incoming message is a readline as secure string
|
|
|
|
|
// if so do the following:
|
|
|
|
|
// (a) Specify a warning message that the server is
|
|
|
|
|
// attempting to read something securely on the client
|
2016-08-02 13:29:09 -07:00
|
|
|
else if (MethodId == RemoteHostMethodId.ReadLineAsSecureString)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
prerequisiteCalls.Add(ConstructWarningMessageForSecureString(
|
|
|
|
|
computerName, RemotingErrorIdStrings.RemoteHostReadLineAsSecureStringPrompt));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if the incoming call is GetBufferContents
|
|
|
|
|
// if so do the following:
|
2017-01-16 13:31:14 -08:00
|
|
|
// (a) Specify a warning message that the server is
|
|
|
|
|
// attempting to read the screen buffer contents
|
2016-03-30 14:20:52 -07:00
|
|
|
// on screen and it has been blocked
|
|
|
|
|
// (b) Modify the message so that call is not executed
|
2016-08-02 13:29:09 -07:00
|
|
|
else if (MethodId == RemoteHostMethodId.GetBufferContents)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
prerequisiteCalls.Add(ConstructWarningMessageForGetBufferContents(computerName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return prerequisiteCalls;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Provides the modified caption for the given caption
|
|
|
|
|
/// Used in ensuring that remote prompt messages are
|
2019-05-03 03:38:06 -07:00
|
|
|
/// tagged with "PowerShell Credential Request"
|
2016-03-30 14:20:52 -07:00
|
|
|
/// </summary>
|
2018-12-29 08:25:49 +05:00
|
|
|
/// <param name="caption">Caption to modify.</param>
|
2018-12-25 21:43:03 +05:00
|
|
|
/// <returns>New modified caption.</returns>
|
2020-11-24 10:12:11 +00:00
|
|
|
private static string ModifyCaption(string caption)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
string pscaption = CredUI.PromptForCredential_DefaultCaption;
|
|
|
|
|
|
|
|
|
|
if (!caption.Equals(pscaption, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
string modifiedCaption = PSRemotingErrorInvariants.FormatResourceString(
|
|
|
|
|
RemotingErrorIdStrings.RemoteHostPromptForCredentialModifiedCaption, caption);
|
|
|
|
|
|
|
|
|
|
return modifiedCaption;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return caption;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Provides the modified message for the given one
|
|
|
|
|
/// Used in ensuring that remote prompt messages
|
2017-01-16 13:31:14 -08:00
|
|
|
/// contain a warning that they originate from a
|
2019-01-06 04:40:24 +05:00
|
|
|
/// different computer.
|
2016-03-30 14:20:52 -07:00
|
|
|
/// </summary>
|
2018-12-29 08:25:49 +05:00
|
|
|
/// <param name="message">Original message to modify.</param>
|
2017-01-16 13:31:14 -08:00
|
|
|
/// <param name="computerName">computername to include in the
|
2016-03-30 14:20:52 -07:00
|
|
|
/// message</param>
|
2018-12-25 21:43:03 +05:00
|
|
|
/// <returns>Message which contains a warning as well.</returns>
|
2020-11-24 10:12:11 +00:00
|
|
|
private static string ModifyMessage(string message, string computerName)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
string modifiedMessage = PSRemotingErrorInvariants.FormatResourceString(
|
2016-07-29 13:02:49 -07:00
|
|
|
RemotingErrorIdStrings.RemoteHostPromptForCredentialModifiedMessage,
|
2016-03-30 14:20:52 -07:00
|
|
|
computerName.ToUpper(),
|
|
|
|
|
message);
|
|
|
|
|
|
|
|
|
|
return modifiedMessage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2017-01-16 13:31:14 -08:00
|
|
|
/// Creates a warning message which displays to the user a
|
|
|
|
|
/// warning stating that the remote host computer is
|
2019-01-06 04:40:24 +05:00
|
|
|
/// actually attempting to read a line as a secure string.
|
2016-03-30 14:20:52 -07:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="computerName">computer name to include
|
|
|
|
|
/// in warning</param>
|
2018-12-29 08:25:49 +05:00
|
|
|
/// <param name="resourceString">Resource string to use.</param>
|
2018-12-25 21:43:03 +05:00
|
|
|
/// <returns>A constructed remote host call message
|
|
|
|
|
/// which will display the warning.</returns>
|
2020-11-24 10:12:11 +00:00
|
|
|
private static RemoteHostCall ConstructWarningMessageForSecureString(string computerName,
|
2016-03-30 14:20:52 -07:00
|
|
|
string resourceString)
|
|
|
|
|
{
|
|
|
|
|
string warning = PSRemotingErrorInvariants.FormatResourceString(
|
2016-07-29 13:02:49 -07:00
|
|
|
resourceString,
|
2016-03-30 14:20:52 -07:00
|
|
|
computerName.ToUpper());
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
return new RemoteHostCall(ServerDispatchTable.VoidCallId,
|
|
|
|
|
RemoteHostMethodId.WriteWarningLine, new object[] { warning });
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a warning message which displays to the user a
|
|
|
|
|
/// warning stating that the remote host computer is
|
|
|
|
|
/// attempting to read the host's buffer contents and that
|
2019-01-06 04:40:24 +05:00
|
|
|
/// it was suppressed.
|
2016-03-30 14:20:52 -07:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="computerName">computer name to include
|
|
|
|
|
/// in warning</param>
|
2018-12-25 21:43:03 +05:00
|
|
|
/// <returns>A constructed remote host call message
|
|
|
|
|
/// which will display the warning.</returns>
|
2020-11-24 10:12:11 +00:00
|
|
|
private static RemoteHostCall ConstructWarningMessageForGetBufferContents(string computerName)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
string warning = PSRemotingErrorInvariants.FormatResourceString(
|
|
|
|
|
RemotingErrorIdStrings.RemoteHostGetBufferContents,
|
|
|
|
|
computerName.ToUpper());
|
|
|
|
|
|
|
|
|
|
return new RemoteHostCall(ServerDispatchTable.VoidCallId,
|
|
|
|
|
RemoteHostMethodId.WriteWarningLine, new object[] { warning });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Encapsulates the method response semantics. Method responses are generated when
|
|
|
|
|
/// RemoteHostCallPacket objects are executed. They can contain both the return values of
|
|
|
|
|
/// the execution as well as exceptions that were thrown in the RemoteHostCallPacket
|
|
|
|
|
/// execution. They can be encoded and decoded for transporting over the wire. A
|
|
|
|
|
/// method response can be used to transport the result of an execution and then to
|
|
|
|
|
/// simulate the execution on the other end.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal class RemoteHostResponse
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Call id.
|
|
|
|
|
/// </summary>
|
2020-11-07 11:36:04 +00:00
|
|
|
private readonly long _callId;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Call id.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal long CallId
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _callId;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Method id.
|
|
|
|
|
/// </summary>
|
2020-11-07 11:36:04 +00:00
|
|
|
private readonly RemoteHostMethodId _methodId;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Return value.
|
|
|
|
|
/// </summary>
|
2020-11-07 11:36:04 +00:00
|
|
|
private readonly object _returnValue;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Exception.
|
|
|
|
|
/// </summary>
|
2020-11-07 11:36:04 +00:00
|
|
|
private readonly Exception _exception;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor for RemoteHostResponse.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal RemoteHostResponse(long callId, RemoteHostMethodId methodId, object returnValue, Exception exception)
|
|
|
|
|
{
|
|
|
|
|
_callId = callId;
|
|
|
|
|
_methodId = methodId;
|
|
|
|
|
_returnValue = returnValue;
|
|
|
|
|
_exception = exception;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Simulate execution.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal object SimulateExecution()
|
|
|
|
|
{
|
|
|
|
|
if (_exception != null)
|
|
|
|
|
{
|
|
|
|
|
throw _exception;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _returnValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Encode and add return value.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void EncodeAndAddReturnValue(PSObject psObject, object returnValue)
|
|
|
|
|
{
|
|
|
|
|
// Do nothing if the return value is null.
|
2020-07-30 16:06:38 -07:00
|
|
|
if (returnValue == null) { return; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// Otherwise add the property.
|
|
|
|
|
RemoteHostEncoder.EncodeAndAddAsProperty(psObject, RemoteDataNameStrings.MethodReturnValue, returnValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Decode return value.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static object DecodeReturnValue(PSObject psObject, Type returnType)
|
|
|
|
|
{
|
|
|
|
|
object returnValue = RemoteHostEncoder.DecodePropertyValue(psObject, RemoteDataNameStrings.MethodReturnValue, returnType);
|
|
|
|
|
return returnValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Encode and add exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void EncodeAndAddException(PSObject psObject, Exception exception)
|
|
|
|
|
{
|
|
|
|
|
RemoteHostEncoder.EncodeAndAddAsProperty(psObject, RemoteDataNameStrings.MethodException, exception);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Decode exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static Exception DecodeException(PSObject psObject)
|
|
|
|
|
{
|
|
|
|
|
object result = RemoteHostEncoder.DecodePropertyValue(psObject, RemoteDataNameStrings.MethodException, typeof(Exception));
|
2020-07-30 16:06:38 -07:00
|
|
|
if (result == null) { return null; }
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
if (result is Exception) { return (Exception)result; }
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
throw RemoteHostExceptions.NewDecodingFailedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Encode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal PSObject Encode()
|
|
|
|
|
{
|
|
|
|
|
// Create a data object and put everything in that and return it.
|
|
|
|
|
PSObject data = RemotingEncoder.CreateEmptyPSObject();
|
|
|
|
|
EncodeAndAddReturnValue(data, _returnValue);
|
|
|
|
|
EncodeAndAddException(data, _exception);
|
|
|
|
|
data.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.CallId, _callId));
|
|
|
|
|
data.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.MethodId, _methodId));
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Decode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static RemoteHostResponse Decode(PSObject data)
|
|
|
|
|
{
|
|
|
|
|
Dbg.Assert(data != null, "Expected data != null");
|
|
|
|
|
|
|
|
|
|
// Extract all the fields from data.
|
|
|
|
|
long callId = RemotingDecoder.GetPropertyValue<long>(data, RemoteDataNameStrings.CallId);
|
|
|
|
|
RemoteHostMethodId methodId = RemotingDecoder.GetPropertyValue<RemoteHostMethodId>(data, RemoteDataNameStrings.MethodId);
|
|
|
|
|
|
|
|
|
|
// Decode the return value and the exception.
|
|
|
|
|
RemoteHostMethodInfo methodInfo = RemoteHostMethodInfo.LookUp(methodId);
|
|
|
|
|
object returnValue = DecodeReturnValue(data, methodInfo.ReturnType);
|
|
|
|
|
Exception exception = DecodeException(data);
|
|
|
|
|
|
|
|
|
|
// Use these values to create a RemoteHostResponse and return it.
|
|
|
|
|
return new RemoteHostResponse(callId, methodId, returnValue, exception);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The RemoteHostExceptions class.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static class RemoteHostExceptions
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// New remote runspace does not support push runspace exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static Exception NewRemoteRunspaceDoesNotSupportPushRunspaceException()
|
|
|
|
|
{
|
|
|
|
|
string resourceString = PSRemotingErrorInvariants.FormatResourceString(
|
|
|
|
|
RemotingErrorIdStrings.RemoteRunspaceDoesNotSupportPushRunspace);
|
|
|
|
|
return new PSRemotingDataStructureException(resourceString);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// New decoding failed exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static Exception NewDecodingFailedException()
|
|
|
|
|
{
|
|
|
|
|
string resourceString = PSRemotingErrorInvariants.FormatResourceString(
|
|
|
|
|
RemotingErrorIdStrings.RemoteHostDecodingFailed);
|
|
|
|
|
return new PSRemotingDataStructureException(resourceString);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// New not implemented exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static Exception NewNotImplementedException(RemoteHostMethodId methodId)
|
|
|
|
|
{
|
|
|
|
|
RemoteHostMethodInfo methodInfo = RemoteHostMethodInfo.LookUp(methodId);
|
|
|
|
|
string resourceString = PSRemotingErrorInvariants.FormatResourceString(
|
|
|
|
|
RemotingErrorIdStrings.RemoteHostMethodNotImplemented, methodInfo.Name);
|
|
|
|
|
return new PSRemotingDataStructureException(resourceString, new PSNotImplementedException());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// New remote host call failed exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static Exception NewRemoteHostCallFailedException(RemoteHostMethodId methodId)
|
|
|
|
|
{
|
|
|
|
|
RemoteHostMethodInfo methodInfo = RemoteHostMethodInfo.LookUp(methodId);
|
|
|
|
|
string resourceString = PSRemotingErrorInvariants.FormatResourceString(
|
|
|
|
|
RemotingErrorIdStrings.RemoteHostCallFailed, methodInfo.Name);
|
|
|
|
|
return new PSRemotingDataStructureException(resourceString);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// New decoding error for error record exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static Exception NewDecodingErrorForErrorRecordException()
|
|
|
|
|
{
|
|
|
|
|
return new PSRemotingDataStructureException(RemotingErrorIdStrings.DecodingErrorForErrorRecord);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// New remote host data encoding not supported exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static Exception NewRemoteHostDataEncodingNotSupportedException(Type type)
|
|
|
|
|
{
|
|
|
|
|
Dbg.Assert(type != null, "Expected type != null");
|
|
|
|
|
return new PSRemotingDataStructureException(
|
|
|
|
|
RemotingErrorIdStrings.RemoteHostDataEncodingNotSupported,
|
|
|
|
|
type.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// New remote host data decoding not supported exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static Exception NewRemoteHostDataDecodingNotSupportedException(Type type)
|
|
|
|
|
{
|
|
|
|
|
Dbg.Assert(type != null, "Expected type != null");
|
|
|
|
|
return new PSRemotingDataStructureException(
|
|
|
|
|
RemotingErrorIdStrings.RemoteHostDataDecodingNotSupported,
|
|
|
|
|
type.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// New unknown target class exception.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static Exception NewUnknownTargetClassException(string className)
|
|
|
|
|
{
|
|
|
|
|
Dbg.Assert(className != null, "Expected className != null");
|
|
|
|
|
return new PSRemotingDataStructureException(RemotingErrorIdStrings.UnknownTargetClass, className);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Exception NewNullClientHostException()
|
|
|
|
|
{
|
|
|
|
|
return new PSRemotingDataStructureException(RemotingErrorIdStrings.RemoteHostNullClientHost);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|