#include "includes.h"
#include "nterr.h"
#include "sids.h"
static BOOL token_sid_in_ace(const NT_USER_TOKEN *token, const SEC_ACE *ace)
{
size_t i;
for (i = 0; i < token->num_sids; i++) {
if (sid_equal(&ace->trustee, &token->user_sids[i]))
return True;
}
return False;
}
static uint32 check_ace(SEC_ACE *ace, NT_USER_TOKEN *token, uint32 acc_desired,
NTSTATUS *status)
{
uint32 mask = ace->info.mask;
if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
return acc_desired;
}
if (!token_sid_in_ace( token, ace))
return acc_desired;
switch (ace->type) {
case SEC_ACE_TYPE_ACCESS_ALLOWED:
acc_desired &= ~mask;
break;
case SEC_ACE_TYPE_ACCESS_DENIED:
if (acc_desired & mask) {
*status = NT_STATUS_ACCESS_DENIED;
return 0xFFFFFFFF;
}
break;
case SEC_ACE_TYPE_SYSTEM_ALARM:
case SEC_ACE_TYPE_SYSTEM_AUDIT:
*status = NT_STATUS_NOT_IMPLEMENTED;
return 0xFFFFFFFF;
default:
*status = NT_STATUS_INVALID_PARAMETER;
return 0xFFFFFFFF;
}
return acc_desired;
}
static BOOL get_max_access( SEC_ACL *the_acl, NT_USER_TOKEN *token, uint32 *granted,
uint32 desired,
NTSTATUS *status)
{
uint32 acc_denied = 0;
uint32 acc_granted = 0;
size_t i;
for ( i = 0 ; i < the_acl->num_aces; i++) {
SEC_ACE *ace = &the_acl->ace[i];
uint32 mask = ace->info.mask;
if (!token_sid_in_ace( token, ace))
continue;
switch (ace->type) {
case SEC_ACE_TYPE_ACCESS_ALLOWED:
acc_granted |= (mask & ~acc_denied);
break;
case SEC_ACE_TYPE_ACCESS_DENIED:
acc_denied |= (mask & ~acc_granted);
break;
case SEC_ACE_TYPE_SYSTEM_ALARM:
case SEC_ACE_TYPE_SYSTEM_AUDIT:
*status = NT_STATUS_NOT_IMPLEMENTED;
*granted = 0;
return False;
default:
*status = NT_STATUS_INVALID_PARAMETER;
*granted = 0;
return False;
}
}
if ((acc_granted == 0) || ((acc_granted & desired) != desired)) {
*status = NT_STATUS_ACCESS_DENIED;
*granted = 0;
return False;
}
*granted = acc_granted;
*status = NT_STATUS_OK;
return True;
}
void se_map_generic(uint32 *access_mask, struct generic_mapping *mapping)
{
uint32 old_mask = *access_mask;
if (*access_mask & GENERIC_READ_ACCESS) {
*access_mask &= ~GENERIC_READ_ACCESS;
*access_mask |= mapping->generic_read;
}
if (*access_mask & GENERIC_WRITE_ACCESS) {
*access_mask &= ~GENERIC_WRITE_ACCESS;
*access_mask |= mapping->generic_write;
}
if (*access_mask & GENERIC_EXECUTE_ACCESS) {
*access_mask &= ~GENERIC_EXECUTE_ACCESS;
*access_mask |= mapping->generic_execute;
}
if (*access_mask & GENERIC_ALL_ACCESS) {
*access_mask &= ~GENERIC_ALL_ACCESS;
*access_mask |= mapping->generic_all;
}
if (old_mask != *access_mask) {
DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
old_mask, *access_mask));
}
}
BOOL se_access_check(SEC_DESC *sd, NT_USER_TOKEN *token,
uint32 acc_desired, uint32 *acc_granted,
NTSTATUS *status)
{
extern NT_USER_TOKEN anonymous_token;
size_t i;
SEC_ACL *the_acl;
fstring sid_str;
uint32 tmp_acc_desired = acc_desired;
if (!status || !acc_granted)
return False;
if (!token)
token = &anonymous_token;
*status = NT_STATUS_OK;
*acc_granted = 0;
DEBUG(10,("se_access_check: requested access %x, for NT token with %u entries and first sid %s.\n",
(unsigned int)acc_desired, (unsigned int)token->num_sids,
sid_to_string(sid_str, &token->user_sids[0])));
if (!sd || (sd && (!(sd->type & SEC_DESC_DACL_PRESENT) || sd->dacl == NULL))) {
*status = NT_STATUS_OK;
*acc_granted = acc_desired;
DEBUG(5, ("se_access_check: no sd or blank DACL, access allowed\n"));
return True;
}
DEBUG(3, ("se_access_check: user sid is %s\n", sid_to_string(sid_str, &token->user_sids[PRIMARY_USER_SID_INDEX]) ));
for (i = 1; i < token->num_sids; i++) {
DEBUG(3, ("se_access_check: also %s\n",
sid_to_string(sid_str, &token->user_sids[i])));
}
if (sd->owner_sid) {
for (i = 0; i < token->num_sids; i++) {
if (sid_equal(&token->user_sids[i], sd->owner_sid)) {
if (tmp_acc_desired & WRITE_DAC_ACCESS)
tmp_acc_desired &= ~WRITE_DAC_ACCESS;
if (tmp_acc_desired & READ_CONTROL_ACCESS)
tmp_acc_desired &= ~READ_CONTROL_ACCESS;
}
}
}
the_acl = sd->dacl;
if (tmp_acc_desired & MAXIMUM_ALLOWED_ACCESS) {
tmp_acc_desired &= ~MAXIMUM_ALLOWED_ACCESS;
return get_max_access( the_acl, token, acc_granted, tmp_acc_desired,
status);
}
for ( i = 0 ; i < the_acl->num_aces && tmp_acc_desired != 0; i++) {
SEC_ACE *ace = &the_acl->ace[i];
DEBUG(10,("se_access_check: ACE %u: type %d, flags = 0x%02x, SID = %s mask = %x, current desired = %x\n",
(unsigned int)i, ace->type, ace->flags,
sid_to_string(sid_str, &ace->trustee),
(unsigned int) ace->info.mask,
(unsigned int)tmp_acc_desired ));
tmp_acc_desired = check_ace( ace, token, tmp_acc_desired, status);
if (NT_STATUS_V(*status)) {
*acc_granted = 0;
DEBUG(5,("se_access_check: ACE %u denied with status %s.\n", (unsigned int)i, get_nt_error_msg(*status)));
return False;
}
}
if (tmp_acc_desired == 0) {
*acc_granted = acc_desired;
*status = NT_STATUS_OK;
DEBUG(5,("se_access_check: access (%x) granted.\n", (unsigned int)acc_desired ));
return True;
}
*acc_granted = 0;
*status = NT_STATUS_ACCESS_DENIED;
DEBUG(5,("se_access_check: access (%x) denied.\n", (unsigned int)acc_desired ));
return False;
}
SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
BOOL child_container)
{
SEC_DESC_BUF *sdb;
SEC_DESC *sd;
SEC_ACL *new_dacl, *the_acl;
SEC_ACE *new_ace_list = NULL;
int new_ace_list_ndx = 0, i;
size_t size;
the_acl = parent_ctr->dacl;
if (!(new_ace_list = talloc(ctx, sizeof(SEC_ACE) * the_acl->num_aces)))
return NULL;
for (i = 0; the_acl && i < the_acl->num_aces; i++) {
SEC_ACE *ace = &the_acl->ace[i];
SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
uint8 new_flags = 0;
BOOL inherit = False;
fstring sid_str;
if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
if (!child_container) {
new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
} else {
new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
}
inherit = True;
}
if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
if (!child_container) {
inherit = False;
} else {
new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
}
}
if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
}
if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_CONTAINER_INHERIT);
}
if (!inherit)
continue;
init_sec_access(&new_ace->info, ace->info.mask);
init_sec_ace(new_ace, &ace->trustee, ace->type,
new_ace->info, new_flags);
sid_to_string(sid_str, &ace->trustee);
DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
" inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
ace->type, ace->flags, ace->info.mask,
sid_str, new_ace->type, new_ace->flags,
new_ace->info.mask));
new_ace_list_ndx++;
}
new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
sd = make_sec_desc(ctx, SEC_DESC_REVISION,
parent_ctr->owner_sid,
parent_ctr->grp_sid,
parent_ctr->sacl,
new_dacl, &size);
sdb = make_sec_desc_buf(ctx, size, sd);
return sdb;
}