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

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

                throw new ArgumentOutOfRangeException(nameof(offset));
            }

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

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

                throw new ArgumentOutOfRangeException(nameof(count));
            }

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

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

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

            int errorCode;

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

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

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

            newOffset = securityBuffer[1].offset;
            return(securityBuffer[1].size);
        }
예제 #2
0
 public void LogRemainingOperations()
 {
     Interlocked.MemoryBarrier();
     GlobalLog.Print("InnerSafeCloseSocket: Releasing with pending operations: " + _refCount);
 }
예제 #3
0
        /*++
         *  VerifyRemoteCertificate - Validates the content of a Remote Certificate
         *
         *  checkCRL if true, checks the certificate revocation list for validity.
         *  checkCertName, if true checks the CN field of the certificate
         * --*/

        //This method validates a remote certificate.
        //SECURITY: The scenario is allowed in semitrust StorePermission is asserted for Chain.Build
        //          A user callback has unique signature so it is safe to call it under permission assert.
        //
        internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate");
            SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;

            // We don't catch exceptions in this method, so it's safe for "accepted" be initialized with true.
            bool             success             = false;
            X509Chain        chain               = null;
            X509Certificate2 remoteCertificateEx = null;

            try
            {
                X509Certificate2Collection remoteCertificateStore;
                remoteCertificateEx           = CertWrapper.GetRemoteCertificate(_securityContext, out remoteCertificateStore);
                _isRemoteCertificateAvailable = remoteCertificateEx != null;

                if (remoteCertificateEx == null)
                {
                    GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate (no remote cert)", (!_remoteCertRequired).ToString());
                    sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable;
                }
                else
                {
                    chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode = _checkCertRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
                    if (remoteCertificateStore != null)
                    {
                        chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore);
                    }

                    // Don't call chain.Build here in the common code, because the Windows version
                    // is potentially going to check for GetLastWin32Error, and that call needs to be
                    // guaranteed to be right after the call to chain.Build.

                    sslPolicyErrors |= CertWrapper.VerifyCertificateProperties(
                        chain,
                        remoteCertificateEx,
                        _checkCertName,
                        _serverMode,
                        _hostName);
                }

                if (remoteCertValidationCallback != null)
                {
                    success = remoteCertValidationCallback(_hostName, remoteCertificateEx, chain, sslPolicyErrors);
                }
                else
                {
                    if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && !_remoteCertRequired)
                    {
                        success = true;
                    }
                    else
                    {
                        success = (sslPolicyErrors == SslPolicyErrors.None);
                    }
                }

                if (Logging.On)
                {
                    if (sslPolicyErrors != SslPolicyErrors.None)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_has_errors);
                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
                        {
                            Logging.PrintInfo(Logging.Web, this, "\t" + SR.net_log_remote_cert_not_available);
                        }

                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
                        {
                            Logging.PrintInfo(Logging.Web, this, "\t" + SR.net_log_remote_cert_name_mismatch);
                        }

                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
                        {
                            foreach (X509ChainStatus chainStatus in chain.ChainStatus)
                            {
                                Logging.PrintInfo(Logging.Web, this, "\t" + chainStatus.StatusInformation);
                            }
                        }
                    }
                    if (success)
                    {
                        if (remoteCertValidationCallback != null)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_user_declared_valid);
                        }
                        else
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_has_no_errors);
                        }
                    }
                    else
                    {
                        if (remoteCertValidationCallback != null)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_user_declared_invalid);
                        }
                    }
                }
                GlobalLog.Print("Cert Validation, remote cert = " + (remoteCertificateEx == null ? "<null>" : remoteCertificateEx.ToString(true)));
            }
            finally
            {
                // At least on Win2k server the chain is found to have dependencies on the original cert context.
                // So it should be closed first.
                if (chain != null)
                {
                    chain.Dispose();
                }

                if (remoteCertificateEx != null)
                {
                    remoteCertificateEx.Dispose();
                }
            }
            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate", success.ToString());
            return(success);
        }
예제 #4
0
 /// <include file='doc\NetworkStream.uex' path='docs/doc[@for="NetworkStream.Close"]/*' />
 /// <devdoc>
 ///    <para>
 ///       Closes the stream, and then closes the underlying socket.
 ///    </para>
 /// </devdoc>
 public override void Close()
 {
     GlobalLog.Print("NetworkStream::Close()");
     ((IDisposable)this).Dispose();
 }
예제 #5
0
        //
        // The app is calling this method after starting an SSL handshake.
        //
        // ATTN: The thumbPrint must be from inspected and possibly cloned user Cert object or we get a security hole in SslCredKey ctor.
        //
        internal static void CacheCredential(SafeFreeCredentials creds, byte[] thumbPrint, SslProtocols sslProtocols, bool isServer, 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, (int)sslProtocols, isServer, 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.
                        //
                        //    We won't shrink cache in the case when NO new handles are coming to it.
                        //
                        if ((s_CachedCreds.Count % 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.Dispose();

                                    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());
            }
        }
