Click here to Skip to main content
6,295,667 members and growing! (14,694 online)
Email Password   helpLost your password?
Languages » C# » General     Intermediate License: The Code Project Open License (CPOL)

LSA Functions - Privileges and Impersonation

By Corinna John

Managing privileges and impersonating users
C#.NET 1.0, .NET 1.1, Win2K, WinXP, Dev
Posted:27 Aug 2003
Views:90,532
Bookmarked:43 times
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
27 votes for this article.
Popularity: 5.55 Rating: 3.88 out of 5
2 votes, 7.4%
1
1 vote, 3.7%
2
2 votes, 7.4%
3
6 votes, 22.2%
4
16 votes, 59.3%
5

Introduction

Sometimes you want your application to do things which the user himself may never do. For example, your application has to read a public folder on an exchange server, but the folder is hidden from the active user for good reasons. Now you need LSA functions, to manage privileges and impersonate another user. This article explains how to import the LSA functions, add rights to accounts and impersonate different users.

SIDs, Policies and Rights

Whenever you alter the privileges of an account, you need its Security Identifier (SID). You can find any account using LookupAccountName.

[DllImport( "advapi32.dll", CharSet=CharSet.Auto, 
    SetLastError=true, PreserveSig=true)]
private static extern bool LookupAccountName( 
    string lpSystemName, string lpAccountName, 
    IntPtr psid, ref int cbsid, 
    StringBuilder domainName, ref int cbdomainLength, 
    ref int use ); 

Before adding  or removing any privileges, we need a policy handle. LsaOpenPolicy opens a handle:

[DllImport("advapi32.dll", PreserveSig=true)]
private static extern UInt32 LsaOpenPolicy(
    ref LSA_UNICODE_STRING SystemName,
    ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
    Int32 DesiredAccess,
    out IntPtr PolicyHandle ); 

Using the SID and the policy handle, LsaAddAccountRights can add privileges:

[DllImport("advapi32.dll", SetLastError=true, PreserveSig=true)]
private static extern long LsaAddAccountRights(
    IntPtr PolicyHandle, IntPtr AccountSid, 
    LSA_UNICODE_STRING[] UserRights,
    long CountOfRights ); 

The LSA functions work with Unicode strings, so we have to use the LSA_UNICODE_STRING structure. This structure contains a buffer for the string, an two integers for the length of the buffer and the length of the actual string in the buffer:

[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING 
{ 
  public UInt16 Length; 
  public UInt16 MaximumLength; 
  public IntPtr Buffer; 
} 

Now it's time to call these functions. First, find the desired account and retrieve the SID.

//pointer an size for the SID

IntPtr sid = IntPtr.Zero;
int sidSize = 0; 

//StringBuilder and size for the domain name

StringBuilder domainName = new StringBuilder();
int nameSize = 0;

//account-type variable for lookup

int accountType = 0; 

//get required buffer size

LookupAccountName(String.Empty, accountName, sid, ref sidSize, 
    domainName, ref nameSize, ref accountType); 

//allocate buffers

domainName = new StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);

//lookup the SID for the account

bool result = LookupAccountName(String.Empty, accountName, sid, 
    ref sidSize, domainName, ref nameSize, ref accountType); 

And secondly, open a policy handle.

//initialize an empty unicode-string

LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING(); 

//initialize a pointer for the policy handle

IntPtr policyHandle = IntPtr.Zero; 

//these attributes are not used, but LsaOpenPolicy 

//wants them to exists

LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();

//get a policy handle

uint resultPolicy = LsaOpenPolicy(ref systemName, ref ObjectAttributes, 
    access, out policyHandle);

And finally we are ready to add privileges.

//initialize an unicode-string for the privilege name

LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1]; 
userRights[0] = new LSA_UNICODE_STRING(); 
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName); 
userRights[0].Length = (UInt16)( privilegeName.Length * 
    UnicodeEncoding.CharSize ); 
userRights[0].MaximumLength = (UInt16)( (privilegeName.Length+1) * 
    UnicodeEncoding.CharSize );

//add the privilege to the account 

long res = LsaAddAccountRights(policyHandle, sid, userRights, 1);
winErrorCode = LsaNtStatusToWinError(res); 
if(winErrorCode != 0)
{ 
    Console.WriteLine("LsaAddAccountRights failed: "+ winErrorCode); 
} 
//close all handles 

LsaClose(policyHandle); 
FreeSid(sid); 

More LSA

Now we can manage user's privileges - but how about being another user? LSA includes a set of functions to impersonate any user. This means, performing an invisible logon an switch between our own identity and the new one.

For example, if you're writing a service and you don't get along with network access of the local service authority, you can define a special domain account for your service and impersonate it at runtime. LogonUser is the function to authenticate a user against a domain:

