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