/*++ 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; }