1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
5 * All rights reserved.
6 *
7 * This software was developed by Robert Watson for the TrustedBSD Project.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30/*
31 * acl_set_file -- set a file/directory ACL by name
32 */
33
34#include <sys/cdefs.h>
35#if 0
36__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_set.c 326193 2017-11-25 17:12:48Z pfg $");
37#else
38__RCSID("$NetBSD: acl_set.c,v 1.1 2020/05/16 18:31:47 christos Exp $");
39#endif
40
41#include "namespace.h"
42#include <sys/types.h>
43#include <sys/acl.h>
44
45#include <errno.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include "acl_support.h"
51
52/*
53 * For POSIX.1e-semantic ACLs, do a presort so the kernel doesn't have to
54 * (the POSIX.1e semantic code will reject unsorted ACL submission).  If it's
55 * not a semantic that the library knows about, just submit it flat and
56 * assume the caller knows what they're up to.
57 */
58int
59acl_set_file(const char *path_p, acl_type_t type, acl_t acl)
60{
61
62	if (acl == NULL || path_p == NULL) {
63		errno = EINVAL;
64		return (-1);
65	}
66	type = _acl_type_unold(type);
67	if (_acl_type_not_valid_for_acl(acl, type)) {
68		errno = EINVAL;
69		return (-1);
70	}
71	if (_posix1e_acl(acl, type))
72		_posix1e_acl_sort(acl);
73
74	acl->ats_cur_entry = 0;
75
76	return (__acl_set_file(path_p, type, &acl->ats_acl));
77}
78
79int
80acl_set_link_np(const char *path_p, acl_type_t type, acl_t acl)
81{
82
83	if (acl == NULL || path_p == NULL) {
84		errno = EINVAL;
85		return (-1);
86	}
87	type = _acl_type_unold(type);
88	if (_acl_type_not_valid_for_acl(acl, type)) {
89		errno = EINVAL;
90		return (-1);
91	}
92	if (_posix1e_acl(acl, type))
93		_posix1e_acl_sort(acl);
94
95	acl->ats_cur_entry = 0;
96
97	return (__acl_set_link(path_p, type, &acl->ats_acl));
98}
99
100int
101acl_set_fd(int fd, acl_t acl)
102{
103
104	if (fpathconf(fd, _PC_ACL_NFS4) == 1)
105		return (acl_set_fd_np(fd, acl, ACL_TYPE_NFS4));
106
107	return (acl_set_fd_np(fd, acl, ACL_TYPE_ACCESS));
108}
109
110int
111acl_set_fd_np(int fd, acl_t acl, acl_type_t type)
112{
113
114	if (acl == NULL) {
115		errno = EINVAL;
116		return (-1);
117	}
118	type = _acl_type_unold(type);
119	if (_acl_type_not_valid_for_acl(acl, type)) {
120		errno = EINVAL;
121		return (-1);
122	}
123	if (_posix1e_acl(acl, type))
124		_posix1e_acl_sort(acl);
125
126	acl->ats_cur_entry = 0;
127
128	return (__acl_set_fd(fd, type, &acl->ats_acl));
129}
130
131/*
132 * acl_set_permset() (23.4.23): sets the permissions of ACL entry entry_d
133 * with the permissions in permset_d
134 */
135int
136acl_set_permset(acl_entry_t entry_d, acl_permset_t permset_d)
137{
138
139	if (!entry_d) {
140		errno = EINVAL;
141		return (-1);
142	}
143
144	if ((*permset_d & ACL_POSIX1E_BITS) != *permset_d) {
145		if ((*permset_d & ACL_NFS4_PERM_BITS) != *permset_d) {
146			errno = EINVAL;
147			return (-1);
148		}
149		if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
150			errno = EINVAL;
151			return (-1);
152		}
153		_entry_brand_as(entry_d, ACL_BRAND_NFS4);
154	}
155
156	entry_d->ae_perm = *permset_d;
157
158	return (0);
159}
160
161/*
162 * acl_set_qualifier() sets the qualifier (ae_id) of the tag for
163 * ACL entry entry_d to the value referred to by tag_qualifier_p
164 */
165int
166acl_set_qualifier(acl_entry_t entry_d, const void *tag_qualifier_p)
167{
168
169	if (!entry_d || !tag_qualifier_p) {
170		errno = EINVAL;
171		return (-1);
172	}
173	switch(entry_d->ae_tag) {
174	case ACL_USER:
175	case ACL_GROUP:
176		entry_d->ae_id = *(const uid_t *)tag_qualifier_p;
177		break;
178	default:
179		errno = EINVAL;
180		return (-1);
181	}
182
183	return (0);
184}
185
186/*
187 * acl_set_tag_type() sets the tag type for ACL entry entry_d to the
188 * value of tag_type
189 */
190int
191acl_set_tag_type(acl_entry_t entry_d, acl_tag_t tag_type)
192{
193
194	if (entry_d == NULL) {
195		errno = EINVAL;
196		return (-1);
197	}
198
199	switch(tag_type) {
200	case ACL_OTHER:
201	case ACL_MASK:
202		if (!_entry_brand_may_be(entry_d, ACL_BRAND_POSIX)) {
203			errno = EINVAL;
204			return (-1);
205		}
206		_entry_brand_as(entry_d, ACL_BRAND_POSIX);
207		break;
208	case ACL_EVERYONE:
209		if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
210			errno = EINVAL;
211			return (-1);
212		}
213		_entry_brand_as(entry_d, ACL_BRAND_NFS4);
214		break;
215	}
216
217	switch(tag_type) {
218	case ACL_USER_OBJ:
219	case ACL_USER:
220	case ACL_GROUP_OBJ:
221	case ACL_GROUP:
222	case ACL_MASK:
223	case ACL_OTHER:
224	case ACL_EVERYONE:
225		entry_d->ae_tag = tag_type;
226		return (0);
227	}
228
229	errno = EINVAL;
230	return (-1);
231}
232
233int
234acl_set_entry_type_np(acl_entry_t entry_d, acl_entry_type_t entry_type)
235{
236
237	if (entry_d == NULL) {
238		errno = EINVAL;
239		return (-1);
240	}
241	if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
242		errno = EINVAL;
243		return (-1);
244	}
245	_entry_brand_as(entry_d, ACL_BRAND_NFS4);
246
247	switch (entry_type) {
248	case ACL_ENTRY_TYPE_ALLOW:
249	case ACL_ENTRY_TYPE_DENY:
250	case ACL_ENTRY_TYPE_AUDIT:
251	case ACL_ENTRY_TYPE_ALARM:
252		entry_d->ae_entry_type = entry_type;
253		return (0);
254	}
255
256	errno = EINVAL;
257	return (-1);
258}
259