From: Lennart Poettering Date: Wed, 11 Aug 2010 20:58:34 +0000 (+0200) Subject: selinux: split off selinux calls into seperate file label.c X-Git-Tag: v8~119 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=e51bc1a23e8f581e4fe46aa4df1bd93b7042c184 selinux: split off selinux calls into seperate file label.c --- diff --git a/Makefile.am b/Makefile.am index 038b72e1e..abd07eb7e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -240,6 +240,7 @@ noinst_LTLIBRARIES = \ libsystemd_basic_la_SOURCES = \ src/util.c \ + src/label.c \ src/hashmap.c \ src/set.c \ src/strv.c \ diff --git a/fixme b/fixme index 20a95cbc4..02e80e883 100644 --- a/fixme +++ b/fixme @@ -85,6 +85,8 @@ * plymouth different shut down msgs +* fix nscd disable + External: * sysv functions should color when stdout is tty, not stdin diff --git a/src/automount.c b/src/automount.c index 047af7759..f81d5a2c7 100644 --- a/src/automount.c +++ b/src/automount.c @@ -37,6 +37,7 @@ #include "dbus-automount.h" #include "bus-errors.h" #include "special.h" +#include "label.h" static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { [AUTOMOUNT_DEAD] = UNIT_INACTIVE, diff --git a/src/label.c b/src/label.c new file mode 100644 index 000000000..d18e5dc7b --- /dev/null +++ b/src/label.c @@ -0,0 +1,291 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "label.h" +#include "util.h" + +#ifdef HAVE_SELINUX +#include +#include + +static struct selabel_handle *label_hnd = NULL; + +static inline bool use_selinux(void) { + static int use_selinux_ind = -1; + + if (use_selinux_ind < 0) + use_selinux_ind = is_selinux_enabled() > 0; + + return use_selinux_ind; +} + +static int label_get_file_label_from_path( + const char *label, + const char *path, + const char *class, + security_context_t *fcon) { + + security_context_t dir_con = NULL; + security_class_t sclass; + int r = 0; + + r = getfilecon(path, &dir_con); + if (r >= 0) { + r = -1; + errno = EINVAL; + + if ((sclass = string_to_security_class(class)) != 0) + r = security_compute_create((security_context_t) label, dir_con, sclass, fcon); + } + if (r < 0) + r = -errno; + + freecon(dir_con); + return r; +} + +#endif + +int label_init(void) { + int r = 0; + +#ifdef HAVE_SELINUX + + if (!use_selinux()) + return 0; + + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + if (!label_hnd) { + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, + "Failed to initialize SELinux context: %m"); + r = (security_getenforce() == 1) ? -errno : 0; + } +#endif + + return r; +} + +int label_fix(const char *path) { + int r = 0; + +#ifdef HAVE_SELINUX + struct stat st; + security_context_t fcon; + + if (!use_selinux() || !label_hnd) + return 0; + + r = lstat(path, &st); + if (r == 0) { + r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); + + if (r == 0) { + r = setfilecon(path, fcon); + freecon(fcon); + } + } + if (r < 0) { + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, + "Unable to fix label of %s: %m", path); + r = (security_getenforce() == 1) ? -errno : 0; + } +#endif + + return r; +} + +void label_finish(void) { + +#ifdef HAVE_SELINUX + if (use_selinux() && label_hnd) + selabel_close(label_hnd); +#endif +} + +int label_get_socket_label_from_exe(const char *exe, char **label) { + + int r = 0; + +#ifdef HAVE_SELINUX + security_context_t mycon = NULL, fcon = NULL; + security_class_t sclass; + + if (!use_selinux()) { + *label = NULL; + return 0; + } + + r = getcon(&mycon); + if (r < 0) + goto fail; + + r = getfilecon(exe, &fcon); + if (r < 0) + goto fail; + + sclass = string_to_security_class("process"); + r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + if (r == 0) + log_debug("SELinux Socket context for %s will be set to %s", exe, *label); + +fail: + if (r < 0 && security_getenforce() == 1) + r = -errno; + + freecon(mycon); + freecon(fcon); +#endif + + return r; +} + +int label_fifofile_set(const char *label, const char *path) { + int r = 0; + +#ifdef HAVE_SELINUX + security_context_t filecon = NULL; + + if (!use_selinux() || !label) + return 0; + + if (((r = label_get_file_label_from_path(label, path, "fifo_file", &filecon)) == 0)) { + if ((r = setfscreatecon(filecon)) < 0) { + log_error("Failed to set SELinux file context (%s) on %s: %m", label, path); + r = -errno; + } + + freecon(filecon); + } + + if (r < 0 && security_getenforce() == 0) + r = 0; +#endif + + return r; +} + +int label_socket_set(const char *label) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return 0; + + if (setsockcreatecon((security_context_t) label) < 0) { + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, + "Failed to set SELinux context (%s) on socket: %m", label); + + if (security_getenforce() == 1) + return -errno; + } +#endif + + return 0; +} + +void label_file_clear(void) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return; + + setfscreatecon(NULL); +#endif +} + +void label_socket_clear(void) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return; + + setsockcreatecon(NULL); +#endif +} + +void label_free(const char *label) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return; + + freecon((security_context_t) label); +#endif +} + +int label_mkdir( + const char *path, + mode_t mode) { + + /* Creates a directory and labels it according to the SELinux policy */ + +#ifdef HAVE_SELINUX + int r; + security_context_t fcon = NULL; + + if (use_selinux() && label_hnd) { + + if (path[0] == '/') + r = selabel_lookup_raw(label_hnd, &fcon, path, mode); + else { + char *cwd = NULL, *newpath = NULL; + + cwd = get_current_dir_name(); + + if (cwd || asprintf(&newpath, "%s/%s", cwd, path) < 0) { + free(cwd); + return -errno; + } + + r = selabel_lookup_raw(label_hnd, &fcon, newpath, mode); + free(cwd); + free(newpath); + } + + if (r == 0) + r = setfscreatecon(fcon); + + if (r < 0 && errno != ENOENT) { + log_error("Failed to set security context %s for %s: %m", fcon, path); + r = -errno; + + if (security_getenforce() == 1) + goto finish; + } + } + + if ((r = mkdir(path, mode)) < 0) + r = -errno; + +finish: + if (use_selinux() && label_hnd) { + setfscreatecon(NULL); + freecon(fcon); + } + + return r; +#else + return mkdir(path, mode); +#endif +} diff --git a/src/label.h b/src/label.h new file mode 100644 index 000000000..5a3c9d109 --- /dev/null +++ b/src/label.h @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foolabelhfoo +#define foolabelhfoo + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include + +int label_init(void); +void label_finish(void); + +int label_fix(const char *path); + +int label_socket_set(const char *label); +void label_socket_clear(void); + +int label_fifofile_set(const char *label, const char *path); +void label_file_clear(void); + +void label_free(const char *label); + +int label_get_socket_label_from_exe(const char *exe, char **label); + +int label_mkdir(const char *path, mode_t mode); + +#endif diff --git a/src/main.c b/src/main.c index 3810033fb..72015bc54 100644 --- a/src/main.c +++ b/src/main.c @@ -45,6 +45,7 @@ #include "conf-parser.h" #include "bus-errors.h" #include "missing.h" +#include "label.h" static enum { ACTION_RUN, diff --git a/src/socket-util.c b/src/socket-util.c index 2af856396..ea2171b5b 100644 --- a/src/socket-util.c +++ b/src/socket-util.c @@ -34,6 +34,7 @@ #include "util.h" #include "socket-util.h" #include "missing.h" +#include "label.h" int socket_address_parse(SocketAddress *a, const char *s) { int r; diff --git a/src/socket.c b/src/socket.c index 5132f8e70..d76a81ff9 100644 --- a/src/socket.c +++ b/src/socket.c @@ -40,6 +40,7 @@ #include "missing.h" #include "special.h" #include "bus-errors.h" +#include "label.h" static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_DEAD] = UNIT_INACTIVE, diff --git a/src/util.c b/src/util.c index a2def2873..4e371d148 100644 --- a/src/util.c +++ b/src/util.c @@ -55,263 +55,7 @@ #include "missing.h" #include "log.h" #include "strv.h" - -#ifdef HAVE_SELINUX -#include -#include - -static struct selabel_handle *label_hnd = NULL; - -static inline bool use_selinux(void) { - static int use_selinux_ind = -1; - - if (use_selinux_ind < 0) - use_selinux_ind = is_selinux_enabled() > 0; - - return use_selinux_ind; -} - -static int label_get_file_label_from_path( - const char *label, - const char *path, - const char *class, - security_context_t *fcon) { - - security_context_t dir_con = NULL; - security_class_t sclass; - int r = 0; - - r = getfilecon(path, &dir_con); - if (r >= 0) { - r = -1; - errno = EINVAL; - - if ((sclass = string_to_security_class(class)) != 0) - r = security_compute_create((security_context_t) label, dir_con, sclass, fcon); - } - if (r < 0) - r = -errno; - - freecon(dir_con); - return r; -} - -#endif - -int label_init(void) { - int r = 0; - -#ifdef HAVE_SELINUX - - if (!use_selinux()) - return 0; - - label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); - if (!label_hnd) { - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Failed to initialize SELinux context: %m"); - r = (security_getenforce() == 1) ? -errno : 0; - } -#endif - - return r; -} - -int label_fix(const char *path) { - int r = 0; - -#ifdef HAVE_SELINUX - struct stat st; - security_context_t fcon; - - if (!use_selinux() || !label_hnd) - return 0; - - r = lstat(path, &st); - if (r == 0) { - r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); - - if (r == 0) { - r = setfilecon(path, fcon); - freecon(fcon); - } - } - if (r < 0) { - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Unable to fix label of %s: %m", path); - r = (security_getenforce() == 1) ? -errno : 0; - } -#endif - - return r; -} - -void label_finish(void) { - -#ifdef HAVE_SELINUX - if (use_selinux() && label_hnd) - selabel_close(label_hnd); -#endif -} - -int label_get_socket_label_from_exe(const char *exe, char **label) { - - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t mycon = NULL, fcon = NULL; - security_class_t sclass; - - if (!use_selinux()) { - *label = NULL; - return 0; - } - - r = getcon(&mycon); - if (r < 0) - goto fail; - - r = getfilecon(exe, &fcon); - if (r < 0) - goto fail; - - sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); - if (r == 0) - log_debug("SELinux Socket context for %s will be set to %s", exe, *label); - -fail: - if (r < 0 && security_getenforce() == 1) - r = -errno; - - freecon(mycon); - freecon(fcon); -#endif - - return r; -} - -int label_fifofile_set(const char *label, const char *path) { - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t filecon = NULL; - - if (!use_selinux() || !label) - return 0; - - if (((r = label_get_file_label_from_path(label, path, "fifo_file", &filecon)) == 0)) { - if ((r = setfscreatecon(filecon)) < 0) { - log_error("Failed to set SELinux file context (%s) on %s: %m", label, path); - r = -errno; - } - - freecon(filecon); - } - - if (r < 0 && security_getenforce() == 0) - r = 0; -#endif - - return r; -} - -int label_socket_set(const char *label) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return 0; - - if (setsockcreatecon((security_context_t) label) < 0) { - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Failed to set SELinux context (%s) on socket: %m", label); - - if (security_getenforce() == 1) - return -errno; - } -#endif - - return 0; -} - -void label_file_clear(void) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - setfscreatecon(NULL); -#endif -} - -void label_socket_clear(void) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - setsockcreatecon(NULL); -#endif -} - -void label_free(const char *label) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - freecon((security_context_t) label); -#endif -} - -static int label_mkdir( - const char *path, - mode_t mode) { - -#ifdef HAVE_SELINUX - int r; - security_context_t fcon = NULL; - - if (use_selinux() && label_hnd) { - if (path[0] == '/') { - r = selabel_lookup_raw(label_hnd, &fcon, path, mode); - } - else { - char *cwd = NULL; - char *newpath = NULL; - cwd = getcwd(NULL,0); - if ((! cwd) || (asprintf(&newpath, "%s/%s",cwd,path) < 0)) { - free(cwd); - return -errno; - } - r = selabel_lookup_raw(label_hnd, &fcon, newpath, mode); - free(cwd); - free(newpath); - } - - if (r == 0) - r = setfscreatecon(fcon); - - if ((r < 0) && (errno != ENOENT)) { - log_error("Failed to set security context %s for %s", fcon, path); - - if (security_getenforce() == 1) - goto finish; - } - } - r = mkdir(path, mode); - -finish: - if (use_selinux() && label_hnd) { - setfscreatecon(NULL); - freecon(fcon); - } - - return r; -#else - return mkdir(path, mode); -#endif -} +#include "label.h" bool streq_ptr(const char *a, const char *b) { diff --git a/src/util.h b/src/util.h index d08c7b0e7..b2a292560 100644 --- a/src/util.h +++ b/src/util.h @@ -361,14 +361,4 @@ int ip_tos_from_string(const char *s); const char *signal_to_string(int i); int signal_from_string(const char *s); -int label_init(void); -int label_fix(const char *path); -void label_finish(void); -int label_socket_set(const char *label); -void label_socket_clear(void); -int label_fifofile_set(const char *label, const char *path); -void label_file_clear(void); -void label_free(const char *label); -int label_get_socket_label_from_exe(const char *exe, char **label); - #endif