/* * Author: Karl MacMillan * * Modified: * Dan Walsh - Added security_load_booleans(). */ #ifndef DISABLE_BOOL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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'; 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; int len; int fd = -1; int ret; char *ptr; if (!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) goto out; assert(ret < len); 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) goto out; assert(ret < len); 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 #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