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