예제 #1
0
 internal static TransportErrorOccuredEventArgs ConstructTransportErrorEventArgs(IntPtr wsmanAPIHandle, WSManClientSessionTransportManager wsmanSessionTM, WSManNativeApi.WSManError errorStruct, TransportMethodEnum transportMethodReportingError, string resourceString, params object[] resourceArgs)
 {
     PSRemotingTransportException exception;
     if ((errorStruct.errorCode == -2144108135) && (wsmanSessionTM != null))
     {
         string redirectLocation = WSManNativeApi.WSManGetSessionOptionAsString(wsmanSessionTM.SessionHandle, WSManNativeApi.WSManSessionOption.WSMAN_OPTION_REDIRECT_LOCATION);
         string str2 = ParseEscapeWSManErrorMessage(WSManNativeApi.WSManGetErrorMessage(wsmanAPIHandle, errorStruct.errorCode)).Trim();
         exception = new PSRemotingTransportRedirectException(redirectLocation, PSRemotingErrorId.URIEndPointNotResolved, RemotingErrorIdStrings.URIEndPointNotResolved, new object[] { str2, redirectLocation });
     }
     else if ((errorStruct.errorCode == -2144108485) && (wsmanSessionTM != null))
     {
         string str3 = wsmanSessionTM.ConnectionInfo.ShellUri.Replace("http://schemas.microsoft.com/powershell/", string.Empty);
         string str4 = PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidConfigurationName, new object[] { str3, wsmanSessionTM.ConnectionInfo.ComputerName });
         exception = new PSRemotingTransportException(PSRemotingErrorId.InvalidConfigurationName, RemotingErrorIdStrings.ConnectExCallBackError, new object[] { wsmanSessionTM.ConnectionInfo.ComputerName, str4 }) {
             TransportMessage = ParseEscapeWSManErrorMessage(WSManNativeApi.WSManGetErrorMessage(wsmanAPIHandle, errorStruct.errorCode))
         };
     }
     else
     {
         string str5 = PSRemotingErrorInvariants.FormatResourceString(resourceString, resourceArgs);
         exception = new PSRemotingTransportException(PSRemotingErrorId.TroubleShootingHelpTopic, RemotingErrorIdStrings.TroubleShootingHelpTopic, new object[] { str5 }) {
             TransportMessage = ParseEscapeWSManErrorMessage(WSManNativeApi.WSManGetErrorMessage(wsmanAPIHandle, errorStruct.errorCode))
         };
     }
     exception.ErrorCode = errorStruct.errorCode;
     return new TransportErrorOccuredEventArgs(exception, transportMethodReportingError);
 }
예제 #2
0
        protected WSManPluginServerSession(
            WSManNativeApi.WSManPluginRequest creationRequestDetails,
            WSManPluginServerTransportManager transportMgr)
        {
            _syncObject = new Object();
            this.creationRequestDetails = creationRequestDetails;
            this.transportMgr = transportMgr;

            transportMgr.PrepareCalled +=
                new EventHandler<EventArgs>(this.HandlePrepareFromTransportManager);
            transportMgr.WSManTransportErrorOccured +=
                new EventHandler<TransportErrorOccuredEventArgs>(this.HandleTransportError);
        }
예제 #3
0
        /// <summary>
        /// unlock the shell / command specified so that the shell / command
        /// starts sending data to the client.
        /// </summary>
        /// <param name="pluginContext"></param>
        /// <param name="requestDetails"></param>
        /// <param name="flags"></param>
        /// <param name="shellContext"></param>
        /// <param name="commandContext"></param>
        /// <param name="streamSet"></param>
        internal void EnableShellOrCommandToSendDataToClient(
            IntPtr pluginContext,
            WSManNativeApi.WSManPluginRequest requestDetails,
            int flags,
            IntPtr shellContext,
            IntPtr commandContext,
            WSManNativeApi.WSManStreamIDSet_UnToMan streamSet)
        {
            if (!validateIncomingContexts(requestDetails, shellContext, "EnableShellOrCommandToSendDataToClient"))
            {
                return;
            }

            SetThreadProperties(requestDetails);

            PSEtwLog.LogAnalyticInformational(PSEventId.ServerClientReceiveRequest,
                    PSOpcode.Open, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                    ((IntPtr)shellContext).ToString(),
                    ((IntPtr)commandContext).ToString(),
                    requestDetails.ToString());

            WSManPluginShellSession mgdShellSession = GetFromActiveShellSessions(shellContext);
            if (null == mgdShellSession)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidShellContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidShellContext)
                    );
                return;
            }

            WSManPluginOperationShutdownContext ctxtToReport = new WSManPluginOperationShutdownContext(pluginContext, shellContext, IntPtr.Zero, true);
            if (null == ctxtToReport)
            {
                ReportOperationComplete(requestDetails, WSManPluginErrorCodes.OutOfMemory);
                return;
            }

            if (IntPtr.Zero == commandContext)
            {
                // the instruction is destined for shell (runspace) session. so let shell handle it
                if (mgdShellSession.EnableSessionToSendDataToClient(requestDetails, flags, streamSet, ctxtToReport))
                {
                    return;
                }
            }
            else
            {
                // the instruction is destined for command
                ctxtToReport.commandContext = commandContext;
                WSManPluginCommandSession mgdCmdSession = mgdShellSession.GetCommandSession(commandContext);

                if (null == mgdCmdSession)
                {
                    ReportOperationComplete(
                        requestDetails,
                        WSManPluginErrorCodes.InvalidCommandContext,
                        StringUtil.Format(
                            RemotingErrorIdStrings.WSManPluginInvalidCommandContext));
                    return;
                }

                if (mgdCmdSession.EnableSessionToSendDataToClient(requestDetails, flags, streamSet, ctxtToReport))
                {
                    return;
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Connect
        /// </summary>
        /// <param name="requestDetails"></param>
        /// <param name="flags"></param>
        /// <param name="shellContext"></param>
        /// <param name="commandContext"></param>
        /// <param name="inboundConnectInformation"></param>
        internal void ConnectShellOrCommand(
            WSManNativeApi.WSManPluginRequest requestDetails,
            int flags,
            IntPtr shellContext,
            IntPtr commandContext,
            WSManNativeApi.WSManData_UnToMan inboundConnectInformation)
        {
            if (!validateIncomingContexts(requestDetails, shellContext, "ConnectShellOrCommand"))
            {
                return;
            }

            //TODO... What does this mean from a new client that has specified diff locale from original client?
            SetThreadProperties(requestDetails);
            //TODO.. Add new ETW events and log
            /*etwTracer.AnalyticChannel.WriteInformation(PSEventId.ServerReceivedData,
                    PSOpcode.Open, PSTask.None,
                ((IntPtr)shellContext).ToString(), ((IntPtr)commandContext).ToString(), ((IntPtr)requestDetails).ToString());*/

            WSManPluginShellSession mgdShellSession = GetFromActiveShellSessions(shellContext);
            if (null == mgdShellSession)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidShellContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidShellContext));
                return;
            }

            if (IntPtr.Zero == commandContext)
            {
                mgdShellSession.ExecuteConnect(requestDetails, flags, inboundConnectInformation);
                return;
            }

            // this connect is on a command
            WSManPluginCommandSession mgdCmdSession = mgdShellSession.GetCommandSession(commandContext);
            if (null == mgdCmdSession)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidCommandContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidCommandContext));
                return;
            }

            mgdCmdSession.ExecuteConnect(requestDetails, flags, inboundConnectInformation);
        }
