| /* |
| * Author: Karl MacMillan <[email protected]> |
| * |
| * Modified: |
| * Dan Walsh <[email protected]> - Added security_load_booleans(). |
| */ |
| |
| #ifndef DISABLE_BOOL |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <stdlib.h> |
| #include <dirent.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdio_ext.h> |
| #include <unistd.h> |
| #include <fnmatch.h> |
| #include <limits.h> |
| #include <ctype.h> |
| #include <errno.h> |
| |
| #include "selinux_internal.h" |
| #include "policy.h" |
| |
| #define SELINUX_BOOL_DIR "/booleans/" |
| |
| static int filename_select(const struct dirent *d) |
| { |
| if (d->d_name[0] == '.' |
| && (d->d_name[1] == '\0' |
| || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) |
| return 0; |
| return 1; |
| } |
| |
| int security_get_boolean_names(char ***names, int *len) |
| { |
| char path[PATH_MAX]; |
| int i, rc; |
| struct dirent **namelist; |
| char **n; |
| |
| if (!len || names == NULL) { |
| errno = EINVAL; |
| return -1; |
| } |
| if (!selinux_mnt) { |
| errno = ENOENT; |
| return -1; |
| } |
| |
| snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR); |
| *len = scandir(path, &namelist, &filename_select, alphasort); |
| if (*len <= 0) { |
| errno = ENOENT; |
| return -1; |
| } |
| |
| n = (char **)malloc(sizeof(char *) * *len); |
| if (!n) { |
| rc = -1; |
| goto bad; |
| } |
| |
| for (i = 0; i < *len; i++) { |
| n[i] = strdup(namelist[i]->d_name); |
| if (!n[i]) { |
| rc = -1; |
| goto bad_freen; |
| } |
| } |
| rc = 0; |
| *names = n; |
| out: |
| for (i = 0; i < *len; i++) { |
| free(namelist[i]); |
| } |
| free(namelist); |
| return rc; |
| bad_freen: |
| if (i > 0) { |
| while (i >= 1) |
| free(n[--i]); |
| } |
| free(n); |
| bad: |
| goto out; |
| } |
| |
| char *selinux_boolean_sub(const char *name) |
| { |
| char *sub = NULL; |
| char *line_buf = NULL; |
| size_t line_len; |
| FILE *cfg; |
| |
| if (!name) |
| return NULL; |
| |
| cfg = fopen(selinux_booleans_subs_path(), "re"); |
| if (!cfg) |
| goto out; |
| |
| while (getline(&line_buf, &line_len, cfg) != -1) { |
| char *ptr; |
| char *src = line_buf; |
| char *dst; |
| while (*src && isspace(*src)) |
| src++; |
| if (!*src) |
| continue; |
| if (src[0] == '#') |
| continue; |
| |
| ptr = src; |
| while (*ptr && !isspace(*ptr)) |
| ptr++; |
| *ptr++ = '\0'; |
| if (strcmp(src, name) != 0) |
| continue; |
| |
| dst = ptr; |
| while (*dst && isspace(*dst)) |
| dst++; |
| if (!*dst) |
| continue; |
| ptr = dst; |
| while (*ptr && !isspace(*ptr)) |
| ptr++; |
| *ptr = '\0'; |
| |
| if (!strchr(dst, '/')) |
| sub = strdup(dst); |
| |
| break; |
| } |
| free(line_buf); |
| fclose(cfg); |
| out: |
| if (!sub) |
| sub = strdup(name); |
| return sub; |
| } |
| |
| static int bool_open(const char *name, int flag) { |
| char *fname = NULL; |
| char *alt_name = NULL; |
| size_t len; |
| int fd = -1; |
| int ret; |
| char *ptr; |
| |
| if (!name || strchr(name, '/')) { |
| errno = EINVAL; |
| return -1; |
| } |
| |
| /* note the 'sizeof' gets us enough room for the '\0' */ |
| len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); |
| fname = malloc(sizeof(char) * len); |
| if (!fname) |
| return -1; |
| |
| ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); |
| if (ret < 0 || (size_t)ret >= len) |
| goto out; |
| |
| fd = open(fname, flag); |
| if (fd >= 0 || errno != ENOENT) |
| goto out; |
| |
| alt_name = selinux_boolean_sub(name); |
| if (!alt_name) |
| goto out; |
| |
| /* note the 'sizeof' gets us enough room for the '\0' */ |
| len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); |
| ptr = realloc(fname, len); |
| if (!ptr) |
| goto out; |
| fname = ptr; |
| |
| ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name); |
| if (ret < 0 || (size_t)ret >= len) |
| goto out; |
| |
| fd = open(fname, flag); |
| out: |
| free(fname); |
| free(alt_name); |
| |
| return fd; |
| } |
| |
| #define STRBUF_SIZE 3 |
| static int get_bool_value(const char *name, char **buf) |
| { |
| int fd, len; |
| int errno_tmp; |
| |
| if (!selinux_mnt) { |
| errno = ENOENT; |
| return -1; |
| } |
| |
| *buf = malloc(sizeof(char) * (STRBUF_SIZE + 1)); |
| if (!*buf) |
| return -1; |
| |
| (*buf)[STRBUF_SIZE] = 0; |
| |
| fd = bool_open(name, O_RDONLY | O_CLOEXEC); |
| if (fd < 0) |
| goto out_err; |
| |
| len = read(fd, *buf, STRBUF_SIZE); |
| errno_tmp = errno; |
| close(fd); |
| errno = errno_tmp; |
| if (len != STRBUF_SIZE) |
| goto out_err; |
| |
| return 0; |
| out_err: |
| free(*buf); |
| return -1; |
| } |
| |
| int security_get_boolean_pending(const char *name) |
| { |
| char *buf; |
| int val; |
| |
| if (get_bool_value(name, &buf)) |
| return -1; |
| |
| if (atoi(&buf[1])) |
| val = 1; |
| else |
| val = 0; |
| free(buf); |
| return val; |
| } |
| |
| int security_get_boolean_active(const char *name) |
| { |
| char *buf; |
| int val; |
| |
| if (get_bool_value(name, &buf)) |
| return -1; |
| |
| buf[1] = '\0'; |
| if (atoi(buf)) |
| val = 1; |
| else |
| val = 0; |
| free(buf); |
| return val; |
| } |
| |
| int security_set_boolean(const char *name, int value) |
| { |
| int fd, ret; |
| char buf[2]; |
| |
| if (!selinux_mnt) { |
| errno = ENOENT; |
| return -1; |
| } |
| if (value < 0 || value > 1) { |
| errno = EINVAL; |
| return -1; |
| } |
| |
| fd = bool_open(name, O_WRONLY | O_CLOEXEC); |
| if (fd < 0) |
| return -1; |
| |
| if (value) |
| buf[0] = '1'; |
| else |
| buf[0] = '0'; |
| buf[1] = '\0'; |
| |
| ret = write(fd, buf, 2); |
| close(fd); |
| |
| if (ret > 0) |
| return 0; |
| else |
| return -1; |
| } |
| |
| int security_commit_booleans(void) |
| { |
| int fd, ret; |
| char buf[2]; |
| char path[PATH_MAX]; |
| |
| if (!selinux_mnt) { |
| errno = ENOENT; |
| return -1; |
| } |
| |
| snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt); |
| fd = open(path, O_WRONLY | O_CLOEXEC); |
| if (fd < 0) |
| return -1; |
| |
| buf[0] = '1'; |
| buf[1] = '\0'; |
| |
| ret = write(fd, buf, 2); |
| close(fd); |
| |
| if (ret > 0) |
| return 0; |
| else |
| return -1; |
| } |
| |
| static void rollback(SELboolean * boollist, int end) |
| { |
| int i; |
| |
| for (i = 0; i < end; i++) |
| security_set_boolean(boollist[i].name, |
| security_get_boolean_active(boollist[i]. |
| name)); |
| } |
| |
| int security_set_boolean_list(size_t boolcnt, SELboolean * boollist, |
| int permanent) |
| { |
| |
| size_t i; |
| for (i = 0; i < boolcnt; i++) { |
| boollist[i].value = !!boollist[i].value; |
| if (security_set_boolean(boollist[i].name, boollist[i].value)) { |
| rollback(boollist, i); |
| return -1; |
| } |
| } |
| |
| /* OK, let's do the commit */ |
| if (security_commit_booleans()) { |
| return -1; |
| } |
| |
| /* Return error as flag no longer used */ |
| if (permanent) |
| return -1; |
| |
| return 0; |
| } |
| |
| /* This function is deprecated */ |
| int security_load_booleans(char *path __attribute__((unused))) |
| { |
| return -1; |
| } |
| #else |
| |
| #include <stdlib.h> |
| #include "selinux_internal.h" |
| |
| int security_set_boolean_list(size_t boolcnt __attribute__((unused)), |
| SELboolean * boollist __attribute__((unused)), |
| int permanent __attribute__((unused))) |
| { |
| return -1; |
| } |
| |
| int security_load_booleans(char *path __attribute__((unused))) |
| { |
| return -1; |
| } |
| |
| int security_get_boolean_names(char ***names __attribute__((unused)), |
| int *len __attribute__((unused))) |
| { |
| return -1; |
| } |
| |
| int security_get_boolean_pending(const char *name __attribute__((unused))) |
| { |
| return -1; |
| } |
| |
| int security_get_boolean_active(const char *name __attribute__((unused))) |
| { |
| return -1; |
| } |
| |
| int security_set_boolean(const char *name __attribute__((unused)), |
| int value __attribute__((unused))) |
| { |
| return -1; |
| } |
| |
| int security_commit_booleans(void) |
| { |
| return -1; |
| } |
| |
| char *selinux_boolean_sub(const char *name __attribute__((unused))) |
| { |
| return NULL; |
| } |
| #endif |
| |