Thursday, July 14, 2005
I was reading through a bunch of documents I had lying around, and found one that might be of interest to developers out there. A team in a previous workplace encountered a strange issue: they were trying to authenticate against a Windows domain (Active Directory-based domain server) using ADSI via .NET's System.DirectoryServices, and in some cases (particular users and particular machines) their login code would bomb with a "Domain Not Found" error or somesuch.

Turns out they were trying to bind to ldap://domain_name, where domain name was programmatically derived from System.Environment.UserDomainName; in some cases said property would return, instead of the logged on user's domain name, the local computer name. Thing is, you would expect a property in System.Environment to return the value of an evironment variable, presumably USERDOMAIN, which we verified contained the appropriate value.

Digging around in the documentation didn't help, so I turned to ye olde Reflector:

public static string get_UserDomainName() {
byte[] array1;
int num1;
StringBuilder builder1;
int num2;
int num3;
bool flag1;
int num4;

new EnvironmentPermission(1, "UserDomainName").Demand();
array1 = new byte[1024];
num1 = array1.Length;
builder1 = new StringBuilder(1024);
num2 = builder1.Capacity;
flag1 = Win32Native.LookupAccountName(null, Environment.UserName, array1, &(num1), builder1, &(num2), &(num3));
if (!flag1)
{
num4 = Marshal.GetLastWin32Error();
if (num4 == 120)
{
throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_Win9x"));
}
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UserDomainName"));
}
return builder1.ToString();
}

Note the function call in bold; a quick look in MSDN revealed the following information:

BOOL LookupAccountName(
  LPCTSTR lpSystemName,
LPCTSTR lpAccountName,
PSID Sid,
LPDWORD cbSid,
LPTSTR ReferencedDomainName,
LPDWORD cchReferencedDomainName,
PSID_NAME_USE peUse );

Parameters

lpSystemName
[in] Pointer to a null-terminated character string that specifies the name of the system. This string can be the name of a remote computer. If this string is NULL, the account name translation begins on the local system. If the name cannot be resolved on the local system, this function will try to resolve the name using domain controllers trusted by the local system. Generally, specify a value for lpSystemName only when the account is in an untrusted domain and the name of a computer in that domain is known.
lpAccountName
[in] Pointer to a null-terminated string that specifies the account name.

Use a fully qualified string in the domain_name\user_name format to ensure that LookupAccountName finds the account in the desired domain.

Note the part marked in red: Environment.UserDomainName does indeed pass null for lpSystemName, so if the machine contains a local user by the same name as the domain user, the local machine name will be returned instead of the domain. This behavior is apparently by design, although I can't figure out how that makes any sense what-so-ever.

There are two easy ways to avoid this issue:

string userDomain = Environment.GetEnvironmentVariable( "USERDOMAIN" );
string userDomain = System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split( @'\' )[ 0 ];

Have fun.

Wednesday, April 26, 2006 9:56:42 PM (Jerusalem Standard Time, UTC+02:00)
Thanks for looking this up and explaining it.
Monday, June 12, 2006 6:14:24 PM (Jerusalem Standard Time, UTC+02:00)
Thanks! You saved my day. This is exactly the problem I was running into. The alternatives seem to work better. Due to its not foreseeable what System.Environment.UserDomainName will return the property is pretty much useless...

Regs,

Uwe
Monday, October 30, 2006 8:31:25 PM (Jerusalem Standard Time, UTC+02:00)
Just ran in to this. Thanks for posting your findings. Not sure I'd lose sleep over it, but it's nice to know why the UserDomainName property wasn't returning what I was expecting it to return.
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Live Comment Preview