Sophie

Sophie

distrib > Mageia > 6 > armv7hl > by-pkgid > 46b27cf721b9554b67d1e715e2360013 > files > 24

krb5-1.15.1-2.1.mga6.src.rpm

From 6d95fa032279ef3a53348243c9d0d4b9233761db Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:30:53 -0400
Subject: [PATCH] krb5-1.15-beta1-selinux-label.patch

SELinux bases access to files on the domain of the requesting process,
the operation being performed, and the context applied to the file.

In many cases, applications needn't be SELinux aware to work properly,
because SELinux can apply a default label to a file based on the label
of the directory in which it's created.

In the case of files such as /etc/krb5.keytab, however, this isn't
sufficient, as /etc/krb5.keytab will almost always need to be given a
label which differs from that of /etc/issue or /etc/resolv.conf.  The
the kdb stash file needs a different label than the database for which
it's holding a master key, even though both typically live in the same
directory.

To give the file the correct label, we can either force a "restorecon"
call to fix a file's label after it's created, or create the file with
the right label, as we attempt to do here.  We lean on THREEPARAMOPEN
and define a similar macro named WRITABLEFOPEN with which we replace
several uses of fopen().

The file creation context that we're manipulating here is a process-wide
attribute.  While for the most part, applications which need to label
files when they're created have tended to be single-threaded, there's
not much we can do to avoid interfering with an application that
manipulates the creation context directly.  Right now we're mediating
access using a library-local mutex, but that can only work for consumers
that are part of this package -- an unsuspecting application will still
stomp all over us.

The selabel APIs for looking up the context should be thread-safe (per
Red Hat #273081), so switching to using them instead of matchpathcon(),
which we used earlier, is some improvement.
---
 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+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 <stdlib.h>
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 <string.h>
 #include <unistd.h>
 
+#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 <assert.h>
 #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 <stdio.h>
 #include <unistd.h>
 
+#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 <k5-label.h>
+#include <k5-platform.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <selinux/label.h>
+
+/* #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(&currentsc);
+
+    /* 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 */