You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
6.4 KiB

4 years ago
  1. #if MYSQL_6_9
  2. // Copyright © 2012, Oracle and/or its affiliates. All rights reserved.
  3. //
  4. // MySQL Connector/NET is licensed under the terms of the GPLv2
  5. // <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
  6. // MySQL Connectors. There are special exceptions to the terms and
  7. // conditions of the GPLv2 as it is applied to this software, see the
  8. // FLOSS License Exception
  9. // <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published
  13. // by the Free Software Foundation; version 2 of the License.
  14. //
  15. // This program is distributed in the hope that it will be useful, but
  16. // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  18. // for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License along
  21. // with this program; if not, write to the Free Software Foundation, Inc.,
  22. // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  23. using System.IO;
  24. using System;
  25. using Externals.MySql.Data.MySqlClient.Properties;
  26. using Externals.MySql.Data.Common;
  27. using System.Text;
  28. using System.Diagnostics;
  29. namespace Externals.MySql.Data.MySqlClient.Authentication
  30. {
  31. internal abstract class MySqlAuthenticationPlugin
  32. {
  33. private NativeDriver driver;
  34. protected byte[] AuthenticationData;
  35. /// <summary>
  36. /// This is a factory method that is used only internally. It creates an auth plugin based on the method type
  37. /// </summary>
  38. internal static MySqlAuthenticationPlugin GetPlugin(string method, NativeDriver driver, byte[] authData)
  39. {
  40. if (method == "mysql_old_password")
  41. {
  42. driver.Close(true);
  43. throw new MySqlException(Resources.OldPasswordsNotSupported);
  44. }
  45. MySqlAuthenticationPlugin plugin = AuthenticationPluginManager.GetPlugin(method);
  46. if (plugin == null)
  47. throw new MySqlException(String.Format(Resources.UnknownAuthenticationMethod, method));
  48. plugin.driver = driver;
  49. plugin.SetAuthData(authData);
  50. return plugin;
  51. }
  52. protected MySqlConnectionStringBuilder Settings
  53. {
  54. get { return driver.Settings; }
  55. }
  56. protected Version ServerVersion
  57. {
  58. get { return new Version(driver.Version.Major, driver.Version.Minor, driver.Version.Build); }
  59. }
  60. internal ClientFlags Flags
  61. {
  62. get { return driver.Flags; }
  63. }
  64. protected Encoding Encoding
  65. {
  66. get { return driver.Encoding; }
  67. }
  68. protected virtual void SetAuthData(byte[] data)
  69. {
  70. AuthenticationData = data;
  71. }
  72. protected virtual void CheckConstraints()
  73. {
  74. }
  75. protected virtual void AuthenticationFailed(Exception ex)
  76. {
  77. string msg = String.Format(Resources.AuthenticationFailed, Settings.Server, GetUsername(), PluginName, ex.Message);
  78. throw new MySqlException(msg, ex);
  79. }
  80. protected virtual void AuthenticationSuccessful()
  81. {
  82. }
  83. protected virtual byte[] MoreData(byte[] data)
  84. {
  85. return null;
  86. }
  87. internal void Authenticate(bool reset)
  88. {
  89. CheckConstraints();
  90. MySqlPacket packet = driver.Packet;
  91. // send auth response
  92. packet.WriteString(GetUsername());
  93. // now write the password
  94. WritePassword(packet);
  95. if ((Flags & ClientFlags.CONNECT_WITH_DB) != 0 || reset)
  96. {
  97. if (!String.IsNullOrEmpty(Settings.Database))
  98. packet.WriteString(Settings.Database);
  99. }
  100. if (reset)
  101. packet.WriteInteger(8, 2);
  102. if ((Flags & ClientFlags.PLUGIN_AUTH) != 0)
  103. packet.WriteString(PluginName);
  104. driver.SetConnectAttrs();
  105. driver.SendPacket(packet);
  106. //read server response
  107. packet = ReadPacket();
  108. byte[] b = packet.Buffer;
  109. if (b[0] == 0xfe)
  110. {
  111. if (packet.IsLastPacket)
  112. {
  113. driver.Close(true);
  114. throw new MySqlException( Resources.OldPasswordsNotSupported );
  115. }
  116. else
  117. {
  118. HandleAuthChange(packet);
  119. }
  120. }
  121. driver.ReadOk(false);
  122. AuthenticationSuccessful();
  123. }
  124. private void WritePassword(MySqlPacket packet)
  125. {
  126. bool secure = (Flags & ClientFlags.SECURE_CONNECTION) != 0;
  127. object password = GetPassword();
  128. if (password is string)
  129. {
  130. if (secure)
  131. packet.WriteLenString((string)password);
  132. else
  133. packet.WriteString((string)password);
  134. }
  135. else if (password == null)
  136. packet.WriteByte(0);
  137. else if (password is byte[])
  138. packet.Write(password as byte[]);
  139. else throw new MySqlException("Unexpected password format: " + password.GetType());
  140. }
  141. private MySqlPacket ReadPacket()
  142. {
  143. try
  144. {
  145. MySqlPacket p = driver.ReadPacket();
  146. return p;
  147. }
  148. catch (MySqlException ex)
  149. {
  150. // make sure this is an auth failed ex
  151. AuthenticationFailed(ex);
  152. return null;
  153. }
  154. }
  155. private void HandleAuthChange(MySqlPacket packet)
  156. {
  157. byte b = packet.ReadByte();
  158. Debug.Assert(b == 0xfe);
  159. string method = packet.ReadString();
  160. byte[] authData = new byte[packet.Length - packet.Position];
  161. Array.Copy(packet.Buffer, packet.Position, authData, 0, authData.Length);
  162. MySqlAuthenticationPlugin plugin = MySqlAuthenticationPlugin.GetPlugin(method, driver, authData);
  163. plugin.AuthenticationChange();
  164. }
  165. private void AuthenticationChange()
  166. {
  167. MySqlPacket packet = driver.Packet;
  168. packet.Clear();
  169. byte[] moreData = MoreData(null);
  170. while (moreData != null && moreData.Length > 0)
  171. {
  172. packet.Clear();
  173. packet.Write(moreData);
  174. driver.SendPacket(packet);
  175. packet = ReadPacket();
  176. byte prefixByte = packet.Buffer[0];
  177. if (prefixByte != 1) return;
  178. // a prefix of 0x01 means need more auth data
  179. byte[] responseData = new byte[packet.Length - 1];
  180. Array.Copy(packet.Buffer, 1, responseData, 0, responseData.Length);
  181. moreData = MoreData(responseData);
  182. }
  183. // we get here if MoreData returned null but the last packet read was a more data packet
  184. ReadPacket();
  185. }
  186. public abstract string PluginName { get; }
  187. public virtual string GetUsername()
  188. {
  189. return Settings.UserID;
  190. }
  191. public virtual object GetPassword()
  192. {
  193. return null;
  194. }
  195. }
  196. }
  197. #endif