xref: /netbsd-src/sys/secmodel/secmodel.c (revision fc666c5147b36f016a261bb5cdc76b303417647d)
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
secmodel_nsecmodels(void)52 secmodel_nsecmodels(void)
53 {
54 
55 	return nsecmodels;
56 }
57 
58 void
secmodel_init(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
secmodel_register(secmodel_t * secmodel,const char * id,const char * name,prop_dictionary_t behavior,secmodel_eval_t eval,secmodel_setinfo_t setinfo)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
secmodel_deregister(secmodel_t sm)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
secmodel_lookup(const char * id)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
secmodel_adjust_behavior(secmodel_t sm,bool added)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
secmodel_plug(secmodel_t sm)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
secmodel_unplug(secmodel_t sm)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
secmodel_setinfo(const char * id,void * v,int * err)230 secmodel_setinfo(const char *id, void *v, int *err)
231 {
232 
233 	return EOPNOTSUPP;
234 }
235 
236 int
secmodel_eval(const char * id,const char * what,void * arg,void * ret)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