1 /* Author: Jason Tang <[email protected]>
2 * Christopher Ashworth <[email protected]>
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 ssize_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
update_checksum_with_bool(Sha256Context * context,bool b)866 static void update_checksum_with_bool(Sha256Context *context, bool b)
867 {
868 uint8_t byte;
869
870 byte = b ? UINT8_C(1) : UINT8_C(0);
871 Sha256Update(context, &byte, 1);
872 }
873
semanage_compile_module(semanage_handle_t * sh,semanage_module_info_t * modinfo,Sha256Context * context)874 static int semanage_compile_module(semanage_handle_t *sh,
875 semanage_module_info_t *modinfo,
876 Sha256Context *context)
877 {
878 char cil_path[PATH_MAX];
879 char hll_path[PATH_MAX];
880 char *compiler_path = NULL;
881 char *cil_data = NULL;
882 char *err_data = NULL;
883 char *start = NULL;
884 char *end = NULL;
885 int status = 0;
886 size_t cil_data_len = 0;
887 size_t err_data_len = 0;
888 struct file_contents hll_contents = {};
889
890 if (!strcasecmp(modinfo->lang_ext, "cil")) {
891 goto cleanup;
892 }
893
894 status = semanage_get_hll_compiler_path(sh, modinfo->lang_ext, &compiler_path);
895 if (status != 0) {
896 goto cleanup;
897 }
898
899 status = semanage_module_get_path(
900 sh,
901 modinfo,
902 SEMANAGE_MODULE_PATH_CIL,
903 cil_path,
904 sizeof(cil_path));
905 if (status != 0) {
906 goto cleanup;
907 }
908
909 status = semanage_module_get_path(
910 sh,
911 modinfo,
912 SEMANAGE_MODULE_PATH_HLL,
913 hll_path,
914 sizeof(hll_path));
915 if (status != 0) {
916 goto cleanup;
917 }
918
919 status = map_compressed_file(sh, hll_path, &hll_contents);
920 if (status < 0) {
921 ERR(sh, "Unable to read file %s\n", hll_path);
922 goto cleanup;
923 }
924
925 status = semanage_pipe_data(sh, compiler_path, hll_contents.data,
926 hll_contents.len, &cil_data, &cil_data_len,
927 &err_data, &err_data_len);
928 if (err_data_len > 0) {
929 for (start = end = err_data; end < err_data + err_data_len; end++) {
930 if (*end == '\n') {
931 fprintf(stderr, "%s: ", modinfo->name);
932 fwrite(start, 1, end - start + 1, stderr);
933 start = end + 1;
934 }
935 }
936
937 if (end != start) {
938 fprintf(stderr, "%s: ", modinfo->name);
939 fwrite(start, 1, end - start, stderr);
940 fprintf(stderr, "\n");
941 }
942 }
943 if (status != 0) {
944 goto cleanup;
945 }
946
947 if (context) {
948 update_checksum_with_len(context, cil_data_len);
949 Sha256Update(context, cil_data, cil_data_len);
950 }
951
952 status = write_compressed_file(sh, cil_path, cil_data, cil_data_len);
953 if (status == -1) {
954 ERR(sh, "Failed to write %s\n", cil_path);
955 goto cleanup;
956 }
957
958 if (sh->conf->remove_hll == 1) {
959 status = unlink(hll_path);
960 if (status != 0) {
961 ERR(sh, "Error while removing HLL file %s: %s", hll_path, strerror(errno));
962 goto cleanup;
963 }
964
965 status = semanage_direct_write_langext(sh, "cil", modinfo);
966 if (status != 0) {
967 goto cleanup;
968 }
969 }
970
971 cleanup:
972 unmap_compressed_file(&hll_contents);
973 free(cil_data);
974 free(err_data);
975 free(compiler_path);
976
977 return status;
978 }
979
modinfo_cmp(const void * a,const void * b)980 static int modinfo_cmp(const void *a, const void *b)
981 {
982 const semanage_module_info_t *ma = a;
983 const semanage_module_info_t *mb = b;
984
985 return strcmp(ma->name, mb->name);
986 }
987
988 struct extra_checksum_params {
989 int disable_dontaudit;
990 int preserve_tunables;
991 int target_platform;
992 int policyvers;
993 };
994
semanage_compile_hll_modules(semanage_handle_t * sh,semanage_module_info_t * modinfos,int num_modinfos,const struct extra_checksum_params * extra,char * cil_checksum)995 static int semanage_compile_hll_modules(semanage_handle_t *sh,
996 semanage_module_info_t *modinfos,
997 int num_modinfos,
998 const struct extra_checksum_params *extra,
999 char *cil_checksum)
1000 {
1001 /* to be incremented when checksum input data format changes */
1002 static const size_t CHECKSUM_EPOCH = 2;
1003
1004 int i, status = 0;
1005 char cil_path[PATH_MAX];
1006 struct stat sb;
1007 Sha256Context context;
1008 SHA256_HASH hash;
1009 struct file_contents contents = {};
1010
1011 assert(sh);
1012 assert(modinfos);
1013
1014 /* Sort modules by name to get consistent ordering. */
1015 qsort(modinfos, num_modinfos, sizeof(*modinfos), &modinfo_cmp);
1016
1017 Sha256Initialise(&context);
1018 update_checksum_with_len(&context, CHECKSUM_EPOCH);
1019 update_checksum_with_bool(&context, !!extra->disable_dontaudit);
1020 update_checksum_with_bool(&context, !!extra->preserve_tunables);
1021 update_checksum_with_len(&context, (size_t)extra->target_platform);
1022 update_checksum_with_len(&context, (size_t)extra->policyvers);
1023
1024 /* prefix with module count to avoid collisions */
1025 update_checksum_with_len(&context, num_modinfos);
1026 for (i = 0; i < num_modinfos; i++) {
1027 status = semanage_module_get_path(
1028 sh,
1029 &modinfos[i],
1030 SEMANAGE_MODULE_PATH_CIL,
1031 cil_path,
1032 sizeof(cil_path));
1033 if (status != 0)
1034 return -1;
1035
1036 if (!semanage_get_ignore_module_cache(sh)) {
1037 status = stat(cil_path, &sb);
1038 if (status == 0) {
1039 status = map_compressed_file(sh, cil_path, &contents);
1040 if (status < 0) {
1041 ERR(sh, "Error mapping file: %s", cil_path);
1042 return -1;
1043 }
1044
1045 /* prefix with length to avoid collisions */
1046 update_checksum_with_len(&context, contents.len);
1047 Sha256Update(&context, contents.data, contents.len);
1048
1049 unmap_compressed_file(&contents);
1050 continue;
1051 } else if (errno != ENOENT) {
1052 ERR(sh, "Unable to access %s: %s\n", cil_path,
1053 strerror(errno));
1054 return -1; //an error in the "stat" call
1055 }
1056 }
1057
1058 status = semanage_compile_module(sh, &modinfos[i], &context);
1059 if (status < 0)
1060 return -1;
1061 }
1062 Sha256Finalise(&context, &hash);
1063
1064 semanage_hash_to_checksum_string(hash.bytes, cil_checksum);
1065 return 0;
1066 }
1067
semanage_compare_checksum(semanage_handle_t * sh,const char * reference)1068 static int semanage_compare_checksum(semanage_handle_t *sh, const char *reference)
1069 {
1070 const char *path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_CHECKSUM);
1071 struct stat sb;
1072 int fd, retval;
1073 char *data;
1074
1075 fd = open(path, O_RDONLY);
1076 if (fd == -1) {
1077 if (errno != ENOENT) {
1078 ERR(sh, "Unable to open %s: %s\n", path, strerror(errno));
1079 return -1;
1080 }
1081 /* Checksum file not present - force a rebuild. */
1082 return 1;
1083 }
1084
1085 if (fstat(fd, &sb) == -1) {
1086 ERR(sh, "Unable to stat %s\n", path);
1087 retval = -1;
1088 goto out_close;
1089 }
1090
1091 if (sb.st_size != (off_t)CHECKSUM_CONTENT_SIZE) {
1092 /* Incompatible/invalid hash type - just force a rebuild. */
1093 WARN(sh, "Module checksum invalid - forcing a rebuild\n");
1094 retval = 1;
1095 goto out_close;
1096 }
1097
1098 data = mmap(NULL, CHECKSUM_CONTENT_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
1099 if (data == MAP_FAILED) {
1100 ERR(sh, "Unable to mmap %s\n", path);
1101 retval = -1;
1102 goto out_close;
1103 }
1104
1105 retval = memcmp(data, reference, CHECKSUM_CONTENT_SIZE) != 0;
1106 munmap(data, sb.st_size);
1107 out_close:
1108 close(fd);
1109 return retval;
1110 }
1111
semanage_write_modules_checksum(semanage_handle_t * sh,const char * checksum)1112 static int semanage_write_modules_checksum(semanage_handle_t *sh,
1113 const char *checksum)
1114 {
1115 const char *path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_CHECKSUM);
1116
1117 return write_file(sh, path, checksum, CHECKSUM_CONTENT_SIZE);
1118 }
1119
1120 /* Files that must exist in order to skip policy rebuild. */
1121 static const int semanage_computed_files[] = {
1122 SEMANAGE_STORE_KERNEL,
1123 SEMANAGE_STORE_FC,
1124 SEMANAGE_STORE_SEUSERS,
1125 SEMANAGE_LINKED,
1126 SEMANAGE_SEUSERS_LINKED,
1127 SEMANAGE_USERS_EXTRA_LINKED
1128 };
1129
1130 /* Copies a file from src to dst. If dst already exists then
1131 * overwrite it. If source doesn't exist then return success.
1132 * Returns 0 on success, -1 on error. */
copy_file_if_exists(const char * src,const char * dst,mode_t mode)1133 static int copy_file_if_exists(const char *src, const char *dst, mode_t mode){
1134 int rc = semanage_copy_file(src, dst, mode, false);
1135 return (rc < 0 && errno != ENOENT) ? rc : 0;
1136 }
1137
1138 /********************* direct API functions ********************/
1139
1140 /* Commits all changes in sandbox to the actual kernel policy.
1141 * Returns commit number on success, -1 on error.
1142 */
semanage_direct_commit(semanage_handle_t * sh)1143 static int semanage_direct_commit(semanage_handle_t * sh)
1144 {
1145 char **mod_filenames = NULL;
1146 char *fc_buffer = NULL;
1147 size_t fc_buffer_len = 0;
1148 const char *ofilename = NULL;
1149 const char *path;
1150 int retval = -1, num_modinfos = 0, i;
1151 sepol_policydb_t *out = NULL;
1152 struct cil_db *cildb = NULL;
1153 semanage_module_info_t *modinfos = NULL;
1154 mode_t mask = umask(0077);
1155 struct stat sb;
1156 char modules_checksum[CHECKSUM_CONTENT_SIZE + 1 /* '\0' */];
1157 struct extra_checksum_params extra;
1158
1159 int do_rebuild, do_write_kernel, do_install;
1160 int fcontexts_modified, ports_modified, seusers_modified,
1161 disable_dontaudit, preserve_tunables, ibpkeys_modified,
1162 ibendports_modified;
1163 dbase_config_t *users = semanage_user_dbase_local(sh);
1164 dbase_config_t *users_base = semanage_user_base_dbase_local(sh);
1165 dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh);
1166 dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh);
1167 dbase_config_t *ports = semanage_port_dbase_local(sh);
1168 dbase_config_t *pports = semanage_port_dbase_policy(sh);
1169 dbase_config_t *ibpkeys = semanage_ibpkey_dbase_local(sh);
1170 dbase_config_t *pibpkeys = semanage_ibpkey_dbase_policy(sh);
1171 dbase_config_t *ibendports = semanage_ibendport_dbase_local(sh);
1172 dbase_config_t *pibendports = semanage_ibendport_dbase_policy(sh);
1173 dbase_config_t *bools = semanage_bool_dbase_local(sh);
1174 dbase_config_t *pbools = semanage_bool_dbase_policy(sh);
1175 dbase_config_t *ifaces = semanage_iface_dbase_local(sh);
1176 dbase_config_t *pifaces = semanage_iface_dbase_policy(sh);
1177 dbase_config_t *nodes = semanage_node_dbase_local(sh);
1178 dbase_config_t *pnodes = semanage_node_dbase_policy(sh);
1179 dbase_config_t *fcontexts = semanage_fcontext_dbase_local(sh);
1180 dbase_config_t *pfcontexts = semanage_fcontext_dbase_policy(sh);
1181 dbase_config_t *seusers = semanage_seuser_dbase_local(sh);
1182 dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh);
1183
1184 /* Modified flags that we need to use more than once. */
1185 ports_modified = ports->dtable->is_modified(ports->dbase);
1186 ibpkeys_modified = ibpkeys->dtable->is_modified(ibpkeys->dbase);
1187 ibendports_modified = ibendports->dtable->is_modified(ibendports->dbase);
1188 seusers_modified = seusers->dtable->is_modified(seusers->dbase);
1189 fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
1190
1191 /* Before we do anything else, flush the join to its component parts.
1192 * This *does not* flush to disk automatically */
1193 if (users->dtable->is_modified(users->dbase)) {
1194 retval = users->dtable->flush(sh, users->dbase);
1195 if (retval < 0)
1196 goto cleanup;
1197 }
1198
1199 /* Rebuild if explicitly requested or any module changes occurred. */
1200 do_rebuild = sh->do_rebuild | sh->modules_modified;
1201
1202 /* Create or remove the disable_dontaudit flag file. */
1203 path = semanage_path(SEMANAGE_TMP, SEMANAGE_DISABLE_DONTAUDIT);
1204 if (stat(path, &sb) == 0)
1205 do_rebuild |= !(sepol_get_disable_dontaudit(sh->sepolh) == 1);
1206 else if (errno == ENOENT) {
1207 /* The file does not exist */
1208 do_rebuild |= (sepol_get_disable_dontaudit(sh->sepolh) == 1);
1209 } else {
1210 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1211 retval = -1;
1212 goto cleanup;
1213 }
1214 if (sepol_get_disable_dontaudit(sh->sepolh) == 1) {
1215 FILE *touch;
1216 touch = fopen(path, "w");
1217 if (touch != NULL) {
1218 if (fclose(touch) != 0) {
1219 ERR(sh, "Error attempting to create disable_dontaudit flag.");
1220 goto cleanup;
1221 }
1222 } else {
1223 ERR(sh, "Error attempting to create disable_dontaudit flag.");
1224 goto cleanup;
1225 }
1226 } else {
1227 if (remove(path) == -1 && errno != ENOENT) {
1228 ERR(sh, "Error removing the disable_dontaudit flag.");
1229 goto cleanup;
1230 }
1231 }
1232
1233 /* Create or remove the preserve_tunables flag file. */
1234 path = semanage_path(SEMANAGE_TMP, SEMANAGE_PRESERVE_TUNABLES);
1235 if (stat(path, &sb) == 0)
1236 do_rebuild |= !(sepol_get_preserve_tunables(sh->sepolh) == 1);
1237 else if (errno == ENOENT) {
1238 /* The file does not exist */
1239 do_rebuild |= (sepol_get_preserve_tunables(sh->sepolh) == 1);
1240 } else {
1241 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1242 retval = -1;
1243 goto cleanup;
1244 }
1245
1246 if (sepol_get_preserve_tunables(sh->sepolh) == 1) {
1247 FILE *touch;
1248 touch = fopen(path, "w");
1249 if (touch != NULL) {
1250 if (fclose(touch) != 0) {
1251 ERR(sh, "Error attempting to create preserve_tunable flag.");
1252 goto cleanup;
1253 }
1254 } else {
1255 ERR(sh, "Error attempting to create preserve_tunable flag.");
1256 goto cleanup;
1257 }
1258 } else {
1259 if (remove(path) == -1 && errno != ENOENT) {
1260 ERR(sh, "Error removing the preserve_tunables flag.");
1261 goto cleanup;
1262 }
1263 }
1264
1265 /*
1266 * This is for systems that have already migrated with an older version
1267 * of semanage_migrate_store. The older version did not copy
1268 * policy.kern so the policy binary must be rebuilt here.
1269 * This also ensures that any linked files that are required
1270 * in order to skip re-linking are present; otherwise, we force
1271 * a rebuild.
1272 */
1273 for (i = 0; !do_rebuild && i < (int)ARRAY_SIZE(semanage_computed_files); i++) {
1274 path = semanage_path(SEMANAGE_TMP, semanage_computed_files[i]);
1275 if (stat(path, &sb) != 0) {
1276 if (errno != ENOENT) {
1277 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1278 retval = -1;
1279 goto cleanup;
1280 }
1281
1282 do_rebuild = 1;
1283 break;
1284 }
1285 }
1286
1287 if (do_rebuild || sh->check_ext_changes) {
1288 retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos);
1289 if (retval < 0) {
1290 goto cleanup;
1291 }
1292
1293 /* No modules - nothing to rebuild. */
1294 if (num_modinfos == 0) {
1295 goto cleanup;
1296 }
1297
1298 extra = (struct extra_checksum_params){
1299 .disable_dontaudit = sepol_get_disable_dontaudit(sh->sepolh),
1300 .preserve_tunables = sepol_get_preserve_tunables(sh->sepolh),
1301 .target_platform = sh->conf->target_platform,
1302 .policyvers = sh->conf->policyvers,
1303 };
1304 retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos,
1305 &extra, modules_checksum);
1306 if (retval < 0) {
1307 ERR(sh, "Failed to compile hll files into cil files.\n");
1308 goto cleanup;
1309 }
1310
1311 if (!do_rebuild && sh->check_ext_changes) {
1312 retval = semanage_compare_checksum(sh, modules_checksum);
1313 if (retval < 0)
1314 goto cleanup;
1315 do_rebuild = retval;
1316 }
1317
1318 retval = semanage_write_modules_checksum(sh, modules_checksum);
1319 if (retval < 0) {
1320 ERR(sh, "Failed to write module checksum file.\n");
1321 goto cleanup;
1322 }
1323 }
1324
1325 /*
1326 * If there were policy changes, or explicitly requested, or
1327 * any required files are missing, rebuild the policy.
1328 */
1329 if (do_rebuild) {
1330 /* =================== Module expansion =============== */
1331
1332 retval = semanage_get_cil_paths(sh, modinfos, num_modinfos, &mod_filenames);
1333 if (retval < 0)
1334 goto cleanup;
1335
1336 retval = semanage_verify_modules(sh, mod_filenames, num_modinfos);
1337 if (retval < 0)
1338 goto cleanup;
1339
1340 cil_db_init(&cildb);
1341
1342 disable_dontaudit = sepol_get_disable_dontaudit(sh->sepolh);
1343 preserve_tunables = sepol_get_preserve_tunables(sh->sepolh);
1344 cil_set_disable_dontaudit(cildb, disable_dontaudit);
1345 cil_set_disable_neverallow(cildb, !(sh->conf->expand_check));
1346 cil_set_preserve_tunables(cildb, preserve_tunables);
1347 cil_set_target_platform(cildb, sh->conf->target_platform);
1348 cil_set_policy_version(cildb, sh->conf->policyvers);
1349
1350 if (sh->conf->handle_unknown != -1) {
1351 cil_set_handle_unknown(cildb, sh->conf->handle_unknown);
1352 }
1353
1354 retval = semanage_load_files(sh, cildb, mod_filenames, num_modinfos);
1355 if (retval < 0) {
1356 goto cleanup;
1357 }
1358
1359 retval = cil_compile(cildb);
1360 if (retval < 0)
1361 goto cleanup;
1362
1363 retval = cil_build_policydb(cildb, &out);
1364 if (retval < 0)
1365 goto cleanup;
1366
1367 /* File Contexts */
1368 retval = cil_filecons_to_string(cildb, &fc_buffer, &fc_buffer_len);
1369 if (retval < 0)
1370 goto cleanup;
1371
1372 /* Write the contexts (including template contexts) to a single file. */
1373 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL);
1374 if (ofilename == NULL) {
1375 retval = -1;
1376 goto cleanup;
1377 }
1378 retval = write_file(sh, ofilename, fc_buffer, fc_buffer_len);
1379 if (retval < 0)
1380 goto cleanup;
1381
1382 /* Split complete and template file contexts into their separate files. */
1383 retval = semanage_split_fc(sh);
1384 if (retval < 0)
1385 goto cleanup;
1386
1387 /* remove FC_TMPL now that it is now longer needed */
1388 unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL));
1389
1390 pfcontexts->dtable->drop_cache(pfcontexts->dbase);
1391
1392 /* SEUsers */
1393 retval = semanage_direct_update_seuser(sh, cildb);
1394 if (retval < 0)
1395 goto cleanup;
1396
1397 /* User Extra */
1398 retval = semanage_direct_update_user_extra(sh, cildb);
1399 if (retval < 0)
1400 goto cleanup;
1401
1402 cil_db_destroy(&cildb);
1403
1404 /* Remove redundancies in binary policy if requested. */
1405 if (sh->conf->optimize_policy) {
1406 retval = sepol_policydb_optimize(out);
1407 if (retval < 0)
1408 goto cleanup;
1409 }
1410
1411 /* Write the linked policy before merging local changes. */
1412 retval = semanage_write_policydb(sh, out,
1413 SEMANAGE_LINKED);
1414 if (retval < 0)
1415 goto cleanup;
1416 } else {
1417 /* Load the existing linked policy, w/o local changes */
1418 retval = sepol_policydb_create(&out);
1419 if (retval < 0)
1420 goto cleanup;
1421
1422 retval = semanage_read_policydb(sh, out, SEMANAGE_LINKED);
1423 if (retval < 0)
1424 goto cleanup;
1425
1426 path = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS_LINKED);
1427 if (stat(path, &sb) == 0) {
1428 retval = semanage_copy_file(path,
1429 semanage_path(SEMANAGE_TMP,
1430 SEMANAGE_STORE_SEUSERS),
1431 0, false);
1432 if (retval < 0)
1433 goto cleanup;
1434 pseusers->dtable->drop_cache(pseusers->dbase);
1435 } else if (errno == ENOENT) {
1436 /* The file does not exist */
1437 pseusers->dtable->clear(sh, pseusers->dbase);
1438 } else {
1439 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1440 retval = -1;
1441 goto cleanup;
1442 }
1443
1444 path = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA_LINKED);
1445 if (stat(path, &sb) == 0) {
1446 retval = semanage_copy_file(path,
1447 semanage_path(SEMANAGE_TMP,
1448 SEMANAGE_USERS_EXTRA),
1449 0, false);
1450 if (retval < 0)
1451 goto cleanup;
1452 pusers_extra->dtable->drop_cache(pusers_extra->dbase);
1453 } else if (errno == ENOENT) {
1454 /* The file does not exist */
1455 pusers_extra->dtable->clear(sh, pusers_extra->dbase);
1456 } else {
1457 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1458 retval = -1;
1459 goto cleanup;
1460 }
1461 }
1462
1463 /*
1464 * Determine what else needs to be done.
1465 * We need to write the kernel policy if we are rebuilding
1466 * or if any other policy component that lives in the kernel
1467 * policy has been modified. We also want to force it when
1468 * check_ext_changes was specified as the various dbases may have
1469 * changes as well.
1470 * We need to install the policy files if any of the managed files
1471 * that live under /etc/selinux (kernel policy, seusers, file contexts)
1472 * will be modified.
1473 */
1474 do_write_kernel = do_rebuild | sh->check_ext_changes |
1475 ports_modified | ibpkeys_modified | ibendports_modified |
1476 bools->dtable->is_modified(bools->dbase) |
1477 ifaces->dtable->is_modified(ifaces->dbase) |
1478 nodes->dtable->is_modified(nodes->dbase) |
1479 users->dtable->is_modified(users_base->dbase);
1480 do_install = do_write_kernel | seusers_modified | fcontexts_modified;
1481
1482 /* Attach our databases to the policydb we just created or loaded. */
1483 dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
1484 dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
1485 dbase_policydb_attach((dbase_policydb_t *) pibpkeys->dbase, out);
1486 dbase_policydb_attach((dbase_policydb_t *) pibendports->dbase, out);
1487 dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out);
1488 dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out);
1489 dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out);
1490
1491 /* Merge local changes */
1492 retval = semanage_base_merge_components(sh);
1493 if (retval < 0)
1494 goto cleanup;
1495
1496 if (do_write_kernel) {
1497 /* Write new kernel policy. */
1498 retval = semanage_write_policydb(sh, out,
1499 SEMANAGE_STORE_KERNEL);
1500 if (retval < 0)
1501 goto cleanup;
1502
1503 /* Run the kernel policy verifier, if any. */
1504 retval = semanage_verify_kernel(sh);
1505 if (retval < 0)
1506 goto cleanup;
1507 }
1508
1509 /* ======= Post-process: Validate non-policydb components ===== */
1510
1511 /* Validate local modifications to file contexts.
1512 * Note: those are still cached, even though they've been
1513 * merged into the main file_contexts. We won't check the
1514 * large file_contexts - checked at compile time */
1515 if (do_rebuild || fcontexts_modified) {
1516 retval = semanage_fcontext_validate_local(sh, out);
1517 if (retval < 0)
1518 goto cleanup;
1519 }
1520
1521 /* Validate local seusers against policy */
1522 if (do_rebuild || seusers_modified) {
1523 retval = semanage_seuser_validate_local(sh, out);
1524 if (retval < 0)
1525 goto cleanup;
1526 }
1527
1528 /* Validate local ports for overlap */
1529 if (do_rebuild || ports_modified) {
1530 retval = semanage_port_validate_local(sh);
1531 if (retval < 0)
1532 goto cleanup;
1533 }
1534
1535 /* Validate local ibpkeys for overlap */
1536 if (do_rebuild || ibpkeys_modified) {
1537 retval = semanage_ibpkey_validate_local(sh);
1538 if (retval < 0)
1539 goto cleanup;
1540 }
1541
1542 /* Validate local ibendports */
1543 if (do_rebuild || ibendports_modified) {
1544 retval = semanage_ibendport_validate_local(sh);
1545 if (retval < 0)
1546 goto cleanup;
1547 }
1548 /* ================== Write non-policydb components ========= */
1549
1550 /* Commit changes to components */
1551 retval = semanage_commit_components(sh);
1552 if (retval < 0)
1553 goto cleanup;
1554
1555 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
1556 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL),
1557 sh->conf->file_mode, false);
1558 if (retval < 0) {
1559 goto cleanup;
1560 }
1561
1562 retval = copy_file_if_exists(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
1563 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL),
1564 sh->conf->file_mode);
1565 if (retval < 0) {
1566 goto cleanup;
1567 }
1568
1569 retval = copy_file_if_exists(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC),
1570 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC),
1571 sh->conf->file_mode);
1572 if (retval < 0) {
1573 goto cleanup;
1574 }
1575
1576 retval = copy_file_if_exists(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS),
1577 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS),
1578 sh->conf->file_mode);
1579 if (retval < 0) {
1580 goto cleanup;
1581 }
1582
1583 /* run genhomedircon if its enabled, this should be the last operation
1584 * which requires the out policydb */
1585 if (!sh->conf->disable_genhomedircon) {
1586 if (out){
1587 if ((retval = semanage_genhomedircon(sh, out, sh->conf->usepasswd,
1588 sh->conf->ignoredirs)) != 0) {
1589 ERR(sh, "semanage_genhomedircon returned error code %d.", retval);
1590 goto cleanup;
1591 }
1592 /* file_contexts.homedirs was created in SEMANAGE_TMP store */
1593 retval = semanage_copy_file(
1594 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS),
1595 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS),
1596 sh->conf->file_mode, false);
1597 if (retval < 0) {
1598 goto cleanup;
1599 }
1600 }
1601 } else {
1602 WARN(sh, "WARNING: genhomedircon is disabled. \
1603 See /etc/selinux/semanage.conf if you need to enable it.");
1604 }
1605
1606 /* free out, if we don't free it before calling semanage_install_sandbox
1607 * then fork() may fail on low memory machines */
1608 sepol_policydb_free(out);
1609 out = NULL;
1610
1611 if (do_install)
1612 retval = semanage_install_sandbox(sh);
1613
1614 cleanup:
1615 for (i = 0; i < num_modinfos; i++) {
1616 semanage_module_info_destroy(sh, &modinfos[i]);
1617 }
1618 free(modinfos);
1619
1620 for (i = 0; mod_filenames != NULL && i < num_modinfos; i++) {
1621 free(mod_filenames[i]);
1622 }
1623
1624 /* Detach from policydb, so it can be freed */
1625 dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase);
1626 dbase_policydb_detach((dbase_policydb_t *) pports->dbase);
1627 dbase_policydb_detach((dbase_policydb_t *) pibpkeys->dbase);
1628 dbase_policydb_detach((dbase_policydb_t *) pibendports->dbase);
1629 dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase);
1630 dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase);
1631 dbase_policydb_detach((dbase_policydb_t *) pbools->dbase);
1632
1633 free(mod_filenames);
1634 sepol_policydb_free(out);
1635 cil_db_destroy(&cildb);
1636
1637 free(fc_buffer);
1638
1639 /* Set commit_err so other functions can detect any errors. Note that
1640 * retval > 0 will be the commit number.
1641 */
1642 if (retval < 0)
1643 sh->commit_err = retval;
1644
1645 if (semanage_remove_tmps(sh) != 0)
1646 retval = -1;
1647
1648 semanage_release_trans_lock(sh);
1649 umask(mask);
1650
1651 return retval;
1652 }
1653
1654 /* Writes a module to the sandbox's module directory, overwriting any
1655 * previous module stored within. Note that module data are not
1656 * free()d by this function; caller is responsible for deallocating it
1657 * if necessary. Returns 0 on success, -1 if out of memory, -2 if the
1658 * data does not represent a valid module file, -3 if error while
1659 * writing file. */
semanage_direct_install(semanage_handle_t * sh,char * data,size_t data_len,const char * module_name,const char * lang_ext)1660 static int semanage_direct_install(semanage_handle_t * sh,
1661 char *data, size_t data_len,
1662 const char *module_name, const char *lang_ext)
1663 {
1664 int status = 0;
1665 int ret = 0;
1666
1667 semanage_module_info_t modinfo;
1668 ret = semanage_module_info_init(sh, &modinfo);
1669 if (ret != 0) {
1670 status = -1;
1671 goto cleanup;
1672 }
1673
1674 ret = semanage_module_info_set_priority(sh, &modinfo, sh->priority);
1675 if (ret != 0) {
1676 status = -1;
1677 goto cleanup;
1678 }
1679
1680 ret = semanage_module_info_set_name(sh, &modinfo, module_name);
1681 if (ret != 0) {
1682 status = -1;
1683 goto cleanup;
1684 }
1685
1686 ret = semanage_module_info_set_lang_ext(sh, &modinfo, lang_ext);
1687 if (ret != 0) {
1688 status = -1;
1689 goto cleanup;
1690 }
1691
1692 ret = semanage_module_info_set_enabled(sh, &modinfo, -1);
1693 if (ret != 0) {
1694 status = -1;
1695 goto cleanup;
1696 }
1697
1698 status = semanage_direct_install_info(sh, &modinfo, data, data_len);
1699
1700 cleanup:
1701
1702 semanage_module_info_destroy(sh, &modinfo);
1703
1704 return status;
1705 }
1706
1707 /* Attempts to link a module to the sandbox's module directory, unlinking any
1708 * previous module stored within. Returns 0 on success, -1 if out of memory, -2 if the
1709 * data does not represent a valid module file, -3 if error while
1710 * writing file. */
1711
semanage_direct_install_file(semanage_handle_t * sh,const char * install_filename)1712 static int semanage_direct_install_file(semanage_handle_t * sh,
1713 const char *install_filename)
1714 {
1715
1716 int retval = -1;
1717 char *path = NULL;
1718 char *filename;
1719 char *lang_ext = NULL;
1720 char *module_name = NULL;
1721 char *separator;
1722 char *version = NULL;
1723 struct file_contents contents = {};
1724
1725 retval = map_compressed_file(sh, install_filename, &contents);
1726 if (retval < 0) {
1727 ERR(sh, "Unable to read file %s\n", install_filename);
1728 goto cleanup;
1729 }
1730
1731 path = strdup(install_filename);
1732 if (path == NULL) {
1733 ERR(sh, "No memory available for strdup.\n");
1734 retval = -1;
1735 goto cleanup;
1736 }
1737
1738 filename = basename(path);
1739
1740 if (contents.compressed) {
1741 separator = strrchr(filename, '.');
1742 if (separator == NULL) {
1743 ERR(sh, "Compressed module does not have a valid extension.");
1744 retval = -1;
1745 goto cleanup;
1746 }
1747 *separator = '\0';
1748 lang_ext = separator + 1;
1749 }
1750
1751 separator = strrchr(filename, '.');
1752 if (separator == NULL) {
1753 if (lang_ext == NULL) {
1754 ERR(sh, "Module does not have a valid extension.");
1755 retval = -1;
1756 goto cleanup;
1757 }
1758 } else {
1759 *separator = '\0';
1760 lang_ext = separator + 1;
1761 }
1762
1763 if (strcmp(lang_ext, "pp") == 0) {
1764 retval = parse_module_headers(sh, contents.data, contents.len,
1765 &module_name, &version);
1766 free(version);
1767 if (retval != 0)
1768 goto cleanup;
1769 }
1770
1771 if (module_name == NULL) {
1772 module_name = strdup(filename);
1773 if (module_name == NULL) {
1774 ERR(sh, "No memory available for module_name.\n");
1775 retval = -1;
1776 goto cleanup;
1777 }
1778 } else if (strcmp(module_name, filename) != 0) {
1779 fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename);
1780 }
1781
1782 retval = semanage_direct_install(sh, contents.data, contents.len,
1783 module_name, lang_ext);
1784
1785 cleanup:
1786 unmap_compressed_file(&contents);
1787 free(module_name);
1788 free(path);
1789
1790 return retval;
1791 }
1792
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)1793 static int semanage_direct_extract(semanage_handle_t * sh,
1794 semanage_module_key_t *modkey,
1795 int extract_cil,
1796 void **mapped_data,
1797 size_t *data_len,
1798 semanage_module_info_t **modinfo)
1799 {
1800 char module_path[PATH_MAX];
1801 char input_file[PATH_MAX];
1802 enum semanage_module_path_type file_type;
1803 int rc = -1;
1804 semanage_module_info_t *_modinfo = NULL;
1805 struct stat sb;
1806 struct file_contents contents = {};
1807
1808 /* get path of module */
1809 rc = semanage_module_get_path(
1810 sh,
1811 (const semanage_module_info_t *)modkey,
1812 SEMANAGE_MODULE_PATH_NAME,
1813 module_path,
1814 sizeof(module_path));
1815 if (rc != 0) {
1816 goto cleanup;
1817 }
1818
1819 if (stat(module_path, &sb) != 0) {
1820 ERR(sh, "Unable to access %s: %s\n", module_path, strerror(errno));
1821 rc = -1;
1822 goto cleanup;
1823 }
1824
1825 rc = semanage_module_get_module_info(sh,
1826 modkey,
1827 &_modinfo);
1828 if (rc != 0) {
1829 goto cleanup;
1830 }
1831
1832 if (extract_cil || strcmp(_modinfo->lang_ext, "cil") == 0) {
1833 file_type = SEMANAGE_MODULE_PATH_CIL;
1834 } else {
1835 file_type = SEMANAGE_MODULE_PATH_HLL;
1836 }
1837
1838 /* get path of what to extract */
1839 rc = semanage_module_get_path(
1840 sh,
1841 _modinfo,
1842 file_type,
1843 input_file,
1844 sizeof(input_file));
1845 if (rc != 0) {
1846 goto cleanup;
1847 }
1848
1849 if (extract_cil == 1 && strcmp(_modinfo->lang_ext, "cil") && stat(input_file, &sb) != 0) {
1850 if (errno != ENOENT) {
1851 ERR(sh, "Unable to access %s: %s\n", input_file, strerror(errno));
1852 rc = -1;
1853 goto cleanup;
1854 }
1855
1856 rc = semanage_compile_module(sh, _modinfo, NULL);
1857 if (rc < 0) {
1858 goto cleanup;
1859 }
1860 }
1861
1862 rc = map_compressed_file(sh, input_file, &contents);
1863 if (rc < 0) {
1864 ERR(sh, "Error mapping file: %s", input_file);
1865 goto cleanup;
1866 }
1867
1868 /* The API promises an mmap'ed pointer */
1869 if (contents.compressed) {
1870 *mapped_data = mmap(NULL, contents.len, PROT_READ|PROT_WRITE,
1871 MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
1872 if (*mapped_data == MAP_FAILED) {
1873 ERR(sh, "Unable to map memory");
1874 rc = -1;
1875 goto cleanup;
1876 }
1877 memcpy(*mapped_data, contents.data, contents.len);
1878 free(contents.data);
1879 } else {
1880 *mapped_data = contents.data;
1881 }
1882
1883 *modinfo = _modinfo;
1884 *data_len = contents.len;
1885
1886 cleanup:
1887 if (rc != 0) {
1888 unmap_compressed_file(&contents);
1889 semanage_module_info_destroy(sh, _modinfo);
1890 free(_modinfo);
1891 }
1892
1893 return rc;
1894 }
1895
1896 /* Removes a module from the sandbox. Returns 0 on success, -1 if out
1897 * of memory, -2 if module not found or could not be removed. */
semanage_direct_remove(semanage_handle_t * sh,char * module_name)1898 static int semanage_direct_remove(semanage_handle_t * sh, char *module_name)
1899 {
1900 int status = 0;
1901 int ret = 0;
1902
1903 semanage_module_key_t modkey;
1904 ret = semanage_module_key_init(sh, &modkey);
1905 if (ret != 0) {
1906 status = -1;
1907 goto cleanup;
1908 }
1909
1910 ret = semanage_module_key_set_priority(sh, &modkey, sh->priority);
1911 if (ret != 0) {
1912 status = -1;
1913 goto cleanup;
1914 }
1915
1916 ret = semanage_module_key_set_name(sh, &modkey, module_name);
1917 if (ret != 0) {
1918 status = -1;
1919 goto cleanup;
1920 }
1921
1922 status = semanage_direct_remove_key(sh, &modkey);
1923
1924 cleanup:
1925 semanage_module_key_destroy(sh, &modkey);
1926 return status;
1927 }
1928
1929 /* Allocate an array of module_info structures for each readable
1930 * module within the store. Note that if the calling program has
1931 * already begun a transaction then this function will get a list of
1932 * modules within the sandbox. The caller is responsible for calling
1933 * semanage_module_info_datum_destroy() on each element of the array
1934 * as well as free()ing the entire list.
1935 */
semanage_direct_list(semanage_handle_t * sh,semanage_module_info_t ** modinfo,int * num_modules)1936 static int semanage_direct_list(semanage_handle_t * sh,
1937 semanage_module_info_t ** modinfo,
1938 int *num_modules)
1939 {
1940 int i, retval = -1;
1941 *modinfo = NULL;
1942 *num_modules = 0;
1943
1944 /* get the read lock when reading from the active
1945 (non-transaction) directory */
1946 if (!sh->is_in_transaction)
1947 if (semanage_get_active_lock(sh) < 0)
1948 return -1;
1949
1950 if (semanage_get_active_modules(sh, modinfo, num_modules) == -1) {
1951 goto cleanup;
1952 }
1953
1954 if (num_modules == 0) {
1955 retval = semanage_direct_get_serial(sh);
1956 goto cleanup;
1957 }
1958
1959 retval = semanage_direct_get_serial(sh);
1960
1961 cleanup:
1962 if (retval < 0) {
1963 for (i = 0; i < *num_modules; i++) {
1964 semanage_module_info_destroy(sh, &(*modinfo[i]));
1965 modinfo[i] = NULL;
1966 }
1967 free(*modinfo);
1968 *modinfo = NULL;
1969 }
1970
1971 if (!sh->is_in_transaction) {
1972 semanage_release_active_lock(sh);
1973 }
1974 return retval;
1975 }
1976
semanage_direct_get_enabled(semanage_handle_t * sh,const semanage_module_key_t * modkey,int * enabled)1977 static int semanage_direct_get_enabled(semanage_handle_t *sh,
1978 const semanage_module_key_t *modkey,
1979 int *enabled)
1980 {
1981 assert(sh);
1982 assert(modkey);
1983 assert(enabled);
1984
1985 int status = 0;
1986 int ret = 0;
1987
1988 char path[PATH_MAX];
1989 struct stat sb;
1990 semanage_module_info_t *modinfo = NULL;
1991
1992 /* get module info */
1993 ret = semanage_module_get_module_info(
1994 sh,
1995 modkey,
1996 &modinfo);
1997 if (ret != 0) {
1998 status = -1;
1999 goto cleanup;
2000 }
2001
2002 /* get disabled file path */
2003 ret = semanage_module_get_path(
2004 sh,
2005 modinfo,
2006 SEMANAGE_MODULE_PATH_DISABLED,
2007 path,
2008 sizeof(path));
2009 if (ret != 0) {
2010 status = -1;
2011 goto cleanup;
2012 }
2013
2014 if (stat(path, &sb) < 0) {
2015 if (errno != ENOENT) {
2016 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
2017 status = -1;
2018 goto cleanup;
2019 }
2020
2021 *enabled = 1;
2022 }
2023 else {
2024 *enabled = 0;
2025 }
2026
2027 cleanup:
2028 semanage_module_info_destroy(sh, modinfo);
2029 free(modinfo);
2030
2031 return status;
2032 }
2033
semanage_direct_set_enabled(semanage_handle_t * sh,const semanage_module_key_t * modkey,int enabled)2034 static int semanage_direct_set_enabled(semanage_handle_t *sh,
2035 const semanage_module_key_t *modkey,
2036 int enabled)
2037 {
2038 assert(sh);
2039 assert(modkey);
2040
2041 int status = 0;
2042 int ret = 0;
2043
2044 char fn[PATH_MAX];
2045 const char *path = NULL;
2046 FILE *fp = NULL;
2047 semanage_module_info_t *modinfo = NULL;
2048 mode_t mask;
2049
2050 /* check transaction */
2051 if (!sh->is_in_transaction) {
2052 if (semanage_begin_transaction(sh) < 0) {
2053 status = -1;
2054 goto cleanup;
2055 }
2056 }
2057
2058 /* validate name */
2059 ret = semanage_module_validate_name(modkey->name);
2060 if (ret != 0) {
2061 errno = 0;
2062 ERR(sh, "Name %s is invalid.", modkey->name);
2063 status = -1;
2064 goto cleanup;
2065 }
2066
2067 /* validate enabled */
2068 ret = semanage_module_validate_enabled(enabled);
2069 if (ret != 0) {
2070 errno = 0;
2071 ERR(sh, "Enabled status %d is invalid.", enabled);
2072 status = -1;
2073 goto cleanup;
2074 }
2075
2076 /* check for disabled path, create if missing */
2077 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED);
2078
2079 ret = semanage_mkdir(sh, path);
2080 if (ret != 0) {
2081 status = -1;
2082 goto cleanup;
2083 }
2084
2085 /* get module info */
2086 ret = semanage_module_get_module_info(
2087 sh,
2088 modkey,
2089 &modinfo);
2090 if (ret != 0) {
2091 status = -1;
2092 goto cleanup;
2093 }
2094
2095 /* get module disabled file */
2096 ret = semanage_module_get_path(
2097 sh,
2098 modinfo,
2099 SEMANAGE_MODULE_PATH_DISABLED,
2100 fn,
2101 sizeof(fn));
2102 if (ret != 0) {
2103 status = -1;
2104 goto cleanup;
2105 }
2106
2107 switch (enabled) {
2108 case 0: /* disable the module */
2109 mask = umask(0077);
2110 fp = fopen(fn, "w");
2111 umask(mask);
2112
2113 if (fp == NULL) {
2114 ERR(sh,
2115 "Unable to disable module %s",
2116 modkey->name);
2117 status = -1;
2118 goto cleanup;
2119 }
2120
2121 ret = fclose(fp);
2122 fp = NULL;
2123 if (ret != 0) {
2124 ERR(sh,
2125 "Unable to close disabled file for module %s",
2126 modkey->name);
2127 status = -1;
2128 goto cleanup;
2129 }
2130
2131 break;
2132 case 1: /* enable the module */
2133 if (unlink(fn) < 0) {
2134 if (errno != ENOENT) {
2135 ERR(sh,
2136 "Unable to enable module %s",
2137 modkey->name);
2138 status = -1;
2139 goto cleanup;
2140 }
2141 else {
2142 /* module already enabled */
2143 errno = 0;
2144 }
2145 }
2146
2147 break;
2148 case -1: /* warn about ignored setting to default */
2149 WARN(sh,
2150 "Setting module %s to 'default' state has no effect",
2151 modkey->name);
2152 break;
2153 }
2154
2155 cleanup:
2156 semanage_module_info_destroy(sh, modinfo);
2157 free(modinfo);
2158
2159 if (fp != NULL) fclose(fp);
2160 return status;
2161 }
2162
semanage_direct_access_check(semanage_handle_t * sh)2163 int semanage_direct_access_check(semanage_handle_t * sh)
2164 {
2165 if (semanage_check_init(sh, sh->conf->store_root_path))
2166 return -1;
2167
2168 return semanage_store_access_check();
2169 }
2170
semanage_direct_mls_enabled(semanage_handle_t * sh)2171 int semanage_direct_mls_enabled(semanage_handle_t * sh)
2172 {
2173 sepol_policydb_t *p = NULL;
2174 int retval;
2175
2176 retval = sepol_policydb_create(&p);
2177 if (retval < 0)
2178 goto cleanup;
2179
2180 retval = semanage_read_policydb(sh, p, SEMANAGE_STORE_KERNEL);
2181 if (retval < 0)
2182 goto cleanup;
2183
2184 retval = sepol_policydb_mls_enabled(p);
2185 cleanup:
2186 sepol_policydb_free(p);
2187 return retval;
2188 }
2189
semanage_direct_get_module_info(semanage_handle_t * sh,const semanage_module_key_t * modkey,semanage_module_info_t ** modinfo)2190 static int semanage_direct_get_module_info(semanage_handle_t *sh,
2191 const semanage_module_key_t *modkey,
2192 semanage_module_info_t **modinfo)
2193 {
2194 assert(sh);
2195 assert(modkey);
2196 assert(modinfo);
2197
2198 int status = 0;
2199 int ret = 0;
2200
2201 char fn[PATH_MAX];
2202 FILE *fp = NULL;
2203 size_t size = 0;
2204 struct stat sb;
2205 char *tmp = NULL;
2206
2207 int i = 0;
2208
2209 semanage_module_info_t *modinfos = NULL;
2210 int modinfos_len = 0;
2211 semanage_module_info_t *highest = NULL;
2212
2213 /* check module name */
2214 ret = semanage_module_validate_name(modkey->name);
2215 if (ret < 0) {
2216 errno = 0;
2217 ERR(sh, "Name %s is invalid.", modkey->name);
2218 status = -1;
2219 goto cleanup;
2220 }
2221
2222 /* if priority == 0, then find the highest priority available */
2223 if (modkey->priority == 0) {
2224 ret = semanage_direct_list_all(sh, &modinfos, &modinfos_len);
2225 if (ret != 0) {
2226 status = -1;
2227 goto cleanup;
2228 }
2229
2230 for (i = 0; i < modinfos_len; i++) {
2231 ret = strcmp(modinfos[i].name, modkey->name);
2232 if (ret == 0) {
2233 highest = &modinfos[i];
2234 break;
2235 }
2236 }
2237
2238 if (highest == NULL) {
2239 status = -1;
2240 goto cleanup;
2241 }
2242
2243 ret = semanage_module_info_create(sh, modinfo);
2244 if (ret != 0) {
2245 status = -1;
2246 goto cleanup;
2247 }
2248
2249 ret = semanage_module_info_clone(sh, highest, *modinfo);
2250 if (ret != 0) {
2251 status = -1;
2252 }
2253
2254 /* skip to cleanup, module was found */
2255 goto cleanup;
2256 }
2257
2258 /* check module priority */
2259 ret = semanage_module_validate_priority(modkey->priority);
2260 if (ret != 0) {
2261 errno = 0;
2262 ERR(sh, "Priority %d is invalid.", modkey->priority);
2263 status = -1;
2264 goto cleanup;
2265 }
2266
2267 /* copy in key values */
2268 ret = semanage_module_info_create(sh, modinfo);
2269 if (ret != 0) {
2270 status = -1;
2271 goto cleanup;
2272 }
2273
2274 ret = semanage_module_info_set_priority(sh, *modinfo, modkey->priority);
2275 if (ret != 0) {
2276 status = -1;
2277 goto cleanup;
2278 }
2279
2280 ret = semanage_module_info_set_name(sh, *modinfo, modkey->name);
2281 if (ret != 0) {
2282 status = -1;
2283 goto cleanup;
2284 }
2285
2286 /* lookup module ext */
2287 ret = semanage_module_get_path(sh,
2288 *modinfo,
2289 SEMANAGE_MODULE_PATH_LANG_EXT,
2290 fn,
2291 sizeof(fn));
2292 if (ret != 0) {
2293 status = -1;
2294 goto cleanup;
2295 }
2296
2297 fp = fopen(fn, "r");
2298
2299 if (fp == NULL) {
2300 ERR(sh,
2301 "Unable to open %s module lang ext file at %s.",
2302 (*modinfo)->name, fn);
2303 status = -1;
2304 goto cleanup;
2305 }
2306
2307 /* set module ext */
2308 if (getline(&tmp, &size, fp) < 0) {
2309 ERR(sh,
2310 "Unable to read %s module lang ext file.",
2311 (*modinfo)->name);
2312 status = -1;
2313 goto cleanup;
2314 }
2315
2316 ret = semanage_module_info_set_lang_ext(sh, *modinfo, tmp);
2317 if (ret != 0) {
2318 status = -1;
2319 goto cleanup;
2320 }
2321 free(tmp);
2322 tmp = NULL;
2323
2324 if (fclose(fp) != 0) {
2325 fp = NULL;
2326 ERR(sh,
2327 "Unable to close %s module lang ext file.",
2328 (*modinfo)->name);
2329 status = -1;
2330 goto cleanup;
2331 }
2332
2333 fp = NULL;
2334
2335 /* lookup enabled/disabled status */
2336 ret = semanage_module_get_path(sh,
2337 *modinfo,
2338 SEMANAGE_MODULE_PATH_DISABLED,
2339 fn,
2340 sizeof(fn));
2341 if (ret != 0) {
2342 status = -1;
2343 goto cleanup;
2344 }
2345
2346 /* set enabled/disabled status */
2347 if (stat(fn, &sb) < 0) {
2348 if (errno != ENOENT) {
2349 ERR(sh, "Unable to access %s: %s\n", fn, strerror(errno));
2350 status = -1;
2351 goto cleanup;
2352 }
2353
2354 ret = semanage_module_info_set_enabled(sh, *modinfo, 1);
2355 if (ret != 0) {
2356 status = -1;
2357 goto cleanup;
2358 }
2359 }
2360 else {
2361 ret = semanage_module_info_set_enabled(sh, *modinfo, 0);
2362 if (ret != 0) {
2363 status = -1;
2364 goto cleanup;
2365 }
2366 }
2367
2368 cleanup:
2369 free(tmp);
2370
2371 if (modinfos != NULL) {
2372 for (i = 0; i < modinfos_len; i++) {
2373 semanage_module_info_destroy(sh, &modinfos[i]);
2374 }
2375 free(modinfos);
2376 }
2377
2378 if (fp != NULL) fclose(fp);
2379 return status;
2380 }
2381
semanage_direct_set_module_info(semanage_handle_t * sh,const semanage_module_info_t * modinfo)2382 static int semanage_direct_set_module_info(semanage_handle_t *sh,
2383 const semanage_module_info_t *modinfo)
2384 {
2385 int status = 0;
2386 int ret = 0;
2387
2388 char fn[PATH_MAX];
2389 const char *path = NULL;
2390 int enabled = 0;
2391 semanage_module_info_t *modinfo_tmp = NULL;
2392
2393 semanage_module_key_t modkey;
2394 ret = semanage_module_key_init(sh, &modkey);
2395 if (ret != 0) {
2396 status = -1;
2397 goto cleanup;
2398 }
2399
2400 /* check transaction */
2401 if (!sh->is_in_transaction) {
2402 if (semanage_begin_transaction(sh) < 0) {
2403 status = -1;
2404 goto cleanup;
2405 }
2406 }
2407
2408 /* validate module */
2409 ret = semanage_module_info_validate(modinfo);
2410 if (ret != 0) {
2411 status = -1;
2412 goto cleanup;
2413 }
2414
2415 sh->modules_modified = 1;
2416
2417 /* check for modules path, create if missing */
2418 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES);
2419
2420 ret = semanage_mkdir(sh, path);
2421 if (ret != 0) {
2422 status = -1;
2423 goto cleanup;
2424 }
2425
2426 /* write priority */
2427 ret = semanage_module_get_path(sh,
2428 modinfo,
2429 SEMANAGE_MODULE_PATH_PRIORITY,
2430 fn,
2431 sizeof(fn));
2432 if (ret != 0) {
2433 status = -1;
2434 goto cleanup;
2435 }
2436
2437 ret = semanage_mkdir(sh, fn);
2438 if (ret != 0) {
2439 status = -1;
2440 goto cleanup;
2441 }
2442
2443 /* write name */
2444 ret = semanage_module_get_path(sh,
2445 modinfo,
2446 SEMANAGE_MODULE_PATH_NAME,
2447 fn,
2448 sizeof(fn));
2449 if (ret != 0) {
2450 status = -1;
2451 goto cleanup;
2452 }
2453
2454 ret = semanage_mkdir(sh, fn);
2455 if (ret != 0) {
2456 status = -1;
2457 goto cleanup;
2458 }
2459
2460 /* write ext */
2461 ret = semanage_direct_write_langext(sh, modinfo->lang_ext, modinfo);
2462 if (ret != 0) {
2463 status = -1;
2464 goto cleanup;
2465 }
2466
2467 /* write enabled/disabled status */
2468
2469 /* check for disabled path, create if missing */
2470 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED);
2471
2472 ret = semanage_mkdir(sh, path);
2473 if (ret != 0) {
2474 status = -1;
2475 goto cleanup;
2476 }
2477
2478 ret = semanage_module_get_path(sh,
2479 modinfo,
2480 SEMANAGE_MODULE_PATH_DISABLED,
2481 fn,
2482 sizeof(fn));
2483 if (ret != 0) {
2484 status = -1;
2485 goto cleanup;
2486 }
2487
2488 ret = semanage_module_key_set_name(sh, &modkey, modinfo->name);
2489 if (ret != 0) {
2490 status = -1;
2491 goto cleanup;
2492 }
2493
2494 if (modinfo->enabled == -1) {
2495 /* default to enabled */
2496 enabled = 1;
2497
2498 /* check if a module is already installed */
2499 ret = semanage_module_get_module_info(sh,
2500 &modkey,
2501 &modinfo_tmp);
2502 if (ret == 0) {
2503 /* set enabled status to current one */
2504 enabled = modinfo_tmp->enabled;
2505 }
2506 }
2507 else {
2508 enabled = modinfo->enabled;
2509 }
2510
2511 ret = semanage_module_set_enabled(sh, &modkey, enabled);
2512 if (ret != 0) {
2513 status = -1;
2514 goto cleanup;
2515 }
2516
2517 cleanup:
2518 semanage_module_key_destroy(sh, &modkey);
2519
2520 semanage_module_info_destroy(sh, modinfo_tmp);
2521 free(modinfo_tmp);
2522
2523 return status;
2524 }
2525
semanage_priorities_filename_select(const struct dirent * d)2526 static int semanage_priorities_filename_select(const struct dirent *d)
2527 {
2528 if (d->d_name[0] == '.' ||
2529 strcmp(d->d_name, "disabled") == 0)
2530 return 0;
2531 return 1;
2532 }
2533
semanage_modules_filename_select(const struct dirent * d)2534 static int semanage_modules_filename_select(const struct dirent *d)
2535 {
2536 if (d->d_name[0] == '.')
2537 return 0;
2538 return 1;
2539 }
2540
semanage_direct_list_all(semanage_handle_t * sh,semanage_module_info_t ** modinfos,int * modinfos_len)2541 static int semanage_direct_list_all(semanage_handle_t *sh,
2542 semanage_module_info_t **modinfos,
2543 int *modinfos_len)
2544 {
2545 assert(sh);
2546 assert(modinfos);
2547 assert(modinfos_len);
2548
2549 int status = 0;
2550 int ret = 0;
2551
2552 int i = 0;
2553 int j = 0;
2554
2555 *modinfos = NULL;
2556 *modinfos_len = 0;
2557 void *tmp = NULL;
2558
2559 const char *toplevel = NULL;
2560
2561 struct dirent **priorities = NULL;
2562 int priorities_len = 0;
2563 char priority_path[PATH_MAX];
2564
2565 struct dirent **modules = NULL;
2566 int modules_len = 0;
2567
2568 uint16_t priority = 0;
2569
2570 semanage_module_info_t *modinfo_tmp = NULL;
2571
2572 semanage_module_info_t modinfo;
2573 ret = semanage_module_info_init(sh, &modinfo);
2574 if (ret != 0) {
2575 status = -1;
2576 goto cleanup;
2577 }
2578
2579 if (sh->is_in_transaction) {
2580 toplevel = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES);
2581 } else {
2582 toplevel = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES);
2583 }
2584
2585 /* find priorities */
2586 priorities_len = scandir(toplevel,
2587 &priorities,
2588 semanage_priorities_filename_select,
2589 versionsort);
2590 if (priorities_len == -1) {
2591 ERR(sh, "Error while scanning directory %s.", toplevel);
2592 status = -1;
2593 goto cleanup;
2594 }
2595
2596 /* for each priority directory */
2597 /* loop through in reverse so that highest priority is first */
2598 for (i = priorities_len - 1; i >= 0; i--) {
2599 /* convert priority string to uint16_t */
2600 ret = semanage_string_to_priority(priorities[i]->d_name,
2601 &priority);
2602 if (ret != 0) {
2603 status = -1;
2604 goto cleanup;
2605 }
2606
2607 /* set our priority */
2608 ret = semanage_module_info_set_priority(sh,
2609 &modinfo,
2610 priority);
2611 if (ret != 0) {
2612 status = -1;
2613 goto cleanup;
2614 }
2615
2616 /* get the priority path */
2617 ret = semanage_module_get_path(sh,
2618 &modinfo,
2619 SEMANAGE_MODULE_PATH_PRIORITY,
2620 priority_path,
2621 sizeof(priority_path));
2622 if (ret != 0) {
2623 status = -1;
2624 goto cleanup;
2625 }
2626
2627 /* cleanup old modules */
2628 if (modules != NULL) {
2629 for (j = 0; j < modules_len; j++) {
2630 free(modules[j]);
2631 modules[j] = NULL;
2632 }
2633 free(modules);
2634 modules = NULL;
2635 modules_len = 0;
2636 }
2637
2638 /* find modules at this priority */
2639 modules_len = scandir(priority_path,
2640 &modules,
2641 semanage_modules_filename_select,
2642 versionsort);
2643 if (modules_len == -1) {
2644 ERR(sh,
2645 "Error while scanning directory %s.",
2646 priority_path);
2647 status = -1;
2648 goto cleanup;
2649 }
2650
2651 if (modules_len == 0) continue;
2652
2653 /* add space for modules */
2654 tmp = realloc(*modinfos,
2655 sizeof(semanage_module_info_t) *
2656 (*modinfos_len + modules_len));
2657 if (tmp == NULL) {
2658 ERR(sh, "Error allocating memory for module array.");
2659 status = -1;
2660 goto cleanup;
2661 }
2662 *modinfos = tmp;
2663
2664 /* for each module directory */
2665 for(j = 0; j < modules_len; j++) {
2666 /* set module name */
2667 ret = semanage_module_info_set_name(
2668 sh,
2669 &modinfo,
2670 modules[j]->d_name);
2671 if (ret != 0) {
2672 status = -1;
2673 goto cleanup;
2674 }
2675
2676 /* get module values */
2677 ret = semanage_direct_get_module_info(
2678 sh,
2679 (const semanage_module_key_t *)
2680 (&modinfo),
2681 &modinfo_tmp);
2682 if (ret != 0) {
2683 status = -1;
2684 goto cleanup;
2685 }
2686
2687 /* copy into array */
2688 ret = semanage_module_info_init(
2689 sh,
2690 &((*modinfos)[*modinfos_len]));
2691 if (ret != 0) {
2692 status = -1;
2693 goto cleanup;
2694 }
2695
2696 ret = semanage_module_info_clone(
2697 sh,
2698 modinfo_tmp,
2699 &((*modinfos)[*modinfos_len]));
2700 if (ret != 0) {
2701 status = -1;
2702 goto cleanup;
2703 }
2704
2705 semanage_module_info_destroy(sh, modinfo_tmp);
2706 free(modinfo_tmp);
2707 modinfo_tmp = NULL;
2708
2709 *modinfos_len += 1;
2710 }
2711 }
2712
2713 cleanup:
2714 semanage_module_info_destroy(sh, &modinfo);
2715
2716 if (priorities != NULL) {
2717 for (i = 0; i < priorities_len; i++) {
2718 free(priorities[i]);
2719 }
2720 free(priorities);
2721 }
2722
2723 if (modules != NULL) {
2724 for (i = 0; i < modules_len; i++) {
2725 free(modules[i]);
2726 }
2727 free(modules);
2728 }
2729
2730 semanage_module_info_destroy(sh, modinfo_tmp);
2731 free(modinfo_tmp);
2732 modinfo_tmp = NULL;
2733
2734 if (status != 0) {
2735 if (modinfos != NULL) {
2736 for (i = 0; i < *modinfos_len; i++) {
2737 semanage_module_info_destroy(
2738 sh,
2739 &(*modinfos)[i]);
2740 }
2741 free(*modinfos);
2742 *modinfos = NULL;
2743 *modinfos_len = 0;
2744 }
2745 }
2746
2747 return status;
2748 }
2749
semanage_direct_install_info(semanage_handle_t * sh,const semanage_module_info_t * modinfo,char * data,size_t data_len)2750 static int semanage_direct_install_info(semanage_handle_t *sh,
2751 const semanage_module_info_t *modinfo,
2752 char *data,
2753 size_t data_len)
2754 {
2755 assert(sh);
2756 assert(modinfo);
2757 assert(data);
2758
2759 int status = 0;
2760 int ret = 0;
2761 int type;
2762 struct stat sb;
2763
2764 char path[PATH_MAX];
2765 mode_t mask = umask(0077);
2766
2767 semanage_module_info_t *higher_info = NULL;
2768 semanage_module_key_t higher_key;
2769 ret = semanage_module_key_init(sh, &higher_key);
2770 if (ret != 0) {
2771 status = -1;
2772 goto cleanup;
2773 }
2774
2775 /* validate module info */
2776 ret = semanage_module_info_validate(modinfo);
2777 if (ret != 0) {
2778 ERR(sh, "%s failed module validation.\n", modinfo->name);
2779 status = -2;
2780 goto cleanup;
2781 }
2782
2783 /* Check for higher priority module and warn if there is one as
2784 * it will override the module currently being installed.
2785 */
2786 ret = semanage_module_key_set_name(sh, &higher_key, modinfo->name);
2787 if (ret != 0) {
2788 status = -1;
2789 goto cleanup;
2790 }
2791
2792 ret = semanage_direct_get_module_info(sh, &higher_key, &higher_info);
2793 if (ret == 0) {
2794 if (higher_info->priority > modinfo->priority) {
2795 errno = 0;
2796 WARN(sh,
2797 "A higher priority %s module exists at priority %d and will override the module currently being installed at priority %d.",
2798 modinfo->name,
2799 higher_info->priority,
2800 modinfo->priority);
2801 }
2802 else if (higher_info->priority < modinfo->priority) {
2803 errno = 0;
2804 INFO(sh,
2805 "Overriding %s module at lower priority %d with module at priority %d.",
2806 modinfo->name,
2807 higher_info->priority,
2808 modinfo->priority);
2809 }
2810
2811 if (higher_info->enabled == 0 && modinfo->enabled == -1) {
2812 errno = 0;
2813 WARN(sh,
2814 "%s module will be disabled after install as there is a disabled instance of this module present in the system.",
2815 modinfo->name);
2816 }
2817 }
2818
2819 /* set module meta data */
2820 ret = semanage_direct_set_module_info(sh, modinfo);
2821 if (ret != 0) {
2822 status = -2;
2823 goto cleanup;
2824 }
2825
2826 /* install module source file */
2827 if (!strcasecmp(modinfo->lang_ext, "cil")) {
2828 type = SEMANAGE_MODULE_PATH_CIL;
2829 } else {
2830 type = SEMANAGE_MODULE_PATH_HLL;
2831 }
2832 ret = semanage_module_get_path(
2833 sh,
2834 modinfo,
2835 type,
2836 path,
2837 sizeof(path));
2838 if (ret != 0) {
2839 status = -3;
2840 goto cleanup;
2841 }
2842
2843 ret = write_compressed_file(sh, path, data, data_len);
2844 if (ret < 0) {
2845 ERR(sh, "Error while writing to %s.", path);
2846 status = -3;
2847 goto cleanup;
2848 }
2849
2850 /* if this is an HLL, delete the CIL cache if it exists so it will get recompiled */
2851 if (type == SEMANAGE_MODULE_PATH_HLL) {
2852 ret = semanage_module_get_path(
2853 sh,
2854 modinfo,
2855 SEMANAGE_MODULE_PATH_CIL,
2856 path,
2857 sizeof(path));
2858 if (ret != 0) {
2859 status = -3;
2860 goto cleanup;
2861 }
2862
2863 if (stat(path, &sb) == 0) {
2864 ret = unlink(path);
2865 if (ret != 0) {
2866 ERR(sh, "Error while removing cached CIL file %s: %s", path, strerror(errno));
2867 status = -3;
2868 goto cleanup;
2869 }
2870 }
2871 }
2872
2873 cleanup:
2874 semanage_module_key_destroy(sh, &higher_key);
2875 semanage_module_info_destroy(sh, higher_info);
2876 free(higher_info);
2877 umask(mask);
2878
2879 return status;
2880 }
2881
semanage_direct_remove_key(semanage_handle_t * sh,const semanage_module_key_t * modkey)2882 static int semanage_direct_remove_key(semanage_handle_t *sh,
2883 const semanage_module_key_t *modkey)
2884 {
2885 assert(sh);
2886 assert(modkey);
2887
2888 int status = 0;
2889 int ret = 0;
2890
2891 char path[PATH_MAX];
2892 semanage_module_info_t *modinfo = NULL;
2893
2894 semanage_module_key_t modkey_tmp;
2895 ret = semanage_module_key_init(sh, &modkey_tmp);
2896 if (ret != 0) {
2897 status = -1;
2898 goto cleanup;
2899 }
2900
2901 /* validate module key */
2902 ret = semanage_module_validate_priority(modkey->priority);
2903 if (ret != 0) {
2904 errno = 0;
2905 ERR(sh, "Priority %d is invalid.", modkey->priority);
2906 status = -1;
2907 goto cleanup;
2908 }
2909
2910 ret = semanage_module_validate_name(modkey->name);
2911 if (ret != 0) {
2912 errno = 0;
2913 ERR(sh, "Name %s is invalid.", modkey->name);
2914 status = -1;
2915 goto cleanup;
2916 }
2917
2918 ret = semanage_module_key_set_name(sh, &modkey_tmp, modkey->name);
2919 if (ret != 0) {
2920 status = -1;
2921 goto cleanup;
2922 }
2923
2924 /* get module path */
2925 ret = semanage_module_get_path(
2926 sh,
2927 (const semanage_module_info_t *)modkey,
2928 SEMANAGE_MODULE_PATH_NAME,
2929 path,
2930 sizeof(path));
2931 if (ret != 0) {
2932 status = -2;
2933 goto cleanup;
2934 }
2935
2936 /* remove directory */
2937 ret = semanage_remove_directory(path);
2938 if (ret != 0) {
2939 ERR(sh, "Unable to remove module %s at priority %d.", modkey->name, modkey->priority);
2940 status = -2;
2941 goto cleanup;
2942 }
2943
2944 /* check if its the last module at any priority */
2945 ret = semanage_module_get_module_info(sh, &modkey_tmp, &modinfo);
2946 if (ret != 0) {
2947 /* info that no other module will override */
2948 errno = 0;
2949 INFO(sh,
2950 "Removing last %s module (no other %s module exists at another priority).",
2951 modkey->name,
2952 modkey->name);
2953
2954 /* remove disabled status file */
2955 ret = semanage_module_get_path(
2956 sh,
2957 (const semanage_module_info_t *)modkey,
2958 SEMANAGE_MODULE_PATH_DISABLED,
2959 path,
2960 sizeof(path));
2961 if (ret != 0) {
2962 status = -1;
2963 goto cleanup;
2964 }
2965
2966 struct stat sb;
2967 if (stat(path, &sb) == 0) {
2968 ret = unlink(path);
2969 if (ret != 0) {
2970 status = -1;
2971 goto cleanup;
2972 }
2973 }
2974 }
2975 else {
2976 /* if a lower priority module is going to become active */
2977 if (modkey->priority > modinfo->priority) {
2978 /* inform what the new active module will be */
2979 errno = 0;
2980 INFO(sh,
2981 "%s module at priority %d is now active.",
2982 modinfo->name,
2983 modinfo->priority);
2984 }
2985 }
2986
2987 cleanup:
2988 semanage_module_key_destroy(sh, &modkey_tmp);
2989
2990 semanage_module_info_destroy(sh, modinfo);
2991 free(modinfo);
2992
2993 return status;
2994 }
2995
2996