|
|
//+----------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2001
//
// File: CompName.h
//
// Contents: Definitions for the computer name management code.
//
// History: 20-April-2001 EricB Created
//
//-----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "netdom.h"
#include "CompName.h"
//+----------------------------------------------------------------------------
//
// Function: NetDomComputerNames
//
// Synopsis: Entry point for the computer name command.
//
// Arguments: [rgNetDomArgs] - The command line argument array.
//
//-----------------------------------------------------------------------------
DWORD NetDomComputerNames(ARG_RECORD * rgNetDomArgs) { DWORD Win32Err = ERROR_SUCCESS;
Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs, eObject, eCommUserNameO, eCommPasswordO, eCommUserNameD, eCommPasswordD, eCommAdd, eCommRemove, eCompNameMakePri, eCompNameEnum, eCommVerify, eCommVerbose, eArgEnd); if (ERROR_SUCCESS != Win32Err) { DisplayHelp(ePriCompName); return Win32Err; }
PWSTR pwzMachine = rgNetDomArgs[eObject].strValue;
if (!pwzMachine) { DisplayHelp(ePriCompName); return ERROR_INVALID_PARAMETER; }
//
// Get the users and passwords if they were entered.
//
ND5_AUTH_INFO MachineUser = {0}, DomainUser = {0};
if (CmdFlagOn(rgNetDomArgs, eCommUserNameO)) { Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs, eCommUserNameO, pwzMachine, &MachineUser); if (ERROR_SUCCESS != Win32Err) { DisplayHelp(ePriCompName); return Win32Err; } }
if (CmdFlagOn(rgNetDomArgs, eCommUserNameD)) { Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs, eCommUserNameD, pwzMachine, &DomainUser); if (ERROR_SUCCESS != Win32Err) { DisplayHelp(ePriCompName); goto CompNameExit; } }
//
// See which name operation is specified.
//
bool fHaveOp = false; PWSTR pwzOp = NULL; NETDOM_ARG_ENUM eOp = eArgNull, eBadOp = eArgNull;
if (CmdFlagOn(rgNetDomArgs, eCommAdd)) { Win32Err = NetDompGetArgumentString(rgNetDomArgs, eCommAdd, &pwzOp); if (NO_ERROR == Win32Err) { eOp = eCommAdd; } }
if (CmdFlagOn(rgNetDomArgs, eCommRemove)) { Win32Err = NetDompGetArgumentString(rgNetDomArgs, eCommRemove, &pwzOp); if (NO_ERROR == Win32Err) { if (eArgNull == eOp) { eOp = eCommRemove; } else { eBadOp = eCommRemove; } } }
if (CmdFlagOn(rgNetDomArgs, eCompNameMakePri)) { Win32Err = NetDompGetArgumentString(rgNetDomArgs, eCompNameMakePri, &pwzOp); if (NO_ERROR == Win32Err) { if (eArgNull == eOp) { eOp = eCompNameMakePri; } else { eBadOp = eCompNameMakePri; } } }
if (CmdFlagOn(rgNetDomArgs, eCompNameEnum)) { Win32Err = NetDompGetArgumentString(rgNetDomArgs, eCompNameEnum, &pwzOp); if (NO_ERROR == Win32Err) { if (eArgNull == eOp) { eOp = eCompNameEnum; } else { eBadOp = eCompNameEnum; } } }
if (CmdFlagOn(rgNetDomArgs, eCommVerify)) { if (eArgNull == eOp) { eOp = eCommVerify; } else { eBadOp = eCommVerify; } }
if (eArgNull != eBadOp) { ASSERT(rgNetDomArgs[eBadOp].strArg1); NetDompDisplayUnexpectedParameter(rgNetDomArgs[eBadOp].strArg1); DisplayHelp(ePriCompName); Win32Err = ERROR_INVALID_PARAMETER; goto CompNameExit; }
if (eArgNull == eOp) { DisplayHelp(ePriCompName); Win32Err = ERROR_INVALID_PARAMETER; goto CompNameExit; }
if (CmdFlagOn(rgNetDomArgs, eCommUserNameO)) { LOG_VERBOSE((MSG_VERBOSE_ESTABLISH_SESSION, pwzMachine)); Win32Err = NetpManageIPCConnect(pwzMachine, MachineUser.User, MachineUser.Password, NETSETUPP_CONNECT_IPC); }
if (NO_ERROR != Win32Err) { goto CompNameExit; }
int cchName = 0; DWORD size = CNLEN + 1; WCHAR wzNBname[CNLEN + 1] = {0};
// To ensure that netdom.exe runs on Win2K, we do
// dynamic loading of the following API that are available
// only in later versions of netapi32.dll
HMODULE hm = NULL; if ( eOp == eCommAdd || eOp == eCommRemove || eOp == eCompNameMakePri || eOp == eCompNameEnum ) { hm = LoadLibrary ( L"netapi32.dll" ); if ( !hm ) { Win32Err = GetLastError (); NetDompDisplayMessage ( MSG_NETAPI32_LOAD_FAILED ); goto CompNameExit; } } //
// Do the operation.
//
switch (eOp) { case eCommAdd:
{ typedef DWORD (*NetAddAltCompName) ( LPCWSTR Server, LPCWSTR AlternateName, LPCWSTR DomainAccount, LPCWSTR DomainAccountPasswd, ULONG Reserved );
NetAddAltCompName pNetAddAltCompName = NULL; pNetAddAltCompName = ( NetAddAltCompName ) GetProcAddress ( hm, "NetAddAlternateComputerName" );
if ( !pNetAddAltCompName ) { NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL ); Win32Err = ERROR_CALL_NOT_IMPLEMENTED; goto CompNameExit; }
// NOTICE-2002/03/04-ericb - SecurityPush: pointer is verified before checking
// string's length
if (!rgNetDomArgs[eCommAdd].strValue || !wcslen(rgNetDomArgs[eCommAdd].strValue)) { DisplayHelp(ePriCompName); Win32Err = ERROR_INVALID_PARAMETER; goto CompNameExit; }
// The name being added should be a Fully Qualified DNS Name (FQDN)
// So check if the name has dots (.) in it.
if ( wcschr ( rgNetDomArgs[eCommAdd].strValue, L'.' ) == NULL ) {
// Create and load the Response strings
WCHAR wzYes[NETDOM_STR_LEN], wzNo[NETDOM_STR_LEN];
if (!LoadString(g_hInstance, IDS_YES, wzYes, NETDOM_STR_LEN) || !LoadString(g_hInstance, IDS_NO, wzNo, NETDOM_STR_LEN)) { DisplayOutput ( L"LoadString FAILED!" ); Win32Err = ERROR_RESOURCE_NAME_NOT_FOUND; goto CompNameExit; }
PWSTR pwszResponse = NULL; BOOL Proceed = FALSE; // Display warning that name being added is not a Full Qualified DNS name
NetDompDisplayMessage ( MSG_COMPNAME_ADD_NOT_FQDN, rgNetDomArgs[eCommAdd].strValue );
// Give the user 3 chances to get in a valid response
int i = 0; for ( ; i < 3; i ++ ) { // Prompt user to Continue ( Y or N )
NetDompDisplayMessage ( MSG_PROMPT_PROCEED, NULL );
if ( -1 != ReadFromIn ( &pwszResponse ) ) { //Compare the first char of response with Yes and No strings
if ( _wcsnicmp ( pwszResponse, wzYes, 1 ) == 0 ) { Proceed = TRUE; break; } if ( _wcsnicmp ( pwszResponse, wzNo, 1 ) == 0 ) { Proceed = FALSE; break; } } else { // Unable to get response from user (typically when input is too large)
// Blank line
DisplayOutput ( L"" ); NetDompDisplayMessage ( MSG_PROMPT_FAILED ); Proceed = FALSE; Win32Err = ERROR_CANCELLED; break; } if ( pwszResponse ) { LocalFree ( pwszResponse ); pwszResponse = NULL; } } if ( i == 3 ) { // Correct response was not entered after 3 tries
DisplayOutput ( L"" ); NetDompDisplayMessage ( MSG_PROMPT_FAILED ); Proceed = FALSE; Win32Err = ERROR_CANCELLED; } LocalFree ( pwszResponse ); DisplayOutput ( L"" ); if ( !Proceed ) { NetDompDisplayMessage ( MSG_COMPNAME_ADD_NOT_COMPLETED ); goto CompNameExit; } }
// If the alternative name being added is longer than 15 chars and
// if it is made the primary name, the corresponding NETBIOS will
// be formed by truncating it to its first 15 chars.
// Inform the user about this case
// Obtain the Netbios name from the DNS name
if ( !DnsHostnameToComputerName( rgNetDomArgs[eCommAdd].strValue, wzNBname, &size ) ) { NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, rgNetDomArgs[eCommAdd].strValue ); Win32Err = GetLastError(); goto CompNameExit; } if ( ( cchName = (int)wcslen( wzNBname ) ) == 0 ) { NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, rgNetDomArgs[eCommAdd].strValue ); Win32Err = ERROR_INVALID_COMPUTERNAME; goto CompNameExit; }
// If the NetBIOS name is truncated, display warning
if ( cchName < (int) wcscspn( rgNetDomArgs[eCommAdd].strValue, L"." ) ) { NetDompDisplayMessage( MSG_COMPNAME_ADD_NETBIOS_TRUNCATE, CNLEN, wzNBname ); }
Win32Err = pNetAddAltCompName ( pwzMachine, rgNetDomArgs[eCommAdd].strValue, DomainUser.User, DomainUser.Password, 0);
if (NO_ERROR == Win32Err) { NetDompDisplayMessage(MSG_COMPNAME_ADD, rgNetDomArgs[eCommAdd].strValue); } else { NetDompDisplayMessage(MSG_COMPNAME_ADD_FAIL, rgNetDomArgs[eCommAdd].strValue); NetDompDisplayErrorMessage(Win32Err); if (ERROR_CAN_NOT_COMPLETE == Win32Err || ERROR_DS_NOT_SUPPORTED == Win32Err) { NetDompDisplayMessage(MSG_COMPNAME_ADD_FAIL_VERSION); } } break; }
case eCommRemove: { typedef DWORD (*NetRemoveAltCompName) ( LPCWSTR Server, LPCWSTR AlternateName, LPCWSTR DomainAccount, LPCWSTR DomainAccountPasswd, ULONG Reserved );
NetRemoveAltCompName pNetRemoveAltCompName = NULL; pNetRemoveAltCompName = ( NetRemoveAltCompName ) GetProcAddress ( hm, "NetRemoveAlternateComputerName" );
if ( !pNetRemoveAltCompName ) { NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL ); Win32Err = ERROR_CALL_NOT_IMPLEMENTED; goto CompNameExit; }
// NOTICE-2002/03/04-ericb - SecurityPush: pointer is verified before checking
// string's length
if (!rgNetDomArgs[eCommRemove].strValue || !wcslen(rgNetDomArgs[eCommRemove].strValue)) { DisplayHelp(ePriCompName); Win32Err = ERROR_INVALID_PARAMETER; goto CompNameExit; } Win32Err = pNetRemoveAltCompName( pwzMachine, rgNetDomArgs[eCommRemove].strValue, DomainUser.User, DomainUser.Password, 0); if (NO_ERROR == Win32Err) { NetDompDisplayMessage(MSG_COMPNAME_REM, rgNetDomArgs[eCommRemove].strValue); } else { NetDompDisplayMessage(MSG_COMPNAME_REM_FAIL, rgNetDomArgs[eCommRemove].strValue); NetDompDisplayErrorMessage(Win32Err); } break; } case eCompNameMakePri: { typedef DWORD (*NetMakeCompNamePri) ( LPCWSTR Server, LPCWSTR AlternateName, LPCWSTR DomainAccount, LPCWSTR DomainAccountPasswd, ULONG Reserved );
NetMakeCompNamePri pNetMakeCompNamePri = NULL; pNetMakeCompNamePri = ( NetMakeCompNamePri ) GetProcAddress ( hm, "NetSetPrimaryComputerName" );
if ( !pNetMakeCompNamePri ) { NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL ); Win32Err = ERROR_CALL_NOT_IMPLEMENTED; goto CompNameExit; }
// NOTICE-2002/03/04-ericb - SecurityPush: pointer is verified before checking
// string's length
if (!rgNetDomArgs[eCompNameMakePri].strValue || !wcslen(rgNetDomArgs[eCompNameMakePri].strValue)) { DisplayHelp(ePriCompName); Win32Err = ERROR_INVALID_PARAMETER; goto CompNameExit; } // If the name being made primary is longer than 15 chars
// the corresponding NETBIOS name will
// be formed by truncating it to its first 15 chars.
// Inform the user about this case
// Obtain the Netbios name from the DNS name
if ( !DnsHostnameToComputerName( rgNetDomArgs[eCompNameMakePri].strValue, wzNBname, &size ) ) { NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, rgNetDomArgs[eCompNameMakePri].strValue ); Win32Err = GetLastError(); goto CompNameExit; } if ( ( cchName = (int)wcslen( wzNBname ) ) == 0 ) { NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, rgNetDomArgs[eCompNameMakePri].strValue ); Win32Err = ERROR_INVALID_COMPUTERNAME; goto CompNameExit; }
// If the NetBIOS name is truncated, display warning
if ( cchName < (int)wcscspn( rgNetDomArgs[eCompNameMakePri].strValue, L"." ) ) { NetDompDisplayMessage( MSG_COMPNAME_MAKE_PRI_NETBIOS_TRUNCATE, CNLEN, wzNBname ); }
Win32Err = pNetMakeCompNamePri( pwzMachine, rgNetDomArgs[eCompNameMakePri].strValue, DomainUser.User, DomainUser.Password, 0); if (NO_ERROR == Win32Err) { NetDompDisplayMessage(MSG_COMPNAME_MAKEPRI, rgNetDomArgs[eCompNameMakePri].strValue); } else { NetDompDisplayMessage(MSG_COMPNAME_MAKEPRI_FAIL, rgNetDomArgs[eCompNameMakePri].strValue); NetDompDisplayErrorMessage(Win32Err);
//Special check for Account already exists error, this can happen
//if there is a Computer Account or a Server Object with the same name
//already present in AD
if ( Win32Err == NERR_UserExists ) { NetDompDisplayMessage ( MSG_COMPNAME_ACCT_EXISTS, wzNBname ); } } break; }
case eCompNameEnum: { typedef DWORD (*NetEnumCompName) ( LPCWSTR Server, NET_COMPUTER_NAME_TYPE NameType, ULONG Reserved, PDWORD EntryCount, LPWSTR **ComputerNames );
NetEnumCompName pNetEnumCompName = NULL; pNetEnumCompName = ( NetEnumCompName ) GetProcAddress ( hm, "NetEnumerateComputerNames" );
if ( !pNetEnumCompName ) { NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL ); Win32Err = ERROR_CALL_NOT_IMPLEMENTED; goto CompNameExit; }
NET_COMPUTER_NAME_TYPE NameType = NetAllComputerNames; WCHAR wzBuf[MAX_PATH+1]; DWORD dwMsgID = MSG_COMPNAME_ENUMALL; int stringLength = 0;
// NOTICE-2002/03/04-ericb - SecurityPush: pointer is verified before checking
// string's length
if (rgNetDomArgs[eCompNameEnum].strValue && wcslen(rgNetDomArgs[eCompNameEnum].strValue)) { // NOTICE-2002/03/04-ericb - SecurityPush: return from LoadString is
// string length, save it for use below after checking that it doesn't
// equal MAX_PATH. (Done by shasan 4/10/2002)
stringLength = LoadString(g_hInstance, IDS_ENUM_ALT, wzBuf, MAX_PATH); if ( !stringLength ) { Win32Err = GetLastError(); goto CompNameExit; } // Check for truncation
if ( stringLength == MAX_PATH ) { Win32Err = ERROR_INSUFFICIENT_BUFFER; goto CompNameExit; } // NOTICE-2002/03/04-ericb - SecurityPush: use _wcsnicmp with length of
// wzBuf from above. (Done by shasan 4/10/2002)
if (_wcsnicmp(wzBuf, rgNetDomArgs[eCompNameEnum].strValue, stringLength) == 0) { NameType = NetAlternateComputerNames; dwMsgID = MSG_COMPNAME_ENUMALT; } else { // NOTICE-2002/03/04-ericb - SecurityPush: return from LoadString is
// string length, save it for use below after checking that it doesn't equal MAX_PATH. (Done by shasan 4/10/2002)
stringLength = LoadString(g_hInstance, IDS_ENUM_PRI, wzBuf, MAX_PATH ); if ( !stringLength ) { Win32Err = GetLastError(); goto CompNameExit; } // Check for truncation
if ( stringLength == MAX_PATH ) { Win32Err = ERROR_INSUFFICIENT_BUFFER; goto CompNameExit; }
// NOTICE-2002/03/04-ericb - SecurityPush: use _wcsnicmp with length of
// wzBuf from above. (Done by shasan 4/10/2002)
if (_wcsnicmp(wzBuf, rgNetDomArgs[eCompNameEnum].strValue, stringLength ) == 0) { NameType = NetPrimaryComputerName; dwMsgID = MSG_COMPNAME_ENUMPRI; } else { // NOTICE-2002/03/04-ericb - SecurityPush: return from LoadString is
// string length, save it for use below after checking that it doesn't equal MAX_PATH.(Done by shasan 4/10/2002)
stringLength = LoadString(g_hInstance, IDS_ENUM_ALL, wzBuf, MAX_PATH); if ( !stringLength ) { Win32Err = GetLastError(); goto CompNameExit; } // Check for truncation
if ( stringLength == MAX_PATH ) { Win32Err = ERROR_INSUFFICIENT_BUFFER; goto CompNameExit; }
// NOTICE-2002/03/04-ericb - SecurityPush: use _wcsnicmp with length of
// wzBuf from above. (Done by shasan 4/10/2002)
if (_wcsnicmp(wzBuf, rgNetDomArgs[eCompNameEnum].strValue, stringLength) == 0) { NameType = NetAllComputerNames; dwMsgID = MSG_COMPNAME_ENUMALL; } else { NetDompDisplayUnexpectedParameter(rgNetDomArgs[eCompNameEnum].strValue); DisplayHelp(ePriCompName); Win32Err = ERROR_INVALID_PARAMETER; goto CompNameExit; } } } } DWORD dwCount = 0; PWSTR * rgpwzNames = NULL; DBG_VERBOSE(("NetEnumerateComputerNames(%ws, %d, 0, etc)\n", pwzMachine, NameType));
Win32Err = pNetEnumCompName ( pwzMachine, NameType, 0, &dwCount, &rgpwzNames); if (NO_ERROR != Win32Err) { NetDompDisplayErrorMessage(Win32Err); goto CompNameExit; }
NetDompDisplayMessage(dwMsgID); for (DWORD i = 0; i < dwCount; i++) { // NOTICE-2002/03/04-ericb - SecurityPush: fail if rgpwzNames[i] is not
// a valid string, don't just assert. (Done by shasan 4/10/2002)
if ( ! rgpwzNames[i] ) { ASSERT(rgpwzNames[i]); Win32Err = ERROR_FUNCTION_FAILED; goto CompNameExit; }
// NOTICE-2002/03/04-ericb - SecurityPush: Use varg.cxx output routine instead of printf. (Done by shasan 4/10/2002)
DisplayOutput ( rgpwzNames[i] ); } if (rgpwzNames) { NetApiBufferFree(rgpwzNames); } } break;
case eCommVerify: Win32Err = VerifyComputerNameRegistrations(pwzMachine, &DomainUser); break;
default: ASSERT(FALSE); Win32Err = ERROR_INVALID_PARAMETER; goto CompNameExit; }
CompNameExit:
if (CmdFlagOn(rgNetDomArgs, eCommUserNameO)) { LOG_VERBOSE((MSG_VERBOSE_DELETE_SESSION, pwzMachine)); NetpManageIPCConnect(pwzMachine, MachineUser.User, MachineUser.Password, NETSETUPP_DISCONNECT_IPC); }
if ( hm ) { FreeLibrary ( hm ); } NetDompFreeAuthIdent(&MachineUser); NetDompFreeAuthIdent(&DomainUser);
return Win32Err; }
//+----------------------------------------------------------------------------
//
// Function: VerifyComputerNameRegistrations
//
// Synopsis: Check that each computer name has a DNS a record and an SPN.
//
//-----------------------------------------------------------------------------
DWORD VerifyComputerNameRegistrations(PCWSTR pwzMachine, ND5_AUTH_INFO * pDomainUser) { DWORD Win32Err = NO_ERROR, dwCount = 0; PWSTR * rgpwzNames = NULL;
HMODULE hm = NULL; HMODULE hm2 = NULL;
//
// See if the computer is joined to a domain.
//
PDOMAIN_CONTROLLER_INFO pDcInfo = NULL; PWSTR * rgwzSPNs = NULL;
LOG_VERBOSE((MSG_COMPNAME_CHECKING_JOIN, pwzMachine)); //
// It's joined, get a DC for the domain. Specify DS_DIRECTORY_SERVICE_REQUIRED
// because we only check for SPNs if the domain is uplevel (supports AD).
//
Win32Err = DsGetDcName(pwzMachine, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED, &pDcInfo);
if (NO_ERROR != Win32Err) { if (ERROR_NO_SUCH_DOMAIN == Win32Err) { // Its joined to a downlevel domain. There is no SPN data.
//
LOG_VERBOSE((MSG_COMPNAME_NOT_UPLEVEL_JOINED)); } else if (RPC_S_UNKNOWN_IF == Win32Err) { LOG_VERBOSE((MSG_COMPNAME_NOT_JOINED)); } else if (RPC_S_SERVER_UNAVAILABLE == Win32Err) { NetDompDisplayMessage(MSG_COMPNAME_COMPUTER_NOT_FOUND, pwzMachine); return Win32Err; } else { NetDompDisplayErrorMessage(Win32Err); return Win32Err; } } else { PWSTR pwzFilter = NULL; PLDAP pLdap = NULL; LDAPMessage * pMessage = NULL; WKSTA_INFO_100 * pInfo = NULL;
do { if (!pDcInfo || !pDcInfo->DomainControllerName) { ASSERT(FALSE); return ERROR_INVALID_FUNCTION; }
LOG_VERBOSE((MSG_COMPNAME_READING_SPNS, pDcInfo->DomainName));
// Read the downlevel name (SAM account name) of the computer.
//
Win32Err = NetWkstaGetInfo(const_cast<PWSTR>(pwzMachine), 100, (PBYTE *)&pInfo);
// NOTICE-2002/03/04-ericb - SecurityPush: check return data from NetWkstaGetInfo (done)
if (ERROR_SUCCESS != Win32Err || !pInfo || !pInfo->wki100_computername) { // NOTICE-2002/03/04-ericb need better message
// ( shasan 4/16/02 - No change in mesg needed as discussed with levone )
NetDompDisplayMessageAndError(MSG_COMPNAME_NO_PRINAME, Win32Err, pwzMachine); break; }
// There could be multiple computer objects with the same CN (in
// different containers), but only one computer object will have this
// SAM-Account-Name.
//
WCHAR wzFilterFormat[] = L"(&(objectCategory=computer)(sAMAccountName=%s$))";
// NOTICE-2002/03/04-ericb - SecurityPush: find length of static string
// using sizeof(wzFilterFormat)/sizeof(WCHAR)-1. Find length of
// pInfo->wki100_computername using StringCchLength with a max length value.
// (fixed by shasan 4/12/2002)
size_t nameLength = 0; HRESULT hr = NULL; hr = StringCchLengthW ( pInfo->wki100_computername, MAX_COMPUTERNAME_LENGTH + 1, &nameLength ); if ( ! SUCCEEDED ( hr ) ) { Win32Err = HRESULT_CODE ( hr ); NetDompDisplayErrorMessage ( Win32Err ); NetApiBufferFree(pDcInfo); return Win32Err; }
pwzFilter = (PWSTR)LocalAlloc(LPTR, ( (sizeof ( wzFilterFormat ) / sizeof ( WCHAR ) - 1) + nameLength + 1 ) * sizeof(WCHAR));
if (!pwzFilter) { NetDompDisplayErrorMessage(ERROR_NOT_ENOUGH_MEMORY); NetApiBufferFree(pDcInfo); return ERROR_NOT_ENOUGH_MEMORY; }
// NOTICE-2002/03/04-ericb - SecurityPush: buffer allocated large enough to
// hold the combined strings.
wsprintf(pwzFilter, wzFilterFormat, pInfo->wki100_computername);
Win32Err = NetDompLdapBind(pDcInfo->DomainControllerName + 2, pDomainUser->pwzUsersDomain, pDomainUser->pwzUserWoDomain, pDomainUser->Password, LDAP_AUTH_NEGOTIATE, &pLdap);
if (ERROR_SUCCESS != Win32Err) { if (ERROR_WRONG_PASSWORD == Win32Err) { NetDompDisplayMessage(MSG_COMPNAME_SPN_NO_ACCESS); Win32Err = NO_ERROR; } break; }
PWSTR Attrib[2] = { L"servicePrincipalName", NULL }; PWSTR pwzDomainDn = NULL;
Win32Err = NetDompLdapReadOneAttribute(pLdap, NULL, // equivalent to L"RootDSE",
L"defaultNamingContext", &pwzDomainDn);
if (ERROR_SUCCESS != Win32Err) { break; }
LDAPMessage * pEntry;
Win32Err = LdapMapErrorToWin32(ldap_search_s(pLdap, pwzDomainDn, LDAP_SCOPE_SUBTREE, pwzFilter, Attrib, 0, &pMessage)); NetApiBufferFree(pwzDomainDn);
if (ERROR_SUCCESS != Win32Err) { break; }
pEntry = ldap_first_entry(pLdap, pMessage);
if (!pEntry) { NetDompDisplayMessage(MSG_COMPNAME_OBJECT_NOT_FOUND, pInfo->wki100_computername); NetDompDisplayMessage(MSG_COMPNAME_SPN_SEARCH_FAILED); break; }
rgwzSPNs = ldap_get_values(pLdap, pEntry, Attrib[0]); if (!rgwzSPNs) { LOG_VERBOSE((MSG_COMPNAME_SPN_SEARCH_FAILED)); } } while (false);
if (Win32Err != ERROR_SUCCESS) { NetDompDisplayMessage(MSG_COMPNAME_SPN_SEARCH_FAILED); NetDompDisplayErrorMessage(Win32Err); } if (pwzFilter) { LocalFree(pwzFilter); } if (pInfo) { NetApiBufferFree(pInfo); } if (pMessage) { ldap_msgfree(pMessage); } if (pLdap) { NetDompLdapUnbind(pLdap); } if (pDcInfo) { NetApiBufferFree(pDcInfo); } }
// To ensure that netdom.exe runs on Win2K, we do
// dynamic loading of the following API that are available
// only in later versions of netapi32.dll
hm = LoadLibrary ( L"netapi32.dll" ); if ( !hm ) { Win32Err = GetLastError (); NetDompDisplayMessage ( MSG_NETAPI32_LOAD_FAILED ); return Win32Err; }
typedef DWORD (*NetEnumCompName) ( LPCWSTR Server, NET_COMPUTER_NAME_TYPE NameType, ULONG Reserved, PDWORD EntryCount, LPWSTR **ComputerNames );
NetEnumCompName pNetEnumCompName = NULL; pNetEnumCompName = ( NetEnumCompName ) GetProcAddress ( hm, "NetEnumerateComputerNames" );
if ( !pNetEnumCompName ) { NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL ); Win32Err = ERROR_CALL_NOT_IMPLEMENTED; return Win32Err; }
Win32Err = pNetEnumCompName (pwzMachine, NetAllComputerNames, 0, &dwCount, &rgpwzNames);
if ( hm ) { FreeLibrary ( hm ); }
if (NO_ERROR != Win32Err) { NetDompDisplayErrorMessage(Win32Err); return Win32Err; }
const WCHAR wzHost[] = L"HOST/"; // NOTICE-2002/03/04-ericb - SecurityPush: getting length of a static string, use
// sizeof(wzHost)/sizeof(WCHAR) - 1 rather than wcslen(). (done)
const size_t cchHost = sizeof(wzHost) / sizeof(WCHAR) - 1; bool fDnsFailed = false, fSpnFailed = false; size_t cchName = 0; HRESULT hr = NULL; for (DWORD i = 0; i < dwCount; i++) { ASSERT(rgpwzNames[i]); LOG_VERBOSE((MSG_COMPNAME_VERIFY_START, rgpwzNames[i])); //
// Check the DNS registration first.
//
PDNS_RECORD rgARecs = NULL;
Win32Err = DnsQuery_W(rgpwzNames[i], DNS_TYPE_A, DNS_QUERY_BYPASS_CACHE, NULL, &rgARecs, NULL);
if (ERROR_SUCCESS != Win32Err || !rgARecs) { Win32Err = DnsQuery_W(rgpwzNames[i], DNS_TYPE_AAAA, DNS_QUERY_BYPASS_CACHE, NULL, &rgARecs, NULL); }
if (ERROR_SUCCESS != Win32Err || !rgARecs) { NetDompDisplayMessageAndError(MSG_COMPNAME_DNS_FAILED, Win32Err, rgpwzNames[i]); fDnsFailed = true; } else { // To ensure that netdom.exe runs on Win2K, we do
// dynamic loading of the following API that are available
// only in later versions of dnsapi.dll
hm2 = LoadLibrary ( L"dnsapi.dll" ); if ( !hm ) { Win32Err = GetLastError (); NetDompDisplayMessage ( MSG_DNSAPI_LOAD_FAILED ); return Win32Err; }
typedef void ( *DnsFreeType ) ( PVOID pData, DNS_FREE_TYPE FreeType ); DnsFreeType pDnsFree = NULL;
pDnsFree = ( DnsFreeType ) GetProcAddress ( hm2, "DnsFree" );
if ( !pDnsFree ) { NetDompDisplayMessage ( MSG_WRONG_DNSAPI_DLL ); Win32Err = ERROR_CALL_NOT_IMPLEMENTED; return Win32Err; }
pDnsFree ( rgARecs, DnsFreeRecordListDeep );
if ( hm2 ) { FreeLibrary ( hm2 ); } } //
// Check the SPN registration. Only checking the Host SPN.
//
bool fFound = false; size_t cchSPN = 0;
if (rgwzSPNs) { for (int j = 0; rgwzSPNs[j]; j++) { // NOTICE-2002/03/04-ericb - SecurityPush: use StringCchLength here. (fixed shasan 4/15/02)
hr = StringCchLength ( rgwzSPNs[j], DNS_MAX_NAME_LENGTH + cchHost + 1, &cchSPN ); if ( !SUCCEEDED (hr) ) { NetDompDisplayErrorMessage ( HRESULT_CODE ( hr ) ); break; } if ( cchSPN < cchHost) { continue; } // NOTICE-2002/03/04-ericb - SecurityPush: length already checked..
if (_wcsnicmp(wzHost, rgwzSPNs[j], cchHost) != 0) { continue; } PWSTR pwz = rgwzSPNs[j] + cchHost; // NOTICE-2002/03/04-ericb - SecurityPush: use _wcsnicmp here after calling
// StringCchLength on pwz. (fixed shasan 4/15/02)
hr = StringCchLengthW ( pwz, DNS_MAX_NAME_LENGTH + 1, &cchName ); if ( !SUCCEEDED (hr) ) { NetDompDisplayErrorMessage ( HRESULT_CODE ( hr ) ); break; }
if (_wcsicmp(rgpwzNames[i], pwz) == 0) { fFound = true; break; } } if (!fFound) { NetDompDisplayMessage(MSG_COMPNAME_SPN_NOT_FOUND, rgpwzNames[i]); fSpnFailed = true; } } else { fSpnFailed = true; } }
if (!fDnsFailed) { NetDompDisplayMessage(MSG_COMPNAME_VERIFY_DNS_OK); } if (!fSpnFailed) { NetDompDisplayMessage(MSG_COMPNAME_VERIFY_SPN_OK); }
if (rgpwzNames) { NetApiBufferFree(rgpwzNames); } if (rgwzSPNs) { ldap_value_free(rgwzSPNs); }
return NO_ERROR; }
|