예제 #5
0
        /// <summary>
        /// Create a new command in the shell context.
        /// </summary>
        /// <param name="pluginContext"></param>
        /// <param name="requestDetails"></param>
        /// <param name="flags"></param>
        /// <param name="shellContext"></param>
        /// <param name="commandLine"></param>
        /// <param name="arguments"></param>
        internal void CreateCommand(
            IntPtr pluginContext,
            WSManNativeApi.WSManPluginRequest requestDetails,
            int flags,
            IntPtr shellContext,
            string commandLine,
            WSManNativeApi.WSManCommandArgSet arguments)
        {
            if (!validateIncomingContexts(requestDetails, shellContext, "WSManRunShellCommandEx"))
            {
                return;
            }

            SetThreadProperties(requestDetails);

            PSEtwLog.LogAnalyticInformational(PSEventId.ServerCreateCommandSession,
                    PSOpcode.Connect, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                ((IntPtr)shellContext).ToString(), requestDetails.ToString());

            WSManPluginShellSession mgdShellSession = GetFromActiveShellSessions(shellContext);
            if (null == mgdShellSession)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidShellContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidShellContext));
                return;
            }

            mgdShellSession.CreateCommand(pluginContext, requestDetails, flags, commandLine, arguments);
        }
예제 #6
0
        /// <summary>
        /// Create a new shell in the plugin context.
        /// </summary>
        /// <param name="pluginContext"></param>
        /// <param name="requestDetails"></param>
        /// <param name="flags"></param>
        /// <param name="extraInfo"></param>
        /// <param name="startupInfo"></param>
        /// <param name="inboundShellInformation"></param>
        internal void CreateShell(
            IntPtr pluginContext,
            WSManNativeApi.WSManPluginRequest requestDetails,
            int flags,
            string extraInfo,
            WSManNativeApi.WSManShellStartupInfo_UnToMan startupInfo,
            WSManNativeApi.WSManData_UnToMan inboundShellInformation)
        {
            if (null == requestDetails)
            {
                // Nothing can be done because requestDetails are required to report operation complete
                PSEtwLog.LogAnalyticInformational(PSEventId.ReportOperationComplete,
                    PSOpcode.Close, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                    "null",
                    Convert.ToString(WSManPluginErrorCodes.NullInvalidInput, CultureInfo.InvariantCulture),
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullInvalidInput,
                        "requestDetails",
                        "WSManPluginShell"),
                    String.Empty);
                return;
            }

            if ((null == requestDetails.senderDetails) ||
                (null == requestDetails.operationInfo))
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullInvalidInput,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullInvalidInput,
                        "requestDetails",
                        "WSManPluginShell"));
                return;
            }

            if (null == startupInfo)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullInvalidInput,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullInvalidInput,
                        "startupInfo",
                        "WSManPluginShell"));
                return;
            }

            if ((0 == startupInfo.inputStreamSet.streamIDsCount) || (0 == startupInfo.outputStreamSet.streamIDsCount))
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullInvalidStreamSets,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullInvalidStreamSet,
                        WSManPluginConstants.SupportedInputStream,
                        WSManPluginConstants.SupportedOutputStream));
                return;
            }

            if (String.IsNullOrEmpty(extraInfo))
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullInvalidInput,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullInvalidInput,
                        "extraInfo",
                        "WSManPluginShell"));
                return;
            }

            WSManPluginInstance.SetThreadProperties(requestDetails);

            // check if protocolversion option is honored
            if (!EnsureOptionsComply(requestDetails))
            {
                return;
            }

            int result = WSManPluginConstants.ExitCodeSuccess;
            WSManPluginShellSession mgdShellSession;
            WSManPluginOperationShutdownContext context;
            System.Byte[] convertedBase64 = null;

            try
            {
                PSSenderInfo senderInfo = GetPSSenderInfo(requestDetails.senderDetails);

                // inbound shell information is already verified by pwrshplugin.dll.. so no need
                // to verify here.
                WSManPluginServerTransportManager serverTransportMgr;

                if (Platform.IsWindows)
                {
                    serverTransportMgr = new WSManPluginServerTransportManager(BaseTransportManager.DefaultFragmentSize, new PSRemotingCryptoHelperServer());
                }

                else
                {
                    serverTransportMgr = new WSManPluginServerTransportManager(BaseTransportManager.DefaultFragmentSize, null);
                }

                PSEtwLog.LogAnalyticInformational(PSEventId.ServerCreateRemoteSession,
                    PSOpcode.Connect, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                    requestDetails.ToString(), senderInfo.UserInfo.Identity.Name, requestDetails.resourceUri);
                ServerRemoteSession remoteShellSession = ServerRemoteSession.CreateServerRemoteSession(senderInfo,
                    requestDetails.resourceUri,
                    extraInfo,
                    serverTransportMgr);

                if (null == remoteShellSession)
                {
                    WSManPluginInstance.ReportWSManOperationComplete(
                        requestDetails,
                        WSManPluginErrorCodes.SessionCreationFailed);
                    return;
                }

                context = new WSManPluginOperationShutdownContext(pluginContext, requestDetails.unmanagedHandle, IntPtr.Zero, false);
                if (null == context)
                {
                    ReportOperationComplete(requestDetails, WSManPluginErrorCodes.OutOfMemory);
                    return;
                }

                // Create a shell session wrapper to track and service future interactions.
                mgdShellSession = new WSManPluginShellSession(requestDetails, serverTransportMgr, remoteShellSession, context);
                AddToActiveShellSessions(mgdShellSession);
                mgdShellSession.SessionClosed += new EventHandler<EventArgs>(HandleShellSessionClosed);

                if (null != inboundShellInformation)
                {
                    if ((uint)WSManNativeApi.WSManDataType.WSMAN_DATA_TYPE_TEXT != inboundShellInformation.Type)
                    {
                        // only text data is supported
                        ReportOperationComplete(
                            requestDetails,
                            WSManPluginErrorCodes.InvalidInputDatatype,
                            StringUtil.Format(
                                RemotingErrorIdStrings.WSManPluginInvalidInputDataType,
                                "WSMAN_DATA_TYPE_TEXT"));
                        DeleteFromActiveShellSessions(requestDetails.unmanagedHandle);
                        return;
                    }
                    else
                    {
                        convertedBase64 = ServerOperationHelpers.ExtractEncodedXmlElement(
                            inboundShellInformation.Text,
                            WSManNativeApi.PS_CREATION_XML_TAG);
                    }
                }

                // now report the shell context to WSMan.
                PSEtwLog.LogAnalyticInformational(PSEventId.ReportContext,
                    PSOpcode.Connect, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                    requestDetails.ToString(), requestDetails.ToString());
                result = wsmanPinvokeStatic.WSManPluginReportContext(requestDetails.unmanagedHandle, 0, requestDetails.unmanagedHandle);

                if (WSManPluginConstants.ExitCodeSuccess != result)
                {
                    ReportOperationComplete(
                        requestDetails,
                        WSManPluginErrorCodes.ReportContextFailed,
                        StringUtil.Format(
                                RemotingErrorIdStrings.WSManPluginReportContextFailed));
                    DeleteFromActiveShellSessions(requestDetails.unmanagedHandle);
                    return;
                }
            }
            catch (System.Exception e)
            {
                CommandProcessorBase.CheckForSevereException(e);

                PSEtwLog.LogOperationalError(PSEventId.TransportError,
                    PSOpcode.Connect, PSTask.None, PSKeyword.UseAlwaysOperational, "00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000",
                    Convert.ToString(WSManPluginErrorCodes.ManagedException, CultureInfo.InvariantCulture), e.Message, e.StackTrace);

                DeleteFromActiveShellSessions(requestDetails.unmanagedHandle);
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.ManagedException,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginManagedException,
                        e.Message));
                return;
            }

            bool isRegisterWaitForSingleObjectSucceeded = true;

            //always synchronize calls to OperationComplete once notification handle is registered.. else duplicate OperationComplete calls are bound to happen
            lock (mgdShellSession.shellSyncObject)
            {
                mgdShellSession.registeredShutdownNotification = 1;

                // Wrap the provided handle so it can be passed to the registration function
                EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);

                if (Platform.IsWindows)
                {
                    SafeWaitHandle safeWaitHandle = new SafeWaitHandle(requestDetails.shutdownNotificationHandle, false); // Owned by WinRM
                    ClrFacade.SetSafeWaitHandle(eventWaitHandle, safeWaitHandle);
                }
                else
                {
                    //On non-windows platforms the shutdown notification is done through a callback instead of a windows event handle.
                    //Register the callback and this will then signal the event. Note, the gch object is deleted in the shell shutdown
                    //notification that will always come in to shut down the operation.

                    GCHandle gch = GCHandle.Alloc(eventWaitHandle);
                    IntPtr p = GCHandle.ToIntPtr(gch);

                    wsmanPinvokeStatic.WSManPluginRegisterShutdownCallback(
                                                           requestDetails.unmanagedHandle,
                                                           WSManPluginManagedEntryWrapper.workerPtrs.UnmanagedStruct.wsManPluginShutdownCallbackNative,
                                                           p);
                }


                mgdShellSession.registeredShutDownWaitHandle = ThreadPool.RegisterWaitForSingleObject(
                                 eventWaitHandle,
                                 new WaitOrTimerCallback(WSManPluginManagedEntryWrapper.PSPluginOperationShutdownCallback),
                                 context,
                                 -1, // INFINITE
                                 true); // TODO: Do I need to worry not being able to set missing WT_TRANSFER_IMPERSONATION?
                if (null == mgdShellSession.registeredShutDownWaitHandle)
                {
                    isRegisterWaitForSingleObjectSucceeded = false;
                }
            }

            if (!isRegisterWaitForSingleObjectSucceeded)
            {
                mgdShellSession.registeredShutdownNotification = 0;
                WSManPluginInstance.ReportWSManOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.ShutdownRegistrationFailed);
                DeleteFromActiveShellSessions(requestDetails.unmanagedHandle);
                return;
            }

            try
            {
                if (convertedBase64 != null)
                {
                    mgdShellSession.SendOneItemToSessionHelper(convertedBase64, WSManPluginConstants.SupportedInputStream);
                }
            }
            catch (System.Exception e)
            {
                CommandProcessorBase.CheckForSevereException(e);

                PSEtwLog.LogOperationalError(PSEventId.TransportError,
                    PSOpcode.Connect, PSTask.None, PSKeyword.UseAlwaysOperational, "00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000",
                    Convert.ToString(WSManPluginErrorCodes.ManagedException, CultureInfo.InvariantCulture), e.Message, e.StackTrace);

                if (Interlocked.Exchange(ref mgdShellSession.registeredShutdownNotification, 0) == 1)
                {
                    // unregister callback.. wait for any ongoing callbacks to complete.. nothing much we could do if this fails
                    bool ignore = mgdShellSession.registeredShutDownWaitHandle.Unregister(null);
                    mgdShellSession.registeredShutDownWaitHandle = null;

                    //this will called OperationComplete
                    PerformCloseOperation(context);
                }
                return;
            }

            return;
        }
