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.

1314 lines
39 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. PVALUE_ENTRY ventry;
  506. ulong i;
  507. if (Value == 0) {
  508. //
  509. // Enumerate all values
  510. //
  511. if (ProtocolEntry->pe_accept_all == TRUE) {
  512. //
  513. // All values permitted.
  514. //
  515. FillInEnumerationEntry(
  516. InterfaceEntry->ie_address,
  517. ProtocolEntry->pe_protocol,
  518. 0,
  519. Buffer,
  520. BufferSize,
  521. EntriesReturned,
  522. EntriesAvailable
  523. );
  524. } else {
  525. for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) {
  526. for (qentry = ProtocolEntry->pe_entries[i].q_next;
  527. qentry != &(ProtocolEntry->pe_entries[i]);
  528. qentry = qentry->q_next
  529. ) {
  530. ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
  531. FillInEnumerationEntry(
  532. InterfaceEntry->ie_address,
  533. ProtocolEntry->pe_protocol,
  534. ventry->ve_value,
  535. Buffer,
  536. BufferSize,
  537. EntriesReturned,
  538. EntriesAvailable
  539. );
  540. }
  541. }
  542. }
  543. } else {
  544. //
  545. // Enumerate a specific value, if it is registered.
  546. //
  547. ventry = FindValueEntry(ProtocolEntry, Value);
  548. if (ventry != NULL) {
  549. FillInEnumerationEntry(
  550. InterfaceEntry->ie_address,
  551. ProtocolEntry->pe_protocol,
  552. ventry->ve_value,
  553. Buffer,
  554. BufferSize,
  555. EntriesReturned,
  556. EntriesAvailable
  557. );
  558. }
  559. }
  560. return;
  561. }
  562. //* EnumerateInterfaceProtocols
  563. //
  564. // This utility routine enumerates protocols associated with
  565. // an interface.
  566. //
  567. //
  568. // Input: InterfaceEntry - Pointer to the associated interface entry.
  569. //
  570. // Protocol - Protocol number to enumerate.
  571. //
  572. // Value - The filter value to enumerate.
  573. //
  574. // Buffer - Pointer to the user's enumeration buffer.
  575. //
  576. // BufferSize - Pointer to the size of the enumeration buffer.
  577. //
  578. // EntriesReturned - Pointer to a running count of enumerated
  579. // entries stored in Buffer.
  580. //
  581. // EntriesAvailable - Pointer to a running count of entries available
  582. // for enumeration.
  583. //
  584. // Returns: Nothing.
  585. //
  586. void
  587. EnumerateInterfaceProtocols(PINTERFACE_ENTRY InterfaceEntry, ulong Protocol,
  588. ulong Value, uchar ** Buffer, ulong * BufferSize,
  589. ulong * EntriesReturned, ulong * EntriesAvailable)
  590. {
  591. PPROTOCOL_ENTRY pentry;
  592. if (Protocol == 0) {
  593. struct Queue *qentry;
  594. //
  595. // Enumerate all protocols.
  596. //
  597. for (qentry = InterfaceEntry->ie_protocol_list.q_next;
  598. qentry != &(InterfaceEntry->ie_protocol_list);
  599. qentry = qentry->q_next
  600. ) {
  601. pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
  602. EnumerateProtocolValues(
  603. InterfaceEntry,
  604. pentry,
  605. Value,
  606. Buffer,
  607. BufferSize,
  608. EntriesReturned,
  609. EntriesAvailable
  610. );
  611. }
  612. } else {
  613. //
  614. // Enumerate a specific protocol
  615. //
  616. pentry = FindProtocolEntry(InterfaceEntry, Protocol);
  617. if (pentry != NULL) {
  618. EnumerateProtocolValues(
  619. InterfaceEntry,
  620. pentry,
  621. Value,
  622. Buffer,
  623. BufferSize,
  624. EntriesReturned,
  625. EntriesAvailable
  626. );
  627. }
  628. }
  629. return;
  630. }
  631. //
  632. // Filter Database Public API.
  633. //
  634. //* InitializeSecurityFilters - Initializes the security filter database.
  635. //
  636. // The routine performs the initialization necessary to enable the
  637. // security filter database for operation.
  638. //
  639. // Input: None.
  640. //
  641. // Returns: Nothing.
  642. //
  643. //
  644. void
  645. InitializeSecurityFilters(void)
  646. {
  647. INITQ(&InterfaceEntryList);
  648. return;
  649. }
  650. //* CleanupSecurityFilters - Deletes the entire security filter database.
  651. //
  652. // This routine deletes all entries from the security filter database.
  653. //
  654. //
  655. // Input: None.
  656. //
  657. // Returns: Nothing.
  658. //
  659. // NOTE: This routine acquires the AddrObjTableLock.
  660. //
  661. //
  662. void
  663. CleanupSecurityFilters(void)
  664. {
  665. PPROTOCOL_ENTRY pentry;
  666. PINTERFACE_ENTRY ientry;
  667. CTELockHandle handle;
  668. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  669. while (!EMPTYQ(&InterfaceEntryList)) {
  670. DEQUEUE(&InterfaceEntryList, ientry, INTERFACE_ENTRY, ie_link);
  671. while (!EMPTYQ(&(ientry->ie_protocol_list))) {
  672. DEQUEUE(&(ientry->ie_protocol_list), pentry, PROTOCOL_ENTRY,
  673. pe_link);
  674. DeleteProtocolValueEntries(pentry);
  675. CTEFreeMem(pentry);
  676. }
  677. CTEFreeMem(ientry);
  678. }
  679. SecurityFilteringEnabled = FALSE;
  680. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  681. return;
  682. }
  683. //* IsSecurityFilteringEnabled
  684. //
  685. // This routine returns the current global status of security filtering.
  686. //
  687. // Entry: Nothing
  688. //
  689. // Returns: 0 if filtering is disabled, !0 if filtering is enabled.
  690. //
  691. extern uint
  692. IsSecurityFilteringEnabled(void)
  693. {
  694. uint enabled;
  695. CTELockHandle handle;
  696. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  697. enabled = SecurityFilteringEnabled;
  698. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  699. return (enabled);
  700. }
  701. //* ControlSecurityFiltering
  702. //
  703. // This routine globally enables/disables security filtering.
  704. //
  705. // Entry: IsEnabled - 0 disabled filtering, !0 enables filtering.
  706. //
  707. // Returns: Nothing
  708. //
  709. extern void
  710. ControlSecurityFiltering(uint IsEnabled)
  711. {
  712. CTELockHandle handle;
  713. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  714. if (IsEnabled) {
  715. SecurityFilteringEnabled = TRUE;
  716. } else {
  717. SecurityFilteringEnabled = FALSE;
  718. }
  719. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  720. return;
  721. }
  722. //* AddProtocolSecurityFilter
  723. //
  724. // This routine enables security filtering for a specified protocol
  725. // on a specified IP interface.
  726. //
  727. // Entry: InterfaceAddress - The interface on which to enable the protocol.
  728. // (in network byte order)
  729. // Protocol - The protocol to enable.
  730. // ConfigName - The configuration key from which to read
  731. // the filter value information.
  732. //
  733. // Returns: Nothing
  734. //
  735. void
  736. AddProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
  737. NDIS_HANDLE ConfigHandle)
  738. {
  739. NDIS_STRING filterList;
  740. ulong filterValue;
  741. ulong i;
  742. PINTERFACE_ENTRY ientry;
  743. PPROTOCOL_ENTRY pentry;
  744. PVOID temp;
  745. CTELockHandle handle;
  746. TDI_STATUS status = 0;
  747. if (IP_ADDR_EQUAL(InterfaceAddress, NULL_IP_ADDR) ||
  748. IP_LOOPBACK_ADDR(InterfaceAddress)
  749. ) {
  750. return;
  751. }
  752. ASSERT((Protocol != 0) && (Protocol <= 0xFF));
  753. //
  754. // Read the protocol-specific filter value list from the registry.
  755. //
  756. filterList.MaximumLength = filterList.Length = 0;
  757. filterList.Buffer = NULL;
  758. if (ConfigHandle != NULL) {
  759. status = GetSecurityFilterList(ConfigHandle, Protocol, &filterList);
  760. }
  761. //
  762. // Preallocate interface & protocol structures. We abort on failure.
  763. // The interface & protocol will be protected by default.
  764. //
  765. ientry = CTEAllocMem(sizeof(INTERFACE_ENTRY));
  766. if (ientry == NULL) {
  767. goto cleanup;
  768. }
  769. ientry->ie_address = InterfaceAddress;
  770. INITQ(&(ientry->ie_protocol_list));
  771. pentry = CTEAllocMem(sizeof(PROTOCOL_ENTRY));
  772. if (pentry == NULL) {
  773. CTEFreeMem(ientry);
  774. goto cleanup;
  775. }
  776. pentry->pe_protocol = Protocol;
  777. pentry->pe_accept_all = FALSE;
  778. for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) {
  779. INITQ(&(pentry->pe_entries[i]));
  780. }
  781. //
  782. // Now go set everything up. First create the interface and protocol
  783. // structures.
  784. //
  785. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  786. temp = FindInterfaceEntry(InterfaceAddress);
  787. if (temp == NULL) {
  788. //
  789. // New interface & protocol.
  790. //
  791. ENQUEUE(&InterfaceEntryList, &(ientry->ie_link));
  792. ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link));
  793. } else {
  794. //
  795. // Existing interface
  796. //
  797. CTEFreeMem(ientry);
  798. ientry = temp;
  799. temp = FindProtocolEntry(ientry, Protocol);
  800. if (temp == NULL) {
  801. //
  802. // New protocol
  803. //
  804. ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link));
  805. } else {
  806. //
  807. // Existing protocol
  808. //
  809. CTEFreeMem(pentry);
  810. }
  811. }
  812. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  813. //
  814. // At this point, the protocol entry is installed, but no values
  815. // are permitted. This is the safest default.
  816. //
  817. if (ConfigHandle != NULL) {
  818. //
  819. // Process the filter value list.
  820. //
  821. if (status == TDI_SUCCESS) {
  822. for (i = 0;
  823. EnumSecurityFilterValue(&filterList, i, &filterValue);
  824. i++
  825. ) {
  826. AddValueSecurityFilter(InterfaceAddress, Protocol,
  827. filterValue);
  828. }
  829. } else if (status == TDI_ITEM_NOT_FOUND) {
  830. //
  831. // No filter registered, permit everything.
  832. //
  833. AddValueSecurityFilter(InterfaceAddress, Protocol, 0);
  834. }
  835. }
  836. cleanup:
  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. CTELockHandle handle;
  1015. *EntriesAvailable = *EntriesReturned = 0;
  1016. CTEGetLock(&AddrObjTableLock.Lock, &handle);
  1017. if (InterfaceAddress == 0) {
  1018. struct Queue *qentry;
  1019. //
  1020. // Enumerate all interfaces.
  1021. //
  1022. for (qentry = InterfaceEntryList.q_next;
  1023. qentry != &InterfaceEntryList;
  1024. qentry = qentry->q_next
  1025. ) {
  1026. ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
  1027. EnumerateInterfaceProtocols(
  1028. ientry,
  1029. Protocol,
  1030. Value,
  1031. &Buffer,
  1032. &BufferSize,
  1033. EntriesReturned,
  1034. EntriesAvailable
  1035. );
  1036. }
  1037. } else {
  1038. //
  1039. // Enumerate a specific interface.
  1040. //
  1041. ientry = FindInterfaceEntry(InterfaceAddress);
  1042. if (ientry != NULL) {
  1043. EnumerateInterfaceProtocols(
  1044. ientry,
  1045. Protocol,
  1046. Value,
  1047. &Buffer,
  1048. &BufferSize,
  1049. EntriesReturned,
  1050. EntriesAvailable
  1051. );
  1052. }
  1053. }
  1054. CTEFreeLock(&AddrObjTableLock.Lock, handle);
  1055. return;
  1056. }
  1057. //* IsPermittedSecurityFilter
  1058. //
  1059. // This routine determines if communications addressed to
  1060. // {Protocol, InterfaceAddress, Value} are permitted by the security filters.
  1061. // It looks up the tuple in the security filter database.
  1062. //
  1063. // Input: InterfaceAddress - The IP interface address to check
  1064. // (in network byte order)
  1065. // IPContext - The IPContext value passed to the transport
  1066. // Protocol - The protocol to check
  1067. // Value - The value to check (in host byte order)
  1068. //
  1069. // Returns: A boolean indicating whether or not the communication is permitted.
  1070. //
  1071. // NOTES:
  1072. //
  1073. // This routine must be called with AddrObjTableLock held.
  1074. //
  1075. //
  1076. BOOLEAN
  1077. IsPermittedSecurityFilter(IPAddr InterfaceAddress, void *IPContext,
  1078. ulong Protocol, ulong FilterValue)
  1079. {
  1080. PINTERFACE_ENTRY ientry;
  1081. PPROTOCOL_ENTRY pentry;
  1082. PVALUE_ENTRY ventry;
  1083. ulong hash_value;
  1084. struct Queue *qentry;
  1085. ASSERT(Protocol <= 0xFF);
  1086. for (qentry = InterfaceEntryList.q_next;
  1087. qentry != &InterfaceEntryList;
  1088. qentry = qentry->q_next
  1089. ) {
  1090. ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
  1091. if (ientry->ie_address == InterfaceAddress) {
  1092. for (qentry = ientry->ie_protocol_list.q_next;
  1093. qentry != &(ientry->ie_protocol_list);
  1094. qentry = qentry->q_next
  1095. ) {
  1096. pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
  1097. if (pentry->pe_protocol == Protocol) {
  1098. if (pentry->pe_accept_all == TRUE) {
  1099. //
  1100. // All values accepted. Permit operation.
  1101. //
  1102. return (TRUE);
  1103. }
  1104. hash_value = VALUE_ENTRY_HASH(FilterValue);
  1105. for (qentry = pentry->pe_entries[hash_value].q_next;
  1106. qentry != &(pentry->pe_entries[hash_value]);
  1107. qentry = qentry->q_next
  1108. ) {
  1109. ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
  1110. if (ventry->ve_value == FilterValue) {
  1111. //
  1112. // Found it. Operation is permitted.
  1113. //
  1114. return (TRUE);
  1115. }
  1116. }
  1117. //
  1118. // {Interface, Protocol} protected, but no value found.
  1119. // Reject operation.
  1120. //
  1121. return (FALSE);
  1122. }
  1123. }
  1124. //
  1125. // Protocol not registered. Reject operation
  1126. //
  1127. return (FALSE);
  1128. }
  1129. }
  1130. //
  1131. // If this packet is on the loopback interface, let it through.
  1132. //
  1133. if (IP_LOOPBACK_ADDR(InterfaceAddress)) {
  1134. return (TRUE);
  1135. }
  1136. //
  1137. // Special check to allow the DHCP client to receive its packets.
  1138. // It is safe to make this check all the time because IP will
  1139. // not permit a packet to get through on an NTE with a zero address
  1140. // unless DHCP is in the process of configuring that NTE.
  1141. //
  1142. if ((Protocol == PROTOCOL_UDP) &&
  1143. (FilterValue == DHCP_CLIENT_PORT) &&
  1144. (*LocalNetInfo.ipi_isdhcpinterface) (IPContext)
  1145. ) {
  1146. return (TRUE);
  1147. }
  1148. //
  1149. // Interface not registered. Deny operation.
  1150. //
  1151. return (FALSE);
  1152. }