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.

1658 lines
37 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. tnspecific.c
  5. Abstract:
  6. This module contains all of the code to drive the
  7. specific tunnel filter list management of IPSecSPD
  8. Service.
  9. Author:
  10. abhisheV 29-October-1999
  11. Environment
  12. User Level: Win32
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. DWORD
  17. ApplyTnTransform(
  18. PINITNFILTER pFilter,
  19. MATCHING_ADDR * pMatchingAddresses,
  20. DWORD dwAddrCnt,
  21. PINITNSFILTER * ppSpecificFilters
  22. )
  23. /*++
  24. Routine Description:
  25. This function expands a generic tunnel filter into its
  26. corresponding specific filters.
  27. Arguments:
  28. pFilter - Generic filter to expand.
  29. pMatchingAddresses - List of local ip addresses whose interface
  30. type matches that of the filter.
  31. dwAddrCnt - Number of local ip addresses in the list.
  32. ppSpecificFilters - List of specific filters expanded for the
  33. given generic filter.
  34. Return Value:
  35. ERROR_SUCCESS - Success.
  36. Win32 Error - Failure.
  37. --*/
  38. {
  39. DWORD dwError = 0;
  40. PINITNSFILTER pSpecificFilters = NULL;
  41. PINITNSFILTER pOutboundSpecificFilters = NULL;
  42. PINITNSFILTER pInboundSpecificFilters = NULL;
  43. PADDR pSrcAddrList = NULL;
  44. DWORD dwSrcAddrCnt = 0;
  45. PADDR pDesAddrList = NULL;
  46. DWORD dwDesAddrCnt = 0;
  47. PADDR pOutDesTunAddrList = NULL;
  48. DWORD dwOutDesTunAddrCnt = 0;
  49. PADDR pInDesTunAddrList = NULL;
  50. DWORD dwInDesTunAddrCnt = 0;
  51. //
  52. // Replace wild card information to generate the new source
  53. // address list.
  54. //
  55. dwError = FormAddressList(
  56. pFilter->SrcAddr,
  57. pMatchingAddresses,
  58. dwAddrCnt,
  59. &pSrcAddrList,
  60. &dwSrcAddrCnt
  61. );
  62. BAIL_ON_WIN32_ERROR(dwError);
  63. //
  64. // Replace wild card information to generate the new destination
  65. // address list.
  66. //
  67. dwError = FormAddressList(
  68. pFilter->DesAddr,
  69. pMatchingAddresses,
  70. dwAddrCnt,
  71. &pDesAddrList,
  72. &dwDesAddrCnt
  73. );
  74. BAIL_ON_WIN32_ERROR(dwError);
  75. //
  76. // Form the outbound and inbound destination tunnel address lists.
  77. //
  78. dwError = FormTnOutboundInboundAddresses(
  79. pFilter,
  80. pMatchingAddresses,
  81. dwAddrCnt,
  82. &pOutDesTunAddrList,
  83. &dwOutDesTunAddrCnt,
  84. &pInDesTunAddrList,
  85. &dwInDesTunAddrCnt
  86. );
  87. BAIL_ON_WIN32_ERROR(dwError);
  88. //
  89. // Form outbound specific filters.
  90. //
  91. dwError = FormSpecificTnFilters(
  92. pFilter,
  93. pSrcAddrList,
  94. dwSrcAddrCnt,
  95. pDesAddrList,
  96. dwDesAddrCnt,
  97. pOutDesTunAddrList,
  98. dwOutDesTunAddrCnt,
  99. FILTER_DIRECTION_OUTBOUND,
  100. &pOutboundSpecificFilters
  101. );
  102. BAIL_ON_WIN32_ERROR(dwError);
  103. //
  104. // Form inbound specific filters.
  105. //
  106. dwError = FormSpecificTnFilters(
  107. pFilter,
  108. pSrcAddrList,
  109. dwSrcAddrCnt,
  110. pDesAddrList,
  111. dwDesAddrCnt,
  112. pInDesTunAddrList,
  113. dwInDesTunAddrCnt,
  114. FILTER_DIRECTION_INBOUND,
  115. &pInboundSpecificFilters
  116. );
  117. BAIL_ON_WIN32_ERROR(dwError);
  118. pSpecificFilters = pOutboundSpecificFilters;
  119. AddToSpecificTnList(
  120. &pSpecificFilters,
  121. pInboundSpecificFilters
  122. );
  123. *ppSpecificFilters = pSpecificFilters;
  124. cleanup:
  125. if (pSrcAddrList) {
  126. FreeSPDMemory(pSrcAddrList);
  127. }
  128. if (pDesAddrList) {
  129. FreeSPDMemory(pDesAddrList);
  130. }
  131. if (pOutDesTunAddrList) {
  132. FreeSPDMemory(pOutDesTunAddrList);
  133. }
  134. if (pInDesTunAddrList) {
  135. FreeSPDMemory(pInDesTunAddrList);
  136. }
  137. return (dwError);
  138. error:
  139. if (pOutboundSpecificFilters) {
  140. FreeIniTnSFilterList(pOutboundSpecificFilters);
  141. }
  142. if (pInboundSpecificFilters) {
  143. FreeIniTnSFilterList(pInboundSpecificFilters);
  144. }
  145. *ppSpecificFilters = NULL;
  146. goto cleanup;
  147. }
  148. DWORD
  149. FormTnOutboundInboundAddresses(
  150. PINITNFILTER pFilter,
  151. MATCHING_ADDR * pMatchingAddresses,
  152. DWORD dwAddrCnt,
  153. PADDR * ppOutDesTunAddrList,
  154. PDWORD pdwOutDesTunAddrCnt,
  155. PADDR * ppInDesTunAddrList,
  156. PDWORD pdwInDesTunAddrCnt
  157. )
  158. /*++
  159. Routine Description:
  160. This function forms the outbound and inbound
  161. destination tunnel address sets for a generic filter.
  162. Arguments:
  163. pFilter - Generic filter under consideration.
  164. pMatchingAddresses - List of local ip addresses whose interface
  165. type matches that of the filter.
  166. dwAddrCnt - Number of local ip addresses in the list.
  167. ppOutDesTunAddrList - List of outbound destination tunnel addresses.
  168. pdwOutDesTunAddrCnt - Number of addresses in the outbound
  169. destination tunnel address list.
  170. ppInDesTunAddrList - List of inbound destination tunnel addresses.
  171. pdwInDesTunAddrCnt - Number of addresses in the inbound
  172. destination tunnel address list.
  173. Return Value:
  174. ERROR_SUCCESS - Success.
  175. Win32 Error - Failure.
  176. --*/
  177. {
  178. DWORD dwError = 0;
  179. PADDR pDesTunAddrList = NULL;
  180. DWORD dwDesTunAddrCnt = 0;
  181. PADDR pOutDesTunAddrList = NULL;
  182. DWORD dwOutDesTunAddrCnt = 0;
  183. PADDR pInDesTunAddrList = NULL;
  184. DWORD dwInDesTunAddrCnt = 0;
  185. //
  186. // Replace wild card information to generate the new destination
  187. // tunnel address list.
  188. //
  189. dwError = FormAddressList(
  190. pFilter->DesTunnelAddr,
  191. pMatchingAddresses,
  192. dwAddrCnt,
  193. &pDesTunAddrList,
  194. &dwDesTunAddrCnt
  195. );
  196. BAIL_ON_WIN32_ERROR(dwError);
  197. //
  198. // Separate the destination tunnel address list into outbound
  199. // and inbound destination tunnel address sets based on the local
  200. // machine's ip addresses.
  201. //
  202. dwError = SeparateAddrList(
  203. pFilter->DesTunnelAddr.AddrType,
  204. pDesTunAddrList,
  205. dwDesTunAddrCnt,
  206. pMatchingAddresses,
  207. dwAddrCnt,
  208. &pInDesTunAddrList,
  209. &dwInDesTunAddrCnt,
  210. &pOutDesTunAddrList,
  211. &dwOutDesTunAddrCnt
  212. );
  213. BAIL_ON_WIN32_ERROR(dwError);
  214. *ppOutDesTunAddrList = pOutDesTunAddrList;
  215. *pdwOutDesTunAddrCnt = dwOutDesTunAddrCnt;
  216. *ppInDesTunAddrList = pInDesTunAddrList;
  217. *pdwInDesTunAddrCnt = dwInDesTunAddrCnt;
  218. cleanup:
  219. if (pDesTunAddrList) {
  220. FreeSPDMemory(pDesTunAddrList);
  221. }
  222. return (dwError);
  223. error:
  224. if (pOutDesTunAddrList) {
  225. FreeSPDMemory(pOutDesTunAddrList);
  226. }
  227. if (pInDesTunAddrList) {
  228. FreeSPDMemory(pInDesTunAddrList);
  229. }
  230. *ppOutDesTunAddrList = NULL;
  231. *pdwOutDesTunAddrCnt = 0;
  232. *ppInDesTunAddrList = NULL;
  233. *pdwInDesTunAddrCnt = 0;
  234. goto cleanup;
  235. }
  236. DWORD
  237. FormSpecificTnFilters(
  238. PINITNFILTER pFilter,
  239. PADDR pSrcAddrList,
  240. DWORD dwSrcAddrCnt,
  241. PADDR pDesAddrList,
  242. DWORD dwDesAddrCnt,
  243. PADDR pDesTunAddrList,
  244. DWORD dwDesTunAddrCnt,
  245. DWORD dwDirection,
  246. PINITNSFILTER * ppSpecificFilters
  247. )
  248. /*++
  249. Routine Description:
  250. This function forms the specific tunnel filters
  251. for the given generic filter and the source and
  252. destination address sets.
  253. Arguments:
  254. pFilter - Generic filter for which specific filters
  255. are to be created.
  256. pSrcAddrList - List of source addresses.
  257. dwSrcAddrCnt - Number of addresses in the source
  258. address list.
  259. pDesAddrList - List of destination addresses.
  260. dwDesAddrCnt - Number of addresses in the destination
  261. address list.
  262. pDesTunAddrList - List of destination tunnel addresses.
  263. dwDesTunAddrCnt - Number of addresses in the destination
  264. tunnel address list.
  265. dwDirection - direction of the resulting specific filters.
  266. ppSpecificFilters - Specific filters created for the given
  267. generic filter and the given addresses.
  268. Return Value:
  269. ERROR_SUCCESS - Success.
  270. Win32 Error - Failure.
  271. --*/
  272. {
  273. DWORD dwError = 0;
  274. PINITNSFILTER pSpecificFilters = NULL;
  275. DWORD i = 0, j = 0, k = 0;
  276. PINITNSFILTER pSpecificFilter = NULL;
  277. for (k = 0; k < dwDesTunAddrCnt; k++) {
  278. for (i = 0; i < dwSrcAddrCnt; i++) {
  279. for (j = 0; j < dwDesAddrCnt; j++) {
  280. dwError = CreateSpecificTnFilter(
  281. pFilter,
  282. pSrcAddrList[i],
  283. pDesAddrList[j],
  284. pDesTunAddrList[k],
  285. &pSpecificFilter
  286. );
  287. BAIL_ON_WIN32_ERROR(dwError);
  288. //
  289. // Set the direction of the filter.
  290. //
  291. pSpecificFilter->dwDirection = dwDirection;
  292. AssignTnFilterWeight(pSpecificFilter);
  293. AddToSpecificTnList(
  294. &pSpecificFilters,
  295. pSpecificFilter
  296. );
  297. }
  298. }
  299. }
  300. *ppSpecificFilters = pSpecificFilters;
  301. return (dwError);
  302. error:
  303. if (pSpecificFilters) {
  304. FreeIniTnSFilterList(pSpecificFilters);
  305. }
  306. *ppSpecificFilters = NULL;
  307. return (dwError);
  308. }
  309. DWORD
  310. CreateSpecificTnFilter(
  311. PINITNFILTER pGenericFilter,
  312. ADDR SrcAddr,
  313. ADDR DesAddr,
  314. ADDR DesTunnelAddr,
  315. PINITNSFILTER * ppSpecificFilter
  316. )
  317. {
  318. DWORD dwError = 0;
  319. PINITNSFILTER pSpecificFilter = NULL;
  320. dwError = AllocateSPDMemory(
  321. sizeof(INITNSFILTER),
  322. &pSpecificFilter
  323. );
  324. BAIL_ON_WIN32_ERROR(dwError);
  325. pSpecificFilter->cRef = 0;
  326. CopyGuid(pGenericFilter->gFilterID, &(pSpecificFilter->gParentID));
  327. dwError = AllocateSPDString(
  328. pGenericFilter->pszFilterName,
  329. &(pSpecificFilter->pszFilterName)
  330. );
  331. BAIL_ON_WIN32_ERROR(dwError);
  332. pSpecificFilter->InterfaceType = pGenericFilter->InterfaceType;
  333. pSpecificFilter->dwFlags = pGenericFilter->dwFlags;
  334. CopyAddresses(SrcAddr, &(pSpecificFilter->SrcAddr));
  335. CopyAddresses(DesAddr, &(pSpecificFilter->DesAddr));
  336. CopyAddresses(
  337. pGenericFilter->SrcTunnelAddr,
  338. &(pSpecificFilter->SrcTunnelAddr)
  339. );
  340. CopyAddresses(DesTunnelAddr, &(pSpecificFilter->DesTunnelAddr));
  341. CopyPorts(pGenericFilter->SrcPort, &(pSpecificFilter->SrcPort));
  342. CopyPorts(pGenericFilter->DesPort, &(pSpecificFilter->DesPort));
  343. CopyProtocols(pGenericFilter->Protocol, &(pSpecificFilter->Protocol));
  344. pSpecificFilter->InboundFilterFlag = pGenericFilter->InboundFilterFlag;
  345. pSpecificFilter->OutboundFilterFlag = pGenericFilter->OutboundFilterFlag;
  346. //
  347. // Direction must be set in the calling routine.
  348. //
  349. pSpecificFilter->dwDirection = 0;
  350. //
  351. // Weight must be set in the calling routine.
  352. //
  353. pSpecificFilter->dwWeight = 0;
  354. CopyGuid(pGenericFilter->gPolicyID, &(pSpecificFilter->gPolicyID));
  355. pSpecificFilter->pIniQMPolicy = NULL;
  356. pSpecificFilter->pNext = NULL;
  357. *ppSpecificFilter = pSpecificFilter;
  358. return (dwError);
  359. error:
  360. if (pSpecificFilter) {
  361. FreeIniTnSFilter(pSpecificFilter);
  362. }
  363. *ppSpecificFilter = NULL;
  364. return (dwError);
  365. }
  366. VOID
  367. AssignTnFilterWeight(
  368. PINITNSFILTER pSpecificFilter
  369. )
  370. /*++
  371. Routine Description:
  372. Computes and assigns the weight to a specific tunnel filter.
  373. The tunnel filter weight consists of the following:
  374. 31 16 12 8 0
  375. +-----------+-----------+-----------+--------+
  376. |AddrMaskWgt| TunnelWgt |ProtocolWgt|PortWgts|
  377. +-----------+-----------+-----------+--------+
  378. Arguments:
  379. pSpecificFilter - Specific tunnel filter to which the weight
  380. is to be assigned.
  381. Return Value:
  382. None.
  383. --*/
  384. {
  385. DWORD dwWeight = 0;
  386. ULONG SrcMask = 0;
  387. ULONG DesMask = 0;
  388. DWORD dwMaskWeight = 0;
  389. DWORD i = 0;
  390. //
  391. // Weight Rule:
  392. // A field with a more specific value gets a higher weight than
  393. // the same field with a lesser specific value.
  394. //
  395. //
  396. // If the protocol is specific then assign the specific protocol
  397. // weight else the weight is zero.
  398. // All the specific filters that have a specific protocol and
  399. // differ only in the protocol field will have the same weight.
  400. //
  401. if (pSpecificFilter->Protocol.dwProtocol != 0) {
  402. dwWeight |= WEIGHT_SPECIFIC_PROTOCOL;
  403. }
  404. //
  405. // If the source port is specific then assign the specific source
  406. // port weight else the weight is zero.
  407. // All the specific filters that have a specific source port and
  408. // differ only in the source port field will have the same weight.
  409. //
  410. if (pSpecificFilter->SrcPort.wPort != 0) {
  411. dwWeight |= WEIGHT_SPECIFIC_SOURCE_PORT;
  412. }
  413. //
  414. // If the destination port is specific then assign the specific
  415. // destination port weight else the weight is zero.
  416. // All the specific filters that have a specific destination port
  417. // and differ only in the destination port field will have the
  418. // same weight.
  419. //
  420. if (pSpecificFilter->DesPort.wPort != 0) {
  421. dwWeight |= WEIGHT_SPECIFIC_DESTINATION_PORT;
  422. }
  423. dwWeight |= WEIGHT_TUNNEL_FILTER;
  424. if (pSpecificFilter->DesTunnelAddr.uIpAddr != SUBNET_ADDRESS_ANY) {
  425. dwWeight |= WEIGHT_SPECIFIC_TUNNEL_FILTER;
  426. }
  427. //
  428. // IP addresses get the weight values based on their mask values.
  429. // In the address case, the weight is computed as a sum of the
  430. // bit positions starting from the position that contains the
  431. // first least significant non-zero bit to the most significant
  432. // bit position of the mask.
  433. // All unique ip addresses have a mask of 0xFFFFFFFF and thus get
  434. // the same weight, which is 1 + 2 + .... + 32.
  435. // A subnet address has a mask with atleast the least significant
  436. // bit zero and thus gets weight in the range (2 + .. + 32) to 0.
  437. //
  438. DesMask = ntohl(pSpecificFilter->DesAddr.uSubNetMask);
  439. for (i = 0; i < sizeof(ULONG) * 8; i++) {
  440. //
  441. // If the bit position contains a non-zero bit, add the bit
  442. // position to the sum.
  443. //
  444. if ((DesMask & 0x1) == 0x1) {
  445. dwMaskWeight += (i+1);
  446. }
  447. //
  448. // Move to the next bit position.
  449. //
  450. DesMask = DesMask >> 1;
  451. }
  452. SrcMask = ntohl(pSpecificFilter->SrcAddr.uSubNetMask);
  453. for (i = 0; i < sizeof(ULONG) * 8; i++) {
  454. //
  455. // If the bit position contains a non-zero bit, add the bit
  456. // position to the sum.
  457. //
  458. if ((SrcMask & 0x1) == 0x1) {
  459. dwMaskWeight += (i+1);
  460. }
  461. //
  462. // Move to the next bit position.
  463. //
  464. SrcMask = SrcMask >> 1;
  465. }
  466. //
  467. // Move the mask weight to the set of bits in the overall weight
  468. // that it occupies.
  469. //
  470. dwMaskWeight = dwMaskWeight << 16;
  471. dwWeight += dwMaskWeight;
  472. pSpecificFilter->dwWeight = dwWeight;
  473. }
  474. VOID
  475. AddToSpecificTnList(
  476. PINITNSFILTER * ppSpecificTnFilterList,
  477. PINITNSFILTER pSpecificTnFilters
  478. )
  479. {
  480. PINITNSFILTER pListOne = NULL;
  481. PINITNSFILTER pListTwo = NULL;
  482. PINITNSFILTER pListMerge = NULL;
  483. PINITNSFILTER pLast = NULL;
  484. if (!(*ppSpecificTnFilterList) && !pSpecificTnFilters) {
  485. return;
  486. }
  487. if (!(*ppSpecificTnFilterList)) {
  488. *ppSpecificTnFilterList = pSpecificTnFilters;
  489. return;
  490. }
  491. if (!pSpecificTnFilters) {
  492. return;
  493. }
  494. pListOne = *ppSpecificTnFilterList;
  495. pListTwo = pSpecificTnFilters;
  496. while (pListOne && pListTwo) {
  497. if ((pListOne->dwWeight) > (pListTwo->dwWeight)) {
  498. if (!pListMerge) {
  499. pListMerge = pListOne;
  500. pLast = pListOne;
  501. pListOne = pListOne->pNext;
  502. }
  503. else {
  504. pLast->pNext = pListOne;
  505. pListOne = pListOne->pNext;
  506. pLast = pLast->pNext;
  507. }
  508. }
  509. else {
  510. if (!pListMerge) {
  511. pListMerge = pListTwo;
  512. pLast = pListTwo;
  513. pListTwo = pListTwo->pNext;
  514. }
  515. else {
  516. pLast->pNext = pListTwo;
  517. pListTwo = pListTwo->pNext;
  518. pLast = pLast->pNext;
  519. }
  520. }
  521. }
  522. if (pListOne) {
  523. pLast->pNext = pListOne;
  524. }
  525. else {
  526. pLast->pNext = pListTwo;
  527. }
  528. *ppSpecificTnFilterList = pListMerge;
  529. return;
  530. }
  531. VOID
  532. FreeIniTnSFilterList(
  533. PINITNSFILTER pIniTnSFilterList
  534. )
  535. {
  536. PINITNSFILTER pFilter = NULL;
  537. PINITNSFILTER pTempFilter = NULL;
  538. pFilter = pIniTnSFilterList;
  539. while (pFilter) {
  540. pTempFilter = pFilter;
  541. pFilter = pFilter->pNext;
  542. FreeIniTnSFilter(pTempFilter);
  543. }
  544. }
  545. VOID
  546. FreeIniTnSFilter(
  547. PINITNSFILTER pIniTnSFilter
  548. )
  549. {
  550. if (pIniTnSFilter) {
  551. if (pIniTnSFilter->pszFilterName) {
  552. FreeSPDString(pIniTnSFilter->pszFilterName);
  553. }
  554. //
  555. // Must not ever free pIniTnSFilter->pIniQMPolicy.
  556. //
  557. FreeSPDMemory(pIniTnSFilter);
  558. }
  559. }
  560. VOID
  561. LinkTnSpecificFilters(
  562. PINIQMPOLICY pIniQMPolicy,
  563. PINITNSFILTER pIniTnSFilters
  564. )
  565. {
  566. PINITNSFILTER pTemp = NULL;
  567. pTemp = pIniTnSFilters;
  568. while (pTemp) {
  569. pTemp->pIniQMPolicy = pIniQMPolicy;
  570. pTemp = pTemp->pNext;
  571. }
  572. return;
  573. }
  574. VOID
  575. RemoveIniTnSFilter(
  576. PINITNSFILTER pIniTnSFilter
  577. )
  578. {
  579. PINITNSFILTER * ppTemp = NULL;
  580. ppTemp = &gpIniTnSFilter;
  581. while (*ppTemp) {
  582. if (*ppTemp == pIniTnSFilter) {
  583. break;
  584. }
  585. ppTemp = &((*ppTemp)->pNext);
  586. }
  587. if (*ppTemp) {
  588. *ppTemp = pIniTnSFilter->pNext;
  589. }
  590. return;
  591. }
  592. DWORD
  593. EnumSpecificTnFilters(
  594. PINITNSFILTER pIniTnSFilterList,
  595. DWORD dwResumeHandle,
  596. DWORD dwPreferredNumEntries,
  597. PTUNNEL_FILTER * ppTnFilters,
  598. PDWORD pdwNumTnFilters
  599. )
  600. /*++
  601. Routine Description:
  602. This function creates enumerated specific filters.
  603. Arguments:
  604. pIniTnSFilterList - List of specific filters to enumerate.
  605. dwResumeHandle - Location in the specific filter list from which
  606. to resume enumeration.
  607. dwPreferredNumEntries - Preferred number of enumeration entries.
  608. ppTnFilters - Enumerated filters returned to the caller.
  609. pdwNumTnFilters - Number of filters actually enumerated.
  610. Return Value:
  611. ERROR_SUCCESS - Success.
  612. Win32 Error - Failure.
  613. --*/
  614. {
  615. DWORD dwError = 0;
  616. DWORD dwNumToEnum = 0;
  617. PINITNSFILTER pIniTnSFilter = NULL;
  618. DWORD i = 0;
  619. PINITNSFILTER pTemp = NULL;
  620. DWORD dwNumTnFilters = 0;
  621. PTUNNEL_FILTER pTnFilters = 0;
  622. PTUNNEL_FILTER pTnFilter = 0;
  623. if (!dwPreferredNumEntries ||
  624. (dwPreferredNumEntries > MAX_TUNNELFILTER_ENUM_COUNT)) {
  625. dwNumToEnum = MAX_TUNNELFILTER_ENUM_COUNT;
  626. }
  627. else {
  628. dwNumToEnum = dwPreferredNumEntries;
  629. }
  630. pIniTnSFilter = pIniTnSFilterList;
  631. for (i = 0; (i < dwResumeHandle) && (pIniTnSFilter != NULL); i++) {
  632. pIniTnSFilter = pIniTnSFilter->pNext;
  633. }
  634. if (!pIniTnSFilter) {
  635. dwError = ERROR_NO_DATA;
  636. BAIL_ON_WIN32_ERROR(dwError);
  637. }
  638. pTemp = pIniTnSFilter;
  639. while (pTemp && (dwNumTnFilters < dwNumToEnum)) {
  640. dwNumTnFilters++;
  641. pTemp = pTemp->pNext;
  642. }
  643. dwError = SPDApiBufferAllocate(
  644. sizeof(TUNNEL_FILTER)*dwNumTnFilters,
  645. &pTnFilters
  646. );
  647. BAIL_ON_WIN32_ERROR(dwError);
  648. pTemp = pIniTnSFilter;
  649. pTnFilter = pTnFilters;
  650. for (i = 0; i < dwNumTnFilters; i++) {
  651. dwError = CopyTnSFilter(
  652. pTemp,
  653. pTnFilter
  654. );
  655. BAIL_ON_WIN32_ERROR(dwError);
  656. pTemp = pTemp->pNext;
  657. pTnFilter++;
  658. }
  659. *ppTnFilters = pTnFilters;
  660. *pdwNumTnFilters = dwNumTnFilters;
  661. return (dwError);
  662. error:
  663. if (pTnFilters) {
  664. FreeTnFilters(
  665. i,
  666. pTnFilters
  667. );
  668. }
  669. *ppTnFilters = NULL;
  670. *pdwNumTnFilters = 0;
  671. return (dwError);
  672. }
  673. DWORD
  674. CopyTnSFilter(
  675. PINITNSFILTER pIniTnSFilter,
  676. PTUNNEL_FILTER pTnFilter
  677. )
  678. /*++
  679. Routine Description:
  680. This function copies an internal filter into an external filter
  681. container.
  682. Arguments:
  683. pIniTnSFilter - Internal filter to copy.
  684. pTnFilter - External filter container in which to copy.
  685. Return Value:
  686. ERROR_SUCCESS - Success.
  687. Win32 Error - Failure.
  688. --*/
  689. {
  690. DWORD dwError = 0;
  691. CopyGuid(pIniTnSFilter->gParentID, &(pTnFilter->gFilterID));
  692. dwError = CopyName(
  693. pIniTnSFilter->pszFilterName,
  694. &(pTnFilter->pszFilterName)
  695. );
  696. BAIL_ON_WIN32_ERROR(dwError);
  697. pTnFilter->InterfaceType = pIniTnSFilter->InterfaceType;
  698. pTnFilter->bCreateMirror = FALSE;
  699. pTnFilter->dwFlags = pIniTnSFilter->dwFlags;
  700. CopyAddresses(pIniTnSFilter->SrcAddr, &(pTnFilter->SrcAddr));
  701. CopyAddresses(pIniTnSFilter->DesAddr, &(pTnFilter->DesAddr));
  702. CopyAddresses(pIniTnSFilter->SrcTunnelAddr, &(pTnFilter->SrcTunnelAddr));
  703. CopyAddresses(pIniTnSFilter->DesTunnelAddr, &(pTnFilter->DesTunnelAddr));
  704. CopyProtocols(pIniTnSFilter->Protocol, &(pTnFilter->Protocol));
  705. CopyPorts(pIniTnSFilter->SrcPort, &(pTnFilter->SrcPort));
  706. CopyPorts(pIniTnSFilter->DesPort, &(pTnFilter->DesPort));
  707. pTnFilter->InboundFilterFlag = pIniTnSFilter->InboundFilterFlag;
  708. pTnFilter->OutboundFilterFlag = pIniTnSFilter->OutboundFilterFlag;
  709. pTnFilter->dwDirection = pIniTnSFilter->dwDirection;
  710. pTnFilter->dwWeight = pIniTnSFilter->dwWeight;
  711. CopyGuid(pIniTnSFilter->gPolicyID, &(pTnFilter->gPolicyID));
  712. error:
  713. return (dwError);
  714. }
  715. DWORD
  716. EnumSelectSpecificTnFilters(
  717. PINITNFILTER pIniTnFilter,
  718. DWORD dwResumeHandle,
  719. DWORD dwPreferredNumEntries,
  720. PTUNNEL_FILTER * ppTnFilters,
  721. PDWORD pdwNumTnFilters
  722. )
  723. /*++
  724. Routine Description:
  725. This function creates enumerated specific filters for
  726. the given generic filter.
  727. Arguments:
  728. pIniTnFilter - Generic filter for which specific filters
  729. are to be enumerated.
  730. dwResumeHandle - Location in the specific filter list for the
  731. given generic filter from which to resume
  732. enumeration.
  733. dwPreferredNumEntries - Preferred number of enumeration entries.
  734. ppTnFilters - Enumerated filters returned to the caller.
  735. pdwNumTnFilters - Number of filters actually enumerated.
  736. Return Value:
  737. ERROR_SUCCESS - Success.
  738. Win32 Error - Failure.
  739. --*/
  740. {
  741. DWORD dwError = 0;
  742. DWORD dwNumToEnum = 0;
  743. DWORD dwNumTnSFilters = 0;
  744. PINITNSFILTER * ppIniTnSFilters = NULL;
  745. DWORD i = 0;
  746. DWORD dwNumTnFilters = 0;
  747. PTUNNEL_FILTER pTnFilters = 0;
  748. PTUNNEL_FILTER pTnFilter = 0;
  749. if (!dwPreferredNumEntries ||
  750. (dwPreferredNumEntries > MAX_TUNNELFILTER_ENUM_COUNT)) {
  751. dwNumToEnum = MAX_TUNNELFILTER_ENUM_COUNT;
  752. }
  753. else {
  754. dwNumToEnum = dwPreferredNumEntries;
  755. }
  756. dwNumTnSFilters = pIniTnFilter->dwNumTnSFilters;
  757. ppIniTnSFilters = pIniTnFilter->ppIniTnSFilters;
  758. if (!dwNumTnSFilters || (dwNumTnSFilters <= dwResumeHandle)) {
  759. dwError = ERROR_NO_DATA;
  760. BAIL_ON_WIN32_ERROR(dwError);
  761. }
  762. dwNumTnFilters = min((dwNumTnSFilters-dwResumeHandle),
  763. dwNumToEnum);
  764. dwError = SPDApiBufferAllocate(
  765. sizeof(TUNNEL_FILTER)*dwNumTnFilters,
  766. &pTnFilters
  767. );
  768. BAIL_ON_WIN32_ERROR(dwError);
  769. pTnFilter = pTnFilters;
  770. for (i = 0; i < dwNumTnFilters; i++) {
  771. dwError = CopyTnSFilter(
  772. *(ppIniTnSFilters + (dwResumeHandle + i)),
  773. pTnFilter
  774. );
  775. BAIL_ON_WIN32_ERROR(dwError);
  776. pTnFilter++;
  777. }
  778. *ppTnFilters = pTnFilters;
  779. *pdwNumTnFilters = dwNumTnFilters;
  780. return (dwError);
  781. error:
  782. if (pTnFilters) {
  783. FreeTnFilters(
  784. i,
  785. pTnFilters
  786. );
  787. }
  788. *ppTnFilters = NULL;
  789. *pdwNumTnFilters = 0;
  790. return (dwError);
  791. }
  792. DWORD
  793. MatchTunnelFilter(
  794. LPWSTR pServerName,
  795. PTUNNEL_FILTER pTnFilter,
  796. DWORD dwFlags,
  797. PTUNNEL_FILTER * ppMatchedTnFilters,
  798. PIPSEC_QM_POLICY * ppMatchedQMPolicies,
  799. DWORD dwPreferredNumEntries,
  800. LPDWORD pdwNumMatches,
  801. LPDWORD pdwResumeHandle
  802. )
  803. /*++
  804. Routine Description:
  805. This function finds the matching tunnel filters for the
  806. given tunnel filter template. The matched filters can not
  807. be more specific than the given filter template.
  808. Arguments:
  809. pServerName - Server on which a filter template is to be matched.
  810. pTnFilter - Filter template to match.
  811. dwFlags - Flags.
  812. ppMatchedTnFilters - Matched tunnel filters returned to the
  813. caller.
  814. ppMatchedQMPolicies - Quick mode policies corresponding to the
  815. matched tunnel filters returned to the
  816. caller.
  817. dwPreferredNumEntries - Preferred number of matched entries.
  818. pdwNumMatches - Number of filters actually matched.
  819. pdwResumeHandle - Handle to the location in the matched filter
  820. list from which to resume enumeration.
  821. Return Value:
  822. ERROR_SUCCESS - Success.
  823. Win32 Error - Failure.
  824. --*/
  825. {
  826. DWORD dwError = 0;
  827. DWORD dwResumeHandle = 0;
  828. DWORD dwNumToMatch = 0;
  829. PINITNSFILTER pIniTnSFilter = NULL;
  830. DWORD i = 0;
  831. BOOL bMatches = FALSE;
  832. PINITNSFILTER pTemp = NULL;
  833. DWORD dwNumMatches = 0;
  834. PINITNSFILTER pLastMatchedFilter = NULL;
  835. PTUNNEL_FILTER pMatchedTnFilters = NULL;
  836. PIPSEC_QM_POLICY pMatchedQMPolicies = NULL;
  837. DWORD dwNumFilters = 0;
  838. DWORD dwNumPolicies = 0;
  839. PTUNNEL_FILTER pMatchedTnFilter = NULL;
  840. PIPSEC_QM_POLICY pMatchedQMPolicy = NULL;
  841. dwError = ValidateTnFilterTemplate(
  842. pTnFilter
  843. );
  844. BAIL_ON_WIN32_ERROR(dwError);
  845. dwResumeHandle = *pdwResumeHandle;
  846. if (!dwPreferredNumEntries) {
  847. dwNumToMatch = 1;
  848. }
  849. else if (dwPreferredNumEntries > MAX_TUNNELFILTER_ENUM_COUNT) {
  850. dwNumToMatch = MAX_TUNNELFILTER_ENUM_COUNT;
  851. }
  852. else {
  853. dwNumToMatch = dwPreferredNumEntries;
  854. }
  855. ENTER_SPD_SECTION();
  856. dwError = ValidateTnSecurity(
  857. SPD_OBJECT_SERVER,
  858. SERVER_ACCESS_ADMINISTER,
  859. NULL,
  860. NULL
  861. );
  862. BAIL_ON_LOCK_ERROR(dwError);
  863. pIniTnSFilter = gpIniTnSFilter;
  864. while ((i < dwResumeHandle) && (pIniTnSFilter != NULL)) {
  865. bMatches = MatchIniTnSFilter(
  866. pIniTnSFilter,
  867. pTnFilter
  868. );
  869. if (bMatches) {
  870. i++;
  871. }
  872. pIniTnSFilter = pIniTnSFilter->pNext;
  873. }
  874. if (!pIniTnSFilter) {
  875. if (!(dwFlags & RETURN_DEFAULTS_ON_NO_MATCH)) {
  876. dwError = ERROR_NO_DATA;
  877. BAIL_ON_LOCK_ERROR(dwError);
  878. }
  879. else {
  880. dwError = CopyTnMatchDefaults(
  881. &pMatchedTnFilters,
  882. &pMatchedQMPolicies,
  883. &dwNumMatches
  884. );
  885. BAIL_ON_LOCK_ERROR(dwError);
  886. BAIL_ON_LOCK_SUCCESS(dwError);
  887. }
  888. }
  889. pTemp = pIniTnSFilter;
  890. while (pTemp && (dwNumMatches < dwNumToMatch)) {
  891. bMatches = MatchIniTnSFilter(
  892. pTemp,
  893. pTnFilter
  894. );
  895. if (bMatches) {
  896. pLastMatchedFilter = pTemp;
  897. dwNumMatches++;
  898. }
  899. pTemp = pTemp->pNext;
  900. }
  901. if (!dwNumMatches) {
  902. if (!(dwFlags & RETURN_DEFAULTS_ON_NO_MATCH)) {
  903. dwError = ERROR_NO_DATA;
  904. BAIL_ON_LOCK_ERROR(dwError);
  905. }
  906. else {
  907. dwError = CopyTnMatchDefaults(
  908. &pMatchedTnFilters,
  909. &pMatchedQMPolicies,
  910. &dwNumMatches
  911. );
  912. BAIL_ON_LOCK_ERROR(dwError);
  913. BAIL_ON_LOCK_SUCCESS(dwError);
  914. }
  915. }
  916. dwError = SPDApiBufferAllocate(
  917. sizeof(TUNNEL_FILTER)*dwNumMatches,
  918. &pMatchedTnFilters
  919. );
  920. BAIL_ON_LOCK_ERROR(dwError);
  921. dwError = SPDApiBufferAllocate(
  922. sizeof(IPSEC_QM_POLICY)*dwNumMatches,
  923. &pMatchedQMPolicies
  924. );
  925. BAIL_ON_LOCK_ERROR(dwError);
  926. if (dwNumMatches == 1) {
  927. dwError = CopyTnSFilter(
  928. pLastMatchedFilter,
  929. pMatchedTnFilters
  930. );
  931. BAIL_ON_LOCK_ERROR(dwError);
  932. dwNumFilters++;
  933. if (pLastMatchedFilter->pIniQMPolicy) {
  934. dwError = CopyQMPolicy(
  935. pLastMatchedFilter->pIniQMPolicy,
  936. pMatchedQMPolicies
  937. );
  938. BAIL_ON_LOCK_ERROR(dwError);
  939. }
  940. else {
  941. memset(pMatchedQMPolicies, 0, sizeof(IPSEC_QM_POLICY));
  942. }
  943. dwNumPolicies++;
  944. }
  945. else {
  946. pTemp = pIniTnSFilter;
  947. pMatchedTnFilter = pMatchedTnFilters;
  948. pMatchedQMPolicy = pMatchedQMPolicies;
  949. i = 0;
  950. while (i < dwNumMatches) {
  951. bMatches = MatchIniTnSFilter(
  952. pTemp,
  953. pTnFilter
  954. );
  955. if (bMatches) {
  956. dwError = CopyTnSFilter(
  957. pTemp,
  958. pMatchedTnFilter
  959. );
  960. BAIL_ON_LOCK_ERROR(dwError);
  961. pMatchedTnFilter++;
  962. dwNumFilters++;
  963. if (pTemp->pIniQMPolicy) {
  964. dwError = CopyQMPolicy(
  965. pTemp->pIniQMPolicy,
  966. pMatchedQMPolicy
  967. );
  968. BAIL_ON_LOCK_ERROR(dwError);
  969. }
  970. else {
  971. memset(pMatchedQMPolicy, 0, sizeof(IPSEC_QM_POLICY));
  972. }
  973. pMatchedQMPolicy++;
  974. dwNumPolicies++;
  975. i++;
  976. }
  977. pTemp = pTemp->pNext;
  978. }
  979. }
  980. lock_success:
  981. LEAVE_SPD_SECTION();
  982. *ppMatchedTnFilters = pMatchedTnFilters;
  983. *ppMatchedQMPolicies = pMatchedQMPolicies;
  984. *pdwNumMatches = dwNumMatches;
  985. *pdwResumeHandle = dwResumeHandle + dwNumMatches;
  986. return (dwError);
  987. lock:
  988. LEAVE_SPD_SECTION();
  989. error:
  990. if (pMatchedTnFilters) {
  991. FreeTnFilters(
  992. dwNumFilters,
  993. pMatchedTnFilters
  994. );
  995. }
  996. if (pMatchedQMPolicies) {
  997. FreeQMPolicies(
  998. dwNumPolicies,
  999. pMatchedQMPolicies
  1000. );
  1001. }
  1002. *ppMatchedTnFilters = NULL;
  1003. *ppMatchedQMPolicies = NULL;
  1004. *pdwNumMatches = 0;
  1005. *pdwResumeHandle = dwResumeHandle;
  1006. return (dwError);
  1007. }
  1008. DWORD
  1009. ValidateTnFilterTemplate(
  1010. PTUNNEL_FILTER pTnFilter
  1011. )
  1012. {
  1013. DWORD dwError = 0;
  1014. BOOL bConflicts = FALSE;
  1015. if (!pTnFilter) {
  1016. dwError = ERROR_INVALID_PARAMETER;
  1017. BAIL_ON_WIN32_ERROR(dwError);
  1018. }
  1019. dwError = VerifyAddresses(pTnFilter->SrcAddr, TRUE, FALSE);
  1020. BAIL_ON_WIN32_ERROR(dwError);
  1021. dwError = VerifyAddresses(pTnFilter->DesAddr, TRUE, TRUE);
  1022. BAIL_ON_WIN32_ERROR(dwError);
  1023. bConflicts = AddressesConflict(
  1024. pTnFilter->SrcAddr,
  1025. pTnFilter->DesAddr
  1026. );
  1027. if (bConflicts) {
  1028. dwError = ERROR_INVALID_PARAMETER;
  1029. BAIL_ON_WIN32_ERROR(dwError);
  1030. }
  1031. dwError = VerifyAddresses(pTnFilter->DesTunnelAddr, TRUE, FALSE);
  1032. BAIL_ON_WIN32_ERROR(dwError);
  1033. dwError = VerifyProtocols(pTnFilter->Protocol);
  1034. BAIL_ON_WIN32_ERROR(dwError);
  1035. dwError = VerifyPortsForProtocol(
  1036. pTnFilter->SrcPort,
  1037. pTnFilter->Protocol
  1038. );
  1039. BAIL_ON_WIN32_ERROR(dwError);
  1040. dwError = VerifyPortsForProtocol(
  1041. pTnFilter->DesPort,
  1042. pTnFilter->Protocol
  1043. );
  1044. BAIL_ON_WIN32_ERROR(dwError);
  1045. if (pTnFilter->dwDirection) {
  1046. if ((pTnFilter->dwDirection != FILTER_DIRECTION_INBOUND) &&
  1047. (pTnFilter->dwDirection != FILTER_DIRECTION_OUTBOUND)) {
  1048. dwError = ERROR_INVALID_PARAMETER;
  1049. BAIL_ON_WIN32_ERROR(dwError);
  1050. }
  1051. }
  1052. error:
  1053. return (dwError);
  1054. }
  1055. BOOL
  1056. MatchIniTnSFilter(
  1057. PINITNSFILTER pIniTnSFilter,
  1058. PTUNNEL_FILTER pTnFilter
  1059. )
  1060. {
  1061. BOOL bMatches = FALSE;
  1062. if (pTnFilter->dwDirection) {
  1063. if (pTnFilter->dwDirection != pIniTnSFilter->dwDirection) {
  1064. return (FALSE);
  1065. }
  1066. }
  1067. if ((pIniTnSFilter->InboundFilterFlag != NEGOTIATE_SECURITY) &&
  1068. (pIniTnSFilter->OutboundFilterFlag != NEGOTIATE_SECURITY)) {
  1069. return (FALSE);
  1070. }
  1071. bMatches = MatchAddresses(
  1072. pIniTnSFilter->SrcAddr,
  1073. pTnFilter->SrcAddr
  1074. );
  1075. if (!bMatches) {
  1076. return (FALSE);
  1077. }
  1078. bMatches = MatchAddresses(
  1079. pIniTnSFilter->DesAddr,
  1080. pTnFilter->DesAddr
  1081. );
  1082. if (!bMatches) {
  1083. return (FALSE);
  1084. }
  1085. bMatches = MatchAddresses(
  1086. pIniTnSFilter->DesTunnelAddr,
  1087. pTnFilter->DesTunnelAddr
  1088. );
  1089. if (!bMatches) {
  1090. return (FALSE);
  1091. }
  1092. bMatches = MatchPorts(
  1093. pIniTnSFilter->SrcPort,
  1094. pTnFilter->SrcPort
  1095. );
  1096. if (!bMatches) {
  1097. return (FALSE);
  1098. }
  1099. bMatches = MatchPorts(
  1100. pIniTnSFilter->DesPort,
  1101. pTnFilter->DesPort
  1102. );
  1103. if (!bMatches) {
  1104. return (FALSE);
  1105. }
  1106. bMatches = MatchProtocols(
  1107. pIniTnSFilter->Protocol,
  1108. pTnFilter->Protocol
  1109. );
  1110. if (!bMatches) {
  1111. return (FALSE);
  1112. }
  1113. return (TRUE);
  1114. }
  1115. DWORD
  1116. CopyTnMatchDefaults(
  1117. PTUNNEL_FILTER * ppTnFilters,
  1118. PIPSEC_QM_POLICY * ppQMPolicies,
  1119. PDWORD pdwNumMatches
  1120. )
  1121. {
  1122. DWORD dwError = 0;
  1123. PTUNNEL_FILTER pTnFilters = NULL;
  1124. PIPSEC_QM_POLICY pQMPolicies = NULL;
  1125. DWORD dwNumFilters = 0;
  1126. DWORD dwNumPolicies = 0;
  1127. if (!gpIniDefaultQMPolicy) {
  1128. dwError = ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND;
  1129. BAIL_ON_WIN32_ERROR(dwError);
  1130. }
  1131. dwError = SPDApiBufferAllocate(
  1132. sizeof(TUNNEL_FILTER),
  1133. &pTnFilters
  1134. );
  1135. BAIL_ON_WIN32_ERROR(dwError);
  1136. dwError = SPDApiBufferAllocate(
  1137. sizeof(IPSEC_QM_POLICY),
  1138. &pQMPolicies
  1139. );
  1140. BAIL_ON_WIN32_ERROR(dwError);
  1141. dwError = CopyDefaultTnFilter(
  1142. pTnFilters,
  1143. gpIniDefaultQMPolicy
  1144. );
  1145. BAIL_ON_WIN32_ERROR(dwError);
  1146. dwNumFilters++;
  1147. dwError = CopyQMPolicy(
  1148. gpIniDefaultQMPolicy,
  1149. pQMPolicies
  1150. );
  1151. BAIL_ON_WIN32_ERROR(dwError);
  1152. dwNumPolicies++;
  1153. *ppTnFilters = pTnFilters;
  1154. *ppQMPolicies = pQMPolicies;
  1155. *pdwNumMatches = 1;
  1156. return (dwError);
  1157. error:
  1158. if (pTnFilters) {
  1159. FreeTnFilters(
  1160. dwNumFilters,
  1161. pTnFilters
  1162. );
  1163. }
  1164. if (pQMPolicies) {
  1165. FreeQMPolicies(
  1166. dwNumPolicies,
  1167. pQMPolicies
  1168. );
  1169. }
  1170. *ppTnFilters = NULL;
  1171. *ppQMPolicies = NULL;
  1172. *pdwNumMatches = 0;
  1173. return (dwError);
  1174. }
  1175. DWORD
  1176. CopyDefaultTnFilter(
  1177. PTUNNEL_FILTER pTnFilter,
  1178. PINIQMPOLICY pIniQMPolicy
  1179. )
  1180. {
  1181. DWORD dwError = 0;
  1182. UuidCreate(&(pTnFilter->gFilterID));
  1183. dwError = CopyName(
  1184. L"0",
  1185. &(pTnFilter->pszFilterName)
  1186. );
  1187. BAIL_ON_WIN32_ERROR(dwError);
  1188. pTnFilter->InterfaceType = INTERFACE_TYPE_ALL;
  1189. pTnFilter->bCreateMirror = TRUE;
  1190. pTnFilter->dwFlags = 0;
  1191. pTnFilter->dwFlags |= IPSEC_QM_POLICY_DEFAULT_POLICY;
  1192. pTnFilter->SrcAddr.AddrType = IP_ADDR_SUBNET;
  1193. pTnFilter->SrcAddr.uIpAddr = SUBNET_ADDRESS_ANY;
  1194. pTnFilter->SrcAddr.uSubNetMask = SUBNET_MASK_ANY;
  1195. pTnFilter->DesAddr.AddrType = IP_ADDR_SUBNET;
  1196. pTnFilter->DesAddr.uIpAddr = SUBNET_ADDRESS_ANY;
  1197. pTnFilter->DesAddr.uSubNetMask = SUBNET_MASK_ANY;
  1198. pTnFilter->SrcTunnelAddr.AddrType = IP_ADDR_SUBNET;
  1199. pTnFilter->SrcTunnelAddr.uIpAddr = SUBNET_ADDRESS_ANY;
  1200. pTnFilter->SrcTunnelAddr.uSubNetMask = SUBNET_MASK_ANY;
  1201. pTnFilter->DesTunnelAddr.AddrType = IP_ADDR_SUBNET;
  1202. pTnFilter->DesTunnelAddr.uIpAddr = SUBNET_ADDRESS_ANY;
  1203. pTnFilter->DesTunnelAddr.uSubNetMask = SUBNET_MASK_ANY;
  1204. pTnFilter->Protocol.ProtocolType = PROTOCOL_UNIQUE;
  1205. pTnFilter->Protocol.dwProtocol = 0;
  1206. pTnFilter->SrcPort.PortType = PORT_UNIQUE;
  1207. pTnFilter->SrcPort.wPort = 0;
  1208. pTnFilter->DesPort.PortType = PORT_UNIQUE;
  1209. pTnFilter->DesPort.wPort = 0;
  1210. pTnFilter->InboundFilterFlag = NEGOTIATE_SECURITY;
  1211. pTnFilter->OutboundFilterFlag = NEGOTIATE_SECURITY;
  1212. pTnFilter->dwDirection = 0;
  1213. pTnFilter->dwWeight = 0;
  1214. CopyGuid(pIniQMPolicy->gPolicyID, &(pTnFilter->gPolicyID));
  1215. error:
  1216. return (dwError);
  1217. }