Forráskód Böngészése

Add SqlCredential support -
- Tds.cs: Use SecureString objects for passwords; Add method to retrieve string from SecureString
- Tds42.cs: Use SecureString for passwords
- Tds50.cs: Use SecureString for passwords
- Tds70.cs: Use SecureString for passwords
- TdsConnectionParameters.cs: Use SecureString for passwords; Initialize Password parameter as cleared string; Add indicator for when password is set
- SqlConnection.cs: Use SecureString for passwords; Add SqlConnect method that accepts an SqlCredential along with the Connection string; Perform checking of parameters to ensure user/password not specified in connection string if credentials have been specified or using credentials when domain login is specified.
- SqlCredential.cs: Add new class with support for credentials
- System.Data.dll.sources: Add SqlCredential.cs to the build list

Neale Ferguson 11 éve
szülő
commit
a83e9cf4aa

+ 17 - 1
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs

@@ -41,7 +41,9 @@ using System.ComponentModel;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Net.Sockets;
 using System.Net.Sockets;
 using System.Globalization;
 using System.Globalization;
+using System.Security;
 using System.Text;
 using System.Text;
+using System.Runtime.InteropServices;
 
 
 namespace Mono.Data.Tds.Protocol
 namespace Mono.Data.Tds.Protocol
 {
 {
@@ -1468,7 +1470,7 @@ namespace Mono.Data.Tds.Protocol
 			t3.Domain = this.connectionParms.DefaultDomain;
 			t3.Domain = this.connectionParms.DefaultDomain;
 			t3.Host = this.connectionParms.Hostname;
 			t3.Host = this.connectionParms.Hostname;
 			t3.Username = this.connectionParms.User;
 			t3.Username = this.connectionParms.User;
-			t3.Password = this.connectionParms.Password;
+			t3.Password = GetPlainPassword(this.connectionParms.Password);
 
 
 			Comm.StartPacket (TdsPacketType.SspAuth); // 0x11
 			Comm.StartPacket (TdsPacketType.SspAuth); // 0x11
 			Comm.Append (t3.GetBytes ());
 			Comm.Append (t3.GetBytes ());
@@ -1919,6 +1921,20 @@ namespace Mono.Data.Tds.Protocol
 			comm.Skip(4);
 			comm.Skip(4);
 		}
 		}
 
 
+		public static string GetPlainPassword(SecureString secPass)
+		{
+			IntPtr plainString = IntPtr.Zero;
+			try
+			{
+				plainString = Marshal.SecureStringToGlobalAllocUnicode(secPass);
+				return Marshal.PtrToStringUni(plainString);
+			}
+			finally
+			{
+				Marshal.ZeroFreeGlobalAllocUnicode(plainString);
+			}
+		}
+
 		#endregion // Private Methods
 		#endregion // Private Methods
 
 
 #if NET_2_0
 #if NET_2_0

+ 3 - 2
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds42.cs

@@ -29,6 +29,7 @@
 //
 //
 
 
 using System;
 using System;
