[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.54

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

CVSweb <webmaster@jp.NetBSD.org>