예제 #6
0
        /*++
         *  VerifyRemoteCertificate - Validates the content of a Remote Certificate
         *
         *  checkCRL if true, checks the certificate revocation list for validity.
         *  checkCertName, if true checks the CN field of the certificate
         * --*/

        //This method validates a remote certificate.
        //SECURITY: The scenario is allowed in semitrust StorePermission is asserted for Chain.Build
        //          A user callback has unique signature so it is safe to call it under permission assert.
        //
        internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback)
        {
            GlobalLog.Enter("SecureChannel#" + LoggingHash.HashString(this) + "::VerifyRemoteCertificate");
            SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;

            // We don't catch exceptions in this method, so it's safe for "accepted" be initialized with true.
            bool             success             = false;
            X509Chain        chain               = null;
            X509Certificate2 remoteCertificateEx = null;

            try
            {
                X509Certificate2Collection remoteCertificateStore;
                remoteCertificateEx           = CertificateValidationPal.GetRemoteCertificate(_securityContext, out remoteCertificateStore);
                _isRemoteCertificateAvailable = remoteCertificateEx != null;

                if (remoteCertificateEx == null)
                {
                    GlobalLog.Leave("SecureChannel#" + LoggingHash.HashString(this) + "::VerifyRemoteCertificate (no remote cert)", (!_remoteCertRequired).ToString());
                    sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable;
                }
                else
                {
                    chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode = _checkCertRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
                    if (remoteCertificateStore != null)
                    {
                        chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore);
                    }

                    sslPolicyErrors |= CertificateValidationPal.VerifyCertificateProperties(
                        chain,
                        remoteCertificateEx,
                        _checkCertName,
                        _serverMode,
                        _hostName);
                }

                if (remoteCertValidationCallback != null)
                {
                    success = remoteCertValidationCallback(_hostName, remoteCertificateEx, chain, sslPolicyErrors);
                }
                else
                {
                    if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && !_remoteCertRequired)
                    {
                        success = true;
                    }
                    else
                    {
                        success = (sslPolicyErrors == SslPolicyErrors.None);
                    }
                }

                if (SecurityEventSource.Log.IsEnabled())
                {
                    if (sslPolicyErrors != SslPolicyErrors.None)
                    {
                        SecurityEventSource.Log.RemoteCertificateError(LoggingHash.HashInt(this), SR.net_log_remote_cert_has_errors);
                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
                        {
                            SecurityEventSource.Log.RemoteCertificateError(LoggingHash.HashInt(this), SR.net_log_remote_cert_not_available);
                        }

                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
                        {
                            SecurityEventSource.Log.RemoteCertificateError(LoggingHash.HashInt(this), SR.net_log_remote_cert_name_mismatch);
                        }

                        if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
                        {
                            string chainStatusString = "ChainStatus: ";
                            foreach (X509ChainStatus chainStatus in chain.ChainStatus)
                            {
                                chainStatusString += "\t" + chainStatus.StatusInformation;
                            }
                            SecurityEventSource.Log.RemoteCertificateError(LoggingHash.HashInt(this), chainStatusString);
                        }
                    }
                    if (success)
                    {
                        if (remoteCertValidationCallback != null)
                        {
                            SecurityEventSource.Log.RemoteCertDeclaredValid(LoggingHash.HashInt(this));
                        }
                        else
                        {
                            SecurityEventSource.Log.RemoteCertHasNoErrors(LoggingHash.HashInt(this));
                        }
                    }
                    else
                    {
                        if (remoteCertValidationCallback != null)
                        {
                            SecurityEventSource.Log.RemoteCertUserDeclaredInvalid(LoggingHash.HashInt(this));
                        }
                    }
                }
                GlobalLog.Print("Cert Validation, remote cert = " + (remoteCertificateEx == null ? "<null>" : remoteCertificateEx.ToString(true)));
            }
            finally
            {
                // At least on Win2k server the chain is found to have dependencies on the original cert context.
                // So it should be closed first.
                if (chain != null)
                {
                    chain.Dispose();
                }

                if (remoteCertificateEx != null)
                {
                    remoteCertificateEx.Dispose();
                }
            }
            GlobalLog.Leave("SecureChannel#" + LoggingHash.HashString(this) + "::VerifyRemoteCertificate", success.ToString());
            return(success);
        }
예제 #7
0
        //
        // Acquire Server Side Certificate information and set it on the class.
        //
        private bool AcquireServerCredentials(ref byte[] thumbPrint)
        {
            GlobalLog.Enter("SecureChannel#" + LoggingHash.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#" + LoggingHash.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#" + LoggingHash.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), LoggingHash.ObjectToString(_credentialsHandle));
            return(cachedCred);
        }
예제 #8
0
        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");
                }
            }
        }
예제 #9
0
 //UEUE
 /// <include file='doc\UDPClient.uex' path='docs/doc[@for="UdpClient.Close"]/*' />
 public void Close()
 {
     GlobalLog.Print("UdpClient::Close()");
     this.FreeResources();
     GC.SuppressFinalize(this);
 }
        // This method will be called by us when the IO completes synchronously and
        // by the ThreadPool when the IO completes asynchronously. (only called on WinNT)
        internal override object PostCompletion(int numBytes)
        {
            SocketError errorCode = (SocketError)ErrorCode;

            Internals.SocketAddress remoteSocketAddress = null;
            if (errorCode == SocketError.Success)
            {
                _localBytesTransferred = numBytes;
                if (SocketsEventSource.Log.IsEnabled())
                {
                    LogBuffer((long)numBytes);
                }

                // get the endpoint
                remoteSocketAddress = IPEndPointExtensions.Serialize(_listenSocket._rightEndPoint);

                IntPtr localAddr;
                int    localAddrLength;
                IntPtr remoteAddr;

                // set the socket context
                try
                {
                    _listenSocket.GetAcceptExSockaddrs(
                        Marshal.UnsafeAddrOfPinnedArrayElement(_buffer, 0),
                        _buffer.Length - (_addressBufferLength * 2),
                        _addressBufferLength,
                        _addressBufferLength,
                        out localAddr,
                        out localAddrLength,
                        out remoteAddr,
                        out remoteSocketAddress.InternalSize);

                    Marshal.Copy(remoteAddr, remoteSocketAddress.Buffer, 0, remoteSocketAddress.Size);

                    IntPtr handle = _listenSocket.SafeHandle.DangerousGetHandle();

                    errorCode = Interop.Winsock.setsockopt(
                        _acceptSocket.SafeHandle,
                        SocketOptionLevel.Socket,
                        SocketOptionName.UpdateAcceptContext,
                        ref handle,
                        Marshal.SizeOf(handle));

                    if (errorCode == SocketError.SocketError)
                    {
                        errorCode = (SocketError)Marshal.GetLastWin32Error();
                    }

                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("AcceptOverlappedAsyncResult#" + LoggingHash.HashString(this) + "::PostCallback() setsockopt handle:" + handle.ToString() + " AcceptSocket:" + LoggingHash.HashString(_acceptSocket) + " itsHandle:" + _acceptSocket.SafeHandle.DangerousGetHandle().ToString() + " returns:" + errorCode.ToString());
                    }
                }
                catch (ObjectDisposedException)
                {
                    errorCode = SocketError.OperationAborted;
                }

                ErrorCode = (int)errorCode;
            }

            if (errorCode != SocketError.Success)
            {
                return(null);
            }

            return(_listenSocket.UpdateAcceptSocket(_acceptSocket, _listenSocket._rightEndPoint.Create(remoteSocketAddress)));
        }
