Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1498 lines
45 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: ncident.cpp
//
// Contents: Implementation of CNetCfgIdentification.
//
// Notes:
//
// History: 21 Mar 1997 danielwe Created
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include <nceh.h>
#include "ncfgval.h"
#include "ncident.h"
#include "ncmisc.h"
#include "ncreg.h"
#include "nsbase.h"
#include "nccom.h"
#include "ncerror.h"
EXTERN_C extern const INT MAX_WORKGROUPNAME_LENGTH;
EXTERN_C extern const INT MAX_DOMAINNAME_LENGTH;
//+---------------------------------------------------------------------------
//
// Function: DeleteStringAndSetNull
//
// Purpose: Frees the given string with delete, and sets it to
// NULL before exiting.
//
// Arguments:
// pszw [in, out] Pointer to string to be freed. The pointer is set to
// NULL before the function exits.
//
// Returns: Nothing.
//
// Author: danielwe 1 Apr 1997
//
// Notes:
//
inline VOID DeleteStringAndSetNull(PWSTR *pszw)
{
AssertSz(pszw, "Param is NULL!");
delete *pszw;
*pszw = NULL;
}
inline HRESULT HrNetValidateName(IN PCWSTR lpMachine,
IN PCWSTR lpName,
IN PCWSTR lpAccount,
IN PCWSTR lpPassword,
IN NETSETUP_NAME_TYPE NameType)
{
NET_API_STATUS nerr;
nerr = NetValidateName(const_cast<PWSTR>(lpMachine),
const_cast<PWSTR>(lpName),
const_cast<PWSTR>(lpAccount),
const_cast<PWSTR>(lpPassword),
NameType);
TraceError("NetValidateName", HRESULT_FROM_WIN32(nerr));
return HrFromNerr(nerr);
}
inline HRESULT HrNetJoinDomain(IN PWSTR lpMachine,
IN PWSTR lpMachineObjectOU,
IN PWSTR lpDomain,
IN PWSTR lpAccount,
IN PWSTR lpPassword,
IN DWORD fJoinOptions)
{
NET_API_STATUS nerr;
HRESULT hr;
if ( fJoinOptions & NETSETUP_JOIN_DOMAIN )
{
hr = HrNetValidateName( lpMachine, lpDomain, lpAccount,
lpPassword, NetSetupDomain );
}
else
{
hr = HrNetValidateName( lpMachine, lpDomain, lpAccount,
lpPassword, NetSetupWorkgroup );
}
if (SUCCEEDED(hr))
{
nerr = NetJoinDomain(lpMachine, lpDomain, lpMachineObjectOU,
lpAccount, lpPassword, fJoinOptions);
TraceError("NetJoinDomain", HRESULT_FROM_WIN32(nerr));
hr = HrFromNerr(nerr);
}
return hr;
}
inline HRESULT HrNetRenameInDomain(IN PWSTR lpMachine,
IN PWSTR lpNewMachine,
IN PWSTR lpAccount,
IN PWSTR lpPassword,
IN DWORD fJoinOptions)
{
NET_API_STATUS nerr;
nerr = NetRenameMachineInDomain(lpMachine, lpNewMachine, lpAccount,
lpPassword, fJoinOptions);
TraceError("NetRenameMachineInDomain", HRESULT_FROM_WIN32(nerr));
return HrFromNerr(nerr);
}
inline HRESULT HrNetUnjoinDomain(IN PWSTR lpAccount,
IN PWSTR lpPassword,
IN DWORD fJoinOptions)
{
NET_API_STATUS nerr;
nerr = NetUnjoinDomain(NULL,lpAccount, lpPassword, fJoinOptions);
TraceError("NetUnjoinDomain", HRESULT_FROM_WIN32(nerr));
return HrFromNerr(nerr);
}
inline HRESULT HrNetGetJoinInformation(IN PWSTR lpNameBuffer,
OUT LPDWORD lpNameBufferSize,
OUT PNETSETUP_JOIN_STATUS BufferType)
{
NET_API_STATUS nerr;
PWSTR JoinBuff = NULL;
nerr = NetGetJoinInformation(NULL, &JoinBuff, BufferType);
if ( nerr == NERR_Success ) {
if ( *BufferType == NetSetupUnjoined ) {
*lpNameBufferSize = 0;
*lpNameBuffer = UNICODE_NULL;
} else {
if ( *lpNameBufferSize >= ( wcslen( JoinBuff ) +1 ) * sizeof( WCHAR ) ) {
wcscpy( lpNameBuffer, JoinBuff );
}
*lpNameBufferSize = wcslen( JoinBuff ) +1;
NetApiBufferFree( JoinBuff );
}
}
TraceError("NetGetJoinInformation", HRESULT_FROM_WIN32(nerr));
return HrFromNerr(nerr);
}
#ifdef DBG
BOOL CNetCfgIdentification::FIsJoinedToDomain()
{
HRESULT hr = S_OK;
NETSETUP_JOIN_STATUS js;
WCHAR wszBuffer[256];
DWORD cchBuffer = celems(wszBuffer);
hr = HrNetGetJoinInformation(wszBuffer, &cchBuffer, &js);
if (SUCCEEDED(hr))
{
if (js == NetSetupUnjoined)
{
// If we're as yet unjoined, only make sure that we marked our
// internal state as being joined to a workgroup called "WORKGROUP"
AssertSz(m_jsCur == NetSetupWorkgroupName, "We're unjoined but not "
"joined to a workgroup!");
AssertSz(m_szwCurDWName, "No current domain or "
"workgroup name?");
AssertSz(!lstrcmpiW(m_szwCurDWName,
SzLoadIds(IDS_WORKGROUP)),
"Workgroup name is not generic!");
}
else
{
AssertSz(js == m_jsCur, "Join status is not what we think it is!!");
}
}
TraceError("CNetCfgIdentification::FIsJoinedToDomain - "
"HrNetGetJoinInformation", hr);
return (m_jsCur == NetSetupDomainName);
}
#endif
//+---------------------------------------------------------------------------
//
// Function: HrFromNerr
//
// Purpose: Converts a NET_API_STATUS code into a NETCFG_E_* HRESULT
// value.
//
// Arguments:
// nerr [in] Status code to convert.
//
// Returns: HRESULT, Converted HRESULT value.
//
// Author: danielwe 21 Mar 1997
//
// Notes:
//
HRESULT HrFromNerr(NET_API_STATUS nerr)
{
HRESULT hr;
switch (nerr)
{
case NERR_Success:
hr = S_OK;
break;
case NERR_SetupAlreadyJoined:
hr = NETCFG_E_ALREADY_JOINED;
break;
case ERROR_DUP_NAME:
hr = NETCFG_E_NAME_IN_USE;
break;
case NERR_SetupNotJoined:
hr = NETCFG_E_NOT_JOINED;
break;
// case NERR_SetupIsDC:
// hr = NETCFG_E_MACHINE_IS_DC;
// break;
// case NERR_SetupNotAServer:
// hr = NETCFG_E_NOT_A_SERVER;
// break;
// case NERR_SetupImproperRole:
// hr = NETCFG_E_INVALID_ROLE;
// break;
case ERROR_INVALID_PARAMETER:
hr = E_INVALIDARG;
break;
case ERROR_ACCESS_DENIED:
hr = E_ACCESSDENIED;
break;
case NERR_InvalidComputer:
case ERROR_NO_SUCH_DOMAIN:
hr = NETCFG_E_INVALID_DOMAIN;
break;
default:
// Generic INetCfgIdentification error
//$ REVIEW (danielwe) 24 Jun 1997: What if this isn't a Win32 error?
hr = HRESULT_FROM_WIN32(nerr);
break;
}
return hr;
}
//
// INetCfgIdentification implementation
//
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrEnsureCurrentComputerName
//
// Purpose: Ensures that the current computer name exists to act on.
//
// Arguments:
// (none)
//
// Returns: HRESULT, Error code.
//
// Author: danielwe 21 Mar 1997
//
// Notes: Sets the m_szwCurComputerName variable.
//
HRESULT CNetCfgIdentification::HrEnsureCurrentComputerName()
{
HRESULT hr = S_OK;
if (!m_szwCurComputerName)
{
PWSTR pszwComputer;
// Go get the current computer name because we don't know it yet.
hr = HrGetCurrentComputerName(&pszwComputer);
if (SUCCEEDED(hr))
{
// m_szwCurComputerName is now set as a side effect
CoTaskMemFree(pszwComputer);
}
}
AssertSz(FImplies(SUCCEEDED(hr), m_szwCurComputerName),
"I MUST have a name here!");
TraceError("CNetCfgIdentification::HrEnsureCurrentComputerName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrGetNewestComputerName
//
// Purpose: Places the most recently referenced computer name into the
// output parameter.
//
// Arguments:
// pwszName [out] Most recently referenced computer name.
//
// Returns: Possible Win32 error code.
//
// Author: danielwe 24 Mar 1997
//
// Notes: If the SetComputerName() method was never called, this sets
// the m_szwCurComputerName variable and returns a pointer to it.
// Otherwise, it will return a pointer to the computer name
// given in the SetComputerName() call.
//
HRESULT CNetCfgIdentification::HrGetNewestComputerName(PCWSTR *pwszName)
{
HRESULT hr = S_OK;
AssertSz(pwszName, "NULL out param!");
*pwszName = NULL;
// New computer name is absent, use current computer name.
hr = HrEnsureCurrentComputerName();
if (FAILED(hr))
goto err;
*pwszName = m_szwCurComputerName;
err:
TraceError("CNetCfgIdentification::HrGetNewestComputerName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrValidateMachineName
//
// Purpose: Validates the given machine name.
//
// Arguments:
// szwName [in] Machine name to validate.
//
// Returns: S_OK if machine name is valid, NETCFG_E_NAME_IN_USE if machine
// name is in use.
//
// Author: danielwe 24 Mar 1997
//
// Notes:
//
HRESULT CNetCfgIdentification::HrValidateMachineName(PCWSTR szwName)
{
HRESULT hr = S_OK;
// Only validate if networking is installed
hr = HrIsNetworkingInstalled();
if (hr == S_OK)
{
// Current computer name is unused for validation of machine name.
hr = HrNetValidateName(NULL,
szwName,
NULL, NULL,
NetSetupMachine);
if (FAILED(hr))
{
//$REVIEW(danielwe): What error code to return here?
TraceError("NetValidateName - Machine Name", hr);
}
}
else if (hr == S_FALSE)
{
// no networking installed. We're fine.
hr = S_OK;
}
TraceError("CNetCfgIdentification::HrValidateMachineName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrValidateWorkgroupName
//
// Purpose: Validates the given workgroup name.
//
// Arguments:
// szwName [in] Workgroup name to validate.
//
// Returns: S_OK if machine name is valid, NETCFG_E_NAME_IN_USE if machine
// name is in use.
//
// Author: danielwe 24 Mar 1997
//
// Notes:
//
HRESULT CNetCfgIdentification::HrValidateWorkgroupName(PCWSTR szwName)
{
HRESULT hr = S_OK;
PCWSTR wszComputerName = NULL;
// If the user has changed the computer name, use it, otherwise get the
// current computer name and use that.
hr = HrGetNewestComputerName(&wszComputerName);
if (FAILED(hr))
goto err;
AssertSz(wszComputerName, "We don't have a computer name!");
hr = HrNetValidateName(const_cast<PWSTR>(wszComputerName),
szwName, NULL, NULL, NetSetupWorkgroup);
if (FAILED(hr))
{
//$REVIEW(danielwe): What error code to return here?
TraceError("NetValidateName - Workgroup Name", hr);
goto err;
}
err:
TraceError("CNetCfgIdentification::HrValidateWorkgroupName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrValidateDomainName
//
// Purpose: Validates the given domain name.
//
// Arguments:
// szwName [in] Name of domain to validate.
// szwUserName [in] Username for authorization purposes.
// szwPassword [in] Password for authorization purposes.
//
// Returns: S_OK if machine name is valid, NETCFG_E_INVALID_DOMAIN if
// domain name is invalid (or non-existent).
//
// Author: danielwe 24 Mar 1997
//
// Notes:
//
HRESULT CNetCfgIdentification::HrValidateDomainName(PCWSTR szwName,
PCWSTR szwUserName,
PCWSTR szwPassword)
{
HRESULT hr = S_OK;
// NetValidateName does not use the machine name in validating the
// domain name. So it is NULL here.
hr = HrNetValidateName(NULL, szwName,
szwUserName,
szwPassword,
NetSetupDomain);
if (FAILED(hr))
{
//$REVIEW(danielwe): What error code to return here?
TraceError("NetValidateName - Domain Name", hr);
goto err;
}
err:
TraceError("CNetCfgIdentification::HrValidateDomainName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::Validate
//
// Purpose: Implements COM function to validate current set of values
// used during the lifetime of this object.
//
// Arguments:
// (none)
//
// Returns: HRESULT, Error code.
//
// Author: danielwe 21 Mar 1997
//
// Notes:
//
STDMETHODIMP CNetCfgIdentification::Validate()
{
HRESULT hr = S_OK;
Validate_INetCfgIdentification_Validate();
COM_PROTECT_TRY
{
if (m_szwNewDWName)
{
if (GetNewJoinStatus() == NetSetupWorkgroupName)
{
// Validate workgroup name
hr = HrValidateWorkgroupName(m_szwNewDWName);
if (FAILED(hr))
goto err;
}
else if (GetNewJoinStatus() == NetSetupDomainName)
{
// Validate domain name
hr = HrValidateDomainName(m_szwNewDWName, m_szwUserName,
m_szwPassword);
if (FAILED(hr))
goto err;
}
#ifdef DBG
else
{
AssertSz(FALSE, "Invalid join status!");
}
#endif
}
}
COM_PROTECT_CATCH;
err:
// Translate all errors to S_FALSE.
if (SUCCEEDED(hr))
{
m_fValid = TRUE;
}
else
{
// spew out trace *before* the assignment so we know what the *real*
// error code was.
TraceError("CNetCfgIdentification::Validate (before S_FALSE)", hr);
hr = S_FALSE;
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::Cancel
//
// Purpose: Cancels any changes made during the lifetime of the object.
//
// Arguments:
// (none)
//
// Returns:
//
// Author: danielwe 25 Mar 1997
//
// Notes: Resets state information and frees any memory previously
// allocted.
//
STDMETHODIMP CNetCfgIdentification::Cancel()
{
HRESULT hr = S_OK;
Validate_INetCfgIdentification_Cancel();
COM_PROTECT_TRY
{
DeleteStringAndSetNull(&m_szwNewDWName);
DeleteStringAndSetNull(&m_szwPassword);
DeleteStringAndSetNull(&m_szwUserName);
DeleteStringAndSetNull(&m_szwCurComputerName);
DeleteStringAndSetNull(&m_szwCurDWName);
m_dwJoinFlags = 0;
m_dwCreateFlags = 0;
m_fValid = FALSE;
m_jsNew = NetSetupUnjoined;
}
COM_PROTECT_CATCH;
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::Apply
//
// Purpose: Implements COM function to apply changes that were made
// during the lifetime of this object.
//
// Arguments:
// (none)
//
// Returns: HRESULT, Error code.
//
// Author: danielwe 21 Mar 1997
//
// Notes:
//
STDMETHODIMP CNetCfgIdentification::Apply()
{
HRESULT hr = S_OK;
Validate_INetCfgIdentification_Apply();
COM_PROTECT_TRY
{
// Has data been validated?
if (!m_fValid)
{
hr = E_UNEXPECTED;
goto err;
}
if (m_szwNewDWName)
{
if (GetNewJoinStatus() == NetSetupWorkgroupName)
{
// The user specified a workgroup name. This means they want
// to join a workgroup.
hr = HrJoinWorkgroup();
if (FAILED(hr))
goto err;
}
else if (GetNewJoinStatus() == NetSetupDomainName)
{
// The user specified a domain name. This means they want to
// join a domain.
hr = HrJoinDomain();
if (FAILED(hr))
goto err;
}
#ifdef DBG
else
{
AssertSz(FALSE, "Invalid join status!");
}
#endif
}
}
COM_PROTECT_CATCH;
err:
// Regardless of result, set valid flag to false again to require
// Validate() to be called again before calling Apply().
// $REVIEW (danielwe): Is this how we want to do it?
m_fValid = FALSE;
TraceError("CNetCfgIdentification::Apply", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrGetCurrentComputerName
//
// Purpose: Calls the Win32 GetComputerName API to get the current
// computer name.
//
// Arguments:
// ppszwComputer [out] Returned computer name.
//
// Returns: HRESULT, Error code.
//
// Author: danielwe 21 Mar 1997
//
// Notes: Makes a private copy of the computer name if obtained from the
// system (for further use).
//
HRESULT CNetCfgIdentification::HrGetCurrentComputerName(PWSTR* ppszwComputer)
{
HRESULT hr = S_OK;
WCHAR szBuffer[MAX_COMPUTERNAME_LENGTH + 1];
DWORD cchBuffer = celems(szBuffer);
if (::GetComputerName(szBuffer, &cchBuffer))
{
// Make a copy for the out param.
hr = HrCoTaskMemAllocAndDupSz (
szBuffer, ppszwComputer, celems(szBuffer) );
if (SUCCEEDED(hr))
{
// Make another copy for our own use.
DeleteStringAndSetNull(&m_szwCurComputerName);
m_szwCurComputerName = SzDupSz(szBuffer);
AssertSz((DWORD)lstrlenW(*ppszwComputer) == cchBuffer,
"This is not how big the string is!");
}
}
else
{
TraceLastWin32Error("::GetComputerName");
hr = HrFromLastWin32Error();
}
TraceError("CNetCfgIdentification::HrGetCurrentComputerName", hr);
return hr;
}
static const WCHAR c_szRegKeyComputerName[] = L"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName";
static const WCHAR c_szRegValueComputerName[] = L"ComputerName";
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrGetNewComputerName
//
// Purpose: Helper function to retreive the new computer name from the
// registry. This will be the same as the active computer name
// unless the user has changed the computer name since booting.
//
// Arguments:
// ppszwComputer [out] Returns new computer name.
//
// Returns: S_OK if successful, Win32 error code otherwise.
//
// Author: danielwe 21 May 1997
//
// Notes:
//
HRESULT CNetCfgIdentification::HrGetNewComputerName(PWSTR* ppszwComputer)
{
HRESULT hr = S_OK;
WCHAR szBuffer[MAX_COMPUTERNAME_LENGTH + 1];
DWORD cbBuffer = sizeof(szBuffer);
HKEY hkeyComputerName;
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyComputerName,
KEY_READ, &hkeyComputerName);
if (SUCCEEDED(hr))
{
hr = HrRegQuerySzBuffer(hkeyComputerName, c_szRegValueComputerName,
szBuffer, &cbBuffer);
if (SUCCEEDED(hr))
{
// Make a copy for the out param.
hr = HrCoTaskMemAllocAndDupSz (
szBuffer, ppszwComputer, celems(szBuffer) );
AssertSz(FImplies(SUCCEEDED(hr),
(lstrlenW(*ppszwComputer) + 1) * sizeof(WCHAR) == cbBuffer),
"This is not how big the string is!");
}
RegCloseKey(hkeyComputerName);
}
TraceError("CNetCfgIdentification::HrGetCurrentComputerName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrEnsureCurrentDomainOrWorkgroupName
//
// Purpose: Obtains the current domain or workgroup to which this machine
// belongs.
//
// Arguments:
// (none)
//
// Returns: S_OK if success, error code otherwise.
//
// Author: danielwe 26 Mar 1997
//
// Notes: A machine can be joined to either or workgroup or a domain. It
// must be joined to one or the other. If it is not, we'll use a
// more or less hardcoded string and "fake it" as if the machine
// was joined to a workgroup. The member variables:
// m_jsCur and m_szwCurDWName are set by this function.
//
// This call only does work once. Subsequent calls do nothing.
//
HRESULT CNetCfgIdentification::HrEnsureCurrentDomainOrWorkgroupName()
{
HRESULT hr = S_OK;
if (!m_szwCurDWName)
{
NETSETUP_JOIN_STATUS js;
WCHAR wszBuffer[256];
PCWSTR wszName;
DWORD cchBuffer = celems(wszBuffer);
hr = HrNetGetJoinInformation(wszBuffer, &cchBuffer, &js);
if (FAILED(hr))
goto err;
AssertSz(FIff(*wszBuffer, cchBuffer), "Buffer size inconsistency!");
if (js == NetSetupUnjoined)
{
// Uh oh. Machine is not joined to workgroup OR domain. Set
// default workgroup name and proceed as if joined to a workgroup.
js = NetSetupWorkgroupName;
// Use default name since HrNetGetJoinInformation() will return
// an empty string which is useless.
wszName = SzLoadIds(IDS_WORKGROUP);
}
else
{
// Use string returned from HrNetGetJoinInformation().
wszName = wszBuffer;
}
m_szwCurDWName = SzDupSz(wszName);
m_jsCur = js;
AssertSz(GetCurrentJoinStatus() == NetSetupWorkgroupName ||
GetCurrentJoinStatus() == NetSetupDomainName,
"Invalid join status flag!");
}
err:
TraceError("CNetCfgIdentification::HrEnsureCurrentDomainOrWorkgroupName",
hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrGetNewestDomainOrWorkgroupName
//
// Purpose: Returns the domain or workgroup name that was most recently
// referenced.
//
// Arguments:
// js [in] Tells whether the domain or workgroup name is wanted.
// pwszName [out] Domain or workgroup name.
//
// Returns: S_OK if success, E_OUTOFMEMORY if no memory.
//
// Author: danielwe 26 Mar 1997
//
// Notes: If the requested name has not been set by the user in a prior
// call, the current name is returned. Otherwise the name the
// user chose previously is returned.
//
HRESULT CNetCfgIdentification::HrGetNewestDomainOrWorkgroupName(
NETSETUP_JOIN_STATUS js,
PCWSTR *pwszName)
{
HRESULT hr = S_OK;
PWSTR szwOut = NULL;
Assert(pwszName);
if (m_szwNewDWName && (GetNewJoinStatus() == js))
{
// Give them back a copy of the domain or workgroup name they
// previously gave us.
szwOut = m_szwNewDWName;
}
else
{
// Get the current workgroup or domain for this machine. It has
// to be in one or the other.
hr = HrEnsureCurrentDomainOrWorkgroupName();
if (FAILED(hr))
goto err;
if (GetCurrentJoinStatus() == js)
{
// Use the current name.
szwOut = m_szwCurDWName;
}
}
Assert(SUCCEEDED(hr));
*pwszName = szwOut;
err:
TraceError("CNetCfgIdentification::HrGetNewestDomainOrWorkgroupName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::GetWorkgroupName
//
// Purpose: Implements COM function to get the current workgroup name.
//
// Arguments:
// ppszwWorkgroup [out] Returns name of current workgroup.
//
// Returns: S_OK if succeeded, S_FALSE if machine is not joined to a
// workgroup, error code otherwise.
//
// Author: danielwe 21 Mar 1997
//
// Notes:
//
STDMETHODIMP CNetCfgIdentification::GetWorkgroupName(PWSTR* ppszwWorkgroup)
{
HRESULT hr = S_OK;
PCWSTR szwWorkgroup = NULL;
Validate_INetCfgIdentification_GetWorkgroupName(ppszwWorkgroup);
COM_PROTECT_TRY
{
*ppszwWorkgroup = NULL;
hr = HrGetNewestDomainOrWorkgroupName(NetSetupWorkgroupName,
&szwWorkgroup);
if (FAILED(hr))
goto err;
if (szwWorkgroup)
{
hr = HrCoTaskMemAllocAndDupSz (
szwWorkgroup, ppszwWorkgroup, MAX_WORKGROUPNAME_LENGTH);
AssertSz(FImplies(SUCCEEDED(hr), lstrlenW(*ppszwWorkgroup) > 0),
"Why is *ppszwWorkgroup empty?");
}
else
{
// Not joined to a workgroup
hr = S_FALSE;
}
}
COM_PROTECT_CATCH;
err:
TraceError("CNetCfgIdentification::GetWorkgroupName",
(hr == S_FALSE) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::GetDomainName
//
// Purpose: Implements COM function to get the current domain name.
//
// Arguments:
// ppszwDomain [out] Returns name of domain to which this computer
// currently belongs.
//
// Returns: S_OK if succeeded, S_FALSE if machine is not joined to a
// domain, error code otherwise.
//
// Author: danielwe 21 Mar 1997
//
// Notes:
//
STDMETHODIMP CNetCfgIdentification::GetDomainName(PWSTR* ppszwDomain)
{
HRESULT hr = S_OK;
PCWSTR szwDomain = NULL;
Validate_INetCfgIdentification_GetDomainName(ppszwDomain);
COM_PROTECT_TRY
{
*ppszwDomain = NULL;
hr = HrGetNewestDomainOrWorkgroupName(NetSetupDomainName,
&szwDomain);
if (FAILED(hr))
goto err;
if (szwDomain)
{
hr = HrCoTaskMemAllocAndDupSz (
szwDomain, ppszwDomain, MAX_DOMAINNAME_LENGTH);
AssertSz(FImplies(SUCCEEDED(hr), lstrlenW(*ppszwDomain) > 0),
"Why is *ppszwDomain empty?");
}
else
{
// Not joined to a domain
hr = S_FALSE;
}
}
COM_PROTECT_CATCH;
err:
TraceError("CNetCfgIdentification::GetDomainName",
(hr == S_FALSE) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrJoinWorkgroup
//
// Purpose: Actually performs the JoinWorkgroup function.
//
// Arguments:
// (none)
//
// Returns: HRESULT, Error code.
//
// Author: danielwe 21 Mar 1997
//
// Notes:
//
HRESULT CNetCfgIdentification::HrJoinWorkgroup()
{
HRESULT hr = S_OK;
PCWSTR wszComputerName = NULL;
AssertSz(m_szwNewDWName &&
GetNewJoinStatus() == NetSetupWorkgroupName,
"If there was no workgroup name, why'd you call me?!");
// If the user has changed the computer name, use it, otherwise get the
// current computer name and use that.
hr = HrGetNewestComputerName(&wszComputerName);
if (FAILED(hr))
goto err;
AssertSz(wszComputerName, "We don't have a computer name!");
hr = HrEnsureCurrentDomainOrWorkgroupName();
if (FAILED(hr))
goto err;
if (FIsJoinedToDomain())
{
// Must unjoin from domain if currently joined.
// If currently joined to a workgroup, this is not necessary.
hr = HrNetUnjoinDomain(m_szwUserName, m_szwPassword, 0);
if (FAILED(hr))
goto err;
// Free username and password
DeleteStringAndSetNull(&m_szwPassword);
DeleteStringAndSetNull(&m_szwUserName);
}
// Go ahead and join the workgroup
hr = HrNetJoinDomain(const_cast<PWSTR>(wszComputerName),
m_szMachineObjectOU,
m_szwNewDWName, NULL, NULL, 0);
if (FAILED(hr))
goto err;
// Make the current workgroup name the new one since the join on the
// new workgroup has succeeded
hr = HrEstablishNewDomainOrWorkgroupName(NetSetupWorkgroupName);
if (FAILED(hr))
goto err;
err:
TraceError("CNetCfgIdentification::HrJoinWorkgroup", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::JoinWorkgroup
//
// Purpose: Implements COM interface to join this computer to a new
// workgroup.
//
// Arguments:
// szwWorkgroup [in] Name of new workgroup to join.
//
// Returns: HRESULT, Error code.
//
// Author: danielwe 21 Mar 1997
//
// Notes: Validates, but does not actually join the workgroup. Only holds
// onto the information until Apply() is called.
//
STDMETHODIMP CNetCfgIdentification::JoinWorkgroup(PCWSTR szwWorkgroup)
{
HRESULT hr = S_OK;
Validate_INetCfgIdentification_JoinWorkgroup(szwWorkgroup);
COM_PROTECT_TRY
{
hr = HrValidateWorkgroupName(szwWorkgroup);
if (FAILED(hr))
goto err;
// Free domain and password given if JoinDomain was called previously
DeleteStringAndSetNull(&m_szwPassword);
DeleteStringAndSetNull(&m_szwUserName);
// Assign in new workgroup name.
m_szwNewDWName = SzDupSz(szwWorkgroup);
m_jsNew = NetSetupWorkgroupName;
}
COM_PROTECT_CATCH;
err:
TraceError("CNetCfgIdentification::JoinWorkgroup", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrEstablishNewDomainOrWorkgroupName
//
// Purpose: When the computer is joined to a new domain or workgroup, this
// function is called to set the correct member variables and
// free the old ones.
//
// Arguments:
// js [in] Indicates whether the computer is joined to a domain or
// workgroup.
//
// Returns: S_OK, or E_OUTOFMEMORY.
//
// Author: danielwe 1 Apr 1997
//
// Notes: Replaces the m_szwCurDWName variable with the new one
// (m_szwNewDWName).
//
HRESULT CNetCfgIdentification::HrEstablishNewDomainOrWorkgroupName(
NETSETUP_JOIN_STATUS js)
{
HRESULT hr = S_OK;
// Make the current domain or workgroup name the new one.
DeleteStringAndSetNull(&m_szwCurDWName);
m_szwCurDWName = SzDupSz(m_szwNewDWName);
m_jsCur = js;
AssertSz(GetCurrentJoinStatus() == NetSetupWorkgroupName ||
GetCurrentJoinStatus() == NetSetupDomainName,
"Invalid join status flag!");
// Free "new" name
DeleteStringAndSetNull(&m_szwNewDWName);
// Also make sure that we don't have a "new" join status either
m_jsNew = NetSetupUnjoined;
TraceError("CNetCfgIdentification::HrEstablishNewDomainOrWorkgroupName",
hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::HrJoinDomain
//
// Purpose: Actually performs the JoinDomain function.
//
// Arguments:
// (none)
//
// Returns: HRESULT, Error code.
//
// Author: danielwe 21 Mar 1997
//
// Notes:
//
HRESULT CNetCfgIdentification::HrJoinDomain()
{
HRESULT hr = S_OK;
PCWSTR wszComputerName = NULL;
DWORD dwJoinOption = 0;
BOOL fIsRename = FALSE;
BOOL fUseNulls = FALSE;
AssertSz(m_szwNewDWName && m_jsNew == NetSetupDomainName,
"If there was no domain name, why'd you call me?!");
AssertSz(FImplies(m_szwPassword,
m_szwUserName),
"Password without username!!");
// If the user has changed the computer name, use it, otherwise get the
// current computer name and use that.
hr = HrGetNewestComputerName(&wszComputerName);
if (FAILED(hr))
goto err;
{
AssertSz(wszComputerName == m_szwCurComputerName, "If I don't have a "
"new computer name, this better be the original one!");
dwJoinOption |= NETSETUP_JOIN_DOMAIN;
}
AssertSz(wszComputerName, "We don't have a computer name!");
AssertSz(dwJoinOption, "No option was set??");
AssertSz(FImplies(m_szwPassword,
m_szwUserName),
"Password without username!");
// Create a machine account if so asked.
if (m_dwJoinFlags & JDF_CREATE_ACCOUNT)
{
dwJoinOption |= NETSETUP_ACCT_CREATE;
}
if (m_dwJoinFlags & JDF_WIN9x_UPGRADE)
{
dwJoinOption |= NETSETUP_WIN9X_UPGRADE;
}
if (m_dwJoinFlags & JDF_JOIN_UNSECURE)
{
dwJoinOption |= NETSETUP_JOIN_UNSECURE;
}
#if defined(REMOTE_BOOT)
// TEMP: On a remote boot machine, prevent machine password change
if (HrIsRemoteBootMachine() == S_OK)
{
TraceTag (ttidNetcfgBase,
"Machine is remote boot, specifying WIN9X_UPGRADE flag to JoinDomain.");
dwJoinOption |= NETSETUP_WIN9X_UPGRADE;
}
#endif // defined(REMOTE_BOOT)
//$ REVIEW (danielwe) 2 Apr 1997: If new domain is same as old, unjoin
// then rejoin??
if (!(fIsRename) && FIsJoinedToDomain())
{
// Must unjoin from domain if currently joined.
// If currently joined to a workgroup, this is not necessary.
// Also we don't unjoin if we are renaming the machine in the domain.
hr = HrNetUnjoinDomain(m_szwUserName,
m_szwPassword, 0);
if (FAILED(hr))
goto err;
}
if (FInSystemSetup())
{
// During system setup, need to pass special flag that tells join code
// to not do certain operations because SAM is not initialized yet.
dwJoinOption |= NETSETUP_INSTALL_INVOCATION;
}
// If the supplied username has astring length of zero, then the join
// API's should be called with NULL's.
//
if ((NULL == m_szwUserName) || (0 == wcslen(m_szwUserName)))
{
fUseNulls = TRUE;
}
// Go ahead and join the domain
if( fIsRename) {
hr = HrNetRenameInDomain(const_cast<PWSTR>(wszComputerName),
m_szwNewDWName,
(fUseNulls ? NULL : m_szwUserName),
(fUseNulls ? NULL : m_szwPassword),
dwJoinOption);
} else {
hr = HrNetJoinDomain(const_cast<PWSTR>(wszComputerName),
m_szMachineObjectOU,
m_szwNewDWName,
(fUseNulls ? NULL : m_szwUserName),
(fUseNulls ? NULL : m_szwPassword),
dwJoinOption);
}
if (FAILED(hr))
{
// Note: (danielwe) Making assumption that failure to join a domain puts us in
// a workgroup. MacM owns the code responsible for this.
m_jsCur = NetSetupWorkgroupName;
goto err;
}
// Make the current domain name the new one since the join on the
// new domain has succeeded
hr = HrEstablishNewDomainOrWorkgroupName(NetSetupDomainName);
if (FAILED(hr))
goto err;
err:
// Free username and password
DeleteStringAndSetNull(&m_szwPassword);
DeleteStringAndSetNull(&m_szwUserName);
TraceError("CNetCfgIdentification::HrJoinDomain", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::JoinDomain
//
// Purpose: Implements COM interface to join this computer to a new
// domain.
//
// Arguments:
// szwDomain [in] New domain name.
// szMachineObjectOU [in] Machine object OU (optional)
// szwUserName [in] User name to use in validation.
// szwPassword [in] Password to use in validation.
// dwJoinFlags [in] Currently can be 0 or JDF_CREATE_ACCOUNT.
//
// Returns: HRESULT, Error code.
//
// Author: danielwe 21 Mar 1997
//
// Notes: Validates, but does not actually join the domain. Only holds
// onto the information until Apply() is called.
//
STDMETHODIMP CNetCfgIdentification::JoinDomain(PCWSTR szwDomain,
PCWSTR szMachineObjectOU,
PCWSTR szwUserName,
PCWSTR szwPassword,
DWORD dwJoinFlags)
{
HRESULT hr = S_OK;
static const WCHAR c_wszBackslash[] = L"\\";
static const WCHAR c_wszAt[] = L"@";
COM_PROTECT_TRY
{
Validate_INetCfgIdentification_JoinDomain(szwDomain, szwUserName,
szwPassword);
#if defined(REMOTE_BOOT)
if (HrIsRemoteBootMachine() == S_FALSE)
#endif // defined(REMOTE_BOOT)
{
// look for non-empty password and empty username or username
// consisting of only the backslash character
if (!FIsStrEmpty(szwPassword) && FIsStrEmpty(szwUserName) ||
!lstrcmpW(szwUserName, c_wszBackslash))
{
// Password without username is invalid.
hr = E_INVALIDARG;
goto err;
}
PWSTR wszNewUserName;
INT cchNewUserName;
// Check if username that was passed in has a backslash in it or
// an '@', or if it is empty.
if (FIsStrEmpty(szwUserName) ||
wcschr(szwUserName, c_wszBackslash[0]) ||
wcschr(szwUserName, c_wszAt[0]))
{
// if so, don't do anything extra
wszNewUserName = NULL;
}
else
{
// if not, we have to append the domain name to the username
cchNewUserName = lstrlenW(szwUserName) + // original username
lstrlenW(szwDomain) + // domain name
1 + // backslash character
1; // terminating NULL
wszNewUserName = new WCHAR[cchNewUserName];
if(wszNewUserName)
{
// Turn username into domain\username format
lstrcpyW(wszNewUserName, szwDomain);
lstrcatW(wszNewUserName, c_wszBackslash);
lstrcatW(wszNewUserName, szwUserName);
AssertSz(lstrlenW(wszNewUserName) + 1 == cchNewUserName,
"Possible memory overwrite in username!");
}
}
// Use wszNewUserName if non-NULL, otherwise use szwUserName
PCWSTR szwUserNameToCopy;
szwUserNameToCopy = wszNewUserName ? wszNewUserName : szwUserName;
m_szwUserName = SzDupSz(szwUserNameToCopy);
m_szwPassword = SzDupSz(szwPassword);
delete [] wszNewUserName;
}
AssertSz(FImplies(m_szwPassword,
m_szwUserName),
"Password without username!");
hr = HrValidateDomainName(szwDomain, m_szwUserName, m_szwPassword);
if (FAILED(hr))
goto err;
// Assign in new strings
m_szwNewDWName = SzDupSz(szwDomain);
if (szMachineObjectOU)
{
m_szMachineObjectOU = SzDupSz(szMachineObjectOU);
}
m_dwJoinFlags = dwJoinFlags;
m_jsNew = NetSetupDomainName;
err:
// suppress compiler error
;
}
COM_PROTECT_CATCH;
TraceError("CNetCfgIdentification::JoinDomain", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CNetCfgIdentification::GetComputerRole
//
// Purpose: Returns the current role of the computer.
//
// Arguments:
// pdwRoleFlags [out] Returns value which determines the role of this
// computer.
//
// Returns: S_OK if success, error code otherwise.
//
// Author: danielwe 26 Mar 1997
//
// Notes: Returned role can be one of:
// SERVER_STANDALONE - The machine is part of a workgroup.
// SERVER_MEMBER - The machine is joined to the domain.
// SERVER_PDC - The machine is a primary domain controller.
// SERVER_BDC - The machine is a backup domain controller.
//
STDMETHODIMP CNetCfgIdentification::GetComputerRole(DWORD* pdwRoleFlags)
{
HRESULT hr = S_OK;
Validate_INetCfgIdentification_GetComputerRole(pdwRoleFlags);
COM_PROTECT_TRY
{
*pdwRoleFlags = 0;
hr = HrEnsureCurrentDomainOrWorkgroupName();
if (SUCCEEDED(hr))
{
if (m_jsNew == NetSetupUnjoined)
{
// The workgroup or domain has not been changed since this
// object was instantiated
if (GetCurrentJoinStatus() == NetSetupDomainName)
{
*pdwRoleFlags = GCR_MEMBER;
}
else if (GetCurrentJoinStatus() == NetSetupWorkgroupName)
{
*pdwRoleFlags = GCR_STANDALONE;
}
#ifdef DBG
else
{
AssertSz(FALSE, "Invalid join status flag!");
}
#endif
}
else
{
// This means the workgroup or domain name has been changed
// since this object was instantiated
if (GetNewJoinStatus() == NetSetupDomainName)
{
*pdwRoleFlags = GCR_MEMBER;
}
else if (GetNewJoinStatus() == NetSetupWorkgroupName)
{
*pdwRoleFlags = GCR_STANDALONE;
}
#ifdef DBG
else
{
AssertSz(FALSE, "Invalid join status flag!");
}
#endif
}
}
}
COM_PROTECT_CATCH;
TraceError("CNetCfgIdentification::GetComputerRole", hr);
return hr;
}