Blame SOURCES/krb5-1.17-beta1-selinux-label.patch

db6389
From 46946e305e4536a56866ff21ac1f6e8ed7c3b814 Mon Sep 17 00:00:00 2001
db6389
From: Robbie Harwood <rharwood@redhat.com>
db6389
Date: Tue, 23 Aug 2016 16:30:53 -0400
db6389
Subject: [PATCH] krb5-1.17-beta1-selinux-label.patch
db6389
db6389
SELinux bases access to files on the domain of the requesting process,
db6389
the operation being performed, and the context applied to the file.
db6389
db6389
In many cases, applications needn't be SELinux aware to work properly,
db6389
because SELinux can apply a default label to a file based on the label
db6389
of the directory in which it's created.
db6389
db6389
In the case of files such as /etc/krb5.keytab, however, this isn't
db6389
sufficient, as /etc/krb5.keytab will almost always need to be given a
db6389
label which differs from that of /etc/issue or /etc/resolv.conf.  The
db6389
the kdb stash file needs a different label than the database for which
db6389
it's holding a master key, even though both typically live in the same
db6389
directory.
db6389
db6389
To give the file the correct label, we can either force a "restorecon"
db6389
call to fix a file's label after it's created, or create the file with
db6389
the right label, as we attempt to do here.  We lean on THREEPARAMOPEN
db6389
and define a similar macro named WRITABLEFOPEN with which we replace
db6389
several uses of fopen().
db6389
db6389
The file creation context that we're manipulating here is a process-wide
db6389
attribute.  While for the most part, applications which need to label
db6389
files when they're created have tended to be single-threaded, there's
db6389
not much we can do to avoid interfering with an application that
db6389
manipulates the creation context directly.  Right now we're mediating
db6389
access using a library-local mutex, but that can only work for consumers
db6389
that are part of this package -- an unsuspecting application will still
db6389
stomp all over us.
db6389
db6389
The selabel APIs for looking up the context should be thread-safe (per
db6389
Red Hat #273081), so switching to using them instead of matchpathcon(),
db6389
which we used earlier, is some improvement.
db6389
---
db6389
 src/aclocal.m4                                |  49 +++
db6389
 src/build-tools/krb5-config.in                |   3 +-
db6389
 src/config/pre.in                             |   3 +-
db6389
 src/configure.in                              |   2 +
db6389
 src/include/k5-int.h                          |   1 +
db6389
 src/include/k5-label.h                        |  32 ++
db6389
 src/include/krb5/krb5.hin                     |   6 +
db6389
 src/kadmin/dbutil/dump.c                      |  11 +-
db6389
 src/kdc/main.c                                |   2 +-
db6389
 src/kprop/kpropd.c                            |   9 +
db6389
 src/lib/kadm5/logger.c                        |   4 +-
db6389
 src/lib/kdb/kdb_log.c                         |   2 +-
db6389
 src/lib/krb5/ccache/cc_dir.c                  |  26 +-
db6389
 src/lib/krb5/keytab/kt_file.c                 |   4 +-
db6389
 src/lib/krb5/os/trace.c                       |   2 +-
db6389
 src/lib/krb5/rcache/rc_dfl.c                  |  13 +
db6389
 src/plugins/kdb/db2/adb_openclose.c           |   2 +-
db6389
 src/plugins/kdb/db2/kdb_db2.c                 |   4 +-
db6389
 src/plugins/kdb/db2/libdb2/btree/bt_open.c    |   3 +-
db6389
 src/plugins/kdb/db2/libdb2/hash/hash.c        |   3 +-
db6389
 src/plugins/kdb/db2/libdb2/recno/rec_open.c   |   4 +-
db6389
 .../kdb/ldap/ldap_util/kdb5_ldap_services.c   |  11 +-
db6389
 src/util/profile/prof_file.c                  |   3 +-
db6389
 src/util/support/Makefile.in                  |   3 +-
db6389
 src/util/support/selinux.c                    | 406 ++++++++++++++++++
db6389
 25 files changed, 587 insertions(+), 21 deletions(-)
db6389
 create mode 100644 src/include/k5-label.h
db6389
 create mode 100644 src/util/support/selinux.c
db6389
db6389
diff --git a/src/aclocal.m4 b/src/aclocal.m4
db6389
index 340546d80..a7afec09e 100644
db6389
--- a/src/aclocal.m4
db6389
+++ b/src/aclocal.m4
db6389
@@ -89,6 +89,7 @@ AC_SUBST_FILE(libnodeps_frag)
db6389
 dnl
db6389
 KRB5_AC_PRAGMA_WEAK_REF
db6389
 WITH_LDAP
db6389
+KRB5_WITH_SELINUX
db6389
 KRB5_LIB_PARAMS
db6389
 KRB5_AC_INITFINI
db6389
 KRB5_AC_ENABLE_THREADS
db6389
@@ -1764,3 +1765,51 @@ AC_SUBST(PAM_LIBS)
db6389
 AC_SUBST(PAM_MAN)
db6389
 AC_SUBST(NON_PAM_MAN)
db6389
 ])dnl
