windows-nt/Source/XPSP1/NT/shell/ext/netplwiz/join.cpp
2020-09-26 16:20:57 +08:00

378 lines
11 KiB
C++

#include "stdafx.h"
#pragma hdrstop
//
// registry information
//
const WCHAR c_szWinLogon[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon";
const WCHAR c_szAutoLogon[] = L"AutoAdminLogon";
const WCHAR c_szDisableCAD[] = L"DisableCAD";
const WCHAR c_szDefUserName[] = L"DefaultUserName";
const WCHAR c_szDefDomain[] = L"DefaultDomainName";
const WCHAR c_szDefPassword[] = L"DefaultPassword";
const WCHAR c_szDefaultPwdKey[] = L"DefaultPassword";
//
// registry helpers
//
BOOL _RegSetSZ(HKEY hk, LPCWSTR pszValueName, LPCWSTR pszValue)
{
DWORD dwSize = lstrlen(pszValue)*SIZEOF(WCHAR);
return ERROR_SUCCESS == RegSetValueEx(hk, pszValueName, 0x0, REG_SZ, (BYTE *)pszValue, dwSize);
}
BOOL _RegSetDWORD(HKEY hk, LPCWSTR pszValueName, DWORD dwValue)
{
DWORD dwSize = SIZEOF(dwValue);
return ERROR_SUCCESS == RegSetValueEx(hk, pszValueName, 0x0, REG_DWORD, (BYTE *)&dwValue, dwSize);
}
BOOL _RegDelValue(HKEY hk, LPCWSTR pszValueName)
{
return ERROR_SUCCESS == RegDeleteValue(hk, pszValueName);
}
INT_PTR CALLBACK _CredDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPCREDINFO pci = (LPCREDINFO)GetWindowLongPtr(hwnd, DWLP_USER);
switch ( uMsg )
{
case WM_INITDIALOG:
{
pci = (LPCREDINFO)lParam;
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
SetDlgItemText(hwnd, IDC_USER, pci->pszUser);
Edit_LimitText(GetDlgItem(hwnd, IDC_USER), pci->cchUser - 1);
SetDlgItemText(hwnd, IDC_DOMAIN, pci->pszDomain);
Edit_LimitText(GetDlgItem(hwnd, IDC_DOMAIN), pci->cchDomain - 1);
SetDlgItemText(hwnd, IDC_PASSWORD, pci->pszPassword);
Edit_LimitText(GetDlgItem(hwnd, IDC_PASSWORD), pci->cchPassword - 1);
return TRUE;
}
case WM_COMMAND:
{
switch ( LOWORD(wParam) )
{
case IDOK:
{
FetchText(hwnd, IDC_DOMAIN, pci->pszDomain, pci->cchDomain);
FetchText(hwnd, IDC_USER, pci->pszUser, pci->cchUser);
if (StrChr(pci->pszUser, TEXT('@')))
{
*(pci->pszDomain) = 0;
}
GetDlgItemText(hwnd, IDC_PASSWORD, pci->pszPassword, pci->cchPassword);
return EndDialog(hwnd, IDOK);
}
case IDCANCEL:
return EndDialog(hwnd, IDCANCEL);
case IDC_USER:
{
if ( HIWORD(wParam) == EN_CHANGE )
{
EnableWindow(GetDlgItem(hwnd, IDOK), FetchTextLength(hwnd, IDC_USER) > 0);
EnableDomainForUPN(GetDlgItem(hwnd, IDC_USER), GetDlgItem(hwnd, IDC_DOMAIN));
}
break;
}
}
return TRUE;
}
}
return FALSE;
}
//
// attempt to join a domain/workgroup using the specified names and OU.
//
HRESULT _AttemptJoin(HWND hwnd, DWORD dwFlags, LPCWSTR pszDomain, LPCWSTR pszUser, LPCWSTR pszUserDomain, LPCWSTR pszPassword)
{
HRESULT hr = S_OK;
#ifndef DONT_JOIN
TCHAR szDomainUser[MAX_DOMAINUSER + 1];
if ( pszUser )
MakeDomainUserString(pszUserDomain, pszUser, szDomainUser, ARRAYSIZE(szDomainUser));
NET_API_STATUS nas = NetJoinDomain(NULL, pszDomain, NULL, szDomainUser, pszPassword, dwFlags);
if ( (nas == ERROR_ACCESS_DENIED) )
{
// perhaps an account exists, but we can't delete it so try and remove
// the account create flag
if ( dwFlags & NETSETUP_ACCT_CREATE )
{
dwFlags &= ~NETSETUP_ACCT_CREATE;
nas = NetJoinDomain(NULL, pszDomain, NULL, szDomainUser, *pszPassword ? pszPassword : NULL, dwFlags);
}
}
if ( (nas != NERR_Success) && (nas != NERR_SetupAlreadyJoined) )
{
TCHAR szMessage[512];
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) nas, 0, szMessage, ARRAYSIZE(szMessage), NULL))
LoadString(g_hinst, IDS_ERR_UNEXPECTED, szMessage, ARRAYSIZE(szMessage));
::DisplayFormatMessage(hwnd, IDS_ERR_CAPTION, IDS_NAW_JOIN_GENERICERROR, MB_OK|MB_ICONERROR, szMessage);
hr = HRESULT_FROM_WIN32(nas);
}
#endif
return hr;
}
void _ShowDcNotFoundErrorDialog(HWND hwnd, LPCWSTR pszDomain, LPCWSTR pszTitle)
{
typedef void (*pfnShowDcNotFoundErrorDialog)(HWND, PCWSTR, PCWSTR);
static HMODULE hNetID = NULL;
static pfnShowDcNotFoundErrorDialog ShowDcNotFoundErrorDialog = NULL;
if (!hNetID)
{
hNetID = LoadLibrary(L"netid.dll");
}
if (hNetID)
{
ShowDcNotFoundErrorDialog = (pfnShowDcNotFoundErrorDialog) GetProcAddress(hNetID, "ShowDcNotFoundErrorDialog");
if (ShowDcNotFoundErrorDialog)
{
ShowDcNotFoundErrorDialog(hwnd, pszDomain, pszTitle);
}
}
}
//
// Handle moving from to a workgroup or domain. To do this we are passed
// a structure containing all the information we need.
//
HRESULT JoinDomain(HWND hwnd, BOOL fDomain, LPCWSTR pszDomain, CREDINFO* pci, BOOL *pfReboot)
{
HRESULT hres = E_FAIL;
DWORD dwFlags = 0x0;
LPWSTR pszCurrentDomain = NULL;
NET_API_STATUS nas;
BOOL fPassedCredentials = (pci && pci->pszUser && pci->pszUser[0] && pci->pszPassword);
CWaitCursor cur;
//
// lets validate the domain name before we go and use it, therefore avoiding
// orphaning the computer too badly
//
nas = NetValidateName(NULL, pszDomain, NULL, NULL, fDomain ? NetSetupDomain:NetSetupWorkgroup);
if (fDomain && (ERROR_NO_SUCH_DOMAIN == nas))
{
WCHAR szTitle[256];
LoadString(g_hinst, IDS_NETWIZCAPTION, szTitle, ARRAYSIZE(szTitle));
_ShowDcNotFoundErrorDialog(hwnd, pszDomain, szTitle);
return E_FAIL;
}
if ( NERR_Success != nas )
{
ShellMessageBox(g_hinst, hwnd,
fDomain ? MAKEINTRESOURCE(IDS_ERR_BADDOMAIN) : MAKEINTRESOURCE(IDS_ERR_BADWORKGROUP),
MAKEINTRESOURCE(IDS_NETWIZCAPTION),
MB_OK|MB_ICONWARNING,
pszDomain);
return E_FAIL;
}
//
// now attempt to join the domain, prompt for credentails if the ones
// specified are not good enough
//
if ( fDomain )
{
dwFlags |= NETSETUP_JOIN_DOMAIN|NETSETUP_ACCT_CREATE|NETSETUP_DOMAIN_JOIN_IF_JOINED;
}
else
{
nas = NetUnjoinDomain(NULL, NULL, NULL, NETSETUP_ACCT_DELETE);
if ( (nas != NERR_Success) && (nas != NERR_SetupNotJoined) )
{
nas = NetUnjoinDomain(NULL, NULL, NULL, 0x0);
}
if ( (nas != NERR_Success) && (nas != NERR_SetupNotJoined) )
{
hres = E_UNEXPECTED;
goto exit_gracefully;
}
*pfReboot = TRUE; // we changed the domain
}
if ( !fDomain || fPassedCredentials)
{
if (fPassedCredentials)
{
hres = _AttemptJoin(hwnd, dwFlags, pszDomain, pci->pszUser, pci->pszDomain, pci->pszPassword);
}
else
{
hres = _AttemptJoin(hwnd, dwFlags, pszDomain, NULL, NULL, NULL);
}
}
if ( fDomain && ((FAILED(hres) || (!fPassedCredentials))) )
{
do
{
if ( IDCANCEL == DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_PSW_JOINCREDENTIALS),
hwnd, _CredDlgProc, (LPARAM)pci) )
{
hres = E_FAIL;
goto exit_gracefully;
}
// The dialog box changed the cursor from a wait cursor to an arrow cursor, so the cursor
// needs to be changed back.. This call could be moved to _AttemptJoin (along with a call to
// reset the cursor). This call is made synchronously from the message loop for this hwnd
cur.WaitCursor();
hres = _AttemptJoin(hwnd, dwFlags, pszDomain, pci->pszUser, pci->pszDomain, pci->pszPassword);
}
while ( FAILED(hres) );
}
exit_gracefully:
if ( SUCCEEDED(hres) )
{
ClearAutoLogon();
*pfReboot = TRUE; // we changed the domain
}
NetApiBufferFree(pszCurrentDomain);
return hres;
}
//
// set and clear the auto admin logon state.
//
// we set the default user and default domain to the specified strings, we then blow away
// the clear text password stored in the registry to replace it with a password stored
// in the LSA secret space.
//
NTSTATUS _SetDefaultPassword(LPCWSTR PasswordBuffer)
{
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES ObjectAttributes;
LSA_HANDLE LsaHandle = NULL;
UNICODE_STRING SecretName;
UNICODE_STRING SecretValue;
InitializeObjectAttributes(&ObjectAttributes, NULL, 0L, (HANDLE)NULL, NULL);
Status = LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_CREATE_SECRET, &LsaHandle);
if (!NT_SUCCESS(Status))
return Status;
RtlInitUnicodeString(&SecretName, c_szDefaultPwdKey);
RtlInitUnicodeString(&SecretValue, PasswordBuffer);
Status = LsaStorePrivateData(LsaHandle, &SecretName, &SecretValue);
LsaClose(LsaHandle);
return Status;
}
//
// Set and clear auto logon for a particular
//
void SetAutoLogon(LPCWSTR pszUserName, LPCWSTR pszPassword)
{
#ifndef DONT_JOIN
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
DWORD dwComputerName = ARRAYSIZE(szComputerName);
HKEY hk;
GetComputerName(szComputerName, &dwComputerName);
SetDefAccount(pszUserName, szComputerName); // also clears auto logon
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
{
_RegSetSZ(hk, c_szAutoLogon, L"1"); // auto admin logon
_RegDelValue(hk, c_szDefPassword); // use the LSA secret for the password
RegCloseKey (hk);
}
_SetDefaultPassword(pszPassword);
#endif
}
//
// clear the auto admin logon
//
STDAPI ClearAutoLogon(VOID)
{
#ifndef DONT_JOIN
HKEY hk;
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
{
_RegSetSZ(hk, c_szAutoLogon, L"0"); // no auto admin logon
_RegDelValue(hk, c_szDefPassword);
RegCloseKey(hk);
}
_SetDefaultPassword(L""); // clear the LSA secret
#endif
return S_OK;
}
//
// set the default account
//
void SetDefAccount(LPCWSTR pszUser, LPCWSTR pszDomain)
{
#ifndef DONT_JOIN
ClearAutoLogon();
HKEY hk;
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
{
_RegSetSZ(hk, c_szDefUserName, pszUser);
_RegSetSZ(hk, c_szDefDomain, pszDomain);
RegCloseKey(hk);
}
#endif
}