void SendMailCallback(IAsyncResult result) { GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback"); try { writer = transport.EndSendMail(result); // If some recipients failed but not others, send the e-mail anyways, but then return the // "Non-fatal" exception reporting the failures. The sync code path does it this way. // Fatal exceptions would have thrown above at transport.EndSendMail(...) SendMailAsyncResult sendResult = (SendMailAsyncResult)result; // Save these and throw them later in SendMessageCallback, after the message has sent. failedRecipientException = sendResult.GetFailedRecipientException(); } catch (Exception e) { Complete(e, result); GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback"); return; } try { if (cancelled) { Complete(null, result); } else { message.BeginSend(writer, DeliveryMethod != SmtpDeliveryMethod.Network, ServerSupportsEai, new AsyncCallback(SendMessageCallback), result.AsyncState); } } catch (Exception e) { Complete(e, result); } GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback"); }
internal static IPEndPoint GetRemoteEndPoint(byte[] memoryBlob, IntPtr originalAddress) { GlobalLog.Enter("HttpApi::GetRemoteEndPoint()"); SocketAddress v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize); SocketAddress v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize); fixed(byte *pMemoryBlob = memoryBlob) { HTTP_REQUEST *request = (HTTP_REQUEST *)pMemoryBlob; IntPtr address = request->Address.pRemoteAddress != null ? (IntPtr)(pMemoryBlob - (byte *)originalAddress + (byte *)request->Address.pRemoteAddress) : IntPtr.Zero; CopyOutAddress(address, ref v4address, ref v6address); } IPEndPoint endpoint = null; if (v4address != null) { endpoint = IPEndPoint.Any.Create(v4address) as IPEndPoint; } else if (v6address != null) { endpoint = IPEndPoint.IPv6Any.Create(v6address) as IPEndPoint; } GlobalLog.Leave("HttpApi::GetRemoteEndPoint()"); return(endpoint); }
internal SecureChannel(string hostname, bool serverMode, SslProtocols sslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName, bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::.ctor", "hostname:" + hostname + " #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo))); if (Logging.On) { Logging.PrintInfo(Logging.Web, this, ".ctor", "hostname=" + hostname + ", #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)) + ", encryptionPolicy=" + encryptionPolicy); } SslStreamPal.VerifyPackageInfo(); _destination = hostname; GlobalLog.Assert(hostname != null, "SecureChannel#{0}::.ctor()|hostname == null", Logging.HashString(this)); _hostName = hostname; _serverMode = serverMode; _sslProtocols = sslProtocols; _serverCertificate = serverCertificate; _clientCertificates = clientCertificates; _remoteCertRequired = remoteCertRequired; _securityContext = null; _checkCertRevocation = checkCertRevocationStatus; _checkCertName = checkCertName; _certSelectionDelegate = certSelectionDelegate; _refreshCredentialNeeded = true; _encryptionPolicy = encryptionPolicy; GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::.ctor"); }
private void ConnectCallback(IAsyncResult result) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::ConnectCallback"); } try { _transport.EndGetConnection(result); if (_cancelled) { Complete(null, result); } else { // Detected durring Begin/EndGetConnection, restrictable using DeliveryFormat bool allowUnicode = IsUnicodeSupported(); ValidateUnicodeRequirement(_message, _recipients, allowUnicode); _transport.BeginSendMail(_message.Sender ?? _message.From, _recipients, _message.BuildDeliveryStatusNotificationString(), allowUnicode, new AsyncCallback(SendMailCallback), result.AsyncState); } } catch (Exception e) { Complete(e, result); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::ConnectCallback"); } }
internal IAsyncResult BeginGetConnection(ServicePoint servicePoint, ContextAwareResult outerResult, AsyncCallback callback, object state) { GlobalLog.Enter("SmtpTransport#" + ValidationHelper.HashString(this) + "::BeginConnect"); IAsyncResult result = null; try{ UpdateServicePoint(servicePoint); connection = new SmtpConnection(this, client, credentials, authenticationModules); connection.Timeout = timeout; if (Logging.On) { Logging.Associate(Logging.Web, this, connection); } if (EnableSsl) { connection.EnableSsl = true; connection.ClientCertificates = ClientCertificates; } result = connection.BeginGetConnection(servicePoint, outerResult, callback, state); } catch (Exception innerException) { throw new SmtpException(SR.GetString(SR.MailHostNotFound), innerException); } GlobalLog.Leave("SmtpTransport#" + ValidationHelper.HashString(this) + "::BeginConnect [....] Completion"); return(result); }
internal IAsyncResult BeginGetConnection(ContextAwareResult outerResult, AsyncCallback callback, object state, string host, int port) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("SmtpTransport#" + LoggingHash.HashString(this) + "::BeginConnect"); } IAsyncResult result = null; try { _connection = new SmtpConnection(this, _client, _credentials, _authenticationModules); _connection.Timeout = _timeout; if (MailEventSource.Log.IsEnabled()) { MailEventSource.Log.Associate(this, _connection); } if (EnableSsl) { _connection.EnableSsl = true; _connection.ClientCertificates = ClientCertificates; } result = _connection.BeginGetConnection(outerResult, callback, state, host, port); } catch (Exception innerException) { throw new SmtpException(SR.MailHostNotFound, innerException); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("SmtpTransport#" + LoggingHash.HashString(this) + "::BeginConnect Sync Completion"); } return(result); }
public void SendAsyncCancel() { if (disposed) { throw new ObjectDisposedException(this.GetType().FullName); } if (Logging.On) { Logging.Enter(Logging.Web, this, "SendAsyncCancel", null); } GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel"); try { if (!InCall || cancelled) { return; } cancelled = true; Abort(); } finally { if (Logging.On) { Logging.Exit(Logging.Web, this, "SendAsyncCancel", null); } GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel"); } }
/*++ * ProcessHandshakeSuccess - * Called on successful completion of Handshake - * used to set header/trailer sizes for encryption use * * Fills in the information about established protocol * --*/ internal void ProcessHandshakeSuccess() { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess"); StreamSizes streamSizes; SslStreamPal.QueryContextStreamSizes(_securityContext, out streamSizes); if (streamSizes != null) { try { _headerSize = streamSizes.header; _trailerSize = streamSizes.trailer; _maxDataSize = checked (streamSizes.maximumMessage - (_headerSize + _trailerSize)); } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess", "StreamSizes out of range."); } throw; } } SslStreamPal.QueryContextConnectionInfo(_securityContext, out _connectionInfo); GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::ProcessHandshakeSuccess"); }
// Server API internal static WebHeaderCollection GetHeaders(byte[] memoryBlob, IntPtr originalAddress) { GlobalLog.Enter("HttpApi::GetHeaders()"); // Return value. WebHeaderCollection headerCollection = new WebHeaderCollection(WebHeaderCollectionType.HttpListenerRequest); fixed(byte *pMemoryBlob = memoryBlob) { HTTP_REQUEST *request = (HTTP_REQUEST *)pMemoryBlob; long fixup = pMemoryBlob - (byte *)originalAddress; int index; // unknown headers if (request->Headers.UnknownHeaderCount != 0) { HTTP_UNKNOWN_HEADER *pUnknownHeader = (HTTP_UNKNOWN_HEADER *)(fixup + (byte *)request->Headers.pUnknownHeaders); for (index = 0; index < request->Headers.UnknownHeaderCount; index++) { // For unknown headers, when header value is empty, RawValueLength will be 0 and // pRawValue will be null. if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) { string headerName = new string(pUnknownHeader->pName + fixup, 0, pUnknownHeader->NameLength); string headerValue; if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) { headerValue = new string(pUnknownHeader->pRawValue + fixup, 0, pUnknownHeader->RawValueLength); } else { headerValue = string.Empty; } headerCollection.AddInternal(headerName, headerValue); } pUnknownHeader++; } } // known headers HTTP_KNOWN_HEADER *pKnownHeader = &request->Headers.KnownHeaders; for (index = 0; index < HttpHeaderRequestMaximum; index++) { // For known headers, when header value is empty, RawValueLength will be 0 and // pRawValue will point to empty string ("\0") if (pKnownHeader->pRawValue != null) { string headerValue = new string(pKnownHeader->pRawValue + fixup, 0, pKnownHeader->RawValueLength); headerCollection.AddInternal(HTTP_REQUEST_HEADER_ID.ToString(index), headerValue); } pKnownHeader++; } } GlobalLog.Leave("HttpApi::GetHeaders()"); return(headerCollection); }
/*++ * Encrypt - Encrypts our bytes before we send them over the wire * * PERF: make more efficient, this does an extra copy when the offset * is non-zero. * * Input: * buffer - bytes for sending * offset - * size - * output - Encrypted bytes * --*/ internal SecurityStatusPal Encrypt(byte[] buffer, int offset, int size, ref byte[] output, out int resultSize) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::Encrypt"); GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() - offset: " + offset.ToString() + " size: " + size.ToString() + " buffersize: " + buffer.Length.ToString()); GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() buffer:"); GlobalLog.Dump(buffer, Math.Min(buffer.Length, 128)); byte[] writeBuffer; try { if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) { throw new ArgumentOutOfRangeException("offset"); } if (size < 0 || size > (buffer == null ? 0 : buffer.Length - offset)) { throw new ArgumentOutOfRangeException("size"); } resultSize = 0; int bufferSizeNeeded = checked (size + _headerSize + _trailerSize); if (output != null && bufferSizeNeeded <= output.Length) { writeBuffer = output; } else { writeBuffer = new byte[bufferSizeNeeded]; } Buffer.BlockCopy(buffer, offset, writeBuffer, _headerSize, size); } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Arguments out of range."); } throw; } SecurityStatusPal secStatus = SslStreamPal.EncryptMessage(_securityContext, writeBuffer, size, _headerSize, _trailerSize, out resultSize); if (secStatus != SecurityStatusPal.OK) { GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt ERROR", secStatus.ToString()); } else { output = writeBuffer; GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt OK", "data size:" + resultSize.ToString()); } return(secStatus); }
internal static uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) { GlobalLog.Enter("HttpApi::GetChunks() memoryBlob:" + ValidationHelper.ToString(memoryBlob)); // Return value. uint dataRead = 0; fixed(byte *pMemoryBlob = memoryBlob) { HTTP_REQUEST *request = (HTTP_REQUEST *)pMemoryBlob; long fixup = pMemoryBlob - (byte *)originalAddress; if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) { HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)(fixup + (byte *)&request->pEntityChunks[dataChunkIndex]); fixed(byte *pReadBuffer = buffer) { byte *pTo = &pReadBuffer[offset]; while (dataChunkIndex < request->EntityChunkCount && dataRead < size) { if (dataChunkOffset >= pDataChunk->BufferLength) { dataChunkOffset = 0; dataChunkIndex++; pDataChunk++; } else { byte *pFrom = pDataChunk->pBuffer + dataChunkOffset + fixup; uint bytesToRead = pDataChunk->BufferLength - (uint)dataChunkOffset; if (bytesToRead > (uint)size) { bytesToRead = (uint)size; } for (uint i = 0; i < bytesToRead; i++) { *(pTo++) = *(pFrom++); } dataRead += bytesToRead; dataChunkOffset += bytesToRead; } } } } //we're finished. if (dataChunkIndex == request->EntityChunkCount) { dataChunkIndex = -1; } } GlobalLog.Leave("HttpApi::GetChunks()"); return(dataRead); }
private void Complete(Exception exception, IAsyncResult result) { ContextAwareResult operationCompletedResult = (ContextAwareResult)result.AsyncState; if (GlobalLog.IsEnabled) { GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::Complete"); } try { if (_cancelled) { //any exceptions were probably caused by cancellation, clear it. exception = null; Abort(); } // An individual failed recipient exception is benign, only abort here if ALL the recipients failed. else if (exception != null && (!(exception is SmtpFailedRecipientException) || ((SmtpFailedRecipientException)exception).fatal)) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SmtpClient#" + LoggingHash.HashString(this) + "::Complete Exception: " + exception.ToString()); } Abort(); if (!(exception is SmtpException)) { exception = new SmtpException(SR.SmtpSendMailFailure, exception); } } else { if (_writer != null) { try { _writer.Close(); } // Close may result in a DataStopCommand and the server may return error codes at this time. catch (SmtpException se) { exception = se; } } _transport.ReleaseConnection(); } } finally { operationCompletedResult.InvokeCallback(exception); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::Complete"); } }
internal void EndGetConnection(IAsyncResult result) { GlobalLog.Enter("SmtpTransport#" + ValidationHelper.HashString(this) + "::EndGetConnection"); try { connection.EndGetConnection(result); } finally { GlobalLog.Leave("SmtpTransport#" + ValidationHelper.HashString(this) + "::EndConnect"); } }
private static void ConnectionCreatedCallback(object request, object state) { GlobalLog.Enter("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::ConnectionCreatedCallback"); ConnectAndHandshakeAsyncResult ConnectAndHandshakeAsyncResult = (ConnectAndHandshakeAsyncResult)request; if (state is Exception) { ConnectAndHandshakeAsyncResult.InvokeCallback((Exception)state); return; } SmtpPooledStream pooledStream = (SmtpPooledStream)(PooledStream)state; try { while (pooledStream.creds != null && pooledStream.creds != ConnectAndHandshakeAsyncResult.connection.credentials) { GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::Connect pooledStream has wrong creds " + ValidationHelper.HashString(pooledStream)); ConnectAndHandshakeAsyncResult.connection.connectionPool.PutConnection(pooledStream, pooledStream.Owner, ConnectAndHandshakeAsyncResult.connection.Timeout, false); pooledStream = (SmtpPooledStream)ConnectAndHandshakeAsyncResult.connection.connectionPool.GetConnection((object)ConnectAndHandshakeAsyncResult, ConnectAndHandshakeAsyncResult.m_ConnectionCreatedCallback, ConnectAndHandshakeAsyncResult.connection.Timeout); if (pooledStream == null) { GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::Connect returning asynchronously"); return; } } if (Logging.On) { Logging.Associate(Logging.Web, ConnectAndHandshakeAsyncResult.connection, pooledStream); } pooledStream.Owner = ConnectAndHandshakeAsyncResult.connection; //needs to be updated for gc reasons pooledStream.creds = ConnectAndHandshakeAsyncResult.connection.credentials; lock (ConnectAndHandshakeAsyncResult.connection) { //if we were cancelled while getting the connection, we should close and return if (ConnectAndHandshakeAsyncResult.connection.isClosed) { ConnectAndHandshakeAsyncResult.connection.connectionPool.PutConnection(pooledStream, pooledStream.Owner, ConnectAndHandshakeAsyncResult.connection.Timeout, false); GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::ConnectionCreatedCallback Connect was aborted " + ValidationHelper.HashString(pooledStream)); ConnectAndHandshakeAsyncResult.InvokeCallback(null); return; } ConnectAndHandshakeAsyncResult.connection.pooledStream = pooledStream; } ConnectAndHandshakeAsyncResult.Handshake(); } catch (Exception e) { ConnectAndHandshakeAsyncResult.InvokeCallback(e); } GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(request) + "::ConnectionCreatedCallback pooledStream#" + ValidationHelper.HashString(pooledStream)); }
void SendMessageCallback(IAsyncResult result) { GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback"); try { message.EndSend(result); // If some recipients failed but not others, throw AFTER sending the message. Complete(failedRecipientException, result); } catch (Exception e) { Complete(e, result); } GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback"); }
internal void GetConnection() { if (GlobalLog.IsEnabled) { GlobalLog.Enter("ConnectAndHandshakeAsyncResult#" + LoggingHash.HashString(this) + "::Connect:"); } if (_connection._isConnected) { throw new InvalidOperationException(SR.SmtpAlreadyConnected); } InitializeConnection(); }
internal ChannelBinding GetChannelBinding(ChannelBindingKind kind) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::GetChannelBindingToken", kind.ToString()); ChannelBinding result = null; if (_securityContext != null) { result = SslStreamPal.QueryContextChannelBinding(_securityContext, kind); } GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::GetChannelBindingToken", Logging.HashString(result)); return(result); }
private unsafe static string GetVerb(HTTP_REQUEST *request, long fixup) { GlobalLog.Enter("HttpApi::GetVerb()"); string verb = null; if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnknown && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) { verb = HttpVerbs[(int)request->Verb]; } else if (request->Verb == HTTP_VERB.HttpVerbUnknown && request->pUnknownVerb != null) { verb = new string(request->pUnknownVerb + fixup, 0, request->UnknownVerbLength); } GlobalLog.Leave("HttpApi::GetVerb() return:" + ValidationHelper.ToString(verb)); return(verb); }
internal void EndGetConnection(IAsyncResult result) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("SmtpTransport#" + LoggingHash.HashString(this) + "::EndGetConnection"); } try { _connection.EndGetConnection(result); } finally { if (GlobalLog.IsEnabled) { GlobalLog.Leave("SmtpTransport#" + LoggingHash.HashString(this) + "::EndConnect"); } } }
// internal ProtocolToken NextMessage(byte[] incoming, int offset, int count) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::NextMessage"); byte[] nextmsg = null; SecurityStatusPal errorCode = GenerateToken(incoming, offset, count, ref nextmsg); if (!_serverMode && errorCode == SecurityStatusPal.CredentialsNeeded) { GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::NextMessage() returned SecurityStatusPal.CredentialsNeeded"); SetRefreshCredentialNeeded(); errorCode = GenerateToken(incoming, offset, count, ref nextmsg); } ProtocolToken token = new ProtocolToken(nextmsg, errorCode); GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::NextMessage", token.ToString()); return(token); }
private static void ConnectionCreatedCallback(object request, object state) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("ConnectAndHandshakeAsyncResult#" + LoggingHash.HashString(request) + "::ConnectionCreatedCallback"); } ConnectAndHandshakeAsyncResult ConnectAndHandshakeAsyncResult = (ConnectAndHandshakeAsyncResult)request; if (state is Exception) { ConnectAndHandshakeAsyncResult.InvokeCallback((Exception)state); return; } try { lock (ConnectAndHandshakeAsyncResult._connection) { //if we were cancelled while getting the connection, we should close and return if (ConnectAndHandshakeAsyncResult._connection._isClosed) { ConnectAndHandshakeAsyncResult._connection.ReleaseConnection(); if (GlobalLog.IsEnabled) { GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + LoggingHash.HashString(request) + "::ConnectionCreatedCallback Connect was aborted "); } ConnectAndHandshakeAsyncResult.InvokeCallback(null); return; } } ConnectAndHandshakeAsyncResult.Handshake(); } catch (Exception e) { ConnectAndHandshakeAsyncResult.InvokeCallback(e); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + LoggingHash.HashString(request) + "::ConnectionCreatedCallback"); } }
internal void GetConnection(bool synchronous) { GlobalLog.Enter("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect: [....]=" + (synchronous ? "true" : "false")); if (connection.isConnected) { throw new InvalidOperationException(SR.GetString(SR.SmtpAlreadyConnected)); } SmtpPooledStream pooledStream = (SmtpPooledStream)connection.connectionPool.GetConnection((object)this, (synchronous ? null : m_ConnectionCreatedCallback), connection.Timeout); GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect returned" + ValidationHelper.HashString(this)); if (pooledStream != null) { try { while (pooledStream.creds != null && pooledStream.creds != connection.credentials) { GlobalLog.Print("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect pooledStream has wrong creds " + ValidationHelper.HashString(pooledStream)); connection.connectionPool.PutConnection(pooledStream, pooledStream.Owner, connection.Timeout, false); pooledStream = (SmtpPooledStream)connection.connectionPool.GetConnection((object)this, (synchronous ? null : m_ConnectionCreatedCallback), connection.Timeout); if (pooledStream == null) { GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect returning asynchronously"); return; } } pooledStream.creds = connection.credentials; pooledStream.Owner = this.connection; //needs to be updated for gc reasons lock (connection) { connection.pooledStream = pooledStream; } Handshake(); } catch (Exception e) { InvokeCallback(e); } } GlobalLog.Leave("ConnectAndHandshakeAsyncResult#" + ValidationHelper.HashString(this) + "::Connect pooledStream#" + ValidationHelper.HashString(pooledStream)); }
private static string GetKnownHeader(HTTP_REQUEST *request, long fixup, int headerIndex) { GlobalLog.Enter("HttpApi::GetKnownHeader()"); string header = null; HTTP_KNOWN_HEADER *pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; GlobalLog.Print("HttpApi::GetKnownHeader() pKnownHeader:0x" + ((IntPtr)pKnownHeader).ToString("x")); GlobalLog.Print("HttpApi::GetKnownHeader() pRawValue:0x" + ((IntPtr)pKnownHeader->pRawValue).ToString("x") + " RawValueLength:" + pKnownHeader->RawValueLength.ToString()); // For known headers, when header value is empty, RawValueLength will be 0 and // pRawValue will point to empty string ("\0") if (pKnownHeader->pRawValue != null) { header = new string(pKnownHeader->pRawValue + fixup, 0, pKnownHeader->RawValueLength); } GlobalLog.Leave("HttpApi::GetKnownHeader() return:" + ValidationHelper.ToString(header)); return(header); }
internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress) { GlobalLog.Enter("HttpApi::GetKnownVerb()"); // Return value. HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown; fixed(byte *pMemoryBlob = memoryBlob) { HTTP_REQUEST *request = (HTTP_REQUEST *)pMemoryBlob; if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) { verb = request->Verb; } } GlobalLog.Leave("HttpApi::GetKnownVerb()"); return(verb); }
private void SendMessageCallback(IAsyncResult result) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::SendMessageCallback"); } try { _message.EndSend(result); // If some recipients failed but not others, throw AFTER sending the message. Complete(_failedRecipientException, result); } catch (Exception e) { Complete(e, result); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::SendMessageCallback"); } }
public void SendAsyncCancel() { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Enter(NetEventSource.ComponentType.Web, this, "SendAsyncCancel", null); } if (GlobalLog.IsEnabled) { GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsyncCancel"); } try { if (!InCall || _cancelled) { return; } _cancelled = true; Abort(); } finally { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Exit(NetEventSource.ComponentType.Web, this, "SendAsyncCancel", null); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsyncCancel"); } } }
public void SendAsync(MailMessage message, object userToken) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Enter(NetEventSource.ComponentType.Web, this, "SendAsync", "DeliveryMethod=" + DeliveryMethod.ToString()); } if (GlobalLog.IsEnabled) { GlobalLog.Enter("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsync Transport#" + LoggingHash.HashString(_transport)); } try { if (InCall) { throw new InvalidOperationException(SR.net_inasync); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (DeliveryMethod == SmtpDeliveryMethod.Network) { CheckHostAndPort(); } _recipients = new MailAddressCollection(); if (message.From == null) { throw new InvalidOperationException(SR.SmtpFromRequired); } if (message.To != null) { foreach (MailAddress address in message.To) { _recipients.Add(address); } } if (message.Bcc != null) { foreach (MailAddress address in message.Bcc) { _recipients.Add(address); } } if (message.CC != null) { foreach (MailAddress address in message.CC) { _recipients.Add(address); } } if (_recipients.Count == 0) { throw new InvalidOperationException(SR.SmtpRecipientRequired); } try { InCall = true; _cancelled = false; _message = message; string pickupDirectory = PickupDirectoryLocation; CredentialCache cache; // Skip token capturing if no credentials are used or they don't include a default one. // Also do capture the token if ICredential is not of CredentialCache type so we don't know what the exact credential response will be. _transport.IdentityRequired = Credentials != null && (ReferenceEquals(Credentials, CredentialCache.DefaultNetworkCredentials) || (cache = Credentials as CredentialCache) == null); _asyncOp = AsyncOperationManager.CreateOperation(userToken); switch (DeliveryMethod) { case SmtpDeliveryMethod.PickupDirectoryFromIis: throw new NotSupportedException(SR.SmtpGetIisPickupDirectoryNotSupported); case SmtpDeliveryMethod.SpecifiedPickupDirectory: { if (EnableSsl) { throw new SmtpException(SR.SmtpPickupDirectoryDoesnotSupportSsl); } _writer = GetFileMailWriter(pickupDirectory); bool allowUnicode = IsUnicodeSupported(); ValidateUnicodeRequirement(message, _recipients, allowUnicode); message.Send(_writer, true, allowUnicode); if (_writer != null) { _writer.Close(); } _transport.ReleaseConnection(); AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, _asyncOp.UserSuppliedState); InCall = false; _asyncOp.PostOperationCompleted(_onSendCompletedDelegate, eventArgs); break; } case SmtpDeliveryMethod.Network: default: _operationCompletedResult = new ContextAwareResult(_transport.IdentityRequired, true, null, this, s_contextSafeCompleteCallback); lock (_operationCompletedResult.StartPostingAsyncOp()) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsync calling BeginConnect. Transport#" + LoggingHash.HashString(_transport)); } _transport.BeginGetConnection(_operationCompletedResult, ConnectCallback, _operationCompletedResult, Host, Port); _operationCompletedResult.FinishPostingAsyncOp(); } break; } } catch (Exception e) { InCall = false; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Exception(NetEventSource.ComponentType.Web, this, "Send", e); } if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) { throw; } Abort(); if (_timedOut) { throw new SmtpException(SR.net_timeout); } if (e is SecurityException || e is AuthenticationException || e is SmtpException) { throw; } throw new SmtpException(SR.SmtpSendMailFailure, e); } } finally { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Exit(NetEventSource.ComponentType.Web, this, "SendAsync", null); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("SmtpClient#" + LoggingHash.HashString(this) + "::SendAsync"); } } }
// // Acquire Server Side Certificate information and set it on the class. // private bool AcquireServerCredentials(ref byte[] thumbPrint) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials"); X509Certificate localCertificate = null; bool cachedCred = false; if (_certSelectionDelegate != null) { X509CertificateCollection tempCollection = new X509CertificateCollection(); tempCollection.Add(_serverCertificate); localCertificate = _certSelectionDelegate(string.Empty, tempCollection, null, Array.Empty <string>()); GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials() Use delegate selected Cert"); } else { localCertificate = _serverCertificate; } if (localCertificate == null) { throw new NotSupportedException(SR.net_ssl_io_no_server_cert); } // SECURITY: Accessing X509 cert Credential is disabled for semitrust. // We no longer need to demand for unmanaged code permissions. // EnsurePrivateKey should do the right demand for us. X509Certificate2 selectedCert = EnsurePrivateKey(localCertificate); if (selectedCert == null) { throw new NotSupportedException(SR.net_ssl_io_no_server_cert); } GlobalLog.Assert(localCertificate.Equals(selectedCert), "AcquireServerCredentials()|'selectedCert' does not match 'localCertificate'."); // // Note selectedCert is a safe ref possibly cloned from the user passed Cert object // byte[] guessedThumbPrint = selectedCert.GetCertHash(); try { SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy); if (cachedCredentialHandle != null) { _credentialsHandle = cachedCredentialHandle; _serverCertificate = localCertificate; cachedCred = true; } else { _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode); thumbPrint = guessedThumbPrint; _serverCertificate = localCertificate; } } finally { // An extra cert could have been created, dispose it now. if ((object)localCertificate != (object)selectedCert) { selectedCert.Dispose(); } } GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle)); return(cachedCred); }
/*++ * 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); }
/*++ * AcquireCredentials - Attempts to find Client Credential * Information, that can be sent to the server. In our case, * this is only Client Certificates, that we have Credential Info. * * How it works: * case 0: Cert Selection delegate is present * Always use its result as the client cert answer. * Try to use cached credential handle whenever feasible. * Do not use cached anonymous creds if the delegate has returned null * and the collection is not empty (allow responding with the cert later). * * case 1: Certs collection is empty * Always use the same statically acquired anonymous SSL Credential * * case 2: Before our Connection with the Server * If we have a cached credential handle keyed by first X509Certificate **content** in the passed collection, then we use that cached * credential and hoping to restart a session. * * Otherwise create a new anonymous (allow responding with the cert later). * * case 3: After our Connection with the Server (i.e. during handshake or re-handshake) * The server has requested that we send it a Certificate then * we Enumerate a list of server sent Issuers trying to match against * our list of Certificates, the first match is sent to the server. * * Once we got a cert we again try to match cached credential handle if possible. * This will not restart a session but helps minimizing the number of handles we create. * * In the case of an error getting a Certificate or checking its private Key we fall back * to the behavior of having no certs, case 1. * * Returns: True if cached creds were used, false otherwise. * * --*/ private bool AcquireClientCredentials(ref byte[] thumbPrint) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials"); // Acquire possible Client Certificate information and set it on the handle. X509Certificate clientCertificate = null; // This is a candidate that can come from the user callback or be guessed when targeting a session restart. ArrayList filteredCerts = new ArrayList(); // This is an intermediate client certs collection that try to use if no selectedCert is available yet. string[] issuers = null; // This is a list of issuers sent by the server, only valid is we do know what the server cert is. bool sessionRestartAttempt = false; // If true and no cached creds we will use anonymous creds. if (_certSelectionDelegate != null) { issuers = GetRequestCertificateAuthorities(); GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() calling CertificateSelectionCallback"); X509Certificate2 remoteCert = null; try { X509Certificate2Collection dummyCollection; remoteCert = CertificateValidationPal.GetRemoteCertificate(_securityContext, out dummyCollection); clientCertificate = _certSelectionDelegate(_hostName, ClientCertificates, remoteCert, issuers); } finally { if (remoteCert != null) { remoteCert.Dispose(); } } if (clientCertificate != null) { if (_credentialsHandle == null) { sessionRestartAttempt = true; } filteredCerts.Add(clientCertificate); if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.net_log_got_certificate_from_delegate); } } else { if (ClientCertificates.Count == 0) { if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_and_have_no_client_cert); } sessionRestartAttempt = true; } else { if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_but_have_client_cert); } } } } else if (_credentialsHandle == null && _clientCertificates != null && _clientCertificates.Count > 0) { // This is where we attempt to restart a session by picking the FIRST cert from the collection. // Otherwise it is either server sending a client cert request or the session is renegotiated. clientCertificate = ClientCertificates[0]; sessionRestartAttempt = true; if (clientCertificate != null) { filteredCerts.Add(clientCertificate); } if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_attempting_restart_using_cert, (clientCertificate == null ? "null" : clientCertificate.ToString(true)))); } } else if (_clientCertificates != null && _clientCertificates.Count > 0) { // // This should be a server request for the client cert sent over currently anonymous sessions. // issuers = GetRequestCertificateAuthorities(); if (Logging.On) { if (issuers == null || issuers.Length == 0) { Logging.PrintInfo(Logging.Web, this, SR.net_log_no_issuers_try_all_certs); } else { Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_server_issuers_look_for_matching_certs, issuers.Length)); } } for (int i = 0; i < _clientCertificates.Count; ++i) { // // Make sure we add only if the cert matches one of the issuers. // If no issuers were sent and then try all client certs starting with the first one. // if (issuers != null && issuers.Length != 0) { X509Certificate2 certificateEx = null; X509Chain chain = null; try { certificateEx = MakeEx(_clientCertificates[i]); if (certificateEx == null) { continue; } GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() root cert:" + certificateEx.Issuer); chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName; chain.Build(certificateEx); bool found = false; // // We ignore any errors happened with chain. // if (chain.ChainElements.Count > 0) { for (int ii = 0; ii < chain.ChainElements.Count; ++ii) { string issuer = chain.ChainElements[ii].Certificate.Issuer; found = Array.IndexOf(issuers, issuer) != -1; if (found) { GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() matched:" + issuer); break; } GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() no match:" + issuer); } } if (!found) { continue; } } finally { if (chain != null) { chain.Dispose(); } if (certificateEx != null && (object)certificateEx != (object)_clientCertificates[i]) { certificateEx.Dispose(); } } } if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_selected_cert, _clientCertificates[i].ToString(true))); } filteredCerts.Add(_clientCertificates[i]); } } bool cachedCred = false; // This is a return result from this method. X509Certificate2 selectedCert = null; // This is a final selected cert (ensured that it does have private key with it). clientCertificate = null; if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_n_certs_after_filtering, filteredCerts.Count)); if (filteredCerts.Count != 0) { Logging.PrintInfo(Logging.Web, this, SR.net_log_finding_matching_certs); } } // // ATTN: When the client cert was returned by the user callback OR it was guessed AND it has no private key, // THEN anonymous (no client cert) credential will be used. // // SECURITY: Accessing X509 cert Credential is disabled for semitrust. // We no longer need to demand for unmanaged code permissions. // EnsurePrivateKey should do the right demand for us. for (int i = 0; i < filteredCerts.Count; ++i) { clientCertificate = filteredCerts[i] as X509Certificate; if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null) { break; } clientCertificate = null; selectedCert = null; } GlobalLog.Assert(((object)clientCertificate == (object)selectedCert) || clientCertificate.Equals(selectedCert), "AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'."); GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Selected Cert = " + (selectedCert == null ? "null" : selectedCert.Subject)); try { // Try to locate cached creds first. // // SECURITY: selectedCert ref if not null is a safe object that does not depend on possible **user** inherited X509Certificate type. // byte[] guessedThumbPrint = selectedCert == null ? null : selectedCert.GetCertHash(); SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy); // We can probably do some optimization here. If the selectedCert is returned by the delegate // we can always go ahead and use the certificate to create our credential // (instead of going anonymous as we do here). if (sessionRestartAttempt && cachedCredentialHandle == null && selectedCert != null) { GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Reset to anonymous session."); // IIS does not renegotiate a restarted session if client cert is needed. // So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate. // The following block happens if client did specify a certificate but no cached creds were found in the cache. // Since we don't restart a session the server side can still challenge for a client cert. if ((object)clientCertificate != (object)selectedCert) { selectedCert.Dispose(); } guessedThumbPrint = null; selectedCert = null; clientCertificate = null; } if (cachedCredentialHandle != null) { if (Logging.On) { Logging.PrintInfo(Logging.Web, SR.net_log_using_cached_credential); } _credentialsHandle = cachedCredentialHandle; _selectedClientCertificate = clientCertificate; cachedCred = true; } else { _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode); thumbPrint = guessedThumbPrint; // Delay until here in case something above threw. _selectedClientCertificate = clientCertificate; } } finally { // An extra cert could have been created, dispose it now. if (selectedCert != null && (object)clientCertificate != (object)selectedCert) { selectedCert.Dispose(); } } GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle)); return(cachedCred); }