1 1.2 maxv /* $NetBSD: secmodel.c,v 1.2 2014/11/04 16:01:58 maxv 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.2 maxv if (sm == NULL) 175 1.2 maxv 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.2 maxv if (sm == NULL) 205 1.2 maxv 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