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. */ 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 error = EFAULT; 176 goto out; 177 } 178 179 /* Check if the secmodel is already present. */ 180 rw_enter(&secmodels_lock, RW_WRITER); 181 tsm = secmodel_lookup(sm->sm_id); 182 if (tsm != NULL) { 183 error = EEXIST; 184 goto out; 185 } 186 187 /* Add the secmodel. */ 188 LIST_INSERT_HEAD(&secmodels, sm, sm_list); 189 190 /* Adjust behavior. */ 191 secmodel_adjust_behavior(sm, true); 192 193 out: 194 /* Unlock the secmodels list. */ 195 rw_exit(&secmodels_lock); 196 197 return error; 198 } 199 200 static int 201 secmodel_unplug(secmodel_t sm) 202 { 203 secmodel_t tsm; 204 int error = 0; 205 206 if (sm == NULL) { 207 error = EFAULT; 208 goto out; 209 } 210 211 /* Make sure the secmodel is present. */ 212 rw_enter(&secmodels_lock, RW_WRITER); 213 tsm = secmodel_lookup(sm->sm_id); 214 if (tsm == NULL) { 215 error = ENOENT; 216 goto out; 217 } 218 219 /* Remove the secmodel. */ 220 LIST_REMOVE(tsm, sm_list); 221 222 /* Adjust behavior. */ 223 secmodel_adjust_behavior(tsm, false); 224 225 out: 226 /* Unlock the secmodels list. */ 227 rw_exit(&secmodels_lock); 228 229 return error; 230 } 231 232 /* XXX TODO */ 233 int 234 secmodel_setinfo(const char *id, void *v, int *err) 235 { 236 237 return EOPNOTSUPP; 238 } 239 240 int 241 secmodel_eval(const char *id, const char *what, void *arg, void *ret) 242 { 243 secmodel_t sm; 244 int error = 0; 245 246 rw_enter(&secmodels_lock, RW_READER); 247 sm = secmodel_lookup(id); 248 if (sm == NULL) { 249 error = EINVAL; 250 goto out; 251 } 252 253 if (sm->sm_eval == NULL) { 254 error = ENOENT; 255 goto out; 256 } 257 258 if (ret == NULL) { 259 error = EFAULT; 260 goto out; 261 } 262 263 error = sm->sm_eval(what, arg, ret); 264 /* pass error from a secmodel(9) callback as a negative value */ 265 error = -error; 266 267 out: 268 rw_exit(&secmodels_lock); 269 270 return error; 271 } 272