ClientRequest.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / ClientRequest.cs / 1 / ClientRequest.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
//
// Presharp uses the c# pragma mechanism to supress its warnings. 
// These are not recognised by the base compiler so we need to explictly
// disable the following warnings. See http://winweb/cse/Tools/PREsharp/userguide/default.asp 
// for details. 
//
#pragma warning disable 1634, 1691      // unknown message, unknown pragma 


namespace Microsoft.InfoCards
{ 
    using System;
    using System.Collections; 
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Diagnostics; 
    using System.IO; //Stream
    using System.Security.Principal; //WindowsIdentity
    using System.ComponentModel; //Win32Exception
    using System.Security; //SecurityException 
    using System.Security.Cryptography.X509Certificates;
    using System.Threading; 
    using System.Runtime.InteropServices; // Marshal 

    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; 

    //
    // Summary: Base class to represent requests from the InfoCard client
    // 
    internal abstract class ClientRequest : Request
    { 
        internal delegate void AsyncEntryCallback(); 

 

        //
        // Timeout for existing user requests to finish.
        // 
        const int OutstandingCallWaitTime = 30000;
 
        // 
        // Collection of outstanding async ops associated with this request.
        // 
        IDictionary m_asyncOps;

        //
        // Collection of cached certs. 
        //
        IDictionary m_cachedCerts; 
 
        //
        // Represents the caller process that initated the client request 
        //
        Process m_callerProcess;

        WindowsIdentity m_callerIdentity; 

        Dictionary   m_contextBag; 
 
        //
        // Cancel callback for current service async operations. 
        //
        object m_serviceAsyncSyncRoot;
        ServiceAsyncOperation m_serviceAsyncOperation;
        bool m_cancelled; 
        bool m_untrusted;
 
 
        //
        // Summary: 
        // Given an RpcHandle pointer returns a Process object corresponding to the calling process.
        //
        // Parameters:
        // RpcHandle  - The RpcHandle for which a process object is desired. 
        //
        // Returns: 
        // The process object that corresponds to the calling process of the RpcHandle. 
        //
        public static Process GetCallingProcessFromRpcHandle( IntPtr RpcHandle ) 
        {
            uint callerPid;

            // Pinvoke the RPC function that gets that pid from the idl handle 
            int err = (int) NativeMethods.I_RpcBindingInqLocalClientPID( RpcHandle, out callerPid );
            if ( 0 != err ) 
            { 

                throw IDT.ThrowHelperError( new CommunicationException( SR.GetString( SR.ServiceErrorGettingClientPid ) ) ); 
            }

            Process clientProcess = null;
 
            bool done=false;
            bool secondTry = false; 
            while( !done ) 
            {
                // 
                // Assume only one pass will be necessary.
                //
                done = true;
 
                try
                { 
                    if( secondTry ) 
                    {
                        // 
                        // This is the second try so we need to update the ACL on the process.
                        //
                        NativeMcppMethods.AddSystemAccessToProcess( RpcHandle, callerPid );
                    } 

                    clientProcess = ProcessMonitor.GetProcessById( (int) callerPid ); 
 
                }
                catch( ArgumentException ) 
                {
                    //
                    // The client process has gone away since the call.
                    // 
                    throw IDT.ThrowHelperError( new UserCancelledException() );
                } 
                catch( Win32Exception e ) 
                {
                    bool tryAgain = false; 
                    if( NativeMethods.ERROR_ACCESS_DENIED == e.NativeErrorCode )
                    {
                        if( !secondTry )
                        { 
                            //
                            // The first try failed.  Set up for a second try in which the Security Descriptor 
                            // on the process of interest will be modified. 
                            //
                            done = false; 
                            secondTry = true;
                            tryAgain = true;
                        }
                    } 
                    if( !tryAgain )
                    { 
                        throw IDT.ThrowHelperError( new SecurityException( SR.GetString( SR.ClientAPIInfocardError ), e ) ); 
                    }
                } 
            }

            return clientProcess;
        } 

 
        // 
        // Summary:
        //  Base CTOR for client requests 
        //
        // Arguments:
        //  callingProcess          - The process in which the caller originated.
        //  callingIdentity         - The WindowsIdentity of the caller 
        //  rpcHandle               - The handle of the native RPC request
        //  inArgs                  - The stream to read input data from 
        //  outArgs                 - The stream to write output data to 
        //
        public ClientRequest( Process callingProcess, WindowsIdentity userIdentity, IntPtr rpcHandle, Stream inArgs, Stream outArgs ) 
            : this( callingProcess, userIdentity, rpcHandle, inArgs, outArgs, ExceptionList.AllNonFatal )
        {
        }
 
