示例#1
0
        private void RunCallback(object o)
        {
            bool globalLogEnabled = GlobalLog.IsEnabled;

            if (globalLogEnabled && !_runCallbackCalled)
            {
                GlobalLog.Assert("RunCallback called without setting runCallbackCalled!");
            }

            // If OnAppDomainUnload beats us to the lock, do nothing: the AppDomain is going down soon anyways.
            // Otherwise, wait until the call to CancelMibChangeNotify2 is done before giving it up.
            lock (s_pendingNotifications)
            {
                if (Environment.HasShutdownStarted)
                {
                    return;
                }

#if DEBUG
                bool successfullyRemoved = s_pendingNotifications.Remove(this);
                if (globalLogEnabled && !successfullyRemoved)
                {
                    GlobalLog.Assert("RunCallback for a TeredoHelper which is not in s_pendingNotifications!");
                }
#else
                s_pendingNotifications.Remove(this);
#endif

                if (globalLogEnabled && (_cancelHandle == null || _cancelHandle.IsInvalid))
                {
                    GlobalLog.Assert("Invalid cancelHandle in RunCallback");
                }

                _cancelHandle.Dispose();
            }

            _callback.Invoke(_state);
        }
示例#2
0
        internal BufferOffsetSize(byte[] buffer, int offset, int size, bool copyBuffer)
        {
            GlobalLog.Assert(buffer != null && buffer.Length >= size + offset, "BufferOffsetSize::.ctor|Illegal parameters.");
            if (copyBuffer)
            {
                byte[] newBuffer = new byte[size];

                System.Buffer.BlockCopy(
                    buffer,    // src
                    offset,    // src index
                    newBuffer, // dest
                    0,         // dest index
                    size);     // total size to copy

                offset = 0;
                buffer = newBuffer;
            }

            Buffer = buffer;
            Offset = offset;
            Size   = size;
            GlobalLog.Print("BufferOffsetSize#" + Logging.HashString(this) + "::.ctor() copyBuffer:" + copyBuffer.ToString() + " this:[" + ToString() + "]");
        }
        // Called to initiate a connection attempt to the next address in the list.  Returns an exception
        // if the attempt failed synchronously, or null if it was successfully initiated.
        private Exception AttemptConnection()
        {
            try
            {
                IPAddress attemptAddress = GetNextAddress(out _lastAttemptSocket);

                if (attemptAddress == null)
                {
                    return(new SocketException((int)SocketError.NoData));
                }

                GlobalLog.Assert(attemptAddress != null, "MultipleConnectAsync.AttemptConnection: attemptAddress is null!");

                _internalArgs.RemoteEndPoint = new IPEndPoint(attemptAddress, _endPoint.Port);

                return(AttemptConnection(_lastAttemptSocket, _internalArgs));
            }
            catch (Exception e)
            {
                GlobalLog.Assert(!(e is ObjectDisposedException), "MultipleConnectAsync.AttemptConnection: unexpected ObjectDisposedException");
                return(e);
            }
        }
示例#4
0
        private Exception AttemptUserConnection()
        {
            Debug.Assert(!SocketPal.SupportsMultipleConnectAttempts);
            Debug.Assert(_lastAttemptSocket != null);

            try
            {
                _lastAttemptSocket.Dispose();

                // Setup the internal args. RemoteEndpoint should already be correct.
                _internalArgs.SetBuffer(_userArgs.Buffer, _userArgs.Offset, _userArgs.Count);

                return(AttemptConnection(UserSocket, _internalArgs));
            }
            catch (Exception e)
            {
                if (e is ObjectDisposedException && GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("MultipleConnectAsync.AttemptConnection: unexpected ObjectDisposedException");
                }
                return(e);
            }
        }
示例#5
0
        private static void WriteCallback(IAsyncResult transportResult)
        {
            if (transportResult.CompletedSynchronously)
            {
                return;
            }

            if ((transportResult.AsyncState is AsyncProtocolRequest) && GlobalLog.IsEnabled)
            {
                GlobalLog.Assert("NegotiateSteam::WriteCallback|State type is wrong, expected AsyncProtocolRequest.");
            }

            AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest)transportResult.AsyncState;

            try
            {
                NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject;
                negoStream.InnerStreamAPM.EndWrite(transportResult);
                if (asyncRequest.Count == 0)
                {
                    // This was the last chunk.
                    asyncRequest.Count = -1;
                }

                negoStream.StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest);
            }
            catch (Exception e)
            {
                if (asyncRequest.IsUserCompleted)
                {
                    // This will throw on a worker thread.
                    throw;
                }

                asyncRequest.CompleteWithError(e);
            }
        }
        internal static int Decrypt(
            SafeDeleteContext securityContext,
            byte[] buffer,
            int offset,
            int count,
            bool isConfidential,
            bool isNtlm,
            out int newOffset,
            uint sequenceNumber)
        {
            if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range.");
                }

                Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range.");

                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range.");
                }

                Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range.");

                throw new ArgumentOutOfRangeException(nameof(count));
            }

            newOffset = offset;
            return(Interop.GssApi.Decrypt(((SafeDeleteNegoContext)securityContext).GssContext, buffer, offset, count));
        }
        private static void ReadCallback(IAsyncResult transportResult)
        {
            if (!(transportResult.AsyncState is LazyAsyncResult))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("ReadCallback|State type is wrong, expected LazyAsyncResult.");
                }

                Debug.Fail("ReadCallback|State type is wrong, expected LazyAsyncResult.");
            }

            if (transportResult.CompletedSynchronously)
            {
                return;
            }

            LazyAsyncResult lazyResult = (LazyAsyncResult)transportResult.AsyncState;

            // Async completion.
            try
            {
                NegoState authState = (NegoState)lazyResult.AsyncObject;
                byte[]    message   = authState._framer.EndReadMessage(transportResult);
                authState.ProcessReceivedBlob(message, lazyResult);
            }
            catch (Exception e)
            {
                if (lazyResult.InternalPeekCompleted)
                {
                    // This will throw on a worker thread.
                    throw;
                }

                lazyResult.InvokeCallback(e);
            }
        }
示例#8
0
        private static void WriteCallback(IAsyncResult transportResult)
        {
            if (transportResult.CompletedSynchronously)
            {
                return;
            }

            GlobalLog.Assert(transportResult.AsyncState is AsyncProtocolRequest, "SslStream::WriteCallback|State type is wrong, expected AsyncProtocolRequest.");
            AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest)transportResult.AsyncState;

            _SslStream sslStream = (_SslStream)asyncRequest.AsyncObject;

            try
            {
                sslStream._SslState.InnerStreamAPM.EndWrite(transportResult);
                sslStream._SslState.FinishWrite();

                if (asyncRequest.Count == 0)
                {
                    // This was the last chunk.
                    asyncRequest.Count = -1;
                }

                sslStream.StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest);
            }
            catch (Exception e)
            {
                if (asyncRequest.IsUserCompleted)
                {
                    // This will throw on a worker thread.
                    throw;
                }

                sslStream._SslState.FinishWrite();
                asyncRequest.CompleteWithError(e);
            }
        }
示例#9
0
        private bool CheckSpn()
        {
            if (_Context.IsKerberos)
            {
                return(true);
            }

            if (_ExtendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.Never ||
                _ExtendedProtectionPolicy.CustomServiceNames == null)
            {
                return(true);
            }

            if (!AuthenticationManager.OSSupportsExtendedProtection)
            {
                GlobalLog.Assert(_ExtendedProtectionPolicy.PolicyEnforcement != PolicyEnforcement.Always,
                                 "User managed to set PolicyEnforcement.Always when the OS does not support extended protection!");
                return(true);
            }

            string clientSpn = _Context.ClientSpecifiedSpn;

            if (String.IsNullOrEmpty(clientSpn))
            {
                if (_ExtendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.WhenSupported)
                {
                    return(true);
                }
            }
            else
            {
                return(_ExtendedProtectionPolicy.CustomServiceNames.Contains(clientSpn));
            }

            return(false);
        }