db6389
+dnl
db6389
+dnl Use libselinux to set file contexts on newly-created files.
db6389
+dnl
db6389
+AC_DEFUN(KRB5_WITH_SELINUX,[
db6389
+AC_ARG_WITH(selinux,[AC_HELP_STRING(--with-selinux,[compile with SELinux labeling support])],
db6389
+           withselinux="$withval",withselinux=auto)
db6389
+old_LIBS="$LIBS"
db6389
+if test "$withselinux" != no ; then
db6389
+       AC_MSG_RESULT([checking for libselinux...])
db6389
+       SELINUX_LIBS=
db6389
+       AC_CHECK_HEADERS(selinux/selinux.h selinux/label.h)
db6389
+       if test "x$ac_cv_header_selinux_selinux_h" != xyes ; then
db6389
+               if test "$withselinux" = auto ; then
db6389
+                       AC_MSG_RESULT([Unable to locate selinux/selinux.h.])
db6389
+                       withselinux=no
db6389
+               else
db6389
+                       AC_MSG_ERROR([Unable to locate selinux/selinux.h.])
db6389
+               fi
db6389
+       fi
db6389
+
db6389
+       LIBS=
db6389
+       unset ac_cv_func_setfscreatecon
db6389
+       AC_CHECK_FUNCS(setfscreatecon selabel_open)
db6389
+       if test "x$ac_cv_func_setfscreatecon" = xno ; then
db6389
+               AC_CHECK_LIB(selinux,setfscreatecon)
db6389
+               unset ac_cv_func_setfscreatecon
db6389
+               AC_CHECK_FUNCS(setfscreatecon selabel_open)
db6389
+               if test "x$ac_cv_func_setfscreatecon" = xyes ; then
db6389
+                       SELINUX_LIBS="$LIBS"
db6389
+               else
db6389
+                       if test "$withselinux" = auto ; then
db6389
+                               AC_MSG_RESULT([Unable to locate libselinux.])
db6389
+                               withselinux=no
db6389
+                       else
db6389
+                               AC_MSG_ERROR([Unable to locate libselinux.])
db6389
+                       fi
db6389
+               fi
db6389
+       fi
db6389
+       if test "$withselinux" != no ; then
db6389
+               AC_MSG_NOTICE([building with SELinux labeling support])
db6389
+               AC_DEFINE(USE_SELINUX,1,[Define if Kerberos-aware tools should set SELinux file contexts when creating files.])
db6389
+               SELINUX_LIBS="$LIBS"
db6389
+		EXTRA_SUPPORT_SYMS="$EXTRA_SUPPORT_SYMS krb5int_labeled_open krb5int_labeled_fopen krb5int_push_fscreatecon_for krb5int_pop_fscreatecon"
db6389
+       fi
db6389
+fi
db6389
+LIBS="$old_LIBS"
db6389
+AC_SUBST(SELINUX_LIBS)
db6389
+])dnl
db6389
diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in
db6389
index f6184da3f..c17cb5eb5 100755
db6389
--- a/src/build-tools/krb5-config.in
db6389
+++ b/src/build-tools/krb5-config.in
db6389
@@ -41,6 +41,7 @@ DL_LIB='@DL_LIB@'
db6389
 DEFCCNAME='@DEFCCNAME@'
db6389
 DEFKTNAME='@DEFKTNAME@'
db6389
 DEFCKTNAME='@DEFCKTNAME@'
db6389
+SELINUX_LIBS='@SELINUX_LIBS@'
db6389
 
db6389
 LIBS='@LIBS@'
db6389
 GEN_LIB=@GEN_LIB@
db6389
@@ -255,7 +256,7 @@ if test -n "$do_libs"; then
db6389
     fi
db6389
 
db6389
     # If we ever support a flag to generate output suitable for static
db6389
-    # linking, we would output "-lkrb5support $GEN_LIB $LIBS $DL_LIB"
db6389
+    # linking, we would output "-lkrb5support $GEN_LIB $LIBS $SELINUX_LIBS $DL_LIB"
db6389
     # here.
db6389
 
db6389
     echo $lib_flags
db6389
diff --git a/src/config/pre.in b/src/config/pre.in
db6389
index ce87e21ca..917357df9 100644
db6389
--- a/src/config/pre.in
db6389
+++ b/src/config/pre.in
db6389
@@ -177,6 +177,7 @@ LD = $(PURE) @LD@
db6389
 KRB_INCLUDES = -I$(BUILDTOP)/include -I$(top_srcdir)/include
db6389
 LDFLAGS = @LDFLAGS@
db6389
 LIBS = @LIBS@
db6389
+SELINUX_LIBS=@SELINUX_LIBS@
db6389
 
db6389
 INSTALL=@INSTALL@
db6389
 INSTALL_STRIP=
db6389
@@ -402,7 +403,7 @@ SUPPORT_LIB			= -l$(SUPPORT_LIBNAME)
db6389
 # HESIOD_LIBS is -lhesiod...
db6389
 HESIOD_LIBS	= @HESIOD_LIBS@
db6389
 
db6389
-KRB5_BASE_LIBS	= $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_LIB) $(LIBS) $(DL_LIB)
db6389
+KRB5_BASE_LIBS	= $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_LIB) $(LIBS) $(SELINUX_LIBS) $(DL_LIB)
db6389
 KDB5_LIBS	= $(KDB5_LIB) $(GSSRPC_LIBS)
db6389
 GSS_LIBS	= $(GSS_KRB5_LIB)
db6389
 # needs fixing if ever used on macOS!
db6389
diff --git a/src/configure.in b/src/configure.in
db6389
index e9a12ac16..93aec682e 100644
db6389
--- a/src/configure.in
db6389
+++ b/src/configure.in
db6389
@@ -1354,6 +1354,8 @@ AC_PATH_PROG(GROFF, groff)
db6389
 
db6389
 KRB5_WITH_PAM
db6389
 
db6389
+KRB5_WITH_SELINUX
db6389
+
db6389
 # Make localedir work in autoconf 2.5x.
db6389
 if test "${localedir+set}" != set; then
db6389
     localedir='$(datadir)/locale'
db6389
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
db6389
index 652242207..8f9329c59 100644
db6389
--- a/src/include/k5-int.h
db6389
+++ b/src/include/k5-int.h
db6389
@@ -128,6 +128,7 @@ typedef unsigned char   u_char;
db6389
 
db6389
 
db6389
 #include "k5-platform.h"
db6389
+#include "k5-label.h"
db6389
 
db6389
 #define KRB5_KDB_MAX_LIFE       (60*60*24) /* one day */
db6389
 #define KRB5_KDB_MAX_RLIFE      (60*60*24*7) /* one week */
