From 721aa7e45ba56530c571743de4762605560f90cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Thu, 10 Jan 2019 13:26:49 +0100 Subject: [PATCH] lib: label temporary files with correct selinux context Resolves: https://github.com/pbrezina/authselect/issues/128 --- configure.ac | 1 + rpm/authselect.spec.in | 1 + src/build_macros.m4 | 13 +++ src/lib/Makefile.am | 3 + src/lib/util/selinux.c | 143 +++++++++++++++++++++++++++++ src/lib/util/{util.h => selinux.h} | 37 +++++--- src/lib/util/template.c | 16 +--- src/lib/util/util.h | 1 + 8 files changed, 192 insertions(+), 23 deletions(-) create mode 100644 src/lib/util/selinux.c copy src/lib/util/{util.h => selinux.h} (50%) diff --git a/configure.ac b/configure.ac index 0ddb875439133d10a9ece8b92a2df1719065d349..667d41c1f67264850fd9e175598214d751078a7e 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,7 @@ m4_include(external/po4a.m4) dnl Required libraries REQUIRE_POPT REQUIRE_CMOCKA +REQUIRE_SELINUX dnl Optional build dependencies - man pages generation CHECK_ASCIIDOC_TOOLS diff --git a/rpm/authselect.spec.in b/rpm/authselect.spec.in index c56ad4e2e0e23c902471fbacdb8bc3742bd8fa2d..f47c77ac3768ccf9c049c9ba512209fad059e418 100644 --- a/rpm/authselect.spec.in +++ b/rpm/authselect.spec.in @@ -24,6 +24,7 @@ BuildRequires: gettext-devel BuildRequires: po4a BuildRequires: %{_bindir}/a2x BuildRequires: libcmocka-devel >= 1.0.0 +BuildRequires: libselinux-devel Requires: authselect-libs%{?_isa} = %{version}-%{release} Suggests: sssd Suggests: samba-winbind diff --git a/src/build_macros.m4 b/src/build_macros.m4 index 5da871ec8cadfa200630420b5fe932d8af0473a3..dfedd47fd84c7201cfad30621761a3c1c564bc18 100644 --- a/src/build_macros.m4 +++ b/src/build_macros.m4 @@ -28,3 +28,16 @@ AC_DEFUN([REQUIRE_CMOCKA], ) AM_CONDITIONAL([HAVE_CMOCKA], [test x$have_cmocka = xyes]) ]) + +AC_DEFUN([REQUIRE_SELINUX], +[ + AC_CHECK_HEADERS(selinux/selinux.h, + [AC_CHECK_LIB(selinux, is_selinux_enabled, + [SELINUX_LIBS="-lselinux"], + [AC_MSG_ERROR([SELinux library is missing])] + )], + [AC_MSG_ERROR([SELinux headers are missing])] + ) + AC_SUBST(SELINUX_LIBS) +]) + diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2726062c421f7836ebc69fbbc0f5410cf3d19803..6c1191c702efbf52d45c7204311e4e9d1e64de3b 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -15,6 +15,7 @@ noinst_HEADERS = \ files/files.h \ profiles/profiles.h \ util/file.h \ + util/selinux.h \ util/string_array.h \ util/string.h \ util/template.h \ @@ -55,6 +56,7 @@ libauthselect_la_SOURCES = \ profiles/list.c \ profiles/read.c \ util/file.c \ + util/selinux.c \ util/string_array.c \ util/string.c \ util/template.c \ @@ -62,6 +64,7 @@ libauthselect_la_SOURCES = \ $(NULL) libauthselect_la_LIBADD = \ $(top_builddir)/src/common/libcommon.la \ + $(SELINUX_LIBS) \ $(NULL) libauthselect_la_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/src/lib/util/selinux.c b/src/lib/util/selinux.c new file mode 100644 index 0000000000000000000000000000000000000000..05c8d7b19b13e1eff6086faa58657c3e41a44cc0 --- /dev/null +++ b/src/lib/util/selinux.c @@ -0,0 +1,143 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2018 Red Hat + + This program 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 3 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include "common/common.h" + +errno_t +selinux_get_default_context(const char *path, + char **_context) +{ + struct selabel_handle *handle; + char *context; + errno_t ret; + + handle = selabel_open(SELABEL_CTX_FILE, NULL, 0); + if (handle == NULL) { + ret = errno; + ERROR("Unable to create selable context [%d]: %s", ret, strerror(ret)); + return ret; + } + + ret = selabel_lookup(handle, &context, path, 0); + if (ret != 0) { + ret = errno; + if (ret == ENOENT) { + return ENOENT; + } + + ERROR("Unable to lookup selinux context [%d]: %s", ret, strerror(ret)); + } else { + *_context = context; + ret = EOK; + } + + selabel_close(handle); + + return ret; +} + +errno_t +selinux_mkstemp_of(const char *filepath, + char **_tmpfile) +{ + char *original_context = NULL; + char *default_context = NULL; + char *tmpfile = NULL; + errno_t ret; + int seret; + int fd; + + seret = getfscreatecon(&original_context); + if (seret != 0) { + ERROR("Unable to get current fscreate selinux context!"); + return EIO; + } + + tmpfile = format("%s.XXXXXX", filepath); + if (tmpfile == NULL) { + ret = ENOMEM; + goto done; + } + + ret = selinux_get_default_context(filepath, &default_context); + if (ret == ENOENT) { + default_context = NULL; + } else if (ret != EOK) { + ERROR("Unable to get default selinux context for [%s] [%d]: %s!", + filepath, ret, strerror(ret)); + goto done; + } + + seret = setfscreatecon(default_context); + if (seret != 0) { + ERROR("Unable to set fscreate selinux context!"); + ret = EIO; + goto done; + } + + fd = mkstemp(tmpfile); + if (fd == -1) { + ret = errno; + + seret = setfscreatecon(original_context); + if (seret != 0) { + ERROR("Unable to restore fscreate selinux context!"); + ret = EIO; + goto done; + } + + goto done; + } + + close(fd); + + seret = setfscreatecon(original_context); + if (seret != 0) { + ERROR("Unable to restore fscreate selinux context!"); + ret = EIO; + goto done; + } + + *_tmpfile = tmpfile; + + ret = EOK; + +done: + if (original_context != NULL) { + freecon(original_context); + } + + if (default_context != NULL) { + freecon(default_context); + } + + if (ret != EOK) { + free(tmpfile); + } + + return ret; +} diff --git a/src/lib/util/util.h b/src/lib/util/selinux.h similarity index 50% copy from src/lib/util/util.h copy to src/lib/util/selinux.h index b81990722d62ccf466c0687454c82ea3ee171436..26f2374140562dd085145845ed3092a0ddcf924e 100644 --- a/src/lib/util/util.h +++ b/src/lib/util/selinux.h @@ -18,20 +18,33 @@ along with this program. If not, see . */ -#ifndef _UTIL_H_ -#define _UTIL_H_ +#ifndef _SELINUX_H_ +#define _SELINUX_H_ + +#include "common/errno_t.h" /** - * Many of the utility functions are not as effective as they can be but - * this is OK since authselect works only with small configuration files - * therefore we can prefer clean and simple code over performance. + * Get default security context for @path. + * + * @param path Path to the file. + * + * @return EOK on success, ENOENT if context was not found, other errno code + * is returned on failure. */ +errno_t +selinux_get_default_context(const char *path); -#include "common/common.h" -#include "lib/util/file.h" -#include "lib/util/string.h" -#include "lib/util/string_array.h" -#include "lib/util/template.h" -#include "lib/util/textfile.h" +/** + * Create temporary file created on @filepath.XXXXXX with security context + * set to default security context of @filepath. + * + * @param filepath File for which a temporary file should be created. + * @param _tmpfile Create temporary file. + * + * @return EOK on success, other errno code on failure. + */ +errno_t +selinux_mkstemp_of(const char *filepath, + char **_tmpfile); -#endif /* _UTIL_H_ */ +#endif /* _SELINUX_H_ */ diff --git a/src/lib/util/template.c b/src/lib/util/template.c index 0eedd2b04146f201a5c37f45c1d08f01c079d61f..9773dcbf1ecbde4fe2408f1b816dce129747806f 100644 --- a/src/lib/util/template.c +++ b/src/lib/util/template.c @@ -27,6 +27,7 @@ #include "common/common.h" #include "lib/util/template.h" #include "lib/util/textfile.h" +#include "lib/util/selinux.h" #include "lib/util/string.h" #include "lib/util/string_array.h" @@ -594,23 +595,16 @@ template_write_temporary(const char *filepath, mode_t oldmask; char *tmpfile; errno_t ret; - int fd; - - tmpfile = format("%s.XXXXXX", filepath); - if (tmpfile == NULL) { - return ENOMEM; - } oldmask = umask(mode); - fd = mkstemp(tmpfile);; - if (fd == -1) { - ret = errno; + ret = selinux_mkstemp_of(filepath, &tmpfile); + if (ret != EOK) { + ERROR("Unable to create temporary file for [%s] [%d]: %s", + filepath, ret, strerror(ret)); goto done; } - close(fd); - ret = template_write(tmpfile, content, mode); if (ret != EOK) { goto done; diff --git a/src/lib/util/util.h b/src/lib/util/util.h index b81990722d62ccf466c0687454c82ea3ee171436..e75afaef316fc8f8fd4d2aabbab7be1aa24e9ac7 100644 --- a/src/lib/util/util.h +++ b/src/lib/util/util.h @@ -29,6 +29,7 @@ #include "common/common.h" #include "lib/util/file.h" +#include "lib/util/selinux.h" #include "lib/util/string.h" #include "lib/util/string_array.h" #include "lib/util/template.h" -- 2.17.2