示例#10
0
        public SecurityBuffer(byte[] data, int offset, int size, SecurityBufferType tokentype)
        {
            if (offset < 0 || offset > (data == null ? 0 : data.Length))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("SecurityBuffer::.ctor", "'offset' out of range.  [" + offset + "]");
                }
                Debug.Fail("SecurityBuffer::.ctor", "'offset' out of range.  [" + offset + "]");
            }
            if (size < 0 || size > (data == null ? 0 : data.Length - offset))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("SecurityBuffer::.ctor", "'size' out of range.  [" + size + "]");
                }
                Debug.Fail("SecurityBuffer::.ctor", "'size' out of range.  [" + size + "]");
            }

            this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length);
            this.size   = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
            this.type   = tokentype;
            this.token  = size == 0 ? null : data;
        }
        private static Exception AttemptConnection(Socket attemptSocket, SocketAsyncEventArgs args)
        {
            try
            {
                GlobalLog.Assert(attemptSocket != null, "MultipleConnectAsync.AttemptConnection: attemptSocket is null!");

                if (!attemptSocket.ConnectAsync(args))
                {
                    return(new SocketException((int)args.SocketError));
                }
            }
            catch (ObjectDisposedException)
            {
                // This can happen if the user closes the socket, and is equivalent to a call
                // to CancelConnectAsync
                return(new SocketException((int)SocketError.OperationAborted));
            }
            catch (Exception e)
            {
                return(e);
            }

            return(null);
        }
        //
        // This is (optionally) called after receiveing a live response
        //
        protected internal override CacheValidationStatus RevalidateCache()
        {
            if (HttpProxyMode)
            {
                return(base.RevalidateCache());
            }


            if (Policy.Level >= RequestCacheLevel.Reload)
            {
                // For those policies cache is never returned
                GlobalLog.Assert("RevalidateCache()", "This validator should not be called for policy = " + Policy.ToString());
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_validator_invalid_for_policy, Policy.ToString()));
                }
                return(CacheValidationStatus.DoNotTakeFromCache);
            }

            // First check is do we still hold on a cached entry?
            if (CacheStream == Stream.Null)
            {
                return(CacheValidationStatus.DoNotTakeFromCache);
            }

            //
            // This is a second+ time validation after receiving at least one response
            //

            CacheValidationStatus result = CacheValidationStatus.DoNotTakeFromCache;

            FtpWebResponse resp = Response as FtpWebResponse;

            if (resp == null)
            {
                // This will result to an application error
                return(CacheValidationStatus.DoNotTakeFromCache);
            }

            if (resp.StatusCode == FtpStatusCode.FileStatus)
            {
                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_response_last_modified, resp.LastModified.ToUniversalTime().ToString("r", CultureInfo.InvariantCulture), resp.ContentLength));
                }
                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_cache_last_modified, CacheEntry.LastModifiedUtc.ToString("r", CultureInfo.InvariantCulture), CacheEntry.StreamSize));
                }

                if (CacheStreamOffset != 0L && CacheEntry.IsPartialEntry)
                {
                    //should never happen
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_partial_and_non_zero_content_offset, CacheStreamOffset.ToString(CultureInfo.InvariantCulture)));
                    }
                    result = CacheValidationStatus.DoNotTakeFromCache;
                }

                if (resp.LastModified.ToUniversalTime() == CacheEntry.LastModifiedUtc)
                {
                    if (CacheEntry.IsPartialEntry)
                    {
                        // A caller will need to use Validator.CacheEntry.StreamSize to figure out what the restart point is

                        if (resp.ContentLength > 0)
                        {
                            this.CacheStreamLength = resp.ContentLength;
                        }
                        else
                        {
                            this.CacheStreamLength = -1;
                        }

                        result = CacheValidationStatus.CombineCachedAndServerResponse;
                    }
                    else if (resp.ContentLength == CacheEntry.StreamSize)
                    {
                        result = CacheValidationStatus.ReturnCachedResponse;
                    }
                    else
                    {
                        result = CacheValidationStatus.DoNotTakeFromCache;
                    }
                }
                else
                {
                    result = CacheValidationStatus.DoNotTakeFromCache;
                }
            }
            else
            {
                result = CacheValidationStatus.DoNotTakeFromCache;
            }

            return(result);
        }
        // This method may add headers under the "Warning" header name
        protected internal override CacheValidationStatus ValidateCache()
        {
            if (HttpProxyMode)
            {
                return(base.ValidateCache());
            }

            if (Policy.Level >= RequestCacheLevel.Reload)
            {
                // For those policies cache is never returned
                GlobalLog.Assert("OnValidateCache()", "This validator should not be called for policy = " + Policy.ToString());
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_validator_invalid_for_policy, Policy.ToString()));
                }
                return(CacheValidationStatus.DoNotTakeFromCache);
            }

            // First check is do we have a cached entry at all?
            if (CacheStream == Stream.Null || CacheEntry.IsPartialEntry)
            {
                if (Policy.Level == RequestCacheLevel.CacheOnly)
                {
                    // Throw because entry was not found and it's cache-only policy
                    FailRequest(WebExceptionStatus.CacheEntryNotFound);
                }
                if (CacheStream == Stream.Null)
                {
                    return(CacheValidationStatus.DoNotTakeFromCache);
                }
                // Otherwise it's a partial entry and we can go on the wire
            }

            CacheStreamOffset = 0L;
            CacheStreamLength = CacheEntry.StreamSize;

            //
            // Before request submission validation
            //
            if (Policy.Level == RequestCacheLevel.Revalidate || CacheEntry.IsPartialEntry)
            {
                return(TryConditionalRequest());
            }

            long contentOffset = Request is FtpWebRequest ? ((FtpWebRequest)Request).ContentOffset: 0L;

            if (CacheFreshnessStatus == CacheFreshnessStatus.Fresh || Policy.Level == RequestCacheLevel.CacheOnly || Policy.Level == RequestCacheLevel.CacheIfAvailable)
            {
                if (contentOffset != 0)
                {
                    if (contentOffset >= CacheStreamLength)
                    {
                        if (Policy.Level == RequestCacheLevel.CacheOnly)
                        {
                            // Throw because request is outside of cached size and it's cache-only policy
                            FailRequest(WebExceptionStatus.CacheEntryNotFound);
                        }
                        return(CacheValidationStatus.DoNotTakeFromCache);
                    }
                    CacheStreamOffset = contentOffset;
                }
                return(CacheValidationStatus.ReturnCachedResponse);
            }

            return(CacheValidationStatus.DoNotTakeFromCache);
        }
        //
        // The app is calling this method after starting an SSL handshake.
        //
        // ATTN: The thumbPrint must be from inspected and possbly cloned user Cert object or we get a security hole in SslCredKey ctor.
        //
        internal static void CacheCredential(SafeFreeCredentials creds, byte[] thumbPrint, SchProtocols allowedProtocols, EncryptionPolicy encryptionPolicy)
        {
            GlobalLog.Assert(creds != null, "CacheCredential|creds == null");
            if (creds.IsInvalid)
            {
                GlobalLog.Print("CacheCredential() Refused to cache an Invalid Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count);
                return;
            }

            object key = new SslCredKey(thumbPrint, allowedProtocols, encryptionPolicy);

            SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference;

            if (cached == null || cached.IsClosed || cached._Target.IsInvalid)
            {
                lock (s_CachedCreds)
                {
                    cached = s_CachedCreds[key] as SafeCredentialReference;

                    if (cached == null || cached.IsClosed)
                    {
                        cached = SafeCredentialReference.CreateReference(creds);

                        if (cached == null)
                        {
                            // Means the handle got closed in between, return it back and let caller deal with the issue.
                            return;
                        }

                        s_CachedCreds[key] = cached;
                        GlobalLog.Print("CacheCredential() Caching New Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count);

                        //
                        // A simplest way of preventing infinite cache grows.
                        //
                        // Security relief (DoS):
                        //     A number of active creds is never greater than a number of _outstanding_
                        //     security sessions, i.e. ssl connections.
                        //     So we will try to shrink cache to the number of active creds once in a while.
                        //
                        //    Just to make clear we won't shrink cache in the case when NO new handles are coming to it.
                        //
                        if ((s_CachedCreds.Count % c_CheckExpiredModulo) == 0)
                        {
                            DictionaryEntry[] toRemoveAttempt = new DictionaryEntry[s_CachedCreds.Count];
                            s_CachedCreds.CopyTo(toRemoveAttempt, 0);

                            for (int i = 0; i < toRemoveAttempt.Length; ++i)
                            {
                                cached = toRemoveAttempt[i].Value as SafeCredentialReference;

                                if (cached != null)
                                {
                                    creds = cached._Target;
                                    cached.Close();

                                    if (!creds.IsClosed && !creds.IsInvalid && (cached = SafeCredentialReference.CreateReference(creds)) != null)
                                    {
                                        s_CachedCreds[toRemoveAttempt[i].Key] = cached;
                                    }
                                    else
                                    {
                                        s_CachedCreds.Remove(toRemoveAttempt[i].Key);
                                    }
                                }
                            }
                            GlobalLog.Print("Scavenged cache, New Cache Count = " + s_CachedCreds.Count);
                        }
                    }
                    else
                    {
                        GlobalLog.Print("CacheCredential() (locked retry) Found already cached Handle = " + cached._Target.ToString());
                    }
                }
            }
            else
            {
                GlobalLog.Print("CacheCredential() Ignoring incoming handle = " + creds.ToString() + " since found already cached Handle = " + cached._Target.ToString());
            }
        }
示例#15
0
        private void ReadComplete(IAsyncResult transportResult)
        {
            while (true)
            {
                // Recover our asyncResult
                InnerAsyncResult userResult = transportResult.AsyncState as InnerAsyncResult;

                try
                {
                    if (!userResult.IsWriteCompletion)
                    {
                        userResult.Count = WrappedStream.EndRead(transportResult);
                        if (userResult.Count == 0)
                        {
                            m_SeenReadEOF = true;
                        }


                        if (!m_ShadowStreamIsDead)
                        {
                            userResult.IsWriteCompletion = true;
                            //Optionally charge notification write IO
                            transportResult = m_ShadowStream.BeginWrite(userResult.Buffer, userResult.Offset, userResult.Count, m_ReadCallback, userResult);
                            if (transportResult.CompletedSynchronously)
                            {
                                continue;
                            }
                            return;
                        }
                    }
                    else
                    {
                        GlobalLog.Assert(!m_ShadowStreamIsDead, "ForwardingReadStream::ReadComplete|ERROR: IsWriteCompletion && m_ShadowStreamIsDead");

                        m_ShadowStream.EndWrite(transportResult);
                        userResult.IsWriteCompletion = false;
                    }
                }
                catch (Exception e)
                {
                    //ASYNC: try to ignore even serious exceptions (nothing to loose?)
                    if (userResult.InternalPeekCompleted)
                    {
                        GlobalLog.Print("ShadowReadStream::ReadComplete() Rethrowing Exception (end), userResult.IsCompleted, stack trace = " + e.ToString());
                        throw;
                    }

                    try
                    {
                        m_ShadowStreamIsDead = true;
                        if (m_ShadowStream is ICloseEx)
                        {
                            ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
                        }
                        else
                        {
                            m_ShadowStream.Close();
                        }
                    }
                    catch (Exception ee)
                    {
                        //ASYNC: Again try to ignore even serious exceptions
                        GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close, stack trace = " + ee.ToString());
                    }

                    if (!userResult.IsWriteCompletion || m_ThrowOnWriteError)
                    {
                        if (transportResult.CompletedSynchronously)
                        {
                            throw;
                        }

                        userResult.InvokeCallback(e);
                        return;
                    }
                }

                // Need to process, re-issue the read.
                try
                {
                    if (m_BytesToSkip != 0L)
                    {
                        m_BytesToSkip   -= userResult.Count;
                        userResult.Count = m_BytesToSkip < (long)userResult.Buffer.Length? (int)m_BytesToSkip: userResult.Buffer.Length;
                        if (m_BytesToSkip == 0L)
                        {
                            // we did hide the original IO request in the outer iaresult state.
                            // charge the real user operation now
                            transportResult = userResult;
                            userResult      = userResult.AsyncState as InnerAsyncResult;
                            GlobalLog.Assert(userResult != null, "ForwardingReadStream::ReadComplete|ERROR: Inner IAResult is null after stream FastForwarding.");
                        }
                        transportResult = WrappedStream.BeginRead(userResult.Buffer, userResult.Offset, userResult.Count, m_ReadCallback, userResult);
                        if (transportResult.CompletedSynchronously)
                        {
                            continue;
                        }
                        return;
                    }
                    //if came to here, complete original user IO
                    userResult.InvokeCallback(userResult.Count);
                    return;
                }
                catch (Exception e)
                {
                    //ASYNC: try to ignore even serious exceptions (nothing to loose?)
                    if (userResult.InternalPeekCompleted)
                    {
                        GlobalLog.Print("ShadowReadStream::ReadComplete() Rethrowing Exception (begin), userResult.IsCompleted, stack trace = " + e.ToString());
                        throw;
                    }

                    try
                    {
                        m_ShadowStreamIsDead = true;
                        if (m_ShadowStream is ICloseEx)
                        {
                            ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
                        }
                        else
                        {
                            m_ShadowStream.Close();
                        }
                    }
                    catch (Exception ee)
                    {
                        //ASYNC: Again try to ignore even serious exceptions
                        GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close (after begin), stack trace = " + ee.ToString());
                    }

                    if (transportResult.CompletedSynchronously)
                    {
                        throw;
                    }

                    // This will set the exception result first then try to execute a user callback
                    userResult.InvokeCallback(e);
                    return;
                }
            }
        }
        private unsafe static void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped)
        {
#if DEBUG
            GlobalLog.SetThreadSource(ThreadKinds.CompletionPort);
            using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
#if TRAVE
                try
                {
#endif
#endif
            //
            // Create an Overlapped object out of the native pointer we're provided with.
            // (this will NOT free the unmanaged memory in the native overlapped structure)
            //
            Overlapped callbackOverlapped         = Overlapped.Unpack(nativeOverlapped);
            BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)callbackOverlapped.AsyncResult;
            Debug.Assert((IntPtr)nativeOverlapped == asyncResult.m_Cache.NativeOverlapped.DangerousGetHandle(), "Handle mismatch");

            // The AsyncResult must be cleared before the callback is called (i.e. before ExtractCache is called).
            // Not doing so leads to a leak where the pinned cached OverlappedData continues to point to the async result object,
            // which points to the Socket (as well as user data), which points to the OverlappedCache, preventing the OverlappedCache
            // finalizer from freeing the pinned OverlappedData.
            callbackOverlapped.AsyncResult = null;

            object returnObject = null;

            GlobalLog.Assert(!asyncResult.InternalPeekCompleted, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|asyncResult.IsCompleted", ValidationHelper.HashString(asyncResult));

            GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::CompletionPortCallback" +
                            " errorCode:" + errorCode.ToString() +
                            " numBytes:" + numBytes.ToString() +
                            " pOverlapped:" + ((int)nativeOverlapped).ToString());

            //
            // complete the IO and invoke the user's callback
            //
            SocketError socketError = (SocketError)errorCode;

            if (socketError != SocketError.Success && socketError != SocketError.OperationAborted)
            {
                // There are cases where passed errorCode does not reflect the details of the underlined socket error.
                // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted,
                //  .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket
                // or receiving data after shutdown (SD_RECV)).  With Winsock/TCP stack rewrite in longhorn, there may
                // be other differences as well."

                Socket socket = asyncResult.AsyncObject as Socket;
                if (socket == null)
                {
                    socketError = SocketError.NotSocket;
                }
                else if (socket.CleanedUp)
                {
                    socketError = SocketError.OperationAborted;
                }
                else
                {
                    try {
                        //
                        // The Async IO completed with a failure.
                        // here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error.
                        //
                        SocketFlags ignore;
                        bool        success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult(
                            socket.SafeHandle,
                            asyncResult.m_Cache.NativeOverlapped,
                            out numBytes,
                            false,
                            out ignore);
                        if (!success)
                        {
                            socketError = (SocketError)Marshal.GetLastWin32Error();
                            GlobalLog.Assert(socketError != 0, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|socketError:0 numBytes:{1}", ValidationHelper.HashString(asyncResult), numBytes);
                        }

                        GlobalLog.Assert(!success, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|Unexpectedly succeeded. errorCode:{1} numBytes:{2}", ValidationHelper.HashString(asyncResult), errorCode, numBytes);
                    }
                    // CleanedUp check above does not always work since this code is subject to race conditions
                    catch (ObjectDisposedException)
                    {
                        socketError = SocketError.OperationAborted;
                    }
                }
            }
            asyncResult.ErrorCode = (int)socketError;
            returnObject          = asyncResult.PostCompletion((int)numBytes);
            asyncResult.ReleaseUnmanagedStructures();
            asyncResult.InvokeCallback(returnObject);
#if DEBUG
#if TRAVE
        }

        catch (Exception exception)
        {
            if (!NclUtilities.IsFatal(exception))
            {
                GlobalLog.Assert("BaseOverlappedAsyncResult::CompletionPortCallback", "Exception in completion callback type:" + exception.GetType().ToString() + " message:" + exception.Message);
            }
            throw;
        }
#endif
        }
#endif
        }
        //
        private void CheckRetrieveOnResponse(Stream responseStream)
        {
            GlobalLog.Assert(_ProtocolStatus == CacheValidationStatus.Continue || _ProtocolStatus == CacheValidationStatus.RetryResponseFromServer, "CheckRetrieveOnResponse()|Unexpected _ProtocolStatus = ", _ProtocolStatus);
            bool closeCacheStream = true;

            try {
                // This will inspect the live response on the correctness matter
                switch (_ProtocolStatus = ValidateResponse())
                {
                case CacheValidationStatus.Continue:
                    closeCacheStream = false;
                    // The response looks good
                    break;

                case CacheValidationStatus.RetryResponseFromServer:
                    closeCacheStream = false;
                    break;

                case CacheValidationStatus.Fail:
                    _ProtocolStatus    = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "ValidateResponse"));
                    break;

                case CacheValidationStatus.DoNotUseCache:
                    break;

                default:
                    _ProtocolStatus    = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "ValidateResponse", _Validator.ValidationStatus.ToString()));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "ValidateResponse()", _Validator.ValidationStatus.ToString()));
                    }
                    break;
                }
            }
            catch (Exception e) {
                closeCacheStream   = true;
                _ProtocolException = e;
                _ProtocolStatus    = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
                }
            }
            finally {
                // This is to release cache entry in case we are not interested in it
                if (closeCacheStream && _ResponseStream != null)
                {
                    _ResponseStream.Close();
                    _ResponseStream        = null;
                    _Validator.CacheStream = Stream.Null;
                }
            }

            if (_ProtocolStatus != CacheValidationStatus.Continue)
            {
                return;
            }

            //
            // only CacheValidationStatus.Continue goes here with closeCacheStream == false
            //

            try {
                //
                switch (_ProtocolStatus = RevalidateCache())
                {
                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.RemoveFromCache:
                case CacheValidationStatus.DoNotTakeFromCache:
                    closeCacheStream = true;
                    break;

                case CacheValidationStatus.ReturnCachedResponse:
                    if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                    {
                        _ProtocolStatus    = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_null_cached_stream, "RevalidateCache()"));
                        }
                        break;
                    }

                    Stream stream = _Validator.CacheStream;

                    if (_Validator.CacheStreamOffset != 0L || _Validator.CacheStreamLength != _Validator.CacheEntry.StreamSize)
                    {
                        stream = new RangeStream(stream, _Validator.CacheStreamOffset, _Validator.CacheStreamLength);
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_returned_range_cache, "RevalidateCache()", _Validator.CacheStreamOffset, _Validator.CacheStreamLength));
                        }
                    }
                    _ResponseStream       = stream;
                    _ResponseStreamLength = _Validator.CacheStreamLength;
                    break;

                case CacheValidationStatus.CombineCachedAndServerResponse:

                    if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                    {
                        _ProtocolStatus    = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_requested_combined_but_null_cached_stream, "RevalidateCache()"));
                        }
                        break;
                    }
                    if (responseStream != null)
                    {
                        stream = new CombinedReadStream(_Validator.CacheStream, responseStream);
                    }
                    else
                    {
                        // So Abort can close the cache stream
                        stream = _Validator.CacheStream;
                    }
                    _ResponseStream       = stream;
                    _ResponseStreamLength = _Validator.CacheStreamLength;
                    break;


                case CacheValidationStatus.Fail:
                    closeCacheStream   = true;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "RevalidateCache"));
                    break;

                default:
                    closeCacheStream   = true;
                    _ProtocolStatus    = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "RevalidateCache", _Validator.ValidationStatus.ToString()));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "RevalidateCache()", _Validator.ValidationStatus.ToString()));
                    }
                    break;
                }
            }
            catch (Exception e) {
                closeCacheStream   = true;
                _ProtocolException = e;
                _ProtocolStatus    = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
                }
            }
            finally {
                // This is to release cache entry in case we are not interested in it
                if (closeCacheStream && _ResponseStream != null)
                {
                    _ResponseStream.Close();
                    _ResponseStream        = null;
                    _Validator.CacheStream = Stream.Null;
                }
            }
        }
        //
        // This method is called after an asynchronous call is made for the user,
        // it checks and acts accordingly if the IO:
        // 1) completed synchronously.
        // 2) was pended.
        // 3) failed.
        //
        internal void CheckAsyncCallResult(int status)
        {
            Socket socket = (Socket)AsyncObject;

            GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::CheckAsyncCallResult() status:" + status.ToString());

            switch (status)
            {
            case SocketErrors.Success:
                //
                // the Async IO call completed synchronously:
                //
                break;

            case SocketErrors.WSAEWOULDBLOCK:
                //
                // the Async IO call was pended:
                // Queue our event to the thread pool.
                //
                Monitor.Exit(socket);

                GlobalLog.Assert(
                    socket.m_AsyncEvent != null,
                    "ConnectAsyncResult: m_AsyncAcceptEvent == null", string.Empty);

                ThreadPool.RegisterWaitForSingleObject(
                    socket.m_AsyncEvent,
                    m_AcceptCallback,
                    this,
                    -1,
                    true);

                //
                // we're done, return
                //
                return;

            default:
                //
                // the Async IO call failed:
                // set the Result to the Win32 error
                //
                ErrorCode = status;
                break;
            }
            //
            // dequeue from the accept list since the accept completed
            //
            socket.AcceptQueue.RemoveAt(socket.AcceptQueue.Count - 1);
            if (socket.AcceptQueue.Count == 0)
            {
                //
                // if the queue is now empty
                // cancel async event
                //
                socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
                //
                // go back to blocking mode
                //
                socket.InternalSetBlocking(true);
            }
            Monitor.Exit(socket);

            if (status == SocketErrors.Success)
            {
                //
                // synchronously complete the IO and call the user's callback.
                //
                InvokeCallback(true);
            }
        }
