xref: /netbsd-src/sys/kern/kern_auth.c (revision 282f07d64373248f1314ff2f3c4d8747d6f372e1)
1 /* $NetBSD: kern_auth.c,v 1.15 2006/07/26 17:13:26 elad Exp $ */
2 
3 /*-
4  * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Elad Efrat.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Todo:
35  *   - Garbage collection to pool_put() unused scopes/listeners.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/queue.h>
41 #include <sys/time.h>
42 #include <sys/proc.h>
43 #include <sys/ucred.h>
44 #include <sys/pool.h>
45 #include <sys/kauth.h>
46 #include <sys/acct.h>
47 #include <sys/sysctl.h>
48 
49 /*
50  * Credentials.
51  */
52 struct kauth_cred {
53 	struct simplelock cr_lock;	/* lock on cr_refcnt */
54 	u_int cr_refcnt;		/* reference count */
55 	uid_t cr_uid;			/* user id */
56 	uid_t cr_euid;			/* effective user id */
57 	uid_t cr_svuid;			/* saved effective user id */
58 	gid_t cr_gid;			/* group id */
59 	gid_t cr_egid;			/* effective group id */
60 	gid_t cr_svgid;			/* saved effective group id */
61 	u_int cr_ngroups;		/* number of groups */
62 	gid_t cr_groups[NGROUPS];	/* group memberships */
63 };
64 
65 /*
66  * Listener.
67  */
68 struct kauth_listener {
69 	kauth_scope_callback_t		func;		/* callback */
70 	kauth_scope_t			scope;		/* scope backpointer */
71 	u_int				refcnt;		/* reference count */
72 	SIMPLEQ_ENTRY(kauth_listener)	listener_next;	/* listener list */
73 };
74 
75 /*
76  * Scope.
77  */
78 struct kauth_scope {
79 	const char		       *id;		/* scope name */
80 	void			       *cookie;		/* user cookie */
81 	u_int				nlisteners;	/* # of listeners */
82 	SIMPLEQ_HEAD(, kauth_listener)	listenq;	/* listener list */
83 	SIMPLEQ_ENTRY(kauth_scope)	next_scope;	/* scope list */
84 };
85 
86 static POOL_INIT(kauth_scope_pool, sizeof(struct kauth_scope), 0, 0, 0,
87 	  "kauth_scopepl", &pool_allocator_nointr);
88 static POOL_INIT(kauth_listener_pool, sizeof(struct kauth_listener), 0, 0, 0,
89 	  "kauth_listenerpl", &pool_allocator_nointr);
90 static POOL_INIT(kauth_cred_pool, sizeof(struct kauth_cred), 0, 0, 0,
91 	  "kauth_credpl", &pool_allocator_nointr);
92 
93 /* List of scopes and its lock. */
94 static SIMPLEQ_HEAD(, kauth_scope) scope_list;
95 static struct simplelock scopes_lock;
96 
97 /* Built-in scopes: generic, process. */
98 static kauth_scope_t kauth_builtin_scope_generic;
99 static kauth_scope_t kauth_builtin_scope_process;
100 
101 /* Allocate new, empty kauth credentials. */
102 kauth_cred_t
103 kauth_cred_alloc(void)
104 {
105 	kauth_cred_t cred;
106 
107 	cred = pool_get(&kauth_cred_pool, PR_WAITOK);
108 	memset(cred, 0, sizeof(*cred));
109 	simple_lock_init(&cred->cr_lock);
110 	cred->cr_refcnt = 1;
111 
112 	return (cred);
113 }
114 
115 /* Increment reference count to cred. */
116 void
117 kauth_cred_hold(kauth_cred_t cred)
118 {
119 	KASSERT(cred != NULL);
120 	KASSERT(cred->cr_refcnt > 0);
121 
122         simple_lock(&cred->cr_lock);
123         cred->cr_refcnt++;
124         simple_unlock(&cred->cr_lock);
125 }
126 
127 /* Decrease reference count to cred. If reached zero, free it. */
128 void
129 kauth_cred_free(kauth_cred_t cred)
130 {
131 	u_int refcnt;
132 
133 	KASSERT(cred != NULL);
134 	KASSERT(cred->cr_refcnt > 0);
135 
136 	simple_lock(&cred->cr_lock);
137 	refcnt = --cred->cr_refcnt;
138 	simple_unlock(&cred->cr_lock);
139 
140 	if (refcnt == 0)
141 		pool_put(&kauth_cred_pool, cred);
142 }
143 
144 void
145 kauth_cred_clone(kauth_cred_t from, kauth_cred_t to)
146 {
147 	KASSERT(from != NULL);
148 	KASSERT(to != NULL);
149 	KASSERT(from->cr_refcnt > 0);
150 
151 	to->cr_uid = from->cr_uid;
152 	to->cr_euid = from->cr_euid;
153 	to->cr_svuid = from->cr_svuid;
154 	to->cr_gid = from->cr_gid;
155 	to->cr_egid = from->cr_egid;
156 	to->cr_svgid = from->cr_svgid;
157 	to->cr_ngroups = from->cr_ngroups;
158 	memcpy(to->cr_groups, from->cr_groups, sizeof(to->cr_groups));
159 }
160 
161 /*
162  * Duplicate cred and return a new kauth_cred_t.
163  */
164 kauth_cred_t
165 kauth_cred_dup(kauth_cred_t cred)
166 {
167 	kauth_cred_t new_cred;
168 
169 	KASSERT(cred != NULL);
170 	KASSERT(cred->cr_refcnt > 0);
171 
172 	new_cred = kauth_cred_alloc();
173 
174 	kauth_cred_clone(cred, new_cred);
175 
176 	return (new_cred);
177 }
178 
179 /*
180  * Similar to crcopy(), only on a kauth_cred_t.
181  * XXX: Is this even needed? [kauth_cred_copy]
182  */
183 kauth_cred_t
184 kauth_cred_copy(kauth_cred_t cred)
185 {
186 	kauth_cred_t new_cred;
187 
188 	KASSERT(cred != NULL);
189 	KASSERT(cred->cr_refcnt > 0);
190 
191 	/* If the provided credentials already have one reference, use them. */
192 	if (cred->cr_refcnt == 1)
193 		return (cred);
194 
195 	new_cred = kauth_cred_alloc();
196 
197 	kauth_cred_clone(cred, new_cred);
198 
199 	kauth_cred_free(cred);
200 
201 	return (new_cred);
202 }
203 
204 uid_t
205 kauth_cred_getuid(kauth_cred_t cred)
206 {
207 	KASSERT(cred != NULL);
208 
209 	return (cred->cr_uid);
210 }
211 
212 uid_t
213 kauth_cred_geteuid(kauth_cred_t cred)
214 {
215 	KASSERT(cred != NULL);
216 
217 	return (cred->cr_euid);
218 }
219 
220 uid_t
221 kauth_cred_getsvuid(kauth_cred_t cred)
222 {
223 	KASSERT(cred != NULL);
224 
225 	return (cred->cr_svuid);
226 }
227 
228 gid_t
229 kauth_cred_getgid(kauth_cred_t cred)
230 {
231 	KASSERT(cred != NULL);
232 
233 	return (cred->cr_gid);
234 }
235 
236 gid_t
237 kauth_cred_getegid(kauth_cred_t cred)
238 {
239 	KASSERT(cred != NULL);
240 
241 	return (cred->cr_egid);
242 }
243 
244 gid_t
245 kauth_cred_getsvgid(kauth_cred_t cred)
246 {
247 	KASSERT(cred != NULL);
248 
249 	return (cred->cr_svgid);
250 }
251 
252 void
253 kauth_cred_setuid(kauth_cred_t cred, uid_t uid)
254 {
255 	KASSERT(cred != NULL);
256 	KASSERT(cred->cr_refcnt == 1);
257 
258 	cred->cr_uid = uid;
259 }
260 
261 void
262 kauth_cred_seteuid(kauth_cred_t cred, uid_t uid)
263 {
264 	KASSERT(cred != NULL);
265 	KASSERT(cred->cr_refcnt == 1);
266 
267 	cred->cr_euid = uid;
268 }
269 
270 void
271 kauth_cred_setsvuid(kauth_cred_t cred, uid_t uid)
272 {
273 	KASSERT(cred != NULL);
274 	KASSERT(cred->cr_refcnt == 1);
275 
276 	cred->cr_svuid = uid;
277 }
278 
279 void
280 kauth_cred_setgid(kauth_cred_t cred, gid_t gid)
281 {
282 	KASSERT(cred != NULL);
283 	KASSERT(cred->cr_refcnt == 1);
284 
285 	cred->cr_gid = gid;
286 }
287 
288 void
289 kauth_cred_setegid(kauth_cred_t cred, gid_t gid)
290 {
291 	KASSERT(cred != NULL);
292 	KASSERT(cred->cr_refcnt == 1);
293 
294 	cred->cr_egid = gid;
295 }
296 
297 void
298 kauth_cred_setsvgid(kauth_cred_t cred, gid_t gid)
299 {
300 	KASSERT(cred != NULL);
301 	KASSERT(cred->cr_refcnt == 1);
302 
303 	cred->cr_svgid = gid;
304 }
305 
306 /* Checks if gid is a member of the groups in cred. */
307 int
308 kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp)
309 {
310 	int i;
311 
312 	KASSERT(cred != NULL);
313 	KASSERT(resultp != NULL);
314 
315 	*resultp = 0;
316 
317 	for (i = 0; i < cred->cr_ngroups; i++)
318 		if (cred->cr_groups[i] == gid) {
319 			*resultp = 1;
320 			break;
321 		}
322 
323 	return (0);
324 }
325 
326 u_int
327 kauth_cred_ngroups(kauth_cred_t cred)
328 {
329 	KASSERT(cred != NULL);
330 
331 	return (cred->cr_ngroups);
332 }
333 
334 /*
335  * Return the group at index idx from the groups in cred.
336  */
337 gid_t
338 kauth_cred_group(kauth_cred_t cred, u_int idx)
339 {
340 	KASSERT(cred != NULL);
341 	KASSERT(idx < cred->cr_ngroups);
342 
343 	return (cred->cr_groups[idx]);
344 }
345 
346 /* XXX elad: gmuid is unused for now. */
347 int
348 kauth_cred_setgroups(kauth_cred_t cred, gid_t *grbuf, size_t len, uid_t gmuid)
349 {
350 	KASSERT(cred != NULL);
351 	KASSERT(cred->cr_refcnt == 1);
352 	KASSERT(len <= sizeof(cred->cr_groups) / sizeof(cred->cr_groups[0]));
353 
354 	if (len)
355 		memcpy(cred->cr_groups, grbuf, len * sizeof(cred->cr_groups[0]));
356 	memset(cred->cr_groups + len, 0xff,
357 	    sizeof(cred->cr_groups) - (len * sizeof(cred->cr_groups[0])));
358 
359 	cred->cr_ngroups = len;
360 
361 	return (0);
362 }
363 
364 int
365 kauth_cred_getgroups(kauth_cred_t cred, gid_t *grbuf, size_t len)
366 {
367 	KASSERT(cred != NULL);
368 	KASSERT(len <= cred->cr_ngroups);
369 
370 	memset(grbuf, 0xff, sizeof(*grbuf) * len);
371 	memcpy(grbuf, cred->cr_groups, sizeof(*grbuf) * len);
372 
373 	return (0);
374 }
375 
376 /*
377  * Match uids in two credentials. Checks if cred1 can access stuff owned by
378  * cred2.
379  * XXX: root bypasses this!
380  */
381 static int
382 kauth_cred_uidmatch(kauth_cred_t cred1, kauth_cred_t cred2)
383 {
384 	KASSERT(cred1 != NULL);
385 	KASSERT(cred2 != NULL);
386 
387 	/* Are we root? */
388 	if (cred1->cr_euid == 0)
389 		return (1);
390 
391 	if (cred1->cr_uid == cred2->cr_uid ||
392 	    cred1->cr_euid == cred2->cr_uid ||
393 	    cred1->cr_uid == cred2->cr_euid ||
394 	    cred1->cr_euid == cred2->cr_euid)
395 		return (1);
396 
397 	return (0);
398 }
399 
400 u_int
401 kauth_cred_getrefcnt(kauth_cred_t cred)
402 {
403 	KASSERT(cred != NULL);
404 
405 	return (cred->cr_refcnt);
406 }
407 
408 /*
409  * Convert userland credentials (struct uucred) to kauth_cred_t.
410  * XXX: For NFS code.
411  */
412 void
413 kauth_cred_uucvt(kauth_cred_t cred, const struct uucred *uuc)
414 {
415 	KASSERT(cred != NULL);
416 	KASSERT(uuc != NULL);
417 
418 	cred->cr_refcnt = 1;
419 	cred->cr_uid = uuc->cr_uid;
420 	cred->cr_euid = uuc->cr_uid;
421 	cred->cr_svuid = uuc->cr_uid;
422 	cred->cr_gid = uuc->cr_gid;
423 	cred->cr_egid = uuc->cr_gid;
424 	cred->cr_svgid = uuc->cr_gid;
425 	cred->cr_ngroups = min(uuc->cr_ngroups, NGROUPS);
426 	kauth_cred_setgroups(cred, __UNCONST(uuc->cr_groups),
427 	    cred->cr_ngroups, -1);
428 }
429 
430 /*
431  * Compare kauth_cred_t and uucred credentials.
432  * XXX: Modelled after crcmp() for NFS.
433  */
434 int
435 kauth_cred_uucmp(kauth_cred_t cred, const struct uucred *uuc)
436 {
437 	KASSERT(cred != NULL);
438 	KASSERT(uuc != NULL);
439 
440 	if (cred->cr_euid == uuc->cr_uid &&
441 	    cred->cr_egid == uuc->cr_gid &&
442 	    cred->cr_ngroups == uuc->cr_ngroups) {
443 		int i;
444 
445 		/* Check if all groups from uuc appear in cred. */
446 		for (i = 0; i < uuc->cr_ngroups; i++) {
447 			int ismember;
448 
449 			ismember = 0;
450 			if (kauth_cred_ismember_gid(cred, uuc->cr_groups[i],
451 			    &ismember) != 0 || !ismember)
452 				return (1);
453 		}
454 
455 		return (0);
456 	}
457 
458 	return (1);
459 }
460 
461 /*
462  * Make a struct ucred out of a kauth_cred_t.  For compatibility.
463  */
464 void
465 kauth_cred_toucred(kauth_cred_t cred, struct ucred *uc)
466 {
467 	KASSERT(cred != NULL);
468 	KASSERT(uc != NULL);
469 
470 	uc->cr_ref = cred->cr_refcnt;
471 	uc->cr_uid = cred->cr_euid;
472 	uc->cr_gid = cred->cr_egid;
473 	uc->cr_ngroups = min(cred->cr_ngroups,
474 			     sizeof(uc->cr_groups) / sizeof(uc->cr_groups[0]));
475 	memcpy(uc->cr_groups, cred->cr_groups,
476 	       uc->cr_ngroups * sizeof(uc->cr_groups[0]));
477 }
478 
479 /*
480  * Make a struct pcred out of a kauth_cred_t.  For compatibility.
481  */
482 void
483 kauth_cred_topcred(kauth_cred_t cred, struct pcred *pc)
484 {
485 	KASSERT(cred != NULL);
486 	KASSERT(pc != NULL);
487 
488 	pc->pc_ucred = NULL;
489 	pc->p_ruid = cred->cr_uid;
490 	pc->p_svuid = cred->cr_svuid;
491 	pc->p_rgid = cred->cr_gid;
492 	pc->p_svgid = cred->cr_svgid;
493 	pc->p_refcnt = cred->cr_refcnt;
494 }
495 
496 /*
497  * Return kauth_cred_t for the current LWP.
498  */
499 kauth_cred_t
500 kauth_cred_get(void)
501 {
502 	return (curlwp->l_cred);
503 }
504 
505 /*
506  * Returns a scope matching the provided id.
507  * Requires the scope list lock to be held by the caller.
508  */
509 static kauth_scope_t
510 kauth_ifindscope(const char *id)
511 {
512 	kauth_scope_t scope;
513 
514 	/* XXX: assert lock on scope list? */
515 
516 	scope = NULL;
517 	SIMPLEQ_FOREACH(scope, &scope_list, next_scope) {
518 		if (strcmp(scope->id, id) == 0)
519 			break;
520 	}
521 
522 	return (scope);
523 }
524 
525 /*
526  * Register a new scope.
527  *
528  * id - identifier for the scope
529  * callback - the scope's default listener
530  * cookie - cookie to be passed to the listener(s)
531  */
532 kauth_scope_t
533 kauth_register_scope(const char *id, kauth_scope_callback_t callback,
534 		     void *cookie)
535 {
536 	kauth_scope_t scope;
537 	kauth_listener_t listener;
538 
539 	/* Sanitize input */
540 	if (id == NULL || callback == NULL)
541 		return (NULL);
542 
543 	/* Allocate space for a new scope and listener. */
544 	scope = pool_get(&kauth_scope_pool, PR_WAITOK);
545 	listener = pool_get(&kauth_listener_pool, PR_WAITOK);
546 
547 	/* Acquire scope list lock. */
548 	simple_lock(&scopes_lock);
549 
550 	/* Check we don't already have a scope with the same id */
551 	if (kauth_ifindscope(id) != NULL) {
552 		simple_unlock(&scopes_lock);
553 
554 		pool_put(&kauth_scope_pool, scope);
555 		pool_put(&kauth_listener_pool, listener);
556 
557 		return (NULL);
558 	}
559 
560 	/* Initialize new scope with parameters */
561 	scope->id = id;
562 	scope->cookie = cookie;
563 	scope->nlisteners = 1;
564 
565 	/* Add default listener */
566 	listener->func = callback;
567 	listener->scope = scope;
568 	listener->refcnt = 0;
569 	SIMPLEQ_INIT(&scope->listenq);
570 	SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next);
571 
572 	/* Insert scope to scopes list */
573 	if (SIMPLEQ_EMPTY(&scope_list))
574 		SIMPLEQ_INSERT_HEAD(&scope_list, scope, next_scope);
575 	else
576 		SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope);
577 
578 	simple_unlock(&scopes_lock);
579 
580 	return (scope);
581 }
582 
583 /*
584  * Initialize the kernel authorization subsystem.
585  *
586  * Initialize the scopes list lock.
587  * Register built-in scopes: generic, process.
588  */
589 void
590 kauth_init(void)
591 {
592 	simple_lock_init(&scopes_lock);
593 
594 	/* Register generic scope. */
595 	kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC,
596 	    kauth_authorize_cb_generic, NULL);
597 
598 	/* Register process scope. */
599 	kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS,
600 	    kauth_authorize_cb_process, NULL);
601 }
602 
603 /*
604  * Deregister a scope.
605  * Requires scope list lock to be held by the caller.
606  *
607  * scope - the scope to deregister
608  */
609 void
610 kauth_deregister_scope(kauth_scope_t scope)
611 {
612 	if (scope != NULL) {
613 		/* Remove scope from list */
614 		SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope);
615 	}
616 }
617 
618 /*
619  * Register a listener.
620  *
621  * id - scope identifier.
622  * callback - the callback routine for the listener.
623  * cookie - cookie to pass unmoidfied to the callback.
624  */
625 kauth_listener_t
626 kauth_listen_scope(const char *id, kauth_scope_callback_t callback,
627 		   void *cookie)
628 {
629 	kauth_scope_t scope;
630 	kauth_listener_t listener;
631 
632 	/* Find scope struct */
633 	simple_lock(&scopes_lock);
634 	scope = kauth_ifindscope(id);
635 	simple_unlock(&scopes_lock);
636 	if (scope == NULL)
637 		return (NULL);
638 
639 	/* Allocate listener */
640 	listener = pool_get(&kauth_listener_pool, PR_WAITOK);
641 
642 	/* Initialize listener with parameters */
643 	listener->func = callback;
644 	listener->refcnt = 0;
645 
646 	/* Add listener to scope */
647 	SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next);
648 
649 	/* Raise number of listeners on scope. */
650 	scope->nlisteners++;
651 	listener->scope = scope;
652 
653 	return (listener);
654 }
655 
656 /*
657  * Deregister a listener.
658  *
659  * listener - listener reference as returned from kauth_listen_scope().
660  */
661 void
662 kauth_unlisten_scope(kauth_listener_t listener)
663 {
664 	if (listener != NULL) {
665 		SIMPLEQ_REMOVE(&listener->scope->listenq, listener,
666 		    kauth_listener, listener_next);
667 		listener->scope->nlisteners--;
668 	}
669 }
670 
671 /*
672  * Authorize a request.
673  *
674  * scope - the scope of the request as defined by KAUTH_SCOPE_* or as
675  *	   returned from kauth_register_scope().
676  * credential - credentials of the user ("actor") making the request.
677  * action - request identifier.
678  * arg[0-3] - passed unmodified to listener(s).
679  */
680 int
681 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred,
682 		       kauth_action_t action, void *arg0, void *arg1,
683 		       void *arg2, void *arg3)
684 {
685 	kauth_listener_t listener;
686 	int error, allow, fail;
687 
688 #if 0 /* defined(LOCKDEBUG) */
689 	spinlock_switchcheck();
690 	simple_lock_only_held(NULL, "kauth_authorize_action");
691 #endif
692 
693 	/* Sanitize input */
694 	if (scope == NULL || cred == NULL)
695 		return (EFAULT);
696 	if (!action)
697 		return (EINVAL);
698 
699 	/*
700 	 * Each scope is associated with at least one listener. We need to
701 	 * traverse that list of listeners, as long as they return either
702 	 * KAUTH_REQUEST_DEFER or KAUTH_REQUEST_ALLOW.
703 	 */
704 	fail = 0;
705 	allow = 0;
706 	SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) {
707 		error = listener->func(cred, action, scope->cookie, arg0,
708 				       arg1, arg2, arg3);
709 
710 		if (error == KAUTH_RESULT_ALLOW)
711 			allow = 1;
712 		else if (error == KAUTH_RESULT_DENY)
713 			fail = 1;
714 	}
715 
716 	return ((allow && !fail) ? 0 : EPERM);
717 };
718 
719 /*
720  * Generic scope default callback.
721  */
722 int
723 kauth_authorize_cb_generic(kauth_cred_t cred, kauth_action_t action,
724 			   void *cookie, void *arg0, void *arg1, void *arg2,
725 			   void *arg3)
726 {
727 	int error;
728 
729 	error = KAUTH_RESULT_DEFER;
730 
731 	switch (action) {
732 	case KAUTH_GENERIC_ISSUSER:
733 		/* Check if credential belongs to superuser. */
734 		if (cred->cr_euid == 0) {
735 			u_short *acflag = (u_short *)arg0;
736 
737 			if (acflag != NULL)
738 				*acflag |= ASU;
739 
740 			error = KAUTH_RESULT_ALLOW;
741 		} else
742 			error = KAUTH_RESULT_DENY;
743 		break;
744 
745 	case KAUTH_GENERIC_CANSEE:
746 		if (!security_curtain) {
747 			error = KAUTH_RESULT_ALLOW;
748 		} else {
749 			kauth_cred_t cred2 = arg0;
750 
751 			if (kauth_cred_uidmatch(cred, cred2))
752 				error = KAUTH_RESULT_ALLOW;
753 			else
754 				error = KAUTH_RESULT_DENY;
755 		}
756 		break;
757 	}
758 
759 	return (error);
760 }
761 
762 /*
763  * Generic scope authorization wrapper.
764  */
765 int
766 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0)
767 {
768 	return (kauth_authorize_action(kauth_builtin_scope_generic, cred,
769 	    action, arg0, NULL, NULL, NULL));
770 }
771 
772 /*
773  * Process scope default callback.
774  */
775 int
776 kauth_authorize_cb_process(kauth_cred_t cred, kauth_action_t action,
777 			   void *cookie, void *arg0, void *arg1, void *arg2,
778 			   void *arg3)
779 {
780 	struct proc *p;
781 	int error;
782 
783 	error = KAUTH_RESULT_DEFER;
784 
785 	p = arg0;
786 
787 	switch (action) {
788 	case KAUTH_PROCESS_CANSIGNAL: {
789 		int signum;
790 
791 		signum = (int)(unsigned long)arg1;
792 
793 		if (kauth_cred_uidmatch(cred, p->p_cred) ||
794 		    (signum == SIGCONT && (curproc->p_session == p->p_session)))
795 			error = KAUTH_RESULT_ALLOW;
796 		else
797 			error = KAUTH_RESULT_DEFER;
798 		break;
799 		}
800 
801 	case KAUTH_PROCESS_CANPTRACE:
802 		if (kauth_cred_uidmatch(cred, p->p_cred))
803 			error = KAUTH_RESULT_ALLOW;
804 		else
805 			error = KAUTH_RESULT_DENY;
806 		break;
807 
808 	case KAUTH_PROCESS_CANSEE:
809 		if (!security_curtain) {
810 			error = KAUTH_RESULT_ALLOW;
811 		} else {
812 			if (kauth_cred_uidmatch(cred, p->p_cred))
813 				error = KAUTH_RESULT_ALLOW;
814 			else
815 				error = KAUTH_RESULT_DENY;
816 				/* arg2 - type of information [XXX NOTIMPL] */
817 		}
818 		break;
819 	}
820 
821 	return (error);
822 }
823 
824 /*
825  * Process scope authorization wrapper.
826  */
827 int
828 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action,
829     struct proc *p, void *arg1, void *arg2, void *arg3)
830 {
831 	return (kauth_authorize_action(kauth_builtin_scope_process, cred,
832 	    action, p, arg1, arg2, arg3));
833 }
834