public static byte[] Create(InitialHandshakePacket handshake, string userName, string password, string database)
		{
			// TODO: verify server capabilities

			var writer = new PayloadWriter();

			writer.WriteInt32((int) (
				ProtocolCapabilities.Protocol41 |
				ProtocolCapabilities.LongPassword |
				ProtocolCapabilities.SecureConnection |
				ProtocolCapabilities.PluginAuth |
				ProtocolCapabilities.PluginAuthLengthEncodedClientData |
				ProtocolCapabilities.MultiStatements |
				ProtocolCapabilities.MultiResults |
				ProtocolCapabilities.PreparedStatementMultiResults |
				(string.IsNullOrWhiteSpace(database) ? 0 : ProtocolCapabilities.ConnectWithDatabase)));
			writer.WriteInt32(0x40000000);
			writer.WriteByte((byte) CharacterSet.Utf8Mb4Binary);
			writer.Write(new byte[23]);
			writer.WriteNullTerminatedString(userName);

			writer.WriteLengthEncodedInteger(20);
			var hashedPassword = AuthenticationUtility.HashPassword(handshake.AuthPluginData, 0, password);
			writer.Write(hashedPassword);

			if (!string.IsNullOrWhiteSpace(database))
				writer.WriteNullTerminatedString(database);

			writer.WriteNullTerminatedString("mysql_native_password");

			return writer.ToBytes();
		}
        public static byte[] Create(InitialHandshakePacket handshake, string userName, string password, string database)
        {
            // TODO: verify server capabilities

            var writer = new PayloadWriter();

            writer.WriteInt32((int)(
                                  ProtocolCapabilities.Protocol41 |
                                  ProtocolCapabilities.LongPassword |
                                  ProtocolCapabilities.SecureConnection |
                                  ProtocolCapabilities.PluginAuth |
                                  ProtocolCapabilities.PluginAuthLengthEncodedClientData |
                                  ProtocolCapabilities.MultiStatements |
                                  ProtocolCapabilities.MultiResults |
                                  ProtocolCapabilities.PreparedStatementMultiResults |
                                  (string.IsNullOrWhiteSpace(database) ? 0 : ProtocolCapabilities.ConnectWithDatabase)));
            writer.WriteInt32(0x40000000);
            writer.WriteByte((byte)CharacterSet.Utf8Mb4Binary);
            writer.Write(new byte[23]);
            writer.WriteNullTerminatedString(userName);

            var authenticationResponse = AuthenticationUtility.CreateAuthenticationResponse(handshake.AuthPluginData, 0, password);

            writer.WriteByte((byte)authenticationResponse.Length);
            writer.Write(authenticationResponse);

            if (!string.IsNullOrWhiteSpace(database))
            {
                writer.WriteNullTerminatedString(database);
            }

            writer.WriteNullTerminatedString("mysql_native_password");

            return(writer.ToBytes());
        }
Beispiel #3
0
        public async Task ConnectAsync(IEnumerable <string> hosts, int port, string userId, string password, string database, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            var connected = await OpenSocketAsync(hosts, port, ioBehavior, cancellationToken).ConfigureAwait(false);

            if (!connected)
            {
                throw new MySqlException("Unable to connect to any of the specified MySQL hosts.");
            }

            var payload = await ReceiveAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            var reader           = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count);
            var initialHandshake = new InitialHandshakePacket(reader);

            if (initialHandshake.AuthPluginName != "mysql_native_password")
            {
                throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
            }
            ServerVersion  = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
            ConnectionId   = initialHandshake.ConnectionId;
            AuthPluginData = initialHandshake.AuthPluginData;

            var response = HandshakeResponse41Packet.Create(initialHandshake, userId, password, database);

            payload = new PayloadData(new ArraySegment <byte>(response));
            await SendReplyAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);
            await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
        }
