|
|
#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; }
|