예제 #7
0
 /// <summary>
 /// Alternate wrapper for WSManPluginOperationComplete. TODO: Needed? I could easily use the handle instead and get rid of this? It is only for easier refactoring...
 /// </summary>
 /// <param name="requestDetails"></param>
 /// <param name="errorCode"></param>
 /// <param name="errorMessage">Pre-formatted localized string</param>
 /// <returns></returns>
 internal static void ReportOperationComplete(
     WSManNativeApi.WSManPluginRequest requestDetails,
     WSManPluginErrorCodes errorCode,
     string errorMessage)
 {
     if (null != requestDetails)
     {
         ReportOperationComplete(requestDetails.unmanagedHandle, errorCode, errorMessage);
     }
     // else cannot report if requestDetails is null.
 }
예제 #8
0
        /// <summary>
        /// extract message from exception (if any) and report operation complete with it to WSMan 
        /// </summary>
        /// <param name="requestDetails"></param>
        /// <param name="reasonForClose"></param>
        internal static void ReportWSManOperationComplete(
            WSManNativeApi.WSManPluginRequest requestDetails,
            Exception reasonForClose)
        {
            Dbg.Assert(null != requestDetails, "requestDetails cannot be null in operation complete.");

            WSManPluginErrorCodes error = WSManPluginErrorCodes.NoError;
            String errorMessage = String.Empty;
            String stackTrace = String.Empty;

            if (null != reasonForClose)
            {
                error = WSManPluginErrorCodes.ManagedException;
                errorMessage = reasonForClose.Message;
                stackTrace = reasonForClose.StackTrace;
            }

            PSEtwLog.LogAnalyticInformational(PSEventId.ReportOperationComplete,
                PSOpcode.Close, PSTask.None,
                PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                requestDetails.ToString(),
                Convert.ToString(error, CultureInfo.InvariantCulture),
                errorMessage,
                stackTrace);

            if (null != reasonForClose)
            {
                // report operation complete to wsman with the error message (if any).
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.ManagedException,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginManagedException,
                        reasonForClose.Message));
            }
            else
            {
                ReportOperationComplete(
                    requestDetails.unmanagedHandle,
                    WSManPluginErrorCodes.NoError);
            }
        }
예제 #9
0
 internal WSManPluginCommandSession(
     WSManNativeApi.WSManPluginRequest creationRequestDetails,
     WSManPluginServerTransportManager transportMgr,
     ServerRemoteSession remoteSession)
     : base(creationRequestDetails, transportMgr)
 {
     _remoteSession = remoteSession;
     cmdSyncObject = new System.Object();
 }
예제 #10
0
        /// <summary>
        /// Main Routine for Connect on a Shell. 
        /// Calls in server remotesessions ExecuteConnect to run the Connect algorithm
        /// This call is synchronous. i.e WSManOperationComplete will be called before the routine completes
        /// </summary>
        /// <param name="requestDetails"></param>
        /// <param name="flags"></param>
        /// <param name="inboundConnectInformation"></param>
        internal override void ExecuteConnect(
            WSManNativeApi.WSManPluginRequest requestDetails, // in
            int flags, // in
            WSManNativeApi.WSManData_UnToMan inboundConnectInformation) // in optional
        {
            if (null == inboundConnectInformation)
            {
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullInvalidInput,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullInvalidInput,
                        "inboundConnectInformation",
                        "WSManPluginShellConnect"));
                return;
            }

            //not registering shutdown event as this is a synchronous operation.

            IntPtr responseXml = IntPtr.Zero;
            try
            {
                System.Byte[] inputData;
                System.Byte[] outputData;

                // Retrieve the string (Base64 encoded) 
                inputData = ServerOperationHelpers.ExtractEncodedXmlElement(
                    inboundConnectInformation.Text,
                    WSManNativeApi.PS_CONNECT_XML_TAG);

                //this will raise exceptions on failure
                try
                {
                    _remoteSession.ExecuteConnect(inputData, out outputData);

                    //construct Xml to send back
                    string responseData = String.Format(System.Globalization.CultureInfo.InvariantCulture,
                                    "<{0} xmlns=\"{1}\">{2}</{0}>",
                                    WSManNativeApi.PS_CONNECTRESPONSE_XML_TAG,
                                    WSManNativeApi.PS_XML_NAMESPACE,
                                    Convert.ToBase64String(outputData));

                    //TODO: currently using OperationComplete to report back the responseXml. This will need to change to use WSManReportObject
                    //that is currently internal.
                    WSManPluginInstance.ReportOperationComplete(requestDetails, WSManPluginErrorCodes.NoError, responseData);
                }
                catch (PSRemotingDataStructureException ex)
                {
                    WSManPluginInstance.ReportOperationComplete(requestDetails, WSManPluginErrorCodes.PluginConnectOperationFailed, ex.Message);
                }
            }
            catch (OutOfMemoryException)
            {
                WSManPluginInstance.ReportOperationComplete(requestDetails, WSManPluginErrorCodes.OutOfMemory);
            }
            finally
            {
                if (responseXml != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(responseXml);
                }
            }

            return;
        }
