Click here to Skip to main content
Click here to Skip to main content

LSA Functions - Privileges and Impersonation

By , 27 Aug 2003
 

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
Software Developer
Germany Germany
Member
Corinna lives in Hannover/Germany (CeBIT City) and works as a Delphi developer, though her favorite language is C#.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionChceck "SeServiceLogonRight already" exist or not for user?memberankyshah26 Jan '11 - 20:06 
Hi Corinna John,
 
Very nice article and it is very helpful. I have one question that, if log on user have already "SeServiceLogonRight" rights then I want to check that if rights already exist then do not add the rights for that user else add the rights. How can I achieve this?? Your help can save my lots of time.. Please reply...
 
Thanks Ankit.
GeneralNice article, even if there are some errors.memberiq-man29 Nov '09 - 22:09 
Hi
 
This is a nice article. It contains a lot of great information and makes it much easier and faster to get a working sample to grant privileges to a user. Specifically I needed to grant the "logon as a service" privilege.
 
It does contain a few errors though. As the previous user comment says, there are errors in the marshalling. I have corrected this in the code I am using, and have not experienced any problems.
 
Best regards
Martin
 
modified on Monday, November 30, 2009 4:27 AM

GeneralRe: Nice article, even if there are some errors.memberalexdresko23 Dec '09 - 8:37 
How about posting the fixed code, dude?
 
I'm not a player, I just code a lot!
Alex Dresko

GeneralRe: Nice article, even if there are some errors.memberiq-man26 Dec '09 - 2:11 
Hi
 
The errors I was refering to are those pointed out by the user making the previous comment (Jecho Jekov).
The fixes I use are nothing else but using the correct P/Invoke signatures he wrote. I checked the remaining P/Invoke signatures, and found no errors. So there really is no "fixed code" to post which has not already been posted in the comment made by Jecho Jekov.
 
Regards
Martin
GeneralRe: Nice article, even if there are some errors.memberalexdresko26 Dec '09 - 7:21 
Well that makes me feel better. I was able to get the fixed code working that someone else posted. Of course, based on the comments within, it seems like they "fixed" it, and then put it back the way it was originally because it wasn't broken in the first place. Smile | :)
 
I'm not a player, I just code a lot!
Alex Dresko

GeneralA bit messy...memberJecho Jekov12 Jun '09 - 9:35 
Hi Corina,
 
Very nice article. However, you should know that "LONG" in C++ is equivalent to "int" in C#. There are several places in your code where you use "long" instead of "int". This may cause random errors during the execution of the code and is the cause for most of the errors posted by other users.
 
More specifically you should change the following in the LsaUtility class (I have not looked at the other classes):
private static extern int LsaAddAccountRights(
	IntPtr PolicyHandle,
	IntPtr AccountSid,
	LSA_UNICODE_STRING[] UserRights,
	int CountOfRights);
private static extern int LsaClose(IntPtr ObjectHandle);
private static extern int LsaNtStatusToWinError(int status);
Regards,
Jecho
GeneralRe: A bit messy...memberMark Richards27 Mar '12 - 5:24 
Hmmm, I'm not so sure about your adjustment to LsaAddAccountRights().
 
MSDN defines the last parameter of this function as receiving an unsigned long, which for C# I would expect to translate to a uint data type.
 
