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.

531 lines
14 KiB

  1. /*#----------------------------------------------------------------------------
  2. **
  3. ** File: sspspm.c
  4. **
  5. ** Synopsis: Security Protocol Module for SSPI Authentication providers.
  6. **
  7. ** This module contains major funtions of the SEC_SSPI.DLL which
  8. ** allows the Internet Explorer to use SSPI providers for authentication.
  9. ** The function exported to the Internet Explorer is Ssp_Load() which
  10. ** passes the address of the Ssp__DownCall() function to the Explorer.
  11. ** Then the Explorer will call Ssp__DownCall() when it needs service from
  12. ** this SPM DLL. The two major functions called by Ssp__DownCall() to
  13. ** service Explorer's request are Ssp__PreProcessRequest() and
  14. ** Ssp__ProcessResponse(). In brief, Ssp__PreProcessRequest() is
  15. ** called before the Explorer sends out a request which does not have
  16. ** any 'Authorization' header yet. And Ssp__ProcessResponse() is called
  17. ** whenever the Explorer receives an 401 'Unauthorized' response from the
  18. ** server. This SPM DLL supports all SSPI packages which are installed
  19. ** on the machine.
  20. **
  21. ** This SPM DLL is called by the Internet Explorer only for its
  22. ** The Internet Explorer only calls this SPM DLL when it needs
  23. ** authentication data in its request/response. In other words, the
  24. ** Explorer never calls this SPM DLL when an authentication succeeded;
  25. ** it never calls this DLL when it decide to give up on a connection
  26. ** because of server response timeout. Because of this fact, this SPM
  27. ** DLL never has sufficient information on the state of each server
  28. ** connection; it only know its state based on the content of the last
  29. ** request and the content of the current response. For this reason, this
  30. ** SPM DLL does not keep state information for each host it has visited
  31. ** unless the information is essential.
  32. ** The security context handle returned from the first call of
  33. ** InitializeSecurityContext() for NEGOTIATE message generation is
  34. ** always the identical for a SSPI package when the same server host is
  35. ** passed. Since the server host name is always in the request/response
  36. ** header, the only information essential in generating a NEGOTIATE or
  37. ** RESPONSE is already available in the header. So unlike most SSPI
  38. ** application, this DLL will not keep the security context handle which
  39. ** it received from the SSPI function calls. Whenever it needs to call
  40. ** the SSPI function for generating a RESPONSE, it will first call the
  41. ** SSPI function without the CHALLENGE to get a security context handle.
  42. ** Then it calls the SSPI function again with the CHALLENGE to generate
  43. ** a RESPONSE.
  44. **
  45. **
  46. ** Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  47. **
  48. ** Authors: LucyC Created 25 Sept. 1995
  49. **
  50. **---------------------------------------------------------------------------*/
  51. #include <wininetp.h>
  52. #include <ntlmsp.h>
  53. #include "sspspm.h"
  54. //
  55. // Global variable where all the SSPI Pkgs data is collected
  56. //
  57. SspData *g_pSspData;
  58. HINSTANCE g_hSecLib = NULL;
  59. /*-----------------------------------------------------------------------------
  60. **
  61. ** Function: SpmAddSSPIPkg
  62. **
  63. ** Synopsis: This function adds a SSPI package to the SPM's package list.
  64. **
  65. ** Arguments: pData - Points to the private SPM data structure containing
  66. ** the package list and the package info.
  67. ** pPkgName - package name
  68. ** cbMaxToken - max size of security token
  69. **
  70. ** Returns: The index in the package list where this new package is added.
  71. ** If failed to add the new package, SSPPKG_ERROR is returned.
  72. **
  73. ** History: LucyC Created 21 Oct. 1995
  74. **
  75. **---------------------------------------------------------------------------*/
  76. static UCHAR
  77. SpmAddSSPIPkg (
  78. SspData *pData,
  79. LPTSTR pPkgName,
  80. ULONG cbMaxToken
  81. )
  82. {
  83. if ( (pData->PkgList[pData->PkgCnt] =
  84. (SSPAuthPkg *)LocalAlloc(0, sizeof(SSPAuthPkg))) == NULL)
  85. {
  86. return SSPPKG_ERROR;
  87. }
  88. if ( (pData->PkgList[pData->PkgCnt]->pName =
  89. (LPSTR)LocalAlloc(0, lstrlen(pPkgName)+1)) == NULL)
  90. {
  91. LocalFree(pData->PkgList[pData->PkgCnt]);
  92. pData->PkgList[pData->PkgCnt] = NULL;
  93. return SSPPKG_ERROR;
  94. }
  95. lstrcpy (pData->PkgList[pData->PkgCnt]->pName, pPkgName);
  96. pData->PkgList[ pData->PkgCnt ]->Capabilities = 0 ;
  97. pData->PkgList[ pData->PkgCnt ]->cbMaxToken = cbMaxToken;
  98. //
  99. // Determine if this package supports anything of interest to
  100. // us.
  101. //
  102. if ( lstrcmpi( pPkgName, NTLMSP_NAME_A ) == 0 )
  103. {
  104. //
  105. // NTLM supports the standard credential structure
  106. //
  107. pData->PkgList[ pData->PkgCnt ]->Capabilities |= SSPAUTHPKG_SUPPORT_NTLM_CREDS ;
  108. }
  109. else if ( lstrcmpi( pPkgName, "Negotiate" ) == 0 )
  110. {
  111. //
  112. // Negotiate supports that cred structure too
  113. //
  114. pData->PkgList[ pData->PkgCnt ]->Capabilities |= SSPAUTHPKG_SUPPORT_NTLM_CREDS ;
  115. }
  116. else
  117. {
  118. //
  119. // Add more comparisons here, eventually.
  120. //
  121. ;
  122. }
  123. pData->PkgCnt++;
  124. return (pData->PkgCnt - 1);
  125. }
  126. /*-----------------------------------------------------------------------------
  127. **
  128. ** Function: SpmFreePkgList
  129. **
  130. ** Synopsis: This function frees memory allocated for the package list.
  131. **
  132. ** Arguments: pData - Points to the private SPM data structure containing
  133. ** the package list and the package info.
  134. **
  135. ** Returns: void.
  136. **
  137. ** History: LucyC Created 21 Oct. 1995
  138. **
  139. **---------------------------------------------------------------------------*/
  140. static VOID
  141. SpmFreePkgList (
  142. SspData *pData
  143. )
  144. {
  145. int ii;
  146. for (ii = 0; ii < pData->PkgCnt; ii++)
  147. {
  148. LocalFree(pData->PkgList[ii]->pName);
  149. LocalFree(pData->PkgList[ii]);
  150. }
  151. LocalFree(pData->PkgList);
  152. }
  153. /*-----------------------------------------------------------------------------
  154. **
  155. ** Function: Ssp__Unload
  156. **
  157. ** Synopsis: This function is called by the Internet Explorer before
  158. ** the SPM DLL is unloaded from the memory.
  159. **
  160. ** Arguments: fpUI - From Explorer for making all UI_SERVICE call
  161. ** pvOpaqueOS - From Explorer for making all UI_SERVICE call
  162. ** htspm - the SPM structure which contains the global data
  163. ** storage for this SPM DLL.
  164. **
  165. ** Returns: always returns SPM_STATUS_OK, which means successful.
  166. **
  167. ** History: LucyC Created 25 Sept. 1995
  168. **
  169. **---------------------------------------------------------------------------*/
  170. DWORD SSPI_Unload()
  171. {
  172. if (!AuthLock())
  173. {
  174. return SPM_STATUS_INSUFFICIENT_BUFFER;
  175. }
  176. if (g_pSspData != NULL)
  177. {
  178. SpmFreePkgList(g_pSspData);
  179. LocalFree(g_pSspData);
  180. g_pSspData = NULL;
  181. }
  182. if (g_hSecLib)
  183. {
  184. FreeLibrary (g_hSecLib);
  185. g_hSecLib = NULL;
  186. }
  187. AuthUnlock();
  188. return SPM_STATUS_OK;
  189. }
  190. /*-----------------------------------------------------------------------------
  191. **
  192. ** Function: SspSPM_InitData
  193. **
  194. ** Synopsis: This function allocates and initializes global data structure
  195. ** of the SPM DLL.
  196. **
  197. ** Arguments:
  198. **
  199. ** Returns: Pointer to the allocated global data structure.
  200. **
  201. ** History: LucyC Created 25 Sept. 1995
  202. **
  203. **---------------------------------------------------------------------------*/
  204. LPVOID SSPI_InitGlobals(void)
  205. {
  206. SspData *pData = NULL;
  207. OSVERSIONINFO VerInfo;
  208. INIT_SECURITY_INTERFACE addrProcISI = NULL;
  209. SECURITY_STATUS sstat;
  210. ULONG ii, cntPkg;
  211. PSecPkgInfo pPkgInfo = NULL;
  212. PSecurityFunctionTable pFuncTbl = NULL;
  213. if (g_pSspData)
  214. return g_pSspData;
  215. static BOOL Initializing = FALSE;
  216. static BOOL Initialized = FALSE;
  217. if (!AuthLock())
  218. {
  219. goto done;
  220. }
  221. if (Initializing)
  222. {
  223. //if re-entered on same thread, fail.
  224. goto leave;
  225. }
  226. else if (g_pSspData)
  227. {
  228. //else some other thread succeeded, and we can fall out.
  229. goto leave;
  230. }
  231. else if (Initialized)
  232. {
  233. //else if we've failed initialization for non-entrancy reasons, don't reattempt
  234. goto leave;
  235. }
  236. Initializing = TRUE;
  237. //Ensure that the AuthLock is never abandoned.
  238. __try
  239. {
  240. //
  241. // Initialize SSP SPM Global Data
  242. //
  243. VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  244. if (!GetVersionEx (&VerInfo)) // If this fails, something has gone wrong
  245. {
  246. goto quit;
  247. }
  248. if (VerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
  249. {
  250. goto quit;
  251. }
  252. if ((pData = (SspData *) LocalAlloc(0, sizeof(SspData))) == NULL) {
  253. goto quit;
  254. }
  255. //
  256. // Keep these information in global SPM
  257. //
  258. ZeroMemory (pData, sizeof(SspData));
  259. //
  260. // Load Security DLL
  261. //
  262. g_hSecLib = LoadLibrary (SSP_SPM_NT_DLL);
  263. if (g_hSecLib == NULL)
  264. {
  265. // This should never happen.
  266. LocalFree(pData);
  267. pData = NULL;
  268. goto Cleanup;
  269. }
  270. addrProcISI = (INIT_SECURITY_INTERFACE) GetProcAddress( g_hSecLib,
  271. SECURITY_ENTRYPOINT);
  272. if (addrProcISI == NULL)
  273. {
  274. LocalFree(pData);
  275. pData = NULL;
  276. goto Cleanup;
  277. }
  278. //
  279. // Get the SSPI function table
  280. //
  281. pFuncTbl = (*addrProcISI)();
  282. if (pFuncTbl == NULL)
  283. {
  284. LocalFree(pData);
  285. pData = NULL;
  286. goto Cleanup;
  287. }
  288. //
  289. // Get list of packages supported
  290. //
  291. sstat = (*(pFuncTbl->EnumerateSecurityPackages))(&cntPkg, &pPkgInfo);
  292. if (sstat != SEC_E_OK || pPkgInfo == NULL)
  293. {
  294. //
  295. // ??? Should we give up here ???
  296. // EnumerateSecurityPackage() failed
  297. //
  298. goto Cleanup;
  299. }
  300. if (cntPkg)
  301. {
  302. //
  303. // Create the package list
  304. //
  305. if ((pData->PkgList = (PSSPAuthPkg *)LocalAlloc(0,
  306. cntPkg*sizeof(PSSPAuthPkg))) == NULL)
  307. {
  308. goto Cleanup;
  309. }
  310. }
  311. for (ii = 0; ii < cntPkg; ii++)
  312. {
  313. //DebugTrace(SSPSPMID, "Found %s SSPI package\n",
  314. // pPkgInfo[ii].Name);
  315. if (SpmAddSSPIPkg (pData,
  316. pPkgInfo[ii].Name,
  317. pPkgInfo[ii].cbMaxToken
  318. ) == SSPPKG_ERROR)
  319. {
  320. goto Cleanup;
  321. }
  322. }
  323. pData->pFuncTbl = pFuncTbl;
  324. pData->bKeepList = TRUE;
  325. if (pData->PkgCnt == 0)
  326. {
  327. goto Cleanup;
  328. }
  329. g_pSspData = pData;
  330. pData = NULL;
  331. }
  332. __except(EXCEPTION_EXECUTE_HANDLER)
  333. {
  334. goto Cleanup;
  335. }
  336. ENDEXCEPT
  337. Cleanup:
  338. if( pPkgInfo != NULL )
  339. {
  340. //
  341. // Free buffer returned by the enumerate security package function
  342. //
  343. (*(pFuncTbl->FreeContextBuffer))(pPkgInfo);
  344. }
  345. if( pData != NULL )
  346. {
  347. SpmFreePkgList (pData);
  348. }
  349. /*
  350. if (g_hSecLib)
  351. {
  352. FreeLibrary (g_hSecLib);
  353. g_hSecLib = NULL;
  354. }
  355. */
  356. quit:
  357. Initialized = TRUE;
  358. Initializing = FALSE;
  359. //jump here if you grabbed the auth lock but don't want to affect Init*
  360. leave:
  361. AuthUnlock();
  362. //jump here IFF you didn't grab the Authlock
  363. done:
  364. return (g_pSspData);
  365. }
  366. INT
  367. GetPkgId(LPTSTR lpszPkgName)
  368. {
  369. int ii;
  370. if ( g_pSspData == NULL )
  371. {
  372. return -1;
  373. }
  374. if (!AuthLock())
  375. {
  376. return -1;
  377. }
  378. for (ii = 0; ii < g_pSspData->PkgCnt; ii++)
  379. {
  380. if (!lstrcmp(g_pSspData->PkgList[ii]->pName, lpszPkgName))
  381. {
  382. AuthUnlock();
  383. return(ii);
  384. }
  385. }
  386. AuthUnlock();
  387. return(-1);
  388. }
  389. DWORD
  390. GetPkgCapabilities(
  391. INT Package
  392. )
  393. {
  394. if (!AuthLock())
  395. {
  396. return 0;
  397. }
  398. DWORD dwCaps;
  399. if ( Package < g_pSspData->PkgCnt )
  400. {
  401. dwCaps = g_pSspData->PkgList[ Package ]->Capabilities ;
  402. }
  403. else
  404. dwCaps = 0 ;
  405. AuthUnlock();
  406. return dwCaps;
  407. }
  408. ULONG
  409. GetPkgMaxToken(
  410. INT Package
  411. )
  412. {
  413. if (!AuthLock())
  414. {
  415. return MAX_AUTH_MSG_SIZE;
  416. }
  417. ULONG dwMaxToken;
  418. if ( Package < g_pSspData->PkgCnt )
  419. {
  420. dwMaxToken = g_pSspData->PkgList[ Package ]->cbMaxToken;
  421. }
  422. else {
  423. // be compatible with old static buffer size
  424. dwMaxToken = MAX_AUTH_MSG_SIZE;
  425. }
  426. AuthUnlock();
  427. return dwMaxToken;
  428. }
  429. //
  430. // Calls to this function are serialized
  431. //
  432. DWORD_PTR SSPI_InitScheme (LPCSTR lpszScheme)
  433. {
  434. int ii;
  435. if (!SSPI_InitGlobals())
  436. return 0;
  437. if (!AuthLock())
  438. {
  439. return 0;
  440. }
  441. // Once initialized, check to see if this scheme is installed
  442. for (ii = 0; ii < g_pSspData->PkgCnt &&
  443. lstrcmp (g_pSspData->PkgList[ii]->pName, lpszScheme); ii++);
  444. if (ii >= g_pSspData->PkgCnt)
  445. {
  446. // This scheme is not installed on this machine
  447. AuthUnlock();
  448. return (0);
  449. }
  450. AuthUnlock();
  451. return ((DWORD_PTR)g_pSspData);
  452. }