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