From 71fe21b5aeac1834df824ff5c6475e653ceb8b6b Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Wed, 4 Jan 2017 13:17:28 -0500 Subject: [PATCH] krb5-1.15-beta1-selinux-label.patch --- src/aclocal.m4 | 49 +++ src/build-tools/krb5-config.in | 3 +- src/config/pre.in | 3 +- src/configure.in | 2 + src/include/k5-int.h | 1 + src/include/k5-label.h | 32 ++ src/include/krb5/krb5.hin | 6 + src/kadmin/dbutil/dump.c | 11 +- src/kdc/main.c | 2 +- src/lib/kadm5/logger.c | 4 +- src/lib/kdb/kdb_log.c | 2 +- src/lib/krb5/ccache/cc_dir.c | 26 +- src/lib/krb5/keytab/kt_file.c | 4 +- src/lib/krb5/os/trace.c | 2 +- src/lib/krb5/rcache/rc_dfl.c | 13 + src/plugins/kdb/db2/adb_openclose.c | 2 +- src/plugins/kdb/db2/kdb_db2.c | 4 +- src/plugins/kdb/db2/libdb2/btree/bt_open.c | 3 +- src/plugins/kdb/db2/libdb2/hash/hash.c | 3 +- src/plugins/kdb/db2/libdb2/recno/rec_open.c | 4 +- .../kdb/ldap/ldap_util/kdb5_ldap_services.c | 11 +- src/slave/kpropd.c | 9 + src/util/profile/prof_file.c | 3 +- src/util/support/Makefile.in | 3 +- src/util/support/selinux.c | 406 +++++++++++++++++++++ 25 files changed, 587 insertions(+), 21 deletions(-) create mode 100644 src/include/k5-label.h create mode 100644 src/util/support/selinux.c diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 508e5fe90..607859f17 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -89,6 +89,7 @@ AC_SUBST_FILE(libnodeps_frag) dnl KRB5_AC_PRAGMA_WEAK_REF WITH_LDAP +KRB5_WITH_SELINUX KRB5_LIB_PARAMS KRB5_AC_INITFINI KRB5_AC_ENABLE_THREADS @@ -1742,3 +1743,51 @@ AC_SUBST(PAM_LIBS) AC_SUBST(PAM_MAN) AC_SUBST(NON_PAM_MAN) ])dnl +dnl +dnl Use libselinux to set file contexts on newly-created files. +dnl +AC_DEFUN(KRB5_WITH_SELINUX,[ +AC_ARG_WITH(selinux,[AC_HELP_STRING(--with-selinux,[compile with SELinux labeling support])], + withselinux="$withval",withselinux=auto) +old_LIBS="$LIBS" +if test "$withselinux" != no ; then + AC_MSG_RESULT([checking for libselinux...]) + SELINUX_LIBS= + AC_CHECK_HEADERS(selinux/selinux.h selinux/label.h) + if test "x$ac_cv_header_selinux_selinux_h" != xyes ; then + if test "$withselinux" = auto ; then + AC_MSG_RESULT([Unable to locate selinux/selinux.h.]) + withselinux=no + else + AC_MSG_ERROR([Unable to locate selinux/selinux.h.]) + fi + fi + + LIBS= + unset ac_cv_func_setfscreatecon + AC_CHECK_FUNCS(setfscreatecon selabel_open) + if test "x$ac_cv_func_setfscreatecon" = xno ; then + AC_CHECK_LIB(selinux,setfscreatecon) + unset ac_cv_func_setfscreatecon + AC_CHECK_FUNCS(setfscreatecon selabel_open) + if test "x$ac_cv_func_setfscreatecon" = xyes ; then + SELINUX_LIBS="$LIBS" + else + if test "$withselinux" = auto ; then + AC_MSG_RESULT([Unable to locate libselinux.]) + withselinux=no + else + AC_MSG_ERROR([Unable to locate libselinux.]) + fi + fi + fi + if test "$withselinux" != no ; then + AC_MSG_NOTICE([building with SELinux labeling support]) + AC_DEFINE(USE_SELINUX,1,[Define if Kerberos-aware tools should set SELinux file contexts when creating files.]) + SELINUX_LIBS="$LIBS" + EXTRA_SUPPORT_SYMS="$EXTRA_SUPPORT_SYMS krb5int_labeled_open krb5int_labeled_fopen krb5int_push_fscreatecon_for krb5int_pop_fscreatecon" + fi +fi +LIBS="$old_LIBS" +AC_SUBST(SELINUX_LIBS) +])dnl diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in index f6184da3f..c17cb5eb5 100755 --- a/src/build-tools/krb5-config.in +++ b/src/build-tools/krb5-config.in @@ -41,6 +41,7 @@ DL_LIB='@DL_LIB@' DEFCCNAME='@DEFCCNAME@' DEFKTNAME='@DEFKTNAME@' DEFCKTNAME='@DEFCKTNAME@' +SELINUX_LIBS='@SELINUX_LIBS@' LIBS='@LIBS@' GEN_LIB=@GEN_LIB@ @@ -255,7 +256,7 @@ if test -n "$do_libs"; then fi # If we ever support a flag to generate output suitable for static - # linking, we would output "-lkrb5support $GEN_LIB $LIBS $DL_LIB" + # linking, we would output "-lkrb5support $GEN_LIB $LIBS $SELINUX_LIBS $DL_LIB" # here. echo $lib_flags diff --git a/src/config/pre.in b/src/config/pre.in index e0626320c..fcea229bd 100644 --- a/src/config/pre.in +++ b/src/config/pre.in @@ -177,6 +177,7 @@ LD = $(PURE) @LD@ KRB_INCLUDES = -I$(BUILDTOP)/include -I$(top_srcdir)/include LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ +SELINUX_LIBS=@SELINUX_LIBS@ INSTALL=@INSTALL@ INSTALL_STRIP= @@ -399,7 +400,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME) # HESIOD_LIBS is -lhesiod... HESIOD_LIBS = @HESIOD_LIBS@ -KRB5_BASE_LIBS = $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_LIB) $(LIBS) $(DL_LIB) +KRB5_BASE_LIBS = $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_LIB) $(LIBS) $(SELINUX_LIBS) $(DL_LIB) KDB5_LIBS = $(KDB5_LIB) $(GSSRPC_LIBS) GSS_LIBS = $(GSS_KRB5_LIB) # needs fixing if ever used on Mac OS X! diff --git a/src/configure.in b/src/configure.in index daabd12c8..acf3a458b 100644 --- a/src/configure.in +++ b/src/configure.in @@ -1338,6 +1338,8 @@ AC_PATH_PROG(GROFF, groff) KRB5_WITH_PAM +KRB5_WITH_SELINUX + # Make localedir work in autoconf 2.5x. if test "${localedir+set}" != set; then localedir='$(datadir)/locale' diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 64991738a..173cb0264 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -128,6 +128,7 @@ typedef unsigned char u_char; #include "k5-platform.h" +#include "k5-label.h" #define KRB5_KDB_MAX_LIFE (60*60*24) /* one day */ #define KRB5_KDB_MAX_RLIFE (60*60*24*7) /* one week */ diff --git a/src/include/k5-label.h b/src/include/k5-label.h new file mode 100644 index 000000000..dfaaa847c --- /dev/null +++ b/src/include/k5-label.h @@ -0,0 +1,32 @@ +#ifndef _KRB5_LABEL_H +#define _KRB5_LABEL_H + +#ifdef THREEPARAMOPEN +#undef THREEPARAMOPEN +#endif +#ifdef WRITABLEFOPEN +#undef WRITABLEFOPEN +#endif + +/* Wrapper functions which help us create files and directories with the right + * context labels. */ +#ifdef USE_SELINUX +#include +#include +#include +#include +#include +FILE *krb5int_labeled_fopen(const char *path, const char *mode); +int krb5int_labeled_creat(const char *path, mode_t mode); +int krb5int_labeled_open(const char *path, int flags, ...); +int krb5int_labeled_mkdir(const char *path, mode_t mode); +int krb5int_labeled_mknod(const char *path, mode_t mode, dev_t device); +#define THREEPARAMOPEN(x,y,z) krb5int_labeled_open(x,y,z) +#define WRITABLEFOPEN(x,y) krb5int_labeled_fopen(x,y) +void *krb5int_push_fscreatecon_for(const char *pathname); +void krb5int_pop_fscreatecon(void *previous); +#else +#define WRITABLEFOPEN(x,y) fopen(x,y) +#define THREEPARAMOPEN(x,y,z) open(x,y,z) +#endif +#endif diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index ac22f4c55..cf60d6c41 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -87,6 +87,12 @@ #define THREEPARAMOPEN(x,y,z) open(x,y,z) #endif +#if KRB5_PRIVATE +#ifndef WRITABLEFOPEN +#define WRITABLEFOPEN(x,y) fopen(x,y) +#endif +#endif + #define KRB5_OLD_CRYPTO #include diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c index f7889bd23..cad53cfbf 100644 --- a/src/kadmin/dbutil/dump.c +++ b/src/kadmin/dbutil/dump.c @@ -148,12 +148,21 @@ create_ofile(char *ofile, char **tmpname) { int fd = -1; FILE *f; +#ifdef USE_SELINUX + void *selabel; +#endif *tmpname = NULL; if (asprintf(tmpname, "%s-XXXXXX", ofile) < 0) goto error; +#ifdef USE_SELINUX + selabel = krb5int_push_fscreatecon_for(ofile); +#endif fd = mkstemp(*tmpname); +#ifdef USE_SELINUX + krb5int_pop_fscreatecon(selabel); +#endif if (fd == -1) goto error; @@ -194,7 +203,7 @@ prep_ok_file(krb5_context context, char *file_name, int *fd) return 0; } - *fd = open(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600); + *fd = THREEPARAMOPEN(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (*fd == -1) { com_err(progname, errno, _("while creating 'ok' file, '%s'"), file_ok); exit_status++; diff --git a/src/kdc/main.c b/src/kdc/main.c index ebc852bba..a4dffb29a 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -872,7 +872,7 @@ write_pid_file(const char *path) FILE *file; unsigned long pid; - file = fopen(path, "w"); + file = WRITABLEFOPEN(path, "w"); if (file == NULL) return errno; pid = (unsigned long) getpid(); diff --git a/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c index ce79fabf7..c53a5743f 100644 --- a/src/lib/kadm5/logger.c +++ b/src/lib/kadm5/logger.c @@ -414,7 +414,7 @@ krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do */ append = (cp[4] == ':') ? O_APPEND : 0; if (append || cp[4] == '=') { - fd = open(&cp[5], O_CREAT | O_WRONLY | append, + fd = THREEPARAMOPEN(&cp[5], O_CREAT | O_WRONLY | append, S_IRUSR | S_IWUSR | S_IRGRP); if (fd != -1) f = fdopen(fd, append ? "a" : "w"); @@ -918,7 +918,7 @@ krb5_klog_reopen(krb5_context kcontext) * In case the old logfile did not get moved out of the * way, open for append to prevent squashing the old logs. */ - f = fopen(log_control.log_entries[lindex].lfu_fname, "a+"); + f = WRITABLEFOPEN(log_control.log_entries[lindex].lfu_fname, "a+"); if (f) { set_cloexec_file(f); log_control.log_entries[lindex].lfu_filep = f; diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c index 766d3002a..6466417b7 100644 --- a/src/lib/kdb/kdb_log.c +++ b/src/lib/kdb/kdb_log.c @@ -476,7 +476,7 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries) int ulogfd = -1; if (stat(logname, &st) == -1) { - ulogfd = open(logname, O_RDWR | O_CREAT, 0600); + ulogfd = THREEPARAMOPEN(logname, O_RDWR | O_CREAT, 0600); if (ulogfd == -1) return errno; diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c index bba64e516..73f0fe62d 100644 --- a/src/lib/krb5/ccache/cc_dir.c +++ b/src/lib/krb5/ccache/cc_dir.c @@ -183,10 +183,19 @@ write_primary_file(const char *primary_path, const char *contents) char *newpath = NULL; FILE *fp = NULL; int fd = -1, status; +#ifdef USE_SELINUX + void *selabel; +#endif if (asprintf(&newpath, "%s.XXXXXX", primary_path) < 0) return ENOMEM; +#ifdef USE_SELINUX + selabel = krb5int_push_fscreatecon_for(primary_path); +#endif fd = mkstemp(newpath); +#ifdef USE_SELINUX + krb5int_pop_fscreatecon(selabel); +#endif if (fd < 0) goto cleanup; #ifdef HAVE_CHMOD @@ -221,10 +230,23 @@ static krb5_error_code verify_dir(krb5_context context, const char *dirname) { struct stat st; + int status; +#ifdef USE_SELINUX + void *selabel; +#endif if (stat(dirname, &st) < 0) { - if (errno == ENOENT && mkdir(dirname, S_IRWXU) == 0) - return 0; + if (errno == ENOENT) { +#ifdef USE_SELINUX + selabel = krb5int_push_fscreatecon_for(dirname); +#endif + status = mkdir(dirname, S_IRWXU); +#ifdef USE_SELINUX + krb5int_pop_fscreatecon(selabel); +#endif + if (status == 0) + return 0; + } k5_setmsg(context, KRB5_FCC_NOFILE, _("Credential cache directory %s does not exist"), dirname); diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c index 6a42f267d..674d88bab 100644 --- a/src/lib/krb5/keytab/kt_file.c +++ b/src/lib/krb5/keytab/kt_file.c @@ -1022,14 +1022,14 @@ krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode) KTCHECKLOCK(id); errno = 0; - KTFILEP(id) = fopen(KTFILENAME(id), + KTFILEP(id) = WRITABLEFOPEN(KTFILENAME(id), (mode == KRB5_LOCKMODE_EXCLUSIVE) ? "rb+" : "rb"); if (!KTFILEP(id)) { if ((mode == KRB5_LOCKMODE_EXCLUSIVE) && (errno == ENOENT)) { /* try making it first time around */ k5_create_secure_file(context, KTFILENAME(id)); errno = 0; - KTFILEP(id) = fopen(KTFILENAME(id), "rb+"); + KTFILEP(id) = WRITABLEFOPEN(KTFILENAME(id), "rb+"); if (!KTFILEP(id)) goto report_errno; writevno = 1; diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c index 83c8d4db8..a19246128 100644 --- a/src/lib/krb5/os/trace.c +++ b/src/lib/krb5/os/trace.c @@ -397,7 +397,7 @@ krb5_set_trace_filename(krb5_context context, const char *filename) fd = malloc(sizeof(*fd)); if (fd == NULL) return ENOMEM; - *fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0600); + *fd = THREEPARAMOPEN(filename, O_WRONLY|O_CREAT|O_APPEND, 0600); if (*fd == -1) { free(fd); return errno; diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c index c4d2c744d..c0f12ed9d 100644 --- a/src/lib/krb5/rcache/rc_dfl.c +++ b/src/lib/krb5/rcache/rc_dfl.c @@ -794,6 +794,9 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id) krb5_error_code retval = 0; krb5_rcache tmp; krb5_deltat lifespan = t->lifespan; /* save original lifespan */ +#ifdef USE_SELINUX + void *selabel; +#endif if (! t->recovering) { name = t->name; @@ -815,7 +818,17 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id) retval = krb5_rc_resolve(context, tmp, 0); if (retval) goto cleanup; +#ifdef USE_SELINUX + if (t->d.fn != NULL) + selabel = krb5int_push_fscreatecon_for(t->d.fn); + else + selabel = NULL; +#endif retval = krb5_rc_initialize(context, tmp, lifespan); +#ifdef USE_SELINUX + if (selabel != NULL) + krb5int_pop_fscreatecon(selabel); +#endif if (retval) goto cleanup; for (q = t->a; q; q = q->na) { diff --git a/src/plugins/kdb/db2/adb_openclose.c b/src/plugins/kdb/db2/adb_openclose.c index 7db30a33b..2b9d01921 100644 --- a/src/plugins/kdb/db2/adb_openclose.c +++ b/src/plugins/kdb/db2/adb_openclose.c @@ -152,7 +152,7 @@ osa_adb_init_db(osa_adb_db_t *dbp, char *filename, char *lockfilename, * needs be open read/write so that write locking can work with * POSIX systems */ - if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) { + if ((lockp->lockinfo.lockfile = WRITABLEFOPEN(lockfilename, "r+")) == NULL) { /* * maybe someone took away write permission so we could only * get shared locks? diff --git a/src/plugins/kdb/db2/kdb_db2.c b/src/plugins/kdb/db2/kdb_db2.c index 4c4036eb4..d90bdeaba 100644 --- a/src/plugins/kdb/db2/kdb_db2.c +++ b/src/plugins/kdb/db2/kdb_db2.c @@ -694,8 +694,8 @@ ctx_create_db(krb5_context context, krb5_db2_context *dbc) if (retval) return retval; - dbc->db_lf_file = open(dbc->db_lf_name, O_CREAT | O_RDWR | O_TRUNC, - 0600); + dbc->db_lf_file = THREEPARAMOPEN(dbc->db_lf_name, + O_CREAT | O_RDWR | O_TRUNC, 0600); if (dbc->db_lf_file < 0) { retval = errno; goto cleanup; diff --git a/src/plugins/kdb/db2/libdb2/btree/bt_open.c b/src/plugins/kdb/db2/libdb2/btree/bt_open.c index 2977b17f3..d5809a5a9 100644 --- a/src/plugins/kdb/db2/libdb2/btree/bt_open.c +++ b/src/plugins/kdb/db2/libdb2/btree/bt_open.c @@ -60,6 +60,7 @@ static char sccsid[] = "@(#)bt_open.c 8.11 (Berkeley) 11/2/95"; #include #include +#include "k5-int.h" #include "db-int.h" #include "btree.h" @@ -203,7 +204,7 @@ __bt_open(fname, flags, mode, openinfo, dflags) goto einval; } - if ((t->bt_fd = open(fname, flags | O_BINARY, mode)) < 0) + if ((t->bt_fd = THREEPARAMOPEN(fname, flags | O_BINARY, mode)) < 0) goto err; } else { diff --git a/src/plugins/kdb/db2/libdb2/hash/hash.c b/src/plugins/kdb/db2/libdb2/hash/hash.c index 76f5d4709..1fa8b8389 100644 --- a/src/plugins/kdb/db2/libdb2/hash/hash.c +++ b/src/plugins/kdb/db2/libdb2/hash/hash.c @@ -51,6 +51,7 @@ static char sccsid[] = "@(#)hash.c 8.12 (Berkeley) 11/7/95"; #include #endif +#include "k5-int.h" #include "db-int.h" #include "hash.h" #include "page.h" @@ -140,7 +141,7 @@ __kdb2_hash_open(file, flags, mode, info, dflags) new_table = 1; } if (file) { - if ((hashp->fp = open(file, flags|O_BINARY, mode)) == -1) + if ((hashp->fp = THREEPARAMOPEN(file, flags|O_BINARY, mode)) == -1) RETURN_ERROR(errno, error0); (void)fcntl(hashp->fp, F_SETFD, 1); } diff --git a/src/plugins/kdb/db2/libdb2/recno/rec_open.c b/src/plugins/kdb/db2/libdb2/recno/rec_open.c index d8b26e701..b0daa7c02 100644 --- a/src/plugins/kdb/db2/libdb2/recno/rec_open.c +++ b/src/plugins/kdb/db2/libdb2/recno/rec_open.c @@ -51,6 +51,7 @@ static char sccsid[] = "@(#)rec_open.c 8.12 (Berkeley) 11/18/94"; #include #include +#include "k5-int.h" #include "db-int.h" #include "recno.h" @@ -68,7 +69,8 @@ __rec_open(fname, flags, mode, openinfo, dflags) int rfd = -1, sverrno; /* Open the user's file -- if this fails, we're done. */ - if (fname != NULL && (rfd = open(fname, flags | O_BINARY, mode)) < 0) + if (fname != NULL && + (rfd = THREEPARAMOPEN(fname, flags | O_BINARY, mode)) < 0) return (NULL); if (fname != NULL && fcntl(rfd, F_SETFD, 1) == -1) { diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c index 022156a5e..3d6994c67 100644 --- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c @@ -203,7 +203,7 @@ kdb5_ldap_stash_service_password(int argc, char **argv) /* set password in the file */ old_mode = umask(0177); - pfile = fopen(file_name, "a+"); + pfile = WRITABLEFOPEN(file_name, "a+"); if (pfile == NULL) { com_err(me, errno, _("Failed to open file %s: %s"), file_name, strerror (errno)); @@ -244,6 +244,9 @@ kdb5_ldap_stash_service_password(int argc, char **argv) * Delete the existing entry and add the new entry */ FILE *newfile; +#ifdef USE_SELINUX + void *selabel; +#endif mode_t omask; @@ -255,7 +258,13 @@ kdb5_ldap_stash_service_password(int argc, char **argv) } omask = umask(077); +#ifdef USE_SELINUX + selabel = krb5int_push_fscreatecon_for(file_name); +#endif newfile = fopen(tmp_file, "w"); +#ifdef USE_SELINUX + krb5int_pop_fscreatecon(selabel); +#endif umask (omask); if (newfile == NULL) { com_err(me, errno, _("Error creating file %s"), tmp_file); diff --git a/src/slave/kpropd.c b/src/slave/kpropd.c index 056c31a42..b78c3d9e5 100644 --- a/src/slave/kpropd.c +++ b/src/slave/kpropd.c @@ -464,6 +464,9 @@ doit(int fd) krb5_enctype etype; int database_fd; char host[INET6_ADDRSTRLEN + 1]; +#ifdef USE_SELINUX + void *selabel; +#endif signal_wrapper(SIGALRM, alarm_handler); alarm(params.iprop_resync_timeout); @@ -520,9 +523,15 @@ doit(int fd) free(name); exit(1); } +#ifdef USE_SELINUX + selabel = krb5int_push_fscreatecon_for(file); +#endif omask = umask(077); lock_fd = open(temp_file_name, O_RDWR | O_CREAT, 0600); (void)umask(omask); +#ifdef USE_SELINUX + krb5int_pop_fscreatecon(selabel); +#endif retval = krb5_lock_file(kpropd_context, lock_fd, KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK); if (retval) { diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c index 907c119bb..0f5462aea 100644 --- a/src/util/profile/prof_file.c +++ b/src/util/profile/prof_file.c @@ -33,6 +33,7 @@ #endif #include "k5-platform.h" +#include "k5-label.h" struct global_shared_profile_data { /* This is the head of the global list of shared trees */ @@ -423,7 +424,7 @@ static errcode_t write_data_to_file(prf_data_t data, const char *outfile, errno = 0; - f = fopen(new_file, "w"); + f = WRITABLEFOPEN(new_file, "w"); if (!f) { retval = errno; if (retval == 0) diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in index 6239e4176..17bcd2a67 100644 --- a/src/util/support/Makefile.in +++ b/src/util/support/Makefile.in @@ -69,6 +69,7 @@ IPC_SYMS= \ STLIBOBJS= \ threads.o \ + selinux.o \ init-addrinfo.o \ plugins.o \ errors.o \ @@ -148,7 +149,7 @@ SRCS=\ SHLIB_EXPDEPS = # Add -lm if dumping thread stats, for sqrt. -SHLIB_EXPLIBS= $(LIBS) $(DL_LIB) +SHLIB_EXPLIBS= $(LIBS) $(SELINUX_LIBS) $(DL_LIB) DEPLIBS= diff --git a/src/util/support/selinux.c b/src/util/support/selinux.c new file mode 100644 index 000000000..230263421 --- /dev/null +++ b/src/util/support/selinux.c @@ -0,0 +1,406 @@ +/* + * Copyright 2007,2008,2009,2011,2012,2013,2016 Red Hat, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Red Hat, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * File-opening wrappers for creating correctly-labeled files. So far, we can + * assume that this is Linux-specific, so we make many simplifying assumptions. + */ + +#include "../../include/autoconf.h" + +#ifdef USE_SELINUX + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* #define DEBUG 1 */ +static void +debug_log(const char *fmt, ...) +{ +#ifdef DEBUG + va_list ap; + va_start(ap, str); + if (isatty(fileno(stderr))) { + vfprintf(stderr, fmt, ap); + } + va_end(ap); +#endif + + return; +} + +/* Mutex used to serialize use of the process-global file creation context. */ +k5_mutex_t labeled_mutex = K5_MUTEX_PARTIAL_INITIALIZER; + +/* Make sure we finish initializing that mutex before attempting to use it. */ +k5_once_t labeled_once = K5_ONCE_INIT; +static void +label_mutex_init(void) +{ + k5_mutex_finish_init(&labeled_mutex); +} + +static struct selabel_handle *selabel_ctx; +static time_t selabel_last_changed; + +MAKE_FINI_FUNCTION(cleanup_fscreatecon); + +static void +cleanup_fscreatecon(void) +{ + if (selabel_ctx != NULL) { + selabel_close(selabel_ctx); + selabel_ctx = NULL; + } +} + +static security_context_t +push_fscreatecon(const char *pathname, mode_t mode) +{ + security_context_t previous, configuredsc, currentsc, derivedsc; + context_t current, derived; + const char *fullpath, *currentuser; + char *genpath; + + previous = configuredsc = currentsc = derivedsc = NULL; + current = derived = NULL; + genpath = NULL; + + fullpath = pathname; + + if (!is_selinux_enabled()) { + goto fail; + } + + if (getfscreatecon(&previous) != 0) { + goto fail; + } + + /* Canonicalize pathname */ + if (pathname[0] != '/') { + char *wd; + size_t len; + len = 0; + + wd = getcwd(NULL, len); + if (wd == NULL) { + goto fail; + } + + len = strlen(wd) + 1 + strlen(pathname) + 1; + genpath = malloc(len); + if (genpath == NULL) { + free(wd); + goto fail; + } + + sprintf(genpath, "%s/%s", wd, pathname); + free(wd); + fullpath = genpath; + } + + debug_log("Looking up context for \"%s\"(%05o).\n", fullpath, mode); + + /* Check whether context file has changed under us */ + if (selabel_ctx != NULL || selabel_last_changed == 0) { + const char *cpath; + struct stat st; + int i = -1; + + cpath = selinux_file_context_path(); + if (cpath == NULL || (i = stat(cpath, &st)) != 0 || + st.st_mtime != selabel_last_changed) { + cleanup_fscreatecon(); + + selabel_last_changed = i ? time(NULL) : st.st_mtime; + } + } + + if (selabel_ctx == NULL) { + selabel_ctx = selabel_open(SELABEL_CTX_FILE, NULL, 0); + } + + if (selabel_ctx != NULL && + selabel_lookup(selabel_ctx, &configuredsc, fullpath, mode) != 0) { + goto fail; + } + + if (genpath != NULL) { + free(genpath); + genpath = NULL; + } + + if (configuredsc == NULL) { + goto fail; + } + + getcon(¤tsc); + + /* AAAAAAAA */ + if (currentsc != NULL) { + derived = context_new(configuredsc); + + if (derived != NULL) { + current = context_new(currentsc); + + if (current != NULL) { + currentuser = context_user_get(current); + + if (currentuser != NULL) { + if (context_user_set(derived, + currentuser) == 0) { + derivedsc = context_str(derived); + + if (derivedsc != NULL) { + freecon(configuredsc); + configuredsc = strdup(derivedsc); + } + } + } + + context_free(current); + } + + context_free(derived); + } + + freecon(currentsc); + } + + debug_log("Setting file creation context to \"%s\".\n", configuredsc); + if (setfscreatecon(configuredsc) != 0) { + debug_log("Unable to determine current context.\n"); + goto fail; + } + + freecon(configuredsc); + return previous; + +fail: + if (previous != NULL) { + freecon(previous); + } + if (genpath != NULL) { + free(genpath); + } + if (configuredsc != NULL) { + freecon(configuredsc); + } + + cleanup_fscreatecon(); + return NULL; +} + +static void +pop_fscreatecon(security_context_t previous) +{ + if (!is_selinux_enabled()) { + return; + } + + if (previous != NULL) { + debug_log("Resetting file creation context to \"%s\".\n", previous); + } else { + debug_log("Resetting file creation context to default.\n"); + } + + /* NULL resets to default */ + setfscreatecon(previous); + + if (previous != NULL) { + freecon(previous); + } + + /* Need to clean this up here otherwise it leaks */ + cleanup_fscreatecon(); +} + +void * +krb5int_push_fscreatecon_for(const char *pathname) +{ + struct stat st; + void *retval; + + k5_once(&labeled_once, label_mutex_init); + k5_mutex_lock(&labeled_mutex); + + if (stat(pathname, &st) != 0) { + st.st_mode = S_IRUSR | S_IWUSR; + } + + retval = push_fscreatecon(pathname, st.st_mode); + return retval ? retval : (void *) -1; +} + +void +krb5int_pop_fscreatecon(void *con) +{ + if (con != NULL) { + pop_fscreatecon((con == (void *) -1) ? NULL : con); + k5_mutex_unlock(&labeled_mutex); + } +} + +FILE * +krb5int_labeled_fopen(const char *path, const char *mode) +{ + FILE *fp; + int errno_save; + security_context_t ctx; + + if ((strcmp(mode, "r") == 0) || + (strcmp(mode, "rb") == 0)) { + return fopen(path, mode); + } + + k5_once(&labeled_once, label_mutex_init); + k5_mutex_lock(&labeled_mutex); + ctx = push_fscreatecon(path, 0); + + fp = fopen(path, mode); + errno_save = errno; + + pop_fscreatecon(ctx); + k5_mutex_unlock(&labeled_mutex); + + errno = errno_save; + return fp; +} + +int +krb5int_labeled_creat(const char *path, mode_t mode) +{ + int fd; + int errno_save; + security_context_t ctx; + + k5_once(&labeled_once, label_mutex_init); + k5_mutex_lock(&labeled_mutex); + ctx = push_fscreatecon(path, 0); + + fd = creat(path, mode); + errno_save = errno; + + pop_fscreatecon(ctx); + k5_mutex_unlock(&labeled_mutex); + + errno = errno_save; + return fd; +} + +int +krb5int_labeled_mknod(const char *path, mode_t mode, dev_t dev) +{ + int ret; + int errno_save; + security_context_t ctx; + + k5_once(&labeled_once, label_mutex_init); + k5_mutex_lock(&labeled_mutex); + ctx = push_fscreatecon(path, mode); + + ret = mknod(path, mode, dev); + errno_save = errno; + + pop_fscreatecon(ctx); + k5_mutex_unlock(&labeled_mutex); + + errno = errno_save; + return ret; +} + +int +krb5int_labeled_mkdir(const char *path, mode_t mode) +{ + int ret; + int errno_save; + security_context_t ctx; + + k5_once(&labeled_once, label_mutex_init); + k5_mutex_lock(&labeled_mutex); + ctx = push_fscreatecon(path, S_IFDIR); + + ret = mkdir(path, mode); + errno_save = errno; + + pop_fscreatecon(ctx); + k5_mutex_unlock(&labeled_mutex); + + errno = errno_save; + return ret; +} + +int +krb5int_labeled_open(const char *path, int flags, ...) +{ + int fd; + int errno_save; + security_context_t ctx; + mode_t mode; + va_list ap; + + if ((flags & O_CREAT) == 0) { + return open(path, flags); + } + + k5_once(&labeled_once, label_mutex_init); + k5_mutex_lock(&labeled_mutex); + ctx = push_fscreatecon(path, 0); + + va_start(ap, flags); + mode = va_arg(ap, mode_t); + fd = open(path, flags, mode); + va_end(ap); + + errno_save = errno; + + pop_fscreatecon(ctx); + k5_mutex_unlock(&labeled_mutex); + + errno = errno_save; + return fd; +} + +#endif /* USE_SELINUX */