1 /* $NetBSD: kern_auth.c,v 1.75 2015/10/06 22:13:39 christos 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.75 2015/10/06 22:13:39 christos 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
kauth_cred_alloc(void)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
kauth_cred_hold(kauth_cred_t cred)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
kauth_cred_free(kauth_cred_t cred)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
kauth_cred_clone1(kauth_cred_t from,kauth_cred_t to,bool copy_groups)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
kauth_cred_clone(kauth_cred_t from,kauth_cred_t to)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
kauth_cred_dup(kauth_cred_t cred)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
kauth_cred_copy(kauth_cred_t cred)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
kauth_proc_fork(struct proc * parent,struct proc * child)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
kauth_proc_chroot(kauth_cred_t cred,struct cwdinfo * cwdi)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
kauth_cred_getuid(kauth_cred_t cred)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
kauth_cred_geteuid(kauth_cred_t cred)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
kauth_cred_getsvuid(kauth_cred_t cred)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
kauth_cred_getgid(kauth_cred_t cred)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
kauth_cred_getegid(kauth_cred_t cred)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
kauth_cred_getsvgid(kauth_cred_t cred)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
kauth_cred_setuid(kauth_cred_t cred,uid_t uid)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
kauth_cred_seteuid(kauth_cred_t cred,uid_t uid)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
kauth_cred_setsvuid(kauth_cred_t cred,uid_t uid)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
kauth_cred_setgid(kauth_cred_t cred,gid_t gid)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
kauth_cred_setegid(kauth_cred_t cred,gid_t gid)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
kauth_cred_setsvgid(kauth_cred_t cred,gid_t gid)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
kauth_cred_ismember_gid(kauth_cred_t cred,gid_t gid,int * resultp)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
kauth_cred_ngroups(kauth_cred_t cred)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
kauth_cred_group(kauth_cred_t cred,u_int idx)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
kauth_cred_setgroups(kauth_cred_t cred,const gid_t * grbuf,size_t len,uid_t gmuid,enum uio_seg seg)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
kauth_proc_setgroups(struct lwp * l,kauth_cred_t ncred)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
kauth_cred_getgroups(kauth_cred_t cred,gid_t * grbuf,size_t len,enum uio_seg seg)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
kauth_register_key(secmodel_t secmodel,kauth_key_t * result)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
kauth_deregister_key(kauth_key_t key)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 *
kauth_cred_getdata(kauth_cred_t cred,kauth_key_t key)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
kauth_cred_setdata(kauth_cred_t cred,kauth_key_t key,void * data)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
kauth_cred_uidmatch(kauth_cred_t cred1,kauth_cred_t cred2)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
kauth_cred_getrefcnt(kauth_cred_t cred)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
kauth_uucred_to_cred(kauth_cred_t cred,const struct uucred * uuc)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 = min(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
kauth_cred_to_uucred(struct uucred * uuc,const kauth_cred_t cred)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 = min(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
kauth_cred_uucmp(kauth_cred_t cred,const struct uucred * uuc)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
kauth_cred_toucred(kauth_cred_t cred,struct ki_ucred * uc)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 = min(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
kauth_cred_topcred(kauth_cred_t cred,struct ki_pcred * pc)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
kauth_cred_get(void)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
kauth_ifindscope(const char * id)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
kauth_register_scope(const char * id,kauth_scope_callback_t callback,void * cookie)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 (scope == NULL)
758 return NULL;
759 if (callback != NULL) {
760 listener = kmem_alloc(sizeof(*listener), KM_SLEEP);
761 if (listener == NULL) {
762 kmem_free(scope, sizeof(*scope));
763 return (NULL);
764 }
765 }
766
767 /*
768 * Acquire scope list lock.
769 */
770 rw_enter(&kauth_lock, RW_WRITER);
771
772 /* Check we don't already have a scope with the same id */
773 if (kauth_ifindscope(id) != NULL) {
774 rw_exit(&kauth_lock);
775
776 kmem_free(scope, sizeof(*scope));
777 if (callback != NULL)
778 kmem_free(listener, sizeof(*listener));
779
780 return (NULL);
781 }
782
783 /* Initialize new scope with parameters */
784 scope->id = id;
785 scope->cookie = cookie;
786 scope->nlisteners = 1;
787
788 SIMPLEQ_INIT(&scope->listenq);
789
790 /* Add default listener */
791 if (callback != NULL) {
792 listener->func = callback;
793 listener->scope = scope;
794 listener->refcnt = 0;
795 SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next);
796 }
797
798 /* Insert scope to scopes list */
799 SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope);
800
801 rw_exit(&kauth_lock);
802
803 return (scope);
804 }
805
806 /*
807 * Initialize the kernel authorization subsystem.
808 *
809 * Initialize the scopes list lock.
810 * Create specificdata domain.
811 * Register the credentials scope, used in kauth(9) internally.
812 * Register built-in scopes: generic, system, process, network, machdep, device.
813 */
814 void
kauth_init(void)815 kauth_init(void)
816 {
817 rw_init(&kauth_lock);
818
819 kauth_cred_cache = pool_cache_init(sizeof(struct kauth_cred),
820 coherency_unit, 0, 0, "kcredpl", NULL, IPL_NONE,
821 NULL, NULL, NULL);
822
823 /* Create specificdata domain. */
824 kauth_domain = specificdata_domain_create();
825
826 /* Register credentials scope. */
827 kauth_builtin_scope_cred =
828 kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL);
829
830 /* Register generic scope. */
831 kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC,
832 NULL, NULL);
833
834 /* Register system scope. */
835 kauth_builtin_scope_system = kauth_register_scope(KAUTH_SCOPE_SYSTEM,
836 NULL, NULL);
837
838 /* Register process scope. */
839 kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS,
840 NULL, NULL);
841
842 /* Register network scope. */
843 kauth_builtin_scope_network = kauth_register_scope(KAUTH_SCOPE_NETWORK,
844 NULL, NULL);
845
846 /* Register machdep scope. */
847 kauth_builtin_scope_machdep = kauth_register_scope(KAUTH_SCOPE_MACHDEP,
848 NULL, NULL);
849
850 /* Register device scope. */
851 kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE,
852 NULL, NULL);
853
854 /* Register vnode scope. */
855 kauth_builtin_scope_vnode = kauth_register_scope(KAUTH_SCOPE_VNODE,
856 NULL, NULL);
857 }
858
859 /*
860 * Deregister a scope.
861 * Requires scope list lock to be held by the caller.
862 *
863 * scope - the scope to deregister
864 */
865 void
kauth_deregister_scope(kauth_scope_t scope)866 kauth_deregister_scope(kauth_scope_t scope)
867 {
868 if (scope != NULL) {
869 /* Remove scope from list */
870 SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope);
871 kmem_free(scope, sizeof(*scope));
872 }
873 }
874
875 /*
876 * Register a listener.
877 *
878 * id - scope identifier.
879 * callback - the callback routine for the listener.
880 * cookie - cookie to pass unmoidfied to the callback.
881 */
882 kauth_listener_t
kauth_listen_scope(const char * id,kauth_scope_callback_t callback,void * cookie)883 kauth_listen_scope(const char *id, kauth_scope_callback_t callback,
884 void *cookie)
885 {
886 kauth_scope_t scope;
887 kauth_listener_t listener;
888
889 listener = kmem_alloc(sizeof(*listener), KM_SLEEP);
890 if (listener == NULL)
891 return (NULL);
892
893 rw_enter(&kauth_lock, RW_WRITER);
894
895 /*
896 * Find scope struct.
897 */
898 scope = kauth_ifindscope(id);
899 if (scope == NULL) {
900 rw_exit(&kauth_lock);
901 kmem_free(listener, sizeof(*listener));
902 return (NULL);
903 }
904
905 /* Allocate listener */
906
907 /* Initialize listener with parameters */
908 listener->func = callback;
909 listener->refcnt = 0;
910
911 /* Add listener to scope */
912 SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next);
913
914 /* Raise number of listeners on scope. */
915 scope->nlisteners++;
916 listener->scope = scope;
917
918 rw_exit(&kauth_lock);
919
920 return (listener);
921 }
922
923 /*
924 * Deregister a listener.
925 *
926 * listener - listener reference as returned from kauth_listen_scope().
927 */
928 void
kauth_unlisten_scope(kauth_listener_t listener)929 kauth_unlisten_scope(kauth_listener_t listener)
930 {
931
932 if (listener != NULL) {
933 rw_enter(&kauth_lock, RW_WRITER);
934 SIMPLEQ_REMOVE(&listener->scope->listenq, listener,
935 kauth_listener, listener_next);
936 listener->scope->nlisteners--;
937 rw_exit(&kauth_lock);
938 kmem_free(listener, sizeof(*listener));
939 }
940 }
941
942 /*
943 * Authorize a request.
944 *
945 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as
946 * returned from kauth_register_scope().
947 * credential - credentials of the user ("actor") making the request.
948 * action - request identifier.
949 * arg[0-3] - passed unmodified to listener(s).
950 *
951 * Returns the aggregated result:
952 * - KAUTH_RESULT_ALLOW if there is at least one KAUTH_RESULT_ALLOW and
953 * zero KAUTH_DESULT_DENY
954 * - KAUTH_RESULT_DENY if there is at least one KAUTH_RESULT_DENY
955 * - KAUTH_RESULT_DEFER if there is nothing but KAUTH_RESULT_DEFER
956 */
957 static int
kauth_authorize_action_internal(kauth_scope_t scope,kauth_cred_t cred,kauth_action_t action,void * arg0,void * arg1,void * arg2,void * arg3)958 kauth_authorize_action_internal(kauth_scope_t scope, kauth_cred_t cred,
959 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3)
960 {
961 kauth_listener_t listener;
962 int error, allow, fail;
963
964 KASSERT(cred != NULL);
965 KASSERT(action != 0);
966
967 /* Short-circuit requests coming from the kernel. */
968 if (cred == NOCRED || cred == FSCRED)
969 return KAUTH_RESULT_ALLOW;
970
971 KASSERT(scope != NULL);
972
973 fail = 0;
974 allow = 0;
975
976 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */
977 SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) {
978 error = listener->func(cred, action, scope->cookie, arg0,
979 arg1, arg2, arg3);
980
981 if (error == KAUTH_RESULT_ALLOW)
982 allow = 1;
983 else if (error == KAUTH_RESULT_DENY)
984 fail = 1;
985 }
986 /* rw_exit(&kauth_lock); */
987
988 if (fail)
989 return (KAUTH_RESULT_DENY);
990
991 if (allow)
992 return (KAUTH_RESULT_ALLOW);
993
994 return (KAUTH_RESULT_DEFER);
995 };
996
997 int
kauth_authorize_action(kauth_scope_t scope,kauth_cred_t cred,kauth_action_t action,void * arg0,void * arg1,void * arg2,void * arg3)998 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred,
999 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3)
1000 {
1001 int r;
1002
1003 r = kauth_authorize_action_internal(scope, cred, action, arg0, arg1,
1004 arg2, arg3);
1005
1006 if (r == KAUTH_RESULT_DENY)
1007 return (EPERM);
1008
1009 if (r == KAUTH_RESULT_ALLOW)
1010 return (0);
1011
1012 if (secmodel_nsecmodels() == 0)
1013 return (0);
1014
1015 return (EPERM);
1016 }
1017
1018 /*
1019 * Generic scope authorization wrapper.
1020 */
1021 int
kauth_authorize_generic(kauth_cred_t cred,kauth_action_t action,void * arg0)1022 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0)
1023 {
1024 return (kauth_authorize_action(kauth_builtin_scope_generic, cred,
1025 action, arg0, NULL, NULL, NULL));
1026 }
1027
1028 /*
1029 * System scope authorization wrapper.
1030 */
1031 int
kauth_authorize_system(kauth_cred_t cred,kauth_action_t action,enum kauth_system_req req,void * arg1,void * arg2,void * arg3)1032 kauth_authorize_system(kauth_cred_t cred, kauth_action_t action,
1033 enum kauth_system_req req, void *arg1, void *arg2, void *arg3)
1034 {
1035 return (kauth_authorize_action(kauth_builtin_scope_system, cred,
1036 action, (void *)req, arg1, arg2, arg3));
1037 }
1038
1039 /*
1040 * Process scope authorization wrapper.
1041 */
1042 int
kauth_authorize_process(kauth_cred_t cred,kauth_action_t action,struct proc * p,void * arg1,void * arg2,void * arg3)1043 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action,
1044 struct proc *p, void *arg1, void *arg2, void *arg3)
1045 {
1046 return (kauth_authorize_action(kauth_builtin_scope_process, cred,
1047 action, p, arg1, arg2, arg3));
1048 }
1049
1050 /*
1051 * Network scope authorization wrapper.
1052 */
1053 int
kauth_authorize_network(kauth_cred_t cred,kauth_action_t action,enum kauth_network_req req,void * arg1,void * arg2,void * arg3)1054 kauth_authorize_network(kauth_cred_t cred, kauth_action_t action,
1055 enum kauth_network_req req, void *arg1, void *arg2, void *arg3)
1056 {
1057 return (kauth_authorize_action(kauth_builtin_scope_network, cred,
1058 action, (void *)req, arg1, arg2, arg3));
1059 }
1060
1061 int
kauth_authorize_machdep(kauth_cred_t cred,kauth_action_t action,void * arg0,void * arg1,void * arg2,void * arg3)1062 kauth_authorize_machdep(kauth_cred_t cred, kauth_action_t action,
1063 void *arg0, void *arg1, void *arg2, void *arg3)
1064 {
1065 return (kauth_authorize_action(kauth_builtin_scope_machdep, cred,
1066 action, arg0, arg1, arg2, arg3));
1067 }
1068
1069 int
kauth_authorize_device(kauth_cred_t cred,kauth_action_t action,void * arg0,void * arg1,void * arg2,void * arg3)1070 kauth_authorize_device(kauth_cred_t cred, kauth_action_t action,
1071 void *arg0, void *arg1, void *arg2, void *arg3)
1072 {
1073 return (kauth_authorize_action(kauth_builtin_scope_device, cred,
1074 action, arg0, arg1, arg2, arg3));
1075 }
1076
1077 int
kauth_authorize_device_tty(kauth_cred_t cred,kauth_action_t action,struct tty * tty)1078 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action,
1079 struct tty *tty)
1080 {
1081 return (kauth_authorize_action(kauth_builtin_scope_device, cred,
1082 action, tty, NULL, NULL, NULL));
1083 }
1084
1085 int
kauth_authorize_device_spec(kauth_cred_t cred,enum kauth_device_req req,struct vnode * vp)1086 kauth_authorize_device_spec(kauth_cred_t cred, enum kauth_device_req req,
1087 struct vnode *vp)
1088 {
1089 return (kauth_authorize_action(kauth_builtin_scope_device, cred,
1090 KAUTH_DEVICE_RAWIO_SPEC, (void *)req, vp, NULL, NULL));
1091 }
1092
1093 int
kauth_authorize_device_passthru(kauth_cred_t cred,dev_t dev,u_long bits,void * data)1094 kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits,
1095 void *data)
1096 {
1097 return (kauth_authorize_action(kauth_builtin_scope_device, cred,
1098 KAUTH_DEVICE_RAWIO_PASSTHRU, (void *)bits, (void *)(u_long)dev,
1099 data, NULL));
1100 }
1101
1102 kauth_action_t
kauth_mode_to_action(mode_t mode)1103 kauth_mode_to_action(mode_t mode)
1104 {
1105 kauth_action_t action = 0;
1106
1107 if (mode & VREAD)
1108 action |= KAUTH_VNODE_READ_DATA;
1109 if (mode & VWRITE)
1110 action |= KAUTH_VNODE_WRITE_DATA;
1111 if (mode & VEXEC)
1112 action |= KAUTH_VNODE_EXECUTE;
1113
1114 return action;
1115 }
1116
1117 kauth_action_t
kauth_extattr_action(mode_t access_mode)1118 kauth_extattr_action(mode_t access_mode)
1119 {
1120 kauth_action_t action = 0;
1121
1122 if (access_mode & VREAD)
1123 action |= KAUTH_VNODE_READ_EXTATTRIBUTES;
1124 if (access_mode & VWRITE)
1125 action |= KAUTH_VNODE_WRITE_EXTATTRIBUTES;
1126
1127 return action;
1128 }
1129
1130 int
kauth_authorize_vnode(kauth_cred_t cred,kauth_action_t action,struct vnode * vp,struct vnode * dvp,int fs_decision)1131 kauth_authorize_vnode(kauth_cred_t cred, kauth_action_t action,
1132 struct vnode *vp, struct vnode *dvp, int fs_decision)
1133 {
1134 int error;
1135
1136 error = kauth_authorize_action_internal(kauth_builtin_scope_vnode, cred,
1137 action, vp, dvp, NULL, NULL);
1138
1139 if (error == KAUTH_RESULT_DENY)
1140 return (EACCES);
1141
1142 if (error == KAUTH_RESULT_ALLOW)
1143 return (0);
1144
1145 /*
1146 * If the file-system does not support decision-before-action, we can
1147 * only short-circuit the operation (deny). If we're here, it means no
1148 * listener denied it, so our only alternative is to supposedly-allow
1149 * it and let the file-system have the last word.
1150 */
1151 if (fs_decision == KAUTH_VNODE_REMOTEFS)
1152 return (0);
1153
1154 return (fs_decision);
1155 }
1156
1157 static int
kauth_cred_hook(kauth_cred_t cred,kauth_action_t action,void * arg0,void * arg1)1158 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0,
1159 void *arg1)
1160 {
1161 int r;
1162
1163 r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action,
1164 arg0, arg1, NULL, NULL);
1165
1166 #ifdef DIAGNOSTIC
1167 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred->listenq))
1168 KASSERT(r == 0);
1169 #endif /* DIAGNOSTIC */
1170
1171 return (r);
1172 }
1173