1 /* $NetBSD: secmodel.c,v 1.2 2014/11/04 16:01:58 maxv 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 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