예제 #1
0
        public void Identify(string database)
        {
            using (var xdrStream = CreateXdrStreamImpl(false))
            {
                try
                {
                    xdrStream.Write(IscCodes.op_connect);
                    xdrStream.Write(IscCodes.op_attach);
                    xdrStream.Write(IscCodes.CONNECT_VERSION3);
                    xdrStream.Write(IscCodes.GenericAchitectureClient);

                    xdrStream.Write(database);

                    var protocols = ProtocolsSupported.Get(_compression);
                    xdrStream.Write(protocols.Count());
                    xdrStream.WriteBuffer(UserIdentificationData());

                    var priority = 0;
                    foreach (var protocol in protocols)
                    {
                        xdrStream.Write(protocol.Version);
                        xdrStream.Write(IscCodes.GenericAchitectureClient);
                        xdrStream.Write(protocol.MinPType);
                        xdrStream.Write(protocol.MaxPType);
                        xdrStream.Write(priority);

                        priority++;
                    }

                    xdrStream.Flush();

                    var operation = xdrStream.ReadOperation();
                    if (operation == IscCodes.op_accept || operation == IscCodes.op_cond_accept || operation == IscCodes.op_accept_data)
                    {
                        _protocolVersion      = xdrStream.ReadInt32();
                        _protocolArchitecture = xdrStream.ReadInt32();
                        _protocolMinimunType  = xdrStream.ReadInt32();

                        if (_protocolVersion < 0)
                        {
                            _protocolVersion = (ushort)(_protocolVersion & IscCodes.FB_PROTOCOL_MASK) | IscCodes.FB_PROTOCOL_FLAG;
                        }

                        if (_compression && !((_protocolMinimunType & IscCodes.pflag_compress) != 0))
                        {
                            _compression = false;
                        }

                        if (operation == IscCodes.op_cond_accept || operation == IscCodes.op_accept_data)
                        {
                            var data             = xdrStream.ReadBuffer();
                            var acceptPluginName = xdrStream.ReadString();
                            var isAuthenticated  = xdrStream.ReadBoolean();
                            var keys             = xdrStream.ReadString();
                            if (!isAuthenticated)
                            {
                                switch (acceptPluginName)
                                {
                                case SrpClient.PluginName:
                                    _authData = Encoding.ASCII.GetBytes(_srp.ClientProof(NormalizeLogin(_userID), _password, data).ToHexString());
                                    break;

                                case SspiHelper.PluginName:
                                    _authData = _sspi.GetClientSecurity(data);
                                    break;

                                default:
                                    throw new ArgumentOutOfRangeException(nameof(acceptPluginName), $"{nameof(acceptPluginName)}={acceptPluginName}");
                                }
                            }
                        }
                    }
                    else if (operation == IscCodes.op_response)
                    {
                        var response = (GenericResponse)ProcessOperation(operation, xdrStream);
                        throw response.Exception;
                    }
                    else
                    {
                        try
                        {
                            Disconnect();
                        }
                        catch
                        { }
                        finally
                        {
                            throw IscException.ForErrorCode(IscCodes.isc_connect_reject);
                        }
                    }
                }
                catch (IOException ex)
                {
                    throw IscException.ForErrorCode(IscCodes.isc_network_error, ex);
                }
                finally
                {
                    // UserIdentificationData might allocate these
                    _srp = null;
                    _sspi?.Dispose();
                    _sspi = null;
                }
            }
        }
        public void Identify(string database)
        {
            try
            {
                Xdr.Write(IscCodes.op_connect);
                Xdr.Write(IscCodes.op_attach);
                Xdr.Write(IscCodes.CONNECT_VERSION3);
                Xdr.Write(IscCodes.GenericAchitectureClient);

                Xdr.Write(database);

                var protocols = ProtocolsSupported.Get(_compression);
                Xdr.Write(protocols.Count());

#warning These out params are ugly, refactor
                var userIdentificationData = UserIdentificationData(out var srp, out var sspi);
                using (sspi)
                {
                    Xdr.WriteBuffer(userIdentificationData);

                    var priority = 0;
                    foreach (var protocol in protocols)
                    {
                        Xdr.Write(protocol.Version);
                        Xdr.Write(IscCodes.GenericAchitectureClient);
                        Xdr.Write(protocol.MinPType);
                        Xdr.Write(protocol.MaxPType);
                        Xdr.Write(priority);

                        priority++;
                    }

                    Xdr.Flush();

                    var operation = Xdr.ReadOperation();
                    if (operation == IscCodes.op_accept || operation == IscCodes.op_cond_accept || operation == IscCodes.op_accept_data)
                    {
                        var wireCryptInitialized = false;

                        ProtocolVersion      = Xdr.ReadInt32();
                        ProtocolArchitecture = Xdr.ReadInt32();
                        ProtocolMinimunType  = Xdr.ReadInt32();

                        if (ProtocolVersion < 0)
                        {
                            ProtocolVersion = (ushort)(ProtocolVersion & IscCodes.FB_PROTOCOL_MASK) | IscCodes.FB_PROTOCOL_FLAG;
                        }

                        if (_compression && !((ProtocolMinimunType & IscCodes.pflag_compress) != 0))
                        {
                            _compression = false;
                        }

                        if (operation == IscCodes.op_cond_accept || operation == IscCodes.op_accept_data)
                        {
                            var serverData       = Xdr.ReadBuffer();
                            var acceptPluginName = Xdr.ReadString();
                            var isAuthenticated  = Xdr.ReadBoolean();
                            var serverKeys       = Xdr.ReadBuffer();
                            if (!isAuthenticated)
                            {
                                switch (acceptPluginName)
                                {
                                case SrpClient.PluginName:
                                    AuthData = Encoding.ASCII.GetBytes(srp.ClientProof(NormalizeLogin(_userID), Password, serverData).ToHexString());
                                    break;

                                case SspiHelper.PluginName:
                                    AuthData = sspi.GetClientSecurity(serverData);
                                    break;

                                default:
                                    throw new ArgumentOutOfRangeException(nameof(acceptPluginName), $"{nameof(acceptPluginName)}={acceptPluginName}");
                                }
                            }

                            if (_compression)
                            {
                                // after reading before writing
                                _firebirdNetworkStream.StartCompression();
                            }

                            if (operation == IscCodes.op_cond_accept)
                            {
                                Xdr.Write(IscCodes.op_cont_auth);
                                Xdr.WriteBuffer(AuthData);
                                Xdr.Write(acceptPluginName);                                 // like CNCT_plugin_name
                                Xdr.Write(acceptPluginName);                                 // like CNCT_plugin_list
                                Xdr.WriteBuffer(serverKeys);
                                Xdr.Flush();
                                var response = (GenericResponse)ProcessOperation(Xdr.ReadOperation(), Xdr);
                                serverKeys      = response.Data;
                                isAuthenticated = true;

                                if (_wireCrypt != WireCryptOption.Disabled)
                                {
                                    Xdr.Write(IscCodes.op_crypt);
                                    Xdr.Write(FirebirdNetworkStream.EncryptionName);
                                    Xdr.Write(SrpClient.SessionKeyName);
                                    Xdr.Flush();

                                    // after writing before reading
                                    _firebirdNetworkStream.StartEncryption(srp.SessionKey);

                                    ProcessOperation(Xdr.ReadOperation(), Xdr);

                                    wireCryptInitialized = true;
                                }
                            }
                        }

                        // fbclient does not care about wirecrypt in older protocols either
                        if (ProtocolVersion == IscCodes.PROTOCOL_VERSION13 && _wireCrypt == WireCryptOption.Required && !wireCryptInitialized)
                        {
                            throw IscException.ForErrorCode(IscCodes.isc_wirecrypt_incompatible);
                        }
                    }
                    else if (operation == IscCodes.op_response)
                    {
                        var response = (GenericResponse)ProcessOperation(operation, Xdr);
                        throw response.Exception;
                    }
                    else
                    {
                        try
                        {
                            Disconnect();
                        }
                        catch
                        { }
                        finally
                        {
                            throw IscException.ForErrorCode(IscCodes.isc_connect_reject);
                        }
                    }
                }
            }
            catch (IOException ex)
            {
                throw IscException.ForErrorCode(IscCodes.isc_network_error, ex);
            }
        }