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.
535 lines
15 KiB
535 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1989-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
init.c
|
|
|
|
Abstract:
|
|
|
|
Initialization
|
|
|
|
Author:
|
|
|
|
Jiandong Ruan
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "init.tmh"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, SmbInitRegistry)
|
|
#pragma alloc_text(PAGE, SmbShutdownRegistry)
|
|
#pragma alloc_text(PAGE, SmbInitTdi)
|
|
#pragma alloc_text(PAGE, SmbShutdownTdi)
|
|
#pragma alloc_text(INIT, SmbCreateSmbDevice)
|
|
#pragma alloc_text(PAGE, SmbDestroySmbDevice)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
SmbInitRegistry(
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
{
|
|
OBJECT_ATTRIBUTES ObAttr;
|
|
NTSTATUS status;
|
|
HANDLE hKey = NULL;
|
|
UNICODE_STRING uncParams;
|
|
ULONG Disposition;
|
|
|
|
PAGED_CODE();
|
|
|
|
InitializeObjectAttributes (
|
|
&ObAttr,
|
|
RegistryPath,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
status = ZwOpenKey (
|
|
&hKey,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObAttr
|
|
);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
RtlInitUnicodeString(&uncParams, L"Parameters");
|
|
InitializeObjectAttributes (
|
|
&ObAttr,
|
|
&uncParams,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
hKey,
|
|
NULL
|
|
);
|
|
status = ZwCreateKey(
|
|
&SmbCfg.ParametersKey,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObAttr,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&Disposition
|
|
);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
RtlInitUnicodeString(&uncParams, L"Linkage");
|
|
InitializeObjectAttributes (
|
|
&ObAttr,
|
|
&uncParams,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
hKey,
|
|
NULL
|
|
);
|
|
status = ZwCreateKey(
|
|
&SmbCfg.LinkageKey,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObAttr,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&Disposition
|
|
);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
ZwClose(hKey);
|
|
hKey = NULL;
|
|
return status;
|
|
|
|
cleanup:
|
|
if (SmbCfg.LinkageKey) {
|
|
ZwClose(SmbCfg.LinkageKey);
|
|
SmbCfg.LinkageKey = NULL;
|
|
}
|
|
if (SmbCfg.ParametersKey) {
|
|
ZwClose(SmbCfg.ParametersKey);
|
|
SmbCfg.ParametersKey = NULL;
|
|
}
|
|
if (hKey) {
|
|
ZwClose(hKey);
|
|
}
|
|
SmbTrace(SMB_TRACE_ERRORS, ("returns %!status!", status));
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
SmbShutdownRegistry(
|
|
VOID
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (SmbCfg.ParametersKey) {
|
|
ZwClose(SmbCfg.ParametersKey);
|
|
SmbCfg.ParametersKey = NULL;
|
|
}
|
|
if (SmbCfg.LinkageKey) {
|
|
ZwClose(SmbCfg.LinkageKey);
|
|
SmbCfg.LinkageKey = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef STANDALONE_SMB
|
|
NTSTATUS
|
|
SmbInitTdi(
|
|
VOID
|
|
)
|
|
{
|
|
UNICODE_STRING ucSmbClientName;
|
|
UNICODE_STRING ucSmbProviderName;
|
|
TDI_CLIENT_INTERFACE_INFO TdiClientInterface;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(&ucSmbProviderName, WC_SMB_TDI_PROVIDER_NAME);
|
|
status = TdiRegisterProvider (&ucSmbProviderName, &SmbCfg.TdiProviderHandle);
|
|
if (NT_SUCCESS (status)) {
|
|
//
|
|
// Register our Handlers with TDI
|
|
//
|
|
RtlInitUnicodeString(&ucSmbClientName, WC_SMB_TDI_CLIENT_NAME);
|
|
RtlZeroMemory(&TdiClientInterface, sizeof(TdiClientInterface));
|
|
|
|
TdiClientInterface.MajorTdiVersion = MAJOR_TDI_VERSION;
|
|
TdiClientInterface.MinorTdiVersion = MINOR_TDI_VERSION;
|
|
TdiClientInterface.ClientName = &ucSmbClientName;
|
|
TdiClientInterface.AddAddressHandlerV2 = SmbAddressArrival;
|
|
TdiClientInterface.DelAddressHandlerV2 = SmbAddressDeletion;
|
|
TdiClientInterface.BindingHandler = SmbBindHandler;
|
|
TdiClientInterface.PnPPowerHandler = NULL;
|
|
|
|
status = TdiRegisterPnPHandlers (&TdiClientInterface, sizeof(TdiClientInterface), &SmbCfg.TdiClientHandle);
|
|
if (!NT_SUCCESS (status)) {
|
|
TdiDeregisterProvider (SmbCfg.TdiProviderHandle);
|
|
SmbCfg.TdiProviderHandle = NULL;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
SmbShutdownTdi(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (SmbCfg.TdiClientHandle) {
|
|
status = TdiDeregisterPnPHandlers(SmbCfg.TdiClientHandle);
|
|
SmbCfg.TdiClientHandle = NULL;
|
|
}
|
|
if (SmbCfg.TdiProviderHandle) {
|
|
status = TdiDeregisterProvider(SmbCfg.TdiProviderHandle);
|
|
SmbCfg.TdiProviderHandle = NULL;
|
|
}
|
|
}
|
|
#else
|
|
VOID
|
|
SmbSetTdiHandles(
|
|
HANDLE ProviderHandle,
|
|
HANDLE ClientHandle
|
|
)
|
|
{
|
|
SmbCfg.TdiClientHandle = ClientHandle;
|
|
SmbCfg.TdiProviderHandle = ProviderHandle;
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
SmbBuildDeviceAcl(
|
|
OUT PACL * DeviceAcl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Lifted from SMB - SmbBuildDeviceAcl)
|
|
This routine builds an ACL which gives Administrators, LocalService and NetworkService
|
|
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, ServiceSid, 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;
|
|
ServiceSid = SeExports->SeLocalServiceSid;
|
|
NetworkSid = SeExports->SeNetworkServiceSid;
|
|
|
|
AclLength = sizeof(ACL) +
|
|
3 * sizeof(ACCESS_ALLOWED_ACE) +
|
|
RtlLengthSid(AdminsSid) +
|
|
RtlLengthSid(ServiceSid) +
|
|
RtlLengthSid(NetworkSid) -
|
|
3 * sizeof(ULONG);
|
|
|
|
NewAcl = ExAllocatePoolWithTag(PagedPool, AclLength, 'ABMS');
|
|
|
|
if (NewAcl == NULL) {
|
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ExFreePool(NewAcl);
|
|
return (Status);
|
|
}
|
|
Status = RtlAddAccessAllowedAce(
|
|
NewAcl,
|
|
ACL_REVISION2,
|
|
AccessMask,
|
|
AdminsSid
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
if (!NT_SUCCESS(Status)) {
|
|
ExFreePool(NewAcl);
|
|
return (Status);
|
|
}
|
|
|
|
Status = RtlAddAccessAllowedAce(
|
|
NewAcl,
|
|
ACL_REVISION2,
|
|
AccessMask,
|
|
ServiceSid
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
if (!NT_SUCCESS(Status)) {
|
|
ExFreePool(NewAcl);
|
|
return (Status);
|
|
}
|
|
|
|
Status = RtlAddAccessAllowedAce(
|
|
NewAcl,
|
|
ACL_REVISION2,
|
|
AccessMask,
|
|
NetworkSid
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
if (!NT_SUCCESS(Status)) {
|
|
ExFreePool(NewAcl);
|
|
return (Status);
|
|
}
|
|
|
|
*DeviceAcl = NewAcl;
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbCreateAdminSecurityDescriptor(PDEVICE_OBJECT dev)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Lifted from NETBT - SmbCreateAdminSecurityDescriptor)
|
|
This routine creates a security descriptor which gives access
|
|
only to Administrtors and LocalService. 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;
|
|
CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR localSecurityDescriptor = (PSECURITY_DESCRIPTOR) buffer;
|
|
SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION;
|
|
|
|
//
|
|
// Build a local security descriptor with an ACL giving only
|
|
// administrators and service access.
|
|
//
|
|
status = SmbBuildDeviceAcl(&rawAcl);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
SmbPrint(SMB_TRACE_PNP, ("SMB: Unable to create Raw ACL, error: 0x%08lx\n", status));
|
|
return (status);
|
|
}
|
|
|
|
(VOID) RtlCreateSecurityDescriptor(
|
|
localSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
|
|
(VOID) RtlSetDaclSecurityDescriptor(
|
|
localSecurityDescriptor,
|
|
TRUE,
|
|
rawAcl,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Now apply the local descriptor to the raw descriptor.
|
|
//
|
|
status = SeSetSecurityDescriptorInfo(
|
|
NULL,
|
|
&securityInformation,
|
|
localSecurityDescriptor,
|
|
&dev->SecurityDescriptor,
|
|
PagedPool,
|
|
IoGetFileObjectGenericMapping()
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
SmbPrint(SMB_TRACE_PNP, ("SMB: SeSetSecurity failed: 0x%08lx\n", status));
|
|
}
|
|
|
|
ExFreePool(rawAcl);
|
|
return (status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmbCreateSmbDevice(
|
|
PSMB_DEVICE *ppDevice,
|
|
USHORT Port,
|
|
UCHAR EndpointName[NETBIOS_NAME_SIZE]
|
|
)
|
|
{
|
|
PSMB_DEVICE DeviceObject;
|
|
NTSTATUS status;
|
|
UNICODE_STRING ExportName, ucName;
|
|
|
|
DeviceObject = NULL;
|
|
*ppDevice = NULL;
|
|
|
|
RtlInitUnicodeString(&ExportName, DD_SMB6_EXPORT_NAME);
|
|
status = IoCreateDevice(
|
|
SmbCfg.DriverObject,
|
|
sizeof(SMB_DEVICE) - sizeof(DEVICE_OBJECT),
|
|
&ExportName,
|
|
FILE_DEVICE_NETWORK,
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
FALSE,
|
|
(PDEVICE_OBJECT*)&DeviceObject
|
|
);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
DeviceObject->Tag = TAG_SMB6_DEVICE;
|
|
KeInitializeSpinLock(&DeviceObject->Lock);
|
|
InitializeListHead(&DeviceObject->UnassociatedConnectionList);
|
|
InitializeListHead(&DeviceObject->ClientList);
|
|
InitializeListHead(&DeviceObject->PendingDeleteConnectionList);
|
|
InitializeListHead(&DeviceObject->PendingDeleteClientList);
|
|
|
|
DeviceObject->ClientBinding = NULL;
|
|
DeviceObject->ServerBinding = NULL;
|
|
|
|
//
|
|
// initialization for FIN attack protection
|
|
//
|
|
DeviceObject->FinAttackProtectionMode = FALSE;
|
|
DeviceObject->LeaveFAPM = SmbReadLong (SmbCfg.ParametersKey, SMB_REG_LEAVE_FAPM, 50, 5);
|
|
DeviceObject->EnterFAPM = SmbReadLong (SmbCfg.ParametersKey, SMB_REG_ENTER_FAPM,
|
|
400, DeviceObject->LeaveFAPM + 50);
|
|
ASSERT(DeviceObject->EnterFAPM > DeviceObject->LeaveFAPM);
|
|
if (DeviceObject->LeaveFAPM >= DeviceObject->EnterFAPM) {
|
|
DeviceObject->EnterFAPM = 2 * DeviceObject->LeaveFAPM;
|
|
}
|
|
if (DeviceObject->LeaveFAPM >= DeviceObject->EnterFAPM) {
|
|
//
|
|
// This means overflow above
|
|
//
|
|
DeviceObject->LeaveFAPM = 50;
|
|
DeviceObject->EnterFAPM = 400;
|
|
}
|
|
|
|
//
|
|
// initialization for synch attack protection
|
|
//
|
|
DeviceObject->MaxBackLog = SmbReadLong(SmbCfg.ParametersKey, L"MaxBackLog", 1000, 100);
|
|
|
|
InitializeListHead(&DeviceObject->DelayedDisconnectList);
|
|
|
|
InitializeListHead(&DeviceObject->DelayedDisconnectList);
|
|
InitializeListHead(&DeviceObject->PendingDisconnectList);
|
|
DeviceObject->PendingDisconnectListNumber = 0;
|
|
KeInitializeEvent(&DeviceObject->PendingDisconnectListEmptyEvent,
|
|
NotificationEvent, TRUE);
|
|
DeviceObject->DisconnectWorkerRunning = FALSE;
|
|
|
|
DeviceObject->ConnectionPoolWorkerQueued = FALSE;
|
|
|
|
DeviceObject->SmbServer = NULL;
|
|
RtlCopyMemory(DeviceObject->EndpointName, EndpointName, NETBIOS_NAME_SIZE);
|
|
ASSERT(DeviceObject->EndpointName[NETBIOS_NAME_SIZE-1] == 0x20);
|
|
|
|
DeviceObject->Port = Port;
|
|
SmbCfg.Tcp4Available = FALSE;
|
|
SmbCfg.Tcp6Available = FALSE;
|
|
|
|
SmbCreateAdminSecurityDescriptor(&DeviceObject->DeviceObject);
|
|
|
|
*ppDevice = DeviceObject;
|
|
return status;
|
|
|
|
cleanup:
|
|
if (DeviceObject) {
|
|
if (SmbCfg.Tcp4Available) {
|
|
SmbShutdownTCP(&DeviceObject->Tcp4);
|
|
SmbCfg.Tcp4Available = FALSE;
|
|
}
|
|
if (SmbCfg.Tcp6Available) {
|
|
SmbShutdownTCP(&DeviceObject->Tcp6);
|
|
SmbCfg.Tcp6Available = FALSE;
|
|
}
|
|
IoDeleteDevice((PDEVICE_OBJECT)DeviceObject);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbDestroySmbDevice(
|
|
PSMB_DEVICE pDevice
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(SmbCfg.Unloading);
|
|
|
|
if (NULL == pDevice) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
SmbTdiDeregister(pDevice);
|
|
|
|
status = KeWaitForSingleObject(
|
|
&pDevice->PendingDisconnectListEmptyEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
ASSERT(status == STATUS_WAIT_0);
|
|
|
|
ASSERT(IsListEmpty(&pDevice->DelayedDisconnectList));
|
|
ASSERT(IsListEmpty(&pDevice->PendingDisconnectList) && pDevice->PendingDisconnectListNumber == 0);
|
|
ASSERT(IsListEmpty(&pDevice->PendingDeleteConnectionList));
|
|
ASSERT(IsListEmpty(&pDevice->PendingDeleteClientList));
|
|
|
|
if (SmbCfg.Tcp4Available) {
|
|
status = SmbShutdownTCP(&pDevice->Tcp4);
|
|
ASSERT(status == STATUS_SUCCESS);
|
|
SmbCfg.Tcp4Available = FALSE;
|
|
}
|
|
if (SmbCfg.Tcp6Available) {
|
|
status = SmbShutdownTCP(&pDevice->Tcp6);
|
|
ASSERT(status == STATUS_SUCCESS);
|
|
SmbCfg.Tcp6Available = FALSE;
|
|
}
|
|
ASSERT(status == STATUS_SUCCESS);
|
|
|
|
SmbShutdownPnP();
|
|
|
|
if (pDevice->ClientBinding) {
|
|
ExFreePool(pDevice->ClientBinding);
|
|
pDevice->ClientBinding = NULL;
|
|
}
|
|
if (pDevice->ServerBinding) {
|
|
ExFreePool(pDevice->ServerBinding);
|
|
pDevice->ServerBinding = NULL;
|
|
}
|
|
IoDeleteDevice((PDEVICE_OBJECT)pDevice);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|