        //
        // Summary: 
        //  Base CTOR for client requests 
        //
        // Arguments: 
        //  callingProcess          - The process in which the caller originated.
        //  callingIdentity         - The WindowsIdentity of the caller
        //  rpcHandle               - The handle of the native RPC request
        //  inArgs                  - The stream to read input data from 
        //  outArgs                 - The stream to write output data to
        //  recoverableExceptions   - Table of exception types that should not be concidered fatal 
        // 
        public ClientRequest( Process callingProcess, WindowsIdentity callingIdentity, IntPtr rpcHandle, Stream inArgs, Stream outArgs, ExceptionList recoverableExceptions )
            : base( rpcHandle, inArgs, outArgs, recoverableExceptions ) 
        {


            IDT.ThrowInvalidArgumentConditional( null == callingProcess, "callingProcess" ); 
            IDT.ThrowInvalidArgumentConditional( null == callingIdentity, "userIdentity" );
            IDT.ThrowInvalidArgumentConditional( IntPtr.Zero == rpcHandle, "rpcHandle" ); 
            IDT.ThrowInvalidArgumentConditional( null == inArgs, "inArgs" ); 
            IDT.ThrowInvalidArgumentConditional( null == outArgs , "outArgs" );
 
            m_callerProcess = callingProcess;
            m_callerIdentity = callingIdentity;

            m_contextBag = new Dictionary( ); 
            m_serviceAsyncSyncRoot = new object();
 
            // 
            // Signal the lifetime monitor that the client is incoming. This
            // can throw a service shutting down exception if we hit the situation where 
            // a shutdown has just become active.
            //
            InfoCardService.LifeTimeMonitor.AddClient();
 
        }
 
        public override WindowsIdentity RequestorIdentity 
        {
            get{ return m_callerIdentity; } 
        }

        public Process CallerProcess
        { 
            get { return m_callerProcess; }
        } 
 
        public uint CallerPid
        { 
            get { return (uint)CallerProcess.Id; }
        }

 
        protected override void OnInitializeAsSystem()
        { 
            if( CallerProcess.HasExited ) 
            {
                throw IDT.ThrowHelperError( new UserCancelledException() ); 
            }
        }

        /* 
         * Unused code, but available if needed.
         * 
        protected bool Cancelled 
        {
            get{ return m_cancelled; } 
        }
        */

 

 
 
        public T GetContext( )
        { 
            object value = null;
            if( m_contextBag.TryGetValue( typeof(T), out value ) )
            {
                return (T)value; 
            }
            return default(T); 
        } 
        public void SetContext( T value )
        { 
            m_contextBag[ typeof(T) ] = value;
        }
        public void ClearContext()
        { 
            m_contextBag.Remove( typeof( T ) );
        } 
 
        //
        // Summary: 
        // This method adds an RpcAsyncResult to the list of RpcAsyncResults associated with this
        // InfoCard request.
        //
        // Parameters: 
        // async        - The RpcAsyncResult to be added.
        // 
        public void AddAsyncOp( RpcAsyncResult async ) 
        {
            lock( SyncRoot ) 
            {
                if( null == m_asyncOps )
                {
                    m_asyncOps = new HybridDictionary(); 
                }
                m_asyncOps[ async.Handle ] = async; 
            } 
        }
 
        //
        // Summary:
        // This method cancels the specifed aysnc operation by handle
        // 
        // Parameters:
        // handle        - The internal handle created for the operation 
        // 
        public void CancelAsyncOp( int handle )
        { 
            RpcAsyncResult rpcAsyncResult;
            lock ( SyncRoot )
            {
                if ( null != m_asyncOps && m_asyncOps.Contains( handle ) ) 
                {
                    rpcAsyncResult = ( RpcAsyncResult ) m_asyncOps[ handle ]; 
                    rpcAsyncResult.Cancel(); 
                }
            } 
        }


        // 
        // Summary:
        // Removes an RpcAsyncResult from the list of the RpcAsyncResults associated with this 
        // InfoCardRequest. 
        //
        // Paramters: 
        // handle   - The id of the RpcAsyncResult to remove.
        //
        public void RemoveAsyncOp( int handle )
        { 
            lock( SyncRoot )
            { 
                m_asyncOps.Remove( handle ); 
            }
        } 

