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