1 /* $NetBSD: kern_auth.c,v 1.64 2009/09/03 04:45:27 elad Exp $ */
4 * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
31 * All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. The name of the author may not be used to endorse or promote products
42 * derived from this software without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
45 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
48 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
49 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
53 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 #include <sys/cdefs.h>
57 __KERNEL_RCSID(0, "$NetBSD: kern_auth.c,v 1.64 2009/09/03 04:45:27 elad Exp $");
59 #include <sys/types.h>
60 #include <sys/param.h>
61 #include <sys/queue.h>
63 #include <sys/ucred.h>
65 #include <sys/kauth.h>
67 #include <sys/rwlock.h>
68 #include <sys/sysctl.h>
69 #include <sys/atomic.h>
70 #include <sys/specificdata.h>
71 #include <sys/vnode.h>
74 * Secmodel-specific credentials.
77 const char *ks_secmodel
; /* secmodel */
78 specificdata_key_t ks_key
; /* key */
84 * A subset of this structure is used in kvm(3) (src/lib/libkvm/kvm_proc.c)
85 * and should be synchronized with this structure when the update is
90 * Ensure that the first part of the credential resides in its own
91 * cache line. Due to sharing there aren't many kauth_creds in a
92 * typical system, but the reference counts change very often.
93 * Keeping it seperate from the rest of the data prevents false
94 * sharing between CPUs.
96 u_int cr_refcnt
; /* reference count */
97 #if COHERENCY_UNIT > 4
98 uint8_t cr_pad
[COHERENCY_UNIT
- 4];
100 uid_t cr_uid
; /* user id */
101 uid_t cr_euid
; /* effective user id */
102 uid_t cr_svuid
; /* saved effective user id */
103 gid_t cr_gid
; /* group id */
104 gid_t cr_egid
; /* effective group id */
105 gid_t cr_svgid
; /* saved effective group id */
106 u_int cr_ngroups
; /* number of groups */
107 gid_t cr_groups
[NGROUPS
]; /* group memberships */
108 specificdata_reference cr_sd
; /* specific data */
114 struct kauth_listener
{
115 kauth_scope_callback_t func
; /* callback */
116 kauth_scope_t scope
; /* scope backpointer */
117 u_int refcnt
; /* reference count */
118 SIMPLEQ_ENTRY(kauth_listener
) listener_next
; /* listener list */
125 const char *id
; /* scope name */
126 void *cookie
; /* user cookie */
127 u_int nlisteners
; /* # of listeners */
128 SIMPLEQ_HEAD(, kauth_listener
) listenq
; /* listener list */
129 SIMPLEQ_ENTRY(kauth_scope
) next_scope
; /* scope list */
132 static int kauth_cred_hook(kauth_cred_t
, kauth_action_t
, void *, void *);
134 /* List of scopes and its lock. */
135 static SIMPLEQ_HEAD(, kauth_scope
) scope_list
=
136 SIMPLEQ_HEAD_INITIALIZER(scope_list
);
138 /* Built-in scopes: generic, process. */
139 static kauth_scope_t kauth_builtin_scope_generic
;
140 static kauth_scope_t kauth_builtin_scope_system
;
141 static kauth_scope_t kauth_builtin_scope_process
;
142 static kauth_scope_t kauth_builtin_scope_network
;
143 static kauth_scope_t kauth_builtin_scope_machdep
;
144 static kauth_scope_t kauth_builtin_scope_device
;
145 static kauth_scope_t kauth_builtin_scope_cred
;
146 static kauth_scope_t kauth_builtin_scope_vnode
;
148 static unsigned int nsecmodels
= 0;
150 static specificdata_domain_t kauth_domain
;
151 static pool_cache_t kauth_cred_cache
;
153 krwlock_t kauth_lock
;
155 /* Allocate new, empty kauth credentials. */
157 kauth_cred_alloc(void)
161 cred
= pool_cache_get(kauth_cred_cache
, PR_WAITOK
);
170 cred
->cr_ngroups
= 0;
172 specificdata_init(kauth_domain
, &cred
->cr_sd
);
173 kauth_cred_hook(cred
, KAUTH_CRED_INIT
, NULL
, NULL
);
178 /* Increment reference count to cred. */
180 kauth_cred_hold(kauth_cred_t cred
)
182 KASSERT(cred
!= NULL
);
183 KASSERT(cred
->cr_refcnt
> 0);
185 atomic_inc_uint(&cred
->cr_refcnt
);
188 /* Decrease reference count to cred. If reached zero, free it. */
190 kauth_cred_free(kauth_cred_t cred
)
193 KASSERT(cred
!= NULL
);
194 KASSERT(cred
->cr_refcnt
> 0);
197 if (atomic_dec_uint_nv(&cred
->cr_refcnt
) > 0)
200 kauth_cred_hook(cred
, KAUTH_CRED_FREE
, NULL
, NULL
);
201 specificdata_fini(kauth_domain
, &cred
->cr_sd
);
202 pool_cache_put(kauth_cred_cache
, cred
);
206 kauth_cred_clone1(kauth_cred_t from
, kauth_cred_t to
, bool copy_groups
)
208 KASSERT(from
!= NULL
);
210 KASSERT(from
->cr_refcnt
> 0);
212 to
->cr_uid
= from
->cr_uid
;
213 to
->cr_euid
= from
->cr_euid
;
214 to
->cr_svuid
= from
->cr_svuid
;
215 to
->cr_gid
= from
->cr_gid
;
216 to
->cr_egid
= from
->cr_egid
;
217 to
->cr_svgid
= from
->cr_svgid
;
219 to
->cr_ngroups
= from
->cr_ngroups
;
220 memcpy(to
->cr_groups
, from
->cr_groups
, sizeof(to
->cr_groups
));
223 kauth_cred_hook(from
, KAUTH_CRED_COPY
, to
, NULL
);
227 kauth_cred_clone(kauth_cred_t from
, kauth_cred_t to
)
229 kauth_cred_clone1(from
, to
, true);
233 * Duplicate cred and return a new kauth_cred_t.
236 kauth_cred_dup(kauth_cred_t cred
)
238 kauth_cred_t new_cred
;
240 KASSERT(cred
!= NULL
);
241 KASSERT(cred
->cr_refcnt
> 0);
243 new_cred
= kauth_cred_alloc();
245 kauth_cred_clone(cred
, new_cred
);
251 * Similar to crcopy(), only on a kauth_cred_t.
252 * XXX: Is this even needed? [kauth_cred_copy]
255 kauth_cred_copy(kauth_cred_t cred
)
257 kauth_cred_t new_cred
;
259 KASSERT(cred
!= NULL
);
260 KASSERT(cred
->cr_refcnt
> 0);
262 /* If the provided credentials already have one reference, use them. */
263 if (cred
->cr_refcnt
== 1)
266 new_cred
= kauth_cred_alloc();
268 kauth_cred_clone(cred
, new_cred
);
270 kauth_cred_free(cred
);
276 kauth_proc_fork(struct proc
*parent
, struct proc
*child
)
279 mutex_enter(parent
->p_lock
);
280 kauth_cred_hold(parent
->p_cred
);
281 child
->p_cred
= parent
->p_cred
;
282 mutex_exit(parent
->p_lock
);
284 /* XXX: relies on parent process stalling during fork() */
285 kauth_cred_hook(parent
->p_cred
, KAUTH_CRED_FORK
, parent
,
290 kauth_cred_getuid(kauth_cred_t cred
)
292 KASSERT(cred
!= NULL
);
294 return (cred
->cr_uid
);
298 kauth_cred_geteuid(kauth_cred_t cred
)
300 KASSERT(cred
!= NULL
);
302 return (cred
->cr_euid
);
306 kauth_cred_getsvuid(kauth_cred_t cred
)
308 KASSERT(cred
!= NULL
);
310 return (cred
->cr_svuid
);
314 kauth_cred_getgid(kauth_cred_t cred
)
316 KASSERT(cred
!= NULL
);
318 return (cred
->cr_gid
);
322 kauth_cred_getegid(kauth_cred_t cred
)
324 KASSERT(cred
!= NULL
);
326 return (cred
->cr_egid
);
330 kauth_cred_getsvgid(kauth_cred_t cred
)
332 KASSERT(cred
!= NULL
);
334 return (cred
->cr_svgid
);
338 kauth_cred_setuid(kauth_cred_t cred
, uid_t uid
)
340 KASSERT(cred
!= NULL
);
341 KASSERT(cred
->cr_refcnt
== 1);
347 kauth_cred_seteuid(kauth_cred_t cred
, uid_t uid
)
349 KASSERT(cred
!= NULL
);
350 KASSERT(cred
->cr_refcnt
== 1);
356 kauth_cred_setsvuid(kauth_cred_t cred
, uid_t uid
)
358 KASSERT(cred
!= NULL
);
359 KASSERT(cred
->cr_refcnt
== 1);
361 cred
->cr_svuid
= uid
;
365 kauth_cred_setgid(kauth_cred_t cred
, gid_t gid
)
367 KASSERT(cred
!= NULL
);
368 KASSERT(cred
->cr_refcnt
== 1);
374 kauth_cred_setegid(kauth_cred_t cred
, gid_t gid
)
376 KASSERT(cred
!= NULL
);
377 KASSERT(cred
->cr_refcnt
== 1);
383 kauth_cred_setsvgid(kauth_cred_t cred
, gid_t gid
)
385 KASSERT(cred
!= NULL
);
386 KASSERT(cred
->cr_refcnt
== 1);
388 cred
->cr_svgid
= gid
;
391 /* Checks if gid is a member of the groups in cred. */
393 kauth_cred_ismember_gid(kauth_cred_t cred
, gid_t gid
, int *resultp
)
397 KASSERT(cred
!= NULL
);
398 KASSERT(resultp
!= NULL
);
402 for (i
= 0; i
< cred
->cr_ngroups
; i
++)
403 if (cred
->cr_groups
[i
] == gid
) {
412 kauth_cred_ngroups(kauth_cred_t cred
)
414 KASSERT(cred
!= NULL
);
416 return (cred
->cr_ngroups
);
420 * Return the group at index idx from the groups in cred.
423 kauth_cred_group(kauth_cred_t cred
, u_int idx
)
425 KASSERT(cred
!= NULL
);
426 KASSERT(idx
< cred
->cr_ngroups
);
428 return (cred
->cr_groups
[idx
]);
431 /* XXX elad: gmuid is unused for now. */
433 kauth_cred_setgroups(kauth_cred_t cred
, const gid_t
*grbuf
, size_t len
,
434 uid_t gmuid
, enum uio_seg seg
)
438 KASSERT(cred
!= NULL
);
439 KASSERT(cred
->cr_refcnt
== 1);
441 if (len
> __arraycount(cred
->cr_groups
))
445 if (seg
== UIO_SYSSPACE
) {
446 memcpy(cred
->cr_groups
, grbuf
,
447 len
* sizeof(cred
->cr_groups
[0]));
449 error
= copyin(grbuf
, cred
->cr_groups
,
450 len
* sizeof(cred
->cr_groups
[0]));
455 memset(cred
->cr_groups
+ len
, 0xff,
456 sizeof(cred
->cr_groups
) - (len
* sizeof(cred
->cr_groups
[0])));
458 cred
->cr_ngroups
= len
;
463 /* This supports sys_setgroups() */
465 kauth_proc_setgroups(struct lwp
*l
, kauth_cred_t ncred
)
471 * At this point we could delete duplicate groups from ncred,
472 * and plausibly sort the list - but in general the later is
476 /* Maybe we should use curproc here ? */
477 cred
= l
->l_proc
->p_cred
;
479 kauth_cred_clone1(cred
, ncred
, false);
481 error
= kauth_authorize_process(cred
, KAUTH_PROCESS_SETID
,
482 l
->l_proc
, NULL
, NULL
, NULL
);
484 proc_crmod_leave(cred
, ncred
, false);
488 /* Broadcast our credentials to the process and other LWPs. */
489 proc_crmod_leave(ncred
, cred
, true);
494 kauth_cred_getgroups(kauth_cred_t cred
, gid_t
*grbuf
, size_t len
,
497 KASSERT(cred
!= NULL
);
499 if (len
> cred
->cr_ngroups
)
502 if (seg
== UIO_USERSPACE
)
503 return copyout(cred
->cr_groups
, grbuf
, sizeof(*grbuf
) * len
);
504 memcpy(grbuf
, cred
->cr_groups
, sizeof(*grbuf
) * len
);
510 kauth_register_key(const char *secmodel
, kauth_key_t
*result
)
513 specificdata_key_t key
;
516 KASSERT(result
!= NULL
);
518 error
= specificdata_key_create(kauth_domain
, &key
, NULL
);
522 k
= kmem_alloc(sizeof(*k
), KM_SLEEP
);
523 k
->ks_secmodel
= secmodel
;
532 kauth_deregister_key(kauth_key_t key
)
534 KASSERT(key
!= NULL
);
536 specificdata_key_delete(kauth_domain
, key
->ks_key
);
537 kmem_free(key
, sizeof(*key
));
543 kauth_cred_getdata(kauth_cred_t cred
, kauth_key_t key
)
545 KASSERT(cred
!= NULL
);
546 KASSERT(key
!= NULL
);
548 return (specificdata_getspecific(kauth_domain
, &cred
->cr_sd
,
553 kauth_cred_setdata(kauth_cred_t cred
, kauth_key_t key
, void *data
)
555 KASSERT(cred
!= NULL
);
556 KASSERT(key
!= NULL
);
558 specificdata_setspecific(kauth_domain
, &cred
->cr_sd
, key
->ks_key
, data
);
562 * Match uids in two credentials.
565 kauth_cred_uidmatch(kauth_cred_t cred1
, kauth_cred_t cred2
)
567 KASSERT(cred1
!= NULL
);
568 KASSERT(cred2
!= NULL
);
570 if (cred1
->cr_uid
== cred2
->cr_uid
||
571 cred1
->cr_euid
== cred2
->cr_uid
||
572 cred1
->cr_uid
== cred2
->cr_euid
||
573 cred1
->cr_euid
== cred2
->cr_euid
)
580 kauth_cred_getrefcnt(kauth_cred_t cred
)
582 KASSERT(cred
!= NULL
);
584 return (cred
->cr_refcnt
);
588 * Convert userland credentials (struct uucred) to kauth_cred_t.
589 * XXX: For NFS & puffs
592 kauth_uucred_to_cred(kauth_cred_t cred
, const struct uucred
*uuc
)
594 KASSERT(cred
!= NULL
);
595 KASSERT(uuc
!= NULL
);
598 cred
->cr_uid
= uuc
->cr_uid
;
599 cred
->cr_euid
= uuc
->cr_uid
;
600 cred
->cr_svuid
= uuc
->cr_uid
;
601 cred
->cr_gid
= uuc
->cr_gid
;
602 cred
->cr_egid
= uuc
->cr_gid
;
603 cred
->cr_svgid
= uuc
->cr_gid
;
604 cred
->cr_ngroups
= min(uuc
->cr_ngroups
, NGROUPS
);
605 kauth_cred_setgroups(cred
, __UNCONST(uuc
->cr_groups
),
606 cred
->cr_ngroups
, -1, UIO_SYSSPACE
);
610 * Convert kauth_cred_t to userland credentials (struct uucred).
611 * XXX: For NFS & puffs
614 kauth_cred_to_uucred(struct uucred
*uuc
, const kauth_cred_t cred
)
616 KASSERT(cred
!= NULL
);
617 KASSERT(uuc
!= NULL
);
620 ng
= min(cred
->cr_ngroups
, NGROUPS
);
621 uuc
->cr_uid
= cred
->cr_euid
;
622 uuc
->cr_gid
= cred
->cr_egid
;
623 uuc
->cr_ngroups
= ng
;
624 kauth_cred_getgroups(cred
, uuc
->cr_groups
, ng
, UIO_SYSSPACE
);
628 * Compare kauth_cred_t and uucred credentials.
629 * XXX: Modelled after crcmp() for NFS.
632 kauth_cred_uucmp(kauth_cred_t cred
, const struct uucred
*uuc
)
634 KASSERT(cred
!= NULL
);
635 KASSERT(uuc
!= NULL
);
637 if (cred
->cr_euid
== uuc
->cr_uid
&&
638 cred
->cr_egid
== uuc
->cr_gid
&&
639 cred
->cr_ngroups
== (uint32_t)uuc
->cr_ngroups
) {
642 /* Check if all groups from uuc appear in cred. */
643 for (i
= 0; i
< uuc
->cr_ngroups
; i
++) {
647 if (kauth_cred_ismember_gid(cred
, uuc
->cr_groups
[i
],
648 &ismember
) != 0 || !ismember
)
659 * Make a struct ucred out of a kauth_cred_t. For compatibility.
662 kauth_cred_toucred(kauth_cred_t cred
, struct ki_ucred
*uc
)
664 KASSERT(cred
!= NULL
);
667 uc
->cr_ref
= cred
->cr_refcnt
;
668 uc
->cr_uid
= cred
->cr_euid
;
669 uc
->cr_gid
= cred
->cr_egid
;
670 uc
->cr_ngroups
= min(cred
->cr_ngroups
, __arraycount(uc
->cr_groups
));
671 memcpy(uc
->cr_groups
, cred
->cr_groups
,
672 uc
->cr_ngroups
* sizeof(uc
->cr_groups
[0]));
676 * Make a struct pcred out of a kauth_cred_t. For compatibility.
679 kauth_cred_topcred(kauth_cred_t cred
, struct ki_pcred
*pc
)
681 KASSERT(cred
!= NULL
);
685 pc
->p_ruid
= cred
->cr_uid
;
686 pc
->p_svuid
= cred
->cr_svuid
;
687 pc
->p_rgid
= cred
->cr_gid
;
688 pc
->p_svgid
= cred
->cr_svgid
;
689 pc
->p_refcnt
= cred
->cr_refcnt
;
693 * Return kauth_cred_t for the current LWP.
698 return (curlwp
->l_cred
);
702 * Returns a scope matching the provided id.
703 * Requires the scope list lock to be held by the caller.
706 kauth_ifindscope(const char *id
)
710 KASSERT(rw_lock_held(&kauth_lock
));
713 SIMPLEQ_FOREACH(scope
, &scope_list
, next_scope
) {
714 if (strcmp(scope
->id
, id
) == 0)
722 * Register a new scope.
724 * id - identifier for the scope
725 * callback - the scope's default listener
726 * cookie - cookie to be passed to the listener(s)
729 kauth_register_scope(const char *id
, kauth_scope_callback_t callback
,
733 kauth_listener_t listener
= NULL
; /* XXX gcc */
739 /* Allocate space for a new scope and listener. */
740 scope
= kmem_alloc(sizeof(*scope
), KM_SLEEP
);
743 if (callback
!= NULL
) {
744 listener
= kmem_alloc(sizeof(*listener
), KM_SLEEP
);
745 if (listener
== NULL
) {
746 kmem_free(scope
, sizeof(*scope
));
752 * Acquire scope list lock.
754 rw_enter(&kauth_lock
, RW_WRITER
);
756 /* Check we don't already have a scope with the same id */
757 if (kauth_ifindscope(id
) != NULL
) {
758 rw_exit(&kauth_lock
);
760 kmem_free(scope
, sizeof(*scope
));
761 if (callback
!= NULL
)
762 kmem_free(listener
, sizeof(*listener
));
767 /* Initialize new scope with parameters */
769 scope
->cookie
= cookie
;
770 scope
->nlisteners
= 1;
772 SIMPLEQ_INIT(&scope
->listenq
);
774 /* Add default listener */
775 if (callback
!= NULL
) {
776 listener
->func
= callback
;
777 listener
->scope
= scope
;
778 listener
->refcnt
= 0;
779 SIMPLEQ_INSERT_HEAD(&scope
->listenq
, listener
, listener_next
);
782 /* Insert scope to scopes list */
783 SIMPLEQ_INSERT_TAIL(&scope_list
, scope
, next_scope
);
785 rw_exit(&kauth_lock
);
791 * Initialize the kernel authorization subsystem.
793 * Initialize the scopes list lock.
794 * Create specificdata domain.
795 * Register the credentials scope, used in kauth(9) internally.
796 * Register built-in scopes: generic, system, process, network, machdep, device.
801 rw_init(&kauth_lock
);
803 kauth_cred_cache
= pool_cache_init(sizeof(struct kauth_cred
),
804 coherency_unit
, 0, 0, "kcredpl", NULL
, IPL_NONE
,
807 /* Create specificdata domain. */
808 kauth_domain
= specificdata_domain_create();
810 /* Register credentials scope. */
811 kauth_builtin_scope_cred
=
812 kauth_register_scope(KAUTH_SCOPE_CRED
, NULL
, NULL
);
814 /* Register generic scope. */
815 kauth_builtin_scope_generic
= kauth_register_scope(KAUTH_SCOPE_GENERIC
,
818 /* Register system scope. */
819 kauth_builtin_scope_system
= kauth_register_scope(KAUTH_SCOPE_SYSTEM
,
822 /* Register process scope. */
823 kauth_builtin_scope_process
= kauth_register_scope(KAUTH_SCOPE_PROCESS
,
826 /* Register network scope. */
827 kauth_builtin_scope_network
= kauth_register_scope(KAUTH_SCOPE_NETWORK
,
830 /* Register machdep scope. */
831 kauth_builtin_scope_machdep
= kauth_register_scope(KAUTH_SCOPE_MACHDEP
,
834 /* Register device scope. */
835 kauth_builtin_scope_device
= kauth_register_scope(KAUTH_SCOPE_DEVICE
,
838 /* Register vnode scope. */
839 kauth_builtin_scope_vnode
= kauth_register_scope(KAUTH_SCOPE_VNODE
,
844 * Deregister a scope.
845 * Requires scope list lock to be held by the caller.
847 * scope - the scope to deregister
850 kauth_deregister_scope(kauth_scope_t scope
)
853 /* Remove scope from list */
854 SIMPLEQ_REMOVE(&scope_list
, scope
, kauth_scope
, next_scope
);
855 kmem_free(scope
, sizeof(*scope
));
860 * Register a listener.
862 * id - scope identifier.
863 * callback - the callback routine for the listener.
864 * cookie - cookie to pass unmoidfied to the callback.
867 kauth_listen_scope(const char *id
, kauth_scope_callback_t callback
,
871 kauth_listener_t listener
;
873 listener
= kmem_alloc(sizeof(*listener
), KM_SLEEP
);
874 if (listener
== NULL
)
877 rw_enter(&kauth_lock
, RW_WRITER
);
882 scope
= kauth_ifindscope(id
);
884 rw_exit(&kauth_lock
);
885 kmem_free(listener
, sizeof(*listener
));
889 /* Allocate listener */
891 /* Initialize listener with parameters */
892 listener
->func
= callback
;
893 listener
->refcnt
= 0;
895 /* Add listener to scope */
896 SIMPLEQ_INSERT_TAIL(&scope
->listenq
, listener
, listener_next
);
898 /* Raise number of listeners on scope. */
900 listener
->scope
= scope
;
902 rw_exit(&kauth_lock
);
908 * Deregister a listener.
910 * listener - listener reference as returned from kauth_listen_scope().
913 kauth_unlisten_scope(kauth_listener_t listener
)
916 if (listener
!= NULL
) {
917 rw_enter(&kauth_lock
, RW_WRITER
);
918 SIMPLEQ_REMOVE(&listener
->scope
->listenq
, listener
,
919 kauth_listener
, listener_next
);
920 listener
->scope
->nlisteners
--;
921 rw_exit(&kauth_lock
);
922 kmem_free(listener
, sizeof(*listener
));
927 * Authorize a request.
929 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as
930 * returned from kauth_register_scope().
931 * credential - credentials of the user ("actor") making the request.
932 * action - request identifier.
933 * arg[0-3] - passed unmodified to listener(s).
935 * Returns the aggregated result:
936 * - KAUTH_RESULT_ALLOW if there is at least one KAUTH_RESULT_ALLOW and
937 * zero KAUTH_DESULT_DENY
938 * - KAUTH_RESULT_DENY if there is at least one KAUTH_RESULT_DENY
939 * - KAUTH_RESULT_DEFER if there is nothing but KAUTH_RESULT_DEFER
942 kauth_authorize_action_internal(kauth_scope_t scope
, kauth_cred_t cred
,
943 kauth_action_t action
, void *arg0
, void *arg1
, void *arg2
, void *arg3
)
945 kauth_listener_t listener
;
946 int error
, allow
, fail
;
948 KASSERT(cred
!= NULL
);
949 KASSERT(action
!= 0);
951 /* Short-circuit requests coming from the kernel. */
952 if (cred
== NOCRED
|| cred
== FSCRED
)
955 KASSERT(scope
!= NULL
);
960 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */
961 SIMPLEQ_FOREACH(listener
, &scope
->listenq
, listener_next
) {
962 error
= listener
->func(cred
, action
, scope
->cookie
, arg0
,
965 if (error
== KAUTH_RESULT_ALLOW
)
967 else if (error
== KAUTH_RESULT_DENY
)
970 /* rw_exit(&kauth_lock); */
973 return (KAUTH_RESULT_DENY
);
976 return (KAUTH_RESULT_ALLOW
);
978 return (KAUTH_RESULT_DEFER
);
982 kauth_authorize_action(kauth_scope_t scope
, kauth_cred_t cred
,
983 kauth_action_t action
, void *arg0
, void *arg1
, void *arg2
, void *arg3
)
987 r
= kauth_authorize_action_internal(scope
, cred
, action
, arg0
, arg1
,
990 if (r
== KAUTH_RESULT_DENY
)
993 if (r
== KAUTH_RESULT_ALLOW
)
1003 * Generic scope authorization wrapper.
1006 kauth_authorize_generic(kauth_cred_t cred
, kauth_action_t action
, void *arg0
)
1008 return (kauth_authorize_action(kauth_builtin_scope_generic
, cred
,
1009 action
, arg0
, NULL
, NULL
, NULL
));
1013 * System scope authorization wrapper.
1016 kauth_authorize_system(kauth_cred_t cred
, kauth_action_t action
,
1017 enum kauth_system_req req
, void *arg1
, void *arg2
, void *arg3
)
1019 return (kauth_authorize_action(kauth_builtin_scope_system
, cred
,
1020 action
, (void *)req
, arg1
, arg2
, arg3
));
1024 * Process scope authorization wrapper.
1027 kauth_authorize_process(kauth_cred_t cred
, kauth_action_t action
,
1028 struct proc
*p
, void *arg1
, void *arg2
, void *arg3
)
1030 return (kauth_authorize_action(kauth_builtin_scope_process
, cred
,
1031 action
, p
, arg1
, arg2
, arg3
));
1035 * Network scope authorization wrapper.
1038 kauth_authorize_network(kauth_cred_t cred
, kauth_action_t action
,
1039 enum kauth_network_req req
, void *arg1
, void *arg2
, void *arg3
)
1041 return (kauth_authorize_action(kauth_builtin_scope_network
, cred
,
1042 action
, (void *)req
, arg1
, arg2
, arg3
));
1046 kauth_authorize_machdep(kauth_cred_t cred
, kauth_action_t action
,
1047 void *arg0
, void *arg1
, void *arg2
, void *arg3
)
1049 return (kauth_authorize_action(kauth_builtin_scope_machdep
, cred
,
1050 action
, arg0
, arg1
, arg2
, arg3
));
1054 kauth_authorize_device(kauth_cred_t cred
, kauth_action_t action
,
1055 void *arg0
, void *arg1
, void *arg2
, void *arg3
)
1057 return (kauth_authorize_action(kauth_builtin_scope_device
, cred
,
1058 action
, arg0
, arg1
, arg2
, arg3
));
1062 kauth_authorize_device_tty(kauth_cred_t cred
, kauth_action_t action
,
1065 return (kauth_authorize_action(kauth_builtin_scope_device
, cred
,
1066 action
, tty
, NULL
, NULL
, NULL
));
1070 kauth_authorize_device_spec(kauth_cred_t cred
, enum kauth_device_req req
,
1073 return (kauth_authorize_action(kauth_builtin_scope_device
, cred
,
1074 KAUTH_DEVICE_RAWIO_SPEC
, (void *)req
, vp
, NULL
, NULL
));
1078 kauth_authorize_device_passthru(kauth_cred_t cred
, dev_t dev
, u_long bits
,
1081 return (kauth_authorize_action(kauth_builtin_scope_device
, cred
,
1082 KAUTH_DEVICE_RAWIO_PASSTHRU
, (void *)bits
, (void *)(u_long
)dev
,
1087 kauth_mode_to_action(mode_t mode
)
1089 kauth_action_t action
= 0;
1092 action
|= KAUTH_VNODE_READ_DATA
;
1094 action
|= KAUTH_VNODE_WRITE_DATA
;
1096 action
|= KAUTH_VNODE_EXECUTE
;
1102 kauth_authorize_vnode(kauth_cred_t cred
, kauth_action_t action
,
1103 struct vnode
*vp
, struct vnode
*dvp
, int fs_decision
)
1107 error
= kauth_authorize_action_internal(kauth_builtin_scope_vnode
, cred
,
1108 action
, vp
, dvp
, NULL
, NULL
);
1110 if (error
== KAUTH_RESULT_DENY
)
1113 if (error
== KAUTH_RESULT_ALLOW
)
1117 * If the file-system does not support decision-before-action, we can
1118 * only short-circuit the operation (deny). If we're here, it means no
1119 * listener denied it, so our only alternative is to supposedly-allow
1120 * it and let the file-system have the last word.
1122 if (fs_decision
== KAUTH_VNODE_REMOTEFS
)
1125 return (fs_decision
);
1129 kauth_cred_hook(kauth_cred_t cred
, kauth_action_t action
, void *arg0
,
1134 r
= kauth_authorize_action(kauth_builtin_scope_cred
, cred
, action
,
1135 arg0
, arg1
, NULL
, NULL
);
1138 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred
->listenq
))
1140 #endif /* DIAGNOSTIC */
1146 secmodel_register(void)
1148 KASSERT(nsecmodels
+ 1 != 0);
1150 rw_enter(&kauth_lock
, RW_WRITER
);
1152 rw_exit(&kauth_lock
);
1156 secmodel_deregister(void)
1158 KASSERT(nsecmodels
!= 0);
1160 rw_enter(&kauth_lock
, RW_WRITER
);
1162 rw_exit(&kauth_lock
);