예제 #11
0
        //
        // This is the static internal callback that will be called when
        // the IO we issued for the user to winsock has completed, either
        // synchronously (Signaled=false) or asynchronously (Signaled=true)
        // when this function gets called it must:
        // 1) update the AsyncResult object with the results of the completed IO
        // 2) signal events that the user might be waiting on
        // 3) cal the callback function that the user might have specified
        //
        internal static void ConnectCallback(object stateObject, bool Signaled)
        {
            ConnectAsyncResult asyncResult = stateObject as ConnectAsyncResult;
            Socket             socket      = asyncResult.AsyncObject as Socket;

            GlobalLog.Enter("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", "Signaled:" + Signaled.ToString());

            GlobalLog.Assert(!asyncResult.IsCompleted, "Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() asyncResult.IsCompleted", "");

            //
            // we now need to get the status of the async completion, we had an easy implementation
            // that uses GetSocketOption(), but VadimE suggested not to use this 'cause it may be
            // buggy on some platforms, so we use WSAEnumNetworkEvents() instead:
            //
            // The best way to do this is to call WSAEnumNetworkEvents and use the error code iError
            // array corresponding to FD_CONNECT. getsockopt (SO_ERROR) may return NO_ERROR under
            // stress even in case of error at least on Winnt4.0 (I don't remember whether I fixed
            // it on Win2000 or WinXP).
            //

            //
            // get async completion
            //

            /*
             * int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
             * GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString());
             */

            NetworkEvents networkEvents = new NetworkEvents();

            networkEvents.Events = AsyncEventBits.FdConnect;

            AutoResetEvent chkAsyncEvent = socket.m_AsyncEvent;

            int errorCode = SocketErrors.WSAENOTSOCK;

            if (chkAsyncEvent != null)
            {
                errorCode =
                    UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents(
                        socket.m_Handle,
                        chkAsyncEvent.Handle,
                        ref networkEvents);

                if (errorCode != SocketErrors.Success)
                {
                    errorCode = Marshal.GetLastWin32Error();
                    GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString());
                }
                else
                {
                    errorCode = networkEvents.ErrorCodes[(int)AsyncEventBitsPos.FdConnectBit];
                    GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString());
                }
            }

            try {
                //
                // cancel async event
                //
                socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
                //
                // go back to blocking mode
                //
                socket.InternalSetBlocking(true);
            }
            catch (Exception exception) {
                GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() caught exception::" + exception.Message);
                asyncResult.Result = exception;
            }

            //
            // if the native non-blocking call failed we'll throw a SocketException in EndConnect()
            //
            if (errorCode != SocketErrors.Success)
            {
                //
                // just save the error code, the SocketException will be thrown in EndConnect()
                //
                asyncResult.ErrorCode = errorCode;
            }
            else
            {
                //
                // the Socket is connected, update our state and performance counter
                //
                socket.SetToConnected();
            }

            //
            // call the user's callback now, if there is one.
            //
            asyncResult.InvokeCallback(false);

            GlobalLog.Leave("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", errorCode.ToString());
        }
        //
        // This method will be called by us when the IO completes synchronously and
        // by the ThreadPool when the IO completes asynchronously. (only called on WinNT)
        //

        internal override object PostCompletion(int numBytes)
        {
            SocketError errorCode = (SocketError)ErrorCode;

            SocketAddress remoteSocketAddress = null;

            if (errorCode == SocketError.Success)
            {
                m_LocalBytesTransferred = numBytes;
                if (Logging.On)
                {
                    LogBuffer((long)numBytes);
                }

                //get the endpoint

                remoteSocketAddress = m_ListenSocket.m_RightEndPoint.Serialize();

                IntPtr localAddr;
                int    localAddrLength;
                IntPtr remoteAddr;

                //set the socket context
                try
                {
                    m_ListenSocket.GetAcceptExSockaddrs(
                        Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, 0),
                        m_Buffer.Length - (m_AddressBufferLength * 2),
                        m_AddressBufferLength,
                        m_AddressBufferLength,
                        out localAddr,
                        out localAddrLength,
                        out remoteAddr,
                        out remoteSocketAddress.m_Size
                        );
                    Marshal.Copy(remoteAddr, remoteSocketAddress.m_Buffer, 0, remoteSocketAddress.m_Size);

                    IntPtr handle = m_ListenSocket.SafeHandle.DangerousGetHandle();

                    errorCode = UnsafeNclNativeMethods.OSSOCK.setsockopt(
                        m_AcceptSocket.SafeHandle,
                        SocketOptionLevel.Socket,
                        SocketOptionName.UpdateAcceptContext,
                        ref handle,
                        Marshal.SizeOf(handle));

                    if (errorCode == SocketError.SocketError)
                    {
                        errorCode = (SocketError)Marshal.GetLastWin32Error();
                    }
                    GlobalLog.Print("AcceptOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::PostCallback() setsockopt handle:" + handle.ToString() + " AcceptSocket:" + ValidationHelper.HashString(m_AcceptSocket) + " itsHandle:" + m_AcceptSocket.SafeHandle.DangerousGetHandle().ToString() + " returns:" + errorCode.ToString());
                }
                catch (ObjectDisposedException)
                {
                    errorCode = SocketError.OperationAborted;
                }

                ErrorCode = (int)errorCode;
            }

            if (errorCode == SocketError.Success)
            {
                return(m_ListenSocket.UpdateAcceptSocket(m_AcceptSocket, m_ListenSocket.m_RightEndPoint.Create(remoteSocketAddress), false));
            }
            else
            {
                return(null);
            }
        }
