|
|
#include "precomp.h"
typedef ULONG SECURITY_INFORMATION;
NTSTATUS AddNetConfigOpsAce(IN PACL Dacl, OUT PACL * DeviceAcl ) /*++
Routine Description:
This routine builds an ACL which 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 NetConfigOpsSid = NULL; ULONG AclLength; NTSTATUS Status; ACCESS_MASK AccessMask = GENERIC_ALL; PACL NewAcl = NULL; ULONG SidSize; SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY; PISID ISid; PACCESS_ALLOWED_ACE AceTemp; int i; //
// Enable access to all the globally defined SIDs
//
GenericMapping = IoGetFileObjectGenericMapping();
RtlMapGenericMask(&AccessMask, GenericMapping);
SidSize = RtlLengthRequiredSid(2); NetConfigOpsSid = (PSID)(ExAllocatePoolWithTag(PagedPool,SidSize, NDIS_TAG_NET_CFG_OPS_ID));
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) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart); AclLength += RtlLengthSid(NetConfigOpsSid);
NewAcl = ExAllocatePoolWithTag( PagedPool, AclLength, NDIS_TAG_NET_CFG_OPS_ACL );
if (NewAcl == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto clean_up; }
Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION2);
if (!NT_SUCCESS(Status)) { goto clean_up; }
for (i = 0; i < Dacl->AceCount; i++) { Status = RtlGetAce(Dacl, i, &AceTemp);
if (NT_SUCCESS(Status)) {
Status = RtlAddAccessAllowedAce(NewAcl, ACL_REVISION2, AceTemp->Mask, &AceTemp->SidStart); }
if (!NT_SUCCESS(Status)) { goto clean_up; } }
// Add Net Config Operators Ace
Status = RtlAddAccessAllowedAce(NewAcl, ACL_REVISION2, AccessMask, NetConfigOpsSid);
if (!NT_SUCCESS(Status)) { goto clean_up; }
*DeviceAcl = NewAcl;
clean_up: if (NetConfigOpsSid) { ExFreePool(NetConfigOpsSid); } if (!NT_SUCCESS(Status) && NewAcl) { ExFreePool(NewAcl); }
return (Status); }
NTSTATUS CreateDeviceDriverSecurityDescriptor( IN PVOID DeviceOrDriverObject, IN BOOLEAN AddNetConfigOps, IN PACL AclToAdd OPTIONAL )
/*++
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; PACL paclDacl = NULL; BOOLEAN bHasDacl; BOOLEAN bDaclDefaulted; PACL NewAcl = NULL; //
// 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 (NT_SUCCESS(status)) { if (bHasDacl) { if (AddNetConfigOps && paclDacl) { status = AddNetConfigOpsAce(paclDacl, &NewAcl); } else if (AclToAdd) { NewAcl = AclToAdd; } else { return STATUS_UNSUCCESSFUL; }
ASSERT(NT_SUCCESS(status)); 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;
ulSecDescSize = sizeof(SECURITY_DESCRIPTOR) + NewAcl->AclSize; sdSecDesc = ExAllocatePoolWithTag(PagedPool, ulSecDescSize, NDIS_TAG_NET_CFG_SEC_DESC);
if (sdSecDesc) { ulDacl = NewAcl->AclSize; daclAbs = ExAllocatePoolWithTag(PagedPool, ulDacl, NDIS_TAG_NET_CFG_DACL);
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 ((AclToAdd == NULL) && NewAcl) { ExFreePool(NewAcl); } } } else { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"NDIS: No Dacl: %x\n", status)); } }
ObReleaseObjectSecurity( sdSecurityDescriptor, memoryAllocated );
return (status); }
NTSTATUS ndisBuildDeviceAcl( OUT PACL *DeviceAcl, IN BOOLEAN AddNetConfigOps, IN BOOLEAN AddNetworkService )
/*++
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 (AddNetworkService) { AclLength += sizeof(ACL) + FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(SeExports->SeNetworkServiceSid); }
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 (AddNetworkService) { Status = RtlAddAccessAllowedAce( NewAcl, ACL_REVISION2, AccessMask, SeExports->SeNetworkServiceSid ); 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, IN BOOLEAN AddNetConfigOps, IN BOOLEAN AddNetworkService )
/*++
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, AddNetworkService);
if (!NT_SUCCESS(Status)) { break; } //1 why (VOID)?
(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; }
NTSTATUS ndisCreateGenericSD( PACL Acl, PCHAR AccessSecurityDescriptor )
/*++
Routine Description:
Creates the SD responsible for giving access to different users.
Arguments:
None.
Return Value:
STATUS_SUCCESS or an appropriate error code.
--*/
{ PSECURITY_DESCRIPTOR AccessSd; NTSTATUS Status;
if (Acl == NULL) return STATUS_UNSUCCESSFUL; do { AccessSd = AccessSecurityDescriptor; Status = RtlCreateSecurityDescriptor( AccessSd, SECURITY_DESCRIPTOR_REVISION1 );
if (!NT_SUCCESS(Status)) { DbgPrint("RtlCreateSecurityDescriptor failed, Status %lx.\n", Status); break; } Status = RtlSetDaclSecurityDescriptor( AccessSd, TRUE, // DaclPresent
Acl, FALSE // DaclDefaulted
); if (!NT_SUCCESS(Status)) { DbgPrint("RtlSetDaclSecurityDescriptor failed, Status %lx.\n", Status); break; }
Status = RtlSetOwnerSecurityDescriptor(AccessSd, SeExports->SeAliasAdminsSid, FALSE); if (!NT_SUCCESS(Status)) { DbgPrint("RtlSetOwnerSecurityDescriptor failed, Status %lx.\n", Status); break; }
Status = RtlSetGroupSecurityDescriptor(AccessSd, SeExports->SeAliasAdminsSid, FALSE);
if (!NT_SUCCESS(Status)) { DbgPrint("RtlSetGroupSecurityDescriptor failed, Status %lx.\n", Status); break; }
}while (FALSE);
return (Status); }
PACL ndisCreateAcl( BOOLEAN Admins, BOOLEAN LocalSystem, BOOLEAN LocalService, BOOLEAN NetworkService, BOOLEAN NetConfigOps, BOOLEAN Users, ACCESS_MASK AccessMask ) { PACL AccessDacl = NULL, pAcl = NULL; ULONG AclLength = 0; PSID NetConfigOpsSid = NULL; ULONG NetConfigOpsSidSize; SID_IDENTIFIER_AUTHORITY NetConfigOpsSidAuth = SECURITY_NT_AUTHORITY; PISID ISid; NTSTATUS Status;
do { if (Admins) { AclLength += sizeof(ACL) + FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(SeExports->SeAliasAdminsSid);
}
if (LocalSystem) { AclLength += sizeof(ACL) + FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(SeExports->SeLocalSystemSid);
} if (LocalService) { AclLength += sizeof(ACL) + FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(SeExports->SeLocalServiceSid);
} if (NetworkService) { AclLength += sizeof(ACL) + FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(SeExports->SeNetworkServiceSid);
}
if (NetConfigOps) { 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 += sizeof(ACL) + FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(NetConfigOpsSid);
}
if (Users) { AclLength += sizeof(ACL) + FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(SeExports->SeAliasUsersSid);
}
AccessDacl = (PACL)ExAllocatePoolWithTag(PagedPool, AclLength, NDIS_TAG_SECURITY); if (AccessDacl == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; }
Status = RtlCreateAcl(AccessDacl, AclLength, ACL_REVISION2); if (!NT_SUCCESS(Status)) { DbgPrint("RtlCreateAcl failed, Status %lx.\n", Status); break; }
if (Admins) { Status = RtlAddAccessAllowedAce( AccessDacl, ACL_REVISION2, (STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL), SeExports->SeAliasAdminsSid ); if (!NT_SUCCESS(Status)) { DbgPrint("RtlAddAccessAllowedAce failed, Status %lx.\n", Status); break; } }
if (LocalSystem) { Status = RtlAddAccessAllowedAce( AccessDacl, ACL_REVISION2, (STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL), SeExports->SeLocalSystemSid ); if (!NT_SUCCESS(Status)) { DbgPrint("RtlAddAccessAllowedAce failed, Status %lx.\n", Status); break; } } if (LocalService) { Status = RtlAddAccessAllowedAce( AccessDacl, ACL_REVISION2, (STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL), SeExports->SeLocalServiceSid ); if (!NT_SUCCESS(Status)) { DbgPrint("RtlAddAccessAllowedAce failed, Status %lx.\n", Status); break; }
} if (NetworkService) { Status = RtlAddAccessAllowedAce( AccessDacl, ACL_REVISION2, (STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL), SeExports->SeNetworkServiceSid ); if (!NT_SUCCESS(Status)) { DbgPrint("RtlAddAccessAllowedAce failed, Status %lx.\n", Status); break; } }
if (NetConfigOps) { Status = RtlAddAccessAllowedAce( AccessDacl, ACL_REVISION2, (STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL), NetConfigOpsSid ); if (!NT_SUCCESS(Status)) { DbgPrint("RtlAddAccessAllowedAce failed, Status %lx.\n", Status); break; }
}
if (Users) { Status = RtlAddAccessAllowedAce( AccessDacl, ACL_REVISION2, AccessMask, SeExports->SeAliasUsersSid ); if (!NT_SUCCESS(Status)) { DbgPrint("RtlAddAccessAllowedAce failed, Status %lx.\n", Status); break; } } pAcl = AccessDacl; }while (FALSE);
if (pAcl == NULL) { if (AccessDacl) FREE_POOL(AccessDacl); } return pAcl; }
|