Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

584 lines
13 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. NTSTATUS
  4. IPSecGetSPI(
  5. PIPSEC_GET_SPI pIpsecGetSPI
  6. )
  7. /*++
  8. Routine Description:
  9. This routine returns the SPI.
  10. Arguments:
  11. pIpsecGetSPI - Pointer to the ipsec get spi structure.
  12. Return Value:
  13. NTSTATUS - The status code from this routine.
  14. --*/
  15. {
  16. NTSTATUS ntStatus = STATUS_SUCCESS;
  17. PIPSEC_ACQUIRE_CONTEXT pIpsecAcquireCtx = NULL;
  18. pIpsecAcquireCtx = (PIPSEC_ACQUIRE_CONTEXT) pIpsecGetSPI->Context;
  19. //
  20. // If context was passed in, then there's a larval SA already setup.
  21. // This is the case for the initiator.
  22. //
  23. if (pIpsecAcquireCtx) {
  24. ntStatus = IPSecInitiatorGetSPI(
  25. pIpsecGetSPI
  26. );
  27. }
  28. else {
  29. ntStatus = IPSecResponderGetSPI(
  30. pIpsecGetSPI
  31. );
  32. }
  33. return (ntStatus);
  34. }
  35. NTSTATUS
  36. IPSecInitiatorGetSPI(
  37. PIPSEC_GET_SPI pIpsecGetSPI
  38. )
  39. {
  40. NTSTATUS ntStatus = STATUS_SUCCESS;
  41. PIPSEC_ACQUIRE_CONTEXT pIpsecAcquireCtx = NULL;
  42. KIRQL kIrql;
  43. pIpsecAcquireCtx = (PIPSEC_ACQUIRE_CONTEXT) pIpsecGetSPI->Context;
  44. //
  45. // Sanity check the incoming context to see if it is actually
  46. // an SA block.
  47. //
  48. ACQUIRE_LOCK(&g_ipsec.LarvalListLock, &kIrql);
  49. if (!NT_SUCCESS(IPSecValidateHandle(pIpsecAcquireCtx, STATE_SA_LARVAL))) {
  50. ntStatus = STATUS_INVALID_PARAMETER;
  51. BAIL_ON_LOCK_NTSTATUS_ERROR(ntStatus);
  52. }
  53. pIpsecGetSPI->SPI = pIpsecAcquireCtx->pSA->sa_SPI;
  54. pIpsecAcquireCtx->pSA->sa_Flags |= FLAGS_SA_INITIATOR;
  55. ntStatus = STATUS_SUCCESS;
  56. lock:
  57. RELEASE_LOCK(&g_ipsec.LarvalListLock, kIrql);
  58. return (ntStatus);
  59. }
  60. NTSTATUS
  61. IPSecResponderGetSPI(
  62. PIPSEC_GET_SPI pIpsecGetSPI
  63. )
  64. {
  65. NTSTATUS ntStatus = STATUS_SUCCESS;
  66. KIRQL kIrql;
  67. PSA_TABLE_ENTRY pInboundSA = NULL;
  68. ULARGE_INTEGER uliSrcDstAddr = {0};
  69. PSA_TABLE_ENTRY pSA = NULL;
  70. PIPSEC_ACQUIRE_CONTEXT pIpsecAcquireCtx = NULL;
  71. AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
  72. if (pIpsecGetSPI->SPI) {
  73. if (!(pIpsecGetSPI->InstantiatedFilter.TunnelFilter)) {
  74. pInboundSA = IPSecLookupSABySPI(
  75. pIpsecGetSPI->SPI,
  76. pIpsecGetSPI->InstantiatedFilter.DestAddr
  77. );
  78. }
  79. else {
  80. pInboundSA = IPSecLookupSABySPI(
  81. pIpsecGetSPI->SPI,
  82. pIpsecGetSPI->InstantiatedFilter.TunnelAddr
  83. );
  84. }
  85. if (pInboundSA) {
  86. ntStatus = STATUS_UNSUCCESSFUL;
  87. BAIL_ON_LOCK_NTSTATUS_ERROR(ntStatus);
  88. }
  89. }
  90. ntStatus = IPSecResponderCreateLarvalSA(
  91. pIpsecGetSPI,
  92. uliSrcDstAddr,
  93. &pSA
  94. );
  95. BAIL_ON_LOCK_NTSTATUS_ERROR(ntStatus);
  96. //
  97. // Get the acquire Context and associate it with the larval SA.
  98. //
  99. pIpsecAcquireCtx = IPSecGetAcquireContext();
  100. if (!pIpsecAcquireCtx) {
  101. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  102. BAIL_ON_LOCK_NTSTATUS_ERROR(ntStatus);
  103. }
  104. pIpsecAcquireCtx->AcquireId = (ULONG)(ULONG_PTR) pSA;
  105. IPSecGenerateRandom(
  106. (PUCHAR)&pIpsecAcquireCtx->AcquireId,
  107. sizeof(ULONG)
  108. );
  109. pIpsecAcquireCtx->pSA = pSA;
  110. pSA->sa_AcquireId = pIpsecAcquireCtx->AcquireId;
  111. pIpsecGetSPI->Context = pIpsecAcquireCtx;
  112. pSA->sa_AcquireCtx = pIpsecAcquireCtx;
  113. pIpsecGetSPI->SPI = pSA->sa_SPI;
  114. ntStatus = STATUS_SUCCESS;
  115. lock:
  116. ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
  117. return (ntStatus);
  118. }
  119. NTSTATUS
  120. IPSecResponderCreateLarvalSA(
  121. PIPSEC_GET_SPI pIpsecGetSPI,
  122. ULARGE_INTEGER uliAddr,
  123. PSA_TABLE_ENTRY * ppSA
  124. )
  125. {
  126. NTSTATUS ntStatus = STATUS_SUCCESS;
  127. PSA_TABLE_ENTRY pSA = NULL;
  128. KIRQL kIrql;
  129. ntStatus = IPSecCreateSA(&pSA);
  130. BAIL_ON_NTSTATUS_ERROR(ntStatus);
  131. pSA->sa_Filter = NULL;
  132. pSA->sa_State = STATE_SA_LARVAL;
  133. IPSEC_BUILD_SRC_DEST_ADDR(
  134. pSA->sa_uliSrcDstAddr,
  135. pIpsecGetSPI->InstantiatedFilter.SrcAddr,
  136. pIpsecGetSPI->InstantiatedFilter.DestAddr
  137. );
  138. IPSEC_BUILD_SRC_DEST_MASK(
  139. pSA->sa_uliSrcDstMask,
  140. pIpsecGetSPI->InstantiatedFilter.SrcMask,
  141. pIpsecGetSPI->InstantiatedFilter.DestMask
  142. );
  143. IPSEC_BUILD_PROTO_PORT_LI(
  144. pSA->sa_uliProtoSrcDstPort,
  145. pIpsecGetSPI->InstantiatedFilter.Protocol,
  146. pIpsecGetSPI->InstantiatedFilter.SrcPort,
  147. pIpsecGetSPI->InstantiatedFilter.DestPort
  148. );
  149. ntStatus = IPSecResponderInsertInboundSA(
  150. pSA,
  151. pIpsecGetSPI,
  152. pIpsecGetSPI->InstantiatedFilter.TunnelFilter
  153. );
  154. BAIL_ON_NTSTATUS_ERROR(ntStatus);
  155. ACQUIRE_LOCK(&g_ipsec.LarvalListLock, &kIrql);
  156. InsertTailList(&g_ipsec.LarvalSAList, &pSA->sa_LarvalLinkage);
  157. IPSEC_INC_STATISTIC(dwNumPendingKeyOps);
  158. RELEASE_LOCK(&g_ipsec.LarvalListLock, kIrql);
  159. ACQUIRE_LOCK(&pSA->sa_Lock, &kIrql);
  160. IPSecStartSATimer(
  161. pSA,
  162. IPSecSAExpired,
  163. pSA->sa_ExpiryTime
  164. );
  165. RELEASE_LOCK(&pSA->sa_Lock, kIrql);
  166. *ppSA = pSA;
  167. return (ntStatus);
  168. error:
  169. if (pSA) {
  170. IPSecFreeSA(pSA);
  171. }
  172. *ppSA = NULL;
  173. return (ntStatus);
  174. }
  175. NTSTATUS
  176. IPSecInitiatorCreateLarvalSA(
  177. PFILTER pFilter,
  178. ULARGE_INTEGER uliAddr,
  179. PSA_TABLE_ENTRY * ppSA,
  180. UCHAR DestType
  181. )
  182. {
  183. NTSTATUS ntStatus = STATUS_SUCCESS;
  184. PSA_TABLE_ENTRY pSA = NULL;
  185. ULARGE_INTEGER uliSrcDstAddr = {0};
  186. ULARGE_INTEGER uliSrcDstMask = {0};
  187. ULARGE_INTEGER uliProtoSrcDstPort = {0};
  188. KIRQL kIrql;
  189. ntStatus = IPSecCreateSA(&pSA);
  190. BAIL_ON_NTSTATUS_ERROR(ntStatus);
  191. pSA->sa_Filter = pFilter;
  192. pSA->sa_State = STATE_SA_LARVAL;
  193. uliSrcDstAddr = uliAddr;
  194. uliSrcDstMask = pFilter->uliSrcDstMask;
  195. uliProtoSrcDstPort = pFilter->uliProtoSrcDstPort;
  196. IPSEC_BUILD_SRC_DEST_ADDR(
  197. pSA->sa_uliSrcDstAddr,
  198. DEST_ADDR,
  199. SRC_ADDR
  200. );
  201. IPSEC_BUILD_SRC_DEST_MASK(
  202. pSA->sa_uliSrcDstMask,
  203. DEST_MASK,
  204. SRC_MASK
  205. );
  206. IPSEC_BUILD_PROTO_PORT_LI(
  207. pSA->sa_uliProtoSrcDstPort,
  208. PROTO,
  209. DEST_PORT,
  210. SRC_PORT
  211. );
  212. pSA->sa_DestType=DestType;
  213. ntStatus = IPSecInitiatorInsertInboundSA(
  214. pSA,
  215. pFilter->TunnelFilter
  216. );
  217. BAIL_ON_NTSTATUS_ERROR(ntStatus);
  218. ACQUIRE_LOCK(&g_ipsec.LarvalListLock, &kIrql);
  219. InsertTailList(&g_ipsec.LarvalSAList, &pSA->sa_LarvalLinkage);
  220. IPSEC_INC_STATISTIC(dwNumPendingKeyOps);
  221. RELEASE_LOCK(&g_ipsec.LarvalListLock, kIrql);
  222. ACQUIRE_LOCK(&pSA->sa_Lock, &kIrql);
  223. IPSecStartSATimer(
  224. pSA,
  225. IPSecSAExpired,
  226. pSA->sa_ExpiryTime
  227. );
  228. RELEASE_LOCK(&pSA->sa_Lock, kIrql);
  229. *ppSA = pSA;
  230. return (ntStatus);
  231. error:
  232. if (pSA) {
  233. IPSecFreeSA(pSA);
  234. }
  235. *ppSA = NULL;
  236. return (ntStatus);
  237. }
  238. NTSTATUS
  239. IPSecFindSA(
  240. BOOLEAN bTunnelFilter,
  241. ULARGE_INTEGER uliSrcDstAddr,
  242. ULARGE_INTEGER uliProtoSrcDstPort,
  243. PFILTER * ppFilter,
  244. PSA_TABLE_ENTRY * ppSA
  245. )
  246. {
  247. NTSTATUS ntStatus = STATUS_SUCCESS;
  248. if (bTunnelFilter) {
  249. ntStatus = IPSecLookupTunnelSA(
  250. uliSrcDstAddr,
  251. uliProtoSrcDstPort,
  252. ppFilter,
  253. ppSA,
  254. FALSE
  255. );
  256. }
  257. else {
  258. #if GPC
  259. if (IS_GPC_ACTIVE()) {
  260. ntStatus = IPSecLookupGpcMaskedSA(
  261. uliSrcDstAddr,
  262. uliProtoSrcDstPort,
  263. ppFilter,
  264. ppSA,
  265. FALSE
  266. );
  267. }
  268. else {
  269. ntStatus = IPSecLookupMaskedSA(
  270. uliSrcDstAddr,
  271. uliProtoSrcDstPort,
  272. ppFilter,
  273. ppSA,
  274. FALSE
  275. );
  276. }
  277. #else
  278. ntStatus = IPSecLookupMaskedSA(
  279. uliSrcDstAddr,
  280. uliProtoSrcDstPort,
  281. ppFilter,
  282. ppSA,
  283. FALSE
  284. );
  285. #endif
  286. }
  287. return (ntStatus);
  288. }
  289. NTSTATUS
  290. IPSecResponderInsertInboundSA(
  291. PSA_TABLE_ENTRY pSA,
  292. PIPSEC_GET_SPI pIpsecGetSPI,
  293. BOOLEAN bTunnelFilter
  294. )
  295. {
  296. NTSTATUS ntStatus = STATUS_SUCCESS;
  297. PFILTER pFilter = NULL;
  298. PSA_TABLE_ENTRY pInboundSA = NULL;
  299. PLIST_ENTRY pSAChain = NULL;
  300. KIRQL kIrql;
  301. tSPI tSpi = 0;
  302. PSA_HASH pHash = NULL;
  303. ntStatus = IPSecFindSA(
  304. bTunnelFilter,
  305. pSA->sa_uliSrcDstAddr,
  306. pSA->sa_uliProtoSrcDstPort,
  307. &pFilter,
  308. &pInboundSA
  309. );
  310. if (!NT_SUCCESS(ntStatus)) {
  311. IPSecBufferEvent(
  312. pSA->SA_SRC_ADDR,
  313. EVENT_IPSEC_NEG_FAILURE,
  314. 1,
  315. FALSE
  316. );
  317. return (ntStatus);
  318. }
  319. ASSERT(pFilter);
  320. if (pIpsecGetSPI->InstantiatedFilter.Protocol != pFilter->PROTO ||
  321. pIpsecGetSPI->InstantiatedFilter.SrcPort != FI_SRC_PORT(pFilter) ||
  322. pIpsecGetSPI->InstantiatedFilter.DestPort != FI_DEST_PORT(pFilter)) {
  323. ntStatus = STATUS_OBJECT_TYPE_MISMATCH;
  324. return (ntStatus);
  325. }
  326. pSAChain = IPSecResolveSAChain(pFilter, pSA->SA_SRC_ADDR);
  327. InsertHeadList(pSAChain, &pSA->sa_FilterLinkage);
  328. pSA->sa_Flags |= FLAGS_SA_ON_FILTER_LIST;
  329. if (pFilter->Flags & FILTER_FLAGS_PASS_THRU) {
  330. pSA->sa_Flags |= FLAGS_SA_PASSTHRU_FILTER;
  331. }
  332. if (pFilter->TunnelFilter) {
  333. pSA->sa_Flags |= FLAGS_SA_TUNNEL;
  334. pSA->sa_TunnelAddr = pFilter->TunnelAddr;
  335. }
  336. //
  337. // Flush this filter from the cache table so that the SA instead of the
  338. // filter is matched on the next lookup.
  339. //
  340. if (IS_EXEMPT_FILTER(pFilter)) {
  341. IPSecInvalidateFilterCacheEntry(pFilter);
  342. }
  343. AcquireWriteLock(&g_ipsec.SPIListLock, &kIrql);
  344. tSpi = pIpsecGetSPI->SPI;
  345. ntStatus = IPSecAllocateSPI(&tSpi, pSA);
  346. if (!NT_SUCCESS(ntStatus)) {
  347. ReleaseWriteLock(&g_ipsec.SPIListLock, kIrql);
  348. return (ntStatus);
  349. }
  350. pSA->sa_SPI = tSpi;
  351. IPSEC_HASH_SPI(
  352. (pSA->sa_TunnelAddr) ? pSA->sa_TunnelAddr : pSA->SA_DEST_ADDR,
  353. tSpi,
  354. pHash
  355. );
  356. InsertHeadList(&pHash->SAList, &pSA->sa_SPILinkage);
  357. pSA->sa_Flags |= FLAGS_SA_ON_SPI_HASH;
  358. ReleaseWriteLock(&g_ipsec.SPIListLock, kIrql);
  359. return (STATUS_SUCCESS);
  360. }
  361. NTSTATUS
  362. IPSecInitiatorInsertInboundSA(
  363. PSA_TABLE_ENTRY pSA,
  364. BOOLEAN bTunnelFilter
  365. )
  366. {
  367. NTSTATUS ntStatus = STATUS_SUCCESS;
  368. PFILTER pFilter = NULL;
  369. PSA_TABLE_ENTRY pInboundSA = NULL;
  370. PLIST_ENTRY pSAChain = NULL;
  371. KIRQL kIrql;
  372. tSPI tSpi = 0;
  373. PSA_HASH pHash = NULL;
  374. ntStatus = IPSecFindSA(
  375. bTunnelFilter,
  376. pSA->sa_uliSrcDstAddr,
  377. pSA->sa_uliProtoSrcDstPort,
  378. &pFilter,
  379. &pInboundSA
  380. );
  381. if (!NT_SUCCESS(ntStatus)) {
  382. IPSecBufferEvent(
  383. pSA->SA_SRC_ADDR,
  384. EVENT_IPSEC_NEG_FAILURE,
  385. 1,
  386. FALSE
  387. );
  388. return (ntStatus);
  389. }
  390. if (ntStatus == STATUS_SUCCESS) {
  391. if (pInboundSA->sa_State == STATE_SA_LARVAL) {
  392. ntStatus = STATUS_DUPLICATE_OBJECTID;
  393. return (ntStatus);
  394. }
  395. }
  396. ASSERT(pFilter);
  397. pSAChain = IPSecResolveSAChain(pFilter, pSA->SA_SRC_ADDR);
  398. InsertHeadList(pSAChain, &pSA->sa_FilterLinkage);
  399. pSA->sa_Flags |= FLAGS_SA_ON_FILTER_LIST;
  400. if (pFilter->Flags & FILTER_FLAGS_PASS_THRU) {
  401. pSA->sa_Flags |= FLAGS_SA_PASSTHRU_FILTER;
  402. }
  403. if (pFilter->TunnelFilter) {
  404. pSA->sa_Flags |= FLAGS_SA_TUNNEL;
  405. pSA->sa_TunnelAddr = pFilter->TunnelAddr;
  406. }
  407. //
  408. // Flush this filter from the cache table so that the SA instead of the
  409. // filter is matched on the next lookup.
  410. //
  411. if (IS_EXEMPT_FILTER(pFilter)) {
  412. IPSecInvalidateFilterCacheEntry(pFilter);
  413. }
  414. AcquireWriteLock(&g_ipsec.SPIListLock, &kIrql);
  415. tSpi = 0;
  416. ntStatus = IPSecAllocateSPI(&tSpi, pSA);
  417. if (!NT_SUCCESS(ntStatus)) {
  418. ReleaseWriteLock(&g_ipsec.SPIListLock, kIrql);
  419. return (ntStatus);
  420. }
  421. pSA->sa_SPI = tSpi;
  422. IPSEC_HASH_SPI(
  423. (pSA->sa_TunnelAddr) ? pSA->sa_TunnelAddr : pSA->SA_DEST_ADDR,
  424. tSpi,
  425. pHash
  426. );
  427. InsertHeadList(&pHash->SAList, &pSA->sa_SPILinkage);
  428. pSA->sa_Flags |= FLAGS_SA_ON_SPI_HASH;
  429. ReleaseWriteLock(&g_ipsec.SPIListLock, kIrql);
  430. return (STATUS_SUCCESS);
  431. }