예제 #13
0
        //
        // This is the static internal callback that will be called when
        // the IO we issued for the user to winsock has completed, either
        // synchronously (Signaled=false) or asynchronously (Signaled=true)
        // when this function gets called it must:
        // 1) update the AsyncResult object with the results of the completed IO
        // 2) signal events that the user might be waiting on
        // 3) cal the callback function that the user might have specified
        //
        internal static void ConnectCallback(object stateObject, bool Signaled)
        {
            ConnectAsyncResult asyncResult = stateObject as ConnectAsyncResult;
            Socket             socket      = asyncResult.AsyncObject as Socket;

            GlobalLog.Enter("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", "Signaled:" + Signaled.ToString());

            GlobalLog.Assert(!asyncResult.IsCompleted, "Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() asyncResult.IsCompleted", "");

            //

            //
            // get async completion
            //

            /*
             * int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
             * GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString());
             */

            NetworkEvents networkEvents = new NetworkEvents();

            networkEvents.Events = AsyncEventBits.FdConnect;

            AutoResetEvent chkAsyncEvent = socket.m_AsyncEvent;

            int errorCode = SocketErrors.WSAENOTSOCK;

            if (chkAsyncEvent != null)
            {
                errorCode =
                    UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents(
                        socket.m_Handle,
                        chkAsyncEvent.Handle,
                        ref networkEvents);

                if (errorCode != SocketErrors.Success)
                {
                    errorCode = Marshal.GetLastWin32Error();
                    GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString());
                }
                else
                {
                    errorCode = networkEvents.ErrorCodes[(int)AsyncEventBitsPos.FdConnectBit];
                    GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString());
                }
            }

            try {
                //
                // cancel async event
                //
                socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
                //
                // go back to blocking mode
                //
                socket.InternalSetBlocking(true);
            }
            catch (Exception exception) {
                GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() caught exception::" + exception.Message);
                asyncResult.Result = exception;
            }

            //
            // if the native non-blocking call failed we'll throw a SocketException in EndConnect()
            //
            if (errorCode != SocketErrors.Success)
            {
                //
                // just save the error code, the SocketException will be thrown in EndConnect()
                //
                asyncResult.ErrorCode = errorCode;
            }
            else
            {
                //
                // the Socket is connected, update our state and performance counter
                //
                socket.SetToConnected();
            }

            //
            // call the user's callback now, if there is one.
            //
            asyncResult.InvokeCallback(false);

            GlobalLog.Leave("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", errorCode.ToString());
        }
예제 #14
0
 protected SafeNativeOverlapped()
     : this(IntPtr.Zero)
 {
     GlobalLog.Print("SafeNativeOverlapped#" + LoggingHash.HashString(this) + "::ctor(null)");
 }
예제 #15
0
        internal unsafe static int CompleteAuthToken(
            ref SafeDeleteContext refContext,
            SecurityBuffer[] inSecBuffers)
        {
            GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken");
            GlobalLog.Print("    refContext       = " + LoggingHash.ObjectToString(refContext));
#if TRACE_VERBOSE
            GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
#endif
            GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null");
            var inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length);

            int errorCode = (int)Interop.SecurityStatus.InvalidHandle;

            // These are pinned user byte arrays passed along with SecurityBuffers.
            GCHandle[] pinnedInBytes = null;

            var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor.Count];
            fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer)
            {
                // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr;
                pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count];
                SecurityBuffer securityBuffer;

                for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index)
                {
                    securityBuffer = inSecBuffers[index];
                    if (securityBuffer != null)
                    {
                        inUnmanagedBuffer[index].count = securityBuffer.size;
                        inUnmanagedBuffer[index].type  = securityBuffer.type;

                        // Use the unmanaged token if it's not null; otherwise use the managed buffer.
                        if (securityBuffer.unmanagedToken != null)
                        {
                            inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle();
                        }
                        else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
                        {
                            inUnmanagedBuffer[index].token = IntPtr.Zero;
                        }
                        else
                        {
                            pinnedInBytes[index]           = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
                            inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
                        }
#if TRACE_VERBOSE
                        GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type);
#endif
                    }
                }

                Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle();
                if (refContext != null)
                {
                    contextHandle = refContext._handle;
                }
                try
                {
                    if (refContext == null || refContext.IsInvalid)
                    {
                        refContext = new SafeDeleteContext_SECURITY();
                    }

                    try
                    {
                        bool ignore = false;
                        refContext.DangerousAddRef(ref ignore);
                        errorCode = Interop.Secur32.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor);
                    }
                    finally
                    {
                        refContext.DangerousRelease();
                    }
                }
                finally
                {
                    if (pinnedInBytes != null)
                    {
                        for (int index = 0; index < pinnedInBytes.Length; index++)
                        {
                            if (pinnedInBytes[index].IsAllocated)
                            {
                                pinnedInBytes[index].Free();
                            }
                        }
                    }
                }
            }

            GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + LoggingHash.ObjectToString(refContext));

            return(errorCode);
        }
