windows-nt/Source/XPSP1/NT/net/ndis/sys/ndissd.c
2020-09-26 16:20:57 +08:00

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