Working with SIDs


Sometimes you know the name of a well-known account, such as Administrators, but you don’t know anything else about it. The Win32 API provides an answer to this dilemma. You can create a SID for the account without knowing anything about it, and then look up the information for that account. This technique proves handy for a number of uses. For example, if you know that you want to create a new user that has starting rights that are the same as a well-known account, you can begin by obtaining information about the well-known account SID. Listing 14.2 shows the essential code you’ll need for this example—the listing doesn’t include items like the function declarations. (You can find the complete source code for this example in the \Chapter 14\C#\LookUpSID or \Chapter 14\VB\LookUpSID folders of the source code located on the Sybex Web site.)

Listing 14.2 Converting a SID to Human Readable Form

start example
private void btnTest_Click(object sender, System.EventArgs e) {    Int32          SIDSize;    // Size of the returned SID.    IntPtr         GuestSID;   // SID of the Guest account.    int            LastError;  // Last error produced by an API call.    Int32          NameSize;   // Size of the account name.    Int32          DomainSize; // Size of the domain name.    StringBuilder  Name;       // Account name.    StringBuilder  Domain;     // Domain name.    SID_NAME_USE   Use;        // Account use.    // Allocate memory for the SID.    GuestSID = Marshal.AllocHGlobal(SECURITY_MAX_SID_SIZE);    // Create the SID.    SIDSize = SECURITY_MAX_SID_SIZE;    if (!CreateWellKnownSid((WELL_KNOWN_SID_TYPE)cbSelect.SelectedIndex,                            IntPtr.Zero,                            GuestSID,                            ref SIDSize))    {       // Get the last error.       LastError = Marshal.GetLastWin32Error();       // Display an error message and exit if not successful.       MessageBox.Show("Error creating the account SID." +                       "\r\nLast Error: " + LastError.ToString(),                       "Application Error",                       MessageBoxButtons.OK,                       MessageBoxIcon.Error);       // Free the memory we allocated.       Marshal.FreeHGlobal(GuestSID);       // Exit the routine.       return;    }    // Obtain the size of the Name and Domain strings.    NameSize = 0;    DomainSize = 0;    Use = SID_NAME_USE.SidTypeAlias;    LookupAccountSid(null,                     GuestSID,                     null,                     ref NameSize,                     null,                     ref DomainSize,                     ref Use);    // Allocate memory for the strings.    Name = new StringBuilder(NameSize);    Domain = new StringBuilder(DomainSize);    // Obtain the SID information.    if (!LookupAccountSid(null,                          GuestSID,                          Name,                          ref NameSize,                          Domain,                          ref DomainSize,                          ref Use))    {       // Get the last error.       LastError = Marshal.GetLastWin32Error();       // Display an error message and exit if not successful.       MessageBox.Show("Error obtaining the account SID data." +                       "\r\nLast Error: " + LastError.ToString(),                       "Application Error",                       MessageBoxButtons.OK,                       MessageBoxIcon.Error);    }    else    {       // Display the account information.       MessageBox.Show("Obtained the SID Account Information" +                       "\r\nName: " + Name.ToString() +                       "\r\nDomain: " + Domain.ToString() +                       "\r\nUse: " + Use.ToString(),                       "Application Output",                       MessageBoxButtons.OK,                       MessageBoxIcon.Information);    }    // Free the memory we allocated.    Marshal.FreeHGlobal(GuestSID); }
end example

Windows provides a wealth of well-known SIDs—predefined SIDs that every machine can use. The CreateWellKnownSid() function will create a SID for a well-known value such as the World. All you need to supply is an enumerated SID type, a pointer to a buffer to hold the SID, and the size of the SID buffer. The domain SID is optional. However, supplying this value will enable you to look up SIDs on other machines. There are 51 enumerated SID types to choose from and the example application lets you test them all. (Some of the well-known SIDs might not work on your machine if you don’t have the required support installed.)

The LookupAccountSid() function accepts a SID as input. It doesn’t matter where you get the SID, as long as the SID is valid. If the call to this function fails, you can assume the SID was invalid—even if it’s a well-known SID. The LookupAccountSid() function returns the name and domain information for the SID, along with the SID usage as indicated by the SID_NAME_USE enumeration.

One of the first tasks the code has to perform is allocating memory for the SID. When working with a .NET application, it’s best to use the Marshal.AllocHGlobal() function.

This function returns an IntPtr to the allocated memory, which you must deallocate later using the Marshal.FreeHGlobal() function. The SECURITY_MAX_SID_SIZE constant defines the maximum size of the SID.

We’ve used a number of techniques for gaining access to error information. This example uses the Microsoft recommended technique of setting the SetLastError argument of the [DllImport] attribute to true, and then using the Marshal.GetLastWin32Error() function to return the error number. Note that the .NET Framework doesn’t provide any means for converting this number into a human-readable form. You still need to use the Win32 API FormatMessage() function to perform the conversion.

Once the code obtains the desired SID, it uses the LookupAccountSid() function to determine the SID information. However, the code requires two calls to the LookupAccountSid() function to perform this task. The first call returns the size of the strings used to contain the account name and domain information. The code uses this information to allocate two StringBuilder variables. The second call returns the actual information.




.Net Development Security Solutions
.NET Development Security Solutions
ISBN: 0782142664
EAN: 2147483647
Year: 2003
Pages: 168

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net