xref: /aosp_15_r20/external/selinux/libsemanage/src/seusers_local.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 /* Copyright (C) 2005 Red Hat, Inc. */
2 
3 struct semanage_seuser;
4 struct semanage_seuser_key;
5 typedef struct semanage_seuser_key record_key_t;
6 typedef struct semanage_seuser record_t;
7 #define DBASE_RECORD_DEFINED
8 
9 #include <sepol/policydb.h>
10 #include <sepol/context.h>
11 #include <libaudit.h>
12 #include <errno.h>
13 #include "user_internal.h"
14 #include "seuser_internal.h"
15 #include "handle.h"
16 #include "database.h"
17 #include "debug.h"
18 #include "string.h"
19 #include <stdlib.h>
20 
semanage_user_roles(semanage_handle_t * handle,const char * sename)21 static char *semanage_user_roles(semanage_handle_t * handle, const char *sename) {
22 	char *roles = NULL;
23 	unsigned int num_roles;
24 	size_t i;
25 	size_t size = 0;
26 	const char **roles_arr;
27 	semanage_user_key_t *key = NULL;
28 	semanage_user_t * user;
29 	if (semanage_user_key_create(handle, sename, &key) >= 0) {
30 		if (semanage_user_query(handle, key, &user) >= 0) {
31 			if (semanage_user_get_roles(handle,
32 						    user,
33 						    &roles_arr,
34 						    &num_roles) >= 0) {
35 				for (i = 0; i<num_roles; i++) {
36 					size += (strlen(roles_arr[i]) + 1);
37 				}
38 				if (num_roles == 0) {
39 					roles = strdup("");
40 				} else {
41 					roles = malloc(size);
42 					if (roles) {
43 						strcpy(roles,roles_arr[0]);
44 						for (i = 1; i<num_roles; i++) {
45 							strcat(roles,",");
46 							strcat(roles,roles_arr[i]);
47 						}
48 					}
49 				}
50 				free(roles_arr);
51 			}
52 			semanage_user_free(user);
53 		}
54 		semanage_user_key_free(key);
55 	}
56 	return roles;
57 }
58 
semanage_seuser_audit(semanage_handle_t * handle,const semanage_seuser_t * seuser,const semanage_seuser_t * previous,int audit_type,int success)59 static int semanage_seuser_audit(semanage_handle_t * handle,
60 			  const semanage_seuser_t * seuser,
61 			  const semanage_seuser_t * previous,
62 			  int audit_type,
63 			  int success) {
64 	const char *name = NULL;
65 	const char *sename = NULL;
66 	char *roles = NULL;
67 	const char *mls = NULL;
68 	const char *psename = NULL;
69 	const char *pmls = NULL;
70 	char *proles = NULL;
71 	char msg[1024];
72 	const char *sep = "-";
73 	int rc = -1;
74 	strcpy(msg, "login");
75 	if (previous) {
76 		name = semanage_seuser_get_name(previous);
77 		psename = semanage_seuser_get_sename(previous);
78 		pmls = semanage_seuser_get_mlsrange(previous);
79 		proles = semanage_user_roles(handle, psename);
80 	}
81 	if (seuser) {
82 		name = semanage_seuser_get_name(seuser);
83 		sename = semanage_seuser_get_sename(seuser);
84 		mls = semanage_seuser_get_mlsrange(seuser);
85 		roles = semanage_user_roles(handle, sename);
86 	}
87 	if (audit_type != AUDIT_ROLE_REMOVE) {
88 		if (sename && (!psename || strcmp(psename, sename) != 0)) {
89 			strcat(msg,sep);
90 			strcat(msg,"sename");
91 			sep = ",";
92 		}
93 		if (roles && (!proles || strcmp(proles, roles) != 0)) {
94 			strcat(msg,sep);
95 			strcat(msg,"role");
96 			sep = ",";
97 		}
98 		if (mls && (!pmls || strcmp(pmls, mls) != 0)) {
99 			strcat(msg,sep);
100 			strcat(msg,"range");
101 		}
102 	}
103 
104 	int fd = audit_open();
105 	if (fd < 0)
106 	{
107 		/* If kernel doesn't support audit, bail out */
108 		if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {
109 			rc = 0;
110 			goto err;
111 		}
112 		rc = fd;
113 		goto err;
114 	}
115 	audit_log_semanage_message(fd, audit_type, NULL, msg, name, 0, sename, roles, mls, psename, proles, pmls, NULL, NULL,NULL, success);
116 	rc = 0;
117 err:
118 	audit_close(fd);
119 	free(roles);
120 	free(proles);
121 	return rc;
122 }
123 
semanage_seuser_modify_local(semanage_handle_t * handle,const semanage_seuser_key_t * key,const semanage_seuser_t * data)124 int semanage_seuser_modify_local(semanage_handle_t * handle,
125 				 const semanage_seuser_key_t * key,
126 				 const semanage_seuser_t * data)
127 {
128 	int rc;
129 	void *callback = (void *) handle->msg_callback;
130 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
131 	const char *sename = semanage_seuser_get_sename(data);
132 	const char *mls_range = semanage_seuser_get_mlsrange(data);
133 	semanage_seuser_t *previous = NULL;
134 	semanage_seuser_t *new = NULL;
135 
136 	if (!sename) {
137 		errno = EINVAL;
138 		return -1;
139 	}
140 	rc = semanage_seuser_clone(handle, data, &new);
141 	if (rc < 0) {
142 		goto err;
143 	}
144 
145 	if (!mls_range && semanage_mls_enabled(handle)) {
146 		semanage_user_key_t *ukey = NULL;
147 		semanage_user_t *u = NULL;
148 		rc = semanage_user_key_create(handle, sename, &ukey);
149 		if (rc < 0)
150 			goto err;
151 
152 		rc = semanage_user_query(handle, ukey, &u);
153 		semanage_user_key_free(ukey);
154 		if (rc >= 0 ) {
155 			mls_range = semanage_user_get_mlsrange(u);
156 			rc = semanage_seuser_set_mlsrange(handle, new, mls_range);
157 			semanage_user_free(u);
158 		}
159 		if (rc < 0)
160 			goto err;
161 	}
162 
163 	handle->msg_callback = NULL;
164 	(void) semanage_seuser_query(handle, key, &previous);
165 	handle->msg_callback = callback;
166 	rc = dbase_modify(handle, dconfig, key, new);
167 	if (semanage_seuser_audit(handle, new, previous, AUDIT_ROLE_ASSIGN, rc == 0) < 0)
168 		rc = -1;
169 err:
170 	if (previous)
171 		semanage_seuser_free(previous);
172 	semanage_seuser_free(new);
173 	return rc;
174 }
175 
semanage_seuser_del_local(semanage_handle_t * handle,const semanage_seuser_key_t * key)176 int semanage_seuser_del_local(semanage_handle_t * handle,
177 			      const semanage_seuser_key_t * key)
178 {
179 	int rc;
180 	semanage_seuser_t *seuser = NULL;
181 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
182 	rc = dbase_del(handle, dconfig, key);
183 	semanage_seuser_query(handle, key, &seuser);
184 	if (semanage_seuser_audit(handle, NULL, seuser, AUDIT_ROLE_REMOVE, rc == 0) < 0)
185 		rc = -1;
186 	if (seuser)
187 		semanage_seuser_free(seuser);
188 	return rc;
189 }
190 
semanage_seuser_query_local(semanage_handle_t * handle,const semanage_seuser_key_t * key,semanage_seuser_t ** response)191 int semanage_seuser_query_local(semanage_handle_t * handle,
192 				const semanage_seuser_key_t * key,
193 				semanage_seuser_t ** response)
194 {
195 
196 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
197 	return dbase_query(handle, dconfig, key, response);
198 }
199 
semanage_seuser_exists_local(semanage_handle_t * handle,const semanage_seuser_key_t * key,int * response)200 int semanage_seuser_exists_local(semanage_handle_t * handle,
201 				 const semanage_seuser_key_t * key,
202 				 int *response)
203 {
204 
205 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
206 	return dbase_exists(handle, dconfig, key, response);
207 }
208 
semanage_seuser_count_local(semanage_handle_t * handle,unsigned int * response)209 int semanage_seuser_count_local(semanage_handle_t * handle,
210 				unsigned int *response)
211 {
212 
213 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
214 	return dbase_count(handle, dconfig, response);
215 }
216 
semanage_seuser_iterate_local(semanage_handle_t * handle,int (* handler)(const semanage_seuser_t * record,void * varg),void * handler_arg)217 int semanage_seuser_iterate_local(semanage_handle_t * handle,
218 				  int (*handler) (const semanage_seuser_t *
219 						  record, void *varg),
220 				  void *handler_arg)
221 {
222 
223 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
224 	return dbase_iterate(handle, dconfig, handler, handler_arg);
225 }
226 
227 
semanage_seuser_list_local(semanage_handle_t * handle,semanage_seuser_t *** records,unsigned int * count)228 int semanage_seuser_list_local(semanage_handle_t * handle,
229 			       semanage_seuser_t *** records,
230 			       unsigned int *count)
231 {
232 
233 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
234 	return dbase_list(handle, dconfig, records, count);
235 }
236 
237 struct validate_handler_arg {
238 	semanage_handle_t *handle;
239 	const sepol_policydb_t *policydb;
240 };
241 
validate_handler(const semanage_seuser_t * seuser,void * varg)242 static int validate_handler(const semanage_seuser_t * seuser, void *varg)
243 {
244 
245 	semanage_user_t *user = NULL;
246 	semanage_user_key_t *key = NULL;
247 	int exists, mls_ok;
248 
249 	/* Unpack varg */
250 	struct validate_handler_arg *arg = (struct validate_handler_arg *)varg;
251 	semanage_handle_t *handle = arg->handle;
252 	const sepol_policydb_t *policydb = arg->policydb;
253 
254 	/* Unpack seuser */
255 	const char *name = semanage_seuser_get_name(seuser);
256 	const char *sename = semanage_seuser_get_sename(seuser);
257 	const char *mls_range = semanage_seuser_get_mlsrange(seuser);
258 	const char *user_mls_range;
259 
260 	/* Make sure the (SElinux) user exists */
261 	if (semanage_user_key_create(handle, sename, &key) < 0)
262 		goto err;
263 	if (semanage_user_exists(handle, key, &exists) < 0)
264 		goto err;
265 	if (!exists) {
266 		ERR(handle, "selinux user %s does not exist", sename);
267 		goto invalid;
268 	}
269 
270 	/* Verify that the mls range is valid, and that it's contained
271 	 * within the (SELinux) user mls range. This range is optional */
272 	if (mls_range && sepol_policydb_mls_enabled(policydb)) {
273 
274 		if (semanage_user_query(handle, key, &user) < 0)
275 			goto err;
276 		user_mls_range = semanage_user_get_mlsrange(user);
277 
278 		if (sepol_mls_check(handle->sepolh, policydb, mls_range) < 0)
279 			goto invalid;
280 		if (sepol_mls_contains(handle->sepolh, policydb,
281 				       user_mls_range, mls_range, &mls_ok) < 0)
282 			goto err;
283 
284 		if (!mls_ok) {
285 			ERR(handle, "MLS range %s for Unix user %s "
286 			    "exceeds allowed range %s for SELinux user %s",
287 			    mls_range, name, user_mls_range, sename);
288 			goto invalid;
289 		}
290 
291 	} else if (mls_range) {
292 		ERR(handle, "MLS is disabled, but MLS range %s "
293 		    "was found for Unix user %s", mls_range, name);
294 		goto invalid;
295 	}
296 
297 	semanage_user_key_free(key);
298 	semanage_user_free(user);
299 	return 0;
300 
301       err:
302 	ERR(handle, "could not check if seuser mapping for %s is valid", name);
303 	semanage_user_key_free(key);
304 	semanage_user_free(user);
305 	return -1;
306 
307       invalid:
308 	if (mls_range)
309 		ERR(handle, "seuser mapping [%s -> (%s, %s)] is invalid",
310 		    name, sename, mls_range);
311 	else
312 		ERR(handle, "seuser mapping [%s -> %s] is invalid",
313 		    name, sename);
314 	semanage_user_key_free(key);
315 	semanage_user_free(user);
316 	return -1;
317 }
318 
319 /* This function may not be called outside a transaction, or
320  * it will (1) deadlock, because iterate is not reentrant outside
321  * a transaction, and (2) be racy, because it makes multiple dbase calls */
322 
semanage_seuser_validate_local(semanage_handle_t * handle,const sepol_policydb_t * policydb)323 int semanage_seuser_validate_local(semanage_handle_t * handle,
324 					  const sepol_policydb_t * policydb)
325 {
326 
327 	struct validate_handler_arg arg;
328 	arg.handle = handle;
329 	arg.policydb = policydb;
330 	return semanage_seuser_iterate_local(handle, validate_handler, &arg);
331 }
332