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 /* Write the linked policy before merging local changes. */
1465 retval = semanage_write_policydb(sh, out,
1466 SEMANAGE_LINKED);
1467 if (retval < 0)
1468 goto cleanup;
1469 } else {
1470 /* Load the existing linked policy, w/o local changes */
1471 retval = sepol_policydb_create(&out);
1472 if (retval < 0)
1473 goto cleanup;
1474
1475 retval = semanage_read_policydb(sh, out, SEMANAGE_LINKED);
1476 if (retval < 0)
1477 goto cleanup;
1478
1479 path = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS_LINKED);
1480 if (stat(path, &sb) == 0) {
1481 retval = semanage_copy_file(path,
1482 semanage_path(SEMANAGE_TMP,
1483 SEMANAGE_STORE_SEUSERS),
1484 0);
1485 if (retval < 0)
1486 goto cleanup;
1487 pseusers->dtable->drop_cache(pseusers->dbase);
1488 } else if (errno == ENOENT) {
1489 /* The file does not exist */
1490 pseusers->dtable->clear(sh, pseusers->dbase);
1491 } else {
1492 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1493 retval = -1;
1494 goto cleanup;
1495 }
1496
1497 path = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA_LINKED);
1498 if (stat(path, &sb) == 0) {
1499 retval = semanage_copy_file(path,
1500 semanage_path(SEMANAGE_TMP,
1501 SEMANAGE_USERS_EXTRA),
1502 0);
1503 if (retval < 0)
1504 goto cleanup;
1505 pusers_extra->dtable->drop_cache(pusers_extra->dbase);
1506 } else if (errno == ENOENT) {
1507 /* The file does not exist */
1508 pusers_extra->dtable->clear(sh, pusers_extra->dbase);
1509 } else {
1510 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1511 retval = -1;
1512 goto cleanup;
1513 }
1514 }
1515
1516 /* Attach our databases to the policydb we just created or loaded. */
1517 dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
1518 dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
1519 dbase_policydb_attach((dbase_policydb_t *) pibpkeys->dbase, out);
1520 dbase_policydb_attach((dbase_policydb_t *) pibendports->dbase, out);
1521 dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out);
1522 dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out);
1523 dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out);
1524
1525 /* Merge local changes */
1526 retval = semanage_base_merge_components(sh);
1527 if (retval < 0)
1528 goto cleanup;
1529
1530 if (do_write_kernel) {
1531 /* Write new kernel policy. */
1532 retval = semanage_write_policydb(sh, out,
1533 SEMANAGE_STORE_KERNEL);
1534 if (retval < 0)
1535 goto cleanup;
1536
1537 /* Run the kernel policy verifier, if any. */
1538 retval = semanage_verify_kernel(sh);
1539 if (retval < 0)
1540 goto cleanup;
1541 }
1542
1543 /* ======= Post-process: Validate non-policydb components ===== */
1544
1545 /* Validate local modifications to file contexts.
1546 * Note: those are still cached, even though they've been
1547 * merged into the main file_contexts. We won't check the
1548 * large file_contexts - checked at compile time */
1549 if (do_rebuild || fcontexts_modified) {
1550 retval = semanage_fcontext_validate_local(sh, out);
1551 if (retval < 0)
1552 goto cleanup;
1553 }
1554
1555 /* Validate local seusers against policy */
1556 if (do_rebuild || seusers_modified) {
1557 retval = semanage_seuser_validate_local(sh, out);
1558 if (retval < 0)
1559 goto cleanup;
1560 }
1561
1562 /* Validate local ports for overlap */
1563 if (do_rebuild || ports_modified) {
1564 retval = semanage_port_validate_local(sh);
1565 if (retval < 0)
1566 goto cleanup;
1567 }
1568
1569 /* Validate local ibpkeys for overlap */
1570 if (do_rebuild || ibpkeys_modified) {
1571 retval = semanage_ibpkey_validate_local(sh);
1572 if (retval < 0)
1573 goto cleanup;
1574 }
1575
1576 /* Validate local ibendports */
1577 if (do_rebuild || ibendports_modified) {
1578 retval = semanage_ibendport_validate_local(sh);
1579 if (retval < 0)
1580 goto cleanup;
1581 }
1582 /* ================== Write non-policydb components ========= */
1583
1584 /* Commit changes to components */
1585 retval = semanage_commit_components(sh);
1586 if (retval < 0)
1587 goto cleanup;
1588
1589 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
1590 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL),
1591 sh->conf->file_mode);
1592 if (retval < 0) {
1593 goto cleanup;
1594 }
1595
1596 retval = copy_file_if_exists(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
1597 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL),
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),
1604 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC),
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_SEUSERS),
1611 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS),
1612 sh->conf->file_mode);
1613 if (retval < 0) {
1614 goto cleanup;
1615 }
1616
1617 /* run genhomedircon if its enabled, this should be the last operation
1618 * which requires the out policydb */
1619 if (!sh->conf->disable_genhomedircon) {
1620 if (out){
1621 if ((retval = semanage_genhomedircon(sh, out, sh->conf->usepasswd,
1622 sh->conf->ignoredirs)) != 0) {
1623 ERR(sh, "semanage_genhomedircon returned error code %d.", retval);
1624 goto cleanup;
1625 }
1626 /* file_contexts.homedirs was created in SEMANAGE_TMP store */
1627 retval = semanage_copy_file(
1628 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS),
1629 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS),
1630 sh->conf->file_mode);
1631 if (retval < 0) {
1632 goto cleanup;
1633 }
1634 }
1635 } else {
1636 WARN(sh, "WARNING: genhomedircon is disabled. \
1637 See /etc/selinux/semanage.conf if you need to enable it.");
1638 }
1639
1640 /* free out, if we don't free it before calling semanage_install_sandbox
1641 * then fork() may fail on low memory machines */
1642 sepol_policydb_free(out);
1643 out = NULL;
1644
1645 if (do_install)
1646 retval = semanage_install_sandbox(sh);
1647
1648 cleanup:
1649 for (i = 0; i < num_modinfos; i++) {
1650 semanage_module_info_destroy(sh, &modinfos[i]);
1651 }
1652 free(modinfos);
1653
1654 for (i = 0; mod_filenames != NULL && i < num_modinfos; i++) {
1655 free(mod_filenames[i]);
1656 }
1657
1658 /* Detach from policydb, so it can be freed */
1659 dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase);
1660 dbase_policydb_detach((dbase_policydb_t *) pports->dbase);
1661 dbase_policydb_detach((dbase_policydb_t *) pibpkeys->dbase);
1662 dbase_policydb_detach((dbase_policydb_t *) pibendports->dbase);
1663 dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase);
1664 dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase);
1665 dbase_policydb_detach((dbase_policydb_t *) pbools->dbase);
1666
1667 free(mod_filenames);
1668 sepol_policydb_free(out);
1669 cil_db_destroy(&cildb);
1670
1671 free(fc_buffer);
1672
1673 /* Set commit_err so other functions can detect any errors. Note that
1674 * retval > 0 will be the commit number.
1675 */
1676 if (retval < 0)
1677 sh->commit_err = retval;
1678
1679 if (semanage_remove_tmps(sh) != 0)
1680 retval = -1;
1681
1682 semanage_release_trans_lock(sh);
1683 umask(mask);
1684
1685 return retval;
1686 }
1687
1688 /* Writes a module to the sandbox's module directory, overwriting any
1689 * previous module stored within. Note that module data are not
1690 * free()d by this function; caller is responsible for deallocating it
1691 * if necessary. Returns 0 on success, -1 if out of memory, -2 if the
1692 * data does not represent a valid module file, -3 if error while
1693 * writing file. */
semanage_direct_install(semanage_handle_t * sh,char * data,size_t data_len,const char * module_name,const char * lang_ext)1694 static int semanage_direct_install(semanage_handle_t * sh,
1695 char *data, size_t data_len,
1696 const char *module_name, const char *lang_ext)
1697 {
1698 int status = 0;
1699 int ret = 0;
1700
1701 semanage_module_info_t modinfo;
1702 ret = semanage_module_info_init(sh, &modinfo);
1703 if (ret != 0) {
1704 status = -1;
1705 goto cleanup;
1706 }
1707
1708 ret = semanage_module_info_set_priority(sh, &modinfo, sh->priority);
1709 if (ret != 0) {
1710 status = -1;
1711 goto cleanup;
1712 }
1713
1714 ret = semanage_module_info_set_name(sh, &modinfo, module_name);
1715 if (ret != 0) {
1716 status = -1;
1717 goto cleanup;
1718 }
1719
1720 ret = semanage_module_info_set_lang_ext(sh, &modinfo, lang_ext);
1721 if (ret != 0) {
1722 status = -1;
1723 goto cleanup;
1724 }
1725
1726 ret = semanage_module_info_set_enabled(sh, &modinfo, -1);
1727 if (ret != 0) {
1728 status = -1;
1729 goto cleanup;
1730 }
1731
1732 status = semanage_direct_install_info(sh, &modinfo, data, data_len);
1733
1734 cleanup:
1735
1736 semanage_module_info_destroy(sh, &modinfo);
1737
1738 return status;
1739 }
1740
1741 /* Attempts to link a module to the sandbox's module directory, unlinking any
1742 * previous module stored within. Returns 0 on success, -1 if out of memory, -2 if the
1743 * data does not represent a valid module file, -3 if error while
1744 * writing file. */
1745
semanage_direct_install_file(semanage_handle_t * sh,const char * install_filename)1746 static int semanage_direct_install_file(semanage_handle_t * sh,
1747 const char *install_filename)
1748 {
1749
1750 int retval = -1;
1751 char *data = NULL;
1752 ssize_t data_len = 0;
1753 int compressed = 0;
1754 char *path = NULL;
1755 char *filename;
1756 char *lang_ext = NULL;
1757 char *module_name = NULL;
1758 char *separator;
1759 char *version = NULL;
1760
1761 if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) {
1762 ERR(sh, "Unable to read file %s\n", install_filename);
1763 retval = -1;
1764 goto cleanup;
1765 }
1766
1767 path = strdup(install_filename);
1768 if (path == NULL) {
1769 ERR(sh, "No memory available for strdup.\n");
1770 retval = -1;
1771 goto cleanup;
1772 }
1773
1774 filename = basename(path);
1775
1776 if (compressed) {
1777 separator = strrchr(filename, '.');
1778 if (separator == NULL) {
1779 ERR(sh, "Compressed module does not have a valid extension.");
1780 retval = -1;
1781 goto cleanup;
1782 }
1783 *separator = '\0';
1784 lang_ext = separator + 1;
1785 }
1786
1787 separator = strrchr(filename, '.');
1788 if (separator == NULL) {
1789 if (lang_ext == NULL) {
1790 ERR(sh, "Module does not have a valid extension.");
1791 retval = -1;
1792 goto cleanup;
1793 }
1794 } else {
1795 *separator = '\0';
1796 lang_ext = separator + 1;
1797 }
1798
1799 if (strcmp(lang_ext, "pp") == 0) {
1800 retval = parse_module_headers(sh, data, data_len, &module_name, &version);
1801 free(version);
1802 if (retval != 0)
1803 goto cleanup;
1804 }
1805
1806 if (module_name == NULL) {
1807 module_name = strdup(filename);
1808 if (module_name == NULL) {
1809 ERR(sh, "No memory available for module_name.\n");
1810 retval = -1;
1811 goto cleanup;
1812 }
1813 } else if (strcmp(module_name, filename) != 0) {
1814 fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename);
1815 }
1816
1817 retval = semanage_direct_install(sh, data, data_len, module_name, lang_ext);
1818
1819 cleanup:
1820 if (data_len > 0) munmap(data, data_len);
1821 free(module_name);
1822 free(path);
1823
1824 return retval;
1825 }
1826
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)1827 static int semanage_direct_extract(semanage_handle_t * sh,
1828 semanage_module_key_t *modkey,
1829 int extract_cil,
1830 void **mapped_data,
1831 size_t *data_len,
1832 semanage_module_info_t **modinfo)
1833 {
1834 char module_path[PATH_MAX];
1835 char input_file[PATH_MAX];
1836 enum semanage_module_path_type file_type;
1837 int rc = -1;
1838 semanage_module_info_t *_modinfo = NULL;
1839 ssize_t _data_len;
1840 char *_data;
1841 int compressed;
1842 struct stat sb;
1843
1844 /* get path of module */
1845 rc = semanage_module_get_path(
1846 sh,
1847 (const semanage_module_info_t *)modkey,
1848 SEMANAGE_MODULE_PATH_NAME,
1849 module_path,
1850 sizeof(module_path));
1851 if (rc != 0) {
1852 goto cleanup;
1853 }
1854
1855 if (stat(module_path, &sb) != 0) {
1856 ERR(sh, "Unable to access %s: %s\n", module_path, strerror(errno));
1857 rc = -1;
1858 goto cleanup;
1859 }
1860
1861 rc = semanage_module_get_module_info(sh,
1862 modkey,
1863 &_modinfo);
1864 if (rc != 0) {
1865 goto cleanup;
1866 }
1867
1868 if (extract_cil || strcmp(_modinfo->lang_ext, "cil") == 0) {
1869 file_type = SEMANAGE_MODULE_PATH_CIL;
1870 } else {
1871 file_type = SEMANAGE_MODULE_PATH_HLL;
1872 }
1873
1874 /* get path of what to extract */
1875 rc = semanage_module_get_path(
1876 sh,
1877 _modinfo,
1878 file_type,
1879 input_file,
1880 sizeof(input_file));
1881 if (rc != 0) {
1882 goto cleanup;
1883 }
1884
1885 if (extract_cil == 1 && strcmp(_modinfo->lang_ext, "cil") && stat(input_file, &sb) != 0) {
1886 if (errno != ENOENT) {
1887 ERR(sh, "Unable to access %s: %s\n", input_file, strerror(errno));
1888 rc = -1;
1889 goto cleanup;
1890 }
1891
1892 rc = semanage_compile_module(sh, _modinfo);
1893 if (rc < 0) {
1894 goto cleanup;
1895 }
1896 }
1897
1898 _data_len = map_file(sh, input_file, &_data, &compressed);
1899 if (_data_len <= 0) {
1900 ERR(sh, "Error mapping file: %s", input_file);
1901 rc = -1;
1902 goto cleanup;
1903 }
1904
1905 *modinfo = _modinfo;
1906 *data_len = (size_t)_data_len;
1907 *mapped_data = _data;
1908
1909 cleanup:
1910 if (rc != 0) {
1911 semanage_module_info_destroy(sh, _modinfo);
1912 free(_modinfo);
1913 }
1914
1915 return rc;
1916 }
1917
1918 /* Removes a module from the sandbox. Returns 0 on success, -1 if out
1919 * of memory, -2 if module not found or could not be removed. */
semanage_direct_remove(semanage_handle_t * sh,char * module_name)1920 static int semanage_direct_remove(semanage_handle_t * sh, char *module_name)
1921 {
1922 int status = 0;
1923 int ret = 0;
1924
1925 semanage_module_key_t modkey;
1926 ret = semanage_module_key_init(sh, &modkey);
1927 if (ret != 0) {
1928 status = -1;
1929 goto cleanup;
1930 }
1931
1932 ret = semanage_module_key_set_priority(sh, &modkey, sh->priority);
1933 if (ret != 0) {
1934 status = -1;
1935 goto cleanup;
1936 }
1937
1938 ret = semanage_module_key_set_name(sh, &modkey, module_name);
1939 if (ret != 0) {
1940 status = -1;
1941 goto cleanup;
1942 }
1943
1944 status = semanage_direct_remove_key(sh, &modkey);
1945
1946 cleanup:
1947 return status;
1948 }
1949
1950 /* Allocate an array of module_info structures for each readable
1951 * module within the store. Note that if the calling program has
1952 * already begun a transaction then this function will get a list of
1953 * modules within the sandbox. The caller is responsible for calling
1954 * semanage_module_info_datum_destroy() on each element of the array
1955 * as well as free()ing the entire list.
1956 */
semanage_direct_list(semanage_handle_t * sh,semanage_module_info_t ** modinfo,int * num_modules)1957 static int semanage_direct_list(semanage_handle_t * sh,
1958 semanage_module_info_t ** modinfo,
1959 int *num_modules)
1960 {
1961 int i, retval = -1;
1962 *modinfo = NULL;
1963 *num_modules = 0;
1964
1965 /* get the read lock when reading from the active
1966 (non-transaction) directory */
1967 if (!sh->is_in_transaction)
1968 if (semanage_get_active_lock(sh) < 0)
1969 return -1;
1970
1971 if (semanage_get_active_modules(sh, modinfo, num_modules) == -1) {
1972 goto cleanup;
1973 }
1974
1975 if (num_modules == 0) {
1976 retval = semanage_direct_get_serial(sh);
1977 goto cleanup;
1978 }
1979
1980 retval = semanage_direct_get_serial(sh);
1981
1982 cleanup:
1983 if (retval < 0) {
1984 for (i = 0; i < *num_modules; i++) {
1985 semanage_module_info_destroy(sh, &(*modinfo[i]));
1986 modinfo[i] = NULL;
1987 }
1988 free(*modinfo);
1989 *modinfo = NULL;
1990 }
1991
1992 if (!sh->is_in_transaction) {
1993 semanage_release_active_lock(sh);
1994 }
1995 return retval;
1996 }
1997
semanage_direct_get_enabled(semanage_handle_t * sh,const semanage_module_key_t * modkey,int * enabled)1998 static int semanage_direct_get_enabled(semanage_handle_t *sh,
1999 const semanage_module_key_t *modkey,
2000 int *enabled)
2001 {
2002 assert(sh);
2003 assert(modkey);
2004 assert(enabled);
2005
2006 int status = 0;
2007 int ret = 0;
2008
2009 char path[PATH_MAX];
2010 struct stat sb;
2011 semanage_module_info_t *modinfo = NULL;
2012
2013 /* get module info */
2014 ret = semanage_module_get_module_info(
2015 sh,
2016 modkey,
2017 &modinfo);
2018 if (ret != 0) {
2019 status = -1;
2020 goto cleanup;
2021 }
2022
2023 /* get disabled file path */
2024 ret = semanage_module_get_path(
2025 sh,
2026 modinfo,
2027 SEMANAGE_MODULE_PATH_DISABLED,
2028 path,
2029 sizeof(path));
2030 if (ret != 0) {
2031 status = -1;
2032 goto cleanup;
2033 }
2034
2035 if (stat(path, &sb) < 0) {
2036 if (errno != ENOENT) {
2037 ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
2038 status = -1;
2039 goto cleanup;
2040 }
2041
2042 *enabled = 1;
2043 }
2044 else {
2045 *enabled = 0;
2046 }
2047
2048 cleanup:
2049 semanage_module_info_destroy(sh, modinfo);
2050 free(modinfo);
2051
2052 return status;
2053 }
2054
semanage_direct_set_enabled(semanage_handle_t * sh,const semanage_module_key_t * modkey,int enabled)2055 static int semanage_direct_set_enabled(semanage_handle_t *sh,
2056 const semanage_module_key_t *modkey,
2057 int enabled)
2058 {
2059 assert(sh);
2060 assert(modkey);
2061
2062 int status = 0;
2063 int ret = 0;
2064
2065 char fn[PATH_MAX];
2066 const char *path = NULL;
2067 FILE *fp = NULL;
2068 semanage_module_info_t *modinfo = NULL;
2069 mode_t mask;
2070
2071 /* check transaction */
2072 if (!sh->is_in_transaction) {
2073 if (semanage_begin_transaction(sh) < 0) {
2074 status = -1;
2075 goto cleanup;
2076 }
2077 }
2078
2079 /* validate name */
2080 ret = semanage_module_validate_name(modkey->name);
2081 if (ret != 0) {
2082 errno = 0;
2083 ERR(sh, "Name %s is invalid.", modkey->name);
2084 status = -1;
2085 goto cleanup;
2086 }
2087
2088 /* validate enabled */
2089 ret = semanage_module_validate_enabled(enabled);
2090 if (ret != 0) {
2091 errno = 0;
2092 ERR(sh, "Enabled status %d is invalid.", enabled);
2093 status = -1;
2094 goto cleanup;
2095 }
2096
2097 /* check for disabled path, create if missing */
2098 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED);
2099
2100 ret = semanage_mkdir(sh, path);
2101 if (ret != 0) {
2102 status = -1;
2103 goto cleanup;
2104 }
2105
2106 /* get module info */
2107 ret = semanage_module_get_module_info(
2108 sh,
2109 modkey,
2110 &modinfo);
2111 if (ret != 0) {
2112 status = -1;
2113 goto cleanup;
2114 }
2115
2116 /* get module disabled file */
2117 ret = semanage_module_get_path(
2118 sh,
2119 modinfo,
2120 SEMANAGE_MODULE_PATH_DISABLED,
2121 fn,
2122 sizeof(fn));
2123 if (ret != 0) {
2124 status = -1;
2125 goto cleanup;
2126 }
2127
2128 switch (enabled) {
2129 case 0: /* disable the module */
2130 mask = umask(0077);
2131 fp = fopen(fn, "w");
2132 umask(mask);
2133
2134 if (fp == NULL) {
2135 ERR(sh,
2136 "Unable to disable module %s",
2137 modkey->name);
2138 status = -1;
2139 goto cleanup;
2140 }
2141
2142 if (fclose(fp) != 0) {
2143 ERR(sh,
2144 "Unable to close disabled file for module %s",
2145 modkey->name);
2146 status = -1;
2147 goto cleanup;
2148 }
2149
2150 fp = NULL;
2151
2152 break;
2153 case 1: /* enable the module */
2154 if (unlink(fn) < 0) {
2155 if (errno != ENOENT) {
2156 ERR(sh,
2157 "Unable to enable module %s",
2158 modkey->name);
2159 status = -1;
2160 goto cleanup;
2161 }
2162 else {
2163 /* module already enabled */
2164 errno = 0;
2165 }
2166 }
2167
2168 break;
2169 case -1: /* warn about ignored setting to default */
2170 WARN(sh,
2171 "Setting module %s to 'default' state has no effect",
2172 modkey->name);
2173 break;
2174 }
2175
2176 cleanup:
2177 semanage_module_info_destroy(sh, modinfo);
2178 free(modinfo);
2179
2180 if (fp != NULL) fclose(fp);
2181 return status;
2182 }
2183
semanage_direct_access_check(semanage_handle_t * sh)2184 int semanage_direct_access_check(semanage_handle_t * sh)
2185 {
2186 if (semanage_check_init(sh, sh->conf->store_root_path))
2187 return -1;
2188
2189 return semanage_store_access_check();
2190 }
2191
semanage_direct_mls_enabled(semanage_handle_t * sh)2192 int semanage_direct_mls_enabled(semanage_handle_t * sh)
2193 {
2194 sepol_policydb_t *p = NULL;
2195 int retval;
2196
2197 retval = sepol_policydb_create(&p);
2198 if (retval < 0)
2199 goto cleanup;
2200
2201 retval = semanage_read_policydb(sh, p, SEMANAGE_STORE_KERNEL);
2202 if (retval < 0)
2203 goto cleanup;
2204
2205 retval = sepol_policydb_mls_enabled(p);
2206 cleanup:
2207 sepol_policydb_free(p);
2208 return retval;
2209 }
2210
semanage_direct_get_module_info(semanage_handle_t * sh,const semanage_module_key_t * modkey,semanage_module_info_t ** modinfo)2211 static int semanage_direct_get_module_info(semanage_handle_t *sh,
2212 const semanage_module_key_t *modkey,
2213 semanage_module_info_t **modinfo)
2214 {
2215 assert(sh);
2216 assert(modkey);
2217 assert(modinfo);
2218
2219 int status = 0;
2220 int ret = 0;
2221
2222 char fn[PATH_MAX];
2223 FILE *fp = NULL;
2224 size_t size = 0;
2225 struct stat sb;
2226 char *tmp = NULL;
2227
2228 int i = 0;
2229
2230 semanage_module_info_t *modinfos = NULL;
2231 int modinfos_len = 0;
2232 semanage_module_info_t *highest = NULL;
2233
2234 /* check module name */
2235 ret = semanage_module_validate_name(modkey->name);
2236 if (ret < 0) {
2237 errno = 0;
2238 ERR(sh, "Name %s is invalid.", modkey->name);
2239 status = -1;
2240 goto cleanup;
2241 }
2242
2243 /* if priority == 0, then find the highest priority available */
2244 if (modkey->priority == 0) {
2245 ret = semanage_direct_list_all(sh, &modinfos, &modinfos_len);
2246 if (ret != 0) {
2247 status = -1;
2248 goto cleanup;
2249 }
2250
2251 for (i = 0; i < modinfos_len; i++) {
2252 ret = strcmp(modinfos[i].name, modkey->name);
2253 if (ret == 0) {
2254 highest = &modinfos[i];
2255 break;
2256 }
2257 }
2258
2259 if (highest == NULL) {
2260 status = -1;
2261 goto cleanup;
2262 }
2263
2264 ret = semanage_module_info_create(sh, modinfo);
2265 if (ret != 0) {
2266 status = -1;
2267 goto cleanup;
2268 }
2269
2270 ret = semanage_module_info_clone(sh, highest, *modinfo);
2271 if (ret != 0) {
2272 status = -1;
2273 }
2274
2275 /* skip to cleanup, module was found */
2276 goto cleanup;
2277 }
2278
2279 /* check module priority */
2280 ret = semanage_module_validate_priority(modkey->priority);
2281 if (ret != 0) {
2282 errno = 0;
2283 ERR(sh, "Priority %d is invalid.", modkey->priority);
2284 status = -1;
2285 goto cleanup;
2286 }
2287
2288 /* copy in key values */
2289 ret = semanage_module_info_create(sh, modinfo);
2290 if (ret != 0) {
2291 status = -1;
2292 goto cleanup;
2293 }
2294
2295 ret = semanage_module_info_set_priority(sh, *modinfo, modkey->priority);
2296 if (ret != 0) {
2297 status = -1;
2298 goto cleanup;
2299 }
2300
2301 ret = semanage_module_info_set_name(sh, *modinfo, modkey->name);
2302 if (ret != 0) {
2303 status = -1;
2304 goto cleanup;
2305 }
2306
2307 /* lookup module ext */
2308 ret = semanage_module_get_path(sh,
2309 *modinfo,
2310 SEMANAGE_MODULE_PATH_LANG_EXT,
2311 fn,
2312 sizeof(fn));
2313 if (ret != 0) {
2314 status = -1;
2315 goto cleanup;
2316 }
2317
2318 fp = fopen(fn, "r");
2319
2320 if (fp == NULL) {
2321 ERR(sh,
2322 "Unable to open %s module lang ext file at %s.",
2323 (*modinfo)->name, fn);
2324 status = -1;
2325 goto cleanup;
2326 }
2327
2328 /* set module ext */
2329 if (getline(&tmp, &size, fp) < 0) {
2330 ERR(sh,
2331 "Unable to read %s module lang ext file.",
2332 (*modinfo)->name);
2333 status = -1;
2334 goto cleanup;
2335 }
2336
2337 ret = semanage_module_info_set_lang_ext(sh, *modinfo, tmp);
2338 if (ret != 0) {
2339 status = -1;
2340 goto cleanup;
2341 }
2342 free(tmp);
2343 tmp = NULL;
2344
2345 if (fclose(fp) != 0) {
2346 ERR(sh,
2347 "Unable to close %s module lang ext file.",
2348 (*modinfo)->name);
2349 status = -1;
2350 goto cleanup;
2351 }
2352
2353 fp = NULL;
2354
2355 /* lookup enabled/disabled status */
2356 ret = semanage_module_get_path(sh,
2357 *modinfo,
2358 SEMANAGE_MODULE_PATH_DISABLED,
2359 fn,
2360 sizeof(fn));
2361 if (ret != 0) {
2362 status = -1;
2363 goto cleanup;
2364 }
2365
2366 /* set enabled/disabled status */
2367 if (stat(fn, &sb) < 0) {
2368 if (errno != ENOENT) {
2369 ERR(sh, "Unable to access %s: %s\n", fn, strerror(errno));
2370 status = -1;
2371 goto cleanup;
2372 }
2373
2374 ret = semanage_module_info_set_enabled(sh, *modinfo, 1);
2375 if (ret != 0) {
2376 status = -1;
2377 goto cleanup;
2378 }
2379 }
2380 else {
2381 ret = semanage_module_info_set_enabled(sh, *modinfo, 0);
2382 if (ret != 0) {
2383 status = -1;
2384 goto cleanup;
2385 }
2386 }
2387
2388 cleanup:
2389 free(tmp);
2390
2391 if (modinfos != NULL) {
2392 for (i = 0; i < modinfos_len; i++) {
2393 semanage_module_info_destroy(sh, &modinfos[i]);
2394 }
2395 free(modinfos);
2396 }
2397
2398 if (fp != NULL) fclose(fp);
2399 return status;
2400 }
2401
semanage_direct_set_module_info(semanage_handle_t * sh,const semanage_module_info_t * modinfo)2402 static int semanage_direct_set_module_info(semanage_handle_t *sh,
2403 const semanage_module_info_t *modinfo)
2404 {
2405 int status = 0;
2406 int ret = 0;
2407
2408 char fn[PATH_MAX];
2409 const char *path = NULL;
2410 int enabled = 0;
2411 semanage_module_info_t *modinfo_tmp = NULL;
2412
2413 semanage_module_key_t modkey;
2414 ret = semanage_module_key_init(sh, &modkey);
2415 if (ret != 0) {
2416 status = -1;
2417 goto cleanup;
2418 }
2419
2420 /* check transaction */
2421 if (!sh->is_in_transaction) {
2422 if (semanage_begin_transaction(sh) < 0) {
2423 status = -1;
2424 goto cleanup;
2425 }
2426 }
2427
2428 /* validate module */
2429 ret = semanage_module_info_validate(modinfo);
2430 if (ret != 0) {
2431 status = -1;
2432 goto cleanup;
2433 }
2434
2435 sh->modules_modified = 1;
2436
2437 /* check for modules path, create if missing */
2438 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES);
2439
2440 ret = semanage_mkdir(sh, path);
2441 if (ret != 0) {
2442 status = -1;
2443 goto cleanup;
2444 }
2445
2446 /* write priority */
2447 ret = semanage_module_get_path(sh,
2448 modinfo,
2449 SEMANAGE_MODULE_PATH_PRIORITY,
2450 fn,
2451 sizeof(fn));
2452 if (ret != 0) {
2453 status = -1;
2454 goto cleanup;
2455 }
2456
2457 ret = semanage_mkdir(sh, fn);
2458 if (ret != 0) {
2459 status = -1;
2460 goto cleanup;
2461 }
2462
2463 /* write name */
2464 ret = semanage_module_get_path(sh,
2465 modinfo,
2466 SEMANAGE_MODULE_PATH_NAME,
2467 fn,
2468 sizeof(fn));
2469 if (ret != 0) {
2470 status = -1;
2471 goto cleanup;
2472 }
2473
2474 ret = semanage_mkdir(sh, fn);
2475 if (ret != 0) {
2476 status = -1;
2477 goto cleanup;
2478 }
2479
2480 /* write ext */
2481 ret = semanage_direct_write_langext(sh, modinfo->lang_ext, modinfo);
2482 if (ret != 0) {
2483 status = -1;
2484 goto cleanup;
2485 }
2486
2487 /* write enabled/disabled status */
2488
2489 /* check for disabled path, create if missing */
2490 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED);
2491
2492 ret = semanage_mkdir(sh, path);
2493 if (ret != 0) {
2494 status = -1;
2495 goto cleanup;
2496 }
2497
2498 ret = semanage_module_get_path(sh,
2499 modinfo,
2500 SEMANAGE_MODULE_PATH_DISABLED,
2501 fn,
2502 sizeof(fn));
2503 if (ret != 0) {
2504 status = -1;
2505 goto cleanup;
2506 }
2507
2508 ret = semanage_module_key_set_name(sh, &modkey, modinfo->name);
2509 if (ret != 0) {
2510 status = -1;
2511 goto cleanup;
2512 }
2513
2514 if (modinfo->enabled == -1) {
2515 /* default to enabled */
2516 enabled = 1;
2517
2518 /* check if a module is already installed */
2519 ret = semanage_module_get_module_info(sh,
2520 &modkey,
2521 &modinfo_tmp);
2522 if (ret == 0) {
2523 /* set enabled status to current one */
2524 enabled = modinfo_tmp->enabled;
2525 }
2526 }
2527 else {
2528 enabled = modinfo->enabled;
2529 }
2530
2531 ret = semanage_module_set_enabled(sh, &modkey, enabled);
2532 if (ret != 0) {
2533 status = -1;
2534 goto cleanup;
2535 }
2536
2537 cleanup:
2538 semanage_module_key_destroy(sh, &modkey);
2539
2540 semanage_module_info_destroy(sh, modinfo_tmp);
2541 free(modinfo_tmp);
2542
2543 return status;
2544 }
2545
semanage_priorities_filename_select(const struct dirent * d)2546 static int semanage_priorities_filename_select(const struct dirent *d)
2547 {
2548 if (d->d_name[0] == '.' ||
2549 strcmp(d->d_name, "disabled") == 0)
2550 return 0;
2551 return 1;
2552 }
2553
semanage_modules_filename_select(const struct dirent * d)2554 static int semanage_modules_filename_select(const struct dirent *d)
2555 {
2556 if (d->d_name[0] == '.')
2557 return 0;
2558 return 1;
2559 }
2560
semanage_direct_list_all(semanage_handle_t * sh,semanage_module_info_t ** modinfos,int * modinfos_len)2561 static int semanage_direct_list_all(semanage_handle_t *sh,
2562 semanage_module_info_t **modinfos,
2563 int *modinfos_len)
2564 {
2565 assert(sh);
2566 assert(modinfos);
2567 assert(modinfos_len);
2568
2569 int status = 0;
2570 int ret = 0;
2571
2572 int i = 0;
2573 int j = 0;
2574
2575 *modinfos = NULL;
2576 *modinfos_len = 0;
2577 void *tmp = NULL;
2578
2579 const char *toplevel = NULL;
2580
2581 struct dirent **priorities = NULL;
2582 int priorities_len = 0;
2583 char priority_path[PATH_MAX];
2584
2585 struct dirent **modules = NULL;
2586 int modules_len = 0;
2587
2588 uint16_t priority = 0;
2589
2590 semanage_module_info_t *modinfo_tmp = NULL;
2591
2592 semanage_module_info_t modinfo;
2593 ret = semanage_module_info_init(sh, &modinfo);
2594 if (ret != 0) {
2595 status = -1;
2596 goto cleanup;
2597 }
2598
2599 if (sh->is_in_transaction) {
2600 toplevel = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES);
2601 } else {
2602 toplevel = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES);
2603 }
2604
2605 /* find priorities */
2606 priorities_len = scandir(toplevel,
2607 &priorities,
2608 semanage_priorities_filename_select,
2609 versionsort);
2610 if (priorities_len == -1) {
2611 ERR(sh, "Error while scanning directory %s.", toplevel);
2612 status = -1;
2613 goto cleanup;
2614 }
2615
2616 /* for each priority directory */
2617 /* loop through in reverse so that highest priority is first */
2618 for (i = priorities_len - 1; i >= 0; i--) {
2619 /* convert priority string to uint16_t */
2620 ret = semanage_string_to_priority(priorities[i]->d_name,
2621 &priority);
2622 if (ret != 0) {
2623 status = -1;
2624 goto cleanup;
2625 }
2626
2627 /* set our priority */
2628 ret = semanage_module_info_set_priority(sh,
2629 &modinfo,
2630 priority);
2631 if (ret != 0) {
2632 status = -1;
2633 goto cleanup;
2634 }
2635
2636 /* get the priority path */
2637 ret = semanage_module_get_path(sh,
2638 &modinfo,
2639 SEMANAGE_MODULE_PATH_PRIORITY,
2640 priority_path,
2641 sizeof(priority_path));
2642 if (ret != 0) {
2643 status = -1;
2644 goto cleanup;
2645 }
2646
2647 /* cleanup old modules */
2648 if (modules != NULL) {
2649 for (j = 0; j < modules_len; j++) {
2650 free(modules[j]);
2651 modules[j] = NULL;
2652 }
2653 free(modules);
2654 modules = NULL;
2655 modules_len = 0;
2656 }
2657
2658 /* find modules at this priority */
2659 modules_len = scandir(priority_path,
2660 &modules,
2661 semanage_modules_filename_select,
2662 versionsort);
2663 if (modules_len == -1) {
2664 ERR(sh,
2665 "Error while scanning directory %s.",
2666 priority_path);
2667 status = -1;
2668 goto cleanup;
2669 }
2670
2671 if (modules_len == 0) continue;
2672
2673 /* add space for modules */
2674 tmp = realloc(*modinfos,
2675 sizeof(semanage_module_info_t) *
2676 (*modinfos_len + modules_len));
2677 if (tmp == NULL) {
2678 ERR(sh, "Error allocating memory for module array.");
2679 status = -1;
2680 goto cleanup;
2681 }
2682 *modinfos = tmp;
2683
2684 /* for each module directory */
2685 for(j = 0; j < modules_len; j++) {
2686 /* set module name */
2687 ret = semanage_module_info_set_name(
2688 sh,
2689 &modinfo,
2690 modules[j]->d_name);
2691 if (ret != 0) {
2692 status = -1;
2693 goto cleanup;
2694 }
2695
2696 /* get module values */
2697 ret = semanage_direct_get_module_info(
2698 sh,
2699 (const semanage_module_key_t *)
2700 (&modinfo),
2701 &modinfo_tmp);
2702 if (ret != 0) {
2703 status = -1;
2704 goto cleanup;
2705 }
2706
2707 /* copy into array */
2708 ret = semanage_module_info_init(
2709 sh,
2710 &((*modinfos)[*modinfos_len]));
2711 if (ret != 0) {
2712 status = -1;
2713 goto cleanup;
2714 }
2715
2716 ret = semanage_module_info_clone(
2717 sh,
2718 modinfo_tmp,
2719 &((*modinfos)[*modinfos_len]));
2720 if (ret != 0) {
2721 status = -1;
2722 goto cleanup;
2723 }
2724
2725 semanage_module_info_destroy(sh, modinfo_tmp);
2726 free(modinfo_tmp);
2727 modinfo_tmp = NULL;
2728
2729 *modinfos_len += 1;
2730 }
2731 }
2732
2733 cleanup:
2734 semanage_module_info_destroy(sh, &modinfo);
2735
2736 if (priorities != NULL) {
2737 for (i = 0; i < priorities_len; i++) {
2738 free(priorities[i]);
2739 }
2740 free(priorities);
2741 }
2742
2743 if (modules != NULL) {
2744 for (i = 0; i < modules_len; i++) {
2745 free(modules[i]);
2746 }
2747 free(modules);
2748 }
2749
2750 semanage_module_info_destroy(sh, modinfo_tmp);
2751 free(modinfo_tmp);
2752 modinfo_tmp = NULL;
2753
2754 if (status != 0) {
2755 if (modinfos != NULL) {
2756 for (i = 0; i < *modinfos_len; i++) {
2757 semanage_module_info_destroy(
2758 sh,
2759 &(*modinfos)[i]);
2760 }
2761 free(*modinfos);
2762 *modinfos = NULL;
2763 *modinfos_len = 0;
2764 }
2765 }
2766
2767 return status;
2768 }
2769
semanage_direct_install_info(semanage_handle_t * sh,const semanage_module_info_t * modinfo,char * data,size_t data_len)2770 static int semanage_direct_install_info(semanage_handle_t *sh,
2771 const semanage_module_info_t *modinfo,
2772 char *data,
2773 size_t data_len)
2774 {
2775 assert(sh);
2776 assert(modinfo);
2777 assert(data);
2778
2779 int status = 0;
2780 int ret = 0;
2781 int type;
2782 struct stat sb;
2783
2784 char path[PATH_MAX];
2785 mode_t mask = umask(0077);
2786
2787 semanage_module_info_t *higher_info = NULL;
2788 semanage_module_key_t higher_key;
2789 ret = semanage_module_key_init(sh, &higher_key);
2790 if (ret != 0) {
2791 status = -1;
2792 goto cleanup;
2793 }
2794
2795 /* validate module info */
2796 ret = semanage_module_info_validate(modinfo);
2797 if (ret != 0) {
2798 ERR(sh, "%s failed module validation.\n", modinfo->name);
2799 status = -2;
2800 goto cleanup;
2801 }
2802
2803 /* Check for higher priority module and warn if there is one as
2804 * it will override the module currently being installed.
2805 */
2806 ret = semanage_module_key_set_name(sh, &higher_key, modinfo->name);
2807 if (ret != 0) {
2808 status = -1;
2809 goto cleanup;
2810 }
2811
2812 ret = semanage_direct_get_module_info(sh, &higher_key, &higher_info);
2813 if (ret == 0) {
2814 if (higher_info->priority > modinfo->priority) {
2815 errno = 0;
2816 WARN(sh,
2817 "A higher priority %s module exists at priority %d and will override the module currently being installed at priority %d.",
2818 modinfo->name,
2819 higher_info->priority,
2820 modinfo->priority);
2821 }
2822 else if (higher_info->priority < modinfo->priority) {
2823 errno = 0;
2824 INFO(sh,
2825 "Overriding %s module at lower priority %d with module at priority %d.",
2826 modinfo->name,
2827 higher_info->priority,
2828 modinfo->priority);
2829 }
2830
2831 if (higher_info->enabled == 0 && modinfo->enabled == -1) {
2832 errno = 0;
2833 WARN(sh,
2834 "%s module will be disabled after install as there is a disabled instance of this module present in the system.",
2835 modinfo->name);
2836 }
2837 }
2838
2839 /* set module meta data */
2840 ret = semanage_direct_set_module_info(sh, modinfo);
2841 if (ret != 0) {
2842 status = -2;
2843 goto cleanup;
2844 }
2845
2846 /* install module source file */
2847 if (!strcasecmp(modinfo->lang_ext, "cil")) {
2848 type = SEMANAGE_MODULE_PATH_CIL;
2849 } else {
2850 type = SEMANAGE_MODULE_PATH_HLL;
2851 }
2852 ret = semanage_module_get_path(
2853 sh,
2854 modinfo,
2855 type,
2856 path,
2857 sizeof(path));
2858 if (ret != 0) {
2859 status = -3;
2860 goto cleanup;
2861 }
2862
2863 ret = bzip(sh, path, data, data_len);
2864 if (ret <= 0) {
2865 ERR(sh, "Error while writing to %s.", path);
2866 status = -3;
2867 goto cleanup;
2868 }
2869
2870 /* if this is an HLL, delete the CIL cache if it exists so it will get recompiled */
2871 if (type == SEMANAGE_MODULE_PATH_HLL) {
2872 ret = semanage_module_get_path(
2873 sh,
2874 modinfo,
2875 SEMANAGE_MODULE_PATH_CIL,
2876 path,
2877 sizeof(path));
2878 if (ret != 0) {
2879 status = -3;
2880 goto cleanup;
2881 }
2882
2883 if (stat(path, &sb) == 0) {
2884 ret = unlink(path);
2885 if (ret != 0) {
2886 ERR(sh, "Error while removing cached CIL file %s: %s", path, strerror(errno));
2887 status = -3;
2888 goto cleanup;
2889 }
2890 }
2891 }
2892
2893 cleanup:
2894 semanage_module_key_destroy(sh, &higher_key);
2895 semanage_module_info_destroy(sh, higher_info);
2896 free(higher_info);
2897 umask(mask);
2898
2899 return status;
2900 }
2901
semanage_direct_remove_key(semanage_handle_t * sh,const semanage_module_key_t * modkey)2902 static int semanage_direct_remove_key(semanage_handle_t *sh,
2903 const semanage_module_key_t *modkey)
2904 {
2905 assert(sh);
2906 assert(modkey);
2907
2908 int status = 0;
2909 int ret = 0;
2910
2911 char path[PATH_MAX];
2912 semanage_module_info_t *modinfo = NULL;
2913
2914 semanage_module_key_t modkey_tmp;
2915 ret = semanage_module_key_init(sh, &modkey_tmp);
2916 if (ret != 0) {
2917 status = -1;
2918 goto cleanup;
2919 }
2920
2921 /* validate module key */
2922 ret = semanage_module_validate_priority(modkey->priority);
2923 if (ret != 0) {
2924 errno = 0;
2925 ERR(sh, "Priority %d is invalid.", modkey->priority);
2926 status = -1;
2927 goto cleanup;
2928 }
2929
2930 ret = semanage_module_validate_name(modkey->name);
2931 if (ret != 0) {
2932 errno = 0;
2933 ERR(sh, "Name %s is invalid.", modkey->name);
2934 status = -1;
2935 goto cleanup;
2936 }
2937
2938 ret = semanage_module_key_set_name(sh, &modkey_tmp, modkey->name);
2939 if (ret != 0) {
2940 status = -1;
2941 goto cleanup;
2942 }
2943
2944 /* get module path */
2945 ret = semanage_module_get_path(
2946 sh,
2947 (const semanage_module_info_t *)modkey,
2948 SEMANAGE_MODULE_PATH_NAME,
2949 path,
2950 sizeof(path));
2951 if (ret != 0) {
2952 status = -2;
2953 goto cleanup;
2954 }
2955
2956 /* remove directory */
2957 ret = semanage_remove_directory(path);
2958 if (ret != 0) {
2959 ERR(sh, "Unable to remove module %s at priority %d.", modkey->name, modkey->priority);
2960 status = -2;
2961 goto cleanup;
2962 }
2963
2964 /* check if its the last module at any priority */
2965 ret = semanage_module_get_module_info(sh, &modkey_tmp, &modinfo);
2966 if (ret != 0) {
2967 /* info that no other module will override */
2968 errno = 0;
2969 INFO(sh,
2970 "Removing last %s module (no other %s module exists at another priority).",
2971 modkey->name,
2972 modkey->name);
2973
2974 /* remove disabled status file */
2975 ret = semanage_module_get_path(
2976 sh,
2977 (const semanage_module_info_t *)modkey,
2978 SEMANAGE_MODULE_PATH_DISABLED,
2979 path,
2980 sizeof(path));
2981 if (ret != 0) {
2982 status = -1;
2983 goto cleanup;
2984 }
2985
2986 struct stat sb;
2987 if (stat(path, &sb) == 0) {
2988 ret = unlink(path);
2989 if (ret != 0) {
2990 status = -1;
2991 goto cleanup;
2992 }
2993 }
2994 }
2995 else {
2996 /* if a lower priority module is going to become active */
2997 if (modkey->priority > modinfo->priority) {
2998 /* inform what the new active module will be */
2999 errno = 0;
3000 INFO(sh,
3001 "%s module at priority %d is now active.",
3002 modinfo->name,
3003 modinfo->priority);
3004 }
3005 }
3006
3007 cleanup:
3008 semanage_module_key_destroy(sh, &modkey_tmp);
3009
3010 semanage_module_info_destroy(sh, modinfo);
3011 free(modinfo);
3012
3013 return status;
3014 }
3015
3016