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