- 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
using System.Diagnostics;
using System.Net.Sockets;
using System.Globalization;
+using System.Security;
using System.Text;
+using System.Runtime.InteropServices;
namespace Mono.Data.Tds.Protocol
{
t3.Domain = this.connectionParms.DefaultDomain;
t3.Host = this.connectionParms.Hostname;
t3.Username = this.connectionParms.User;
- t3.Password = this.connectionParms.Password;
+ t3.Password = GetPlainPassword(this.connectionParms.Password);
Comm.StartPacket (TdsPacketType.SspAuth); // 0x11
Comm.Append (t3.GetBytes ());
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
#if NET_2_0
//
using System;
+using System.Security;
namespace Mono.Data.Tds.Protocol {
public sealed class Tds42 : Tds
Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
// 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));
// hostproc (offset 93 0x5d)
// remote passwords
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));
// tds version
using Mono.Data.Tds;
using System;
using System.Text;
+using System.Security;
namespace Mono.Data.Tds.Protocol
{
// password (offset 62 0x3e)
// 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));
// hostproc (offset 93 0x5d)
// remote passwords
// 202-457
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));
// tds version
using System;
using System.Globalization;
using System.Text;
+using System.Security;
using Mono.Security.Protocol.Ntlm;
return IsConnected;
}
- private static string EncryptPassword (string pass)
+ private static string EncryptPassword (SecureString secPass)
{
int xormask = 0x5a5a;
- int len = pass.Length;
+ int len = secPass.Length;
char[] chars = new char[len];
+ string pass = GetPlainPassword(secPass);
for (int i = 0; i < len; ++i) {
int c = ((int) (pass[i])) ^ xormask;
//
using System;
+using System.Security;
namespace Mono.Data.Tds.Protocol
{
public string Hostname;
public string Language;
public string LibraryName;
- public string Password;
+ public SecureString Password;
+ public bool PasswordSet;
public string ProgName;
public string User;
public bool DomainLogin;
Hostname = System.Net.Dns.GetHostName();
Language = String.Empty;
LibraryName = "Mono";
- Password = String.Empty;
+ Password = new SecureString();
+ PasswordSet = false;
ProgName = "Mono";
User = String.Empty;
DomainLogin = false;
#if NET_2_0
using System.Collections.Generic;
#endif
+using System.Security;
namespace System.Data.SqlClient
{
// The connection string that identifies this connection
string connectionString;
+ // The connection credentials
+ SqlCredential credentials;
+
// The transaction object for the current transaction
SqlTransaction transaction;
ConnectionString = connectionString;
}
+ public SqlConnection (string connectionString, SqlCredential cred)
+ {
+ ConnectionString = connectionString;
+ Credentials = cred;
+ }
+
#endregion // Constructors
#region Properties
}
}
+ public SqlCredential Credentials {
+ get {
+ return credentials;
+ }
+ set {
+ credentials = value;
+ }
+ }
+
#if !NET_2_0
[DataSysDescription ("Current connection timeout value, 'Connect Timeout=X' in the ConnectionString.")]
#endif
if (!tds.IsConnected) {
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);
} catch {
if (pooling)
break;
case "password" :
case "pwd" :
- parms.Password = value;
+ parms.Password = new SecureString();
+ foreach (char c in value)
+ parms.Password.AppendChar(c);
+ parms.PasswordSet = true;
break;
case "persistsecurityinfo" :
case "persist security info" :
--- /dev/null
+//
+// System.Data.SqlClient.SqlCredential.cs
+//
+// Author:
+// Neale Ferguson (neale@sinenomine.net)
+//
+// 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
+ }
+}
System.Data.SqlClient/SqlCommandBuilder.cs
System.Data.SqlClient/SqlConnection.cs
System.Data.SqlClient/SqlConnectionStringBuilder.cs
+System.Data.SqlClient/SqlCredential.cs
System.Data.SqlClient/SqlDataAdapter.cs
System.Data.SqlClient/SqlDataReader.cs
System.Data.SqlClient/SqlDataSourceConverter.cs