예제 #16
0
        public void SendAsync(MailMessage message, object userToken)
        {
            if (disposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }
            if (Logging.On)
            {
                Logging.Enter(Logging.Web, this, "SendAsync", "DeliveryMethod=" + DeliveryMethod.ToString());
            }
            GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync Transport#" + ValidationHelper.HashString(transport));
            try {
                if (InCall)
                {
                    throw new InvalidOperationException(SR.GetString(SR.net_inasync));
                }

                if (message == null)
                {
                    throw new ArgumentNullException("message");
                }

                if (DeliveryMethod == SmtpDeliveryMethod.Network)
                {
                    CheckHostAndPort();
                }

                recipients = new MailAddressCollection();

                if (message.From == null)
                {
                    throw new InvalidOperationException(SR.GetString(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.GetString(SR.SmtpRecipientRequired));
                }

                try {
                    InCall       = true;
                    cancelled    = false;
                    this.message = message;
                    string pickupDirectory = PickupDirectoryLocation;

#if !FEATURE_PAL
                    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 && (Credentials is SystemNetworkCredential || (cache = Credentials as CredentialCache) == null || cache.IsDefaultInCache);
#endif // !FEATURE_PAL

                    asyncOp = AsyncOperationManager.CreateOperation(userToken);
                    switch (DeliveryMethod)
                    {
#if !FEATURE_PAL
                    case SmtpDeliveryMethod.PickupDirectoryFromIis:
                        pickupDirectory = IisPickupDirectory.GetPickupDirectory();
                        goto case SmtpDeliveryMethod.SpecifiedPickupDirectory;
#endif // !FEATURE_PAL
                    case SmtpDeliveryMethod.SpecifiedPickupDirectory:
                    {
                        if (EnableSsl)
                        {
                            throw new SmtpException(SR.GetString(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, _ContextSafeCompleteCallback);
                        lock (operationCompletedResult.StartPostingAsyncOp())
                        {
                            GlobalLog.Print("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync calling BeginConnect.  Transport#" + ValidationHelper.HashString(transport));
                            transport.BeginGetConnection(ServicePoint, operationCompletedResult, ConnectCallback, operationCompletedResult);
                            operationCompletedResult.FinishPostingAsyncOp();
                        }
                        break;
                    }
                }
                catch (Exception e) {
                    InCall = false;

                    if (Logging.On)
                    {
                        Logging.Exception(Logging.Web, this, "Send", e);
                    }

                    if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal)
                    {
                        throw;
                    }

                    Abort();
                    if (timedOut)
                    {
                        throw new SmtpException(SR.GetString(SR.net_timeout));
                    }

                    if (e is SecurityException ||
                        e is AuthenticationException ||
                        e is SmtpException)
                    {
                        throw;
                    }

                    throw new SmtpException(SR.GetString(SR.SmtpSendMailFailure), e);
                }
            } finally {
                if (Logging.On)
                {
                    Logging.Exit(Logging.Web, this, "SendAsync", null);
                }
                GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync");
            }
        }
예제 #17
0
        //-------------------------------------------------------------------
        internal unsafe static int AcceptSecurityContext(
            ref SafeFreeCredentials inCredentials,
            ref SafeDeleteContext refContext,
            Interop.Secur32.ContextFlags inFlags,
            Interop.Secur32.Endianness endianness,
            SecurityBuffer inSecBuffer,
            SecurityBuffer[] inSecBuffers,
            SecurityBuffer outSecBuffer,
            ref Interop.Secur32.ContextFlags outFlags)
        {
#if TRACE_VERBOSE
            GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex");
            GlobalLog.Print("    credential       = " + inCredentials.ToString());
            GlobalLog.Print("    refContext       = " + LoggingHash.ObjectToString(refContext));

            GlobalLog.Print("    inFlags          = " + inFlags);

            if (inSecBuffers == null)
            {
                GlobalLog.Print("    inSecBuffers     = (null)");
            }
            else
            {
                GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
            }
#endif
            GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null");
            GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null");

            if (inCredentials == null)
            {
                throw new ArgumentNullException("inCredentials");
            }

            Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null;
            if (inSecBuffer != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);
            }
            else if (inSecBuffers != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length);
            }

            Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);

            // Actually, this is returned in outFlags.
            bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false;

            int errorCode = -1;

            Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle();
            if (refContext != null)
            {
                contextHandle = refContext._handle;
            }

            // These are pinned user byte arrays passed along with SecurityBuffers.
            GCHandle[] pinnedInBytes  = null;
            GCHandle   pinnedOutBytes = new GCHandle();

            // Optional output buffer that may need to be freed.
            SafeFreeContextBuffer outFreeContextBuffer = null;
            try
            {
                pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned);
                var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count];
                fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer)
                {
                    if (inSecurityBufferDescriptor != null)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr;
                        pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count];
                        SecurityBuffer securityBuffer;
                        for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index)
                        {
                            securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index];
                            if (securityBuffer != null)
                            {
                                // Copy the SecurityBuffer content into unmanaged place holder.
                                inUnmanagedBuffer[index].count = securityBuffer.size;
                                inUnmanagedBuffer[index].type  = securityBuffer.type;

                                // Use the unmanaged token if it's not null; otherwise use the managed buffer.
                                if (securityBuffer.unmanagedToken != null)
                                {
                                    inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle();
                                }
                                else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
                                {
                                    inUnmanagedBuffer[index].token = IntPtr.Zero;
                                }
                                else
                                {
                                    pinnedInBytes[index]           = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
                                    inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
                                }
#if TRACE_VERBOSE
                                GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type);
#endif
                            }
                        }
                    }

                    var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1];
                    fixed(void *outUnmanagedBufferPtr = outUnmanagedBuffer)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr;
                        // Copy the SecurityBuffer content into unmanaged place holder.
                        outUnmanagedBuffer[0].count = outSecBuffer.size;
                        outUnmanagedBuffer[0].type  = outSecBuffer.type;

                        if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
                        {
                            outUnmanagedBuffer[0].token = IntPtr.Zero;
                        }
                        else
                        {
                            outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
                        }

                        if (isSspiAllocated)
                        {
                            outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
                        }

                        if (refContext == null || refContext.IsInvalid)
                        {
                            refContext = new SafeDeleteContext_SECURITY();
                        }

                        errorCode = MustRunAcceptSecurityContext_SECURITY(
                            ref inCredentials,
                            contextHandle.IsZero ? null : &contextHandle,
                            inSecurityBufferDescriptor,
                            inFlags,
                            endianness,
                            refContext,
                            outSecurityBufferDescriptor,
                            ref outFlags,
                            outFreeContextBuffer);

                        GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext  Marshalling OUT buffer");
                        // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
                        outSecBuffer.size = outUnmanagedBuffer[0].count;
                        outSecBuffer.type = outUnmanagedBuffer[0].type;
                        if (outSecBuffer.size > 0)
                        {
                            outSecBuffer.token = new byte[outSecBuffer.size];
                            Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size);
                        }
                        else
                        {
                            outSecBuffer.token = null;
                        }
                    }
                }
            }
            finally
            {
                if (pinnedInBytes != null)
                {
                    for (int index = 0; index < pinnedInBytes.Length; index++)
                    {
                        if (pinnedInBytes[index].IsAllocated)
                        {
                            pinnedInBytes[index].Free();
                        }
                    }
                }

                if (pinnedOutBytes.IsAllocated)
                {
                    pinnedOutBytes.Free();
                }

                if (outFreeContextBuffer != null)
                {
                    outFreeContextBuffer.Dispose();
                }
            }

            GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + LoggingHash.ObjectToString(refContext));

            return(errorCode);
        }
예제 #18
0
        private static SecurityStatusPal EstablishSecurityContext(
            SafeFreeNegoCredentials credential,
            ref SafeDeleteContext context,
            string targetName,
            ContextFlagsPal inFlags,
            SecurityBuffer inputBuffer,
            SecurityBuffer outputBuffer,
            ref ContextFlagsPal outFlags)
        {
            bool isNtlmOnly = credential.IsNtlmOnly;

            if (context == null)
            {
                // Empty target name causes the failure on Linux, hence passing a non-empty string
                context = isNtlmOnly ? new SafeDeleteNegoContext(credential, credential.UserName) : new SafeDeleteNegoContext(credential, targetName);
            }

            SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context;

            try
            {
                Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags);
                uint outputFlags;
                int  isNtlmUsed;
                SafeGssContextHandle contextHandle = negoContext.GssContext;
                bool done = Interop.GssApi.EstablishSecurityContext(
                    ref contextHandle,
                    credential.GssCredential,
                    isNtlmOnly,
                    negoContext.TargetName,
                    inputFlags,
                    inputBuffer?.token,
                    out outputBuffer.token,
                    out outputFlags,
                    out isNtlmUsed);

                Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi");
                outputBuffer.size   = outputBuffer.token.Length;
                outputBuffer.offset = 0;

                outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags);

                // Save the inner context handle for further calls to NetSecurity
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
                if (null == negoContext.GssContext)
                {
                    negoContext.SetGssContext(contextHandle);
                }

                // Populate protocol used for authentication
                if (done)
                {
                    negoContext.SetAuthenticationPackage(Convert.ToBoolean(isNtlmUsed));
                }

                SecurityStatusPalErrorCode errorCode = done ?
                                                       (negoContext.IsNtlmUsed && outputBuffer.size > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) :
                                                       SecurityStatusPalErrorCode.ContinueNeeded;
                return(new SecurityStatusPal(errorCode));
            }
            catch (Exception ex)
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("Exception Caught. - " + ex);
                }

                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
        }
