summaryrefslogtreecommitdiffstats
path: root/lib/libc/posix1e/acl_delete_entry.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/posix1e/acl_delete_entry.c')
-rw-r--r--lib/libc/posix1e/acl_delete_entry.c100
1 files changed, 89 insertions, 11 deletions
diff --git a/lib/libc/posix1e/acl_delete_entry.c b/lib/libc/posix1e/acl_delete_entry.c
index 3195fac..7dd60b8 100644
--- a/lib/libc/posix1e/acl_delete_entry.c
+++ b/lib/libc/posix1e/acl_delete_entry.c
@@ -33,6 +33,39 @@ __FBSDID("$FreeBSD$");
#include "un-namespace.h"
#include <errno.h>
#include <string.h>
+#include <stdio.h>
+
+#include "acl_support.h"
+
+static int
+_entry_matches(const acl_entry_t a, const acl_entry_t b)
+{
+ /*
+ * There is a semantical difference here between NFSv4 and POSIX
+ * draft ACLs. In POSIX, there may be only one entry for the particular
+ * user or group. In NFSv4 ACL, there may be any number of them. We're
+ * trying to be more specific here in that case.
+ */
+ switch (_entry_brand(a)) {
+ case ACL_BRAND_NFS4:
+ if (a->ae_tag != b->ae_tag || a->ae_entry_type != b->ae_entry_type)
+ return (0);
+
+ /* If ae_ids matter, compare them as well. */
+ if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
+ if (a->ae_id != b->ae_id)
+ return (0);
+ }
+
+ return (1);
+
+ default:
+ if ((a->ae_tag == b->ae_tag) && (a->ae_id == b->ae_id))
+ return (1);
+ }
+
+ return (0);
+}
/*
* acl_delete_entry() (23.4.9): remove the ACL entry indicated by entry_d
@@ -42,7 +75,7 @@ int
acl_delete_entry(acl_t acl, acl_entry_t entry_d)
{
struct acl *acl_int;
- int i;
+ int i, j, found = 0;
if (acl == NULL || entry_d == NULL) {
errno = EINVAL;
@@ -51,29 +84,74 @@ acl_delete_entry(acl_t acl, acl_entry_t entry_d)
acl_int = &acl->ats_acl;
+ if (_entry_brand(entry_d) != _acl_brand(acl)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
if ((acl->ats_acl.acl_cnt < 1) ||
(acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
errno = EINVAL;
return (-1);
}
- for (i = 0; i < acl->ats_acl.acl_cnt; i++) {
- /* if this is our entry... */
- if ((acl->ats_acl.acl_entry[i].ae_tag == entry_d->ae_tag) &&
- (acl->ats_acl.acl_entry[i].ae_id == entry_d->ae_id)) {
+ for (i = 0; i < acl->ats_acl.acl_cnt;) {
+ if (_entry_matches(&(acl->ats_acl.acl_entry[i]), entry_d)) {
/* ...shift the remaining entries... */
- for (; i < acl->ats_acl.acl_cnt - 1; ++i)
- acl->ats_acl.acl_entry[i] =
- acl->ats_acl.acl_entry[i+1];
+ for (j = i; j < acl->ats_acl.acl_cnt - 1; ++j)
+ acl->ats_acl.acl_entry[j] =
+ acl->ats_acl.acl_entry[j+1];
/* ...drop the count and zero the unused entry... */
acl->ats_acl.acl_cnt--;
- bzero(&acl->ats_acl.acl_entry[i],
+ bzero(&acl->ats_acl.acl_entry[j],
sizeof(struct acl_entry));
acl->ats_cur_entry = 0;
- return (0);
- }
+
+ /* Continue with the loop to remove all maching entries. */
+ found = 1;
+ } else
+ i++;
}
+ if (found)
+ return (0);
errno = EINVAL;
return (-1);
}
+
+int
+acl_delete_entry_np(acl_t acl, int offset)
+{
+ struct acl *acl_int;
+ int i;
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ acl_int = &acl->ats_acl;
+
+ if (offset < 0 || offset >= acl_int->acl_cnt) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((acl->ats_acl.acl_cnt < 1) ||
+ (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* ...shift the remaining entries... */
+ for (i = offset; i < acl->ats_acl.acl_cnt - 1; ++i)
+ acl->ats_acl.acl_entry[i] =
+ acl->ats_acl.acl_entry[i+1];
+ /* ...drop the count and zero the unused entry... */
+ acl->ats_acl.acl_cnt--;
+ bzero(&acl->ats_acl.acl_entry[i],
+ sizeof(struct acl_entry));
+ acl->ats_cur_entry = 0;
+
+ return (0);
+}
OpenPOWER on IntegriCloud