db6389
diff --git a/src/include/k5-label.h b/src/include/k5-label.h
db6389
new file mode 100644
db6389
index 000000000..dfaaa847c
db6389
--- /dev/null
db6389
+++ b/src/include/k5-label.h
db6389
@@ -0,0 +1,32 @@
db6389
+#ifndef _KRB5_LABEL_H
db6389
+#define _KRB5_LABEL_H
db6389
+
db6389
+#ifdef THREEPARAMOPEN
db6389
+#undef THREEPARAMOPEN
db6389
+#endif
db6389
+#ifdef WRITABLEFOPEN
db6389
+#undef WRITABLEFOPEN
db6389
+#endif
db6389
+
db6389
+/* Wrapper functions which help us create files and directories with the right
db6389
+ * context labels. */
db6389
+#ifdef USE_SELINUX
db6389
+#include <sys/types.h>
db6389
+#include <sys/stat.h>
db6389
+#include <fcntl.h>
db6389
+#include <stdio.h>
db6389
+#include <unistd.h>
db6389
+FILE *krb5int_labeled_fopen(const char *path, const char *mode);
db6389
+int krb5int_labeled_creat(const char *path, mode_t mode);
db6389
+int krb5int_labeled_open(const char *path, int flags, ...);
db6389
+int krb5int_labeled_mkdir(const char *path, mode_t mode);
db6389
+int krb5int_labeled_mknod(const char *path, mode_t mode, dev_t device);
db6389
+#define THREEPARAMOPEN(x,y,z) krb5int_labeled_open(x,y,z)
db6389
+#define WRITABLEFOPEN(x,y) krb5int_labeled_fopen(x,y)
db6389
+void *krb5int_push_fscreatecon_for(const char *pathname);
db6389
+void krb5int_pop_fscreatecon(void *previous);
db6389
+#else
db6389
+#define WRITABLEFOPEN(x,y) fopen(x,y)
db6389
+#define THREEPARAMOPEN(x,y,z) open(x,y,z)
db6389
+#endif
db6389
+#endif
db6389
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
db6389
index c40a6cca8..3ff86d7ff 100644
db6389
--- a/src/include/krb5/krb5.hin
db6389
+++ b/src/include/krb5/krb5.hin
db6389
@@ -87,6 +87,12 @@
db6389
 #define THREEPARAMOPEN(x,y,z) open(x,y,z)
db6389
 #endif
db6389
 
db6389
+#if KRB5_PRIVATE
db6389
+#ifndef WRITABLEFOPEN
db6389
+#define WRITABLEFOPEN(x,y) fopen(x,y)
db6389
+#endif
db6389
+#endif
db6389
+
db6389
 #define KRB5_OLD_CRYPTO
db6389
 
db6389
 #include <stdlib.h>
db6389
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
db6389
index c9574c6e1..8301a33d0 100644
db6389
--- a/src/kadmin/dbutil/dump.c
db6389
+++ b/src/kadmin/dbutil/dump.c
db6389
@@ -148,12 +148,21 @@ create_ofile(char *ofile, char **tmpname)
db6389
 {
db6389
     int fd = -1;
db6389
     FILE *f;
db6389
+#ifdef USE_SELINUX
db6389
+    void *selabel;
db6389
+#endif
db6389
 
db6389
     *tmpname = NULL;
db6389
     if (asprintf(tmpname, "%s-XXXXXX", ofile) < 0)
db6389
         goto error;
db6389
 
db6389
+#ifdef USE_SELINUX
db6389
+    selabel = krb5int_push_fscreatecon_for(ofile);
db6389
+#endif
db6389
     fd = mkstemp(*tmpname);
db6389
+#ifdef USE_SELINUX
db6389
+    krb5int_pop_fscreatecon(selabel);
db6389
+#endif
db6389
     if (fd == -1)
db6389
         goto error;
db6389
 
db6389
@@ -197,7 +206,7 @@ prep_ok_file(krb5_context context, char *file_name, int *fd_out)
db6389
         goto cleanup;
db6389
     }
db6389
 
db6389
-    fd = open(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600);
db6389
+    fd = THREEPARAMOPEN(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600);
db6389
     if (fd == -1) {
db6389
         com_err(progname, errno, _("while creating 'ok' file, '%s'"), file_ok);
db6389
         goto cleanup;
db6389
diff --git a/src/kdc/main.c b/src/kdc/main.c
db6389
index 408c723f5..663fd6303 100644
db6389
--- a/src/kdc/main.c
db6389
+++ b/src/kdc/main.c
db6389
@@ -858,7 +858,7 @@ write_pid_file(const char *path)
db6389
     FILE *file;
db6389
     unsigned long pid;
db6389
 
db6389
-    file = fopen(path, "w");
db6389
+    file = WRITABLEFOPEN(path, "w");
db6389
     if (file == NULL)
db6389
         return errno;
db6389
     pid = (unsigned long) getpid();
db6389
diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c
db6389
index 68323dd0f..4cc035dc6 100644
db6389
--- a/src/kprop/kpropd.c
db6389
+++ b/src/kprop/kpropd.c
db6389
@@ -488,6 +488,9 @@ doit(int fd)
db6389
     krb5_enctype etype;
db6389
     int database_fd;
db6389
     char host[INET6_ADDRSTRLEN + 1];
db6389
+#ifdef USE_SELINUX
db6389
+    void *selabel;
db6389
+#endif
db6389
 
db6389
     signal_wrapper(SIGALRM, alarm_handler);
db6389
     alarm(params.iprop_resync_timeout);
db6389
@@ -543,9 +546,15 @@ doit(int fd)
db6389
         free(name);
db6389
         exit(1);
db6389
     }
db6389
+#ifdef USE_SELINUX
db6389
+    selabel = krb5int_push_fscreatecon_for(file);
db6389
+#endif
db6389
     omask = umask(077);
db6389
     lock_fd = open(temp_file_name, O_RDWR | O_CREAT, 0600);
db6389
     (void)umask(omask);
db6389
+#ifdef USE_SELINUX
db6389
+    krb5int_pop_fscreatecon(selabel);
db6389
+#endif
db6389
     retval = krb5_lock_file(kpropd_context, lock_fd,
db6389
                             KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK);
