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.

1315 lines
38 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1990-1993 **/
  4. /********************************************************************/
  5. /* :ts=4 */
  6. //** SECFLTR.C - Security Filter Support
  7. //
  8. //
  9. // Security filters provide a mechanism by which the transport protocol
  10. // traffic accepted on IP interfaces may be controlled. Security filtering
  11. // is globally enabled or disabled for all IP interfaces and transports.
  12. // If filtering is enabled, incoming traffic is filtered based on registered
  13. // {interface, protocol, transport value} tuples. The tuples specify
  14. // permissible traffic. All other values will be rejected. For UDP datagrams
  15. // and TCP connections, the transport value is the port number. For RawIP
  16. // datagrams, the transport value is the IP protocol number. An entry exists
  17. // in the filter database for all active interfaces and protocols in the
  18. // system.
  19. //
  20. // The initial status of security filtering - enabled or disabled, is
  21. // controlled by the registry parameter
  22. //
  23. // Services\Tcpip\Parameters\EnableSecurityFilters
  24. //
  25. // If the parameter is not found, filtering is disabled.
  26. //
  27. // The list of permissible values for each protocol is stored in the registry
  28. // under the <Adaptername>\Parameters\Tcpip key in MULTI_SZ parameters.
  29. // The parameter names are TCPAllowedPorts, UDPAllowedPorts and
  30. // RawIPAllowedProtocols. If no parameter is found for a particular protocol,
  31. // all values are permissible. If a parameter is found, the string identifies
  32. // the permissible values. If the string is empty, no values are permissible.
  33. //
  34. // Filter Operation (Filtering Enabled):
  35. //
  36. // IF ( Match(interface, protocol) AND ( AllValuesPermitted(Protocol) OR
  37. // Match(Value) ))
  38. // THEN operation permitted.
  39. // ELSE operation rejected.
  40. //
  41. // Database Implementation:
  42. //
  43. // The filter database is implemented as a three-level structure. The top
  44. // level is a list of interface entries. Each interface entry points to
  45. // a list of protocol entries. Each protocol entry contains a bucket hash
  46. // table used to store transport value entries.
  47. //
  48. // The following calls may be used to access the security filter database:
  49. //
  50. // InitializeSecurityFilters
  51. // CleanupSecurityFilters
  52. // IsSecurityFilteringEnabled
  53. // ControlSecurityFiltering
  54. // AddProtocolSecurityFilter
  55. // DeleteProtocolSecurityFilter
  56. // AddValueSecurityFilter
  57. // DeleteValueSecurityFilter
  58. // EnumerateSecurityFilters
  59. // IsPermittedSecurityFilter
  60. //
  61. #include "precomp.h"
  62. #include "addr.h"
  63. #include "tlcommon.h"
  64. #include "udp.h"
  65. #include "tcp.h"
  66. #include "raw.h"
  67. #include "tcpcfg.h"
  68. #include "tcpinfo.h"
  69. #include "secfltr.h"
  70. //
  71. // All of the init code can be discarded.
  72. //
  73. #ifdef ALLOC_PRAGMA
  74. #pragma alloc_text(INIT, InitializeSecurityFilters)
  75. #endif
  76. //
  77. // The following routines must be supplied by each platform which implements
  78. // security filters.
  79. //
  80. extern TDI_STATUS
  81. GetSecurityFilterList(
  82. IN NDIS_HANDLE ConfigHandle,
  83. IN ulong Protocol,
  84. IN OUT PNDIS_STRING FilterList
  85. );
  86. extern uint
  87. EnumSecurityFilterValue(
  88. IN PNDIS_STRING FilterList,
  89. IN ulong Index,
  90. OUT ulong * FilterValue
  91. );
  92. //
  93. // Constants
  94. //
  95. #define DHCP_CLIENT_PORT 68
  96. //
  97. // Modification Opcodes
  98. //
  99. #define ADD_VALUE_SECURITY_FILTER 0
  100. #define DELETE_VALUE_SECURITY_FILTER 1
  101. //
  102. // Types
  103. //
  104. //
  105. // Structure for a transport value entry.
  106. //
  107. struct value_entry {
  108. struct Queue ve_link;
  109. ulong ve_value;
  110. };
  111. typedef struct value_entry VALUE_ENTRY, *PVALUE_ENTRY;
  112. #define VALUE_ENTRY_HASH_SIZE 16
  113. #define VALUE_ENTRY_HASH(value) (value % VALUE_ENTRY_HASH_SIZE)
  114. //
  115. // Structure for a protocol entry.
  116. //
  117. struct protocol_entry {
  118. struct Queue pe_link;
  119. ulong pe_protocol;
  120. ULONG pe_accept_all; // TRUE if all values are accepted.
  121. struct Queue pe_entries[VALUE_ENTRY_HASH_SIZE];
  122. };
  123. typedef struct protocol_entry PROTOCOL_ENTRY, *PPROTOCOL_ENTRY;
  124. //
  125. // Structure for an interface entry.
  126. //
  127. struct interface_entry {
  128. struct Queue ie_link;
  129. IPAddr ie_address;
  130. struct Queue ie_protocol_list; // list of protocols to filter
  131. };
  132. typedef struct interface_entry INTERFACE_ENTRY, *PINTERFACE_ENTRY;
  133. //
  134. // Global Data
  135. //
  136. //
  137. // This list of interface entries is the root of the filter database.
  138. //
  139. struct Queue InterfaceEntryList;
  140. //
  141. // The filter operations are synchronized using the AddrObjTableLock.
  142. //
  143. extern IPInfo LocalNetInfo;
  144. //
  145. // Filter Database Helper Functions
  146. //
  147. //* FindInterfaceEntry - Search for an interface entry.
  148. //
  149. // This utility routine searches the security filter database
  150. // for the specified interface entry.
  151. //
  152. //
  153. // Input: InterfaceAddress - The address of the interface to search for.
  154. //
  155. //
  156. // Returns: A pointer to the database entry for the Interface,
  157. // or NULL if no match was found.
  158. //
  159. //
  160. PINTERFACE_ENTRY
  161. FindInterfaceEntry(ULONG InterfaceAddress)
  162. {
  163. PINTERFACE_ENTRY ientry;
  164. struct Queue *qentry;
  165. for (qentry = InterfaceEntryList.q_next;
  166. qentry != &InterfaceEntryList;
  167. qentry = qentry->q_next
  168. ) {
  169. ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
  170. if (ientry->ie_address == InterfaceAddress) {
  171. return (ientry);
  172. }
  173. }
  174. return (NULL);
  175. }
  176. //* FindProtocolEntry - Search for a protocol associated with an interface.
  177. //
  178. // This utility routine searches the security filter database
  179. // for the specified protocol registered under the specified interface.
  180. //
  181. //
  182. // Input: InterfaceEntry - A pointer to an interface entry to search under.
  183. // Protocol - The protocol value to search for.
  184. //
  185. //
  186. // Returns: A pointer to the database entry for the <Address, Protocol>,
  187. // or NULL if no match was found.
  188. //
  189. //
  190. PPROTOCOL_ENTRY
  191. FindProtocolEntry(PINTERFACE_ENTRY InterfaceEntry, ULONG Protocol)
  192. {
  193. PPROTOCOL_ENTRY pentry;
  194. struct Queue *qentry;
  195. for (qentry = InterfaceEntry->ie_protocol_list.q_next;
  196. qentry != &(InterfaceEntry->ie_protocol_list);
  197. qentry = qentry->q_next
  198. ) {
  199. pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
  200. if (pentry->pe_protocol == Protocol) {
  201. return (pentry);
  202. }
  203. }
  204. return (NULL);
  205. }
  206. //* FindValueEntry - Search for a value on a particular protocol.
  207. //
  208. // This utility routine searches the security filter database
  209. // for the specified value registered under the specified protocol.
  210. //
  211. //
  212. // Input: ProtocolEntry - A pointer to the database structure for the
  213. // Protocol to search.
  214. // FilterValue - The value to search for.
  215. //
  216. //
  217. // Returns: A pointer to the database entry for the <Protocol, Value>,
  218. // or NULL if no match was found.
  219. //
  220. //
  221. PVALUE_ENTRY
  222. FindValueEntry(PPROTOCOL_ENTRY ProtocolEntry, ULONG FilterValue)
  223. {
  224. PVALUE_ENTRY ventry;
  225. ulong hash_value = VALUE_ENTRY_HASH(FilterValue);
  226. struct Queue *qentry;
  227. for (qentry = ProtocolEntry->pe_entries[hash_value].q_next;
  228. qentry != &(ProtocolEntry->pe_entries[hash_value]);
  229. qentry = qentry->q_next
  230. ) {
  231. ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
  232. if (ventry->ve_value == FilterValue) {
  233. return (ventry);
  234. }
  235. }
  236. return (NULL);
  237. }
  238. //* DeleteProtocolValueEntries
  239. //
  240. // This utility routine deletes all the value entries associated with
  241. // a protocol filter entry.
  242. //
  243. //
  244. // Input: ProtocolEntry - The protocol filter entry for which to
  245. // delete the value entries.
  246. //
  247. //
  248. // Returns: Nothing
  249. //
  250. void
  251. DeleteProtocolValueEntries(PPROTOCOL_ENTRY ProtocolEntry)
  252. {
  253. ulong i;
  254. PVALUE_ENTRY entry;
  255. for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) {
  256. while (!EMPTYQ(&(ProtocolEntry->pe_entries[i]))) {
  257. DEQUEUE(&(ProtocolEntry->pe_entries[i]), entry, VALUE_ENTRY, ve_link);
  258. CTEFreeMem(entry);
  259. }
  260. }
  261. return;
  262. }
  263. //* ModifyProtocolEntry
  264. //
  265. // This utility routine modifies one or more filter values associated
  266. // with a protocol.
  267. //
  268. //
  269. // Input: Operation - The operation to perform (add or delete)
  270. //
  271. // ProtocolEntry - A pointer to the protocol entry structure on
  272. // which to operate.
  273. //
  274. // FilterValue - The value to add or delete.
  275. //
  276. //
  277. // Returns: TDI_STATUS code
  278. //
  279. TDI_STATUS
  280. ModifyProtocolEntry(ulong Operation, PPROTOCOL_ENTRY ProtocolEntry,
  281. ulong FilterValue)
  282. {
  283. TDI_STATUS status = TDI_SUCCESS;
  284. if (FilterValue == 0) {
  285. if (Operation == ADD_VALUE_SECURITY_FILTER) {
  286. //
  287. // Accept all values for the protocol
  288. //
  289. ProtocolEntry->pe_accept_all = TRUE;
  290. } else {
  291. //
  292. // Reject all values for the protocol
  293. //
  294. ProtocolEntry->pe_accept_all = FALSE;
  295. }
  296. DeleteProtocolValueEntries(ProtocolEntry);
  297. } else {
  298. PVALUE_ENTRY ventry;
  299. ulong hash_value;
  300. //
  301. // This request modifies an individual entry.
  302. //
  303. ventry = FindValueEntry(ProtocolEntry, FilterValue);
  304. if (Operation == ADD_VALUE_SECURITY_FILTER) {
  305. if (ventry == NULL) {
  306. ventry = CTEAllocMem(sizeof(VALUE_ENTRY));
  307. if (ventry != NULL) {
  308. ventry->ve_value = FilterValue;
  309. hash_value = VALUE_ENTRY_HASH(FilterValue);
  310. ENQUEUE(&(ProtocolEntry->pe_entries[hash_value]),
  311. &(ventry->ve_link));
  312. ProtocolEntry->pe_accept_all = FALSE;
  313. } else {
  314. status = TDI_NO_RESOURCES;
  315. }
  316. }
  317. } else {
  318. if (ventry != NULL) {
  319. REMOVEQ(&(ventry->ve_link));
  320. CTEFreeMem(ventry);
  321. }
  322. }
  323. }
  324. return (status);
  325. }
  326. //* ModifyInterfaceEntry
  327. //
  328. // This utility routine modifies the value entries of one or more protocol
  329. // entries associated with an interface.
  330. //
  331. //
  332. // Input: Operation - The operation to perform (add or delete)
  333. //
  334. // ProtocolEntry - A pointer to the interface entry structure on
  335. // which to operate.
  336. //
  337. // Protocol - The protocol on which to operate.
  338. //
  339. // FilterValue - The value to add or delete.
  340. //
  341. //
  342. // Returns: TDI_STATUS code
  343. //
  344. TDI_STATUS
  345. ModifyInterfaceEntry(ulong Operation, PINTERFACE_ENTRY InterfaceEntry,
  346. ulong Protocol, ulong FilterValue)
  347. {
  348. PPROTOCOL_ENTRY pentry;
  349. TDI_STATUS status;
  350. TDI_STATUS returnStatus = TDI_SUCCESS;
  351. if (Protocol == 0) {
  352. struct Queue *qentry;
  353. //
  354. // Modify all protocols on the interface
  355. //
  356. for (qentry = InterfaceEntry->ie_protocol_list.q_next;
  357. qentry != &(InterfaceEntry->ie_protocol_list);
  358. qentry = qentry->q_next
  359. ) {
  360. pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
  361. status = ModifyProtocolEntry(Operation, pentry, FilterValue);
  362. if (status != TDI_SUCCESS) {
  363. returnStatus = status;
  364. }
  365. }
  366. } else {
  367. //
  368. // Modify a specific protocol on the interface
  369. //
  370. pentry = FindProtocolEntry(InterfaceEntry, Protocol);
  371. if (pentry != NULL) {
  372. returnStatus = ModifyProtocolEntry(Operation, pentry, FilterValue);
  373. } else {
  374. returnStatus = TDI_INVALID_PARAMETER;
  375. }
  376. }
  377. return (returnStatus);
  378. }
  379. //* ModifySecurityFilter - Add or delete an entry.
  380. //
  381. // This routine adds or deletes an entry to/from the security filter database.
  382. //
  383. //
  384. // Input: Operation - The operation to perform (Add or Delete)
  385. // InterfaceAddress - The interface address to modify.
  386. // Protocol - The protocol to modify.
  387. // FilterValue - The transport value to add/delete.
  388. //
  389. // Returns: A TDI status code:
  390. // TDI_INVALID_PARAMETER if the protocol is not in the database.
  391. // TDI_ADDR_INVALID if the interface is not in the database.
  392. // TDI_NO_RESOURCES if memory could not be allocated.
  393. // TDI_SUCCESS otherwise
  394. //
  395. // NOTES:
  396. //
  397. TDI_STATUS
  398. ModifySecurityFilter(ulong Operation, IPAddr InterfaceAddress, ulong Protocol,
  399. ulong FilterValue)
  400. {
  401. PINTERFACE_ENTRY ientry;
  402. TDI_STATUS status;
  403. TDI_STATUS returnStatus = TDI_SUCCESS;
  404. if (InterfaceAddress == 0) {
  405. struct Queue *qentry;
  406. //
  407. // Modify on all interfaces
  408. //
  409. for (qentry = InterfaceEntryList.q_next;
  410. qentry != &InterfaceEntryList;
  411. qentry = qentry->q_next
  412. ) {
  413. ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
  414. status = ModifyInterfaceEntry(Operation, ientry, Protocol,
  415. FilterValue);
  416. if (status != TDI_SUCCESS) {
  417. returnStatus = status;
  418. }
  419. }
  420. } else {
  421. ientry = FindInterfaceEntry(InterfaceAddress);
  422. if (ientry != NULL) {
  423. returnStatus = ModifyInterfaceEntry(Operation, ientry, Protocol,
  424. FilterValue);
  425. } else {
  426. returnStatus = TDI_ADDR_INVALID;
  427. }
  428. }
  429. return (returnStatus);
  430. }
  431. //* FillInEnumerationEntry
  432. //
  433. // This utility routine fills in an enumeration entry for a particular
  434. // filter value entry.
  435. //
  436. //
  437. // Input: InterfaceAddress - The address of the associated interface.
  438. //
  439. // Protocol - The associated protocol number.
  440. //
  441. // Value - The enumerated value.
  442. //
  443. // Buffer - Pointer to the user's enumeration buffer.
  444. //
  445. // BufferSize - Pointer to the size of the enumeration buffer.
  446. //
  447. // EntriesReturned - Pointer to a running count of enumerated
  448. // entries stored in Buffer.
  449. //
  450. // EntriesAvailable - Pointer to a running count of entries available
  451. // for enumeration.
  452. //
  453. // Returns: Nothing.
  454. //
  455. // Note: Values written to enumeration entry are in host byte order.
  456. //
  457. void
  458. FillInEnumerationEntry(IPAddr InterfaceAddress, ulong Protocol, ulong Value,
  459. uchar ** Buffer, ulong * BufferSize,
  460. ulong * EntriesReturned, ulong * EntriesAvailable)
  461. {
  462. TCPSecurityFilterEntry *entry = (TCPSecurityFilterEntry *) * Buffer;
  463. if (*BufferSize >= sizeof(TCPSecurityFilterEntry)) {
  464. entry->tsf_address = net_long(InterfaceAddress);
  465. entry->tsf_protocol = Protocol;
  466. entry->tsf_value = Value;
  467. *Buffer += sizeof(TCPSecurityFilterEntry);
  468. *BufferSize -= sizeof(TCPSecurityFilterEntry);
  469. (*EntriesReturned)++;
  470. }
  471. (*EntriesAvailable)++;
  472. return;
  473. }
  474. //* EnumerateProtocolValues
  475. //
  476. // This utility routine enumerates values associated with a
  477. // protocol on an interface.
  478. //
  479. //
  480. // Input: InterfaceEntry - Pointer to the associated interface entry.
  481. //
  482. // ProtocolEntry - Pointer to the protocol being enumerated.
  483. //
  484. // Value - The value to enumerate.
  485. //
  486. // Buffer - Pointer to the user's enumeration buffer.
  487. //
  488. // BufferSize - Pointer to the size of the enumeration buffer.
  489. //
  490. // EntriesReturned - Pointer to a running count of enumerated
  491. // entries stored in Buffer.
  492. //
  493. // EntriesAvailable - Pointer to a running count of entries available
  494. // for enumeration.
  495. //
  496. // Returns: Nothing.
  497. //
  498. void
  499. EnumerateProtocolValues(PINTERFACE_ENTRY InterfaceEntry,
  500. PPROTOCOL_ENTRY ProtocolEntry, ulong Value,
  501. uchar ** Buffer, ulong * BufferSize,
  502. ulong * EntriesReturned, ulong * EntriesAvailable)
  503. {
  504. struct Queue *qentry;
  505. TDI_STATUS status = TDI_SUCCESS;
  506. PVALUE_ENTRY ventry;
  507. ulong i;
  508. if (Value == 0) {
  509. //
  510. // Enumerate all values
  511. //
  512. if (ProtocolEntry->pe_accept_all == TRUE) {
  513. //
  514. // All values permitted.
  515. //
  516. FillInEnumerationEntry(
  517. InterfaceEntry->ie_address,
  518. ProtocolEntry->pe_protocol,
  519. 0,
  520. Buffer,
  521. BufferSize,
  522. EntriesReturned,
  523. EntriesAvailable
  524. );
  525. } else {
  526. for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) {
  527. for (qentry = ProtocolEntry->pe_entries[i].q_next;
  528. qentry != &(ProtocolEntry->pe_entries[i]);
  529. qentry = qentry->q_next
  530. ) {
  531. ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
  532. FillInEnumerationEntry(
  533. InterfaceEntry->ie_address,
  534. ProtocolEntry->pe_protocol,
  535. ventry->ve_value,
  536. Buffer,
  537. BufferSize,
  538. EntriesReturned,
  539. EntriesAvailable
  540. );
  541. }
  542. }
  543. }
  544. } else {
  545. //
  546. // Enumerate a specific value, if it is registered.
  547. //
  548. ventry = FindValueEntry(ProtocolEntry, Value);
  549. if (ventry != NULL) {
  550. FillInEnumerationEntry(
  551. InterfaceEntry->ie_address,
  552. ProtocolEntry->pe_protocol,
  553. ventry->ve_value,
  554. Buffer,
  555. BufferSize,
  556. EntriesReturned,
  557. EntriesAvailable
  558. );
  559. }
  560. }
  561. return;
  562. }
  563. //* EnumerateInterfaceProtocols
  564. //
  565. // This utility routine enumerates protocols associated with
  566. // an interface.
  567. //
  568. //
  569. // Input: InterfaceEntry - Pointer to the associated interface entry.
  570. //
  571. // Protocol - Protocol number to enumerate.
  572. //
  573. // Value - The filter value to enumerate.
  574. //
  575. // Buffer - Pointer to the user's enumeration buffer.
  576. //
  577. // BufferSize - Pointer to the size of the enumeration buffer.
  578. //
  579. // EntriesReturned - Pointer to a running count of enumerated
  580. // entries stored in Buffer.
  581. //
  582. // EntriesAvailable - Pointer to a running count of entries available
  583. // for enumeration.
  584. //
  585. // Returns: Nothing.
  586. //
  587. void
  588. EnumerateInterfaceProtocols(PINTERFACE_ENTRY InterfaceEntry, ulong Protocol,
  589. ulong Value, uchar ** Buffer, ulong * BufferSize,
  590. ulong * EntriesReturned, ulong * EntriesAvailable)
  591. {
  592. PPROTOCOL_ENTRY pentry;
  593. if (Protocol == 0) {
  594. struct Queue *qentry;
  595. //
  596. // Enumerate all protocols.
  597. //
  598. for (qentry = InterfaceEntry->ie_protocol_list.q_next;
  599. qentry != &(InterfaceEntry->ie_protocol_list);
  600. qentry = qentry->q_next
  601. ) {
  602. pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
  603. EnumerateProtocolValues(
  604. InterfaceEntry,
  605. pentry,
  606. Value,
  607. Buffer,
  608. BufferSize,
  609. EntriesReturned,
  610. EntriesAvailable
  611. );
  612. }
  613. } else {
  614. //
  615. // Enumerate a specific protocol
  616. //
  617. pentry = FindProtocolEntry(InterfaceEntry, Protocol);
  618. if (pentry != NULL) {
  619. EnumerateProtocolValues(
  620. InterfaceEntry,
  621. pentry,
  622. Value,
  623. Buffer,
  624. BufferSize,
  625. EntriesReturned,
  626. EntriesAvailable
  627. );
  628. }
  629. }
  630. return;
  631. }
  632. //
  633. // Filter Database Public API.
  634. //
  635. //* InitializeSecurityFilters - Initializes the security filter database.
  636. //
  637. // The routine performs the initialization necessary to enable the
  638. // security filter database for operation.
  639. //
  640. // Input: None.
  641. //
  642. // Returns: Nothing.
  643. //
  644. //
  645. void
  646. InitializeSecurityFilters(void)
  647. {
  648. INITQ(&InterfaceEntryList);
  649. return;
  650. }
  651. //* CleanupSecurityFilters - Deletes the entire security filter database.
  652. //
  653. // This routine deletes all entries from the security filter database.
  654. //
  655. //
  656. // Input: None.
  657. //
  658. // Returns: Nothing.
  659. //
  660. // NOTE: This routine acquires the AddrObjTableLock.
  661. //
  662. //
  663. void
  664. CleanupSecurityFilters(void)
  665. {
  666. PPROTOCOL_ENTRY pentry;
  667. PINTERFACE_ENTRY ientry;
  668. CTELockHandle handle;
  669. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  670. while (!EMPTYQ(&InterfaceEntryList)) {
  671. DEQUEUE(&InterfaceEntryList, ientry, INTERFACE_ENTRY, ie_link);
  672. while (!EMPTYQ(&(ientry->ie_protocol_list))) {
  673. DEQUEUE(&(ientry->ie_protocol_list), pentry, PROTOCOL_ENTRY,
  674. pe_link);
  675. DeleteProtocolValueEntries(pentry);
  676. CTEFreeMem(pentry);
  677. }
  678. CTEFreeMem(ientry);
  679. }
  680. SecurityFilteringEnabled = FALSE;
  681. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  682. return;
  683. }
  684. //* IsSecurityFilteringEnabled
  685. //
  686. // This routine returns the current global status of security filtering.
  687. //
  688. // Entry: Nothing
  689. //
  690. // Returns: 0 if filtering is disabled, !0 if filtering is enabled.
  691. //
  692. extern uint
  693. IsSecurityFilteringEnabled(void)
  694. {
  695. uint enabled;
  696. CTELockHandle handle;
  697. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  698. enabled = SecurityFilteringEnabled;
  699. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  700. return (enabled);
  701. }
  702. //* ControlSecurityFiltering
  703. //
  704. // This routine globally enables/disables security filtering.
  705. //
  706. // Entry: IsEnabled - 0 disabled filtering, !0 enables filtering.
  707. //
  708. // Returns: Nothing
  709. //
  710. extern void
  711. ControlSecurityFiltering(uint IsEnabled)
  712. {
  713. CTELockHandle handle;
  714. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  715. if (IsEnabled) {
  716. SecurityFilteringEnabled = TRUE;
  717. } else {
  718. SecurityFilteringEnabled = FALSE;
  719. }
  720. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  721. return;
  722. }
  723. //* AddProtocolSecurityFilter
  724. //
  725. // This routine enables security filtering for a specified protocol
  726. // on a specified IP interface.
  727. //
  728. // Entry: InterfaceAddress - The interface on which to enable the protocol.
  729. // (in network byte order)
  730. // Protocol - The protocol to enable.
  731. // ConfigName - The configuration key from which to read
  732. // the filter value information.
  733. //
  734. // Returns: Nothing
  735. //
  736. void
  737. AddProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
  738. NDIS_HANDLE ConfigHandle)
  739. {
  740. NDIS_STRING filterList;
  741. ulong filterValue;
  742. ulong i;
  743. PINTERFACE_ENTRY ientry;
  744. PPROTOCOL_ENTRY pentry;
  745. PVOID temp;
  746. CTELockHandle handle;
  747. TDI_STATUS status;
  748. if (IP_ADDR_EQUAL(InterfaceAddress, NULL_IP_ADDR) ||
  749. IP_LOOPBACK_ADDR(InterfaceAddress)
  750. ) {
  751. return;
  752. }
  753. ASSERT((Protocol != 0) && (Protocol <= 0xFF));
  754. //
  755. // Read the protocol-specific filter value list from the registry.
  756. //
  757. filterList.MaximumLength = filterList.Length = 0;
  758. filterList.Buffer = NULL;
  759. if (ConfigHandle != NULL) {
  760. status = GetSecurityFilterList(ConfigHandle, Protocol, &filterList);
  761. }
  762. //
  763. // Preallocate interface & protocol structures. We abort on failure.
  764. // The interface & protocol will be protected by default.
  765. //
  766. ientry = CTEAllocMem(sizeof(INTERFACE_ENTRY));
  767. if (ientry == NULL) {
  768. return;
  769. }
  770. ientry->ie_address = InterfaceAddress;
  771. INITQ(&(ientry->ie_protocol_list));
  772. pentry = CTEAllocMem(sizeof(PROTOCOL_ENTRY));
  773. if (pentry == NULL) {
  774. CTEFreeMem(ientry);
  775. return;
  776. }
  777. pentry->pe_protocol = Protocol;
  778. pentry->pe_accept_all = FALSE;
  779. for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) {
  780. INITQ(&(pentry->pe_entries[i]));
  781. }
  782. //
  783. // Now go set everything up. First create the interface and protocol
  784. // structures.
  785. //
  786. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  787. temp = FindInterfaceEntry(InterfaceAddress);
  788. if (temp == NULL) {
  789. //
  790. // New interface & protocol.
  791. //
  792. ENQUEUE(&InterfaceEntryList, &(ientry->ie_link));
  793. ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link));
  794. } else {
  795. //
  796. // Existing interface
  797. //
  798. CTEFreeMem(ientry);
  799. ientry = temp;
  800. temp = FindProtocolEntry(ientry, Protocol);
  801. if (temp == NULL) {
  802. //
  803. // New protocol
  804. //
  805. ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link));
  806. } else {
  807. //
  808. // Existing protocol
  809. //
  810. CTEFreeMem(pentry);
  811. }
  812. }
  813. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  814. //
  815. // At this point, the protocol entry is installed, but no values
  816. // are permitted. This is the safest default.
  817. //
  818. if (ConfigHandle != NULL) {
  819. //
  820. // Process the filter value list.
  821. //
  822. if (status == TDI_SUCCESS) {
  823. for (i = 0;
  824. EnumSecurityFilterValue(&filterList, i, &filterValue);
  825. i++
  826. ) {
  827. AddValueSecurityFilter(InterfaceAddress, Protocol,
  828. filterValue);
  829. }
  830. } else if (status == TDI_ITEM_NOT_FOUND) {
  831. //
  832. // No filter registered, permit everything.
  833. //
  834. AddValueSecurityFilter(InterfaceAddress, Protocol, 0);
  835. }
  836. }
  837. if (filterList.Buffer != NULL) {
  838. CTEFreeMem(filterList.Buffer);
  839. }
  840. return;
  841. }
  842. //* DeleteProtocolSecurityFilter
  843. //
  844. // This routine disables security filtering for a specified protocol
  845. // on a specified IP interface.
  846. //
  847. // Entry: InterfaceAddress - The interface on which to disable the protocol.
  848. // (in network byte order)
  849. // Protocol - The protocol to disable.
  850. //
  851. // Returns: Nothing
  852. //
  853. void
  854. DeleteProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol)
  855. {
  856. PINTERFACE_ENTRY ientry;
  857. PPROTOCOL_ENTRY pentry;
  858. CTELockHandle handle;
  859. BOOLEAN deleteInterface = FALSE;
  860. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  861. ientry = FindInterfaceEntry(InterfaceAddress);
  862. if (ientry != NULL) {
  863. ASSERT(!EMPTYQ(&(ientry->ie_protocol_list)));
  864. pentry = FindProtocolEntry(ientry, Protocol);
  865. if (pentry != NULL) {
  866. REMOVEQ(&(pentry->pe_link));
  867. }
  868. if (EMPTYQ(&(ientry->ie_protocol_list))) {
  869. //
  870. // Last protocol, delete interface as well.
  871. //
  872. REMOVEQ(&(ientry->ie_link));
  873. deleteInterface = TRUE;
  874. }
  875. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  876. if (pentry != NULL) {
  877. DeleteProtocolValueEntries(pentry);
  878. CTEFreeMem(pentry);
  879. }
  880. if (deleteInterface) {
  881. ASSERT(EMPTYQ(&(ientry->ie_protocol_list)));
  882. CTEFreeMem(ientry);
  883. }
  884. } else {
  885. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  886. }
  887. return;
  888. }
  889. //* AddValueSecurityFilter - Add an entry.
  890. //
  891. // This routine adds a value entry for a specified protocol on a specified
  892. // interface in the security filter database.
  893. //
  894. //
  895. // Input: InterfaceAddress - The interface address to which to add.
  896. // (in network byte order)
  897. // Protocol - The protocol to which to add.
  898. // FilterValue - The transport value to add.
  899. // (in host byte order)
  900. //
  901. // Returns: A TDI status code:
  902. // TDI_INVALID_PARAMETER if the protocol is not in the database.
  903. // TDI_ADDR_INVALID if the interface is not in the database.
  904. // TDI_NO_RESOURCES if memory could not be allocated.
  905. // TDI_SUCCESS otherwise
  906. //
  907. // NOTES:
  908. //
  909. // This routine acquires AddrObjTableLock.
  910. //
  911. // Zero is a wildcard value. Supplying a zero value for the
  912. // InterfaceAddress and/or Protocol causes the operation to be applied
  913. // to all interfaces and/or protocols, as appropriate. Supplying a
  914. // non-zero value causes the operation to be applied to only the
  915. // specified interface and/or protocol. Supplying a FilterValue parameter
  916. // of zero causes all values to be acceptable. Any previously
  917. // registered values are deleted from the database.
  918. //
  919. TDI_STATUS
  920. AddValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol, ulong FilterValue)
  921. {
  922. CTELockHandle handle;
  923. TDI_STATUS status;
  924. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  925. status = ModifySecurityFilter(ADD_VALUE_SECURITY_FILTER, InterfaceAddress,
  926. Protocol, FilterValue);
  927. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  928. return (status);
  929. }
  930. //* DeleteValueSecurityFilter - Delete an entry.
  931. //
  932. // This routine deletes a value entry for a specified protocol on a specified
  933. // interface in the security filter database.
  934. //
  935. //
  936. // Input: InterfaceAddress - The interface address from which to delete.
  937. // (in network byte order)
  938. // Protocol - The protocol from which to delete.
  939. // FilterValue - The transport value to delete.
  940. // (in host byte order)
  941. //
  942. // Returns: A TDI status code:
  943. // TDI_INVALID_PARAMETER if the protocol is not in the database.
  944. // TDI_ADDR_INVALID if the interface is not in the database.
  945. // TDI_NO_RESOURCES if memory could not be allocated.
  946. // TDI_SUCCESS otherwise
  947. //
  948. // NOTES:
  949. //
  950. // This routine acquires AddrObjTableLock.
  951. //
  952. // Zero is a wildcard value. Supplying a zero value for the
  953. // InterfaceAddress and/or Protocol causes the operation to be applied
  954. // to all interfaces and/or protocols, as appropriate. Supplying a
  955. // non-zero value causes the operation to be applied to only the
  956. // specified interface and/or protocol. Supplying a FilterValue parameter
  957. // of zero causes all values to be rejected. Any previously
  958. // registered values are deleted from the database.
  959. //
  960. TDI_STATUS
  961. DeleteValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
  962. ulong FilterValue)
  963. {
  964. CTELockHandle handle;
  965. TDI_STATUS status;
  966. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  967. status = ModifySecurityFilter(DELETE_VALUE_SECURITY_FILTER,
  968. InterfaceAddress, Protocol, FilterValue);
  969. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  970. return (status);
  971. }
  972. //* EnumerateSecurityFilters - Enumerate security filter database.
  973. //
  974. // This routine enumerates the contents of the security filter database
  975. // for the specified protocol and IP interface.
  976. //
  977. // Input: InterfaceAddress - The interface address to enumerate. A value
  978. // of zero means enumerate all interfaces.
  979. // (in network byte order)
  980. //
  981. // Protocol - The protocol to enumerate. A value of zero
  982. // means enumerate all protocols.
  983. //
  984. // Value - The Protocol value to enumerate. A value of
  985. // zero means enumerate all protocol values.
  986. // (in host byte order)
  987. //
  988. // Buffer - A pointer to a buffer into which to put
  989. // the returned filter entries.
  990. //
  991. // BufferSize - On input, the size in bytes of Buffer.
  992. // On output, the number of bytes written.
  993. //
  994. // EntriesAvailable - On output, the total number of filter entries
  995. // available in the database.
  996. //
  997. // Returns: A TDI status code:
  998. //
  999. // TDI_ADDR_INVALID if the address is not a valid IP interface.
  1000. // TDI_SUCCESS otherwise.
  1001. //
  1002. // NOTES:
  1003. //
  1004. // This routine acquires AddrObjTableLock.
  1005. //
  1006. // Entries written to output buffer are in host byte order.
  1007. //
  1008. void
  1009. EnumerateSecurityFilters(IPAddr InterfaceAddress, ulong Protocol,
  1010. ulong Value, uchar * Buffer, ulong BufferSize,
  1011. ulong * EntriesReturned, ulong * EntriesAvailable)
  1012. {
  1013. PINTERFACE_ENTRY ientry;
  1014. TDI_STATUS status = TDI_SUCCESS;
  1015. CTELockHandle handle;
  1016. *EntriesAvailable = *EntriesReturned = 0;
  1017. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  1018. if (InterfaceAddress == 0) {
  1019. struct Queue *qentry;
  1020. //
  1021. // Enumerate all interfaces.
  1022. //
  1023. for (qentry = InterfaceEntryList.q_next;
  1024. qentry != &InterfaceEntryList;
  1025. qentry = qentry->q_next
  1026. ) {
  1027. ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
  1028. EnumerateInterfaceProtocols(
  1029. ientry,
  1030. Protocol,
  1031. Value,
  1032. &Buffer,
  1033. &BufferSize,
  1034. EntriesReturned,
  1035. EntriesAvailable
  1036. );
  1037. }
  1038. } else {
  1039. //
  1040. // Enumerate a specific interface.
  1041. //
  1042. ientry = FindInterfaceEntry(InterfaceAddress);
  1043. if (ientry != NULL) {
  1044. EnumerateInterfaceProtocols(
  1045. ientry,
  1046. Protocol,
  1047. Value,
  1048. &Buffer,
  1049. &BufferSize,
  1050. EntriesReturned,
  1051. EntriesAvailable
  1052. );
  1053. }
  1054. }
  1055. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  1056. return;
  1057. }
  1058. //* IsPermittedSecurityFilter
  1059. //
  1060. // This routine determines if communications addressed to
  1061. // {Protocol, InterfaceAddress, Value} are permitted by the security filters.
  1062. // It looks up the tuple in the security filter database.
  1063. //
  1064. // Input: InterfaceAddress - The IP interface address to check
  1065. // (in network byte order)
  1066. // IPContext - The IPContext value passed to the transport
  1067. // Protocol - The protocol to check
  1068. // Value - The value to check (in host byte order)
  1069. //
  1070. // Returns: A boolean indicating whether or not the communication is permitted.
  1071. //
  1072. // NOTES:
  1073. //
  1074. // This routine must be called with AddrObjTableLock held.
  1075. //
  1076. //
  1077. BOOLEAN
  1078. IsPermittedSecurityFilter(IPAddr InterfaceAddress, void *IPContext,
  1079. ulong Protocol, ulong FilterValue)
  1080. {
  1081. PINTERFACE_ENTRY ientry;
  1082. PPROTOCOL_ENTRY pentry;
  1083. PVALUE_ENTRY ventry;
  1084. ulong hash_value;
  1085. struct Queue *qentry;
  1086. ASSERT(Protocol <= 0xFF);
  1087. for (qentry = InterfaceEntryList.q_next;
  1088. qentry != &InterfaceEntryList;
  1089. qentry = qentry->q_next
  1090. ) {
  1091. ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
  1092. if (ientry->ie_address == InterfaceAddress) {
  1093. for (qentry = ientry->ie_protocol_list.q_next;
  1094. qentry != &(ientry->ie_protocol_list);
  1095. qentry = qentry->q_next
  1096. ) {
  1097. pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
  1098. if (pentry->pe_protocol == Protocol) {
  1099. if (pentry->pe_accept_all == TRUE) {
  1100. //
  1101. // All values accepted. Permit operation.
  1102. //
  1103. return (TRUE);
  1104. }
  1105. hash_value = VALUE_ENTRY_HASH(FilterValue);
  1106. for (qentry = pentry->pe_entries[hash_value].q_next;
  1107. qentry != &(pentry->pe_entries[hash_value]);
  1108. qentry = qentry->q_next
  1109. ) {
  1110. ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
  1111. if (ventry->ve_value == FilterValue) {
  1112. //
  1113. // Found it. Operation is permitted.
  1114. //
  1115. return (TRUE);
  1116. }
  1117. }
  1118. //
  1119. // {Interface, Protocol} protected, but no value found.
  1120. // Reject operation.
  1121. //
  1122. return (FALSE);
  1123. }
  1124. }
  1125. //
  1126. // Protocol not registered. Reject operation
  1127. //
  1128. return (FALSE);
  1129. }
  1130. }
  1131. //
  1132. // If this packet is on the loopback interface, let it through.
  1133. //
  1134. if (IP_LOOPBACK_ADDR(InterfaceAddress)) {
  1135. return (TRUE);
  1136. }
  1137. //
  1138. // Special check to allow the DHCP client to receive its packets.
  1139. // It is safe to make this check all the time because IP will
  1140. // not permit a packet to get through on an NTE with a zero address
  1141. // unless DHCP is in the process of configuring that NTE.
  1142. //
  1143. if ((Protocol == PROTOCOL_UDP) &&
  1144. (FilterValue == DHCP_CLIENT_PORT) &&
  1145. (*LocalNetInfo.ipi_isdhcpinterface) (IPContext)
  1146. ) {
  1147. return (TRUE);
  1148. }
  1149. //
  1150. // Interface not registered. Deny operation.
  1151. //
  1152. return (FALSE);
  1153. }