示例#19
0
        internal static int Encrypt(
            SafeDeleteContext securityContext,
            byte[] buffer,
            int offset,
            int count,
            bool isConfidential,
            bool isNtlm,
            ref byte[] output,
            uint sequenceNumber)
        {
            SecSizes sizes = SSPIWrapper.QueryContextAttributes(
                GlobalSSPI.SSPIAuth,
                securityContext,
                Interop.SspiCli.ContextAttribute.Sizes
                ) as SecSizes;

            try
            {
                int maxCount = checked (Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer);

                if (count > maxCount || count < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.net_io_out_range, maxCount));
                }
            }
            catch (Exception e)
            {
                if (!ExceptionCheck.IsFatal(e))
                {
                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range.");
                    }

                    Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range.");
                }

                throw;
            }

            int resultSize = count + sizes.SecurityTrailer + sizes.BlockSize;

            if (output == null || output.Length < resultSize + 4)
            {
                output = new byte[resultSize + 4];
            }

            // Make a copy of user data for in-place encryption.
            Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count);

            // Prepare buffers TOKEN(signature), DATA and Padding.
            var securityBuffer = new SecurityBuffer[3];

            securityBuffer[0] = new SecurityBuffer(output, 4, sizes.SecurityTrailer, SecurityBufferType.Token);
            securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, SecurityBufferType.Data);
            securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer + count, sizes.BlockSize, SecurityBufferType.Padding);

            int errorCode;

            if (isConfidential)
            {
                errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber);
            }
            else
            {
                if (isNtlm)
                {
                    securityBuffer[1].type |= SecurityBufferType.ReadOnlyFlag;
                }

                errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0);
            }

            if (errorCode != 0)
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                }
                throw new Win32Exception(errorCode);
            }

            // Compacting the result.
            resultSize = securityBuffer[0].size;
            bool forceCopy = false;

            if (resultSize != sizes.SecurityTrailer)
            {
                forceCopy = true;
                Buffer.BlockCopy(output, securityBuffer[1].offset, output, 4 + resultSize, securityBuffer[1].size);
            }

            resultSize += securityBuffer[1].size;
            if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.SecurityTrailer)))
            {
                Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size);
            }

            resultSize += securityBuffer[2].size;
            unchecked
            {
                // TODO (Issue #6063): Should be offset by offset
                output[0] = (byte)((resultSize) & 0xFF);
                output[1] = (byte)(((resultSize) >> 8) & 0xFF);
                output[2] = (byte)(((resultSize) >> 16) & 0xFF);
                output[3] = (byte)(((resultSize) >> 24) & 0xFF);
            }

            return(resultSize + 4);
        }
