#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int permanent = 0; int no_reload = 0; int verbose = 0; int setbool(char **list, size_t start, size_t end); static __attribute__((__noreturn__)) void usage(void) { fputs ("\nUsage: setsebool [ -NPV ] boolean value | bool1=val1 bool2=val2...\n\n", stderr); exit(1); } int main(int argc, char **argv) { size_t rc; int clflag; /* holds codes for command line flags */ if (argc < 2) usage(); while (1) { clflag = getopt(argc, argv, "PNV"); if (clflag == -1) break; switch (clflag) { case 'P': permanent = 1; break; case 'N': no_reload = 1; break; case 'V': verbose = 1; break; default: usage(); break; } } if (argc - optind < 1) { fprintf(stderr, "Error: boolean name required\n"); usage(); } /* Check to see which way we are being called. If a '=' is passed, we'll enforce the list syntax. If not we'll enforce the original syntax for backward compatibility. */ if (strchr(argv[optind], '=') == 0) { int len; char *bool_list[1]; if ((argc - optind) != 2) usage(); /* Add 1 for the '=' */ len = strlen(argv[optind]) + strlen(argv[optind + 1]) + 2; bool_list[0] = (char *)malloc(len); if (bool_list[0] == NULL) { fputs("Out of memory - aborting\n", stderr); return 1; } snprintf(bool_list[0], len, "%s=%s", argv[optind], argv[optind + 1]); rc = setbool(bool_list, 0, 1); free(bool_list[0]); } else rc = setbool(argv, optind, argc); return rc; } /* Apply temporal boolean changes to policy via libselinux */ static int selinux_set_boolean_list(size_t boolcnt, SELboolean * boollist) { if (security_set_boolean_list(boolcnt, boollist, 0)) { if (errno == ENOENT) fprintf(stderr, "Could not change active booleans: " "Invalid boolean\n"); else if (errno) { if (getuid() == 0) { perror("Could not change active booleans"); } else { perror("Could not change active booleans. Please try as root"); } } return -1; } return 0; } /* Apply permanent boolean changes to policy via libsemanage */ static int semanage_set_boolean_list(size_t boolcnt, SELboolean * boollist) { size_t j; semanage_handle_t *handle = NULL; semanage_bool_t *boolean = NULL; semanage_bool_key_t *bool_key = NULL; int managed; int result; int enabled = is_selinux_enabled(); handle = semanage_handle_create(); if (handle == NULL) { fprintf(stderr, "Could not create semanage library handle\n"); goto err; } if (!verbose) { semanage_msg_set_callback(handle, NULL, NULL); } managed = semanage_is_managed(handle); if (managed < 0) { fprintf(stderr, "Error when checking whether policy is managed\n"); goto err; } else if (managed == 0) { if (getuid() == 0) { fprintf(stderr, "Cannot set persistent booleans without managed policy.\n"); } else { fprintf(stderr, "Cannot set persistent booleans, please try as root.\n"); } goto err; } if (semanage_connect(handle) < 0) goto err; if (semanage_begin_transaction(handle) < 0) goto err; for (j = 0; j < boolcnt; j++) { if (semanage_bool_create(handle, &boolean) < 0) goto err; if (semanage_bool_set_name(handle, boolean, boollist[j].name) < 0) goto err; semanage_bool_set_value(boolean, boollist[j].value); if (semanage_bool_key_extract(handle, boolean, &bool_key) < 0) goto err; semanage_bool_exists(handle, bool_key, &result); if (!result) { semanage_bool_exists_local(handle, bool_key, &result); if (!result) { fprintf(stderr, "Boolean %s is not defined\n", boollist[j].name); goto err; } } if (semanage_bool_modify_local(handle, bool_key, boolean) < 0) goto err; if (enabled && semanage_bool_set_active(handle, bool_key, boolean) < 0) { fprintf(stderr, "Failed to change boolean %s: %m\n", boollist[j].name); goto err; } semanage_bool_key_free(bool_key); semanage_bool_free(boolean); bool_key = NULL; boolean = NULL; } if (no_reload) semanage_set_reload(handle, 0); if (semanage_commit(handle) < 0) { fprintf(stderr, "Failed to commit changes to booleans: %m\n"); goto err; } semanage_disconnect(handle); semanage_handle_destroy(handle); return 0; err: semanage_bool_key_free(bool_key); semanage_bool_free(boolean); semanage_handle_destroy(handle); return -1; } /* Given an array of strings in the form "boolname=value", a start index, and a finish index...walk the list and set the bool. */ int setbool(char **list, size_t start, size_t end) { char *name, *value_ptr; int j = 0, value; size_t i = start; size_t boolcnt = end - start; struct passwd *pwd; SELboolean *vallist = calloc(boolcnt, sizeof(SELboolean)); if (!vallist) goto omem; while (i < end) { name = list[i]; value_ptr = strchr(list[i], '='); if (value_ptr == NULL) { fprintf(stderr, "setsebool: '=' not found in boolean expression %s\n", list[i]); goto err; } *value_ptr = '\0'; value_ptr++; if (strcmp(value_ptr, "1") == 0 || strcasecmp(value_ptr, "true") == 0 || strcasecmp(value_ptr, "on") == 0) value = 1; else if (strcmp(value_ptr, "0") == 0 || strcasecmp(value_ptr, "false") == 0 || strcasecmp(value_ptr, "off") == 0) value = 0; else { fprintf(stderr, "setsebool: illegal value " "%s for boolean %s\n", value_ptr, name); goto err; } vallist[j].value = value; vallist[j].name = strdup(name); if (!vallist[j].name) goto omem; i++; j++; /* Now put it back */ value_ptr--; *value_ptr = '='; } if (permanent) { if (semanage_set_boolean_list(boolcnt, vallist) < 0) goto err; } else { if (selinux_set_boolean_list(boolcnt, vallist) < 0) goto err; } /* Now log what was done */ pwd = getpwuid(getuid()); i = start; while (i < end) { name = list[i]; value_ptr = strchr(name, '='); *value_ptr = '\0'; value_ptr++; if (pwd && pwd->pw_name) syslog(LOG_NOTICE, "The %s policy boolean was changed to %s by %s", name, value_ptr, pwd->pw_name); else syslog(LOG_NOTICE, "The %s policy boolean was changed to %s by uid:%d", name, value_ptr, getuid()); i++; } for (i = 0; i < boolcnt; i++) free(vallist[i].name); free(vallist); return 0; omem: fprintf(stderr, "setsebool: out of memory"); err: if (vallist) { for (i = 0; i < boolcnt; i++) free(vallist[i].name); free(vallist); } return -1; }