1*aca3beaaSApple OSS Distributions /*
2*aca3beaaSApple OSS Distributions * Copyright (c) 2004-2016 Apple Inc. All rights reserved.
3*aca3beaaSApple OSS Distributions *
4*aca3beaaSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*aca3beaaSApple OSS Distributions *
6*aca3beaaSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*aca3beaaSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*aca3beaaSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*aca3beaaSApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*aca3beaaSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*aca3beaaSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*aca3beaaSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*aca3beaaSApple OSS Distributions * terms of an Apple operating system software license agreement.
14*aca3beaaSApple OSS Distributions *
15*aca3beaaSApple OSS Distributions * Please obtain a copy of the License at
16*aca3beaaSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*aca3beaaSApple OSS Distributions *
18*aca3beaaSApple OSS Distributions * The Original Code and all software distributed under the License are
19*aca3beaaSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*aca3beaaSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*aca3beaaSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*aca3beaaSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*aca3beaaSApple OSS Distributions * Please see the License for the specific language governing rights and
24*aca3beaaSApple OSS Distributions * limitations under the License.
25*aca3beaaSApple OSS Distributions *
26*aca3beaaSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*aca3beaaSApple OSS Distributions */
28*aca3beaaSApple OSS Distributions
29*aca3beaaSApple OSS Distributions /*
30*aca3beaaSApple OSS Distributions * Centralized authorisation framework.
31*aca3beaaSApple OSS Distributions */
32*aca3beaaSApple OSS Distributions
33*aca3beaaSApple OSS Distributions #include <sys/appleapiopts.h>
34*aca3beaaSApple OSS Distributions #include <sys/param.h> /* XXX trim includes */
35*aca3beaaSApple OSS Distributions #include <sys/acct.h>
36*aca3beaaSApple OSS Distributions #include <sys/systm.h>
37*aca3beaaSApple OSS Distributions #include <sys/ucred.h>
38*aca3beaaSApple OSS Distributions #include <sys/proc_internal.h>
39*aca3beaaSApple OSS Distributions #include <sys/timeb.h>
40*aca3beaaSApple OSS Distributions #include <sys/times.h>
41*aca3beaaSApple OSS Distributions #include <sys/malloc.h>
42*aca3beaaSApple OSS Distributions #include <sys/vnode_internal.h>
43*aca3beaaSApple OSS Distributions #include <sys/kauth.h>
44*aca3beaaSApple OSS Distributions #include <sys/stat.h>
45*aca3beaaSApple OSS Distributions
46*aca3beaaSApple OSS Distributions #include <security/audit/audit.h>
47*aca3beaaSApple OSS Distributions
48*aca3beaaSApple OSS Distributions #include <sys/mount.h>
49*aca3beaaSApple OSS Distributions #include <sys/sysproto.h>
50*aca3beaaSApple OSS Distributions #include <mach/message.h>
51*aca3beaaSApple OSS Distributions
52*aca3beaaSApple OSS Distributions #include <kern/locks.h>
53*aca3beaaSApple OSS Distributions
54*aca3beaaSApple OSS Distributions
55*aca3beaaSApple OSS Distributions /*
56*aca3beaaSApple OSS Distributions * Authorization scopes.
57*aca3beaaSApple OSS Distributions */
58*aca3beaaSApple OSS Distributions
59*aca3beaaSApple OSS Distributions LCK_GRP_DECLARE(kauth_lck_grp, "kauth");
60*aca3beaaSApple OSS Distributions static LCK_MTX_DECLARE(kauth_scope_mtx, &kauth_lck_grp);
61*aca3beaaSApple OSS Distributions #define KAUTH_SCOPELOCK() lck_mtx_lock(&kauth_scope_mtx);
62*aca3beaaSApple OSS Distributions #define KAUTH_SCOPEUNLOCK() lck_mtx_unlock(&kauth_scope_mtx);
63*aca3beaaSApple OSS Distributions
64*aca3beaaSApple OSS Distributions /*
65*aca3beaaSApple OSS Distributions * We support listeners for scopes that have not been registered yet.
66*aca3beaaSApple OSS Distributions * If a listener comes in for a scope that is not active we hang the listener
67*aca3beaaSApple OSS Distributions * off our kauth_dangling_listeners list and once the scope becomes active we
68*aca3beaaSApple OSS Distributions * remove it from kauth_dangling_listeners and add it to the active scope.
69*aca3beaaSApple OSS Distributions */
70*aca3beaaSApple OSS Distributions struct kauth_listener {
71*aca3beaaSApple OSS Distributions TAILQ_ENTRY(kauth_listener) kl_link;
72*aca3beaaSApple OSS Distributions const char * kl_identifier;
73*aca3beaaSApple OSS Distributions kauth_scope_callback_t kl_callback;
74*aca3beaaSApple OSS Distributions void * kl_idata;
75*aca3beaaSApple OSS Distributions };
76*aca3beaaSApple OSS Distributions
77*aca3beaaSApple OSS Distributions /* XXX - kauth_todo - there is a race if a scope listener is removed while we
78*aca3beaaSApple OSS Distributions * we are in the kauth_authorize_action code path. We intentionally do not take
79*aca3beaaSApple OSS Distributions * a scope lock in order to get the best possible performance. we will fix this
80*aca3beaaSApple OSS Distributions * post Tiger.
81*aca3beaaSApple OSS Distributions * Until the race is fixed our kext clients are responsible for all active
82*aca3beaaSApple OSS Distributions * requests that may be in their callback code or on the way to their callback
83*aca3beaaSApple OSS Distributions * code before they free kauth_listener.kl_callback or kauth_listener.kl_idata.
84*aca3beaaSApple OSS Distributions * We keep copies of these in our kauth_local_listener in an attempt to limit
85*aca3beaaSApple OSS Distributions * our expose to unlisten race.
86*aca3beaaSApple OSS Distributions */
87*aca3beaaSApple OSS Distributions struct kauth_local_listener {
88*aca3beaaSApple OSS Distributions kauth_listener_t kll_listenerp;
89*aca3beaaSApple OSS Distributions kauth_scope_callback_t kll_callback;
90*aca3beaaSApple OSS Distributions void * kll_idata;
91*aca3beaaSApple OSS Distributions };
92*aca3beaaSApple OSS Distributions typedef struct kauth_local_listener *kauth_local_listener_t;
93*aca3beaaSApple OSS Distributions
94*aca3beaaSApple OSS Distributions static TAILQ_HEAD(, kauth_listener) kauth_dangling_listeners =
95*aca3beaaSApple OSS Distributions TAILQ_HEAD_INITIALIZER(kauth_dangling_listeners);
96*aca3beaaSApple OSS Distributions
97*aca3beaaSApple OSS Distributions /*
98*aca3beaaSApple OSS Distributions * Scope listeners need to be reworked to be dynamic.
99*aca3beaaSApple OSS Distributions * We intentionally used a static table to avoid locking issues with linked
100*aca3beaaSApple OSS Distributions * lists. The listeners may be called quite often.
101*aca3beaaSApple OSS Distributions * XXX - kauth_todo
102*aca3beaaSApple OSS Distributions */
103*aca3beaaSApple OSS Distributions #define KAUTH_SCOPE_MAX_LISTENERS 15
104*aca3beaaSApple OSS Distributions
105*aca3beaaSApple OSS Distributions struct kauth_scope {
106*aca3beaaSApple OSS Distributions TAILQ_ENTRY(kauth_scope) ks_link;
107*aca3beaaSApple OSS Distributions volatile struct kauth_local_listener ks_listeners[KAUTH_SCOPE_MAX_LISTENERS];
108*aca3beaaSApple OSS Distributions const char * ks_identifier;
109*aca3beaaSApple OSS Distributions kauth_scope_callback_t ks_callback;
110*aca3beaaSApple OSS Distributions void * ks_idata;
111*aca3beaaSApple OSS Distributions u_int ks_flags;
112*aca3beaaSApple OSS Distributions };
113*aca3beaaSApple OSS Distributions
114*aca3beaaSApple OSS Distributions /* values for kauth_scope.ks_flags */
115*aca3beaaSApple OSS Distributions #define KS_F_HAS_LISTENERS (1 << 0)
116*aca3beaaSApple OSS Distributions
117*aca3beaaSApple OSS Distributions static TAILQ_HEAD(, kauth_scope) kauth_scopes = TAILQ_HEAD_INITIALIZER(kauth_scopes);
118*aca3beaaSApple OSS Distributions
119*aca3beaaSApple OSS Distributions static int kauth_add_callback_to_scope(kauth_scope_t sp, kauth_listener_t klp);
120*aca3beaaSApple OSS Distributions static void kauth_scope_init(void);
121*aca3beaaSApple OSS Distributions static kauth_scope_t kauth_alloc_scope(const char *identifier, kauth_scope_callback_t callback, void *idata);
122*aca3beaaSApple OSS Distributions static kauth_listener_t kauth_alloc_listener(const char *identifier, kauth_scope_callback_t callback, void *idata);
123*aca3beaaSApple OSS Distributions #if 0
124*aca3beaaSApple OSS Distributions static int kauth_scope_valid(kauth_scope_t scope);
125*aca3beaaSApple OSS Distributions #endif
126*aca3beaaSApple OSS Distributions
127*aca3beaaSApple OSS Distributions kauth_scope_t kauth_scope_process;
128*aca3beaaSApple OSS Distributions static int kauth_authorize_process_callback(kauth_cred_t _credential, void *_idata, kauth_action_t _action,
129*aca3beaaSApple OSS Distributions uintptr_t arg0, uintptr_t arg1, __unused uintptr_t arg2, __unused uintptr_t arg3);
130*aca3beaaSApple OSS Distributions kauth_scope_t kauth_scope_generic;
131*aca3beaaSApple OSS Distributions static int kauth_authorize_generic_callback(kauth_cred_t _credential, void *_idata, kauth_action_t _action,
132*aca3beaaSApple OSS Distributions uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
133*aca3beaaSApple OSS Distributions kauth_scope_t kauth_scope_fileop;
134*aca3beaaSApple OSS Distributions
135*aca3beaaSApple OSS Distributions extern int cansignal(struct proc *, kauth_cred_t, struct proc *, int);
136*aca3beaaSApple OSS Distributions extern char * get_pathbuff(void);
137*aca3beaaSApple OSS Distributions extern void release_pathbuff(char *path);
138*aca3beaaSApple OSS Distributions
139*aca3beaaSApple OSS Distributions /*
140*aca3beaaSApple OSS Distributions * Initialization.
141*aca3beaaSApple OSS Distributions */
142*aca3beaaSApple OSS Distributions void
kauth_init(void)143*aca3beaaSApple OSS Distributions kauth_init(void)
144*aca3beaaSApple OSS Distributions {
145*aca3beaaSApple OSS Distributions /* bring up kauth subsystem components */
146*aca3beaaSApple OSS Distributions kauth_scope_init();
147*aca3beaaSApple OSS Distributions }
148*aca3beaaSApple OSS Distributions
149*aca3beaaSApple OSS Distributions static void
kauth_scope_init(void)150*aca3beaaSApple OSS Distributions kauth_scope_init(void)
151*aca3beaaSApple OSS Distributions {
152*aca3beaaSApple OSS Distributions kauth_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS, kauth_authorize_process_callback, NULL);
153*aca3beaaSApple OSS Distributions kauth_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC, kauth_authorize_generic_callback, NULL);
154*aca3beaaSApple OSS Distributions kauth_scope_fileop = kauth_register_scope(KAUTH_SCOPE_FILEOP, NULL, NULL);
155*aca3beaaSApple OSS Distributions }
156*aca3beaaSApple OSS Distributions
157*aca3beaaSApple OSS Distributions /*
158*aca3beaaSApple OSS Distributions * Scope registration.
159*aca3beaaSApple OSS Distributions */
160*aca3beaaSApple OSS Distributions
161*aca3beaaSApple OSS Distributions static kauth_scope_t
kauth_alloc_scope(const char * identifier,kauth_scope_callback_t callback,void * idata)162*aca3beaaSApple OSS Distributions kauth_alloc_scope(const char *identifier, kauth_scope_callback_t callback, void *idata)
163*aca3beaaSApple OSS Distributions {
164*aca3beaaSApple OSS Distributions kauth_scope_t sp;
165*aca3beaaSApple OSS Distributions
166*aca3beaaSApple OSS Distributions /*
167*aca3beaaSApple OSS Distributions * Allocate and populate the scope structure.
168*aca3beaaSApple OSS Distributions */
169*aca3beaaSApple OSS Distributions sp = kalloc_type(struct kauth_scope, Z_WAITOK | Z_ZERO | Z_NOFAIL);
170*aca3beaaSApple OSS Distributions sp->ks_flags = 0;
171*aca3beaaSApple OSS Distributions sp->ks_identifier = identifier;
172*aca3beaaSApple OSS Distributions sp->ks_idata = idata;
173*aca3beaaSApple OSS Distributions sp->ks_callback = callback;
174*aca3beaaSApple OSS Distributions return sp;
175*aca3beaaSApple OSS Distributions }
176*aca3beaaSApple OSS Distributions
177*aca3beaaSApple OSS Distributions static kauth_listener_t
kauth_alloc_listener(const char * identifier,kauth_scope_callback_t callback,void * idata)178*aca3beaaSApple OSS Distributions kauth_alloc_listener(const char *identifier, kauth_scope_callback_t callback, void *idata)
179*aca3beaaSApple OSS Distributions {
180*aca3beaaSApple OSS Distributions kauth_listener_t lsp;
181*aca3beaaSApple OSS Distributions
182*aca3beaaSApple OSS Distributions /*
183*aca3beaaSApple OSS Distributions * Allocate and populate the listener structure.
184*aca3beaaSApple OSS Distributions */
185*aca3beaaSApple OSS Distributions lsp = kalloc_type(struct kauth_listener, Z_WAITOK | Z_NOFAIL);
186*aca3beaaSApple OSS Distributions lsp->kl_identifier = identifier;
187*aca3beaaSApple OSS Distributions lsp->kl_idata = idata;
188*aca3beaaSApple OSS Distributions lsp->kl_callback = callback;
189*aca3beaaSApple OSS Distributions return lsp;
190*aca3beaaSApple OSS Distributions }
191*aca3beaaSApple OSS Distributions
192*aca3beaaSApple OSS Distributions kauth_scope_t
kauth_register_scope(const char * identifier,kauth_scope_callback_t callback,void * idata)193*aca3beaaSApple OSS Distributions kauth_register_scope(const char *identifier, kauth_scope_callback_t callback, void *idata)
194*aca3beaaSApple OSS Distributions {
195*aca3beaaSApple OSS Distributions kauth_scope_t sp, tsp;
196*aca3beaaSApple OSS Distributions kauth_listener_t klp;
197*aca3beaaSApple OSS Distributions
198*aca3beaaSApple OSS Distributions if ((sp = kauth_alloc_scope(identifier, callback, idata)) == NULL) {
199*aca3beaaSApple OSS Distributions return NULL;
200*aca3beaaSApple OSS Distributions }
201*aca3beaaSApple OSS Distributions
202*aca3beaaSApple OSS Distributions /*
203*aca3beaaSApple OSS Distributions * Lock the list and insert.
204*aca3beaaSApple OSS Distributions */
205*aca3beaaSApple OSS Distributions KAUTH_SCOPELOCK();
206*aca3beaaSApple OSS Distributions TAILQ_FOREACH(tsp, &kauth_scopes, ks_link) {
207*aca3beaaSApple OSS Distributions /* duplicate! */
208*aca3beaaSApple OSS Distributions if (strncmp(tsp->ks_identifier, identifier,
209*aca3beaaSApple OSS Distributions strlen(tsp->ks_identifier) + 1) == 0) {
210*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
211*aca3beaaSApple OSS Distributions kfree_type(struct kauth_scope, sp);
212*aca3beaaSApple OSS Distributions return NULL;
213*aca3beaaSApple OSS Distributions }
214*aca3beaaSApple OSS Distributions }
215*aca3beaaSApple OSS Distributions TAILQ_INSERT_TAIL(&kauth_scopes, sp, ks_link);
216*aca3beaaSApple OSS Distributions
217*aca3beaaSApple OSS Distributions /*
218*aca3beaaSApple OSS Distributions * Look for listeners waiting for this scope, move them to the active scope
219*aca3beaaSApple OSS Distributions * listener table.
220*aca3beaaSApple OSS Distributions * Note that we have to restart the scan every time we remove an entry
221*aca3beaaSApple OSS Distributions * from the list, since we can't remove the current item from the list.
222*aca3beaaSApple OSS Distributions */
223*aca3beaaSApple OSS Distributions restart:
224*aca3beaaSApple OSS Distributions TAILQ_FOREACH(klp, &kauth_dangling_listeners, kl_link) {
225*aca3beaaSApple OSS Distributions if (strncmp(klp->kl_identifier, sp->ks_identifier,
226*aca3beaaSApple OSS Distributions strlen(klp->kl_identifier) + 1) == 0) {
227*aca3beaaSApple OSS Distributions /* found a match on the dangling listener list. add it to the
228*aca3beaaSApple OSS Distributions * the active scope.
229*aca3beaaSApple OSS Distributions */
230*aca3beaaSApple OSS Distributions if (kauth_add_callback_to_scope(sp, klp) == 0) {
231*aca3beaaSApple OSS Distributions TAILQ_REMOVE(&kauth_dangling_listeners, klp, kl_link);
232*aca3beaaSApple OSS Distributions } else {
233*aca3beaaSApple OSS Distributions #if 0
234*aca3beaaSApple OSS Distributions printf("%s - failed to add listener to scope \"%s\" \n", __FUNCTION__, sp->ks_identifier);
235*aca3beaaSApple OSS Distributions #endif
236*aca3beaaSApple OSS Distributions break;
237*aca3beaaSApple OSS Distributions }
238*aca3beaaSApple OSS Distributions goto restart;
239*aca3beaaSApple OSS Distributions }
240*aca3beaaSApple OSS Distributions }
241*aca3beaaSApple OSS Distributions
242*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
243*aca3beaaSApple OSS Distributions return sp;
244*aca3beaaSApple OSS Distributions }
245*aca3beaaSApple OSS Distributions
246*aca3beaaSApple OSS Distributions
247*aca3beaaSApple OSS Distributions
248*aca3beaaSApple OSS Distributions void
kauth_deregister_scope(kauth_scope_t scope)249*aca3beaaSApple OSS Distributions kauth_deregister_scope(kauth_scope_t scope)
250*aca3beaaSApple OSS Distributions {
251*aca3beaaSApple OSS Distributions int i;
252*aca3beaaSApple OSS Distributions
253*aca3beaaSApple OSS Distributions KAUTH_SCOPELOCK();
254*aca3beaaSApple OSS Distributions
255*aca3beaaSApple OSS Distributions TAILQ_REMOVE(&kauth_scopes, scope, ks_link);
256*aca3beaaSApple OSS Distributions
257*aca3beaaSApple OSS Distributions /* relocate listeners back to the waiting list */
258*aca3beaaSApple OSS Distributions for (i = 0; i < KAUTH_SCOPE_MAX_LISTENERS; i++) {
259*aca3beaaSApple OSS Distributions if (scope->ks_listeners[i].kll_listenerp != NULL) {
260*aca3beaaSApple OSS Distributions TAILQ_INSERT_TAIL(&kauth_dangling_listeners, scope->ks_listeners[i].kll_listenerp, kl_link);
261*aca3beaaSApple OSS Distributions scope->ks_listeners[i].kll_listenerp = NULL;
262*aca3beaaSApple OSS Distributions /*
263*aca3beaaSApple OSS Distributions * XXX - kauth_todo - WARNING, do not clear kll_callback or
264*aca3beaaSApple OSS Distributions * kll_idata here. they are part of our scope unlisten race hack
265*aca3beaaSApple OSS Distributions */
266*aca3beaaSApple OSS Distributions }
267*aca3beaaSApple OSS Distributions }
268*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
269*aca3beaaSApple OSS Distributions kfree_type(struct kauth_scope, scope);
270*aca3beaaSApple OSS Distributions
271*aca3beaaSApple OSS Distributions return;
272*aca3beaaSApple OSS Distributions }
273*aca3beaaSApple OSS Distributions
274*aca3beaaSApple OSS Distributions kauth_listener_t
kauth_listen_scope(const char * identifier,kauth_scope_callback_t callback,void * idata)275*aca3beaaSApple OSS Distributions kauth_listen_scope(const char *identifier, kauth_scope_callback_t callback, void *idata)
276*aca3beaaSApple OSS Distributions {
277*aca3beaaSApple OSS Distributions kauth_listener_t klp;
278*aca3beaaSApple OSS Distributions kauth_scope_t sp;
279*aca3beaaSApple OSS Distributions
280*aca3beaaSApple OSS Distributions if ((klp = kauth_alloc_listener(identifier, callback, idata)) == NULL) {
281*aca3beaaSApple OSS Distributions return NULL;
282*aca3beaaSApple OSS Distributions }
283*aca3beaaSApple OSS Distributions
284*aca3beaaSApple OSS Distributions /*
285*aca3beaaSApple OSS Distributions * Lock the scope list and check to see whether this scope already exists.
286*aca3beaaSApple OSS Distributions */
287*aca3beaaSApple OSS Distributions KAUTH_SCOPELOCK();
288*aca3beaaSApple OSS Distributions TAILQ_FOREACH(sp, &kauth_scopes, ks_link) {
289*aca3beaaSApple OSS Distributions if (strncmp(sp->ks_identifier, identifier,
290*aca3beaaSApple OSS Distributions strlen(sp->ks_identifier) + 1) == 0) {
291*aca3beaaSApple OSS Distributions /* scope exists, add it to scope listener table */
292*aca3beaaSApple OSS Distributions if (kauth_add_callback_to_scope(sp, klp) == 0) {
293*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
294*aca3beaaSApple OSS Distributions return klp;
295*aca3beaaSApple OSS Distributions }
296*aca3beaaSApple OSS Distributions /* table already full */
297*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
298*aca3beaaSApple OSS Distributions kfree_type(struct kauth_listener, klp);
299*aca3beaaSApple OSS Distributions return NULL;
300*aca3beaaSApple OSS Distributions }
301*aca3beaaSApple OSS Distributions }
302*aca3beaaSApple OSS Distributions
303*aca3beaaSApple OSS Distributions /* scope doesn't exist, put on waiting list. */
304*aca3beaaSApple OSS Distributions TAILQ_INSERT_TAIL(&kauth_dangling_listeners, klp, kl_link);
305*aca3beaaSApple OSS Distributions
306*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
307*aca3beaaSApple OSS Distributions
308*aca3beaaSApple OSS Distributions return klp;
309*aca3beaaSApple OSS Distributions }
310*aca3beaaSApple OSS Distributions
311*aca3beaaSApple OSS Distributions void
kauth_unlisten_scope(kauth_listener_t listener)312*aca3beaaSApple OSS Distributions kauth_unlisten_scope(kauth_listener_t listener)
313*aca3beaaSApple OSS Distributions {
314*aca3beaaSApple OSS Distributions kauth_scope_t sp;
315*aca3beaaSApple OSS Distributions kauth_listener_t klp;
316*aca3beaaSApple OSS Distributions int i, listener_count, do_free;
317*aca3beaaSApple OSS Distributions
318*aca3beaaSApple OSS Distributions KAUTH_SCOPELOCK();
319*aca3beaaSApple OSS Distributions
320*aca3beaaSApple OSS Distributions /* search the active scope for this listener */
321*aca3beaaSApple OSS Distributions TAILQ_FOREACH(sp, &kauth_scopes, ks_link) {
322*aca3beaaSApple OSS Distributions do_free = 0;
323*aca3beaaSApple OSS Distributions if ((sp->ks_flags & KS_F_HAS_LISTENERS) != 0) {
324*aca3beaaSApple OSS Distributions listener_count = 0;
325*aca3beaaSApple OSS Distributions for (i = 0; i < KAUTH_SCOPE_MAX_LISTENERS; i++) {
326*aca3beaaSApple OSS Distributions if (sp->ks_listeners[i].kll_listenerp == listener) {
327*aca3beaaSApple OSS Distributions sp->ks_listeners[i].kll_listenerp = NULL;
328*aca3beaaSApple OSS Distributions do_free = 1;
329*aca3beaaSApple OSS Distributions /*
330*aca3beaaSApple OSS Distributions * XXX - kauth_todo - WARNING, do not clear kll_callback or
331*aca3beaaSApple OSS Distributions * kll_idata here. they are part of our scope unlisten race hack
332*aca3beaaSApple OSS Distributions */
333*aca3beaaSApple OSS Distributions } else if (sp->ks_listeners[i].kll_listenerp != NULL) {
334*aca3beaaSApple OSS Distributions listener_count++;
335*aca3beaaSApple OSS Distributions }
336*aca3beaaSApple OSS Distributions }
337*aca3beaaSApple OSS Distributions if (do_free) {
338*aca3beaaSApple OSS Distributions if (listener_count == 0) {
339*aca3beaaSApple OSS Distributions sp->ks_flags &= ~KS_F_HAS_LISTENERS;
340*aca3beaaSApple OSS Distributions }
341*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
342*aca3beaaSApple OSS Distributions kfree_type(struct kauth_listener, listener);
343*aca3beaaSApple OSS Distributions return;
344*aca3beaaSApple OSS Distributions }
345*aca3beaaSApple OSS Distributions }
346*aca3beaaSApple OSS Distributions }
347*aca3beaaSApple OSS Distributions
348*aca3beaaSApple OSS Distributions /* if not active, check the dangling list */
349*aca3beaaSApple OSS Distributions TAILQ_FOREACH(klp, &kauth_dangling_listeners, kl_link) {
350*aca3beaaSApple OSS Distributions if (klp == listener) {
351*aca3beaaSApple OSS Distributions TAILQ_REMOVE(&kauth_dangling_listeners, klp, kl_link);
352*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
353*aca3beaaSApple OSS Distributions kfree_type(struct kauth_listener, listener);
354*aca3beaaSApple OSS Distributions return;
355*aca3beaaSApple OSS Distributions }
356*aca3beaaSApple OSS Distributions }
357*aca3beaaSApple OSS Distributions
358*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
359*aca3beaaSApple OSS Distributions return;
360*aca3beaaSApple OSS Distributions }
361*aca3beaaSApple OSS Distributions
362*aca3beaaSApple OSS Distributions /*
363*aca3beaaSApple OSS Distributions * Authorization requests.
364*aca3beaaSApple OSS Distributions *
365*aca3beaaSApple OSS Distributions * Returns: 0 Success
366*aca3beaaSApple OSS Distributions * EPERM Operation not permitted
367*aca3beaaSApple OSS Distributions *
368*aca3beaaSApple OSS Distributions * Imputed: *arg3, modified Callback return - depends on callback
369*aca3beaaSApple OSS Distributions * modification of *arg3, if any
370*aca3beaaSApple OSS Distributions */
371*aca3beaaSApple OSS Distributions int
kauth_authorize_action(kauth_scope_t scope,kauth_cred_t credential,kauth_action_t action,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)372*aca3beaaSApple OSS Distributions kauth_authorize_action(kauth_scope_t scope, kauth_cred_t credential, kauth_action_t action,
373*aca3beaaSApple OSS Distributions uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
374*aca3beaaSApple OSS Distributions {
375*aca3beaaSApple OSS Distributions int result, ret, i;
376*aca3beaaSApple OSS Distributions
377*aca3beaaSApple OSS Distributions /* ask the scope */
378*aca3beaaSApple OSS Distributions if (scope->ks_callback != NULL) {
379*aca3beaaSApple OSS Distributions result = scope->ks_callback(credential, scope->ks_idata, action, arg0, arg1, arg2, arg3);
380*aca3beaaSApple OSS Distributions } else {
381*aca3beaaSApple OSS Distributions result = KAUTH_RESULT_DEFER;
382*aca3beaaSApple OSS Distributions }
383*aca3beaaSApple OSS Distributions
384*aca3beaaSApple OSS Distributions /* check with listeners */
385*aca3beaaSApple OSS Distributions if ((scope->ks_flags & KS_F_HAS_LISTENERS) != 0) {
386*aca3beaaSApple OSS Distributions for (i = 0; i < KAUTH_SCOPE_MAX_LISTENERS; i++) {
387*aca3beaaSApple OSS Distributions /* XXX - kauth_todo - there is a race here if listener is removed - we will fix this post Tiger.
388*aca3beaaSApple OSS Distributions * Until the race is fixed our kext clients are responsible for all active requests that may
389*aca3beaaSApple OSS Distributions * be in their callbacks or on the way to their callbacks before they free kl_callback or kl_idata.
390*aca3beaaSApple OSS Distributions * We keep copies of these in our kauth_local_listener in an attempt to limit our expose to
391*aca3beaaSApple OSS Distributions * unlisten race.
392*aca3beaaSApple OSS Distributions */
393*aca3beaaSApple OSS Distributions if (scope->ks_listeners[i].kll_listenerp == NULL ||
394*aca3beaaSApple OSS Distributions scope->ks_listeners[i].kll_callback == NULL) {
395*aca3beaaSApple OSS Distributions continue;
396*aca3beaaSApple OSS Distributions }
397*aca3beaaSApple OSS Distributions
398*aca3beaaSApple OSS Distributions ret = scope->ks_listeners[i].kll_callback(
399*aca3beaaSApple OSS Distributions credential, scope->ks_listeners[i].kll_idata,
400*aca3beaaSApple OSS Distributions action, arg0, arg1, arg2, arg3);
401*aca3beaaSApple OSS Distributions if ((ret == KAUTH_RESULT_DENY) ||
402*aca3beaaSApple OSS Distributions (result == KAUTH_RESULT_DEFER)) {
403*aca3beaaSApple OSS Distributions result = ret;
404*aca3beaaSApple OSS Distributions }
405*aca3beaaSApple OSS Distributions }
406*aca3beaaSApple OSS Distributions }
407*aca3beaaSApple OSS Distributions
408*aca3beaaSApple OSS Distributions /* we need an explicit allow, or the auth fails */
409*aca3beaaSApple OSS Distributions /* XXX need a mechanism for auth failure to be signalled vs. denial */
410*aca3beaaSApple OSS Distributions return result == KAUTH_RESULT_ALLOW ? 0 : EPERM;
411*aca3beaaSApple OSS Distributions }
412*aca3beaaSApple OSS Distributions
413*aca3beaaSApple OSS Distributions /*
414*aca3beaaSApple OSS Distributions * Default authorization handlers.
415*aca3beaaSApple OSS Distributions */
416*aca3beaaSApple OSS Distributions int
kauth_authorize_allow(__unused kauth_cred_t credential,__unused void * idata,__unused kauth_action_t action,__unused uintptr_t arg0,__unused uintptr_t arg1,__unused uintptr_t arg2,__unused uintptr_t arg3)417*aca3beaaSApple OSS Distributions kauth_authorize_allow(__unused kauth_cred_t credential, __unused void *idata, __unused kauth_action_t action,
418*aca3beaaSApple OSS Distributions __unused uintptr_t arg0, __unused uintptr_t arg1, __unused uintptr_t arg2, __unused uintptr_t arg3)
419*aca3beaaSApple OSS Distributions {
420*aca3beaaSApple OSS Distributions return KAUTH_RESULT_ALLOW;
421*aca3beaaSApple OSS Distributions }
422*aca3beaaSApple OSS Distributions
423*aca3beaaSApple OSS Distributions #if 0
424*aca3beaaSApple OSS Distributions /*
425*aca3beaaSApple OSS Distributions * Debugging support.
426*aca3beaaSApple OSS Distributions */
427*aca3beaaSApple OSS Distributions static int
428*aca3beaaSApple OSS Distributions kauth_scope_valid(kauth_scope_t scope)
429*aca3beaaSApple OSS Distributions {
430*aca3beaaSApple OSS Distributions kauth_scope_t sp;
431*aca3beaaSApple OSS Distributions
432*aca3beaaSApple OSS Distributions KAUTH_SCOPELOCK();
433*aca3beaaSApple OSS Distributions TAILQ_FOREACH(sp, &kauth_scopes, ks_link) {
434*aca3beaaSApple OSS Distributions if (sp == scope) {
435*aca3beaaSApple OSS Distributions break;
436*aca3beaaSApple OSS Distributions }
437*aca3beaaSApple OSS Distributions }
438*aca3beaaSApple OSS Distributions KAUTH_SCOPEUNLOCK();
439*aca3beaaSApple OSS Distributions return (sp == NULL) ? 0 : 1;
440*aca3beaaSApple OSS Distributions }
441*aca3beaaSApple OSS Distributions #endif
442*aca3beaaSApple OSS Distributions
443*aca3beaaSApple OSS Distributions /*
444*aca3beaaSApple OSS Distributions * Process authorization scope.
445*aca3beaaSApple OSS Distributions */
446*aca3beaaSApple OSS Distributions
447*aca3beaaSApple OSS Distributions int
kauth_authorize_process(kauth_cred_t credential,kauth_action_t action,struct proc * process,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)448*aca3beaaSApple OSS Distributions kauth_authorize_process(kauth_cred_t credential, kauth_action_t action, struct proc *process, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
449*aca3beaaSApple OSS Distributions {
450*aca3beaaSApple OSS Distributions return kauth_authorize_action(kauth_scope_process, credential, action, (uintptr_t)process, arg1, arg2, arg3);
451*aca3beaaSApple OSS Distributions }
452*aca3beaaSApple OSS Distributions
453*aca3beaaSApple OSS Distributions static int
kauth_authorize_process_callback(kauth_cred_t credential,__unused void * idata,kauth_action_t action,uintptr_t arg0,uintptr_t arg1,__unused uintptr_t arg2,__unused uintptr_t arg3)454*aca3beaaSApple OSS Distributions kauth_authorize_process_callback(kauth_cred_t credential, __unused void *idata, kauth_action_t action,
455*aca3beaaSApple OSS Distributions uintptr_t arg0, uintptr_t arg1, __unused uintptr_t arg2, __unused uintptr_t arg3)
456*aca3beaaSApple OSS Distributions {
457*aca3beaaSApple OSS Distributions switch (action) {
458*aca3beaaSApple OSS Distributions case KAUTH_PROCESS_CANSIGNAL:
459*aca3beaaSApple OSS Distributions panic("KAUTH_PROCESS_CANSIGNAL not implemented");
460*aca3beaaSApple OSS Distributions /* XXX credential wrong here */
461*aca3beaaSApple OSS Distributions /* arg0 - process to signal
462*aca3beaaSApple OSS Distributions * arg1 - signal to send the process
463*aca3beaaSApple OSS Distributions */
464*aca3beaaSApple OSS Distributions if (cansignal(current_proc(), credential, (struct proc *)arg0, (int)arg1)) {
465*aca3beaaSApple OSS Distributions return KAUTH_RESULT_ALLOW;
466*aca3beaaSApple OSS Distributions }
467*aca3beaaSApple OSS Distributions break;
468*aca3beaaSApple OSS Distributions case KAUTH_PROCESS_CANTRACE:
469*aca3beaaSApple OSS Distributions /* current_proc() - process that will do the tracing
470*aca3beaaSApple OSS Distributions * arg0 - process to be traced
471*aca3beaaSApple OSS Distributions * arg1 - pointer to int - reason (errno) for denial
472*aca3beaaSApple OSS Distributions */
473*aca3beaaSApple OSS Distributions if (cantrace(current_proc(), credential, (proc_t)arg0, (int *)arg1)) {
474*aca3beaaSApple OSS Distributions return KAUTH_RESULT_ALLOW;
475*aca3beaaSApple OSS Distributions }
476*aca3beaaSApple OSS Distributions break;
477*aca3beaaSApple OSS Distributions }
478*aca3beaaSApple OSS Distributions
479*aca3beaaSApple OSS Distributions /* no explicit result, so defer to others in the chain */
480*aca3beaaSApple OSS Distributions return KAUTH_RESULT_DEFER;
481*aca3beaaSApple OSS Distributions }
482*aca3beaaSApple OSS Distributions
483*aca3beaaSApple OSS Distributions /*
484*aca3beaaSApple OSS Distributions * File system operation authorization scope. This is really only a notification
485*aca3beaaSApple OSS Distributions * of the file system operation, not an authorization check. Thus the result is
486*aca3beaaSApple OSS Distributions * not relevant.
487*aca3beaaSApple OSS Distributions * arguments passed to KAUTH_FILEOP_OPEN listeners
488*aca3beaaSApple OSS Distributions * arg0 is pointer to vnode (vnode *) for given user path.
489*aca3beaaSApple OSS Distributions * arg1 is pointer to path (char *) passed in to open.
490*aca3beaaSApple OSS Distributions * arguments passed to KAUTH_FILEOP_CLOSE listeners
491*aca3beaaSApple OSS Distributions * arg0 is pointer to vnode (vnode *) for file to be closed.
492*aca3beaaSApple OSS Distributions * arg1 is pointer to path (char *) of file to be closed.
493*aca3beaaSApple OSS Distributions * arg2 is close flags.
494*aca3beaaSApple OSS Distributions * arguments passed to KAUTH_FILEOP_WILL_RENAME listeners
495*aca3beaaSApple OSS Distributions * arg0 is pointer to vnode (vnode *) of the file being renamed
496*aca3beaaSApple OSS Distributions * arg1 is pointer to the "from" path (char *)
497*aca3beaaSApple OSS Distributions * arg2 is pointer to the "to" path (char *)
498*aca3beaaSApple OSS Distributions * arguments passed to KAUTH_FILEOP_RENAME listeners
499*aca3beaaSApple OSS Distributions * arg0 is pointer to "from" path (char *).
500*aca3beaaSApple OSS Distributions * arg1 is pointer to "to" path (char *).
501*aca3beaaSApple OSS Distributions * arguments passed to KAUTH_FILEOP_EXCHANGE listeners
502*aca3beaaSApple OSS Distributions * arg0 is pointer to file 1 path (char *).
503*aca3beaaSApple OSS Distributions * arg1 is pointer to file 2 path (char *).
504*aca3beaaSApple OSS Distributions * arguments passed to KAUTH_FILEOP_EXEC listeners
505*aca3beaaSApple OSS Distributions * arg0 is pointer to vnode (vnode *) for executable.
506*aca3beaaSApple OSS Distributions * arg1 is pointer to path (char *) to executable.
507*aca3beaaSApple OSS Distributions */
508*aca3beaaSApple OSS Distributions
509*aca3beaaSApple OSS Distributions int
kauth_authorize_fileop_has_listeners(void)510*aca3beaaSApple OSS Distributions kauth_authorize_fileop_has_listeners(void)
511*aca3beaaSApple OSS Distributions {
512*aca3beaaSApple OSS Distributions /*
513*aca3beaaSApple OSS Distributions * return 1 if we have any listeners for the fileop scope
514*aca3beaaSApple OSS Distributions * otherwize return 0
515*aca3beaaSApple OSS Distributions */
516*aca3beaaSApple OSS Distributions if ((kauth_scope_fileop->ks_flags & KS_F_HAS_LISTENERS) != 0) {
517*aca3beaaSApple OSS Distributions return 1;
518*aca3beaaSApple OSS Distributions }
519*aca3beaaSApple OSS Distributions return 0;
520*aca3beaaSApple OSS Distributions }
521*aca3beaaSApple OSS Distributions
522*aca3beaaSApple OSS Distributions int
kauth_authorize_fileop(kauth_cred_t credential,kauth_action_t action,uintptr_t arg0,uintptr_t arg1)523*aca3beaaSApple OSS Distributions kauth_authorize_fileop(kauth_cred_t credential, kauth_action_t action, uintptr_t arg0, uintptr_t arg1)
524*aca3beaaSApple OSS Distributions {
525*aca3beaaSApple OSS Distributions char *namep = NULL;
526*aca3beaaSApple OSS Distributions int name_len;
527*aca3beaaSApple OSS Distributions uintptr_t arg2 = 0;
528*aca3beaaSApple OSS Distributions
529*aca3beaaSApple OSS Distributions /* we do not have a primary handler for the fileop scope so bail out if
530*aca3beaaSApple OSS Distributions * there are no listeners.
531*aca3beaaSApple OSS Distributions */
532*aca3beaaSApple OSS Distributions if ((kauth_scope_fileop->ks_flags & KS_F_HAS_LISTENERS) == 0) {
533*aca3beaaSApple OSS Distributions return 0;
534*aca3beaaSApple OSS Distributions }
535*aca3beaaSApple OSS Distributions
536*aca3beaaSApple OSS Distributions if (action == KAUTH_FILEOP_OPEN ||
537*aca3beaaSApple OSS Distributions action == KAUTH_FILEOP_CLOSE ||
538*aca3beaaSApple OSS Distributions action == KAUTH_FILEOP_EXEC ||
539*aca3beaaSApple OSS Distributions action == KAUTH_FILEOP_WILL_RENAME) {
540*aca3beaaSApple OSS Distributions /* get path to the given vnode as a convenience to our listeners.
541*aca3beaaSApple OSS Distributions */
542*aca3beaaSApple OSS Distributions namep = get_pathbuff();
543*aca3beaaSApple OSS Distributions name_len = MAXPATHLEN;
544*aca3beaaSApple OSS Distributions if (vn_getpath((vnode_t)arg0, namep, &name_len) != 0) {
545*aca3beaaSApple OSS Distributions release_pathbuff(namep);
546*aca3beaaSApple OSS Distributions return 0;
547*aca3beaaSApple OSS Distributions }
548*aca3beaaSApple OSS Distributions if (action == KAUTH_FILEOP_CLOSE ||
549*aca3beaaSApple OSS Distributions action == KAUTH_FILEOP_WILL_RENAME) {
550*aca3beaaSApple OSS Distributions /*
551*aca3beaaSApple OSS Distributions * - Close has some flags that come in via arg1.
552*aca3beaaSApple OSS Distributions * - Will-rename wants to pass the vnode and
553*aca3beaaSApple OSS Distributions * both paths to the listeners ("to" path
554*aca3beaaSApple OSS Distributions * starts in arg1, moves to arg2).
555*aca3beaaSApple OSS Distributions */
556*aca3beaaSApple OSS Distributions arg2 = arg1;
557*aca3beaaSApple OSS Distributions }
558*aca3beaaSApple OSS Distributions arg1 = (uintptr_t)namep;
559*aca3beaaSApple OSS Distributions }
560*aca3beaaSApple OSS Distributions kauth_authorize_action(kauth_scope_fileop, credential, action, arg0, arg1, arg2, 0);
561*aca3beaaSApple OSS Distributions
562*aca3beaaSApple OSS Distributions if (namep != NULL) {
563*aca3beaaSApple OSS Distributions release_pathbuff(namep);
564*aca3beaaSApple OSS Distributions }
565*aca3beaaSApple OSS Distributions
566*aca3beaaSApple OSS Distributions return 0;
567*aca3beaaSApple OSS Distributions }
568*aca3beaaSApple OSS Distributions
569*aca3beaaSApple OSS Distributions /*
570*aca3beaaSApple OSS Distributions * Generic authorization scope.
571*aca3beaaSApple OSS Distributions */
572*aca3beaaSApple OSS Distributions
573*aca3beaaSApple OSS Distributions int
kauth_authorize_generic(kauth_cred_t credential,kauth_action_t action)574*aca3beaaSApple OSS Distributions kauth_authorize_generic(kauth_cred_t credential, kauth_action_t action)
575*aca3beaaSApple OSS Distributions {
576*aca3beaaSApple OSS Distributions if (credential == NULL) {
577*aca3beaaSApple OSS Distributions panic("auth against NULL credential");
578*aca3beaaSApple OSS Distributions }
579*aca3beaaSApple OSS Distributions
580*aca3beaaSApple OSS Distributions return kauth_authorize_action(kauth_scope_generic, credential, action, 0, 0, 0, 0);
581*aca3beaaSApple OSS Distributions }
582*aca3beaaSApple OSS Distributions
583*aca3beaaSApple OSS Distributions static int
kauth_authorize_generic_callback(kauth_cred_t credential,__unused void * idata,kauth_action_t action,__unused uintptr_t arg0,__unused uintptr_t arg1,__unused uintptr_t arg2,__unused uintptr_t arg3)584*aca3beaaSApple OSS Distributions kauth_authorize_generic_callback(kauth_cred_t credential, __unused void *idata, kauth_action_t action,
585*aca3beaaSApple OSS Distributions __unused uintptr_t arg0, __unused uintptr_t arg1, __unused uintptr_t arg2, __unused uintptr_t arg3)
586*aca3beaaSApple OSS Distributions {
587*aca3beaaSApple OSS Distributions switch (action) {
588*aca3beaaSApple OSS Distributions case KAUTH_GENERIC_ISSUSER:
589*aca3beaaSApple OSS Distributions /* XXX == 0 ? */
590*aca3beaaSApple OSS Distributions return (kauth_cred_getuid(credential) == 0) ?
591*aca3beaaSApple OSS Distributions KAUTH_RESULT_ALLOW : KAUTH_RESULT_DENY;
592*aca3beaaSApple OSS Distributions }
593*aca3beaaSApple OSS Distributions
594*aca3beaaSApple OSS Distributions /* no explicit result, so defer to others in the chain */
595*aca3beaaSApple OSS Distributions return KAUTH_RESULT_DEFER;
596*aca3beaaSApple OSS Distributions }
597*aca3beaaSApple OSS Distributions
598*aca3beaaSApple OSS Distributions /*
599*aca3beaaSApple OSS Distributions * ACL evaluator.
600*aca3beaaSApple OSS Distributions *
601*aca3beaaSApple OSS Distributions * Determines whether the credential has the requested rights for an object secured by the supplied
602*aca3beaaSApple OSS Distributions * ACL.
603*aca3beaaSApple OSS Distributions *
604*aca3beaaSApple OSS Distributions * Evaluation proceeds from the top down, with access denied if any ACE denies any of the requested
605*aca3beaaSApple OSS Distributions * rights, or granted if all of the requested rights are satisfied by the ACEs so far.
606*aca3beaaSApple OSS Distributions */
607*aca3beaaSApple OSS Distributions int
kauth_acl_evaluate(kauth_cred_t cred,kauth_acl_eval_t eval)608*aca3beaaSApple OSS Distributions kauth_acl_evaluate(kauth_cred_t cred, kauth_acl_eval_t eval)
609*aca3beaaSApple OSS Distributions {
610*aca3beaaSApple OSS Distributions int applies, error, i, gotguid;
611*aca3beaaSApple OSS Distributions kauth_ace_t ace;
612*aca3beaaSApple OSS Distributions guid_t guid;
613*aca3beaaSApple OSS Distributions uint32_t rights;
614*aca3beaaSApple OSS Distributions int wkguid;
615*aca3beaaSApple OSS Distributions
616*aca3beaaSApple OSS Distributions if (cred == NULL) {
617*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL - got NULL credential");
618*aca3beaaSApple OSS Distributions return EINVAL;
619*aca3beaaSApple OSS Distributions }
620*aca3beaaSApple OSS Distributions
621*aca3beaaSApple OSS Distributions if (eval == NULL) {
622*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL - got NULL ACL evaluator");
623*aca3beaaSApple OSS Distributions return EINVAL;
624*aca3beaaSApple OSS Distributions }
625*aca3beaaSApple OSS Distributions
626*aca3beaaSApple OSS Distributions /* always allowed to do nothing */
627*aca3beaaSApple OSS Distributions if (eval->ae_requested == 0) {
628*aca3beaaSApple OSS Distributions eval->ae_result = KAUTH_RESULT_ALLOW;
629*aca3beaaSApple OSS Distributions return 0;
630*aca3beaaSApple OSS Distributions }
631*aca3beaaSApple OSS Distributions
632*aca3beaaSApple OSS Distributions eval->ae_residual = eval->ae_requested;
633*aca3beaaSApple OSS Distributions eval->ae_found_deny = FALSE;
634*aca3beaaSApple OSS Distributions
635*aca3beaaSApple OSS Distributions /*
636*aca3beaaSApple OSS Distributions * Get our guid for comparison purposes.
637*aca3beaaSApple OSS Distributions */
638*aca3beaaSApple OSS Distributions if ((error = kauth_cred_getguid(cred, &guid)) != 0) {
639*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL - can't get credential GUID (%d)", error);
640*aca3beaaSApple OSS Distributions error = 0;
641*aca3beaaSApple OSS Distributions gotguid = 0;
642*aca3beaaSApple OSS Distributions } else {
643*aca3beaaSApple OSS Distributions gotguid = 1;
644*aca3beaaSApple OSS Distributions }
645*aca3beaaSApple OSS Distributions
646*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL - %d entries, initial residual %x", eval->ae_count, eval->ae_residual);
647*aca3beaaSApple OSS Distributions for (i = 0, ace = eval->ae_acl; i < eval->ae_count; i++, ace++) {
648*aca3beaaSApple OSS Distributions /*
649*aca3beaaSApple OSS Distributions * Skip inherit-only entries.
650*aca3beaaSApple OSS Distributions */
651*aca3beaaSApple OSS Distributions if (ace->ace_flags & KAUTH_ACE_ONLY_INHERIT) {
652*aca3beaaSApple OSS Distributions continue;
653*aca3beaaSApple OSS Distributions }
654*aca3beaaSApple OSS Distributions
655*aca3beaaSApple OSS Distributions /*
656*aca3beaaSApple OSS Distributions * Expand generic rights, if appropriate.
657*aca3beaaSApple OSS Distributions */
658*aca3beaaSApple OSS Distributions rights = ace->ace_rights;
659*aca3beaaSApple OSS Distributions if (rights & KAUTH_ACE_GENERIC_ALL) {
660*aca3beaaSApple OSS Distributions rights |= eval->ae_exp_gall;
661*aca3beaaSApple OSS Distributions }
662*aca3beaaSApple OSS Distributions if (rights & KAUTH_ACE_GENERIC_READ) {
663*aca3beaaSApple OSS Distributions rights |= eval->ae_exp_gread;
664*aca3beaaSApple OSS Distributions }
665*aca3beaaSApple OSS Distributions if (rights & KAUTH_ACE_GENERIC_WRITE) {
666*aca3beaaSApple OSS Distributions rights |= eval->ae_exp_gwrite;
667*aca3beaaSApple OSS Distributions }
668*aca3beaaSApple OSS Distributions if (rights & KAUTH_ACE_GENERIC_EXECUTE) {
669*aca3beaaSApple OSS Distributions rights |= eval->ae_exp_gexec;
670*aca3beaaSApple OSS Distributions }
671*aca3beaaSApple OSS Distributions
672*aca3beaaSApple OSS Distributions /*
673*aca3beaaSApple OSS Distributions * Determine whether this entry applies to the current request. This
674*aca3beaaSApple OSS Distributions * saves us checking the GUID if the entry has nothing to do with what
675*aca3beaaSApple OSS Distributions * we're currently doing.
676*aca3beaaSApple OSS Distributions */
677*aca3beaaSApple OSS Distributions switch (ace->ace_flags & KAUTH_ACE_KINDMASK) {
678*aca3beaaSApple OSS Distributions case KAUTH_ACE_PERMIT:
679*aca3beaaSApple OSS Distributions if (!(eval->ae_residual & rights)) {
680*aca3beaaSApple OSS Distributions continue;
681*aca3beaaSApple OSS Distributions }
682*aca3beaaSApple OSS Distributions break;
683*aca3beaaSApple OSS Distributions case KAUTH_ACE_DENY:
684*aca3beaaSApple OSS Distributions if (!(eval->ae_requested & rights)) {
685*aca3beaaSApple OSS Distributions continue;
686*aca3beaaSApple OSS Distributions }
687*aca3beaaSApple OSS Distributions eval->ae_found_deny = TRUE;
688*aca3beaaSApple OSS Distributions break;
689*aca3beaaSApple OSS Distributions default:
690*aca3beaaSApple OSS Distributions /* we don't recognise this ACE, skip it */
691*aca3beaaSApple OSS Distributions continue;
692*aca3beaaSApple OSS Distributions }
693*aca3beaaSApple OSS Distributions
694*aca3beaaSApple OSS Distributions /*
695*aca3beaaSApple OSS Distributions * Verify whether this entry applies to the credential.
696*aca3beaaSApple OSS Distributions */
697*aca3beaaSApple OSS Distributions wkguid = kauth_wellknown_guid(&ace->ace_applicable);
698*aca3beaaSApple OSS Distributions switch (wkguid) {
699*aca3beaaSApple OSS Distributions case KAUTH_WKG_OWNER:
700*aca3beaaSApple OSS Distributions applies = eval->ae_options & KAUTH_AEVAL_IS_OWNER;
701*aca3beaaSApple OSS Distributions break;
702*aca3beaaSApple OSS Distributions case KAUTH_WKG_GROUP:
703*aca3beaaSApple OSS Distributions if (!gotguid || (eval->ae_options & KAUTH_AEVAL_IN_GROUP_UNKNOWN)) {
704*aca3beaaSApple OSS Distributions applies = ((ace->ace_flags & KAUTH_ACE_KINDMASK) == KAUTH_ACE_DENY);
705*aca3beaaSApple OSS Distributions } else {
706*aca3beaaSApple OSS Distributions applies = eval->ae_options & KAUTH_AEVAL_IN_GROUP;
707*aca3beaaSApple OSS Distributions }
708*aca3beaaSApple OSS Distributions break;
709*aca3beaaSApple OSS Distributions /* we short-circuit these here rather than wasting time calling the group membership code */
710*aca3beaaSApple OSS Distributions case KAUTH_WKG_EVERYBODY:
711*aca3beaaSApple OSS Distributions applies = 1;
712*aca3beaaSApple OSS Distributions break;
713*aca3beaaSApple OSS Distributions case KAUTH_WKG_NOBODY:
714*aca3beaaSApple OSS Distributions applies = 0;
715*aca3beaaSApple OSS Distributions break;
716*aca3beaaSApple OSS Distributions
717*aca3beaaSApple OSS Distributions default:
718*aca3beaaSApple OSS Distributions /* check to see whether it's exactly us, or a group we are a member of */
719*aca3beaaSApple OSS Distributions applies = !gotguid ? 0 : kauth_guid_equal(&guid, &ace->ace_applicable);
720*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL - ACE applicable " K_UUID_FMT " caller " K_UUID_FMT " %smatched",
721*aca3beaaSApple OSS Distributions K_UUID_ARG(ace->ace_applicable), K_UUID_ARG(guid), applies ? "" : "not ");
722*aca3beaaSApple OSS Distributions
723*aca3beaaSApple OSS Distributions if (!applies) {
724*aca3beaaSApple OSS Distributions error = !gotguid ? ENOENT : kauth_cred_ismember_guid(cred, &ace->ace_applicable, &applies);
725*aca3beaaSApple OSS Distributions /*
726*aca3beaaSApple OSS Distributions * If we can't resolve group membership, we have to limit misbehaviour.
727*aca3beaaSApple OSS Distributions * If the ACE is an 'allow' ACE, assume the cred is not a member (avoid
728*aca3beaaSApple OSS Distributions * granting excess access). If the ACE is a 'deny' ACE, assume the cred
729*aca3beaaSApple OSS Distributions * is a member (avoid failing to deny).
730*aca3beaaSApple OSS Distributions */
731*aca3beaaSApple OSS Distributions if (error != 0) {
732*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL[%d] - can't get membership, making pessimistic assumption", i);
733*aca3beaaSApple OSS Distributions switch (ace->ace_flags & KAUTH_ACE_KINDMASK) {
734*aca3beaaSApple OSS Distributions case KAUTH_ACE_PERMIT:
735*aca3beaaSApple OSS Distributions applies = 0;
736*aca3beaaSApple OSS Distributions break;
737*aca3beaaSApple OSS Distributions case KAUTH_ACE_DENY:
738*aca3beaaSApple OSS Distributions applies = 1;
739*aca3beaaSApple OSS Distributions break;
740*aca3beaaSApple OSS Distributions }
741*aca3beaaSApple OSS Distributions } else {
742*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL - %s group member", applies ? "is" : "not");
743*aca3beaaSApple OSS Distributions }
744*aca3beaaSApple OSS Distributions } else {
745*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL - entry matches caller");
746*aca3beaaSApple OSS Distributions }
747*aca3beaaSApple OSS Distributions }
748*aca3beaaSApple OSS Distributions if (!applies) {
749*aca3beaaSApple OSS Distributions continue;
750*aca3beaaSApple OSS Distributions }
751*aca3beaaSApple OSS Distributions
752*aca3beaaSApple OSS Distributions /*
753*aca3beaaSApple OSS Distributions * Apply ACE to outstanding rights.
754*aca3beaaSApple OSS Distributions */
755*aca3beaaSApple OSS Distributions switch (ace->ace_flags & KAUTH_ACE_KINDMASK) {
756*aca3beaaSApple OSS Distributions case KAUTH_ACE_PERMIT:
757*aca3beaaSApple OSS Distributions /* satisfy any rights that this ACE grants */
758*aca3beaaSApple OSS Distributions eval->ae_residual = eval->ae_residual & ~rights;
759*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL[%d] - rights %x leave residual %x", i, rights, eval->ae_residual);
760*aca3beaaSApple OSS Distributions /* all rights satisfied? */
761*aca3beaaSApple OSS Distributions if (eval->ae_residual == 0) {
762*aca3beaaSApple OSS Distributions eval->ae_result = KAUTH_RESULT_ALLOW;
763*aca3beaaSApple OSS Distributions return 0;
764*aca3beaaSApple OSS Distributions }
765*aca3beaaSApple OSS Distributions break;
766*aca3beaaSApple OSS Distributions case KAUTH_ACE_DENY:
767*aca3beaaSApple OSS Distributions /* deny the request if any of the requested rights is denied */
768*aca3beaaSApple OSS Distributions if (eval->ae_requested & rights) {
769*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL[%d] - denying based on %x", i, rights);
770*aca3beaaSApple OSS Distributions eval->ae_result = KAUTH_RESULT_DENY;
771*aca3beaaSApple OSS Distributions return 0;
772*aca3beaaSApple OSS Distributions }
773*aca3beaaSApple OSS Distributions break;
774*aca3beaaSApple OSS Distributions default:
775*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ACL - unknown entry kind %d", ace->ace_flags & KAUTH_ACE_KINDMASK);
776*aca3beaaSApple OSS Distributions break;
777*aca3beaaSApple OSS Distributions }
778*aca3beaaSApple OSS Distributions }
779*aca3beaaSApple OSS Distributions /* if not permitted, defer to other modes of authorisation */
780*aca3beaaSApple OSS Distributions eval->ae_result = KAUTH_RESULT_DEFER;
781*aca3beaaSApple OSS Distributions return 0;
782*aca3beaaSApple OSS Distributions }
783*aca3beaaSApple OSS Distributions
784*aca3beaaSApple OSS Distributions /*
785*aca3beaaSApple OSS Distributions * Perform ACL inheritance and umask-ACL handling.
786*aca3beaaSApple OSS Distributions *
787*aca3beaaSApple OSS Distributions * Entries are inherited from the ACL on dvp. A caller-supplied
788*aca3beaaSApple OSS Distributions * ACL is in initial, and the result is output into product.
789*aca3beaaSApple OSS Distributions * If the process has a umask ACL and one is not supplied, we use
790*aca3beaaSApple OSS Distributions * the umask ACL.
791*aca3beaaSApple OSS Distributions * If isdir is set, the resultant ACL is for a directory, otherwise it is for a file.
792*aca3beaaSApple OSS Distributions */
793*aca3beaaSApple OSS Distributions int
kauth_acl_inherit(vnode_t dvp,kauth_acl_t initial,kauth_acl_t * product,int isdir,vfs_context_t ctx)794*aca3beaaSApple OSS Distributions kauth_acl_inherit(vnode_t dvp, kauth_acl_t initial, kauth_acl_t *product, int isdir, vfs_context_t ctx)
795*aca3beaaSApple OSS Distributions {
796*aca3beaaSApple OSS Distributions int entries, error, index;
797*aca3beaaSApple OSS Distributions unsigned int i;
798*aca3beaaSApple OSS Distributions struct vnode_attr dva;
799*aca3beaaSApple OSS Distributions kauth_acl_t inherit, result;
800*aca3beaaSApple OSS Distributions
801*aca3beaaSApple OSS Distributions /*
802*aca3beaaSApple OSS Distributions * Fetch the ACL from the directory. This should never fail.
803*aca3beaaSApple OSS Distributions * Note that we don't manage inheritance when the remote server is
804*aca3beaaSApple OSS Distributions * doing authorization, since this means server enforcement of
805*aca3beaaSApple OSS Distributions * inheritance semantics; we just want to compose the initial
806*aca3beaaSApple OSS Distributions * ACL and any inherited ACE entries from the container object.
807*aca3beaaSApple OSS Distributions *
808*aca3beaaSApple OSS Distributions * XXX TODO: <rdar://3634665> wants a "umask ACL" from the process.
809*aca3beaaSApple OSS Distributions */
810*aca3beaaSApple OSS Distributions inherit = NULL;
811*aca3beaaSApple OSS Distributions /*
812*aca3beaaSApple OSS Distributions * If there is no initial ACL, or there is, and the initial ACLs
813*aca3beaaSApple OSS Distributions * flags do not request "no inheritance", then we inherit. This allows
814*aca3beaaSApple OSS Distributions * initial object creation via open_extended() and mkdir_extended()
815*aca3beaaSApple OSS Distributions * to reject inheritance for themselves and for inferior nodes by
816*aca3beaaSApple OSS Distributions * specifying a non-NULL inital ACL which has the KAUTH_ACL_NO_INHERIT
817*aca3beaaSApple OSS Distributions * flag set in the flags field.
818*aca3beaaSApple OSS Distributions */
819*aca3beaaSApple OSS Distributions if ((initial == NULL || !(initial->acl_flags & KAUTH_ACL_NO_INHERIT)) &&
820*aca3beaaSApple OSS Distributions (dvp != NULL) && !vfs_authopaque(vnode_mount(dvp))) {
821*aca3beaaSApple OSS Distributions VATTR_INIT(&dva);
822*aca3beaaSApple OSS Distributions VATTR_WANTED(&dva, va_acl);
823*aca3beaaSApple OSS Distributions if ((error = vnode_getattr(dvp, &dva, ctx)) != 0) {
824*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ERROR - could not get parent directory ACL for inheritance");
825*aca3beaaSApple OSS Distributions return error;
826*aca3beaaSApple OSS Distributions }
827*aca3beaaSApple OSS Distributions if (VATTR_IS_SUPPORTED(&dva, va_acl)) {
828*aca3beaaSApple OSS Distributions inherit = dva.va_acl;
829*aca3beaaSApple OSS Distributions }
830*aca3beaaSApple OSS Distributions }
831*aca3beaaSApple OSS Distributions
832*aca3beaaSApple OSS Distributions /*
833*aca3beaaSApple OSS Distributions * Compute the number of entries in the result ACL by scanning the
834*aca3beaaSApple OSS Distributions * input lists.
835*aca3beaaSApple OSS Distributions */
836*aca3beaaSApple OSS Distributions entries = 0;
837*aca3beaaSApple OSS Distributions if (inherit != NULL) {
838*aca3beaaSApple OSS Distributions for (i = 0; i < inherit->acl_entrycount; i++) {
839*aca3beaaSApple OSS Distributions if (inherit->acl_ace[i].ace_flags & (isdir ? KAUTH_ACE_DIRECTORY_INHERIT : KAUTH_ACE_FILE_INHERIT)) {
840*aca3beaaSApple OSS Distributions entries++;
841*aca3beaaSApple OSS Distributions }
842*aca3beaaSApple OSS Distributions }
843*aca3beaaSApple OSS Distributions }
844*aca3beaaSApple OSS Distributions
845*aca3beaaSApple OSS Distributions if (initial == NULL) {
846*aca3beaaSApple OSS Distributions /*
847*aca3beaaSApple OSS Distributions * XXX 3634665 TODO: if the initial ACL is not specfied by
848*aca3beaaSApple OSS Distributions * XXX the caller, fetch the umask ACL from the process,
849*aca3beaaSApple OSS Distributions * and use it in place of "initial".
850*aca3beaaSApple OSS Distributions */
851*aca3beaaSApple OSS Distributions }
852*aca3beaaSApple OSS Distributions
853*aca3beaaSApple OSS Distributions if (initial != NULL) {
854*aca3beaaSApple OSS Distributions if (initial->acl_entrycount != KAUTH_FILESEC_NOACL) {
855*aca3beaaSApple OSS Distributions entries += initial->acl_entrycount;
856*aca3beaaSApple OSS Distributions } else {
857*aca3beaaSApple OSS Distributions initial = NULL;
858*aca3beaaSApple OSS Distributions }
859*aca3beaaSApple OSS Distributions }
860*aca3beaaSApple OSS Distributions
861*aca3beaaSApple OSS Distributions /*
862*aca3beaaSApple OSS Distributions * If there is no initial ACL, and no inheritable entries, the
863*aca3beaaSApple OSS Distributions * object should be created with no ACL at all.
864*aca3beaaSApple OSS Distributions * Note that this differs from the case where the initial ACL
865*aca3beaaSApple OSS Distributions * is empty, in which case the object must also have an empty ACL.
866*aca3beaaSApple OSS Distributions */
867*aca3beaaSApple OSS Distributions if ((entries == 0) && (initial == NULL)) {
868*aca3beaaSApple OSS Distributions *product = NULL;
869*aca3beaaSApple OSS Distributions error = 0;
870*aca3beaaSApple OSS Distributions goto out;
871*aca3beaaSApple OSS Distributions }
872*aca3beaaSApple OSS Distributions
873*aca3beaaSApple OSS Distributions /*
874*aca3beaaSApple OSS Distributions * Allocate the result buffer.
875*aca3beaaSApple OSS Distributions */
876*aca3beaaSApple OSS Distributions if ((result = kauth_acl_alloc(entries)) == NULL) {
877*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" ERROR - could not allocate %d-entry result buffer for inherited ACL", entries);
878*aca3beaaSApple OSS Distributions error = ENOMEM;
879*aca3beaaSApple OSS Distributions goto out;
880*aca3beaaSApple OSS Distributions }
881*aca3beaaSApple OSS Distributions
882*aca3beaaSApple OSS Distributions /*
883*aca3beaaSApple OSS Distributions * Composition is simply:
884*aca3beaaSApple OSS Distributions * - initial direct ACEs
885*aca3beaaSApple OSS Distributions * - inherited ACEs from new parent
886*aca3beaaSApple OSS Distributions */
887*aca3beaaSApple OSS Distributions index = 0;
888*aca3beaaSApple OSS Distributions if (initial != NULL) {
889*aca3beaaSApple OSS Distributions for (i = 0; i < initial->acl_entrycount; i++) {
890*aca3beaaSApple OSS Distributions if (!(initial->acl_ace[i].ace_flags & KAUTH_ACE_INHERITED)) {
891*aca3beaaSApple OSS Distributions result->acl_ace[index++] = initial->acl_ace[i];
892*aca3beaaSApple OSS Distributions }
893*aca3beaaSApple OSS Distributions }
894*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" INHERIT - applied %d of %d initial entries", index, initial->acl_entrycount);
895*aca3beaaSApple OSS Distributions }
896*aca3beaaSApple OSS Distributions if (inherit != NULL) {
897*aca3beaaSApple OSS Distributions for (i = 0; i < inherit->acl_entrycount; i++) {
898*aca3beaaSApple OSS Distributions /*
899*aca3beaaSApple OSS Distributions * Inherit onto this object? We inherit only if
900*aca3beaaSApple OSS Distributions * the target object is a container object and the
901*aca3beaaSApple OSS Distributions * KAUTH_ACE_DIRECTORY_INHERIT bit is set, OR if
902*aca3beaaSApple OSS Distributions * if the target object is not a container, and
903*aca3beaaSApple OSS Distributions * the KAUTH_ACE_FILE_INHERIT bit is set.
904*aca3beaaSApple OSS Distributions */
905*aca3beaaSApple OSS Distributions if (inherit->acl_ace[i].ace_flags & (isdir ? KAUTH_ACE_DIRECTORY_INHERIT : KAUTH_ACE_FILE_INHERIT)) {
906*aca3beaaSApple OSS Distributions result->acl_ace[index] = inherit->acl_ace[i];
907*aca3beaaSApple OSS Distributions result->acl_ace[index].ace_flags |= KAUTH_ACE_INHERITED;
908*aca3beaaSApple OSS Distributions result->acl_ace[index].ace_flags &= ~KAUTH_ACE_ONLY_INHERIT;
909*aca3beaaSApple OSS Distributions /*
910*aca3beaaSApple OSS Distributions * We do not re-inherit inheritance flags
911*aca3beaaSApple OSS Distributions * if the ACE from the container has a
912*aca3beaaSApple OSS Distributions * KAUTH_ACE_LIMIT_INHERIT, OR if the new
913*aca3beaaSApple OSS Distributions * object is not itself a container (since
914*aca3beaaSApple OSS Distributions * inheritance is always container-based).
915*aca3beaaSApple OSS Distributions */
916*aca3beaaSApple OSS Distributions if ((result->acl_ace[index].ace_flags & KAUTH_ACE_LIMIT_INHERIT) || !isdir) {
917*aca3beaaSApple OSS Distributions result->acl_ace[index].ace_flags &=
918*aca3beaaSApple OSS Distributions ~(KAUTH_ACE_INHERIT_CONTROL_FLAGS);
919*aca3beaaSApple OSS Distributions }
920*aca3beaaSApple OSS Distributions index++;
921*aca3beaaSApple OSS Distributions }
922*aca3beaaSApple OSS Distributions }
923*aca3beaaSApple OSS Distributions }
924*aca3beaaSApple OSS Distributions result->acl_entrycount = index;
925*aca3beaaSApple OSS Distributions *product = result;
926*aca3beaaSApple OSS Distributions KAUTH_DEBUG(" INHERIT - product ACL has %d entries", index);
927*aca3beaaSApple OSS Distributions error = 0;
928*aca3beaaSApple OSS Distributions out:
929*aca3beaaSApple OSS Distributions if (inherit != NULL) {
930*aca3beaaSApple OSS Distributions kauth_acl_free(inherit);
931*aca3beaaSApple OSS Distributions }
932*aca3beaaSApple OSS Distributions return error;
933*aca3beaaSApple OSS Distributions }
934*aca3beaaSApple OSS Distributions
935*aca3beaaSApple OSS Distributions /*
936*aca3beaaSApple OSS Distributions * Optimistically copy in a kauth_filesec structure
937*aca3beaaSApple OSS Distributions *
938*aca3beaaSApple OSS Distributions * Parameters: xsecurity user space kauth_filesec_t
939*aca3beaaSApple OSS Distributions * xsecdstpp pointer to kauth_filesec_t to be
940*aca3beaaSApple OSS Distributions * modified to contain the contain a
941*aca3beaaSApple OSS Distributions * pointer to an allocated copy of the
942*aca3beaaSApple OSS Distributions * user space argument
943*aca3beaaSApple OSS Distributions *
944*aca3beaaSApple OSS Distributions * Returns: 0 Success
945*aca3beaaSApple OSS Distributions * ENOMEM Insufficient memory for the copy.
946*aca3beaaSApple OSS Distributions * EINVAL The user space data was invalid, or
947*aca3beaaSApple OSS Distributions * there were too many ACE entries.
948*aca3beaaSApple OSS Distributions * EFAULT The user space address was invalid;
949*aca3beaaSApple OSS Distributions * this may mean 'fsec_entrycount' in
950*aca3beaaSApple OSS Distributions * the user copy is corrupt/incorrect.
951*aca3beaaSApple OSS Distributions *
952*aca3beaaSApple OSS Distributions * Implicit returns: xsecdestpp, modified (only if successful!)
953*aca3beaaSApple OSS Distributions *
954*aca3beaaSApple OSS Distributions * Notes: The returned kauth_filesec_t is in host byte order
955*aca3beaaSApple OSS Distributions *
956*aca3beaaSApple OSS Distributions * The caller is responsible for freeing the returned
957*aca3beaaSApple OSS Distributions * kauth_filesec_t in the success case using the function
958*aca3beaaSApple OSS Distributions * kauth_filesec_free()
959*aca3beaaSApple OSS Distributions *
960*aca3beaaSApple OSS Distributions * Our largest initial guess is 32; this needs to move to
961*aca3beaaSApple OSS Distributions * a manifest constant in <sys/kauth.h>.
962*aca3beaaSApple OSS Distributions */
963*aca3beaaSApple OSS Distributions int
kauth_copyinfilesec(user_addr_t xsecurity,kauth_filesec_t * xsecdestpp)964*aca3beaaSApple OSS Distributions kauth_copyinfilesec(user_addr_t xsecurity, kauth_filesec_t *xsecdestpp)
965*aca3beaaSApple OSS Distributions {
966*aca3beaaSApple OSS Distributions int error;
967*aca3beaaSApple OSS Distributions kauth_filesec_t fsec;
968*aca3beaaSApple OSS Distributions size_t count;
969*aca3beaaSApple OSS Distributions size_t copysize;
970*aca3beaaSApple OSS Distributions
971*aca3beaaSApple OSS Distributions error = 0;
972*aca3beaaSApple OSS Distributions fsec = NULL;
973*aca3beaaSApple OSS Distributions
974*aca3beaaSApple OSS Distributions /*
975*aca3beaaSApple OSS Distributions * Make a guess at the size of the filesec. We start with the base
976*aca3beaaSApple OSS Distributions * pointer, and look at how much room is left on the page, clipped
977*aca3beaaSApple OSS Distributions * to a sensible upper bound. If it turns out this isn't enough,
978*aca3beaaSApple OSS Distributions * we'll size based on the actual ACL contents and come back again.
979*aca3beaaSApple OSS Distributions *
980*aca3beaaSApple OSS Distributions * The upper bound must be less than KAUTH_ACL_MAX_ENTRIES. The
981*aca3beaaSApple OSS Distributions * value here is fairly arbitrary. It's ok to have a zero count.
982*aca3beaaSApple OSS Distributions *
983*aca3beaaSApple OSS Distributions * Because we're just using these values to make a guess about the
984*aca3beaaSApple OSS Distributions * number of entries, the actual address doesn't matter, only their
985*aca3beaaSApple OSS Distributions * relative offsets into the page. We take advantage of this to
986*aca3beaaSApple OSS Distributions * avoid an overflow in the rounding step (this is a user-provided
987*aca3beaaSApple OSS Distributions * parameter, so caution pays off).
988*aca3beaaSApple OSS Distributions */
989*aca3beaaSApple OSS Distributions {
990*aca3beaaSApple OSS Distributions user_addr_t known_bound = (xsecurity & PAGE_MASK) + KAUTH_FILESEC_SIZE(0);
991*aca3beaaSApple OSS Distributions user_addr_t uaddr = (user_addr_t)mach_vm_round_page(known_bound);
992*aca3beaaSApple OSS Distributions count = (uaddr - known_bound) / sizeof(struct kauth_ace);
993*aca3beaaSApple OSS Distributions }
994*aca3beaaSApple OSS Distributions if (count > 32) {
995*aca3beaaSApple OSS Distributions count = 32;
996*aca3beaaSApple OSS Distributions }
997*aca3beaaSApple OSS Distributions restart:
998*aca3beaaSApple OSS Distributions if ((fsec = kauth_filesec_alloc((int)count)) == NULL) {
999*aca3beaaSApple OSS Distributions error = ENOMEM;
1000*aca3beaaSApple OSS Distributions goto out;
1001*aca3beaaSApple OSS Distributions }
1002*aca3beaaSApple OSS Distributions copysize = KAUTH_FILESEC_SIZE(count);
1003*aca3beaaSApple OSS Distributions if ((error = copyin(xsecurity, (caddr_t)fsec, copysize)) != 0) {
1004*aca3beaaSApple OSS Distributions goto out;
1005*aca3beaaSApple OSS Distributions }
1006*aca3beaaSApple OSS Distributions
1007*aca3beaaSApple OSS Distributions /* validate the filesec header */
1008*aca3beaaSApple OSS Distributions if (fsec->fsec_magic != KAUTH_FILESEC_MAGIC) {
1009*aca3beaaSApple OSS Distributions error = EINVAL;
1010*aca3beaaSApple OSS Distributions goto out;
1011*aca3beaaSApple OSS Distributions }
1012*aca3beaaSApple OSS Distributions
1013*aca3beaaSApple OSS Distributions /*
1014*aca3beaaSApple OSS Distributions * Is there an ACL payload, and is it too big?
1015*aca3beaaSApple OSS Distributions */
1016*aca3beaaSApple OSS Distributions if ((fsec->fsec_entrycount != KAUTH_FILESEC_NOACL) &&
1017*aca3beaaSApple OSS Distributions (fsec->fsec_entrycount > count)) {
1018*aca3beaaSApple OSS Distributions if (fsec->fsec_entrycount > KAUTH_ACL_MAX_ENTRIES) {
1019*aca3beaaSApple OSS Distributions /* XXX This should be E2BIG */
1020*aca3beaaSApple OSS Distributions error = EINVAL;
1021*aca3beaaSApple OSS Distributions goto out;
1022*aca3beaaSApple OSS Distributions }
1023*aca3beaaSApple OSS Distributions count = fsec->fsec_entrycount;
1024*aca3beaaSApple OSS Distributions kauth_filesec_free(fsec);
1025*aca3beaaSApple OSS Distributions goto restart;
1026*aca3beaaSApple OSS Distributions }
1027*aca3beaaSApple OSS Distributions
1028*aca3beaaSApple OSS Distributions out:
1029*aca3beaaSApple OSS Distributions if (error) {
1030*aca3beaaSApple OSS Distributions if (fsec) {
1031*aca3beaaSApple OSS Distributions kauth_filesec_free(fsec);
1032*aca3beaaSApple OSS Distributions }
1033*aca3beaaSApple OSS Distributions } else {
1034*aca3beaaSApple OSS Distributions *xsecdestpp = fsec;
1035*aca3beaaSApple OSS Distributions AUDIT_ARG(opaque, fsec, copysize);
1036*aca3beaaSApple OSS Distributions }
1037*aca3beaaSApple OSS Distributions return error;
1038*aca3beaaSApple OSS Distributions }
1039*aca3beaaSApple OSS Distributions
1040*aca3beaaSApple OSS Distributions /*
1041*aca3beaaSApple OSS Distributions * Allocate a block of memory containing a filesec structure, immediately
1042*aca3beaaSApple OSS Distributions * followed by 'count' kauth_ace structures.
1043*aca3beaaSApple OSS Distributions *
1044*aca3beaaSApple OSS Distributions * Parameters: count Number of kauth_ace structures needed
1045*aca3beaaSApple OSS Distributions *
1046*aca3beaaSApple OSS Distributions * Returns: !NULL A pointer to the allocated block
1047*aca3beaaSApple OSS Distributions * NULL Invalid 'count' or insufficient memory
1048*aca3beaaSApple OSS Distributions *
1049*aca3beaaSApple OSS Distributions * Notes: Returned memory area assumes that the structures are packed
1050*aca3beaaSApple OSS Distributions * densely, so this function may only be used by code that also
1051*aca3beaaSApple OSS Distributions * assumes no padding following structures.
1052*aca3beaaSApple OSS Distributions *
1053*aca3beaaSApple OSS Distributions * The returned structure must be freed by the caller using the
1054*aca3beaaSApple OSS Distributions * function kauth_filesec_free(), in case we decide to use an
1055*aca3beaaSApple OSS Distributions * allocation mechanism that is aware of the object size at some
1056*aca3beaaSApple OSS Distributions * point, since the object size is only available by introspecting
1057*aca3beaaSApple OSS Distributions * the object itself.
1058*aca3beaaSApple OSS Distributions */
1059*aca3beaaSApple OSS Distributions kauth_filesec_t
kauth_filesec_alloc(int count)1060*aca3beaaSApple OSS Distributions kauth_filesec_alloc(int count)
1061*aca3beaaSApple OSS Distributions {
1062*aca3beaaSApple OSS Distributions kauth_filesec_t fsp;
1063*aca3beaaSApple OSS Distributions
1064*aca3beaaSApple OSS Distributions /* if the caller hasn't given us a valid size hint, assume the worst */
1065*aca3beaaSApple OSS Distributions if ((count < 0) || (count > KAUTH_ACL_MAX_ENTRIES)) {
1066*aca3beaaSApple OSS Distributions return NULL;
1067*aca3beaaSApple OSS Distributions }
1068*aca3beaaSApple OSS Distributions
1069*aca3beaaSApple OSS Distributions fsp = kalloc_data(KAUTH_FILESEC_SIZE(count), Z_WAITOK);
1070*aca3beaaSApple OSS Distributions if (fsp != NULL) {
1071*aca3beaaSApple OSS Distributions fsp->fsec_magic = KAUTH_FILESEC_MAGIC;
1072*aca3beaaSApple OSS Distributions fsp->fsec_owner = kauth_null_guid;
1073*aca3beaaSApple OSS Distributions fsp->fsec_group = kauth_null_guid;
1074*aca3beaaSApple OSS Distributions fsp->fsec_entrycount = KAUTH_FILESEC_NOACL;
1075*aca3beaaSApple OSS Distributions fsp->fsec_flags = 0;
1076*aca3beaaSApple OSS Distributions }
1077*aca3beaaSApple OSS Distributions return fsp;
1078*aca3beaaSApple OSS Distributions }
1079*aca3beaaSApple OSS Distributions
1080*aca3beaaSApple OSS Distributions /*
1081*aca3beaaSApple OSS Distributions * Free a kauth_filesec_t that was previous allocated, either by a direct
1082*aca3beaaSApple OSS Distributions * call to kauth_filesec_alloc() or by calling a function that calls it.
1083*aca3beaaSApple OSS Distributions *
1084*aca3beaaSApple OSS Distributions * Parameters: fsp kauth_filesec_t to free
1085*aca3beaaSApple OSS Distributions *
1086*aca3beaaSApple OSS Distributions * Returns: (void)
1087*aca3beaaSApple OSS Distributions *
1088*aca3beaaSApple OSS Distributions * Notes: The kauth_filesec_t to be freed is assumed to be in host
1089*aca3beaaSApple OSS Distributions * byte order so that this function can introspect it in the
1090*aca3beaaSApple OSS Distributions * future to determine its size, if necesssary.
1091*aca3beaaSApple OSS Distributions */
1092*aca3beaaSApple OSS Distributions void
kauth_filesec_free(kauth_filesec_t fsp)1093*aca3beaaSApple OSS Distributions kauth_filesec_free(kauth_filesec_t fsp)
1094*aca3beaaSApple OSS Distributions {
1095*aca3beaaSApple OSS Distributions #ifdef KAUTH_DEBUG_ENABLE
1096*aca3beaaSApple OSS Distributions if (fsp == KAUTH_FILESEC_NONE) {
1097*aca3beaaSApple OSS Distributions panic("freeing KAUTH_FILESEC_NONE");
1098*aca3beaaSApple OSS Distributions }
1099*aca3beaaSApple OSS Distributions if (fsp == KAUTH_FILESEC_WANTED) {
1100*aca3beaaSApple OSS Distributions panic("freeing KAUTH_FILESEC_WANTED");
1101*aca3beaaSApple OSS Distributions }
1102*aca3beaaSApple OSS Distributions #endif
1103*aca3beaaSApple OSS Distributions kfree_data_addr(fsp);
1104*aca3beaaSApple OSS Distributions }
1105*aca3beaaSApple OSS Distributions
1106*aca3beaaSApple OSS Distributions /*
1107*aca3beaaSApple OSS Distributions * Set the endianness of a filesec and an ACL; if 'acl' is NULL, use the
1108*aca3beaaSApple OSS Distributions * ACL interior to 'fsec' instead. If the endianness doesn't change, then
1109*aca3beaaSApple OSS Distributions * this function will have no effect.
1110*aca3beaaSApple OSS Distributions *
1111*aca3beaaSApple OSS Distributions * Parameters: kendian The endianness to set; this is either
1112*aca3beaaSApple OSS Distributions * KAUTH_ENDIAN_HOST or KAUTH_ENDIAN_DISK.
1113*aca3beaaSApple OSS Distributions * fsec The filesec to convert.
1114*aca3beaaSApple OSS Distributions * acl The ACL to convert (optional)
1115*aca3beaaSApple OSS Distributions *
1116*aca3beaaSApple OSS Distributions * Returns: (void)
1117*aca3beaaSApple OSS Distributions *
1118*aca3beaaSApple OSS Distributions * Notes: We use ntohl() because it has a transitive property on Intel
1119*aca3beaaSApple OSS Distributions * machines and no effect on PPC mancines. This guarantees us
1120*aca3beaaSApple OSS Distributions * that the swapping only occurs if the endiannes is wrong.
1121*aca3beaaSApple OSS Distributions */
1122*aca3beaaSApple OSS Distributions void
kauth_filesec_acl_setendian(int kendian,kauth_filesec_t fsec,kauth_acl_t acl)1123*aca3beaaSApple OSS Distributions kauth_filesec_acl_setendian(int kendian, kauth_filesec_t fsec, kauth_acl_t acl)
1124*aca3beaaSApple OSS Distributions {
1125*aca3beaaSApple OSS Distributions uint32_t compare_magic = KAUTH_FILESEC_MAGIC;
1126*aca3beaaSApple OSS Distributions uint32_t invert_magic = ntohl(KAUTH_FILESEC_MAGIC);
1127*aca3beaaSApple OSS Distributions uint32_t compare_acl_entrycount;
1128*aca3beaaSApple OSS Distributions uint32_t i;
1129*aca3beaaSApple OSS Distributions
1130*aca3beaaSApple OSS Distributions if (compare_magic == invert_magic) {
1131*aca3beaaSApple OSS Distributions return;
1132*aca3beaaSApple OSS Distributions }
1133*aca3beaaSApple OSS Distributions
1134*aca3beaaSApple OSS Distributions /* If no ACL, use ACL interior to 'fsec' instead */
1135*aca3beaaSApple OSS Distributions if (acl == NULL) {
1136*aca3beaaSApple OSS Distributions acl = &fsec->fsec_acl;
1137*aca3beaaSApple OSS Distributions }
1138*aca3beaaSApple OSS Distributions
1139*aca3beaaSApple OSS Distributions compare_acl_entrycount = acl->acl_entrycount;
1140*aca3beaaSApple OSS Distributions
1141*aca3beaaSApple OSS Distributions /*
1142*aca3beaaSApple OSS Distributions * Only convert what needs to be converted, and only if the arguments
1143*aca3beaaSApple OSS Distributions * are valid. The following switch and tests effectively reject
1144*aca3beaaSApple OSS Distributions * conversions on invalid magic numbers as a desirable side effect.
1145*aca3beaaSApple OSS Distributions */
1146*aca3beaaSApple OSS Distributions switch (kendian) {
1147*aca3beaaSApple OSS Distributions case KAUTH_ENDIAN_HOST: /* not in host, convert to host */
1148*aca3beaaSApple OSS Distributions if (fsec->fsec_magic != invert_magic) {
1149*aca3beaaSApple OSS Distributions return;
1150*aca3beaaSApple OSS Distributions }
1151*aca3beaaSApple OSS Distributions /* acl_entrycount is byteswapped */
1152*aca3beaaSApple OSS Distributions compare_acl_entrycount = ntohl(acl->acl_entrycount);
1153*aca3beaaSApple OSS Distributions break;
1154*aca3beaaSApple OSS Distributions case KAUTH_ENDIAN_DISK: /* not in disk, convert to disk */
1155*aca3beaaSApple OSS Distributions if (fsec->fsec_magic != compare_magic) {
1156*aca3beaaSApple OSS Distributions return;
1157*aca3beaaSApple OSS Distributions }
1158*aca3beaaSApple OSS Distributions break;
1159*aca3beaaSApple OSS Distributions default: /* bad argument */
1160*aca3beaaSApple OSS Distributions return;
1161*aca3beaaSApple OSS Distributions }
1162*aca3beaaSApple OSS Distributions
1163*aca3beaaSApple OSS Distributions /* We are go for conversion */
1164*aca3beaaSApple OSS Distributions fsec->fsec_magic = ntohl(fsec->fsec_magic);
1165*aca3beaaSApple OSS Distributions acl->acl_entrycount = ntohl(acl->acl_entrycount);
1166*aca3beaaSApple OSS Distributions if (compare_acl_entrycount != KAUTH_FILESEC_NOACL) {
1167*aca3beaaSApple OSS Distributions acl->acl_flags = ntohl(acl->acl_flags);
1168*aca3beaaSApple OSS Distributions
1169*aca3beaaSApple OSS Distributions /* swap ACE rights and flags */
1170*aca3beaaSApple OSS Distributions for (i = 0; i < compare_acl_entrycount; i++) {
1171*aca3beaaSApple OSS Distributions acl->acl_ace[i].ace_flags = ntohl(acl->acl_ace[i].ace_flags);
1172*aca3beaaSApple OSS Distributions acl->acl_ace[i].ace_rights = ntohl(acl->acl_ace[i].ace_rights);
1173*aca3beaaSApple OSS Distributions }
1174*aca3beaaSApple OSS Distributions }
1175*aca3beaaSApple OSS Distributions }
1176*aca3beaaSApple OSS Distributions
1177*aca3beaaSApple OSS Distributions /*
1178*aca3beaaSApple OSS Distributions * Allocate an ACL buffer.
1179*aca3beaaSApple OSS Distributions */
1180*aca3beaaSApple OSS Distributions kauth_acl_t
kauth_acl_alloc(int count)1181*aca3beaaSApple OSS Distributions kauth_acl_alloc(int count)
1182*aca3beaaSApple OSS Distributions {
1183*aca3beaaSApple OSS Distributions /* if the caller hasn't given us a valid size hint, assume the worst */
1184*aca3beaaSApple OSS Distributions if ((count < 0) || (count > KAUTH_ACL_MAX_ENTRIES)) {
1185*aca3beaaSApple OSS Distributions return NULL;
1186*aca3beaaSApple OSS Distributions }
1187*aca3beaaSApple OSS Distributions
1188*aca3beaaSApple OSS Distributions return kalloc_data(KAUTH_ACL_SIZE(count), Z_WAITOK | Z_ZERO);
1189*aca3beaaSApple OSS Distributions }
1190*aca3beaaSApple OSS Distributions
1191*aca3beaaSApple OSS Distributions void
kauth_acl_free(kauth_acl_t aclp)1192*aca3beaaSApple OSS Distributions kauth_acl_free(kauth_acl_t aclp)
1193*aca3beaaSApple OSS Distributions {
1194*aca3beaaSApple OSS Distributions kfree_data_addr(aclp);
1195*aca3beaaSApple OSS Distributions }
1196*aca3beaaSApple OSS Distributions
1197*aca3beaaSApple OSS Distributions
1198*aca3beaaSApple OSS Distributions /*
1199*aca3beaaSApple OSS Distributions * WARNING - caller must hold KAUTH_SCOPELOCK
1200*aca3beaaSApple OSS Distributions */
1201*aca3beaaSApple OSS Distributions static int
kauth_add_callback_to_scope(kauth_scope_t sp,kauth_listener_t klp)1202*aca3beaaSApple OSS Distributions kauth_add_callback_to_scope(kauth_scope_t sp, kauth_listener_t klp)
1203*aca3beaaSApple OSS Distributions {
1204*aca3beaaSApple OSS Distributions int i;
1205*aca3beaaSApple OSS Distributions
1206*aca3beaaSApple OSS Distributions for (i = 0; i < KAUTH_SCOPE_MAX_LISTENERS; i++) {
1207*aca3beaaSApple OSS Distributions if (sp->ks_listeners[i].kll_listenerp == NULL) {
1208*aca3beaaSApple OSS Distributions sp->ks_listeners[i].kll_callback = klp->kl_callback;
1209*aca3beaaSApple OSS Distributions sp->ks_listeners[i].kll_idata = klp->kl_idata;
1210*aca3beaaSApple OSS Distributions sp->ks_listeners[i].kll_listenerp = klp;
1211*aca3beaaSApple OSS Distributions sp->ks_flags |= KS_F_HAS_LISTENERS;
1212*aca3beaaSApple OSS Distributions return 0;
1213*aca3beaaSApple OSS Distributions }
1214*aca3beaaSApple OSS Distributions }
1215*aca3beaaSApple OSS Distributions return ENOSPC;
1216*aca3beaaSApple OSS Distributions }
1217