I agree, however, with the changes to LsaClose and LsaNtStatusToWinError, both of which use NTSTAUS (an unsigned long, translating to a C# int).
- Mark R.

QuestionError adding "Logon As Service" right to User Accountmembersullivrp2 Jun '09 - 7:00 
Corrina,
 
Great article, it has helped me out a lot, now if I could just resolve my current error, it would help even more!
 
My journey started with http://weblogs.asp.net/avnerk/archive/2007/05/08/setting-windows-service-account-c-and-wmi.aspx and I later ran across this follow-up posting http://weblogs.asp.net/avnerk/archive/2007/05/10/granting-user-rights-in-c.aspx which led me to http://www.hightechtalks.com/csharp/lsa-functions-276626.html.
 
I did some more searching and ran across http://blog.deploymentengineering.com/2008/09/different-year-same-problem.html which pointed me to your article. I then started cleaning up the example that was available and have ran into my current problem "1734 (The array bounds are invalid.)" when calling LsaAddAccountRights() to add "Log On As A Service" right to a user account.
 
During my various searches, I found the following link which lists available logon user rights http://support.microsoft.com/?id=279664 and http://support.microsoft.com/default.aspx?scid=kb;en-us;132958 provides additional information abour managing user privileges programmatically.
 
I have followed the following websites with no luck...all appear to be doing essentially the same thing that I am and implementing the differences yields the same result.
 
http://social.msdn.microsoft.com/forums/en-US/vbgeneral/thread/2d7d8115-a2ea-4d02-927b-667b20c047db/
 
http://social.msdn.microsoft.com/Forums/en-US/clr/thread/fd055d60-e030-4edc-b7a9-1962d6f7339e
 
http://www.pinvoke.net/default.aspx/advapi32/LsaAddAccountRights.html
 
http://pinvoke.net/default.aspx/advapi32/LsaOpenPolicy.html
 

Please help!
 

Here is the cleaned up code:
 
if (LSAUtility.SetRight(accountName, "SeServiceLogonRight", out errorMessage) == 0)
 
{
 
System.Windows.Forms.MessageBox.Show("The account " + accountName + " has been granted the Log On As A Service right.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
 
} // end if
 
else
 
{
 
System.Windows.Forms.MessageBox.Show("The Log On As A Service right was not added due to the following error: " + errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
 
} // end else
 
----------------------------------------------
 

using System;
 
using System.Runtime.InteropServices; // DllImport
 
using System.Text;
 
namespace MyUtils
 
{
 
/// <summary>
 
/// The Local Security Authority (LSA) Utility
 
/// </summary>
 

public class LSAUtility
 
{
 
#region Import the LSA functions
 
[DllImport("advapi32.dll", PreserveSig = true)]
 
private static extern Int32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, out IntPtr PolicyHandle);
 
[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);
 
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
 
private static extern Int32 LsaAddAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING UserRights, int CountOfRights);
 

[DllImport("advapi32.dll")]
 
private static extern bool IsValidSid(IntPtr pSid);
 
[DllImport("advapi32")]
 
public static extern void FreeSid(IntPtr pSid);
 

[DllImport("advapi32.dll")]
 
private static extern Int32 LsaClose(IntPtr ObjectHandle);
 

[DllImport("advapi32.dll")]
 
private static extern Int32 LsaNtStatusToWinError(Int32 status);
 
[DllImport("kernel32.dll")]
 
private static extern int GetLastError();
 
#endregion Import the LSA functions
 
#region Structures
 
#region LSA_OBJECT_ATTRIBUTES
 
[StructLayout(LayoutKind.Sequential)]
 
private struct LSA_OBJECT_ATTRIBUTES
 
{
 
public IntPtr RootDirectory;
 
public IntPtr SecurityDescriptor;
 
public IntPtr SecurityQualityOfService;
 
public LSA_UNICODE_STRING ObjectName;
 
public UInt32 Attributes;
 
public UInt32 Length;
 
} // LSA_OBJECT_ATTRIBUTES
 
#endregion LSA_OBJECT_ATTRIBUTES
 
#region LSA_UNICODE_STRING
 
[StructLayout(LayoutKind.Sequential)]
 
private struct LSA_UNICODE_STRING
 
{
 
public IntPtr Buffer;
 
public UInt16 Length;
 
public UInt16 MaximumLength;
 
} // LSA_UNICODE_STRING
 
#endregion LSA_UNICODE_STRING
 
#endregion Structures
 
#region Enumeration
 
#region LSA_AccessPolicy
 
private enum LSA_AccessPolicy : long
 
{
 
POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
 
POLICY_CREATE_ACCOUNT = 0x00000010L,
 
POLICY_CREATE_PRIVILEGE = 0x00000040L,
 
POLICY_CREATE_SECRET = 0x00000020L,
 
POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
 
POLICY_LOOKUP_NAMES = 0x00000800L,
 
POLICY_NOTIFICATION = 0x00001000L,
 
POLICY_SERVER_ADMIN = 0x00000400L,
 
POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
 
POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
 
POLICY_TRUST_ADMIN = 0x00000008L,
 
POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
 
POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L
 
} // LSA_AccessPolicy
 
#endregion LSA_AccessPolicy
 
#endregion Enumeration
 
#region Methods
 
/// <summary>Adds a privilege to an account</summary>
 
/// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
 
/// <param name="privilegeName">Name of the privilege</param>
 
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
 
public static Int32 SetRight(string accountName, string privilegeName, out string errorMessage)
 
{
 
int accountType = 0; // account-type variable for lookup
 
int nameSize = 0; // size of the domain name
 
int sidSize = 0; // size of the SID
 
IntPtr sid = IntPtr.Zero; // pointer for the SID
 

Int32 winErrorCode = 0; // contains the last error
 
StringBuilder domainName = null; // StringBuilder for the domain name
 
errorMessage = "";
 
// get required buffer size
 
LookupAccountName(null, 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
 
if (!LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType))
 
{
 
winErrorCode = GetLastError();
 
errorMessage = "An error occurred while Looking up the Account Name, Error Code: " + winErrorCode;
 
} // end if
 

else
 
{
 
// combine all policies
 
int access = (int) (LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
 
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
 
LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
 
LSA_AccessPolicy.POLICY_CREATE_SECRET |
 
LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
 
LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
 
LSA_AccessPolicy.POLICY_NOTIFICATION |
 
LSA_AccessPolicy.POLICY_SERVER_ADMIN |
 
LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
 
LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
 
LSA_AccessPolicy.POLICY_TRUST_ADMIN |
 
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
 
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION);
 
// Operation result
 
Int32 result;
 
// initialize a pointer for the policy handle
 
IntPtr policyHandle = IntPtr.Zero;
 
// initialize an empty unicode-string
 
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
 

// this variable and it's attributes are not used, but LsaOpenPolicy wants them to exists
 
LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
 
// get a policy handle
 
result = LsaOpenPolicy(ref systemName, ref ObjectAttributes, access, out policyHandle);
 
winErrorCode = LsaNtStatusToWinError(result);
 

if (winErrorCode != 0)
 
{
 
errorMessage = "An error occurred while opening the policy, Error Code: " + winErrorCode;
 
} // end if
 
else // Now that we have the SID and the policy, we can add the right to the account.
 
{
 
// initialize a unicode-string for the privilege name
 
LSA_UNICODE_STRING userRight = new LSA_UNICODE_STRING();
 
userRight.Buffer = Marshal.StringToHGlobalUni(privilegeName);
 
userRight.Length = (UInt16) (privilegeName.Length * UnicodeEncoding.CharSize);
 
userRight.MaximumLength = (UInt16) ((privilegeName.Length + 1) * UnicodeEncoding.CharSize);
 

// add the right to the account
 
result = LsaAddAccountRights(policyHandle, sid, userRight, 1);
 
winErrorCode = LsaNtStatusToWinError(result);
 
if (winErrorCode != 0)
 
{
 
errorMessage = "An error occurred while adding the account right, Error Code: " + winErrorCode;
 
} // end if
 
Marshal.FreeHGlobal(userRight.Buffer);
 
LsaClose(policyHandle);
 
} // end else
 
FreeSid(sid);
 
} // end else
 
return winErrorCode;
 
} // SetRight()
 
#endregion Methods
 
} // class LSAUtility
 
} // namespace MyUtils
AnswerRe: Error adding "Logon As Service" right to User Accountmembersullivrp3 Jun '09 - 8:48 
Ok, ok, ok.....be prepared for the stupidest fix ever.....in the LSA_UNICODE_STRING structure, public IntPtr Buffer has to be declared after Length and MaximumLength! Don't ask me why, because I don't know and I really don't care...actually I do care, but just don't know why.
 
In the posted code above I had changed userRight from an array to a variable; however, apparently the websites that I visited which stated that it did not have to be an array are wrong as I did have to change back to an array in order to get it to work.
 
The updated code is listed below so that others hopefully don't have to waste as much time as I have searching for a simple solution to the problem at hand.
 
using System;
using System.Runtime.InteropServices; // DllImport
using System.Text;
 
namespace myUtils
{
 
/// <summary>
/// The Local Security Authority (LSA) Utility
/// </summary>

public class LSAUtility
{
 
#region Import the LSA functions
 
[DllImport("advapi32.dll", PreserveSig = true)]
private static extern Int32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, out IntPtr PolicyHandle);
 
[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);
 
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
private static extern Int32 LsaAddAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, int CountOfRights);

[DllImport("advapi32.dll")]
private static extern bool IsValidSid(IntPtr pSid);
 
[DllImport("advapi32")]
public static extern void FreeSid(IntPtr pSid);

[DllImport("advapi32.dll")]
private static extern Int32 LsaClose(IntPtr ObjectHandle);

[DllImport("advapi32.dll")]
private static extern Int32 LsaNtStatusToWinError(Int32 status);
 
[DllImport("kernel32.dll")]
private static extern int GetLastError();
 
#endregion Import the LSA functions
 
#region Structures
 
#region LSA_OBJECT_ATTRIBUTES
 
[StructLayout(LayoutKind.Sequential)]
private struct LSA_OBJECT_ATTRIBUTES
{
 
public int Attributes;
public int Length;
 
public IntPtr RootDirectory;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
 
public LSA_UNICODE_STRING ObjectName;
 
} // LSA_OBJECT_ATTRIBUTES
 
#endregion LSA_OBJECT_ATTRIBUTES
 
#region LSA_UNICODE_STRING
 
[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING
{
 
public UInt16 Length;
public UInt16 MaximumLength;
 
// NOTE: Buffer has to be declared after Length and MaximumLength;
// otherwise, you will get winErrorCode: 1734 (The array bounds are invalid.)
// and waste lots of time trying to track down what causes the error!
public IntPtr Buffer;
 
} // LSA_UNICODE_STRING
 
#endregion LSA_UNICODE_STRING
 
#endregion Structures
 
#region Enumeration
 
#region LSA_AccessPolicy
 
private enum LSA_AccessPolicy : long
{
 
POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,
POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
POLICY_TRUST_ADMIN = 0x00000008L,
POLICY_CREATE_ACCOUNT = 0x00000010L,
POLICY_CREATE_SECRET = 0x00000020L,
POLICY_CREATE_PRIVILEGE = 0x00000040L,
POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
POLICY_SERVER_ADMIN = 0x00000400L,
POLICY_LOOKUP_NAMES = 0x00000800L,
POLICY_NOTIFICATION = 0x00001000L
 
} // LSA_AccessPolicy
 
#endregion LSA_AccessPolicy
 
#endregion Enumeration
 
#region Methods
 
/// <summary>Adds a privilege to an account</summary>
/// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
/// <param name="privilegeName">Name of the privilege</param>
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
public static Int32 SetRight(string accountName, string privilegeName, out string errorMessage)
{
 
int accountType = 0; // account-type variable for lookup
int nameSize = 0; // size of the domain name
int sidSize = 0; // size of the SID
 
IntPtr sid = IntPtr.Zero; // pointer for the SID

Int32 winErrorCode = 0; // contains the last error
 
StringBuilder domainName = null; // StringBuilder for the domain name
 
errorMessage = "";
 
// get required buffer size
LookupAccountName(null, 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
if (!LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType))
{
winErrorCode = GetLastError();
 
errorMessage = "An error occurred while Looking up the Account Name, Error Code: " + winErrorCode;
} // end if

else
{
// combine all policies
int access = (int) (LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
LSA_AccessPolicy.POLICY_CREATE_SECRET |
LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
LSA_AccessPolicy.POLICY_NOTIFICATION |
LSA_AccessPolicy.POLICY_SERVER_ADMIN |
LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
LSA_AccessPolicy.POLICY_TRUST_ADMIN |
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION);
 
Int32 result; // Operation result
 
IntPtr policyHandle = IntPtr.Zero; // initialize a pointer for the policy handle
 
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING(); // initialize an empty unicode-string

// this variable and it's attributes are not used, but LsaOpenPolicy wants them to exists
LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
 
// get a policy handle
result = LsaOpenPolicy(ref systemName, ref ObjectAttributes, access, out policyHandle);
 
winErrorCode = LsaNtStatusToWinError(result);

if (winErrorCode != 0)
{
errorMessage = "An error occurred while opening the policy, Error Code: " + winErrorCode;
} // end if
 
else // Now that we have the SID and the policy, we can add the right to the account.
{
// initialize a 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 right to the account
result = LsaAddAccountRights(policyHandle, sid, userRights, 1);
 
winErrorCode = LsaNtStatusToWinError(result);
 
if (winErrorCode != 0)
{
errorMessage = "An error occurred while adding the account right, Error Code: " + winErrorCode;
} // end if
 
Marshal.FreeHGlobal(userRights[0].Buffer);
 
LsaClose(policyHandle);
} // end else
 
FreeSid(sid);
} // end else
 
return winErrorCode;
 
} // SetRight()
 
#endregion Methods
 
} // class LSAUtility
} // namespace myUtils
GeneralRe: Error adding "Logon As Service" right to User AccountmemberCorinna John3 Jun '09 - 9:14 
Hi,
 
that's because of the unmanaged structure layout. You have to declare unmanaged types exactly as the Windows SDK headers do. They will be marshalled byte-by-byte. Wink | ;)
 
This statement is false.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 28 Aug 2003
Article Copyright 2003 by Corinna John
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid