kern_auth.c revision 1.45 1 /* $NetBSD: kern_auth.c,v 1.45 2007/02/18 15:20:34 dsl Exp $ */
2
3 /*-
4 * Copyright (c) 2005, 2006 Elad Efrat <elad (at) 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. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: kern_auth.c,v 1.45 2007/02/18 15:20:34 dsl Exp $");
32
33 #define _KAUTH_PRIVATE
34
35 #include <sys/param.h>
36 #include <sys/queue.h>
37 #include <sys/proc.h>
38 #include <sys/ucred.h>
39 #include <sys/pool.h>
40 #include <sys/kauth.h>
41 #include <sys/kauth_impl.h>
42 #include <sys/kmem.h>
43 #include <sys/rwlock.h>
44 #include <sys/sysctl.h> /* for pi_[p]cread */
45
46 /*
47 * Secmodel-specific credentials.
48 */
49 struct kauth_key {
50 const char *ks_secmodel; /* secmodel */
51 specificdata_key_t ks_key; /* key */
52 };
53
54 /*
55 * Listener.
56 */
57 struct kauth_listener {
58 kauth_scope_callback_t func; /* callback */
59 kauth_scope_t scope; /* scope backpointer */
60 u_int refcnt; /* reference count */
61 SIMPLEQ_ENTRY(kauth_listener) listener_next; /* listener list */
62 };
63
64 /*
65 * Scope.
66 */
67 struct kauth_scope {
68 const char *id; /* scope name */
69 void *cookie; /* user cookie */
70 u_int nlisteners; /* # of listeners */
71 SIMPLEQ_HEAD(, kauth_listener) listenq; /* listener list */
72 SIMPLEQ_ENTRY(kauth_scope) next_scope; /* scope list */
73 };
74
75 static int kauth_cred_hook(kauth_cred_t, kauth_action_t, void *, void *);
76
77 static POOL_INIT(kauth_cred_pool, sizeof(struct kauth_cred), 0, 0, 0,
78 "kauthcredpl", &pool_allocator_nointr);
79
80 /* List of scopes and its lock. */
81 static SIMPLEQ_HEAD(, kauth_scope) scope_list;
82
83 /* Built-in scopes: generic, process. */
84 static kauth_scope_t kauth_builtin_scope_generic;
85 static kauth_scope_t kauth_builtin_scope_system;
86 static kauth_scope_t kauth_builtin_scope_process;
87 static kauth_scope_t kauth_builtin_scope_network;
88 static kauth_scope_t kauth_builtin_scope_machdep;
89 static kauth_scope_t kauth_builtin_scope_device;
90 static kauth_scope_t kauth_builtin_scope_cred;
91
92 static unsigned int nsecmodels = 0;
93
94 static specificdata_domain_t kauth_domain;
95 krwlock_t kauth_lock;
96
97 /* Allocate new, empty kauth credentials. */
98 kauth_cred_t
99 kauth_cred_alloc(void)
100 {
101 kauth_cred_t cred;
102
103 cred = pool_get(&kauth_cred_pool, PR_WAITOK);
104 memset(cred, 0, sizeof(*cred));
105 mutex_init(&cred->cr_lock, MUTEX_DEFAULT, IPL_NONE);
106 cred->cr_refcnt = 1;
107 specificdata_init(kauth_domain, &cred->cr_sd);
108 kauth_cred_hook(cred, KAUTH_CRED_INIT, NULL, NULL);
109
110 return (cred);
111 }
112
113 /* Increment reference count to cred. */
114 void
115 kauth_cred_hold(kauth_cred_t cred)
116 {
117 KASSERT(cred != NULL);
118 KASSERT(cred->cr_refcnt > 0);
119
120 mutex_enter(&cred->cr_lock);
121 cred->cr_refcnt++;
122 mutex_exit(&cred->cr_lock);
123 }
124
125 /* Decrease reference count to cred. If reached zero, free it. */
126 void
127 kauth_cred_free(kauth_cred_t cred)
128 {
129 u_int refcnt;
130
131 KASSERT(cred != NULL);
132 KASSERT(cred->cr_refcnt > 0);
133
134 mutex_enter(&cred->cr_lock);
135 refcnt = --cred->cr_refcnt;
136 mutex_exit(&cred->cr_lock);
137
138 if (refcnt == 0) {
139 kauth_cred_hook(cred, KAUTH_CRED_FREE, NULL, NULL);
140 specificdata_fini(kauth_domain, &cred->cr_sd);
141 mutex_destroy(&cred->cr_lock);
142 pool_put(&kauth_cred_pool, cred);
143 }
144 }
145
146 void
147 kauth_cred_clone(kauth_cred_t from, kauth_cred_t to)
148 {
149 KASSERT(from != NULL);
150 KASSERT(to != NULL);
151 KASSERT(from->cr_refcnt > 0);
152
153 to->cr_uid = from->cr_uid;
154 to->cr_euid = from->cr_euid;
155 to->cr_svuid = from->cr_svuid;
156 to->cr_gid = from->cr_gid;
157 to->cr_egid = from->cr_egid;
158 to->cr_svgid = from->cr_svgid;
159 to->cr_ngroups = from->cr_ngroups;
160 memcpy(to->cr_groups, from->cr_groups, sizeof(to->cr_groups));
161
162 kauth_cred_hook(from, KAUTH_CRED_COPY, to, NULL);
163 }
164
165 /*
166 * Duplicate cred and return a new kauth_cred_t.
167 */
168 kauth_cred_t
169 kauth_cred_dup(kauth_cred_t cred)
170 {
171 kauth_cred_t new_cred;
172
173 KASSERT(cred != NULL);
174 KASSERT(cred->cr_refcnt > 0);
175
176 new_cred = kauth_cred_alloc();
177
178 kauth_cred_clone(cred, new_cred);
179
180 return (new_cred);
181 }
182
183 /*
184 * Similar to crcopy(), only on a kauth_cred_t.
185 * XXX: Is this even needed? [kauth_cred_copy]
186 */
187 kauth_cred_t
188 kauth_cred_copy(kauth_cred_t cred)
189 {
190 kauth_cred_t new_cred;
191
192 KASSERT(cred != NULL);
193 KASSERT(cred->cr_refcnt > 0);
194
195 /* If the provided credentials already have one reference, use them. */
196 if (cred->cr_refcnt == 1)
197 return (cred);
198
199 new_cred = kauth_cred_alloc();
200
201 kauth_cred_clone(cred, new_cred);
202
203 kauth_cred_free(cred);
204
205 return (new_cred);
206 }
207
208 void
209 kauth_proc_fork(struct proc *parent, struct proc *child)
210 {
211
212 mutex_enter(&parent->p_mutex);
213 kauth_cred_hold(parent->p_cred);
214 child->p_cred = parent->p_cred;
215 mutex_exit(&parent->p_mutex);
216
217 /* XXX: relies on parent process stalling during fork() */
218 kauth_cred_hook(parent->p_cred, KAUTH_CRED_FORK, parent,
219 child);
220 }
221
222 uid_t
223 kauth_cred_getuid(kauth_cred_t cred)
224 {
225 KASSERT(cred != NULL);
226
227 return (cred->cr_uid);
228 }
229
230 uid_t
231 kauth_cred_geteuid(kauth_cred_t cred)
232 {
233 KASSERT(cred != NULL);
234
235 return (cred->cr_euid);
236 }
237
238 uid_t
239 kauth_cred_getsvuid(kauth_cred_t cred)
240 {
241 KASSERT(cred != NULL);
242
243 return (cred->cr_svuid);
244 }
245
246 gid_t
247 kauth_cred_getgid(kauth_cred_t cred)
248 {
249 KASSERT(cred != NULL);
250
251 return (cred->cr_gid);
252 }
253
254 gid_t
255 kauth_cred_getegid(kauth_cred_t cred)
256 {
257 KASSERT(cred != NULL);
258
259 return (cred->cr_egid);
260 }
261
262 gid_t
263 kauth_cred_getsvgid(kauth_cred_t cred)
264 {
265 KASSERT(cred != NULL);
266
267 return (cred->cr_svgid);
268 }
269
270 void
271 kauth_cred_setuid(kauth_cred_t cred, uid_t uid)
272 {
273 KASSERT(cred != NULL);
274 KASSERT(cred->cr_refcnt == 1);
275
276 cred->cr_uid = uid;
277 }
278
279 void
280 kauth_cred_seteuid(kauth_cred_t cred, uid_t uid)
281 {
282 KASSERT(cred != NULL);
283 KASSERT(cred->cr_refcnt == 1);
284
285 cred->cr_euid = uid;
286 }
287
288 void
289 kauth_cred_setsvuid(kauth_cred_t cred, uid_t uid)
290 {
291 KASSERT(cred != NULL);
292 KASSERT(cred->cr_refcnt == 1);
293
294 cred->cr_svuid = uid;
295 }
296
297 void
298 kauth_cred_setgid(kauth_cred_t cred, gid_t gid)
299 {
300 KASSERT(cred != NULL);
301 KASSERT(cred->cr_refcnt == 1);
302
303 cred->cr_gid = gid;
304 }
305
306 void
307 kauth_cred_setegid(kauth_cred_t cred, gid_t gid)
308 {
309 KASSERT(cred != NULL);
310 KASSERT(cred->cr_refcnt == 1);
311
312 cred->cr_egid = gid;
313 }
314
315 void
316 kauth_cred_setsvgid(kauth_cred_t cred, gid_t gid)
317 {
318 KASSERT(cred != NULL);
319 KASSERT(cred->cr_refcnt == 1);
320
321 cred->cr_svgid = gid;
322 }
323
324 /* Checks if gid is a member of the groups in cred. */
325 int
326 kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp)
327 {
328 int i;
329
330 KASSERT(cred != NULL);
331 KASSERT(resultp != NULL);
332
333 *resultp = 0;
334
335 for (i = 0; i < cred->cr_ngroups; i++)
336 if (cred->cr_groups[i] == gid) {
337 *resultp = 1;
338 break;
339 }
340
341 return (0);
342 }
343
344 u_int
345 kauth_cred_ngroups(kauth_cred_t cred)
346 {
347 KASSERT(cred != NULL);
348
349 return (cred->cr_ngroups);
350 }
351
352 /*
353 * Return the group at index idx from the groups in cred.
354 */
355 gid_t
356 kauth_cred_group(kauth_cred_t cred, u_int idx)
357 {
358 KASSERT(cred != NULL);
359 KASSERT(idx < cred->cr_ngroups);
360
361 return (cred->cr_groups[idx]);
362 }
363
364 /* XXX elad: gmuid is unused for now. */
365 int
366 kauth_cred_setgroups(kauth_cred_t cred, gid_t *grbuf, size_t len, uid_t gmuid)
367 {
368 KASSERT(cred != NULL);
369 KASSERT(cred->cr_refcnt == 1);
370 KASSERT(len <= sizeof(cred->cr_groups) / sizeof(cred->cr_groups[0]));
371
372 if (len)
373 memcpy(cred->cr_groups, grbuf, len * sizeof(cred->cr_groups[0]));
374 memset(cred->cr_groups + len, 0xff,
375 sizeof(cred->cr_groups) - (len * sizeof(cred->cr_groups[0])));
376
377 cred->cr_ngroups = len;
378
379 return (0);
380 }
381
382 int
383 kauth_cred_getgroups(kauth_cred_t cred, gid_t *grbuf, size_t len)
384 {
385 KASSERT(cred != NULL);
386 KASSERT(len <= cred->cr_ngroups);
387
388 memset(grbuf, 0xff, sizeof(*grbuf) * len);
389 memcpy(grbuf, cred->cr_groups, sizeof(*grbuf) * len);
390
391 return (0);
392 }
393
394 int
395 kauth_register_key(const char *secmodel, kauth_key_t *result)
396 {
397 kauth_key_t k;
398 specificdata_key_t key;
399 int error;
400
401 KASSERT(result != NULL);
402
403 error = specificdata_key_create(kauth_domain, &key, NULL);
404 if (error)
405 return (error);
406
407 k = kmem_alloc(sizeof(*k), KM_SLEEP);
408 k->ks_secmodel = secmodel;
409 k->ks_key = key;
410
411 *result = k;
412
413 return (0);
414 }
415
416 int
417 kauth_deregister_key(kauth_key_t key)
418 {
419 KASSERT(key != NULL);
420
421 specificdata_key_delete(kauth_domain, key->ks_key);
422 kmem_free(key, sizeof(*key));
423
424 return (0);
425 }
426
427 void *
428 kauth_cred_getdata(kauth_cred_t cred, kauth_key_t key)
429 {
430 KASSERT(cred != NULL);
431 KASSERT(key != NULL);
432
433 return (specificdata_getspecific(kauth_domain, &cred->cr_sd,
434 key->ks_key));
435 }
436
437 void
438 kauth_cred_setdata(kauth_cred_t cred, kauth_key_t key, void *data)
439 {
440 KASSERT(cred != NULL);
441 KASSERT(key != NULL);
442
443 specificdata_setspecific(kauth_domain, &cred->cr_sd, key->ks_key, data);
444 }
445
446 /*
447 * Match uids in two credentials.
448 */
449 int
450 kauth_cred_uidmatch(kauth_cred_t cred1, kauth_cred_t cred2)
451 {
452 KASSERT(cred1 != NULL);
453 KASSERT(cred2 != NULL);
454
455 if (cred1->cr_uid == cred2->cr_uid ||
456 cred1->cr_euid == cred2->cr_uid ||
457 cred1->cr_uid == cred2->cr_euid ||
458 cred1->cr_euid == cred2->cr_euid)
459 return (1);
460
461 return (0);
462 }
463
464 u_int
465 kauth_cred_getrefcnt(kauth_cred_t cred)
466 {
467 KASSERT(cred != NULL);
468
469 return (cred->cr_refcnt);
470 }
471
472 /*
473 * Convert userland credentials (struct uucred) to kauth_cred_t.
474 * XXX: For NFS & puffs
475 */
476 void
477 kauth_uucred_to_cred(kauth_cred_t cred, const struct uucred *uuc)
478 {
479 KASSERT(cred != NULL);
480 KASSERT(uuc != NULL);
481
482 cred->cr_refcnt = 1;
483 cred->cr_uid = uuc->cr_uid;
484 cred->cr_euid = uuc->cr_uid;
485 cred->cr_svuid = uuc->cr_uid;
486 cred->cr_gid = uuc->cr_gid;
487 cred->cr_egid = uuc->cr_gid;
488 cred->cr_svgid = uuc->cr_gid;
489 cred->cr_ngroups = min(uuc->cr_ngroups, NGROUPS);
490 kauth_cred_setgroups(cred, __UNCONST(uuc->cr_groups),
491 cred->cr_ngroups, -1);
492 }
493
494 /*
495 * Convert kauth_cred_t to userland credentials (struct uucred).
496 * XXX: For NFS & puffs
497 */
498 void
499 kauth_cred_to_uucred(struct uucred *uuc, const kauth_cred_t cred)
500 {
501 KASSERT(cred != NULL);
502 KASSERT(uuc != NULL);
503 int ng;
504
505 ng = min(cred->cr_ngroups, NGROUPS);
506 uuc->cr_uid = cred->cr_euid;
507 uuc->cr_gid = cred->cr_egid;
508 uuc->cr_ngroups = ng;
509 kauth_cred_getgroups(cred, uuc->cr_groups, ng);
510 }
511
512 /*
513 * Compare kauth_cred_t and uucred credentials.
514 * XXX: Modelled after crcmp() for NFS.
515 */
516 int
517 kauth_cred_uucmp(kauth_cred_t cred, const struct uucred *uuc)
518 {
519 KASSERT(cred != NULL);
520 KASSERT(uuc != NULL);
521
522 if (cred->cr_euid == uuc->cr_uid &&
523 cred->cr_egid == uuc->cr_gid &&
524 cred->cr_ngroups == uuc->cr_ngroups) {
525 int i;
526
527 /* Check if all groups from uuc appear in cred. */
528 for (i = 0; i < uuc->cr_ngroups; i++) {
529 int ismember;
530
531 ismember = 0;
532 if (kauth_cred_ismember_gid(cred, uuc->cr_groups[i],
533 &ismember) != 0 || !ismember)
534 return (1);
535 }
536
537 return (0);
538 }
539
540 return (1);
541 }
542
543 /*
544 * Make a struct ucred out of a kauth_cred_t. For compatibility.
545 */
546 void
547 kauth_cred_toucred(kauth_cred_t cred, struct ki_ucred *uc)
548 {
549 KASSERT(cred != NULL);
550 KASSERT(uc != NULL);
551
552 uc->cr_ref = cred->cr_refcnt;
553 uc->cr_uid = cred->cr_euid;
554 uc->cr_gid = cred->cr_egid;
555 uc->cr_ngroups = min(cred->cr_ngroups,
556 sizeof(uc->cr_groups) / sizeof(uc->cr_groups[0]));
557 memcpy(uc->cr_groups, cred->cr_groups,
558 uc->cr_ngroups * sizeof(uc->cr_groups[0]));
559 }
560
561 /*
562 * Make a struct pcred out of a kauth_cred_t. For compatibility.
563 */
564 void
565 kauth_cred_topcred(kauth_cred_t cred, struct ki_pcred *pc)
566 {
567 KASSERT(cred != NULL);
568 KASSERT(pc != NULL);
569
570 pc->p_pad = NULL;
571 pc->p_ruid = cred->cr_uid;
572 pc->p_svuid = cred->cr_svuid;
573 pc->p_rgid = cred->cr_gid;
574 pc->p_svgid = cred->cr_svgid;
575 pc->p_refcnt = cred->cr_refcnt;
576 }
577
578 /*
579 * Return kauth_cred_t for the current LWP.
580 */
581 kauth_cred_t
582 kauth_cred_get(void)
583 {
584 return (curlwp->l_cred);
585 }
586
587 /*
588 * Returns a scope matching the provided id.
589 * Requires the scope list lock to be held by the caller.
590 */
591 static kauth_scope_t
592 kauth_ifindscope(const char *id)
593 {
594 kauth_scope_t scope;
595
596 KASSERT(rw_lock_held(&kauth_lock));
597
598 scope = NULL;
599 SIMPLEQ_FOREACH(scope, &scope_list, next_scope) {
600 if (strcmp(scope->id, id) == 0)
601 break;
602 }
603
604 return (scope);
605 }
606
607 /*
608 * Register a new scope.
609 *
610 * id - identifier for the scope
611 * callback - the scope's default listener
612 * cookie - cookie to be passed to the listener(s)
613 */
614 kauth_scope_t
615 kauth_register_scope(const char *id, kauth_scope_callback_t callback,
616 void *cookie)
617 {
618 kauth_scope_t scope;
619 kauth_listener_t listener = NULL; /* XXX gcc */
620
621 /* Sanitize input */
622 if (id == NULL)
623 return (NULL);
624
625 /* Allocate space for a new scope and listener. */
626 scope = kmem_alloc(sizeof(*scope), KM_SLEEP);
627 if (scope == NULL)
628 return NULL;
629 if (callback != NULL) {
630 listener = kmem_alloc(sizeof(*listener), KM_SLEEP);
631 if (listener == NULL) {
632 kmem_free(scope, sizeof(*scope));
633 return (NULL);
634 }
635 }
636
637 /*
638 * Acquire scope list lock.
639 */
640 rw_enter(&kauth_lock, RW_WRITER);
641
642 /* Check we don't already have a scope with the same id */
643 if (kauth_ifindscope(id) != NULL) {
644 rw_exit(&kauth_lock);
645
646 kmem_free(scope, sizeof(*scope));
647 if (callback != NULL)
648 kmem_free(listener, sizeof(*listener));
649
650 return (NULL);
651 }
652
653 /* Initialize new scope with parameters */
654 scope->id = id;
655 scope->cookie = cookie;
656 scope->nlisteners = 1;
657
658 SIMPLEQ_INIT(&scope->listenq);
659
660 /* Add default listener */
661 if (callback != NULL) {
662 listener->func = callback;
663 listener->scope = scope;
664 listener->refcnt = 0;
665 SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next);
666 }
667
668 /* Insert scope to scopes list */
669 SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope);
670
671 rw_exit(&kauth_lock);
672
673 return (scope);
674 }
675
676 /*
677 * Initialize the kernel authorization subsystem.
678 *
679 * Initialize the scopes list lock.
680 * Create specificdata domain.
681 * Register the credentials scope, used in kauth(9) internally.
682 * Register built-in scopes: generic, system, process, network, machdep, device.
683 */
684 void
685 kauth_init(void)
686 {
687 SIMPLEQ_INIT(&scope_list);
688 rw_init(&kauth_lock);
689
690 /* Create specificdata domain. */
691 kauth_domain = specificdata_domain_create();
692
693 /* Register credentials scope. */
694 kauth_builtin_scope_cred =
695 kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL);
696
697 /* Register generic scope. */
698 kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC,
699 NULL, NULL);
700
701 /* Register system scope. */
702 kauth_builtin_scope_system = kauth_register_scope(KAUTH_SCOPE_SYSTEM,
703 NULL, NULL);
704
705 /* Register process scope. */
706 kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS,
707 NULL, NULL);
708
709 /* Register network scope. */
710 kauth_builtin_scope_network = kauth_register_scope(KAUTH_SCOPE_NETWORK,
711 NULL, NULL);
712
713 /* Register machdep scope. */
714 kauth_builtin_scope_machdep = kauth_register_scope(KAUTH_SCOPE_MACHDEP,
715 NULL, NULL);
716
717 /* Register device scope. */
718 kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE,
719 NULL, NULL);
720 }
721
722 /*
723 * Deregister a scope.
724 * Requires scope list lock to be held by the caller.
725 *
726 * scope - the scope to deregister
727 */
728 void
729 kauth_deregister_scope(kauth_scope_t scope)
730 {
731 if (scope != NULL) {
732 /* Remove scope from list */
733 SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope);
734 kmem_free(scope, sizeof(*scope));
735 }
736 }
737
738 /*
739 * Register a listener.
740 *
741 * id - scope identifier.
742 * callback - the callback routine for the listener.
743 * cookie - cookie to pass unmoidfied to the callback.
744 */
745 kauth_listener_t
746 kauth_listen_scope(const char *id, kauth_scope_callback_t callback,
747 void *cookie)
748 {
749 kauth_scope_t scope;
750 kauth_listener_t listener;
751
752 listener = kmem_alloc(sizeof(*listener), KM_SLEEP);
753 if (listener == NULL)
754 return (NULL);
755
756 rw_enter(&kauth_lock, RW_WRITER);
757
758 /*
759 * Find scope struct.
760 */
761 scope = kauth_ifindscope(id);
762 if (scope == NULL) {
763 rw_exit(&kauth_lock);
764 kmem_free(listener, sizeof(*listener));
765 return (NULL);
766 }
767
768 /* Allocate listener */
769
770 /* Initialize listener with parameters */
771 listener->func = callback;
772 listener->refcnt = 0;
773
774 /* Add listener to scope */
775 SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next);
776
777 /* Raise number of listeners on scope. */
778 scope->nlisteners++;
779 listener->scope = scope;
780
781 rw_exit(&kauth_lock);
782
783 return (listener);
784 }
785
786 /*
787 * Deregister a listener.
788 *
789 * listener - listener reference as returned from kauth_listen_scope().
790 */
791 void
792 kauth_unlisten_scope(kauth_listener_t listener)
793 {
794
795 if (listener != NULL) {
796 rw_enter(&kauth_lock, RW_WRITER);
797 SIMPLEQ_REMOVE(&listener->scope->listenq, listener,
798 kauth_listener, listener_next);
799 listener->scope->nlisteners--;
800 rw_exit(&kauth_lock);
801 kmem_free(listener, sizeof(*listener));
802 }
803 }
804
805 /*
806 * Authorize a request.
807 *
808 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as
809 * returned from kauth_register_scope().
810 * credential - credentials of the user ("actor") making the request.
811 * action - request identifier.
812 * arg[0-3] - passed unmodified to listener(s).
813 */
814 int
815 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred,
816 kauth_action_t action, void *arg0, void *arg1,
817 void *arg2, void *arg3)
818 {
819 kauth_listener_t listener;
820 int error, allow, fail;
821
822 #if 0 /* defined(LOCKDEBUG) */
823 spinlock_switchcheck();
824 simple_lock_only_held(NULL, "kauth_authorize_action");
825 #endif
826
827 KASSERT(cred != NULL);
828 KASSERT(action != 0);
829
830 /* Short-circuit requests coming from the kernel. */
831 if (cred == NOCRED || cred == FSCRED)
832 return (0);
833
834 KASSERT(scope != NULL);
835
836 fail = 0;
837 allow = 0;
838
839 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */
840 SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) {
841 error = listener->func(cred, action, scope->cookie, arg0,
842 arg1, arg2, arg3);
843
844 if (error == KAUTH_RESULT_ALLOW)
845 allow = 1;
846 else if (error == KAUTH_RESULT_DENY)
847 fail = 1;
848 }
849 /* rw_exit(&kauth_lock); */
850
851 if (fail)
852 return (EPERM);
853
854 if (allow)
855 return (0);
856
857 if (!nsecmodels)
858 return (0);
859
860 return (EPERM);
861 };
862
863 /*
864 * Generic scope authorization wrapper.
865 */
866 int
867 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0)
868 {
869 return (kauth_authorize_action(kauth_builtin_scope_generic, cred,
870 action, arg0, NULL, NULL, NULL));
871 }
872
873 /*
874 * System scope authorization wrapper.
875 */
876 int
877 kauth_authorize_system(kauth_cred_t cred, kauth_action_t action,
878 enum kauth_system_req req, void *arg1, void *arg2, void *arg3)
879 {
880 return (kauth_authorize_action(kauth_builtin_scope_system, cred,
881 action, (void *)req, arg1, arg2, arg3));
882 }
883
884 /*
885 * Process scope authorization wrapper.
886 */
887 int
888 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action,
889 struct proc *p, void *arg1, void *arg2, void *arg3)
890 {
891 return (kauth_authorize_action(kauth_builtin_scope_process, cred,
892 action, p, arg1, arg2, arg3));
893 }
894
895 /*
896 * Network scope authorization wrapper.
897 */
898 int
899 kauth_authorize_network(kauth_cred_t cred, kauth_action_t action,
900 enum kauth_network_req req, void *arg1, void *arg2, void *arg3)
901 {
902 return (kauth_authorize_action(kauth_builtin_scope_network, cred,
903 action, (void *)req, arg1, arg2, arg3));
904 }
905
906 int
907 kauth_authorize_machdep(kauth_cred_t cred, kauth_action_t action,
908 void *arg0, void *arg1, void *arg2, void *arg3)
909 {
910 return (kauth_authorize_action(kauth_builtin_scope_machdep, cred,
911 action, arg0, arg1, arg2, arg3));
912 }
913
914 int
915 kauth_authorize_device(kauth_cred_t cred, kauth_action_t action,
916 void *arg0, void *arg1, void *arg2, void *arg3)
917 {
918 return (kauth_authorize_action(kauth_builtin_scope_device, cred,
919 action, arg0, arg1, arg2, arg3));
920 }
921
922 int
923 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action,
924 struct tty *tty)
925 {
926 return (kauth_authorize_action(kauth_builtin_scope_device, cred,
927 action, tty, NULL, NULL, NULL));
928 }
929
930 int
931 kauth_authorize_device_spec(kauth_cred_t cred, enum kauth_device_req req,
932 struct vnode *vp)
933 {
934 return (kauth_authorize_action(kauth_builtin_scope_device, cred,
935 KAUTH_DEVICE_RAWIO_SPEC, (void *)req, vp, NULL, NULL));
936 }
937
938 int
939 kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits,
940 void *data)
941 {
942 return (kauth_authorize_action(kauth_builtin_scope_device, cred,
943 KAUTH_DEVICE_RAWIO_PASSTHRU, (void *)bits, (void *)(u_long)dev,
944 data, NULL));
945 }
946
947 static int
948 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0,
949 void *arg1)
950 {
951 int r;
952
953 r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action,
954 arg0, arg1, NULL, NULL);
955
956 #ifdef DIAGNOSTIC
957 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred->listenq))
958 KASSERT(r == 0);
959 #endif /* DIAGNOSTIC */
960
961 return (r);
962 }
963
964 void
965 secmodel_register(void)
966 {
967 KASSERT(nsecmodels + 1 != 0);
968
969 rw_enter(&kauth_lock, RW_WRITER);
970 nsecmodels++;
971 rw_exit(&kauth_lock);
972 }
973
974 void
975 secmodel_deregister(void)
976 {
977 KASSERT(nsecmodels != 0);
978
979 rw_enter(&kauth_lock, RW_WRITER);
980 nsecmodels--;
981 rw_exit(&kauth_lock);
982 }
983