+/*!
+ * Helper function for posix_acls_to_uaperms() to convert Posix ACL permissions
+ * into access rights needed to fill ua_permissions of a FPUnixPrivs structure.
+ *
+ * @param entry (r) Posix ACL entry
+ *
+ * @returns access rights
+ */
+static u_char acl_permset_to_uarights(acl_entry_t entry) {
+ acl_permset_t permset;
+ u_char rights = 0;
+
+ if (acl_get_permset(entry, &permset) == -1)
+ return rights;
+
+#ifdef HAVE_ACL_GET_PERM_NP
+ if (acl_get_perm_np(permset, ACL_READ))
+#else
+ if (acl_get_perm(permset, ACL_READ))
+#endif
+ rights |= AR_UREAD;
+
+#ifdef HAVE_ACL_GET_PERM_NP
+ if (acl_get_perm_np(permset, ACL_WRITE))
+#else
+ if (acl_get_perm(permset, ACL_WRITE))
+#endif
+ rights |= AR_UWRITE;
+
+#ifdef HAVE_ACL_GET_PERM_NP
+ if (acl_get_perm_np(permset, ACL_EXECUTE))
+#else
+ if (acl_get_perm(permset, ACL_EXECUTE))
+#endif
+ rights |= AR_USEARCH;
+
+ return rights;
+}
+
+/*!
+ * Update FPUnixPrivs for a file-system object on a volume supporting ACLs
+ *
+ * Checks permissions granted by ACLS for a user to one fs-object and
+ * updates user and group permissions in given struct maccess. As OS X
+ * doesn't conform to Posix 1003.1e Draft 17 it expects proper group
+ * permissions in st_mode of struct stat even if the fs-object has an
+ * ACL_MASK entry, st_mode gets modified to properly reflect group
+ * permissions.
+ *
+ * @param path (r) path to filesystem object
+ * @param sb (rw) struct stat of path
+ * @param maccess (rw) struct maccess of path
+ *
+ * @returns 0 or -1 on error
+ */
+static int posix_acls_to_uaperms(const AFPObj *obj, const char *path, struct stat *sb, struct maccess *ma) {
+ EC_INIT;
+
+ int entry_id = ACL_FIRST_ENTRY;
+ acl_entry_t entry;
+ acl_tag_t tag;
+ acl_t acl = NULL;
+ uid_t *uid;
+ gid_t *gid;
+ uid_t whoami = geteuid();
+
+ u_char group_rights = 0x00;
+ u_char acl_rights = 0x00;
+ u_char mask = 0xff;
+
+ EC_NULL_LOG(acl = acl_get_file(path, ACL_TYPE_ACCESS));
+
+ /* iterate through all ACEs */
+ while (acl_get_entry(acl, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ EC_ZERO_LOG(acl_get_tag_type(entry, &tag));
+
+ switch (tag) {
+ case ACL_USER:
+ EC_NULL_LOG(uid = (uid_t *)acl_get_qualifier(entry));
+
+ if (*uid == obj->uid && !(whoami == sb->st_uid)) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_USER: %u", *uid);
+ acl_rights |= acl_permset_to_uarights(entry);
+ }
+ acl_free(uid);
+ break;
+
+ case ACL_GROUP_OBJ:
+ group_rights = acl_permset_to_uarights(entry);
+ LOG(log_maxdebug, logtype_afpd, "ACL_GROUP_OBJ: %u", sb->st_gid);
+
+ if (gmem(sb->st_gid, obj->ngroups, obj->groups) && !(whoami == sb->st_uid))
+ acl_rights |= group_rights;
+ break;
+
+ case ACL_GROUP:
+ EC_NULL_LOG(gid = (gid_t *)acl_get_qualifier(entry));
+
+ if (gmem(*gid, obj->ngroups, obj->groups) && !(whoami == sb->st_uid)) {
+ LOG(log_maxdebug, logtype_afpd, "ACL_GROUP: %u", *gid);
+ acl_rights |= acl_permset_to_uarights(entry);
+ }
+ acl_free(gid);
+ break;
+
+ case ACL_MASK:
+ mask = acl_permset_to_uarights(entry);
+ LOG(log_maxdebug, logtype_afpd, "ACL_MASK: 0x%02x", mask);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (obj->options.flags & OPTION_ACL2MACCESS) {
+ /* apply the mask and adjust user and group permissions */
+ ma->ma_user |= (acl_rights & mask);
+ ma->ma_group = (group_rights & mask);
+ }
+
+ if (obj->options.flags & OPTION_ACL2MODE) {
+ /* update st_mode to properly reflect group permissions */
+ sb->st_mode &= ~S_IRWXG;
+ if (ma->ma_group & AR_USEARCH)
+ sb->st_mode |= S_IXGRP;
+ if (ma->ma_group & AR_UWRITE)
+ sb->st_mode |= S_IWGRP;
+ if (ma->ma_group & AR_UREAD)
+ sb->st_mode |= S_IRGRP;
+ }
+
+EC_CLEANUP:
+ if (acl) acl_free(acl);
+
+ EC_EXIT;
+}
+
+#if 0