From 0c7f33bb6b16ef7dd27816489d9ec0b5c758c64f Mon Sep 17 00:00:00 2001 From: Sumit Bose 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 --- 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