Source code of Windows XP (NT5)
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.

1693 lines
52 KiB

  1. #include "stdafx.h"
  2. #include "grpinfo.h"
  3. #include <dsgetdc.h> // DsGetDCName and DS structures
  4. #include <ntdsapi.h>
  5. #include <activeds.h> // ADsGetObject
  6. #include <rasdlg.h>
  7. #include <raserror.h>
  8. #pragma hdrstop
  9. CGroupPageBase* g_pGroupPageBase; // used for the group page
  10. DWORD g_dwWhichNet = 0;
  11. UINT g_uWizardIs = NAW_NETID;
  12. BOOL g_fRebootOnExit = FALSE;
  13. BOOL g_fShownLastPage = FALSE;
  14. BOOL g_fCreatedConnection = FALSE; // we created a RAS connection during the wizard, therefore kill it on exit
  15. BOOL g_fMachineRenamed = FALSE;
  16. WCHAR g_szUser[MAX_DOMAINUSER + 1] = { L'\0' };
  17. WCHAR g_szDomain[MAX_DOMAIN + 1] = { L'\0' };
  18. WCHAR g_szCompDomain[MAX_DOMAIN + 1] = { L'\0' };
  19. // Stuff for creating a default autologon user
  20. #define ITEMDATA_DEFAULTLOCALUSER 0xDEADBEEF
  21. // default workgroup to be joined
  22. #define DEFAULT_WORKGROUP L"WORKGROUP"
  23. // Set the Wizard buttons for the dialog
  24. void SetWizardButtons(HWND hwndPage, DWORD dwButtons)
  25. {
  26. HWND hwndParent = GetParent(hwndPage);
  27. if (g_uWizardIs != NAW_NETID)
  28. {
  29. EnableWindow(GetDlgItem(hwndParent,IDHELP),FALSE);
  30. ShowWindow(GetDlgItem(hwndParent,IDHELP),SW_HIDE);
  31. }
  32. if (g_fRebootOnExit)
  33. {
  34. TCHAR szBuffer[80];
  35. LoadString(g_hinst, IDS_CLOSE, szBuffer, ARRAYSIZE(szBuffer));
  36. SetDlgItemText(hwndParent, IDCANCEL, szBuffer);
  37. }
  38. PropSheet_SetWizButtons(hwndParent, dwButtons);
  39. }
  40. // intro dialog - set the title text etc
  41. INT_PTR CALLBACK _IntroDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  42. {
  43. switch (uMsg)
  44. {
  45. case WM_INITDIALOG:
  46. {
  47. SendDlgItemMessage(hwnd, IDC_TITLE, WM_SETFONT, (WPARAM)GetIntroFont(hwnd), 0);
  48. return TRUE;
  49. }
  50. case WM_NOTIFY:
  51. {
  52. LPNMHDR pnmh = (LPNMHDR)lParam;
  53. switch (pnmh->code)
  54. {
  55. case PSN_SETACTIVE:
  56. SetWizardButtons(hwnd, PSWIZB_NEXT);
  57. return TRUE;
  58. case PSN_WIZNEXT:
  59. {
  60. switch (g_uWizardIs)
  61. {
  62. case NAW_PSDOMAINJOINED:
  63. WIZARDNEXT(hwnd, IDD_PSW_ADDUSER);
  64. break;
  65. default:
  66. // Let the wizard go to the next page
  67. break;
  68. }
  69. return TRUE;
  70. }
  71. }
  72. break;
  73. }
  74. }
  75. return FALSE;
  76. }
  77. // how do they user this machine corp/vs home
  78. INT_PTR CALLBACK _HowUseDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  79. {
  80. switch (uMsg)
  81. {
  82. case WM_INITDIALOG:
  83. CheckRadioButton(hwnd, IDC_NETWORKED, IDC_NOTNETWORKED, IDC_NETWORKED);
  84. return TRUE;
  85. case WM_NOTIFY:
  86. {
  87. LPNMHDR pnmh = (LPNMHDR)lParam;
  88. switch (pnmh->code)
  89. {
  90. case PSN_SETACTIVE:
  91. SetWizardButtons(hwnd, PSWIZB_NEXT|PSWIZB_BACK);
  92. return TRUE;
  93. case PSN_WIZBACK:
  94. WIZARDNEXT(hwnd, IDD_PSW_WELCOME);
  95. return TRUE;
  96. case PSN_WIZNEXT:
  97. {
  98. if (IsDlgButtonChecked(hwnd, IDC_NETWORKED) == BST_CHECKED)
  99. {
  100. WIZARDNEXT(hwnd, IDD_PSW_WHICHNET);
  101. }
  102. else
  103. {
  104. g_dwWhichNet = IDC_NONE;
  105. if (SUCCEEDED(JoinDomain(hwnd, FALSE, DEFAULT_WORKGROUP, NULL, &g_fRebootOnExit)))
  106. {
  107. WIZARDNEXT(hwnd, IDD_PSW_DONE);
  108. }
  109. else
  110. {
  111. WIZARDNEXT(hwnd, -1);
  112. }
  113. }
  114. return TRUE;
  115. }
  116. }
  117. break;
  118. }
  119. }
  120. return FALSE;
  121. }
  122. // determine the network they want to join
  123. INT_PTR CALLBACK _WhichNetDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  124. {
  125. switch (uMsg)
  126. {
  127. case WM_INITDIALOG:
  128. CheckRadioButton(hwnd, IDC_DOMAIN, IDC_WORKGROUP, IDC_DOMAIN);
  129. return TRUE;
  130. case WM_NOTIFY:
  131. {
  132. LPNMHDR pnmh = (LPNMHDR)lParam;
  133. switch (pnmh->code)
  134. {
  135. case PSN_SETACTIVE:
  136. SetWizardButtons(hwnd, PSWIZB_NEXT|PSWIZB_BACK);
  137. return TRUE;
  138. case PSN_WIZBACK:
  139. WIZARDNEXT(hwnd, IDD_PSW_HOWUSE);
  140. return TRUE;
  141. case PSN_WIZNEXT:
  142. {
  143. if (IsDlgButtonChecked(hwnd, IDC_DOMAIN) == BST_CHECKED)
  144. {
  145. g_dwWhichNet = IDC_DOMAIN;
  146. WIZARDNEXT(hwnd, IDD_PSW_DOMAININFO);
  147. }
  148. else
  149. {
  150. g_dwWhichNet = IDC_WORKGROUP;
  151. WIZARDNEXT(hwnd, IDD_PSW_WORKGROUP);
  152. }
  153. return TRUE;
  154. }
  155. }
  156. break;
  157. }
  158. }
  159. return FALSE;
  160. }
  161. // we are joining a workgroup etc
  162. INT_PTR CALLBACK _WorkgroupDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  163. {
  164. switch (uMsg)
  165. {
  166. case WM_INITDIALOG:
  167. {
  168. Edit_LimitText(GetDlgItem(hwnd, IDC_WORKGROUP), MAX_WORKGROUP);
  169. SetDlgItemText(hwnd, IDC_WORKGROUP, DEFAULT_WORKGROUP);
  170. return TRUE;
  171. }
  172. case WM_NOTIFY:
  173. {
  174. LPNMHDR pnmh = (LPNMHDR)lParam;
  175. switch (pnmh->code)
  176. {
  177. case PSN_SETACTIVE:
  178. {
  179. DWORD dwButtons = PSWIZB_NEXT|PSWIZB_BACK;
  180. if (!FetchTextLength(hwnd, IDC_WORKGROUP))
  181. dwButtons &= ~PSWIZB_NEXT;
  182. SetWizardButtons(hwnd, dwButtons);
  183. return TRUE;
  184. }
  185. case PSN_WIZBACK:
  186. WIZARDNEXT(hwnd, IDD_PSW_WHICHNET);
  187. return TRUE;
  188. case PSN_WIZNEXT:
  189. {
  190. WCHAR szWorkgroup[MAX_WORKGROUP+1];
  191. FetchText(hwnd, IDC_WORKGROUP, szWorkgroup, ARRAYSIZE(szWorkgroup));
  192. if (SUCCEEDED(JoinDomain(hwnd, FALSE, szWorkgroup, NULL, &g_fRebootOnExit)))
  193. {
  194. ClearAutoLogon();
  195. WIZARDNEXT(hwnd, IDD_PSW_DONE);
  196. }
  197. else
  198. {
  199. WIZARDNEXT(hwnd, -1);
  200. }
  201. return TRUE;
  202. }
  203. }
  204. break;
  205. }
  206. case WM_COMMAND:
  207. {
  208. if (HIWORD(wParam) == EN_CHANGE)
  209. {
  210. DWORD dwButtons = PSWIZB_NEXT|PSWIZB_BACK;
  211. if (!FetchTextLength(hwnd, IDC_WORKGROUP))
  212. dwButtons &= ~PSWIZB_NEXT;
  213. SetWizardButtons(hwnd, dwButtons);
  214. return TRUE;
  215. }
  216. break;
  217. }
  218. }
  219. return FALSE;
  220. }
  221. // were done, show the final page
  222. INT_PTR CALLBACK _DoneDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  223. {
  224. switch (uMsg)
  225. {
  226. case WM_INITDIALOG:
  227. SendDlgItemMessage(hwnd, IDC_TITLE, WM_SETFONT, (WPARAM)GetIntroFont(hwnd), 0);
  228. return TRUE;
  229. case WM_NOTIFY:
  230. {
  231. LPNMHDR pnmh = (LPNMHDR)lParam;
  232. switch (pnmh->code)
  233. {
  234. case PSN_SETACTIVE:
  235. {
  236. TCHAR szBuffer[MAX_PATH];
  237. // change the closing prompt if we are supposed to be
  238. LoadString(g_hinst,
  239. g_fRebootOnExit ? IDS_NETWIZFINISHREBOOT:IDS_NETWIZFINISH,
  240. szBuffer, ARRAYSIZE(szBuffer));
  241. SetDlgItemText(hwnd, IDC_FINISHSTATIC, szBuffer);
  242. SetWizardButtons(hwnd, PSWIZB_BACK|PSWIZB_FINISH);
  243. g_fShownLastPage = TRUE; // show the last page of the wizard
  244. return TRUE;
  245. }
  246. case PSN_WIZBACK:
  247. {
  248. switch (g_dwWhichNet)
  249. {
  250. case IDC_DOMAIN:
  251. WIZARDNEXT(hwnd, g_fMachineRenamed ? IDD_PSW_COMPINFO : IDD_PSW_ADDUSER);
  252. break;
  253. case IDC_WORKGROUP:
  254. WIZARDNEXT(hwnd, IDD_PSW_WORKGROUP);
  255. break;
  256. case IDC_NONE:
  257. WIZARDNEXT(hwnd, IDD_PSW_HOWUSE);
  258. break;
  259. }
  260. return TRUE;
  261. }
  262. }
  263. break;
  264. }
  265. }
  266. return FALSE;
  267. }
  268. // subclass this is used for the setup scenario where we want to remove various
  269. // buttons and stop the dialog from being moved. therefore we subclass the
  270. // wizard during its creation and lock its place.
  271. static WNDPROC _oldDlgWndProc;
  272. LRESULT CALLBACK _WizardSubWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  273. {
  274. //
  275. // on WM_WINDOWPOSCHANGING and the window is moving then lets centre it onto the
  276. // desktop window. unfortunately setting the DS_CENTER bit doesn't buy us anything
  277. // as the wizard is resized after creation.
  278. //
  279. if (uMsg == WM_WINDOWPOSCHANGING)
  280. {
  281. LPWINDOWPOS lpwp = (LPWINDOWPOS)lParam;
  282. RECT rcDlg, rcDesktop;
  283. GetWindowRect(hwnd, &rcDlg);
  284. GetWindowRect(GetDesktopWindow(), &rcDesktop);
  285. lpwp->x = ((rcDesktop.right-rcDesktop.left)-(rcDlg.right-rcDlg.left))/2;
  286. lpwp->y = ((rcDesktop.bottom-rcDesktop.top)-(rcDlg.bottom-rcDlg.top))/2;
  287. lpwp->flags &= ~SWP_NOMOVE;
  288. }
  289. return _oldDlgWndProc(hwnd, uMsg, wParam, lParam);
  290. }
  291. int CALLBACK _PropSheetCB(HWND hwnd, UINT uMsg, LPARAM lParam)
  292. {
  293. switch (uMsg)
  294. {
  295. // in pre-create lets set the window styles accorindlgy
  296. // - remove the context menu and system menu
  297. case PSCB_PRECREATE:
  298. {
  299. DLGTEMPLATE *pdlgtmp = (DLGTEMPLATE*)lParam;
  300. pdlgtmp->style &= ~(DS_CONTEXTHELP|WS_SYSMENU);
  301. break;
  302. }
  303. // we now have a dialog, so lets sub class it so we can stop it being
  304. // move around.
  305. case PSCB_INITIALIZED:
  306. {
  307. if (g_uWizardIs != NAW_NETID)
  308. _oldDlgWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)_WizardSubWndProc);
  309. break;
  310. }
  311. }
  312. return FALSE;
  313. }
  314. // gather domain information about the user
  315. INT_PTR CALLBACK _DomainInfoDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  316. {
  317. switch ( uMsg )
  318. {
  319. case WM_INITDIALOG:
  320. return TRUE;
  321. case WM_NOTIFY:
  322. {
  323. LPNMHDR pnmh = (LPNMHDR)lParam;
  324. switch (pnmh->code)
  325. {
  326. case PSN_SETACTIVE:
  327. SetWizardButtons(hwnd, PSWIZB_NEXT|PSWIZB_BACK);
  328. return TRUE;
  329. case PSN_WIZBACK:
  330. {
  331. if ( g_uWizardIs != NAW_NETID )
  332. WIZARDNEXT(hwnd, IDD_PSW_WELCOME);
  333. return TRUE;
  334. }
  335. }
  336. break;
  337. }
  338. }
  339. return FALSE;
  340. }
  341. // handle searching the active directory for an object
  342. //
  343. // Search columns are returns as a ADS_SEARCH_COLUMN which is like a variant,
  344. // but, the data form is more specific to a DS.
  345. //
  346. // We only need strings, therefore barf if any other type is given to us.
  347. //
  348. HRESULT _GetStringFromColumn(ADS_SEARCH_COLUMN *pasc, LPWSTR pBuffer, INT cchBuffer)
  349. {
  350. switch ( pasc->dwADsType )
  351. {
  352. case ADSTYPE_DN_STRING:
  353. case ADSTYPE_CASE_EXACT_STRING:
  354. case ADSTYPE_CASE_IGNORE_STRING:
  355. case ADSTYPE_PRINTABLE_STRING:
  356. case ADSTYPE_NUMERIC_STRING:
  357. StrCpyN(pBuffer, pasc->pADsValues[0].DNString, cchBuffer);
  358. break;
  359. default:
  360. return E_FAIL;
  361. }
  362. return S_OK;
  363. }
  364. //
  365. // Search the DS for a computer object that matches this computer name, if
  366. // we find one then try and crack the name to give us something that
  367. // can be used to join a domain.
  368. //
  369. HRESULT _FindComputerInDomain(LPWSTR pszUserName, LPWSTR pszUserDomain, LPWSTR pszSearchDomain, LPWSTR pszPassword, BSTR *pbstrCompDomain)
  370. {
  371. HRESULT hres;
  372. CWaitCursor cur;
  373. HRESULT hrInit = SHCoInitialize();
  374. WCHAR wszComputerObjectPath[MAX_PATH + 1] = { 0 }; // path to the computer object
  375. // Lets try and deterrmine the domain to search by taking the users domain and
  376. // calling DsGetDcName with it.
  377. PDOMAIN_CONTROLLER_INFO pdci;
  378. DWORD dwres = DsGetDcName(NULL, pszSearchDomain, NULL, NULL, DS_RETURN_DNS_NAME|DS_DIRECTORY_SERVICE_REQUIRED, &pdci);
  379. if ( (NO_ERROR == dwres) && pdci->DnsForestName )
  380. {
  381. TCHAR szDomainUser[MAX_DOMAINUSER + 1];
  382. MakeDomainUserString(pszUserDomain, pszUserName, szDomainUser, ARRAYSIZE(szDomainUser));
  383. WCHAR szBuffer[MAX_PATH + 1];
  384. wsprintf(szBuffer, L"GC://%s", pdci->DnsForestName);
  385. // now open the GC with the domain user (formatting the forest name above)
  386. IDirectorySearch* pds = NULL;
  387. hres = ADsOpenObject(szBuffer, szDomainUser, pszPassword, ADS_SECURE_AUTHENTICATION, IID_PPV_ARG(IDirectorySearch, &pds));
  388. if (SUCCEEDED(hres))
  389. {
  390. // we have a GC object, so lets search it...
  391. ADS_SEARCHPREF_INFO prefInfo[1];
  392. prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; // sub-tree search
  393. prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
  394. prefInfo[0].vValue.Integer = ADS_SCOPE_SUBTREE;
  395. hres = pds->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo));
  396. if (SUCCEEDED(hres))
  397. {
  398. LPWSTR c_aszAttributes[] = { L"ADsPath", };
  399. // using the computer name for this object lets scope the query accordingly
  400. WCHAR szComputerName[MAX_COMPUTERNAME + 1];
  401. DWORD dwComputerName = ARRAYSIZE(szComputerName);
  402. GetComputerName(szComputerName, &dwComputerName);
  403. wsprintf(szBuffer, L"(&(sAMAccountType=805306369)(sAMAccountName=%s$))", szComputerName);
  404. // issue the query
  405. ADS_SEARCH_HANDLE hSearch = NULL;
  406. hres = pds->ExecuteSearch(szBuffer, c_aszAttributes, ARRAYSIZE(c_aszAttributes), &hSearch);
  407. if (SUCCEEDED(hres))
  408. {
  409. // we executed the search, so we can now attempt to read the results back
  410. hres = pds->GetNextRow(hSearch);
  411. if (SUCCEEDED(hres) && (hres != S_ADS_NOMORE_ROWS))
  412. {
  413. // we received a result back, so lets get the ADsPath of the computer
  414. ADS_SEARCH_COLUMN ascADsPath;
  415. hres = pds->GetColumn(hSearch, L"ADsPath", &ascADsPath);
  416. if (SUCCEEDED(hres))
  417. hres = _GetStringFromColumn(&ascADsPath, wszComputerObjectPath, ARRAYSIZE(wszComputerObjectPath));
  418. }
  419. pds->CloseSearchHandle(hSearch);
  420. }
  421. }
  422. pds->Release();
  423. }
  424. NetApiBufferFree(pdci);
  425. }
  426. else
  427. {
  428. hres = E_FAIL;
  429. }
  430. // So we found an object that is of the category computer, and it has the same name
  431. // as the computer object we are looking for. Lets try and crack the name now
  432. // and determine which domain it is in.
  433. if (SUCCEEDED(hres))
  434. {
  435. IADsPathname* padp = NULL;
  436. hres = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (LPVOID*)&padp);
  437. if (SUCCEEDED(hres))
  438. {
  439. hres = padp->Set(wszComputerObjectPath, ADS_SETTYPE_FULL);
  440. if (SUCCEEDED(hres))
  441. {
  442. BSTR bstrX500DN = NULL;
  443. hres = padp->Retrieve(ADS_FORMAT_X500_DN, &bstrX500DN);
  444. if (SUCCEEDED(hres))
  445. {
  446. PDS_NAME_RESULT pdnr = NULL;
  447. dwres = DsCrackNames(NULL, DS_NAME_FLAG_SYNTACTICAL_ONLY,
  448. DS_FQDN_1779_NAME, DS_CANONICAL_NAME,
  449. 1, &bstrX500DN, &pdnr);
  450. if ( (NO_ERROR == dwres) && (pdnr->cItems == 1))
  451. {
  452. // try and get the NETBIOS name for the domain
  453. dwres = DsGetDcName(NULL, pdnr->rItems->pDomain, NULL, NULL, DS_IS_DNS_NAME|DS_RETURN_FLAT_NAME, &pdci);
  454. if (NO_ERROR == dwres)
  455. {
  456. if ( pbstrCompDomain )
  457. *pbstrCompDomain = SysAllocString(pdci->DomainName);
  458. hres = ((pbstrCompDomain && !*pbstrCompDomain)) ? E_OUTOFMEMORY:S_OK;
  459. }
  460. else
  461. {
  462. hres = E_FAIL; // no flat name for the domain
  463. }
  464. DsFreeNameResult(pdnr);
  465. }
  466. else
  467. {
  468. hres = E_FAIL; // failed to find the computer in the domain
  469. }
  470. SysFreeString(bstrX500DN);
  471. }
  472. }
  473. padp->Release();
  474. }
  475. }
  476. SHCoUninitialize(hrInit);
  477. return hres;
  478. }
  479. // This is the phonebook callback, it is used to notify the book of the user name, domain
  480. // and password to be used in this connection. It is also used to receive changes made by
  481. // the user.
  482. VOID WINAPI _PhoneBkCB(ULONG_PTR dwCallBkID, DWORD dwEvent, LPWSTR pszEntry, void *pEventArgs)
  483. {
  484. RASNOUSER *pInfo = (RASNOUSER *)pEventArgs;
  485. CREDINFO *pci = (CREDINFO *)dwCallBkID;
  486. switch ( dwEvent )
  487. {
  488. case RASPBDEVENT_NoUser:
  489. {
  490. //
  491. // we are about to initialize the phonebook dialog, therefore
  492. // lets pass through our credential information.
  493. //
  494. pInfo->dwSize = SIZEOF(RASNOUSER);
  495. pInfo->dwFlags = 0;
  496. pInfo->dwTimeoutMs = 0;
  497. StrCpy(pInfo->szUserName, pci->pszUser);
  498. StrCpy(pInfo->szDomain, pci->pszDomain);
  499. StrCpy(pInfo->szPassword, pci->pszPassword);
  500. break;
  501. }
  502. case RASPBDEVENT_NoUserEdit:
  503. {
  504. //
  505. // the user has changed the credetials we supplied for the
  506. // login, therefore we must update them in our copy accordingly.
  507. //
  508. if ( pInfo->szUserName[0] )
  509. StrCpyN(pci->pszUser, pInfo->szUserName, pci->cchUser);
  510. if ( pInfo->szPassword[0] )
  511. StrCpyN(pci->pszPassword, pInfo->szPassword, pci->cchPassword);
  512. if ( pInfo->szDomain[0] )
  513. StrCpyN(pci->pszDomain, pInfo->szDomain, pci->cchDomain);
  514. break;
  515. }
  516. }
  517. }
  518. // modify the RAS key for allowing phone book edits - so we can create a connectiod
  519. // during setup.
  520. BOOL SetAllowKey(DWORD dwNewValue, DWORD* pdwOldValue)
  521. {
  522. BOOL fValueWasSet = FALSE;
  523. HKEY hkey = NULL;
  524. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_USERS, TEXT(".DEFAULT\\Software\\Microsoft\\RAS Logon Phonebook"), NULL,
  525. TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL))
  526. {
  527. const LPCTSTR pcszAllowEdit = TEXT("AllowLogonPhonebookEdits");
  528. if (NULL != pdwOldValue)
  529. {
  530. DWORD dwType = 0;
  531. DWORD cbSize = sizeof(DWORD);
  532. if (ERROR_SUCCESS != RegQueryValueEx(hkey, pcszAllowEdit, NULL, &dwType, (LPBYTE)pdwOldValue, &cbSize))
  533. {
  534. *pdwOldValue = 0; // Assume FALSE if the value doesn't exist
  535. }
  536. }
  537. // Set the new value
  538. if (ERROR_SUCCESS == RegSetValueEx(hkey, pcszAllowEdit, NULL, REG_DWORD, (CONST BYTE*) &dwNewValue, sizeof (DWORD)))
  539. {
  540. fValueWasSet = TRUE;
  541. }
  542. RegCloseKey(hkey);
  543. }
  544. return fValueWasSet;
  545. }
  546. //
  547. // The user is trying to advance from the user info tab in the Wizard. Therefore
  548. // we must take the information they have entered and:
  549. //
  550. // - log in using RAS (if ras is selected)
  551. // - try and locate a computer object
  552. // - if we find a computer object then allow them to use it
  553. //
  554. // If we failed to find a computer object, or the user found one and decided not
  555. // to use then we advance them to the 'computer info' page in the wizard. If
  556. // they decide to use it then we must apply it and advance to permissions.
  557. //
  558. void _DoUserInfoNext(HWND hwnd)
  559. {
  560. HRESULT hres;
  561. WCHAR szPassword[MAX_PASSWORD + 1];
  562. BSTR bstrCompDomain = NULL;
  563. LONG idNextPage = -1;
  564. TCHAR szSearchDomain[MAX_DOMAIN + 1]; *szSearchDomain = 0;
  565. BOOL fTranslateNameTriedAndFailed = FALSE;
  566. // fSetAllowKey - Have we set the regval that says "allow connectiod creation before logon?"
  567. BOOL fSetAllowKey = FALSE;
  568. DWORD dwPreviousAllowValue = 0;
  569. //
  570. // read the user, domain and password from the dialog. then
  571. // lets search for the computer object that matches the currently
  572. // configure computer name.
  573. //
  574. FetchText(hwnd, IDC_USER, g_szUser, ARRAYSIZE(g_szUser));
  575. FetchText(hwnd, IDC_DOMAIN, g_szDomain, ARRAYSIZE(g_szDomain));
  576. FetchText(hwnd, IDC_PASSWORD, szPassword, ARRAYSIZE(szPassword));
  577. // Handle possible UPN case
  578. if (StrChr(g_szUser, TEXT('@')))
  579. {
  580. *g_szDomain = 0;
  581. }
  582. //
  583. // before we search for the computer object lets check to see if we should be using RAS
  584. // to get ourselves onto the network.
  585. //
  586. if ( IsDlgButtonChecked(hwnd, IDC_DIALUP) == BST_CHECKED )
  587. {
  588. fSetAllowKey = SetAllowKey(1, &dwPreviousAllowValue);
  589. // Its ok to use globals here - we want to overwrite them.
  590. CREDINFO ci = { g_szUser, ARRAYSIZE(g_szUser),
  591. g_szDomain, ARRAYSIZE(g_szDomain),
  592. szPassword, ARRAYSIZE(szPassword) };
  593. RASPBDLG info = { 0 };
  594. info.dwSize = SIZEOF(info);
  595. info.hwndOwner = hwnd;
  596. info.dwFlags = RASPBDFLAG_NoUser;
  597. info.pCallback = _PhoneBkCB;
  598. info.dwCallbackId = (ULONG_PTR)&ci;
  599. if ( !RasPhonebookDlg(NULL, NULL, &info) )
  600. {
  601. hres = E_FAIL; // failed to show the phone book
  602. goto exit_gracefully;
  603. }
  604. // Signal that the wizard has created a RAS connection.
  605. // Just to be extra paranoid, only do this if the wizard isn't a NETID wizard
  606. if (g_uWizardIs != NAW_NETID)
  607. {
  608. g_fCreatedConnection = TRUE;
  609. }
  610. SetDlgItemText(hwnd, IDC_USER, g_szUser);
  611. SetDlgItemText(hwnd, IDC_DOMAIN, g_szDomain);
  612. }
  613. //
  614. // now attempt to look up the computer object in the user domain.
  615. //
  616. if (StrChr(g_szUser, TEXT('@')))
  617. {
  618. TCHAR szDomainUser[MAX_DOMAINUSER + 1];
  619. ULONG ch = ARRAYSIZE(szDomainUser);
  620. if (TranslateName(g_szUser, NameUserPrincipal, NameSamCompatible, szDomainUser, &ch))
  621. {
  622. TCHAR szUser[MAX_USER + 1];
  623. DomainUserString_GetParts(szDomainUser, szUser, ARRAYSIZE(szUser), szSearchDomain, ARRAYSIZE(szSearchDomain));
  624. }
  625. else
  626. {
  627. fTranslateNameTriedAndFailed = TRUE;
  628. }
  629. }
  630. if (0 == *szSearchDomain)
  631. lstrcpyn(szSearchDomain, g_szDomain, ARRAYSIZE(szSearchDomain));
  632. hres = _FindComputerInDomain(g_szUser, g_szDomain, szSearchDomain, szPassword, &bstrCompDomain);
  633. switch ( hres )
  634. {
  635. case S_OK:
  636. {
  637. StrCpy(g_szCompDomain, bstrCompDomain); // they want to change the domain
  638. //
  639. // we found an object in the DS that matches the current computer name
  640. // and domain. show the domain to the user before we join, allowing them
  641. // to confirm that this is what they want to do.
  642. //
  643. if ( IDYES == ShellMessageBox(g_hinst, hwnd,
  644. MAKEINTRESOURCE(IDS_ABOUTTOJOIN), MAKEINTRESOURCE(IDS_USERINFO),
  645. MB_YESNO|MB_ICONQUESTION,
  646. bstrCompDomain) )
  647. {
  648. //
  649. // they don't want to modify the parameters so lets do the join.
  650. //
  651. idNextPage = IDD_PSW_ADDUSER;
  652. // Make local copies of the user/domain buffers since we don't want to modify globals
  653. TCHAR szUser[MAX_DOMAINUSER + 1]; lstrcpyn(szUser, g_szUser, ARRAYSIZE(szUser));
  654. TCHAR szDomain[MAX_DOMAIN + 1]; lstrcpyn(szDomain, g_szDomain, ARRAYSIZE(szDomain));
  655. CREDINFO ci = {szUser, ARRAYSIZE(szUser), szDomain, ARRAYSIZE(szDomain), szPassword, ARRAYSIZE(szPassword)};
  656. if ( FAILED(JoinDomain(hwnd, TRUE, bstrCompDomain, &ci, &g_fRebootOnExit)) )
  657. {
  658. idNextPage = -1; // don't advance they failed to join
  659. }
  660. }
  661. else
  662. {
  663. idNextPage = IDD_PSW_COMPINFO;
  664. }
  665. break;
  666. }
  667. case HRESULT_FROM_WIN32(ERROR_INVALID_DOMAINNAME):
  668. {
  669. // the domain was invalid, so we should really tell them
  670. ShellMessageBox(g_hinst, hwnd,
  671. MAKEINTRESOURCE(IDS_ERR_BADDOMAIN), MAKEINTRESOURCE(IDS_USERINFO),
  672. MB_OK|MB_ICONWARNING, g_szDomain);
  673. break;
  674. }
  675. case HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD):
  676. case HRESULT_FROM_WIN32(ERROR_LOGON_FAILURE):
  677. case HRESULT_FROM_WIN32(ERROR_BAD_USERNAME):
  678. {
  679. // this was a credentail failure, so lets tell the user they got something
  680. // wrong, and let them correct it.
  681. if (!fTranslateNameTriedAndFailed)
  682. {
  683. ShellMessageBox(g_hinst, hwnd,
  684. MAKEINTRESOURCE(IDS_ERR_BADPWUSER), MAKEINTRESOURCE(IDS_USERINFO),
  685. MB_OK|MB_ICONWARNING);
  686. break;
  687. }
  688. else
  689. {
  690. // Fall through... We tried to translate a UPN but we failed, so
  691. // we want to act as if we just failed to find a computer account
  692. goto default_label;
  693. }
  694. }
  695. default:
  696. {
  697. default_label:
  698. // failed to find a computer that matches the information we have, therefore
  699. // lets advance to the computer information page.
  700. StrCmp(g_szCompDomain, g_szDomain);
  701. idNextPage = IDD_PSW_COMPINFO;
  702. break;
  703. }
  704. }
  705. exit_gracefully:
  706. // Reset the "allow connectiod creation before login" value if appropriate
  707. if (fSetAllowKey)
  708. SetAllowKey(dwPreviousAllowValue, NULL);
  709. SysFreeString(bstrCompDomain);
  710. SetDlgItemText(hwnd, IDC_PASSWORD, L"");
  711. WIZARDNEXT(hwnd, idNextPage);
  712. }
  713. //
  714. // wizard page to handle the user information (name, password and domain);
  715. //
  716. BOOL _UserInfoBtnState(HWND hwnd)
  717. {
  718. DWORD dwButtons = PSWIZB_NEXT|PSWIZB_BACK;
  719. // the username/domain fields cannot be blank
  720. if ( !FetchTextLength(hwnd, IDC_USER) )
  721. dwButtons &= ~PSWIZB_NEXT;
  722. if (IsWindowEnabled(GetDlgItem(hwnd, IDC_DOMAIN)))
  723. {
  724. if ( !FetchTextLength(hwnd, IDC_DOMAIN) )
  725. dwButtons &= ~PSWIZB_NEXT;
  726. }
  727. SetWizardButtons(hwnd, dwButtons);
  728. return TRUE;
  729. }
  730. INT_PTR CALLBACK _UserInfoDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  731. {
  732. switch ( uMsg )
  733. {
  734. case WM_INITDIALOG:
  735. {
  736. Edit_LimitText(GetDlgItem(hwnd, IDC_USER), MAX_DOMAINUSER);
  737. Edit_LimitText(GetDlgItem(hwnd, IDC_PASSWORD), MAX_PASSWORD);
  738. Edit_LimitText(GetDlgItem(hwnd, IDC_DOMAIN), MAX_DOMAIN);
  739. // if we are launched from the netid tab then lets read the current
  740. // user and domain and display accordingly.
  741. if ( g_uWizardIs == NAW_NETID )
  742. {
  743. DWORD dwcchUser = ARRAYSIZE(g_szUser);
  744. DWORD dwcchDomain = ARRAYSIZE(g_szDomain);
  745. GetCurrentUserAndDomainName(g_szUser, &dwcchUser, g_szDomain, &dwcchDomain);
  746. ShowWindow(GetDlgItem(hwnd, IDC_DIALUP), SW_HIDE);
  747. }
  748. SetDlgItemText(hwnd, IDC_USER, g_szUser);
  749. SetDlgItemText(hwnd, IDC_DOMAIN, g_szDomain);
  750. EnableDomainForUPN(GetDlgItem(hwnd, IDC_USER), GetDlgItem(hwnd, IDC_DOMAIN));
  751. return TRUE;
  752. }
  753. case WM_NOTIFY:
  754. {
  755. LPNMHDR pnmh = (LPNMHDR)lParam;
  756. switch (pnmh->code)
  757. {
  758. case PSN_SETACTIVE:
  759. return _UserInfoBtnState(hwnd);
  760. case PSN_WIZBACK:
  761. WIZARDNEXT(hwnd, IDD_PSW_DOMAININFO);
  762. return TRUE;
  763. case PSN_WIZNEXT:
  764. _DoUserInfoNext(hwnd); // handles setting the next page etc
  765. return TRUE;
  766. }
  767. break;
  768. }
  769. case WM_COMMAND:
  770. {
  771. switch (HIWORD(wParam))
  772. {
  773. case EN_CHANGE:
  774. if ((IDC_USER == LOWORD(wParam)) || (IDC_DOMAIN == LOWORD(wParam)))
  775. {
  776. EnableDomainForUPN(GetDlgItem(hwnd, IDC_USER), GetDlgItem(hwnd, IDC_DOMAIN));
  777. _UserInfoBtnState(hwnd);
  778. }
  779. }
  780. break;
  781. }
  782. }
  783. return FALSE;
  784. }
  785. // modifying the computer name etc
  786. BOOL _IsTCPIPAvailable(void)
  787. {
  788. BOOL fTCPIPAvailable = FALSE;
  789. HKEY hk;
  790. DWORD dwSize = 0;
  791. // we check to see if the TCP/IP stack is installed and which object it is
  792. // bound to, this is a string, we don't check the value only that the
  793. // length is non-zero.
  794. if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  795. TEXT("System\\CurrentControlSet\\Services\\Tcpip\\Linkage"),
  796. 0x0,
  797. KEY_QUERY_VALUE, &hk) )
  798. {
  799. if ( ERROR_SUCCESS == RegQueryValueEx(hk, TEXT("Export"), 0x0, NULL, NULL, &dwSize) )
  800. {
  801. if ( dwSize > 2 )
  802. {
  803. fTCPIPAvailable = TRUE;
  804. }
  805. }
  806. RegCloseKey(hk);
  807. }
  808. return (fTCPIPAvailable);
  809. }
  810. BOOL _ChangeMachineName(HWND hwnd, WCHAR* pszDomainUser, WCHAR* pszPassword)
  811. {
  812. BOOL fSuccess = FALSE;
  813. // the user has entered a short computer name (possibly a DNS host name), retrieve it
  814. WCHAR szNewShortMachineName[MAX_COMPUTERNAME + 1];
  815. FetchText(hwnd, IDC_COMPUTERNAME, szNewShortMachineName, ARRAYSIZE(szNewShortMachineName));
  816. // get the current short computer name
  817. WCHAR szOldShortMachineName[MAX_COMPUTERNAME + 1];
  818. DWORD cchShort = ARRAYSIZE(szOldShortMachineName);
  819. BOOL fGotOldName = GetComputerName(szOldShortMachineName, &cchShort);
  820. if (fGotOldName)
  821. {
  822. // did the user change the short computer name?
  823. if (0 != StrCmpI(szOldShortMachineName, szNewShortMachineName))
  824. {
  825. g_fMachineRenamed = TRUE;
  826. // if so we need to rename the machine in the domain. For this we need the NetBIOS computer name
  827. WCHAR szNewNetBIOSMachineName[MAX_COMPUTERNAME + 1];
  828. // Get the netbios name from the short name
  829. DWORD cchNetbios = ARRAYSIZE(szNewNetBIOSMachineName);
  830. DnsHostnameToComputerName(szNewShortMachineName, szNewNetBIOSMachineName, &cchNetbios);
  831. // rename the computer in the domain
  832. NET_API_STATUS rename_status = ::NetRenameMachineInDomain(0, szNewNetBIOSMachineName,
  833. pszDomainUser, pszPassword, NETSETUP_ACCT_CREATE);
  834. // if the domain rename succeeded
  835. BOOL fDomainRenameSucceeded = (rename_status == ERROR_SUCCESS);
  836. if (fDomainRenameSucceeded)
  837. {
  838. // set the new short name locally
  839. BOOL fLocalRenameSucceeded;
  840. // do we have TCPIP?
  841. if (_IsTCPIPAvailable())
  842. {
  843. // We can set the name using the short name
  844. fLocalRenameSucceeded = ::SetComputerNameEx(ComputerNamePhysicalDnsHostname,
  845. szNewShortMachineName);
  846. }
  847. else
  848. {
  849. // We need to set using the netbios name - kind of a hack
  850. fLocalRenameSucceeded = ::SetComputerNameEx(ComputerNamePhysicalNetBIOS,
  851. szNewNetBIOSMachineName);
  852. }
  853. fSuccess = fLocalRenameSucceeded;
  854. }
  855. // Handle errors that may have occured changing the name
  856. if (rename_status != ERROR_SUCCESS)
  857. {
  858. TCHAR szMessage[512];
  859. switch (rename_status)
  860. {
  861. case NERR_UserExists:
  862. {
  863. // We don't really mean "user exists" in this case, we mean
  864. // "computer name exists", so load that reason string
  865. LoadString(g_hinst, IDS_COMPNAME_EXISTS, szMessage, ARRAYSIZE(szMessage));
  866. }
  867. break;
  868. default:
  869. {
  870. if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) rename_status, 0, szMessage, ARRAYSIZE(szMessage), NULL))
  871. LoadString(g_hinst, IDS_ERR_UNEXPECTED, szMessage, ARRAYSIZE(szMessage));
  872. }
  873. break;
  874. }
  875. // Note that this is not a hard error, so we use the information icon
  876. ::DisplayFormatMessage(hwnd, IDS_ERR_CAPTION, IDS_NAW_NAMECHANGE_ERROR, MB_OK|MB_ICONINFORMATION, szMessage);
  877. }
  878. }
  879. else
  880. {
  881. // Computer name hasn't changed - just return success
  882. fSuccess = TRUE;
  883. }
  884. }
  885. return(fSuccess);
  886. }
  887. // handle processing the changes
  888. HRESULT _ChangeNameAndJoin(HWND hwnd)
  889. {
  890. WCHAR szDomain[MAX_DOMAIN + 1];
  891. WCHAR szUser[MAX_DOMAINUSER + 1]; szUser[0] = 0;
  892. WCHAR szPassword[MAX_PASSWORD + 1]; szPassword[0] = 0;
  893. BOOL fNameChangeSucceeded = FALSE;
  894. FetchText(hwnd, IDC_DOMAIN, szDomain, ARRAYSIZE(szDomain));
  895. // try to join the new domain
  896. TCHAR szUserDomain[MAX_DOMAIN + 1]; *szUserDomain = 0;
  897. CREDINFO ci = { szUser, ARRAYSIZE(szUser), szUserDomain, ARRAYSIZE(szUserDomain), szPassword, ARRAYSIZE(szPassword) };
  898. HRESULT hres = JoinDomain(hwnd, TRUE, szDomain, &ci, &g_fRebootOnExit);
  899. if (SUCCEEDED(hres))
  900. {
  901. #ifndef DONT_JOIN
  902. LPTSTR pszUser = szUser[0] ? szUser : NULL;
  903. LPTSTR pszPassword = szPassword[0] ?szPassword : NULL;
  904. fNameChangeSucceeded = _ChangeMachineName(hwnd, pszUser, pszPassword);
  905. #endif
  906. }
  907. return hres;;
  908. }
  909. // ensure the wizard buttons reflect what we can do
  910. BOOL _CompInfoBtnState(HWND hwnd)
  911. {
  912. DWORD dwButtons = PSWIZB_NEXT|PSWIZB_BACK;
  913. if ( !FetchTextLength(hwnd, IDC_COMPUTERNAME) )
  914. dwButtons &= ~PSWIZB_NEXT;
  915. if ( !FetchTextLength(hwnd, IDC_DOMAIN) )
  916. dwButtons &= ~PSWIZB_NEXT;
  917. SetWizardButtons(hwnd, dwButtons);
  918. return TRUE;
  919. }
  920. BOOL _ValidateMachineName(HWND hwnd)
  921. {
  922. BOOL fNameInUse = FALSE;
  923. NET_API_STATUS name_status = NERR_Success;
  924. // the user has entered a short computer name (possibly a DNS host name), retrieve it
  925. WCHAR szNewShortMachineName[MAX_COMPUTERNAME + 1];
  926. FetchText(hwnd, IDC_COMPUTERNAME, szNewShortMachineName, ARRAYSIZE(szNewShortMachineName));
  927. // get the current short computer name
  928. WCHAR szOldShortMachineName[MAX_COMPUTERNAME + 1];
  929. DWORD cchShort = ARRAYSIZE(szOldShortMachineName);
  930. BOOL fGotOldName = GetComputerName(szOldShortMachineName, &cchShort);
  931. if (fGotOldName)
  932. {
  933. // did the user change the short computer name?
  934. if (0 != StrCmpI(szOldShortMachineName, szNewShortMachineName))
  935. {
  936. // first we need to check the flat, netbios name
  937. WCHAR szNewNetBIOSMachineName[MAX_COMPUTERNAME + 1];
  938. // Get the netbios name from the short name
  939. DWORD cchNetbios = ARRAYSIZE(szNewNetBIOSMachineName);
  940. DnsHostnameToComputerName(szNewShortMachineName, szNewNetBIOSMachineName, &cchNetbios);
  941. name_status = NetValidateName(NULL, szNewNetBIOSMachineName, NULL, NULL, NetSetupMachine);
  942. }
  943. }
  944. if (name_status != NERR_Success)
  945. {
  946. TCHAR szMessage[512];
  947. if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) name_status, 0, szMessage, ARRAYSIZE(szMessage), NULL))
  948. LoadString(g_hinst, IDS_ERR_UNEXPECTED, szMessage, ARRAYSIZE(szMessage));
  949. ::DisplayFormatMessage(hwnd, IDS_ERR_CAPTION, IDS_MACHINENAMEINUSE, MB_ICONERROR | MB_OK, szMessage);
  950. }
  951. return (name_status == NERR_Success);
  952. }
  953. INT_PTR CALLBACK _CompInfoDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  954. {
  955. switch ( uMsg )
  956. {
  957. case WM_INITDIALOG:
  958. Edit_LimitText(GetDlgItem(hwnd, IDC_DOMAIN), MAX_DOMAIN);
  959. Edit_LimitText(GetDlgItem(hwnd, IDC_COMPUTERNAME), MAX_COMPUTERNAME);
  960. return TRUE;
  961. case WM_NOTIFY:
  962. {
  963. LPNMHDR pnmh = (LPNMHDR)lParam;
  964. switch (pnmh->code)
  965. {
  966. case PSN_SETACTIVE:
  967. {
  968. WCHAR szCompName[MAX_PATH + 1], szMessage[MAX_PATH+MAX_DOMAIN];
  969. DWORD dwBuffer = ARRAYSIZE(szCompName);
  970. // fill in the user domain
  971. FormatMessageString(IDS_COMPNOTFOUND, szMessage, ARRAYSIZE(szMessage), g_szDomain);
  972. SetDlgItemText(hwnd, IDC_COMPINFO, szMessage);
  973. // default the computer name to something sensible
  974. GetComputerName(szCompName, &dwBuffer);
  975. SetDlgItemText(hwnd, IDC_COMPUTERNAME, szCompName);
  976. SetDlgItemText(hwnd, IDC_DOMAIN, g_szCompDomain);
  977. return _CompInfoBtnState(hwnd);
  978. }
  979. case PSN_WIZBACK:
  980. WIZARDNEXT(hwnd, IDD_PSW_USERINFO);
  981. return TRUE;
  982. case PSN_WIZNEXT:
  983. {
  984. INT idNextPage = -1;
  985. if (_ValidateMachineName(hwnd))
  986. {
  987. if (SUCCEEDED(_ChangeNameAndJoin(hwnd)))
  988. {
  989. if (!g_fMachineRenamed)
  990. {
  991. idNextPage = IDD_PSW_ADDUSER;
  992. }
  993. else
  994. {
  995. idNextPage = IDD_PSW_DONE;
  996. }
  997. }
  998. }
  999. WIZARDNEXT(hwnd, idNextPage);
  1000. return TRUE;
  1001. }
  1002. }
  1003. break;
  1004. }
  1005. case WM_COMMAND:
  1006. {
  1007. if ( HIWORD(wParam) == EN_CHANGE )
  1008. return _CompInfoBtnState(hwnd);
  1009. break;
  1010. }
  1011. }
  1012. return FALSE;
  1013. }
  1014. // changing the group membership for the user, adds a domain user to a local group on the machine
  1015. // eg. NET LOCALGROUP /ADD
  1016. BOOL _AddUserToGroup(HWND hwnd, LPCTSTR pszLocalGroup, LPCWSTR pszUser, LPCWSTR pszDomain)
  1017. {
  1018. #ifndef DONT_JOIN
  1019. BOOL fResult = FALSE;
  1020. NET_API_STATUS nas;
  1021. LOCALGROUP_MEMBERS_INFO_3 lgm;
  1022. TCHAR szDomainUser[MAX_DOMAINUSER + 1];
  1023. CWaitCursor cur;
  1024. MakeDomainUserString(pszDomain, pszUser, szDomainUser, ARRAYSIZE(szDomainUser));
  1025. lgm.lgrmi3_domainandname = szDomainUser;
  1026. nas = NetLocalGroupAddMembers(NULL, pszLocalGroup, 3, (BYTE *)&lgm, 1);
  1027. switch ( nas )
  1028. {
  1029. // Success conditions
  1030. case NERR_Success:
  1031. case ERROR_MEMBER_IN_GROUP:
  1032. case ERROR_MEMBER_IN_ALIAS:
  1033. {
  1034. fResult = TRUE;
  1035. break;
  1036. }
  1037. case ERROR_INVALID_MEMBER:
  1038. {
  1039. DisplayFormatMessage(hwnd,
  1040. IDS_PERMISSIONS, IDS_ERR_BADUSER,
  1041. MB_OK|MB_ICONWARNING, pszUser, pszDomain);
  1042. break;
  1043. }
  1044. case ERROR_NO_SUCH_MEMBER:
  1045. {
  1046. DisplayFormatMessage(hwnd,
  1047. IDS_PERMISSIONS, IDS_ERR_NOSUCHUSER,
  1048. MB_OK|MB_ICONWARNING, pszUser, pszDomain);
  1049. break;
  1050. }
  1051. default:
  1052. {
  1053. TCHAR szMessage[512];
  1054. if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) nas, 0, szMessage, ARRAYSIZE(szMessage), NULL))
  1055. LoadString(g_hinst, IDS_ERR_UNEXPECTED, szMessage, ARRAYSIZE(szMessage));
  1056. ::DisplayFormatMessage(hwnd, IDS_ERR_CAPTION, IDS_ERR_ADDUSER, MB_OK|MB_ICONERROR, szMessage);
  1057. fResult = FALSE;
  1058. break;
  1059. }
  1060. }
  1061. return(fResult);
  1062. #else
  1063. return TRUE;
  1064. #endif
  1065. }
  1066. // ensure the wizard buttons reflect what we can do
  1067. BOOL _PermissionsBtnState(HWND hwnd)
  1068. {
  1069. // Next is always valid
  1070. DWORD dwButtons = PSWIZB_NEXT | PSWIZB_BACK;
  1071. SetWizardButtons(hwnd, dwButtons);
  1072. return TRUE;
  1073. }
  1074. // BtnState function for _AddUserDlgProc
  1075. BOOL _AddUserBtnState(HWND hwnd)
  1076. {
  1077. DWORD dwButtons = PSWIZB_NEXT|PSWIZB_BACK;
  1078. BOOL fEnableEdits;
  1079. if (BST_CHECKED == Button_GetCheck(GetDlgItem(hwnd, IDC_ADDUSER)))
  1080. {
  1081. // Enable the user and domain edits
  1082. fEnableEdits = TRUE;
  1083. if ( !FetchTextLength(hwnd, IDC_USER) )
  1084. dwButtons &= ~PSWIZB_NEXT;
  1085. }
  1086. else
  1087. {
  1088. // Disable user and domain edits
  1089. fEnableEdits = FALSE;
  1090. }
  1091. EnableWindow(GetDlgItem(hwnd, IDC_USER), fEnableEdits);
  1092. if (fEnableEdits)
  1093. {
  1094. EnableDomainForUPN(GetDlgItem(hwnd, IDC_USER), GetDlgItem(hwnd, IDC_DOMAIN));
  1095. }
  1096. else
  1097. {
  1098. EnableWindow(GetDlgItem(hwnd, IDC_DOMAIN), FALSE);
  1099. }
  1100. EnableWindow(GetDlgItem(hwnd, IDC_USER_STATIC), fEnableEdits);
  1101. EnableWindow(GetDlgItem(hwnd, IDC_DOMAIN_STATIC), fEnableEdits);
  1102. SetWizardButtons(hwnd, dwButtons);
  1103. return TRUE;
  1104. }
  1105. INT_PTR CALLBACK _AddUserDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1106. {
  1107. switch ( uMsg )
  1108. {
  1109. case WM_INITDIALOG:
  1110. Edit_LimitText(GetDlgItem(hwnd, IDC_USER), MAX_DOMAINUSER);
  1111. Edit_LimitText(GetDlgItem(hwnd, IDC_DOMAIN), MAX_DOMAIN);
  1112. Button_SetCheck(GetDlgItem(hwnd, IDC_ADDUSER), BST_CHECKED);
  1113. return TRUE;
  1114. case WM_NOTIFY:
  1115. {
  1116. LPNMHDR pnmh = (LPNMHDR)lParam;
  1117. switch (pnmh->code)
  1118. {
  1119. case PSN_SETACTIVE:
  1120. {
  1121. SetDlgItemText(hwnd, IDC_USER, g_szUser);
  1122. SetDlgItemText(hwnd, IDC_DOMAIN, g_szDomain);
  1123. _AddUserBtnState(hwnd);
  1124. return TRUE;
  1125. }
  1126. case PSN_WIZBACK:
  1127. {
  1128. if ( g_uWizardIs == NAW_PSDOMAINJOINED )
  1129. WIZARDNEXT(hwnd, IDD_PSW_WELCOME);
  1130. else
  1131. WIZARDNEXT(hwnd, IDD_PSW_USERINFO);
  1132. return TRUE;
  1133. }
  1134. case PSN_WIZNEXT:
  1135. {
  1136. if (BST_CHECKED == Button_GetCheck(GetDlgItem(hwnd, IDC_ADDUSER)))
  1137. {
  1138. FetchText(hwnd, IDC_USER, g_szUser, ARRAYSIZE(g_szUser));
  1139. FetchText(hwnd, IDC_DOMAIN, g_szDomain, ARRAYSIZE(g_szDomain));
  1140. if (StrChr(g_szUser, TEXT('@')))
  1141. {
  1142. *g_szDomain = 0;
  1143. }
  1144. WIZARDNEXT(hwnd, IDD_PSW_PERMISSIONS);
  1145. }
  1146. else
  1147. {
  1148. WIZARDNEXT(hwnd, IDD_PSW_DONE);
  1149. }
  1150. return TRUE;
  1151. }
  1152. }
  1153. break;
  1154. }
  1155. case WM_COMMAND:
  1156. {
  1157. switch ( HIWORD(wParam) )
  1158. {
  1159. case EN_CHANGE:
  1160. case BN_CLICKED:
  1161. _AddUserBtnState(hwnd);
  1162. break;
  1163. }
  1164. break;
  1165. }
  1166. }
  1167. return FALSE;
  1168. }
  1169. //
  1170. // DlgProc for the permissions page.
  1171. //
  1172. INT_PTR CALLBACK _PermissionsDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1173. {
  1174. // Handle local-group related messages
  1175. g_pGroupPageBase->HandleGroupMessage(hwnd, uMsg, wParam, lParam);
  1176. switch ( uMsg )
  1177. {
  1178. case WM_INITDIALOG:
  1179. return TRUE;
  1180. case WM_NOTIFY:
  1181. {
  1182. LPNMHDR pnmh = (LPNMHDR)lParam;
  1183. switch (pnmh->code)
  1184. {
  1185. case PSN_SETACTIVE:
  1186. {
  1187. // Set the "What level of access do you want to grant %S" message
  1188. TCHAR szMessage[256];
  1189. TCHAR szDisplayName[MAX_DOMAINUSER];
  1190. // Make a domain/user string
  1191. MakeDomainUserString(g_szDomain, g_szUser, szDisplayName, ARRAYSIZE(szDisplayName));
  1192. FormatMessageString(IDS_WHATACCESS_FORMAT, szMessage, ARRAYSIZE(szMessage), szDisplayName);
  1193. SetDlgItemText(hwnd, IDC_WHATACCESS, szMessage);
  1194. return _PermissionsBtnState(hwnd);
  1195. }
  1196. case PSN_WIZBACK:
  1197. {
  1198. WIZARDNEXT(hwnd, IDD_PSW_ADDUSER);
  1199. return TRUE;
  1200. }
  1201. case PSN_WIZNEXT:
  1202. {
  1203. // Get the local group here! TODO
  1204. TCHAR szGroup[MAX_GROUP + 1];
  1205. CUserInfo::GROUPPSEUDONYM gs;
  1206. g_pGroupPageBase->GetSelectedGroup(hwnd, szGroup, ARRAYSIZE(szGroup), &gs);
  1207. if ( !_AddUserToGroup(hwnd, szGroup, g_szUser, g_szDomain) )
  1208. {
  1209. WIZARDNEXT(hwnd, -1);
  1210. }
  1211. else
  1212. {
  1213. SetDefAccount(g_szUser, g_szDomain);
  1214. WIZARDNEXT(hwnd, IDD_PSW_DONE);
  1215. }
  1216. return TRUE;
  1217. }
  1218. }
  1219. break;
  1220. }
  1221. case WM_COMMAND:
  1222. {
  1223. switch ( HIWORD(wParam) )
  1224. {
  1225. case EN_CHANGE:
  1226. return _PermissionsBtnState(hwnd);
  1227. }
  1228. break;
  1229. }
  1230. }
  1231. return FALSE;
  1232. }
  1233. // pages that make up the wizard
  1234. #define WIZDLG(name, dlgproc, dwFlags) \
  1235. { MAKEINTRESOURCE(IDD_PSW_##name##), dlgproc, MAKEINTRESOURCE(IDS_##name##), MAKEINTRESOURCE(IDS_##name##_SUB), dwFlags }
  1236. WIZPAGE pages[] =
  1237. {
  1238. WIZDLG(WELCOME, _IntroDlgProc, PSP_HIDEHEADER),
  1239. WIZDLG(HOWUSE, _HowUseDlgProc, 0),
  1240. WIZDLG(WHICHNET, _WhichNetDlgProc, 0),
  1241. WIZDLG(DOMAININFO, _DomainInfoDlgProc, 0),
  1242. WIZDLG(USERINFO, _UserInfoDlgProc, 0),
  1243. WIZDLG(COMPINFO, _CompInfoDlgProc, 0),
  1244. WIZDLG(ADDUSER, _AddUserDlgProc, 0),
  1245. WIZDLG(PERMISSIONS, _PermissionsDlgProc, 0),
  1246. WIZDLG(WORKGROUP, _WorkgroupDlgProc, 0),
  1247. WIZDLG(DONE, _DoneDlgProc, PSP_HIDEHEADER),
  1248. };
  1249. STDAPI NetAccessWizard(HWND hwnd, UINT uType, BOOL *pfReboot)
  1250. {
  1251. // init comctrl
  1252. INITCOMMONCONTROLSEX iccex = { 0 };
  1253. iccex.dwSize = sizeof (iccex);
  1254. iccex.dwICC = ICC_LISTVIEW_CLASSES;
  1255. InitCommonControlsEx(&iccex);
  1256. switch (uType)
  1257. {
  1258. case NAW_NETID:
  1259. break;
  1260. case NAW_PSDOMAINJOINFAILED:
  1261. g_dwWhichNet = IDC_NONE;
  1262. g_uWizardIs = uType;
  1263. break;
  1264. case NAW_PSDOMAINJOINED:
  1265. g_dwWhichNet = IDC_DOMAIN;
  1266. g_uWizardIs = uType;
  1267. break;
  1268. default:
  1269. return E_INVALIDARG;
  1270. }
  1271. // create the pages
  1272. HPROPSHEETPAGE rghpage[ARRAYSIZE(pages)];
  1273. INT cPages = 0;
  1274. for (cPages = 0 ; cPages < ARRAYSIZE(pages) ; cPages++)
  1275. {
  1276. PROPSHEETPAGE psp = { 0 };
  1277. WCHAR szBuffer[MAX_PATH] = { 0 };
  1278. psp.dwSize = SIZEOF(PROPSHEETPAGE);
  1279. psp.hInstance = g_hinst;
  1280. psp.lParam = cPages;
  1281. psp.dwFlags = PSP_USETITLE | PSP_DEFAULT | PSP_USEHEADERTITLE |
  1282. PSP_USEHEADERSUBTITLE | pages[cPages].dwFlags;
  1283. psp.pszTemplate = pages[cPages].idPage;
  1284. psp.pfnDlgProc = pages[cPages].pDlgProc;
  1285. psp.pszTitle = MAKEINTRESOURCE(IDS_NETWIZCAPTION);
  1286. psp.pszHeaderTitle = pages[cPages].pHeading;
  1287. psp.pszHeaderSubTitle = pages[cPages].pSubHeading;
  1288. rghpage[cPages] = CreatePropertySheetPage(&psp);
  1289. }
  1290. // display the wizard
  1291. PROPSHEETHEADER psh = { 0 };
  1292. psh.dwSize = SIZEOF(PROPSHEETHEADER);
  1293. psh.hwndParent = hwnd;
  1294. psh.hInstance = g_hinst;
  1295. psh.dwFlags = PSH_WIZARD | PSH_WIZARD97 | PSH_WATERMARK |
  1296. PSH_STRETCHWATERMARK | PSH_HEADER | PSH_USECALLBACK;
  1297. psh.pszbmHeader = MAKEINTRESOURCE(IDB_PSW_BANNER);
  1298. psh.pszbmWatermark = MAKEINTRESOURCE(IDB_PSW_WATERMARK);
  1299. psh.nPages = cPages;
  1300. psh.phpage = rghpage;
  1301. psh.pfnCallback = _PropSheetCB;
  1302. // Create the global CGroupPageBase object if necessary
  1303. CGroupInfoList grouplist;
  1304. if (SUCCEEDED(grouplist.Initialize()))
  1305. {
  1306. g_pGroupPageBase = new CGroupPageBase(NULL, &grouplist);
  1307. if (NULL != g_pGroupPageBase)
  1308. {
  1309. PropertySheetIcon(&psh, MAKEINTRESOURCE(IDI_PSW));
  1310. delete g_pGroupPageBase;
  1311. }
  1312. }
  1313. //
  1314. // Hang up the all RAS connections if the wizard created one. It is assumed that no non-wizard connections will
  1315. // exist at this time. 90% of the time, they've just changed their domain membership anyway to they will
  1316. // be just about to reboot. Hanging up all connections MAY cause trouble if: There were existing connections
  1317. // before the pre-logon wizard started AND the user cancelled after making connections with the wizard but before
  1318. // changing their domain. There are no situations where this currently happens.
  1319. //
  1320. if (g_fCreatedConnection)
  1321. {
  1322. RASCONN* prgrasconn = (RASCONN*) LocalAlloc(0, sizeof(RASCONN));
  1323. if (NULL != prgrasconn)
  1324. {
  1325. prgrasconn[0].dwSize = sizeof(RASCONN);
  1326. DWORD cb = sizeof(RASCONN);
  1327. DWORD nConn = 0;
  1328. DWORD dwSuccess = RasEnumConnections(prgrasconn, &cb, &nConn);
  1329. if (ERROR_BUFFER_TOO_SMALL == dwSuccess)
  1330. {
  1331. LocalFree(prgrasconn);
  1332. prgrasconn = (RASCONN*) LocalAlloc(0, cb);
  1333. if (NULL != prgrasconn)
  1334. {
  1335. prgrasconn[0].dwSize = sizeof(RASCONN);
  1336. dwSuccess = RasEnumConnections(prgrasconn, &cb, &nConn);
  1337. }
  1338. }
  1339. if (0 == dwSuccess)
  1340. {
  1341. // Make sure we have one and only one connection before hanging up
  1342. for (DWORD i = 0; i < nConn; i ++)
  1343. {
  1344. RasHangUp(prgrasconn[i].hrasconn);
  1345. }
  1346. }
  1347. LocalFree(prgrasconn);
  1348. }
  1349. }
  1350. //
  1351. // restart the machine if we need to, eg: the domain changed
  1352. //
  1353. if (pfReboot)
  1354. *pfReboot = g_fRebootOnExit;
  1355. //
  1356. // if this is coming from setup, then lets display the message
  1357. //
  1358. if (g_fRebootOnExit && !g_fShownLastPage && (g_uWizardIs != NAW_NETID))
  1359. {
  1360. ShellMessageBox(g_hinst,
  1361. hwnd,
  1362. MAKEINTRESOURCE(IDS_RESTARTREQUIRED), MAKEINTRESOURCE(IDS_NETWIZCAPTION),
  1363. MB_OK);
  1364. }
  1365. return S_OK;
  1366. }