/* * @implemented */ BOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor) { BOOLEAN Result; Result = RtlValidSecurityDescriptor (pSecurityDescriptor); if (Result == FALSE) SetLastError(RtlNtStatusToDosError(STATUS_INVALID_SECURITY_DESCR)); return (BOOL)Result; }
static NTSTATUS FspFsvolSetSecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); /* is this a valid FileObject? */ if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext)) return STATUS_INVALID_DEVICE_REQUEST; NTSTATUS Result; PFILE_OBJECT FileObject = IrpSp->FileObject; FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_DESC *FileDesc = FileObject->FsContext2; SECURITY_INFORMATION SecurityInformation = IrpSp->Parameters.SetSecurity.SecurityInformation; PSECURITY_DESCRIPTOR SecurityDescriptor = IrpSp->Parameters.SetSecurity.SecurityDescriptor; ULONG SecurityDescriptorSize = 0; ASSERT(FileNode == FileDesc->FileNode); #if 0 /* captured security descriptor is always valid */ if (0 == SecurityDescriptor || !RtlValidSecurityDescriptor(SecurityDescriptor)) return STATUS_INVALID_PARAMETER; #endif SecurityDescriptorSize = RtlLengthSecurityDescriptor(SecurityDescriptor); FspFileNodeAcquireExclusive(FileNode, Full); FSP_FSCTL_TRANSACT_REQ *Request; Result = FspIopCreateRequestEx(Irp, 0, SecurityDescriptorSize, FspFsvolSetSecurityRequestFini, &Request); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Full); return Result; } Request->Kind = FspFsctlTransactSetSecurityKind; Request->Req.SetSecurity.UserContext = FileNode->UserContext; Request->Req.SetSecurity.UserContext2 = FileDesc->UserContext2; Request->Req.SetSecurity.SecurityInformation = SecurityInformation; Request->Req.SetSecurity.SecurityDescriptor.Offset = 0; Request->Req.SetSecurity.SecurityDescriptor.Size = (UINT16)SecurityDescriptorSize; RtlCopyMemory(Request->Buffer, SecurityDescriptor, SecurityDescriptorSize); FspFileNodeSetOwner(FileNode, Full, Request); FspIopRequestContext(Request, RequestFileNode) = FileNode; return FSP_STATUS_IOQ_POST; }
//---------------------------------------------------------------------- // // NTIRemoveWorldAce // // Scans the passed security descriptor's DACL, looking for // the World SID's ACE (its first because the of the way device object // security descriptors are created) and removes it. // // If successful, the original security descriptor is deallocated // and a new one is returned. // //---------------------------------------------------------------------- NTSTATUS NTIRemoveWorldAce( PSECURITY_DESCRIPTOR SecurityDescriptor, PSECURITY_DESCRIPTOR *NewSecurityDescriptor ) { PSECURITY_DESCRIPTOR absSecurityDescriptor; PSECURITY_DESCRIPTOR relSecurityDescriptor; PACE_HEADER aceHeader; NTSTATUS status; PACL Dacl; BOOLEAN DaclPresent, DaclDefaulted; USHORT aceIndex; ULONG worldSidLength; SID_IDENTIFIER_AUTHORITY worldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; PULONG worldSidSubAuthority; ULONG relLength; PSID worldSid; PSID aceSid; // // First, get an absolute version of the self-relative descriptor // relLength = RtlLengthSecurityDescriptor( SecurityDescriptor ); status = NTIMakeAbsoluteSD( SecurityDescriptor, &absSecurityDescriptor ); if( !NT_SUCCESS( status )) { return status; } // // Pull the DACL out so that we can scan it // status = RtlGetDaclSecurityDescriptor( absSecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted ); if( !NT_SUCCESS( status ) || !DaclPresent ) { DbgPrint(("Secsys: strange - couldn't get DACL from our absolute SD: %x\n", status )); ExFreePool( absSecurityDescriptor ); return status; } // // Initialize a SID that identifies the world-authority so // that we can recognize it in the ACL // worldSidLength = RtlLengthRequiredSid( 1 ); worldSid = (PSID) ExAllocatePool( PagedPool, worldSidLength ); RtlInitializeSid( worldSid, &worldSidAuthority, 1 ); worldSidSubAuthority = RtlSubAuthoritySid( worldSid, 0 ); *worldSidSubAuthority = SECURITY_WORLD_RID; // // Now march through the ACEs looking for the World ace. We could // do one of two things: // // - remove the ACE // - convert it into a grant-nothing ACE // // For demonstration purposes I'll remove the ACE. In addition, // this requires that I implement kernel-mode GetAce and DeleteAce functions, // since they are not implemented by the NT kernel. // DbgPrint(("Secsys: %d ACEs in DACL\n", Dacl->AceCount )); for( aceIndex = 0; aceIndex < Dacl->AceCount; aceIndex++ ) { aceHeader = NTIGetAce( Dacl, aceIndex ); DbgPrint((" ACE: type: %s mask: %x\n", (aceHeader->AceType & ACCESS_DENIED_ACE_TYPE ? "Deny" : "Allow"), *(PULONG) ((PUCHAR) aceHeader + sizeof(ACE_HEADER)))); // // Get the SID in this ACE and see if its the WORLD (Everyone) SID // aceSid = (PSID) ((PUCHAR) aceHeader + sizeof(ACE_HEADER) + sizeof(ULONG)); if( RtlEqualSid( worldSid, aceSid )) { // // We found it: remove it. // DbgPrint(("Secsys: Deleting ace %d\n", aceIndex )); NTIDeleteAce( Dacl, aceIndex ); break; } } // // Write new DACL back to security descriptor // status = RtlSetDaclSecurityDescriptor( absSecurityDescriptor, TRUE, Dacl, FALSE ); if( !NT_SUCCESS( status )) { DbgPrint(("Secsys: Could not update SD Dacl: %x\n", status )); goto cleanup; } // // Make sure its valid // if( !RtlValidSecurityDescriptor( absSecurityDescriptor )) { DbgPrint(("Secsys: SD after remove is invalid!\n")); status = STATUS_UNSUCCESSFUL; goto cleanup; } // // Now convert the security descriptor back to // self-relative // relSecurityDescriptor = ExAllocatePool( PagedPool, relLength ); status = RtlAbsoluteToSelfRelativeSD( absSecurityDescriptor, relSecurityDescriptor, &relLength ); if( !NT_SUCCESS( status )) { DbgPrint(("Could not convert absolute SD to relative: %x\n", status )); } // // Final step, free the original security descriptor and return the new one // ExFreePool( SecurityDescriptor ); *NewSecurityDescriptor = relSecurityDescriptor; cleanup: ExFreePool( worldSid ); ExFreePool( absSecurityDescriptor ); return status; }
//---------------------------------------------------------------------- // // NTIMakeAbsoluteSD // // Takes a self-relative security descriptor and returns an allocated // absolute version. Caller is responsibile for freeing the allocated // buffer on success. // //---------------------------------------------------------------------- NTSTATUS NTIMakeAbsoluteSD( PSECURITY_DESCRIPTOR RelSecurityDescriptor, PSECURITY_DESCRIPTOR *pAbsSecurityDescriptor ) { NTSTATUS status; BOOLEAN DaclPresent, DaclDefaulted, OwnerDefaulted, GroupDefaulted; PACL Dacl; PSID Owner, Group; PSECURITY_DESCRIPTOR absSecurityDescriptor; // // Initialize buffer pointers // absSecurityDescriptor = (PSECURITY_DESCRIPTOR) ExAllocatePool( NonPagedPool, 1024 ); *pAbsSecurityDescriptor = absSecurityDescriptor; // // Create an absolute-form security descriptor for manipulation. // The one on the security descriptor is in self-relative form. // status = RtlCreateSecurityDescriptor( absSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); if( !NT_SUCCESS( status ) ) { DbgPrint(("Secsys: Unable to initialize security descriptor\n")); goto cleanup; } // // Locate the descriptor's DACL and apply the DACL to the new // descriptor we're going to modify // status = RtlGetDaclSecurityDescriptor( RelSecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted ); if( !NT_SUCCESS( status ) || !DaclPresent ) { if( !NT_SUCCESS( status )) { DbgPrint(("Secsys: Error obtaining security descriptor's DACL: %x\n", status )); } else { DbgPrint(("Secsys: Security descriptor does not have a DACL\n" )); } goto cleanup; } status = RtlSetDaclSecurityDescriptor( absSecurityDescriptor, DaclPresent, Dacl, DaclDefaulted ); if( !NT_SUCCESS( status )) { DbgPrint(("Secsys: Coult not set new security descriptor DACL: %x\n", status )); goto cleanup; } // // We would get and apply the SACL at this point, but NT does not export // the appropriate function, RtlGetSaclSecurityDescriptor :-( // // // Get and apply the owner // status = RtlGetOwnerSecurityDescriptor( RelSecurityDescriptor, &Owner, &OwnerDefaulted ); if( !NT_SUCCESS( status )) { DbgPrint(("Secsys: Could not security descriptor owner: %x\n", Owner )); goto cleanup; } status = RtlSetOwnerSecurityDescriptor( absSecurityDescriptor, Owner, OwnerDefaulted ); if( !NT_SUCCESS( status )) { DbgPrint(("Secsys: Could not set owner: %x\n", status )); goto cleanup; } // // Get and apply group // status = RtlGetGroupSecurityDescriptor( RelSecurityDescriptor, &Group, &GroupDefaulted ); if( !NT_SUCCESS( status )) { DbgPrint(("Secsys: Could not security descriptor group: %x\n", Owner )); goto cleanup; } status = RtlSetGroupSecurityDescriptor( absSecurityDescriptor, Group, GroupDefaulted ); if( !NT_SUCCESS( status )) { DbgPrint(("Secsys: Could not set group: %x\n", status )); goto cleanup; } // // Finally, make sure that what we made is valid // if( !RtlValidSecurityDescriptor( absSecurityDescriptor )) { DbgPrint(("Secsys: absolute descriptor not valid!\n")); status = STATUS_UNSUCCESSFUL; } // // Done! Return. // cleanup: if( !NT_SUCCESS( status ) ) { ExFreePool( absSecurityDescriptor ); } return status; }
static DWORD LwpsLegacyCreateSecurityDescriptor( IN BOOLEAN bIsWorldReadable, IN OUT PSECURITY_DESCRIPTOR_ABSOLUTE *ppSecurityDescriptor ) { NTSTATUS status = STATUS_SUCCESS; int EE = 0; PSECURITY_DESCRIPTOR_ABSOLUTE pSecDesc = NULL; PACL pDacl = NULL; PSID pRootSid = NULL; PSID pAdminsSid = NULL; PSID pEveryoneSid = NULL; PSID pOwnerSid = NULL; PSID pGroupSid = NULL; DWORD dwError = 0; status = RtlAllocateWellKnownSid(WinLocalSystemSid, NULL, &pRootSid); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = RtlAllocateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &pAdminsSid); GOTO_CLEANUP_ON_STATUS_EE(status, EE); if (bIsWorldReadable) { status = RtlAllocateWellKnownSid(WinWorldSid, NULL, &pEveryoneSid); GOTO_CLEANUP_ON_STATUS_EE(status, EE); } status = LW_RTL_ALLOCATE( &pSecDesc, VOID, SECURITY_DESCRIPTOR_ABSOLUTE_MIN_SIZE); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = RtlCreateSecurityDescriptorAbsolute( pSecDesc, SECURITY_DESCRIPTOR_REVISION); GOTO_CLEANUP_ON_STATUS_EE(status, EE); // Owner: Root status = RtlDuplicateSid(&pOwnerSid, pRootSid); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = RtlSetOwnerSecurityDescriptor( pSecDesc, pOwnerSid, FALSE); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pOwnerSid = NULL; // Group: Administrators status = RtlDuplicateSid(&pGroupSid, pAdminsSid); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = RtlSetGroupSecurityDescriptor( pSecDesc, pGroupSid, FALSE); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pGroupSid = NULL; // Do not set Sacl currently // DACL status = LwpsLegacyBuildRestrictedDaclForKey( pRootSid, pEveryoneSid, &pDacl); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = RtlSetDaclSecurityDescriptor( pSecDesc, TRUE, pDacl, FALSE); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pDacl = NULL; if (!RtlValidSecurityDescriptor(pSecDesc)) { status = STATUS_INVALID_SECURITY_DESCR; GOTO_CLEANUP_ON_STATUS_EE(status, EE); } cleanup: if (status) { if (pSecDesc) { LwpsLegacyFreeSecurityDescriptor(&pSecDesc); } } LW_RTL_FREE(&pDacl); LW_RTL_FREE(&pRootSid); LW_RTL_FREE(&pAdminsSid); LW_RTL_FREE(&pEveryoneSid); LW_RTL_FREE(&pOwnerSid); LW_RTL_FREE(&pGroupSid); *ppSecurityDescriptor = pSecDesc; dwError = LwNtStatusToWin32Error(status); LSA_PSTORE_LOG_LEAVE_ERROR_EE(dwError, EE); return dwError; }
/****************************************************************************** * IsValidSecurityDescriptor [ADVAPI32.@] * * PARAMS * lpsecdesc [] */ BOOL WINAPI IsValidSecurityDescriptor( PSECURITY_DESCRIPTOR SecurityDescriptor ) { CallWin32ToNt (RtlValidSecurityDescriptor(SecurityDescriptor)); }
BOOL EditDefaultDacl( HWND hwndOwner, HANDLE Instance, HANDLE MyToken ) { NTSTATUS Status; BOOL Success = FALSE; DWORD EditResult; HANDLE Token = NULL; PTOKEN_DEFAULT_DACL DefaultDacl = NULL; PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; PTOKEN_OWNER Owner = NULL; PTOKEN_PRIMARY_GROUP PrimaryGroup = NULL; WCHAR string[MAX_STRING_LENGTH]; // // Get the window text so we can use it as the token name // GetWindowTextW(((PMYTOKEN)MyToken)->hwnd, string, sizeof(string)/sizeof(*string)); // // Get a handle to the token // Token = OpenToken(MyToken, TOKEN_QUERY); if (Token == NULL) { DbgPrint("SECEDIT : Failed to open the token with TOKEN_QUERY access\n"); goto CleanupAndExit; } // // Read the default DACL from the token // if (!GetTokenInfo(Token, TokenDefaultDacl, (PPVOID)&DefaultDacl)) { DbgPrint("SECEDIT : Failed to read default DACL from token\n"); goto CleanupAndExit; } // // Get the owner and group of the token // if (!GetTokenInfo(Token, TokenOwner, (PPVOID)&Owner)) { DbgPrint("SECEDIT : Failed to read owner from token\n"); goto CleanupAndExit; } if (!GetTokenInfo(Token, TokenPrimaryGroup, (PPVOID)&PrimaryGroup)) { DbgPrint("SECEDIT : Failed to read primary group from token\n"); goto CleanupAndExit; } // // Create a security descriptor // SecurityDescriptor = Alloc(SECURITY_DESCRIPTOR_MIN_LENGTH); if (SecurityDescriptor == NULL) { DbgPrint("SECEDIT : Failed to allocate security descriptor\n"); goto CleanupAndExit; } Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); ASSERT(NT_SUCCESS(Status)); // // Set the DACL on the security descriptor // Status = RtlSetDaclSecurityDescriptor( SecurityDescriptor, TRUE, // DACL present DefaultDacl->DefaultDacl, FALSE // DACL defaulted ); ASSERT(NT_SUCCESS(Status)); // // Put the owner and group in the security descriptor to keep the // ACL editor happy // Status = RtlSetOwnerSecurityDescriptor( SecurityDescriptor, Owner->Owner, FALSE // Owner defaulted ); ASSERT(NT_SUCCESS(Status)); Status = RtlSetGroupSecurityDescriptor( SecurityDescriptor, PrimaryGroup->PrimaryGroup, FALSE // Owner defaulted ); ASSERT(NT_SUCCESS(Status)); ASSERT(RtlValidSecurityDescriptor(SecurityDescriptor)); // // Call the ACL editor, it will call our ApplySecurity function // to store any ACL changes in the token. // Success = EditTokenDefaultAcl( hwndOwner, Instance, string, MyToken, SecurityDescriptor, &EditResult ); if (!Success) { DbgPrint("SECEDIT: Failed to edit token DACL\n"); } CleanupAndExit: if (DefaultDacl != NULL) { FreeTokenInfo(DefaultDacl); } if (SecurityDescriptor != NULL) { FreeTokenInfo(SecurityDescriptor); } if (PrimaryGroup != NULL) { FreeTokenInfo(PrimaryGroup); } if (Owner != NULL) { FreeTokenInfo(Owner); } if (Token != NULL) { CloseToken(Token); } return(Success); }