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.

1836 lines
58 KiB

  1. //--------------------------------------------------------------------------
  2. // Sicily.cpp
  3. //--------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "imnxport.h"
  6. #include "sicily.h"
  7. #include "dllmain.h"
  8. #include "resource.h"
  9. #include "imnxport.h"
  10. #include "strconst.h"
  11. #include <shlwapi.h>
  12. #include "demand.h"
  13. //--------------------------------------------------------------------------
  14. // NTLMSSP_SIGNATURE
  15. //--------------------------------------------------------------------------
  16. #define NTLMSSP_SIGNATURE "NTLMSSP"
  17. //--------------------------------------------------------------------------
  18. // NegotiateFlags
  19. //--------------------------------------------------------------------------
  20. #define NTLMSSP_NEGOTIATE_UNICODE 0x0001 // Text strings are in unicode
  21. //--------------------------------------------------------------------------
  22. // Security Buffer Counts
  23. //--------------------------------------------------------------------------
  24. #define SEC_BUFFER_NUM_NORMAL_BUFFERS 1
  25. //--------------------------------------------------------------------------
  26. // Security Buffer Indexes
  27. //--------------------------------------------------------------------------
  28. #define SEC_BUFFER_CHALLENGE_INDEX 0
  29. #define SEC_BUFFER_USERNAME_INDEX 1
  30. #define SEC_BUFFER_PASSWORD_INDEX 2
  31. #define SEC_BUFFER_NUM_EXTENDED_BUFFERS 3
  32. //--------------------------------------------------------------------------
  33. // NTLM_MESSAGE_TYPE
  34. //--------------------------------------------------------------------------
  35. typedef enum {
  36. NtLmNegotiate = 1,
  37. NtLmChallenge,
  38. NtLmAuthenticate,
  39. NtLmUnknown
  40. } NTLM_MESSAGE_TYPE;
  41. //--------------------------------------------------------------------------
  42. // STRING
  43. //--------------------------------------------------------------------------
  44. typedef struct _STRING {
  45. USHORT Length;
  46. USHORT MaximumLength;
  47. PWCHAR Buffer;
  48. } STRING, *PSTRING;
  49. //--------------------------------------------------------------------------
  50. // AUTHENTICATE_MESSAGE
  51. //--------------------------------------------------------------------------
  52. typedef struct _AUTHENTICATE_MESSAGE {
  53. UCHAR Signature[sizeof(NTLMSSP_SIGNATURE)];
  54. NTLM_MESSAGE_TYPE MessageType;
  55. STRING LmChallengeResponse;
  56. STRING NtChallengeResponse;
  57. STRING DomainName;
  58. STRING UserName;
  59. STRING Workstation;
  60. STRING SessionKey;
  61. ULONG NegotiateFlags;
  62. } AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
  63. //--------------------------------------------------------------------------
  64. // Constants
  65. //--------------------------------------------------------------------------
  66. #define CCHMAX_NTLM_DOMAIN 255
  67. #define LOGON_OK 10000
  68. //--------------------------------------------------------------------------
  69. // String Constants
  70. //--------------------------------------------------------------------------
  71. static const CHAR c_szSecurityDLL[] = "security.dll";
  72. static const CHAR c_szSecur32DLL[] = "secur32.dll";
  73. //--------------------------------------------------------------------------
  74. // MSN/DPA CleareCredentialsCache Function Prototype
  75. //--------------------------------------------------------------------------
  76. typedef BOOL (WINAPI * PFNCLEANUPCREDENTIALCACHE)(void);
  77. //--------------------------------------------------------------------------
  78. // CREDENTIAL
  79. //--------------------------------------------------------------------------
  80. typedef struct tagCREDENTIAL *LPCREDENTIAL;
  81. typedef struct tagCREDENTIAL {
  82. CHAR szServer[CCHMAX_SERVER_NAME];
  83. CHAR szUserName[CCHMAX_USERNAME];
  84. CHAR szPassword[CCHMAX_PASSWORD];
  85. CHAR szDomain[CCHMAX_NTLM_DOMAIN];
  86. DWORD cRetry;
  87. LPCREDENTIAL pNext;
  88. } CREDENTIAL;
  89. //--------------------------------------------------------------------------
  90. // SSPIPROMPTINFO
  91. //--------------------------------------------------------------------------
  92. typedef struct tagSSPIPROMPTINFO {
  93. HRESULT hrResult;
  94. LPSSPICONTEXT pContext;
  95. ULONG fContextAttrib;
  96. PSecBufferDesc pInDescript;
  97. PSecBufferDesc pOutDescript;
  98. TimeStamp tsExpireTime;
  99. PCtxtHandle phCtxCurrent;
  100. DWORD dwFlags;
  101. } SSPIPROMPTINFO, *LPSSPIPROMPTINFO;
  102. //--------------------------------------------------------------------------
  103. // SSPILOGON
  104. //--------------------------------------------------------------------------
  105. typedef struct tagSSPILOGON {
  106. LPCREDENTIAL pCredential;
  107. LPSSPICONTEXT pContext;
  108. } SSPILOGON, *LPSSPILOGON;
  109. //--------------------------------------------------------------------------
  110. // SSPILOGONFLAGS
  111. //--------------------------------------------------------------------------
  112. typedef DWORD SSPILOGONFLAGS;
  113. #define SSPI_LOGON_RETRY 0x00000001
  114. #define SSPI_LOGON_FLUSH 0x00000002
  115. //--------------------------------------------------------------------------
  116. // Globals
  117. //--------------------------------------------------------------------------
  118. static PSecurityFunctionTable g_pFunctions = NULL;
  119. static HINSTANCE g_hInstSSPI = NULL;
  120. static LPCREDENTIAL g_pCredentialHead=NULL;
  121. static LPSSPIPACKAGE g_prgPackage=NULL;
  122. static DWORD g_cPackages=0;
  123. //--------------------------------------------------------------------------
  124. // base642six
  125. //--------------------------------------------------------------------------
  126. static const int base642six[256] = {
  127. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  128. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
  129. 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
  130. 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
  131. 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
  132. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  133. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  134. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  135. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  136. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  137. 64,64,64,64,64,64,64,64,64,64,64,64,64
  138. };
  139. //--------------------------------------------------------------------------
  140. // six2base64
  141. //--------------------------------------------------------------------------
  142. static const char six2base64[64] = {
  143. 'A','B','C','D','E','F','G','H','I','J','K','L','M',
  144. 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
  145. 'a','b','c','d','e','f','g','h','i','j','k','l','m',
  146. 'n','o','p','q','r','s','t','u','v','w','x','y','z',
  147. '0','1','2','3','4','5','6','7','8','9','+','/'
  148. };
  149. //--------------------------------------------------------------------------
  150. // uu2six
  151. //--------------------------------------------------------------------------
  152. const int uu2six[256] = {
  153. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  154. 64,64,64,64,64,64,64,64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
  155. 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,
  156. 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
  157. 0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  158. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  159. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  160. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  161. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  162. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  163. 64,64,64,64,64,64,64,64,64,64,64,64,64
  164. };
  165. //--------------------------------------------------------------------------
  166. // six2uu
  167. //--------------------------------------------------------------------------
  168. static const char six2uu[64] = {
  169. '`','!','"','#','$','%','&','\'','(',')','*','+',',',
  170. '-','.','/','0','1','2','3','4','5','6','7','8','9',
  171. ':',';','<','=','>','?','@','A','B','C','D','E','F',
  172. 'G','H','I','J','K','L','M','N','O','P','Q','R','S',
  173. 'T','U','V','W','X','Y','Z','[','\\',']','^','_'
  174. };
  175. //--------------------------------------------------------------------------
  176. // Prototypes
  177. //--------------------------------------------------------------------------
  178. HRESULT SSPIFlushMSNCredentialCache(void);
  179. //--------------------------------------------------------------------------
  180. // SSPISetBuffer
  181. //--------------------------------------------------------------------------
  182. HRESULT SSPISetBuffer(LPCSTR pszString, SSPIBUFFERTYPE tyBuffer,
  183. DWORD cbBuffer, LPSSPIBUFFER pBuffer)
  184. {
  185. // Trace
  186. TraceCall("SSPISetBuffer");
  187. // No Length Passed In ?
  188. if (SSPI_STRING == tyBuffer)
  189. {
  190. // Get the Length
  191. pBuffer->cbBuffer = lstrlen(pszString) + 1;
  192. // Too Long
  193. if (pBuffer->cbBuffer > CBMAX_SSPI_BUFFER)
  194. pBuffer->cbBuffer = CBMAX_SSPI_BUFFER;
  195. // Copy the data
  196. CopyMemory(pBuffer->szBuffer, pszString, pBuffer->cbBuffer);
  197. // Stuff a Null
  198. pBuffer->szBuffer[pBuffer->cbBuffer - 1] = '\0';
  199. // Loop
  200. while (pBuffer->cbBuffer >= 2)
  201. {
  202. // Not a CRLF
  203. if ('\r' != pBuffer->szBuffer[pBuffer->cbBuffer - 2] && '\n' != pBuffer->szBuffer[pBuffer->cbBuffer - 2])
  204. break;
  205. // Decrement Length
  206. pBuffer->cbBuffer--;
  207. // Null Terminate
  208. pBuffer->szBuffer[pBuffer->cbBuffer - 1] = '\0';
  209. }
  210. }
  211. // Otherwise, set cbBuffer
  212. else
  213. {
  214. // Set cbBuffer
  215. pBuffer->cbBuffer = min(cbBuffer + 1, CBMAX_SSPI_BUFFER);
  216. // Null Terminate
  217. pBuffer->szBuffer[pBuffer->cbBuffer - 1] = '\0';
  218. // Copy the data
  219. CopyMemory(pBuffer->szBuffer, pszString, pBuffer->cbBuffer);
  220. }
  221. // Done
  222. return(S_OK);
  223. }
  224. //--------------------------------------------------------------------------
  225. // GetCredentialDlgProc
  226. //--------------------------------------------------------------------------
  227. INT_PTR CALLBACK GetCredentialDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  228. {
  229. // Locals
  230. LPSSPILOGON pLogon=(LPSSPILOGON)GetWndThisPtr(hwnd);
  231. CHAR szRes[CCHMAX_RES];
  232. CHAR szTitle[CCHMAX_RES + CCHMAX_SERVER_NAME];
  233. // Trace
  234. TraceCall("GetCredentialDlgProc");
  235. // Handle Message
  236. switch (uMsg)
  237. {
  238. case WM_INITDIALOG:
  239. // Get the pointer
  240. pLogon = (LPSSPILOGON)lParam;
  241. Assert(pLogon);
  242. // Set pContext hwndLogon
  243. pLogon->pContext->hwndLogon = hwnd;
  244. // Set myself to the foreground
  245. SetForegroundWindow(hwnd);
  246. // Center remember location
  247. CenterDialog(hwnd);
  248. // Limit Text
  249. Edit_LimitText(GetDlgItem(hwnd, IDE_USERNAME), CCHMAX_USERNAME - 1);
  250. Edit_LimitText(GetDlgItem(hwnd, IDE_PASSWORD), CCHMAX_PASSWORD - 1);
  251. Edit_LimitText(GetDlgItem(hwnd, IDE_DOMAIN), CCHMAX_NTLM_DOMAIN - 1);
  252. // Set Window Title
  253. GetWindowText(hwnd, szRes, ARRAYSIZE(szRes));
  254. wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s - %s", szRes, pLogon->pCredential->szServer);
  255. SetWindowText(hwnd, szTitle);
  256. // Set User Name
  257. Edit_SetText(GetDlgItem(hwnd, IDE_USERNAME), pLogon->pCredential->szUserName);
  258. Edit_SetText(GetDlgItem(hwnd, IDE_PASSWORD), pLogon->pCredential->szPassword);
  259. Edit_SetText(GetDlgItem(hwnd, IDE_DOMAIN), pLogon->pCredential->szDomain);
  260. // Focus
  261. if (pLogon->pCredential->szUserName[0] == '\0')
  262. SetFocus(GetDlgItem(hwnd, IDE_USERNAME));
  263. else
  264. SetFocus(GetDlgItem(hwnd, IDE_PASSWORD));
  265. // Save the pointer
  266. SetWndThisPtr(hwnd, pLogon);
  267. // Done
  268. return(FALSE);
  269. case WM_COMMAND:
  270. switch(GET_WM_COMMAND_ID(wParam,lParam))
  271. {
  272. case IDCANCEL:
  273. if (pLogon)
  274. pLogon->pContext->hwndLogon = NULL;
  275. EndDialog(hwnd, IDCANCEL);
  276. return(TRUE);
  277. case IDOK:
  278. Assert(pLogon);
  279. if (pLogon)
  280. {
  281. Edit_GetText(GetDlgItem(hwnd, IDE_USERNAME), pLogon->pCredential->szUserName, CCHMAX_USERNAME);
  282. Edit_GetText(GetDlgItem(hwnd, IDE_PASSWORD), pLogon->pCredential->szPassword, CCHMAX_PASSWORD);
  283. Edit_GetText(GetDlgItem(hwnd, IDE_DOMAIN), pLogon->pCredential->szDomain, CCHMAX_NTLM_DOMAIN);
  284. pLogon->pContext->hwndLogon = NULL;
  285. }
  286. EndDialog(hwnd, LOGON_OK);
  287. return(TRUE);
  288. }
  289. break;
  290. case WM_DESTROY:
  291. // This is here because when OE shuts down and this dialog is displayed, a WM_QUIT is posted to the thread
  292. // that this dialog lives on. WM_QUIT causes a WM_DESTROY dialog to get sent to this dialog, but the parent
  293. // doesn't seem to get re-enabled
  294. EnableWindow(GetParent(hwnd), TRUE);
  295. // Null out the this pointer
  296. SetWndThisPtr(hwnd, NULL);
  297. // Set pContext hwndLogon
  298. if (pLogon)
  299. pLogon->pContext->hwndLogon = NULL;
  300. // Done
  301. return(FALSE);
  302. }
  303. // Done
  304. return(FALSE);
  305. }
  306. //--------------------------------------------------------------------------
  307. // SSPIFillAuth
  308. //--------------------------------------------------------------------------
  309. HRESULT SSPIFillAuth(LPCSTR pszUserName, LPCSTR pszPassword, LPCSTR pszDomain,
  310. SEC_WINNT_AUTH_IDENTITY *pAuth)
  311. {
  312. // Set Flags
  313. pAuth->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  314. // Fill It
  315. pAuth->User = (unsigned char *)(pszUserName ? pszUserName : c_szEmpty);
  316. pAuth->UserLength = lstrlen((LPSTR)pAuth->User);
  317. pAuth->Domain = (unsigned char *)(pszDomain ? pszDomain : c_szEmpty);
  318. pAuth->DomainLength = lstrlen((LPSTR)pAuth->Domain);
  319. pAuth->Password = (unsigned char *)(pszPassword ? pszPassword : c_szEmpty);
  320. pAuth->PasswordLength = lstrlen((LPSTR)pAuth->Password);
  321. // Done
  322. return(S_OK);
  323. }
  324. //--------------------------------------------------------------------------
  325. // SSPIAuthFromCredential
  326. //--------------------------------------------------------------------------
  327. HRESULT SSPIAuthFromCredential(LPCREDENTIAL pCredential, SEC_WINNT_AUTH_IDENTITY *pAuth)
  328. {
  329. // Fill It
  330. SSPIFillAuth(pCredential->szUserName, pCredential->szPassword, pCredential->szDomain, pAuth);
  331. // Done
  332. return(S_OK);
  333. }
  334. //--------------------------------------------------------------------------
  335. // SSPIFindCredential
  336. //--------------------------------------------------------------------------
  337. HRESULT SSPIFindCredential(LPSSPICONTEXT pContext, ITransportCallback *pCallback)
  338. {
  339. // Locals
  340. HRESULT hr=S_OK;
  341. LPCREDENTIAL pCurrent;
  342. LPCREDENTIAL pPrevious=NULL;
  343. LPCREDENTIAL pNew=NULL;
  344. SSPILOGON Logon;
  345. HWND hwndParent=NULL;
  346. ITransportCallbackService *pService=NULL;
  347. // Trace
  348. TraceCall("SSPIFindCredential");
  349. // Invalid Arg
  350. Assert(pContext->pszServer && pCallback);
  351. // No Callback
  352. if (NULL == pCallback)
  353. return TraceResult(E_INVALIDARG);
  354. // Thread Safety
  355. EnterCriticalSection(&g_csDllMain);
  356. // Search the list for cached credentials...
  357. for (pCurrent=g_pCredentialHead; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  358. {
  359. // Is this It ?
  360. if (lstrcmpi(pContext->pszServer, pCurrent->szServer) == 0)
  361. break;
  362. // Save Previous
  363. pPrevious = pCurrent;
  364. }
  365. // If we found one and there are no retries...
  366. if (pCurrent)
  367. {
  368. // If no retries, then use this
  369. if (0 == pCurrent->cRetry)
  370. {
  371. // Reset pContext ?
  372. SafeMemFree(pContext->pszUserName);
  373. SafeMemFree(pContext->pszPassword);
  374. SafeMemFree(pContext->pszDomain);
  375. // Duplicate the good stuff
  376. IF_NULLEXIT(pContext->pszUserName = PszDupA((LPSTR)pCurrent->szUserName));
  377. IF_NULLEXIT(pContext->pszDomain = PszDupA((LPSTR)pCurrent->szDomain));
  378. IF_NULLEXIT(pContext->pszPassword = PszDupA((LPSTR)pCurrent->szPassword));
  379. // Increment retry count
  380. pCurrent->cRetry++;
  381. // Thread Safety
  382. LeaveCriticalSection(&g_csDllMain);
  383. // Done
  384. goto exit;
  385. }
  386. // Unlink pCurrent from the list
  387. if (pPrevious)
  388. {
  389. Assert(pPrevious->pNext == pCurrent);
  390. pPrevious->pNext = pCurrent->pNext;
  391. }
  392. else
  393. {
  394. Assert(g_pCredentialHead == pCurrent);
  395. g_pCredentialHead = pCurrent->pNext;
  396. }
  397. }
  398. // Thread Safety
  399. LeaveCriticalSection(&g_csDllMain);
  400. // Didn't find anything...allocate one
  401. if (NULL == pCurrent)
  402. {
  403. // Allocate
  404. IF_NULLEXIT(pNew = (LPCREDENTIAL)g_pMalloc->Alloc(sizeof(CREDENTIAL)));
  405. // Zero
  406. ZeroMemory(pNew, sizeof(CREDENTIAL));
  407. // Set pCurrent
  408. pCurrent = pNew;
  409. // Store the Server Name
  410. StrCpyN(pCurrent->szServer, pContext->pszServer, ARRAYSIZE(pCurrent->szServer));
  411. }
  412. // No pNext
  413. pCurrent->pNext = NULL;
  414. // QI pTransport for ITransportCallbackService
  415. hr = pCallback->QueryInterface(IID_ITransportCallbackService, (LPVOID *)&pService);
  416. if (FAILED(hr))
  417. {
  418. // Raid-69382 (2/5/99): CDO: loop in ISMTPTransport/INNTPTransport when Sicily authentication fails
  419. // Clients who don't support this interface, I will treat them as a cancel.
  420. pContext->fPromptCancel = TRUE;
  421. TraceResult(hr);
  422. goto exit;
  423. }
  424. // Get a Window Handle
  425. hr = pService->GetParentWindow(0, &hwndParent);
  426. if (FAILED(hr))
  427. {
  428. // Raid-69382 (2/5/99): CDO: loop in ISMTPTransport/INNTPTransport when Sicily authentication fails
  429. // Clients who don't support this interface, I will treat them as a cancel.
  430. pContext->fPromptCancel = TRUE;
  431. TraceResult(hr);
  432. goto exit;
  433. }
  434. // No Parent...
  435. if (NULL == hwndParent || FALSE == IsWindow(hwndParent))
  436. {
  437. hr = TraceResult(E_FAIL);
  438. goto exit;
  439. }
  440. // Bring to the foreground
  441. ShowWindow(hwndParent, SW_SHOW);
  442. SetForegroundWindow(hwndParent);
  443. // Clear the password
  444. *pCurrent->szPassword = '\0';
  445. // Initialize Current...
  446. if (pContext->pszUserName)
  447. StrCpyN(pCurrent->szUserName, pContext->pszUserName, ARRAYSIZE(pCurrent->szUserName));
  448. if (pContext->pszDomain)
  449. StrCpyN(pCurrent->szDomain, pContext->pszDomain, ARRAYSIZE(pCurrent->szDomain));
  450. // Set Logon
  451. Logon.pCredential = pCurrent;
  452. Logon.pContext = pContext;
  453. // Do the Dialog Box
  454. if (LOGON_OK != DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(IDD_NTLMPROMPT), hwndParent, GetCredentialDlgProc, (LPARAM)&Logon))
  455. {
  456. pContext->fPromptCancel = TRUE;
  457. hr = TraceResult(E_FAIL);
  458. goto exit;
  459. }
  460. // Not cancel
  461. pContext->fPromptCancel = FALSE;
  462. // Reset pContext ?
  463. SafeMemFree(pContext->pszUserName);
  464. SafeMemFree(pContext->pszPassword);
  465. SafeMemFree(pContext->pszDomain);
  466. // Duplicate the good stuff
  467. IF_NULLEXIT(pContext->pszUserName = PszDupA((LPSTR)pCurrent->szUserName));
  468. IF_NULLEXIT(pContext->pszDomain = PszDupA((LPSTR)pCurrent->szDomain));
  469. IF_NULLEXIT(pContext->pszPassword = PszDupA((LPSTR)pCurrent->szPassword));
  470. // Set Next
  471. pCurrent->pNext = g_pCredentialHead;
  472. // Reset Head
  473. g_pCredentialHead = pCurrent;
  474. // Set Retry Count
  475. pCurrent->cRetry++;
  476. // Don't Free It
  477. pNew = NULL;
  478. exit:
  479. // Cleanup
  480. SafeMemFree(pNew);
  481. SafeRelease(pService);
  482. // Done
  483. return(hr);
  484. }
  485. //--------------------------------------------------------------------------
  486. // SSPIFreeCredentialList
  487. //--------------------------------------------------------------------------
  488. HRESULT SSPIFreeCredentialList(void)
  489. {
  490. // Locals
  491. LPCREDENTIAL pCurrent;
  492. LPCREDENTIAL pNext;
  493. // Trace
  494. TraceCall("SSPIFreeCredentialList");
  495. // Thread Safety
  496. EnterCriticalSection(&g_csDllMain);
  497. // Set pCurrent
  498. pCurrent = g_pCredentialHead;
  499. // While we have a node
  500. while (pCurrent)
  501. {
  502. // Save pNext
  503. pNext = pCurrent->pNext;
  504. // Free pCurrent
  505. g_pMalloc->Free(pCurrent);
  506. // Goto Next
  507. pCurrent = pNext;
  508. }
  509. // Clear the header
  510. g_pCredentialHead = NULL;
  511. // Thread Safety
  512. LeaveCriticalSection(&g_csDllMain);
  513. // Done
  514. return(S_OK);
  515. }
  516. //--------------------------------------------------------------------------
  517. // SSPIUninitialize
  518. //--------------------------------------------------------------------------
  519. HRESULT SSPIUninitialize(void)
  520. {
  521. // Trace
  522. TraceCall("SSPIUninitialize");
  523. // If we have loaded the dll...
  524. if (g_hInstSSPI)
  525. {
  526. // Free the Lib
  527. FreeLibrary(g_hInstSSPI);
  528. }
  529. // Free Credential List
  530. SSPIFreeCredentialList();
  531. // Free Packages
  532. if (g_prgPackage)
  533. {
  534. // Loop through Packages
  535. for (DWORD i = 0; i < g_cPackages; i++)
  536. {
  537. // Free pszName
  538. SafeMemFree(g_prgPackage[i].pszName);
  539. // Free pszComment
  540. SafeMemFree(g_prgPackage[i].pszComment);
  541. }
  542. // Free packages
  543. SafeMemFree(g_prgPackage);
  544. // No Packages
  545. g_cPackages = 0;
  546. }
  547. // Done
  548. return(S_OK);
  549. }
  550. //--------------------------------------------------------------------------
  551. // SSPIIsInstalled
  552. //--------------------------------------------------------------------------
  553. HRESULT SSPIIsInstalled(void)
  554. {
  555. // Locals
  556. HRESULT hr=S_FALSE;
  557. INIT_SECURITY_INTERFACE addrProcISI = NULL;
  558. // Trace
  559. TraceCall("SSPIIsInstalled");
  560. // Thread Safety
  561. EnterCriticalSection(&g_csDllMain);
  562. // Already Loaded ?
  563. if (g_hInstSSPI)
  564. {
  565. hr = S_OK;
  566. goto exit;
  567. }
  568. // Load Security DLL
  569. if (S_OK == IsPlatformWinNT())
  570. g_hInstSSPI = LoadLibrary(c_szSecurityDLL);
  571. else
  572. g_hInstSSPI = LoadLibrary(c_szSecur32DLL);
  573. // Could not be loaded
  574. if (NULL == g_hInstSSPI)
  575. {
  576. TraceInfo("SSPI: LoadLibrary failed.");
  577. goto exit;
  578. }
  579. // Load the function table
  580. addrProcISI = (INIT_SECURITY_INTERFACE)GetProcAddress(g_hInstSSPI, SECURITY_ENTRYPOINT);
  581. if (NULL == addrProcISI)
  582. {
  583. TraceInfo("SSPI: GetProcAddress failed failed.");
  584. goto exit;
  585. }
  586. // Get the SSPI function table
  587. g_pFunctions = (*addrProcISI)();
  588. // If the didn't work
  589. if (NULL == g_pFunctions)
  590. {
  591. // Free the library
  592. FreeLibrary(g_hInstSSPI);
  593. // Null the handle
  594. g_hInstSSPI = NULL;
  595. // Failed to get the function table
  596. TraceInfo("SSPI: Load Function Table failed.");
  597. // Done
  598. goto exit;
  599. }
  600. // Woo-hoo
  601. hr = S_OK;
  602. exit:
  603. // Thread Safety
  604. LeaveCriticalSection(&g_csDllMain);
  605. // Done
  606. return(hr);
  607. }
  608. //--------------------------------------------------------------------------
  609. // SSPIGetPackages
  610. //--------------------------------------------------------------------------
  611. HRESULT SSPIGetPackages(LPSSPIPACKAGE *pprgPackage, LPDWORD pcPackages)
  612. {
  613. // Locals
  614. SECURITY_STATUS hr=SEC_E_OK;
  615. PSecPkgInfo prgPackage=NULL;
  616. ULONG i;
  617. // Trace
  618. TraceCall("SSPIGetPackages");
  619. // Check Params
  620. if (NULL == pprgPackage || NULL == pcPackages)
  621. return TraceResult(E_INVALIDARG);
  622. // Not Initialized
  623. if (NULL == g_hInstSSPI || NULL == g_pFunctions)
  624. return TraceResult(E_UNEXPECTED);
  625. // Init
  626. *pprgPackage = NULL;
  627. *pcPackages = 0;
  628. // Already have packages ?
  629. EnterCriticalSection(&g_csDllMain);
  630. // Do I already have the packages ?
  631. if (NULL == g_prgPackage)
  632. {
  633. // Enumerate security packages
  634. IF_FAILEXIT(hr = (*(g_pFunctions->EnumerateSecurityPackages))(&g_cPackages, &prgPackage));
  635. // RAID - 29645 - EnumerateSecurityPackages seems to return cSec = Rand and pSec == NULL, so, I need to return at this point if cSec == 0 or pSec == NULL
  636. if (0 == g_cPackages || NULL == prgPackage)
  637. {
  638. hr = TraceResult(E_FAIL);
  639. goto exit;
  640. }
  641. // Allocate pprgPackage
  642. IF_NULLEXIT(g_prgPackage = (LPSSPIPACKAGE)ZeroAllocate(g_cPackages * sizeof(SSPIPACKAGE)));
  643. // Copy data into ppPackages
  644. for (i = 0; i < g_cPackages; i++)
  645. {
  646. g_prgPackage[i].ulCapabilities = prgPackage[i].fCapabilities;
  647. g_prgPackage[i].wVersion = prgPackage[i].wVersion;
  648. g_prgPackage[i].cbMaxToken = prgPackage[i].cbMaxToken;
  649. g_prgPackage[i].pszName = PszDupA(prgPackage[i].Name);
  650. g_prgPackage[i].pszComment = PszDupA(prgPackage[i].Comment);
  651. }
  652. }
  653. // Return Global
  654. *pprgPackage = g_prgPackage;
  655. *pcPackages = g_cPackages;
  656. exit:
  657. // Already have packages ?
  658. LeaveCriticalSection(&g_csDllMain);
  659. // Free the package
  660. if (prgPackage)
  661. {
  662. // Free the Array
  663. (*(g_pFunctions->FreeContextBuffer))(prgPackage);
  664. }
  665. // Done
  666. return(hr);
  667. }
  668. //--------------------------------------------------------------------------
  669. // SSPILogon
  670. //--------------------------------------------------------------------------
  671. HRESULT SSPILogon(LPSSPICONTEXT pContext, BOOL fRetry, BOOL fBase64,
  672. LPCSTR pszPackage, LPINETSERVER pServer, ITransportCallback *pCallback)
  673. {
  674. // Locals
  675. SECURITY_STATUS hr = SEC_E_OK;
  676. TimeStamp tsLifeTime;
  677. SEC_WINNT_AUTH_IDENTITY *pAuth = NULL;
  678. SEC_WINNT_AUTH_IDENTITY Auth={0};
  679. // Trace
  680. TraceCall("SSPILogon");
  681. // Validate
  682. Assert(pCallback);
  683. // Invalid Args
  684. if (NULL == pContext || NULL == pszPackage || NULL == pCallback)
  685. return TraceResult(E_INVALIDARG);
  686. // Not Initialized
  687. if (NULL == g_hInstSSPI || NULL == g_pFunctions)
  688. return TraceResult(E_UNEXPECTED);
  689. // Already have credential
  690. if (pContext->fCredential && SSPI_STATE_USE_CACHED == pContext->tyState)
  691. goto exit;
  692. // Installed ?
  693. if (S_FALSE == SSPIIsInstalled())
  694. {
  695. hr = TraceResult(IXP_E_LOAD_SICILY_FAILED);
  696. goto exit;
  697. }
  698. // Reset fPropmtCancel
  699. pContext->fPromptCancel = FALSE;
  700. // No retry
  701. if (NULL == pContext->pCallback)
  702. {
  703. // Locals
  704. ITransportCallbackService *pService;
  705. // Validate
  706. Assert(!pContext->pszPackage && !pContext->pszServer && !pContext->pCallback && !pContext->pszUserName && !pContext->pszPassword);
  707. // Save fBase64
  708. pContext->fBase64 = fBase64;
  709. // Copy Some Strings
  710. IF_NULLEXIT(pContext->pszPackage = PszDupA(pszPackage));
  711. IF_NULLEXIT(pContext->pszServer = PszDupA(pServer->szServerName));
  712. IF_NULLEXIT(pContext->pszUserName = PszDupA(pServer->szUserName));
  713. // Empty Password
  714. if (FALSE == FIsEmptyA(pServer->szPassword))
  715. {
  716. // Copy It
  717. IF_NULLEXIT(pContext->pszPassword = PszDupA(pServer->szPassword));
  718. }
  719. // Assume Callback
  720. pContext->pCallback = pCallback;
  721. pContext->pCallback->AddRef();
  722. // Supports Callback Service
  723. if (SUCCEEDED(pContext->pCallback->QueryInterface(IID_ITransportCallbackService, (LPVOID *)&pService)))
  724. {
  725. // This object supports the Service
  726. pContext->fService = TRUE;
  727. // Release
  728. pService->Release();
  729. }
  730. // Otherwise
  731. else
  732. pContext->fService = FALSE;
  733. }
  734. // Clear current credential
  735. if (pContext->fCredential)
  736. {
  737. // Free Credential Handle
  738. (*(g_pFunctions->FreeCredentialHandle))(&pContext->hCredential);
  739. // No Credential
  740. pContext->fCredential = FALSE;
  741. }
  742. // Use Cached
  743. if (SSPI_STATE_USE_CACHED == pContext->tyState)
  744. {
  745. // If not a retry...
  746. if (FALSE == fRetry)
  747. {
  748. // No Retries
  749. pContext->cRetries = 0;
  750. // Thread Safety
  751. EnterCriticalSection(&g_csDllMain);
  752. // Search the list for cached credentials...
  753. for (LPCREDENTIAL pCurrent=g_pCredentialHead; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  754. {
  755. // Is this It ?
  756. if (lstrcmpi(pContext->pszServer, pCurrent->szServer) == 0)
  757. {
  758. pCurrent->cRetry = 0;
  759. break;
  760. }
  761. }
  762. // Thread Safety
  763. LeaveCriticalSection(&g_csDllMain);
  764. }
  765. // Otherwise, assume we will need to force a prompt...
  766. else
  767. {
  768. // Increment Retry Count
  769. pContext->cRetries++;
  770. // Valid Retry States...
  771. Assert(SSPI_STATE_USE_CACHED == pContext->tyRetryState || SSPI_STATE_PROMPT_USE_PACKAGE == pContext->tyRetryState);
  772. // The next phase may be to tell the package to prompt...
  773. pContext->tyState = pContext->tyRetryState;
  774. }
  775. }
  776. // Use Supplied
  777. else if (SSPI_STATE_USE_SUPPLIED == pContext->tyState)
  778. {
  779. // Locals
  780. CredHandle hCredential;
  781. // Next State...
  782. pContext->tyState = SSPI_STATE_USE_CACHED;
  783. // Fill It
  784. SSPIFillAuth(NULL, NULL, NULL, &Auth);
  785. // Do some security stuff
  786. if (SUCCEEDED((*(g_pFunctions->AcquireCredentialsHandle))(NULL, (LPSTR)pContext->pszPackage, SECPKG_CRED_OUTBOUND, NULL, &Auth, NULL, NULL, &hCredential, &tsLifeTime)))
  787. {
  788. // Free the Handle
  789. (*(g_pFunctions->FreeCredentialHandle))(&hCredential);
  790. }
  791. // Use Supplied Credentials...
  792. SSPIFillAuth(pContext->pszUserName, pContext->pszPassword, pContext->pszDomain, &Auth);
  793. // Set pAuth
  794. pAuth = &Auth;
  795. }
  796. // Otherwise, try to get cached credentials
  797. else if (SSPI_STATE_PROMPT_USE_OWN == pContext->tyState)
  798. {
  799. // Next State...
  800. pContext->tyState = SSPI_STATE_USE_CACHED;
  801. // Failure
  802. IF_FAILEXIT(hr = SSPIFindCredential(pContext, pCallback));
  803. // Fill and return credentials
  804. SSPIFillAuth(pContext->pszUserName, pContext->pszPassword, pContext->pszDomain, &Auth);
  805. // Set Auth Information
  806. pAuth = &Auth;
  807. }
  808. // Do some security stuff
  809. IF_FAILEXIT(hr = (*(g_pFunctions->AcquireCredentialsHandle))(NULL, (LPSTR)pContext->pszPackage, SECPKG_CRED_OUTBOUND, NULL, pAuth, NULL, NULL, &pContext->hCredential, &tsLifeTime));
  810. // We have a credential
  811. pContext->fCredential = TRUE;
  812. exit:
  813. // Done
  814. return(hr);
  815. }
  816. //--------------------------------------------------------------------------
  817. // SSPIGetNegotiate
  818. //--------------------------------------------------------------------------
  819. HRESULT SSPIGetNegotiate(LPSSPICONTEXT pContext, LPSSPIBUFFER pNegotiate)
  820. {
  821. // Locals
  822. HRESULT hr=S_OK;
  823. // Trace
  824. TraceCall("SSPIGetNegotiate");
  825. // Invalid Args
  826. if (NULL == pContext || NULL == pNegotiate)
  827. return TraceResult(E_INVALIDARG);
  828. // Not Initialized
  829. if (NULL == g_hInstSSPI || NULL == g_pFunctions)
  830. return TraceResult(E_UNEXPECTED);
  831. // If the context is currently initialized
  832. if (pContext->fContext)
  833. {
  834. // Delete this context
  835. (*(g_pFunctions->DeleteSecurityContext))(&pContext->hContext);
  836. // No Context
  837. pContext->fContext = FALSE;
  838. }
  839. // Reset this state.
  840. pContext->fUsedSuppliedCreds = FALSE;
  841. // Build Negotiation String
  842. IF_FAILEXIT(hr = SSPIMakeOutboundMessage(pContext, 0, pNegotiate, NULL));
  843. exit:
  844. // Done
  845. return(hr);
  846. }
  847. //--------------------------------------------------------------------------
  848. // SSPIResponseFromChallenge
  849. //--------------------------------------------------------------------------
  850. HRESULT SSPIResponseFromChallenge(LPSSPICONTEXT pContext, LPSSPIBUFFER pChallenge,
  851. LPSSPIBUFFER pResponse)
  852. {
  853. // Locals
  854. HRESULT hr=S_OK;
  855. DWORD nBytesReceived;
  856. DWORD dwFlags=0;
  857. SecBufferDesc Descript;
  858. SecBuffer Buffer[SEC_BUFFER_NUM_EXTENDED_BUFFERS];
  859. // Trace
  860. TraceCall("SSPIResponseFromChallenge");
  861. // Invalid Args
  862. if (NULL == pContext || NULL == pChallenge || NULL == pResponse)
  863. return TraceResult(E_INVALIDARG);
  864. // Not Initialized
  865. if (NULL == g_hInstSSPI || NULL == g_pFunctions)
  866. return TraceResult(E_UNEXPECTED);
  867. // More Unexpected Stuff
  868. if (FALSE == pContext->fContext || FALSE == pContext->fCredential)
  869. return TraceResult(E_UNEXPECTED);
  870. // Decode the Challenge Buffer
  871. IF_FAILEXIT(hr == SSPIDecodeBuffer(pContext->fBase64, pChallenge));
  872. // Fill SecBufferDesc
  873. Descript.ulVersion = 0;
  874. Descript.pBuffers = Buffer;
  875. Descript.cBuffers = 1;
  876. // Setup the challenge input buffer always (0th buffer)
  877. Buffer[SEC_BUFFER_CHALLENGE_INDEX].pvBuffer = pChallenge->szBuffer;
  878. Buffer[SEC_BUFFER_CHALLENGE_INDEX].cbBuffer = pChallenge->cbBuffer - 1;
  879. Buffer[SEC_BUFFER_CHALLENGE_INDEX].BufferType = SECBUFFER_TOKEN;
  880. // If Digest
  881. if (FALSE == pContext->fUsedSuppliedCreds && lstrcmpi(pContext->pszPackage, "digest") == 0)
  882. {
  883. // If we have a user, setup the user buffer (1st buffer)
  884. Buffer[SEC_BUFFER_USERNAME_INDEX].pvBuffer = pContext->pszUserName ? pContext->pszUserName : NULL;
  885. Buffer[SEC_BUFFER_USERNAME_INDEX].cbBuffer = pContext->pszUserName ? lstrlen(pContext->pszUserName) : NULL;
  886. Buffer[SEC_BUFFER_USERNAME_INDEX].BufferType = SECBUFFER_TOKEN;
  887. // If we have a password, setup the password buffer (2nd buffer for
  888. // a total of 3 buffers passed in (challenge + user + pass)
  889. Buffer[SEC_BUFFER_PASSWORD_INDEX].pvBuffer = pContext->pszPassword ? pContext->pszPassword : NULL;
  890. Buffer[SEC_BUFFER_PASSWORD_INDEX].cbBuffer = pContext->pszPassword ? lstrlen(pContext->pszPassword) : NULL;
  891. Buffer[SEC_BUFFER_PASSWORD_INDEX].BufferType = SECBUFFER_TOKEN;
  892. // If either or both user and pass passed in, set num input buffers to 3 // (SEC_BUFFER_NUM_EXTENDED_BUFFERS)
  893. if (pContext->pszUserName || pContext->pszPassword)
  894. Descript.cBuffers = SEC_BUFFER_NUM_EXTENDED_BUFFERS;
  895. // else we're just passing in the one challenge buffer (0th buffer as usual)
  896. else
  897. Descript.cBuffers = SEC_BUFFER_NUM_NORMAL_BUFFERS;
  898. // We are supplying creds
  899. pContext->fUsedSuppliedCreds = TRUE;
  900. // Set dwFlags
  901. dwFlags = ISC_REQ_USE_SUPPLIED_CREDS;
  902. }
  903. // Prepare for OutMsg
  904. IF_FAILEXIT(hr = SSPIMakeOutboundMessage(pContext, dwFlags, pResponse, &Descript));
  905. exit:
  906. // Done
  907. return(hr);
  908. }
  909. //--------------------------------------------------------------------------
  910. // SSPIReleaseContext
  911. //--------------------------------------------------------------------------
  912. HRESULT SSPIReleaseContext(LPSSPICONTEXT pContext)
  913. {
  914. // Was Context Initialized
  915. if (pContext->fContext)
  916. {
  917. // Delete the Security Context
  918. (*(g_pFunctions->DeleteSecurityContext))(&pContext->hContext);
  919. // No context
  920. pContext->fContext = FALSE;
  921. }
  922. // Done
  923. return(S_OK);
  924. }
  925. //--------------------------------------------------------------------------
  926. // SSPIFreeContext
  927. //--------------------------------------------------------------------------
  928. HRESULT SSPIFreeContext(LPSSPICONTEXT pContext)
  929. {
  930. // Locals
  931. SSPICONTEXTSTATE tyState;
  932. SSPICONTEXTSTATE tyRetryState;
  933. DWORD cRetries;
  934. // Trace
  935. TraceCall("SSPIFreeContext");
  936. // Is the context initialized
  937. if (pContext->fContext)
  938. {
  939. // Delete It
  940. (*(g_pFunctions->DeleteSecurityContext))(&pContext->hContext);
  941. // No Context
  942. pContext->fContext = FALSE;
  943. }
  944. // Credential Handle Initialized
  945. if (pContext->fCredential)
  946. {
  947. // Free Credential Handle
  948. (*(g_pFunctions->FreeCredentialHandle))(&pContext->hCredential);
  949. // No Context
  950. pContext->fCredential = FALSE;
  951. }
  952. // Free Package, Server and Callback
  953. SafeMemFree(pContext->pszPackage);
  954. SafeMemFree(pContext->pszUserName);
  955. SafeMemFree(pContext->pszPassword);
  956. SafeMemFree(pContext->pszServer);
  957. SafeRelease(pContext->pCallback);
  958. // Close hMutexUI
  959. if (pContext->hwndLogon)
  960. {
  961. // Nuke the Window
  962. DestroyWindow(pContext->hwndLogon);
  963. // Null
  964. pContext->hwndLogon = NULL;
  965. }
  966. // Save It
  967. tyState = (SSPICONTEXTSTATE)pContext->tyState;
  968. tyRetryState = (SSPICONTEXTSTATE)pContext->tyRetryState;
  969. cRetries = pContext->cRetries;
  970. // Zero It Out
  971. ZeroMemory(pContext, sizeof(SSPICONTEXT));
  972. // Do Prompt
  973. pContext->tyState = tyState;
  974. pContext->tyRetryState = tyRetryState;
  975. pContext->cRetries = cRetries;
  976. // Done
  977. return(S_OK);
  978. }
  979. // --------------------------------------------------------------------------------
  980. // SSPIPromptThreadEntry
  981. // --------------------------------------------------------------------------------
  982. DWORD SSPIPromptThreadEntry(LPDWORD pdwParam)
  983. {
  984. // Locals
  985. HRESULT hr=S_OK;
  986. LPSSPIPROMPTINFO pPrompt=(LPSSPIPROMPTINFO)pdwParam;
  987. // Trace
  988. TraceCall("SSPIPromptThreadEntry");
  989. // Validate
  990. Assert(pPrompt && pPrompt->pContext);
  991. // Fixup pInDescript
  992. if (pPrompt->pInDescript && pPrompt->pInDescript->cBuffers >= 3 && lstrcmpi(pPrompt->pContext->pszPackage, "digest") == 0)
  993. {
  994. // Raid-66013: Make sure the password is empty or digest will crash
  995. pPrompt->pInDescript->pBuffers[SEC_BUFFER_PASSWORD_INDEX].pvBuffer = NULL;
  996. pPrompt->pInDescript->pBuffers[SEC_BUFFER_PASSWORD_INDEX].cbBuffer = 0;
  997. //pPrompt->pInDescript->cBuffers = 2;
  998. }
  999. // Try to get the package to prompt for credentials...
  1000. pPrompt->hrResult = (*(g_pFunctions->InitializeSecurityContext))(
  1001. &pPrompt->pContext->hCredential,
  1002. pPrompt->phCtxCurrent,
  1003. pPrompt->pContext->pszServer,
  1004. pPrompt->dwFlags | ISC_REQ_PROMPT_FOR_CREDS,
  1005. 0,
  1006. SECURITY_NATIVE_DREP,
  1007. pPrompt->pInDescript,
  1008. 0,
  1009. &pPrompt->pContext->hContext,
  1010. pPrompt->pOutDescript,
  1011. &pPrompt->fContextAttrib,
  1012. &pPrompt->tsExpireTime);
  1013. // Trace
  1014. TraceResultSz(pPrompt->hrResult, "SSPIPromptThreadEntry");
  1015. // Done
  1016. return(0);
  1017. }
  1018. //--------------------------------------------------------------------------
  1019. // SSPISetAccountUserName
  1020. //--------------------------------------------------------------------------
  1021. HRESULT SSPISetAccountUserName(LPCSTR pszName, LPSSPICONTEXT pContext)
  1022. {
  1023. // Locals
  1024. HRESULT hr=S_OK;
  1025. DWORD dwServerType;
  1026. IImnAccount *pAccount=NULL;
  1027. ITransportCallbackService *pService=NULL;
  1028. // Trace
  1029. TraceCall("SSPISetAccountUserName");
  1030. // Validate Args
  1031. Assert(pszName);
  1032. Assert(pContext);
  1033. Assert(pContext->pCallback);
  1034. // Get ITransportCallbackService
  1035. IF_FAILEXIT(hr = pContext->pCallback->QueryInterface(IID_ITransportCallbackService, (LPVOID *)&pService));
  1036. // Get the Account
  1037. IF_FAILEXIT(hr = pService->GetAccount(&dwServerType, &pAccount));
  1038. // SRV_POP3
  1039. if (ISFLAGSET(dwServerType, SRV_POP3))
  1040. {
  1041. // Set the UserName
  1042. IF_FAILEXIT(hr = pAccount->SetPropSz(AP_POP3_USERNAME, (LPSTR)pszName));
  1043. }
  1044. // SRV_SMTP
  1045. else if (ISFLAGSET(dwServerType, SRV_SMTP))
  1046. {
  1047. // Set the UserName
  1048. IF_FAILEXIT(hr = pAccount->SetPropSz(AP_SMTP_USERNAME, (LPSTR)pszName));
  1049. }
  1050. // SRV_IMAP
  1051. else if (ISFLAGSET(dwServerType, SRV_IMAP))
  1052. {
  1053. // Set the UserName
  1054. IF_FAILEXIT(hr = pAccount->SetPropSz(AP_IMAP_USERNAME, (LPSTR)pszName));
  1055. }
  1056. // SRV_NNTP
  1057. else if (ISFLAGSET(dwServerType, SRV_NNTP))
  1058. {
  1059. // Set the UserName
  1060. IF_FAILEXIT(hr = pAccount->SetPropSz(AP_NNTP_USERNAME, (LPSTR)pszName));
  1061. }
  1062. // Save Changes
  1063. pAccount->SaveChanges();
  1064. exit:
  1065. // Cleanup
  1066. SafeRelease(pService);
  1067. SafeRelease(pAccount);
  1068. // Done
  1069. return(hr);
  1070. }
  1071. //--------------------------------------------------------------------------
  1072. // SSPIMakeOutboundMessage
  1073. //--------------------------------------------------------------------------
  1074. HRESULT SSPIMakeOutboundMessage(LPSSPICONTEXT pContext, DWORD dwFlags,
  1075. LPSSPIBUFFER pBuffer, PSecBufferDesc pInDescript)
  1076. {
  1077. // Locals
  1078. SECURITY_STATUS hr=S_OK;
  1079. SSPIPROMPTINFO Prompt={0};
  1080. SecBuffer OutBuffer;
  1081. SecBufferDesc OutDescript;
  1082. ULONG fContextAttrib;
  1083. TimeStamp tsExpireTime;
  1084. HANDLE hPromptThread;
  1085. DWORD dwThreadId;
  1086. DWORD dwWait;
  1087. MSG msg;
  1088. PCtxtHandle phCtxCurrent=NULL;
  1089. PAUTHENTICATE_MESSAGE pAuthMsg;
  1090. LPSTR pszName=NULL;
  1091. // Invalid Args
  1092. if (NULL == pContext || NULL == pBuffer)
  1093. return TraceResult(E_INVALIDARG);
  1094. // Bad Context
  1095. if (NULL == pContext->pszPackage)
  1096. return TraceResult(E_INVALIDARG);
  1097. // Bad Context
  1098. if (NULL == pContext->pszServer)
  1099. return TraceResult(E_INVALIDARG);
  1100. // Bad Context
  1101. if (NULL == pContext->pCallback)
  1102. return TraceResult(E_INVALIDARG);
  1103. // Not Initialized
  1104. if (NULL == g_hInstSSPI || NULL == g_pFunctions)
  1105. return TraceResult(E_UNEXPECTED);
  1106. // Bad State
  1107. if (FALSE == pContext->fCredential)
  1108. return TraceResult(E_UNEXPECTED);
  1109. // Validate
  1110. Assert(pInDescript == NULL ? FALSE == pContext->fContext : TRUE);
  1111. // Initialize Out Descriptor
  1112. OutDescript.ulVersion = 0;
  1113. OutDescript.cBuffers = 1;
  1114. OutDescript.pBuffers = &OutBuffer;
  1115. // Initialize Output Buffer
  1116. OutBuffer.cbBuffer = CBMAX_SSPI_BUFFER - 1;
  1117. OutBuffer.BufferType = SECBUFFER_TOKEN;
  1118. OutBuffer.pvBuffer = pBuffer->szBuffer;
  1119. // phCtxCurrent
  1120. if (pInDescript)
  1121. {
  1122. // Set Current Context
  1123. phCtxCurrent = &pContext->hContext;
  1124. }
  1125. // First Retry ?
  1126. if (SSPI_STATE_PROMPT_USE_PACKAGE == pContext->tyState && (0 != lstrcmpi(pContext->pszPackage, "digest") || pInDescript))
  1127. {
  1128. // Force failure to do the prompt
  1129. hr = SEC_E_NO_CREDENTIALS;
  1130. }
  1131. // Otherwise, do the next security context
  1132. else
  1133. {
  1134. // Generate a negotiate/authenticate message to be sent to the server.
  1135. hr = (*(g_pFunctions->InitializeSecurityContext))(&pContext->hCredential, phCtxCurrent, pContext->pszServer, dwFlags, 0, SECURITY_NATIVE_DREP, pInDescript, 0, &pContext->hContext, &OutDescript, &fContextAttrib, &tsExpireTime);
  1136. }
  1137. // Set Retry State...
  1138. pContext->tyRetryState = SSPI_STATE_PROMPT_USE_PACKAGE;
  1139. // Failure
  1140. if (FAILED(hr))
  1141. {
  1142. // Trace
  1143. TraceResult(hr);
  1144. // No credentials ? lets do it again and get some credentials
  1145. if (SEC_E_NO_CREDENTIALS != hr)
  1146. goto exit;
  1147. // If no retries yet...
  1148. if (TRUE == pContext->fService && 0 == lstrcmpi(pContext->pszPackage, "MSN") && 0 == pContext->cRetries)
  1149. {
  1150. // Don't retry again...
  1151. pContext->tyState = SSPI_STATE_USE_SUPPLIED;
  1152. // Do the logon Now...
  1153. hr = SSPILogon(pContext, FALSE, pContext->fBase64, pContext->pszPackage, NULL, pContext->pCallback);
  1154. // Cancel ?
  1155. Assert(FALSE == pContext->fPromptCancel);
  1156. // Success
  1157. if (SUCCEEDED(hr))
  1158. {
  1159. // Try Again
  1160. hr = (*(g_pFunctions->InitializeSecurityContext))(&pContext->hCredential, NULL, pContext->pszServer, 0, 0, SECURITY_NATIVE_DREP, NULL, 0, &pContext->hContext, &OutDescript, &fContextAttrib, &tsExpireTime);
  1161. }
  1162. }
  1163. // Still Failed ?
  1164. if (FAILED(hr))
  1165. {
  1166. // Fill up the prompt info...
  1167. Assert(dwFlags == 0 || dwFlags == ISC_REQ_USE_SUPPLIED_CREDS);
  1168. Prompt.pContext = pContext;
  1169. Prompt.pInDescript = pInDescript;
  1170. Prompt.pOutDescript = &OutDescript;
  1171. Prompt.phCtxCurrent = phCtxCurrent;
  1172. Prompt.dwFlags = dwFlags;
  1173. // Create the Thread
  1174. IF_NULLEXIT(hPromptThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SSPIPromptThreadEntry, &Prompt, 0, &dwThreadId));
  1175. // Wait for the thread to finish
  1176. WaitForSingleObject(hPromptThread, INFINITE);
  1177. // This is what I tried to do so that the spooler window would paint, but it caused all sorts of voodo
  1178. #if 0
  1179. // Wait for the thread to finish
  1180. while (1)
  1181. {
  1182. // Wait
  1183. dwWait = MsgWaitForMultipleObjects(1, &hPromptThread, FALSE, INFINITE, QS_PAINT);
  1184. // Done ?
  1185. if (dwWait != WAIT_OBJECT_0 + 1)
  1186. break;
  1187. // Pump Messages
  1188. while (PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE))
  1189. {
  1190. // Translate the Message
  1191. TranslateMessage(&msg);
  1192. // Dispatch the Message
  1193. DispatchMessage(&msg);
  1194. }
  1195. }
  1196. #endif
  1197. // Close the Thread
  1198. CloseHandle(hPromptThread);
  1199. // Set hr
  1200. hr = Prompt.hrResult;
  1201. // If that failed
  1202. if (FAILED(hr))
  1203. {
  1204. // Decide when its no longer needed to continue...
  1205. if (SEC_E_NO_CREDENTIALS == hr)
  1206. goto exit;
  1207. // Only do this if on negotiate phase otherwise NTLM prompt comes up twice
  1208. if (NULL == pInDescript)
  1209. {
  1210. // Do Prompt
  1211. pContext->tyState = SSPI_STATE_PROMPT_USE_OWN;
  1212. // Do the logon Now...
  1213. hr = SSPILogon(pContext, TRUE, pContext->fBase64, pContext->pszPackage, NULL, pContext->pCallback);
  1214. // Cancel ?
  1215. if (pContext->fPromptCancel)
  1216. {
  1217. hr = TraceResult(E_FAIL);
  1218. goto exit;
  1219. }
  1220. // Success
  1221. if (SUCCEEDED(hr))
  1222. {
  1223. // Try Again
  1224. hr = (*(g_pFunctions->InitializeSecurityContext))(&pContext->hCredential, phCtxCurrent, pContext->pszServer, 0, 0, SECURITY_NATIVE_DREP, pInDescript, 0, &pContext->hContext, &OutDescript, &fContextAttrib, &tsExpireTime);
  1225. }
  1226. }
  1227. }
  1228. }
  1229. }
  1230. // Success
  1231. if (SUCCEEDED(hr))
  1232. {
  1233. // We have a context
  1234. pContext->fContext = TRUE;
  1235. // If MSN or NTLM...
  1236. if (TRUE == pContext->fService && 0 == lstrcmpi(pContext->pszPackage, "MSN"))
  1237. {
  1238. // Look at the buffer...
  1239. pAuthMsg = (PAUTHENTICATE_MESSAGE)pBuffer->szBuffer;
  1240. // Validate Signature
  1241. Assert(0 == StrCmpNI((LPCSTR)pAuthMsg->Signature, NTLMSSP_SIGNATURE, sizeof(NTLMSSP_SIGNATURE)));
  1242. // Right Phase ?
  1243. if (NtLmAuthenticate == pAuthMsg->MessageType)
  1244. {
  1245. // Allocate
  1246. IF_NULLEXIT(pszName = (LPSTR)g_pMalloc->Alloc(pAuthMsg->UserName.Length + sizeof(CHAR)));
  1247. // Copy the name
  1248. CopyMemory(pszName, (LPBYTE)pBuffer->szBuffer + PtrToUlong(pAuthMsg->UserName.Buffer), pAuthMsg->UserName.Length);
  1249. // Stuff a Null....
  1250. pszName[pAuthMsg->UserName.Length] = '\0';
  1251. // If Context UserName is empty, lets store pszName into the account
  1252. if ('\0' == *pContext->pszUserName)
  1253. {
  1254. // Put pszName as the username for this account
  1255. if (SUCCEEDED(SSPISetAccountUserName(pszName, pContext)))
  1256. {
  1257. // Reset the UserName
  1258. SafeMemFree(pContext->pszUserName);
  1259. // Copy the new username
  1260. IF_NULLEXIT(pContext->pszUserName = PszDupA(pszName));
  1261. }
  1262. }
  1263. // Name Change
  1264. if (lstrcmpi(pszName, pContext->pszUserName) != 0)
  1265. {
  1266. // Don't retry again...
  1267. pContext->tyState = SSPI_STATE_USE_SUPPLIED;
  1268. // Set Retry State...
  1269. pContext->tyRetryState = SSPI_STATE_USE_CACHED;
  1270. // Do the logon Now...
  1271. hr = SSPILogon(pContext, FALSE, pContext->fBase64, pContext->pszPackage, NULL, pContext->pCallback);
  1272. // Cancel ?
  1273. Assert(FALSE == pContext->fPromptCancel);
  1274. // Success
  1275. if (SUCCEEDED(hr))
  1276. {
  1277. // Try Again
  1278. hr = (*(g_pFunctions->InitializeSecurityContext))(&pContext->hCredential, NULL, pContext->pszServer, 0, 0, SECURITY_NATIVE_DREP, NULL, 0, &pContext->hContext, &OutDescript, &fContextAttrib, &tsExpireTime);
  1279. }
  1280. // Fail, but continue...
  1281. if (FAILED(hr))
  1282. {
  1283. // We are going to need to prompt...
  1284. pContext->tyState = SSPI_STATE_PROMPT_USE_PACKAGE;
  1285. // Trace
  1286. TraceResult(hr);
  1287. // Always Succeed, but cause authentication to fail...
  1288. hr = S_OK;
  1289. // Reset Length
  1290. OutBuffer.cbBuffer = 0;
  1291. }
  1292. }
  1293. }
  1294. }
  1295. }
  1296. // Otherwise...
  1297. else
  1298. {
  1299. // Trace
  1300. TraceResult(hr);
  1301. // Always Succeed, but cause authentication to fail...
  1302. hr = S_OK;
  1303. // Reset Length
  1304. OutBuffer.cbBuffer = 0;
  1305. }
  1306. // Continue required
  1307. pBuffer->fContinue = (SEC_I_CONTINUE_NEEDED == hr) ? TRUE : FALSE;
  1308. // Set cbBuffer
  1309. pBuffer->cbBuffer = OutBuffer.cbBuffer + 1;
  1310. // Null Terminate
  1311. pBuffer->szBuffer[pBuffer->cbBuffer - 1] = '\0';
  1312. // need to encode the blob before send out
  1313. IF_FAILEXIT(hr == SSPIEncodeBuffer(pContext->fBase64, pBuffer));
  1314. // All Good
  1315. hr = S_OK;
  1316. exit:
  1317. // Cleanup
  1318. SafeMemFree(pszName);
  1319. // Done
  1320. return(hr);
  1321. }
  1322. //-------------------------------------------------------------------------------------------
  1323. // SSPIEncodeBuffer
  1324. //-------------------------------------------------------------------------------------------
  1325. HRESULT SSPIEncodeBuffer(BOOL fBase64, LPSSPIBUFFER pBuffer)
  1326. {
  1327. // Locals
  1328. LPBYTE pbIn=(LPBYTE)pBuffer->szBuffer;
  1329. DWORD cbIn=pBuffer->cbBuffer - 1;
  1330. BYTE rgbOut[CBMAX_SSPI_BUFFER - 1];
  1331. LPBYTE pbOut=rgbOut;
  1332. DWORD i;
  1333. // Trace
  1334. TraceCall("SSPIEncodeBuffer");
  1335. // Validate
  1336. Assert(pBuffer->szBuffer[pBuffer->cbBuffer - 1] == '\0');
  1337. // Set the lookup table to use to encode
  1338. LPCSTR rgchDict = (fBase64 ? six2base64 : six2uu);
  1339. // Loop
  1340. for (i = 0; i < cbIn; i += 3)
  1341. {
  1342. // Encode
  1343. *(pbOut++) = rgchDict[*pbIn >> 2];
  1344. *(pbOut++) = rgchDict[((*pbIn << 4) & 060) | ((pbIn[1] >> 4) & 017)];
  1345. *(pbOut++) = rgchDict[((pbIn[1] << 2) & 074) | ((pbIn[2] >> 6) & 03)];
  1346. *(pbOut++) = rgchDict[pbIn[2] & 077];
  1347. // Increment pbIn
  1348. pbIn += 3;
  1349. }
  1350. // If nbytes was not a multiple of 3, then we have encoded too many characters. Adjust appropriately.
  1351. if (i == cbIn + 1)
  1352. {
  1353. // There were only 2 bytes in that last group
  1354. pbOut[-1] = '=';
  1355. }
  1356. // There was only 1 byte in that last group
  1357. else if (i == cbIn + 2)
  1358. {
  1359. pbOut[-1] = '=';
  1360. pbOut[-2] = '=';
  1361. }
  1362. // Null Terminate
  1363. *pbOut = '\0';
  1364. // Copy Back into pBuffer
  1365. SSPISetBuffer((LPCSTR)rgbOut, SSPI_STRING, 0, pBuffer);
  1366. // Done
  1367. return(S_OK);
  1368. }
  1369. //-------------------------------------------------------------------------------------------
  1370. // SSPIDecodeBuffer
  1371. //-------------------------------------------------------------------------------------------
  1372. HRESULT SSPIDecodeBuffer(BOOL fBase64, LPSSPIBUFFER pBuffer)
  1373. {
  1374. // Locals
  1375. LPSTR pszStart=pBuffer->szBuffer;
  1376. LPBYTE pbIn=(LPBYTE)pBuffer->szBuffer;
  1377. DWORD cbIn=pBuffer->cbBuffer - 1;
  1378. BYTE rgbOut[CBMAX_SSPI_BUFFER - 1];
  1379. LPBYTE pbOut=rgbOut;
  1380. DWORD cbOutLeft = ARRAYSIZE(rgbOut)-1;
  1381. long cbDecode;
  1382. DWORD cbOut=0;
  1383. // Trace
  1384. TraceCall("SSPIDecodeBuffer");
  1385. // Validate
  1386. Assert(pBuffer->szBuffer[pBuffer->cbBuffer - 1] == '\0');
  1387. // Set the lookup table to use to encode
  1388. const int *rgiDict = (fBase64 ? base642six : uu2six);
  1389. // Strip leading whitespace
  1390. while (*pszStart == ' ' || *pszStart == '\t')
  1391. pszStart++;
  1392. // Set pbIn
  1393. pbIn = (LPBYTE)pszStart;
  1394. // Hmmm, I don't know what this does
  1395. while (rgiDict[*(pbIn++)] <= 63)
  1396. {};
  1397. // Actual Number of bytes to encode
  1398. cbDecode = (long) ((LPBYTE)pbIn - (LPBYTE)pszStart) - 1;
  1399. // Computed length of outbound buffer
  1400. cbOut = ((cbDecode + 3) / 4) * 3;
  1401. // Reset pbIn
  1402. pbIn = (LPBYTE)pszStart;
  1403. // Decode
  1404. while ((cbDecode > 0) && (3 <= cbOutLeft))
  1405. {
  1406. // Decode
  1407. *(pbOut++) = (unsigned char) (rgiDict[*pbIn] << 2 | rgiDict[pbIn[1]] >> 4);
  1408. *(pbOut++) = (unsigned char) (rgiDict[pbIn[1]] << 4 | rgiDict[pbIn[2]] >> 2);
  1409. *(pbOut++) = (unsigned char) (rgiDict[pbIn[2]] << 6 | rgiDict[pbIn[3]]);
  1410. cbOutLeft -= 3;
  1411. Assert((cbDecode <= 0) || (3 <= cbOutLeft)); // If this happens, then cbDecode was calculated incorrectly and we will overflow the buffer.
  1412. // Increment pbIn
  1413. pbIn += 4;
  1414. // Decrement cbDecode
  1415. cbDecode -= 4;
  1416. }
  1417. // Special termination case
  1418. if (cbDecode & 03)
  1419. {
  1420. if (rgiDict[pbIn[-2]] > 63)
  1421. cbOut -= 2;
  1422. else
  1423. cbOut -= 1;
  1424. }
  1425. // Set the Outbuffer
  1426. SSPISetBuffer((LPCSTR)rgbOut, SSPI_BLOB, cbOut, pBuffer);
  1427. // Done
  1428. return(S_OK);
  1429. }
  1430. //-------------------------------------------------------------------------------------------
  1431. // SSPIFlushMSNCredentialCache - This code was given to us by kingra/MSN (see csager)
  1432. //-------------------------------------------------------------------------------------------
  1433. HRESULT SSPIFlushMSNCredentialCache(void)
  1434. {
  1435. // Locals
  1436. HRESULT hr=S_OK;
  1437. HKEY hKey=NULL;
  1438. DWORD dwType;
  1439. CHAR szDllName[MAX_PATH];
  1440. CHAR szProviders[1024];
  1441. DWORD cb=ARRAYSIZE(szProviders);
  1442. HINSTANCE hInstDll=NULL;
  1443. PFNCLEANUPCREDENTIALCACHE pfnCleanupCredentialCache;
  1444. // Open the HKLM Reg Entry
  1445. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\SecurityProviders", 0, KEY_READ, &hKey))
  1446. {
  1447. hr = TraceResult(E_FAIL);
  1448. goto exit;
  1449. }
  1450. // Read the Providers
  1451. if (ERROR_SUCCESS != RegQueryValueEx(hKey, "SecurityProviders", NULL, &dwType, (LPBYTE)szProviders, &cb))
  1452. {
  1453. hr = TraceResult(E_FAIL);
  1454. goto exit;
  1455. }
  1456. // Upper Case the Providers
  1457. CharUpperBuff(szProviders, (DWORD)min(cb,ARRAYSIZE(szProviders)));
  1458. // Map to something...
  1459. if (StrStrA(szProviders, "MSAPSSPS.DLL"))
  1460. StrCpyN(szDllName, "MSAPSSPS.DLL", ARRAYSIZE(szDllName));
  1461. else if (StrStrA(szProviders, "MSAPSSPC.DLL"))
  1462. StrCpyN(szDllName, "MSAPSSPC.DLL", ARRAYSIZE(szDllName));
  1463. else
  1464. {
  1465. hr = TraceResult(E_FAIL);
  1466. goto exit;
  1467. }
  1468. // Load the DLL
  1469. hInstDll = LoadLibrary(szDllName);
  1470. // Failed to Load
  1471. if (NULL == hInstDll)
  1472. {
  1473. hr = TraceResult(E_FAIL);
  1474. goto exit;
  1475. }
  1476. // Get the ProcAddress
  1477. pfnCleanupCredentialCache = (PFNCLEANUPCREDENTIALCACHE)GetProcAddress(hInstDll, "CleanupCredentialCache");
  1478. // Failure ?
  1479. if (NULL == pfnCleanupCredentialCache)
  1480. {
  1481. hr = TraceResult(E_FAIL);
  1482. goto exit;
  1483. }
  1484. // Call the function that clears the cache
  1485. if (!pfnCleanupCredentialCache())
  1486. {
  1487. hr = TraceResult(E_FAIL);
  1488. goto exit;
  1489. }
  1490. exit:
  1491. // Cleanup
  1492. if (hKey)
  1493. RegCloseKey(hKey);
  1494. if (hInstDll)
  1495. FreeLibrary(hInstDll);
  1496. // Done
  1497. return(hr);
  1498. }