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