You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1112 lines
38 KiB
1112 lines
38 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
|