Пример #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="pluginContext">PVOID</param>
        /// <param name="requestDetails">WSMAN_PLUGIN_REQUEST*</param>
        /// <param name="flags">DWORD</param>
        /// <param name="extraInfo">PCWSTR</param>
        /// <param name="startupInfo">WSMAN_SHELL_STARTUP_INFO*</param>
        /// <param name="inboundShellInformation">WSMAN_DATA*</param>
        public static void WSManPluginShell(
            IntPtr pluginContext,
            IntPtr requestDetails,
            int flags,
            [MarshalAs(UnmanagedType.LPWStr)] string extraInfo,
            IntPtr startupInfo,
            IntPtr inboundShellInformation)
        {
            if (IntPtr.Zero == pluginContext)
            {
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullPluginContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullPluginContext,
                        "pluginContext",
                        "WSManPluginShell")
                    );
                return;
            }

#if (DEBUG)
            // In debug builds, allow remote runspaces to wait for debugger attach
            if (Environment.GetEnvironmentVariable("__PSRemoteRunspaceWaitForDebugger", EnvironmentVariableTarget.Machine) != null)
            {
                bool debuggerAttached = false;
                while (!debuggerAttached)
                {
                    System.Threading.Thread.Sleep(100);
                }
            }
#endif

            WSManPluginInstance.PerformWSManPluginShell(pluginContext, requestDetails, flags, extraInfo, startupInfo, inboundShellInformation);
        }
 /// <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);
 }
        // 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));
            }
        }
        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();
        }
 /// <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;
 }
Пример #6
0
        /// <summary>
        /// Called only once during shutdown. This is used to perform various deinitializations.
        /// </summary>
        /// <param name="pluginContext">PVOID</param>
        public static void ShutdownPlugin(
            IntPtr pluginContext)
        {
            WSManPluginInstance.PerformShutdown(pluginContext);

            if (null != workerPtrs)
            {
                workerPtrs.Dispose();
            }
        }
 // Report Operation Complete using the send request details.
 internal void ReportSendOperationComplete()
 {
     lock (_syncObject)
     {
         if (null != sendRequestDetails)
         {
             // report and clear the send request details
             WSManPluginInstance.ReportWSManOperationComplete(sendRequestDetails, lastErrorReported);
             sendRequestDetails = null;
         }
     }
 }
Пример #8
0
        /// <summary>
        /// Callback used to register with thread pool to notify when a plugin operation shuts down.
        /// Conforms to:
        ///     public delegate void WaitOrTimerCallback( Object state, bool timedOut )
        /// </summary>
        /// <param name="operationContext">PVOID</param>
        /// <param name="timedOut">BOOLEAN</param>
        /// <returns></returns>
        public static void PSPluginOperationShutdownCallback(
            object operationContext,
            bool timedOut)
        {
            if (null == operationContext)
            {
                return;
            }

            WSManPluginOperationShutdownContext context = (WSManPluginOperationShutdownContext)operationContext;

            context.isShuttingDown = true;

            WSManPluginInstance.PerformCloseOperation(context);
        }
Пример #9
0
        internal override void CloseOperation(
            WSManPluginOperationShutdownContext context,
            Exception reasonForClose)
        {
            // let command sessions to close.
            lock (cmdSyncObject)
            {
                if (isClosed)
                {
                    return;
                }

                if (!context.isReceiveOperation)
                {
                    isClosed = true;
                }
            }

            WSManPluginInstance.SetThreadProperties(creationRequestDetails);

            bool isRcvOp = context.isReceiveOperation;
            // only one thread will be here.
            bool isRcvOpShuttingDown = (context.isShuttingDown) &&
                                       (context.isReceiveOperation) &&
                                       (context.commandContext == creationRequestDetails.unmanagedHandle);

            bool isCmdShuttingDown = (context.isShuttingDown) &&
                                     (!context.isReceiveOperation) &&
                                     (context.commandContext == creationRequestDetails.unmanagedHandle);

            // close the pending send operation if any
            ReportSendOperationComplete();
            // close the shell's transport manager first..so we wont send data.
            transportMgr.DoClose(isRcvOpShuttingDown, reasonForClose);

            if (!isRcvOp)
            {
                // raise session closed event and let dependent code to release resources.
                // null check is not performed here because Managed C++ will take care of this.
                base.SafeInvokeSessionClosed(creationRequestDetails.unmanagedHandle, EventArgs.Empty);
                // Send Operation Complete to WSMan service
                WSManPluginInstance.ReportWSManOperationComplete(creationRequestDetails, reasonForClose);
                // let base class release its resources
                this.Close(isCmdShuttingDown);
            }
        }
