secmodel.c revision 1.1.6.2 1 /* $NetBSD: secmodel.c,v 1.1.6.2 2012/04/17 00:08:50 yamt Exp $ */
2 /*-
3 * Copyright (c) 2011 Elad Efrat <elad (at) 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