|

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.
IntPtr sid = IntPtr.Zero;
int sidSize = 0;
StringBuilder domainName = new StringBuilder();
int nameSize = 0;
int accountType = 0;
LookupAccountName(String.Empty, accountName, sid, ref sidSize,
domainName, ref nameSize, ref accountType);
domainName = new StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);
bool result = LookupAccountName(String.Empty, accountName, sid,
ref sidSize, domainName, ref nameSize, ref accountType);
And secondly, open a policy handle.
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
IntPtr policyHandle = IntPtr.Zero;
LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
uint resultPolicy = LsaOpenPolicy(ref systemName, ref ObjectAttributes,
access, out policyHandle);
And finally we are ready to add privileges.
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 );
long res = LsaAddAccountRights(policyHandle, sid, userRights, 1);
winErrorCode = LsaNtStatusToWinError(res);
if(winErrorCode != 0)
{
Console.WriteLine("LsaAddAccountRights failed: "+ winErrorCode);
}
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.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 31 (Total in Forum: 31) (Refresh) | FirstPrevNext |
|
 |
|
|
hello,
how to give to a programm the privilege of an user ?
I'am using remore server (ipcchannel).
1)the remote server is launch by windows service : when user insert usb device (a key) the server cannot eject this device.
2)I launch the serveur myself directly( with user account ) when user insert usb device (a key) the server can eject this device.
how to give privilege to the server ?
An idea ? thanks
Vincent
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
LsaNtStatusToWinError work incorect. Need next change: [DllImport("advapi32.dll")] private static extern uint LsaNtStatusToWinError(uint status); [DllImport("advapi32.dll", SetLastError=true, PreserveSig=true)] private static extern uint LsaAddAccountRights( IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, long CountOfRights);
Sorry, bad english.
|
| Sign In·View Thread·PermaLink | 4.40/5 (2 votes) |
|
|
|
 |
