1/*
2 * Copyright (c) 2004, 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/appleapiopts.h>
25#include <sys/types.h>
26#include <sys/acl.h>
27#include <errno.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "aclvar.h"
32
33#if __DARWIN_ACL_EXTENDED_ALLOW != KAUTH_ACE_PERMIT
34#  error __DARWIN_ACL_EXTENDED_ALLOW != KAUTH_ACE_PERMIT
35#endif
36#if __DARWIN_ACL_EXTENDED_DENY != KAUTH_ACE_DENY
37#  error __DARWIN_ACL_EXTENDED_DENY != KAUTH_ACE_DENY
38#endif
39
40int
41acl_copy_entry(acl_entry_t dest, acl_entry_t src)
42{
43	/* validate arguments */
44	_ACL_VALIDATE_ENTRY(dest);
45	_ACL_VALIDATE_ENTRY(src);
46	if (dest == src) {
47		errno = EINVAL;
48		return(-1);
49	}
50	bcopy(src, dest, sizeof(*src));
51	return(0);
52}
53
54int
55acl_create_entry_np(acl_t *acl_p, acl_entry_t *entry_p, int index)
56{
57	struct _acl	*ap = *acl_p;
58	int		i;
59
60	/* validate arguments */
61	_ACL_VALIDATE_ACL(ap);
62	if (ap->a_entries >= ACL_MAX_ENTRIES) {
63		errno = ENOMEM;
64		return(-1);
65	}
66	if (index == ACL_LAST_ENTRY)
67		index = ap->a_entries;
68	if (index > ap->a_entries) {
69		errno = ERANGE;
70		return(-1);
71	}
72
73	/* move following entries out of the way */
74	for (i = ap->a_entries; i > index; i--)
75		ap->a_ace[i] = ap->a_ace[i - 1];
76	ap->a_entries++;
77
78	/* initialise new entry */
79	memset(&ap->a_ace[index], 0, sizeof(ap->a_ace[index]));
80	ap->a_ace[index].ae_magic = _ACL_ENTRY_MAGIC;
81	ap->a_ace[index].ae_tag = ACL_UNDEFINED_TAG;
82
83	*entry_p = &ap->a_ace[index];
84	return(0);
85}
86
87int
88acl_create_entry(acl_t *acl_p, acl_entry_t *entry_p)
89{
90	return(acl_create_entry_np(acl_p, entry_p, ACL_LAST_ENTRY));
91}
92
93int
94acl_delete_entry(acl_t acl, acl_entry_t entry)
95{
96	int	i;
97
98	_ACL_VALIDATE_ACL(acl);
99	_ACL_VALIDATE_ENTRY(entry);
100	_ACL_VALIDATE_ENTRY_CONTAINED(acl, entry);
101
102	/* copy following entries down & invalidate last slot */
103	acl->a_entries--;
104	for (i = entry - &acl->a_ace[0]; i < acl->a_entries; i++)
105		acl->a_ace[i] = acl->a_ace[i + 1];
106	acl->a_ace[acl->a_entries].ae_magic = 0;
107	/* Sync up the iterator's position if necessary */
108	if (acl->a_last_get >= (entry - &acl->a_ace[0]))
109	  acl->a_last_get--;
110
111	return(0);
112}
113
114int
115acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p)
116{
117
118	_ACL_VALIDATE_ACL(acl);
119	if ((entry_id != ACL_FIRST_ENTRY) &&
120	    (entry_id != ACL_NEXT_ENTRY) &&
121	    (entry_id != ACL_LAST_ENTRY) &&
122	    ((entry_id < 0) || (entry_id >= acl->a_entries))) {
123		errno = EINVAL;
124		return(-1);
125	}
126	if (entry_id == ACL_FIRST_ENTRY)
127	  entry_id = 0;
128	else
129	  if (entry_id == ACL_NEXT_ENTRY) {
130	    entry_id = acl->a_last_get + 1;
131	  }
132	  else
133	    if (entry_id == ACL_LAST_ENTRY)
134	      entry_id = acl->a_entries - 1;
135
136	if (entry_id >= acl->a_entries) {
137	  errno = EINVAL;
138	  return (-1);
139	}
140
141	*entry_p = &acl->a_ace[entry_id];
142	acl->a_last_get = entry_id;
143
144	return(0);
145}
146
147void *
148acl_get_qualifier(acl_entry_t entry)
149{
150	acl_tag_t	tag_type;
151	void		*result;
152	int		error;
153
154	result = NULL;
155	if (!_ACL_VALID_ENTRY(entry)) {
156		errno = EINVAL;
157	} else if ((error = acl_get_tag_type(entry, &tag_type)) != 0) {
158		/* errno is set by acl_get_tag_type */
159	} else {
160		switch(tag_type) {
161		case ACL_EXTENDED_ALLOW:
162		case ACL_EXTENDED_DENY:
163			if ((result = malloc(sizeof(guid_t))) != NULL)
164				bcopy(&entry->ae_applicable, result, sizeof(guid_t));
165			break;
166		default:
167			errno = EINVAL;
168			break;
169		}
170	}
171	return(result);
172}
173
174int
175acl_get_tag_type(acl_entry_t entry, acl_tag_t *tag_type_p)
176{
177	_ACL_VALIDATE_ENTRY(entry);
178
179	*tag_type_p = entry->ae_tag;
180	return(0);
181}
182
183int
184acl_set_qualifier(acl_entry_t entry, const void *tag_qualifier_p)
185{
186	acl_tag_t	tag_type;
187
188	_ACL_VALIDATE_ENTRY(entry);
189	if (acl_get_tag_type(entry, &tag_type) != 0)
190		return(-1);
191
192	switch(tag_type) {
193	case ACL_EXTENDED_ALLOW:
194	case ACL_EXTENDED_DENY:
195		bcopy(tag_qualifier_p, &entry->ae_applicable, sizeof(guid_t));
196		break;
197	default:
198		errno = EINVAL;
199		return(-1);
200	}
201	return(0);
202}
203
204int
205acl_set_tag_type(acl_entry_t entry, acl_tag_t tag_type)
206{
207	_ACL_VALIDATE_ENTRY(entry);
208
209	switch(tag_type) {
210	case ACL_EXTENDED_ALLOW:
211	case ACL_EXTENDED_DENY:
212		entry->ae_tag = tag_type;
213		break;
214	default:
215		errno = EINVAL;
216		return(-1);
217	}
218	return(0);
219}
220