        //
        // Summary:
        // Finds an RpcAsyncResult in the list of the RpcAsyncResults 
        // associated with this Request.
        // 
        // Paramters: 
        // handle   - The id of the RpcAsyncResult to remove.
        // 
        private RpcAsyncResult FindAsyncOp( int handle )
        {
            RpcAsyncResult rpcAsyncResult;
            lock ( SyncRoot ) 
            {
                rpcAsyncResult = ( RpcAsyncResult ) m_asyncOps[ handle ]; 
            } 
            return rpcAsyncResult;
        } 


        //
        // Summary: 
        // Function for UIEndRequest to call to ascertain that
        // all async ops have been completed/cancelled. 
        // 
        protected void CheckIfAllAsyncOpsCompleted()
        { 
            lock( SyncRoot )
            {
                if( null != m_asyncOps )
                { 
                    foreach( RpcAsyncResult theResult in m_asyncOps.Values )
                    { 
                        IDT.DebugAssert( theResult.IsCanceled || theResult.IsCompleted, 
                            "AsyncOp's endrequest must have occurred before UI End" );
                    } 
                }

            }
        } 

 
        // 
        // Summary:
        // Given the handle to an RpcAsyncResult this method will look it up and wait until the associated 
        // async operation has completed.
        //
        // Paramters:
        // handle    - The handle of an RpcAsyncResult associated with this request. 
        //
        // Remarks: 
        // Running on UIAgent RPC Thread. 
        //
        public RpcAsyncResult WaitForAsyncCompletion( int handle ) 
        {
            RpcAsyncResult result = FindAsyncOp( handle );

            if( null == result ) 
            {
                throw IDT.ThrowHelperError( new CommunicationException( SR.GetString( SR.ServiceInvalidAsyncHandle ) ) ); 
            } 

            IAsyncResult async = ( IAsyncResult )result; 

            //
            // This is where End***Request thread waits until the begin completes.
            // 
            async.AsyncWaitHandle.WaitOne();
            Exception e = result.Exception; 
            if( null != e ) 
            {
                throw new InfoCardRequestException( SR.GetString( SR.ServiceAsyncOpGeneratedException ), e ); 
            }

            return result;
        } 
        //
        // Even though the recipientIdentifier can be calculated from the cert directly, 
        // we pass it in to avoid the additonal computation 
        //
        public void CertCacheAdd( string recipientIdentifier, X509Certificate2 cert ) 
        {
            //
            //
 
            lock ( SyncRoot )
            { 
                if ( null == m_cachedCerts ) 
                {
                    m_cachedCerts = new HybridDictionary(); 
                }

                m_cachedCerts[ recipientIdentifier ] = cert;
 
            }
        } 
 
        public X509Certificate2 CertCacheFind( string recipientId )
        { 
            lock ( SyncRoot )
            {
                return ( X509Certificate2 ) m_cachedCerts[ recipientId ];
            } 
        }
 
 
        //
        // Summary: 
        // Called be native RPC code to see if client is authorized to call
        // the client API interface.
        //
        // Remarks: 
        // Checks to make sure that incoming clients are authenticated as
        // windows principals. 
        // 
        // Parameters:
        // rpcIfHandle   - An rpc interface handle for the client api interface. 
        // context       - An RPC binding handle.
        //
        static public uint Authorize( IntPtr rpcIfHandle, IntPtr context )
        { 
            uint err = NativeMethods.ERROR_ACCESS_DENIED;
            IDT.ThrowInvalidArgumentConditional( IntPtr.Zero == rpcIfHandle, "rpcIfHandle" ); 
            IDT.ThrowInvalidArgumentConditional( IntPtr.Zero == context, "context" ); 

            try 
            {
                using( WindowsIdentity id = Utility.GetWindowsIdentity( context ) )
                {
                    if( !id.IsAuthenticated ) 
                    {
                        throw IDT.ThrowHelperError( new SecurityException() ); 
                    } 

                    if( !ValidateToken( context, id ) ) 
                    {
                        throw IDT.ThrowHelperError( new CommunicationException( SR.GetString( SR.ServiceInvalidCallerToken ) ) );
                    }
                    // 
                    // The client has passed all checks, let them in.
                    // 
                    err = 0; 
                }
            } 
            catch( System.Runtime.CompilerServices.RuntimeWrappedException rwe )
            {
                IDT.TraceAndLogException( rwe );
                IDT.TraceDebug( "an exception was generated: \n{0}", rwe.ToString() ); 
                InfoCardService.Crash();
            } 
            catch( SecurityException ) 
            {
                IDT.Assert( NativeMethods.ERROR_ACCESS_DENIED == err, "Unexpected value for err!" ); 
            }

            catch( InfoCardBaseException )
            { 
                throw;
            } 
            // 
            // Review: We are ok to catch all here as we are effectively transferring the error between threads.
            // 
            #pragma warning suppress 56500  // do not catch null reference or seh exceptions.
            catch( Exception e )
            {
                if ( IDT.IsFatal( e ) ) 
                {
                    InfoCardService.Crash( e ); 
                } 

                throw IDT.ThrowHelperError( 
                                new CommunicationException(
                                    SR.GetString( SR.ServiceUnableToValidateCallerToken, e.Message )
                                    ) );
 
            }
            // 
            // Review: We are ok to catch all here as we are effectively transferring the error between threads. 
            //
            #pragma warning suppress 56500 

            return err;
        }
 
