HOWTO: Determine if a Windows NT Computer Is a Domain Member
ID: Q179891
|
The information in this article applies to:
-
Microsoft Windows NT Workstation versions 3.5, 3.51, 4.0
-
Microsoft Windows 2000
SUMMARY
This article describes how to determine if a computer running Windows NT
Workstation is a member of a domain, a member of a workgroup, or a stand-
alone computer using the Local Security Authority APIs.
MORE INFORMATION
To determine if a computer running Windows NT Workstation is a member of a
domain, a member of a workgroup, or a stand-alone computer using Local
Security Authority APIs, follow these steps:
- Open the Policy object of the local computer using LsaOpenPolicy.
- Use LsaQueryInformationPolicy to retrieve domain information.
- Check the value of the SID field. If the value is NULL, the computer is
either a stand-alone computer or part of a workgroup. If the Name field
points to a string that matches the local workstation name, the computer
is a stand-alone computer. Otherwise, the Name field points to the
workgroup name.
- If the SID pointer has a value, the computer is part of a domain. The
domain name is stored in the Name field.
The LsaQueryInformationPolicy API returns a pointer to
POLICY_PRIMARY_DOMAIN_INFO structure. The declaration for this structure
follows:
typdef struct _POLICY_PRIMARY_DOMAIN_INFO {
LSA_UNICODE_STRING Name;
PSID Sid;
} POLICY_PRIMARY_DOMAIN_INFO, *PPOLICY_PRIMARY_DOMAIN_INFO;
Notice the Name field declaration. Name is a pointer to an
LSA_UNICODE_STRING. The LSA_UNICODE_STRING declaration follows:
typedef struct _LSA_UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
To access the UNICODE string returned by the API, follow these steps:
PPOLICY_PRIMARY_DOMAIN_INFO pPolicy;
//
// Open the policy object and call LsaQueryInformationPolicy.
//
.
.
.
//
// Print the Name field on the screen.
//
printf("pPolicy->Name.Buffer : %S\n", pPolicy->Name.Buffer );
The following console application illustrates how to determine if a
computer running Window NT Workstation is a member of a domain or workgroup
or a stand-alone computer:
#define UNICODE
#define INCL_NET
#include <windows.h>
//
// ntsecapi.h is not automatically installed with the SDK.
// You need to retrieve the file from the samples directory
// tree for the win32 SDK or the platform SDK.
//
// [sdk root]\samples\win32\winnt\security\include
//
// You can statically link this code to the following library files:
//
// adv32api.lib - Lsa APIs
// netapi32.lib - LM APIs
//
#include <ntsecapi.h>
#include <lm.h>
#include <stdio.h>
#include <string.h>
//
// Function declarations
// ----------------------
// The following helper functions were copied from the following article
// in the Microsoft Knowledge Base:
//
// ARTICLE-ID: Q170620
// TITLE : HOWTO: Manage Computer Domain Membership Programmatically
//
// LsaOpenPolicy wrapper function.
//
NTSTATUS OpenPolicy( LPWSTR computername,
DWORD DesiredAccess,
PLSA_HANDLE Phandle);
//
// Quick and Dirty Error display routine.
//
void
DisplayNtStatus(
LPSTR szAPI, // Pointer to function name (ANSI).
NTSTATUS Status // NTSTATUS error value.
);
//
// Lsa string initialization routine.
//
void
InitLsaString(
PLSA_UNICODE_STRING LsaString, // Destination.
LPWSTR String // Source (Unicode).
);
//
// Displays the windows error string.
//
void
DisplayWinError(
LPSTR szAPI,
DWORD WinError
);
//----------------------------------------------------------------------
//
// Main function declaration.
//
int __cdecl wmain( int argc, wchar_t *argv[] )
{
LSA_HANDLE PolicyHandle;
NTSTATUS status;
PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo;
PWKSTA_INFO_100 pwkiWorkstationInfo;
DWORD netret;
//
// You need the local workstation name. Use NetWkstaGetInfo at level
// 100 to retrieve a WKSTA_INFO_100 structure.
//
// The wki100_computername field contains a pointer to a UNICODE
// string containing the local computer name.
//
netret = NetWkstaGetInfo( NULL, 100, (LPBYTE *)&pwkiWorkstationInfo);
if( netret == NERR_Success )
{
//
// We have the workstation name in:
// pwkiWorkstationInfo->wki100_computername
//
// Next, open the policy object for the local system using
// the OpenPolicy helper function described later in
// this source file.
//
status = OpenPolicy( NULL,
GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle);
//
// Error checking.
//
if( status )
{
DisplayNtStatus("OpenPolicy Error: ", status );
}
else
{
//
// You have a handle to the policy object. Now, get the
// domain information using LsaQueryInformationPolicy.
//
status = LsaQueryInformationPolicy( PolicyHandle,
PolicyPrimaryDomainInformation,
&ppdiDomainInfo);
if( status )
{
DisplayNtStatus(
"LsaQueryInformationPolicy Error: ",
status );
}
else
{
//
// Check the Sid pointer, if it is null, the
// workstation is either a stand-alone computer
// or a member of a workgroup.
//
if( ppdiDomainInfo->Sid )
{
//
// Member of a domain. Display it.
//
printf( "Member of Domain %S\n",
ppdiDomainInfo->Name.Buffer);
}
else
{
//
// Since the pointer to the SID was null, it
// could be either a stand-alone computer
// (ppdiDomainInfo->Name.Buffer matches the
// local machine name) or it could be part
// of a workgroup.
//
// Compare this string with the one returned
// by NetWkstaGetInfo.
//
if( wcsncmp( ppdiDomainInfo->Name.Buffer,
pwkiWorkstationInfo->wki100_computername,
wcslen( pwkiWorkstationInfo->wki100_computername)) )
{
//
// The wcsncmp returns non zero if
// the two strings do not match. This means
// that the workstation is part of a
// workgroup.
//
printf(" Member of workgroup %S\n",
ppdiDomainInfo->Name.Buffer);
}
else
printf("%S is a standalone workstation\n" ,
ppdiDomainInfo->Name.Buffer);
}
}
}
//
// Clean up all the memory buffers created by the LSA and
// Net* APIs.
//
NetApiBufferFree( pwkiWorkstationInfo );
LsaFreeMemory( (LPVOID)ppdiDomainInfo );
}
else DisplayNtStatus( "NetWkstaGetInfo Error: ", netret);
//
// Display a completion message.
//
printf("Execution Completed\n");
return 0;
}
//
// LsaOpenPolicy wrapper function.
//
NTSTATUS
OpenPolicy(
LPWSTR ServerName,
DWORD DesiredAccess,
PLSA_HANDLE PolicyHandle
)
{
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_UNICODE_STRING ServerString;
PLSA_UNICODE_STRING Server = NULL;
//
// Always initialize the object attributes to all zeroes.
//
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
if (ServerName != NULL) {
//
// Make a LSA_UNICODE_STRING out of the LPWSTR passed in.
//
InitLsaString(&ServerString, ServerName);
Server = &ServerString;
}
//
// Attempt to open the policy.
//
return LsaOpenPolicy(
Server,
&ObjectAttributes,
DesiredAccess,
PolicyHandle
);
}
//
// Simple status error display routine.
//
void
DisplayNtStatus(
LPSTR szAPI,
NTSTATUS Status
)
{
//
// Convert the NTSTATUS to Winerror. Then call DisplayWinError().
//
DisplayWinError(szAPI, LsaNtStatusToWinError(Status));
}
//
// Helper function to build LSA UNICODE strings.
//
void
InitLsaString(
PLSA_UNICODE_STRING LsaString,
LPWSTR String
)
{
DWORD StringLength;
if (String == NULL) {
LsaString->Buffer = NULL;
LsaString->Length = 0;
LsaString->MaximumLength = 0;
return;
}
StringLength = wcslen(String);
LsaString->Buffer = String;
LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
}
//
// Displays the error messages for a given code.
//
void
DisplayWinError(
LPSTR szAPI,
DWORD WinError
)
{
LPSTR MessageBuffer;
DWORD dwBufferLength;
//
// TODO: Get this fprintf out of here.
//
fprintf(stderr,"%s error!\n", szAPI);
if(dwBufferLength=FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
WinError,
GetUserDefaultLangID(),
(LPSTR) &MessageBuffer,
0,
NULL
))
{
DWORD dwBytesWritten; // unused
//
// Output message string on stderr.
//
WriteFile(
GetStdHandle(STD_ERROR_HANDLE),
MessageBuffer,
dwBufferLength,
&dwBytesWritten,
NULL
);
//
// Free the buffer allocated by the system.
//
LocalFree(MessageBuffer);
}
}
Additional query words:
Keywords : kbnetwork kbAPI kbWinOS2000 kbSDKPlatform kbNetAPI kbGrpNet
Version : WINDOWS:; winnt:3.5,3.51,4.0
Platform : WINDOWS winnt
Issue type : kbhowto