db6389
     if (retval) {
db6389
diff --git a/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c
db6389
index c6885edf2..9aec3c05e 100644
db6389
--- a/src/lib/kadm5/logger.c
db6389
+++ b/src/lib/kadm5/logger.c
db6389
@@ -309,7 +309,7 @@ krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do
db6389
                      */
db6389
                     append = (cp[4] == ':') ? O_APPEND : 0;
db6389
                     if (append || cp[4] == '=') {
db6389
-                        fd = open(&cp[5], O_CREAT | O_WRONLY | append,
db6389
+                        fd = THREEPARAMOPEN(&cp[5], O_CREAT | O_WRONLY | append,
db6389
                                   S_IRUSR | S_IWUSR | S_IRGRP);
db6389
                         if (fd != -1)
db6389
                             f = fdopen(fd, append ? "a" : "w");
db6389
@@ -776,7 +776,7 @@ krb5_klog_reopen(krb5_context kcontext)
db6389
              * In case the old logfile did not get moved out of the
db6389
              * way, open for append to prevent squashing the old logs.
db6389
              */
db6389
-            f = fopen(log_control.log_entries[lindex].lfu_fname, "a+");
db6389
+            f = WRITABLEFOPEN(log_control.log_entries[lindex].lfu_fname, "a+");
db6389
             if (f) {
db6389
                 set_cloexec_file(f);
db6389
                 log_control.log_entries[lindex].lfu_filep = f;
db6389
diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c
db6389
index 2659a2501..e9b95fce5 100644
db6389
--- a/src/lib/kdb/kdb_log.c
db6389
+++ b/src/lib/kdb/kdb_log.c
db6389
@@ -480,7 +480,7 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries)
db6389
         return ENOMEM;
db6389
 
db6389
     if (stat(logname, &st) == -1) {
db6389
-        log_ctx->ulogfd = open(logname, O_RDWR | O_CREAT, 0600);
db6389
+        log_ctx->ulogfd = THREEPARAMOPEN(logname, O_RDWR | O_CREAT, 0600);
db6389
         if (log_ctx->ulogfd == -1) {
db6389
             retval = errno;
db6389
             goto cleanup;
db6389
diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c
db6389
index bba64e516..73f0fe62d 100644
db6389
--- a/src/lib/krb5/ccache/cc_dir.c
db6389
+++ b/src/lib/krb5/ccache/cc_dir.c
db6389
@@ -183,10 +183,19 @@ write_primary_file(const char *primary_path, const char *contents)
db6389
     char *newpath = NULL;
db6389
     FILE *fp = NULL;
db6389
     int fd = -1, status;
db6389
+#ifdef USE_SELINUX
db6389
+    void *selabel;
db6389
+#endif
db6389
 
db6389
     if (asprintf(&newpath, "%s.XXXXXX", primary_path) < 0)
db6389
         return ENOMEM;
db6389
+#ifdef USE_SELINUX
db6389
+    selabel = krb5int_push_fscreatecon_for(primary_path);
db6389
+#endif
db6389
     fd = mkstemp(newpath);
db6389
+#ifdef USE_SELINUX
db6389
+    krb5int_pop_fscreatecon(selabel);
db6389
+#endif
db6389
     if (fd < 0)
db6389
         goto cleanup;
db6389
 #ifdef HAVE_CHMOD
db6389
@@ -221,10 +230,23 @@ static krb5_error_code
db6389
 verify_dir(krb5_context context, const char *dirname)
db6389
 {
db6389
     struct stat st;
db6389
+    int status;
db6389
+#ifdef USE_SELINUX
db6389
+    void *selabel;
db6389
+#endif
db6389
 
db6389
     if (stat(dirname, &st) < 0) {
db6389
-        if (errno == ENOENT && mkdir(dirname, S_IRWXU) == 0)
db6389
-            return 0;
db6389
+        if (errno == ENOENT) {
db6389
+#ifdef USE_SELINUX
db6389
+            selabel = krb5int_push_fscreatecon_for(dirname);
db6389
+#endif
db6389
+            status = mkdir(dirname, S_IRWXU);
db6389
+#ifdef USE_SELINUX
db6389
+            krb5int_pop_fscreatecon(selabel);
db6389
+#endif
db6389
+            if (status == 0)
db6389
+                return 0;
db6389
+        }
db6389
         k5_setmsg(context, KRB5_FCC_NOFILE,
db6389
                   _("Credential cache directory %s does not exist"),
db6389
                   dirname);
db6389
diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c
db6389
index 89cb68680..21c80d419 100644
db6389
--- a/src/lib/krb5/keytab/kt_file.c
db6389
+++ b/src/lib/krb5/keytab/kt_file.c
db6389
@@ -1024,14 +1024,14 @@ krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
db6389
 
db6389
     KTCHECKLOCK(id);
db6389
     errno = 0;
db6389
-    KTFILEP(id) = fopen(KTFILENAME(id),
db6389
+    KTFILEP(id) = WRITABLEFOPEN(KTFILENAME(id),
db6389
                         (mode == KRB5_LOCKMODE_EXCLUSIVE) ? "rb+" : "rb");
db6389
     if (!KTFILEP(id)) {
db6389
         if ((mode == KRB5_LOCKMODE_EXCLUSIVE) && (errno == ENOENT)) {
db6389
             /* try making it first time around */
db6389
             k5_create_secure_file(context, KTFILENAME(id));
db6389
             errno = 0;
db6389
-            KTFILEP(id) = fopen(KTFILENAME(id), "rb+");
db6389
+            KTFILEP(id) = WRITABLEFOPEN(KTFILENAME(id), "rb+");
db6389
             if (!KTFILEP(id))
db6389
                 goto report_errno;
db6389
             writevno = 1;
db6389
diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
db6389
index 4fff8f38c..40a9e7b10 100644
db6389
--- a/src/lib/krb5/os/trace.c
db6389
+++ b/src/lib/krb5/os/trace.c
db6389
@@ -458,7 +458,7 @@ krb5_set_trace_filename(krb5_context context, const char *filename)
db6389
     fd = malloc(sizeof(*fd));
db6389
     if (fd == NULL)
db6389
         return ENOMEM;
db6389
-    *fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0600);
db6389
+    *fd = THREEPARAMOPEN(filename, O_WRONLY|O_CREAT|O_APPEND, 0600);
db6389
     if (*fd == -1) {
db6389
         free(fd);
db6389
         return errno;
db6389
diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c
db6389
index 1e0cb22c9..f5e93b1ab 100644
db6389
--- a/src/lib/krb5/rcache/rc_dfl.c
db6389
+++ b/src/lib/krb5/rcache/rc_dfl.c
db6389
@@ -793,6 +793,9 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id)
db6389
     krb5_error_code retval = 0;
db6389
     krb5_rcache tmp;
db6389
     krb5_deltat lifespan = t->lifespan;  /* save original lifespan */
db6389
+#ifdef USE_SELINUX
db6389
+    void *selabel;
db6389
+#endif
db6389
 
db6389
     if (! t->recovering) {
db6389
         name = t->name;
db6389
@@ -814,7 +817,17 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id)
db6389
     retval = krb5_rc_resolve(context, tmp, 0);
db6389
     if (retval)
db6389
         goto cleanup;
db6389
+#ifdef USE_SELINUX
db6389
+    if (t->d.fn != NULL)
db6389
+        selabel = krb5int_push_fscreatecon_for(t->d.fn);
db6389
+    else
db6389
+        selabel = NULL;
db6389
+#endif
db6389
     retval = krb5_rc_initialize(context, tmp, lifespan);
db6389
+#ifdef USE_SELINUX
db6389
+    if (selabel != NULL)
db6389
+        krb5int_pop_fscreatecon(selabel);
db6389
+#endif
db6389
     if (retval)
db6389
         goto cleanup;
db6389
     for (q = t->a; q; q = q->na) {
db6389
diff --git a/src/plugins/kdb/db2/adb_openclose.c b/src/plugins/kdb/db2/adb_openclose.c
db6389
index 7db30a33b..2b9d01921 100644
db6389
--- a/src/plugins/kdb/db2/adb_openclose.c
db6389
+++ b/src/plugins/kdb/db2/adb_openclose.c
db6389
@@ -152,7 +152,7 @@ osa_adb_init_db(osa_adb_db_t *dbp, char *filename, char *lockfilename,
db6389
          * needs be open read/write so that write locking can work with
db6389
          * POSIX systems
db6389
          */
db6389
-        if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) {
db6389
+        if ((lockp->lockinfo.lockfile = WRITABLEFOPEN(lockfilename, "r+")) == NULL) {
db6389
             /*
db6389
              * maybe someone took away write permission so we could only
db6389
              * get shared locks?
db6389
diff --git a/src/plugins/kdb/db2/kdb_db2.c b/src/plugins/kdb/db2/kdb_db2.c
db6389
index 5106a5c99..e481e8121 100644
db6389
--- a/src/plugins/kdb/db2/kdb_db2.c
db6389
+++ b/src/plugins/kdb/db2/kdb_db2.c
db6389
@@ -694,8 +694,8 @@ ctx_create_db(krb5_context context, krb5_db2_context *dbc)
db6389
     if (retval)
db6389
         return retval;
db6389
 
db6389
-    dbc->db_lf_file = open(dbc->db_lf_name, O_CREAT | O_RDWR | O_TRUNC,
db6389
-                           0600);
db6389
+    dbc->db_lf_file = THREEPARAMOPEN(dbc->db_lf_name,
db6389
+                                     O_CREAT | O_RDWR | O_TRUNC, 0600);
db6389
     if (dbc->db_lf_file < 0) {
db6389
         retval = errno;
db6389
         goto cleanup;
db6389
diff --git a/src/plugins/kdb/db2/libdb2/btree/bt_open.c b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
db6389
index 2977b17f3..d5809a5a9 100644
db6389
--- a/src/plugins/kdb/db2/libdb2/btree/bt_open.c
db6389
+++ b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
db6389
@@ -60,6 +60,7 @@ static char sccsid[] = "@(#)bt_open.c	8.11 (Berkeley) 11/2/95";
db6389
 #include <string.h>
db6389
 #include <unistd.h>
db6389
 
db6389
+#include "k5-int.h"
db6389
 #include "db-int.h"
db6389
 #include "btree.h"
db6389
 
db6389
@@ -203,7 +204,7 @@ __bt_open(fname, flags, mode, openinfo, dflags)
db6389
 			goto einval;
db6389
 		}
db6389
 
db6389
-		if ((t->bt_fd = open(fname, flags | O_BINARY, mode)) < 0)
db6389
+		if ((t->bt_fd = THREEPARAMOPEN(fname, flags | O_BINARY, mode)) < 0)
db6389
 			goto err;
db6389
 
db6389
 	} else {
db6389
diff --git a/src/plugins/kdb/db2/libdb2/hash/hash.c b/src/plugins/kdb/db2/libdb2/hash/hash.c
db6389
index 862dbb164..686a960c9 100644
db6389
--- a/src/plugins/kdb/db2/libdb2/hash/hash.c
db6389
+++ b/src/plugins/kdb/db2/libdb2/hash/hash.c
db6389
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)hash.c	8.12 (Berkeley) 11/7/95";
db6389
 #include <assert.h>
db6389
 #endif
db6389
 
db6389
+#include "k5-int.h"
db6389
 #include "db-int.h"
db6389
 #include "hash.h"
db6389
 #include "page.h"
db6389
@@ -129,7 +130,7 @@ __kdb2_hash_open(file, flags, mode, info, dflags)
db6389
 		new_table = 1;
db6389
 	}
db6389
 	if (file) {
db6389
-		if ((hashp->fp = open(file, flags|O_BINARY, mode)) == -1)
db6389
+		if ((hashp->fp = THREEPARAMOPEN(file, flags|O_BINARY, mode)) == -1)
db6389
 			RETURN_ERROR(errno, error0);
db6389
 		(void)fcntl(hashp->fp, F_SETFD, 1);
db6389
 	}
db6389
diff --git a/src/plugins/kdb/db2/libdb2/recno/rec_open.c b/src/plugins/kdb/db2/libdb2/recno/rec_open.c
db6389
index d8b26e701..b0daa7c02 100644
db6389
--- a/src/plugins/kdb/db2/libdb2/recno/rec_open.c
db6389
+++ b/src/plugins/kdb/db2/libdb2/recno/rec_open.c
db6389
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)rec_open.c	8.12 (Berkeley) 11/18/94";
db6389
 #include <stdio.h>
db6389
 #include <unistd.h>
db6389
 
db6389
+#include "k5-int.h"
db6389
 #include "db-int.h"
db6389
 #include "recno.h"
db6389
 
db6389
@@ -68,7 +69,8 @@ __rec_open(fname, flags, mode, openinfo, dflags)
db6389
 	int rfd = -1, sverrno;
db6389
 
db6389
 	/* Open the user's file -- if this fails, we're done. */
db6389
-	if (fname != NULL && (rfd = open(fname, flags | O_BINARY, mode)) < 0)
db6389
+	if (fname != NULL &&
db6389
+            (rfd = THREEPARAMOPEN(fname, flags | O_BINARY, mode)) < 0)
db6389
 		return (NULL);
db6389
 
db6389
 	if (fname != NULL && fcntl(rfd, F_SETFD, 1) == -1) {
db6389
diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
db6389
index 1ed72afe9..ce038fc3d 100644
db6389
--- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
db6389
+++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
db6389
@@ -194,7 +194,7 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
db6389
 
db6389
     /* set password in the file */
db6389
     old_mode = umask(0177);
db6389
-    pfile = fopen(file_name, "a+");
db6389
+    pfile = WRITABLEFOPEN(file_name, "a+");
db6389
     if (pfile == NULL) {
db6389
         com_err(me, errno, _("Failed to open file %s: %s"), file_name,
db6389
                 strerror (errno));
db6389
@@ -235,6 +235,9 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
db6389
          * Delete the existing entry and add the new entry
db6389
          */
db6389
         FILE *newfile;
db6389
+#ifdef USE_SELINUX
db6389
+        void *selabel;
db6389
+#endif
db6389
 
db6389
         mode_t omask;
db6389
 
db6389
@@ -246,7 +249,13 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
db6389
         }
db6389
 
db6389
         omask = umask(077);
db6389
+#ifdef USE_SELINUX
db6389
+        selabel = krb5int_push_fscreatecon_for(file_name);
db6389
+#endif
db6389
         newfile = fopen(tmp_file, "w");
db6389
+#ifdef USE_SELINUX
db6389
+        krb5int_pop_fscreatecon(selabel);
db6389
+#endif
db6389
         umask (omask);
db6389
         if (newfile == NULL) {
db6389
             com_err(me, errno, _("Error creating file %s"), tmp_file);
db6389
diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c
db6389
index 24e41fb80..0dcb6b543 100644
db6389
--- a/src/util/profile/prof_file.c
db6389
+++ b/src/util/profile/prof_file.c
db6389
@@ -33,6 +33,7 @@
db6389
 #endif
db6389
 
db6389
 #include "k5-platform.h"
db6389
+#include "k5-label.h"
db6389
 
db6389
 struct global_shared_profile_data {
db6389
     /* This is the head of the global list of shared trees */
db6389
@@ -391,7 +392,7 @@ static errcode_t write_data_to_file(prf_data_t data, const char *outfile,
db6389
 
db6389
     errno = 0;
db6389
 
db6389
-    f = fopen(new_file, "w");
db6389
+    f = WRITABLEFOPEN(new_file, "w");
db6389
     if (!f) {
db6389
         retval = errno;
db6389
         if (retval == 0)
db6389
diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
db6389
index db7b030b8..321672bcb 100644
db6389
--- a/src/util/support/Makefile.in
db6389
+++ b/src/util/support/Makefile.in
db6389
@@ -69,6 +69,7 @@ IPC_SYMS= \
db6389
 
db6389
 STLIBOBJS= \
db6389
 	threads.o \
db6389
+	selinux.o \
db6389
 	init-addrinfo.o \
db6389
 	plugins.o \
db6389
 	errors.o \
db6389
@@ -160,7 +161,7 @@ SRCS=\
db6389
 
db6389
 SHLIB_EXPDEPS =
db6389
 # Add -lm if dumping thread stats, for sqrt.
db6389
-SHLIB_EXPLIBS= $(LIBS) $(DL_LIB)
db6389
+SHLIB_EXPLIBS= $(LIBS) $(SELINUX_LIBS) $(DL_LIB)
db6389
 
db6389
 DEPLIBS=
db6389
 
db6389
diff --git a/src/util/support/selinux.c b/src/util/support/selinux.c
db6389
new file mode 100644
db6389
index 000000000..6d41f3244
db6389
--- /dev/null
db6389
+++ b/src/util/support/selinux.c
db6389
@@ -0,0 +1,406 @@
db6389
+/*
db6389
+ * Copyright 2007,2008,2009,2011,2012,2013,2016 Red Hat, Inc.  All Rights Reserved.
db6389
+ *
db6389
+ * Redistribution and use in source and binary forms, with or without
db6389
+ * modification, are permitted provided that the following conditions are met:
db6389
+ *
db6389
+ *  Redistributions of source code must retain the above copyright notice, this
db6389
+ *  list of conditions and the following disclaimer.
db6389
+ *
db6389
+ *  Redistributions in binary form must reproduce the above copyright notice,
db6389
+ *  this list of conditions and the following disclaimer in the documentation
db6389
+ *  and/or other materials provided with the distribution.
db6389
+ *
db6389
+ *  Neither the name of Red Hat, Inc. nor the names of its contributors may be
db6389
+ *  used to endorse or promote products derived from this software without
db6389
+ *  specific prior written permission.
db6389
+ *
db6389
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
db6389
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
db6389
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
db6389
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
db6389
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
db6389
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
db6389
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
db6389
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
db6389
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
db6389
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
db6389
+ * POSSIBILITY OF SUCH DAMAGE.
db6389
+ *
db6389
+ * File-opening wrappers for creating correctly-labeled files.  So far, we can
db6389
+ * assume that this is Linux-specific, so we make many simplifying assumptions.
db6389
+ */
db6389
+
db6389
+#include "../../include/autoconf.h"
db6389
+
db6389
+#ifdef USE_SELINUX
db6389
+
db6389
+#include <k5-label.h>
db6389
+#include <k5-platform.h>
db6389
+
db6389
+#include <sys/types.h>
db6389
+#include <sys/stat.h>
db6389
+
db6389
+#include <errno.h>
db6389
+#include <fcntl.h>
db6389
+#include <limits.h>
db6389
+#include <pthread.h>
db6389
+#include <stdarg.h>
db6389
+#include <stdio.h>
db6389
+#include <stdlib.h>
db6389
+#include <string.h>
db6389
+#include <unistd.h>
db6389
+
db6389
+#include <selinux/selinux.h>
db6389
+#include <selinux/context.h>
db6389
+#include <selinux/label.h>
db6389
+
db6389
+/* #define DEBUG 1 */
db6389
+static void
db6389
+debug_log(const char *fmt, ...)
db6389
+{
db6389
+#ifdef DEBUG
db6389
+    va_list ap;
db6389
+    va_start(ap, fmt);
db6389
+    if (isatty(fileno(stderr))) {
db6389
+        vfprintf(stderr, fmt, ap);
db6389
+    }
db6389
+    va_end(ap);
db6389
+#endif
db6389
+
db6389
+    return;
db6389
+}
db6389
+
db6389
+/* Mutex used to serialize use of the process-global file creation context. */
db6389
+k5_mutex_t labeled_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
db6389
+
db6389
+/* Make sure we finish initializing that mutex before attempting to use it. */
db6389
+k5_once_t labeled_once = K5_ONCE_INIT;
db6389
+static void
db6389
+label_mutex_init(void)
db6389
+{
db6389
+    k5_mutex_finish_init(&labeled_mutex);
db6389
+}
db6389
+
db6389
+static struct selabel_handle *selabel_ctx;
db6389
+static time_t selabel_last_changed;
db6389
+
db6389
+MAKE_FINI_FUNCTION(cleanup_fscreatecon);
db6389
+
db6389
+static void
db6389
+cleanup_fscreatecon(void)
db6389
+{
db6389
+    if (selabel_ctx != NULL) {
db6389
+        selabel_close(selabel_ctx);
db6389
+        selabel_ctx = NULL;
db6389
+    }
db6389
+}
db6389
+
db6389
+static security_context_t
db6389
+push_fscreatecon(const char *pathname, mode_t mode)
db6389
+{
db6389
+    security_context_t previous, configuredsc, currentsc, derivedsc;
db6389
+    context_t current, derived;
db6389
+    const char *fullpath, *currentuser;
db6389
+    char *genpath;
db6389
+
db6389
+    previous = configuredsc = currentsc = derivedsc = NULL;
db6389
+    current = derived = NULL;
db6389
+    genpath = NULL;
db6389
+
db6389
+    fullpath = pathname;
db6389
+
db6389
+    if (!is_selinux_enabled()) {
db6389
+        goto fail;
db6389
+    }
db6389
+
db6389
+    if (getfscreatecon(&previous) != 0) {
db6389
+        goto fail;
db6389
+    }
db6389
+
db6389
+    /* Canonicalize pathname */
db6389
+    if (pathname[0] != '/') {
db6389
+        char *wd;
db6389
+        size_t len;
db6389
+        len = 0;
db6389
+
db6389
+        wd = getcwd(NULL, len);
db6389
+        if (wd == NULL) {
db6389
+            goto fail;
db6389
+        }
db6389
+
db6389
+        len = strlen(wd) + 1 + strlen(pathname) + 1;
db6389
+        genpath = malloc(len);
db6389
+        if (genpath == NULL) {
db6389
+            free(wd);
db6389
+            goto fail;
db6389
+        }
db6389
+
db6389
+        sprintf(genpath, "%s/%s", wd, pathname);
db6389
+        free(wd);
db6389
+        fullpath = genpath;
db6389
+    }
db6389
+
db6389
+    debug_log("Looking up context for \"%s\"(%05o).\n", fullpath, mode);
db6389
+
db6389
+    /* Check whether context file has changed under us */
db6389
+    if (selabel_ctx != NULL || selabel_last_changed == 0) {
db6389
+        const char *cpath;
db6389
+        struct stat st;
db6389
+        int i = -1;
db6389
+
db6389
+        cpath = selinux_file_context_path();
db6389
+        if (cpath == NULL || (i = stat(cpath, &st)) != 0 ||
db6389
+            st.st_mtime != selabel_last_changed) {
db6389
+            cleanup_fscreatecon();
db6389
+
db6389
+            selabel_last_changed = i ? time(NULL) : st.st_mtime;
db6389
+        }
db6389
+    }
db6389
+
db6389
+    if (selabel_ctx == NULL) {
db6389
+        selabel_ctx = selabel_open(SELABEL_CTX_FILE, NULL, 0);
db6389
+    }
db6389
+
db6389
+    if (selabel_ctx != NULL &&
db6389
+        selabel_lookup(selabel_ctx, &configuredsc, fullpath, mode) != 0) {
db6389
+        goto fail;
db6389
+    }
db6389
+
db6389
+    if (genpath != NULL) {
db6389
+        free(genpath);
db6389
+        genpath = NULL;
db6389
+    }
db6389
+
db6389
+    if (configuredsc == NULL) {
db6389
+        goto fail;
db6389
+    }
db6389
+
db6389
+    getcon(&currentsc);
db6389
+
db6389
+    /* AAAAAAAA */
db6389
+    if (currentsc != NULL) {
db6389
+        derived = context_new(configuredsc);
db6389
+
db6389
+        if (derived != NULL) {
db6389
+            current = context_new(currentsc);
db6389
+
db6389
+            if (current != NULL) {
db6389
+                currentuser = context_user_get(current);
db6389
+
db6389
+                if (currentuser != NULL) {
db6389
+                    if (context_user_set(derived,
db6389
+                                         currentuser) == 0) {
db6389
+                        derivedsc = context_str(derived);
db6389
+
db6389
+                        if (derivedsc != NULL) {
db6389
+                            freecon(configuredsc);
db6389
+                            configuredsc = strdup(derivedsc);
db6389
+                        }
db6389
+                    }
db6389
+                }
db6389
+
db6389
+                context_free(current);
db6389
+            }
db6389
+
db6389
+            context_free(derived);
db6389
+        }
db6389
+
db6389
+        freecon(currentsc);
db6389
+    }
db6389
+
db6389
+    debug_log("Setting file creation context to \"%s\".\n", configuredsc);
db6389
+    if (setfscreatecon(configuredsc) != 0) {
db6389
+        debug_log("Unable to determine current context.\n");
db6389
+        goto fail;
db6389
+    }
db6389
+
db6389
+    freecon(configuredsc);
db6389
+    return previous;
db6389
+
db6389
+fail:
db6389
+    if (previous != NULL) {
db6389
+        freecon(previous);
db6389
+    }
db6389
+    if (genpath != NULL) {
db6389
+        free(genpath);
db6389
+    }
db6389
+    if (configuredsc != NULL) {
db6389
+        freecon(configuredsc);
db6389
+    }
db6389
+
db6389
+    cleanup_fscreatecon();
db6389
+    return NULL;
db6389
+}
db6389
+
db6389
+static void
db6389
+pop_fscreatecon(security_context_t previous)
db6389
+{
db6389
+    if (!is_selinux_enabled()) {
db6389
+        return;
db6389
+    }
db6389
+
db6389
+    if (previous != NULL) {
db6389
+        debug_log("Resetting file creation context to \"%s\".\n", previous);
db6389
+    } else {
db6389
+        debug_log("Resetting file creation context to default.\n");
db6389
+    }
db6389
+
db6389
+    /* NULL resets to default */
db6389
+    setfscreatecon(previous);
db6389
+
db6389
+    if (previous != NULL) {
db6389
+        freecon(previous);
db6389
+    }
db6389
+
db6389
+    /* Need to clean this up here otherwise it leaks */
db6389
+    cleanup_fscreatecon();
db6389
+}
db6389
+
db6389
+void *
db6389
+krb5int_push_fscreatecon_for(const char *pathname)
db6389
+{
db6389
+    struct stat st;
db6389
+    void *retval;
db6389
+
db6389
+    k5_once(&labeled_once, label_mutex_init);
db6389
+    k5_mutex_lock(&labeled_mutex);
db6389
+
db6389
+    if (stat(pathname, &st) != 0) {
db6389
+        st.st_mode = S_IRUSR | S_IWUSR;
db6389
+    }
db6389
+
db6389
+    retval = push_fscreatecon(pathname, st.st_mode);
db6389
+    return retval ? retval : (void *) -1;
db6389
+}
db6389
+
db6389
+void
db6389
+krb5int_pop_fscreatecon(void *con)
db6389
+{
db6389
+    if (con != NULL) {
db6389
+        pop_fscreatecon((con == (void *) -1) ? NULL : con);
db6389
+        k5_mutex_unlock(&labeled_mutex);
db6389
+    }
db6389
+}
db6389
+
db6389
+FILE *
db6389
+krb5int_labeled_fopen(const char *path, const char *mode)
db6389
+{
db6389
+    FILE *fp;
db6389
+    int errno_save;
db6389
+    security_context_t ctx;
db6389
+
db6389
+    if ((strcmp(mode, "r") == 0) ||
db6389
+        (strcmp(mode, "rb") == 0)) {
db6389
+        return fopen(path, mode);
db6389
+    }
db6389
+
db6389
+    k5_once(&labeled_once, label_mutex_init);
db6389
+    k5_mutex_lock(&labeled_mutex);
db6389
+    ctx = push_fscreatecon(path, 0);
db6389
+
db6389
+    fp = fopen(path, mode);
db6389
+    errno_save = errno;
db6389
+
db6389
+    pop_fscreatecon(ctx);
db6389
+    k5_mutex_unlock(&labeled_mutex);
db6389
+
db6389
+    errno = errno_save;
db6389
+    return fp;
db6389
+}
db6389
+
db6389
+int
db6389
+krb5int_labeled_creat(const char *path, mode_t mode)
db6389
+{
db6389
+    int fd;
db6389
+    int errno_save;
db6389
+    security_context_t ctx;
db6389
+
db6389
+    k5_once(&labeled_once, label_mutex_init);
db6389
+    k5_mutex_lock(&labeled_mutex);
db6389
+    ctx = push_fscreatecon(path, 0);
db6389
+
db6389
+    fd = creat(path, mode);
db6389
+    errno_save = errno;
db6389
+
db6389
+    pop_fscreatecon(ctx);
db6389
+    k5_mutex_unlock(&labeled_mutex);
db6389
+
db6389
+    errno = errno_save;
db6389
+    return fd;
db6389
+}
db6389
+
db6389
+int
db6389
+krb5int_labeled_mknod(const char *path, mode_t mode, dev_t dev)
db6389
+{
db6389
+    int ret;
db6389
+    int errno_save;
db6389
+    security_context_t ctx;
db6389
+
db6389
+    k5_once(&labeled_once, label_mutex_init);
db6389
+    k5_mutex_lock(&labeled_mutex);
db6389
+    ctx = push_fscreatecon(path, mode);
db6389
+
db6389
+    ret = mknod(path, mode, dev);
db6389
+    errno_save = errno;
db6389
+
db6389
+    pop_fscreatecon(ctx);
db6389
+    k5_mutex_unlock(&labeled_mutex);
db6389
+
db6389
+    errno = errno_save;
db6389
+    return ret;
db6389
+}
db6389
+
db6389
+int
db6389
+krb5int_labeled_mkdir(const char *path, mode_t mode)
db6389
+{
db6389
+    int ret;
db6389
+    int errno_save;
db6389
+    security_context_t ctx;
db6389
+
db6389
+    k5_once(&labeled_once, label_mutex_init);
db6389
+    k5_mutex_lock(&labeled_mutex);
db6389
+    ctx = push_fscreatecon(path, S_IFDIR);
db6389
+
db6389
+    ret = mkdir(path, mode);
db6389
+    errno_save = errno;
db6389
+
db6389
+    pop_fscreatecon(ctx);
db6389
+    k5_mutex_unlock(&labeled_mutex);
db6389
+
db6389
+    errno = errno_save;
db6389
+    return ret;
db6389
+}
db6389
+
db6389
+int
db6389
+krb5int_labeled_open(const char *path, int flags, ...)
db6389
+{
db6389
+    int fd;
db6389
+    int errno_save;
db6389
+    security_context_t ctx;
db6389
+    mode_t mode;
db6389
+    va_list ap;
db6389
+
db6389
+    if ((flags & O_CREAT) == 0) {
db6389
+        return open(path, flags);
db6389
+    }
db6389
+
db6389
+    k5_once(&labeled_once, label_mutex_init);
db6389
+    k5_mutex_lock(&labeled_mutex);
db6389
+    ctx = push_fscreatecon(path, 0);
db6389
+
db6389
+    va_start(ap, flags);
db6389
+    mode = va_arg(ap, mode_t);
db6389
+    fd = open(path, flags, mode);
db6389
+    va_end(ap);
db6389
+
db6389
+    errno_save = errno;
db6389
+
db6389
+    pop_fscreatecon(ctx);
db6389
+    k5_mutex_unlock(&labeled_mutex);
db6389
+
db6389
+    errno = errno_save;
db6389
+    return fd;
db6389
+}
db6389
+
db6389
+#endif /* USE_SELINUX */