Beispiel #4
0
        public async Task ConnectAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            var connected = false;

            if (cs.ConnectionType == ConnectionType.Tcp)
            {
                connected = await OpenTcpSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            else if (cs.ConnectionType == ConnectionType.Unix)
            {
                connected = await OpenUnixSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            if (!connected)
            {
                throw new MySqlException("Unable to connect to any of the specified MySQL hosts.");
            }

            var socketByteHandler = new SocketByteHandler(m_socket);

            m_payloadHandler = new StandardPayloadHandler(socketByteHandler);

            var payload = await ReceiveAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            var reader           = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count);
            var initialHandshake = new InitialHandshakePacket(reader);

            if (initialHandshake.AuthPluginName != "mysql_native_password")
            {
                throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
            }
            ServerVersion  = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
            ConnectionId   = initialHandshake.ConnectionId;
            AuthPluginData = initialHandshake.AuthPluginData;
            if (cs.UseCompression && !initialHandshake.ProtocolCapabilities.HasFlag(ProtocolCapabilities.Compress))
            {
                cs = cs.WithUseCompression(false);
            }

            if (cs.SslMode != MySqlSslMode.None)
            {
                await InitSslAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }

            var response = HandshakeResponse41Packet.Create(initialHandshake, cs);

            payload = new PayloadData(new ArraySegment <byte>(response));
            await SendReplyAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

            payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            OkPayload.Create(payload);

            if (cs.UseCompression)
            {
                m_payloadHandler = new CompressedPayloadHandler(m_payloadHandler.ByteHandler);
            }
        }
        public static byte[] Create(InitialHandshakePacket handshake, ConnectionSettings cs)
        {
            // TODO: verify server capabilities

            var writer = CapabilitiesPayload(cs);

            writer.WriteNullTerminatedString(cs.UserID);
            var authenticationResponse = AuthenticationUtility.CreateAuthenticationResponse(handshake.AuthPluginData, 0, cs.Password);

            writer.WriteByte((byte)authenticationResponse.Length);
            writer.Write(authenticationResponse);

            if (!string.IsNullOrWhiteSpace(cs.Database))
            {
                writer.WriteNullTerminatedString(cs.Database);
            }

            writer.WriteNullTerminatedString("mysql_native_password");

            return(writer.ToBytes());
        }