示例#20
0
 internal InternalException()
 {
     GlobalLog.Assert("InternalException thrown.");
 }
示例#21
0
        internal HttpWebResponse(Uri responseUri, KnownHttpVerb verb, CoreResponseData coreData, string mediaType, bool usesProxySemantics, DecompressionMethods decompressionMethod)
        {
            m_Uri                = responseUri;
            m_Verb               = verb;
            m_MediaType          = mediaType;
            m_UsesProxySemantics = usesProxySemantics;

            m_ConnectStream       = coreData.m_ConnectStream;
            m_HttpResponseHeaders = coreData.m_ResponseHeaders;
            m_ContentLength       = coreData.m_ContentLength;
            m_StatusCode          = coreData.m_StatusCode;
            m_StatusDescription   = coreData.m_StatusDescription;
            m_IsVersionHttp11     = coreData.m_IsVersionHttp11;


            //if the returned contentlength is zero, preemptively invoke calldone on the stream.
            //this will wake up any pending reads.
            if (m_ContentLength == 0 && m_ConnectStream is ConnectStream)
            {
                ((ConnectStream)m_ConnectStream).CallDone();
            }

            // handle Content-Location header, by combining it with the orginal request.
            string contentLocation = m_HttpResponseHeaders[HttpKnownHeaderNames.ContentLocation];

            if (contentLocation != null)
            {
                try
                {
                    m_Uri = new Uri(m_Uri, contentLocation);
                }
                catch (UriFormatException e)
                {
                    GlobalLog.Assert("Exception on response Uri parsing.", e.ToString());
                }
            }
            // decompress responses by hooking up a final response Stream - only if user required it
            if (decompressionMethod != DecompressionMethods.None)
            {
                string contentEncoding = m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding];
                if (contentEncoding != null)
                {
                    if (((decompressionMethod & DecompressionMethods.GZip) != 0) && contentEncoding.IndexOf(HttpWebRequest.GZipHeader) != -1)
                    {
                        m_ConnectStream = new GZipWrapperStream(m_ConnectStream, CompressionMode.Decompress);
                        m_ContentLength = -1; // unknown on compressed streams

                        // Setting a response header after parsing will ruin the Common Header optimization.
                        // This seems like a corner case.  ContentEncoding could be added as a common header, with a special
                        // property allowing it to be nulled.
                        m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding] = null;
                    }
                    else if (((decompressionMethod & DecompressionMethods.Deflate) != 0) && contentEncoding.IndexOf(HttpWebRequest.DeflateHeader) != -1)
                    {
                        m_ConnectStream = new DeflateWrapperStream(m_ConnectStream, CompressionMode.Decompress);
                        m_ContentLength = -1; // unknown on compressed streams

                        // Setting a response header after parsing will ruin the Common Header optimization.
                        // This seems like a corner case.  ContentEncoding could be added as a common header, with a special
                        // property allowing it to be nulled.
                        m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding] = null;
                    }
                }
            }
        }
