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

Cache object: 6d20c3f9717aca4b461ecebf910da6b8


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