Beispiel #6
0
        public async Task ConnectAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            lock (m_lock)
            {
                VerifyState(State.Created);
                m_state = State.Connecting;
            }
            var connected = false;

            if (cs.ConnectionType == ConnectionType.Tcp)
            {
                connected = await OpenTcpSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            else if (cs.ConnectionType == ConnectionType.Unix)
            {
                connected = await OpenUnixSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            if (!connected)
            {
                lock (m_lock)
                    m_state = State.Failed;
                throw new MySqlException("Unable to connect to any of the specified MySQL hosts.");
            }

            var byteHandler = new SocketByteHandler(m_socket);

            m_payloadHandler = new StandardPayloadHandler(byteHandler);

            var payload = await ReceiveAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            var reader           = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count);
            var initialHandshake = new InitialHandshakePacket(reader);

            // if PluginAuth is supported, then use the specified auth plugin; else, fall back to protocol capabilities to determine the auth type to use
            string authPluginName;

            if ((initialHandshake.ProtocolCapabilities & ProtocolCapabilities.PluginAuth) != 0)
            {
                authPluginName = initialHandshake.AuthPluginName;
            }
            else
            {
                authPluginName = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.SecureConnection) == 0 ? "mysql_old_password" : "mysql_native_password";
            }
            if (authPluginName != "mysql_native_password" && authPluginName != "sha256_password" && authPluginName != "caching_sha2_password")
            {
                throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
            }

            ServerVersion    = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
            ConnectionId     = initialHandshake.ConnectionId;
            AuthPluginData   = initialHandshake.AuthPluginData;
            m_useCompression = cs.UseCompression && (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Compress) != 0;

            var serverSupportsSsl = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Ssl) != 0;

            if (cs.SslMode != MySqlSslMode.None && (cs.SslMode != MySqlSslMode.Preferred || serverSupportsSsl))
            {
                if (!serverSupportsSsl)
                {
                    throw new MySqlException("Server does not support SSL");
                }
                await InitSslAsync(initialHandshake.ProtocolCapabilities, cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }

            m_supportsConnectionAttributes = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.ConnectionAttributes) != 0;
            if (m_supportsConnectionAttributes && s_connectionAttributes == null)
            {
                s_connectionAttributes = CreateConnectionAttributes();
            }

            m_supportsDeprecateEof = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.DeprecateEof) != 0;

            var response = HandshakeResponse41Packet.Create(initialHandshake, cs, m_useCompression, m_supportsConnectionAttributes ? s_connectionAttributes : null);

            payload = new PayloadData(new ArraySegment <byte>(response));
            await SendReplyAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

            payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            // if server doesn't support the authentication fast path, it will send a new challenge
            if (payload.HeaderByte == AuthenticationMethodSwitchRequestPayload.Signature)
            {
                payload = await SwitchAuthenticationAsync(cs, payload, ioBehavior, cancellationToken).ConfigureAwait(false);
            }

            OkPayload.Create(payload);

            if (m_useCompression)
            {
                m_payloadHandler = new CompressedPayloadHandler(m_payloadHandler.ByteHandler);
            }
        }
		public override async Task OpenAsync(CancellationToken cancellationToken)
		{
			VerifyNotDisposed();
			if (State != ConnectionState.Closed)
				throw new InvalidOperationException("Cannot Open when State is {0}.".FormatInvariant(State));
#if !NETSTANDARD1_3
			if (System.Transactions.Transaction.Current != null)
				throw new NotSupportedException("Ambient transactions are not supported. Use BeginTransaction instead.");
#endif

			if (m_connectionStringBuilder.UseCompression)
				throw new NotSupportedException("Compression not supported.");

			SetState(ConnectionState.Connecting);

			bool success = false;
			try
			{
				var pool = ConnectionPool.GetPool(m_connectionStringBuilder);
				m_session = pool?.TryGetSession();
				if (m_session == null)
				{
					m_session = new MySqlSession(pool);
					var connected = await m_session.ConnectAsync(m_connectionStringBuilder.Server.Split(','), (int) m_connectionStringBuilder.Port).ConfigureAwait(false);
					if (!connected)
					{
						SetState(ConnectionState.Closed);
						throw new MySqlException("Unable to connect to any of the specified MySQL hosts.");
					}

					var payload = await m_session.ReceiveAsync(cancellationToken).ConfigureAwait(false);
					var reader = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count);
					var initialHandshake = new InitialHandshakePacket(reader);
					if (initialHandshake.AuthPluginName != "mysql_native_password")
						throw new NotSupportedException("Only 'mysql_native_password' authentication method is supported.");
					m_session.ServerVersion = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
					m_session.AuthPluginData = initialHandshake.AuthPluginData;

					var response = HandshakeResponse41Packet.Create(initialHandshake, m_connectionStringBuilder.UserID, m_connectionStringBuilder.Password, m_database);
					payload = new PayloadData(new ArraySegment<byte>(response));
					await m_session.SendReplyAsync(payload, cancellationToken).ConfigureAwait(false);
					await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false);
					// TODO: Check success
				}
				else if (m_connectionStringBuilder.ConnectionReset)
				{
					if (m_session.ServerVersion.Version.CompareTo(ServerVersions.SupportsResetConnection) >= 0)
					{
						await m_session.SendAsync(ResetConnectionPayload.Create(), cancellationToken).ConfigureAwait(false);
						var payload = await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false);
						OkPayload.Create(payload);
					}
					else
					{
						// optimistically hash the password with the challenge from the initial handshake (supported by MariaDB; doesn't appear to be supported by MySQL)
						var hashedPassword = AuthenticationUtility.HashPassword(m_session.AuthPluginData, 0, m_connectionStringBuilder.Password);
						var payload = ChangeUserPayload.Create(m_connectionStringBuilder.UserID, hashedPassword, m_database);
						await m_session.SendAsync(payload, cancellationToken).ConfigureAwait(false);
						payload = await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false);
						if (payload.HeaderByte == AuthenticationMethodSwitchRequestPayload.Signature)
						{
							// if the server didn't support the hashed password; rehash with the new challenge
							var switchRequest = AuthenticationMethodSwitchRequestPayload.Create(payload);
							if (switchRequest.Name != "mysql_native_password")
								throw new NotSupportedException("Only 'mysql_native_password' authentication method is supported.");
							hashedPassword = AuthenticationUtility.HashPassword(switchRequest.Data, 0, m_connectionStringBuilder.Password);
							payload = new PayloadData(new ArraySegment<byte>(hashedPassword));
							await m_session.SendReplyAsync(payload, cancellationToken).ConfigureAwait(false);
							payload = await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false);
						}
						OkPayload.Create(payload);
					}
				}

				m_hasBeenOpened = true;
				SetState(ConnectionState.Open);
				success = true;
			}
			catch (MySqlException)
			{
				SetState(ConnectionState.Closed);
				throw;
			}
			catch (SocketException ex)
			{
				SetState(ConnectionState.Closed);
				throw new MySqlException("Unable to connect to any of the specified MySQL hosts.", ex);
			}
			finally
			{
				if (!success)
					Utility.Dispose(ref m_session);
			}
		}
        public async Task ConnectAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            var connected = false;

            if (cs.ConnectionType == ConnectionType.Tcp)
            {
                connected = await OpenTcpSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            else if (cs.ConnectionType == ConnectionType.Unix)
            {
                connected = await OpenUnixSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            if (!connected)
            {
                throw new MySqlException("Unable to connect to any of the specified MySQL hosts.");
            }

            var socketByteHandler = new SocketByteHandler(m_socket);

            m_payloadHandler = new StandardPayloadHandler(socketByteHandler);

            var payload = await ReceiveAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            var reader           = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count);
            var initialHandshake = new InitialHandshakePacket(reader);

            // if PluginAuth is supported, then use the specified auth plugin; else, fall back to protocol capabilities to determine the auth type to use
            string authPluginName;

            if ((initialHandshake.ProtocolCapabilities & ProtocolCapabilities.PluginAuth) != 0)
            {
                authPluginName = initialHandshake.AuthPluginName;
            }
            else
            {
                authPluginName = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.SecureConnection) == 0 ? "mysql_old_password" : "mysql_native_password";
            }
            if (authPluginName != "mysql_native_password")
            {
                throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
            }

            ServerVersion  = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
            ConnectionId   = initialHandshake.ConnectionId;
            AuthPluginData = initialHandshake.AuthPluginData;
            if (cs.UseCompression && (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Compress) == 0)
            {
                cs = cs.WithUseCompression(false);
            }

            var serverSupportsSsl = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Ssl) != 0;

            if (cs.SslMode != MySqlSslMode.None && (cs.SslMode != MySqlSslMode.Preferred || serverSupportsSsl))
            {
                if (!serverSupportsSsl)
                {
                    throw new MySqlException("Server does not support SSL");
                }
                await InitSslAsync(initialHandshake.ProtocolCapabilities, cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }

            var response = HandshakeResponse41Packet.Create(initialHandshake, cs);

            payload = new PayloadData(new ArraySegment <byte>(response));
            await SendReplyAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

            payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            OkPayload.Create(payload);

            if (cs.UseCompression)
            {
                m_payloadHandler = new CompressedPayloadHandler(m_payloadHandler.ByteHandler);
            }
        }