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