672 lines
18 KiB
C
672 lines
18 KiB
C
#include "precomp.h"
|
|
|
|
typedef ULONG SECURITY_INFORMATION;
|
|
|
|
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 NetConfigOpsSid = NULL;
|
|
PSID NetworkServiceSid = 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;
|
|
NetworkServiceSid = SeExports->SeNetworkServiceSid;
|
|
|
|
SidSize = RtlLengthRequiredSid(2);
|
|
NetConfigOpsSid = (PSID)(ExAllocatePool(PagedPool,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 = ExAllocatePool(
|
|
PagedPool,
|
|
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;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto clean_up;
|
|
}
|
|
|
|
*DeviceAcl = NewAcl;
|
|
|
|
clean_up:
|
|
if (NetConfigOpsSid) {
|
|
ExFreePool(NetConfigOpsSid);
|
|
}
|
|
if (!NT_SUCCESS(Status) && NewAcl) {
|
|
ExFreePool(NewAcl);
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CreateDeviceDriverSecurityDescriptor(PVOID DeviceOrDriverObject)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates the SD responsible for giving access to different users.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or an appropriate error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
BOOLEAN memoryAllocated = FALSE;
|
|
PSECURITY_DESCRIPTOR sdSecurityDescriptor = NULL;
|
|
ULONG sdSecurityDescriptorLength;
|
|
CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR localSecurityDescriptor =
|
|
(PSECURITY_DESCRIPTOR) & buffer;
|
|
SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION;
|
|
PACL paclDacl = NULL;
|
|
BOOLEAN bHasDacl;
|
|
BOOLEAN bDaclDefaulted;
|
|
PACCESS_ALLOWED_ACE pAce = NULL;
|
|
PACL NewAcl = NULL;
|
|
INT i;
|
|
|
|
//
|
|
// Get a pointer to the security descriptor from the driver/device object.
|
|
//
|
|
|
|
status = ObGetObjectSecurity(
|
|
DeviceOrDriverObject,
|
|
&sdSecurityDescriptor,
|
|
&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(sdSecurityDescriptor, &bHasDacl, &paclDacl, &bDaclDefaulted);
|
|
|
|
if (bHasDacl)
|
|
{
|
|
status = AddNetConfigOpsAce(paclDacl, &NewAcl);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
PSECURITY_DESCRIPTOR sdSecDesc = NULL;
|
|
ULONG ulSecDescSize = 0;
|
|
PACL daclAbs = NULL;
|
|
ULONG ulDacl = 0;
|
|
PACL saclAbs = NULL;
|
|
ULONG ulSacl = 0;
|
|
PSID Owner = NULL;
|
|
ULONG ulOwnerSize = 0;
|
|
PSID PrimaryGroup = NULL;
|
|
ULONG ulPrimaryGroupSize = 0;
|
|
BOOLEAN bOwnerDefault;
|
|
BOOLEAN bGroupDefault;
|
|
BOOLEAN HasSacl = FALSE;
|
|
BOOLEAN SaclDefaulted = FALSE;
|
|
SECURITY_INFORMATION secInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
|
HANDLE hIp;
|
|
HANDLE hTcp;
|
|
|
|
ulSecDescSize = sizeof(sdSecDesc) + NewAcl->AclSize;
|
|
sdSecDesc = ExAllocatePool(PagedPool, ulSecDescSize);
|
|
|
|
if (sdSecDesc)
|
|
{
|
|
ulDacl = NewAcl->AclSize;
|
|
daclAbs = ExAllocatePool(PagedPool, ulDacl);
|
|
|
|
if (daclAbs)
|
|
{
|
|
status = RtlGetOwnerSecurityDescriptor(sdSecurityDescriptor, &Owner, &bOwnerDefault);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
ulOwnerSize = RtlLengthSid(Owner);
|
|
|
|
status = RtlGetGroupSecurityDescriptor(sdSecurityDescriptor, &PrimaryGroup, &bGroupDefault);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = RtlGetSaclSecurityDescriptor(sdSecurityDescriptor, &HasSacl, &saclAbs, &SaclDefaulted);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
if (HasSacl)
|
|
{
|
|
ulSacl = saclAbs->AclSize;
|
|
secInfo |= SACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
ulPrimaryGroupSize= RtlLengthSid(PrimaryGroup);
|
|
|
|
status = RtlSelfRelativeToAbsoluteSD(sdSecurityDescriptor, sdSecDesc, &ulSecDescSize, daclAbs,
|
|
&ulDacl, saclAbs, &ulSacl, Owner, &ulOwnerSize, PrimaryGroup, &ulPrimaryGroupSize);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = RtlSetDaclSecurityDescriptor(sdSecDesc, TRUE, NewAcl, FALSE);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = ObSetSecurityObjectByPointer(DeviceOrDriverObject, secInfo, sdSecDesc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sdSecDesc)
|
|
{
|
|
// Since this is a Self-Relative security descriptor, freeing it also frees
|
|
// Owner and PrimaryGroup.
|
|
ExFreePool(sdSecDesc);
|
|
}
|
|
|
|
if (daclAbs)
|
|
{
|
|
ExFreePool(daclAbs);
|
|
}
|
|
}
|
|
|
|
if (NewAcl)
|
|
{
|
|
ExFreePool(NewAcl);
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"TCP: No Dacl: %x\n", status));
|
|
}
|
|
|
|
ObReleaseObjectSecurity(
|
|
sdSecurityDescriptor,
|
|
memoryAllocated
|
|
);
|
|
|
|
return (status);
|
|
}
|
|
|
|
NTSTATUS
|
|
ndisBuildDeviceAcl(
|
|
OUT PACL *DeviceAcl,
|
|
IN BOOLEAN AddNetConfigOps
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds an ACL which gives Administrators, LocalSystem,
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PGENERIC_MAPPING GenericMapping;
|
|
ULONG AclLength;
|
|
ACCESS_MASK AccessMask = GENERIC_ALL;
|
|
PACL NewAcl;
|
|
PSID NetConfigOpsSid = NULL;
|
|
ULONG NetConfigOpsSidSize;
|
|
SID_IDENTIFIER_AUTHORITY NetConfigOpsSidAuth = SECURITY_NT_AUTHORITY;
|
|
PISID ISid;
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// Enable access to all the globally defined SIDs
|
|
//
|
|
|
|
GenericMapping = IoGetFileObjectGenericMapping();
|
|
|
|
RtlMapGenericMask(&AccessMask, GenericMapping );
|
|
|
|
|
|
AclLength = sizeof(ACL) +
|
|
FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) +
|
|
RtlLengthSid(SeExports->SeAliasAdminsSid);
|
|
|
|
|
|
if (AddNetConfigOps)
|
|
{
|
|
NetConfigOpsSidSize = RtlLengthRequiredSid(2);
|
|
NetConfigOpsSid = (PSID)ALLOC_FROM_POOL(NetConfigOpsSidSize, NDIS_TAG_NET_CFG_OPS_ID);
|
|
|
|
if (NULL == NetConfigOpsSid)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
Status = RtlInitializeSid(NetConfigOpsSid, &NetConfigOpsSidAuth, 2);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
ISid = (PISID)(NetConfigOpsSid);
|
|
ISid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
|
|
ISid->SubAuthority[1] = DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS;
|
|
|
|
AclLength += RtlLengthSid(NetConfigOpsSid) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart);
|
|
}
|
|
|
|
NewAcl = ALLOC_FROM_POOL(AclLength, NDIS_TAG_SECURITY);
|
|
|
|
if (NewAcl == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(NewAcl, AclLength);
|
|
|
|
Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION );
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
FREE_POOL(NewAcl);
|
|
break;
|
|
}
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
NewAcl,
|
|
ACL_REVISION2,
|
|
AccessMask,
|
|
SeExports->SeAliasAdminsSid
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (AddNetConfigOps)
|
|
{
|
|
// Add Net Config Operators Ace
|
|
Status = RtlAddAccessAllowedAce(NewAcl,
|
|
ACL_REVISION2,
|
|
AccessMask,
|
|
NetConfigOpsSid);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
|
|
|
|
*DeviceAcl = NewAcl;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}while (FALSE);
|
|
|
|
if (NetConfigOpsSid)
|
|
{
|
|
ExFreePool(NetConfigOpsSid);
|
|
}
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ndisCreateSecurityDescriptor(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT PSECURITY_DESCRIPTOR * pSecurityDescriptor,
|
|
BOOLEAN AddNetConfigOps
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a security descriptor which gives access
|
|
only to certain priviliged accounts. This descriptor is used
|
|
to access check processes that open a handle to miniport device
|
|
objects.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or an appropriate error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PACL devAcl = NULL;
|
|
NTSTATUS Status;
|
|
BOOLEAN memoryAllocated = FALSE;
|
|
PSECURITY_DESCRIPTOR CurSecurityDescriptor;
|
|
PSECURITY_DESCRIPTOR NewSecurityDescriptor;
|
|
ULONG CurSecurityDescriptorLength;
|
|
CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR localSecurityDescriptor =
|
|
(PSECURITY_DESCRIPTOR)buffer;
|
|
SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION;
|
|
BOOLEAN bReleaseObjectSecurity = FALSE;
|
|
|
|
|
|
do
|
|
{
|
|
|
|
*pSecurityDescriptor = NULL;
|
|
|
|
//
|
|
// Get a pointer to the security descriptor from the device object.
|
|
//
|
|
Status = ObGetObjectSecurity(
|
|
DeviceObject,
|
|
&CurSecurityDescriptor,
|
|
&memoryAllocated
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ASSERT(memoryAllocated == FALSE);
|
|
break;
|
|
}
|
|
bReleaseObjectSecurity = TRUE;
|
|
|
|
//
|
|
// Build a local security descriptor with an ACL giving only
|
|
// certain priviliged accounts.
|
|
//
|
|
Status = ndisBuildDeviceAcl(&devAcl, AddNetConfigOps);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
(VOID)RtlCreateSecurityDescriptor(
|
|
localSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
|
|
(VOID)RtlSetDaclSecurityDescriptor(
|
|
localSecurityDescriptor,
|
|
TRUE,
|
|
devAcl,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Make a copy of the security descriptor. This copy will be the raw descriptor.
|
|
//
|
|
CurSecurityDescriptorLength = RtlLengthSecurityDescriptor(
|
|
CurSecurityDescriptor
|
|
);
|
|
|
|
NewSecurityDescriptor = ALLOC_FROM_POOL(CurSecurityDescriptorLength, NDIS_TAG_SECURITY);
|
|
|
|
if (NewSecurityDescriptor == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
RtlMoveMemory(
|
|
NewSecurityDescriptor,
|
|
CurSecurityDescriptor,
|
|
CurSecurityDescriptorLength
|
|
);
|
|
|
|
*pSecurityDescriptor = NewSecurityDescriptor;
|
|
|
|
//
|
|
// Now apply the local descriptor to the raw descriptor.
|
|
//
|
|
Status = SeSetSecurityDescriptorInfo(
|
|
NULL,
|
|
&securityInformation,
|
|
localSecurityDescriptor,
|
|
pSecurityDescriptor,
|
|
NonPagedPool,
|
|
IoGetFileObjectGenericMapping()
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ASSERT(*pSecurityDescriptor == NewSecurityDescriptor);
|
|
FREE_POOL(*pSecurityDescriptor);
|
|
*pSecurityDescriptor = NULL;
|
|
break;
|
|
}
|
|
|
|
if (*pSecurityDescriptor != NewSecurityDescriptor)
|
|
{
|
|
ExFreePool(NewSecurityDescriptor);
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}while (FALSE);
|
|
|
|
|
|
if (bReleaseObjectSecurity)
|
|
{
|
|
ObReleaseObjectSecurity(
|
|
CurSecurityDescriptor,
|
|
memoryAllocated
|
|
);
|
|
}
|
|
|
|
if (devAcl!=NULL)
|
|
{
|
|
FREE_POOL(devAcl);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
BOOLEAN
|
|
ndisCheckAccess (
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp,
|
|
PNTSTATUS Status,
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compares security context of the endpoint creator to that
|
|
of the administrator and local system.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet.
|
|
|
|
IrpSp - pointer to the IO stack location to use for this request.
|
|
|
|
Status - returns status generated by access check on failure.
|
|
|
|
Return Value:
|
|
|
|
TRUE - the creator has admin or local system privilige
|
|
FALSE - the creator is just a plain user
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN accessGranted;
|
|
PACCESS_STATE accessState;
|
|
PIO_SECURITY_CONTEXT securityContext;
|
|
PPRIVILEGE_SET privileges = NULL;
|
|
ACCESS_MASK grantedAccess;
|
|
PGENERIC_MAPPING GenericMapping;
|
|
ACCESS_MASK AccessMask = GENERIC_ALL;
|
|
|
|
//
|
|
// Enable access to all the globally defined SIDs
|
|
//
|
|
|
|
GenericMapping = IoGetFileObjectGenericMapping();
|
|
|
|
RtlMapGenericMask( &AccessMask, GenericMapping );
|
|
|
|
|
|
securityContext = IrpSp->Parameters.Create.SecurityContext;
|
|
accessState = securityContext->AccessState;
|
|
|
|
SeLockSubjectContext(&accessState->SubjectSecurityContext);
|
|
|
|
accessGranted = SeAccessCheck(
|
|
SecurityDescriptor,
|
|
&accessState->SubjectSecurityContext,
|
|
TRUE,
|
|
AccessMask,
|
|
0,
|
|
&privileges,
|
|
IoGetFileObjectGenericMapping(),
|
|
(KPROCESSOR_MODE)((IrpSp->Flags & SL_FORCE_ACCESS_CHECK)
|
|
? UserMode
|
|
: Irp->RequestorMode),
|
|
&grantedAccess,
|
|
Status
|
|
);
|
|
|
|
if (privileges) {
|
|
(VOID) SeAppendPrivileges(
|
|
accessState,
|
|
privileges
|
|
);
|
|
SeFreePrivileges(privileges);
|
|
}
|
|
|
|
if (accessGranted) {
|
|
accessState->PreviouslyGrantedAccess |= grantedAccess;
|
|
accessState->RemainingDesiredAccess &= ~( grantedAccess | MAXIMUM_ALLOWED );
|
|
ASSERT (NT_SUCCESS (*Status));
|
|
}
|
|
else {
|
|
ASSERT (!NT_SUCCESS (*Status));
|
|
}
|
|
SeUnlockSubjectContext(&accessState->SubjectSecurityContext);
|
|
|
|
return accessGranted;
|
|
}
|
|
|
|
|
|
|