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.

490 lines
13 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;
  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))))
  85. {
  86. return SSPPKG_ERROR;
  87. }
  88. if ( !(pData->PkgList[pData->PkgCnt]->pName =
  89. (LPSTR)LocalAlloc(0, lstrlen(pPkgName)+1)))
  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 (InterlockedExchange((LPLONG)&Initializing, TRUE)) {
  218. while (!Initialized) {
  219. SleepEx(0, TRUE);
  220. }
  221. goto quit;
  222. }
  223. //
  224. // Initialize SSP SPM Global Data
  225. //
  226. VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  227. if (!GetVersionEx (&VerInfo)) // If this fails, something has gone wrong
  228. {
  229. goto quit;
  230. }
  231. if (VerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
  232. {
  233. goto quit;
  234. }
  235. if (!(pData = (SspData *) LocalAlloc(0, sizeof(SspData)))) {
  236. goto quit;
  237. }
  238. //
  239. // Keep these information in global SPM
  240. //
  241. ZeroMemory (pData, sizeof(SspData));
  242. //
  243. // Load Security DLL
  244. //
  245. g_hSecLib = LoadLibrary (SSP_SPM_NT_DLL);
  246. if (g_hSecLib == NULL)
  247. {
  248. // This should never happen.
  249. LocalFree(pData);
  250. pData = NULL;
  251. goto Cleanup;
  252. }
  253. addrProcISI = (INIT_SECURITY_INTERFACE) GetProcAddress( g_hSecLib,
  254. SECURITY_ENTRYPOINT);
  255. if (addrProcISI == NULL)
  256. {
  257. LocalFree(pData);
  258. pData = NULL;
  259. goto Cleanup;
  260. }
  261. //
  262. // Get the SSPI function table
  263. //
  264. pFuncTbl = (*addrProcISI)();
  265. //
  266. // Get list of packages supported
  267. //
  268. sstat = (*(pFuncTbl->EnumerateSecurityPackages))(&cntPkg, &pPkgInfo);
  269. if (sstat != SEC_E_OK || pPkgInfo == NULL)
  270. {
  271. //
  272. // ??? Should we give up here ???
  273. // EnumerateSecurityPackage() failed
  274. //
  275. goto Cleanup;
  276. }
  277. if (cntPkg)
  278. {
  279. //
  280. // Create the package list
  281. //
  282. if (!(pData->PkgList = (PSSPAuthPkg *)LocalAlloc(0,
  283. cntPkg*sizeof(PSSPAuthPkg))))
  284. {
  285. goto Cleanup;
  286. }
  287. }
  288. for (ii = 0; ii < cntPkg; ii++)
  289. {
  290. //DebugTrace(SSPSPMID, "Found %s SSPI package\n",
  291. // pPkgInfo[ii].Name);
  292. if (SpmAddSSPIPkg (pData,
  293. pPkgInfo[ii].Name,
  294. pPkgInfo[ii].cbMaxToken
  295. ) == SSPPKG_ERROR)
  296. {
  297. goto Cleanup;
  298. }
  299. }
  300. pData->pFuncTbl = pFuncTbl;
  301. pData->bKeepList = TRUE;
  302. if (pData->PkgCnt == 0)
  303. {
  304. goto Cleanup;
  305. }
  306. g_pSspData = pData;
  307. pData = NULL;
  308. Cleanup:
  309. if( pPkgInfo != NULL )
  310. {
  311. //
  312. // Free buffer returned by the enumerate security package function
  313. //
  314. (*(pFuncTbl->FreeContextBuffer))(pPkgInfo);
  315. }
  316. if( pData != NULL )
  317. {
  318. SpmFreePkgList (pData);
  319. }
  320. if (g_hSecLib)
  321. {
  322. FreeLibrary (g_hSecLib);
  323. g_hSecLib = NULL;
  324. }
  325. quit:
  326. Initialized = TRUE;
  327. return (g_pSspData);
  328. }
  329. INT
  330. GetPkgId(LPTSTR lpszPkgName)
  331. {
  332. int ii;
  333. if ( g_pSspData == NULL )
  334. {
  335. return -1;
  336. }
  337. if (!AuthLock())
  338. {
  339. return -1;
  340. }
  341. for (ii = 0; ii < g_pSspData->PkgCnt; ii++)
  342. {
  343. if (!lstrcmp(g_pSspData->PkgList[ii]->pName, lpszPkgName))
  344. {
  345. AuthUnlock();
  346. return(ii);
  347. }
  348. }
  349. AuthUnlock();
  350. return(-1);
  351. }
  352. DWORD
  353. GetPkgCapabilities(
  354. INT Package
  355. )
  356. {
  357. if (!AuthLock())
  358. {
  359. return 0;
  360. }
  361. DWORD dwCaps;
  362. if ( Package < g_pSspData->PkgCnt )
  363. {
  364. dwCaps = g_pSspData->PkgList[ Package ]->Capabilities ;
  365. }
  366. else
  367. dwCaps = 0 ;
  368. AuthUnlock();
  369. return dwCaps;
  370. }
  371. ULONG
  372. GetPkgMaxToken(
  373. INT Package
  374. )
  375. {
  376. if (!AuthLock())
  377. {
  378. return MAX_AUTH_MSG_SIZE;
  379. }
  380. ULONG dwMaxToken;
  381. if ( Package < g_pSspData->PkgCnt )
  382. {
  383. dwMaxToken = g_pSspData->PkgList[ Package ]->cbMaxToken;
  384. }
  385. else {
  386. // be compatible with old static buffer size
  387. dwMaxToken = MAX_AUTH_MSG_SIZE;
  388. }
  389. AuthUnlock();
  390. return dwMaxToken;
  391. }
  392. //
  393. // Calls to this function are serialized
  394. //
  395. DWORD_PTR SSPI_InitScheme (LPCSTR lpszScheme)
  396. {
  397. int ii;
  398. if (!SSPI_InitGlobals())
  399. return 0;
  400. if (!AuthLock())
  401. {
  402. return 0;
  403. }
  404. // Once initialized, check to see if this scheme is installed
  405. for (ii = 0; ii < g_pSspData->PkgCnt &&
  406. lstrcmp (g_pSspData->PkgList[ii]->pName, lpszScheme); ii++);
  407. if (ii >= g_pSspData->PkgCnt)
  408. {
  409. // This scheme is not installed on this machine
  410. AuthUnlock();
  411. return (0);
  412. }
  413. AuthUnlock();
  414. return ((DWORD_PTR)g_pSspData);
  415. }