예제 #11
0
        // Create a new command in the shell context.
        internal void CreateCommand(
            IntPtr pluginContext,
            WSManNativeApi.WSManPluginRequest requestDetails,
            int flags,
            string commandLine,
            WSManNativeApi.WSManCommandArgSet arguments)
        {
            try
            {
                // inbound cmd information is already verified.. so no need to verify here.
                WSManPluginCommandTransportManager serverCmdTransportMgr = new WSManPluginCommandTransportManager(transportMgr);
                serverCmdTransportMgr.Initialize();

                // Apply quota limits on the command transport manager
                _remoteSession.ApplyQuotaOnCommandTransportManager(serverCmdTransportMgr);

                WSManPluginCommandSession mgdCmdSession = new WSManPluginCommandSession(requestDetails, serverCmdTransportMgr, _remoteSession);
                AddToActiveCmdSessions(mgdCmdSession);
                mgdCmdSession.SessionClosed += new EventHandler<EventArgs>(this.HandleCommandSessionClosed);

                mgdCmdSession.shutDownContext = new WSManPluginOperationShutdownContext(
                    pluginContext,
                    creationRequestDetails.unmanagedHandle,
                    mgdCmdSession.creationRequestDetails.unmanagedHandle,
                    false);

                do
                {
                    if (!mgdCmdSession.ProcessArguments(arguments))
                    {
                        WSManPluginInstance.ReportOperationComplete(
                            requestDetails,
                            WSManPluginErrorCodes.InvalidArgSet,
                            StringUtil.Format(
                                RemotingErrorIdStrings.WSManPluginInvalidArgSet,
                                "WSManPluginCommand"));
                        break;
                    }

                    // Report plugin context to WSMan
                    mgdCmdSession.ReportContext();
                } while (false);
            }
            catch (System.Exception e)
            {
                CommandProcessorBase.CheckForSevereException(e);

                // if there is an exception creating remote session send the message to client.
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.ManagedException,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginManagedException,
                        e.Message));
            }
        }
예제 #12
0
        internal WSManPluginShellSession(
            WSManNativeApi.WSManPluginRequest creationRequestDetails,
            WSManPluginServerTransportManager transportMgr,
            ServerRemoteSession remoteSession,
            WSManPluginOperationShutdownContext shutDownContext)
            : base(creationRequestDetails, transportMgr)
        {
            _remoteSession = remoteSession;
            _remoteSession.Closed +=
                new EventHandler<RemoteSessionStateMachineEventArgs>(this.HandleServerRemoteSessionClosed);

            _activeCommandSessions = new Dictionary<IntPtr, WSManPluginCommandSession>();
            this.shellSyncObject = new System.Object();
            this.shutDownContext = shutDownContext;
        }
예제 #13
0
 internal abstract void ExecuteConnect(
     WSManNativeApi.WSManPluginRequest requestDetails, // in
     int flags, // in
     WSManNativeApi.WSManData_UnToMan inboundConnectInformation); // in optional
예제 #14
0
        internal bool EnableSessionToSendDataToClient(
            WSManNativeApi.WSManPluginRequest requestDetails,
            int flags,
            WSManNativeApi.WSManStreamIDSet_UnToMan streamSet,
            WSManPluginOperationShutdownContext ctxtToReport)
        {
            if (true == isClosed)
            {
                WSManPluginInstance.ReportWSManOperationComplete(requestDetails, lastErrorReported);
                return false;
            }

            if ((null == streamSet) ||
                (1 != streamSet.streamIDsCount))
            {
                // only "stdout" is the supported output stream.
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidOutputStream,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidOutputStream,
                        WSManPluginConstants.SupportedOutputStream));
                return false;
            }

            if (!String.Equals(streamSet.streamIDs[0], WSManPluginConstants.SupportedOutputStream, StringComparison.Ordinal))
            {
                // only "stdout" is the supported output stream.
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidOutputStream,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidOutputStream,
                        WSManPluginConstants.SupportedOutputStream));
                return false;
            }

            return transportMgr.EnableTransportManagerSendDataToClient(requestDetails, ctxtToReport);
        }
예제 #15
0
        internal void DoClose(
            bool isShuttingDown,
            Exception reasonForClose)
        {
            if (_isClosed)
            {
                return;
            }

            lock (_syncObject)
            {
                if (_isClosed)
                {
                    return;
                }

                _isClosed          = true;
                _lastErrorReported = reasonForClose;

                if (!_isRequestPending)
                {
                    // release threads blocked on the sending data to client if any
                    _waitHandle.Set();
                }
            }

            // only one thread will reach here

            // let everyone know that we are about to close
            try
            {
                RaiseClosingEvent();

                foreach (var cmdTransportKvp in _activeCmdTransportManagers)
                {
                    cmdTransportKvp.Value.Close(reasonForClose);
                }

                _activeCmdTransportManagers.Clear();

                if (_registeredShutDownWaitHandle != null)
                {
                    // This will not wait for the callback to complete.
                    _registeredShutDownWaitHandle.Unregister(null);
                    _registeredShutDownWaitHandle = null;
                }

                // Delete the context only if isShuttingDown != true. isShuttingDown will
                // be true only when the method is called from RegisterWaitForSingleObject
                // handler..in which case the context will be freed from the callback.
                if (_shutDownContext != null)
                {
                    _shutDownContext = null;
                }

                // This might happen when client did not send a receive request
                // but the server is closing
                if (_requestDetails != null)
                {
                    // Notify that no more data is being sent on this transport.
                    WSManNativeApi.WSManPluginReceiveResult(
                        _requestDetails.unmanagedHandle,
                        (int)WSManNativeApi.WSManFlagReceive.WSMAN_FLAG_RECEIVE_RESULT_NO_MORE_DATA,
                        WSManPluginConstants.SupportedOutputStream,
                        IntPtr.Zero,
                        WSManNativeApi.WSMAN_COMMAND_STATE_DONE,
                        0);

                    WSManPluginInstance.ReportWSManOperationComplete(_requestDetails, reasonForClose);
                    // We should not use request details again after reporting operation complete
                    // so releasing the resource. Remember not to free this memory as this memory
                    // is allocated and owned by WSMan.
                    _requestDetails = null;
                }
            }
            finally
            {
                // dispose resources
                _waitHandle.Dispose();
            }
        }
예제 #16
0
        internal bool ProcessArguments(
            WSManNativeApi.WSManCommandArgSet arguments)
        {
            if (1 != arguments.argsCount)
            {
                return false;
            }

            System.Byte[] convertedBase64 = Convert.FromBase64String(arguments.args[0]);
            transportMgr.ProcessRawData(convertedBase64, WSManPluginConstants.SupportedInputStream);

            return true;
        }
