Skip to content

Commit 1959498

Browse files
committed
Initial commit
1 parent 3f55331 commit 1959498

File tree

10 files changed

+722
-0
lines changed

10 files changed

+722
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{ABA77D40-8D43-42EE-BE03-44E4AD93672A}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>AdysTech.CredentialManager</RootNamespace>
11+
<AssemblyName>AdysTech.CredentialManager</AssemblyName>
12+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
</PropertyGroup>
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16+
<DebugSymbols>true</DebugSymbols>
17+
<DebugType>full</DebugType>
18+
<Optimize>false</Optimize>
19+
<OutputPath>bin\Debug\</OutputPath>
20+
<DefineConstants>DEBUG;TRACE</DefineConstants>
21+
<ErrorReport>prompt</ErrorReport>
22+
<WarningLevel>4</WarningLevel>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25+
<DebugType>pdbonly</DebugType>
26+
<Optimize>true</Optimize>
27+
<OutputPath>bin\Release\</OutputPath>
28+
<DefineConstants>TRACE</DefineConstants>
29+
<ErrorReport>prompt</ErrorReport>
30+
<WarningLevel>4</WarningLevel>
31+
</PropertyGroup>
32+
<ItemGroup>
33+
<Reference Include="System" />
34+
<Reference Include="System.Core" />
35+
<Reference Include="System.Xml.Linq" />
36+
<Reference Include="System.Data.DataSetExtensions" />
37+
<Reference Include="Microsoft.CSharp" />
38+
<Reference Include="System.Data" />
39+
<Reference Include="System.Xml" />
40+
</ItemGroup>
41+
<ItemGroup>
42+
<Compile Include="Credential.cs" />
43+
<Compile Include="CredentialManager.cs" />
44+
<Compile Include="NativeStructs.cs" />
45+
<Compile Include="CriticalCredentialHandle.cs" />
46+
<Compile Include="Properties\AssemblyInfo.cs" />
47+
</ItemGroup>
48+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
49+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
50+
Other similar extension points exist, see Microsoft.Common.targets.
51+
<Target Name="BeforeBuild">
52+
</Target>
53+
<Target Name="AfterBuild">
54+
</Target>
55+
-->
56+
</Project>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Runtime.InteropServices;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace AdysTech.CredentialManager
9+
{
10+
internal class Credential
11+
{
12+
public UInt32 Flags;
13+
public NativeStructs.CredentialType Type;
14+
public string TargetName;
15+
public string Comment;
16+
public DateTime LastWritten;
17+
public UInt32 CredentialBlobSize;
18+
public string CredentialBlob;
19+
public NativeStructs.Persistance Persist;
20+
public UInt32 AttributeCount;
21+
public IntPtr Attributes;
22+
public string TargetAlias;
23+
public string UserName;
24+
25+
public Credential()
26+
{
27+
28+
}
29+
30+
internal Credential(NativeStructs.NativeCredential ncred)
31+
{
32+
CredentialBlobSize = ncred.CredentialBlobSize;
33+
CredentialBlob = Marshal.PtrToStringUni (ncred.CredentialBlob,
34+
(int) ncred.CredentialBlobSize / 2);
35+
UserName = Marshal.PtrToStringUni (ncred.UserName);
36+
TargetName = Marshal.PtrToStringUni (ncred.TargetName);
37+
TargetAlias = Marshal.PtrToStringUni (ncred.TargetAlias);
38+
Type = ncred.Type;
39+
Flags = ncred.Flags;
40+
Persist = (NativeStructs.Persistance) ncred.Persist;
41+
LastWritten = DateTime.FromFileTime ((long) ( (ulong) ncred.LastWritten.dwHighDateTime << 32 | (ulong) ncred.LastWritten.dwLowDateTime ));
42+
}
43+
44+
public Credential(System.Net.NetworkCredential credential)
45+
{
46+
CredentialBlob = credential.Password;
47+
UserName = String.IsNullOrWhiteSpace (credential.Domain) ? credential.UserName : credential.Domain + "\\" + credential.UserName;
48+
CredentialBlobSize = (UInt32) Encoding.Unicode.GetBytes (credential.Password).Length;
49+
AttributeCount = 0;
50+
Attributes = IntPtr.Zero;
51+
Comment = null;
52+
TargetAlias = null;
53+
Type = NativeStructs.CredentialType.GENERIC;
54+
Persist = NativeStructs.Persistance.SESSION;
55+
}
56+
57+
/// <summary>
58+
/// This method derives a NativeCredential instance from a given Credential instance.
59+
/// </summary>
60+
/// <param name="cred">The managed Credential counterpart containing data to be stored.</param>
61+
/// <returns>A NativeCredential instance that is derived from the given Credential
62+
/// instance.</returns>
63+
internal NativeStructs.NativeCredential GetNativeCredential()
64+
{
65+
NativeStructs.NativeCredential ncred = new NativeStructs.NativeCredential ();
66+
ncred.AttributeCount = 0;
67+
ncred.Attributes = IntPtr.Zero;
68+
ncred.Comment = IntPtr.Zero;
69+
ncred.TargetAlias = IntPtr.Zero;
70+
ncred.Type = this.Type;
71+
ncred.Persist = (UInt32) this.Persist;
72+
ncred.UserName = Marshal.StringToCoTaskMemUni (this.UserName);
73+
ncred.TargetName = Marshal.StringToCoTaskMemUni (this.TargetName);
74+
ncred.CredentialBlob = Marshal.StringToCoTaskMemUni (this.CredentialBlob);
75+
ncred.CredentialBlobSize = (UInt32) this.CredentialBlobSize;
76+
if ( this.LastWritten != DateTime.MinValue )
77+
{
78+
var fileTime = this.LastWritten.ToFileTimeUtc ();
79+
ncred.LastWritten.dwLowDateTime = (int) ( fileTime & 0xFFFFFFFFL );
80+
ncred.LastWritten.dwHighDateTime = (int) ( ( fileTime >> 32 ) & 0xFFFFFFFFL );
81+
}
82+
return ncred;
83+
}
84+
}
85+
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
using Microsoft.Win32.SafeHandles;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.ComponentModel;
5+
using System.Linq;
6+
using System.Net;
7+
using System.Runtime.InteropServices;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace AdysTech.CredentialManager
12+
{
13+
14+
//ref: http://blogs.msdn.com/b/peerchan/archive/2005/11/01/487834.aspx
15+
16+
public static class CredentialManager
17+
{
18+
19+
20+
public static NetworkCredential PromptForCredentials(string Target)
21+
{
22+
var username = String.Empty;
23+
var passwd = String.Empty;
24+
var domain = String.Empty;
25+
26+
if ( !PromptForCredentials (Target, out username, out passwd, out domain) )
27+
return null;
28+
return new NetworkCredential (username, passwd, domain);
29+
}
30+
31+
public static NetworkCredential PromptForCredentials(string Target, string Message, string Caption)
32+
{
33+
var username = String.Empty;
34+
var passwd = String.Empty;
35+
var domain = String.Empty;
36+
37+
if ( !PromptForCredentials (Target, Message, Caption, out username, out passwd, out domain) )
38+
return null;
39+
return new NetworkCredential (username, passwd, domain);
40+
}
41+
42+
internal static bool PromptForCredentials(string target, out string user, out string password, out string domain)
43+
{
44+
return PromptForCredentials (target, new NativeStructs.CredentialUIInfo (), out user, out password, out domain);
45+
}
46+
47+
internal static bool PromptForCredentials(string target, string Message, string Caption, out string user, out string password, out string domain)
48+
{
49+
NativeStructs.CredentialUIInfo credUI = new NativeStructs.CredentialUIInfo ();
50+
credUI.pszMessageText = Message;
51+
credUI.pszCaptionText = Caption;
52+
return PromptForCredentials (target, credUI, out user, out password, out domain);
53+
}
54+
55+
private static bool PromptForCredentials(string target, NativeStructs.CredentialUIInfo credUI, out string user, out string password, out string domain)
56+
{
57+
// Setup the flags and variables
58+
StringBuilder userPassword = new StringBuilder (), userID = new StringBuilder ();
59+
credUI.cbSize = Marshal.SizeOf (credUI);
60+
bool save = true;
61+
NativeStructs.CredentialUIFlags flags = NativeStructs.CredentialUIFlags.COMPLETE_USERNAME | NativeStructs.CredentialUIFlags.PERSIST | NativeStructs.CredentialUIFlags.EXCLUDE_CERTIFICATES;
62+
63+
// Prompt the user
64+
NativeStructs.CredentialUIReturnCodes returnCode = NativeStructs.CredUIPromptForCredentials (ref credUI, target, IntPtr.Zero, 0, userID, 100, userPassword, 100, ref save, flags);
65+
66+
password = userPassword.ToString ();
67+
68+
StringBuilder userBuilder = new StringBuilder ();
69+
StringBuilder domainBuilder = new StringBuilder ();
70+
71+
returnCode = NativeStructs.CredUIParseUserName (userID.ToString (), userBuilder, int.MaxValue, domainBuilder, int.MaxValue);
72+
switch ( returnCode )
73+
{
74+
case NativeStructs.CredentialUIReturnCodes.NO_ERROR: // The username is valid.
75+
user = userBuilder.ToString ();
76+
domain = domainBuilder.ToString ();
77+
return true;
78+
79+
case NativeStructs.CredentialUIReturnCodes.ERROR_INVALID_ACCOUNT_NAME: // The username is not valid.
80+
user = userID.ToString ();
81+
domain = null;
82+
return false;
83+
84+
case NativeStructs.CredentialUIReturnCodes.ERROR_INSUFFICIENT_BUFFER: // One of the buffers is too small.
85+
throw new OutOfMemoryException ();
86+
87+
case NativeStructs.CredentialUIReturnCodes.ERROR_INVALID_PARAMETER: // ulUserMaxChars or ulDomainMaxChars is zero OR userName, user, or domain is NULL.
88+
throw new ArgumentNullException ("userName");
89+
90+
default:
91+
user = null;
92+
domain = null;
93+
return false;
94+
}
95+
}
96+
97+
98+
99+
100+
public static bool SaveCredentials(string Target, NetworkCredential credential)
101+
{
102+
// Go ahead with what we have are stuff it into the CredMan structures.
103+
Credential cred = new Credential (credential);
104+
cred.TargetName = Target;
105+
cred.Persist = NativeStructs.Persistance.ENTERPRISE;
106+
NativeStructs.NativeCredential ncred = cred.GetNativeCredential ();
107+
// Write the info into the CredMan storage.
108+
bool written = NativeStructs.CredWrite (ref ncred, 0);
109+
int lastError = Marshal.GetLastWin32Error ();
110+
if ( written )
111+
{
112+
return true;
113+
}
114+
else
115+
{
116+
string message = string.Format ("CredWrite failed with the error code {0}.", lastError);
117+
throw new Exception (message);
118+
}
119+
}
120+
121+
public static NetworkCredential GetCredentials(string Target)
122+
{
123+
IntPtr nCredPtr;
124+
var username = String.Empty;
125+
var passwd = String.Empty;
126+
var domain = String.Empty;
127+
128+
// Make the API call using the P/Invoke signature
129+
bool ret = NativeStructs.CredRead (Target, NativeStructs.CredentialType.GENERIC, 0, out nCredPtr);
130+
int lastError = Marshal.GetLastWin32Error ();
131+
if ( !ret )
132+
throw new Win32Exception (lastError, "CredDelete throw an error");
133+
134+
// If the API was successful then...
135+
if ( ret )
136+
{
137+
using ( CriticalCredentialHandle critCred = new CriticalCredentialHandle (nCredPtr) )
138+
{
139+
Credential cred = critCred.GetCredential ();
140+
passwd = cred.CredentialBlob;
141+
var user = cred.UserName;
142+
StringBuilder userBuilder = new StringBuilder ();
143+
StringBuilder domainBuilder = new StringBuilder ();
144+
NativeStructs.CredUIParseUserName (user, userBuilder, int.MaxValue, domainBuilder, int.MaxValue);
145+
username = userBuilder.ToString ();
146+
domain = domainBuilder.ToString ();
147+
return new NetworkCredential (username, passwd, domain);
148+
}
149+
}
150+
return null;
151+
}
152+
153+
public static bool RemoveCredentials(string Target)
154+
{
155+
// Make the API call using the P/Invoke signature
156+
var ret = NativeStructs.CredDelete (Target, NativeStructs.CredentialType.GENERIC, 0);
157+
int lastError = Marshal.GetLastWin32Error ();
158+
if ( !ret )
159+
throw new Win32Exception (lastError, "CredDelete throw an error");
160+
return ret;
161+
}
162+
163+
public static string GetBasicAuthString(this NetworkCredential cred)
164+
{
165+
byte[] credentialBuffer = new UTF8Encoding ().GetBytes (cred.UserName + ":" + cred.Password);
166+
return Convert.ToBase64String (credentialBuffer);
167+
}
168+
}
169+
}
170+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Microsoft.Win32.SafeHandles;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Runtime.InteropServices;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
9+
namespace AdysTech.CredentialManager
10+
{
11+
sealed class CriticalCredentialHandle : CriticalHandleZeroOrMinusOneIsInvalid
12+
{
13+
// Set the handle.
14+
internal CriticalCredentialHandle(IntPtr preexistingHandle)
15+
{
16+
SetHandle (preexistingHandle);
17+
}
18+
19+
internal Credential GetCredential()
20+
{
21+
if ( !IsInvalid )
22+
{
23+
// Get the Credential from the mem location
24+
NativeStructs.NativeCredential ncred = (NativeStructs.NativeCredential) Marshal.PtrToStructure (handle,
25+
typeof (NativeStructs.NativeCredential));
26+
27+
// Create a managed Credential type and fill it with data from the native counterpart.
28+
Credential cred = new Credential (ncred);
29+
30+
return cred;
31+
}
32+
else
33+
{
34+
throw new InvalidOperationException ("Invalid CriticalHandle!");
35+
}
36+
}
37+
38+
// Perform any specific actions to release the handle in the ReleaseHandle method.
39+
// Often, you need to use Pinvoke to make a call into the Win32 API to release the
40+
// handle. In this case, however, we can use the Marshal class to release the unmanaged memory.
41+
42+
override protected bool ReleaseHandle()
43+
{
44+
// If the handle was set, free it. Return success.
45+
if ( !IsInvalid )
46+
{
47+
// NOTE: We should also ZERO out the memory allocated to the handle, before free'ing it
48+
// so there are no traces of the sensitive data left in memory.
49+
NativeStructs.CredFree (handle);
50+
// Mark the handle as invalid for future users.
51+
SetHandleAsInvalid ();
52+
return true;
53+
}
54+
// Return false.
55+
return false;
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)