1/* $NetBSD: secmodel.c,v 1.1 2011/12/04 19:24:59 jym Exp $ */ 2/*- 3 * Copyright (c) 2011 Elad Efrat <elad@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. */ 42static LIST_HEAD(, secmodel_descr) secmodels = 43 LIST_HEAD_INITIALIZER(secmodels); 44static unsigned int secmodel_copy_cred_on_fork = false; 45static krwlock_t secmodels_lock; 46static int nsecmodels = 0; /* number of registered secmodels */ 47 48static int secmodel_plug(secmodel_t); 49static int secmodel_unplug(secmodel_t); 50 51int 52secmodel_nsecmodels(void) 53{ 54 55 return nsecmodels; 56} 57 58void 59secmodel_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 */ 70int 71secmodel_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 */ 101int 102secmodel_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 */ 120static secmodel_t 121secmodel_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 */ 142static void 143secmodel_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 168static int 169secmodel_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 198static int 199secmodel_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 */ 229int 230secmodel_setinfo(const char *id, void *v, int *err) 231{ 232 233 return EOPNOTSUPP; 234} 235 236int 237secmodel_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