예제 #1
0
        /// <summary>
        /// adds shell session to activeShellSessions store and returns the id
        /// at which the session is added.
        /// </summary>
        /// <param name="newShellSession"></param>
        private void AddToActiveShellSessions(
            WSManPluginShellSession newShellSession)
        {
            int count = -1;
            lock (_syncObject)
            {
                IntPtr key = newShellSession.creationRequestDetails.unmanagedHandle;
                Dbg.Assert(IntPtr.Zero != key, "NULL handles should not be provided");

                if (!_activeShellSessions.ContainsKey(key))
                {
                    _activeShellSessions.Add(key, newShellSession);

                    // trigger an event outside the lock
                    count = _activeShellSessions.Count;
                }
            }

            if (-1 != count)
            {
                // Raise session count changed event
                WSManServerChannelEvents.RaiseActiveSessionsChangedEvent(new ActiveSessionsChangedEventArgs(count));
            }
        }
예제 #2
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;
        }