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