74 lines
2.9 KiB
Plaintext
74 lines
2.9 KiB
Plaintext
Internals of the libacl library
|
|
===============================
|
|
|
|
Posix 1003.1e DS17 leaves the library developer relatively few choices
|
|
on how to implement the library. A pseudo object oriented approach
|
|
seems necessary (otherwise, not all of the requirements can be met).
|
|
Unfortunately, C is no object oriented language, so the classes etc.
|
|
need to be hand coded. Here is how it works.
|
|
|
|
From the user's point of view, the following things are objects:
|
|
|
|
F - acl_t objects
|
|
- acl_entry_t objects
|
|
- acl_permset_t objects
|
|
F - strings returned by acl_to_text
|
|
F - entities returned by acl_get_qualifier
|
|
|
|
The objects flagged with F need to be freed with acl_free() when they
|
|
are no longer needed.
|
|
|
|
The user gets pointers to the contents of these objects. Each object
|
|
also has a prefix, which is not accessible from the user. The complete
|
|
objects are declared in <lib/libacl.h>. The p_magic field of the
|
|
prefix is set to <object_name>_MAGIC.
|
|
|
|
The macros ext2int() and int2ext() convert between the internal and
|
|
external view on objects. The macros new_obj_p() and new_var_obj_p()
|
|
create a new object and object with variable size, respectively. See
|
|
the code for the rest.
|
|
|
|
The code necessary to access fields in objects, especially in objects
|
|
accessed through indirections, would get almost unreadable. The second
|
|
ACL entry of an ACL would be:
|
|
|
|
acl_obj *acl_p;
|
|
acl_entry_obj *acl_entry_p = acl_p->i.a_ring->i.e_next;
|
|
|
|
For better readability, all the "i.a_", "i.e_" etc. parts can be
|
|
hidden using macros:
|
|
|
|
acl_obj *acl_p;
|
|
acl_entry_obj *acl_entry_p = acl_p->aring->enext;
|
|
|
|
|
|
ACLs and ACL entries
|
|
====================
|
|
The ACL entries associated with an ACL are stored on a sorted double
|
|
linked list. The first and last entries in that list are available via
|
|
ACL object. This is implemented with a little trick:
|
|
|
|
The acl_obj and acl_entry_obj have {a,e}_prev and {a,e}_prev
|
|
pointers at the same memory location (directly after the object
|
|
prefix). The a_prev and a_next entries of an acl_obj are
|
|
initialized to point to the acl_obj itself (this requires a type
|
|
cast). We only need to check if the acl_obj object has been
|
|
reached to detect the end of the list. Since the acl_obj object
|
|
isn't actually an acl_entry_obj object, care must be taken not to
|
|
manipulate any of the other acl_entry_obj fields other than e_prev
|
|
and e_next.
|
|
|
|
Whenever an entry is changed, __acl_reorder_obj_p() reorders the
|
|
entries accordingly. This takes O(n^2) time, but that's not a big
|
|
problem as long as ACLs don't contain very many entries. Some of the
|
|
library functions need a sorted ACL anyway, so the best we could
|
|
possibly do is O(n*log(n)), with a sorted flag in each ACL, and a
|
|
complicated sorting function (the linked list would have to be
|
|
converted to an array first to allow more efficient sorting).
|
|
|
|
|
|
Hope that helps. Good luck!
|
|
|
|
Andreas
|
|
|