1- using Microsoft . Win32 . SafeHandles ;
2- using System ;
3- using System . Collections . Generic ;
1+ using System ;
42using System . ComponentModel ;
5- using System . Linq ;
3+ using System . Diagnostics ;
64using System . Net ;
75using System . Runtime . InteropServices ;
86using System . Text ;
9- using System . Threading . Tasks ;
107
118namespace AdysTech . CredentialManager
129{
@@ -20,14 +17,15 @@ public static class CredentialManager
2017 /// Opens OS Version specific Window prompting for credentials
2118 /// </summary>
2219 /// <param name="Target">A descriptive text for where teh credentials being asked are used for</param>
20+ /// <param name="save">Whether or not to offer the checkbox to save the credentials</param>
2321 /// <returns>NetworkCredential object containing the user name, </returns>
24- public static NetworkCredential PromptForCredentials ( string Target )
22+ public static NetworkCredential PromptForCredentials ( string Target , ref bool save )
2523 {
2624 var username = String . Empty ;
2725 var passwd = String . Empty ;
2826 var domain = String . Empty ;
2927
30- if ( ! PromptForCredentials ( Target , out username , out passwd , out domain ) )
28+ if ( ! PromptForCredentials ( Target , ref save , out username , out passwd , out domain ) )
3129 return null ;
3230 return new NetworkCredential ( username , passwd , domain ) ;
3331 }
@@ -36,73 +34,165 @@ public static NetworkCredential PromptForCredentials(string Target)
3634 /// Opens OS Version specific Window prompting for credentials
3735 /// </summary>
3836 /// <param name="Target">A descriptive text for where teh credentials being asked are used for</param>
37+ /// <param name="save">Whether or not to offer the checkbox to save the credentials</param>
3938 /// <param name="Message">A brief message to display in the dialog box</param>
4039 /// <param name="Caption">Title for the dialog box</param>
4140 /// <returns>NetworkCredential object containing the user name, </returns>
42- public static NetworkCredential PromptForCredentials ( string Target , string Message , string Caption )
41+ public static NetworkCredential PromptForCredentials ( string Target , ref bool save , string Message , string Caption )
4342 {
4443 var username = String . Empty ;
4544 var passwd = String . Empty ;
4645 var domain = String . Empty ;
4746
48- if ( ! PromptForCredentials ( Target , Message , Caption , out username , out passwd , out domain ) )
47+ if ( ! PromptForCredentials ( Target , ref save , Message , Caption , out username , out passwd , out domain ) )
4948 return null ;
5049 return new NetworkCredential ( username , passwd , domain ) ;
5150 }
5251
53- internal static bool PromptForCredentials ( string target , out string user , out string password , out string domain )
52+ internal static bool PromptForCredentials ( string target , ref bool save , out string user , out string password , out string domain )
5453 {
55- return PromptForCredentials ( target , new NativeStructs . CredentialUIInfo ( ) , out user , out password , out domain ) ;
54+ return PromptForCredentials ( target , new NativeCode . CredentialUIInfo ( ) , ref save , out user , out password , out domain ) ;
5655 }
5756
58- internal static bool PromptForCredentials ( string target , string Message , string Caption , out string user , out string password , out string domain )
57+ internal static bool PromptForCredentials ( string target , ref bool save , string Message , string Caption , out string user , out string password , out string domain )
5958 {
60- NativeStructs . CredentialUIInfo credUI = new NativeStructs . CredentialUIInfo ( ) ;
59+ NativeCode . CredentialUIInfo credUI = new NativeCode . CredentialUIInfo ( ) ;
6160 credUI . pszMessageText = Message ;
6261 credUI . pszCaptionText = Caption ;
63- return PromptForCredentials ( target , credUI , out user , out password , out domain ) ;
62+ return PromptForCredentials ( target , credUI , ref save , out user , out password , out domain ) ;
6463 }
6564
66- private static bool PromptForCredentials ( string target , NativeStructs . CredentialUIInfo credUI , out string user , out string password , out string domain )
65+ private static bool PromptForCredentials ( string target , NativeCode . CredentialUIInfo credUI , ref bool save , out string user , out string password , out string domain )
6766 {
67+ user = String . Empty ;
68+ password = String . Empty ;
69+ domain = String . Empty ;
70+
71+
72+
6873 // Setup the flags and variables
69- StringBuilder userPassword = new StringBuilder ( ) , userID = new StringBuilder ( ) ;
7074 credUI . cbSize = Marshal . SizeOf ( credUI ) ;
75+ int errorcode = 0 ;
76+ uint dialogReturn ;
77+ uint authPackage = 0 ;
78+
79+ IntPtr outCredBuffer = new IntPtr ( ) ;
80+ uint outCredSize ;
81+ var flags = NativeCode . PromptForWindowsCredentialsFlags . GenericCredentials | NativeCode . PromptForWindowsCredentialsFlags . EnumerateCurrentUser ;
82+ flags = save ? flags | NativeCode . PromptForWindowsCredentialsFlags . ShowCheckbox : flags ;
83+
84+ // Setup the flags and variables
85+ int result = NativeCode . CredUIPromptForWindowsCredentials ( ref credUI ,
86+ errorcode ,
87+ ref authPackage ,
88+ IntPtr . Zero ,
89+ 0 ,
90+ out outCredBuffer ,
91+ out outCredSize ,
92+ ref save ,
93+ flags ) ;
94+
95+ var usernameBuf = new StringBuilder ( 100 ) ;
96+ var passwordBuf = new StringBuilder ( 100 ) ;
97+ var domainBuf = new StringBuilder ( 100 ) ;
98+
99+ int maxUserName = 100 ;
100+ int maxDomain = 100 ;
101+ int maxPassword = 100 ;
102+ if ( result == 0 )
103+ {
104+ if ( NativeCode . CredUnPackAuthenticationBuffer ( 0 , outCredBuffer , outCredSize , usernameBuf , ref maxUserName ,
105+ domainBuf , ref maxDomain , passwordBuf , ref maxPassword ) )
106+ {
107+ user = usernameBuf . ToString ( ) ;
108+ password = passwordBuf . ToString ( ) ;
109+ domain = domainBuf . ToString ( ) ;
110+ if ( String . IsNullOrWhiteSpace ( domain ) )
111+ {
112+ Debug . WriteLine ( "Domain null" ) ;
113+ if ( ! ParseUserName ( usernameBuf . ToString ( ) , maxUserName , maxDomain , out user , out password ) )
114+ user = usernameBuf . ToString ( ) ;
115+ }
116+ }
117+
118+ //mimic SecureZeroMem function to make sure buffer is zeroed out. SecureZeroMem is not an exported function, neither is RtlSecureZeroMemory
119+ var zeroBytes = new byte [ outCredSize ] ;
120+ Marshal . Copy ( zeroBytes , 0 , outCredBuffer , ( int ) outCredSize ) ;
121+
122+ //clear the memory allocated by CredUIPromptForWindowsCredentials
123+ NativeCode . CoTaskMemFree ( outCredBuffer ) ;
124+ return true ;
125+ }
126+
127+ user = null ;
128+ domain = null ;
129+ return false ;
130+ }
131+
132+ private static bool ParseUserName ( string usernameBuf , int maxUserName , int maxDomain , out string user , out string domain )
133+ {
134+ StringBuilder userBuilder = new StringBuilder ( ) ;
135+ StringBuilder domainBuilder = new StringBuilder ( ) ;
136+ user = String . Empty ;
137+ domain = String . Empty ;
138+
139+ var returnCode = NativeCode . CredUIParseUserName ( usernameBuf , userBuilder , maxUserName , domainBuilder , maxDomain ) ;
140+ Debug . WriteLine ( returnCode ) ;
141+ switch ( returnCode )
142+ {
143+ case NativeCode . CredentialUIReturnCodes . Success : // The username is valid.
144+ user = userBuilder . ToString ( ) ;
145+ domain = domainBuilder . ToString ( ) ;
146+ return true ;
147+ }
148+ return false ;
149+ }
150+
151+ /// <summary>
152+ /// Accepts credentials in a console window
153+ /// </summary>
154+ /// <param name="Target">A descriptive text for where teh credentials being asked are used for</param>
155+ /// <returns>NetworkCredential object containing the user name, </returns>
156+ public static NetworkCredential PromptForCredentialsConsole ( string target )
157+ {
158+ var user = String . Empty ;
159+ var password = String . Empty ;
160+ var domain = String . Empty ;
161+
162+ // Setup the flags and variables
163+ StringBuilder userPassword = new StringBuilder ( ) , userID = new StringBuilder ( ) ;
71164 bool save = true ;
72- NativeStructs . CredentialUIFlags flags = NativeStructs . CredentialUIFlags . COMPLETE_USERNAME | NativeStructs . CredentialUIFlags . PERSIST | NativeStructs . CredentialUIFlags . EXCLUDE_CERTIFICATES ;
165+ NativeCode . CredentialUIFlags flags = NativeCode . CredentialUIFlags . CompleteUsername | NativeCode . CredentialUIFlags . ExcludeCertificates ;
73166
74167 // Prompt the user
75- NativeStructs . CredentialUIReturnCodes returnCode = NativeStructs . CredUIPromptForCredentials ( ref credUI , target , IntPtr . Zero , 0 , userID , 100 , userPassword , 100 , ref save , flags ) ;
168+ NativeCode . CredentialUIReturnCodes returnCode = NativeCode . CredUICmdLinePromptForCredentials ( target , IntPtr . Zero , 0 , userID , 100 , userPassword , 100 , ref save , flags ) ;
76169
77170 password = userPassword . ToString ( ) ;
78171
79172 StringBuilder userBuilder = new StringBuilder ( ) ;
80173 StringBuilder domainBuilder = new StringBuilder ( ) ;
81174
82- returnCode = NativeStructs . CredUIParseUserName ( userID . ToString ( ) , userBuilder , int . MaxValue , domainBuilder , int . MaxValue ) ;
175+ returnCode = NativeCode . CredUIParseUserName ( userID . ToString ( ) , userBuilder , int . MaxValue , domainBuilder , int . MaxValue ) ;
83176 switch ( returnCode )
84177 {
85- case NativeStructs . CredentialUIReturnCodes . NO_ERROR : // The username is valid.
178+ case NativeCode . CredentialUIReturnCodes . Success : // The username is valid.
86179 user = userBuilder . ToString ( ) ;
87180 domain = domainBuilder . ToString ( ) ;
88- return true ;
181+ break ;
89182
90- case NativeStructs . CredentialUIReturnCodes . ERROR_INVALID_ACCOUNT_NAME : // The username is not valid.
183+ case NativeCode . CredentialUIReturnCodes . InvalidAccountName : // The username is not valid.
91184 user = userID . ToString ( ) ;
92185 domain = null ;
93- return false ;
186+ break ;
94187
95- case NativeStructs . CredentialUIReturnCodes . ERROR_INSUFFICIENT_BUFFER : // One of the buffers is too small.
188+ case NativeCode . CredentialUIReturnCodes . InsufficientBuffer : // One of the buffers is too small.
96189 throw new OutOfMemoryException ( ) ;
97190
98- case NativeStructs . CredentialUIReturnCodes . ERROR_INVALID_PARAMETER : // ulUserMaxChars or ulDomainMaxChars is zero OR userName, user, or domain is NULL.
191+ case NativeCode . CredentialUIReturnCodes . InvalidParameter : // ulUserMaxChars or ulDomainMaxChars is zero OR userName, user, or domain is NULL.
99192 throw new ArgumentNullException ( "userName" ) ;
100193
101- default :
102- user = null ;
103- domain = null ;
104- return false ;
105194 }
195+ return new NetworkCredential ( user , password , domain ) ;
106196 }
107197
108198
@@ -118,10 +208,10 @@ public static bool SaveCredentials(string Target, NetworkCredential credential)
118208 // Go ahead with what we have are stuff it into the CredMan structures.
119209 Credential cred = new Credential ( credential ) ;
120210 cred . TargetName = Target ;
121- cred . Persist = NativeStructs . Persistance . ENTERPRISE ;
122- NativeStructs . NativeCredential ncred = cred . GetNativeCredential ( ) ;
211+ cred . Persist = NativeCode . Persistance . Entrprise ;
212+ NativeCode . NativeCredential ncred = cred . GetNativeCredential ( ) ;
123213 // Write the info into the CredMan storage.
124- bool written = NativeStructs . CredWrite ( ref ncred , 0 ) ;
214+ bool written = NativeCode . CredWrite ( ref ncred , 0 ) ;
125215 int lastError = Marshal . GetLastWin32Error ( ) ;
126216 if ( written )
127217 {
@@ -148,7 +238,7 @@ public static NetworkCredential GetCredentials(string Target)
148238 var domain = String . Empty ;
149239
150240 // Make the API call using the P/Invoke signature
151- bool ret = NativeStructs . CredRead ( Target , NativeStructs . CredentialType . GENERIC , 0 , out nCredPtr ) ;
241+ bool ret = NativeCode . CredRead ( Target , NativeCode . CredentialType . Generic , 0 , out nCredPtr ) ;
152242 int lastError = Marshal . GetLastWin32Error ( ) ;
153243 if ( ! ret )
154244 throw new Win32Exception ( lastError , "CredDelete throw an error" ) ;
@@ -163,12 +253,12 @@ public static NetworkCredential GetCredentials(string Target)
163253 var user = cred . UserName ;
164254 StringBuilder userBuilder = new StringBuilder ( ) ;
165255 StringBuilder domainBuilder = new StringBuilder ( ) ;
166- var ret1 = NativeStructs . CredUIParseUserName ( user , userBuilder , int . MaxValue , domainBuilder , int . MaxValue ) ;
256+ var ret1 = NativeCode . CredUIParseUserName ( user , userBuilder , int . MaxValue , domainBuilder , int . MaxValue ) ;
167257 lastError = Marshal . GetLastWin32Error ( ) ;
168258
169259 //assuming invalid account name to be not meeting condition for CredUIParseUserName
170260 //"The name must be in UPN or down-level format, or a certificate"
171- if ( ret1 == NativeStructs . CredentialUIReturnCodes . ERROR_INVALID_ACCOUNT_NAME )
261+ if ( ret1 == NativeCode . CredentialUIReturnCodes . InvalidAccountName )
172262 userBuilder . Append ( user ) ;
173263 else if ( ( uint ) ret1 > 0 )
174264 throw new Win32Exception ( lastError , "CredUIParseUserName throw an error" ) ;
@@ -190,7 +280,7 @@ public static NetworkCredential GetCredentials(string Target)
190280 public static bool RemoveCredentials ( string Target )
191281 {
192282 // Make the API call using the P/Invoke signature
193- var ret = NativeStructs . CredDelete ( Target , NativeStructs . CredentialType . GENERIC , 0 ) ;
283+ var ret = NativeCode . CredDelete ( Target , NativeCode . CredentialType . Generic , 0 ) ;
194284 int lastError = Marshal . GetLastWin32Error ( ) ;
195285 if ( ! ret )
196286 throw new Win32Exception ( lastError , "CredDelete throw an error" ) ;
0 commit comments