示例#22
0
 private void LogBuffer(int size)
 {
     GlobalLog.Assert(SocketsEventSource.Log.IsEnabled(), "ReceiveMessageOverlappedAsyncResult#{0}::LogBuffer()|Logging is off!", LoggingHash.HashString(this));
     SocketsEventSource.Dump(SocketsEventSource.MethodType.PostCompletion, _wsaBuffer->Pointer, Math.Min(_wsaBuffer->Length, size));
 }
        // Callback which fires when an internal connection attempt completes.
        // If it failed and there are more addresses to try, do it.
        private void InternalConnectCallback(object sender, SocketAsyncEventArgs args)
        {
            Exception exception = null;

            lock (_lockObject)
            {
                if (_state == State.Canceled)
                {
                    // If Cancel was called before we got the lock, the Socket will be closed soon.  We need to report
                    // OperationAborted (even though the connection actually completed), or the user will try to use a
                    // closed Socket.
                    exception = new SocketException((int)SocketError.OperationAborted);
                }
                else if (_state == State.ConnectAttempt)
                {
                    if (args.SocketError == SocketError.Success)
                    {
                        if (RequiresUserConnectAttempt)
                        {
                            exception = AttemptUserConnection();

                            if (exception == null)
                            {
                                // Don't call the callback; we've started a connection attempt on the
                                // user's socket.
                                _state = State.UserConnectAttempt;
                                return;
                            }
                        }

                        // The connection attempt succeeded or the user connect attempt failed synchronously; go to the
                        // completed state. The callback will be called outside the lock.
                        _state = State.Completed;
                    }
                    else if (args.SocketError == SocketError.OperationAborted)
                    {
                        // The socket was closed while the connect was in progress.  This can happen if the user
                        // closes the socket, and is equivalent to a call to CancelConnectAsync
                        exception = new SocketException((int)SocketError.OperationAborted);
                        _state    = State.Canceled;
                    }
                    else
                    {
                        // Try again, if there are more IPAddresses to be had.

                        // If the underlying OS does not support multiple connect attempts
                        // on the same socket, dispose the socket used for the last attempt.
                        if (!SocketPal.SupportsMultipleConnectAttempts)
                        {
                            _lastAttemptSocket.Dispose();
                        }

                        // Keep track of this because it will be overwritten by AttemptConnection
                        SocketError currentFailure   = args.SocketError;
                        Exception   connectException = AttemptConnection();

                        if (connectException == null)
                        {
                            // don't call the callback, another connection attempt is successfully started
                            return;
                        }
                        else
                        {
                            SocketException socketException = connectException as SocketException;
                            if (socketException != null && socketException.SocketErrorCode == SocketError.NoData)
                            {
                                // If the error is NoData, that means there are no more IPAddresses to attempt
                                // a connection to.  Return the last error from an actual connection instead.
                                exception = new SocketException((int)currentFailure);
                            }
                            else
                            {
                                exception = connectException;
                            }

                            _state = State.Completed;
                        }
                    }
                }
                else
                {
                    GlobalLog.Assert(_state == State.UserConnectAttempt, "MultipleConnectAsync.InternalConnectCallback(): Unexpected object state");
                    GlobalLog.Assert(RequiresUserConnectAttempt, "MultipleConnectAsync.InternalConnectCallback(): State.UserConnectAttempt without RequiresUserConnectAttempt");

                    if (args.SocketError == SocketError.Success)
                    {
                        _state = State.Completed;
                    }
                    else if (args.SocketError == SocketError.OperationAborted)
                    {
                        // The socket was closed while the connect was in progress.  This can happen if the user
                        // closes the socket, and is equivalent to a call to CancelConnectAsync
                        exception = new SocketException((int)SocketError.OperationAborted);
                        _state    = State.Canceled;
                    }
                    else
                    {
                        // The connect attempt on the user's socket failed. Return the corresponding error.
                        exception = new SocketException((int)args.SocketError);
                        _state    = State.Completed;
                    }
                }
            }

            if (exception == null)
            {
                Succeed();
            }
            else
            {
                AsyncFail(exception);
            }
        }
