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