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.

553 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000, Microsoft Corporation
  3. Module Name:
  4. elutil.c
  5. Abstract:
  6. Tools and ends
  7. Revision History:
  8. sachins, Apr 23 2001, Created
  9. --*/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. //
  13. // EAPOLUI function mapping
  14. //
  15. EAPOLUIFUNCMAP EapolUIFuncMap[NUM_EAPOL_DLG_MSGS]=
  16. {
  17. {EAPOLUI_GET_USERIDENTITY, ElGetUserIdentityDlgWorker, ElGetUserIdentityDlgWorker, TRUE, SID_GetUserIdentity},
  18. {EAPOLUI_GET_USERNAMEPASSWORD, ElGetUserNamePasswordDlgWorker, NULL, TRUE, SID_GetUserNamePassword},
  19. {EAPOLUI_INVOKEINTERACTIVEUI, ElInvokeInteractiveUIDlgWorker, NULL, TRUE, SID_InvokeInteractiveUI},
  20. {EAPOLUI_EAP_NOTIFICATION, NULL, NULL, TRUE, 0},
  21. {EAPOLUI_REAUTHENTICATE, NULL, NULL, FALSE, 0},
  22. {EAPOLUI_CREATEBALLOON, NULL, NULL, TRUE, SID_AuthenticationFailed},
  23. {EAPOLUI_CLEANUP, NULL, NULL, FALSE, 0},
  24. {EAPOLUI_DUMMY, NULL, NULL, FALSE, 0}
  25. };
  26. //
  27. // ElCanShowBalloon
  28. //
  29. // Description:
  30. // Function called by netshell, to query if balloon is to be displayed
  31. //
  32. // Arguments:
  33. // pGUIDConn - Interface GUID string
  34. // pszConnectionName - Connection Name
  35. // pszBalloonText - Pointer to text to be display
  36. // pszCookie - EAPOL specific information
  37. //
  38. // Return values:
  39. // S_OK - Display balloon
  40. // S_FALSE - Do not display balloon
  41. //
  42. HRESULT
  43. ElCanShowBalloon (
  44. IN const GUID * pGUIDConn,
  45. IN const WCHAR * pszConnectionName,
  46. IN OUT BSTR * pszBalloonText,
  47. IN OUT BSTR * pszCookie
  48. )
  49. {
  50. EAPOL_EAP_UI_CONTEXT *pEapolUIContext = NULL;
  51. DWORD dwIndex = 0;
  52. DWORD dwSessionId = 0;
  53. WCHAR cwszBuffer[MAX_BALLOON_MSG_LEN];
  54. WCHAR wsSSID[MAX_SSID_LEN+1];
  55. DWORD dwSizeOfSSID = 0;
  56. BYTE *bSSID = NULL;
  57. WCHAR *pszFinalBalloonText = NULL;
  58. DWORD dwFinalStringId = 0;
  59. DWORD dwRetCode = NO_ERROR;
  60. DWORD dwRetCode1 = NO_ERROR;
  61. HRESULT hr = S_OK;
  62. do
  63. {
  64. pEapolUIContext = (EAPOL_EAP_UI_CONTEXT *)(*pszCookie);
  65. if (!ProcessIdToSessionId (GetCurrentProcessId (), &dwSessionId))
  66. {
  67. dwRetCode = GetLastError ();
  68. break;
  69. }
  70. if (pEapolUIContext->dwSessionId != dwSessionId)
  71. {
  72. // Not intended for this session
  73. dwRetCode = ERROR_INVALID_PARAMETER;
  74. break;
  75. }
  76. dwSizeOfSSID = pEapolUIContext->dwSizeOfSSID;
  77. bSSID = pEapolUIContext->bSSID;
  78. for (dwIndex=0; dwIndex < NUM_EAPOL_DLG_MSGS; dwIndex++)
  79. {
  80. if (pEapolUIContext->dwEAPOLUIMsgType ==
  81. EapolUIFuncMap[dwIndex].dwEAPOLUIMsgType)
  82. {
  83. if (EapolUIFuncMap[dwIndex].fShowBalloon)
  84. {
  85. TRACE1 (RPC, "ElCanShowBalloon: Response function found, msg (%ld)",
  86. EapolUIContext->dwEAPOLUIMsgType);
  87. dwFinalStringId = EapolUIFuncMap[dwIndex].dwStringID;
  88. // Verify is balloon indeed needs to be popped up OR
  89. // can purpose be achieved without user involvement
  90. if (EapolUIFuncMap[dwIndex].EapolUIVerify != NULL)
  91. {
  92. // Indicate that it is verification cycle, by passing
  93. // NULL connection name, to indicate no display !
  94. dwRetCode1 = EapolUIFuncMap[dwIndex].EapolUIVerify (
  95. NULL,
  96. pEapolUIContext
  97. );
  98. if (dwRetCode1 == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION)
  99. {
  100. // Continue with show balloon
  101. dwRetCode = NO_ERROR;
  102. }
  103. else
  104. {
  105. if (dwRetCode1 != NO_ERROR)
  106. {
  107. switch (dwRetCode1)
  108. {
  109. case ERROR_NO_EAPTLS_CERTIFICATE:
  110. // No certificate found
  111. // Pop balloon accordingly
  112. dwFinalStringId = SID_NoCertificateFound;
  113. // Since we wont take action on this
  114. // balloon being clicked, flag it as
  115. // EAPOLUI_DUMMY
  116. pEapolUIContext->dwEAPOLUIMsgType = EAPOLUI_DUMMY;
  117. dwRetCode = NO_ERROR;
  118. break;
  119. case ERROR_NO_SMART_CARD_READER:
  120. // No smartcard reader found
  121. dwFinalStringId = SID_NoSmartCardReaderFound;
  122. // Since we wont take action on this
  123. // balloon being clicked, flag it as
  124. // EAPOLUI_DUMMY
  125. pEapolUIContext->dwEAPOLUIMsgType = EAPOLUI_DUMMY;
  126. dwRetCode = NO_ERROR;
  127. break;
  128. default:
  129. // Continue with show balloon for any
  130. // error in verification function
  131. dwRetCode = NO_ERROR;
  132. break;
  133. }
  134. }
  135. else
  136. {
  137. // No need to process more.
  138. // Response has been sent successfully
  139. // without user intervention
  140. dwRetCode = ERROR_CAN_NOT_COMPLETE;
  141. break;
  142. }
  143. }
  144. }
  145. if (dwFinalStringId != 0)
  146. {
  147. // Load string based on Id
  148. if (dwFinalStringId <= SID_NoCertificateFound)
  149. {
  150. if (LoadString (GetModuleHandle(cszModuleName), dwFinalStringId, cwszBuffer, MAX_BALLOON_MSG_LEN) == 0)
  151. {
  152. dwRetCode = GetLastError ();
  153. break;
  154. }
  155. }
  156. else
  157. {
  158. if (LoadString (WZCGetSPResModule(), dwFinalStringId, cwszBuffer, MAX_BALLOON_MSG_LEN) == 0)
  159. {
  160. dwRetCode = GetLastError ();
  161. break;
  162. }
  163. }
  164. // Append the network-name / SSID
  165. if (dwSizeOfSSID != 0)
  166. {
  167. if (0 == MultiByteToWideChar (
  168. CP_ACP,
  169. 0,
  170. bSSID,
  171. dwSizeOfSSID,
  172. wsSSID,
  173. MAX_SSID_LEN+1))
  174. {
  175. dwRetCode = GetLastError();
  176. break;
  177. }
  178. if ((pszFinalBalloonText = MALLOC ((wcslen(cwszBuffer)+1+ dwSizeOfSSID)*sizeof(WCHAR))) == NULL)
  179. {
  180. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  181. break;
  182. }
  183. wcscpy (pszFinalBalloonText, cwszBuffer);
  184. memcpy ((BYTE *)(pszFinalBalloonText + wcslen(cwszBuffer)), (BYTE *)wsSSID, dwSizeOfSSID*sizeof(WCHAR));
  185. pszFinalBalloonText[wcslen(cwszBuffer)+dwSizeOfSSID] = L'\0';
  186. }
  187. else
  188. {
  189. // Append a "." (period)
  190. if ((pszFinalBalloonText = MALLOC ((wcslen(cwszBuffer) + 3)*sizeof(WCHAR))) == NULL)
  191. {
  192. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  193. break;
  194. }
  195. wcscpy (pszFinalBalloonText, cwszBuffer);
  196. pszFinalBalloonText[wcslen(cwszBuffer)+1] = L'.';
  197. pszFinalBalloonText[wcslen(cwszBuffer)+2] = L'\0';
  198. }
  199. if (*pszBalloonText)
  200. {
  201. if (!SysReAllocString (pszBalloonText, pszFinalBalloonText))
  202. {
  203. dwRetCode = ERROR_CAN_NOT_COMPLETE;
  204. break;
  205. }
  206. }
  207. else
  208. {
  209. *pszBalloonText = SysAllocString (pszFinalBalloonText);
  210. if (*pszBalloonText == NULL)
  211. {
  212. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  213. break;
  214. }
  215. }
  216. }
  217. else
  218. {
  219. // Display the string that was passed
  220. }
  221. // If notification message, check to see if explorer
  222. // needs to be started off
  223. if (pEapolUIContext->dwEAPOLUIMsgType == EAPOLUI_EAP_NOTIFICATION)
  224. {
  225. // Parse text message
  226. // Attach to cookie
  227. }
  228. }
  229. else
  230. {
  231. TRACE1 (RPC, "ElCanShowBalloon: No balloon display, msg (%ld)",
  232. EapolUIContext.dwEAPOLUIMsgType);
  233. }
  234. }
  235. }
  236. }
  237. while (FALSE);
  238. if (pszFinalBalloonText != NULL)
  239. {
  240. FREE (pszFinalBalloonText);
  241. }
  242. if (dwRetCode != NO_ERROR)
  243. {
  244. hr = S_FALSE;
  245. }
  246. return hr;
  247. }
  248. //
  249. // ElOnBalloonClick
  250. //
  251. // Description:
  252. //
  253. // Function called by netshell, in response to a balloon click
  254. //
  255. // Arguments:
  256. // pGUIDConn - Interface GUID string
  257. // szCookie - EAPOL specific information
  258. //
  259. // Return values:
  260. // S_OK - No error
  261. // S_FALSE - Error
  262. //
  263. HRESULT
  264. ElOnBalloonClick (
  265. IN const GUID * pGUIDConn,
  266. IN const WCHAR * pszConnectionName,
  267. IN const BSTR szCookie
  268. )
  269. {
  270. EAPOL_EAP_UI_CONTEXT *pEapolUIContext = NULL;
  271. DWORD dwIndex = 0;
  272. DWORD dwSessionId = 0;
  273. DWORD dwRetCode = NO_ERROR;
  274. WCHAR *pwszConnectionName = NULL;
  275. HRESULT hr = S_OK;
  276. do
  277. {
  278. pEapolUIContext = (EAPOL_EAP_UI_CONTEXT *)szCookie;
  279. pwszConnectionName = (WCHAR *)pszConnectionName;
  280. for (dwIndex=0; dwIndex < NUM_EAPOL_DLG_MSGS; dwIndex++)
  281. {
  282. if (pEapolUIContext->dwEAPOLUIMsgType ==
  283. EapolUIFuncMap[dwIndex].dwEAPOLUIMsgType)
  284. {
  285. if (EapolUIFuncMap[dwIndex].EapolUIFunc)
  286. {
  287. TRACE1 (RPC, "ElOnBalloonClick: Response function found, msg (%ld)",
  288. EapolUIContext->dwEAPOLUIMsgType);
  289. // Cleanup any previous dialogs for this interface
  290. if ((dwRetCode =
  291. ElDialogCleanup (
  292. (WCHAR *)pszConnectionName,
  293. szCookie
  294. )) != NO_ERROR)
  295. {
  296. TRACE0 (RPC, "ElOnBalloonClick: Error in dialog cleanup");
  297. break;
  298. }
  299. if ((dwRetCode =
  300. EapolUIFuncMap[dwIndex].EapolUIFunc (
  301. pwszConnectionName,
  302. pEapolUIContext
  303. )) != NO_ERROR)
  304. {
  305. TRACE1 (RPC, "ElOnBalloonClick: Response function failed with error %ld",
  306. dwRetCode);
  307. }
  308. }
  309. else
  310. {
  311. TRACE1 (RPC, "ElOnBalloonClick: No response function, msg (%ld)",
  312. EapolUIContext.dwEAPOLUIMsgType);
  313. }
  314. break;
  315. }
  316. }
  317. }
  318. while (FALSE);
  319. hr = HRESULT_FROM_NT (dwRetCode);
  320. return hr;
  321. }
  322. //
  323. // ElSecureEncodePw
  324. //
  325. // Description:
  326. //
  327. // Encrypt password locally using user-ACL
  328. //
  329. DWORD
  330. ElSecureEncodePw (
  331. IN PWCHAR *ppwszPassword,
  332. OUT DATA_BLOB *pDataBlob
  333. )
  334. {
  335. DWORD dwRetCode = NO_ERROR;
  336. DATA_BLOB blobIn, blobOut;
  337. do
  338. {
  339. blobIn.cbData = (wcslen (*ppwszPassword) + 1)*sizeof(WCHAR);
  340. blobIn.pbData = (BYTE *)*ppwszPassword;
  341. if (!CryptProtectData (
  342. &blobIn,
  343. L"",
  344. NULL,
  345. NULL,
  346. NULL,
  347. 0,
  348. &blobOut))
  349. {
  350. dwRetCode = GetLastError ();
  351. break;
  352. }
  353. // copy over blob to password
  354. if (pDataBlob->pbData != NULL)
  355. {
  356. FREE (pDataBlob->pbData);
  357. pDataBlob->pbData = NULL;
  358. pDataBlob->cbData = 0;
  359. }
  360. pDataBlob->pbData = MALLOC (blobOut.cbData);
  361. if (pDataBlob->pbData == NULL)
  362. {
  363. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  364. break;
  365. }
  366. memcpy (pDataBlob->pbData, blobOut.pbData, blobOut.cbData);
  367. pDataBlob->cbData = blobOut.cbData;
  368. }
  369. while (FALSE);
  370. if (blobOut.pbData != NULL)
  371. {
  372. LocalFree (blobOut.pbData);
  373. }
  374. if (dwRetCode != NO_ERROR)
  375. {
  376. if (pDataBlob->pbData != NULL)
  377. {
  378. FREE (pDataBlob->pbData);
  379. pDataBlob->pbData = NULL;
  380. pDataBlob->cbData = 0;
  381. }
  382. }
  383. return dwRetCode;
  384. }
  385. //
  386. // ElQueryConnectionStatusText
  387. //
  388. // Description:
  389. //
  390. // Function called by netshell, to query appropriate text for 802.1X states
  391. //
  392. // Arguments:
  393. // pGUIDConn - Interface GUID string
  394. // ncs - NETCON_STATUS for the interface
  395. // pszStatusText - Detailed 802.1X status to be displayed
  396. //
  397. // Return values:
  398. // S_OK - No error
  399. // S_FALSE - Error
  400. //
  401. HRESULT
  402. ElQueryConnectionStatusText (
  403. IN const GUID * pGUIDConn,
  404. IN const NETCON_STATUS ncs,
  405. IN OUT BSTR * pszStatusText
  406. )
  407. {
  408. WCHAR wszGuid[GUID_STRING_LEN_WITH_TERM];
  409. WCHAR cwszBuffer[MAX_BALLOON_MSG_LEN];
  410. EAPOL_INTF_STATE EapolIntfState = {0};
  411. DWORD dwStringId = 0;
  412. DWORD dwRetCode = NO_ERROR;
  413. HRESULT hr = S_OK;
  414. do
  415. {
  416. ZeroMemory ((PVOID)&EapolIntfState, sizeof(EAPOL_INTF_STATE));
  417. StringFromGUID2 (pGUIDConn, wszGuid, GUID_STRING_LEN_WITH_TERM);
  418. // Query current EAPOL state
  419. if ((dwRetCode = WZCEapolQueryState (
  420. NULL,
  421. wszGuid,
  422. &EapolIntfState
  423. )) != NO_ERROR)
  424. {
  425. break;
  426. }
  427. // Assign appropriate display string
  428. switch (EapolIntfState.dwEapUIState)
  429. {
  430. case 0:
  431. if (EapolIntfState.dwState == EAPOLSTATE_ACQUIRED)
  432. {
  433. dwStringId = SID_ContactingServer;
  434. }
  435. break;
  436. case EAPUISTATE_WAITING_FOR_IDENTITY:
  437. dwStringId = SID_AcquiringIdentity;
  438. break;
  439. case EAPUISTATE_WAITING_FOR_UI_RESPONSE:
  440. dwStringId = SID_UserResponse;
  441. break;
  442. }
  443. if (dwStringId != 0)
  444. {
  445. // Load string based on Id
  446. if (dwStringId <= SID_NoCertificateFound)
  447. {
  448. if (LoadString (GetModuleHandle(cszModuleName), dwStringId, cwszBuffer, MAX_BALLOON_MSG_LEN) == 0)
  449. {
  450. dwRetCode = GetLastError ();
  451. break;
  452. }
  453. }
  454. else
  455. {
  456. if (LoadString (WZCGetSPResModule(), dwStringId, cwszBuffer, MAX_BALLOON_MSG_LEN) == 0)
  457. {
  458. dwRetCode = GetLastError ();
  459. break;
  460. }
  461. }
  462. if (*pszStatusText)
  463. {
  464. if (!SysReAllocString (pszStatusText, cwszBuffer))
  465. {
  466. dwRetCode = ERROR_CAN_NOT_COMPLETE;
  467. break;
  468. }
  469. }
  470. else
  471. {
  472. *pszStatusText = SysAllocString (cwszBuffer);
  473. if (*pszStatusText == NULL)
  474. {
  475. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  476. break;
  477. }
  478. }
  479. }
  480. else
  481. {
  482. // Indicate to netshell that it need not process this response
  483. hr = S_FALSE;
  484. }
  485. }
  486. while (FALSE);
  487. if (dwRetCode != NO_ERROR)
  488. hr = HRESULT_FROM_NT (dwRetCode);
  489. WZCEapolFreeState (&EapolIntfState);
  490. return hr;
  491. }