+static uint32_t posix_permset_to_darwin_rights(acl_entry_t e, int is_dir)
+{
+ EC_INIT;
+ uint32_t rights = 0;
+ acl_permset_t permset;
+
+ EC_ZERO_LOG(acl_get_permset(e, &permset));
+
+ if (acl_get_perm(permset, ACL_READ))
+ rights = DARWIN_ACE_READ_DATA
+ | DARWIN_ACE_READ_EXTATTRIBUTES
+ | DARWIN_ACE_READ_ATTRIBUTES
+ | DARWIN_ACE_READ_SECURITY;
+ if (acl_get_perm(permset, ACL_WRITE)) {
+ rights |= DARWIN_ACE_WRITE_DATA
+ | DARWIN_ACE_APPEND_DATA
+ | DARWIN_ACE_WRITE_EXTATTRIBUTES
+ | DARWIN_ACE_WRITE_ATTRIBUTES;
+ if (is_dir)
+ rights |= DARWIN_ACE_DELETE_CHILD;
+ }
+ if (acl_get_perm(permset, ACL_EXECUTE))
+ rights |= DARWIN_ACE_EXECUTE;
+
+EC_CLEANUP:
+ LOG(log_maxdebug, logtype_afpd, "mapped rights: 0x%08x", rights);
+ return rights;
+}
+
+/*!
+ * Compile access rights for a user to one file-system object
+ *
+ * This combines combines all access rights for a user to one fs-object and
+ * returns the result as a Darwin allowed rights ACE.
+ * This must honor trivial ACEs which are a mode_t mapping.
+ *
+ * @param path (r) path to filesystem object
+ * @param sb (r) struct stat of path
+ * @param result (rw) resulting Darwin allow ACE
+ *
+ * @returns 0 or -1 on error
+ */
+static int posix_acl_rights(const char *path,
+ const struct stat *sb,
+ uint32_t *result)
+{
+ EC_INIT;
+ int havemask = 0;
+ int entry_id = ACL_FIRST_ENTRY;
+ uint32_t rights = 0, maskrights = 0;
+ uid_t *uid = NULL;
+ gid_t *gid = NULL;
+ acl_t acl = NULL;
+ acl_entry_t e;
+ acl_tag_t tag;
+
+ EC_NULL_LOG(acl = acl_get_file(path, ACL_TYPE_ACCESS));
+
+ /* itereate through all ACEs to get the mask */
+ while (!havemask && acl_get_entry(acl, entry_id, &e) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ EC_ZERO_LOG(acl_get_tag_type(e, &tag));
+ switch (tag) {
+ case ACL_MASK:
+ maskrights = posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ LOG(log_maxdebug, logtype_afpd, "maskrights: 0x%08x", maskrights);
+ havemask = 1;
+ break;
+ default:
+ continue;
+ }
+ }
+
+ /* itereate through all ACEs */
+ entry_id = ACL_FIRST_ENTRY;
+ while (acl_get_entry(acl, entry_id, &e) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ EC_ZERO_LOG(acl_get_tag_type(e, &tag));
+ switch (tag) {
+ case ACL_USER:
+ EC_NULL_LOG(uid = (uid_t *)acl_get_qualifier(e));
+ if (*uid == uuid) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_USER: %u", *uid);
+ rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ }
+ acl_free(uid);
+ uid = NULL;
+ break;
+ case ACL_USER_OBJ:
+ if (sb->st_uid == uuid) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_USER_OBJ: %u", sb->st_uid);
+ rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ }
+ break;
+ case ACL_GROUP:
+ EC_NULL_LOG(gid = (gid_t *)acl_get_qualifier(e));
+ if (gmem(*gid)) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_GROUP: %u", *gid);
+ rights |= (posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode)) & maskrights);
+ }
+ acl_free(gid);
+ gid = NULL;
+ break;
+ case ACL_GROUP_OBJ:
+ if (gmem(sb->st_gid)) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_GROUP_OBJ: %u", sb->st_gid);
+ rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ }
+ break;
+ case ACL_OTHER:
+ LOG(log_maxdebug, logtype_afpd, "ACL_OTHER");
+ rights |= posix_permset_to_darwin_rights(e, S_ISDIR(sb->st_mode));
+ break;
+ default:
+ continue;
+ }
+ } /* while */
+
+ *result |= rights;
+
+EC_CLEANUP:
+ if (acl) acl_free(acl);
+ if (uid) acl_free(uid);
+ if (gid) acl_free(gid);
+ EC_EXIT;
+}
+