xref: /netbsd-src/sys/secmodel/secmodel.c (revision fc666c5147b36f016a261bb5cdc76b303417647d)
1*fc666c51Smaxv /* $NetBSD: secmodel.c,v 1.2 2014/11/04 16:01:58 maxv Exp $ */
2926571dfSjym /*-
3926571dfSjym  * Copyright (c) 2011 Elad Efrat <elad@NetBSD.org>
4926571dfSjym  * All rights reserved.
5926571dfSjym  *
6926571dfSjym  * Redistribution and use in source and binary forms, with or without
7926571dfSjym  * modification, are permitted provided that the following conditions
8926571dfSjym  * are met:
9926571dfSjym  * 1. Redistributions of source code must retain the above copyright
10926571dfSjym  *    notice, this list of conditions and the following disclaimer.
11926571dfSjym  * 2. Redistributions in binary form must reproduce the above copyright
12926571dfSjym  *    notice, this list of conditions and the following disclaimer in the
13926571dfSjym  *    documentation and/or other materials provided with the distribution.
14926571dfSjym  * 3. The name of the author may not be used to endorse or promote products
15926571dfSjym  *    derived from this software without specific prior written permission.
16926571dfSjym  *
17926571dfSjym  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18926571dfSjym  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19926571dfSjym  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20926571dfSjym  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21926571dfSjym  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22926571dfSjym  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23926571dfSjym  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24926571dfSjym  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25926571dfSjym  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26926571dfSjym  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27926571dfSjym  */
28926571dfSjym 
29926571dfSjym #include <sys/types.h>
30926571dfSjym #include <sys/param.h>
31926571dfSjym #include <sys/errno.h>
32926571dfSjym 
33926571dfSjym #include <sys/atomic.h>
34926571dfSjym #include <sys/kauth.h>
35926571dfSjym #include <sys/kmem.h>
36926571dfSjym #include <sys/queue.h>
37926571dfSjym #include <sys/rwlock.h>
38926571dfSjym #include <secmodel/secmodel.h>
39926571dfSjym #include <prop/proplib.h>
40926571dfSjym 
41926571dfSjym /* List of secmodels, parameters, and lock. */
42926571dfSjym static LIST_HEAD(, secmodel_descr) secmodels =
43926571dfSjym     LIST_HEAD_INITIALIZER(secmodels);
44926571dfSjym static unsigned int secmodel_copy_cred_on_fork = false;
45926571dfSjym static krwlock_t secmodels_lock;
46926571dfSjym static int nsecmodels = 0; /* number of registered secmodels */
47926571dfSjym 
48926571dfSjym static int secmodel_plug(secmodel_t);
49926571dfSjym static int secmodel_unplug(secmodel_t);
50926571dfSjym 
51926571dfSjym int
secmodel_nsecmodels(void)52926571dfSjym secmodel_nsecmodels(void)
53926571dfSjym {
54926571dfSjym 
55926571dfSjym 	return nsecmodels;
56926571dfSjym }
57926571dfSjym 
58926571dfSjym void
secmodel_init(void)59926571dfSjym secmodel_init(void)
60926571dfSjym {
61926571dfSjym 
62926571dfSjym 	rw_init(&secmodels_lock);
63926571dfSjym 
64926571dfSjym 	secmodel_copy_cred_on_fork = false;
65926571dfSjym }
66926571dfSjym 
67926571dfSjym /*
68926571dfSjym  * Register a new secmodel.
69926571dfSjym  */
70926571dfSjym int
secmodel_register(secmodel_t * secmodel,const char * id,const char * name,prop_dictionary_t behavior,secmodel_eval_t eval,secmodel_setinfo_t setinfo)71926571dfSjym secmodel_register(secmodel_t *secmodel, const char *id, const char *name,
72926571dfSjym 		  prop_dictionary_t behavior,
73926571dfSjym 		  secmodel_eval_t eval, secmodel_setinfo_t setinfo)
74926571dfSjym {
75926571dfSjym 	int err;
76926571dfSjym 	secmodel_t sm;
77926571dfSjym 
78926571dfSjym 	sm = kmem_alloc(sizeof(*sm), KM_SLEEP);
79926571dfSjym 
80926571dfSjym 	sm->sm_id = id;
81926571dfSjym 	sm->sm_name = name;
82926571dfSjym 	sm->sm_behavior = behavior;
83926571dfSjym 	sm->sm_eval = eval;
84926571dfSjym 	sm->sm_setinfo = setinfo;
85926571dfSjym 
86926571dfSjym 	err = secmodel_plug(sm);
87926571dfSjym 	if (err == 0) {
88926571dfSjym 		atomic_inc_uint(&nsecmodels);
89926571dfSjym 	} else {
90926571dfSjym 		kmem_free(sm, sizeof(*sm));
91926571dfSjym 		sm = NULL;
92926571dfSjym 	}
93926571dfSjym 
94926571dfSjym 	*secmodel = sm;
95926571dfSjym 	return err;
96926571dfSjym }
97926571dfSjym 
98926571dfSjym /*
99926571dfSjym  * Deregister a secmodel.
100926571dfSjym  */
101926571dfSjym int
secmodel_deregister(secmodel_t sm)102926571dfSjym secmodel_deregister(secmodel_t sm)
103926571dfSjym {
104926571dfSjym 	int error;
105926571dfSjym 
106926571dfSjym 	error = secmodel_unplug(sm);
107926571dfSjym 	if (error == 0) {
108926571dfSjym 		atomic_dec_uint(&nsecmodels);
109926571dfSjym 		kmem_free(sm, sizeof(*sm));
110926571dfSjym 	}
111926571dfSjym 
112926571dfSjym 	return error;
113926571dfSjym }
114926571dfSjym 
115926571dfSjym /*
116926571dfSjym  * Lookup a secmodel by its id.
117926571dfSjym  *
118926571dfSjym  * Requires "secmodels_lock" handling by the caller.
119926571dfSjym  */
120926571dfSjym static secmodel_t
secmodel_lookup(const char * id)121926571dfSjym secmodel_lookup(const char *id)
122926571dfSjym {
123926571dfSjym 	secmodel_t tsm;
124926571dfSjym 
125926571dfSjym 	KASSERT(rw_lock_held(&secmodels_lock));
126926571dfSjym 
127926571dfSjym 	LIST_FOREACH(tsm, &secmodels, sm_list) {
128926571dfSjym 		if (strcasecmp(tsm->sm_id, id) == 0) {
129926571dfSjym 			return tsm;
130926571dfSjym 		}
131926571dfSjym 	}
132926571dfSjym 
133926571dfSjym 	return NULL;
134926571dfSjym }
135926571dfSjym 
136926571dfSjym /*
137926571dfSjym  * Adjust system-global secmodel behavior following the addition
138926571dfSjym  * or removal of a secmodel.
139926571dfSjym  *
140926571dfSjym  * Requires "secmodels_lock" to be held by the caller.
141926571dfSjym  */
142926571dfSjym static void
secmodel_adjust_behavior(secmodel_t sm,bool added)143926571dfSjym secmodel_adjust_behavior(secmodel_t sm, bool added)
144926571dfSjym {
145926571dfSjym 	bool r, b;
146926571dfSjym 
147926571dfSjym 	KASSERT(rw_write_held(&secmodels_lock));
148926571dfSjym 
149926571dfSjym #define	ADJUST_COUNTER(which, added)		\
150926571dfSjym 	do {					\
151926571dfSjym 		if (added) {			\
152926571dfSjym 			(which)++;		\
153926571dfSjym 		} else {			\
154926571dfSjym 			if ((which) > 0)	\
155926571dfSjym 				(which)--;	\
156926571dfSjym 		}				\
157926571dfSjym 	} while (/*CONSTCOND*/0)
158926571dfSjym 
159926571dfSjym 	/* Copy credentials on fork? */
160926571dfSjym 	r = prop_dictionary_get_bool(sm->sm_behavior, "copy-cred-on-fork", &b);
161926571dfSjym 	if (r) {
162926571dfSjym 		ADJUST_COUNTER(secmodel_copy_cred_on_fork, added);
163926571dfSjym 	}
164926571dfSjym 
165926571dfSjym #undef ADJUST_COUNTER
166926571dfSjym }
167926571dfSjym 
168926571dfSjym static int
secmodel_plug(secmodel_t sm)169926571dfSjym secmodel_plug(secmodel_t sm)
170926571dfSjym {
171926571dfSjym 	secmodel_t tsm;
172926571dfSjym 	int error = 0;
173926571dfSjym 
174*fc666c51Smaxv 	if (sm == NULL)
175*fc666c51Smaxv 		return EFAULT;
176926571dfSjym 
177926571dfSjym 	/* Check if the secmodel is already present. */
178926571dfSjym 	rw_enter(&secmodels_lock, RW_WRITER);
179926571dfSjym 	tsm = secmodel_lookup(sm->sm_id);
180926571dfSjym 	if (tsm != NULL) {
181926571dfSjym 		error = EEXIST;
182926571dfSjym 		goto out;
183926571dfSjym 	}
184926571dfSjym 
185926571dfSjym 	/* Add the secmodel. */
186926571dfSjym 	LIST_INSERT_HEAD(&secmodels, sm, sm_list);
187926571dfSjym 
188926571dfSjym 	/* Adjust behavior. */
189926571dfSjym 	secmodel_adjust_behavior(sm, true);
190926571dfSjym 
191926571dfSjym  out:
192926571dfSjym 	/* Unlock the secmodels list. */
193926571dfSjym 	rw_exit(&secmodels_lock);
194926571dfSjym 
195926571dfSjym 	return error;
196926571dfSjym }
197926571dfSjym 
198926571dfSjym static int
secmodel_unplug(secmodel_t sm)199926571dfSjym secmodel_unplug(secmodel_t sm)
200926571dfSjym {
201926571dfSjym 	secmodel_t tsm;
202926571dfSjym 	int error = 0;
203926571dfSjym 
204*fc666c51Smaxv 	if (sm == NULL)
205*fc666c51Smaxv 		return EFAULT;
206926571dfSjym 
207926571dfSjym 	/* Make sure the secmodel is present. */
208926571dfSjym 	rw_enter(&secmodels_lock, RW_WRITER);
209926571dfSjym 	tsm = secmodel_lookup(sm->sm_id);
210926571dfSjym 	if (tsm == NULL) {
211926571dfSjym 		error = ENOENT;
212926571dfSjym 		goto out;
213926571dfSjym 	}
214926571dfSjym 
215926571dfSjym 	/* Remove the secmodel. */
216926571dfSjym 	LIST_REMOVE(tsm, sm_list);
217926571dfSjym 
218926571dfSjym 	/* Adjust behavior. */
219926571dfSjym 	secmodel_adjust_behavior(tsm, false);
220926571dfSjym 
221926571dfSjym  out:
222926571dfSjym 	/* Unlock the secmodels list. */
223926571dfSjym 	rw_exit(&secmodels_lock);
224926571dfSjym 
225926571dfSjym 	return error;
226926571dfSjym }
227926571dfSjym 
228926571dfSjym /* XXX TODO */
229926571dfSjym int
secmodel_setinfo(const char * id,void * v,int * err)230926571dfSjym secmodel_setinfo(const char *id, void *v, int *err)
231926571dfSjym {
232926571dfSjym 
233926571dfSjym 	return EOPNOTSUPP;
234926571dfSjym }
235926571dfSjym 
236926571dfSjym int
secmodel_eval(const char * id,const char * what,void * arg,void * ret)237926571dfSjym secmodel_eval(const char *id, const char *what, void *arg, void *ret)
238926571dfSjym {
239926571dfSjym 	secmodel_t sm;
240926571dfSjym 	int error = 0;
241926571dfSjym 
242926571dfSjym 	rw_enter(&secmodels_lock, RW_READER);
243926571dfSjym 	sm = secmodel_lookup(id);
244926571dfSjym 	if (sm == NULL) {
245926571dfSjym 		error = EINVAL;
246926571dfSjym 		goto out;
247926571dfSjym 	}
248926571dfSjym 
249926571dfSjym 	if (sm->sm_eval == NULL) {
250926571dfSjym 		error = ENOENT;
251926571dfSjym 		goto out;
252926571dfSjym 	}
253926571dfSjym 
254926571dfSjym 	if (ret == NULL) {
255926571dfSjym 		error = EFAULT;
256926571dfSjym 		goto out;
257926571dfSjym 	}
258926571dfSjym 
259926571dfSjym 	error = sm->sm_eval(what, arg, ret);
260926571dfSjym 	/* pass error from a secmodel(9) callback as a negative value */
261926571dfSjym 	error = -error;
262926571dfSjym 
263926571dfSjym  out:
264926571dfSjym 	rw_exit(&secmodels_lock);
265926571dfSjym 
266926571dfSjym 	return error;
267926571dfSjym }
268