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.
2852 lines
82 KiB
2852 lines
82 KiB
/*++
|
|
|
|
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"
|
|
#include "info.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;
|
|
|
|
|
|
GPC_STATUS GPCcfInfoAddNotifyIpsec(GPC_CLIENT_HANDLE ClCtxt,
|
|
GPC_HANDLE GpcHandle,
|
|
PTC_INTERFACE_ID InterfaceInfo,
|
|
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,
|
|
PTC_INTERFACE_ID InterfaceInfo,
|
|
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;
|
|
|
|
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-attack protection checks are made
|
|
|
|
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);
|
|
|
|
#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);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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
|
|
|
|
//
|
|
// Initialize the connection callback object. We do not treat its
|
|
// failure as fatal, and continue to function even in case of failure.
|
|
// We may log it in the future.
|
|
//
|
|
TcpInitCcb();
|
|
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if (ExIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) {
|
|
tcpxsum_routine = tcpxsum_xmmi;
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip: Loading XMMI Prefetch Checksum\n"));
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
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;
|
|
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
|
|
TCPMaxHalfOpen = 100;
|
|
TCPMaxHalfOpenRetried = 80;
|
|
#else // MILLEN
|
|
if (!MmIsThisAnNtAsSystem()) {
|
|
TCPMaxHalfOpen = 100;
|
|
TCPMaxHalfOpenRetried = 80;
|
|
} else {
|
|
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 | OBJ_KERNEL_HANDLE,
|
|
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",
|
|
(PULONG)&KAInterval
|
|
);
|
|
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"KeepAliveTime",
|
|
(PULONG)&KeepAliveTime
|
|
);
|
|
|
|
status = TCPInitializeParameter(
|
|
keyHandle,
|
|
L"EnablePMTUBHDetect",
|
|
(PULONG)&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",
|
|
(PULONG)&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
|
|
|
|
// We can not have negative size windows
|
|
if ( (LONG) DefaultRcvWin < 0 ) {
|
|
DefaultRcvWin = TCP_MAX_SCALED_WIN;
|
|
}
|
|
|
|
status = TCPInitializeParameter(
|
|
keyHandle,
|
|
L"TcpNumConnections",
|
|
(PULONG)&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",
|
|
(PULONG)&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",
|
|
(PULONG)&NumTcbTablePartitions
|
|
);
|
|
if (NumTcbTablePartitions > (MAXIMUM_PROCESSORS * MAXIMUM_PROCESSORS)) {
|
|
NumTcbTablePartitions = (MAXIMUM_PROCESSORS * MAXIMUM_PROCESSORS);
|
|
}
|
|
NumTcbTablePartitions = ComputeLargerOrEqualPowerOfTwo(NumTcbTablePartitions);
|
|
|
|
|
|
// Default to 128 buckets per partition
|
|
MaxHashTableSize = 128 * NumTcbTablePartitions;
|
|
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"MaxHashTableSize",
|
|
(PULONG)&MaxHashTableSize
|
|
);
|
|
|
|
if (MaxHashTableSize < 64) {
|
|
MaxHashTableSize = 64;
|
|
} else if (MaxHashTableSize > 0xffff) {
|
|
MaxHashTableSize = 0x10000;
|
|
}
|
|
MaxHashTableSize = ComputeLargerOrEqualPowerOfTwo(MaxHashTableSize);
|
|
if (MaxHashTableSize < NumTcbTablePartitions) {
|
|
MaxHashTableSize = 128 * 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);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
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",
|
|
(PULONG)&GlobalMaxRcvWin
|
|
);
|
|
|
|
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"SynAttackProtect",
|
|
(unsigned long *)&SynAttackProtect
|
|
);
|
|
|
|
if (SynAttackProtect) {
|
|
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"TCPMaxHalfOpen",
|
|
(PULONG)&TCPMaxHalfOpen
|
|
);
|
|
|
|
if (TCPMaxHalfOpen < MIN_THRESHOLD_MAX_HO) {
|
|
TCPMaxHalfOpen = MIN_THRESHOLD_MAX_HO;
|
|
}
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"TCPMaxHalfOpenRetried",
|
|
(PULONG)&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",
|
|
(PULONG)&FinWait2TO
|
|
);
|
|
|
|
if (FinWait2TO > 300) {
|
|
FinWait2TO = 300;
|
|
}
|
|
FinWait2TO = MS_TO_TICKS(FinWait2TO * 1000);
|
|
|
|
NTWMaxConnectTime = MS_TO_TICKS(NTWMaxConnectTime * 1000);
|
|
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"MaxUserPort",
|
|
(PULONG)&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",
|
|
(PULONG)&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",
|
|
(PULONG)&DeadGWDetect
|
|
);
|
|
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"EnableSecurityFilters",
|
|
(PULONG)&SecurityFilteringEnabled
|
|
);
|
|
|
|
#ifdef ACC
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"AllowUserRawAccess",
|
|
(PULONG)&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",
|
|
(PULONG)&MaxSendSegments
|
|
);
|
|
|
|
TCPInitializeParameter(
|
|
keyHandle,
|
|
L"DisableLargeSendOffload",
|
|
(PULONG)&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);
|
|
|
|
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;
|
|
TimerWheel = (PTIMER_WHEEL)(((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);
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// 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;
|
|
|
|
TcpUnInitCcb();
|
|
|
|
#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,
|
|
PTC_INTERFACE_ID InterfaceInfo,
|
|
ULONG CfInfoSize,
|
|
PVOID CfInfo,
|
|
PGPC_CLIENT_HANDLE pClInfoCxt)
|
|
{
|
|
InterlockedIncrement((PLONG)&GPCcfInfo);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_GPC)
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo Add notification %x\n", GPCcfInfo));
|
|
|
|
InterlockedIncrement((PLONG)&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((PLONG)&GPCcfInfo);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_GPC)
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo remove notification %x\n", GPCcfInfo));
|
|
|
|
InterlockedDecrement((PLONG)&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,
|
|
PTC_INTERFACE_ID InterfaceInfo,
|
|
ULONG CfInfoSize,
|
|
PVOID CfInfo,
|
|
PGPC_CLIENT_HANDLE pClInfoCxt)
|
|
{
|
|
InterlockedIncrement((PLONG)&GPCcfInfo);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_GPC)
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo Add notification %x\n", GPCcfInfo));
|
|
|
|
InterlockedIncrement((PLONG)&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((PLONG)&GPCcfInfo);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_GPC)
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"tcpip - Cfinfo remove notification %x\n", GPCcfInfo));
|
|
|
|
InterlockedDecrement((PLONG)&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 * FIELD_OFFSET(ACCESS_ALLOWED_ACE,SidStart) +
|
|
RtlLengthSid(AdminsSid) +
|
|
RtlLengthSid(SystemSid) +
|
|
RtlLengthSid(NetworkSid);
|
|
|
|
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_REVISION,
|
|
AccessMask,
|
|
AdminsSid
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(
|
|
NewAcl,
|
|
ACL_REVISION,
|
|
AccessMask,
|
|
SystemSid
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
// Add acl for NetworkSid!
|
|
|
|
Status = RtlAddAccessAllowedAce(
|
|
NewAcl,
|
|
ACL_REVISION,
|
|
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;
|
|
SetTcpipStatus.TcpipSendICMPErr = SendICMPErr;
|
|
|
|
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 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;
|
|
PACE_HEADER AceTemp;
|
|
int i;
|
|
//
|
|
// Enable access to all the globally defined SIDs
|
|
//
|
|
|
|
GenericMapping = IoGetFileObjectGenericMapping();
|
|
|
|
RtlMapGenericMask(&AccessMask, GenericMapping);
|
|
|
|
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;
|
|
}
|
|
|
|
*RtlSubAuthoritySid(NetConfigOpsSid, 0) =
|
|
SECURITY_BUILTIN_DOMAIN_RID;
|
|
*RtlSubAuthoritySid(NetConfigOpsSid, 1) =
|
|
DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS;
|
|
|
|
AclLength = Dacl->AclSize;
|
|
|
|
AclLength = Dacl->AclSize +
|
|
2*FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) +
|
|
RtlLengthSid(NetConfigOpsSid) +
|
|
RtlLengthSid(NetworkSid);
|
|
|
|
NewAcl = CTEAllocMemBoot(AclLength);
|
|
|
|
if (NewAcl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto clean_up;
|
|
}
|
|
|
|
Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto clean_up;
|
|
}
|
|
|
|
for (i = 0; i < Dacl->AceCount; i++) {
|
|
Status = RtlGetAce(Dacl, i, &AceTemp);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = RtlAddAce(NewAcl, ACL_REVISION, MAXULONG, AceTemp,
|
|
AceTemp->AceSize);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto clean_up;
|
|
}
|
|
}
|
|
|
|
// Add Net Config Operators Ace
|
|
Status = RtlAddAccessAllowedAce(NewAcl,
|
|
ACL_REVISION,
|
|
AccessMask,
|
|
NetConfigOpsSid);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto clean_up;
|
|
}
|
|
|
|
|
|
// Add Network Services Ace
|
|
Status = RtlAddAccessAllowedAce(NewAcl,
|
|
ACL_REVISION,
|
|
AccessMask,
|
|
NetworkSid);
|
|
|
|
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;
|
|
PACL Dacl = NULL;
|
|
BOOLEAN HasDacl = FALSE;
|
|
BOOLEAN DaclDefaulted = FALSE;
|
|
PACL NewAcl = NULL;
|
|
|
|
//
|
|
// 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 && Dacl != NULL)
|
|
{
|
|
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
|
|
|
|
|
|
|