예제 #17
0
        internal void SendOneItemToSession(
            WSManNativeApi.WSManPluginRequest requestDetails,
            int flags,
            string stream,
            WSManNativeApi.WSManData_UnToMan inboundData)
        {
            if ((!String.Equals(stream, WSManPluginConstants.SupportedInputStream, StringComparison.Ordinal)) &&
                (!String.Equals(stream, WSManPluginConstants.SupportedPromptResponseStream, StringComparison.Ordinal)))
            {
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidInputStream,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidInputStream,
                        WSManPluginConstants.SupportedInputStream));
                return;
            }

            if (null == inboundData)
            {
                // no data is supplied..just ignore.
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NoError);
                return;
            }

            if ((uint)WSManNativeApi.WSManDataType.WSMAN_DATA_TYPE_BINARY != inboundData.Type)
            {
                // only binary data is supported
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidInputDatatype,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidInputStream,
                        "WSMAN_DATA_TYPE_BINARY"));
                return;
            }

            lock (_syncObject)
            {
                if (true == isClosed)
                {
                    WSManPluginInstance.ReportWSManOperationComplete(requestDetails, lastErrorReported);
                    return;
                }
                // store the send request details..because the operation complete
                // may happen from a different thread.
                sendRequestDetails = requestDetails;
            }

            SendOneItemToSessionHelper(inboundData.Data, stream);

            // report operation complete.
            ReportSendOperationComplete();
        }
예제 #18
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="requestDetails"></param>
 internal void Stop(
     WSManNativeApi.WSManPluginRequest requestDetails)
 {
     // stop the command..command will be stoped if we raise ClosingEvent on
     // transport manager.
     transportMgr.PerformStop();
     WSManPluginInstance.ReportWSManOperationComplete(requestDetails, null);
 }
예제 #19
0
        /// <summary>
        /// Sets thread properties like UI Culture, Culture etc..This is needed as code is transitioning from
        /// unmanaged heap to managed heap...and thread properties are not set correctly during this 
        /// transition.
        /// Currently WSMan provider supplies only UI Culture related data..so only UI Culture is set.
        /// </summary>
        /// <param name="requestDetails"></param>
        internal static void SetThreadProperties(
            WSManNativeApi.WSManPluginRequest requestDetails)
        {
            // requestDetails cannot not be null.
            Dbg.Assert(null != requestDetails, "requestDetails cannot be null");

            //IntPtr nativeLocaleData = IntPtr.Zero;
            WSManNativeApi.WSManDataStruct outputStruct = new WSManNativeApi.WSManDataStruct();
            int hResult = wsmanPinvokeStatic.WSManPluginGetOperationParameters(
                requestDetails.unmanagedHandle,
                WSManPluginConstants.WSManPluginParamsGetRequestedLocale,
                outputStruct);
            //ref nativeLocaleData);
            bool retreivingLocaleSucceeded = (0 == hResult);
            WSManNativeApi.WSManData_UnToMan localeData = WSManNativeApi.WSManData_UnToMan.UnMarshal(outputStruct); // nativeLocaleData

            //IntPtr nativeDataLocaleData = IntPtr.Zero;
            hResult = wsmanPinvokeStatic.WSManPluginGetOperationParameters(
                requestDetails.unmanagedHandle,
                WSManPluginConstants.WSManPluginParamsGetRequestedDataLocale,
                outputStruct);
            //ref nativeDataLocaleData);
            bool retreivingDataLocaleSucceeded = ((int)WSManPluginErrorCodes.NoError == hResult);
            WSManNativeApi.WSManData_UnToMan dataLocaleData = WSManNativeApi.WSManData_UnToMan.UnMarshal(outputStruct); // nativeDataLocaleData

            // Set the UI Culture
            try
            {
                if (retreivingLocaleSucceeded && ((uint)WSManNativeApi.WSManDataType.WSMAN_DATA_TYPE_TEXT == localeData.Type))
                {
                    CultureInfo uiCultureToUse = new CultureInfo(localeData.Text);
                    ClrFacade.SetCurrentThreadUiCulture(uiCultureToUse);
                }
            }
            // ignore if there is any exception constructing the culture..
            catch (ArgumentException)
            {
            }

            // Set the Culture
            try
            {
                if (retreivingDataLocaleSucceeded && ((uint)WSManNativeApi.WSManDataType.WSMAN_DATA_TYPE_TEXT == dataLocaleData.Type))
                {
                    CultureInfo cultureToUse = new CultureInfo(dataLocaleData.Text);
                    ClrFacade.SetCurrentThreadCulture(cultureToUse);
                }
            }
            // ignore if there is any exception constructing the culture..
            catch (ArgumentException)
            {
            }
        }
예제 #20
0
 /// <summary>
 /// Main routine for connect on a command/pipeline.. Currently NO-OP
 /// will be enhanced later to support intelligent connect... like ending input streams on pipelines
 /// that are still waiting for input data
 /// </summary>
 /// <param name="requestDetails"></param>
 /// <param name="flags"></param>
 /// <param name="inboundConnectInformation"></param>
 internal override void ExecuteConnect(
     WSManNativeApi.WSManPluginRequest requestDetails,
     int flags,
     WSManNativeApi.WSManData_UnToMan inboundConnectInformation)
 {
     WSManPluginInstance.ReportOperationComplete(
         requestDetails,
         WSManPluginErrorCodes.NoError);
     return;
 }
예제 #21
0
 /// <summary>
 /// Wrapper for WSManPluginOperationComplete. It performs validation prior to making the call.
 /// </summary>
 /// <param name="requestDetails"></param>
 /// <param name="errorCode"></param>
 internal static void ReportOperationComplete(
     WSManNativeApi.WSManPluginRequest requestDetails,
     WSManPluginErrorCodes errorCode)
 {
     if (null != requestDetails &&
         IntPtr.Zero != requestDetails.unmanagedHandle)
     {
         wsmanPinvokeStatic.WSManPluginOperationComplete(
             requestDetails.unmanagedHandle,
             0,
             (int)errorCode,
             null);
     }
     // else cannot report if requestDetails is null.
 }