示例#24
0
        //
        // SetUnmanagedStructures -
        //
        //  This needs to be called for overlapped IO to function properly.
        //
        //  Fills in Overlapped Structures used in an Async Overlapped Winsock call
        //  these calls are outside the runtime and are unmanaged code, so we need
        //  to prepare specific structures and ints that lie in unmanaged memory
        //  since the Overlapped calls can be Async
        //
        internal void SetUnmanagedStructures(object objectsToPin)
        {
            if (!m_DisableOverlapped)
            {
                // Casting to object[] is very expensive.  Only do it once.
                object[] objectsToPinArray   = null;
                bool     triedCastingToArray = false;

                bool useCache = false;
                if (m_Cache != null)
                {
                    if (objectsToPin == null && m_Cache.PinnedObjects == null)
                    {
                        useCache = true;
                    }
                    else if (m_Cache.PinnedObjects != null)
                    {
                        if (m_Cache.PinnedObjectsArray == null)
                        {
                            if (objectsToPin == m_Cache.PinnedObjects)
                            {
                                useCache = true;
                            }
                        }
                        else if (objectsToPin != null)
                        {
                            triedCastingToArray = true;
                            objectsToPinArray   = objectsToPin as object[];
                            if (objectsToPinArray != null && objectsToPinArray.Length == 0)
                            {
                                objectsToPinArray = null;
                            }
                            if (objectsToPinArray != null && objectsToPinArray.Length == m_Cache.PinnedObjectsArray.Length)
                            {
                                useCache = true;
                                for (int i = 0; i < objectsToPinArray.Length; i++)
                                {
                                    if (objectsToPinArray[i] != m_Cache.PinnedObjectsArray[i])
                                    {
                                        useCache = false;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                if (!useCache && m_Cache != null)
                {
                    GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::SetUnmanagedStructures() Cache miss - freeing cache.");
                    m_Cache.Free();
                    m_Cache = null;
                }

                Socket s = (Socket)AsyncObject;
                if (m_UseOverlappedIO)
                {
                    GlobalLog.Assert(m_UnmanagedBlob == null, "BaseOverlappedAsyncResult#{0}::SetUnmanagedStructures()|Unmanaged blob already allocated. (Called twice?)", ValidationHelper.HashString(this));
                    m_UnmanagedBlob = SafeOverlappedFree.Alloc(s.SafeHandle);

                    PinUnmanagedObjects(objectsToPin);

                    //
                    // create the event handle
                    //

                    m_OverlappedEvent = new AutoResetEvent(false);

                    //
                    // fill in the overlapped structure with the event handle.
                    //

                    Marshal.WriteIntPtr(m_UnmanagedBlob.DangerousGetHandle(), Win32.OverlappedhEventOffset, m_OverlappedEvent.SafeWaitHandle.DangerousGetHandle());
                }
                else
                {
                    //
                    // Bind the Win32 Socket Handle to the ThreadPool
                    //
                    s.BindToCompletionPort();

                    if (m_Cache == null)
                    {
                        GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() Creating new overlapped cache.");
                        if (objectsToPinArray != null)
                        {
                            m_Cache = new OverlappedCache(new Overlapped(), objectsToPinArray, s_IOCallback);
                        }
                        else
                        {
                            m_Cache = new OverlappedCache(new Overlapped(), objectsToPin, s_IOCallback, triedCastingToArray);
                        }
                    }
                    else
                    {
                        GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() Using cached overlapped.");
                    }

                    m_Cache.Overlapped.AsyncResult = this;

#if DEBUG
                    unsafe { m_InitialNativeOverlapped = *((NativeOverlapped *)m_Cache.NativeOverlapped); }
#endif

                    GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() overlapped:" + ValidationHelper.HashString(m_Cache.Overlapped) + " NativeOverlapped = " + m_Cache.NativeOverlapped.ToString("x"));
                }
            }
        }
示例#25
0
        /*++
         *  GenerateToken - Called after each successive state
         *  in the Client - Server handshake.  This function
         *  generates a set of bytes that will be sent next to
         *  the server.  The server responds, each response,
         *  is pass then into this function, again, and the cycle
         *  repeats until successful connection, or failure.
         *
         *  Input:
         *      input  - bytes from the wire
         *      output - ref to byte [], what we will send to the
         *          server in response
         *  Return:
         *      errorCode - an SSPI error code
         * --*/
        private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref byte[] output)
        {
#if TRACE_VERBOSE
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::GenerateToken, _refreshCredentialNeeded = " + _refreshCredentialNeeded);
#endif

            if (offset < 0 || offset > (input == null ? 0 : input.Length))
            {
                GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::GenerateToken", "Argument 'offset' out of range.");
                throw new ArgumentOutOfRangeException("offset");
            }

            if (count < 0 || count > (input == null ? 0 : input.Length - offset))
            {
                GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::GenerateToken", "Argument 'count' out of range.");
                throw new ArgumentOutOfRangeException("count");
            }

            SecurityBuffer   incomingSecurity        = null;
            SecurityBuffer[] incomingSecurityBuffers = null;

            if (input != null)
            {
                incomingSecurity        = new SecurityBuffer(input, offset, count, SecurityBufferType.Token);
                incomingSecurityBuffers = new SecurityBuffer[]
                {
                    incomingSecurity,
                    new SecurityBuffer(null, 0, 0, SecurityBufferType.Empty)
                };
            }

            SecurityBuffer outgoingSecurity = new SecurityBuffer(null, SecurityBufferType.Token);

            SecurityStatusPal errorCode = 0;

            bool   cachedCreds = false;
            byte[] thumbPrint  = null;

            //
            // Looping through ASC or ISC with potentially cached credential that could have been
            // already disposed from a different thread before ISC or ASC dir increment a cred ref count.
            //
            try
            {
                do
                {
                    thumbPrint = null;
                    if (_refreshCredentialNeeded)
                    {
                        cachedCreds = _serverMode
                                        ? AcquireServerCredentials(ref thumbPrint)
                                        : AcquireClientCredentials(ref thumbPrint);
                    }

                    if (_serverMode)
                    {
                        errorCode = SslStreamPal.AcceptSecurityContext(
                            ref _credentialsHandle,
                            ref _securityContext,
                            incomingSecurity,
                            outgoingSecurity,
                            _remoteCertRequired);
                    }
                    else
                    {
                        if (incomingSecurity == null)
                        {
                            errorCode = SslStreamPal.InitializeSecurityContext(
                                ref _credentialsHandle,
                                ref _securityContext,
                                _destination,
                                incomingSecurity,
                                outgoingSecurity);
                        }
                        else
                        {
                            errorCode = SslStreamPal.InitializeSecurityContext(
                                _credentialsHandle,
                                ref _securityContext,
                                _destination,
                                incomingSecurityBuffers,
                                outgoingSecurity);
                        }
                    }
                } while (cachedCreds && _credentialsHandle == null);
            }
            finally
            {
                if (_refreshCredentialNeeded)
                {
                    _refreshCredentialNeeded = false;

                    //
                    // Assuming the ISC or ASC has referenced the credential,
                    // we want to call dispose so to decrement the effective ref count.
                    //
                    if (_credentialsHandle != null)
                    {
                        _credentialsHandle.Dispose();
                    }

                    //
                    // This call may bump up the credential reference count further.
                    // Note that thumbPrint is retrieved from a safe cert object that was possible cloned from the user passed cert.
                    //
                    if (!cachedCreds && _securityContext != null && !_securityContext.IsInvalid && _credentialsHandle != null && !_credentialsHandle.IsInvalid)
                    {
                        SslSessionsCache.CacheCredential(_credentialsHandle, thumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);
                    }
                }
            }

            output = outgoingSecurity.token;

#if TRACE_VERBOSE
            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::GenerateToken()", Interop.MapSecurityStatus((uint)errorCode));
#endif
            return((SecurityStatusPal)errorCode);
        }
示例#26
0
        private unsafe static void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped)
        {
#if DEBUG
            GlobalLog.SetThreadSource(ThreadKinds.CompletionPort);
            using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
#endif
            //
            // Create an Overlapped object out of the native pointer we're provided with.
            // (this will NOT free the unmanaged memory in the native overlapped structure)
            //
            Overlapped callbackOverlapped         = Overlapped.Unpack(nativeOverlapped);
            BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)callbackOverlapped.AsyncResult;

            // The AsyncResult must be cleared before the callback is called (i.e. before ExtractCache is called).
            // Not doing so leads to a leak where the pinned cached OverlappedData continues to point to the async result object,
            // which points to the Socket (as well as user data), which points to the OverlappedCache, preventing the OverlappedCache
            // finalizer from freeing the pinned OverlappedData.
            callbackOverlapped.AsyncResult = null;

            object returnObject = null;

            GlobalLog.Assert(!asyncResult.InternalPeekCompleted, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|asyncResult.IsCompleted", ValidationHelper.HashString(asyncResult));

            GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::CompletionPortCallback" +
                            " errorCode:" + errorCode.ToString() +
                            " numBytes:" + numBytes.ToString() +
                            " pOverlapped:" + ((int)nativeOverlapped).ToString());

            //
            // complete the IO and invoke the user's callback
            //
            SocketError socketError = (SocketError)errorCode;

            if (socketError != SocketError.Success && socketError != SocketError.OperationAborted)
            {
                Socket socket = asyncResult.AsyncObject as Socket;
                if (socket == null)
                {
                    socketError = SocketError.NotSocket;
                }
                else if (socket.CleanedUp)
                {
                    socketError = SocketError.OperationAborted;
                }
                else
                {
                    try {
                        //
                        // The Async IO completed with a failure.
                        // here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error.
                        //
                        bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult(
                            socket.SafeHandle,
                            (IntPtr)nativeOverlapped,
                            out numBytes,
                            false,
                            IntPtr.Zero);

                        if (!success)
                        {
                            socketError = (SocketError)Marshal.GetLastWin32Error();
                            GlobalLog.Assert(socketError != 0, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|socketError:0 numBytes:{1}", ValidationHelper.HashString(asyncResult), numBytes);
                        }

                        GlobalLog.Assert(!success, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|Unexpectedly succeeded. errorCode:{1} numBytes:{2}", ValidationHelper.HashString(asyncResult), errorCode, numBytes);
                    }
                    // CleanedUp check above does not always work since this code is subject to race conditions
                    catch (ObjectDisposedException)
                    {
                        socketError = SocketError.OperationAborted;
                    }
                }
            }
            asyncResult.ErrorCode = (int)socketError;
            returnObject          = asyncResult.PostCompletion((int)numBytes);
            asyncResult.ReleaseUnmanagedStructures();
            asyncResult.InvokeCallback(returnObject);
#if DEBUG
        }
#endif
        }
        //
        // Private methods
        //

        //
        // This method may be invoked as part of the request submission but before issuing a live request
        //
        private void CheckRetrieveBeforeSubmit()
        {
            GlobalLog.Assert(_ProtocolStatus == CacheValidationStatus.Continue, "CheckRetrieveBeforeSubmit()|Unexpected _ProtocolStatus = {0}", _ProtocolStatus);

            try {
                while (true)
                {
                    RequestCacheEntry cacheEntry;

                    if (_Validator.CacheStream != null && _Validator.CacheStream != Stream.Null)
                    {
                        // Reset to Initial state
                        _Validator.CacheStream.Close();
                        _Validator.CacheStream = Stream.Null;
                    }

                    if (_Validator.StrictCacheErrors)
                    {
                        _Validator.CacheStream = _RequestCache.Retrieve(_Validator.CacheKey, out cacheEntry);
                    }
                    else
                    {
                        Stream stream;
                        _RequestCache.TryRetrieve(_Validator.CacheKey, out cacheEntry, out stream);
                        _Validator.CacheStream = stream;
                    }

                    if (cacheEntry == null)
                    {
                        cacheEntry = new RequestCacheEntry();
                        cacheEntry.IsPrivateEntry = _RequestCache.IsPrivateCache;
                        _Validator.FetchCacheEntry(cacheEntry);
                    }

                    if (_Validator.CacheStream == null)
                    {
                        // If entry does not have a stream an empty stream wrapper must be returned.
                        // A null or Stream.Null value stands for non existent cache entry.
                        _Validator.CacheStream = Stream.Null;
                    }

                    ValidateFreshness(cacheEntry);

                    _ProtocolStatus = ValidateCache();

                    // This will tell us what to do next
                    switch (_ProtocolStatus)
                    {
                    case CacheValidationStatus.ReturnCachedResponse:
                        if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                        {
                            if (Logging.On)
                            {
                                Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_no_cache_entry, "ValidateCache()"));
                            }
                            _ProtocolStatus    = CacheValidationStatus.Fail;
                            _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                            break;
                        }

                        // Final decision is made, check on a range response from cache
                        Stream stream = _Validator.CacheStream;
                        // The entry can now be replaced as we are not going for cache entry metadata-only  update
                        _RequestCache.UnlockEntry(_Validator.CacheStream);

                        if (_Validator.CacheStreamOffset != 0L || _Validator.CacheStreamLength != _Validator.CacheEntry.StreamSize)
                        {
                            stream = new RangeStream(stream, _Validator.CacheStreamOffset, _Validator.CacheStreamLength);
                            if (Logging.On)
                            {
                                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_returned_range_cache, "ValidateCache()", _Validator.CacheStreamOffset, _Validator.CacheStreamLength));
                            }
                        }
                        _ResponseStream       = stream;
                        _ResponseStreamLength = _Validator.CacheStreamLength;
                        break;

                    case CacheValidationStatus.Continue:
                        // copy a cache stream ref
                        _ResponseStream = _Validator.CacheStream;
                        break;

                    case CacheValidationStatus.RetryResponseFromCache:
                        // loop thought cache retrieve
                        continue;

                    case CacheValidationStatus.DoNotTakeFromCache:
                    case CacheValidationStatus.DoNotUseCache:
                        break;

                    case CacheValidationStatus.Fail:
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "ValidateCache"));
                        break;

                    default:
                        _ProtocolStatus    = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "ValidateCache", _Validator.ValidationStatus.ToString()));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "ValidateCache()", _Validator.ValidationStatus.ToString()));
                        }
                        break;
                    }
                    break;
                }
            }
            catch (Exception e) {
                _ProtocolStatus    = CacheValidationStatus.Fail;
                _ProtocolException = e;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
                }
            }
            finally {
                // This is to release cache entry on error
                if (_ResponseStream == null && _Validator.CacheStream != null && _Validator.CacheStream != Stream.Null)
                {
                    _Validator.CacheStream.Close();
                    _Validator.CacheStream = Stream.Null;
                }
            }
        }
