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.

618 lines
17 KiB

  1. #include "mslocusr.h"
  2. #include "msluglob.h"
  3. #include "resource.h"
  4. #include <winnetwk.h>
  5. #include <netspi.h>
  6. #pragma data_seg(".shared")
  7. char szDefaultLogonUsername[MAX_PATH] = "";
  8. char szDefaultLogonPassword[MAX_PATH] = "";
  9. BOOL fDoDefaultLogon = FALSE;
  10. #pragma data_seg()
  11. struct LogonData
  12. {
  13. LPLOGONINFO lpAuthentInfo;
  14. DWORD dwFlags;
  15. IUser **ppOut;
  16. HBITMAP hbmTransparent;
  17. };
  18. void ObfuscateString(LPSTR pszBuffer)
  19. {
  20. DWORD dwMask = 0xa95e633b; /* nice random collection of bits */
  21. unsigned char ch;
  22. do {
  23. ch = *pszBuffer;
  24. *(pszBuffer++) = ch ^ (unsigned char)(dwMask & 0xff);
  25. dwMask = (dwMask >> 8) | (dwMask << 24);
  26. } while (ch);
  27. }
  28. void DeObfuscateString(LPSTR pszBuffer)
  29. {
  30. DWORD dwMask = 0xa95e633b; /* nice random collection of bits */
  31. unsigned char ch;
  32. do {
  33. ch = *pszBuffer ^ (unsigned char)(dwMask & 0xff);
  34. *(pszBuffer++) = ch;
  35. dwMask = (dwMask >> 8) | (dwMask << 24);
  36. } while (ch);
  37. }
  38. void CacheLogonCredentials(LPCSTR pszUsername, LPCSTR pszPassword)
  39. {
  40. lstrcpy(szDefaultLogonUsername, pszUsername);
  41. lstrcpy(szDefaultLogonPassword, pszPassword);
  42. fDoDefaultLogon = TRUE;
  43. ObfuscateString(szDefaultLogonUsername);
  44. ObfuscateString(szDefaultLogonPassword);
  45. }
  46. SPIENTRY NPGetCaps(
  47. DWORD nIndex
  48. )
  49. {
  50. switch (nIndex) {
  51. case WNNC_SPEC_VERSION:
  52. return 0x00040001; /* spec version 4.1 */
  53. case WNNC_NET_TYPE:
  54. return WNNC_NET_MSNET;
  55. case WNNC_DRIVER_VERSION:
  56. return 0x00010000; /* driver version 1.0 */
  57. case WNNC_USER:
  58. return
  59. // WNNC_USR_GETUSER |
  60. 0;
  61. case WNNC_CONNECTION:
  62. return
  63. 0;
  64. case WNNC_DIALOG:
  65. return
  66. 0;
  67. case WNNC_ENUMERATION:
  68. return
  69. 0;
  70. case WNNC_START:
  71. return 0x1; /* started */
  72. case WNNC_RESOURCE:
  73. return
  74. 0;
  75. case WNNC_AUTHENTICATION:
  76. return
  77. WNNC_AUTH_LOGON |
  78. WNNC_AUTH_LOGOFF |
  79. // WNNC_AUTH_GETHOMEDIRECTORY |
  80. // WNNC_AUTH_GETPOLICYPATH |
  81. 0;
  82. }
  83. return 0;
  84. }
  85. // FEATURE not multimonitor friendly
  86. VOID PlaceDialog(HWND hDlg, BOOL fTopThird)
  87. {
  88. RECT rc;
  89. int dyScreen = GetSystemMetrics(SM_CYSCREEN);
  90. int yDialog;
  91. GetWindowRect(hDlg,&rc);
  92. if (fTopThird)
  93. yDialog = (dyScreen / 3) - ((rc.bottom-rc.top) / 2);
  94. else
  95. yDialog = (dyScreen - (rc.bottom - rc.top)) / 2;
  96. SetWindowPos(hDlg,NULL,
  97. (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2,
  98. yDialog, 0, 0, SWP_NOSIZE);
  99. }
  100. void UserSelected(HWND hwndLB, int iItem)
  101. {
  102. BOOL fNeedPassword;
  103. BOOL fEnableOK;
  104. if (iItem == LB_ERR) {
  105. fNeedPassword = FALSE;
  106. fEnableOK = FALSE;
  107. }
  108. else {
  109. IUser *pUser = (IUser *)::SendMessage(hwndLB, LB_GETITEMDATA, iItem, 0);
  110. fNeedPassword = FAILED(pUser->Authenticate(""));
  111. fEnableOK = TRUE;
  112. }
  113. HWND hDlg = GetParent(hwndLB);
  114. EnableWindow(GetDlgItem(hDlg, IDC_PASSWORD_LABEL), fNeedPassword);
  115. EnableWindow(GetDlgItem(hDlg, IDC_PASSWORD), fNeedPassword);
  116. EnableWindow(GetDlgItem(hDlg, IDOK), fEnableOK);
  117. }
  118. HRESULT FillUserList(HWND hwndLB, IUserDatabase *pDB, LPCSTR pszDefaultSelection,
  119. BOOL fIncludeGuest, PFNSELNOTIFY pfnSelNotify)
  120. {
  121. IEnumUnknown *pEnum;
  122. BOOL fSelectionSet = FALSE;
  123. if (fIncludeGuest) {
  124. NLS_STR nlsTemp(MAX_RES_STR_LEN);
  125. if (nlsTemp.LoadString(IDS_GUEST_USERNAME) == ERROR_SUCCESS) {
  126. UINT iItem = (UINT)::SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)nlsTemp.QueryPch());
  127. if (iItem != LB_ERR && iItem != LB_ERRSPACE) {
  128. ::SendMessage(hwndLB, LB_SETITEMDATA, iItem, 0);
  129. }
  130. }
  131. }
  132. HRESULT hres = pDB->EnumUsers(&pEnum);
  133. if (SUCCEEDED(hres)) {
  134. IUnknown *pUnk;
  135. while (pEnum->Next(1, &pUnk, NULL) == S_OK) {
  136. IUser *pUser;
  137. if (SUCCEEDED(pUnk->QueryInterface(IID_IUser, (void **)&pUser))) {
  138. char szBuf[cchMaxUsername+1];
  139. DWORD cbBuffer = sizeof(szBuf);
  140. if (SUCCEEDED(pUser->GetName(szBuf, &cbBuffer))) {
  141. UINT iItem = (UINT)::SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuf);
  142. if (iItem != LB_ERR && iItem != LB_ERRSPACE) {
  143. if (::SendMessage(hwndLB, LB_SETITEMDATA, iItem, (LPARAM)pUser) == LB_ERR)
  144. ::SendMessage(hwndLB, LB_SETITEMDATA, iItem, 0);
  145. if (!fSelectionSet) {
  146. if (pszDefaultSelection != NULL && !::stricmpf(szBuf, pszDefaultSelection)) {
  147. fSelectionSet = TRUE;
  148. ::SendMessage(hwndLB, LB_SETCURSEL, iItem, 0);
  149. if (pfnSelNotify != NULL)
  150. (*pfnSelNotify)(hwndLB, iItem);
  151. }
  152. }
  153. }
  154. }
  155. /* Note that pUser is not Release()d here, since the
  156. * listbox has a pointer to it.
  157. */
  158. }
  159. pUnk->Release();
  160. }
  161. if (!fSelectionSet) {
  162. if (pfnSelNotify)
  163. (*pfnSelNotify)(hwndLB, LB_ERR);
  164. }
  165. else {
  166. /* If we select the default item above, then insert more names
  167. * above it, the focus rect and the selection will be different,
  168. * which is confusing if the user tabs to the listbox. Work
  169. * around this by setting the caret index manually.
  170. */
  171. LRESULT iItem = ::SendMessage(hwndLB, LB_GETCURSEL, 0, 0);
  172. if (iItem != LB_ERR)
  173. ::SendMessage(hwndLB, LB_SETCURSEL, iItem, 0);
  174. }
  175. pEnum->Release();
  176. }
  177. if (FAILED(hres))
  178. return hres;
  179. return fSelectionSet ? NOERROR : S_FALSE;
  180. }
  181. BOOL IsMemphis(void)
  182. {
  183. OSVERSIONINFOA osvi;
  184. osvi.dwOSVersionInfoSize = sizeof(osvi);
  185. GetVersionExA(&osvi);
  186. return (VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId &&
  187. (osvi.dwMajorVersion > 4 ||
  188. (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion >= 10)));
  189. }
  190. DWORD InitLogonDialog(HWND hwndDialog, LogonData *pld)
  191. {
  192. DWORD err = WN_NO_NETWORK;
  193. BOOL fSelectionSet = FALSE;
  194. ::SetWindowLongPtr(hwndDialog, DWLP_USER, (LONG_PTR)pld);
  195. PlaceDialog(hwndDialog, FALSE);
  196. int idBitmap;
  197. DWORD dwFlags;
  198. if (IsMemphis())
  199. idBitmap = IDB_IMAGE_WIN98_LOGON;
  200. else
  201. idBitmap = IDB_IMAGE_LOGON;
  202. /* The bitmap we show at the top of the logon dialog has black text on a
  203. * transparent background. If the dialog background is very dark, the
  204. * text will be unreadable. In that case we use a static bitmap with
  205. * a white background. For more common background colors, though, we use
  206. * LoadImage to load a transparent image and replace the bitmap in the
  207. * dialog.
  208. *
  209. * CODEWORK: Could try a variant of COLORISLIGHT macro from shell32,
  210. * defview.cpp; it seems pretty aggressive about declaring blues in
  211. * particular as "dark". Maybe we could have the alternate bitmap be
  212. * 3D-mapped as well, but have white text and maybe a white box around
  213. * the Windows flag, then we could always be transparent and just choose
  214. * one or the other at an arbitrary cutoff point.
  215. */
  216. DWORD clrBtnFace = GetSysColor(COLOR_3DFACE);
  217. if ((LOBYTE(clrBtnFace) >= 128) ||
  218. (LOBYTE(clrBtnFace >> 8) >= 128) ||
  219. (LOBYTE(clrBtnFace >> 16) >= 128)) {
  220. dwFlags = LR_LOADMAP3DCOLORS; /* we'll use a transparent bitmap */
  221. }
  222. else {
  223. idBitmap++; /* advance to static bitmap ID */
  224. dwFlags = LR_DEFAULTCOLOR;
  225. }
  226. pld->hbmTransparent = (HBITMAP)LoadImage(::hInstance,
  227. MAKEINTRESOURCE(idBitmap),
  228. IMAGE_BITMAP, 0, 0,
  229. dwFlags);
  230. if (pld->hbmTransparent != NULL) {
  231. HBITMAP hbmOld = (HBITMAP)SendDlgItemMessage(hwndDialog,
  232. IDC_MAIN_CAPTION,
  233. STM_SETIMAGE,
  234. (WPARAM)IMAGE_BITMAP,
  235. (LPARAM)pld->hbmTransparent);
  236. /* If we set the new bitmap into the control, we got the old one
  237. * back. Delete the old one. We will also have to delete the
  238. * new one when the dialog is dismissed.
  239. */
  240. if (hbmOld != NULL)
  241. DeleteObject(hbmOld);
  242. }
  243. IUserDatabase *pDB;
  244. if (SUCCEEDED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) {
  245. HRESULT hres = FillUserList(GetDlgItem(hwndDialog, IDC_USERNAME),
  246. pDB, pld->lpAuthentInfo ? pld->lpAuthentInfo->lpUsername : NULL,
  247. FALSE, UserSelected);
  248. if (SUCCEEDED(hres)) {
  249. err = ERROR_SUCCESS;
  250. ::SetFocus(::GetDlgItem(hwndDialog, hres == NOERROR ? IDC_PASSWORD : IDC_USERNAME));
  251. }
  252. pDB->Release();
  253. }
  254. return err;
  255. }
  256. BOOL ValidateLogonDialog(HWND hwndDialog)
  257. {
  258. LRESULT iItem = ::SendDlgItemMessage(hwndDialog, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  259. if (iItem == LB_ERR)
  260. return FALSE;
  261. IUser *pUser = (IUser *)::SendDlgItemMessage(hwndDialog, IDC_USERNAME, LB_GETITEMDATA, iItem, 0);
  262. if (pUser != NULL) {
  263. NLS_STR nlsUsername(cchMaxUsername+1);
  264. if (nlsUsername.QueryError())
  265. return FALSE;
  266. DWORD cbBuffer = nlsUsername.QueryAllocSize();
  267. pUser->GetName(nlsUsername.Party(), &cbBuffer);
  268. nlsUsername.DonePartying();
  269. HWND hwndPassword = ::GetDlgItem(hwndDialog, IDC_PASSWORD);
  270. NLS_STR nlsPassword(::GetWindowTextLength(hwndPassword)+2);
  271. if (nlsPassword.QueryError())
  272. return FALSE;
  273. ::GetWindowText(hwndPassword, nlsPassword.Party(), nlsPassword.QueryAllocSize()-1);
  274. nlsPassword.DonePartying();
  275. if (SUCCEEDED(pUser->Authenticate(nlsPassword.QueryPch()))) {
  276. LogonData *pld = (LogonData *)::GetWindowLongPtr(hwndDialog, DWLP_USER);
  277. if (pld->lpAuthentInfo) {
  278. DWORD cbUsername = pld->lpAuthentInfo->cbUsername;
  279. DWORD cbPassword = pld->lpAuthentInfo->cbPassword;
  280. NPSCopyNLS(&nlsUsername, pld->lpAuthentInfo->lpUsername, &cbUsername);
  281. NPSCopyNLS(&nlsPassword, pld->lpAuthentInfo->lpPassword, &cbPassword);
  282. }
  283. if (pld->ppOut) {
  284. *pld->ppOut = pUser;
  285. pUser->AddRef();
  286. }
  287. if (pld->dwFlags & LUA_FORNEXTLOGON) {
  288. CacheLogonCredentials(nlsUsername.QueryPch(), nlsPassword.QueryPch());
  289. }
  290. return TRUE;
  291. }
  292. NLS_STR nlsTitle(MAX_RES_STR_LEN);
  293. NLS_STR nlsMessage(MAX_RES_STR_LEN);
  294. if (!nlsTitle.QueryError() && !nlsMessage.QueryError()) {
  295. nlsTitle.LoadString(IDS_LOGONTITLE);
  296. nlsMessage.LoadString(IDS_BADPASSWORD);
  297. ::MessageBox(hwndDialog, nlsMessage.QueryPch(), nlsTitle.QueryPch(), MB_ICONSTOP | MB_OK);
  298. }
  299. ::SetFocus(hwndPassword);
  300. ::SendMessage(hwndPassword, EM_SETSEL, (WPARAM)(INT)0, (WPARAM)(INT)-1);
  301. }
  302. return FALSE;
  303. }
  304. void DestroyUserList(HWND hwndLB)
  305. {
  306. LRESULT cItems = ::SendMessage(hwndLB, LB_GETCOUNT, 0, 0);
  307. for (LRESULT iItem = 0; iItem < cItems; iItem++) {
  308. IUser *pUser = (IUser *)::SendMessage(hwndLB, LB_GETITEMDATA, iItem, 0);
  309. if (pUser != NULL) {
  310. pUser->Release();
  311. }
  312. }
  313. }
  314. void ExitLogonDialog(HWND hwndDialog, DWORD err)
  315. {
  316. DestroyUserList(GetDlgItem(hwndDialog, IDC_USERNAME));
  317. LogonData *pld = (LogonData *)::GetWindowLongPtr(hwndDialog, DWLP_USER);
  318. if (pld->hbmTransparent != NULL)
  319. DeleteObject(pld->hbmTransparent);
  320. ::EndDialog(hwndDialog, err);
  321. }
  322. extern "C" {
  323. INT_PTR LogonDlgProc(
  324. HWND hwndDlg,
  325. UINT msg,
  326. WPARAM wParam,
  327. LPARAM lParam
  328. )
  329. {
  330. #if 0 /*** no help for now ***/
  331. // Help text array
  332. static DWORD aIds[] = {
  333. IDC_DUMMY1, IDH_NET_LOG_USERNAME,
  334. IDD_LOG_USERNAME, IDH_NET_LOG_USERNAME,
  335. IDC_DUMMY2, IDH_NET_LOG_PASSWORD,
  336. IDD_LOG_PASSWORD, IDH_NET_LOG_PASSWORD,
  337. IDC_LOGOFRAME, NO_HELP,
  338. IDC_DUMMY3, NO_HELP,
  339. 0,0
  340. };
  341. #endif
  342. switch (msg) {
  343. case WM_INITDIALOG:
  344. {
  345. DWORD err = ::InitLogonDialog(hwndDlg, (LogonData *)lParam);
  346. if (err != ERROR_SUCCESS) {
  347. ::ExitLogonDialog(hwndDlg, err);
  348. }
  349. }
  350. return FALSE; /* we set the focus */
  351. case WM_COMMAND:
  352. switch (LOWORD(wParam)) {
  353. case IDCANCEL:
  354. ::ExitLogonDialog(hwndDlg, WN_CANCEL);
  355. return TRUE; /* we processed a message */
  356. case IDOK:
  357. if (::ValidateLogonDialog(hwndDlg))
  358. ::ExitLogonDialog(hwndDlg, WN_SUCCESS);
  359. return TRUE; /* we processed a message */
  360. case IDC_USERNAME:
  361. if (HIWORD(wParam) == LBN_SELCHANGE) {
  362. int iItem = (int)::SendDlgItemMessage(hwndDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  363. UserSelected((HWND)lParam, iItem);
  364. }
  365. }
  366. break;
  367. #if 0 /*** no help for now ***/
  368. case WM_HELP:
  369. WinHelp( ((LPHELPINFO)lParam)->hItemHandle, szHelpFile,
  370. HELP_WM_HELP, (DWORD)(LPVOID)aIds );
  371. return TRUE;
  372. case WM_CONTEXTMENU:
  373. WinHelp( (HWND)wParam, szHelpFile, HELP_CONTEXTMENU,
  374. (DWORD)(LPVOID)aIds );
  375. return TRUE;
  376. #endif
  377. }
  378. return FALSE; /* we didn't process the message */
  379. }
  380. }; /* extern "C" */
  381. DWORD DoLogonDialog(HWND hwndOwner, LPLOGONINFO lpAuthentInfo)
  382. {
  383. LogonData ld;
  384. ld.lpAuthentInfo = lpAuthentInfo;
  385. ld.dwFlags = 0;
  386. ld.ppOut = NULL;
  387. ld.hbmTransparent = NULL;
  388. INT_PTR nRet = ::DialogBoxParam(::hInstance, MAKEINTRESOURCE(IDD_LOGON),
  389. hwndOwner, LogonDlgProc, (LPARAM)&ld);
  390. if (nRet == -1)
  391. return WN_OUT_OF_MEMORY;
  392. else
  393. return (DWORD)nRet;
  394. }
  395. HRESULT DoUserDialog(HWND hwndOwner, DWORD dwFlags, IUser **ppOut)
  396. {
  397. LogonData ld;
  398. ld.lpAuthentInfo = NULL;
  399. ld.dwFlags = dwFlags;
  400. ld.ppOut = ppOut;
  401. if (ppOut != NULL)
  402. *ppOut = NULL;
  403. INT_PTR nRet = ::DialogBoxParam(::hInstance, MAKEINTRESOURCE(IDD_LOGON),
  404. hwndOwner, LogonDlgProc, (LPARAM)&ld);
  405. if (nRet == -1)
  406. return E_OUTOFMEMORY;
  407. else
  408. return (nRet == WN_SUCCESS) ? S_OK : E_ABORT;
  409. }
  410. DWORD TryDefaultLogon(LPCSTR pszUsername, LPCSTR pszPassword, LPLOGONINFO lpAuthentInfo)
  411. {
  412. IUserDatabase *pDB = NULL;
  413. if (FAILED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) {
  414. return WN_OUT_OF_MEMORY;
  415. }
  416. DWORD err;
  417. IUser *pUser;
  418. if (SUCCEEDED(pDB->GetUser(pszUsername, &pUser))) {
  419. if (SUCCEEDED(pUser->Authenticate(pszPassword)))
  420. err = WN_SUCCESS;
  421. else
  422. err = WN_BAD_PASSWORD;
  423. pUser->Release();
  424. }
  425. else {
  426. err = WN_BAD_USER;
  427. }
  428. pDB->Release();
  429. if (err == WN_SUCCESS) {
  430. DWORD cbUsername = lpAuthentInfo->cbUsername;
  431. DWORD cbPassword = lpAuthentInfo->cbPassword;
  432. NPSCopyString(pszUsername, lpAuthentInfo->lpUsername, &cbUsername);
  433. NPSCopyString(pszPassword, lpAuthentInfo->lpPassword, &cbPassword);
  434. }
  435. return err;
  436. }
  437. SPIENTRY NPLogon(
  438. HWND hwndOwner,
  439. LPLOGONINFO lpAuthentInfo,
  440. LPLOGONINFO lpPreviousAuthentInfo,
  441. LPTSTR lpLogonScript,
  442. DWORD dwBufferSize,
  443. DWORD dwFlags
  444. )
  445. {
  446. /* ignore logon done notification, we only act on logon starting */
  447. if (dwFlags & LOGON_DONE) {
  448. return WN_SUCCESS;
  449. }
  450. /* we have nothing to do if we're not the primary logon provider */
  451. if (!(dwFlags & LOGON_PRIMARY)) {
  452. return WN_SUCCESS;
  453. }
  454. /* make sure profiles are enabled, fall back to windows logon if not */
  455. HKEY hkeyLogon;
  456. DWORD err;
  457. DWORD fProfilesEnabled = FALSE;
  458. DWORD cbData = sizeof(fProfilesEnabled);
  459. err = ::RegOpenKey(HKEY_LOCAL_MACHINE, ::szLogonKey, &hkeyLogon);
  460. if (err != ERROR_SUCCESS)
  461. return WN_NO_NETWORK;
  462. err = ::RegQueryValueEx(hkeyLogon, ::szUserProfiles, NULL, NULL,
  463. (LPBYTE)&fProfilesEnabled, &cbData);
  464. ::RegCloseKey(hkeyLogon);
  465. if (err != ERROR_SUCCESS || !fProfilesEnabled)
  466. return WN_NO_NETWORK;
  467. /* If we have cached logon credentials, attempt to use them. */
  468. if (fDoDefaultLogon) {
  469. DeObfuscateString(szDefaultLogonUsername);
  470. DeObfuscateString(szDefaultLogonPassword);
  471. DWORD err = TryDefaultLogon(szDefaultLogonUsername, szDefaultLogonPassword, lpAuthentInfo);
  472. ::memsetf(szDefaultLogonUsername, '\0', sizeof(szDefaultLogonUsername));
  473. ::memsetf(szDefaultLogonPassword, '\0', sizeof(szDefaultLogonPassword));
  474. fDoDefaultLogon = FALSE;
  475. if (err == WN_SUCCESS)
  476. return WN_SUCCESS;
  477. }
  478. return DoLogonDialog(hwndOwner, lpAuthentInfo);
  479. }
  480. SPIENTRY NPLogoff(
  481. HWND hwndOwner,
  482. LPLOGONINFO lpAuthentInfo,
  483. DWORD dwReason
  484. )
  485. {
  486. return WN_SUCCESS;
  487. }
  488. SPIENTRY NPGetPolicyPath(
  489. LPTSTR lpPath,
  490. LPDWORD lpBufferSize,
  491. DWORD dwFlags
  492. )
  493. {
  494. return WN_NOT_SUPPORTED;
  495. }