[DllImport("advapi32.dll")]
private static extern bool LogonUser( 
    String lpszUsername, 
    String lpszDomain, 
    String lpszPassword, 
    int dwLogonType, 
    int dwLogonProvider, 
    ref IntPtr phToken );

LogonUser verifies the logon parameters an creates a security token. Whenever a user logs onto a workstation, a security token is created. All applications launched by this user hold a copy of this token. He have to copy our new token using DuplicateToken.

[DllImport("advapi32.dll")]
private static extern bool DuplicateToken( 
    IntPtr ExistingTokenHandle, 
    int ImpersonationLevel, 
    ref IntPtr DuplicateTokenHandle );

Now we got a copy of the security token, we can create a WindowsIdentity and impersonate the user. The .NET framework contains classes for impersonating users, once we got the right token.

using System.Security.Principal;
//...

WindowsIdentity newId = new WindowsIdentity(duplicateTokenHandle);
WindowsImpersonationContext impersonatedUser = newId.Impersonate();

Of course we have to free the handles at last.

if (existingTokenHandle != IntPtr.Zero)
{ 
    CloseHandle(existingTokenHandle); 
} 
if (duplicateTokenHandle != IntPtr.Zero)
{ 
    CloseHandle(duplicateTokenHandle); 
} 

When we have finished the special tasks, we can switch back to our normal identity

impersonatedUser.Undo(); 

Using the code

In the LogonDemo project there are LsaUtility.cs and LogonUtility.cs. LsaUtility.cs imports the functions necessary for managing privileges and contains the static method SetRight (String accountName, String privilegeName). It adds a named privilege to an account. LogonUtility.cs contains everything you need to impersonate a user.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Corinna John


Member
Corinna lives in Hannover/Germany (CeBIT City) and works as a Delphi developer, though her favorite language is C#.
Occupation: Software Developer
Location: Germany Germany

Other popular C# articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 39 (Total in Forum: 39) (Refresh)FirstPrevNext
GeneralA bit messy... PinmemberJecho Jekov10:35 12 Jun '09  
QuestionError adding "Logon As Service" right to User Account Pinmembersullivrp8:00 2 Jun '09  
AnswerRe: Error adding "Logon As Service" right to User Account Pinmembersullivrp9:48 3 Jun '09  
GeneralRe: Error adding "Logon As Service" right to User Account PinmemberCorinna John10:14 3 Jun '09  
GeneralRe: Error adding "Logon As Service" right to User Account Pinmembersullivrp11:22 3 Jun '09  
GeneralRe: Error adding "Logon As Service" right to User Account PinmemberCorinna John11:51 3 Jun '09  
GeneralRe: Error adding "Logon As Service" right to User Account Pinmembersullivrp6:39 4 Jun '09  
Questionhow give user'privilege to a programm ? Pinmembervincent317:45 20 Oct '06  
AnswerRe: how give user'privilege to a programm ? Pinmembervincent318:57 20 Oct '06  
GeneralLsaNtStatusToWinError work incorect. PinmemberSeregil2:02 15 Jun '06  
GeneralChanging Domain Group Policy PinmemberScott S.6:29 22 May '06  
QuestionImpersonation??? Pinmembertee_jay8:46 23 Mar '06  
AnswerRe: Impersonation??? PinmemberScott S.6:14 22 May '06  
GeneralLsaOpenPolicy Error...again Pinmembermr24shoe13:22 20 Mar '06  
GeneralRe: LsaOpenPolicy Error...again PinmemberJecho Jekov10:37 12 Jun '09  
GeneralVery good job Pinmembersegelfix11:48 19 Mar '06  
GeneralImpersonation - Console App - SAMBA Pinmemberlucasfong11:55 6 Jan '05  
GeneralLsaOpenPolicy Error PinmemberKermittt21:42 15 Sep '04  
GeneralRe: LsaOpenPolicy Error Pinmembergav_jackson5:24 5 Jan '05  
GeneralRe: LsaOpenPolicy Error PinmemberKermittt12:58 5 Jan '05  
GeneralRe: LsaOpenPolicy Error Pinmembergav_jackson22:59 5 Jan '05  
GeneralRe: LsaOpenPolicy Error PinmemberKermittt12:49 6 Jan '05  
GeneralRe: LsaOpenPolicy Error PinmemberTokus9:53 17 Jul '06  
GeneralRe: LsaOpenPolicy Error Pinmemberneotussanonis14:13 24 May '07  
GeneralUndocumented Lsa* Functions?? PinmemberDan Madden7:49 26 Aug '04  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 27 Aug 2003
Editor: Nishant Sivakumar
Copyright 2003 by Corinna John
Everything else Copyright © CodeProject, 1999-2009
Web13 | Advertise on the Code Project