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