예제 #22
0
        /// <summary>
        /// Constructs a WSManTransportErrorOccuredEventArgs instance from the supplied data
        /// </summary>
        /// <param name="wsmanAPIHandle">
        /// WSMan API handle to use to get error messages from WSMan error id(s)
        /// </param>
        /// <param name="wsmanSessionTM">
        /// Session Transportmanager to use to get error messages (for redirect)
        /// </param>
        /// <param name="errorStruct">
        /// Error structure supplied by callbacks from WSMan API
        /// </param>
        /// <param name="transportMethodReportingError">
        /// The transport method call that reported this error.
        /// </param>
        /// <param name="resourceString">
        /// resource string that holds the message.
        /// </param>
        /// <param name="resourceArgs">
        /// Arguments to pass to the resource
        /// </param>
        /// <returns>
        /// An instance of WSManTransportErrorOccuredEventArgs
        /// </returns>
        internal static TransportErrorOccuredEventArgs ConstructTransportErrorEventArgs(IntPtr wsmanAPIHandle,
            WSManClientSessionTransportManager wsmanSessionTM,
            WSManNativeApi.WSManError errorStruct,
            TransportMethodEnum transportMethodReportingError,
            string resourceString,
            params object[] resourceArgs)
        {
            PSRemotingTransportException e;

            //For the first two special error conditions, it is remotely possible that the wsmanSessionTM is null when the failures are returned 
            //as part of command TM operations (could be returned because of RC retries under the hood)
            //Not worth to handle these cases separately as there are very corner scenarios, but need to make sure wsmanSessionTM is not referenced


            // Destination server is reporting that URI redirect is required for this user.
            if ((errorStruct.errorCode == WSManNativeApi.ERROR_WSMAN_REDIRECT_REQUESTED) && (wsmanSessionTM != null))
            {
                IntPtr wsmanSessionHandle = wsmanSessionTM.SessionHandle;
                // populate the transport message with the redirection uri..this will
                // allow caller to make a new connection.
                string redirectLocation = WSManNativeApi.WSManGetSessionOptionAsString(wsmanSessionHandle,
                    WSManNativeApi.WSManSessionOption.WSMAN_OPTION_REDIRECT_LOCATION);
                string winrmMessage = ParseEscapeWSManErrorMessage(
                    WSManNativeApi.WSManGetErrorMessage(wsmanAPIHandle, errorStruct.errorCode)).Trim();

                e = new PSRemotingTransportRedirectException(redirectLocation,
                    PSRemotingErrorId.URIEndPointNotResolved,
                    RemotingErrorIdStrings.URIEndPointNotResolved,
                    winrmMessage,
                    redirectLocation);
            }
            else if ((errorStruct.errorCode == WSManNativeApi.ERROR_WSMAN_INVALID_RESOURCE_URI) && (wsmanSessionTM != null))
            {
                string configurationName =
                    wsmanSessionTM.ConnectionInfo.ShellUri.Replace(Remoting.Client.WSManNativeApi.ResourceURIPrefix, string.Empty);
                string errorMessage = PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidConfigurationName,
                                                   configurationName,
                                                   wsmanSessionTM.ConnectionInfo.ComputerName);

                e = new PSRemotingTransportException(PSRemotingErrorId.InvalidConfigurationName,
                                                   RemotingErrorIdStrings.ConnectExCallBackError, wsmanSessionTM.ConnectionInfo.ComputerName, errorMessage);

                e.TransportMessage = ParseEscapeWSManErrorMessage(
                   WSManNativeApi.WSManGetErrorMessage(wsmanAPIHandle, errorStruct.errorCode));
            }
            else
            {
                // Construct specific error message and then append this message pointing to our own
                // help topic. PowerShell's about help topic "about_Remote_Troubleshooting" should
                // contain all the trouble shooting information.
                string wsManErrorMessage = PSRemotingErrorInvariants.FormatResourceString(resourceString, resourceArgs);
                e = new PSRemotingTransportException(PSRemotingErrorId.TroubleShootingHelpTopic,
                    RemotingErrorIdStrings.TroubleShootingHelpTopic,
                    wsManErrorMessage);

                e.TransportMessage = ParseEscapeWSManErrorMessage(
                    WSManNativeApi.WSManGetErrorMessage(wsmanAPIHandle, errorStruct.errorCode));
            }

            e.ErrorCode = errorStruct.errorCode;
            TransportErrorOccuredEventArgs eventargs =
                new TransportErrorOccuredEventArgs(e, transportMethodReportingError);
            return eventargs;
        }
예제 #23
0
        /// <summary>
        /// Helper function to validate incoming values
        /// </summary>
        /// <param name="requestDetails"></param>
        /// <param name="shellContext"></param>
        /// <param name="inputFunctionName"></param>
        /// <returns></returns>
        private bool validateIncomingContexts(
            WSManNativeApi.WSManPluginRequest requestDetails,
            IntPtr shellContext,
            string inputFunctionName)
        {
            if (null == requestDetails)
            {
                // Nothing can be done because requestDetails are required to report operation complete
                PSEtwLog.LogAnalyticInformational(PSEventId.ReportOperationComplete,
                    PSOpcode.Close, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                    "null",
                    Convert.ToString(WSManPluginErrorCodes.NullInvalidInput, CultureInfo.InvariantCulture),
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullInvalidInput,
                        "requestDetails",
                        inputFunctionName),
                    String.Empty);
                return false;
            }

            if (IntPtr.Zero == shellContext)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullShellContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullShellContext,
                        "ShellContext",
                        inputFunctionName));
                return false;
            }
            return true;
        }
예제 #24
0
        /// <summary>
        /// Sets a DWORD value for a WSMan Session option.
        /// </summary>
        /// <param name="option"></param>
        /// <param name="dwordData"></param>
        /// <exception cref="PSInvalidOperationException">
        /// Setting session option failed with a non-zero error code.
        /// </exception>
        internal void SetWSManSessionOption(WSManNativeApi.WSManSessionOption option, int dwordData)
        {
            int result = WSManNativeApi.WSManSetSessionOption(_wsManSessionHandle,
                option, new WSManNativeApi.WSManDataDWord(dwordData));

            if (result != 0)
            {
                // Get the error message from WSMan
                string errorMessage = WSManNativeApi.WSManGetErrorMessage(WSManAPIData.WSManAPIHandle, result);

                PSInvalidOperationException exception = new PSInvalidOperationException(errorMessage);
                throw exception;
            }
        }
예제 #25
0
        internal void StopCommand(
            WSManNativeApi.WSManPluginRequest requestDetails,
            IntPtr shellContext,
            IntPtr commandContext)
        {
            if (null == requestDetails)
            {
                // Nothing can be done because requestDetails are required to report operation complete
                PSEtwLog.LogAnalyticInformational(PSEventId.ReportOperationComplete,
                    PSOpcode.Close, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                    "null",
                    Convert.ToString(WSManPluginErrorCodes.NullInvalidInput, CultureInfo.InvariantCulture),
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullInvalidInput,
                        "requestDetails",
                        "StopCommand"),
                    String.Empty);
                return;
            }

            SetThreadProperties(requestDetails);

            PSEtwLog.LogAnalyticInformational(PSEventId.ServerStopCommand,
                    PSOpcode.Disconnect, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                    ((IntPtr)shellContext).ToString(),
                    ((IntPtr)commandContext).ToString(),
                    requestDetails.ToString());

            WSManPluginShellSession mgdShellSession = GetFromActiveShellSessions(shellContext);
            if (null == mgdShellSession)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidShellContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidShellContext));
                return;
            }

            WSManPluginCommandSession mgdCommandSession = mgdShellSession.GetCommandSession(commandContext);
            if (null == mgdCommandSession)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidCommandContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidCommandContext));
                return;
            }

            mgdCommandSession.Stop(requestDetails);
        }
예제 #26
0
        /// <summary>
        /// Sets a string value for a WSMan Session option.
        /// </summary>
        /// <param name="option"></param>
        /// <param name="stringData"></param>
        /// <exception cref="PSInvalidOperationException">
        /// Setting session option failed with a non-zero error code.
        /// </exception>
        internal void SetWSManSessionOption(WSManNativeApi.WSManSessionOption option, string stringData)
        {
            using (WSManNativeApi.WSManData_ManToUn data = new WSManNativeApi.WSManData_ManToUn(stringData))
            {
                int result = WSManNativeApi.WSManSetSessionOption(_wsManSessionHandle,
                      option, data);

                if (result != 0)
                {
                    // Get the error message from WSMan
                    string errorMessage = WSManNativeApi.WSManGetErrorMessage(WSManAPIData.WSManAPIHandle, result);

                    PSInvalidOperationException exception = new PSInvalidOperationException(errorMessage);
                    throw exception;
                }
            }
        }