Пример #10
0
        internal override void CloseOperation(
            WSManPluginOperationShutdownContext context,
            Exception reasonForClose)
        {
            // let command sessions to close.
            lock (shellSyncObject)
            {
                if (isClosed)
                {
                    return;
                }

                if (!context.isReceiveOperation)
                {
                    isClosed = true;
                }
            }

            WSManPluginInstance.SetThreadProperties(creationRequestDetails);

            bool isRcvOpShuttingDown = (context.isShuttingDown) && (context.isReceiveOperation);
            bool isRcvOp             = context.isReceiveOperation;
            bool isShuttingDown      = context.isShuttingDown;

            // close the pending send operation if any
            ReportSendOperationComplete();
            // close the shell's transport manager after commands handled the operation
            transportMgr.DoClose(isRcvOpShuttingDown, reasonForClose);

            if (!isRcvOp)
            {
                // Initiate close on the active command sessions and then clear the internal
                // Command Session dictionary
                CloseAndClearCommandSessions(reasonForClose);
                // raise session closed event and let dependent code to release resources.
                // null check is not performed here because the handler will take care of this.
                base.SafeInvokeSessionClosed(creationRequestDetails.unmanagedHandle, EventArgs.Empty);
                // Send Operation Complete to WSMan service
                WSManPluginInstance.ReportWSManOperationComplete(creationRequestDetails, reasonForClose);
                // let base class release its resources
                base.Close(isShuttingDown);
            }
            // TODO: Do this.Dispose(); here?
        }
        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));
        }
Пример #12
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="pluginContext">PVOID</param>
        /// <param name="requestDetails">WSMAN_PLUGIN_REQUEST*</param>
        /// <param name="flags">DWORD</param>
        /// <param name="shellContext">PVOID</param>
        /// <param name="commandContext">PVOID optional</param>
        /// <param name="code">PCWSTR</param>
        public static void WSManPluginSignal(
            IntPtr pluginContext,
            IntPtr requestDetails,
            int flags,
            IntPtr shellContext,
            IntPtr commandContext,
            [MarshalAs(UnmanagedType.LPWStr)] string code)
        {
            if ((IntPtr.Zero == pluginContext) || (IntPtr.Zero == shellContext))
            {
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullPluginContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullPluginContext,
                        "Plugin Context",
                        "WSManPluginSignal")
                    );
                return;
            }

            WSManPluginInstance.PerformWSManPluginSignal(pluginContext, requestDetails, flags, shellContext, commandContext, code);
        }
Пример #13
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="pluginContext">PVOID</param>
        /// <param name="requestDetails">WSMAN_PLUGIN_REQUEST*</param>
        /// <param name="flags">DWORD</param>
        /// <param name="shellContext">PVOID</param>
        /// <param name="commandContext">PVOID optional</param>
        /// <param name="streamSet">WSMAN_STREAM_ID_SET* optional</param>
        public static void WSManPluginReceive(
            IntPtr pluginContext,
            IntPtr requestDetails,
            int flags,
            IntPtr shellContext,
            IntPtr commandContext,
            IntPtr streamSet)
        {
            if (IntPtr.Zero == pluginContext)
            {
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullPluginContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullPluginContext,
                        "Plugin Context",
                        "WSManPluginReceive")
                    );
                return;
            }

            WSManPluginInstance.PerformWSManPluginReceive(pluginContext, requestDetails, flags, shellContext, commandContext, streamSet);
        }
