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