예제 #27
0
        /// <summary>
        /// Send data to the shell / command specified.
        /// </summary>
        /// <param name="requestDetails"></param>
        /// <param name="flags"></param>
        /// <param name="shellContext"></param>
        /// <param name="commandContext"></param>
        /// <param name="stream"></param>
        /// <param name="inboundData"></param>
        internal void SendOneItemToShellOrCommand(
            WSManNativeApi.WSManPluginRequest requestDetails,
            int flags,
            IntPtr shellContext,
            IntPtr commandContext,
            string stream,
            WSManNativeApi.WSManData_UnToMan inboundData)
        {
            if (!validateIncomingContexts(requestDetails, shellContext, "SendOneItemToShellOrCommand"))
            {
                return;
            }

            SetThreadProperties(requestDetails);

            PSEtwLog.LogAnalyticInformational(PSEventId.ServerReceivedData,
                    PSOpcode.Open, PSTask.None,
                    PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                ((IntPtr)shellContext).ToString(), ((IntPtr)commandContext).ToString(), requestDetails.ToString());

            WSManPluginShellSession mgdShellSession = GetFromActiveShellSessions(shellContext);
            if (null == mgdShellSession)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidShellContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidShellContext)
                    );
                return;
            }

            if (IntPtr.Zero == commandContext)
            {
                // the data is destined for shell (runspace) session. so let shell handle it
                mgdShellSession.SendOneItemToSession(requestDetails, flags, stream, inboundData);
                return;
            }

            // the data is destined for command.
            WSManPluginCommandSession mgdCmdSession = mgdShellSession.GetCommandSession(commandContext);
            if (null == mgdCmdSession)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.InvalidCommandContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginInvalidCommandContext));
                return;
            }

            mgdCmdSession.SendOneItemToSession(requestDetails, flags, stream, inboundData);
        }
예제 #28
0
        /// <summary>
        /// Was private. Made protected internal for easier testing
        /// </summary>
        /// <param name="requestDetails"></param>
        /// <returns></returns>
        protected internal bool EnsureOptionsComply(
            WSManNativeApi.WSManPluginRequest requestDetails)
        {
            WSManNativeApi.WSManOption[] options = requestDetails.operationInfo.optionSet.options;
            bool isProtocolVersionDeclared = false;

            for (int i = 0; i < options.Length; i++) // What about requestDetails.operationInfo.optionSet.optionsCount? It is a hold over from the C++ API. Safer is Length.
            {
                WSManNativeApi.WSManOption option = options[i];

                if (String.Equals(option.name, WSManPluginConstants.PowerShellStartupProtocolVersionName, StringComparison.Ordinal))
                {
                    if (!EnsureProtocolVersionComplies(requestDetails, option.value))
                    {
                        return false;
                    }
                    isProtocolVersionDeclared = true;
                }

                if (0 == String.Compare(option.name, 0, WSManPluginConstants.PowerShellOptionPrefix, 0, WSManPluginConstants.PowerShellOptionPrefix.Length, StringComparison.Ordinal))
                {
                    if (option.mustComply)
                    {
                        ReportOperationComplete(
                            requestDetails,
                            WSManPluginErrorCodes.OptionNotUnderstood,
                            StringUtil.Format(
                                RemotingErrorIdStrings.WSManPluginOptionNotUnderstood,
                                option.name,
                                System.Management.Automation.PSVersionInfo.BuildVersion,
                                WSManPluginConstants.PowerShellStartupProtocolVersionValue));
                        return false;
                    }
                }
            }

            if (!isProtocolVersionDeclared)
            {
                ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.ProtocolVersionNotFound,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginProtocolVersionNotFound,
                        WSManPluginConstants.PowerShellStartupProtocolVersionName,
                        System.Management.Automation.PSVersionInfo.BuildVersion,
                        WSManPluginConstants.PowerShellStartupProtocolVersionValue));
                return false;
            }

            return true;
        }
예제 #29
0
        /// <summary>
        /// used to create PSPrincipal object from senderDetails struct.
        /// </summary>
        /// <param name="senderDetails"></param>
        /// <returns></returns>
        private PSSenderInfo GetPSSenderInfo(
            WSManNativeApi.WSManSenderDetails senderDetails)
        {
            // senderDetails will not be null.
            Dbg.Assert(null != senderDetails, "senderDetails cannot be null");

            // Construct PSIdentity
            PSCertificateDetails psCertDetails = null;
            // Construct Certificate Details
            if (null != senderDetails.certificateDetails)
            {
                psCertDetails = new PSCertificateDetails(
                    senderDetails.certificateDetails.subject,
                    senderDetails.certificateDetails.issuerName,
                    senderDetails.certificateDetails.issuerThumbprint);
            }

            // Construct PSPrincipal
            PSIdentity psIdentity = new PSIdentity(senderDetails.authenticationMechanism, true, senderDetails.senderName, psCertDetails);

            // For Virtual and RunAs accounts WSMan specifies the client token via an environment variable and
            // senderDetails.clientToken should not be used.
            IntPtr clientToken = GetRunAsClientToken();
            clientToken = (clientToken != IntPtr.Zero) ? clientToken : senderDetails.clientToken;
            WindowsIdentity windowsIdentity = null;
            if (clientToken != IntPtr.Zero)
            {
                try
                {
                    windowsIdentity = new WindowsIdentity(clientToken, senderDetails.authenticationMechanism);
                }
                // Suppress exceptions..So windowsIdentity = null in these cases
                catch (ArgumentException)
                {
                    // userToken is 0.
                    // -or-
                    // userToken is duplicated and invalid for impersonation.
                }
                catch (System.Security.SecurityException)
                {
                    // The caller does not have the correct permissions. 
                    // -or-
                    // A Win32 error occurred.
                }
            }

            PSPrincipal userPrincipal = new PSPrincipal(psIdentity, windowsIdentity);
            PSSenderInfo result = new PSSenderInfo(userPrincipal, senderDetails.httpUrl);
            return result;
        }
예제 #30
0
        /// <summary>
        /// Verifies that the protocol version is in the correct syntax and supported.
        /// </summary>
        /// <param name="requestDetails"></param>
        /// <param name="clientVersionString"></param>
        /// <returns></returns>
        protected internal bool EnsureProtocolVersionComplies(
            WSManNativeApi.WSManPluginRequest requestDetails,
            string clientVersionString)
        {
            if (String.Equals(clientVersionString, WSManPluginConstants.PowerShellStartupProtocolVersionValue, StringComparison.Ordinal))
            {
                return true;
            }

            // Check if major versions are equal and server's minor version is smaller..
            // if so client's version is supported by the server. The understanding is
            // that minor version changes do not break the protocol.
            System.Version clientVersion = Utils.StringToVersion(clientVersionString);
            System.Version serverVersion = Utils.StringToVersion(WSManPluginConstants.PowerShellStartupProtocolVersionValue);

            if ((null != clientVersion) && (null != serverVersion) &&
                (clientVersion.Major == serverVersion.Major) &&
                (clientVersion.Minor >= serverVersion.Minor))
            {
                return true;
            }

            ReportOperationComplete(
                requestDetails,
                WSManPluginErrorCodes.ProtocolVersionNotMatch,
                StringUtil.Format(
                    RemotingErrorIdStrings.WSManPluginProtocolVersionNotMatch,
                    WSManPluginConstants.PowerShellStartupProtocolVersionValue,
                    System.Management.Automation.PSVersionInfo.BuildVersion,
                    clientVersionString));
            return false;
        }