        //
        // Summary: 
        // Validates that the caller's token is in the form we require 
        // Parameters:
        // rpcItfHandle     - the rpc interface handle for the incoming call 
        // rpcIdentity     - the incoming rpc identity
        //
        private static bool ValidateToken( IntPtr rpcItfHandle, WindowsIdentity rpcIdentity )
        { 
            //
            // Retrieve the calling process identity 
            // 
            Process p = GetCallingProcessFromRpcHandle(rpcItfHandle);
            WindowsIdentity caller = NativeMcppMethods.CreateServiceExecutionIdentity( p ); 

            //
            // We must have the same identity as the calling process token
            // 
            bool ok = ( caller.User.Value == rpcIdentity.User.Value );
 
            // 
            // Calling process token must not be running under changed credentials
            // 
            if( ok )
            {
                ok = NativeMcppMethods.IsTokenValid( p );
            } 
            return ok;
 
        } 

        // 
        // Summary: Free any resources held by this class.
        // Be sure to call base.OnDisposeAsSystem before returning
        // so that the base class has an opportunity to do its cleanup
        // 
        protected override void OnDisposeAsSystem()
        { 
            m_callerProcess = null; 

            // 
            // Clean up any async requests that are still outstanding.
            //
            object[] asyncOps = null;
            lock( SyncRoot ) 
            {
                if( null != m_asyncOps ) 
                { 
                    asyncOps = new object[ m_asyncOps.Values.Count ];
                    m_asyncOps.Values.CopyTo( asyncOps, 0 ); 
                }
            }
            //
            // Dispose of each async result outside of the lock since Disposal will cause the async result to 
            // take the lock and remove itself from the dictionary.
            // 
            if( null != asyncOps ) 
            {
                foreach( RpcAsyncResult result in asyncOps ) 
                {
                    result.Dispose();
                }
            } 

            InfoCardService.LifeTimeMonitor.RemoveClient(); 
 
            //
            // Always call base.OnDisposeAsSystem before returning 
            //
            base.OnDisposeAsSystem();
        }
 
        //
        // Summary: 
        //  Executes the specified delegate on a thread pool thread, and waits for it to complete. 
        //  If canceled, the cancel delegate is called.
        // 
        protected void ExecuteCancelable( AsyncEntryCallback entry, AsyncEntryCallback cancel )
        {
            lock( m_serviceAsyncSyncRoot )
            { 
                //
                // If we received a cancel message before we were able to create or between two 
                //   the async operations, we will just throw the appropriate exception. 
                //
                if( m_cancelled ) 
                {
                    //
                    // Throw untrusted if the user clicked "return to safe page".
                    // 
                    if( m_untrusted )
                    { 
                        throw IDT.ThrowHelperError( new UntrustedRecipientException() ); 
                    }
                    else 
                    {
                        throw IDT.ThrowHelperError( new UserCancelledException() );
                    }
                } 

 
                IDT.Assert( null == m_serviceAsyncOperation, "Only a single cancelable service operation can be running at a time" ); 

                m_serviceAsyncOperation = new ServiceAsyncOperation( entry, cancel ); 
                try
                {

                    if( !ThreadPool.QueueUserWorkItem( IDT.ThunkCallback( new WaitCallback( ServiceAsyncEntry ) ), m_serviceAsyncOperation ) ) 
                    {
                        throw IDT.ThrowHelperError( new CommunicationException( SR.GetString( SR.UnableToQueueThreadpool ) ) ); 
                    } 

                    m_serviceAsyncOperation.WaitForCompletion(); 

                    if( m_serviceAsyncOperation.WasCancelled )
                    {
                        if( m_untrusted ) 
                        {
                            throw IDT.ThrowHelperError( new UntrustedRecipientException() ); 
                        } 
                        else
                        { 
                            throw IDT.ThrowHelperError( new UserCancelledException() );
                        }
                    }
                    if( null != m_serviceAsyncOperation.ExecutionException ) 
                    {
                        throw IDT.ThrowHelperError( new CommunicationException( m_serviceAsyncOperation.ExecutionException.Message, m_serviceAsyncOperation.ExecutionException ) ); 
                    } 
                }
                finally 
                {
                    m_serviceAsyncOperation = null;
                }
            } 
        }
 
