Impersonation in C#
August 25, 2007 | Leave a Comment
using System;
using System.Threading;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
[assembly:SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode=true)]
[assembly:PermissionSetAttribute(SecurityAction.RequestMinimum, Name = “FullTrust”)]
namespace QAWEB
{
/// <summary>
/// Credentials for doing NT impersonation
/// </summary>
public struct NTCredential
{
public NTCredential(string userName, string password, string domainName)
{
this.UserName = userName;
this.Password = password;
this.DomainName = domainName;
}
public string UserName, Password, DomainName;
}
/// <summary>
/// Summary description for Impersonate.
/// </summary>
public unsafe struct ImpersonationData
{
public IntPtr TokenHandle;
public IntPtr DupeTokenHandle;
public WindowsIdentity Identity;
public WindowsImpersonationContext ImpersonatedUser;
public ImpersonationData(IntPtr TokenHandle, IntPtr DupeTokenHandle, WindowsIdentity Identity, WindowsImpersonationContext ImpersonatedUser)
{
this.TokenHandle = TokenHandle;
this.DupeTokenHandle = DupeTokenHandle;
this.Identity = Identity;
this.ImpersonatedUser = ImpersonatedUser;
}
}
public unsafe class Impersonation
{
[DllImport(“advapi32.dll”, SetLastError=true)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport(“kernel32.dll”, CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int dwFlags, ref IntPtr lpSource,
int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr *Arguments);
[DllImport(“kernel32.dll”, CharSet=CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
[DllImport(“advapi32.dll”, CharSet=CharSet.Auto, SetLastError=true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
public Impersonation()
{
//
// TODO: Add constructor logic here
//
}
public ImpersonationData Impersonate(NTCredential credential)
{
return DoImpersonation(credential);
}
//TODO: Should be internal. Need to figure out how to get to the companies list before they are fully auth’d.
// public ImpersonationData ImpersonateMasterUser()
// {
// ImpersonationData impData = DoImpersonation(Registry.GetInitialCredentials());
// impData.Identity.Impersonate();
// return impData;
// }
ImpersonationData DoImpersonation(NTCredential credential)
{
IntPtr tokenHandle = new IntPtr(0);
IntPtr dupeTokenHandle = new IntPtr(0);
WindowsImpersonationContext impersonatedUser = null;
// Get the user token for the specified user, machine, and password using the
// unmanaged LogonUser method.
const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
const int LOGON32_LOGON_INTERACTIVE = 2;
//const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
//const int LOGON32_PROVIDER_WINNT50 = 3;
const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
//const int LOGON32_LOGON_NETWORK = 3;
const int SecurityImpersonation = 2;
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(credential.UserName, credential.DomainName, credential.Password,
LOGON32_LOGON_INTERACTIVE , LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
throw new Exception(String.Format(“LogonUser failed with error code : {0}, message: {1}”, ret, GetErrorMessage(ret)));
}
bool retVal = DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle);
if (false == retVal)
{
CloseHandle(tokenHandle);
}
// The token that is passed to the following constructor must
// be a primary token in order to use it for impersonation.
WindowsIdentity newId = new WindowsIdentity(dupeTokenHandle);
impersonatedUser = newId.Impersonate();
return new ImpersonationData(tokenHandle,dupeTokenHandle,newId,impersonatedUser);
}
public unsafe static string GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0×00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0×00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0×00001000;
int messageSize = 255;
String lpMsgBuf = “”;
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
IntPtr ptrlpSource = IntPtr.Zero;
IntPtr prtArguments = IntPtr.Zero;
int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0, ref lpMsgBuf, messageSize, &prtArguments);
if (0 == retVal)
{
throw new Exception(“Failed to format message for error code “ + errorCode + “. “);
}
return lpMsgBuf;
}
public bool Unimpersonate(ImpersonationData impersonationData)
{
if (impersonationData.ImpersonatedUser != null)
{
// Stop impersonating the user.
impersonationData.ImpersonatedUser.Undo();
// Free the tokens.
if (impersonationData.TokenHandle != IntPtr.Zero)
CloseHandle(impersonationData.TokenHandle );
if (impersonationData.DupeTokenHandle != IntPtr.Zero)
CloseHandle(impersonationData.DupeTokenHandle);
return true;
}
else
return false;
}
}
}
Understanding COM+ in .net
August 23, 2007 | Leave a Comment
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/entserv.asp
Operator Overloading, Bitwise Operations, and Simulated Enumerations
August 23, 2007 | Leave a Comment
This small program is a useful example of how to perform 1) bitwise manipulations 2) C# operator overloading 3) Enumeration simulation, a la Java.
using System;
using System.Collections.Generic;
using System.Text;namespace OperatorOverloading
{
class PageMode
{
private int _value;
public static PageMode Create = new PageMode(0×01);
public static PageMode Read = new PageMode(0×02);
public static PageMode Update = new PageMode(0×04);
public static PageMode Delete = new PageMode(0×08);
public PageMode() {
_value = 0×00;
}
private PageMode(int value)
{
_value = value;
}
public static PageMode operator +(PageMode op1, PageMode op2)
{
PageMode returnVal = new PageMode();
returnVal._value = op1._value | op2._value;
return returnVal;
}
public static bool operator ==(PageMode lhs, PageMode rhs)
{
bool returnVal = (lhs._value & rhs._value) == rhs._value;
return returnVal;
}
public static bool operator !=(PageMode lhs, PageMode rhs)
{
bool returnVal = (lhs._value & rhs._value) == rhs._value;
return returnVal;
}
}
class Program
{
static PageMode currentValue = new PageMode();
static void Main(string[] args)
{
currentValue = PageMode.Read + PageMode.Update;
currentValue += PageMode.Create;
if (currentValue == PageMode.Create)
{
Console.WriteLine(”Create Mode”);
}
if (currentValue == PageMode.Read)
{
Console.WriteLine(”Read Mode”);
}
if (currentValue == PageMode.Update)
{
Console.WriteLine(”Update Mode”);
}
if (currentValue == PageMode.Delete)
{
Console.WriteLine(”Delete Mode”);
}
Console.WriteLine(”Press Any Key to continue…”);
Console.ReadLine();
}
}
}
Thinking in C#
August 23, 2007 | 1 Comment
I was surprised to see a coding pattern that I would commonly use in C++ and be told that was NOT the best way to do this in C#.
int len = array.Length ( );
for ( int i = 0; i < len; i ++ )
{
array[ i ] = 0;
}
In C++, there’s a performance gain in this example because the array Length() member is only called once and the value is cached for use inside the loop.
Apparently, because of how the JIT compiler unrolls loops and optimises bounds checking, the following pattern is going to produce more eficient code in C#, even though my C++ knowledge says otherwise.
for ( int i = 0; i < array.Length( ); i++ )
{
array[ i ] = 0;
}
This highlights my lack of C# knowledge lead me to this good article on the msdn with an in-depth explanation:
“Performance Considerations for Run-Time Technologies in the .NET Framework”
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/dotnetperftechs.asp