예제 #31
0
        /// <summary>
        /// If flush is true, data will be sent immediately to the client. This is accomplished
        /// by using WSMAN_FLAG_RECEIVE_FLUSH flag provided by WSMan API.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="flush"></param>
        /// <param name="reportAsPending"></param>
        /// <param name="reportAsDataBoundary"></param>
        protected override void SendDataToClient(
            byte[] data,
            bool flush,
            bool reportAsPending,
            bool reportAsDataBoundary)
        {
            if (true == _isClosed)
            {
                return;
            }

            // double-check locking mechanism is used here to avoid entering into lock
            // every time data is sent..entering/exiting from lock is costly.
            if (!_isRequestPending)
            {
                // Dont send data until we have received request from client.
                // The following blocks the calling thread. The thread is
                // unblocked once a request from client arrives.
                _waitHandle.WaitOne();
                _isRequestPending = true;
                // at this point request must be pending..so dispose waitHandle
                _waitHandle.Dispose();
            }

            int result = (int)WSManPluginErrorCodes.NoError;

            // at this point we have pending request from client. so it is safe
            // to send data to client using WSMan API.
            using (WSManNativeApi.WSManData_ManToUn dataToBeSent = new WSManNativeApi.WSManData_ManToUn(data))
            {
                lock (_syncObject)
                {
                    if (!_isClosed)
                    {
                        int flags = 0;
                        if (flush)
                        {
                            flags |= (int)WSManNativeApi.WSManFlagReceive.WSMAN_FLAG_RECEIVE_FLUSH;
                        }
                        if (reportAsDataBoundary)
                        {
                            // currently assigning hardcoded value for this flag, this is a new change in wsman.h and needs to be replaced with the actual definition once
                            // modified wsman.h is in public headers
                            flags |= (int)WSManNativeApi.WSManFlagReceive.WSMAN_FLAG_RECEIVE_RESULT_DATA_BOUNDARY;
                        }

                        result = WSManNativeApi.WSManPluginReceiveResult(
                            _requestDetails.unmanagedHandle,
                            flags,
                            WSManPluginConstants.SupportedOutputStream,
                            dataToBeSent,
                            reportAsPending ? WSManNativeApi.WSMAN_COMMAND_STATE_PENDING : null,
                            0);
                    }
                }
            }

            if ((int)WSManPluginErrorCodes.NoError != result)
            {
                ReportError(result, "WSManPluginReceiveResult");
            }
        }
예제 #32
0
        /// <summary>
        /// report operation complete to WSMan and supply a reason (if any)
        /// </summary>
        /// <param name="requestDetails"></param>
        /// <param name="errorCode"></param>
        internal static void ReportWSManOperationComplete(
            WSManNativeApi.WSManPluginRequest requestDetails,
            WSManPluginErrorCodes errorCode)
        {
            Dbg.Assert(null != requestDetails, "requestDetails cannot be null in operation complete.");

            PSEtwLog.LogAnalyticInformational(PSEventId.ReportOperationComplete,
                PSOpcode.Close, PSTask.None,
                PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                (requestDetails.unmanagedHandle).ToString(),
                Convert.ToString(errorCode, CultureInfo.InvariantCulture),
                String.Empty,
                String.Empty);

            ReportOperationComplete(requestDetails.unmanagedHandle, errorCode);
        }
        /// <summary>
        /// Report session context to WSMan..this will let WSMan send ACK to
        /// client and client can send data.
        /// </summary>
        internal void ReportContext()
        {
            int  result = 0;
            bool isRegisterWaitForSingleObjectFailed = false;

            lock (_syncObject)
            {
                if (true == isClosed)
                {
                    return;
                }

                if (!isContextReported)
                {
                    isContextReported = true;
                    PSEtwLog.LogAnalyticInformational(PSEventId.ReportContext,
                                                      PSOpcode.Connect, PSTask.None,
                                                      PSKeyword.ManagedPlugin | PSKeyword.UseAlwaysAnalytic,
                                                      creationRequestDetails.ToString(), creationRequestDetails.ToString());

                    //RACE TO BE FIXED - As soon as this API is called, WinRM service will send CommandResponse back and Signal is expected anytime
                    // If Signal comes and executes before registering the notification handle, cleanup will be messed
                    result = WSManNativeApi.WSManPluginReportContext(creationRequestDetails.unmanagedHandle, 0, creationRequestDetails.unmanagedHandle);
                    if (Platform.IsWindows && (WSManPluginConstants.ExitCodeSuccess == result))
                    {
                        registeredShutdownNotification = 1;

                        // Wrap the provided handle so it can be passed to the registration function
                        SafeWaitHandle  safeWaitHandle  = new SafeWaitHandle(creationRequestDetails.shutdownNotificationHandle, false); // Owned by WinRM
                        EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
                        ClrFacade.SetSafeWaitHandle(eventWaitHandle, safeWaitHandle);

                        // Register shutdown notification handle
                        this.registeredShutDownWaitHandle = ThreadPool.RegisterWaitForSingleObject(
                            eventWaitHandle,
                            new WaitOrTimerCallback(WSManPluginManagedEntryWrapper.PSPluginOperationShutdownCallback),
                            shutDownContext,
                            -1,    // INFINITE
                            true); // TODO: Do I need to worry not being able to set missing WT_TRANSFER_IMPERSONATION?
                        if (null == this.registeredShutDownWaitHandle)
                        {
                            isRegisterWaitForSingleObjectFailed = true;
                            registeredShutdownNotification      = 0;
                        }
                    }
                }
            }

            if ((WSManPluginConstants.ExitCodeSuccess != result) || (isRegisterWaitForSingleObjectFailed))
            {
                string errorMessage;
                if (isRegisterWaitForSingleObjectFailed)
                {
                    errorMessage = StringUtil.Format(RemotingErrorIdStrings.WSManPluginShutdownRegistrationFailed);
                }
                else
                {
                    errorMessage = StringUtil.Format(RemotingErrorIdStrings.WSManPluginReportContextFailed);
                }

                // Report error and close the session
                Exception mgdException = new InvalidOperationException(errorMessage);
                Close(mgdException);
            }
        }
예제 #34
0
        internal static TransportErrorOccuredEventArgs ConstructTransportErrorEventArgs(
            IntPtr wsmanAPIHandle,
            IntPtr wsmanSessionHandle,
            WSManNativeApi.WSManError errorStruct,
            TransportMethodEnum transportMethodReportingError,
            PSRemotingErrorId errorResourceID,
            params object[] resourceArgs)
        {
            PSRemotingTransportException e;

            if (errorStruct.errorCode == -2144108135)
            {
                string sessionOptionAsString = WSManNativeApi.WSManGetSessionOptionAsString(wsmanSessionHandle, WSManNativeApi.WSManSessionOption.WSMAN_OPTION_REDIRECT_LOCATION);
                string str = WSManTransportManagerUtils.ParseEscapeWSManErrorMessage(WSManNativeApi.WSManGetErrorMessage(wsmanAPIHandle, errorStruct.errorCode)).Trim();
                e = (PSRemotingTransportException) new PSRemotingTransportRedirectException(sessionOptionAsString, PSRemotingErrorId.URIEndPointNotResolved, new object[2]
                {
                    (object)str,
                    (object)sessionOptionAsString
                });
            }
            else
            {
                e = new PSRemotingTransportException(PSRemotingErrorId.TroubleShootingHelpTopic, new object[1]
                {
                    (object)PSRemotingErrorInvariants.FormatResourceString(errorResourceID, resourceArgs)
                });
                e.TransportMessage = WSManTransportManagerUtils.ParseEscapeWSManErrorMessage(WSManNativeApi.WSManGetErrorMessage(wsmanAPIHandle, errorStruct.errorCode));
            }
            e.ErrorCode = errorStruct.errorCode;
            return(new TransportErrorOccuredEventArgs(e, transportMethodReportingError));
        }