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.

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