+using System.Security;
 
 
 namespace Mono.Data.Tds.Protocol {
 namespace Mono.Data.Tds.Protocol {
         public sealed class Tds42 : Tds
         public sealed class Tds42 : Tds
@@ -77,7 +78,7 @@ namespace Mono.Data.Tds.Protocol {
 			Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 			Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
 
 			// password (offset 62 0x3e)
 			// password (offset 62 0x3e)
-			tmp = Comm.Append (connectionParameters.Password, 30, pad);
+			tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 30, pad);
 			Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 			Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
 
 			// hostproc (offset 93 0x5d)
 			// hostproc (offset 93 0x5d)
@@ -145,7 +146,7 @@ namespace Mono.Data.Tds.Protocol {
 
 
 			// remote passwords
 			// remote passwords
 			Comm.Append (empty, 2, pad);
 			Comm.Append (empty, 2, pad);
-			tmp = Comm.Append (connectionParameters.Password, 253, pad);
+			tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 253, pad);
 			Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
 			Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
 
 
 			// tds version
 			// tds version

+ 3 - 2
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds50.cs

@@ -31,6 +31,7 @@
 using Mono.Data.Tds;
 using Mono.Data.Tds;
 using System;
 using System;
 using System.Text;
 using System.Text;
+using System.Security;
 
 
 namespace Mono.Data.Tds.Protocol
 namespace Mono.Data.Tds.Protocol
 {
 {
@@ -118,7 +119,7 @@ namespace Mono.Data.Tds.Protocol
 
 
 			// password (offset 62 0x3e)
 			// password (offset 62 0x3e)
 			// 62-92
 			// 62-92
-			tmp = Comm.Append (connectionParameters.Password, 30, pad);
+			tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 30, pad);
 			Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 			Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
 
 			// hostproc (offset 93 0x5d)
 			// hostproc (offset 93 0x5d)
@@ -187,7 +188,7 @@ namespace Mono.Data.Tds.Protocol
 			// remote passwords
 			// remote passwords
 			// 202-457	
 			// 202-457	
 			Comm.Append (empty, 2, pad);
 			Comm.Append (empty, 2, pad);
-			tmp = Comm.Append (connectionParameters.Password, 253, pad);
+			tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 253, pad);
 			Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
 			Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
 
 
 			// tds version
 			// tds version

+ 4 - 2
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds70.cs

@@ -37,6 +37,7 @@
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 using System.Text;
 using System.Text;
+using System.Security;
 
 
 using Mono.Security.Protocol.Ntlm;
 using Mono.Security.Protocol.Ntlm;
 
 
@@ -392,11 +393,12 @@ namespace Mono.Data.Tds.Protocol
 			return IsConnected;
 			return IsConnected;
 		}
 		}
 
 
