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