|
|
Corinna,
Its nice to run across articles that remain relevant long after they were written ... good one!
I am attempting to update an existing VB6 application that automates a very involved installation of a server product. It creates user accounts, groups, files, file shares, DCOM components, and COM+ applications and proxies, etc. It works just fine in work groups and in Win2k domains, but in a Windows 2003 domain the server only runs for a little while after installation.
I determined that it is because during the installation of the COM+ application, the account used as it's identity is implicitly set into the local security policy with the "Log on as batch job" privilege. But in the W2003 domain the overriding global policy proceeds to write over that change to local policy. Seems to do it periodically even without the system restarting.
Anyway, I wanted to know if I could use these calls to give the server's identity account the "Log on a batch job" privilege in the domains Global Policy for Local Security Settings? And it so, what would the calls look like parameter wise? I shouldn't have any trouble porting sample code to VB6 even though I'm a C/C++/C# guy.
Ciao, Scott
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Nice Article!!
But I've a bit different query & after reading this article i guess you can very well guide me!
Problem: I want to impersoante a user & the only information that i have for the purpose is his SID. How can I do that?
Description: I know that i can easily impersonate a user using LogonUser() & then fire ImpersonateLoggedOnUser() on the access token that i get from LogonUser(). But I don't have the user's User Name & Password (which LogonUser() takes as input. I only have his SID.
>>> Please assume i've tried most of the impersonation approaches. 
Please HELP!!
Thanks in advance. TJ
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
TJ,
You can't do it with just a SID otherwise every virus out there would impersonate Administrator using its well known SID! If you also had the password, you could lookup the account name matching the SID to do the logon.
The only other way I can think of off hand is complicated... * Must be using Kerberos for authentication * Your process's identity (logged on user?) has to have delegation privilege * The user you want to impersonate has to be logged on * A process they are running must pass a kerberos authentication token to your process that includes the delegation information * Your process must receive the kerberos info set it into the thread * The thread must then enable impersonation Good luck if you go this route because as I said above, it is complicated ... I attempted it in the past in C# over remoting and had it working "most of the time" ... sometimes it just failed and I was never able to determine why.
The question is: "When is Microsoft going to add optional security to the .NET remoting framework classes to automate authentication and impersonation?"
Ciao, Scott S
|
| Sign In·View Thread·PermaLink | 3.00/5 (1 vote) |
|
|
|
 |
|
|
I reviewed the thread below regarding the LsaOpenPolicyError...I received the same "error":
I added a bit of code to check the error code returned (4294967296) from OpenPolicy:
if(winErrorCode != 0){ Console.WriteLine("OpenPolicy failed: "+ winErrorCode); System.ComponentModel.Win32Exception ex = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); Console.WriteLine("1 " + ex.Message + " (" + Marshal.GetLastWin32Error().ToString() + ") "); System.ComponentModel.Win32Exception ex2 = new System.ComponentModel.Win32Exception((int)winErrorCode); Console.WriteLine("2 " + ex2.Message + " (" + winErrorCode.ToString() + ") "); } else { ...
The spit-out from win2k is:
1 Overlapped I/O operation is in progress (127)
2 The operation completed successfully (4294967296)
The code works on an XP machine, but I receive the "error" on Win2k machines. I found the "completed successfully" interesting, so I allowed the next block (LsaAddAccount) to execute, and received the same "error".
I checked the security policy, and was happy to see that it worked!
So, this "error" (4294967296) seems to actually be a success code. So I modified the check's to look like this:
if(winErrorCode != 0 && winErrorCode != 4294967296){
I've also found that in
winErrorCode = LsaNtStatusToWinError(resultPolicy); on XP, winErrorCode will be 0. On Win2k, winErrorCode will be 4294967296. Don't know exactly why...
Just thought you'd all like to know.
shoe
-- modified at 18:22 Monday 20th March, 2006
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Hallo Corinna,
Ihr Code hat mich auf den richtigen Weg gebracht für das, was ich tun will.
Das einzige, was mir abgegangen ist, "RemoveRight" (Recht löschen) und "HasRight" (Abfrage, ob ein Account ein bestimmtes Recht besitzt) sowie eine öffentliche Enumeration von Rechten.
Ich habe diese Dinge in meiner Version von "LsaUtilities.cs" ergänzt und würde Ihnen das Resultat gerne zum Test zur Verfügung stellen. Derzeit habe ich nur die Logon-Features überprüft.
Ich hoffe, Sie können aus dieser Nachricht meine Email-Adresse ermitteln, sonst senden Sie mir bitte bei Interesse einfach eine SMS mit Ihrer Email an 004369912197955.
Liebe Grüße aus Österreich Peter Pranter
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, I have banging my head against the wall for about 2 weeks trying to figure this out. My goal is to write a file to a SAMBA share in a C# console app. I have an account set up in SAMBA and also set up in windows with identical username and password. I have read that this is the way to do it. I have found that i am impersonating the user correctly but when i go to write the file an error is raised telling me that it is a bad username and/or password. According to the SAMBA logs the impersonated users credentials are not being sent, instead MY login credentials are being sent. Do you have any ideas? It would be greatly appreciated. Cheers, Lucas.
Lucas
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
I've built these LSA functions into a VB command line app so that I can call it from within an InstallShield setup project. The primary purpose was so that I can call SetRight with SeServiceLogonRight to make sure the user has the "Logon as a Service" right, before I try to set a username/password on the service I'm installing.
On WinXP this has worked like a charm, but when I tested it on Win2k I got an error from LsaOpenPolicy. From my application the error is reported as "OpenPolicy failed: 4294967296". At first I thought it must have been an error that crept in when I converted the code to VB, but on further investigation it appears this isn't a valid error number at all. As far as I can tell this is just the max value for an integer. So I tried the original test app from this article and it returns the error "Privilege not added: +winErrorCode". (Note: In both of these cases I was trying to give the privilege to the Administrator of the local PC, but I get the same error no matter what user I use)
As far as I can tell this is still necessary on Win2k because after the error occurs my service is left with LocalSystem as the logon user.
Is there some good reason why this isn't working on Win2k or am I missing something obvious?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I don't think I ever did get that working. In the end I found a pre-compiled version of ssplogon.exe like what is described here.
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q180548
The one I have takes a command line like... ssplogon.exe <domain> <user> <password> ...and returns a value in the ERRORLEVEL indicating if the logon wass sucessful or not.
If this will suit you purpose, let me know and I can send u a copy of the exe.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
i've had a read through that article.
could you post some sample c# code as i am not quite sure what to do.
basically the bit i am interested in is more enabling privileges for different accounts (specifically log on as service)
cheers
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Sorry bout that, I went off on completely the wrong track there. The code for the class I ended up using is below. I converted Corinna's class to VB.NET (since that's my language of choice) and if I recall correctly the problem went away somewhere during the conversion. If there was something specific I fixed it's too long ago for me to recall what it was now. Hopefully if you compare the 2 you might be able to spot what's different, or maybe you could just compile this into a dll that you can use from your C# projects.
To grant the Logon As A Service right you'd call the SetRight function like this...
Dim lsaResult As Long = LsaFunctions.SetRight("domain\account", "SeServiceLogonRight") ...and a 0 result means it was sucessful.
Here's my VB.NET class, which is basically equivilent to Corinna's LsaUtility class. (BTW... sorry for the long post everyone, but I can't see any other way to attach this.)
Imports System.Text Imports System.Runtime.InteropServices
Public Class LsaFunctions
' Import the LSA functions _ Private Shared Function LsaOpenPolicy(ByRef SystemName As LSA_UNICODE_STRING, ByRef ObjectAttributes As LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle As IntPtr) As UInt32 End Function
_ Private Shared Function LsaAddAccountRights(ByVal PolicyHandle As IntPtr, ByVal AccountSid As IntPtr, ByVal UserRights As LSA_UNICODE_STRING(), ByVal CountOfRights As Long) As UInt32 End Function
_ Public Shared Sub FreeSid(ByVal pSid As IntPtr) End Sub
_ Private Shared Function LookupAccountName(ByVal lpSystemName As String, ByVal lpAccountName As String, ByVal psid As IntPtr, ByRef cbsid As Int32, ByVal domainName As StringBuilder, ByRef cbdomainLength As Int32, ByRef use As Int32) As Boolean End Function
_ Private Shared Function IsValidSid(ByVal pSid As IntPtr) As Boolean End Function
_ Private Shared Function LsaClose(ByVal ObjectHandle As IntPtr) As Long End Function
_ Private Shared Function GetLastError() As Long End Function
' Define the structures _ Private Structure LSA_UNICODE_STRING Public Length As UInt16 Public MaximumLength As UInt16 Public Buffer As IntPtr End Structure
_ Private Structure LSA_OBJECT_ATTRIBUTES Public Length As Int32 Public RootDirectory As IntPtr Public ObjectName As LSA_UNICODE_STRING Public Attributes As UInt32 Public SecurityDescriptor As IntPtr Public SecurityQualityOfService As IntPtr End Structure
' Enum all policies Private Enum LSA_AccessPolicy As Long POLICY_VIEW_LOCAL_INFORMATION = &H1L POLICY_VIEW_AUDIT_INFORMATION = &H2L POLICY_GET_PRIVATE_INFORMATION = &H4L POLICY_TRUST_ADMIN = &H8L POLICY_CREATE_ACCOUNT = &H10L POLICY_CREATE_SECRET = &H20L POLICY_CREATE_PRIVILEGE = &H40L POLICY_SET_DEFAULT_QUOTA_LIMITS = &H80L POLICY_SET_AUDIT_REQUIREMENTS = &H100L POLICY_AUDIT_LOG_ADMIN = &H200L POLICY_SERVER_ADMIN = &H400L POLICY_LOOKUP_NAMES = &H800L POLICY_NOTIFICATION = &H1000L End Enum
' Adds a privilege to an account ' Name of an account - "domain\account" or only "account" ' Name ofthe privilege ' The windows error code returned by LsaAddAccountRights Public Shared Function SetRight(ByVal accountName As String, ByVal privilegeName As String) As Long Dim winErrorCode As Long = 0 ' contains the last error
' pointer an size for the SID Dim sid As IntPtr = IntPtr.Zero Dim sidSize As Int32 = 0
' StringBuilder and size for the domain name Dim domainName As StringBuilder = New StringBuilder Dim nameSize As Int32 = 0
' account-type variable for lookup Dim accountType As Int32 = 0
' get required buffer size LookupAccountName(String.Empty, accountName, sid, sidSize, domainName, nameSize, accountType)
' allocate buffers domainName = New StringBuilder(nameSize) sid = Marshal.AllocHGlobal(sidSize)
' lookup the SID for the account Dim result As Boolean = LookupAccountName(String.Empty, accountName, sid, sidSize, domainName, nameSize, accountType)
' say what you're doing 'Dim msg As String 'msg &= "LookupAccountName result = " & result & vbCrLf 'msg &= "IsValidSid: " & IsValidSid(sid) & vbCrLf 'msg &= "LookupAccountName domainName: " & domainName.ToString() 'MessageBox.Show(msg)
If Not result Then winErrorCode = GetLastError() MessageBox.Show("LookupAccountName failed: " & winErrorCode, "ServiceUtils") Else ' initialize an empty unicode-string Dim systemName As LSA_UNICODE_STRING = New LSA_UNICODE_STRING
' Combine policies required to grant/deny privileges Dim access As Int32 = CInt( _ LSA_AccessPolicy.POLICY_CREATE_ACCOUNT Or _ LSA_AccessPolicy.POLICY_LOOKUP_NAMES)
' initialize a pointer for the policy handle Dim policyHandle As IntPtr = IntPtr.Zero
' these attributes are not used, but LsaOpenPolicy wants them to exists Dim ObjectAttributes As LSA_OBJECT_ATTRIBUTES = New LSA_OBJECT_ATTRIBUTES ObjectAttributes.Length = 0 ObjectAttributes.RootDirectory = IntPtr.Zero ObjectAttributes.Attributes = UInt32.Parse("0") ObjectAttributes.SecurityDescriptor = IntPtr.Zero ObjectAttributes.SecurityQualityOfService = IntPtr.Zero
' get a policy handle Dim resultPolicy As UInt32 = LsaOpenPolicy(systemName, ObjectAttributes, access, policyHandle)
If Not resultPolicy.ToString = "0" Then MessageBox.Show("OpenPolicy failed: " & resultPolicy.ToString, "ServiceUtils") Else ' Now that we have the SID an the policy, ' we can add rights to the account.
' initialize an unicode-string for the privilege name Dim userRights(1) As LSA_UNICODE_STRING userRights(0) = New LSA_UNICODE_STRING userRights(0).Buffer = Marshal.StringToHGlobalUni(privilegeName) userRights(0).Length = UInt16.Parse(privilegeName.Length * UnicodeEncoding.CharSize) userRights(0).MaximumLength = UInt16.Parse((privilegeName.Length + 1) * UnicodeEncoding.CharSize)
' add the right to the account Dim resultRights As UInt32 = LsaAddAccountRights(policyHandle, sid, userRights, 1) If Not resultRights.ToString = "0" Then MessageBox.Show("LsaAddAccountRights failed: " & resultRights.ToString, "ServiceUtils") End If
LsaClose(policyHandle) End If FreeSid(sid) End If
Return winErrorCode End Function End Class
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
fixed the errors:
private static extern long LsaAddAccountRights( IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, UInt32 CountOfRights );
private static extern long LsaNtStatusToWinError(UInt32 status);
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I know this is an old thread, but I am just reading it now. I am interested in a compiled version of SSPLOGIN.EXE. I don't seem to be able to find it anywhere.
Thanks Neo
Kermittt wrote: The one I have takes a command line like... ssplogon.exe ...and returns a value in the ERRORLEVEL indicating if the logon wass sucessful or not.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
I am creating some test apps to set privs/rights on a system. I have ran accross some functions that Microsoft shows in MSDN, but it doesn have anything else I searched the I-Net for these functions, but all I ever get are sites that show the Definition file for AdvApi32.dll. I know they are exported in the AdvApi32.dll (because I have some working), but I need to know the params that are past to get them to work correctly. Is there anyone that has some real documentation on these things???
Search for ACCOUNT_VIEW in MSDN and you will have 2 returns:
Account Object Access Rights HOWTO: Manage User Privileges Programmatically in Windows NT
Here is some functions I am talking about:
LsaOpenAccount LsaCreateAccount LsaGetSystemAccessAccount LsaSetSystemAccessAccount LsaAddPrivilegesToAccount LsaRemovePrivilegesFromAccount ... ...
Here are some DEFs I am talking about:
ACCOUNT_VIEW This access type is required to read the account information. This includes the privileges assigned to the account, memory quotas assigned, and any special access types granted.
ACCOUNT_ADJUST_PRIVILEGES This access type is required to assign privileges to or remove privileges from an account.
ACCOUNT_ADJUST_QUOTAS This access type is required to change the system quotas assigned to an account.
ACCOUNT_ADJUST_SYSTEM_ACCESS This access type is required to update the system access flags for the account.
Regards,
Dan
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Dan,
there is no documuntation for exported functions that are not declared in ntsecapi.h. I think the sample from KB 132958^ has been published by accident.
You can get a list of exported functions from the winehq.org CVS^, but they don't have the parameters.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Excuse me: How can I get the fullname of the user by the user's SID? (When you are registering to be a user of the windows system,you must write the sid,fullname and the descriptions)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Use LookupAccountSid API for the purpose. I used the API in VC++, but there must a C# replica for this method.
"Work Smarter, not Harder!"  TJ
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Is it possible to contain the impersonation to a given AppDomain rather than the impersonation consuming the full process? I have a service running under the local system account, but need to impersonate the current user for some functionality. However I dont want the full service to change it's access rights. I can spawn a seperate process (which impersonates a specifed user) but this therefore consumes more memory.
Any ideas?
Thanks Chris
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi, I try included examples and have question about retriving of SID - SID which I retrived for my acount in example (via function LookupAccountName) was integer number (e.g. 1580697). I try convert this number via function ConvertSidToStringSid to string representation and got path to application, something like this "\memoTest\ConsoleApplication1". What's wrong, how can I retrive SID in format like 'S-1-5-21-1431262831-1455604309-1834353910-1000'?
Thanks
Drc
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
If you haven't got it yet:
To Get the SID....
Example:
GetAccountSid(NULL,"UserName",&sid);
////////////////////////////////////////////////////////////////////// BOOL GetAccountSid(LPTSTR SystemName, LPTSTR AccountName, PSID *Sid) { LPTSTR ReferencedDomain=NULL; DWORD cbSid=128; // initial allocation attempt DWORD cchReferencedDomain=16; // initial allocation size SID_NAME_USE peUse; BOOL bSuccess=FALSE; // assume this function will fail
__try {
// // initial memory allocations // *Sid = (PSID)HeapAlloc(GetProcessHeap(), 0, cbSid);
if(*Sid == NULL) __leave;
ReferencedDomain = (LPTSTR)HeapAlloc(GetProcessHeap(),0,cchReferencedDomain * sizeof(TCHAR)); if(ReferencedDomain == NULL) __leave;
// // Obtain the SID of the specified account on the specified system. // while(!LookupAccountName( SystemName, // machine to lookup account on AccountName, // account to lookup *Sid, // SID of interest &cbSid, // size of SID ReferencedDomain, // domain account was found on &cchReferencedDomain, &peUse )) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // // reallocate memory // *Sid = (PSID)HeapReAlloc(GetProcessHeap(), 0, *Sid, cbSid);
if(*Sid == NULL) __leave;
ReferencedDomain = (LPTSTR)HeapReAlloc( GetProcessHeap(), 0, ReferencedDomain, cchReferencedDomain * sizeof(TCHAR));
if(ReferencedDomain == NULL) __leave; } else __leave; }
// // Indicate success. // bSuccess=TRUE;
} // try __finally {
// // Cleanup and indicate failure, if appropriate. //
HeapFree(GetProcessHeap(), 0, ReferencedDomain);
if(!bSuccess) { if(*Sid != NULL) { HeapFree(GetProcessHeap(), 0, *Sid); *Sid = NULL; } }
} // finally
return bSuccess; }
Now to Make it Text:
Example:
.... LPSTR sidText = NULL; DWORD cbSid = 128;
sidText = (LPSTR) LocalAlloc(LPTR, cbSid); if (sidText) { if(GetTextualSid(psid, sidText, &cbSid)) { m_edtSID.SetWindowText(sidText); } else { m_edtSID.SetWindowText(""); } LocalFree(sidText); } ....
//////////////////////////////////////////////////////////////////// BOOL GetTextualSid(PSID pSid, PTSTR TextualSid, PDWORD pdwBufferLen) { BOOL fSuccess = | | | | | |