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); }
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); } }
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); } }
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); } }
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); } }
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); }
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()); } }
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); } }
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); }
internal InternalException() { GlobalLog.Assert("InternalException thrown."); }
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; } } } }
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); } }
// // 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")); } } }
/*++ * 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); }
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; } } }
// // 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); }
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); }
// 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); } }