2.6 Parsing — views

To read a security descriptor, ACL, or ACE you use zero-copy views. A view is a caller-allocated, opaque, stack-friendly struct that borrows the buffer you parse — see the view rules. Every accessor that yields a SID, a nested ACL, or a blob returns a pointer into the original buffer, so that buffer must outlive the view and everything derived from it.

typedef struct peios_sd_view        { uint64_t _opaque[8]; } peios_sd_view;
typedef struct peios_acl_view       { uint64_t _opaque[4]; } peios_acl_view;
typedef struct peios_ace_view       { uint64_t _opaque[4]; } peios_ace_view;
typedef struct peios_sid_array_view { uint64_t _opaque[4]; } peios_sid_array_view;

The _opaque arrays are sized for stack allocation with headroom — declare a view as a local and never read its fields.

2.6.0.1 Security-descriptor views #

int      peios_sd_parse(const void *sd, size_t len, peios_sd_view *out);
uint16_t peios_sd_view_control(const peios_sd_view *v);
int      peios_sd_view_owner(const peios_sd_view *v, const void **sid, size_t *len);
int      peios_sd_view_group(const peios_sd_view *v, const void **sid, size_t *len);
int      peios_sd_view_dacl(const peios_sd_view *v, peios_acl_view *out);
int      peios_sd_view_sacl(const peios_sd_view *v, peios_acl_view *out);

peios_sd_parse validates a self-relative SD and populates out, returning 0 or -1 (EINVAL). peios_sd_view_control returns the raw control-bit word.

The four component accessors return 0 with their out-params set on success, or -1 if the component is absent. For the DACL and SACL, -1 also covers the NULL-DACL case — since an absent DACL and a NULL DACL are the same thing in KACS, a -1 from peios_sd_view_dacl uniformly means "no DACL constrains this object."

2.6.0.2 ACL and ACE views #

You can also parse a bare ACL directly — a token's default DACL, for instance, arrives as an ACL, not wrapped in an SD:

int      peios_acl_parse(const void *acl, size_t len, peios_acl_view *out);
unsigned peios_acl_view_count(const peios_acl_view *a);
int      peios_acl_view_ace(const peios_acl_view *a, unsigned i, peios_ace_view *out);

peios_acl_view_count gives the number of ACEs; peios_acl_view_ace populates out for ACE i (0-based, in stored order), returning 0 or -1 (ERANGE for an out-of-range index). Iterate in the obvious way:

unsigned n = peios_acl_view_count(&dacl);
for (unsigned i = 0; i < n; i++) {
    peios_ace_view ace;
    peios_acl_view_ace(&dacl, i, &ace);
    /* inspect ace … */
}

Each ACE is read through its own accessors:

uint8_t  peios_ace_view_type(const peios_ace_view *e);
uint8_t  peios_ace_view_flags(const peios_ace_view *e);
uint32_t peios_ace_view_mask(const peios_ace_view *e);
int      peios_ace_view_sid(const peios_ace_view *e, const void **sid, size_t *len);
int      peios_ace_view_object_type(const peios_ace_view *e, const uint8_t **guid16);
int      peios_ace_view_inherited_object_type(const peios_ace_view *e,
                                              const uint8_t **guid16);
int      peios_ace_view_app_data(const peios_ace_view *e, const void **data,
                                 size_t *len);
AccessorYields
_type / _flags / _maskThe ACE's KACS_ACE_TYPE_* type, KACS_ACE_FLAG_* flags, and 32-bit access mask.
_sidThe trustee SID (a pointer into the buffer). 0 / -1.
_object_typeThe object GUID of an object ACE — 0 with *guid16 set to the 16 bytes, or -1 if not present / not an object ACE.
_inherited_object_typeThe inherited-object GUID, same convention.
_app_dataTrailing application data of a callback or resource-attribute ACE — for a callback ACE, this is the conditional-expression bytecode you can render with peios_sddl_format_condition.

2.6.0.3 SID-and-attributes arrays #

Several token classes — GROUPS, RESTRICTED_SIDS, DEVICE_GROUPS, CAPABILITIES — return a packed [count][sid_len][sid][attrs]… blob rather than an ACL. Parse those with the SID-array view:

int      peios_sid_array_parse(const void *blob, size_t len, peios_sid_array_view *out);
unsigned peios_sid_array_count(const peios_sid_array_view *a);
int      peios_sid_array_get(const peios_sid_array_view *a, unsigned i,
                             const void **sid, size_t *len, uint32_t *attrs);

peios_sid_array_get yields the i-th entry's SID (a pointer into the blob), its length, and its 32-bit attribute word (the KACS_SE_GROUP_* flags — enabled, mandatory, deny-only, and so on).

Edit this page