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