1 /* Author: Jason Tang <jtang@tresys.com>
2 * Christopher Ashworth <cashworth@tresys.com>
3 *
4 * Copyright (C) 2004-2006 Tresys Technology, LLC
5 * Copyright (C) 2005 Red Hat, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <sepol/module.h>
23 #include <sepol/handle.h>
24 #include <sepol/cil/cil.h>
25 #include <selinux/selinux.h>
26
27 #include <assert.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdio_ext.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <sys/mman.h>
37 #include <sys/wait.h>
38 #include <limits.h>
39 #include <errno.h>
40 #include <dirent.h>
41
42 #include "user_internal.h"
43 #include "seuser_internal.h"
44 #include "port_internal.h"
45 #include "ibpkey_internal.h"
46 #include "ibendport_internal.h"
47 #include "iface_internal.h"
48 #include "boolean_internal.h"
49 #include "fcontext_internal.h"
50 #include "node_internal.h"
51 #include "genhomedircon.h"
52
53 #include "debug.h"
54 #include "handle.h"
55 #include "compressed_file.h"
56 #include "modules.h"
57 #include "direct_api.h"
58 #include "semanage_store.h"
59 #include "database_policydb.h"
60 #include "policy.h"
61 #include "sha256.h"
62
63 #define PIPE_READ 0
64 #define PIPE_WRITE 1
65 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
66
67 static void semanage_direct_destroy(semanage_handle_t * sh);
68 static int semanage_direct_disconnect(semanage_handle_t * sh);
69 static int semanage_direct_begintrans(semanage_handle_t * sh);
70 static int semanage_direct_commit(semanage_handle_t * sh);
71 static int semanage_direct_install(semanage_handle_t * sh, char *data,
72 size_t data_len, const char *module_name, const char *lang_ext);
73 static int semanage_direct_install_file(semanage_handle_t * sh, const char *module_name);
74 static int semanage_direct_extract(semanage_handle_t * sh,
75 semanage_module_key_t *modkey,
76 int extract_cil,
77 void **mapped_data,
78 size_t *data_len,
79 semanage_module_info_t **modinfo);
80 static int semanage_direct_remove(semanage_handle_t * sh, char *module_name);
81 static int semanage_direct_list(semanage_handle_t * sh,
82 semanage_module_info_t ** modinfo,
83 int *num_modules);
84 static int semanage_direct_get_enabled(semanage_handle_t *sh,
85 const semanage_module_key_t *modkey,
86 int *enabled);
87 static int semanage_direct_set_enabled(semanage_handle_t *sh,
88 const semanage_module_key_t *modkey,
89 int enabled);
90
91 static int semanage_direct_get_module_info(semanage_handle_t *sh,
92 const semanage_module_key_t *modkey,
93 semanage_module_info_t **modinfo);
94
95 static int semanage_direct_list_all(semanage_handle_t *sh,
96 semanage_module_info_t **modinfo,
97 int *num_modules);
98
99 static int semanage_direct_install_info(semanage_handle_t *sh,
100 const semanage_module_info_t *modinfo,
101 char *data,
102 size_t data_len);
103
104 static int semanage_direct_remove_key(semanage_handle_t *sh,
105 const semanage_module_key_t *modkey);
106
107 static struct semanage_policy_table direct_funcs = {
108 .get_serial = semanage_direct_get_serial,
109 .destroy = semanage_direct_destroy,
110 .disconnect = semanage_direct_disconnect,
111 .begin_trans = semanage_direct_begintrans,
112 .commit = semanage_direct_commit,
113 .install = semanage_direct_install,
114 .extract = semanage_direct_extract,
115 .install_file = semanage_direct_install_file,
116 .remove = semanage_direct_remove,
117 .list = semanage_direct_list,
118 .get_enabled = semanage_direct_get_enabled,
119 .set_enabled = semanage_direct_set_enabled,
120 .get_module_info = semanage_direct_get_module_info,
121 .list_all = semanage_direct_list_all,
122 .install_info = semanage_direct_install_info,
123 .remove_key = semanage_direct_remove_key,
124 };
125
semanage_direct_is_managed(semanage_handle_t * sh)126 int semanage_direct_is_managed(semanage_handle_t * sh)
127 {
128 if (semanage_check_init(sh, sh->conf->store_root_path))
129 goto err;
130
131 if (semanage_access_check(sh) < 0)
132 return 0;
133
134 return 1;
135
136 err:
137 ERR(sh, "could not check whether policy is managed");
138 return STATUS_ERR;
139 }
140
141 /* Check that the module store exists, creating it if necessary.
142 */
semanage_direct_connect(semanage_handle_t * sh)143 int semanage_direct_connect(semanage_handle_t * sh)
144 {
145 const char *path;
146 struct stat sb;
147
148 if (semanage_check_init(sh, sh->conf->store_root_path))
149 goto err;
150
151 if (sh->create_store)
152 if (semanage_create_store(sh, 1))
153 goto err;
154
155 sh->u.direct.translock_file_fd = -1;
156 sh->u.direct.activelock_file_fd = -1;
157
158 /* set up function pointers */
159 sh->funcs = &direct_funcs;
160
161 /* Object databases: local modifications */
162 if (user_base_file_dbase_init(sh,
163 semanage_path(SEMANAGE_ACTIVE,
164 SEMANAGE_USERS_BASE_LOCAL),
165 semanage_path(SEMANAGE_TMP,
166 SEMANAGE_USERS_BASE_LOCAL),
167 semanage_user_base_dbase_local(sh)) < 0)
168 goto err;
169
170 if (user_extra_file_dbase_init(sh,
171 semanage_path(SEMANAGE_ACTIVE,
172 SEMANAGE_USERS_EXTRA_LOCAL),
173 semanage_path(SEMANAGE_TMP,
174 SEMANAGE_USERS_EXTRA_LOCAL),
175 semanage_user_extra_dbase_local(sh)) < 0)
176 goto err;
177
178 if (user_join_dbase_init(sh,
179 semanage_user_base_dbase_local(sh),
180 semanage_user_extra_dbase_local(sh),
181 semanage_user_dbase_local(sh)) < 0)
182 goto err;
183
184 if (port_file_dbase_init(sh,
185 semanage_path(SEMANAGE_ACTIVE,
186 SEMANAGE_PORTS_LOCAL),
187 semanage_path(SEMANAGE_TMP,
188 SEMANAGE_PORTS_LOCAL),
189 semanage_port_dbase_local(sh)) < 0)
190 goto err;
191
192 if (iface_file_dbase_init(sh,
193 semanage_path(SEMANAGE_ACTIVE,
194 SEMANAGE_INTERFACES_LOCAL),
195 semanage_path(SEMANAGE_TMP,
196 SEMANAGE_INTERFACES_LOCAL),
197 semanage_iface_dbase_local(sh)) < 0)
198 goto err;
199
200 if (bool_file_dbase_init(sh,
201 semanage_path(SEMANAGE_ACTIVE,
202 SEMANAGE_BOOLEANS_LOCAL),
203 semanage_path(SEMANAGE_TMP,
204 SEMANAGE_BOOLEANS_LOCAL),
205 semanage_bool_dbase_local(sh)) < 0)
206 goto err;
207
208 if (fcontext_file_dbase_init(sh,
209 semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC_LOCAL),
210 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
211 semanage_fcontext_dbase_local(sh)) < 0)
212 goto err;
213
214 if (fcontext_file_dbase_init(sh,
215 semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC_HOMEDIRS),
216 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS),
217 semanage_fcontext_dbase_homedirs(sh)) < 0)
218 goto err;
219
220 if (seuser_file_dbase_init(sh,
221 semanage_path(SEMANAGE_ACTIVE,
222 SEMANAGE_SEUSERS_LOCAL),
223 semanage_path(SEMANAGE_TMP,
224 SEMANAGE_SEUSERS_LOCAL),
225 semanage_seuser_dbase_local(sh)) < 0)
226 goto err;
227
228 if (node_file_dbase_init(sh,
229 semanage_path(SEMANAGE_ACTIVE,
230 SEMANAGE_NODES_LOCAL),
231 semanage_path(SEMANAGE_TMP,
232 SEMANAGE_NODES_LOCAL),
233 semanage_node_dbase_local(sh)) < 0)
234 goto err;
235
236 if (ibpkey_file_dbase_init(sh,
237 semanage_path(SEMANAGE_ACTIVE,
238 SEMANAGE_IBPKEYS_LOCAL),
239 semanage_path(SEMANAGE_TMP,
240 SEMANAGE_IBPKEYS_LOCAL),
241 semanage_ibpkey_dbase_local(sh)) < 0)
242 goto err;
243
244 if (ibendport_file_dbase_init(sh,
245 semanage_path(SEMANAGE_ACTIVE,
246 SEMANAGE_IBENDPORTS_LOCAL),
247 semanage_path(SEMANAGE_TMP,
248 SEMANAGE_IBENDPORTS_LOCAL),
249 semanage_ibendport_dbase_local(sh)) < 0)
250 goto err;
251
252 /* Object databases: local modifications + policy */
253 if (user_base_policydb_dbase_init(sh,
254 semanage_user_base_dbase_policy(sh)) <
255 0)
256 goto err;
257
258 if (user_extra_file_dbase_init(sh,
259 semanage_path(SEMANAGE_ACTIVE,
260 SEMANAGE_USERS_EXTRA),
261 semanage_path(SEMANAGE_TMP,
262 SEMANAGE_USERS_EXTRA),
263 semanage_user_extra_dbase_policy(sh)) <
264 0)
265 goto err;
266
267 if (user_join_dbase_init(sh,
268 semanage_user_base_dbase_policy(sh),
269 semanage_user_extra_dbase_policy(sh),
270 semanage_user_dbase_policy(sh)) < 0)
271 goto err;
272
273 if (port_policydb_dbase_init(sh, semanage_port_dbase_policy(sh)) < 0)
274 goto err;
275
276 if (ibpkey_policydb_dbase_init(sh, semanage_ibpkey_dbase_policy(sh)) < 0)
277 goto err;
278
279 if (ibendport_policydb_dbase_init(sh, semanage_ibendport_dbase_policy(sh)) < 0)
280 goto err;
281
282 if (iface_policydb_dbase_init(sh, semanage_iface_dbase_policy(sh)) < 0)
283 goto err;
284
285 if (bool_policydb_dbase_init(sh, semanage_bool_dbase_policy(sh)) < 0)
286 goto err;
287
288 if (fcontext_file_dbase_init(sh,
289 semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC),
290 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC),
291 semanage_fcontext_dbase_policy(sh)) < 0)
292 goto err;
293
294 if (seuser_file_dbase_init(sh,
295 semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_SEUSERS),
296 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS),
297 semanage_seuser_dbase_policy(sh)) < 0)
298 goto err;
299
300 if (node_policydb_dbase_init(sh, semanage_node_dbase_policy(sh)) < 0)
301 goto err;
302
303 /* Active kernel policy */
304 if (bool_activedb_dbase_init(sh, semanage_bool_dbase_active(sh)) < 0)
305 goto err;
306
307 /* set the disable dontaudit value */
308 path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_DISABLE_DONTAUDIT);
309
310 if (stat(path, &sb) == 0)
311 sepol_set_disable_dontaudit(sh->sepolh, 1);
312 else if (errno == ENOENT) {
313 /* The file does not exist */
314 sepol_set_disable_dontaudit(sh->sepolh, 0);
315 } else {
316 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
317 goto err;
318 }
319
320 return STATUS_SUCCESS;
321
322 err:
323 ERR(sh, "could not establish direct connection");
324 return STATUS_ERR;
325 }
326
semanage_direct_destroy(semanage_handle_t * sh)327 static void semanage_direct_destroy(semanage_handle_t * sh
328 __attribute__ ((unused)))
329 {
330 /* do nothing */
331 }
332
semanage_remove_tmps(semanage_handle_t * sh)333 static int semanage_remove_tmps(semanage_handle_t *sh)
334 {
335 if (sh->commit_err)
336 return 0;
337
338 /* destroy sandbox if it exists */
339 if (semanage_remove_directory
340 (semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL)) < 0) {
341 if (errno != ENOENT) {
342 ERR(sh, "Could not cleanly remove sandbox %s.",
343 semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL));
344 return -1;
345 }
346 }
347
348 /* destroy tmp policy if it exists */
349 if (semanage_remove_directory
350 (semanage_final_path(SEMANAGE_FINAL_TMP,
351 SEMANAGE_FINAL_TOPLEVEL)) < 0) {
352 if (errno != ENOENT) {
353 ERR(sh, "Could not cleanly remove tmp %s.",
354 semanage_final_path(SEMANAGE_FINAL_TMP,
355 SEMANAGE_FINAL_TOPLEVEL));
356 return -1;
357 }
358 }
359
360 return 0;
361 }
362
semanage_direct_disconnect(semanage_handle_t * sh)363 static int semanage_direct_disconnect(semanage_handle_t *sh)
364 {
365 int retval = 0;
366
367 /* destroy transaction and remove tmp files if no commit error */
368 if (sh->is_in_transaction) {
369 retval = semanage_remove_tmps(sh);
370 semanage_release_trans_lock(sh);
371 }
372
373 /* Release object databases: local modifications */
374 user_base_file_dbase_release(semanage_user_base_dbase_local(sh));
375 user_extra_file_dbase_release(semanage_user_extra_dbase_local(sh));
376 user_join_dbase_release(semanage_user_dbase_local(sh));
377 port_file_dbase_release(semanage_port_dbase_local(sh));
378 ibpkey_file_dbase_release(semanage_ibpkey_dbase_local(sh));
379 ibendport_file_dbase_release(semanage_ibendport_dbase_local(sh));
380 iface_file_dbase_release(semanage_iface_dbase_local(sh));
381 bool_file_dbase_release(semanage_bool_dbase_local(sh));
382 fcontext_file_dbase_release(semanage_fcontext_dbase_local(sh));
383 fcontext_file_dbase_release(semanage_fcontext_dbase_homedirs(sh));
384 seuser_file_dbase_release(semanage_seuser_dbase_local(sh));
385 node_file_dbase_release(semanage_node_dbase_local(sh));
386
387 /* Release object databases: local modifications + policy */
388 user_base_policydb_dbase_release(semanage_user_base_dbase_policy(sh));
389 user_extra_file_dbase_release(semanage_user_extra_dbase_policy(sh));
390 user_join_dbase_release(semanage_user_dbase_policy(sh));
391 port_policydb_dbase_release(semanage_port_dbase_policy(sh));
392 ibpkey_policydb_dbase_release(semanage_ibpkey_dbase_policy(sh));
393 ibendport_policydb_dbase_release(semanage_ibendport_dbase_policy(sh));
394 iface_policydb_dbase_release(semanage_iface_dbase_policy(sh));
395 bool_policydb_dbase_release(semanage_bool_dbase_policy(sh));
396 fcontext_file_dbase_release(semanage_fcontext_dbase_policy(sh));
397 seuser_file_dbase_release(semanage_seuser_dbase_policy(sh));
398 node_policydb_dbase_release(semanage_node_dbase_policy(sh));
399
400 /* Release object databases: active kernel policy */
401 bool_activedb_dbase_release(semanage_bool_dbase_active(sh));
402
403 return retval;
404 }
405
semanage_direct_begintrans(semanage_handle_t * sh)406 static int semanage_direct_begintrans(semanage_handle_t * sh)
407 {
408 if (semanage_get_trans_lock(sh) < 0) {
409 return -1;
410 }
411 if ((semanage_make_sandbox(sh)) < 0) {
412 return -1;
413 }
414 if ((semanage_make_final(sh)) < 0) {
415 return -1;
416 }
417 return 0;
418 }
419
420 /********************* utility functions *********************/
421
422 /* Takes a module stored in 'module_data' and parses its headers.
423 * Sets reference variables 'module_name' to module's name, and
424 * 'version' to module's version. The caller is responsible for
425 * free()ing 'module_name', and 'version'; they will be
426 * set to NULL upon entering this function. Returns 0 on success, -1
427 * if out of memory.
428 */
parse_module_headers(semanage_handle_t * sh,char * module_data,size_t data_len,char ** module_name,char ** version)429 static int parse_module_headers(semanage_handle_t * sh, char *module_data,
430 size_t data_len, char **module_name,
431 char **version)
432 {
433 struct sepol_policy_file *pf;
434 int file_type;
435 *module_name = *version = NULL;
436
437 if (sepol_policy_file_create(&pf)) {
438 ERR(sh, "Out of memory!");
439 return -1;
440 }
441 sepol_policy_file_set_mem(pf, module_data, data_len);
442 sepol_policy_file_set_handle(pf, sh->sepolh);
443 if (module_data != NULL && data_len > 0)
444 sepol_module_package_info(pf, &file_type, module_name,
445 version);
446 sepol_policy_file_free(pf);
447
448 return 0;
449 }
450
451 /* Writes a block of data to a file. Returns 0 on success, -1 on
452 * error. */
write_file(semanage_handle_t * sh,const char * filename,const char * data,size_t num_bytes)453 static int write_file(semanage_handle_t * sh,
454 const char *filename, const char *data, size_t num_bytes)
455 {
456 int out;
457
458 if ((out =
459 open(filename, O_WRONLY | O_CREAT | O_TRUNC,
460 S_IRUSR | S_IWUSR)) == -1) {
461 ERR(sh, "Could not open %s for writing.", filename);
462 return -1;
463 }
464 if (write(out, data, num_bytes) == -1) {
465 ERR(sh, "Error while writing to %s.", filename);
466 close(out);
467 return -1;
468 }
469 close(out);
470 return 0;
471 }
472
semanage_direct_update_user_extra(semanage_handle_t * sh,cil_db_t * cildb)473 static int semanage_direct_update_user_extra(semanage_handle_t * sh, cil_db_t *cildb)
474 {
475 const char *ofilename = NULL;
476 int retval = -1;
477 char *data = NULL;
478 size_t size = 0;
479
480 dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh);
481
482 retval = cil_userprefixes_to_string(cildb, &data, &size);
483 if (retval != SEPOL_OK) {
484 goto cleanup;
485 }
486
487 if (size > 0) {
488 /*
489 * Write the users_extra entries from CIL modules.
490 * This file is used as our baseline when we do not require
491 * re-linking.
492 */
493 ofilename = semanage_path(SEMANAGE_TMP,
494 SEMANAGE_USERS_EXTRA_LINKED);
495 if (ofilename == NULL) {
496 retval = -1;
497 goto cleanup;
498 }
499 retval = write_file(sh, ofilename, data, size);
500 if (retval < 0)
501 goto cleanup;
502
503 /*
504 * Write the users_extra file; users_extra.local
505 * will be merged into this file.
506 */
507 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA);
508 if (ofilename == NULL) {
509 retval = -1;
510 goto cleanup;
511 }
512 retval = write_file(sh, ofilename, data, size);
513 if (retval < 0)
514 goto cleanup;
515
516 pusers_extra->dtable->drop_cache(pusers_extra->dbase);
517
518 } else {
519 retval = pusers_extra->dtable->clear(sh, pusers_extra->dbase);
520 }
521
522 cleanup:
523 free(data);
524
525 return retval;
526 }
527
semanage_direct_update_seuser(semanage_handle_t * sh,cil_db_t * cildb)528 static int semanage_direct_update_seuser(semanage_handle_t * sh, cil_db_t *cildb)
529 {
530 const char *ofilename = NULL;
531 int retval = -1;
532 char *data = NULL;
533 size_t size = 0;
534
535 dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh);
536
537 retval = cil_selinuxusers_to_string(cildb, &data, &size);
538 if (retval != SEPOL_OK) {
539 goto cleanup;
540 }
541
542 if (size > 0) {
543 /*
544 * Write the seusers entries from CIL modules.
545 * This file is used as our baseline when we do not require
546 * re-linking.
547 */
548 ofilename = semanage_path(SEMANAGE_TMP,
549 SEMANAGE_SEUSERS_LINKED);
550 if (ofilename == NULL) {
551 retval = -1;
552 goto cleanup;
553 }
554 retval = write_file(sh, ofilename, data, size);
555 if (retval < 0)
556 goto cleanup;
557
558 /*
559 * Write the seusers file; seusers.local will be merged into
560 * this file.
561 */
562 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS);
563 if (ofilename == NULL) {
564 retval = -1;
565 goto cleanup;
566 }
567 retval = write_file(sh, ofilename, data, size);
568 if (retval < 0)
569 goto cleanup;
570
571 pseusers->dtable->drop_cache(pseusers->dbase);
572 } else {
573 retval = pseusers->dtable->clear(sh, pseusers->dbase);
574 }
575
576 cleanup:
577 free(data);
578
579 return retval;
580 }
581
read_from_pipe_to_data(semanage_handle_t * sh,size_t initial_len,int fd,char ** out_data_read,size_t * out_read_len)582 static int read_from_pipe_to_data(semanage_handle_t *sh, size_t initial_len, int fd, char **out_data_read, size_t *out_read_len)
583 {
584 size_t max_len = initial_len;
585 size_t read_len = 0;
586 size_t data_read_len = 0;
587 char *data_read = NULL;
588
589 if (max_len <= 0) {
590 max_len = 1;
591 }
592 data_read = malloc(max_len * sizeof(*data_read));
593 if (data_read == NULL) {
594 ERR(sh, "Failed to malloc, out of memory.\n");
595 return -1;
596 }
597
598 while ((read_len = read(fd, data_read + data_read_len, max_len - data_read_len)) > 0) {
599 data_read_len += read_len;
600 if (data_read_len == max_len) {
601 max_len *= 2;
602 data_read = realloc(data_read, max_len);
603 if (data_read == NULL) {
604 ERR(sh, "Failed to realloc, out of memory.\n");
605 return -1;
606 }
607 }
608 }
609
610 *out_read_len = data_read_len;
611 *out_data_read = data_read;
612
613 return 0;
614 }
615
semanage_pipe_data(semanage_handle_t * sh,char * path,char * in_data,size_t in_data_len,char ** out_data,size_t * out_data_len,char ** err_data,size_t * err_data_len)616 static int semanage_pipe_data(semanage_handle_t *sh, char *path, char *in_data, size_t in_data_len, char **out_data, size_t *out_data_len, char **err_data, size_t *err_data_len)
617 {
618 int input_fd[2] = {-1, -1};
619 int output_fd[2] = {-1, -1};
620 int err_fd[2] = {-1, -1};
621 pid_t pid;
622 char *data_read = NULL;
623 char *err_data_read = NULL;
624 int retval;
625 int status = 0;
626 size_t initial_len;
627 size_t data_read_len = 0;
628 size_t err_data_read_len = 0;
629 struct sigaction old_signal;
630 struct sigaction new_signal;
631 new_signal.sa_handler = SIG_IGN;
632 sigemptyset(&new_signal.sa_mask);
633 new_signal.sa_flags = 0;
634 /* This is needed in case the read end of input_fd is closed causing a SIGPIPE signal to be sent.
635 * If SIGPIPE is not caught, the signal will cause semanage to terminate immediately. The sigaction below
636 * creates a new_signal that ignores SIGPIPE allowing the write to exit cleanly.
637 *
638 * Another sigaction is called in cleanup to restore the original behavior when a SIGPIPE is received.
639 */
640 sigaction(SIGPIPE, &new_signal, &old_signal);
641
642 retval = pipe(input_fd);
643 if (retval == -1) {
644 ERR(sh, "Unable to create pipe for input pipe: %s\n", strerror(errno));
645 goto cleanup;
646 }
647 retval = pipe(output_fd);
648 if (retval == -1) {
649 ERR(sh, "Unable to create pipe for output pipe: %s\n", strerror(errno));
650 goto cleanup;
651 }
652 retval = pipe(err_fd);
653 if (retval == -1) {
654 ERR(sh, "Unable to create pipe for error pipe: %s\n", strerror(errno));
655 goto cleanup;
656 }
657
658 pid = fork();
659 if (pid == -1) {
660 ERR(sh, "Unable to fork from parent: %s.", strerror(errno));
661 retval = -1;
662 goto cleanup;
663 } else if (pid == 0) {
664 retval = dup2(input_fd[PIPE_READ], STDIN_FILENO);
665 if (retval == -1) {
666 ERR(sh, "Unable to dup2 input pipe: %s\n", strerror(errno));
667 goto cleanup;
668 }
669 retval = dup2(output_fd[PIPE_WRITE], STDOUT_FILENO);
670 if (retval == -1) {
671 ERR(sh, "Unable to dup2 output pipe: %s\n", strerror(errno));
672 goto cleanup;
673 }
674 retval = dup2(err_fd[PIPE_WRITE], STDERR_FILENO);
675 if (retval == -1) {
676 ERR(sh, "Unable to dup2 error pipe: %s\n", strerror(errno));
677 goto cleanup;
678 }
679
680 retval = close(input_fd[PIPE_WRITE]);
681 if (retval == -1) {
682 ERR(sh, "Unable to close input pipe: %s\n", strerror(errno));
683 goto cleanup;
684 }
685 retval = close(output_fd[PIPE_READ]);
686 if (retval == -1) {
687 ERR(sh, "Unable to close output pipe: %s\n", strerror(errno));
688 goto cleanup;
689 }
690 retval = close(err_fd[PIPE_READ]);
691 if (retval == -1) {
692 ERR(sh, "Unable to close error pipe: %s\n", strerror(errno));
693 goto cleanup;
694 }
695 retval = execl(path, path, NULL);
696 if (retval == -1) {
697 ERR(sh, "Unable to execute %s : %s\n", path, strerror(errno));
698 _exit(EXIT_FAILURE);
699 }
700 } else {
701 retval = close(input_fd[PIPE_READ]);
702 input_fd[PIPE_READ] = -1;
703 if (retval == -1) {
704 ERR(sh, "Unable to close read end of input pipe: %s\n", strerror(errno));
705 goto cleanup;
706 }
707
708 retval = close(output_fd[PIPE_WRITE]);
709 output_fd[PIPE_WRITE] = -1;
710 if (retval == -1) {
711 ERR(sh, "Unable to close write end of output pipe: %s\n", strerror(errno));
712 goto cleanup;
713 }
714
715 retval = close(err_fd[PIPE_WRITE]);
716 err_fd[PIPE_WRITE] = -1;
717 if (retval == -1) {
718 ERR(sh, "Unable to close write end of error pipe: %s\n", strerror(errno));
719 goto cleanup;
720 }
721
722 retval = write(input_fd[PIPE_WRITE], in_data, in_data_len);
723 if (retval == -1) {
724 ERR(sh, "Failed to write data to input pipe: %s\n", strerror(errno));
725 goto cleanup;
726 }
727 retval = close(input_fd[PIPE_WRITE]);
728 input_fd[PIPE_WRITE] = -1;
729 if (retval == -1) {
730 ERR(sh, "Unable to close write end of input pipe: %s\n", strerror(errno));
731 goto cleanup;
732 }
733
734 initial_len = 1 << 17;
735 retval = read_from_pipe_to_data(sh, initial_len, output_fd[PIPE_READ], &data_read, &data_read_len);
736 if (retval != 0) {
737 goto cleanup;
738 }
739 retval = close(output_fd[PIPE_READ]);
740 output_fd[PIPE_READ] = -1;
741 if (retval == -1) {
742 ERR(sh, "Unable to close read end of output pipe: %s\n", strerror(errno));
743 goto cleanup;
744 }
745
746 initial_len = 1 << 9;
747 retval = read_from_pipe_to_data(sh, initial_len, err_fd[PIPE_READ], &err_data_read, &err_data_read_len);
748 if (retval != 0) {
749 goto cleanup;
750 }
751 retval = close(err_fd[PIPE_READ]);
752 err_fd[PIPE_READ] = -1;
753 if (retval == -1) {
754 ERR(sh, "Unable to close read end of error pipe: %s\n", strerror(errno));
755 goto cleanup;
756 }
757
758 if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status)) {
759 ERR(sh, "Child process %s did not exit cleanly.", path);
760 retval = -1;
761 goto cleanup;
762 }
763 if (WEXITSTATUS(status) != 0) {
764 ERR(sh, "Child process %s failed with code: %d.", path, WEXITSTATUS(status));
765 retval = -1;
766 goto cleanup;
767 }
768 }
769
770 retval = 0;
771
772 cleanup:
773 sigaction(SIGPIPE, &old_signal, NULL);
774
775 if (data_read != NULL) {
776 *out_data = data_read;
777 *out_data_len = data_read_len;
778 }
779
780 if (err_data_read != NULL) {
781 *err_data = err_data_read;
782 *err_data_len = err_data_read_len;
783 }
784
785 if (output_fd[PIPE_READ] != -1) {
786 close(output_fd[PIPE_READ]);
787 }
788 if (output_fd[PIPE_WRITE] != -1) {
789 close(output_fd[PIPE_WRITE]);
790 }
791 if (err_fd[PIPE_READ] != -1) {
792 close(err_fd[PIPE_READ]);
793 }
794 if (err_fd[PIPE_WRITE] != -1) {
795 close(err_fd[PIPE_WRITE]);
796 }
797 if (input_fd[PIPE_READ] != -1) {
798 close(input_fd[PIPE_READ]);
799 }
800 if (input_fd[PIPE_WRITE] != -1) {
801 close(input_fd[PIPE_WRITE]);
802 }
803
804 return retval;
805 }
806
semanage_direct_write_langext(semanage_handle_t * sh,const char * lang_ext,const semanage_module_info_t * modinfo)807 static int semanage_direct_write_langext(semanage_handle_t *sh,
808 const char *lang_ext,
809 const semanage_module_info_t *modinfo)
810 {
811 int ret = -1;
812 char fn[PATH_MAX];
813 FILE *fp = NULL;
814
815 ret = semanage_module_get_path(sh,
816 modinfo,
817 SEMANAGE_MODULE_PATH_LANG_EXT,
818 fn,
819 sizeof(fn));
820 if (ret != 0) {
821 goto cleanup;
822 }
823
824 fp = fopen(fn, "w");
825 if (fp == NULL) {
826 ERR(sh, "Unable to open %s module ext file.", modinfo->name);
827 ret = -1;
828 goto cleanup;
829 }
830
831 if (fputs(lang_ext, fp) < 0) {
832 ERR(sh, "Unable to write %s module ext file.", modinfo->name);
833 ret = -1;
834 goto cleanup;
835 }
836
837 if (fclose(fp) != 0) {
838 ERR(sh, "Unable to close %s module ext file.", modinfo->name);
839 fp = NULL;
840 ret = -1;
841 goto cleanup;
842 }
843
844 fp = NULL;
845
846 ret = 0;
847
848 cleanup:
849 if (fp != NULL) fclose(fp);
850
851 return ret;
852 }
853
update_checksum_with_len(Sha256Context * context,size_t s)854 static void update_checksum_with_len(Sha256Context *context, size_t s)
855 {
856 int i;
857 uint8_t buffer[8];
858
859 for (i = 0; i < 8; i++) {
860 buffer[i] = s & 0xff;
861 s >>= 8;
862 }
863 Sha256Update(context, buffer, 8);
864 }
865
semanage_compile_module(semanage_handle_t * sh,semanage_module_info_t * modinfo,Sha256Context * context)866 static int semanage_compile_module(semanage_handle_t *sh,
867 semanage_module_info_t *modinfo,
868 Sha256Context *context)
869 {
870 char cil_path[PATH_MAX];
871 char hll_path[PATH_MAX];
872 char *compiler_path = NULL;
873 char *cil_data = NULL;
874 char *err_data = NULL;
875 char *start = NULL;
876 char *end = NULL;
877 int status = 0;
878 size_t cil_data_len = 0;
879 size_t err_data_len = 0;
880 struct file_contents hll_contents = {};
881
882 if (!strcasecmp(modinfo->lang_ext, "cil")) {
883 goto cleanup;
884 }
885
886 status = semanage_get_hll_compiler_path(sh, modinfo->lang_ext, &compiler_path);
887 if (status != 0) {
888 goto cleanup;
889 }
890
891 status = semanage_module_get_path(
892 sh,
893 modinfo,
894 SEMANAGE_MODULE_PATH_CIL,
895 cil_path,
896 sizeof(cil_path));
897 if (status != 0) {
898 goto cleanup;
899 }
900
901 status = semanage_module_get_path(
902 sh,
903 modinfo,
904 SEMANAGE_MODULE_PATH_HLL,
905 hll_path,
906 sizeof(hll_path));
907 if (status != 0) {
908 goto cleanup;
909 }
910
911 status = map_compressed_file(sh, hll_path, &hll_contents);
912 if (status < 0) {
913 ERR(sh, "Unable to read file %s\n", hll_path);
914 goto cleanup;
915 }
916
917 status = semanage_pipe_data(sh, compiler_path, hll_contents.data,
918 hll_contents.len, &cil_data, &cil_data_len,
919 &err_data, &err_data_len);
920 if (err_data_len > 0) {
921 for (start = end = err_data; end < err_data + err_data_len; end++) {
922 if (*end == '\n') {
923 fprintf(stderr, "%s: ", modinfo->name);
924 fwrite(start, 1, end - start + 1, stderr);
925 start = end + 1;
926 }
927 }
928
929 if (end != start) {
930 fprintf(stderr, "%s: ", modinfo->name);
931 fwrite(start, 1, end - start, stderr);
932 fprintf(stderr, "\n");
933 }
934 }
935 if (status != 0) {
936 goto cleanup;
937 }
938
939 if (context) {
940 update_checksum_with_len(context, cil_data_len);
941 Sha256Update(context, cil_data, cil_data_len);
942 }
943
944 status = write_compressed_file(sh, cil_path, cil_data, cil_data_len);
945 if (status == -1) {
946 ERR(sh, "Failed to write %s\n", cil_path);
947 goto cleanup;
948 }
949
950 if (sh->conf->remove_hll == 1) {
951 status = unlink(hll_path);
952 if (status != 0) {
953 ERR(sh, "Error while removing HLL file %s: %s", hll_path, strerror(errno));
954 goto cleanup;
955 }
956
957 status = semanage_direct_write_langext(sh, "cil", modinfo);
958 if (status != 0) {
959 goto cleanup;
960 }
961 }
962
963 cleanup:
964 unmap_compressed_file(&hll_contents);
965 free(cil_data);
966 free(err_data);
967 free(compiler_path);
968
969 return status;
970 }
971
modinfo_cmp(const void * a,const void * b)972 static int modinfo_cmp(const void *a, const void *b)
973 {
974 const semanage_module_info_t *ma = a;
975 const semanage_module_info_t *mb = b;
976
977 return strcmp(ma->name, mb->name);
978 }
979
semanage_compile_hll_modules(semanage_handle_t * sh,semanage_module_info_t * modinfos,int num_modinfos,char * cil_checksum)980 static int semanage_compile_hll_modules(semanage_handle_t *sh,
981 semanage_module_info_t *modinfos,
982 int num_modinfos,
983 char *cil_checksum)
984 {
985 /* to be incremented when checksum input data format changes */
986 static const size_t CHECKSUM_EPOCH = 1;
987
988 int i, status = 0;
989 char cil_path[PATH_MAX];
990 struct stat sb;
991 Sha256Context context;
992 SHA256_HASH hash;
993 struct file_contents contents = {};
994
995 assert(sh);
996 assert(modinfos);
997
998 /* Sort modules by name to get consistent ordering. */
999 qsort(modinfos, num_modinfos, sizeof(*modinfos), &modinfo_cmp);
1000
1001 Sha256Initialise(&context);
1002 update_checksum_with_len(&context, CHECKSUM_EPOCH);
1003
1004 /* prefix with module count to avoid collisions */
1005 update_checksum_with_len(&context, num_modinfos);
1006 for (i = 0; i < num_modinfos; i++) {
1007 status = semanage_module_get_path(
1008 sh,
1009 &modinfos[i],
1010 SEMANAGE_MODULE_PATH_CIL,
1011 cil_path,
1012 sizeof(cil_path));
1013 if (status != 0)
1014 return -1;
1015
1016 if (!semanage_get_ignore_module_cache(sh)) {
1017 status = stat(cil_path, &sb);
1018 if (status == 0) {
1019 status = map_compressed_file(sh, cil_path, &contents);
1020 if (status < 0) {
1021 ERR(sh, "Error mapping file: %s", cil_path);
1022 return -1;
1023 }
1024
1025 /* prefix with length to avoid collisions */
1026 update_checksum_with_len(&context, contents.len);
1027 Sha256Update(&context, contents.data, contents.len);
1028
1029 unmap_compressed_file(&contents);
1030 continue;
1031 } else if (errno != ENOENT) {
1032 ERR(sh, "Unable to access %s: %s\n", cil_path,
1033 strerror(errno));
1034 return -1; //an error in the "stat" call
1035 }
1036 }
1037
1038 status = semanage_compile_module(sh, &modinfos[i], &context);
1039 if (status < 0)
1040 return -1;
1041 }
1042 Sha256Finalise(&context, &hash);
1043
1044 semanage_hash_to_checksum_string(hash.bytes, cil_checksum);
1045 return 0;
1046 }
1047
semanage_compare_checksum(semanage_handle_t * sh,const char * reference)1048 static int semanage_compare_checksum(semanage_handle_t *sh, const char *reference)
1049 {
1050 const char *path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_CHECKSUM);
1051 struct stat sb;
1052 int fd, retval;
1053 char *data;
1054
1055 fd = open(path, O_RDONLY);
1056 if (fd == -1) {
1057 if (errno != ENOENT) {
1058 ERR(sh, "Unable to open %s: %s\n", path, strerror(errno));
1059 return -1;
1060 }
1061 /* Checksum file not present - force a rebuild. */
1062 return 1;
1063 }
1064
1065 if (fstat(fd, &sb) == -1) {
1066 ERR(sh, "Unable to stat %s\n", path);
1067 retval = -1;
1068 goto out_close;
1069 }
1070
1071 if (sb.st_size != (off_t)CHECKSUM_CONTENT_SIZE) {
1072 /* Incompatible/invalid hash type - just force a rebuild. */
1073 WARN(sh, "Module checksum invalid - forcing a rebuild\n");
1074 retval = 1;
1075 goto out_close;
1076 }
1077
1078 data = mmap(NULL, CHECKSUM_CONTENT_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
1079 if (data == MAP_FAILED) {
1080 ERR(sh, "Unable to mmap %s\n", path);
1081 retval = -1;
1082 goto out_close;
1083 }
1084
1085 retval = memcmp(data, reference, CHECKSUM_CONTENT_SIZE) != 0;
1086 munmap(data, sb.st_size);
1087 out_close:
1088 close(fd);
1089 return retval;
1090 }
1091
semanage_write_modules_checksum(semanage_handle_t * sh,const char * checksum)1092 static int semanage_write_modules_checksum(semanage_handle_t *sh,
1093 const char *checksum)
1094 {
1095 const char *path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_CHECKSUM);
1096
1097 return write_file(sh, path, checksum, CHECKSUM_CONTENT_SIZE);
1098 }
1099
1100 /* Files that must exist in order to skip policy rebuild. */
1101 static const int semanage_computed_files[] = {
1102 SEMANAGE_STORE_KERNEL,
1103 SEMANAGE_STORE_FC,
1104 SEMANAGE_STORE_SEUSERS,
1105 SEMANAGE_LINKED,
1106 SEMANAGE_SEUSERS_LINKED,
1107 SEMANAGE_USERS_EXTRA_LINKED
1108 };
1109
1110 /* Copies a file from src to dst. If dst already exists then
1111 * overwrite it. If source doesn't exist then return success.
1112 * Returns 0 on success, -1 on error. */
copy_file_if_exists(const char * src,const char * dst,mode_t mode)1113 static int copy_file_if_exists(const char *src, const char *dst, mode_t mode){
1114 int rc = semanage_copy_file(src, dst, mode, false);
1115 return (rc < 0 && errno != ENOENT) ? rc : 0;
1116 }
1117
1118 /********************* direct API functions ********************/
1119
1120 /* Commits all changes in sandbox to the actual kernel policy.
1121 * Returns commit number on success, -1 on error.
1122 */
semanage_direct_commit(semanage_handle_t * sh)1123 static int semanage_direct_commit(semanage_handle_t * sh)
1124 {
1125 char **mod_filenames = NULL;
1126 char *fc_buffer = NULL;
1127 size_t fc_buffer_len = 0;
1128 const char *ofilename = NULL;
1129 const char *path;
1130 int retval = -1, num_modinfos = 0, i;
1131 sepol_policydb_t *out = NULL;
1132 struct cil_db *cildb = NULL;
1133 semanage_module_info_t *modinfos = NULL;
1134 mode_t mask = umask(0077);
1135 struct stat sb;
1136 char modules_checksum[CHECKSUM_CONTENT_SIZE + 1 /* '\0' */];
1137
1138 int do_rebuild, do_write_kernel, do_install;
1139 int fcontexts_modified, ports_modified, seusers_modified,
1140 disable_dontaudit, preserve_tunables, ibpkeys_modified,
1141 ibendports_modified;
1142 dbase_config_t *users = semanage_user_dbase_local(sh);
1143 dbase_config_t *users_base = semanage_user_base_dbase_local(sh);
1144 dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh);
1145 dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh);
1146 dbase_config_t *ports = semanage_port_dbase_local(sh);
1147 dbase_config_t *pports = semanage_port_dbase_policy(sh);
1148 dbase_config_t *ibpkeys = semanage_ibpkey_dbase_local(sh);
1149 dbase_config_t *pibpkeys = semanage_ibpkey_dbase_policy(sh);
1150 dbase_config_t *ibendports = semanage_ibendport_dbase_local(sh);
1151 dbase_config_t *pibendports = semanage_ibendport_dbase_policy(sh);
1152 dbase_config_t *bools = semanage_bool_dbase_local(sh);
1153 dbase_config_t *pbools = semanage_bool_dbase_policy(sh);
1154 dbase_config_t *ifaces = semanage_iface_dbase_local(sh);
1155 dbase_config_t *pifaces = semanage_iface_dbase_policy(sh);
1156 dbase_config_t *nodes = semanage_node_dbase_local(sh);
1157 dbase_config_t *pnodes = semanage_node_dbase_policy(sh);
1158 dbase_config_t *fcontexts = semanage_fcontext_dbase_local(sh);
1159 dbase_config_t *pfcontexts = semanage_fcontext_dbase_policy(sh);
1160 dbase_config_t *seusers = semanage_seuser_dbase_local(sh);
1161 dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh);
1162
1163 /* Modified flags that we need to use more than once. */
1164 ports_modified = ports->dtable->is_modified(ports->dbase);
1165 ibpkeys_modified = ibpkeys->dtable->is_modified(ibpkeys->dbase);
1166 ibendports_modified = ibendports->dtable->is_modified(ibendports->dbase);
1167 seusers_modified = seusers->dtable->is_modified(seusers->dbase);
1168 fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
1169
1170 /* Before we do anything else, flush the join to its component parts.
1171 * This *does not* flush to disk automatically */
1172 if (users->dtable->is_modified(users->dbase)) {
1173 retval = users->dtable->flush(sh, users->dbase);
1174 if (retval < 0)
1175 goto cleanup;
1176 }
1177
1178 /* Rebuild if explicitly requested or any module changes occurred. */
1179 do_rebuild = sh->do_rebuild | sh->modules_modified;
1180
1181 /* Create or remove the disable_dontaudit flag file. */
1182 path = semanage_path(SEMANAGE_TMP, SEMANAGE_DISABLE_DONTAUDIT);
1183 if (stat(path, &sb) == 0)
1184 do_rebuild |= !(sepol_get_disable_dontaudit(sh->sepolh) == 1);
1185 else if (errno == ENOENT) {
1186 /* The file does not exist */
1187 do_rebuild |= (sepol_get_disable_dontaudit(sh->sepolh) == 1);
1188 } else {
1189 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1190 retval = -1;
1191 goto cleanup;
1192 }
1193 if (sepol_get_disable_dontaudit(sh->sepolh) == 1) {
1194 FILE *touch;
1195 touch = fopen(path, "w");
1196 if (touch != NULL) {
1197 if (fclose(touch) != 0) {
1198 ERR(sh, "Error attempting to create disable_dontaudit flag.");
1199 goto cleanup;
1200 }
1201 } else {
1202 ERR(sh, "Error attempting to create disable_dontaudit flag.");
1203 goto cleanup;
1204 }
1205 } else {
1206 if (remove(path) == -1 && errno != ENOENT) {
1207 ERR(sh, "Error removing the disable_dontaudit flag.");
1208 goto cleanup;
1209 }
1210 }
1211
1212 /* Create or remove the preserve_tunables flag file. */
1213 path = semanage_path(SEMANAGE_TMP, SEMANAGE_PRESERVE_TUNABLES);
1214 if (stat(path, &sb) == 0)
1215 do_rebuild |= !(sepol_get_preserve_tunables(sh->sepolh) == 1);
1216 else if (errno == ENOENT) {
1217 /* The file does not exist */
1218 do_rebuild |= (sepol_get_preserve_tunables(sh->sepolh) == 1);
1219 } else {
1220 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1221 retval = -1;
1222 goto cleanup;
1223 }
1224
1225 if (sepol_get_preserve_tunables(sh->sepolh) == 1) {
1226 FILE *touch;
1227 touch = fopen(path, "w");
1228 if (touch != NULL) {
1229 if (fclose(touch) != 0) {
1230 ERR(sh, "Error attempting to create preserve_tunable flag.");
1231 goto cleanup;
1232 }
1233 } else {
1234 ERR(sh, "Error attempting to create preserve_tunable flag.");
1235 goto cleanup;
1236 }
1237 } else {
1238 if (remove(path) == -1 && errno != ENOENT) {
1239 ERR(sh, "Error removing the preserve_tunables flag.");
1240 goto cleanup;
1241 }
1242 }
1243
1244 /*
1245 * This is for systems that have already migrated with an older version
1246 * of semanage_migrate_store. The older version did not copy
1247 * policy.kern so the policy binary must be rebuilt here.
1248 * This also ensures that any linked files that are required
1249 * in order to skip re-linking are present; otherwise, we force
1250 * a rebuild.
1251 */
1252 for (i = 0; !do_rebuild && i < (int)ARRAY_SIZE(semanage_computed_files); i++) {
1253 path = semanage_path(SEMANAGE_TMP, semanage_computed_files[i]);
1254 if (stat(path, &sb) != 0) {
1255 if (errno != ENOENT) {
1256 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1257 retval = -1;
1258 goto cleanup;
1259 }
1260
1261 do_rebuild = 1;
1262 break;
1263 }
1264 }
1265
1266 if (do_rebuild || sh->check_ext_changes) {
1267 retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos);
1268 if (retval < 0) {
1269 goto cleanup;
1270 }
1271
1272 /* No modules - nothing to rebuild. */
1273 if (num_modinfos == 0) {
1274 goto cleanup;
1275 }
1276
1277 retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos,
1278 modules_checksum);
1279 if (retval < 0) {
1280 ERR(sh, "Failed to compile hll files into cil files.\n");
1281 goto cleanup;
1282 }
1283
1284 if (!do_rebuild && sh->check_ext_changes) {
1285 retval = semanage_compare_checksum(sh, modules_checksum);
1286 if (retval < 0)
1287 goto cleanup;
1288 do_rebuild = retval;
1289 }
1290
1291 retval = semanage_write_modules_checksum(sh, modules_checksum);
1292 if (retval < 0) {
1293 ERR(sh, "Failed to write module checksum file.\n");
1294 goto cleanup;
1295 }
1296 }
1297
1298 /*
1299 * If there were policy changes, or explicitly requested, or
1300 * any required files are missing, rebuild the policy.
1301 */
1302 if (do_rebuild) {
1303 /* =================== Module expansion =============== */
1304
1305 retval = semanage_get_cil_paths(sh, modinfos, num_modinfos, &mod_filenames);
1306 if (retval < 0)
1307 goto cleanup;
1308
1309 retval = semanage_verify_modules(sh, mod_filenames, num_modinfos);
1310 if (retval < 0)
1311 goto cleanup;
1312
1313 cil_db_init(&cildb);
1314
1315 disable_dontaudit = sepol_get_disable_dontaudit(sh->sepolh);
1316 preserve_tunables = sepol_get_preserve_tunables(sh->sepolh);
1317 cil_set_disable_dontaudit(cildb, disable_dontaudit);
1318 cil_set_disable_neverallow(cildb, !(sh->conf->expand_check));
1319 cil_set_preserve_tunables(cildb, preserve_tunables);
1320 cil_set_target_platform(cildb, sh->conf->target_platform);
1321 cil_set_policy_version(cildb, sh->conf->policyvers);
1322
1323 if (sh->conf->handle_unknown != -1) {
1324 cil_set_handle_unknown(cildb, sh->conf->handle_unknown);
1325 }
1326
1327 retval = semanage_load_files(sh, cildb, mod_filenames, num_modinfos);
1328 if (retval < 0) {
1329 goto cleanup;
1330 }
1331
1332 retval = cil_compile(cildb);
1333 if (retval < 0)
1334 goto cleanup;
1335
1336 retval = cil_build_policydb(cildb, &out);
1337 if (retval < 0)
1338 goto cleanup;
1339
1340 /* File Contexts */
1341 retval = cil_filecons_to_string(cildb, &fc_buffer, &fc_buffer_len);
1342 if (retval < 0)
1343 goto cleanup;
1344
1345 /* Write the contexts (including template contexts) to a single file. */
1346 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL);
1347 if (ofilename == NULL) {
1348 retval = -1;
1349 goto cleanup;
1350 }
1351 retval = write_file(sh, ofilename, fc_buffer, fc_buffer_len);
1352 if (retval < 0)
1353 goto cleanup;
1354
1355 /* Split complete and template file contexts into their separate files. */
1356 retval = semanage_split_fc(sh);
1357 if (retval < 0)
1358 goto cleanup;
1359
1360 /* remove FC_TMPL now that it is now longer needed */
1361 unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL));
1362
1363 pfcontexts->dtable->drop_cache(pfcontexts->dbase);
1364
1365 /* SEUsers */
1366 retval = semanage_direct_update_seuser(sh, cildb);
1367 if (retval < 0)
1368 goto cleanup;
1369
1370 /* User Extra */
1371 retval = semanage_direct_update_user_extra(sh, cildb);
1372 if (retval < 0)
1373 goto cleanup;
1374
1375 cil_db_destroy(&cildb);
1376
1377 /* Remove redundancies in binary policy if requested. */
1378 if (sh->conf->optimize_policy) {
1379 retval = sepol_policydb_optimize(out);
1380 if (retval < 0)
1381 goto cleanup;
1382 }
1383
1384 /* Write the linked policy before merging local changes. */
1385 retval = semanage_write_policydb(sh, out,
1386 SEMANAGE_LINKED);
1387 if (retval < 0)
1388 goto cleanup;
1389 } else {
1390 /* Load the existing linked policy, w/o local changes */
1391 retval = sepol_policydb_create(&out);
1392 if (retval < 0)
1393 goto cleanup;
1394
1395 retval = semanage_read_policydb(sh, out, SEMANAGE_LINKED);
1396 if (retval < 0)
1397 goto cleanup;
1398
1399 path = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS_LINKED);
1400 if (stat(path, &sb) == 0) {
1401 retval = semanage_copy_file(path,
1402 semanage_path(SEMANAGE_TMP,
1403 SEMANAGE_STORE_SEUSERS),
1404 0, false);
1405 if (retval < 0)
1406 goto cleanup;
1407 pseusers->dtable->drop_cache(pseusers->dbase);
1408 } else if (errno == ENOENT) {
1409 /* The file does not exist */
1410 pseusers->dtable->clear(sh, pseusers->dbase);
1411 } else {
1412 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1413 retval = -1;
1414 goto cleanup;
1415 }
1416
1417 path = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA_LINKED);
1418 if (stat(path, &sb) == 0) {
1419 retval = semanage_copy_file(path,
1420 semanage_path(SEMANAGE_TMP,
1421 SEMANAGE_USERS_EXTRA),
1422 0, false);
1423 if (retval < 0)
1424 goto cleanup;
1425 pusers_extra->dtable->drop_cache(pusers_extra->dbase);
1426 } else if (errno == ENOENT) {
1427 /* The file does not exist */
1428 pusers_extra->dtable->clear(sh, pusers_extra->dbase);
1429 } else {
1430 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1431 retval = -1;
1432 goto cleanup;
1433 }
1434 }
1435
1436 /*
1437 * Determine what else needs to be done.
1438 * We need to write the kernel policy if we are rebuilding
1439 * or if any other policy component that lives in the kernel
1440 * policy has been modified. We also want to force it when
1441 * check_ext_changes was specified as the various dbases may have
1442 * changes as well.
1443 * We need to install the policy files if any of the managed files
1444 * that live under /etc/selinux (kernel policy, seusers, file contexts)
1445 * will be modified.
1446 */
1447 do_write_kernel = do_rebuild | sh->check_ext_changes |
1448 ports_modified | ibpkeys_modified | ibendports_modified |
1449 bools->dtable->is_modified(bools->dbase) |
1450 ifaces->dtable->is_modified(ifaces->dbase) |
1451 nodes->dtable->is_modified(nodes->dbase) |
1452 users->dtable->is_modified(users_base->dbase);
1453 do_install = do_write_kernel | seusers_modified | fcontexts_modified;
1454
1455 /* Attach our databases to the policydb we just created or loaded. */
1456 dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
1457 dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
1458 dbase_policydb_attach((dbase_policydb_t *) pibpkeys->dbase, out);
1459 dbase_policydb_attach((dbase_policydb_t *) pibendports->dbase, out);
1460 dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out);
1461 dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out);
1462 dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out);
1463
1464 /* Merge local changes */
1465 retval = semanage_base_merge_components(sh);
1466 if (retval < 0)
1467 goto cleanup;
1468
1469 if (do_write_kernel) {
1470 /* Write new kernel policy. */
1471 retval = semanage_write_policydb(sh, out,
1472 SEMANAGE_STORE_KERNEL);
1473 if (retval < 0)
1474 goto cleanup;
1475
1476 /* Run the kernel policy verifier, if any. */
1477 retval = semanage_verify_kernel(sh);
1478 if (retval < 0)
1479 goto cleanup;
1480 }
1481
1482 /* ======= Post-process: Validate non-policydb components ===== */
1483
1484 /* Validate local modifications to file contexts.
1485 * Note: those are still cached, even though they've been
1486 * merged into the main file_contexts. We won't check the
1487 * large file_contexts - checked at compile time */
1488 if (do_rebuild || fcontexts_modified) {
1489 retval = semanage_fcontext_validate_local(sh, out);
1490 if (retval < 0)
1491 goto cleanup;
1492 }
1493
1494 /* Validate local seusers against policy */
1495 if (do_rebuild || seusers_modified) {
1496 retval = semanage_seuser_validate_local(sh, out);
1497 if (retval < 0)
1498 goto cleanup;
1499 }
1500
1501 /* Validate local ports for overlap */
1502 if (do_rebuild || ports_modified) {
1503 retval = semanage_port_validate_local(sh);
1504 if (retval < 0)
1505 goto cleanup;
1506 }
1507
1508 /* Validate local ibpkeys for overlap */
1509 if (do_rebuild || ibpkeys_modified) {
1510 retval = semanage_ibpkey_validate_local(sh);
1511 if (retval < 0)
1512 goto cleanup;
1513 }
1514
1515 /* Validate local ibendports */
1516 if (do_rebuild || ibendports_modified) {
1517 retval = semanage_ibendport_validate_local(sh);
1518 if (retval < 0)
1519 goto cleanup;
1520 }
1521 /* ================== Write non-policydb components ========= */
1522
1523 /* Commit changes to components */
1524 retval = semanage_commit_components(sh);
1525 if (retval < 0)
1526 goto cleanup;
1527
1528 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
1529 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL),
1530 sh->conf->file_mode, false);
1531 if (retval < 0) {
1532 goto cleanup;
1533 }
1534
1535 retval = copy_file_if_exists(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
1536 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL),
1537 sh->conf->file_mode);
1538 if (retval < 0) {
1539 goto cleanup;
1540 }
1541
1542 retval = copy_file_if_exists(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC),
1543 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC),
1544 sh->conf->file_mode);
1545 if (retval < 0) {
1546 goto cleanup;
1547 }
1548
1549 retval = copy_file_if_exists(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS),
1550 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS),
1551 sh->conf->file_mode);
1552 if (retval < 0) {
1553 goto cleanup;
1554 }
1555
1556 /* run genhomedircon if its enabled, this should be the last operation
1557 * which requires the out policydb */
1558 if (!sh->conf->disable_genhomedircon) {
1559 if (out){
1560 if ((retval = semanage_genhomedircon(sh, out, sh->conf->usepasswd,
1561 sh->conf->ignoredirs)) != 0) {
1562 ERR(sh, "semanage_genhomedircon returned error code %d.", retval);
1563 goto cleanup;
1564 }
1565 /* file_contexts.homedirs was created in SEMANAGE_TMP store */
1566 retval = semanage_copy_file(
1567 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS),
1568 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS),
1569 sh->conf->file_mode, false);
1570 if (retval < 0) {
1571 goto cleanup;
1572 }
1573 }
1574 } else {
1575 WARN(sh, "WARNING: genhomedircon is disabled. \
1576 See /etc/selinux/semanage.conf if you need to enable it.");
1577 }
1578
1579 /* free out, if we don't free it before calling semanage_install_sandbox
1580 * then fork() may fail on low memory machines */
1581 sepol_policydb_free(out);
1582 out = NULL;
1583
1584 if (do_install)
1585 retval = semanage_install_sandbox(sh);
1586
1587 cleanup:
1588 for (i = 0; i < num_modinfos; i++) {
1589 semanage_module_info_destroy(sh, &modinfos[i]);
1590 }
1591 free(modinfos);
1592
1593 for (i = 0; mod_filenames != NULL && i < num_modinfos; i++) {
1594 free(mod_filenames[i]);
1595 }
1596
1597 /* Detach from policydb, so it can be freed */
1598 dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase);
1599 dbase_policydb_detach((dbase_policydb_t *) pports->dbase);
1600 dbase_policydb_detach((dbase_policydb_t *) pibpkeys->dbase);
1601 dbase_policydb_detach((dbase_policydb_t *) pibendports->dbase);
1602 dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase);
1603 dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase);
1604 dbase_policydb_detach((dbase_policydb_t *) pbools->dbase);
1605
1606 free(mod_filenames);
1607 sepol_policydb_free(out);
1608 cil_db_destroy(&cildb);
1609
1610 free(fc_buffer);
1611
1612 /* Set commit_err so other functions can detect any errors. Note that
1613 * retval > 0 will be the commit number.
1614 */
1615 if (retval < 0)
1616 sh->commit_err = retval;
1617
1618 if (semanage_remove_tmps(sh) != 0)
1619 retval = -1;
1620
1621 semanage_release_trans_lock(sh);
1622 umask(mask);
1623
1624 return retval;
1625 }
1626
1627 /* Writes a module to the sandbox's module directory, overwriting any
1628 * previous module stored within. Note that module data are not
1629 * free()d by this function; caller is responsible for deallocating it
1630 * if necessary. Returns 0 on success, -1 if out of memory, -2 if the
1631 * data does not represent a valid module file, -3 if error while
1632 * writing file. */
semanage_direct_install(semanage_handle_t * sh,char * data,size_t data_len,const char * module_name,const char * lang_ext)1633 static int semanage_direct_install(semanage_handle_t * sh,
1634 char *data, size_t data_len,
1635 const char *module_name, const char *lang_ext)
1636 {
1637 int status = 0;
1638 int ret = 0;
1639
1640 semanage_module_info_t modinfo;
1641 ret = semanage_module_info_init(sh, &modinfo);
1642 if (ret != 0) {
1643 status = -1;
1644 goto cleanup;
1645 }
1646
1647 ret = semanage_module_info_set_priority(sh, &modinfo, sh->priority);
1648 if (ret != 0) {
1649 status = -1;
1650 goto cleanup;
1651 }
1652
1653 ret = semanage_module_info_set_name(sh, &modinfo, module_name);
1654 if (ret != 0) {
1655 status = -1;
1656 goto cleanup;
1657 }
1658
1659 ret = semanage_module_info_set_lang_ext(sh, &modinfo, lang_ext);
1660 if (ret != 0) {
1661 status = -1;
1662 goto cleanup;
1663 }
1664
1665 ret = semanage_module_info_set_enabled(sh, &modinfo, -1);
1666 if (ret != 0) {
1667 status = -1;
1668 goto cleanup;
1669 }
1670
1671 status = semanage_direct_install_info(sh, &modinfo, data, data_len);
1672
1673 cleanup:
1674
1675 semanage_module_info_destroy(sh, &modinfo);
1676
1677 return status;
1678 }
1679
1680 /* Attempts to link a module to the sandbox's module directory, unlinking any
1681 * previous module stored within. Returns 0 on success, -1 if out of memory, -2 if the
1682 * data does not represent a valid module file, -3 if error while
1683 * writing file. */
1684
semanage_direct_install_file(semanage_handle_t * sh,const char * install_filename)1685 static int semanage_direct_install_file(semanage_handle_t * sh,
1686 const char *install_filename)
1687 {
1688
1689 int retval = -1;
1690 char *path = NULL;
1691 char *filename;
1692 char *lang_ext = NULL;
1693 char *module_name = NULL;
1694 char *separator;
1695 char *version = NULL;
1696 struct file_contents contents = {};
1697
1698 retval = map_compressed_file(sh, install_filename, &contents);
1699 if (retval < 0) {
1700 ERR(sh, "Unable to read file %s\n", install_filename);
1701 goto cleanup;
1702 }
1703
1704 path = strdup(install_filename);
1705 if (path == NULL) {
1706 ERR(sh, "No memory available for strdup.\n");
1707 retval = -1;
1708 goto cleanup;
1709 }
1710
1711 filename = basename(path);
1712
1713 if (contents.compressed) {
1714 separator = strrchr(filename, '.');
1715 if (separator == NULL) {
1716 ERR(sh, "Compressed module does not have a valid extension.");
1717 retval = -1;
1718 goto cleanup;
1719 }
1720 *separator = '\0';
1721 lang_ext = separator + 1;
1722 }
1723
1724 separator = strrchr(filename, '.');
1725 if (separator == NULL) {
1726 if (lang_ext == NULL) {
1727 ERR(sh, "Module does not have a valid extension.");
1728 retval = -1;
1729 goto cleanup;
1730 }
1731 } else {
1732 *separator = '\0';
1733 lang_ext = separator + 1;
1734 }
1735
1736 if (strcmp(lang_ext, "pp") == 0) {
1737 retval = parse_module_headers(sh, contents.data, contents.len,
1738 &module_name, &version);
1739 free(version);
1740 if (retval != 0)
1741 goto cleanup;
1742 }
1743
1744 if (module_name == NULL) {
1745 module_name = strdup(filename);
1746 if (module_name == NULL) {
1747 ERR(sh, "No memory available for module_name.\n");
1748 retval = -1;
1749 goto cleanup;
1750 }
1751 } else if (strcmp(module_name, filename) != 0) {
1752 fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename);
1753 }
1754
1755 retval = semanage_direct_install(sh, contents.data, contents.len,
1756 module_name, lang_ext);
1757
1758 cleanup:
1759 unmap_compressed_file(&contents);
1760 free(module_name);
1761 free(path);
1762
1763 return retval;
1764 }
1765
semanage_direct_extract(semanage_handle_t * sh,semanage_module_key_t * modkey,int extract_cil,void ** mapped_data,size_t * data_len,semanage_module_info_t ** modinfo)1766 static int semanage_direct_extract(semanage_handle_t * sh,
1767 semanage_module_key_t *modkey,
1768 int extract_cil,
1769 void **mapped_data,
1770 size_t *data_len,
1771 semanage_module_info_t **modinfo)
1772 {
1773 char module_path[PATH_MAX];
1774 char input_file[PATH_MAX];
1775 enum semanage_module_path_type file_type;
1776 int rc = -1;
1777 semanage_module_info_t *_modinfo = NULL;
1778 struct stat sb;
1779 struct file_contents contents = {};
1780
1781 /* get path of module */
1782 rc = semanage_module_get_path(
1783 sh,
1784 (const semanage_module_info_t *)modkey,
1785 SEMANAGE_MODULE_PATH_NAME,
1786 module_path,
1787 sizeof(module_path));
1788 if (rc != 0) {
1789 goto cleanup;
1790 }
1791
1792 if (stat(module_path, &sb) != 0) {
1793 ERR(sh, "Unable to access %s: %s\n", module_path, strerror(errno));
1794 rc = -1;
1795 goto cleanup;
1796 }
1797
1798 rc = semanage_module_get_module_info(sh,
1799 modkey,
1800 &_modinfo);
1801 if (rc != 0) {
1802 goto cleanup;
1803 }
1804
1805 if (extract_cil || strcmp(_modinfo->lang_ext, "cil") == 0) {
1806 file_type = SEMANAGE_MODULE_PATH_CIL;
1807 } else {
1808 file_type = SEMANAGE_MODULE_PATH_HLL;
1809 }
1810
1811 /* get path of what to extract */
1812 rc = semanage_module_get_path(
1813 sh,
1814 _modinfo,
1815 file_type,
1816 input_file,
1817 sizeof(input_file));
1818 if (rc != 0) {
1819 goto cleanup;
1820 }
1821
1822 if (extract_cil == 1 && strcmp(_modinfo->lang_ext, "cil") && stat(input_file, &sb) != 0) {
1823 if (errno != ENOENT) {
1824 ERR(sh, "Unable to access %s: %s\n", input_file, strerror(errno));
1825 rc = -1;
1826 goto cleanup;
1827 }
1828
1829 rc = semanage_compile_module(sh, _modinfo, NULL);
1830 if (rc < 0) {
1831 goto cleanup;
1832 }
1833 }
1834
1835 rc = map_compressed_file(sh, input_file, &contents);
1836 if (rc < 0) {
1837 ERR(sh, "Error mapping file: %s", input_file);
1838 goto cleanup;
1839 }
1840
1841 /* The API promises an mmap'ed pointer */
1842 if (contents.compressed) {
1843 *mapped_data = mmap(NULL, contents.len, PROT_READ|PROT_WRITE,
1844 MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
1845 if (*mapped_data == MAP_FAILED) {
1846 ERR(sh, "Unable to map memory");
1847 rc = -1;
1848 goto cleanup;
1849 }
1850 memcpy(*mapped_data, contents.data, contents.len);
1851 free(contents.data);
1852 } else {
1853 *mapped_data = contents.data;
1854 }
1855
1856 *modinfo = _modinfo;
1857 *data_len = contents.len;
1858
1859 cleanup:
1860 if (rc != 0) {
1861 unmap_compressed_file(&contents);
1862 semanage_module_info_destroy(sh, _modinfo);
1863 free(_modinfo);
1864 }
1865
1866 return rc;
1867 }
1868
1869 /* Removes a module from the sandbox. Returns 0 on success, -1 if out
1870 * of memory, -2 if module not found or could not be removed. */
semanage_direct_remove(semanage_handle_t * sh,char * module_name)1871 static int semanage_direct_remove(semanage_handle_t * sh, char *module_name)
1872 {
1873 int status = 0;
1874 int ret = 0;
1875
1876 semanage_module_key_t modkey;
1877 ret = semanage_module_key_init(sh, &modkey);
1878 if (ret != 0) {
1879 status = -1;
1880 goto cleanup;
1881 }
1882
1883 ret = semanage_module_key_set_priority(sh, &modkey, sh->priority);
1884 if (ret != 0) {
1885 status = -1;
1886 goto cleanup;
1887 }
1888
1889 ret = semanage_module_key_set_name(sh, &modkey, module_name);
1890 if (ret != 0) {
1891 status = -1;
1892 goto cleanup;
1893 }
1894
1895 status = semanage_direct_remove_key(sh, &modkey);
1896
1897 cleanup:
1898 semanage_module_key_destroy(sh, &modkey);
1899 return status;
1900 }
1901
1902 /* Allocate an array of module_info structures for each readable
1903 * module within the store. Note that if the calling program has
1904 * already begun a transaction then this function will get a list of
1905 * modules within the sandbox. The caller is responsible for calling
1906 * semanage_module_info_datum_destroy() on each element of the array
1907 * as well as free()ing the entire list.
1908 */
semanage_direct_list(semanage_handle_t * sh,semanage_module_info_t ** modinfo,int * num_modules)1909 static int semanage_direct_list(semanage_handle_t * sh,
1910 semanage_module_info_t ** modinfo,
1911 int *num_modules)
1912 {
1913 int i, retval = -1;
1914 *modinfo = NULL;
1915 *num_modules = 0;
1916
1917 /* get the read lock when reading from the active
1918 (non-transaction) directory */
1919 if (!sh->is_in_transaction)
1920 if (semanage_get_active_lock(sh) < 0)
1921 return -1;
1922
1923 if (semanage_get_active_modules(sh, modinfo, num_modules) == -1) {
1924 goto cleanup;
1925 }
1926
1927 if (num_modules == 0) {
1928 retval = semanage_direct_get_serial(sh);
1929 goto cleanup;
1930 }
1931
1932 retval = semanage_direct_get_serial(sh);
1933
1934 cleanup:
1935 if (retval < 0) {
1936 for (i = 0; i < *num_modules; i++) {
1937 semanage_module_info_destroy(sh, &(*modinfo[i]));
1938 modinfo[i] = NULL;
1939 }
1940 free(*modinfo);
1941 *modinfo = NULL;
1942 }
1943
1944 if (!sh->is_in_transaction) {
1945 semanage_release_active_lock(sh);
1946 }
1947 return retval;
1948 }
1949
semanage_direct_get_enabled(semanage_handle_t * sh,const semanage_module_key_t * modkey,int * enabled)1950 static int semanage_direct_get_enabled(semanage_handle_t *sh,
1951 const semanage_module_key_t *modkey,
1952 int *enabled)
1953 {
1954 assert(sh);
1955 assert(modkey);
1956 assert(enabled);
1957
1958 int status = 0;
1959 int ret = 0;
1960
1961 char path[PATH_MAX];
1962 struct stat sb;
1963 semanage_module_info_t *modinfo = NULL;
1964
1965 /* get module info */
1966 ret = semanage_module_get_module_info(
1967 sh,
1968 modkey,
1969 &modinfo);
1970 if (ret != 0) {
1971 status = -1;
1972 goto cleanup;
1973 }
1974
1975 /* get disabled file path */
1976 ret = semanage_module_get_path(
1977 sh,
1978 modinfo,
1979 SEMANAGE_MODULE_PATH_DISABLED,
1980 path,
1981 sizeof(path));
1982 if (ret != 0) {
1983 status = -1;
1984 goto cleanup;
1985 }
1986
1987 if (stat(path, &sb) < 0) {
1988 if (errno != ENOENT) {
1989 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1990 status = -1;
1991 goto cleanup;
1992 }
1993
1994 *enabled = 1;
1995 }
1996 else {
1997 *enabled = 0;
1998 }
1999
2000 cleanup:
2001 semanage_module_info_destroy(sh, modinfo);
2002 free(modinfo);
2003
2004 return status;
2005 }
2006
semanage_direct_set_enabled(semanage_handle_t * sh,const semanage_module_key_t * modkey,int enabled)2007 static int semanage_direct_set_enabled(semanage_handle_t *sh,
2008 const semanage_module_key_t *modkey,
2009 int enabled)
2010 {
2011 assert(sh);
2012 assert(modkey);
2013
2014 int status = 0;
2015 int ret = 0;
2016
2017 char fn[PATH_MAX];
2018 const char *path = NULL;
2019 FILE *fp = NULL;
2020 semanage_module_info_t *modinfo = NULL;
2021 mode_t mask;
2022
2023 /* check transaction */
2024 if (!sh->is_in_transaction) {
2025 if (semanage_begin_transaction(sh) < 0) {
2026 status = -1;
2027 goto cleanup;
2028 }
2029 }
2030
2031 /* validate name */
2032 ret = semanage_module_validate_name(modkey->name);
2033 if (ret != 0) {
2034 errno = 0;
2035 ERR(sh, "Name %s is invalid.", modkey->name);
2036 status = -1;
2037 goto cleanup;
2038 }
2039
2040 /* validate enabled */
2041 ret = semanage_module_validate_enabled(enabled);
2042 if (ret != 0) {
2043 errno = 0;
2044 ERR(sh, "Enabled status %d is invalid.", enabled);
2045 status = -1;
2046 goto cleanup;
2047 }
2048
2049 /* check for disabled path, create if missing */
2050 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED);
2051
2052 ret = semanage_mkdir(sh, path);
2053 if (ret != 0) {
2054 status = -1;
2055 goto cleanup;
2056 }
2057
2058 /* get module info */
2059 ret = semanage_module_get_module_info(
2060 sh,
2061 modkey,
2062 &modinfo);
2063 if (ret != 0) {
2064 status = -1;
2065 goto cleanup;
2066 }
2067
2068 /* get module disabled file */
2069 ret = semanage_module_get_path(
2070 sh,
2071 modinfo,
2072 SEMANAGE_MODULE_PATH_DISABLED,
2073 fn,
2074 sizeof(fn));
2075 if (ret != 0) {
2076 status = -1;
2077 goto cleanup;
2078 }
2079
2080 switch (enabled) {
2081 case 0: /* disable the module */
2082 mask = umask(0077);
2083 fp = fopen(fn, "w");
2084 umask(mask);
2085
2086 if (fp == NULL) {
2087 ERR(sh,
2088 "Unable to disable module %s",
2089 modkey->name);
2090 status = -1;
2091 goto cleanup;
2092 }
2093
2094 ret = fclose(fp);
2095 fp = NULL;
2096 if (ret != 0) {
2097 ERR(sh,
2098 "Unable to close disabled file for module %s",
2099 modkey->name);
2100 status = -1;
2101 goto cleanup;
2102 }
2103
2104 break;
2105 case 1: /* enable the module */
2106 if (unlink(fn) < 0) {
2107 if (errno != ENOENT) {
2108 ERR(sh,
2109 "Unable to enable module %s",
2110 modkey->name);
2111 status = -1;
2112 goto cleanup;
2113 }
2114 else {
2115 /* module already enabled */
2116 errno = 0;
2117 }
2118 }
2119
2120 break;
2121 case -1: /* warn about ignored setting to default */
2122 WARN(sh,
2123 "Setting module %s to 'default' state has no effect",
2124 modkey->name);
2125 break;
2126 }
2127
2128 cleanup:
2129 semanage_module_info_destroy(sh, modinfo);
2130 free(modinfo);
2131
2132 if (fp != NULL) fclose(fp);
2133 return status;
2134 }
2135
semanage_direct_access_check(semanage_handle_t * sh)2136 int semanage_direct_access_check(semanage_handle_t * sh)
2137 {
2138 if (semanage_check_init(sh, sh->conf->store_root_path))
2139 return -1;
2140
2141 return semanage_store_access_check();
2142 }
2143
semanage_direct_mls_enabled(semanage_handle_t * sh)2144 int semanage_direct_mls_enabled(semanage_handle_t * sh)
2145 {
2146 sepol_policydb_t *p = NULL;
2147 int retval;
2148
2149 retval = sepol_policydb_create(&p);
2150 if (retval < 0)
2151 goto cleanup;
2152
2153 retval = semanage_read_policydb(sh, p, SEMANAGE_STORE_KERNEL);
2154 if (retval < 0)
2155 goto cleanup;
2156
2157 retval = sepol_policydb_mls_enabled(p);
2158 cleanup:
2159 sepol_policydb_free(p);
2160 return retval;
2161 }
2162
semanage_direct_get_module_info(semanage_handle_t * sh,const semanage_module_key_t * modkey,semanage_module_info_t ** modinfo)2163 static int semanage_direct_get_module_info(semanage_handle_t *sh,
2164 const semanage_module_key_t *modkey,
2165 semanage_module_info_t **modinfo)
2166 {
2167 assert(sh);
2168 assert(modkey);
2169 assert(modinfo);
2170
2171 int status = 0;
2172 int ret = 0;
2173
2174 char fn[PATH_MAX];
2175 FILE *fp = NULL;
2176 size_t size = 0;
2177 struct stat sb;
2178 char *tmp = NULL;
2179
2180 int i = 0;
2181
2182 semanage_module_info_t *modinfos = NULL;
2183 int modinfos_len = 0;
2184 semanage_module_info_t *highest = NULL;
2185
2186 /* check module name */
2187 ret = semanage_module_validate_name(modkey->name);
2188 if (ret < 0) {
2189 errno = 0;
2190 ERR(sh, "Name %s is invalid.", modkey->name);
2191 status = -1;
2192 goto cleanup;
2193 }
2194
2195 /* if priority == 0, then find the highest priority available */
2196 if (modkey->priority == 0) {
2197 ret = semanage_direct_list_all(sh, &modinfos, &modinfos_len);
2198 if (ret != 0) {
2199 status = -1;
2200 goto cleanup;
2201 }
2202
2203 for (i = 0; i < modinfos_len; i++) {
2204 ret = strcmp(modinfos[i].name, modkey->name);
2205 if (ret == 0) {
2206 highest = &modinfos[i];
2207 break;
2208 }
2209 }
2210
2211 if (highest == NULL) {
2212 status = -1;
2213 goto cleanup;
2214 }
2215
2216 ret = semanage_module_info_create(sh, modinfo);
2217 if (ret != 0) {
2218 status = -1;
2219 goto cleanup;
2220 }
2221
2222 ret = semanage_module_info_clone(sh, highest, *modinfo);
2223 if (ret != 0) {
2224 status = -1;
2225 }
2226
2227 /* skip to cleanup, module was found */
2228 goto cleanup;
2229 }
2230
2231 /* check module priority */
2232 ret = semanage_module_validate_priority(modkey->priority);
2233 if (ret != 0) {
2234 errno = 0;
2235 ERR(sh, "Priority %d is invalid.", modkey->priority);
2236 status = -1;
2237 goto cleanup;
2238 }
2239
2240 /* copy in key values */
2241 ret = semanage_module_info_create(sh, modinfo);
2242 if (ret != 0) {
2243 status = -1;
2244 goto cleanup;
2245 }
2246
2247 ret = semanage_module_info_set_priority(sh, *modinfo, modkey->priority);
2248 if (ret != 0) {
2249 status = -1;
2250 goto cleanup;
2251 }
2252
2253 ret = semanage_module_info_set_name(sh, *modinfo, modkey->name);
2254 if (ret != 0) {
2255 status = -1;
2256 goto cleanup;
2257 }
2258
2259 /* lookup module ext */
2260 ret = semanage_module_get_path(sh,
2261 *modinfo,
2262 SEMANAGE_MODULE_PATH_LANG_EXT,
2263 fn,
2264 sizeof(fn));
2265 if (ret != 0) {
2266 status = -1;
2267 goto cleanup;
2268 }
2269
2270 fp = fopen(fn, "r");
2271
2272 if (fp == NULL) {
2273 ERR(sh,
2274 "Unable to open %s module lang ext file at %s.",
2275 (*modinfo)->name, fn);
2276 status = -1;
2277 goto cleanup;
2278 }
2279
2280 /* set module ext */
2281 if (getline(&tmp, &size, fp) < 0) {
2282 ERR(sh,
2283 "Unable to read %s module lang ext file.",
2284 (*modinfo)->name);
2285 status = -1;
2286 goto cleanup;
2287 }
2288
2289 ret = semanage_module_info_set_lang_ext(sh, *modinfo, tmp);
2290 if (ret != 0) {
2291 status = -1;
2292 goto cleanup;
2293 }
2294 free(tmp);
2295 tmp = NULL;
2296
2297 if (fclose(fp) != 0) {
2298 fp = NULL;
2299 ERR(sh,
2300 "Unable to close %s module lang ext file.",
2301 (*modinfo)->name);
2302 status = -1;
2303 goto cleanup;
2304 }
2305
2306 fp = NULL;
2307
2308 /* lookup enabled/disabled status */
2309 ret = semanage_module_get_path(sh,
2310 *modinfo,
2311 SEMANAGE_MODULE_PATH_DISABLED,
2312 fn,
2313 sizeof(fn));
2314 if (ret != 0) {
2315 status = -1;
2316 goto cleanup;
2317 }
2318
2319 /* set enabled/disabled status */
2320 if (stat(fn, &sb) < 0) {
2321 if (errno != ENOENT) {
2322 ERR(sh, "Unable to access %s: %s\n", fn, strerror(errno));
2323 status = -1;
2324 goto cleanup;
2325 }
2326
2327 ret = semanage_module_info_set_enabled(sh, *modinfo, 1);
2328 if (ret != 0) {
2329 status = -1;
2330 goto cleanup;
2331 }
2332 }
2333 else {
2334 ret = semanage_module_info_set_enabled(sh, *modinfo, 0);
2335 if (ret != 0) {
2336 status = -1;
2337 goto cleanup;
2338 }
2339 }
2340
2341 cleanup:
2342 free(tmp);
2343
2344 if (modinfos != NULL) {
2345 for (i = 0; i < modinfos_len; i++) {
2346 semanage_module_info_destroy(sh, &modinfos[i]);
2347 }
2348 free(modinfos);
2349 }
2350
2351 if (fp != NULL) fclose(fp);
2352 return status;
2353 }
2354
semanage_direct_set_module_info(semanage_handle_t * sh,const semanage_module_info_t * modinfo)2355 static int semanage_direct_set_module_info(semanage_handle_t *sh,
2356 const semanage_module_info_t *modinfo)
2357 {
2358 int status = 0;
2359 int ret = 0;
2360
2361 char fn[PATH_MAX];
2362 const char *path = NULL;
2363 int enabled = 0;
2364 semanage_module_info_t *modinfo_tmp = NULL;
2365
2366 semanage_module_key_t modkey;
2367 ret = semanage_module_key_init(sh, &modkey);
2368 if (ret != 0) {
2369 status = -1;
2370 goto cleanup;
2371 }
2372
2373 /* check transaction */
2374 if (!sh->is_in_transaction) {
2375 if (semanage_begin_transaction(sh) < 0) {
2376 status = -1;
2377 goto cleanup;
2378 }
2379 }
2380
2381 /* validate module */
2382 ret = semanage_module_info_validate(modinfo);
2383 if (ret != 0) {
2384 status = -1;
2385 goto cleanup;
2386 }
2387
2388 sh->modules_modified = 1;
2389
2390 /* check for modules path, create if missing */
2391 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES);
2392
2393 ret = semanage_mkdir(sh, path);
2394 if (ret != 0) {
2395 status = -1;
2396 goto cleanup;
2397 }
2398
2399 /* write priority */
2400 ret = semanage_module_get_path(sh,
2401 modinfo,
2402 SEMANAGE_MODULE_PATH_PRIORITY,
2403 fn,
2404 sizeof(fn));
2405 if (ret != 0) {
2406 status = -1;
2407 goto cleanup;
2408 }
2409
2410 ret = semanage_mkdir(sh, fn);
2411 if (ret != 0) {
2412 status = -1;
2413 goto cleanup;
2414 }
2415
2416 /* write name */
2417 ret = semanage_module_get_path(sh,
2418 modinfo,
2419 SEMANAGE_MODULE_PATH_NAME,
2420 fn,
2421 sizeof(fn));
2422 if (ret != 0) {
2423 status = -1;
2424 goto cleanup;
2425 }
2426
2427 ret = semanage_mkdir(sh, fn);
2428 if (ret != 0) {
2429 status = -1;
2430 goto cleanup;
2431 }
2432
2433 /* write ext */
2434 ret = semanage_direct_write_langext(sh, modinfo->lang_ext, modinfo);
2435 if (ret != 0) {
2436 status = -1;
2437 goto cleanup;
2438 }
2439
2440 /* write enabled/disabled status */
2441
2442 /* check for disabled path, create if missing */
2443 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED);
2444
2445 ret = semanage_mkdir(sh, path);
2446 if (ret != 0) {
2447 status = -1;
2448 goto cleanup;
2449 }
2450
2451 ret = semanage_module_get_path(sh,
2452 modinfo,
2453 SEMANAGE_MODULE_PATH_DISABLED,
2454 fn,
2455 sizeof(fn));
2456 if (ret != 0) {
2457 status = -1;
2458 goto cleanup;
2459 }
2460
2461 ret = semanage_module_key_set_name(sh, &modkey, modinfo->name);
2462 if (ret != 0) {
2463 status = -1;
2464 goto cleanup;
2465 }
2466
2467 if (modinfo->enabled == -1) {
2468 /* default to enabled */
2469 enabled = 1;
2470
2471 /* check if a module is already installed */
2472 ret = semanage_module_get_module_info(sh,
2473 &modkey,
2474 &modinfo_tmp);
2475 if (ret == 0) {
2476 /* set enabled status to current one */
2477 enabled = modinfo_tmp->enabled;
2478 }
2479 }
2480 else {
2481 enabled = modinfo->enabled;
2482 }
2483
2484 ret = semanage_module_set_enabled(sh, &modkey, enabled);
2485 if (ret != 0) {
2486 status = -1;
2487 goto cleanup;
2488 }
2489
2490 cleanup:
2491 semanage_module_key_destroy(sh, &modkey);
2492
2493 semanage_module_info_destroy(sh, modinfo_tmp);
2494 free(modinfo_tmp);
2495
2496 return status;
2497 }
2498
semanage_priorities_filename_select(const struct dirent * d)2499 static int semanage_priorities_filename_select(const struct dirent *d)
2500 {
2501 if (d->d_name[0] == '.' ||
2502 strcmp(d->d_name, "disabled") == 0)
2503 return 0;
2504 return 1;
2505 }
2506
semanage_modules_filename_select(const struct dirent * d)2507 static int semanage_modules_filename_select(const struct dirent *d)
2508 {
2509 if (d->d_name[0] == '.')
2510 return 0;
2511 return 1;
2512 }
2513
semanage_direct_list_all(semanage_handle_t * sh,semanage_module_info_t ** modinfos,int * modinfos_len)2514 static int semanage_direct_list_all(semanage_handle_t *sh,
2515 semanage_module_info_t **modinfos,
2516 int *modinfos_len)
2517 {
2518 assert(sh);
2519 assert(modinfos);
2520 assert(modinfos_len);
2521
2522 int status = 0;
2523 int ret = 0;
2524
2525 int i = 0;
2526 int j = 0;
2527
2528 *modinfos = NULL;
2529 *modinfos_len = 0;
2530 void *tmp = NULL;
2531
2532 const char *toplevel = NULL;
2533
2534 struct dirent **priorities = NULL;
2535 int priorities_len = 0;
2536 char priority_path[PATH_MAX];
2537
2538 struct dirent **modules = NULL;
2539 int modules_len = 0;
2540
2541 uint16_t priority = 0;
2542
2543 semanage_module_info_t *modinfo_tmp = NULL;
2544
2545 semanage_module_info_t modinfo;
2546 ret = semanage_module_info_init(sh, &modinfo);
2547 if (ret != 0) {
2548 status = -1;
2549 goto cleanup;
2550 }
2551
2552 if (sh->is_in_transaction) {
2553 toplevel = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES);
2554 } else {
2555 toplevel = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES);
2556 }
2557
2558 /* find priorities */
2559 priorities_len = scandir(toplevel,
2560 &priorities,
2561 semanage_priorities_filename_select,
2562 versionsort);
2563 if (priorities_len == -1) {
2564 ERR(sh, "Error while scanning directory %s.", toplevel);
2565 status = -1;
2566 goto cleanup;
2567 }
2568
2569 /* for each priority directory */
2570 /* loop through in reverse so that highest priority is first */
2571 for (i = priorities_len - 1; i >= 0; i--) {
2572 /* convert priority string to uint16_t */
2573 ret = semanage_string_to_priority(priorities[i]->d_name,
2574 &priority);
2575 if (ret != 0) {
2576 status = -1;
2577 goto cleanup;
2578 }
2579
2580 /* set our priority */
2581 ret = semanage_module_info_set_priority(sh,
2582 &modinfo,
2583 priority);
2584 if (ret != 0) {
2585 status = -1;
2586 goto cleanup;
2587 }
2588
2589 /* get the priority path */
2590 ret = semanage_module_get_path(sh,
2591 &modinfo,
2592 SEMANAGE_MODULE_PATH_PRIORITY,
2593 priority_path,
2594 sizeof(priority_path));
2595 if (ret != 0) {
2596 status = -1;
2597 goto cleanup;
2598 }
2599
2600 /* cleanup old modules */
2601 if (modules != NULL) {
2602 for (j = 0; j < modules_len; j++) {
2603 free(modules[j]);
2604 modules[j] = NULL;
2605 }
2606 free(modules);
2607 modules = NULL;
2608 modules_len = 0;
2609 }
2610
2611 /* find modules at this priority */
2612 modules_len = scandir(priority_path,
2613 &modules,
2614 semanage_modules_filename_select,
2615 versionsort);
2616 if (modules_len == -1) {
2617 ERR(sh,
2618 "Error while scanning directory %s.",
2619 priority_path);
2620 status = -1;
2621 goto cleanup;
2622 }
2623
2624 if (modules_len == 0) continue;
2625
2626 /* add space for modules */
2627 tmp = realloc(*modinfos,
2628 sizeof(semanage_module_info_t) *
2629 (*modinfos_len + modules_len));
2630 if (tmp == NULL) {
2631 ERR(sh, "Error allocating memory for module array.");
2632 status = -1;
2633 goto cleanup;
2634 }
2635 *modinfos = tmp;
2636
2637 /* for each module directory */
2638 for(j = 0; j < modules_len; j++) {
2639 /* set module name */
2640 ret = semanage_module_info_set_name(
2641 sh,
2642 &modinfo,
2643 modules[j]->d_name);
2644 if (ret != 0) {
2645 status = -1;
2646 goto cleanup;
2647 }
2648
2649 /* get module values */
2650 ret = semanage_direct_get_module_info(
2651 sh,
2652 (const semanage_module_key_t *)
2653 (&modinfo),
2654 &modinfo_tmp);
2655 if (ret != 0) {
2656 status = -1;
2657 goto cleanup;
2658 }
2659
2660 /* copy into array */
2661 ret = semanage_module_info_init(
2662 sh,
2663 &((*modinfos)[*modinfos_len]));
2664 if (ret != 0) {
2665 status = -1;
2666 goto cleanup;
2667 }
2668
2669 ret = semanage_module_info_clone(
2670 sh,
2671 modinfo_tmp,
2672 &((*modinfos)[*modinfos_len]));
2673 if (ret != 0) {
2674 status = -1;
2675 goto cleanup;
2676 }
2677
2678 semanage_module_info_destroy(sh, modinfo_tmp);
2679 free(modinfo_tmp);
2680 modinfo_tmp = NULL;
2681
2682 *modinfos_len += 1;
2683 }
2684 }
2685
2686 cleanup:
2687 semanage_module_info_destroy(sh, &modinfo);
2688
2689 if (priorities != NULL) {
2690 for (i = 0; i < priorities_len; i++) {
2691 free(priorities[i]);
2692 }
2693 free(priorities);
2694 }
2695
2696 if (modules != NULL) {
2697 for (i = 0; i < modules_len; i++) {
2698 free(modules[i]);
2699 }
2700 free(modules);
2701 }
2702
2703 semanage_module_info_destroy(sh, modinfo_tmp);
2704 free(modinfo_tmp);
2705 modinfo_tmp = NULL;
2706
2707 if (status != 0) {
2708 if (modinfos != NULL) {
2709 for (i = 0; i < *modinfos_len; i++) {
2710 semanage_module_info_destroy(
2711 sh,
2712 &(*modinfos)[i]);
2713 }
2714 free(*modinfos);
2715 *modinfos = NULL;
2716 *modinfos_len = 0;
2717 }
2718 }
2719
2720 return status;
2721 }
2722
semanage_direct_install_info(semanage_handle_t * sh,const semanage_module_info_t * modinfo,char * data,size_t data_len)2723 static int semanage_direct_install_info(semanage_handle_t *sh,
2724 const semanage_module_info_t *modinfo,
2725 char *data,
2726 size_t data_len)
2727 {
2728 assert(sh);
2729 assert(modinfo);
2730 assert(data);
2731
2732 int status = 0;
2733 int ret = 0;
2734 int type;
2735 struct stat sb;
2736
2737 char path[PATH_MAX];
2738 mode_t mask = umask(0077);
2739
2740 semanage_module_info_t *higher_info = NULL;
2741 semanage_module_key_t higher_key;
2742 ret = semanage_module_key_init(sh, &higher_key);
2743 if (ret != 0) {
2744 status = -1;
2745 goto cleanup;
2746 }
2747
2748 /* validate module info */
2749 ret = semanage_module_info_validate(modinfo);
2750 if (ret != 0) {
2751 ERR(sh, "%s failed module validation.\n", modinfo->name);
2752 status = -2;
2753 goto cleanup;
2754 }
2755
2756 /* Check for higher priority module and warn if there is one as
2757 * it will override the module currently being installed.
2758 */
2759 ret = semanage_module_key_set_name(sh, &higher_key, modinfo->name);
2760 if (ret != 0) {
2761 status = -1;
2762 goto cleanup;
2763 }
2764
2765 ret = semanage_direct_get_module_info(sh, &higher_key, &higher_info);
2766 if (ret == 0) {
2767 if (higher_info->priority > modinfo->priority) {
2768 errno = 0;
2769 WARN(sh,
2770 "A higher priority %s module exists at priority %d and will override the module currently being installed at priority %d.",
2771 modinfo->name,
2772 higher_info->priority,
2773 modinfo->priority);
2774 }
2775 else if (higher_info->priority < modinfo->priority) {
2776 errno = 0;
2777 INFO(sh,
2778 "Overriding %s module at lower priority %d with module at priority %d.",
2779 modinfo->name,
2780 higher_info->priority,
2781 modinfo->priority);
2782 }
2783
2784 if (higher_info->enabled == 0 && modinfo->enabled == -1) {
2785 errno = 0;
2786 WARN(sh,
2787 "%s module will be disabled after install as there is a disabled instance of this module present in the system.",
2788 modinfo->name);
2789 }
2790 }
2791
2792 /* set module meta data */
2793 ret = semanage_direct_set_module_info(sh, modinfo);
2794 if (ret != 0) {
2795 status = -2;
2796 goto cleanup;
2797 }
2798
2799 /* install module source file */
2800 if (!strcasecmp(modinfo->lang_ext, "cil")) {
2801 type = SEMANAGE_MODULE_PATH_CIL;
2802 } else {
2803 type = SEMANAGE_MODULE_PATH_HLL;
2804 }
2805 ret = semanage_module_get_path(
2806 sh,
2807 modinfo,
2808 type,
2809 path,
2810 sizeof(path));
2811 if (ret != 0) {
2812 status = -3;
2813 goto cleanup;
2814 }
2815
2816 ret = write_compressed_file(sh, path, data, data_len);
2817 if (ret < 0) {
2818 ERR(sh, "Error while writing to %s.", path);
2819 status = -3;
2820 goto cleanup;
2821 }
2822
2823 /* if this is an HLL, delete the CIL cache if it exists so it will get recompiled */
2824 if (type == SEMANAGE_MODULE_PATH_HLL) {
2825 ret = semanage_module_get_path(
2826 sh,
2827 modinfo,
2828 SEMANAGE_MODULE_PATH_CIL,
2829 path,
2830 sizeof(path));
2831 if (ret != 0) {
2832 status = -3;
2833 goto cleanup;
2834 }
2835
2836 if (stat(path, &sb) == 0) {
2837 ret = unlink(path);
2838 if (ret != 0) {
2839 ERR(sh, "Error while removing cached CIL file %s: %s", path, strerror(errno));
2840 status = -3;
2841 goto cleanup;
2842 }
2843 }
2844 }
2845
2846 cleanup:
2847 semanage_module_key_destroy(sh, &higher_key);
2848 semanage_module_info_destroy(sh, higher_info);
2849 free(higher_info);
2850 umask(mask);
2851
2852 return status;
2853 }
2854
semanage_direct_remove_key(semanage_handle_t * sh,const semanage_module_key_t * modkey)2855 static int semanage_direct_remove_key(semanage_handle_t *sh,
2856 const semanage_module_key_t *modkey)
2857 {
2858 assert(sh);
2859 assert(modkey);
2860
2861 int status = 0;
2862 int ret = 0;
2863
2864 char path[PATH_MAX];
2865 semanage_module_info_t *modinfo = NULL;
2866
2867 semanage_module_key_t modkey_tmp;
2868 ret = semanage_module_key_init(sh, &modkey_tmp);
2869 if (ret != 0) {
2870 status = -1;
2871 goto cleanup;
2872 }
2873
2874 /* validate module key */
2875 ret = semanage_module_validate_priority(modkey->priority);
2876 if (ret != 0) {
2877 errno = 0;
2878 ERR(sh, "Priority %d is invalid.", modkey->priority);
2879 status = -1;
2880 goto cleanup;
2881 }
2882
2883 ret = semanage_module_validate_name(modkey->name);
2884 if (ret != 0) {
2885 errno = 0;
2886 ERR(sh, "Name %s is invalid.", modkey->name);
2887 status = -1;
2888 goto cleanup;
2889 }
2890
2891 ret = semanage_module_key_set_name(sh, &modkey_tmp, modkey->name);
2892 if (ret != 0) {
2893 status = -1;
2894 goto cleanup;
2895 }
2896
2897 /* get module path */
2898 ret = semanage_module_get_path(
2899 sh,
2900 (const semanage_module_info_t *)modkey,
2901 SEMANAGE_MODULE_PATH_NAME,
2902 path,
2903 sizeof(path));
2904 if (ret != 0) {
2905 status = -2;
2906 goto cleanup;
2907 }
2908
2909 /* remove directory */
2910 ret = semanage_remove_directory(path);
2911 if (ret != 0) {
2912 ERR(sh, "Unable to remove module %s at priority %d.", modkey->name, modkey->priority);
2913 status = -2;
2914 goto cleanup;
2915 }
2916
2917 /* check if its the last module at any priority */
2918 ret = semanage_module_get_module_info(sh, &modkey_tmp, &modinfo);
2919 if (ret != 0) {
2920 /* info that no other module will override */
2921 errno = 0;
2922 INFO(sh,
2923 "Removing last %s module (no other %s module exists at another priority).",
2924 modkey->name,
2925 modkey->name);
2926
2927 /* remove disabled status file */
2928 ret = semanage_module_get_path(
2929 sh,
2930 (const semanage_module_info_t *)modkey,
2931 SEMANAGE_MODULE_PATH_DISABLED,
2932 path,
2933 sizeof(path));
2934 if (ret != 0) {
2935 status = -1;
2936 goto cleanup;
2937 }
2938
2939 struct stat sb;
2940 if (stat(path, &sb) == 0) {
2941 ret = unlink(path);
2942 if (ret != 0) {
2943 status = -1;
2944 goto cleanup;
2945 }
2946 }
2947 }
2948 else {
2949 /* if a lower priority module is going to become active */
2950 if (modkey->priority > modinfo->priority) {
2951 /* inform what the new active module will be */
2952 errno = 0;
2953 INFO(sh,
2954 "%s module at priority %d is now active.",
2955 modinfo->name,
2956 modinfo->priority);
2957 }
2958 }
2959
2960 cleanup:
2961 semanage_module_key_destroy(sh, &modkey_tmp);
2962
2963 semanage_module_info_destroy(sh, modinfo);
2964 free(modinfo);
2965
2966 return status;
2967 }
2968
2969