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