//+--------------------------------------------------------------------------- // // 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 #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(lpMachine), const_cast(lpName), const_cast(lpAccount), const_cast(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(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(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(wszComputerName), m_szwNewDWName, (fUseNulls ? NULL : m_szwUserName), (fUseNulls ? NULL : m_szwPassword), dwJoinOption); } else { hr = HrNetJoinDomain(const_cast(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; }