예제 #19
0
        /*++
         *  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#" + LoggingHash.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#" + LoggingHash.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 (SecurityEventSource.Log.IsEnabled())
                    {
                        SecurityEventSource.Log.CertificateFromDelegate(LoggingHash.HashInt(this));
                    }
                }
                else
                {
                    if (ClientCertificates.Count == 0)
                    {
                        if (SecurityEventSource.Log.IsEnabled())
                        {
                            SecurityEventSource.Log.NoDelegateNoClientCert(LoggingHash.HashInt(this));
                        }

                        sessionRestartAttempt = true;
                    }
                    else
                    {
                        if (SecurityEventSource.Log.IsEnabled())
                        {
                            SecurityEventSource.Log.NoDelegateButClientCert(LoggingHash.HashInt(this));
                        }
                    }
                }
            }
            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 (SecurityEventSource.Log.IsEnabled())
                {
                    SecurityEventSource.Log.AttemptingRestartUsingCert(clientCertificate == null ? "null" : clientCertificate.ToString(true), LoggingHash.HashInt(this));
                }
            }
            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 (SecurityEventSource.Log.IsEnabled())
                {
                    if (issuers == null || issuers.Length == 0)
                    {
                        SecurityEventSource.Log.NoIssuersTryAllCerts(LoggingHash.HashInt(this));
                    }
                    else
                    {
                        SecurityEventSource.Log.LookForMatchingCerts(issuers.Length, LoggingHash.HashInt(this));
                    }
                }

                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#" + LoggingHash.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#" + LoggingHash.HashString(this) + "::AcquireClientCredentials() matched:" + issuer);
                                        break;
                                    }
                                    GlobalLog.Print("SecureChannel#" + LoggingHash.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 (SecurityEventSource.Log.IsEnabled())
                    {
                        SecurityEventSource.Log.SelectedCert(_clientCertificates[i].ToString(true), LoggingHash.HashInt(this));
                    }

                    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 (SecurityEventSource.Log.IsEnabled())
            {
                SecurityEventSource.Log.CertsAfterFiltering(filteredCerts.Count, LoggingHash.HashInt(this));
                if (filteredCerts.Count != 0)
                {
                    SecurityEventSource.Log.FindingMatchingCerts(LoggingHash.HashInt(this));
                }
            }

            //
            // 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#" + LoggingHash.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#" + LoggingHash.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 (SecurityEventSource.Log.IsEnabled())
                    {
                        SecurityEventSource.Log.UsingCachedCredential(LoggingHash.HashInt(this));
                    }

                    _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#" + LoggingHash.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), LoggingHash.ObjectToString(_credentialsHandle));
            return(cachedCred);
        }
예제 #20
0
 /// <devdoc>
 ///    <para>
 ///       Creates a new instance of the <see cref='System.Net.Sockets.SocketException'/> class with the default error code.
 ///    </para>
 /// </devdoc>
 public SocketException() : base(Marshal.GetLastWin32Error())
 {
     GlobalLog.Print("SocketException::.ctor() " + NativeErrorCode.ToString() + ":" + Message);
 }
예제 #21
0
            private unsafe SocketError InnerReleaseHandle()
            {
                int errorCode;

                // If _blockable was set in BlockingRelease, it's safe to block here, which means
                // we can honor the linger options set on the socket.  It also means closesocket() might return WSAEWOULDBLOCK, in which
                // case we need to do some recovery.
                if (_blockable)
                {
                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") Following 'blockable' branch.");
                    }

                    errorCode = Interop.Sys.Close(handle);
                    if (errorCode == -1)
                    {
                        errorCode = (int)Interop.Sys.GetLastError();
                    }

                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close()#1:" + errorCode.ToString());
                    }
#if DEBUG
                    _closeSocketHandle = handle;
                    _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode);
#endif

                    // If it's not EWOULDBLOCK, there's no more recourse - we either succeeded or failed.
                    if (errorCode != (int)Interop.Error.EWOULDBLOCK)
                    {
                        return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode));
                    }

                    // The socket must be non-blocking with a linger timeout set.
                    // We have to set the socket to blocking.
                    errorCode = Interop.Sys.Fcntl.DangerousSetIsNonBlocking(handle, 0);
                    if (errorCode == 0)
                    {
                        // The socket successfully made blocking; retry the close().
                        errorCode = Interop.Sys.Close(handle);

                        if (GlobalLog.IsEnabled)
                        {
                            GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close()#2:" + errorCode.ToString());
                        }
#if DEBUG
                        _closeSocketHandle = handle;
                        _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode);
#endif
                        return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode));
                    }

                    // The socket could not be made blocking; fall through to the regular abortive close.
                }

                // By default or if CloseAsIs() path failed, set linger timeout to zero to get an abortive close (RST).
                var linger = new Interop.Sys.LingerOption {
                    OnOff   = 1,
                    Seconds = 0
                };

                errorCode = (int)Interop.Sys.DangerousSetLingerOption((int)handle, &linger);
#if DEBUG
                _closeSocketLinger = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode);
#endif
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") setsockopt():" + errorCode.ToString());
                }

                if (errorCode != 0 && errorCode != (int)Interop.Error.EINVAL && errorCode != (int)Interop.Error.ENOPROTOOPT)
                {
                    // Too dangerous to try closesocket() - it might block!
                    return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode));
                }

                errorCode = Interop.Sys.Close(handle);
#if DEBUG
                _closeSocketHandle = handle;
                _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode);
#endif
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close#3():" + (errorCode == -1 ? (int)Interop.Sys.GetLastError() : errorCode).ToString());
                }

                return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode));
            }
예제 #22
0
 /// <devdoc>
 ///    <para>
 ///       Creates a new instance of the <see cref='System.Net.Sockets.SocketException'/> class with the specified error code.
 ///    </para>
 /// </devdoc>
 public SocketException(int errorCode) : base(errorCode)
 {
     GlobalLog.Print("SocketException::.ctor(int) " + NativeErrorCode.ToString() + ":" + Message);
 }
예제 #23
0
        GetChunkSize(IReadChunkBytes Source, out int chunkSize)
        {
            int BytesRead;
            int Size;
            int Current;

            GlobalLog.Enter("GetChunkSize");
            Size = 0;

            //
            // Loop while we have data. If we run out of data and exit the loop
            // at the bottom, then we've run out of data and haven't found the
            // length.

            Current   = Source.NextByte;
            BytesRead = 0;

            if (Current == 10 || Current == 13)
            {
                GlobalLog.Print(" Got Char: " + Current.ToString());
                BytesRead++;
                Current = Source.NextByte;
            }

            while (Current != -1)
            {
                // Get the next byte, and decode it.

                if (Current >= '0' && Current <= '9')
                {
                    // Normalize it to 0 based.

                    Current -= '0';
                }
                else
                {
                    // If we're here, this might be a hex digit.
                    // If it is, normalize it to 10 based.

                    if (Current >= 'a' && Current <= 'f')
                    {
                        Current -= 'a';
                    }
                    else
                    {
                        if (Current >= 'A' && Current <= 'F')
                        {
                            Current -= 'A';
                        }
                        else
                        {
                            // Done with the decoding. If we haven't actually
                            // decoded a digit yet, we'll end up returning
                            // 0, which will signal the error.


                            // Push back the byte we read and didn't use.

                            Source.NextByte = Current;

                            chunkSize = Size;

                            // Return how many bytes we took.

                            GlobalLog.Print("*Size* = " + Size.ToString());
                            GlobalLog.Leave("GetChunkSize", BytesRead);
                            return(BytesRead);
                        }
                    }

                    // If we get here we've had an A-F digit, add 10
                    // to it to normalize it.

                    Current += 10;
                }

                // Update the size and our state.

                Size *= 16;
                Size += Current;

                BytesRead++;
                Current = Source.NextByte;
            }

            chunkSize = Size;
            GlobalLog.Print("*Size* = " + Size.ToString());
            GlobalLog.Leave("GetChunkSize", -1);
            return(-1);
        }
예제 #24
0
 protected SocketException(SerializationInfo serializationInfo, StreamingContext streamingContext)
     : base(serializationInfo, streamingContext)
 {
     GlobalLog.Print("SocketException::.ctor(serialized) " + NativeErrorCode.ToString() + ":" + Message);
 }
예제 #25
0
            private SocketError InnerReleaseHandle()
            {
                SocketError errorCode;

                // If _blockable was set in BlockingRelease, it's safe to block here, which means
                // we can honor the linger options set on the socket.  It also means closesocket() might return WSAEWOULDBLOCK, in which
                // case we need to do some recovery.
                if (_blockable)
                {
                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") Following 'blockable' branch.");
                    }

                    errorCode = Interop.Winsock.closesocket(handle);
#if DEBUG
                    _closeSocketHandle = handle;
                    _closeSocketResult = errorCode;
#endif
                    if (errorCode == SocketError.SocketError)
                    {
                        errorCode = (SocketError)Marshal.GetLastWin32Error();
                    }
                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket()#1:" + errorCode.ToString());
                    }

                    // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed.
                    if (errorCode != SocketError.WouldBlock)
                    {
                        return(errorCode);
                    }

                    // The socket must be non-blocking with a linger timeout set.
                    // We have to set the socket to blocking.
                    int nonBlockCmd = 0;
                    errorCode = Interop.Winsock.ioctlsocket(
                        handle,
                        Interop.Winsock.IoctlSocketConstants.FIONBIO,
                        ref nonBlockCmd);
                    if (errorCode == SocketError.SocketError)
                    {
                        errorCode = (SocketError)Marshal.GetLastWin32Error();
                    }

                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket()#1:" + errorCode.ToString());
                    }

                    // This can fail if there's a pending WSAEventSelect.  Try canceling it.
                    if (errorCode == SocketError.InvalidArgument)
                    {
                        errorCode = Interop.Winsock.WSAEventSelect(
                            handle,
                            IntPtr.Zero,
                            Interop.Winsock.AsyncEventBits.FdNone);

                        if (GlobalLog.IsEnabled)
                        {
                            GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") WSAEventSelect():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString());
                        }

                        // Now retry the ioctl.
                        errorCode = Interop.Winsock.ioctlsocket(
                            handle,
                            Interop.Winsock.IoctlSocketConstants.FIONBIO,
                            ref nonBlockCmd);

                        if (GlobalLog.IsEnabled)
                        {
                            GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket#2():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString());
                        }
                    }

                    // If that succeeded, try again.
                    if (errorCode == SocketError.Success)
                    {
                        errorCode = Interop.Winsock.closesocket(handle);
#if DEBUG
                        _closeSocketHandle = handle;
                        _closeSocketResult = errorCode;
#endif
                        if (errorCode == SocketError.SocketError)
                        {
                            errorCode = (SocketError)Marshal.GetLastWin32Error();
                        }
                        if (GlobalLog.IsEnabled)
                        {
                            GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#2():" + errorCode.ToString());
                        }

                        // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed.
                        if (errorCode != SocketError.WouldBlock)
                        {
                            return(errorCode);
                        }
                    }

                    // It failed.  Fall through to the regular abortive close.
                }

                // By default or if CloseAsIs() path failed, set linger timeout to zero to get an abortive close (RST).
                Interop.Winsock.Linger lingerStruct;
                lingerStruct.OnOff = 1;
                lingerStruct.Time  = 0;

                errorCode = Interop.Winsock.setsockopt(
                    handle,
                    SocketOptionLevel.Socket,
                    SocketOptionName.Linger,
                    ref lingerStruct,
                    4);
#if DEBUG
                _closeSocketLinger = errorCode;
#endif
                if (errorCode == SocketError.SocketError)
                {
                    errorCode = (SocketError)Marshal.GetLastWin32Error();
                }
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") setsockopt():" + errorCode.ToString());
                }

                if (errorCode != SocketError.Success && errorCode != SocketError.InvalidArgument && errorCode != SocketError.ProtocolOption)
                {
                    // Too dangerous to try closesocket() - it might block!
                    return(errorCode);
                }

                errorCode = Interop.Winsock.closesocket(handle);
#if DEBUG
                _closeSocketHandle = handle;
                _closeSocketResult = errorCode;
#endif
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#3():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString());
                }

                return(errorCode);
            }
예제 #26
0
        internal static int Encrypt(
            SafeDeleteContext securityContext,
            byte[] buffer,
            int offset,
            int count,
            bool isConfidential,
            bool isNtlm,
            ref byte[] output,
            uint sequenceNumber)
        {
            SecSizes sizes = SSPIWrapper.QueryContextAttributes(
                GlobalSSPI.SSPIAuth,
                securityContext,
                Interop.SspiCli.ContextAttribute.Sizes
                ) as SecSizes;

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

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

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

                throw;
            }

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

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

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

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

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

            int errorCode;

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

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

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

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

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

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

            resultSize += securityBuffer[2].size;
            unchecked
            {
                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);
        }
예제 #27
0
        private unsafe static void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped)
        {
#if DEBUG
            GlobalLog.SetThreadSource(ThreadKinds.CompletionPort);
            using (GlobalLog.SetThreadKind(ThreadKinds.System))
            {
#endif
            BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped);

            object returnObject = null;

            if (asyncResult.InternalPeekCompleted)
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.AssertFormat("BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|asyncResult.IsCompleted", LoggingHash.HashString(asyncResult));
                }
                Debug.Fail("BaseOverlappedAsyncResult#" + LoggingHash.HashString(asyncResult) + "::CompletionPortCallback()|asyncResult.IsCompleted");
            }
            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Print(
                    "BaseOverlappedAsyncResult#" + LoggingHash.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 = Interop.Winsock.WSAGetOverlappedResult(
                            socket.SafeHandle,
                            asyncResult.NativeOverlapped,
                            out numBytes,
                            false,
                            out ignore);
                        if (!success)
                        {
                            socketError = (SocketError)Marshal.GetLastWin32Error();
                            if (socketError == 0)
                            {
                                if (GlobalLog.IsEnabled)
                                {
                                    GlobalLog.AssertFormat("BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|socketError:0 numBytes:{1}", LoggingHash.HashString(asyncResult), numBytes);
                                }
                                Debug.Fail("BaseOverlappedAsyncResult#" + LoggingHash.HashString(asyncResult) + "::CompletionPortCallback()|socketError:0 numBytes:" + numBytes);
                            }
                        }

                        if (success)
                        {
                            if (GlobalLog.IsEnabled)
                            {
                                GlobalLog.AssertFormat("BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|Unexpectedly succeeded. errorCode:{1} numBytes:{2}", LoggingHash.HashString(asyncResult), errorCode, numBytes);
                            }
                            Debug.Fail("BaseOverlappedAsyncResult#" + LoggingHash.HashString(asyncResult) + "::CompletionPortCallback()|Unexpectedly succeeded. errorCode:" + errorCode + " numBytes: " + numBytes);
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                        // CleanedUp check above does not always work since this code is subject to race conditions
                        socketError = SocketError.OperationAborted;
                    }
                }
            }
            asyncResult.ErrorCode = (int)socketError;
            returnObject          = asyncResult.PostCompletion((int)numBytes);
            asyncResult.ReleaseUnmanagedStructures();
            asyncResult.InvokeCallback(returnObject);
#if DEBUG
        }
#endif
        }
예제 #28
0
        public static unsafe SecurityStatusPal EncryptMessage(SafeDeleteContext securityContext, byte[] input, int offset, int size, int headerSize, int trailerSize, ref byte[] output, out int resultSize)
        {
            // Ensure that there is sufficient space for the message output.
            int bufferSizeNeeded;

            try
            {
                bufferSizeNeeded = checked (size + headerSize + trailerSize);
            }
            catch
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range.");
                }
                Debug.Fail("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range.");
                throw;
            }
            if (output == null || output.Length < bufferSizeNeeded)
            {
                output = new byte[bufferSizeNeeded];
            }

            // Copy the input into the output buffer to prepare for SCHANNEL's expectations
            Buffer.BlockCopy(input, offset, output, headerSize, size);

            const int NumSecBuffers   = 4; // header + data + trailer + empty
            var       unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[NumSecBuffers];
            var       sdcInOut        = new Interop.SspiCli.SecBufferDesc(NumSecBuffers);

            sdcInOut.pBuffers = unmanagedBuffer;
            fixed(byte *outputPtr = output)
            {
                Interop.SspiCli.SecBuffer *headerSecBuffer = &unmanagedBuffer[0];
                headerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_HEADER;
                headerSecBuffer->pvBuffer   = (IntPtr)outputPtr;
                headerSecBuffer->cbBuffer   = headerSize;

                Interop.SspiCli.SecBuffer *dataSecBuffer = &unmanagedBuffer[1];
                dataSecBuffer->BufferType = SecurityBufferType.SECBUFFER_DATA;
                dataSecBuffer->pvBuffer   = (IntPtr)(outputPtr + headerSize);
                dataSecBuffer->cbBuffer   = size;

                Interop.SspiCli.SecBuffer *trailerSecBuffer = &unmanagedBuffer[2];
                trailerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_TRAILER;
                trailerSecBuffer->pvBuffer   = (IntPtr)(outputPtr + headerSize + size);
                trailerSecBuffer->cbBuffer   = trailerSize;

                Interop.SspiCli.SecBuffer *emptySecBuffer = &unmanagedBuffer[3];
                emptySecBuffer->BufferType = SecurityBufferType.SECBUFFER_EMPTY;
                emptySecBuffer->cbBuffer   = 0;
                emptySecBuffer->pvBuffer   = IntPtr.Zero;

                int errorCode = GlobalSSPI.SSPISecureChannel.EncryptMessage(securityContext, sdcInOut, 0);

                if (errorCode != 0)
                {
                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("SslStreamPal.Windows: SecureChannel#" + LoggingHash.HashString(securityContext) + "::Encrypt ERROR" + errorCode.ToString("x"));
                    }

                    resultSize = 0;
                    return(SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode));
                }

                Debug.Assert(headerSecBuffer->cbBuffer >= 0 && dataSecBuffer->cbBuffer >= 0 && trailerSecBuffer->cbBuffer >= 0);
                Debug.Assert(checked (headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer) <= output.Length);

                resultSize = checked (headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer);
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK));
            }
        }