/****************************************************************************** * RtlEqualSid [NTDLL.@] * */ BOOL WINAPI RtlEqualSid( PSID pSid1, PSID pSid2 ) { if (!RtlValidSid(pSid1) || !RtlValidSid(pSid2)) return FALSE; if (*RtlSubAuthorityCountSid(pSid1) != *RtlSubAuthorityCountSid(pSid2)) return FALSE; if (memcmp(pSid1, pSid2, RtlLengthSid(pSid1)) != 0) return FALSE; return TRUE; }
static BOOLEAN TestValidateSamLogonInfo( NetrValidationInfo ***pppLogonInfo, DWORD dwNumUsers ) { BOOLEAN bRet = TRUE; DWORD i = 0; for (i = 0; i < dwNumUsers; i++) { NetrValidationInfo **ppLogonInfo = pppLogonInfo[i]; ASSERT_UNICODE_STRING_VALID_MSG(&ppLogonInfo[2]->sam2->base.account_name, ("(i = %u)\n", i)); ASSERT_UNICODE_STRING_VALID_MSG(&ppLogonInfo[2]->sam2->base.full_name, ("(i = %u)\n", i)); ASSERT_UNICODE_STRING_VALID_MSG(&ppLogonInfo[2]->sam2->base.logon_script, ("(i = %u)\n", i)); ASSERT_UNICODE_STRING_VALID_MSG(&ppLogonInfo[2]->sam2->base.profile_path, ("(i = %u)\n", i)); ASSERT_UNICODE_STRING_VALID_MSG(&ppLogonInfo[2]->sam2->base.home_directory, ("(i = %u)\n", i)); ASSERT_UNICODE_STRING_VALID_MSG(&ppLogonInfo[2]->sam2->base.home_drive, ("(i = %u)\n", i)); ASSERT_UNICODE_STRING_VALID_MSG(&ppLogonInfo[2]->sam2->base.logon_server, ("(i = %u)\n", i)); ASSERT_UNICODE_STRING_VALID_MSG(&ppLogonInfo[2]->sam2->base.domain, ("(i = %u)\n", i)); ASSERT_TEST_MSG((ppLogonInfo[2]->sam2->base.domain_sid != NULL && RtlValidSid(ppLogonInfo[2]->sam2->base.domain_sid)), ("(i = %u)\n", i)); ASSERT_TEST_MSG(ppLogonInfo[2]->sam2->base.acct_flags & ACB_NORMAL, ("(i = %u)\n", i)); } return bRet; }
BOOLEAN RtlpIsValidLittleEndianSidBuffer( IN PVOID Buffer, IN ULONG BufferSize, OUT PULONG BufferUsed ) { NTSTATUS status = STATUS_SUCCESS; PSID littleEndianSid = (PSID) Buffer; ULONG size = 0; if (BufferSize < SID_MIN_SIZE) { status = STATUS_INVALID_SID; GOTO_CLEANUP(); } size = RtlLengthRequiredSid(LW_LTOH8(littleEndianSid->SubAuthorityCount)); if (!RtlpIsBufferAvailable(BufferSize, 0, size)) { status = STATUS_INVALID_SID; GOTO_CLEANUP(); } // This is ok since it only looks at 1-byte fields: status = RtlValidSid(littleEndianSid) ? STATUS_SUCCESS : STATUS_INVALID_SID; cleanup: *BufferUsed = NT_SUCCESS(status) ? size : 0; return NT_SUCCESS(status); }
static void print_sid (const char *prefix, int idx, PISID sid) { DWORD i; cyglsa_printf ("%s", prefix); if (idx >= 0) cyglsa_printf ("[%d] ", idx); cyglsa_printf ("(0x%08x) ", (INT_PTR) sid); if (!sid) cyglsa_printf ("NULL\n"); else if (IsBadReadPtr (sid, 8)) cyglsa_printf ("INVALID POINTER\n"); else if (!RtlValidSid ((PSID) sid)) cyglsa_printf ("INVALID SID\n"); else if (IsBadReadPtr (sid, 8 + sizeof (DWORD) * sid->SubAuthorityCount)) cyglsa_printf ("INVALID POINTER SPACE\n"); else { cyglsa_printf ("S-%d-%d", sid->Revision, sid->IdentifierAuthority.Value[5]); for (i = 0; i < sid->SubAuthorityCount; ++i) cyglsa_printf ("-%lu", sid->SubAuthority[i]); cyglsa_printf ("\n"); } }
/************************************************************************** * RtlCopySid [NTDLL.@] */ DWORD WINAPI RtlCopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid ) { if (!pSourceSid || !RtlValidSid(pSourceSid) || (nDestinationSidLength < RtlLengthSid(pSourceSid))) return FALSE; if (nDestinationSidLength < (pSourceSid->SubAuthorityCount*4+8)) return FALSE; memmove(pDestinationSid, pSourceSid, pSourceSid->SubAuthorityCount*4+8); return TRUE; }
/* * @implemented */ BOOLEAN NTAPI RtlValidSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor) { PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor; PSID Owner, Group; PACL Sacl, Dacl; PAGED_CODE_RTL(); _SEH2_TRY { /* Fail on bad revisions */ if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return FALSE; /* Owner SID must be valid if present */ Owner = SepGetOwnerFromDescriptor(Sd); if ((Owner) && (!RtlValidSid(Owner))) return FALSE; /* Group SID must be valid if present */ Group = SepGetGroupFromDescriptor(Sd); if ((Owner) && (!RtlValidSid(Group))) return FALSE; /* DACL must be valid if present */ Dacl = SepGetDaclFromDescriptor(Sd); if ((Dacl) && (!RtlValidAcl(Dacl))) return FALSE; /* SACL must be valid if present */ Sacl = SepGetSaclFromDescriptor(Sd); if ((Sacl) && (!RtlValidAcl(Sacl))) return FALSE; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Access fault, bail out */ return FALSE; } _SEH2_END; /* All good */ return TRUE; }
DWORD VmDirRESTCacheGetBuiltInAdminsGroupSid( PVDIR_REST_HEAD_CACHE pRestCache, PSID* ppBuiltInAdminsGroupSid ) { DWORD dwError = 0; ULONG ulSidLen = 0; BOOLEAN bInLock = FALSE; PSID pSid = NULL; if (!pRestCache || !ppBuiltInAdminsGroupSid) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER); } VMDIR_RWLOCK_READLOCK(bInLock, gpVdirRestCache->pRWLock, 0); if (!RtlValidSid(pRestCache->pBuiltInAdminsGroupSid)) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_NOT_FOUND); } ulSidLen = RtlLengthSid(pRestCache->pBuiltInAdminsGroupSid); dwError = VmDirAllocateMemory(ulSidLen, (PVOID*)&pSid); BAIL_ON_VMDIR_ERROR(dwError); dwError = RtlCopySid(ulSidLen, pSid, pRestCache->pBuiltInAdminsGroupSid); BAIL_ON_VMDIR_ERROR(dwError); *ppBuiltInAdminsGroupSid = pSid; cleanup: VMDIR_RWLOCK_UNLOCK(bInLock, gpVdirRestCache->pRWLock); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError); VMDIR_SAFE_FREE_MEMORY(pSid); goto cleanup; }
/****************************************************************************** * RtlAddAccessDeniedAce [NTDLL.@] */ NTSTATUS WINAPI RtlAddAccessDeniedAce( IN OUT PACL pAcl, IN DWORD dwAceRevision, IN DWORD AccessMask, IN PSID pSid) { DWORD dwSidLength; ACCESS_DENIED_ACE* lpADA; TRACE("(%p,0x%08lx,0x%08lx,%p)!\n", pAcl, dwAceRevision, AccessMask, pSid); if( !RtlValidSid( pSid ) ) { return STATUS_INVALID_SID; } dwSidLength = RtlLengthSid( pSid ) - sizeof( DWORD ); if( !RtlFirstFreeAce( pAcl, (PACE_HEADER*)&lpADA) ) { if( lpADA == NULL ) return STATUS_INVALID_ACL; else return STATUS_ALLOTTED_SPACE_EXCEEDED; } if( ((BYTE*)lpADA + sizeof( *lpADA ) + dwSidLength ) > ((BYTE*)pAcl + pAcl->AclSize) ) { return STATUS_ALLOTTED_SPACE_EXCEEDED; } lpADA->Header.AceType = ACCESS_DENIED_ACE_TYPE; lpADA->Header.AceFlags = 0; /* Not set with RtlAddAccessDeniedAce. */ lpADA->Header.AceSize = sizeof( *lpADA ); lpADA->Mask = AccessMask; memcpy( &lpADA->SidStart, pSid, dwSidLength ); pAcl->AceCount++; return STATUS_SUCCESS; }
static DWORD ValidateParameters( PCSTR pszSid ) { DWORD dwError = 0; NTSTATUS ntStatus = STATUS_SUCCESS; PSID pSid = NULL; BAIL_ON_INVALID_STRING(pszSid); ntStatus = RtlAllocateSidFromCString(&pSid, pszSid); if (ntStatus != STATUS_SUCCESS) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } if (RtlValidSid(pSid) && pSid->SubAuthorityCount != 4) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } cleanup: if (pSid) { RTL_FREE(&pSid); } return dwError; error: goto cleanup; }
static BOOLEAN TestValidateDomainTrusts( NetrDomainTrust *pTrusts, DWORD dwNumTrusts ) { BOOLEAN bRet = TRUE; DWORD i = 0; for (i = 0; i < dwNumTrusts; i++) { NetrDomainTrust *pTrust = &(pTrusts[i]); ASSERT_TEST_MSG(pTrust->netbios_name != NULL, ("(i = %u)\n", i)); ASSERT_TEST_MSG(pTrust->dns_name != NULL, ("(i = %u)\n", i)); ASSERT_TEST_MSG((pTrust->trust_type >= 1 && pTrust->trust_type <= 4), ("(i = %u)\n", i)); ASSERT_TEST_MSG((pTrust->sid != NULL && RtlValidSid(pTrust->sid)), ("(i = %u)\n", i)); } return bRet; }
/* * @implemented */ NTSTATUS NTAPI RtlConvertSidToUnicodeString(PUNICODE_STRING String, PSID Sid_, BOOLEAN AllocateBuffer) { WCHAR Buffer[256]; PWSTR wcs; ULONG Length; ULONG i; PISID Sid = Sid_; PAGED_CODE_RTL(); if (RtlValidSid (Sid) == FALSE) return STATUS_INVALID_SID; wcs = Buffer; wcs += swprintf (wcs, L"S-%u-", Sid->Revision); if (Sid->IdentifierAuthority.Value[0] == 0 && Sid->IdentifierAuthority.Value[1] == 0) { wcs += swprintf (wcs, L"%lu", (ULONG)Sid->IdentifierAuthority.Value[2] << 24 | (ULONG)Sid->IdentifierAuthority.Value[3] << 16 | (ULONG)Sid->IdentifierAuthority.Value[4] << 8 | (ULONG)Sid->IdentifierAuthority.Value[5]); } else { wcs += swprintf (wcs, L"0x%02hx%02hx%02hx%02hx%02hx%02hx", Sid->IdentifierAuthority.Value[0], Sid->IdentifierAuthority.Value[1], Sid->IdentifierAuthority.Value[2], Sid->IdentifierAuthority.Value[3], Sid->IdentifierAuthority.Value[4], Sid->IdentifierAuthority.Value[5]); } for (i = 0; i < Sid->SubAuthorityCount; i++) { wcs += swprintf (wcs, L"-%u", Sid->SubAuthority[i]); } if (AllocateBuffer) { if (!RtlCreateUnicodeString(String, Buffer)) { return STATUS_NO_MEMORY; } } else { Length = (wcs - Buffer) * sizeof(WCHAR); if (Length > String->MaximumLength) return STATUS_BUFFER_TOO_SMALL; String->Length = Length; RtlCopyMemory (String->Buffer, Buffer, Length); if (Length < String->MaximumLength) String->Buffer[Length / sizeof(WCHAR)] = 0; } return STATUS_SUCCESS; }
void TestsSeQueryInformationToken(PACCESS_TOKEN Token) { NTSTATUS Status; PVOID Buffer = NULL; PSID sid; PTOKEN_OWNER Towner; PTOKEN_DEFAULT_DACL TDefDacl; PTOKEN_GROUPS TGroups; ULONG GroupCount; PACL acl; PTOKEN_STATISTICS TStats; PTOKEN_TYPE TType; PTOKEN_USER TUser; BOOLEAN Flag; ULONG i; //----------------------------------------------------------------// // Testing SeQueryInformationToken with various args // //----------------------------------------------------------------// ok(Token != NULL, "Token is not captured. Testing SQIT interrupted\n\n"); if (Token == NULL) return; Status = SeQueryInformationToken(Token, TokenOwner, &Buffer); ok((Status == STATUS_SUCCESS), "SQIT with TokenOwner arg fails with status 0x%X\n", Status); if (Status == STATUS_SUCCESS) { ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenOwner arg. But Buffer = NULL\n"); if (Buffer) { Towner = (TOKEN_OWNER *)Buffer; sid = Towner->Owner; ok((RtlValidSid(sid) == TRUE), "TokenOwner's SID is not a valid SID\n"); ExFreePool(Buffer); } } //----------------------------------------------------------------// Buffer = NULL; Status = SeQueryInformationToken(Token, TokenDefaultDacl, &Buffer); ok(Status == STATUS_SUCCESS, "SQIT with TokenDefaultDacl fails with status 0x%X\n", Status); if (Status == STATUS_SUCCESS) { ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenDefaultDacl arg. But Buffer = NULL\n"); if (Buffer) { TDefDacl = (PTOKEN_DEFAULT_DACL)Buffer; acl = TDefDacl->DefaultDacl; ok(((acl->AclRevision == ACL_REVISION || acl->AclRevision == ACL_REVISION_DS) == TRUE), "DACL is invalid\n"); ExFreePool(Buffer); } } //----------------------------------------------------------------// Buffer = NULL; Status = SeQueryInformationToken(Token, TokenGroups, &Buffer); ok(Status == STATUS_SUCCESS, "SQIT with TokenGroups fails with status 0x%X\n", Status); if (Status == STATUS_SUCCESS) { ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenGroups arg. But Buffer = NULL\n"); if (Buffer) { TGroups = (PTOKEN_GROUPS)Buffer; GroupCount = TGroups->GroupCount; Flag = TRUE; for (i = 0; i < GroupCount; i++) { sid = TGroups->Groups[i].Sid; if (!RtlValidSid(sid)) { Flag = FALSE; break; } } ok((Flag == TRUE), "TokenGroup's SIDs are not valid\n"); ExFreePool(Buffer); } } //----------------------------------------------------------------// // Call SQIT with TokenImpersonationLevel argument // // What's up? Why SQIT fails with right arg? Buffer = NULL; Status = SeQueryInformationToken(Token, TokenImpersonationLevel, &Buffer); ok(Status == STATUS_SUCCESS, "SQIT with TokenImpersonationLevel fails with status 0x%X\n", Status); Buffer = NULL; Status = SeQueryInformationToken(Token, TokenImpersonationLevel, &Buffer); ok(Status == STATUS_SUCCESS, "and again: SQIT with TokenImpersonationLevel fails with status 0x%X\n", Status); if (Status == STATUS_SUCCESS) { ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenImpersonationLevel arg. But Buffer = NULL\n"); } else { ok(Buffer == NULL, "Wrong. SQIT call is't success. But Buffer != NULL\n"); } //----------------------------------------------------------------// Buffer = NULL; Status = SeQueryInformationToken(Token, TokenStatistics, &Buffer); ok(Status == STATUS_SUCCESS, "SQIT with TokenStatistics fails with status 0x%X\n", Status); if (Status == STATUS_SUCCESS) { ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenStatistics arg. But Buffer = NULL\n"); if (Buffer) { TStats = (PTOKEN_STATISTICS)Buffer; // just put 0 into 1st arg or use trace to print TokenStatistics f ok(1, "print statistics:\n\tTokenID = %u_%d\n\tSecurityImperLevel = %d\n\tPrivCount = %d\n\tGroupCount = %d\n\n", TStats->TokenId.LowPart, TStats->TokenId.HighPart, TStats->ImpersonationLevel, TStats->PrivilegeCount, TStats->GroupCount ); ExFreePool(TStats); } } else { ok(Buffer == NULL, "Wrong. SQIT call is't success. But Buffer != NULL\n"); } //----------------------------------------------------------------// Buffer = NULL; Status = SeQueryInformationToken(Token, TokenType, &Buffer); ok(Status == STATUS_SUCCESS, "SQIT with TokenType fails with status 0x%X\n", Status); if (Status == STATUS_SUCCESS) { ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenType arg. But Buffer = NULL\n"); if (Buffer) { TType = (PTOKEN_TYPE)Buffer; ok((*TType == TokenPrimary || *TType == TokenImpersonation), "TokenType in not a primary nor impersonation. FAILED\n"); ExFreePool(TType); } } //----------------------------------------------------------------// Buffer = NULL; Status = SeQueryInformationToken(Token, TokenUser, &Buffer); ok(Status == STATUS_SUCCESS, "SQIT with TokenUser fails\n"); if (Status == STATUS_SUCCESS) { ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenUser arg. But Buffer = NULL\n"); if (Buffer) { TUser = (PTOKEN_USER)Buffer; ok(RtlValidSid(TUser->User.Sid), "TokenUser has an invalid Sid\n"); ExFreePool(TUser); } } //----------------------------------------------------------------// Buffer = NULL; Status = SeQueryInformationToken(Token, TokenSandBoxInert, &Buffer); ok(Status != STATUS_SUCCESS, "SQIT must fail with wrong TOKEN_INFORMATION_CLASS arg\n"); }
NTSTATUS RtlAllocateCStringFromSid( OUT PSTR* StringSid, IN PSID Sid ) { NTSTATUS status = STATUS_SUCCESS; PSTR result = NULL; size_t size = 0; int count = 0; ULONG i = 0; if (!StringSid || !RtlValidSid(Sid)) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } size = RTLP_STRING_SID_MAX_CHARS(Sid->SubAuthorityCount); status = RTL_ALLOCATE(&result, CHAR, size); GOTO_CLEANUP_ON_STATUS(status); if (Sid->IdentifierAuthority.Value[0] || Sid->IdentifierAuthority.Value[1]) { count += snprintf(result + count, size - count, "S-%u-0x%.2X%.2X%.2X%.2X%.2X%.2X", Sid->Revision, Sid->IdentifierAuthority.Value[0], Sid->IdentifierAuthority.Value[1], Sid->IdentifierAuthority.Value[2], Sid->IdentifierAuthority.Value[3], Sid->IdentifierAuthority.Value[4], Sid->IdentifierAuthority.Value[5]); } else { ULONG value = 0; value |= (ULONG) Sid->IdentifierAuthority.Value[5]; value |= (ULONG) Sid->IdentifierAuthority.Value[4] << 8; value |= (ULONG) Sid->IdentifierAuthority.Value[3] << 16; value |= (ULONG) Sid->IdentifierAuthority.Value[2] << 24; count += snprintf(result + count, size - count, "S-%u-%u", Sid->Revision, value); } for (i = 0; i < Sid->SubAuthorityCount; i++) { count += snprintf(result + count, size - count, "-%u", Sid->SubAuthority[i]); } status = STATUS_SUCCESS; cleanup: if (!NT_SUCCESS(status)) { RTL_FREE(&result); } if (StringSid) { *StringSid = result; } return status; }
NTSTATUS RtlCreateAccessToken( OUT PACCESS_TOKEN* AccessToken, IN PTOKEN_USER User, IN PTOKEN_GROUPS Groups, IN PTOKEN_PRIVILEGES Privileges, IN PTOKEN_OWNER Owner, IN PTOKEN_PRIMARY_GROUP PrimaryGroup, IN PTOKEN_DEFAULT_DACL DefaultDacl, IN OPTIONAL PTOKEN_UNIX Unix ) { NTSTATUS status = STATUS_SUCCESS; int unixError = 0; ULONG requiredSize = 0; PACCESS_TOKEN token = NULL; ULONG i = 0; ULONG size = 0; PVOID location = NULL; if (!User || !User->User.Sid || !Groups || !Owner || !PrimaryGroup || !DefaultDacl) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } if (!RtlValidSid(User->User.Sid) || (Owner->Owner && !RtlValidSid(Owner->Owner)) || (PrimaryGroup->PrimaryGroup && !RtlValidSid(PrimaryGroup->PrimaryGroup))) { status = STATUS_INVALID_SID; GOTO_CLEANUP(); } // No user attributes currently exist. if (User->User.Attributes != 0) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } for (i = 0; i < Groups->GroupCount; i++) { // TODO-Perhaps validate Group attributes if (!Groups->Groups[i].Sid) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } if (!RtlValidSid(Groups->Groups[i].Sid)) { status = STATUS_INVALID_SID; GOTO_CLEANUP(); } } if (DefaultDacl->DefaultDacl && !RtlValidAcl(DefaultDacl->DefaultDacl, NULL)) { status = STATUS_INVALID_ACL; GOTO_CLEANUP(); } // Compute size required requiredSize = sizeof(*token); size = RtlLengthSid(User->User.Sid); status = RtlSafeAddULONG(&requiredSize, requiredSize, size); GOTO_CLEANUP_ON_STATUS(status); if (Owner->Owner) { size = RtlLengthSid(Owner->Owner); status = RtlSafeAddULONG(&requiredSize, requiredSize, size); GOTO_CLEANUP_ON_STATUS(status); } if (PrimaryGroup->PrimaryGroup) { size = RtlLengthSid(PrimaryGroup->PrimaryGroup); status = RtlSafeAddULONG(&requiredSize, requiredSize, size); GOTO_CLEANUP_ON_STATUS(status); } if (DefaultDacl->DefaultDacl) { status = RtlSafeAddULONG(&requiredSize, requiredSize, DefaultDacl->DefaultDacl->AclSize); GOTO_CLEANUP_ON_STATUS(status); } status = RtlSafeMultiplyULONG(&size, sizeof(Groups->Groups[0]), Groups->GroupCount); GOTO_CLEANUP_ON_STATUS(status); status = RtlSafeAddULONG(&requiredSize, requiredSize, size); GOTO_CLEANUP_ON_STATUS(status); for (i = 0; i < Groups->GroupCount; i++) { size = RtlLengthSid(Groups->Groups[i].Sid); status = RtlSafeAddULONG(&requiredSize, requiredSize, size); GOTO_CLEANUP_ON_STATUS(status); } status = RtlSafeMultiplyULONG(&size, sizeof(Privileges->Privileges[0]), Privileges->PrivilegeCount); GOTO_CLEANUP_ON_STATUS(status); status = RtlSafeAddULONG(&requiredSize, requiredSize, size); GOTO_CLEANUP_ON_STATUS(status); status = RTL_ALLOCATE(&token, ACCESS_TOKEN, requiredSize); GOTO_CLEANUP_ON_STATUS(status); location = LW_PTR_ADD(token, sizeof(*token)); // Initialize token->ReferenceCount = 1; token->Flags = 0; unixError = pthread_rwlock_init(&token->RwLock, NULL); if (unixError) { LW_RTL_LOG_ERROR("Failed to init rwlock in access token " "(error = %d).", unixError); status = LwErrnoToNtStatus(unixError); GOTO_CLEANUP(); } token->pRwLock = &token->RwLock; token->User.Attributes = User->User.Attributes; token->User.Sid = (PSID) location; location = RtlpAppendData(location, User->User.Sid, RtlLengthSid(User->User.Sid)); token->GroupCount = Groups->GroupCount; token->Groups = (PSID_AND_ATTRIBUTES) location; location = LwRtlOffsetToPointer(location, sizeof(Groups->Groups[0]) * Groups->GroupCount); for (i = 0; i < Groups->GroupCount; i++) { token->Groups[i].Attributes = Groups->Groups[i].Attributes; token->Groups[i].Sid = (PSID) location; location = RtlpAppendData(location, Groups->Groups[i].Sid, RtlLengthSid(Groups->Groups[i].Sid)); } token->PrivilegeCount = Privileges->PrivilegeCount; token->Privileges = (PLUID_AND_ATTRIBUTES) location; location = LwRtlOffsetToPointer( location, sizeof(Privileges->Privileges[0]) * Privileges->PrivilegeCount); memcpy(token->Privileges, Privileges->Privileges, sizeof(token->Privileges[0]) * token->PrivilegeCount); if (Owner->Owner) { token->Owner = (PSID) location; location = RtlpAppendData(location, Owner->Owner, RtlLengthSid(Owner->Owner)); } if (PrimaryGroup->PrimaryGroup) { token->PrimaryGroup = (PSID) location; location = RtlpAppendData(location, PrimaryGroup->PrimaryGroup, RtlLengthSid(PrimaryGroup->PrimaryGroup)); } if (DefaultDacl->DefaultDacl) { token->DefaultDacl = (PACL) location; location = RtlpAppendData(location, DefaultDacl->DefaultDacl, DefaultDacl->DefaultDacl->AclSize); } if (Unix) { SetFlag(token->Flags, ACCESS_TOKEN_FLAG_UNIX_PRESENT); token->Uid = Unix->Uid; token->Gid = Unix->Gid; token->Umask = Unix->Umask; } if (location != LW_PTR_ADD(token, requiredSize)) { status = STATUS_ASSERTION_FAILURE; GOTO_CLEANUP(); } status = STATUS_SUCCESS; cleanup: if (!NT_SUCCESS(status)) { RtlReleaseAccessToken(&token); } *AccessToken = token; return status; }
FLT_POSTOP_CALLBACK_STATUS claimsmanPostOperation( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) /*++ Routine Description: This routine is the post-operation completion routine for this miniFilter. This is non-pageable because it may be called at DPC level. Arguments: Data - Pointer to the filter callbackData that is passed to us. FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. CompletionContext - The completion context set in the pre-operation routine. Flags - Denotes whether the completion is successful or is being drained. Return Value: The return value is the status of the operation. --*/ { UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(CompletionContext); UNREFERENCED_PARAMETER(Flags); NTSTATUS status; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; PUNICODE_STRING fileName = NULL; PTOKEN_USER pTokenUser = NULL; UNICODE_STRING sidString; LARGE_INTEGER Timeout; Timeout.QuadPart = (LONGLONG)1 * 10 * 1000 * 1000; // If there is no client registered, bail out immediately! // If the event is from kernel, bail out immediately! // If the event check for existence of file, bail out immediately! if ( (ClaimsmanData.ClientPort == NULL) || (Data->RequestorMode == KernelMode) || (Data->IoStatus.Information == FILE_DOES_NOT_EXIST) || (Data->IoStatus.Information == FILE_EXISTS) ) { return FLT_POSTOP_FINISHED_PROCESSING; } // We got a log record, if there is a file object, get its name. if (FltObjects->FileObject != NULL) { status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); } else { // Can't get a name when there's no file object status = STATUS_UNSUCCESSFUL; } if (NT_SUCCESS(status)) { FltParseFileNameInformation(nameInfo); fileName = &nameInfo->Name; // Produces way too much logging //PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, // ("claimsman!claimsmanPostOperation: fileName=%wZ\n", fileName)); } else { // No point continuing because we obviously did not get a filename anyways return FLT_POSTOP_FINISHED_PROCESSING; } //The only IRP you can trust for user information is IRP_MJ_CREATE. Things //like write can be in arbitrary thread context, and even if the call works //you can get the wrong SID. status = SeQueryInformationToken(SeQuerySubjectContextToken(&(Data->Iopb->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext)), TokenUser, &pTokenUser); if (STATUS_SUCCESS == status && RtlValidSid(pTokenUser->User.Sid)) { // Interesting extension? if (ClaimsmanCheckExtension(&nameInfo->Extension)) { CLAIMSMAN_MESSAGE msg; status = RtlConvertSidToUnicodeString(&sidString, pTokenUser->User.Sid, TRUE); if (NT_SUCCESS(status)) { PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: SID=%wZ\n", &sidString)); } else { // No point continuing because we obviously did not get a valid SID FltReleaseFileNameInformation(nameInfo); ExFreePool(pTokenUser); return FLT_POSTOP_FINISHED_PROCESSING; } if (ClaimsmanCheckUserIgnore(&sidString)) { // Ignored user! Bail out! FltReleaseFileNameInformation(nameInfo); ExFreePool(pTokenUser); RtlFreeUnicodeString(&sidString); return FLT_POSTOP_FINISHED_PROCESSING; } LONGLONG size; LONGLONG modified; getSizeModified(FltObjects->Instance, fileName, &size, &modified); InitializeMessage(&msg, &sidString, fileName, FltObjects->FileObject->ReadAccess, FltObjects->FileObject->WriteAccess, FltObjects->FileObject->DeleteAccess, size, modified, Data->IoStatus.Status); // Ready, send the message! // But only if there's a client connected if (ClaimsmanData.ClientPort != NULL) { FltSendMessage(ClaimsmanData.Filter, &ClaimsmanData.ClientPort, &msg, sizeof(msg), NULL, 0, &Timeout ); PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: sent message=%d\n", status)); } else { PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: no client connected!")); } RtlFreeUnicodeString(&sidString); } } FltReleaseFileNameInformation(nameInfo); if (pTokenUser != NULL) { ExFreePool(pTokenUser); } return FLT_POSTOP_FINISHED_PROCESSING; }
PSECURITY_DESCRIPTOR NTAPI INIT_FUNCTION CmpHiveRootSecurityDescriptor(VOID) { NTSTATUS Status; PSECURITY_DESCRIPTOR SecurityDescriptor; PACL Acl, AclCopy; PSID Sid[4]; SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; ULONG AceLength, AclLength, SidLength; PACE_HEADER AceHeader; ULONG i; PAGED_CODE(); /* Phase 1: Allocate SIDs */ SidLength = RtlLengthRequiredSid(1); Sid[0] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); Sid[1] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); Sid[2] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); SidLength = RtlLengthRequiredSid(2); Sid[3] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); /* Make sure all SIDs were allocated */ if (!(Sid[0]) || !(Sid[1]) || !(Sid[2]) || !(Sid[3])) { /* Bugcheck */ KeBugCheckEx(REGISTRY_ERROR, 11, 1, 0, 0); } /* Phase 2: Initialize all SIDs */ Status = RtlInitializeSid(Sid[0], &WorldAuthority, 1); Status |= RtlInitializeSid(Sid[1], &NtAuthority, 1); Status |= RtlInitializeSid(Sid[2], &NtAuthority, 1); Status |= RtlInitializeSid(Sid[3], &NtAuthority, 2); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 2, 0, 0); /* Phase 2: Setup SID Sub Authorities */ *RtlSubAuthoritySid(Sid[0], 0) = SECURITY_WORLD_RID; *RtlSubAuthoritySid(Sid[1], 0) = SECURITY_RESTRICTED_CODE_RID; *RtlSubAuthoritySid(Sid[2], 0) = SECURITY_LOCAL_SYSTEM_RID; *RtlSubAuthoritySid(Sid[3], 0) = SECURITY_BUILTIN_DOMAIN_RID; *RtlSubAuthoritySid(Sid[3], 1) = DOMAIN_ALIAS_RID_ADMINS; /* Make sure all SIDs are valid */ ASSERT(RtlValidSid(Sid[0])); ASSERT(RtlValidSid(Sid[1])); ASSERT(RtlValidSid(Sid[2])); ASSERT(RtlValidSid(Sid[3])); /* Phase 3: Calculate ACL Length */ AclLength = sizeof(ACL); for (i = 0; i < 4; i++) { /* This is what MSDN says to do */ AceLength = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart); AceLength += SeLengthSid(Sid[i]); AclLength += AceLength; } /* Phase 3: Allocate the ACL */ Acl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_CM); if (!Acl) KeBugCheckEx(REGISTRY_ERROR, 11, 3, 0, 0); /* Phase 4: Create the ACL */ Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 4, Status, 0); /* Phase 5: Build the ACL */ Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[0]); Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[1]); Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[2]); Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[3]); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 5, Status, 0); /* Phase 5: Make the ACEs inheritable */ Status = RtlGetAce(Acl, 0,( PVOID*)&AceHeader); ASSERT(NT_SUCCESS(Status)); AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; Status = RtlGetAce(Acl, 1, (PVOID*)&AceHeader); ASSERT(NT_SUCCESS(Status)); AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; Status = RtlGetAce(Acl, 2, (PVOID*)&AceHeader); ASSERT(NT_SUCCESS(Status)); AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; Status = RtlGetAce(Acl, 3, (PVOID*)&AceHeader); ASSERT(NT_SUCCESS(Status)); AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; /* Phase 6: Allocate the security descriptor and make space for the ACL */ SecurityDescriptor = ExAllocatePoolWithTag(PagedPool, sizeof(SECURITY_DESCRIPTOR) + AclLength, TAG_CM); if (!SecurityDescriptor) KeBugCheckEx(REGISTRY_ERROR, 11, 6, 0, 0); /* Phase 6: Make a copy of the ACL */ AclCopy = (PACL)((PISECURITY_DESCRIPTOR)SecurityDescriptor + 1); RtlCopyMemory(AclCopy, Acl, AclLength); /* Phase 7: Create the security descriptor */ Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 7, Status, 0); /* Phase 8: Set the ACL as a DACL */ Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, AclCopy, FALSE); if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 8, Status, 0); /* Free the SIDs and original ACL */ for (i = 0; i < 4; i++) ExFreePoolWithTag(Sid[i], TAG_CM); ExFreePoolWithTag(Acl, TAG_CM); /* Return the security descriptor */ return SecurityDescriptor; }
/* * @implemented */ BOOLEAN NTAPI RtlValidRelativeSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptorInput, IN ULONG SecurityDescriptorLength, IN SECURITY_INFORMATION RequiredInformation) { PISECURITY_DESCRIPTOR_RELATIVE Sd = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptorInput; PSID Owner, Group; PACL Dacl, Sacl; ULONG Length; PAGED_CODE_RTL(); /* Note that Windows allows no DACL/SACL even if RequiredInfo wants it */ /* Do we have enough space, is the revision vaild, and is this SD relative? */ if ((SecurityDescriptorLength < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) || (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) || !(Sd->Control & SE_SELF_RELATIVE)) { /* Nope, bail out */ return FALSE; } /* Is there an owner? */ if (Sd->Owner) { /* Try to access it */ if (!RtlpValidateSDOffsetAndSize(Sd->Owner, SecurityDescriptorLength, sizeof(SID), &Length)) { /* It's beyond the buffer, fail */ return FALSE; } /* Read the owner, check if it's valid and if the buffer contains it */ Owner = (PSID)((ULONG_PTR)Sd->Owner + (ULONG_PTR)Sd); if (!RtlValidSid(Owner) || (Length < RtlLengthSid(Owner))) return FALSE; } else if (RequiredInformation & OWNER_SECURITY_INFORMATION) { /* No owner but the caller expects one, fail */ return FALSE; } /* Is there a group? */ if (Sd->Group) { /* Try to access it */ if (!RtlpValidateSDOffsetAndSize(Sd->Group, SecurityDescriptorLength, sizeof(SID), &Length)) { /* It's beyond the buffer, fail */ return FALSE; } /* Read the group, check if it's valid and if the buffer contains it */ Group = (PSID)((ULONG_PTR)Sd->Group + (ULONG_PTR)Sd); if (!RtlValidSid(Group) || (Length < RtlLengthSid(Group))) return FALSE; } else if (RequiredInformation & GROUP_SECURITY_INFORMATION) { /* No group, but the caller expects one, fail */ return FALSE; } /* Is there a DACL? */ if ((Sd->Control & SE_DACL_PRESENT) == SE_DACL_PRESENT) { /* Try to access it */ if (!RtlpValidateSDOffsetAndSize(Sd->Dacl, SecurityDescriptorLength, sizeof(ACL), &Length)) { /* It's beyond the buffer, fail */ return FALSE; } /* Read the DACL, check if it's valid and if the buffer contains it */ Dacl = (PSID)((ULONG_PTR)Sd->Dacl + (ULONG_PTR)Sd); if (!(RtlValidAcl(Dacl)) || (Length < Dacl->AclSize)) return FALSE; } /* Is there a SACL? */ if ((Sd->Control & SE_SACL_PRESENT) == SE_SACL_PRESENT) { /* Try to access it */ if (!RtlpValidateSDOffsetAndSize(Sd->Sacl, SecurityDescriptorLength, sizeof(ACL), &Length)) { /* It's beyond the buffer, fail */ return FALSE; } /* Read the SACL, check if it's valid and if the buffer contains it */ Sacl = (PSID)((ULONG_PTR)Sd->Sacl + (ULONG_PTR)Sd); if (!(RtlValidAcl(Sacl)) || (Length < Sacl->AclSize)) return FALSE; } /* All good */ return TRUE; }
NTSTATUS NTAPI RtlpAddKnownAce(IN PACL Acl, IN ULONG Revision, IN ULONG Flags, IN ACCESS_MASK AccessMask, IN PSID Sid, IN UCHAR Type) { PKNOWN_ACE Ace; ULONG AceSize, InvalidFlags; PAGED_CODE_RTL(); /* Check the validity of the SID */ if (!RtlValidSid(Sid)) return STATUS_INVALID_SID; /* Check the validity of the revision */ if ((Acl->AclRevision > ACL_REVISION4) || (Revision > ACL_REVISION4)) { return STATUS_REVISION_MISMATCH; } /* Pick the smallest of the revisions */ if (Revision < Acl->AclRevision) Revision = Acl->AclRevision; /* Validate the flags */ if (Type == SYSTEM_AUDIT_ACE_TYPE) { InvalidFlags = Flags & ~(VALID_INHERIT_FLAGS | SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG); } else { InvalidFlags = Flags & ~VALID_INHERIT_FLAGS; } /* If flags are invalid, bail out */ if (InvalidFlags != 0) return STATUS_INVALID_PARAMETER; /* If ACL is invalid, bail out */ if (!RtlValidAcl(Acl)) return STATUS_INVALID_ACL; /* If there's no free ACE, bail out */ if (!RtlFirstFreeAce(Acl, (PACE*)&Ace)) return STATUS_INVALID_ACL; /* Calculate the size of the ACE and bail out if it's too small */ AceSize = RtlLengthSid(Sid) + sizeof(ACE); if (!(Ace) || ((ULONG_PTR)Ace + AceSize > (ULONG_PTR)Acl + Acl->AclSize)) { return STATUS_ALLOTTED_SPACE_EXCEEDED; } /* Initialize the header and common fields */ Ace->Header.AceFlags = (BYTE)Flags; Ace->Header.AceType = Type; Ace->Header.AceSize = (WORD)AceSize; Ace->Mask = AccessMask; /* Copy the SID */ RtlCopySid(RtlLengthSid(Sid), &Ace->SidStart, Sid); /* Fill out the ACL header and return */ Acl->AceCount++; Acl->AclRevision = (BYTE)Revision; return STATUS_SUCCESS; }
/****************************************************************************** * IsValidSid [ADVAPI32.@] * * PARAMS * pSid [] */ BOOL WINAPI IsValidSid( PSID pSid ) { return RtlValidSid( pSid ); }