acl_delete_entry.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2001-2002 Chris D. Faulhaber
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/lib/libc/posix1e/acl_delete_entry.c 330897 2018-03-14 03:19:51Z eadler $");
31
32#include <sys/types.h>
33#include "namespace.h"
34#include <sys/acl.h>
35#include "un-namespace.h"
36#include <errno.h>
37#include <string.h>
38#include <stdio.h>
39
40#include "acl_support.h"
41
42static int
43_entry_matches(const acl_entry_t a, const acl_entry_t b)
44{
45	/*
46	 * There is a semantical difference here between NFSv4 and POSIX
47	 * draft ACLs.  In POSIX, there may be only one entry for the particular
48	 * user or group.  In NFSv4 ACL, there may be any number of them.  We're
49	 * trying to be more specific here in that case.
50	 */
51	switch (_entry_brand(a)) {
52	case ACL_BRAND_NFS4:
53		if (a->ae_tag != b->ae_tag || a->ae_entry_type != b->ae_entry_type)
54			return (0);
55
56		/* If ae_ids matter, compare them as well. */
57		if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
58			if (a->ae_id != b->ae_id)
59				return (0);
60		}
61
62		return (1);
63
64	default:
65		if ((a->ae_tag == b->ae_tag) && (a->ae_id == b->ae_id))
66			return (1);
67	}
68
69	return (0);
70}
71
72/*
73 * acl_delete_entry() (23.4.9): remove the ACL entry indicated by entry_d
74 * from acl.
75 */
76int
77acl_delete_entry(acl_t acl, acl_entry_t entry_d)
78{
79	struct acl *acl_int;
80	struct acl_entry entry_int;
81	int i, j, found = 0;
82
83	if (acl == NULL || entry_d == NULL) {
84		errno = EINVAL;
85		return (-1);
86	}
87
88	acl_int = &acl->ats_acl;
89
90	if (_entry_brand(entry_d) != _acl_brand(acl)) {
91		errno = EINVAL;
92		return (-1);
93	}
94
95	if ((acl->ats_acl.acl_cnt < 1) ||
96	    (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
97		errno = EINVAL;
98		return (-1);
99	}
100
101	/* Use a local copy to prevent deletion of more than this entry */
102	entry_int = *entry_d;
103
104	for (i = 0; i < acl->ats_acl.acl_cnt;) {
105		if (_entry_matches(&(acl->ats_acl.acl_entry[i]), &entry_int)) {
106			/* ...shift the remaining entries... */
107			for (j = i; j < acl->ats_acl.acl_cnt - 1; ++j)
108				acl->ats_acl.acl_entry[j] =
109				    acl->ats_acl.acl_entry[j+1];
110			/* ...drop the count and zero the unused entry... */
111			acl->ats_acl.acl_cnt--;
112			bzero(&acl->ats_acl.acl_entry[j],
113			    sizeof(struct acl_entry));
114			acl->ats_cur_entry = 0;
115
116			/* Continue with the loop to remove all matching entries. */
117			found = 1;
118		} else
119			i++;
120	}
121
122	if (found)
123		return (0);
124
125	errno = EINVAL;
126	return (-1);
127}
128
129int
130acl_delete_entry_np(acl_t acl, int offset)
131{
132	struct acl *acl_int;
133	int i;
134
135	if (acl == NULL) {
136		errno = EINVAL;
137		return (-1);
138	}
139
140	acl_int = &acl->ats_acl;
141
142	if (offset < 0 || offset >= acl_int->acl_cnt) {
143		errno = EINVAL;
144		return (-1);
145	}
146
147	if ((acl->ats_acl.acl_cnt < 1) ||
148	    (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
149		errno = EINVAL;
150		return (-1);
151	}
152
153	/* ...shift the remaining entries... */
154	for (i = offset; i < acl->ats_acl.acl_cnt - 1; ++i)
155		acl->ats_acl.acl_entry[i] =
156		    acl->ats_acl.acl_entry[i+1];
157	/* ...drop the count and zero the unused entry... */
158	acl->ats_acl.acl_cnt--;
159	bzero(&acl->ats_acl.acl_entry[i],
160	    sizeof(struct acl_entry));
161	acl->ats_cur_entry = 0;
162
163	return (0);
164}
165