C++ – How to get Windows domain name

cdnswindows

How can i get the domain name of the machine (if the machine is in fact joined to a domain)?

And, of course, if the machine is not joined to a domain the function should return

  • null, or
  • an empty string, or
  • the name of the machine, or
  • "."

Notes:

  • the NetGetJoinInformation Win32 function returns the legacy NetBIOS name of the domain (e.g. AVATOPIA), not the name of the domain (e.g. avatopia.local)

  • the USERDOMAIN environment variable returns the domain of the logged on user, which can be different from the machine; and also returns the legacy NetBIOS name of the domain (e.g. AVATOPIA)

  • the USERDNSDOMAIN environment variable returns the domain name of the logged on user, which can be different from the machine

Microsoft has a knowledge base article How to retrieve current user and domain names on Windows NT, Windows 2000, or Windows XP, which relies on getting the user's security token and calling LookupAccountSid.

  • the LookupAccountSid Win32 function returns the legacy NetBIOS name of the domain (e.g. AVATOPIA); and also returns the domain of the logged on user, which can be different from the machine

Update One

i've also tried using ADs object to bind to the IADs interface of the domain:

IADs domain;
ADsGetObject("LDAP://rootDES", IDs, out domain);

problem with this approach is that:

  • you cannot get the domain name (only the distinguished name)
  • it doesn't work if the user does not have permissions to query AD
  • it doesn't work if the user is not a valid user in active directory
  • it only works for Active Directory domains

Update Two:

Just to be clear what i want is:

enter image description here

Bonus Reading

Best Answer

Here you go:

#include <Windows.h>
#include <DSRole.h>

#pragma comment(lib, "netapi32.lib")

#include <stdio.h>

int main(int argc, char ** argv)
{
    DSROLE_PRIMARY_DOMAIN_INFO_BASIC * info;
    DWORD dw;

    dw = DsRoleGetPrimaryDomainInformation(NULL,
                                           DsRolePrimaryDomainInfoBasic,
                                           (PBYTE *)&info);
    if (dw != ERROR_SUCCESS)
    {
        wprintf(L"DsRoleGetPrimaryDomainInformation: %u\n", dw);
        return dw;
    }

    if (info->DomainNameDns == NULL)
    {
        wprintf(L"DomainNameDns is NULL\n");
    }
    else
    {
        wprintf(L"DomainNameDns: %s\n", info->DomainNameDns);
    }

    return 0;
}

Anybody using DsRoleGetPrimaryDomainInformation in production use should consider calling DsRoleFreeMemory to free the memory block when the information is no longer needed (as per discussion in the comments).

The function returns three different domain names, e.g.:

  • Domain Forest Name: e.g. stackoverflow.com
  • Domain DNS Name: e.g. stackoverflow.com
  • Domain NetBIOS Name: e.g. STACKOVERFLOW

If the machine is not joined to a domain, then both Forest and dns are blank, with only NetBios name filled with the name of the workgroup, e.g.:

  • Domain Forest Name: null
  • Domain DNS Name: e.g. null
  • Domain NetBIOS Name: e.g. WORKGROUP

The function also returns a flag indicating if the machine is joined to a domain:

  • DsRole_RoleMemberWorkstation: workstation that is a member of a domain
  • DsRole_RoleMemberServer: server that is a member of a domain
  • DsRole_RolePrimaryDomainController: primary domain controller
  • DsRole_RoleBackupDomainController: backup domain controller

or not:

  • DsRole_RoleStandaloneWorkstation: workstation that is not a member of a domain
  • DsRole_RoleStandaloneServer: server that is not a member of a domain