        // 
        // Summary:
        //  Cancel the current outstanding aysnc operation and any new ones. 
        // Params
        // untrusted    - whether we are cancelling due to a trust decision by the user.
        //
        protected void CancelServiceAsyncOperation( bool untrusted ) 
        {
            if( null != m_serviceAsyncOperation ) 
            { 
                m_serviceAsyncOperation.Cancel();
            } 
            m_untrusted = untrusted;
            m_cancelled = true;
        }
 
        //
        // Summary: 
        //  ThreadPool entry point for service async operations. 
        //
        static void ServiceAsyncEntry( object state ) 
        {
            ServiceAsyncOperation callback = (ServiceAsyncOperation)state;
            try
            { 
                callback.Execute();
            } 
            finally 
            {
                callback.Complete(); 
            }
        }

 

        // 
        // Summary: 
        //  State info for the current service async operation
        // 
        class ServiceAsyncOperation
        {
            AsyncEntryCallback  m_cancelCallback;
            AsyncEntryCallback  m_entryCallback; 
            ManualResetEvent    m_syncEvent;
            Exception           m_exception; 
            bool                m_complete; 
            bool                m_cancelled;
            object              m_sync; 

            public ServiceAsyncOperation( AsyncEntryCallback entry, AsyncEntryCallback cancel )
            {
                m_entryCallback = entry; 
                m_cancelCallback = cancel;
                m_sync = new object(); 
                m_syncEvent = new ManualResetEvent( false ); 
            }
 
            public bool WasCancelled
            {
                get{ return m_cancelled; }
            } 
            public Exception ExecutionException
            { 
                get{ return m_exception; } 
            }
 
            //
            // Summary:
            //  Completes the operation
            // 
            public void Complete()
            { 
                if( !m_complete ) 
                {
                    lock( m_sync ) 
                    {
                        if( !m_complete )
                        {
                            m_complete = true; 
                            m_syncEvent.Set();
                        } 
                    } 
                }
            } 

            //
            // Summary
            //  Waits for completion.of the operation 
            //
            public void WaitForCompletion() 
            { 
                m_syncEvent.WaitOne();
            } 

            //
            // Summary:
            //  Starts the operations, and handles the exceptions. 
            //
            public void Execute() 
            { 

                lock( m_sync ) 
                {
                    //
                    // if this object has ever been cancelled, we will immediatley
                    //  return.  This can happen if a cancel is recieved between 
                    //  service async calls.
                    // 
                    if( m_cancelled ) 
                    {
                        return; 
                    }

                    m_complete = false;
                    m_syncEvent.Reset(); 
                }
                try 
                { 
                    m_entryCallback();
                } 
                #pragma warning suppress 56500  // do not catch null reference or seh exceptions.
                catch( Exception e )
                {
                    if ( IDT.IsFatal( e ) ) 
                    {
                        InfoCardService.Crash( e ); 
                    } 
                    else
                    { 
                        m_exception =  e;
                    }
                }
            } 

            // 
            // Summary: 
            //  Cancel the async operation.
            // 
            public void Cancel()
            {
                lock( m_sync )
                { 
                    if( m_complete )
                    { 
                        return; 
                    }
                    m_cancelled = true; 
                    try
                    {
                        if( null != m_cancelCallback )
                        { 
                            m_cancelCallback();
                        } 
                    } 
                    finally
                    { 
                        Complete();
                    }
                }
            } 

        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK