NerdyHearn
Home
Blog

Contact
Mailing List

Software


Blog
Twitter

NerdyHearn - Blog


<< Back To All Blogs

Retrieving the SID of a user or group account using the Win32 SDK and C#

Wednesday, May 27th, 2009

SIDs are very useful for using as unique identifers, especially when you are working with computers or situations in which both local computer user accounts as well as domain accounts are available with system permissions.
SIDs are also what a large percentage of permissions-based SDK calls use, and therefore it is very useful to take a user account name and return the SID.

.NET supports some of the features of the Windows file system out of the box, but if you are looking to go much deeper then it is time to jump into the Win32 SDK and PInvoke.

Retrieving the SID is a good starting point, so without further ado, here is my function with comments inline:

// Helper function to convert a sid to a string sid, also in the Win32 SDK
[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool ConvertSidToStringSid(
[MarshalAs(UnmanagedType.LPArray)] byte[] pSID,
out IntPtr ptrSid);

// The actual Lookup SDK call
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LookupAccountName(
string lpSystemName,
string lpAccountName,
IntPtr Sid,
ref int cbSid,
string lpReferenceDomainName,
ref int cchReferencedDomainName,
ref SID_NAME_USE peUse);

// Enum for Sid Name Use
public enum SID_NAME_USE
{
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer
}

public static string RetrieveSid(string AccountName)
{
byte[] Sid = null;
uint cbSid = 0;
StringBuilder referencedDomainName = new StringBuilder();
uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;
SID_NAME_USE sidUse;

bool result = LookupAccountName(null, AccountName, Sid, ref cbSid, referencedDomainName, ref cchReferencedDomainName, out sidUse);

if (!result)
{
// There are other ways to retrieve the last error, but they are not friendly with C#
int err = Marshal.GetLastWin32Error();
// This will occur if your flags are wrong or the buffer has not been allocated
// This error will almost always occur the first time it hits LookupAccountName because the buffer size is unknown (and therefore not allocated)
if (err == 122 || err == 1004)
{
Sid = new byte[cbSid];
// This will ensure the array is the proper size in the string builder
referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
if (!LookupAccountName(null, AccountName, Sid, ref cbSid, referencedDomainName, ref cchReferencedDomainName, out sidUse))
// This will cast the error code to a user-friendly string
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
// Initialize a C#-version of a pointer for the SID to return
IntPtr ptrSid;
if (ConvertSidToStringSid(Sid, out ptrSid))
{
// Convert the Side to a string variant
string sidString = Marshal.PtrToStringAuto(ptrSid);
// Make sure to clean up your non-managed mess
LocalFree(ptrSid);
return sidString;
}
// Return empty if it fails, you could also throw an exception here
return string.Empty;
}

It may seem like a lot of code at first, but this is about as easy as it gets when it comes to the Win32 SDK.

PInvokin' Tom Out.


Tags

CSharp Win32 PInvoke

Related Blogs

Retrieving data from SharePoint SOAP Requests using LINQ
Good Ol Cross-Threaded Socket Action
Using MOSS and WSS SharePoint Workflow to Resize Images in an Image Library
Autostarting a Windows Service directly after install in C#
Retrieving Text from Win32 SDK's GetLastError() in C#

Comments

Currently no comments.

Add A Comment

Name:


URL:


Email Address: (not public, used to send notifications on further comments)


Comments:



Enter the text above, except for the 1st and last character:


NerdyHearn - Latest tech news relating to C#, ASP.NET, SharePoint, PHP, general development, and more. SaveMySerials - Protect yourself from theft, fire, natural disasters and more by recording your serial numbers