示例#28
0
        //
        // This method is called after an asynchronous call is made for the user,
        // it checks and acts accordingly if the IO:
        // 1) completed synchronously.
        // 2) was pended.
        // 3) failed.
        //
        internal unsafe SocketError CheckAsyncCallOverlappedResult(SocketError errorCode)
        {
#if DEBUG
            m_SavedErrorCode = errorCode;
#endif

            //
            // Check if the Async IO call:
            // 1) was pended.
            // 2) completed synchronously.
            // 3) failed.
            //
            if (m_UseOverlappedIO)
            {
                //
                // we're using overlapped IO under Win9x (or NT with registry setting overriding
                // completion port usage)
                //
                switch (errorCode)
                {
                case 0:
                case SocketError.IOPending:

                    //
                    // the Async IO call was pended:
                    // Queue our event to the thread pool.
                    //
                    GlobalLog.Assert(m_UnmanagedBlob != null, "BaseOverlappedAsyncResult#{0}::CheckAsyncCallOverlappedResult()|Unmanaged blob isn't allocated.", ValidationHelper.HashString(this));
                    ThreadPool.UnsafeRegisterWaitForSingleObject(
                        m_OverlappedEvent,
                        new WaitOrTimerCallback(OverlappedCallback),
                        this,
                        -1,
                        true);

                    //
                    // we're done, completion will be asynchronous
                    // in the callback. return
                    //
                    return(SocketError.Success);

                default:
                    //
                    // the Async IO call failed:
                    // set the number of bytes transferred to -1 (error)
                    //
                    ErrorCode = (int)errorCode;
                    Result    = -1;
                    ReleaseUnmanagedStructures();
                    break;
                }
            }
            else
            {
#if DEBUG
                OverlappedCache cache = m_Cache;
                if (cache != null)
                {
                    unsafe
                    {
                        NativeOverlapped *nativeOverlappedPtr = (NativeOverlapped *)cache.NativeOverlapped;
                        if (nativeOverlappedPtr != null)
                        {
                            m_IntermediateNativeOverlapped = *nativeOverlappedPtr;
                        }
                    }
                }
#endif
                //
                // We're using completion ports under WinNT.  Release one reference on the structures for
                // the main thread.
                //
                ReleaseUnmanagedStructures();

                switch (errorCode)
                {
                //
                // ignore cases in which a completion packet will be queued:
                // we'll deal with this IO in the callback
                //
                case 0:
                case SocketError.IOPending:
                    //
                    // ignore, do nothing
                    //
                    return(SocketError.Success);

                //
                // in the remaining cases a completion packet will NOT be queued:
                // we'll have to call the callback explicitly signaling an error
                //
                default:
                    //
                    // call the callback with error code
                    //
                    ErrorCode = (int)errorCode;
                    Result    = -1;

                    // The AsyncResult must be cleared since the callback isn't going to be called.
                    // Not doing so leads to a leak where the pinned cached OverlappedData continues to point to the async result object,
                    // which points to the Socket (as well as user data) and to the OverlappedCache, preventing the OverlappedCache
                    // finalizer from freeing the pinned OverlappedData.
                    if (m_Cache != null)
                    {
                        // Could be null only if SetUnmanagedStructures weren't called.
                        m_Cache.Overlapped.AsyncResult = null;
                    }

                    ReleaseUnmanagedStructures();  // Additional release for the completion that won't happen.
                    break;
                }
            }
            return(errorCode);
        }
