1/*
2 * Copyright (c) 2008, 2009 Edward Tomasz Napiera��a <trasz@FreeBSD.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/types.h>
27#include <sys/param.h>
28#include <sys/systm.h>
29#include <sys/types.h>
30#include <sys/malloc.h>
31#include <sys/errno.h>
32#include <sys/zfs_acl.h>
33#include <sys/acl.h>
34
35struct zfs2bsd {
36	uint32_t	zb_zfs;
37	int		zb_bsd;
38};
39
40static const struct zfs2bsd perms[] = {{ACE_READ_DATA, ACL_READ_DATA},
41			{ACE_WRITE_DATA, ACL_WRITE_DATA},
42			{ACE_EXECUTE, ACL_EXECUTE},
43			{ACE_APPEND_DATA, ACL_APPEND_DATA},
44			{ACE_DELETE_CHILD, ACL_DELETE_CHILD},
45			{ACE_DELETE, ACL_DELETE},
46			{ACE_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
47			{ACE_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
48			{ACE_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
49			{ACE_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
50			{ACE_READ_ACL, ACL_READ_ACL},
51			{ACE_WRITE_ACL, ACL_WRITE_ACL},
52			{ACE_WRITE_OWNER, ACL_WRITE_OWNER},
53			{ACE_SYNCHRONIZE, ACL_SYNCHRONIZE},
54			{0, 0}};
55
56static const struct zfs2bsd flags[] = {{ACE_FILE_INHERIT_ACE,
57			    ACL_ENTRY_FILE_INHERIT},
58			{ACE_DIRECTORY_INHERIT_ACE,
59			    ACL_ENTRY_DIRECTORY_INHERIT},
60			{ACE_NO_PROPAGATE_INHERIT_ACE,
61			    ACL_ENTRY_NO_PROPAGATE_INHERIT},
62			{ACE_INHERIT_ONLY_ACE,
63			    ACL_ENTRY_INHERIT_ONLY},
64			{ACE_INHERITED_ACE,
65			    ACL_ENTRY_INHERITED},
66			{ACE_SUCCESSFUL_ACCESS_ACE_FLAG,
67			    ACL_ENTRY_SUCCESSFUL_ACCESS},
68			{ACE_FAILED_ACCESS_ACE_FLAG,
69			    ACL_ENTRY_FAILED_ACCESS},
70			{0, 0}};
71
72static int
73_bsd_from_zfs(uint32_t zfs, const struct zfs2bsd *table)
74{
75	const struct zfs2bsd *tmp;
76	int bsd = 0;
77
78	for (tmp = table; tmp->zb_zfs != 0; tmp++) {
79		if (zfs & tmp->zb_zfs)
80			bsd |= tmp->zb_bsd;
81	}
82
83	return (bsd);
84}
85
86static uint32_t
87_zfs_from_bsd(int bsd, const struct zfs2bsd *table)
88{
89	const struct zfs2bsd *tmp;
90	uint32_t zfs = 0;
91
92	for (tmp = table; tmp->zb_bsd != 0; tmp++) {
93		if (bsd & tmp->zb_bsd)
94			zfs |= tmp->zb_zfs;
95	}
96
97	return (zfs);
98}
99
100int
101acl_from_aces(struct acl *aclp, const ace_t *aces, int nentries)
102{
103	int i;
104	struct acl_entry *entry;
105	const ace_t *ace;
106
107	if (nentries < 1) {
108		printf("acl_from_aces: empty ZFS ACL; returning EINVAL.\n");
109		return (EINVAL);
110	}
111
112	if (nentries > ACL_MAX_ENTRIES) {
113		/*
114		 * I believe it may happen only when moving a pool
115		 * from SunOS to FreeBSD.
116		 */
117		printf("acl_from_aces: ZFS ACL too big to fit "
118		    "into 'struct acl'; returning EINVAL.\n");
119		return (EINVAL);
120	}
121
122	memset(aclp, 0, sizeof (*aclp));
123	aclp->acl_maxcnt = ACL_MAX_ENTRIES;
124	aclp->acl_cnt = nentries;
125
126	for (i = 0; i < nentries; i++) {
127		entry = &(aclp->acl_entry[i]);
128		ace = &(aces[i]);
129
130		if (ace->a_flags & ACE_OWNER)
131			entry->ae_tag = ACL_USER_OBJ;
132		else if (ace->a_flags & ACE_GROUP)
133			entry->ae_tag = ACL_GROUP_OBJ;
134		else if (ace->a_flags & ACE_EVERYONE)
135			entry->ae_tag = ACL_EVERYONE;
136		else if (ace->a_flags & ACE_IDENTIFIER_GROUP)
137			entry->ae_tag = ACL_GROUP;
138		else
139			entry->ae_tag = ACL_USER;
140
141		if (entry->ae_tag == ACL_USER || entry->ae_tag == ACL_GROUP)
142			entry->ae_id = ace->a_who;
143		else
144			entry->ae_id = ACL_UNDEFINED_ID;
145
146		entry->ae_perm = _bsd_from_zfs(ace->a_access_mask, perms);
147		entry->ae_flags = _bsd_from_zfs(ace->a_flags, flags);
148
149		switch (ace->a_type) {
150		case ACE_ACCESS_ALLOWED_ACE_TYPE:
151			entry->ae_entry_type = ACL_ENTRY_TYPE_ALLOW;
152			break;
153		case ACE_ACCESS_DENIED_ACE_TYPE:
154			entry->ae_entry_type = ACL_ENTRY_TYPE_DENY;
155			break;
156		case ACE_SYSTEM_AUDIT_ACE_TYPE:
157			entry->ae_entry_type = ACL_ENTRY_TYPE_AUDIT;
158			break;
159		case ACE_SYSTEM_ALARM_ACE_TYPE:
160			entry->ae_entry_type = ACL_ENTRY_TYPE_ALARM;
161			break;
162		default:
163			panic("acl_from_aces: a_type is 0x%x", ace->a_type);
164		}
165	}
166
167	return (0);
168}
169
170void
171aces_from_acl(ace_t *aces, int *nentries, const struct acl *aclp)
172{
173	int i;
174	const struct acl_entry *entry;
175	ace_t *ace;
176
177	memset(aces, 0, sizeof (*aces) * aclp->acl_cnt);
178
179	*nentries = aclp->acl_cnt;
180
181	for (i = 0; i < aclp->acl_cnt; i++) {
182		entry = &(aclp->acl_entry[i]);
183		ace = &(aces[i]);
184
185		ace->a_who = entry->ae_id;
186
187		if (entry->ae_tag == ACL_USER_OBJ)
188			ace->a_flags = ACE_OWNER;
189		else if (entry->ae_tag == ACL_GROUP_OBJ)
190			ace->a_flags = (ACE_GROUP | ACE_IDENTIFIER_GROUP);
191		else if (entry->ae_tag == ACL_GROUP)
192			ace->a_flags = ACE_IDENTIFIER_GROUP;
193		else if (entry->ae_tag == ACL_EVERYONE)
194			ace->a_flags = ACE_EVERYONE;
195		else /* ACL_USER */
196			ace->a_flags = 0;
197
198		ace->a_access_mask = _zfs_from_bsd(entry->ae_perm, perms);
199		ace->a_flags |= _zfs_from_bsd(entry->ae_flags, flags);
200
201		switch (entry->ae_entry_type) {
202		case ACL_ENTRY_TYPE_ALLOW:
203			ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
204			break;
205		case ACL_ENTRY_TYPE_DENY:
206			ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
207			break;
208		case ACL_ENTRY_TYPE_ALARM:
209			ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE;
210			break;
211		case ACL_ENTRY_TYPE_AUDIT:
212			ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE;
213			break;
214		default:
215			panic("aces_from_acl: ae_entry_type is 0x%x",
216			    entry->ae_entry_type);
217		}
218	}
219}
220