Blob Blame History Raw
From 0c7f33bb6b16ef7dd27816489d9ec0b5c758c64f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 1 Dec 2014 17:36:56 +0100
Subject: [PATCH 125/128] krb5_child: become user earlier

The host keytab and the FAST credential cache are copied into memory
early at startup to allow to drop privileges earlier.

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
 Makefile.am                     |   1 +
 src/providers/krb5/krb5_child.c | 131 ++++++++++++++++++++++++++++------------
 2 files changed, 94 insertions(+), 38 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 3d16428856d6cb2e9e190b0df8895ab3f45db39c..6f6db56f5d6229b530cc6f18f66c42f22140bdeb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2531,6 +2531,7 @@ libsss_ad_la_LDFLAGS = \
 krb5_child_SOURCES = \
     src/providers/krb5/krb5_child.c \
     src/providers/krb5/krb5_ccache.c \
+    src/providers/krb5/krb5_keytab.c \
     src/providers/dp_pam_data_util.c \
     src/util/user_info_msg.c \
     src/util/sss_krb5.c \
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index d828dd550251d70851edcdc6b1eda6f5c051baf2..ce8a9235e1d64bccc91d367bc744cca2b32a40da 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -42,6 +42,12 @@
 
 #define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw"
 
+enum k5c_fast_opt {
+    K5C_FAST_NEVER,
+    K5C_FAST_TRY,
+    K5C_FAST_DEMAND,
+};
+
 struct krb5_req {
     krb5_context ctx;
     krb5_principal princ;
@@ -67,6 +73,7 @@ struct krb5_req {
     char *old_ccname;
     bool old_cc_valid;
     bool old_cc_active;
+    enum k5c_fast_opt fast_val;
 };
 
 static krb5_context krb5_error_ctx;
@@ -1839,6 +1846,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
     char *fast_principal;
     krb5_error_code kerr;
     char *tmp_str;
+    char *new_ccname;
 
     tmp_str = getenv(SSSD_KRB5_FAST_PRINCIPAL);
     if (tmp_str) {
@@ -1881,6 +1889,15 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
         return kerr;
     }
 
+    kerr = copy_ccache_into_memory(kr, kr->ctx, kr->fast_ccname, &new_ccname);
+    if (kerr != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "copy_ccache_into_memory failed.\n");
+        return kerr;
+    }
+
+    talloc_free(kr->fast_ccname);
+    kr->fast_ccname = new_ccname;
+
     kerr = sss_krb5_get_init_creds_opt_set_fast_ccache_name(kr->ctx,
                                                             kr->options,
                                                             kr->fast_ccname);
@@ -1908,12 +1925,6 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
     return EOK;
 }
 
-enum k5c_fast_opt {
-    K5C_FAST_NEVER,
-    K5C_FAST_TRY,
-    K5C_FAST_DEMAND,
-};
-
 static errno_t check_use_fast(enum k5c_fast_opt *_fast_val)
 {
     char *use_fast_str;
@@ -2064,19 +2075,8 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
 {
     krb5_error_code kerr;
     int parse_flags;
-    enum k5c_fast_opt fast_val;
 
-    kerr = check_use_fast(&fast_val);
-    if (kerr != EOK) {
-        return kerr;
-    }
-
-    kerr = k5c_ccache_setup(kr, offline);
-    if (kerr != EOK) {
-        return kerr;
-    }
-
-    if (offline || (fast_val == K5C_FAST_NEVER && kr->validate == false)) {
+    if (offline || (kr->fast_val == K5C_FAST_NEVER && kr->validate == false)) {
         /* If krb5_child was started as setuid, but we don't need to
          * perform either validation or FAST, just drop privileges to
          * the user who is logging in. The same applies to the offline case
@@ -2097,12 +2097,6 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
               "Cannot read [%s] from environment.\n", SSSD_KRB5_REALM);
     }
 
-    kerr = krb5_init_context(&kr->ctx);
-    if (kerr != 0) {
-        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
-        return kerr;
-    }
-
     /* Set the global error context */
     krb5_error_ctx = kr->ctx;
 
@@ -2145,12 +2139,6 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
         return ENOMEM;
     }
 
-    kerr = sss_krb5_get_init_creds_opt_alloc(kr->ctx, &kr->options);
-    if (kerr != 0) {
-        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
-        return kerr;
-    }
-
 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_RESPONDER
     kerr = krb5_get_init_creds_opt_set_responder(kr->ctx, kr->options,
                                                  sss_krb5_responder, kr);
@@ -2175,14 +2163,6 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
 
     if (!offline) {
         set_canonicalize_option(kr->options);
-
-        if (fast_val != K5C_FAST_NEVER) {
-            kerr = k5c_setup_fast(kr, fast_val == K5C_FAST_DEMAND);
-            if (kerr != EOK) {
-                DEBUG(SSSDBG_OP_FAILURE, "Cannot set up FAST\n");
-                return kerr;
-            }
-        }
     }
 
 /* TODO: set options, e.g.
@@ -2199,6 +2179,63 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
     return kerr;
 }
 
+static krb5_error_code privileged_krb5_setup(struct krb5_req *kr,
+                                             uint32_t offline)
+{
+    krb5_error_code kerr;
+    int ret;
+    char *mem_keytab;
+
+    kerr = krb5_init_context(&kr->ctx);
+    if (kerr != 0) {
+        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+        return kerr;
+    }
+
+    kerr = sss_krb5_get_init_creds_opt_alloc(kr->ctx, &kr->options);
+    if (kerr != 0) {
+        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+        return kerr;
+    }
+
+    ret = check_use_fast(&kr->fast_val);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "check_use_fast failed.\n");
+        return ret;;
+    }
+
+    /* For ccache types FILE: and DIR: we might need to create some directory
+     * components as root */
+    ret = k5c_ccache_setup(kr, offline);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "k5c_ccache_setup failed.\n");
+        return ret;
+    }
+
+    if (!(offline ||
+            (kr->fast_val == K5C_FAST_NEVER && kr->validate == false))) {
+        kerr = copy_keytab_into_memory(kr, kr->ctx, kr->keytab, &mem_keytab,
+                                       NULL);
+        if (kerr != 0) {
+            DEBUG(SSSDBG_OP_FAILURE, "copy_keytab_into_memory failed.\n");
+            return kerr;
+        }
+
+        talloc_free(kr->keytab);
+        kr->keytab = mem_keytab;
+
+        if (kr->fast_val != K5C_FAST_NEVER) {
+            kerr = k5c_setup_fast(kr, kr->fast_val == K5C_FAST_DEMAND);
+            if (kerr != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, "Cannot set up FAST\n");
+                return kerr;
+            }
+        }
+    }
+
+    return 0;
+}
+
 int main(int argc, const char *argv[])
 {
     struct krb5_req *kr = NULL;
@@ -2207,6 +2244,7 @@ int main(int argc, const char *argv[])
     poptContext pc;
     int debug_fd = -1;
     errno_t ret;
+    krb5_error_code kerr;
 
     struct poptOption long_options[] = {
         POPT_AUTOHELP
@@ -2274,6 +2312,23 @@ int main(int argc, const char *argv[])
 
     close(STDIN_FILENO);
 
+    kerr = privileged_krb5_setup(kr, offline);
+    if (kerr != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "privileged_krb5_setup failed.\n");
+        ret = EFAULT;
+        goto done;
+    }
+
+    kerr = become_user(kr->uid, kr->gid);
+    if (kerr != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
+        ret = EFAULT;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_INTERNAL,
+          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
+
     ret = k5c_setup(kr, offline);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_child_setup failed.\n");
-- 
1.9.3