Home | History | Annotate | Line # | Download | only in secmodel
      1 /* $NetBSD: secmodel.c,v 1.2 2014/11/04 16:01:58 maxv Exp $ */
      2 /*-
      3  * Copyright (c) 2011 Elad Efrat <elad (at) NetBSD.org>
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/types.h>
     30 #include <sys/param.h>
     31 #include <sys/errno.h>
     32 
     33 #include <sys/atomic.h>
     34 #include <sys/kauth.h>
     35 #include <sys/kmem.h>
     36 #include <sys/queue.h>
     37 #include <sys/rwlock.h>
     38 #include <secmodel/secmodel.h>
     39 #include <prop/proplib.h>
     40 
     41 /* List of secmodels, parameters, and lock. */
     42 static LIST_HEAD(, secmodel_descr) secmodels =
     43     LIST_HEAD_INITIALIZER(secmodels);
     44 static unsigned int secmodel_copy_cred_on_fork = false;
     45 static krwlock_t secmodels_lock;
     46 static int nsecmodels = 0; /* number of registered secmodels */
     47 
     48 static int secmodel_plug(secmodel_t);
     49 static int secmodel_unplug(secmodel_t);
     50 
     51 int
     52 secmodel_nsecmodels(void)
     53 {
     54 
     55 	return nsecmodels;
     56 }
     57 
     58 void
     59 secmodel_init(void)
     60 {
     61 
     62 	rw_init(&secmodels_lock);
     63 
     64 	secmodel_copy_cred_on_fork = false;
     65 }
     66 
     67 /*
     68  * Register a new secmodel.
     69  */
     70 int
     71 secmodel_register(secmodel_t *secmodel, const char *id, const char *name,
     72 		  prop_dictionary_t behavior,
     73 		  secmodel_eval_t eval, secmodel_setinfo_t setinfo)
     74 {
     75 	int err;
     76 	secmodel_t sm;
     77 
     78 	sm = kmem_alloc(sizeof(*sm), KM_SLEEP);
     79 
     80 	sm->sm_id = id;
     81 	sm->sm_name = name;
     82 	sm->sm_behavior = behavior;
     83 	sm->sm_eval = eval;
     84 	sm->sm_setinfo = setinfo;
     85 
     86 	err = secmodel_plug(sm);
     87 	if (err == 0) {
     88 		atomic_inc_uint(&nsecmodels);
     89 	} else {
     90 		kmem_free(sm, sizeof(*sm));
     91 		sm = NULL;
     92 	}
     93 
     94 	*secmodel = sm;
     95 	return err;
     96 }
     97 
     98 /*
     99  * Deregister a secmodel.
    100  */
    101 int
    102 secmodel_deregister(secmodel_t sm)
    103 {
    104 	int error;
    105 
    106 	error = secmodel_unplug(sm);
    107 	if (error == 0) {
    108 		atomic_dec_uint(&nsecmodels);
    109 		kmem_free(sm, sizeof(*sm));
    110 	}
    111 
    112 	return error;
    113 }
    114 
    115 /*
    116  * Lookup a secmodel by its id.
    117  *
    118  * Requires "secmodels_lock" handling by the caller.
    119  */
    120 static secmodel_t
    121 secmodel_lookup(const char *id)
    122 {
    123 	secmodel_t tsm;
    124 
    125 	KASSERT(rw_lock_held(&secmodels_lock));
    126 
    127 	LIST_FOREACH(tsm, &secmodels, sm_list) {
    128 		if (strcasecmp(tsm->sm_id, id) == 0) {
    129 			return tsm;
    130 		}
    131 	}
    132 
    133 	return NULL;
    134 }
    135 
    136 /*
    137  * Adjust system-global secmodel behavior following the addition
    138  * or removal of a secmodel.
    139  *
    140  * Requires "secmodels_lock" to be held by the caller.
    141  */
    142 static void
    143 secmodel_adjust_behavior(secmodel_t sm, bool added)
    144 {
    145 	bool r, b;
    146 
    147 	KASSERT(rw_write_held(&secmodels_lock));
    148 
    149 #define	ADJUST_COUNTER(which, added)		\
    150 	do {					\
    151 		if (added) {			\
    152 			(which)++;		\
    153 		} else {			\
    154 			if ((which) > 0)	\
    155 				(which)--;	\
    156 		}				\
    157 	} while (/*CONSTCOND*/0)
    158 
    159 	/* Copy credentials on fork? */
    160 	r = prop_dictionary_get_bool(sm->sm_behavior, "copy-cred-on-fork", &b);
    161 	if (r) {
    162 		ADJUST_COUNTER(secmodel_copy_cred_on_fork, added);
    163 	}
    164 
    165 #undef ADJUST_COUNTER
    166 }
    167 
    168 static int
    169 secmodel_plug(secmodel_t sm)
    170 {
    171 	secmodel_t tsm;
    172 	int error = 0;
    173 
    174 	if (sm == NULL)
    175 		return EFAULT;
    176 
    177 	/* Check if the secmodel is already present. */
    178 	rw_enter(&secmodels_lock, RW_WRITER);
    179 	tsm = secmodel_lookup(sm->sm_id);
    180 	if (tsm != NULL) {
    181 		error = EEXIST;
    182 		goto out;
    183 	}
    184 
    185 	/* Add the secmodel. */
    186 	LIST_INSERT_HEAD(&secmodels, sm, sm_list);
    187 
    188 	/* Adjust behavior. */
    189 	secmodel_adjust_behavior(sm, true);
    190 
    191  out:
    192 	/* Unlock the secmodels list. */
    193 	rw_exit(&secmodels_lock);
    194 
    195 	return error;
    196 }
    197 
    198 static int
    199 secmodel_unplug(secmodel_t sm)
    200 {
    201 	secmodel_t tsm;
    202 	int error = 0;
    203 
    204 	if (sm == NULL)
    205 		return EFAULT;
    206 
    207 	/* Make sure the secmodel is present. */
    208 	rw_enter(&secmodels_lock, RW_WRITER);
    209 	tsm = secmodel_lookup(sm->sm_id);
    210 	if (tsm == NULL) {
    211 		error = ENOENT;
    212 		goto out;
    213 	}
    214 
    215 	/* Remove the secmodel. */
    216 	LIST_REMOVE(tsm, sm_list);
    217 
    218 	/* Adjust behavior. */
    219 	secmodel_adjust_behavior(tsm, false);
    220 
    221  out:
    222 	/* Unlock the secmodels list. */
    223 	rw_exit(&secmodels_lock);
    224 
    225 	return error;
    226 }
    227 
    228 /* XXX TODO */
    229 int
    230 secmodel_setinfo(const char *id, void *v, int *err)
    231 {
    232 
    233 	return EOPNOTSUPP;
    234 }
    235 
    236 int
    237 secmodel_eval(const char *id, const char *what, void *arg, void *ret)
    238 {
    239 	secmodel_t sm;
    240 	int error = 0;
    241 
    242 	rw_enter(&secmodels_lock, RW_READER);
    243 	sm = secmodel_lookup(id);
    244 	if (sm == NULL) {
    245 		error = EINVAL;
    246 		goto out;
    247 	}
    248 
    249 	if (sm->sm_eval == NULL) {
    250 		error = ENOENT;
    251 		goto out;
    252 	}
    253 
    254 	if (ret == NULL) {
    255 		error = EFAULT;
    256 		goto out;
    257 	}
    258 
    259 	error = sm->sm_eval(what, arg, ret);
    260 	/* pass error from a secmodel(9) callback as a negative value */
    261 	error = -error;
    262 
    263  out:
    264 	rw_exit(&secmodels_lock);
    265 
    266 	return error;
    267 }
    268