-		private static string EncryptPassword (string pass)
+		private static string EncryptPassword (SecureString secPass)
 		{
 		{
 			int xormask = 0x5a5a;
 			int xormask = 0x5a5a;
-			int len = pass.Length;
+			int len = secPass.Length;
 			char[] chars = new char[len];
 			char[] chars = new char[len];
+			string pass = GetPlainPassword(secPass);
 
 
 			for (int i = 0; i < len; ++i) {
 			for (int i = 0; i < len; ++i) {
 				int c = ((int) (pass[i])) ^ xormask;
 				int c = ((int) (pass[i])) ^ xormask;

+ 5 - 2
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionParameters.cs

@@ -31,6 +31,7 @@
 //
 //
 
 
 using System;
 using System;
+using System.Security;
 
 
 namespace Mono.Data.Tds.Protocol
 namespace Mono.Data.Tds.Protocol
 {
 {
@@ -42,7 +43,8 @@ namespace Mono.Data.Tds.Protocol
 		public string Hostname;
 		public string Hostname;
 		public string Language;
 		public string Language;
 		public string LibraryName;
 		public string LibraryName;
-		public string Password;
+		public SecureString Password;
+		public bool PasswordSet;
 		public string ProgName;
 		public string ProgName;
 		public string User;
 		public string User;
 		public bool DomainLogin;
 		public bool DomainLogin;
@@ -62,7 +64,8 @@ namespace Mono.Data.Tds.Protocol
 			Hostname = System.Net.Dns.GetHostName();
 			Hostname = System.Net.Dns.GetHostName();
 			Language = String.Empty;
 			Language = String.Empty;
 			LibraryName = "Mono";
 			LibraryName = "Mono";
-			Password = String.Empty;
+			Password = new SecureString();
+			PasswordSet = false;
 			ProgName = "Mono";
 			ProgName = "Mono";
 			User = String.Empty;
 			User = String.Empty;
 			DomainLogin = false; 
 			DomainLogin = false; 

+ 33 - 1
mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs

@@ -56,6 +56,7 @@ using System.Xml;
 #if NET_2_0
 #if NET_2_0
 using System.Collections.Generic;
 using System.Collections.Generic;
 #endif
 #endif
+using System.Security;
 
 
 namespace System.Data.SqlClient
 namespace System.Data.SqlClient
 {
 {
@@ -93,6 +94,9 @@ namespace System.Data.SqlClient
 		// The connection string that identifies this connection
 		// The connection string that identifies this connection
 		string connectionString;
 		string connectionString;
 
 
+		// The connection credentials
+		SqlCredential credentials;
+
 		// The transaction object for the current transaction
 		// The transaction object for the current transaction
 		SqlTransaction transaction;
 		SqlTransaction transaction;
 
 
@@ -133,6 +137,12 @@ namespace System.Data.SqlClient
 			ConnectionString = connectionString;
 			ConnectionString = connectionString;
 		}
 		}
 
 
+		public SqlConnection (string connectionString, SqlCredential cred)
+		{
+			ConnectionString = connectionString;
+			Credentials = cred;
+		}
+
 		#endregion // Constructors
 		#endregion // Constructors
 
 
 		#region Properties
 		#region Properties
@@ -155,6 +165,15 @@ namespace System.Data.SqlClient
 			}
 			}
 		}
 		}
 	
 	
+		public SqlCredential Credentials {
+			get {
+				return credentials;
+			}
+			set {
+				credentials = value;
+			}
+		}
+	
 #if !NET_2_0
 #if !NET_2_0
 		[DataSysDescription ("Current connection timeout value, 'Connect Timeout=X' in the ConnectionString.")]	
 		[DataSysDescription ("Current connection timeout value, 'Connect Timeout=X' in the ConnectionString.")]	
 #endif
 #endif
@@ -563,6 +582,16 @@ namespace System.Data.SqlClient
 
 
 			if (!tds.IsConnected) {
 			if (!tds.IsConnected) {
 				try {
 				try {
+					if (Credentials != null) {
+						if (parms.User != String.Empty)
+							throw new ArgumentException("UserID already specified");
+						if (parms.PasswordSet)
+							throw new ArgumentException("Password already specified");
+						if (parms.DomainLogin != false)
+							throw new ArgumentException("Cannot use credentials with DomainLogin");
+						parms.User = Credentials.UserId;
+						parms.Password = Credentials.Password;
+					}
 					tds.Connect (parms);
 					tds.Connect (parms);
 				} catch {
 				} catch {
 					if (pooling)
 					if (pooling)
@@ -879,7 +908,10 @@ namespace System.Data.SqlClient
 				break;
 				break;
 			case "password" :
 			case "password" :
 			case "pwd" :
 			case "pwd" :
-				parms.Password = value;
+				parms.Password = new SecureString();
+				foreach (char c in value)
+					parms.Password.AppendChar(c);
+				parms.PasswordSet = true;
 				break;
 				break;
 			case "persistsecurityinfo" :
 			case "persistsecurityinfo" :
 			case "persist security info" :
 			case "persist security info" :

+ 76 - 0
mcs/class/System.Data/System.Data.SqlClient/SqlCredential.cs

@@ -0,0 +1,76 @@
+//
+// System.Data.SqlClient.SqlCredential.cs
+//
+// Author:
+//   Neale Ferguson ([email protected])
+//
+// Copyright (C) Neale Ferguson, 2014
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Data;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace System.Data.SqlClient {
+	/// <summary>
+	/// Describes an error from a SQL database.
+	/// </summary>
+	[Serializable]
+	public sealed class SqlCredential
+	{
+		#region Fields
+
+		string uid = "";
+		SecureString pwd = null;
+
+		#endregion // Fields
+
+		#region Constructors
+
+		public SqlCredential (string user, SecureString password)
+		{
+			if (user == null)
+				throw new ArgumentNullException("UserID");
+			if (password == null)
+				throw new ArgumentNullException("Password");
+			this.uid = user;
+			this.pwd = password;
+		}
+
+		#endregion // Constructors
+		
+		#region Properties
+
+		public string UserId {
+			get { return uid; }
+		}
+
+		public SecureString Password {
+			get { return pwd; }
+		}
+
+		#endregion
+	}
+}

+ 1 - 0
mcs/class/System.Data/System.Data.dll.sources

@@ -289,6 +289,7 @@ System.Data.SqlClient/SqlCommand.cs
 System.Data.SqlClient/SqlCommandBuilder.cs
 System.Data.SqlClient/SqlCommandBuilder.cs
 System.Data.SqlClient/SqlConnection.cs
 System.Data.SqlClient/SqlConnection.cs
 System.Data.SqlClient/SqlConnectionStringBuilder.cs
 System.Data.SqlClient/SqlConnectionStringBuilder.cs
+System.Data.SqlClient/SqlCredential.cs
 System.Data.SqlClient/SqlDataAdapter.cs
 System.Data.SqlClient/SqlDataAdapter.cs
 System.Data.SqlClient/SqlDataReader.cs
 System.Data.SqlClient/SqlDataReader.cs
 System.Data.SqlClient/SqlDataSourceConverter.cs
 System.Data.SqlClient/SqlDataSourceConverter.cs