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.

493 lines
9.3 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. certcach.cxx
  5. Abstract:
  6. Contains class implementation for certificate cache object.
  7. This object will hold various Certificate entries.
  8. Contents:
  9. SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY
  10. SECURITY_CACHE_LIST_ENTRY::~SECURITY_CACHE_LIST_ENTRY
  11. SECURITY_CACHE_LIST_ENTRY::AddRef
  12. SECURITY_CACHE_LIST_ENTRY::Release
  13. SECURITY_CACHE_LIST_ENTRY::Clear
  14. SECURITY_CACHE_LIST::Find
  15. SECURITY_CACHE_LIST::Add
  16. SECURITY_CACHE_LIST::ClearList
  17. TODO: Add Cert validation. What if Cert is given but different?
  18. Author:
  19. Arthur L Bierer (arthurbi) 20-Apr-1996
  20. Revision History:
  21. 20-Apr-1996 arthurbi
  22. Created
  23. --*/
  24. #include <wininetp.h>
  25. //
  26. // private manifests
  27. //
  28. #define MAX_CERT_CACHE_CERTS 16
  29. //
  30. // private types
  31. //
  32. //
  33. // SECURITY_CACHE_LIST_ENTRY member functions
  34. //
  35. SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY(
  36. IN LPSTR lpszHostName
  37. )
  38. /*++
  39. Routine Description:
  40. SECURITY_CACHE_LIST_ENTRY constructor. Create object; don't add it to list
  41. Arguments:
  42. lpszHostName - name of host for which this cache entry created
  43. Return Value:
  44. None.
  45. --*/
  46. {
  47. DEBUG_ENTER((DBG_OBJECTS,
  48. None,
  49. "SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY",
  50. "%q",
  51. lpszHostName
  52. ));
  53. #if INET_DEBUG
  54. _List.Flink = _List.Blink = NULL;
  55. #endif
  56. _cRef = 1;
  57. _fInCache = FALSE;
  58. _ServerName = lpszHostName;
  59. ZeroMemory(&_CertInfo, sizeof(_CertInfo));
  60. _dwSecurityFlags = 0;
  61. _dwStatusFlags = 0;
  62. _pCertContextArray = NULL;
  63. #if INET_DEBUG
  64. m_Signature = 0x454c4353; // 'SCLE'
  65. #endif
  66. DEBUG_LEAVE(0);
  67. }
  68. SECURITY_CACHE_LIST_ENTRY::~SECURITY_CACHE_LIST_ENTRY()
  69. /*++
  70. Routine Description:
  71. SECURITY_CACHE_LIST_ENTRY destructor.
  72. Arguments:
  73. None.
  74. Return Value:
  75. None.
  76. --*/
  77. {
  78. DEBUG_ENTER((DBG_OBJECTS,
  79. None,
  80. "~SECURITY_CACHE_LIST_ENTRY",
  81. "{%#x [%q]}",
  82. this,
  83. _ServerName.StringAddress()
  84. ));
  85. INET_ASSERT((_List.Flink == NULL) && (_List.Blink == NULL));
  86. Clear();
  87. DEBUG_LEAVE(0);
  88. }
  89. LONG
  90. SECURITY_CACHE_LIST_ENTRY::AddRef(
  91. VOID
  92. )
  93. /*++
  94. Routine Description:
  95. Increment reference count of SECURITY_CACHE_LIST_ENTRY
  96. Arguments:
  97. None.
  98. Return Value:
  99. LONG - reference count after increment
  100. --*/
  101. {
  102. DEBUG_ENTER((DBG_OBJECTS,
  103. Int,
  104. "SECURITY_CACHE_LIST_ENTRY::AddRef",
  105. "{%#x [%q, %d]}",
  106. this,
  107. _ServerName.StringAddress(),
  108. _cRef
  109. ));
  110. InterlockedIncrement(&_cRef);
  111. DEBUG_LEAVE(_cRef);
  112. return _cRef;
  113. }
  114. LONG
  115. SECURITY_CACHE_LIST_ENTRY::Release(
  116. VOID
  117. )
  118. /*++
  119. Routine Description:
  120. Decrement reference count and destroy object if (<=) zero
  121. Arguments:
  122. None.
  123. Return Value:
  124. LONG - reference count after decrement
  125. --*/
  126. {
  127. DEBUG_ENTER((DBG_OBJECTS,
  128. Int,
  129. "SECURITY_CACHE_LIST_ENTRY::Release",
  130. "{%q [%d]}",
  131. _ServerName.StringAddress(),
  132. _cRef
  133. ));
  134. LONG cRet;
  135. if (0 >= (cRet = InterlockedDecrement(&_cRef))) {
  136. delete this;
  137. }
  138. DEBUG_LEAVE(cRet);
  139. return cRet;
  140. }
  141. VOID
  142. SECURITY_CACHE_LIST_ENTRY::Clear()
  143. /*++
  144. Routine Description:
  145. Clear out SECURITY_CACHE_LIST_ENTRY
  146. Arguments:
  147. Clear -
  148. Return Value:
  149. None.
  150. --*/
  151. {
  152. if (_CertInfo.pCertificate != NULL)
  153. {
  154. SAFE_WRAP_REVERT_USER_VOID(CertFreeCertificateContext, (_CertInfo.pCertificate));
  155. _CertInfo.pCertificate = NULL;
  156. }
  157. ZeroMemory(&_CertInfo, sizeof(_CertInfo));
  158. _CertInfo.dwSize = sizeof(_CertInfo);
  159. _dwSecurityFlags = 0;
  160. _dwStatusFlags = 0;
  161. _ServerName = NULL;
  162. if( _pCertContextArray )
  163. {
  164. delete _pCertContextArray;
  165. _pCertContextArray = NULL;
  166. }
  167. }
  168. //
  169. // SECURITY_CACHE_LIST member functions
  170. //
  171. VOID
  172. SECURITY_CACHE_LIST::ClearList(
  173. VOID
  174. )
  175. /*++
  176. Routine Description:
  177. description-of-function.
  178. Arguments:
  179. None.
  180. Return Value:
  181. None.
  182. --*/
  183. {
  184. DEBUG_ENTER((DBG_OBJECTS,
  185. None,
  186. "SECURITY_CACHE_LIST::ClearList",
  187. NULL
  188. ));
  189. if (!LockSerializedList(&_List))
  190. {
  191. DEBUG_PRINT(OBJECTS,
  192. ERROR,
  193. ("Failed to obtain lock -- SECURITY_CACHE_LIST potentially leaked\n"
  194. ));
  195. goto quit;
  196. }
  197. while (!IsSerializedListEmpty(&_List)) {
  198. SECURITY_CACHE_LIST_ENTRY * CacheEntry;
  199. //
  200. // remove the PROXY_SERVER_LIST_ENTRY at the head of the serialized
  201. // list
  202. //
  203. LPVOID entry = SlDequeueHead(&_List);
  204. //
  205. // entry should not be NULL - IsSerializedListEmpty() told us we
  206. // could expect something
  207. //
  208. INET_ASSERT(entry != NULL);
  209. //
  210. // get the address of the object (should be the same as entry) and
  211. // delete it
  212. //
  213. CacheEntry = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
  214. DEBUG_PRINT(OBJECTS,
  215. INFO,
  216. ("releasing %q (%d)\n",
  217. CacheEntry->_ServerName.StringAddress(),
  218. CacheEntry->_cRef
  219. ));
  220. CacheEntry->Release();
  221. }
  222. UnlockSerializedList(&_List);
  223. quit:
  224. DEBUG_LEAVE(0);
  225. }
  226. DWORD
  227. SECURITY_CACHE_LIST::Add(
  228. IN SECURITY_CACHE_LIST_ENTRY * entry
  229. )
  230. /*++
  231. Routine Description:
  232. Adds a CertInfo Structure to the list front of the list.
  233. Arguments:
  234. lpszHost - Hostname to add.
  235. Return Value:
  236. DWORD
  237. Success - ERROR_SUCCESS
  238. Failure - ERROR_NOT_ENOUGH_MEMORY
  239. --*/
  240. {
  241. DEBUG_ENTER((DBG_HTTP,
  242. Dword,
  243. "SECURITY_CACHE_LIST::Add",
  244. "%#x [%q, %d]",
  245. entry,
  246. entry ? entry->_ServerName.StringAddress() : "",
  247. entry ? entry->_cRef : 0
  248. ));
  249. DWORD error = ERROR_SUCCESS;
  250. INET_ASSERT(entry != NULL);
  251. if (entry != NULL) {
  252. if (LockSerializedList(&_List))
  253. {
  254. //
  255. // If we've grown too much, nuke the oldest one.
  256. //
  257. if (ElementsOnSerializedList(&_List) >= MAX_CERT_CACHE_CERTS) {
  258. SECURITY_CACHE_LIST_ENTRY *pOld;
  259. LPVOID old_entry = SlDequeueTail(&_List);
  260. INET_ASSERT(old_entry != NULL);
  261. pOld = CONTAINING_RECORD(old_entry, SECURITY_CACHE_LIST_ENTRY, _List);
  262. //
  263. // entry should not be NULL - IsSerializedListEmpty() told us we
  264. // could expect something
  265. //
  266. pOld->_fInCache = FALSE;
  267. //
  268. // Clean Our old object, and reinstatiate with a new name.
  269. //
  270. pOld->Release();
  271. }
  272. if (InsertAtHeadOfSerializedList(&_List, &entry->_List)) {
  273. entry->AddRef();
  274. entry->_fInCache = TRUE;
  275. }
  276. UnlockSerializedList(&_List);
  277. }
  278. else
  279. error = ERROR_NOT_ENOUGH_MEMORY;
  280. }
  281. DEBUG_LEAVE(error);
  282. return error;
  283. }
  284. SECURITY_CACHE_LIST_ENTRY *
  285. SECURITY_CACHE_LIST::Find(
  286. IN LPSTR lpszHost
  287. )
  288. /*++
  289. Routine Description:
  290. Searches the linked list for the Cert, and returns
  291. the found entry, or NULL if not found.
  292. Arguments:
  293. lpszHost - Hostname to search on.
  294. Return Value:
  295. CERT_CACHE_LIST_ENTRY *
  296. Success - Pointer to found entry.
  297. Failure - NULL, not found.
  298. --*/
  299. {
  300. DEBUG_ENTER((DBG_HTTP,
  301. Pointer,
  302. "SECURITY_CACHE_LIST::Find",
  303. "%q",
  304. lpszHost
  305. ));
  306. SECURITY_CACHE_LIST_ENTRY * info = NULL;
  307. //
  308. // BUGBUG need to validate against Server Certifcate on every
  309. // connection, this Find only validates by Hostname.
  310. // What about DNS spoofing? Won't we be hosed?
  311. //
  312. //
  313. // TODO if found, need to push to front of list.
  314. //
  315. if (LockSerializedList(&_List))
  316. {
  317. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  318. entry != (PLIST_ENTRY)SlSelf(&_List);
  319. entry = entry->Flink)
  320. {
  321. info = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
  322. //
  323. // check to see if they match.
  324. //
  325. if (info->_ServerName.Stricmp(lpszHost) == 0) {
  326. info->AddRef();
  327. break; // match.
  328. }
  329. info = NULL;
  330. }
  331. UnlockSerializedList(&_List);
  332. }
  333. DEBUG_LEAVE(info);
  334. return info;
  335. }