Skip to content

Commit b3a0536

Browse files
committed
Allow plugin name without null terminator. Fixes #351
1 parent f28561e commit b3a0536

File tree

5 files changed

+36
-5
lines changed

5 files changed

+36
-5
lines changed

src/MySqlConnector/ByteArrayReader.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22

33
namespace MySql.Data
44
{
@@ -104,6 +104,19 @@ public byte[] ReadNullTerminatedByteString()
104104
return substring;
105105
}
106106

107+
public byte[] ReadNullOrEofTerminatedByteString()
108+
{
109+
int index = m_offset;
110+
while (index < m_maxOffset && m_buffer[index] != 0)
111+
index++;
112+
byte[] substring = new byte[index - m_offset];
113+
Buffer.BlockCopy(m_buffer, m_offset, substring, 0, substring.Length);
114+
if (index < m_maxOffset && m_buffer[index] == 0)
115+
index++;
116+
m_offset = index;
117+
return substring;
118+
}
119+
107120
public byte[] ReadByteString(int length)
108121
{
109122
VerifyRead(length);

src/MySqlConnector/Serialization/InitialHandshakePacket.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Text;
33

44
namespace MySql.Data.Serialization
@@ -36,8 +36,10 @@ internal InitialHandshakePacket(ByteArrayReader reader)
3636
AuthPluginData = concatenated;
3737
}
3838
if ((ProtocolCapabilities & ProtocolCapabilities.PluginAuth) != 0)
39-
AuthPluginName = Encoding.UTF8.GetString(reader.ReadNullTerminatedByteString());
39+
AuthPluginName = Encoding.UTF8.GetString(reader.ReadNullOrEofTerminatedByteString());
4040
}
41+
if (reader.BytesRemaining != 0)
42+
throw new FormatException("Extra bytes at end of payload.");
4143
}
4244

4345
const byte c_protocolVersion = 0x0A;

tests/MySqlConnector.Tests/ConnectionTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Data;
23
using System.Diagnostics;
34
using System.Threading;
45
using System.Threading.Tasks;
@@ -117,6 +118,17 @@ public void LeakReaders()
117118
}
118119
}
119120

121+
[Fact]
122+
public void AuthPluginNameNotNullTerminated()
123+
{
124+
m_server.SuppressAuthPluginNameTerminatingNull = true;
125+
using (var connection = new MySqlConnection(m_csb.ConnectionString))
126+
{
127+
connection.Open();
128+
Assert.Equal(ConnectionState.Open, connection.State);
129+
}
130+
}
131+
120132
private static async Task WaitForConditionAsync<T>(T expected, Func<T> getValue)
121133
{
122134
var sw = Stopwatch.StartNew();

tests/MySqlConnector.Tests/FakeMySqlServer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Net;
44
using System.Net.Sockets;
@@ -45,6 +45,8 @@ public void Stop()
4545

4646
public string ServerVersion { get; set; } = "5.7.10-test";
4747

48+
public bool SuppressAuthPluginNameTerminatingNull { get; set; }
49+
4850
internal void ClientDisconnected() => Interlocked.Decrement(ref m_activeConnections);
4951

5052
private async Task AcceptConnectionsAsync()

tests/MySqlConnector.Tests/FakeMySqlServerConnection.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,9 @@ private void WriteInitialHandshake(BinaryWriter writer)
170170
writer.Write(authData, 8, authData.Length - 8);
171171
if (authData.Length - 8 < 13)
172172
writer.Write(new byte[13 - (authData.Length - 8)]); // have to write at least 13 bytes
173-
writer.WriteNullTerminated("mysql_native_password");
173+
writer.Write(Encoding.UTF8.GetBytes("mysql_native_password"));
174+
if (!m_server.SuppressAuthPluginNameTerminatingNull)
175+
writer.Write((byte) 0);
174176
}
175177

176178
private static void WriteOk(BinaryWriter writer)

0 commit comments

Comments
 (0)