Пример #14
0
        /// <summary>
        /// </summary>
        /// <param name="pluginContext">PVOID.</param>
        /// <param name="requestDetails">WSMAN_PLUGIN_REQUEST*.</param>
        /// <param name="flags">DWORD.</param>
        /// <param name="shellContext">PVOID.</param>
        /// <param name="commandContext">PVOID optional.</param>
        /// <param name="inboundConnectInformation">WSMAN_DATA* optional.</param>
        public static void WSManPluginConnect(
            IntPtr pluginContext,
            IntPtr requestDetails,
            int flags,
            IntPtr shellContext,
            IntPtr commandContext,
            IntPtr inboundConnectInformation)
        {
            if (pluginContext == IntPtr.Zero)
            {
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullPluginContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullPluginContext,
                        "pluginContext",
                        "WSManPluginConnect")
                    );
                return;
            }

            WSManPluginInstance.PerformWSManPluginConnect(pluginContext, requestDetails, flags, shellContext, commandContext, inboundConnectInformation);
        }
Пример #15
0
        /// <summary>
        /// </summary>
        /// <param name="pluginContext">PVOID.</param>
        /// <param name="requestDetails">WSMAN_PLUGIN_REQUEST*.</param>
        /// <param name="flags">DWORD.</param>
        /// <param name="shellContext">PVOID.</param>
        /// <param name="commandLine">PCWSTR.</param>
        /// <param name="arguments">WSMAN_COMMAND_ARG_SET* optional.</param>
        public static void WSManPluginCommand(
            IntPtr pluginContext,
            IntPtr requestDetails,
            int flags,
            IntPtr shellContext,
            [MarshalAs(UnmanagedType.LPWStr)] string commandLine,
            IntPtr arguments)
        {
            if (pluginContext == IntPtr.Zero)
            {
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.NullPluginContext,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginNullPluginContext,
                        "Plugin Context",
                        "WSManPluginCommand")
                    );
                return;
            }

            WSManPluginInstance.PerformWSManPluginCommand(pluginContext, requestDetails, flags, shellContext, commandLine, arguments);
        }
        /// <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;
        }
Пример #17
0
        internal bool EnableTransportManagerSendDataToClient(
            WSManNativeApi.WSManPluginRequest requestDetails,
            WSManPluginOperationShutdownContext ctxtToReport)
        {
            _shutDownContext = ctxtToReport;
            bool isRegisterWaitForSingleObjectSucceeded = true;

            lock (_syncObject)
            {
                if (_isRequestPending)
                {
                    // if a request is already pending..ignore this.
                    WSManPluginInstance.ReportWSManOperationComplete(
                        requestDetails,
                        WSManPluginErrorCodes.NoError);
                    return(false);
                }

                if (_isClosed)
                {
                    WSManPluginInstance.ReportWSManOperationComplete(requestDetails, _lastErrorReported);
                    return(false);
                }

                _isRequestPending = true;
                _requestDetails   = requestDetails;

                if (Platform.IsWindows)
                {
                    // Wrap the provided handle so it can be passed to the registration function
                    SafeWaitHandle  safeWaitHandle  = new SafeWaitHandle(requestDetails.shutdownNotificationHandle, false); // Owned by WinRM
                    EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
                    eventWaitHandle.SafeWaitHandle = safeWaitHandle;

                    _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 (_registeredShutDownWaitHandle == null)
                    {
                        isRegisterWaitForSingleObjectSucceeded = false;
                    }
                }
                // release thread waiting to send data to the client.
                _waitHandle.Set();
            }

            if (!isRegisterWaitForSingleObjectSucceeded)
            {
                WSManPluginInstance.PerformCloseOperation(ctxtToReport);
                WSManPluginInstance.ReportOperationComplete(
                    requestDetails,
                    WSManPluginErrorCodes.ShutdownRegistrationFailed,
                    StringUtil.Format(
                        RemotingErrorIdStrings.WSManPluginShutdownRegistrationFailed));
                return(false);
            }

            return(true);
        }
Пример #18
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();
            }
        }