Friday, October 20, 2006 4:29 PM bart

Reset the password of a SQL Server account programmatically - SecureString real world demo

Simple question today: "How to change the password of a SQL Server account programmatically using .NET?". The answer: Microsoft.SqlServer.Management.Common.

Create a simple Console Application project and add a reference to the Microsoft.SqlServer.ConnectionInfo.dll assembly (should be listed on your machine if you've installed any flavor of SQL Server 2005).

Here's the code of our password change tool:


using System; using System.Security; using System.Runtime.InteropServices; using Microsoft.SqlServer.Management.Common; namespace SqlResetPwd { class Program { static void Main(string[] args) { Console.WriteLine("Reset SQL Server password"); Console.WriteLine("-------------------------\n"); Console.Write("Server name: "); string instance = Console.ReadLine(); Console.Write("User name: "); string user = Console.ReadLine(); Console.Write("Password: "); SecureString pwd = AskPassword(); Console.WriteLine(); Console.WriteLine(); Console.Write("Trying to connect... "); ServerConnection conn = new ServerConnection(instance, user, pwd); try { conn.Connect(); Console.WriteLine("Connected."); Console.WriteLine(); conn.Disconnect(); conn = new ServerConnection(instance, user, pwd); SecureString newPwd, conPwd; while (true) { Console.Write("New password: "); newPwd = AskPassword(); Console.WriteLine(); Console.Write("Confirm: "); conPwd = AskPassword(); Console.WriteLine(); if (!Match(newPwd, conPwd)) { Console.WriteLine("The specified passwords do not match. Please try again."); } else { try { conn.ChangePassword(newPwd); break; } catch (Exception ex) { Console.WriteLine("Failed to change password. " + ex.Message); } } } Console.WriteLine(); Console.WriteLine("Password changed successfully."); } catch (ConnectionFailureException ex) { Console.WriteLine((ex.InnerException != null ? ex.InnerException.Message : "Failed.")); } finally { conn.SqlConnectionObject.Close(); } } static SecureString AskPassword() { SecureString pwd = new SecureString(); while (true) { ConsoleKeyInfo i = Console.ReadKey(true); if (i.Key == ConsoleKey.Enter) { break; } else if (i.Key == ConsoleKey.Backspace) { pwd.RemoveAt(pwd.Length - 1); Console.Write("\b \b"); } else { pwd.AppendChar(i.KeyChar); Console.Write("*"); } } return pwd; } unsafe static bool Match(SecureString s1, SecureString s2) { if (s1.Length != s2.Length) return false; IntPtr bs1 = Marshal.SecureStringToBSTR(s1); IntPtr bs2 = Marshal.SecureStringToBSTR(s2); char* ps1 = (char*) bs1.ToPointer(); char* ps2 = (char*) bs2.ToPointer(); try { for (int i = 0; i < s1.Length; i++) if (ps1[i] != ps2[i]) return false; return true; } finally { if (IntPtr.Zero != bs1) Marshal.ZeroFreeBSTR(bs1); if (IntPtr.Zero != bs2) Marshal.ZeroFreeBSTR(bs2); } } } }


A few interesting things to mention:

  • The AskPassword method uses Console.ReadKey(true) to get one key stroke at a time, without printing the character to the console (the "true" parameter takes care of that). If the key is <ENTER>, the loop stops. If it is <BACKSPACE>, the last character is removed from the SecureString password and a backspace-space-backspace sequence is printed to the console to remove the last * character. Otherwise, the key character is appended to the SecureString password and an * character is printed on the screen.
  • Match compares two SecureStrings with one another. To do so, it uses unsafe code to iterate over the SecureString. By doing so, no System.String ends up in the managed heap, which keeps things more secure than they would be in such a case. That's the end goal of SecureString after all.
  • The ServerConnection class can be used to reset a password and knows about SecureString to deal with passwords, which is just great.

For more information on SecureString, see my "Talking about System.Security.SecureString" blog post too.

Have fun!

kick it on | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under: , ,


No Comments