示例#29
0
        internal static int Decrypt(
            SafeDeleteContext securityContext,
            byte[] buffer,
            int offset,
            int count,
            bool isConfidential,
            bool isNtlm,
            out int newOffset,
            uint sequenceNumber)
        {
            if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range.");
                }

                Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range.");

                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range.");
                }

                Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range.");

                throw new ArgumentOutOfRangeException(nameof(count));
            }

            if (isNtlm)
            {
                return(DecryptNtlm(securityContext, buffer, offset, count, isConfidential, out newOffset, sequenceNumber));
            }

            //
            // Kerberos and up
            //
            var securityBuffer = new SecurityBuffer[2];

            securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.Stream);
            securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.Data);

            int errorCode;

            if (isConfidential)
            {
                errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber);
            }
            else
            {
                errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber);
            }

            if (errorCode != 0)
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("NTAuthentication#" + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                }
                throw new Win32Exception(errorCode);
            }

            if (securityBuffer[1].type != SecurityBufferType.Data)
            {
                throw new InternalException();
            }

            newOffset = securityBuffer[1].offset;
            return(securityBuffer[1].size);
        }
示例#30
0
        // Called when the DNS query completes (either synchronously or asynchronously).  Checks for failure and
        // starts the first connection attempt if it succeeded.  Returns true if the operation will be asynchronous,
        // false if it has failed synchronously.
        private bool DoDnsCallback(IAsyncResult result, bool sync)
        {
            Exception exception = null;

            lock (_lockObject)
            {
                // If the connection attempt was canceled during the dns query, the user's callback has already been
                // called asynchronously and we simply need to return.
                if (_state == State.Canceled)
                {
                    return(true);
                }

                if (_state != State.DnsQuery && GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("MultipleConnectAsync.DoDnsCallback(): Unexpected object state");
                }

                try
                {
                    _addressList = DnsAPMExtensions.EndGetHostAddresses(result);
                    if (_addressList == null && GlobalLog.IsEnabled)
                    {
                        GlobalLog.Assert("MultipleConnectAsync.DoDnsCallback(): EndGetHostAddresses returned null!");
                    }
                }
                catch (Exception e)
                {
                    _state    = State.Completed;
                    exception = e;
                }

                // If the dns query succeeded, try to connect to the first address
                if (exception == null)
                {
                    _state = State.ConnectAttempt;

                    _internalArgs            = new SocketAsyncEventArgs();
                    _internalArgs.Completed += InternalConnectCallback;

                    if (!RequiresUserConnectAttempt)
                    {
                        _internalArgs.SetBuffer(_userArgs.Buffer, _userArgs.Offset, _userArgs.Count);
                    }

                    exception = AttemptConnection();

                    if (exception != null)
                    {
                        // There was a synchronous error while connecting
                        _state = State.Completed;
                    }
                }
            }

            // Call this outside of the lock because it might call the user's callback.
            if (exception != null)
            {
                return(Fail(sync, exception));
            }
            else
            {
                return(true);
            }
        }