Linux
Apache
MySQL
PHP

CSS
XHTML1.1
XML/RSS

Creative Commons

2007-03-23 21:26:26

Getting an AD domain's netBIOS name from a UPN

I have been doing some C++ Win32 development lately and wanted to share two custom functions I needed to write. The point of my project was to authenticate a user to a server with Active Directory (using the LogonUser function) and make sure the user is a member of a certain domain group. The user logs in with his UPN, which gives us the DNS domain, however for the COM calls to work, the distinguished name and netBIOS names were also needed. This is where the custom functions come into play.
After the UPN is split into two variables, username and dns domain, the dns domain can be passed to the netbiosDomain function...
/* This function will take the dns domain (ad.foo.com), query the directory, and return it's equivalent netBIOS name (FOO) */ CString netbiosDomain (LPSTR dns) { CString cdns = dns; CString dn = domainDN(cdns); CString toReturn; IADsContainer *pPart = NULL; HRESULT hrPart; CString dnn; dnn.Format("%s%s", "LDAP://CN=Partitions,CN=Configuration,", dn); hrPart = ADsGetObject(CComBSTR(dnn), IID_IADsContainer, (void**) &pPart); IEnumVARIANT *pEnum = NULL; hrPart = ADsBuildEnumerator( pPart, &pEnum ); if (SUCCEEDED(hrPart)) { VARIANT var; ULONG lFetch; IADs *pChild=NULL; VariantInit(&var); while( SUCCEEDED(ADsEnumerateNext( pEnum, 1, &var, &lFetch )) && lFetch == 1 ) { hrPart = V_DISPATCH(&var)->QueryInterface( IID_IADs, (void**) &pChild ); if ( SUCCEEDED(hrPart) ) { VARIANT var1, var2; VariantInit(&var1); VariantInit(&var2); if (!pChild->Get(CComBSTR("dnsRoot"), &var1)) { if (CString(var1.bstrVal).MakeLower() == cdns.MakeLower()) { if (!pChild->Get(CComBSTR("nETBIOSName"), &var2)) { toReturn.Format ("%s", CString(var2.bstrVal)); } } } VariantClear(&var2); VariantClear(&var1); pChild->Release(); } } VariantClear(&var); } pPart->Release(); return toReturn; }
... which, in turn, calls the domainDN function...
/* This function will take a DNS domain (ad.foo.com) and return the equivalent distinguished name (dc=ad,dc=foo,dc=com) */ CString domainDN (CString lDomain) { CString token; int curPos = 0; int x = 0; CString toReturn = ""; CString toReturnn = ""; token = lDomain.Tokenize(".",curPos); while (token != "") { if (x == 0) toReturnn.Format("%sdc=%s", toReturn, token); else toReturnn.Format("%s,dc=%s", toReturn, token); token = lDomain.Tokenize(".",curPos); toReturn = toReturnn; x++; } return toReturn; }
... and ultimately netbiosDomain will return the netBIOS domain name.
So why is all of this necessary? If the DNS domain is ad.foo.com, isn't the netBIOS name "ad"? By default, yes. But administrators have the option of making the netBIOS domain name different from the first part of the DNS domain. Here's an example. Say you have a company that has two sectors, Foo and Bar. Foo.com and bar.com are domains controlled by *nix machines running BIND. You want to create Active Directory domains for your Windows workstations in each of the sectors. The most sensible AD domain names would be ad.foo.com and ad.bar.com. However, when creating these domains, the default netBIOS name for both would be "AD". How will your users know which one to pick from the domain list? They wouldn't. In this case, you would want to make the netBIOS names FOO and BAR, respectively. That is why the above two functions are necessary.
NOTE: Keep in mind, this project was a Win32 MFC project, therefore some of the variable types won't be available to other types of projects. I'm sure if you're smart enough to be doing this type of work that you'll be smart enough to adapt these functions so they work for you.
ANOTHER NOTE: For the COM calls (ADsGetObject, etc.) to work, COM needs to be initialized. In my project, these functions were called from parts of the code where COM was already initialized, but if you want to do this yourself, you'll need to CoInitialize(NULL) before making a COM call and CoUnInitialize() when you're done.

Back

1 comments


2007-03-25 13:01:16


dave says...
Don't be so silly... there aren't any companies like that ! =)

Actually, the problem comes up in sharepoint as well. The import of user profiles from the AD fails, and so far is STILL failing because of said disparity. Anyway, I've a bug in to microsoft about it, and I get to use lots of neat 'internal only' tools from microsoft to capture data about sharepoint -- even though I am averse to sharepoint as a concept, taking it apart is still fun. There's always the reflector, which works for everything, but hey, I'm a programmer stuck in the career of a sysadmin, leave me alone. I need SOME fun in my life.


Post a comment!

Name:
Comment: