/********************************************************/ /* ntapi: Native API core library */ /* Copyright (C) 2013--2017 Z. Gilboa */ /* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ /********************************************************/ #include #include #include #include #include "ntapi_impl.h" #define __SID_SYSTEM {1,1,{{0,0,0,0,0,5}},{18}} #define __SID_OWNER_RIGHTS {1,1,{{0,0,0,0,0,3}},{4}} #define __SID_AUTHENTICATED_USERS {1,1,{{0,0,0,0,0,5}},{11}} #define __SID_ADMINISTRATORS {1,2,{{0,0,0,0,0,5}},{32,544}} static const nt_sid sid_system = __SID_SYSTEM; static const nt_sid sid_owner_rights = __SID_OWNER_RIGHTS; static const nt_sid sid_auth_users = __SID_AUTHENTICATED_USERS; static const nt_sid_os sid_admins = __SID_ADMINISTRATORS; static nt_access_allowed_ace * __acl_ace_init( nt_access_allowed_ace * ace, uint32_t mask, const nt_sid * sid, uint32_t flags, uint16_t * aces) { if (mask == 0) return ace; ace->mask = mask; ace->header.ace_type = NT_ACE_TYPE_ACCESS_ALLOWED; ace->header.ace_flags = flags; ace->header.ace_size = sizeof(uint32_t) * sid->sub_authority_count + __offsetof(nt_access_allowed_ace,sid_start) + __offsetof(nt_sid,sub_authority); __ntapi->tt_sid_copy( (nt_sid *)&ace->sid_start, sid); (*aces)++; return (nt_access_allowed_ace *)((size_t)ace + ace->header.ace_size); } void __stdcall __ntapi_acl_init_common_descriptor( __out nt_sd_common_buffer * sd, __in const nt_sid * owner, __in const nt_sid * group, __in const nt_sid * other, __in const nt_sid * admin, __in uint32_t owner_access, __in uint32_t group_access, __in uint32_t other_access, __in uint32_t admin_access, __in uint32_t system_access, __in uint32_t ace_flags) { nt_access_allowed_ace * ace; uint16_t ace_count = 0; /* sd header */ sd->sd.revision = 1; sd->sd.sbz_1st = 0; sd->sd.control = NT_SE_SELF_RELATIVE | NT_SE_DACL_PRESENT | NT_SE_DACL_PROTECTED; sd->sd.offset_owner = __offsetof(nt_sd_common_buffer,owner); sd->sd.offset_group = 0; sd->sd.offset_dacl = __offsetof(nt_sd_common_buffer,dacl); sd->sd.offset_sacl = 0; /* owner, group, other: default sid's */ owner = owner ? owner : __ntapi_internals()->user; group = group ? group : owner; other = other ? other : &sid_auth_users; /* owner sid */ __ntapi->tt_sid_copy( (nt_sid *)&sd->owner, owner); /* is the local system account both the owner and the group? */ if (!__ntapi->tt_sid_compare(owner,&sid_system)) if (!__ntapi->tt_sid_compare(group,&sid_system)) if (system_access == owner_access) system_access = 0; /* is the built-in administrators group both the owner and the group? */ if (!__ntapi->tt_sid_compare(owner,(nt_sid *)&sid_admins)) if (!__ntapi->tt_sid_compare(group,(nt_sid *)&sid_admins)) if (admin_access == owner_access) admin_access = 0; /* ace's */ ace = (nt_access_allowed_ace *)&sd->buffer; ace = __acl_ace_init(ace,system_access,&sid_system,ace_flags,&ace_count); ace = __acl_ace_init(ace,owner_access,&sid_owner_rights,ace_flags,&ace_count); ace = __acl_ace_init(ace,group_access,group,ace_flags,&ace_count); ace = __acl_ace_init(ace,other_access,other,ace_flags,&ace_count); if (admin_access) { admin = admin ? admin : (nt_sid *)&sid_admins; ace = __acl_ace_init(ace,admin_access,admin,ace_flags,&ace_count); } /* dacl */ sd->dacl.acl_revision = 0x02; sd->dacl.sbz_1st = 0; sd->dacl.acl_size = (uint16_t)((char *)ace - (char *)&sd->dacl); sd->dacl.ace_count = ace_count; sd->dacl.sbz_2nd = 0; } static int32_t __acl_init_common_meta_impl( __out nt_sd_common_meta * meta, __in nt_sd * sd) { int i; nt_sid * sid; nt_acl * acl; nt_access_allowed_ace * ace; nt_access_allowed_ace * sysace; nt_sid * syssid; unsigned char * value; unsigned char sacnt; char * mark = (char *)sd; meta->sd = sd; meta->owner = sd->offset_owner ? (nt_sid *)(mark + sd->offset_owner) : 0; meta->group = 0; meta->dacl = sd->offset_dacl ? (nt_acl *)(mark + sd->offset_dacl) : 0; meta->owner_ace = 0; meta->owner_sid = 0; meta->group_ace = 0; meta->group_sid = 0; meta->other_ace = 0; meta->other_sid = 0; meta->admin_ace = 0; meta->admin_sid = 0; meta->system_acc = 0; if (!meta->owner) return NT_STATUS_INVALID_OWNER; if (!(acl = meta->dacl)) return NT_STATUS_SUCCESS; if (acl->ace_count == 0) return NT_STATUS_SUCCESS; if (acl->ace_count > 5) return NT_STATUS_NOT_SUPPORTED; ace = (nt_access_allowed_ace *)&acl[1]; for (i=0; iace_count; i++) { if (ace->header.ace_type != NT_ACE_TYPE_ACCESS_ALLOWED) return NT_STATUS_NOT_SUPPORTED; mark = (char *)ace + ace->header.ace_size; ace = (nt_access_allowed_ace *)mark; } ace = (nt_access_allowed_ace *)&acl[1]; for (i=0; iace_count; i++) { sid = (nt_sid *)&ace->sid_start; value = sid->identifier_authority.value; if (!(__ntapi->tt_sid_compare(sid,&sid_system))) { meta->system_acc = ace->mask; sysace = ace; syssid = sid; } else if (!(__ntapi->tt_sid_compare(sid,&sid_owner_rights))) { if (meta->owner_ace) return NT_STATUS_INVALID_ACL; meta->owner_ace = ace; meta->owner_sid = sid; } else if (!(__ntapi->tt_sid_compare(sid,&sid_auth_users))) { if (meta->other_ace) return NT_STATUS_INVALID_ACL; meta->other_ace = ace; meta->other_sid = sid; } else if (!(__ntapi->tt_sid_compare(sid,meta->owner))) { if (meta->group_ace) return NT_STATUS_INVALID_ACL; meta->group_ace = ace; meta->group_sid = sid; } else if (!(__ntapi->tt_sid_compare(sid,(nt_sid *)&sid_admins))) { if (meta->admin_ace) return NT_STATUS_INVALID_ACL; meta->admin_ace = ace; meta->admin_sid = sid; } else if ((value[0] == 0) && (value[1] == 0) && (value[2] == 0) && (value[3] == 0) && (value[4] == 0) && (value[5] == 5) && (sid->sub_authority[0] == 21) && ((sacnt = sid->sub_authority_count)) && (sid->sub_authority[sacnt - 1] == 500)) { if (meta->admin_ace) return NT_STATUS_INVALID_ACL; meta->admin_ace = ace; meta->admin_sid = sid; } else { if (meta->group_ace) return NT_STATUS_INVALID_ACL; meta->group_ace = ace; meta->group_sid = sid; meta->group = sid; } mark = (char *)ace + ace->header.ace_size; ace = (nt_access_allowed_ace *)mark; } if (!meta->group_ace && meta->owner_ace) { if (meta->owner_ace->mask != meta->system_acc) { if (!__ntapi->tt_sid_compare(meta->owner,&sid_system)) { meta->group_ace = sysace; meta->group_sid = syssid; meta->group = syssid; meta->system_acc = meta->owner_ace->mask; } } } return NT_STATUS_SUCCESS; } static int32_t __acl_init_common_meta_strict( __out nt_sd_common_meta * meta, __in nt_sd * sd) { int32_t status; nt_sd_common_meta m; if ((status = __acl_init_common_meta_impl(&m,sd))) return status; meta->sd = m.sd; meta->owner = m.owner; meta->group = m.group; meta->dacl = m.dacl; meta->owner_ace = m.owner_ace; meta->owner_sid = m.owner_sid; meta->group_ace = m.group_ace; meta->group_sid = m.group_sid; meta->other_ace = m.other_ace; meta->other_sid = m.other_sid; meta->admin_ace = m.admin_ace; meta->admin_sid = m.admin_sid; meta->system_acc = m.system_acc; return NT_STATUS_SUCCESS; } static int32_t __acl_init_common_meta_query( __out nt_sd_common_meta * meta, __in nt_sd * sd) { __acl_init_common_meta_impl(meta,sd); return NT_STATUS_SUCCESS; } int32_t __stdcall __ntapi_acl_init_common_descriptor_meta( __out nt_sd_common_meta * meta, __in nt_sd * sd, __in uint32_t options) { switch (options) { case NT_ACL_INIT_COMMON_DESCRIPTION_META_QUERY_MODE: return __acl_init_common_meta_query(meta,sd); case NT_ACL_INIT_COMMON_DESCRIPTION_META_STRICT_MODE: return __acl_init_common_meta_strict(meta,sd); default: return NT_STATUS_INVALID_PARAMETER; } }