Monday, October 5, 2009

c#: Getting Foreign Security Principal Displayname

While working on a project, I needed to enumerate all Foreign Security Principals (FSP) and capture their display name from Active Directory.
Enumerating FSP is very easy by using DirectorySearcher class:

DirectoryEntry userEntry = new DirectoryEntry("LDAP://domain/CN=ForeignSecurityPrincipals,DC=domain,DC=com");
DirectorySearcher userLookup = new DirectorySearcher(userEntry);
SearchResultCollection results = userLookup.FindAll();
foreach (SearchResult result in results)
{
DirectoryEntry childEntry = result.GetDirectoryEntry();
foreach (String val in childEntry.Properties.PropertyNames)
{
Debug.WriteLine(val + "\t" + childEntry.Properties[val].Value);
}
}

This produces the following results:
objectClass System.Object[]
cn ForeignSecurityPrincipals
description Default container for security identifiers (SIDs) associated with objects from external, trusted domains
distinguishedName CN=ForeignSecurityPrincipals,DC=,DC=com
instanceType 4
whenCreated 4/21/2001 3:00:47 PM
whenChanged 8/12/2005 11:51:48 PM
uSNCreated System.__ComObject
uSNChanged System.__ComObject
showInAdvancedViewOnly False
name ForeignSecurityPrincipals
objectGUID System.Byte[]
systemFlags -1946157056
objectCategory CN=Container,CN=Schema,CN=Configuration,DC=,DC=com
isCriticalSystemObject True
dSCorePropagationData System.Object[]
nTSecurityDescriptor System.__ComObject

From this you can see that the AD entry for FSP doesn't contain the Displayname field. However if you use Active Directory Tools for Users, you can see the SID and Displayname under FSP folder. If you have access to the other domains, you can do a SID lookup on the other domains to get the Displayname. Otherwise to get the Displayname of a FSP, you need to call a win32 api function and pass the SID. So import the advapi32.dll and call LookupAccountSid api to resolve the name like this:
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool LookupAccountSid(
string lpSystemName,
[MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
System.Text.StringBuilder lpName,
ref uint cchName,
System.Text.StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out SID_NAME_USE peUse);


LookupAccountSid(null, Sid, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sidUse))

download code

-paul