windows-nt/Source/XPSP1/NT/net/tcpip/driver/tcp/ntinit.c

2951 lines
82 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
ntinit.c
Abstract:
NT specific routines for loading and configuring the TCP/UDP driver.
Author:
Mike Massa (mikemas) Aug 13, 1993
Revision History:
Who When What
-------- -------- ----------------------------------------------
mikemas 08-13-93 created
Notes:
--*/
#include "precomp.h"
#if !MILLEN
#include <ipfilter.h>
#include <ipsec.h>
#endif // !MILLEN
#include "tdint.h"
#include "addr.h"
#include "tcp.h"
#include "tcb.h"
#include "udp.h"
#include "raw.h"
#include "tcpconn.h"
#include "mdlpool.h"
#include "pplasl.h"
#include "tcprcv.h"
#include "tcpsend.h"
#include "tlcommon.h"
#include "tcpcfg.h"
#include "secfltr.h"
#if GPC
#include <qos.h>
#include <traffic.h>
#include "gpcifc.h"
#include "ntddtc.h"
GPC_HANDLE hGpcClient[GPC_CF_MAX] = {0};
ulong GpcCfCounts[GPC_CF_MAX] = {0};
GPC_EXPORTED_CALLS GpcEntries;
GPC_CLIENT_FUNC_LIST GpcHandlers;
ulong GPCcfInfo = 0;
ulong ServiceTypeOffset = FIELD_OFFSET(CF_INFO_QOS, ToSValue);
GPC_STATUS GPCcfInfoAddNotifyIpsec(GPC_CLIENT_HANDLE ClCtxt,
GPC_HANDLE GpcHandle,
ULONG CfInfoSize,
PVOID CfInfo,
PGPC_CLIENT_HANDLE pClInfoCxt);
GPC_STATUS GPCcfInfoRemoveNotifyIpsec(GPC_CLIENT_HANDLE ClCtxt,
GPC_CLIENT_HANDLE ClInfoCxt);
GPC_STATUS GPCcfInfoAddNotifyQoS(GPC_CLIENT_HANDLE ClCtxt,
GPC_HANDLE GpcHandle,
ULONG CfInfoSize,
PVOID CfInfo,
PGPC_CLIENT_HANDLE pClInfoCxt);
GPC_STATUS GPCcfInfoRemoveNotifyQoS(GPC_CLIENT_HANDLE ClCtxt,
GPC_CLIENT_HANDLE ClInfoCxt);
#endif
ReservedPortListEntry *PortRangeList = NULL;
VOID
GetReservedPortList(
NDIS_HANDLE ConfigHandle
);
//
// Global variables.
//
PDRIVER_OBJECT TCPDriverObject = NULL;
PDEVICE_OBJECT TCPDeviceObject = NULL;
PDEVICE_OBJECT UDPDeviceObject = NULL;
PDEVICE_OBJECT RawIPDeviceObject = NULL;
extern PDEVICE_OBJECT IPDeviceObject;
TCPXSUM_ROUTINE tcpxsum_routine = tcpxsum;
#if ACC
PSECURITY_DESCRIPTOR TcpAdminSecurityDescriptor;
extern uint AllowUserRawAccess;
typedef ULONG SECURITY_INFORMATION;
BOOLEAN
IsRunningOnPersonal (
VOID
);
#endif
extern uint DisableLargeSendOffload;
//
//Place holder for Maximum duplicate acks we would like
//to see before we do fast retransmit
//
extern uint MaxDupAcks;
MM_SYSTEMSIZE systemSize;
extern uint MaxHashTableSize;
extern uint NumTcbTablePartitions;
extern uint PerPartitionSize;
extern uint LogPerPartitionSize;
#define CACHE_LINE_SIZE 64
#define CACHE_ALIGN_MASK (~(CACHE_LINE_SIZE-1))
CTELock *pTWTCBTableLock;
CTELock *pTCBTableLock;
CTELock *pSynTCBTableLock;
extern Queue *TWQueue;
extern Queue *TWTCBTable;
extern TCB **TCBTable;
extern Queue *SYNTCBTable;
extern PTIMER_WHEEL TimerWheel;
PTIMER_WHEEL OrgTimerWheel;
extern TCPConn **ConnTable;
extern uint MaxConnBlocks;
extern uint ConnPerBlock;
extern uint GlobalMaxRcvWin;
extern uint TcpHostOpts;
extern uint TcpHostSendOpts;
extern uint MaxRcvWin;
HANDLE TCPRegistrationHandle;
HANDLE UDPRegistrationHandle;
HANDLE IPRegistrationHandle;
//SynAttackProtect=0 no syn flood attack protection
//SynAttackProtect !0 syn flood attack protection
//SynAttackProtect !0 syn flood attack protection+forced(non-dynamic)
// delayed connect acceptance
uint SynAttackProtect; //syn-att protection checks
// are made
uint TCPPortsExhausted; //# of ports exhausted
uint TCPMaxPortsExhausted; //Max # of ports that must be exhausted
// for syn-att protection to kick in
uint TCPMaxPortsExhaustedLW; //Low-watermark of # of ports exhausted
//When reached, we revert to normal
// count for syn-ack retries
uint TCPMaxHalfOpen; //Max # of half-open connections allowed
// before we dec. the syn-ack retries
uint TCPMaxHalfOpenRetried; //Max # of half-open conn. that have
// been retried at least 1 time
uint TCPMaxHalfOpenRetriedLW; //Low-watermark of the above. When
// go down to it, we revert to normal
// # of retries for syn-acks
uint TCPHalfOpen; //# of half-open connections
uint TCPHalfOpenRetried; //# of half-open conn. that have been
//retried at least once
PDEVICE_OBJECT IPSECDeviceObject;
PFILE_OBJECT IPSECFileObject;
extern uint Time_Proc;
extern HANDLE TcbPool;
extern HANDLE TimewaitTcbPool;
extern HANDLE SynTcbPool;
extern void ArpUnload(PDRIVER_OBJECT);
extern CTETimer TCBTimer[];
extern BOOLEAN fTCBTimerStopping;
extern CTEBlockStruc TcpipUnloadBlock;
HANDLE AddressChangeHandle;
extern ulong DefaultTOSValue;
extern ulong DisableUserTOSSetting;
extern uint MaxSendSegments;
//
// External function prototypes
//
int
tlinit(
void
);
NTSTATUS
TCPDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
TCPDispatchInternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
IPDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
IPDriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
IPPostDriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
GetRegMultiSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData
);
PWCHAR
EnumRegMultiSz(
IN PWCHAR MszString,
IN ULONG MszStringLength,
IN ULONG StringIndex
);
uint InitIsnGenerator();
#if !MILLEN
extern ulong g_cRandIsnStore;
#endif // !MILLEN
#if MILLEN
extern VOID InitializeWDebDebug();
#endif // MILLEN
//
// Local funcion prototypes
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
void *
TLRegisterProtocol(
uchar Protocol,
void *RcvHandler,
void *XmitHandler,
void *StatusHandler,
void *RcvCmpltHandler,
void *PnPHandler,
void *ElistHandler
);
IP_STATUS
TLGetIPInfo(
IPInfo * Buffer,
int Size
);
uchar
TCPGetConfigInfo(
void
);
NTSTATUS
TCPInitializeParameter(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG Value
);
#if !MILLEN
NTSTATUS
IpsecInitialize(
void
);
NTSTATUS
IpsecDeinitialize(
void
);
#endif
#if !MILLEN
#ifdef i386
NTSTATUS
TCPSetChecksumRoutine(
VOID
);
#endif
#endif // !MILLEN
uint
EnumSecurityFilterValue(
PNDIS_STRING FilterList,
ulong Index,
ulong * FilterValue
);
VOID
TCPAcdBind();
#ifdef ACC
typedef ULONG SECURITY_INFORMATION;
NTSTATUS
TcpBuildDeviceAcl(
OUT PACL * DeviceAcl
);
NTSTATUS
TcpCreateAdminSecurityDescriptor(
VOID
);
NTSTATUS
AddNetConfigOpsAce(IN PACL Dacl,
OUT PACL * DeviceAcl
);
NTSTATUS
CreateDeviceDriverSecurityDescriptor(PVOID DeviceOrDriverObject
);
#endif // ACC
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(INIT, TLRegisterProtocol)
#pragma alloc_text(INIT, TLGetIPInfo)
#pragma alloc_text(INIT, TCPGetConfigInfo)
#pragma alloc_text(INIT, TCPInitializeParameter)
#if !MILLEN
#pragma alloc_text(INIT, IpsecInitialize)
#endif
#if !MILLEN
#ifdef i386
#pragma alloc_text(INIT, TCPSetChecksumRoutine)
#endif
#endif // !MILLEN
#pragma alloc_text(PAGE, EnumSecurityFilterValue)
#pragma alloc_text(INIT, TCPAcdBind)
#ifdef ACC
#pragma alloc_text(INIT, TcpBuildDeviceAcl)
#pragma alloc_text(INIT, TcpCreateAdminSecurityDescriptor)
#pragma alloc_text(INIT, AddNetConfigOpsAce)
#pragma alloc_text(INIT, CreateDeviceDriverSecurityDescriptor)
#endif // ACC
#endif
//
// Function definitions
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Initialization routine for the TCP/UDP driver.
Arguments:
DriverObject - Pointer to the TCP driver object created by the system.
DeviceDescription - The name of TCP's node in the registry.
Return Value:
The final status from the initialization operation.
--*/
{
NTSTATUS status;
UNICODE_STRING deviceName;
UNICODE_STRING SymbolicDeviceName;
USHORT i;
int initStatus;
DEBUGMSGINIT();
DEBUGMSG(DBG_TRACE && DBG_INIT,
(DTEXT("+DriverEntry(%x, %x)\n"), DriverObject, RegistryPath));
TdiInitialize();
//
// IP calls the security filter code, so initialize it first.
//
InitializeSecurityFilters();
//
// Initialize IP
//
status = IPDriverEntry(DriverObject, RegistryPath);
if (!NT_SUCCESS(status)) {
DEBUGMSG(DBG_ERROR && DBG_INIT,
(DTEXT("TCPIP: IP Initialization failure %x\n"), status));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-DriverEntry [%x]\n"), status));
return (status);
}
#if !MILLEN
//
// Initialize IPSEC
//
status = IpsecInitialize();
if (!NT_SUCCESS(status)) {
DEBUGMSG(DBG_ERROR && DBG_INIT,
(DTEXT("TCPIP: IPSEC Initialization failure %x\n"), status));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-DriverEntry [%x]\n"), status));
goto init_failed;
}
#endif
//
// Initialize TCP, UDP, and RawIP
//
TCPDriverObject = DriverObject;
//
// Create the device objects. IoCreateDevice zeroes the memory
// occupied by the object.
//
RtlInitUnicodeString(&deviceName, DD_TCP_DEVICE_NAME);
RtlInitUnicodeString(&SymbolicDeviceName, DD_TCP_SYMBOLIC_DEVICE_NAME);
status = IoCreateDevice(
DriverObject,
0,
&deviceName,
FILE_DEVICE_NETWORK,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&TCPDeviceObject
);
if (!NT_SUCCESS(status)) {
CTELogEvent(
DriverObject,
EVENT_TCPIP_CREATE_DEVICE_FAILED,
1,
1,
&deviceName.Buffer,
0,
NULL
);
DEBUGMSG(DBG_ERROR && DBG_INIT,
(DTEXT("DriverEntry: failure %x to create TCP device object %ws\n"),
status, DD_TCP_DEVICE_NAME));
goto init_failed;
}
status = IoCreateSymbolicLink(&SymbolicDeviceName, &deviceName);
if (!NT_SUCCESS(status)) {
CTELogEvent(
DriverObject,
EVENT_TCPIP_CREATE_DEVICE_FAILED,
1,
1,
&deviceName.Buffer,
0,
NULL
);
DEBUGMSG(DBG_ERROR && DBG_INIT,
(DTEXT("DriverEntry: failure %x to create TCP symbolic device link %ws\n"),
status, DD_TCP_SYMBOLIC_DEVICE_NAME));
goto init_failed;
}
RtlInitUnicodeString(&deviceName, DD_UDP_DEVICE_NAME);
status = IoCreateDevice(
DriverObject,
0,
&deviceName,
FILE_DEVICE_NETWORK,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&UDPDeviceObject
);
if (!NT_SUCCESS(status)) {
CTELogEvent(
DriverObject,
EVENT_TCPIP_CREATE_DEVICE_FAILED,
1,
1,
&deviceName.Buffer,
0,
NULL
);
TCPTRACE((
"TCP: Failed to create UDP device object, status %lx\n",
status
));
goto init_failed;
}
RtlInitUnicodeString(&deviceName, DD_RAW_IP_DEVICE_NAME);
status = IoCreateDevice(
DriverObject,
0,
&deviceName,
FILE_DEVICE_NETWORK,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&RawIPDeviceObject
);
if (!NT_SUCCESS(status)) {
CTELogEvent(
DriverObject,
EVENT_TCPIP_CREATE_DEVICE_FAILED,
1,
1,
&deviceName.Buffer,
0,
NULL
);
TCPTRACE((
"TCP: Failed to create Raw IP device object, status %lx\n",
status
));
goto init_failed;
}
//
// Initialize the driver object
//
DriverObject->DriverUnload = ArpUnload;
DriverObject->FastIoDispatch = NULL;
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = TCPDispatch;
}
//
// We special case Internal Device Controls because they are the
// hot path for kernel-mode clients.
//
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
TCPDispatchInternalDeviceControl;
//
// Intialize the device objects.
//
TCPDeviceObject->Flags |= DO_DIRECT_IO;
UDPDeviceObject->Flags |= DO_DIRECT_IO;
RawIPDeviceObject->Flags |= DO_DIRECT_IO;
#ifdef ACC
// Change the different devices and Objects to allow access to Network Configuration Operators
if (!IsRunningOnPersonal()) {
status = CreateDeviceDriverSecurityDescriptor(IPDeviceObject);
if (!NT_SUCCESS(status)) {
goto init_failed;
}
status = CreateDeviceDriverSecurityDescriptor(TCPDeviceObject);
if (!NT_SUCCESS(status)) {
goto init_failed;
}
status = CreateDeviceDriverSecurityDescriptor(IPSECDeviceObject);
if (!NT_SUCCESS(status)) {
goto init_failed;
}
}
//
// Create the security descriptor used for raw socket access checks.
//
status = TcpCreateAdminSecurityDescriptor();
if (!NT_SUCCESS(status)) {
goto init_failed;
}
#endif // ACC
#if !MILLEN
#ifdef i386
//
// Set the checksum routine pointer according to the processor available
//
TCPSetChecksumRoutine();
#endif
#endif // !MILLEN
//
// Finally, initialize the stack.
//
initStatus = tlinit();
if (initStatus == TRUE) {
//
// Get the automatic connection driver
// entry points.
//
TCPAcdBind();
RtlInitUnicodeString(&deviceName, DD_TCP_DEVICE_NAME);
(void)TdiRegisterDeviceObject(&deviceName, &TCPRegistrationHandle);
RtlInitUnicodeString(&deviceName, DD_UDP_DEVICE_NAME);
(void)TdiRegisterDeviceObject(&deviceName, &UDPRegistrationHandle);
RtlInitUnicodeString(&deviceName, DD_RAW_IP_DEVICE_NAME);
(void)TdiRegisterDeviceObject(&deviceName, &IPRegistrationHandle);
// do the ndis register protocol now after all the intialization
// is complete, o/w we get bindadapter even before we r fully
// initialized.
status = IPPostDriverEntry(DriverObject, RegistryPath);
if (!NT_SUCCESS(status)) {
DEBUGMSG(DBG_ERROR && DBG_INIT,
(DTEXT("TCPIP: IP post-init failure %x\n"), status));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-DriverEntry [%x]\n"), status));
return (status);
}
#if GPC
status = GpcInitialize(&GpcEntries);
if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"GpcInitialize Failed! Status: 0x%x\n", status));
//return status;
} else {
//
// Need to register as GPC client. Try it now.
// we register clients for QOS and IPSEC
//
memset(&GpcHandlers, 0, sizeof(GPC_CLIENT_FUNC_LIST));
GpcHandlers.ClAddCfInfoNotifyHandler = GPCcfInfoAddNotifyQoS;
GpcHandlers.ClRemoveCfInfoNotifyHandler = GPCcfInfoRemoveNotifyQoS;
status = GpcEntries.GpcRegisterClientHandler(
GPC_CF_QOS, // classification family
0, // flags
1, // default max priority
&GpcHandlers, // client notification vector - no notifications to TCPIP required
0, // client context, not needed
&hGpcClient[GPC_CF_QOS]);
if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"GPC registerclient QOS status %x hGpcClient %p\n",
status, hGpcClient[GPC_CF_QOS]));
hGpcClient[GPC_CF_QOS] = NULL;
}
GpcHandlers.ClAddCfInfoNotifyHandler = GPCcfInfoAddNotifyIpsec;
GpcHandlers.ClRemoveCfInfoNotifyHandler = GPCcfInfoRemoveNotifyIpsec;
status = GpcEntries.GpcRegisterClientHandler(
GPC_CF_IPSEC, // classification family
0, // flags
GPC_PRIORITY_IPSEC, // default max priority
&GpcHandlers, // client notification vector - no notifications to TCPIP required
0, // client context, not needed
&hGpcClient[GPC_CF_IPSEC]);
if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"GPC registerclient IPSEC status %x hGpcClient %p\n",
status, hGpcClient[GPC_CF_IPSEC]));
hGpcClient[GPC_CF_IPSEC] = NULL;
}
}
#endif
if (InitIsnGenerator() == FALSE) {
DEBUGMSG(DBG_ERROR && DBG_INIT,
(DTEXT("InitIsnGenerator failure. TCP/IP failing to start.\n")));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-DriverEntry [%x]\n"), status));
return (STATUS_UNSUCCESSFUL);
}
// Millennium TCPIP has debugger extensions built in!
#if MILLEN
InitializeWDebDebug();
#endif // MILLEN
#if TRACE_EVENT
//
// Register with WMI for Enable/Disable Notification
// of Trace Logging
//
TCPCPHandlerRoutine = NULL;
IoWMIRegistrationControl(
TCPDeviceObject,
WMIREG_ACTION_REGISTER |
WMIREG_FLAG_TRACE_PROVIDER |
WMIREG_NOTIFY_TDI_IO
);
#endif
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-DriverEntry [SUCCESS]\n")));
return (STATUS_SUCCESS);
}
DEBUGMSG(DBG_ERROR && DBG_INIT,
(DTEXT("TCPIP: TCP initialization failed, IP still available.\n")));
CTELogEvent(
DriverObject,
EVENT_TCPIP_TCP_INIT_FAILED,
1,
0,
NULL,
0,
NULL
);
status = STATUS_UNSUCCESSFUL;
init_failed:
DEBUGMSG(DBG_ERROR && DBG_INIT,
(DTEXT("TCPIP DriverEntry initialization failure!\n")));
//
// IP has successfully started, but TCP & UDP failed. Set the
// Dispatch routine to point to IP only, since the TCP and UDP
// devices don't exist.
//
if (TCPDeviceObject != NULL) {
IoDeleteDevice(TCPDeviceObject);
}
if (UDPDeviceObject != NULL) {
IoDeleteDevice(UDPDeviceObject);
}
if (RawIPDeviceObject != NULL) {
IoDeleteDevice(RawIPDeviceObject);
}
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = IPDispatch;
}
#if !MILLEN
if (IPSECFileObject) {
IpsecDeinitialize();
}
#endif
return (status);
}
#if !MILLEN
#ifdef i386
NTSTATUS
TCPSetChecksumRoutine(
VOID
)
/*++
Routine Description:
This routine sets the checksum routine function pointer to the
appropriate routine based on the processor features available
Arguments:
None
Return Value:
STATUS_SUCCESS - if successful
--*/
{
SYSTEM_PROCESSOR_INFORMATION Info;
ULONG Length;
ULONG Features;
ULONG Processors;
ULONG i;
NTSTATUS Status;
BOOLEAN TcpipUsePrefetch;
#if WINVER < 0x0500
KAFFINITY OriginalAffinity;
#endif /* WINVER */
//
// First check to see that I have at least Intel Pentium. This simplifies
// the cpuid
//
Status = ZwQuerySystemInformation(SystemProcessorInformation,
&Info,
sizeof(Info),
&Length);
if (!NT_SUCCESS(Status)) {
return (Status);
}
if (Info.ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL ||
Info.ProcessorLevel < 5) {
Status = STATUS_INSUFFICIENT_RESOURCES;
return (Status);
}
Status = STATUS_SUCCESS;
TcpipUsePrefetch = TRUE;
Processors = KeNumberProcessors;
//
// Affinity thread to boot processor
//
#if WINVER < 0x0500
OriginalAffinity = KeSetAffinityThread(KeGetCurrentThread(), 1);
#else /* WINVER >= 0x0500 */
KeSetSystemAffinityThread(1);
#endif /* WINVER */
for (i = 0; i < Processors; i++) {
if (i != 0) {
#if WINVER < 0x0500
KeSetAffinityThread(KeGetCurrentThread(), 1 << i);
#else /* WINVER >= 0x0500 */
KeSetSystemAffinityThread(1 << i);
#endif /* WINVER */
}
_asm {
push ebx
mov eax, 1
;cpuid
_emit 0fh
_emit 0a2h
mov Features, edx
pop ebx
}
//
// Check for Prefetch Present
//
if (!(Features & 0x02000000)) {
//
// All processors must have prefetch before we can use it.
// We start with it enabled, if any processor does not have
// it we clear it,
TcpipUsePrefetch = FALSE;
}
}
#if WINVER < 0x0500
KeSetAffinityThread(KeGetCurrentThread(), OriginalAffinity);
#else /* WINVER >= 0x0500 */
KeRevertToUserAffinityThread();
#endif /* WINVER */
if (TcpipUsePrefetch == TRUE) {
tcpxsum_routine = tcpxsum_xmmi;
}
return (Status);
}
#endif
#endif // !MILLEN
IP_STATUS
TLGetIPInfo(
IPInfo * Buffer,
int Size
)
/*++
Routine Description:
Returns information necessary for TCP to call into IP.
Arguments:
Buffer - A pointer to the IP information structure.
Size - The size of Buffer.
Return Value:
The IP status of the operation.
--*/
{
return (IPGetInfo(Buffer, Size));
}
void *
TLRegisterProtocol(
uchar Protocol,
void *RcvHandler,
void *XmitHandler,
void *StatusHandler,
void *RcvCmpltHandler,
void *PnPHandler,
void *ElistHandler
)
/*++
Routine Description:
Calls the IP driver's protocol registration function.
Arguments:
Protocol - The protocol number to register.
RcvHandler - Transport's packet receive handler.
XmitHandler - Transport's packet transmit complete handler.
StatusHandler - Transport's status update handler.
RcvCmpltHandler - Transport's receive complete handler
Return Value:
A context value for the protocol to pass to IP when transmitting.
--*/
{
return (IPRegisterProtocol(
Protocol,
RcvHandler,
XmitHandler,
StatusHandler,
RcvCmpltHandler,
PnPHandler,
ElistHandler));
}
//
// Interval in milliseconds between keepalive transmissions until a
// response is received.
//
#define DEFAULT_KEEPALIVE_INTERVAL 1000
//
// time to first keepalive transmission. 2 hours == 7,200,000 milliseconds
//
#define DEFAULT_KEEPALIVE_TIME 7200000
#define MIN_THRESHOLD_MAX_HO 1
#define MIN_THRESHOLD_MAX_HO_RETRIED 80
uchar
TCPGetConfigInfo(
void
)
/*++
Routine Description:
Initializes TCP global configuration parameters.
Arguments:
None.
Return Value:
Zero on failure, nonzero on success.
--*/
{
HANDLE keyHandle;
NTSTATUS status;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING UKeyName;
ULONG maxConnectRexmits = 0;
ULONG maxConnectResponseRexmits = 0;
ULONG maxDataRexmits = 0;
ULONG pptpmaxDataRexmits = 0;
ULONG useRFC1122UrgentPointer = 0;
BOOLEAN AsSystem;
ULONG tcp1323opts = 3; //turning off 1323 options by default
ULONG SackOpts;
ULONG i, j;
DEBUGMSG(DBG_TRACE && DBG_INIT,
(DTEXT("+TCPGetConfigInfo()\n")));
//
// Initialize to the defaults in case an error occurs somewhere.
//
KAInterval = DEFAULT_KEEPALIVE_INTERVAL;
KeepAliveTime = DEFAULT_KEEPALIVE_TIME;
PMTUDiscovery = TRUE;
PMTUBHDetect = FALSE;
DeadGWDetect = TRUE;
DefaultRcvWin = 0; // Automagically pick a reasonable one.
MaxConnections = DEFAULT_MAX_CONNECTIONS;
maxConnectRexmits = MAX_CONNECT_REXMIT_CNT;
maxConnectResponseRexmits = MAX_CONNECT_RESPONSE_REXMIT_CNT;
pptpmaxDataRexmits = maxDataRexmits = MAX_REXMIT_CNT;
BSDUrgent = TRUE;
FinWait2TO = FIN_WAIT2_TO;
NTWMaxConnectCount = NTW_MAX_CONNECT_COUNT;
NTWMaxConnectTime = NTW_MAX_CONNECT_TIME;
MaxUserPort = DEFAULT_MAX_USER_PORT;
// Default number of duplicate acks
MaxDupAcks = 2;
SynAttackProtect = 0; //by default it is always off
#if MILLEN
TCPMaxPortsExhausted = 5;
TCPMaxHalfOpen = 100;
TCPMaxHalfOpenRetried = 80;
#else // MILLEN
if (!MmIsThisAnNtAsSystem()) {
TCPMaxPortsExhausted = 5;
TCPMaxHalfOpen = 100;
TCPMaxHalfOpenRetried = 80;
} else {
TCPMaxPortsExhausted = 5;
TCPMaxHalfOpen = 500;
TCPMaxHalfOpenRetried = 400;
}
#endif // !MILLEN
SecurityFilteringEnabled = FALSE;
#ifdef ACC
AllowUserRawAccess = FALSE;
#endif
//
// Read the TCP optional (hidden) registry parameters.
//
#if !MILLEN
RtlInitUnicodeString(
&UKeyName,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
);
#else // !MILLEN
RtlInitUnicodeString(
&UKeyName,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\VxD\\MSTCP"
);
#endif // MILLEN
DEBUGMSG(DBG_INFO && DBG_INIT,
(DTEXT("TCPGetConfigInfo: Opening key %ws\n"), UKeyName.Buffer));
memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
InitializeObjectAttributes(
&objectAttributes,
&UKeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
status = ZwOpenKey(
&keyHandle,
KEY_READ,
&objectAttributes
);
DEBUGMSG(!NT_SUCCESS(status) && DBG_ERROR,
(DTEXT("TCPGetConfigInfo: failed to open TCP registry configuration: %ws\n"),
UKeyName.Buffer));
if (NT_SUCCESS(status)) {
DEBUGMSG(DBG_INFO && DBG_INIT,
(DTEXT("TCPGetConfigInfo: successfully opened registry to read.\n")));
#if !MILLEN
TCPInitializeParameter(
keyHandle,
L"IsnStoreSize",
&g_cRandIsnStore
);
#endif // !MILLEN
TCPInitializeParameter(
keyHandle,
L"KeepAliveInterval",
&KAInterval
);
TCPInitializeParameter(
keyHandle,
L"KeepAliveTime",
&KeepAliveTime
);
status = TCPInitializeParameter(
keyHandle,
L"EnablePMTUBHDetect",
&PMTUBHDetect
);
#if MILLEN
//
// Backwards compatibility. If 'EnablePMTUBHDetect' value does not exist,
// then attempt to read legacy 'PMTUBlackHoleDetect'.
//
if (!NT_SUCCESS(status)) {
TCPInitializeParameter(
keyHandle,
L"PMTUBlackHoleDetect",
&PMTUBHDetect
);
}
#endif // MILLEN
status = TCPInitializeParameter(
keyHandle,
L"TcpWindowSize",
&DefaultRcvWin
);
#if MILLEN
//
// Backwards compatibility. If 'TcpWindowSize' value does not exist,
// then attempt to read legacy 'DefaultRcvWindow'.
//
if (!NT_SUCCESS(status)) {
TCPInitializeParameter(
keyHandle,
L"DefaultRcvWindow",
&DefaultRcvWin
);
}
#endif // MILLEN
status = TCPInitializeParameter(
keyHandle,
L"TcpNumConnections",
&MaxConnections
);
#if MILLEN
//
// Backwards compatibility. If 'TcpNumConnections' value does not exist,
// then attempt to read legacy 'MaxConnections'.
//
if (!NT_SUCCESS(status)) {
TCPInitializeParameter(
keyHandle,
L"MaxConnections",
&MaxConnections
);
}
#endif // MILLEN
status = TCPInitializeParameter(
keyHandle,
L"TcpMaxConnectRetransmissions",
&maxConnectRexmits
);
#if MILLEN
//
// Backwards compatibility. If 'TcpMaxConnectRetransmissions' value does not exist,
// then attempt to read legacty 'MaxConnectRetries'.
//
if (!NT_SUCCESS(status)) {
TCPInitializeParameter(
keyHandle,
L"MaxConnectRetries",
&maxConnectRexmits
);
}
#endif // MILLEN
if (maxConnectRexmits > 255) {
maxConnectRexmits = 255;
}
TCPInitializeParameter(
keyHandle,
L"TcpMaxConnectResponseRetransmissions",
&maxConnectResponseRexmits
);
if (maxConnectResponseRexmits > 255) {
maxConnectResponseRexmits = 255;
}
status = TCPInitializeParameter(
keyHandle,
L"TcpMaxDataRetransmissions",
&maxDataRexmits
);
#if MILLEN
//
// Backwards compatibility. If 'TcpMaxDataRetransmissions' value does not exist,
// then attempt to read legacy 'MaxDataRetries'.
//
if (!NT_SUCCESS(status)) {
TCPInitializeParameter(
keyHandle,
L"MaxDataRetries",
&maxDataRexmits
);
}
#endif // MILLEN
if (maxDataRexmits > 255) {
maxDataRexmits = 255;
}
// Limit the MaxDupAcks to 3
status = TCPInitializeParameter(
keyHandle,
L"TcpMaxDupAcks",
&MaxDupAcks
);
#if MILLEN
//
// Backwards compatibility. If 'TcpMaxDupAcks' value does not exist,
// then attempt to read legacy 'MaxDupAcks'.
//
if (!NT_SUCCESS(status)) {
TCPInitializeParameter(
keyHandle,
L"MaxDupAcks",
&MaxDupAcks
);
}
#endif // MILLEN
if (MaxDupAcks > 3) {
MaxDupAcks = 3;
}
if (MaxDupAcks == 0) {
MaxDupAcks = 1;
}
#if MILLEN
MaxConnBlocks = 16;
#else // MILLEN
systemSize = MmQuerySystemSize();
if (MmIsThisAnNtAsSystem()) {
if (systemSize == MmSmallSystem) {
MaxConnBlocks = 128;
} else if (systemSize == MmMediumSystem) {
MaxConnBlocks = 256;
} else {
#if defined(_WIN64)
MaxConnBlocks = 4096;
#else
MaxConnBlocks = 1024;
#endif
}
} else {
//for workstation, small system limit default number of connections to 4K.
// medium system 8k
// Large system 32k connections
if (systemSize == MmSmallSystem) {
MaxConnBlocks = 16;
} else if (systemSize == MmMediumSystem) {
MaxConnBlocks = 32;
} else {
MaxConnBlocks = 128;
}
}
#endif // !MILLEN
#if MILLEN
NumTcbTablePartitions = 1;
#else
NumTcbTablePartitions = (KeNumberProcessors * KeNumberProcessors);
#endif
TCPInitializeParameter(
keyHandle,
L"NumTcbTablePartitions",
&NumTcbTablePartitions
);
if (NumTcbTablePartitions > (MAXIMUM_PROCESSORS * MAXIMUM_PROCESSORS)) {
NumTcbTablePartitions = (MAXIMUM_PROCESSORS * MAXIMUM_PROCESSORS);
}
NumTcbTablePartitions = ComputeLargerOrEqualPowerOfTwo(NumTcbTablePartitions);
// Default to 128 TCBs per partition
MaxHashTableSize = 128 * NumTcbTablePartitions;
TCPInitializeParameter(
keyHandle,
L"MaxHashTableSize",
&MaxHashTableSize
);
if (MaxHashTableSize < 64) {
MaxHashTableSize = 64;
} else if (MaxHashTableSize > 0xffff) {
MaxHashTableSize = 0x10000;
}
MaxHashTableSize = ComputeLargerOrEqualPowerOfTwo(MaxHashTableSize);
if (MaxHashTableSize < NumTcbTablePartitions) {
MaxHashTableSize = NumTcbTablePartitions;
}
ASSERT(IsPowerOfTwo(MaxHashTableSize));
//since hash table size is power of 2 and cache line size
//is power of 2 and number of partion is even,
//entries per partions will be power of 2 and multiple of
//cache line size.
PerPartitionSize = MaxHashTableSize / NumTcbTablePartitions;
ASSERT(IsPowerOfTwo(PerPartitionSize));
LogPerPartitionSize =
ComputeShiftForLargerOrEqualPowerOfTwo(PerPartitionSize);
TWTCBTable = CTEAllocMemBoot(MaxHashTableSize * sizeof(*TWTCBTable));
if (TWTCBTable == NULL) {
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate tw tcb table of size %x\n", MaxHashTableSize));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
for (i = 0; i < MaxHashTableSize; i++)
{
INITQ(&TWTCBTable[i]);
}
TCBTable = CTEAllocMemBoot(MaxHashTableSize * sizeof(*TCBTable));
if (TCBTable == NULL) {
ExFreePool(TWTCBTable);
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate tcb table of size %x\n", MaxHashTableSize));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
NdisZeroMemory(TCBTable, MaxHashTableSize * sizeof(*TCBTable));
SYNTCBTable = CTEAllocMemBoot(MaxHashTableSize * sizeof(*SYNTCBTable));
if (SYNTCBTable == NULL) {
ExFreePool(TWTCBTable);
ExFreePool(TCBTable);
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate syn tcb table of size %x\n", MaxHashTableSize));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
for (i = 0; i < MaxHashTableSize; i++)
{
INITQ(&SYNTCBTable[i]);
}
pSynTCBTableLock = CTEAllocMemBoot(NumTcbTablePartitions * sizeof(CTELock));
if (pSynTCBTableLock == NULL) {
ExFreePool(TCBTable);
ExFreePool(TWTCBTable);
ExFreePool(SYNTCBTable);
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate twtcb lock table \n"));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
pTWTCBTableLock = CTEAllocMemBoot(NumTcbTablePartitions * sizeof(CTELock));
if (pTWTCBTableLock == NULL) {
ExFreePool(TCBTable);
ExFreePool(TWTCBTable);
ExFreePool(SYNTCBTable);
ExFreePool(pSynTCBTableLock);
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate twtcb lock table \n"));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
pTCBTableLock = CTEAllocMemBoot(NumTcbTablePartitions * sizeof(CTELock));
if (pTCBTableLock == NULL) {
ExFreePool(TCBTable);
ExFreePool(TWTCBTable);
ExFreePool(pTWTCBTableLock);
ExFreePool(SYNTCBTable);
ExFreePool(pSynTCBTableLock);
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate tcb lock table \n"));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
TWQueue = CTEAllocMemBoot(NumTcbTablePartitions * sizeof(Queue));
if (TWQueue == NULL) {
ExFreePool(TCBTable);
ExFreePool(TWTCBTable);
ExFreePool(pTWTCBTableLock);
ExFreePool(SYNTCBTable);
ExFreePool(pSynTCBTableLock);
ExFreePool(pTCBTableLock);
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate Twqueue \n"));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
TimerWheel = CTEAllocMemBoot(NumTcbTablePartitions * sizeof(TIMER_WHEEL) + CACHE_LINE_SIZE);
if (TimerWheel == NULL) {
ExFreePool(TCBTable);
ExFreePool(TWTCBTable);
ExFreePool(pTWTCBTableLock);
ExFreePool(SYNTCBTable);
ExFreePool(pSynTCBTableLock);
ExFreePool(pTCBTableLock);
ExFreePool(TWQueue);
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate Twqueue \n"));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
OrgTimerWheel = TimerWheel;
(ULONG_PTR) TimerWheel = ((ULONG_PTR) TimerWheel + CACHE_LINE_SIZE) & CACHE_ALIGN_MASK;
for (i = 0; i < NumTcbTablePartitions; i++) {
CTEInitLock(&pTCBTableLock[i]);
CTEInitLock(&pTWTCBTableLock[i]);
CTEInitLock(&pSynTCBTableLock[i]);
INITQ(&TWQueue[i])
// Init the timer wheel
CTEInitLock(&TimerWheel[i].tw_lock);
#ifdef TIMER_TEST
TimerWheel[i].tw_starttick = 0xfffff000;
#else
TimerWheel[i].tw_starttick = 0;
#endif
for(j = 0; j < TIMER_WHEEL_SIZE; j++) {
INITQ(&TimerWheel[i].tw_timerslot[j])
}
}
if (MaxConnections != DEFAULT_MAX_CONNECTIONS) {
//make it even
MaxConnBlocks = ((MaxConnections >> 1) << 1);
//allow minimum of 1k level 1 conn blocks.
//this gives minimum of 256K connections capability
if (MaxConnBlocks < 1024) {
MaxConnBlocks = 1024;
}
}
ConnTable = CTEAllocMemBoot(MaxConnBlocks * sizeof(TCPConnBlock *));
if (ConnTable == NULL) {
ExFreePool(OrgTimerWheel);
ExFreePool(TWQueue);
ExFreePool(TCBTable);
ExFreePool(TWTCBTable);
ExFreePool(pTWTCBTableLock);
ExFreePool(pTCBTableLock);
ExFreePool(SYNTCBTable);
ExFreePool(pSynTCBTableLock);
ZwClose(keyHandle);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate ConnTable \n"));
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [failure]\n")));
return (0);
}
status = TCPInitializeParameter(
keyHandle,
L"Tcp1323Opts",
&tcp1323opts
);
if (status == STATUS_SUCCESS) {
// Check if TS and/or WS options
// are enabled.
TcpHostOpts = TCP_FLAG_WS | TCP_FLAG_TS;
if (!(tcp1323opts & TCP_FLAG_TS)) {
TcpHostOpts &= ~TCP_FLAG_TS;
}
if (!(tcp1323opts & TCP_FLAG_WS)) {
TcpHostOpts &= ~TCP_FLAG_WS;
} else {
MaxRcvWin = 0x3fffffff;
}
TcpHostSendOpts = TcpHostOpts;
} else {
TcpHostSendOpts = 0;
}
TcpHostOpts |= TCP_FLAG_SACK;
status = TCPInitializeParameter(
keyHandle,
L"SackOpts",
&SackOpts
);
if (status == STATUS_SUCCESS) {
//Check if Sack option is enabled
//If so, set it in global options variable
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Sackopts %x\n", SackOpts));
if (!SackOpts) {
TcpHostOpts &= ~TCP_FLAG_SACK;
}
}
TCPInitializeParameter(
keyHandle,
L"GlobalMaxTcpWindowSize",
&GlobalMaxRcvWin
);
TCPInitializeParameter(
keyHandle,
L"SynAttackProtect",
(unsigned long *)&SynAttackProtect
);
if (SynAttackProtect) {
TCPInitializeParameter(
keyHandle,
L"TCPMaxPortsExhausted",
&TCPMaxPortsExhausted
);
TCPMaxPortsExhaustedLW = MAX((TCPMaxPortsExhausted >> 1) + (TCPMaxPortsExhausted >> 2), 1);
TCPInitializeParameter(
keyHandle,
L"TCPMaxHalfOpen",
&TCPMaxHalfOpen
);
if (TCPMaxHalfOpen < MIN_THRESHOLD_MAX_HO) {
TCPMaxHalfOpen = MIN_THRESHOLD_MAX_HO;
}
TCPInitializeParameter(
keyHandle,
L"TCPMaxHalfOpenRetried",
&TCPMaxHalfOpenRetried
);
if ((TCPMaxHalfOpenRetried > TCPMaxHalfOpen) ||
(TCPMaxHalfOpenRetried < MIN_THRESHOLD_MAX_HO_RETRIED)) {
TCPMaxHalfOpenRetried = MIN_THRESHOLD_MAX_HO_RETRIED;
}
TCPMaxHalfOpenRetriedLW = (TCPMaxHalfOpenRetried >> 1) +
(TCPMaxHalfOpenRetried >> 2);
}
//
// If we fail, then set to same value as maxDataRexmit so that the
// max(pptpmaxDataRexmit,maxDataRexmit) is a decent value
// Need this since TCPInitializeParameter no longer "initializes"
// to a default value
//
if (TCPInitializeParameter(keyHandle,
L"PPTPTcpMaxDataRetransmissions",
&pptpmaxDataRexmits) != STATUS_SUCCESS) {
pptpmaxDataRexmits = maxDataRexmits;
}
if (pptpmaxDataRexmits > 255) {
pptpmaxDataRexmits = 255;
}
status = TCPInitializeParameter(
keyHandle,
L"TcpUseRFC1122UrgentPointer",
&useRFC1122UrgentPointer
);
#if MILLEN
//
// Backwards compatibility. If TcpUseRFC1122UrgentPointer does not exist,
// then check for BSDUrgent. These values are logical opposites.
//
if (!NT_SUCCESS(status)) {
ULONG tmpBsdUrgent = TRUE;
status = TCPInitializeParameter(
keyHandle,
L"BSDUrgent",
&tmpBsdUrgent);
if (NT_SUCCESS(status)) {
useRFC1122UrgentPointer = !tmpBsdUrgent;
}
}
#endif
if (useRFC1122UrgentPointer) {
BSDUrgent = FALSE;
}
TCPInitializeParameter(
keyHandle,
L"TcpTimedWaitDelay",
&FinWait2TO
);
if (FinWait2TO > 300) {
FinWait2TO = 300;
}
FinWait2TO = MS_TO_TICKS(FinWait2TO * 1000);
NTWMaxConnectTime = MS_TO_TICKS(NTWMaxConnectTime * 1000);
TCPInitializeParameter(
keyHandle,
L"MaxUserPort",
&MaxUserPort
);
if (MaxUserPort < 5000) {
MaxUserPort = 5000;
}
if (MaxUserPort > 65534) {
MaxUserPort = 65534;
}
GetReservedPortList(keyHandle);
//Reserve ports if
//
// Read a few IP optional (hidden) registry parameters that TCP
// cares about.
//
status = TCPInitializeParameter(
keyHandle,
L"EnablePMTUDiscovery",
&PMTUDiscovery
);
#if MILLEN
//
// Backwards compatibility. If 'EnablePMTUDiscovery' value does not exist,
// then attempt to read legacy 'PMTUDiscovery'.
//
if (!NT_SUCCESS(status)) {
TCPInitializeParameter(
keyHandle,
L"PMTUDiscovery",
&PMTUDiscovery
);
}
#endif // MILLEN
TCPInitializeParameter(
keyHandle,
L"EnableDeadGWDetect",
&DeadGWDetect
);
TCPInitializeParameter(
keyHandle,
L"EnableSecurityFilters",
&SecurityFilteringEnabled
);
#ifdef ACC
TCPInitializeParameter(
keyHandle,
L"AllowUserRawAccess",
&AllowUserRawAccess
);
#endif // ACC
status = TCPInitializeParameter(
keyHandle,
L"DefaultTOSValue",
&DefaultTOSValue
);
#if MILLEN
//
// Backwards compatibility. Read 'DefaultTOS' if 'DefaultTOSValue' is
// not present.
//
if (!NT_SUCCESS(status)) {
TCPInitializeParameter(
keyHandle,
L"DefaultTOS",
&DefaultTOSValue
);
}
#endif // MILLEN
TCPInitializeParameter(
keyHandle,
L"DisableUserTOSSetting",
&DisableUserTOSSetting
);
TCPInitializeParameter(
keyHandle,
L"MaxSendSegments",
&MaxSendSegments
);
TCPInitializeParameter(
keyHandle,
L"DisableLargeSendOffload",
&DisableLargeSendOffload
);
ZwClose(keyHandle);
}
MaxConnectRexmitCount = maxConnectRexmits;
MaxConnectResponseRexmitCount = maxConnectResponseRexmits;
MaxConnectResponseRexmitCountTmp = MaxConnectResponseRexmitCount;
//
// Use the greater of the two, hence both values should be valid
//
MaxDataRexmitCount = (maxDataRexmits > pptpmaxDataRexmits ? maxDataRexmits : pptpmaxDataRexmits);
DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-TCPGetConfigInfo [SUCCESS]\n")));
return (1);
}
#define WORK_BUFFER_SIZE 256
extern NTSTATUS
GetRegDWORDValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG ValueData
);
NTSTATUS
TCPInitializeParameter(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG Value
)
/*++
Routine Description:
Initializes a ULONG parameter from the registry or to a default
parameter if accessing the registry value fails.
Arguments:
KeyHandle - An open handle to the registry key for the parameter.
ValueName - The UNICODE name of the registry value to read.
Value - The ULONG into which to put the data.
DefaultValue - The default to assign if reading the registry fails.
Return Value:
None.
--*/
{
return (GetRegDWORDValue(KeyHandle, ValueName, Value));
}
VOID
GetReservedPortList(
NDIS_HANDLE ConfigHandle
)
{
UNICODE_STRING PortList;
PWCHAR nextRange;
TDI_STATUS status;
PortList.Buffer = CTEAllocMemBoot(WORK_BUFFER_SIZE * sizeof(WCHAR));
if (!PortList.Buffer) {
return;
}
PortList.Buffer[0] = UNICODE_NULL;
PortList.Length = 0;
PortList.MaximumLength = WORK_BUFFER_SIZE * sizeof(WCHAR);
PortRangeList = NULL;
if (PortList.Buffer) {
NdisZeroMemory(PortList.Buffer, WORK_BUFFER_SIZE * sizeof(WCHAR));
status = GetRegMultiSZValue(
ConfigHandle,
L"ReservedPorts",
&PortList
);
if (NT_SUCCESS(status)) {
for (nextRange = PortList.Buffer;
*nextRange != L'\0';
nextRange += wcslen(nextRange) + 1) {
PWCHAR tmps = nextRange;
USHORT upval = 0, loval = 0, tmpval = 0;
BOOLEAN error = FALSE;
ReservedPortListEntry *ListEntry;
while (*tmps != L'\0') {
if (*tmps == L'-') {
tmps++;
loval = tmpval;
tmpval = 0;
}
if (*tmps >= L'0' && *tmps <= L'9') {
tmpval = tmpval * 10 + (*tmps - L'0');
} else {
error = TRUE;
break;
}
tmps++;
}
upval = tmpval;
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"loval %d upval %d\n", loval, upval));
if (!error && (loval > 0) && (upval > 0) && (loval <= upval) &&
(upval <= MaxUserPort) && (loval <= MaxUserPort)) {
ListEntry = CTEAllocMemBoot(sizeof(ReservedPortListEntry));
if (ListEntry) {
//Insert this range.
//No need to take locks
//since we are at initialization.
ListEntry->UpperRange = upval;
ListEntry->LowerRange = loval;
ListEntry->next = PortRangeList;
PortRangeList = ListEntry;
}
}
}
}
CTEFreeMem(PortList.Buffer);
}
}
TDI_STATUS
GetSecurityFilterList(
NDIS_HANDLE ConfigHandle,
ulong Protocol,
PNDIS_STRING FilterList
)
{
PWCHAR parameterName;
TDI_STATUS status;
if (Protocol == PROTOCOL_TCP) {
parameterName = L"TcpAllowedPorts";
} else if (Protocol == PROTOCOL_UDP) {
parameterName = L"UdpAllowedPorts";
} else {
parameterName = L"RawIpAllowedProtocols";
}
status = GetRegMultiSZValue(
ConfigHandle,
parameterName,
FilterList
);
if (!NT_SUCCESS(status)) {
FilterList->Length = 0;
}
return (status);
}
uint
EnumSecurityFilterValue(
PNDIS_STRING FilterList,
ulong Index,
ulong * FilterValue
)
{
PWCHAR valueString;
UNICODE_STRING unicodeString;
NTSTATUS status;
PAGED_CODE();
valueString = EnumRegMultiSz(
FilterList->Buffer,
FilterList->Length,
Index
);
if ((valueString == NULL) || (valueString[0] == UNICODE_NULL)) {
return (FALSE);
}
RtlInitUnicodeString(&unicodeString, valueString);
status = RtlUnicodeStringToInteger(&unicodeString, 0, FilterValue);
if (!(NT_SUCCESS(status))) {
TCPTRACE(("TCP: Invalid filter value %ws\n", valueString));
return (FALSE);
}
return (TRUE);
}
VOID
TCPFreeupMemory()
/*++
Routine Description:
This routine frees up the memory at the TCP layer
Arguments:
NULL
Return Value:
None.
--*/
{
CTELockHandle Handle;
PNDIS_BUFFER curTCPHeader;
TCPConnReq *tcpConnReq;
TCPRcvReq *tcpRcvReq;
TCPSendReq *tcpSendReq;
PSINGLE_LIST_ENTRY BufferLink;
Queue *QueuePtr;
TCPReq *ReqPtr;
TCB *curTCB;
//
// Walk various lists and free assoc blocks
//
// DG header list
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Freeing DG headers....\n"));
MdpDestroyPool(DgHeaderPool);
if (AddrObjTable) {
CTEFreeMem(AddrObjTable);
}
PplDestroyPool(TcbPool);
PplDestroyPool(SynTcbPool);
#ifdef ACC
if (TcpAdminSecurityDescriptor) {
ExFreePool(TcpAdminSecurityDescriptor);
}
#endif
}
VOID
TCPUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This routine cleans up the TCP layer.
Arguments:
DriverObject - Pointer to driver object created by the system.
Return Value:
None. When the function returns, the driver is unloaded.
--*/
{
NTSTATUS status;
uint i;
#if !MILLEN
//
// Deinitialize IPSEC first
//
status = IpsecDeinitialize();
#endif
//
// Shut down all timers/events
//
CTEInitBlockStrucEx(&TcpipUnloadBlock);
fTCBTimerStopping = TRUE;
for (i = 0; i < Time_Proc; i++) {
if (!CTEStopTimer(&TCBTimer[i])) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not stop TCB timer - waiting on unload event\n"));
#if !MILLEN
if (KeReadStateEvent(&(TcpipUnloadBlock.cbs_event))) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Event is signaled...\n"));
}
#endif // !MILLEN
(VOID) CTEBlock(&TcpipUnloadBlock);
KeClearEvent(&TcpipUnloadBlock.cbs_event);
}
}
#if GPC
//
if (hGpcClient[GPC_CF_QOS]) {
status = GpcEntries.GpcDeregisterClientHandler(hGpcClient[GPC_CF_QOS]);
hGpcClient[GPC_CF_QOS] = NULL;
}
if (hGpcClient[GPC_CF_IPSEC]) {
status = GpcEntries.GpcDeregisterClientHandler(hGpcClient[GPC_CF_IPSEC]);
hGpcClient[GPC_CF_IPSEC] = NULL;
}
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Deregistering GPC\n"));
status = GpcDeinitialize(&GpcEntries);
#endif
//
// Clean up all residual memory
//
TCPFreeupMemory();
//
// Deregister address notifn handler with TDI
//
(void)TdiDeregisterPnPHandlers(AddressChangeHandle);
//
// Deregister our devices with TDI
//
(void)TdiDeregisterDeviceObject(TCPRegistrationHandle);
(void)TdiDeregisterDeviceObject(UDPRegistrationHandle);
(void)TdiDeregisterDeviceObject(IPRegistrationHandle);
#if TRACE_EVENT
//
// Deregister with WMI
//
IoWMIRegistrationControl(TCPDeviceObject, WMIREG_ACTION_DEREGISTER);
#endif
//
// Delete devices
//
IoDeleteDevice(TCPDeviceObject);
IoDeleteDevice(UDPDeviceObject);
IoDeleteDevice(RawIPDeviceObject);
}
#if GPC
GPC_STATUS
GPCcfInfoAddNotifyIpsec(GPC_CLIENT_HANDLE ClCtxt,
GPC_HANDLE GpcHandle,
ULONG CfInfoSize,
PVOID CfInfo,
PGPC_CLIENT_HANDLE pClInfoCxt)
{
InterlockedIncrement(&GPCcfInfo);
IF_TCPDBG(TCP_DEBUG_GPC)
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo Add notification %x\n", GPCcfInfo));
InterlockedIncrement(&GpcCfCounts[GPC_CF_IPSEC]);
IF_TCPDBG(TCP_DEBUG_GPC)
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo Add notification IPSEC:%x\n", GpcCfCounts[GPC_CF_IPSEC]));
return (STATUS_SUCCESS);
}
GPC_STATUS
GPCcfInfoRemoveNotifyIpsec(GPC_CLIENT_HANDLE ClCtxt,
GPC_CLIENT_HANDLE ClInfoCxt)
{
InterlockedDecrement(&GPCcfInfo);
IF_TCPDBG(TCP_DEBUG_GPC)
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo remove notification %x\n", GPCcfInfo));
InterlockedDecrement(&GpcCfCounts[GPC_CF_IPSEC]);
IF_TCPDBG(TCP_DEBUG_GPC)
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo Add notification IPSEC: %x\n", GpcCfCounts[GPC_CF_IPSEC]));
return (STATUS_SUCCESS);
}
GPC_STATUS
GPCcfInfoAddNotifyQoS(GPC_CLIENT_HANDLE ClCtxt,
GPC_HANDLE GpcHandle,
ULONG CfInfoSize,
PVOID CfInfo,
PGPC_CLIENT_HANDLE pClInfoCxt)
{
InterlockedIncrement(&GPCcfInfo);
IF_TCPDBG(TCP_DEBUG_GPC)
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo Add notification %x\n", GPCcfInfo));
InterlockedIncrement(&GpcCfCounts[GPC_CF_QOS]);
IF_TCPDBG(TCP_DEBUG_GPC)
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo Add notification QOS: %x\n", GpcCfCounts[GPC_CF_QOS]));
return (STATUS_SUCCESS);
}
GPC_STATUS
GPCcfInfoRemoveNotifyQoS(GPC_CLIENT_HANDLE ClCtxt,
GPC_CLIENT_HANDLE ClInfoCxt)
{
InterlockedDecrement(&GPCcfInfo);
IF_TCPDBG(TCP_DEBUG_GPC)
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo remove notification %x\n", GPCcfInfo));
InterlockedDecrement(&GpcCfCounts[GPC_CF_QOS]);
IF_TCPDBG(TCP_DEBUG_GPC)
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo Add notification %x\n", GpcCfCounts[GPC_CF_QOS]));
return (STATUS_SUCCESS);
}
#endif
#if ACC
NTSTATUS
TcpBuildDeviceAcl(
OUT PACL * DeviceAcl
)
/*++
Routine Description:
(Lifted from AFD - AfdBuildDeviceAcl)
This routine builds an ACL which gives Administrators and LocalSystem
principals full access. All other principals have no access.
Arguments:
DeviceAcl - Output pointer to the new ACL.
Return Value:
STATUS_SUCCESS or an appropriate error code.
--*/
{
PGENERIC_MAPPING GenericMapping;
PSID AdminsSid;
PSID SystemSid;
PSID NetworkSid;
ULONG AclLength;
NTSTATUS Status;
ACCESS_MASK AccessMask = GENERIC_ALL;
PACL NewAcl;
//
// Enable access to all the globally defined SIDs
//
GenericMapping = IoGetFileObjectGenericMapping();
RtlMapGenericMask(&AccessMask, GenericMapping);
AdminsSid = SeExports->SeAliasAdminsSid;
SystemSid = SeExports->SeLocalSystemSid;
NetworkSid = SeExports->SeNetworkServiceSid;
AclLength = sizeof(ACL) +
3 * sizeof(ACCESS_ALLOWED_ACE) +
RtlLengthSid(AdminsSid) +
RtlLengthSid(SystemSid) +
RtlLengthSid(NetworkSid) -
3 * sizeof(ULONG);
NewAcl = CTEAllocMemBoot(AclLength);
if (NewAcl == NULL) {
return (STATUS_INSUFFICIENT_RESOURCES);
}
Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION);
if (!NT_SUCCESS(Status)) {
CTEFreeMem(NewAcl);
return (Status);
}
Status = RtlAddAccessAllowedAce(
NewAcl,
ACL_REVISION2,
AccessMask,
AdminsSid
);
ASSERT(NT_SUCCESS(Status));
Status = RtlAddAccessAllowedAce(
NewAcl,
ACL_REVISION2,
AccessMask,
SystemSid
);
ASSERT(NT_SUCCESS(Status));
// Add acl for NetworkSid!
Status = RtlAddAccessAllowedAce(
NewAcl,
ACL_REVISION2,
AccessMask,
NetworkSid
);
ASSERT(NT_SUCCESS(Status));
*DeviceAcl = NewAcl;
return (STATUS_SUCCESS);
} // TcpBuildDeviceAcl
NTSTATUS
TcpCreateAdminSecurityDescriptor(
VOID
)
/*++
Routine Description:
(Lifted from AFD - AfdCreateAdminSecurityDescriptor)
This routine creates a security descriptor which gives access
only to Administrtors and LocalSystem. This descriptor is used
to access check raw endpoint opens and exclisive access to transport
addresses.
Arguments:
None.
Return Value:
STATUS_SUCCESS or an appropriate error code.
--*/
{
PACL rawAcl = NULL;
NTSTATUS status;
BOOLEAN memoryAllocated = FALSE;
PSECURITY_DESCRIPTOR tcpSecurityDescriptor;
ULONG tcpSecurityDescriptorLength;
CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
PSECURITY_DESCRIPTOR localSecurityDescriptor =
(PSECURITY_DESCRIPTOR) & buffer;
PSECURITY_DESCRIPTOR localTcpAdminSecurityDescriptor;
SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION;
//
// Get a pointer to the security descriptor from the TCP device object.
//
status = ObGetObjectSecurity(
TCPDeviceObject,
&tcpSecurityDescriptor,
&memoryAllocated
);
if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
"TCP: Unable to get security descriptor, error: %x\n",
status
));
ASSERT(memoryAllocated == FALSE);
return (status);
}
//
// Build a local security descriptor with an ACL giving only
// administrators and system access.
//
status = TcpBuildDeviceAcl(&rawAcl);
if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"TCP: Unable to create Raw ACL, error: %x\n", status));
goto error_exit;
}
(VOID) RtlCreateSecurityDescriptor(
localSecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION
);
(VOID) RtlSetDaclSecurityDescriptor(
localSecurityDescriptor,
TRUE,
rawAcl,
FALSE
);
//
// Make a copy of the TCP descriptor. This copy will be the raw descriptor.
//
tcpSecurityDescriptorLength = RtlLengthSecurityDescriptor(
tcpSecurityDescriptor
);
localTcpAdminSecurityDescriptor = ExAllocatePool(
PagedPool,
tcpSecurityDescriptorLength,
);
if (localTcpAdminSecurityDescriptor == NULL) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"TCP: couldn't allocate security descriptor\n"));
goto error_exit;
}
RtlMoveMemory(
localTcpAdminSecurityDescriptor,
tcpSecurityDescriptor,
tcpSecurityDescriptorLength
);
TcpAdminSecurityDescriptor = localTcpAdminSecurityDescriptor;
//
// Now apply the local descriptor to the raw descriptor.
//
status = SeSetSecurityDescriptorInfo(
NULL,
&securityInformation,
localSecurityDescriptor,
&TcpAdminSecurityDescriptor,
PagedPool,
IoGetFileObjectGenericMapping()
);
if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"TCP: SeSetSecurity failed, %lx\n", status));
ASSERT(TcpAdminSecurityDescriptor == localTcpAdminSecurityDescriptor);
ExFreePool(TcpAdminSecurityDescriptor);
TcpAdminSecurityDescriptor = NULL;
goto error_exit;
}
if (TcpAdminSecurityDescriptor != localTcpAdminSecurityDescriptor) {
ExFreePool(localTcpAdminSecurityDescriptor);
}
status = STATUS_SUCCESS;
error_exit:
ObReleaseObjectSecurity(
tcpSecurityDescriptor,
memoryAllocated
);
if (rawAcl != NULL) {
CTEFreeMem(rawAcl);
}
return (status);
}
#endif // ACC
#if !MILLEN
NTSTATUS
IpsecInitialize(
void
)
/*++
Routine Description:
Initialize IPSEC.SYS.
Arguments:
None.
Return Value:
None.
--*/
{
UNICODE_STRING IPSECDeviceName;
IPSEC_SET_TCPIP_STATUS SetTcpipStatus;
PIRP Irp;
IO_STATUS_BLOCK StatusBlock;
KEVENT Event;
NTSTATUS status;
IPSECDeviceObject = NULL;
IPSECFileObject = NULL;
RtlInitUnicodeString(&IPSECDeviceName, DD_IPSEC_DEVICE_NAME);
//
// Keep a reference to the IPSec driver so it won't unload before us.
//
status = IoGetDeviceObjectPointer( &IPSECDeviceName,
FILE_ALL_ACCESS,
&IPSECFileObject,
&IPSECDeviceObject);
if (!NT_SUCCESS(status)) {
IPSECFileObject = NULL;
return (status);
}
SetTcpipStatus.TcpipStatus = TRUE;
SetTcpipStatus.TcpipFreeBuff = FreeIprBuff;
SetTcpipStatus.TcpipAllocBuff = IPAllocBuff;
SetTcpipStatus.TcpipGetInfo = IPGetInfo;
SetTcpipStatus.TcpipNdisRequest = IPProxyNdisRequest;
SetTcpipStatus.TcpipSetIPSecStatus = IPSetIPSecStatus;
SetTcpipStatus.TcpipSetIPSecPtr = SetIPSecPtr;
SetTcpipStatus.TcpipUnSetIPSecPtr = UnSetIPSecPtr;
SetTcpipStatus.TcpipUnSetIPSecSendPtr = UnSetIPSecSendPtr;
SetTcpipStatus.TcpipTCPXsum = tcpxsum;
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest( IOCTL_IPSEC_SET_TCPIP_STATUS,
IPSECDeviceObject,
&SetTcpipStatus,
sizeof(IPSEC_SET_TCPIP_STATUS),
NULL,
0,
FALSE,
&Event,
&StatusBlock);
if (Irp) {
status = IoCallDriver(IPSECDeviceObject, Irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject( &Event,
Executive,
KernelMode,
FALSE,
NULL);
status = StatusBlock.Status;
}
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
return (status);
}
NTSTATUS
IpsecDeinitialize(
void
)
/*++
Routine Description:
Deinitialize IPSEC.SYS.
Arguments:
None.
Return Value:
None.
--*/
{
IPSEC_SET_TCPIP_STATUS SetTcpipStatus;
PIRP Irp;
IO_STATUS_BLOCK StatusBlock;
KEVENT Event;
NTSTATUS status;
if (!IPSECFileObject) {
return (STATUS_SUCCESS);
}
RtlZeroMemory(&SetTcpipStatus, sizeof(IPSEC_SET_TCPIP_STATUS));
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest( IOCTL_IPSEC_SET_TCPIP_STATUS,
IPSECDeviceObject,
&SetTcpipStatus,
sizeof(IPSEC_SET_TCPIP_STATUS),
NULL,
0,
FALSE,
&Event,
&StatusBlock);
if (Irp) {
status = IoCallDriver(IPSECDeviceObject, Irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject( &Event,
Executive,
KernelMode,
FALSE,
NULL);
status = StatusBlock.Status;
}
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
ObDereferenceObject(IPSECFileObject);
IPSECFileObject = NULL;
return (status);
}
NTSTATUS
AddNetConfigOpsAce(IN PACL Dacl,
OUT PACL * DeviceAcl
)
/*++
Routine Description:
This routine builds an ACL which gives adds the Network Configuration Operators group
to the principals allowed to control the driver.
Arguments:
Dacl - Existing DACL.
DeviceAcl - Output pointer to the new ACL.
Return Value:
STATUS_SUCCESS or an appropriate error code.
--*/
{
PGENERIC_MAPPING GenericMapping;
PSID AdminsSid = NULL;
PSID SystemSid = NULL;
PSID NetworkSid = NULL;
PSID NetConfigOpsSid = NULL;
ULONG AclLength;
NTSTATUS Status;
ACCESS_MASK AccessMask = GENERIC_ALL;
PACL NewAcl = NULL;
ULONG SidSize;
SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY;
PISID ISid;
PACCESS_ALLOWED_ACE AceTemp;
int i;
//
// Enable access to all the globally defined SIDs
//
GenericMapping = IoGetFileObjectGenericMapping();
RtlMapGenericMask(&AccessMask, GenericMapping);
AdminsSid = SeExports->SeAliasAdminsSid;
SystemSid = SeExports->SeLocalSystemSid;
NetworkSid = SeExports->SeNetworkServiceSid;
SidSize = RtlLengthRequiredSid(3);
NetConfigOpsSid = (PSID)(CTEAllocMemBoot(SidSize));
if (NULL == NetConfigOpsSid) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = RtlInitializeSid(NetConfigOpsSid, &sidAuth, 2);
if (Status != STATUS_SUCCESS) {
goto clean_up;
}
ISid = (PISID)(NetConfigOpsSid);
ISid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
ISid->SubAuthority[1] = DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS;
AclLength = Dacl->AclSize;
AclLength += sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - 2 * sizeof(ULONG);
AclLength += RtlLengthSid(NetConfigOpsSid);
NewAcl = CTEAllocMemBoot(AclLength);
if (NewAcl == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto clean_up;
}
Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION2);
if (!NT_SUCCESS(Status)) {
goto clean_up;
}
for (i = 0; i < Dacl->AceCount; i++) {
Status = RtlGetAce(Dacl, i, &AceTemp);
if (NT_SUCCESS(Status)) {
Status = RtlAddAccessAllowedAce(NewAcl,
ACL_REVISION2,
AceTemp->Mask,
&AceTemp->SidStart);
}
if (!NT_SUCCESS(Status)) {
goto clean_up;
}
}
// Add Net Config Operators Ace
Status = RtlAddAccessAllowedAce(NewAcl,
ACL_REVISION2,
AccessMask,
NetConfigOpsSid);
if (!NT_SUCCESS(Status)) {
goto clean_up;
}
*DeviceAcl = NewAcl;
clean_up:
if (NetConfigOpsSid) {
CTEFreeMem(NetConfigOpsSid);
}
if (!NT_SUCCESS(Status) && NewAcl) {
CTEFreeMem(NewAcl);
}
return (Status);
}
NTSTATUS
CreateDeviceDriverSecurityDescriptor(PVOID DeviceOrDriverObject)
/*++
Routine Description:
Creates the SD responsible for giving access to different users.
Arguments:
DeviceOrDriverObject - Object to which to assign the Access Rights.
Return Value:
STATUS_SUCCESS or an appropriate error code.
--*/
{
NTSTATUS status;
BOOLEAN memoryAllocated = FALSE;
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
ULONG SecurityDescriptorLength;
CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
PSECURITY_DESCRIPTOR localSecurityDescriptor =
(PSECURITY_DESCRIPTOR) & buffer;
SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION;
PACL Dacl = NULL;
BOOLEAN HasDacl = FALSE;
BOOLEAN DaclDefaulted = FALSE;
PACL NewAcl = NULL;
INT i;
//
// Get a pointer to the security descriptor from the driver/device object.
//
status = ObGetObjectSecurity(
DeviceOrDriverObject,
&SecurityDescriptor,
&memoryAllocated
);
if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
"TCP: Unable to get security descriptor, error: %x\n",
status
));
ASSERT(memoryAllocated == FALSE);
return (status);
}
status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, &HasDacl, &Dacl, &DaclDefaulted);
if (NT_SUCCESS(status) && HasDacl)
{
status = AddNetConfigOpsAce(Dacl, &NewAcl);
if (NT_SUCCESS(status)) {
PSECURITY_DESCRIPTOR SecDesc = NULL;
ULONG SecDescSize = 0;
PACL AbsDacl = NULL;
ULONG DaclSize = 0;
PACL AbsSacl = NULL;
ULONG ulSacl = 0;
PSID Owner = NULL;
ULONG OwnerSize = 0;
PSID PrimaryGroup = NULL;
ULONG PrimaryGroupSize = 0;
BOOLEAN OwnerDefault = FALSE;
BOOLEAN GroupDefault = FALSE;
BOOLEAN HasSacl = FALSE;
BOOLEAN SaclDefaulted = FALSE;
SECURITY_INFORMATION secInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
SecDescSize = sizeof(SecDesc) + NewAcl->AclSize;
SecDesc = CTEAllocMemBoot(SecDescSize);
if (SecDesc) {
DaclSize = NewAcl->AclSize;
AbsDacl = CTEAllocMemBoot(DaclSize);
if (AbsDacl) {
status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor, &Owner, &OwnerDefault);
if (NT_SUCCESS(status)) {
OwnerSize = RtlLengthSid(Owner);
status = RtlGetGroupSecurityDescriptor(SecurityDescriptor, &PrimaryGroup, &GroupDefault);
if (NT_SUCCESS(status)) {
PrimaryGroupSize = RtlLengthSid(PrimaryGroup);
status = RtlGetSaclSecurityDescriptor(SecurityDescriptor, &HasSacl, &AbsSacl, &SaclDefaulted);
if (NT_SUCCESS(status)) {
if (HasSacl) {
ulSacl = AbsSacl->AclSize;
secInfo |= SACL_SECURITY_INFORMATION;
}
status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor, SecDesc, &SecDescSize, AbsDacl,
&DaclSize, AbsSacl, &ulSacl, Owner, &OwnerSize, PrimaryGroup, &PrimaryGroupSize);
if (NT_SUCCESS(status)) {
status = RtlSetDaclSecurityDescriptor(SecDesc, TRUE, NewAcl, FALSE);
if (NT_SUCCESS(status)) {
status = ObSetSecurityObjectByPointer(DeviceOrDriverObject, secInfo, SecDesc);
}
}
}
}
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (SecDesc) {
// Since this is a Self-Relative security descriptor, freeing it also frees
// Owner and PrimaryGroup.
CTEFreeMem(SecDesc);
}
if (AbsDacl) {
CTEFreeMem(AbsDacl);
}
}
if (NewAcl) {
CTEFreeMem(NewAcl);
}
}
} else {
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"TCP: No Dacl: %x\n", status));
}
ObReleaseObjectSecurity(
SecurityDescriptor,
memoryAllocated
);
return (status);
}
//
// Function: IsRunningOnPersonal
//
// Purpose: Determines whether running on Whistler Personal
//
// Returns: Returns true if running on Personal - FALSE otherwise
BOOLEAN
IsRunningOnPersonal(
VOID
)
{
OSVERSIONINFOEXW OsVer = {0};
ULONGLONG ConditionMask = 0;
BOOLEAN IsPersonal = TRUE;
OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
OsVer.wSuiteMask = VER_SUITE_PERSONAL;
OsVer.wProductType = VER_NT_WORKSTATION;
VER_SET_CONDITION(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_AND);
if (RtlVerifyVersionInfo(&OsVer, VER_PRODUCT_TYPE | VER_SUITENAME,
ConditionMask) == STATUS_REVISION_MISMATCH) {
IsPersonal = FALSE;
}
return IsPersonal;
}
#endif