[BACK]Return to kern_auth.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/kern_auth.c, Revision 1.51.8.3

1.51.8.3! matt        1: /* $NetBSD: kern_auth.c,v 1.51.8.2 2007/11/08 10:59:59 matt Exp $ */
        !             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.51.8.3! matt       67: __KERNEL_RCSID(0, "$NetBSD: kern_auth.c,v 1.51.8.2 2007/11/08 10:59:59 matt 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.51.8.3! matt       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.51.8.2  matt       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.51.8.3! matt      106:        uint8_t cr_pad[CACHE_LINE_SIZE - sizeof(u_int)];
        !           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.51.8.3! 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.51.8.2  matt      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.51.8.2  matt      166:        cred = pool_cache_get(kauth_cred_cache, PR_WAITOK);
                    167:
1.2       elad      168:        cred->cr_refcnt = 1;
1.51.8.2  matt      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.51.8.3! matt      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.51.8.3! matt      201:        if (atomic_dec_uint_nv(&cred->cr_refcnt) > 0)
        !           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.51.8.1  matt      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.51.8.1  matt      449:                if (seg == UIO_SYSSPACE) {
1.49      dsl       450:                        memcpy(cred->cr_groups, grbuf,
                    451:                            len * sizeof(cred->cr_groups[0]));
1.51.8.1  matt      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.51.8.1  matt      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.51.8.1  matt      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.51.8.2  matt      808:        kauth_cred_cache = pool_cache_init(sizeof(struct kauth_cred),
                    809:            CACHE_LINE_SIZE, 0, 0, "kcredpl", NULL, IPL_NONE,
1.51.8.3! matt      810:            NULL, NULL, NULL);
1.51.8.2  matt      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>