From 3f32e79858f268ce6501de44e5158e8c12f688dd Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 22 Mar 2017 13:01:18 +0100 Subject: [PATCH 72/72] KRB5: Authenticate users in a non-POSIX domain using a MEMORY ccache Related to: https://pagure.io/SSSD/sssd/issue/3310 The following changes were done to the Kerberos authentication code in order to support authentication in a non-POSIX environment: - delayed authentication is disabled in non-POSIX domains - when a user logs in in a non-POSIX domain, SSSD uses a MEMORY:$username ccache and destroys is then krb5_child finishes so that just the numeric result is used - krb5_child doesn't drop privileges in this configuration because there is nothing to drop privileges to Reviewed-by: Sumit Bose --- src/providers/krb5/krb5_auth.c | 62 ++++++++++++++++------ src/providers/krb5/krb5_auth.h | 2 + src/providers/krb5/krb5_child.c | 32 +++++++++-- src/providers/krb5/krb5_child_handler.c | 15 +++++- .../krb5/krb5_delayed_online_authentication.c | 7 +++ src/providers/krb5/krb5_init.c | 3 ++ 6 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index c2d6d7eeacc1f766024c4d629f25fd0f0be24e5e..2faf18d17a735476c20f9cc27b15be4a39cadc5c 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -42,6 +42,8 @@ #include "providers/krb5/krb5_utils.h" #include "providers/krb5/krb5_ccache.h" +#define NON_POSIX_CCNAME_FMT "MEMORY:sssd_nonposix_dummy_%u" + static int krb5_mod_ccname(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *domain, @@ -200,6 +202,7 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx, talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup); kr->pd = pd; + kr->dom = dom; kr->krb5_ctx = krb5_ctx; ret = get_krb_primary(krb5_ctx->name_to_primary, @@ -275,8 +278,11 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, return; } - ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); - if (ret != EOK) { + ret = add_user_to_delayed_online_authentication(krb5_ctx, domain, pd, uid); + if (ret == ENOTSUP) { + /* This error is not fatal */ + DEBUG(SSSDBG_MINOR_FAILURE, "Delayed authentication not supported\n"); + } else if (ret != EOK) { /* This error is not fatal */ DEBUG(SSSDBG_CRIT_FAILURE, "add_user_to_delayed_online_authentication failed.\n"); @@ -291,21 +297,43 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr, { const char *ccname_template; - ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL); + switch (kr->dom->type) { + case DOM_TYPE_POSIX: + ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL); - kr->ccname = expand_ccname_template(kr, kr, ccname_template, - kr->krb5_ctx->illegal_path_re, true, - be_ctx->domain->case_sensitive); - if (kr->ccname == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n"); - return ENOMEM; - } + kr->ccname = expand_ccname_template(kr, kr, ccname_template, + kr->krb5_ctx->illegal_path_re, true, + be_ctx->domain->case_sensitive); + if (kr->ccname == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n"); + return ENOMEM; + } - kr->old_ccname = ldb_msg_find_attr_as_string(user_msg, - SYSDB_CCACHE_FILE, NULL); - if (kr->old_ccname == NULL) { - DEBUG(SSSDBG_TRACE_LIBS, - "No ccache file for user [%s] found.\n", kr->pd->user); + kr->old_ccname = ldb_msg_find_attr_as_string(user_msg, + SYSDB_CCACHE_FILE, NULL); + if (kr->old_ccname == NULL) { + DEBUG(SSSDBG_TRACE_LIBS, + "No ccache file for user [%s] found.\n", kr->pd->user); + } + break; + case DOM_TYPE_APPLICATION: + DEBUG(SSSDBG_TRACE_FUNC, + "Domain type application, will use in-memory ccache\n"); + /* We don't care about using cryptographic randomness, just + * a non-predictable ccname, so using rand() here is fine + */ + kr->ccname = talloc_asprintf(kr, + NON_POSIX_CCNAME_FMT, + rand() % UINT_MAX); + if (kr->ccname == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n"); + return ENOMEM; + } + + break; + default: + DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported domain type\n"); + return EINVAL; } return EOK; @@ -617,7 +645,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, kr->uid = sss_view_ldb_msg_find_attr_as_uint64(state->domain, res->msgs[0], SYSDB_UIDNUM, 0); - if (kr->uid == 0) { + if (kr->uid == 0 && state->domain->type == DOM_TYPE_POSIX) { DEBUG(SSSDBG_CONF_SETTINGS, "UID for user [%s] not known.\n", pd->user); ret = ENOENT; @@ -627,7 +655,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, kr->gid = sss_view_ldb_msg_find_attr_as_uint64(state->domain, res->msgs[0], SYSDB_GIDNUM, 0); - if (kr->gid == 0) { + if (kr->gid == 0 && state->domain->type == DOM_TYPE_POSIX) { DEBUG(SSSDBG_CONF_SETTINGS, "GID for user [%s] not known.\n", pd->user); ret = ENOENT; diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h index 75ad916e79b29043120543ab3c4c1bd27e09d913..8ad3aeff21e58f9055ae144eaa450992c6391ba6 100644 --- a/src/providers/krb5/krb5_auth.h +++ b/src/providers/krb5/krb5_auth.h @@ -50,6 +50,7 @@ struct krb5child_req { struct pam_data *pd; struct krb5_ctx *krb5_ctx; + struct sss_domain_info *dom; const char *ccname; const char *old_ccname; @@ -118,6 +119,7 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len, struct krb5_child_response **_res); errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, + struct sss_domain_info *domain, struct pam_data *pd, uid_t uid); errno_t init_delayed_online_authentication(struct krb5_ctx *krb5_ctx, diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index a4128dda6b0861a95dba223047d66c4158b1afb6..cbbc892bee0365892ac66d3654c974d325166b60 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -80,6 +80,7 @@ struct krb5_req { char *ccname; char *keytab; bool validate; + bool posix_domain; bool send_pac; bool use_enterprise_princ; char *fast_ccname; @@ -102,6 +103,16 @@ struct krb5_req { static krb5_context krb5_error_ctx; #define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error) +static errno_t k5c_become_user(uid_t uid, gid_t gid, bool is_posix) +{ + if (is_posix == false) { + DEBUG(SSSDBG_TRACE_FUNC, + "Will not drop privileges for a non-POSIX user\n"); + return EOK; + } + return become_user(uid, gid); +} + static krb5_error_code set_lifetime_options(struct cli_opts *cli_opts, krb5_get_init_creds_opt *options) { @@ -1561,6 +1572,15 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n"); } + /* In a non-POSIX environment, we only care about the return code from + * krb5_child, so let's not even attempt to create the ccache + */ + if (kr->posix_domain == false) { + DEBUG(SSSDBG_TRACE_LIBS, + "Finished authentication in a non-POSIX domain\n"); + goto done; + } + /* If kr->ccname is cache collection (DIR:/...), we want to work * directly with file ccache (DIR::/...), but cache collection * should be returned back to back end. @@ -2146,6 +2166,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, size_t p = 0; uint32_t len; uint32_t validate; + uint32_t posix_domain; uint32_t send_pac; uint32_t use_enterprise_princ; struct pam_data *pd; @@ -2167,6 +2188,8 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, SAFEALIGN_COPY_UINT32_CHECK(&kr->gid, buf + p, size, &p); SAFEALIGN_COPY_UINT32_CHECK(&validate, buf + p, size, &p); kr->validate = (validate == 0) ? false : true; + SAFEALIGN_COPY_UINT32_CHECK(&posix_domain, buf + p, size, &p); + kr->posix_domain = (posix_domain == 0) ? false : true; SAFEALIGN_COPY_UINT32_CHECK(offline, buf + p, size, &p); SAFEALIGN_COPY_UINT32_CHECK(&send_pac, buf + p, size, &p); kr->send_pac = (send_pac == 0) ? false : true; @@ -2331,6 +2354,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, krb5_context ctx, uid_t fast_uid, gid_t fast_gid, + bool posix_domain, struct cli_opts *cli_opts, const char *primary, const char *realm, @@ -2420,7 +2444,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, /* Try to carry on */ } - kerr = become_user(fast_uid, fast_gid); + kerr = k5c_become_user(fast_uid, fast_gid, posix_domain); if (kerr != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed: %d\n", kerr); exit(1); @@ -2572,7 +2596,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand) } kerr = check_fast_ccache(kr, kr->ctx, kr->fast_uid, kr->fast_gid, - kr->cli_opts, + kr->posix_domain, kr->cli_opts, fast_principal, fast_principal_realm, kr->keytab, &kr->fast_ccname); if (kerr != 0) { @@ -2773,7 +2797,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) * the user who is logging in. The same applies to the offline case * the user who is logging in. The same applies to the offline case. */ - kerr = become_user(kr->uid, kr->gid); + kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain); if (kerr != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n"); return kerr; @@ -3075,7 +3099,7 @@ int main(int argc, const char *argv[]) if ((sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN && sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_KEYPAD)) { - kerr = become_user(kr->uid, kr->gid); + kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain); if (kerr != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n"); ret = EFAULT; diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index 680e67b089fcb32280352af24aae35af133a52f3..87e79a06e917aadb622455bccfc2e9c6769f70c2 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -107,6 +107,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, uint32_t validate; uint32_t send_pac; uint32_t use_enterprise_principal; + uint32_t posix_domain; size_t username_len = 0; errno_t ret; @@ -131,6 +132,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, break; } + switch (kr->dom->type) { + case DOM_TYPE_POSIX: + posix_domain = 1; + break; + case DOM_TYPE_APPLICATION: + posix_domain = 0; + break; + default: + return EINVAL; + } + if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) { use_enterprise_principal = false; } else { @@ -151,7 +163,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, kr->pd->cmd == SSS_CMD_RENEW || kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + + buf->size += 5*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + sss_authtok_get_size(kr->pd->authtok); buf->size += sizeof(uint32_t); @@ -182,6 +194,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp); SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp); SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp); + SAFEALIGN_COPY_UINT32(&buf->data[rp], &posix_domain, &rp); SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp); SAFEALIGN_COPY_UINT32(&buf->data[rp], &send_pac, &rp); SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp); diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c index bf2ef775573ba6bad79a99ad43b5d9748516e794..1cb7eade0e4cb9afbc4d031a07b3519ba08456d6 100644 --- a/src/providers/krb5/krb5_delayed_online_authentication.c +++ b/src/providers/krb5/krb5_delayed_online_authentication.c @@ -234,6 +234,7 @@ static void delayed_online_authentication_callback(void *private_data) } errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, + struct sss_domain_info *domain, struct pam_data *pd, uid_t uid) { @@ -242,6 +243,12 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, hash_value_t value; struct pam_data *new_pd; + if (domain->type != DOM_TYPE_POSIX) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Domain type does not support delayed authentication\n"); + return ENOTSUP; + } + if (krb5_ctx->deferred_auth_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Missing context for delayed online authentication.\n"); diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c index 12c8dfcc49af75de619ec0858aaff81504698273..66ae68fb4773af3987f2062246bc6493107c74d5 100644 --- a/src/providers/krb5/krb5_init.c +++ b/src/providers/krb5/krb5_init.c @@ -136,6 +136,9 @@ errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx, return ENOMEM; } + /* Only needed to generate random ccache names for non-POSIX domains */ + srand(time(NULL) * getpid()); + ret = sss_krb5_get_options(ctx, be_ctx->cdb, be_ctx->conf_path, &ctx->opts); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get krb5 options [%d]: %s\n", -- 2.9.3