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.

377 lines
11 KiB

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. //
  4. // registry information
  5. //
  6. const WCHAR c_szWinLogon[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon";
  7. const WCHAR c_szAutoLogon[] = L"AutoAdminLogon";
  8. const WCHAR c_szDisableCAD[] = L"DisableCAD";
  9. const WCHAR c_szDefUserName[] = L"DefaultUserName";
  10. const WCHAR c_szDefDomain[] = L"DefaultDomainName";
  11. const WCHAR c_szDefPassword[] = L"DefaultPassword";
  12. const WCHAR c_szDefaultPwdKey[] = L"DefaultPassword";
  13. //
  14. // registry helpers
  15. //
  16. BOOL _RegSetSZ(HKEY hk, LPCWSTR pszValueName, LPCWSTR pszValue)
  17. {
  18. DWORD dwSize = lstrlen(pszValue)*SIZEOF(WCHAR);
  19. return ERROR_SUCCESS == RegSetValueEx(hk, pszValueName, 0x0, REG_SZ, (BYTE *)pszValue, dwSize);
  20. }
  21. BOOL _RegSetDWORD(HKEY hk, LPCWSTR pszValueName, DWORD dwValue)
  22. {
  23. DWORD dwSize = SIZEOF(dwValue);
  24. return ERROR_SUCCESS == RegSetValueEx(hk, pszValueName, 0x0, REG_DWORD, (BYTE *)&dwValue, dwSize);
  25. }
  26. BOOL _RegDelValue(HKEY hk, LPCWSTR pszValueName)
  27. {
  28. return ERROR_SUCCESS == RegDeleteValue(hk, pszValueName);
  29. }
  30. INT_PTR CALLBACK _CredDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  31. {
  32. LPCREDINFO pci = (LPCREDINFO)GetWindowLongPtr(hwnd, DWLP_USER);
  33. switch ( uMsg )
  34. {
  35. case WM_INITDIALOG:
  36. {
  37. pci = (LPCREDINFO)lParam;
  38. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  39. SetDlgItemText(hwnd, IDC_USER, pci->pszUser);
  40. Edit_LimitText(GetDlgItem(hwnd, IDC_USER), pci->cchUser - 1);
  41. SetDlgItemText(hwnd, IDC_DOMAIN, pci->pszDomain);
  42. Edit_LimitText(GetDlgItem(hwnd, IDC_DOMAIN), pci->cchDomain - 1);
  43. SetDlgItemText(hwnd, IDC_PASSWORD, pci->pszPassword);
  44. Edit_LimitText(GetDlgItem(hwnd, IDC_PASSWORD), pci->cchPassword - 1);
  45. return TRUE;
  46. }
  47. case WM_COMMAND:
  48. {
  49. switch ( LOWORD(wParam) )
  50. {
  51. case IDOK:
  52. {
  53. FetchText(hwnd, IDC_DOMAIN, pci->pszDomain, pci->cchDomain);
  54. FetchText(hwnd, IDC_USER, pci->pszUser, pci->cchUser);
  55. if (StrChr(pci->pszUser, TEXT('@')))
  56. {
  57. *(pci->pszDomain) = 0;
  58. }
  59. GetDlgItemText(hwnd, IDC_PASSWORD, pci->pszPassword, pci->cchPassword);
  60. return EndDialog(hwnd, IDOK);
  61. }
  62. case IDCANCEL:
  63. return EndDialog(hwnd, IDCANCEL);
  64. case IDC_USER:
  65. {
  66. if ( HIWORD(wParam) == EN_CHANGE )
  67. {
  68. EnableWindow(GetDlgItem(hwnd, IDOK), FetchTextLength(hwnd, IDC_USER) > 0);
  69. EnableDomainForUPN(GetDlgItem(hwnd, IDC_USER), GetDlgItem(hwnd, IDC_DOMAIN));
  70. }
  71. break;
  72. }
  73. }
  74. return TRUE;
  75. }
  76. }
  77. return FALSE;
  78. }
  79. //
  80. // attempt to join a domain/workgroup using the specified names and OU.
  81. //
  82. HRESULT _AttemptJoin(HWND hwnd, DWORD dwFlags, LPCWSTR pszDomain, LPCWSTR pszUser, LPCWSTR pszUserDomain, LPCWSTR pszPassword)
  83. {
  84. HRESULT hr = S_OK;
  85. #ifndef DONT_JOIN
  86. TCHAR szDomainUser[MAX_DOMAINUSER + 1];
  87. if ( pszUser )
  88. MakeDomainUserString(pszUserDomain, pszUser, szDomainUser, ARRAYSIZE(szDomainUser));
  89. NET_API_STATUS nas = NetJoinDomain(NULL, pszDomain, NULL, szDomainUser, pszPassword, dwFlags);
  90. if ( (nas == ERROR_ACCESS_DENIED) )
  91. {
  92. // perhaps an account exists, but we can't delete it so try and remove
  93. // the account create flag
  94. if ( dwFlags & NETSETUP_ACCT_CREATE )
  95. {
  96. dwFlags &= ~NETSETUP_ACCT_CREATE;
  97. nas = NetJoinDomain(NULL, pszDomain, NULL, szDomainUser, *pszPassword ? pszPassword : NULL, dwFlags);
  98. }
  99. }
  100. if ( (nas != NERR_Success) && (nas != NERR_SetupAlreadyJoined) )
  101. {
  102. TCHAR szMessage[512];
  103. if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) nas, 0, szMessage, ARRAYSIZE(szMessage), NULL))
  104. LoadString(g_hinst, IDS_ERR_UNEXPECTED, szMessage, ARRAYSIZE(szMessage));
  105. ::DisplayFormatMessage(hwnd, IDS_ERR_CAPTION, IDS_NAW_JOIN_GENERICERROR, MB_OK|MB_ICONERROR, szMessage);
  106. hr = HRESULT_FROM_WIN32(nas);
  107. }
  108. #endif
  109. return hr;
  110. }
  111. void _ShowDcNotFoundErrorDialog(HWND hwnd, LPCWSTR pszDomain, LPCWSTR pszTitle)
  112. {
  113. typedef void (*pfnShowDcNotFoundErrorDialog)(HWND, PCWSTR, PCWSTR);
  114. static HMODULE hNetID = NULL;
  115. static pfnShowDcNotFoundErrorDialog ShowDcNotFoundErrorDialog = NULL;
  116. if (!hNetID)
  117. {
  118. hNetID = LoadLibrary(L"netid.dll");
  119. }
  120. if (hNetID)
  121. {
  122. ShowDcNotFoundErrorDialog = (pfnShowDcNotFoundErrorDialog) GetProcAddress(hNetID, "ShowDcNotFoundErrorDialog");
  123. if (ShowDcNotFoundErrorDialog)
  124. {
  125. ShowDcNotFoundErrorDialog(hwnd, pszDomain, pszTitle);
  126. }
  127. }
  128. }
  129. //
  130. // Handle moving from to a workgroup or domain. To do this we are passed
  131. // a structure containing all the information we need.
  132. //
  133. HRESULT JoinDomain(HWND hwnd, BOOL fDomain, LPCWSTR pszDomain, CREDINFO* pci, BOOL *pfReboot)
  134. {
  135. HRESULT hres = E_FAIL;
  136. DWORD dwFlags = 0x0;
  137. LPWSTR pszCurrentDomain = NULL;
  138. NET_API_STATUS nas;
  139. BOOL fPassedCredentials = (pci && pci->pszUser && pci->pszUser[0] && pci->pszPassword);
  140. CWaitCursor cur;
  141. //
  142. // lets validate the domain name before we go and use it, therefore avoiding
  143. // orphaning the computer too badly
  144. //
  145. nas = NetValidateName(NULL, pszDomain, NULL, NULL, fDomain ? NetSetupDomain:NetSetupWorkgroup);
  146. if (fDomain && (ERROR_NO_SUCH_DOMAIN == nas))
  147. {
  148. WCHAR szTitle[256];
  149. LoadString(g_hinst, IDS_NETWIZCAPTION, szTitle, ARRAYSIZE(szTitle));
  150. _ShowDcNotFoundErrorDialog(hwnd, pszDomain, szTitle);
  151. return E_FAIL;
  152. }
  153. if ( NERR_Success != nas )
  154. {
  155. ShellMessageBox(g_hinst, hwnd,
  156. fDomain ? MAKEINTRESOURCE(IDS_ERR_BADDOMAIN) : MAKEINTRESOURCE(IDS_ERR_BADWORKGROUP),
  157. MAKEINTRESOURCE(IDS_NETWIZCAPTION),
  158. MB_OK|MB_ICONWARNING,
  159. pszDomain);
  160. return E_FAIL;
  161. }
  162. //
  163. // now attempt to join the domain, prompt for credentails if the ones
  164. // specified are not good enough
  165. //
  166. if ( fDomain )
  167. {
  168. dwFlags |= NETSETUP_JOIN_DOMAIN|NETSETUP_ACCT_CREATE|NETSETUP_DOMAIN_JOIN_IF_JOINED;
  169. }
  170. else
  171. {
  172. nas = NetUnjoinDomain(NULL, NULL, NULL, NETSETUP_ACCT_DELETE);
  173. if ( (nas != NERR_Success) && (nas != NERR_SetupNotJoined) )
  174. {
  175. nas = NetUnjoinDomain(NULL, NULL, NULL, 0x0);
  176. }
  177. if ( (nas != NERR_Success) && (nas != NERR_SetupNotJoined) )
  178. {
  179. hres = E_UNEXPECTED;
  180. goto exit_gracefully;
  181. }
  182. *pfReboot = TRUE; // we changed the domain
  183. }
  184. if ( !fDomain || fPassedCredentials)
  185. {
  186. if (fPassedCredentials)
  187. {
  188. hres = _AttemptJoin(hwnd, dwFlags, pszDomain, pci->pszUser, pci->pszDomain, pci->pszPassword);
  189. }
  190. else
  191. {
  192. hres = _AttemptJoin(hwnd, dwFlags, pszDomain, NULL, NULL, NULL);
  193. }
  194. }
  195. if ( fDomain && ((FAILED(hres) || (!fPassedCredentials))) )
  196. {
  197. do
  198. {
  199. if ( IDCANCEL == DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_PSW_JOINCREDENTIALS),
  200. hwnd, _CredDlgProc, (LPARAM)pci) )
  201. {
  202. hres = E_FAIL;
  203. goto exit_gracefully;
  204. }
  205. // The dialog box changed the cursor from a wait cursor to an arrow cursor, so the cursor
  206. // needs to be changed back.. This call could be moved to _AttemptJoin (along with a call to
  207. // reset the cursor). This call is made synchronously from the message loop for this hwnd
  208. cur.WaitCursor();
  209. hres = _AttemptJoin(hwnd, dwFlags, pszDomain, pci->pszUser, pci->pszDomain, pci->pszPassword);
  210. }
  211. while ( FAILED(hres) );
  212. }
  213. exit_gracefully:
  214. if ( SUCCEEDED(hres) )
  215. {
  216. ClearAutoLogon();
  217. *pfReboot = TRUE; // we changed the domain
  218. }
  219. NetApiBufferFree(pszCurrentDomain);
  220. return hres;
  221. }
  222. //
  223. // set and clear the auto admin logon state.
  224. //
  225. // we set the default user and default domain to the specified strings, we then blow away
  226. // the clear text password stored in the registry to replace it with a password stored
  227. // in the LSA secret space.
  228. //
  229. NTSTATUS _SetDefaultPassword(LPCWSTR PasswordBuffer)
  230. {
  231. NTSTATUS Status = STATUS_SUCCESS;
  232. OBJECT_ATTRIBUTES ObjectAttributes;
  233. LSA_HANDLE LsaHandle = NULL;
  234. UNICODE_STRING SecretName;
  235. UNICODE_STRING SecretValue;
  236. InitializeObjectAttributes(&ObjectAttributes, NULL, 0L, (HANDLE)NULL, NULL);
  237. Status = LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_CREATE_SECRET, &LsaHandle);
  238. if (!NT_SUCCESS(Status))
  239. return Status;
  240. RtlInitUnicodeString(&SecretName, c_szDefaultPwdKey);
  241. RtlInitUnicodeString(&SecretValue, PasswordBuffer);
  242. Status = LsaStorePrivateData(LsaHandle, &SecretName, &SecretValue);
  243. LsaClose(LsaHandle);
  244. return Status;
  245. }
  246. //
  247. // Set and clear auto logon for a particular
  248. //
  249. void SetAutoLogon(LPCWSTR pszUserName, LPCWSTR pszPassword)
  250. {
  251. #ifndef DONT_JOIN
  252. WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
  253. DWORD dwComputerName = ARRAYSIZE(szComputerName);
  254. HKEY hk;
  255. GetComputerName(szComputerName, &dwComputerName);
  256. SetDefAccount(pszUserName, szComputerName); // also clears auto logon
  257. if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
  258. {
  259. _RegSetSZ(hk, c_szAutoLogon, L"1"); // auto admin logon
  260. _RegDelValue(hk, c_szDefPassword); // use the LSA secret for the password
  261. RegCloseKey (hk);
  262. }
  263. _SetDefaultPassword(pszPassword);
  264. #endif
  265. }
  266. //
  267. // clear the auto admin logon
  268. //
  269. STDAPI ClearAutoLogon(VOID)
  270. {
  271. #ifndef DONT_JOIN
  272. HKEY hk;
  273. if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
  274. {
  275. _RegSetSZ(hk, c_szAutoLogon, L"0"); // no auto admin logon
  276. _RegDelValue(hk, c_szDefPassword);
  277. RegCloseKey(hk);
  278. }
  279. _SetDefaultPassword(L""); // clear the LSA secret
  280. #endif
  281. return S_OK;
  282. }
  283. //
  284. // set the default account
  285. //
  286. void SetDefAccount(LPCWSTR pszUser, LPCWSTR pszDomain)
  287. {
  288. #ifndef DONT_JOIN
  289. ClearAutoLogon();
  290. HKEY hk;
  291. if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
  292. {
  293. _RegSetSZ(hk, c_szDefUserName, pszUser);
  294. _RegSetSZ(hk, c_szDefDomain, pszDomain);
  295. RegCloseKey(hk);
  296. }
  297. #endif
  298. }