Blame SOURCES/downstream-SELinux-integration.patch

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