The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_auth.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 98bae1a94a0d1acfcec19709ffe771be


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.