xref: /netbsd-src/sys/kern/kern_auth.c (revision 76c7fc5f6b13ed0b1508e6b313e88e59977ed78e)
1 /* $NetBSD: kern_auth.c,v 1.77 2018/09/03 16:29:35 riastradh Exp $ */
2 
3 /*-
4  * Copyright (c) 2005, 2006 Elad Efrat <elad@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.77 2018/09/03 16:29:35 riastradh 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