URL: https://github.com/SSSD/sssd/pull/5450 Author: justin-stephenson Title: #5450: kcm: add support for kerberos tgt renewals Action: synchronized
To pull the PR as Git branch: git remote add ghsssd https://github.com/SSSD/sssd git fetch ghsssd pull/5450/head:pr5450 git checkout pr5450
From 82161222b68fea341c5d0f34af603086ae9371eb Mon Sep 17 00:00:00 2001 From: Justin Stephenson <jstep...@redhat.com> Date: Tue, 1 Dec 2020 11:28:59 -0500 Subject: [PATCH 1/7] KCM: Read and set KCM renewal and krb5 options Add new renewal options to enable KCM renewal functionality tgt_renewal tgt_renewal_inherit Krb5 options below will be read from the [kcm] configuration section, or a domain section when a tgt_renewal_inherit domain is provided. krb5_renew_interval krb5_renew_lifetime krb5_lifetime krb5_validate krb5_canonicalize krb5_auth_timeout --- Makefile.am | 3 + src/confdb/confdb.h | 8 + src/config/cfg_rules.ini | 8 + src/man/sssd-kcm.8.xml | 49 ++++++ src/responder/kcm/kcm.c | 43 +++++ src/responder/kcm/kcm_renew.c | 316 ++++++++++++++++++++++++++++++++++ src/responder/kcm/kcm_renew.h | 3 + 7 files changed, 430 insertions(+) create mode 100644 src/responder/kcm/kcm_renew.c create mode 100644 src/responder/kcm/kcm_renew.h diff --git a/Makefile.am b/Makefile.am index 7bb4d6e9d2..bfc50f1e69 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1798,6 +1798,8 @@ sssd_kcm_SOURCES = \ src/responder/kcm/kcmsrv_ccache_secdb.c \ src/responder/kcm/kcmsrv_ops.c \ src/responder/kcm/kcmsrv_op_queue.c \ + src/providers/krb5/krb5_opts.c \ + src/providers/data_provider_opts.c \ src/util/sss_sockets.c \ src/util/sss_krb5.c \ src/util/sss_iobuf.c \ @@ -1815,6 +1817,7 @@ sssd_kcm_LDADD = \ $(KRB5_LIBS) \ $(JANSSON_LIBS) \ $(SSSD_LIBS) \ + $(CARES_LIBS) \ $(UUID_LIBS) \ $(SYSTEMD_DAEMON_LIBS) \ $(SSSD_INTERNAL_LTLIBS) \ diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index 2290217739..437a473d5e 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -289,6 +289,14 @@ #define CONFDB_KCM_MAX_CCACHES "max_ccaches" #define CONFDB_KCM_MAX_UID_CCACHES "max_uid_ccaches" #define CONFDB_KCM_MAX_CCACHE_SIZE "max_ccache_size" +#define CONFDB_KCM_TGT_RENEWAL "tgt_renewal" +#define CONFDB_KCM_TGT_RENEWAL_INHERIT "tgt_renewal_inherit" +#define CONFDB_KCM_KRB5_LIFETIME "krb5_lifetime" +#define CONFDB_KCM_KRB5_RENEWABLE_LIFETIME "krb5_renewable_lifetime" +#define CONFDB_KCM_KRB5_RENEW_INTERVAL "krb5_renew_interval" +#define CONFDB_KCM_KRB5_VALIDATE "krb5_validate" +#define CONFDB_KCM_KRB5_CANONICALIZE "krb5_canonicalize" +#define CONFDB_KCM_KRB5_AUTH_TIMEOUT "krb5_auth_timeout" /* Certificate mapping rules */ #define CONFDB_CERTMAP_BASEDN "cn=certmap,cn=config" diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index 149b4d78ef..a247b3bff2 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -330,6 +330,14 @@ option = responder_idle_timeout option = max_ccaches option = max_uid_ccaches option = max_ccache_size +option = tgt_renewal +option = tgt_renewal_inherit +option = krb5_lifetime +option = krb5_renewable_lifetime +option = krb5_renew_interval +option = krb5_validate +option = krb5_canonicalize +option = krb5_auth_timeout # Session recording [rule/allowed_session_recording_options] diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml index 14ba122a5c..5f81af7367 100644 --- a/src/man/sssd-kcm.8.xml +++ b/src/man/sssd-kcm.8.xml @@ -162,6 +162,42 @@ systemctl restart sssd-kcm.service </para> </refsect1> + <refsect1 id='renewals'> + <title>RENEWALS</title> + <para> + The sssd-kcm service can be configured to attempt TGT + renewal for renewable TGTs stored in the KCM ccache. + Renewals are only attempted when half of the ticket + lifetime has been reached. KCM Renewals are configured + when the following option is set in the [kcm] section: + <programlisting> +krb5_renew_interval + </programlisting> + </para> + <para> + If [kcm] section renewal options are absent, SSSD will + fallback to using the krb5_* options listed below from + the *first* auth_provider=krb5 domain, if available. + </para> + <para> + The following krb5 options can be configured in the + [kcm] section to control renewal behavior, these + options are described in detail in the + <citerefentry> + <refentrytitle>sssd-krb5</refentrytitle> + <manvolnum>5</manvolnum> + </citerefentry> manual page. + <programlisting> + krb5_renew_interval + krb5_renew_lifetime + krb5_lifetime + krb5_validate + krb5_canonicalize + krb5_auth_timeout + </programlisting> + </para> + </refsect1> + <refsect1 id='options'> <title>CONFIGURATION OPTIONS</title> <para> @@ -249,6 +285,19 @@ systemctl restart sssd-kcm.service </para> </listitem> </varlistentry> + <varlistentry> + <term>krb5_renew_interval (integer)</term> + <listitem> + <para> + The time in seconds between TGT renewal attempts for + all KCM-stored renewable tickets. Renewals only trigger + when about half of their ticket lifetime is exceeded. + </para> + <para> + Default: 0 (Automatic renewal is disabled) + </para> + </listitem> + </varlistentry> </variablelist> </refsect1> diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c index 97e37a0144..609ca1220a 100644 --- a/src/responder/kcm/kcm.c +++ b/src/responder/kcm/kcm.c @@ -25,7 +25,9 @@ #include "responder/kcm/kcmsrv_ccache.h" #include "responder/kcm/kcmsrv_pvt.h" +#include "responder/kcm/kcm_renew.h" #include "responder/common/responder.h" +#include "providers/krb5/krb5_common.h" #include "util/util.h" #include "util/sss_krb5.h" @@ -48,6 +50,39 @@ static int kcm_responder_ctx_destructor(void *ptr) return 0; } +static errno_t kcm_renewals_init(struct tevent_context *ev, + struct resp_ctx *rctx, + struct kcm_ctx *kctx, + struct krb5_ctx *krb5_ctx, + time_t renew_intv, + bool *_renewal_enabled) +{ +#ifndef HAVE_KCM_RENEWAL + return EOK; +#else + errno_t ret; + + ret = kcm_get_renewal_config(kctx, &krb5_ctx, &renew_intv); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "fatal error getting KCM renewal config\n"); + return ret; + } + + if (renew_intv > 0) { + *_renewal_enabled = true; + + ret = kcm_renewals_setup(rctx, krb5_ctx, ev, kctx->kcm_data->db, renew_intv); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "fatal error initializing KCM renewals\n"); + return ret; + } + } + + return EOK; +#endif +} + static errno_t kcm_get_ccdb_be(struct kcm_ctx *kctx) { errno_t ret; @@ -210,6 +245,8 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, { struct resp_ctx *rctx; struct kcm_ctx *kctx; + struct krb5_ctx *krb5_ctx = NULL; + time_t renew_intv = 0; int ret; rctx = talloc_zero(mem_ctx, struct resp_ctx); @@ -254,6 +291,12 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, goto fail; } + ret = kcm_renewals_init(ev, rctx, kctx, krb5_ctx, renew_intv); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "fatal error getting KCM renewal config\n"); + goto fail; + } + /* Set up file descriptor limits */ responder_set_fd_limit(kctx->fd_limit); diff --git a/src/responder/kcm/kcm_renew.c b/src/responder/kcm/kcm_renew.c new file mode 100644 index 0000000000..2a9bda8312 --- /dev/null +++ b/src/responder/kcm/kcm_renew.c @@ -0,0 +1,316 @@ +extern struct dp_option default_krb5_opts[]; + +struct kcm_renew_tgt_ctx { + struct tevent_context *ev; + struct krb5child_req *kr; + + struct krb5_ctx *krb5_ctx; + struct auth_data *auth_data; + + uint8_t *buf; + ssize_t len; +}; + +struct auth_data { + struct krb5_ctx *krb5_ctx; + uid_t uid; + gid_t gid; + const char *ccname; + const char *upn; +}; + +static void kcm_renew_tgt_done(struct tevent_req *req); + +static errno_t kcm_set_options(struct krb5_ctx *krb5_ctx, + char *lifetime, + char *rtime, + bool validate, + bool canonicalize, + int timeout, + char *renew_intv, + time_t *_renew_intv_tm) +{ + errno_t ret; + krb5_error_code kerr; + krb5_deltat renew_interval_delta; + + if (renew_intv != NULL) { + kerr = krb5_string_to_deltat(renew_intv, &renew_interval_delta); + if (kerr != 0) { + DEBUG(SSSDBG_FATAL_FAILURE, "krb5_string_to_deltat failed\n"); + ret = ENOMEM; + goto done; + } + + *_renew_intv_tm = renew_interval_delta; + } else { + *_renew_intv_tm = 0; + } + + if (lifetime != NULL) { + ret = krb5_string_to_deltat(lifetime, &krb5_ctx->lifetime); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to convert lifetime string.\n"); + goto done; + } + krb5_ctx->lifetime_str = lifetime; + } + + if (rtime != 0) { + ret = krb5_string_to_deltat(rtime, &krb5_ctx->rlife); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to convert renewable lifetime " + "string.\n"); + goto done; + } + } + + ret = dp_opt_set_bool(krb5_ctx->opts, KRB5_VALIDATE, validate); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot set krb5 child timeout\n"); + goto done; + } + + krb5_ctx->canonicalize = canonicalize; + + if (timeout > 0) { + ret = dp_opt_set_int(krb5_ctx->opts, KRB5_AUTH_TIMEOUT, timeout); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot set krb5 child timeout\n"); + goto done; + } + } + + ret = EOK; +done: + return ret; +} + +static errno_t kcm_read_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *cpath, + char **_lifetime, + char **_rtime, + bool *_validate, + bool *_canonicalize, + int *_timeout, + char **_renew_intv) +{ + TALLOC_CTX *tmp_ctx; + char *lifetime; + char *rtime; + bool validate; + bool canonicalize; + int timeout; + char *renew_intv; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = confdb_get_string(cdb, tmp_ctx, cpath, + CONFDB_KCM_KRB5_LIFETIME, NULL, + &lifetime); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot read %s/%s [%d]: %s\n", cpath, + CONFDB_KCM_KRB5_LIFETIME, ret, sss_strerror(ret)); + goto done; + } + + ret = confdb_get_string(cdb, tmp_ctx, cpath, + CONFDB_KCM_KRB5_RENEWABLE_LIFETIME, NULL, + &rtime); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot read %s/%s [%d]: %s\n", cpath, + CONFDB_KCM_KRB5_RENEWABLE_LIFETIME, ret, sss_strerror(ret)); + goto done; + } + + ret = confdb_get_bool(cdb, cpath, + CONFDB_KCM_KRB5_VALIDATE, false, + &validate); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot read %s/%s [%d]: %s\n", cpath, + CONFDB_KCM_KRB5_VALIDATE, ret, sss_strerror(ret)); + goto done; + } + + ret = confdb_get_bool(cdb, cpath, + CONFDB_KCM_KRB5_CANONICALIZE, false, + &canonicalize); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot read %s/%s [%d]: %s\n", cpath, + CONFDB_KCM_KRB5_CANONICALIZE, ret, sss_strerror(ret)); + goto done; + } + + ret = confdb_get_int(cdb, cpath, + CONFDB_KCM_KRB5_AUTH_TIMEOUT, 0, + &timeout); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot read %s/%s [%d]: %s\n", cpath, + CONFDB_KCM_KRB5_AUTH_TIMEOUT, ret, sss_strerror(ret)); + goto done; + } + + ret = confdb_get_string(cdb, tmp_ctx, cpath, + CONFDB_KCM_KRB5_RENEW_INTERVAL, NULL, + &renew_intv); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot read %s/%s [%d]: %s\n", cpath, + CONFDB_KCM_KRB5_AUTH_TIMEOUT, ret, sss_strerror(ret)); + goto done; + } + + + *_lifetime = talloc_steal(mem_ctx, lifetime); + *_rtime = talloc_steal(mem_ctx, rtime); + *_validate = validate; + *_canonicalize = canonicalize; + *_timeout = timeout; + *_renew_intv = renew_intv; + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +int kcm_get_renewal_config(struct kcm_ctx *kctx, + struct krb5_ctx **_krb5_ctx, + time_t *_renew_intv) +{ + int ret; + struct krb5_ctx *krb5_ctx; + char *lifetime; + char *rtime; + bool validate; + bool canonicalize; + int timeout; + char *renew_intv; + time_t renew_intv_tm; + bool tgt_renewal; + char *tgt_renewal_inherit; + const char *conf_path; + int i; + + krb5_ctx = talloc_zero(kctx->rctx, struct krb5_ctx); + if (krb5_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "fatal error allocating krb5_ctx\n"); + ret = ENOMEM; + goto done; + } + + /* Set default Kerberos options */ + krb5_ctx->opts = talloc_zero_array(krb5_ctx, struct dp_option, KRB5_OPTS); + if (krb5_ctx->opts == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "fatal error allocating krb5_ctx opts\n"); + ret = ENOMEM; + goto done; + } + + for (i = 0; i < KRB5_OPTS; i++) { + krb5_ctx->opts[i].opt_name = default_krb5_opts[i].opt_name; + krb5_ctx->opts[i].type = default_krb5_opts[i].type; + krb5_ctx->opts[i].def_val = default_krb5_opts[i].def_val; + switch (krb5_ctx->opts[i].type) { + case DP_OPT_STRING: + ret = dp_opt_set_string(krb5_ctx->opts, i, + default_krb5_opts[i].def_val.string); + break; + case DP_OPT_BLOB: + ret = dp_opt_set_blob(krb5_ctx->opts, i, + default_krb5_opts[i].def_val.blob); + break; + case DP_OPT_NUMBER: + ret = dp_opt_set_int(krb5_ctx->opts, i, + default_krb5_opts[i].def_val.number); + break; + case DP_OPT_BOOL: + ret = dp_opt_set_bool(krb5_ctx->opts, i, + default_krb5_opts[i].def_val.boolean); + break; + } + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed setting default KCM kerberos " + "options\n"); + talloc_free(krb5_ctx->opts); + goto done; + } + } + + ret = confdb_get_bool(kctx->rctx->cdb, + kctx->rctx->confdb_service_path, + CONFDB_KCM_TGT_RENEWAL, false, + &tgt_renewal); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot get KCM TGT Renewal\n"); + goto done; + } + + if (tgt_renewal == false) { + goto done; + } + + ret = confdb_get_string(kctx->rctx->cdb, + kctx->rctx, + kctx->rctx->confdb_service_path, + CONFDB_KCM_TGT_RENEWAL_INHERIT, + NULL, + &tgt_renewal_inherit); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot get KCM TGT Renewal Inherit\n"); + goto done; + } + + /* Override with config options */ + if (tgt_renewal_inherit == NULL) { + ret = kcm_read_options(kctx, kctx->rctx->cdb, kctx->rctx->confdb_service_path, + &lifetime, &rtime, &validate, &canonicalize, + &timeout, &renew_intv); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to read KCM renewal options\n"); + goto done; + } + } else { + conf_path = talloc_asprintf(kctx->rctx, CONFDB_DOMAIN_PATH_TMPL, + tgt_renewal_inherit); + if (conf_path == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n"); + ret = ENOMEM; + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Inherit KCM options for domain [%s]\n", conf_path); + ret = kcm_read_options(kctx, kctx->rctx->cdb, conf_path, + &lifetime, &rtime, &validate, &canonicalize, + &timeout, &renew_intv); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed reading domain inherit renewal options\n"); + goto done; + } + } + + ret = kcm_set_options(krb5_ctx, lifetime, rtime, validate, canonicalize, + timeout, renew_intv, &renew_intv_tm); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed setting KCM renewal options\n"); + goto done; + } + + *_renew_intv = renew_intv_tm; + *_krb5_ctx = krb5_ctx; + ret = EOK; +done: + if (ret != EOK) { + talloc_free(krb5_ctx); + } + return ret; +} + + diff --git a/src/responder/kcm/kcm_renew.h b/src/responder/kcm/kcm_renew.h new file mode 100644 index 0000000000..0bb1bf8d5c --- /dev/null +++ b/src/responder/kcm/kcm_renew.h @@ -0,0 +1,3 @@ +int kcm_get_renewal_config(struct kcm_ctx *kctx, + struct krb5_ctx **_krb5_ctx); + From 5617633fbf5ff30b95a5f613f8c6e6ced85b1ad4 Mon Sep 17 00:00:00 2001 From: Justin Stephenson <jstep...@redhat.com> Date: Mon, 3 May 2021 18:21:37 +0000 Subject: [PATCH 2/7] KCM: Prepare and execute renewals Find and unmarshal renewable tickets in the list of KCM ccaches, process and trigger renewals for tgts aftert half of their lifetime is exceeded. --- Makefile.am | 3 + src/providers/krb5/krb5_child_handler.c | 12 +- src/responder/kcm/kcm.c | 2 +- src/responder/kcm/kcm_renew.c | 428 +++++++++++++++++++++++ src/responder/kcm/kcm_renew.h | 51 ++- src/responder/kcm/kcmsrv_ccache.c | 124 +++++++ src/responder/kcm/kcmsrv_ccache.h | 16 + src/responder/kcm/kcmsrv_ccache_be.h | 9 + src/responder/kcm/kcmsrv_ccache_binary.c | 2 +- src/responder/kcm/kcmsrv_ccache_secdb.c | 172 +++++++++ src/util/secrets/secrets.c | 89 +++++ src/util/secrets/secrets.h | 7 + src/util/sss_krb5.c | 10 + src/util/sss_krb5.h | 5 + 14 files changed, 919 insertions(+), 11 deletions(-) diff --git a/Makefile.am b/Makefile.am index bfc50f1e69..d23fb9473a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -766,6 +766,7 @@ dist_noinst_HEADERS = \ src/responder/secrets/secsrv_private.h \ src/responder/secrets/secsrv_local.h \ src/responder/secrets/secsrv_proxy.h \ + src/responder/kcm/kcm_renew.h \ src/responder/kcm/kcmsrv_pvt.h \ src/responder/kcm/kcmsrv_ccache.h \ src/responder/kcm/kcmsrv_ccache_pvt.h \ @@ -1789,6 +1790,7 @@ endif if BUILD_KCM sssd_kcm_SOURCES = \ src/responder/kcm/kcm.c \ + src/responder/kcm/kcm_renew.c \ src/responder/kcm/kcmsrv_cmd.c \ src/responder/kcm/kcmsrv_ccache.c \ src/responder/kcm/kcmsrv_ccache_binary.c \ @@ -1799,6 +1801,7 @@ sssd_kcm_SOURCES = \ src/responder/kcm/kcmsrv_ops.c \ src/responder/kcm/kcmsrv_op_queue.c \ src/providers/krb5/krb5_opts.c \ + src/providers/krb5/krb5_child_handler.c \ src/providers/data_provider_opts.c \ src/util/sss_sockets.c \ src/util/sss_krb5.c \ diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index 155ae3c3c9..f601bb7b8e 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -113,7 +113,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; + uint32_t posix_domain = 0; size_t username_len = 0; errno_t ret; @@ -138,14 +138,10 @@ static errno_t create_send_buffer(struct krb5child_req *kr, break; } - switch (kr->dom->type) { - case DOM_TYPE_POSIX: + /* Renewals from KCM do not initialize kr->dom */ + if (kr->pd->cmd == SSS_CMD_RENEW || kr->dom->type == DOM_TYPE_POSIX) { posix_domain = 1; - break; - case DOM_TYPE_APPLICATION: - posix_domain = 0; - break; - default: + } else if (kr->dom->type != DOM_TYPE_APPLICATION) { return EINVAL; } diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c index 609ca1220a..754d1dd197 100644 --- a/src/responder/kcm/kcm.c +++ b/src/responder/kcm/kcm.c @@ -71,7 +71,7 @@ static errno_t kcm_renewals_init(struct tevent_context *ev, if (renew_intv > 0) { *_renewal_enabled = true; - ret = kcm_renewals_setup(rctx, krb5_ctx, ev, kctx->kcm_data->db, renew_intv); + ret = kcm_renewal_setup(rctx, krb5_ctx, ev, kctx->kcm_data->db, renew_intv); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing KCM renewals\n"); diff --git a/src/responder/kcm/kcm_renew.c b/src/responder/kcm/kcm_renew.c index 2a9bda8312..6f8132ebab 100644 --- a/src/responder/kcm/kcm_renew.c +++ b/src/responder/kcm/kcm_renew.c @@ -1,3 +1,36 @@ +/* + SSSD + + KCM Kerberos renewals -- Renew a TGT automatically + + Authors: + Justin Stephenson <jstep...@redhat.com> + + Copyright (C) 2020 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "util/util.h" +#include "providers/krb5/krb5_common.h" +#include "providers/krb5/krb5_auth.h" +#include "providers/krb5/krb5_utils.h" +#include "providers/krb5/krb5_ccache.h" +#include "responder/kcm/kcmsrv_ccache.h" +#include "responder/kcm/kcmsrv_pvt.h" +#include "responder/kcm/kcmsrv_ccache_pvt.h" +#include "responder/kcm/kcm_renew.h" + extern struct dp_option default_krb5_opts[]; struct kcm_renew_tgt_ctx { @@ -313,4 +346,399 @@ int kcm_get_renewal_config(struct kcm_ctx *kctx, return ret; } +static errno_t kcm_child_req_setup(TALLOC_CTX *mem_ctx, + struct auth_data *auth_data, + struct krb5_ctx *krb5_ctx, + struct krb5child_req **_req) +{ + struct krb5child_req *krreq; + const char *kcm_ccname = NULL; + errno_t ret; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Setup for renewal of [%s] " \ + "for principal name [%s]\n", + auth_data->upn, + auth_data->ccname); + + krreq = talloc_zero(mem_ctx, struct krb5child_req); + if (krreq == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "krreq talloc_zero failed\n"); + ret = ENOMEM; + goto fail; + } + krreq->krb5_ctx = krb5_ctx; + if (krreq->krb5_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to create allocate krb5_ctx\n"); + ret = ENOMEM; + goto fail; + } + + /* Set uid and gid */ + krreq->uid = auth_data->uid; + krreq->gid = auth_data->gid; + + kcm_ccname = talloc_asprintf(mem_ctx, "KCM:%s", + auth_data->ccname); + if (kcm_ccname == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to strdup ccname\n"); + ret = ENOMEM; + goto fail; + } + + krreq->upn = talloc_strdup(mem_ctx, auth_data->upn); + if (krreq->upn == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to strdup upn"); + ret = ENOMEM; + goto fail; + } + + krreq->ccname = kcm_ccname; + if (krreq->ccname == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to strdup ccname"); + ret = ENOMEM; + goto fail; + } + + /* Set PAM Data */ + krreq->pd = create_pam_data(krreq); + if (krreq->pd == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "create_pam_data failed\n"); + ret = ENOMEM; + goto fail; + } + + krreq->pd->cmd = SSS_CMD_RENEW; + krreq->pd->user = talloc_strdup(mem_ctx, auth_data->upn); + if (krreq->pd->user == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "talloc_strdup key failed\n"); + ret = ENOMEM; + goto fail; + } + + /* Set authtok values */ + sss_authtok_set_empty(krreq->pd->newauthtok); + + ret = sss_authtok_set_ccfile(krreq->pd->authtok, kcm_ccname, 0); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed setting authtok ccname\n"); + ret = ENOMEM; + goto fail; + } + + krreq->old_ccname = kcm_ccname; + if (krreq->old_ccname == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to strdup ccname"); + ret = ENOMEM; + goto fail; + } + + *_req = krreq; + return EOK; +fail: + talloc_zfree(krreq); + return ret; +} + +static void kcm_renew_tgt(struct tevent_context *ev, + struct tevent_immediate *imm, + void *private_data) +{ + struct auth_data *auth_data = talloc_get_type(private_data, + struct auth_data); + struct tevent_req *req; + struct kcm_renew_tgt_ctx *ctx = NULL; + errno_t ret; + + ctx = talloc_zero(auth_data, struct kcm_renew_tgt_ctx); + if (ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "ctx talloc_zero failed\n"); + return; + } + + ret = kcm_child_req_setup(auth_data, auth_data, + auth_data->krb5_ctx, &ctx->kr); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Cannot setup krchild request\n"); + talloc_free(auth_data); + return; + } + + req = handle_child_send(ctx, ev, ctx->kr); + if (req == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Cannot create child request\n"); + talloc_free(auth_data); + return; + } + + tevent_req_set_callback(req, kcm_renew_tgt_done, ctx); + + return; +} + +static void kcm_renew_tgt_done(struct tevent_req *req) +{ + struct kcm_renew_tgt_ctx *ctx = tevent_req_callback_data(req, + struct kcm_renew_tgt_ctx); + int ret; + struct krb5_child_response *res; + + ret = handle_child_recv(req, ctx, &ctx->buf, &ctx->len); + talloc_free(req); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "handle_child_recv failure\n"); + goto done; + } + ret = parse_krb5_child_response(ctx, ctx->buf, ctx->len, ctx->kr->pd, + 0, &res); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Krb5 child returned an error! Please " \ + "inspect the krb5_child.log file\n"); + goto done; + } + if (res->msg_status != EOK) { + DEBUG(SSSDBG_TRACE_FUNC, "Renewal failed - krb5_child [%d]\n", + res->msg_status); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Successfully renewed [%s]\n", res->ccname); +done: + talloc_zfree(ctx); + return; +} + +static errno_t kcm_creds_check_times(TALLOC_CTX *mem_ctx, + struct renew_tgt_ctx *renew_tgt_ctx, + krb5_creds *creds, + struct kcm_ccache *cc, + const char *client_name) +{ + struct tgt_times tgtt; + time_t now; + time_t start_renew; + struct auth_data *auth_data; + struct tevent_immediate *imm; + int ret; + + memset(&tgtt, 0, sizeof(tgtt)); + tgtt.authtime = creds->times.authtime; + tgtt.starttime = creds->times.starttime; + tgtt.endtime = creds->times.endtime; + tgtt.renew_till = creds->times.renew_till; + + now = time(NULL); + /* Attempt renewal only after half of the ticket lifetime has exceeded */ + start_renew = (time_t) (tgtt.starttime + 0.5 * (tgtt.endtime - tgtt.starttime)); + if (tgtt.renew_till >= tgtt.endtime && tgtt.renew_till >= now + && tgtt.endtime >= now && start_renew <= now) { + DEBUG(SSSDBG_TRACE_INTERNAL, "Renewal cred ready!\n"); + auth_data = talloc_zero(renew_tgt_ctx, struct auth_data); + if (auth_data == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n"); + ret = ENOMEM; + goto done; + } + + auth_data->krb5_ctx = renew_tgt_ctx->krb5_ctx; + auth_data->upn = talloc_strdup(auth_data, client_name); + auth_data->uid = cc->owner.uid; + auth_data->gid = cc->owner.gid; + auth_data->ccname = cc->name; + if (auth_data->upn == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + + imm = tevent_create_immediate(auth_data); + if (imm == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n"); + ret = ENOMEM; + goto done; + } + + tevent_schedule_immediate(imm, renew_tgt_ctx->ev, kcm_renew_tgt, + auth_data); + } else { + DEBUG(SSSDBG_TRACE_INTERNAL, "Time not applicable\n"); + } + + ret = EOK; +done: + return ret; +} + +errno_t kcm_renew_all_tgts(TALLOC_CTX *mem_ctx, + struct renew_tgt_ctx *renew_tgt_ctx, + struct kcm_ccache **cc_list) +{ + TALLOC_CTX *tmp_ctx; + size_t count = 0; + int ret; + struct kcm_ccache *cc; + char *client_name; + krb5_context krb_context; + krb5_creds **extracted_creds; + krb5_error_code kerr; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create tmp talloc_ctx\n"); + ret = ENOMEM; + goto done; + } + + if (cc_list == NULL) { + ret = EOK; + goto done; + } + + kerr = krb5_init_context(&krb_context); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to init context\n"); + goto done; + } + + count = talloc_array_length(cc_list); + if (count <= 1) { + DEBUG(SSSDBG_TRACE_FUNC, "No renewal entries found.\n"); + ret = EOK; + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Found [%lu] renewal entries.\n", count - 1); + for (int i = 0; i < count - 1; i++) { + cc = cc_list[i]; + DEBUG(SSSDBG_TRACE_FUNC, + "Checking ccache [%s] for creds to renew\n", cc->name); + + extracted_creds = kcm_cc_unmarshal(mem_ctx, krb_context, cc); + if (extracted_creds == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed unmarshalling creds\n"); + goto done; + } + + for (int j = 0; extracted_creds[j] != NULL; j++) { + kerr = krb5_unparse_name(mem_ctx, extracted_creds[j]->client, + &client_name); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed unparsing name\n"); + goto done; + } + + kcm_creds_check_times(mem_ctx, renew_tgt_ctx, extracted_creds[j], + cc, client_name); + } + } + + ret = EOK; +done: + if (tmp_ctx != NULL) { + talloc_free(tmp_ctx); + } + krb5_free_context(krb_context); + return ret; +} + +static void kcm_renew_tgt_timer_handler(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval current_time, + void *data) +{ + struct renew_tgt_ctx *renew_tgt_ctx = talloc_get_type(data, + struct renew_tgt_ctx); + errno_t ret; + struct timeval next; + struct kcm_ccache **cc_list; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failure in tmp_ctx talloc_new\n"); + return; + } + + /* forget the timer event, it will be freed by the tevent timer loop */ + renew_tgt_ctx->te = NULL; + + /* Reschedule timer */ + next = tevent_timeval_current_ofs(renew_tgt_ctx->timer_interval, 0); + renew_tgt_ctx->te = tevent_add_timer(ev, renew_tgt_ctx, + next, kcm_renew_tgt_timer_handler, + renew_tgt_ctx); + if (renew_tgt_ctx->te == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup timer\n"); + talloc_zfree(renew_tgt_ctx); + return; + } + + /* Prepare KCM ccache list for renewals */ + ret = kcm_ccdb_renew_tgts(renew_tgt_ctx->rctx, renew_tgt_ctx->krb5_ctx, + ev, renew_tgt_ctx->db, &cc_list); + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_ALL, "No ccache renewal entries to prepare.\n"); + ret = EOK; + return; + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to add KCM tickets to table.\n"); + talloc_zfree(renew_tgt_ctx); + return; + } + + ret = kcm_renew_all_tgts(tmp_ctx, renew_tgt_ctx, cc_list); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to attempt renewal of KCM ticket" + " table.\n"); + talloc_zfree(renew_tgt_ctx); + return; + } + + talloc_free(tmp_ctx); +} + +errno_t kcm_renewal_setup(struct resp_ctx *rctx, + struct krb5_ctx *krb5_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + time_t renew_intv) +{ + int ret; + struct timeval next; + + krb5_ctx->renew_tgt_ctx = talloc_zero(krb5_ctx, struct renew_tgt_ctx); + if (krb5_ctx->renew_tgt_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n"); + return ENOMEM; + } + + krb5_ctx->renew_tgt_ctx->rctx = rctx; + krb5_ctx->renew_tgt_ctx->krb5_ctx = krb5_ctx; + krb5_ctx->renew_tgt_ctx->db = db, + krb5_ctx->renew_tgt_ctx->ev = ev; + krb5_ctx->renew_tgt_ctx->timer_interval = renew_intv; + + /* Check KCM for tickets to renew */ + next = tevent_timeval_current_ofs(krb5_ctx->renew_tgt_ctx->timer_interval, + 0); + krb5_ctx->renew_tgt_ctx->te = tevent_add_timer(ev, krb5_ctx->renew_tgt_ctx, + next, + kcm_renew_tgt_timer_handler, + krb5_ctx->renew_tgt_ctx); + if (krb5_ctx->renew_tgt_ctx->te == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n"); + ret = ENOMEM; + goto fail; + } + + return EOK; + +fail: + talloc_zfree(krb5_ctx->renew_tgt_ctx); + return ret; +} diff --git a/src/responder/kcm/kcm_renew.h b/src/responder/kcm/kcm_renew.h index 0bb1bf8d5c..518221e547 100644 --- a/src/responder/kcm/kcm_renew.h +++ b/src/responder/kcm/kcm_renew.h @@ -1,3 +1,52 @@ +/* + SSSD + + KCM Renewal, private header file + + Authors: + Justin Stephenson <jstep...@redhat.com> + + Copyright (C) 2020 Red Hat + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __KCM_RENEW_H__ +#define __KCM_RENEW_H__ + +#include "providers/krb5/krb5_common.h" +#include "src/providers/krb5/krb5_ccache.h" +#include "util/sss_ptr_hash.h" + +struct renew_tgt_ctx { + struct kcm_ccache **cc_list; + struct tevent_context *ev; + struct krb5_ctx *krb5_ctx; + struct resp_ctx *rctx; + struct kcm_ccdb *db; + time_t timer_interval; + struct tevent_timer *te; +}; + + int kcm_get_renewal_config(struct kcm_ctx *kctx, - struct krb5_ctx **_krb5_ctx); + struct krb5_ctx **_krb5_ctx, + time_t *_renew_intv); + +errno_t kcm_renewal_setup(struct resp_ctx *rctx, struct krb5_ctx *kctx, + struct tevent_context *ev, struct kcm_ccdb *db, + time_t renew_intv); +#endif /* __KCM_RENEW_H__ */ diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c index 60eacd4516..ea250c4af0 100644 --- a/src/responder/kcm/kcmsrv_ccache.c +++ b/src/responder/kcm/kcmsrv_ccache.c @@ -24,10 +24,13 @@ #include "util/crypto/sss_crypto.h" #include "util/util.h" #include "util/sss_krb5.h" +#include "src/providers/krb5/krb5_ccache.h" +#include "responder/kcm/kcm_renew.h" #include "responder/kcm/kcmsrv_ccache.h" #include "responder/kcm/kcmsrv_ccache_pvt.h" #include "responder/kcm/kcmsrv_ccache_be.h" + static struct kcm_cred *kcm_cred_dup(TALLOC_CTX *mem_ctx, struct kcm_cred *crd); @@ -279,6 +282,85 @@ errno_t kcm_cc_set_header(struct kcm_ccache *cc, return EOK; } +struct kcm_unmarshall_ctx { + krb5_creds **creds; + krb5_context krb_ctx; +}; + +static int kcm_cc_unmarshall_destructor(struct kcm_unmarshall_ctx *kcm_uctx) +{ + int i; + + for (i = 0; kcm_uctx->creds[i] != NULL; i++) { + krb5_free_creds(kcm_uctx->krb_ctx, kcm_uctx->creds[i]); + } + + return 0; +} + +krb5_creds **kcm_cc_unmarshal(TALLOC_CTX *mem_ctx, + krb5_context krb_context, + struct kcm_ccache *cc) +{ + TALLOC_CTX *tmp_ctx; + struct kcm_cred *cred; + krb5_data *cred_data; + krb5_creds **cred_list; + errno_t ret; + krb5_error_code kerr; + struct kcm_unmarshall_ctx *kcm_uctx; + int i = 0; + int count = 0; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + goto done; + } + + kcm_uctx = talloc_zero(tmp_ctx, struct kcm_unmarshall_ctx); + if (kcm_uctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to talloc kcm_uctx\n"); + goto done; + } + + for (cred = kcm_cc_get_cred(cc); cred != NULL; cred = kcm_cc_next_cred(cred)) { + count++; + } + + cred_list = talloc_zero_array(tmp_ctx, krb5_creds *, count + 1); + + for (cred = kcm_cc_get_cred(cc); cred != NULL; cred = kcm_cc_next_cred(cred), i++) { + cred_data = talloc_zero(mem_ctx, struct _krb5_data); + if (cred_data == NULL) { + goto done; + } + ret = get_krb5_data_from_cred(tmp_ctx, cred->cred_blob, cred_data); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to convert to krb5_data\n"); + goto done; + } + + kerr = krb5_unmarshal_credentials(krb_context, cred_data, + &cred_list[i]); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to unmarshal creds\n"); + goto done; + } + } + + cred_list[count] = NULL; + kcm_uctx->krb_ctx = krb_context; + kcm_uctx->creds = cred_list; + talloc_set_destructor(kcm_uctx, kcm_cc_unmarshall_destructor); + + talloc_steal(mem_ctx, cred_list); + + return cred_list; +done: + talloc_free(tmp_ctx); + return NULL; +} + errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t _uuid) { if (crd == NULL) { @@ -293,6 +375,48 @@ struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd) return crd ? crd->cred_blob : NULL; } +errno_t kcm_ccdb_renew_tgts(TALLOC_CTX *mem_ctx, + struct krb5_ctx *krb5_ctx, + struct tevent_context *ev, + struct kcm_ccdb *ccdb, + struct kcm_ccache ***_cc_list) +{ + TALLOC_CTX *tmp_ctx; + struct kcm_ccache **cc; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + if (krb5_ctx == NULL || ev == NULL || ccdb == NULL) { + ret = EINVAL; + return ret; + } + + if (ccdb->ops->list_all_cc == NULL) { + DEBUG(SSSDBG_TRACE_INTERNAL, "List all cc function not available\n"); + ret = EINVAL; + goto done; + } + + ret = ccdb->ops->list_all_cc(tmp_ctx, krb5_ctx, ev, ccdb, &cc); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failure to execute ccdb renewal init\n"); + return ret; + } else if (ret == ENOENT) { + goto done; + } + + *_cc_list = talloc_steal(mem_ctx, cc); + + ret = EOK; +done: + + return ret; +} + struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct confdb_ctx *cdb, diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h index 77cf8f61d5..e3d5cbbe46 100644 --- a/src/responder/kcm/kcmsrv_ccache.h +++ b/src/responder/kcm/kcmsrv_ccache.h @@ -29,6 +29,7 @@ #include "util/util.h" #include "util/sss_iobuf.h" #include "util/util_creds.h" +#include "providers/krb5/krb5_common.h" #include "responder/kcm/kcmsrv_pvt.h" #define UUID_BYTES 16 @@ -112,6 +113,10 @@ errno_t kcm_cc_set_header(struct kcm_ccache *cc, const char *sec_key, struct cli_creds *client); +krb5_creds **kcm_cc_unmarshal(TALLOC_CTX *mem_ctx, + krb5_context krb_context, + struct kcm_ccache *cc); + errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t uuid); /* @@ -140,6 +145,14 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, const char *confdb_service_path, enum kcm_ccdb_be cc_be); +/* + * Prepare KCM ccache list for renewals + */ +errno_t kcm_ccdb_renew_tgts(TALLOC_CTX *mem_ctx, + struct krb5_ctx *kctx, + struct tevent_context *ev, + struct kcm_ccdb *cdb, + struct kcm_ccache ***_cc_list); /* * In KCM, each ccache name is usually in the form of "UID:<num> @@ -376,4 +389,7 @@ errno_t kcm_ccache_to_sec_input_binary(TALLOC_CTX *mem_ctx, struct kcm_ccache *cc, struct sss_iobuf **_payload); +errno_t bin_to_krb_data(TALLOC_CTX *mem_ctx, + struct sss_iobuf *buf, + krb5_data *out); #endif /* _KCMSRV_CCACHE_H_ */ diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h index 166af3a764..b7ea5e2454 100644 --- a/src/responder/kcm/kcmsrv_ccache_be.h +++ b/src/responder/kcm/kcmsrv_ccache_be.h @@ -62,6 +62,13 @@ typedef errno_t uuid_t dfl); +typedef errno_t +(*ccdb_list_all_cc_fn)(TALLOC_CTX *mem_ctx, + struct krb5_ctx *kctx, + struct tevent_context *ev, + struct kcm_ccdb *cdb, + struct kcm_ccache ***_cc_list); + typedef struct tevent_req * (*ccdb_list_send_fn)(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -173,6 +180,8 @@ struct kcm_ccdb_ops { ccdb_get_default_send_fn get_default_send; ccdb_get_default_recv_fn get_default_recv; + ccdb_list_all_cc_fn list_all_cc; + ccdb_list_send_fn list_send; ccdb_list_recv_fn list_recv; diff --git a/src/responder/kcm/kcmsrv_ccache_binary.c b/src/responder/kcm/kcmsrv_ccache_binary.c index 7bfdbf13bf..d2d5d2fa1e 100644 --- a/src/responder/kcm/kcmsrv_ccache_binary.c +++ b/src/responder/kcm/kcmsrv_ccache_binary.c @@ -141,7 +141,7 @@ errno_t kcm_ccache_to_sec_input_binary(TALLOC_CTX *mem_ctx, return ret; } -static errno_t bin_to_krb_data(TALLOC_CTX *mem_ctx, +errno_t bin_to_krb_data(TALLOC_CTX *mem_ctx, struct sss_iobuf *buf, krb5_data *out) { diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c index ea5c8f9ee3..3c44f57bb8 100644 --- a/src/responder/kcm/kcmsrv_ccache_secdb.c +++ b/src/responder/kcm/kcmsrv_ccache_secdb.c @@ -27,8 +27,12 @@ #include "util/util.h" #include "util/secrets/secrets.h" #include "util/crypto/sss_crypto.h" +#include "util/sss_krb5.h" +#include "util/strtonum.h" #include "responder/kcm/kcmsrv_ccache_pvt.h" #include "responder/kcm/kcmsrv_ccache_be.h" +#include "responder/kcm/kcm_renew.h" +#include "providers/krb5/krb5_ccache.h" #define KCM_SECDB_URL "/kcm/persistent" #define KCM_SECDB_BASE_FMT KCM_SECDB_URL"/%"SPRIuid"/" @@ -818,10 +822,176 @@ static errno_t ccdb_secdb_get_default_recv(struct tevent_req *req, return EOK; } +static errno_t ccdb_secdb_get_cc_for_uuid(size_t uuid_list_count, + const char **uuid_list, + const char **uid_list, + struct ccdb_secdb *secdb, + struct kcm_ccache **cc_list, + int *_new_count) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + uid_t uid; + char **list; + uuid_t uuid; + char *uuid_str; + char *secdb_key; + struct cli_creds *cli_cred; + int real_count = 0; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + return ret; + } + + cli_cred = talloc_zero(tmp_ctx, struct cli_creds); + if (cli_cred == NULL) { + ret = ENOMEM; + goto done; + } + + for (size_t i = 0; i < uuid_list_count; i++) { + struct passwd *pwd; + + cc_list[i] = talloc_zero(cc_list, struct kcm_ccache); + if (cc_list[i] == NULL) { + ret = ENOMEM; + goto done; + } + + ret = split_on_separator(tmp_ctx, uuid_list[i], ':', true, true, &list, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_INTERNAL, "split on separator failed\n"); + goto done; + } + + uuid_str = list[0]; + uuid_str[UUID_STR_SIZE - 1] = '\0'; + ret = uuid_parse(uuid_str, uuid); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_INTERNAL, "uuid parse of [%s] failed\n", list[0]); + goto done; + } + uid = strtouint32(uid_list[i], NULL, 10); + uid = strtouint32(uid_list[i], NULL, 10); + ret = errno; + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID conversion\n"); + goto done; + } + + errno = 0; + pwd = getpwuid(uid); + if (pwd == NULL) { + ret = errno; + DEBUG(SSSDBG_OP_FAILURE, "Failed to get pwd entry for " + "[%d] [%d]: %s\n", uid, ret, sss_strerror(ret)); + /* Not fatal */ + continue; + } + + cli_cred->ucred.uid = pwd->pw_uid; + cli_cred->ucred.gid = pwd->pw_gid; + + ret = key_by_uuid(tmp_ctx, secdb->sctx, cli_cred, uuid, &secdb_key); + if (ret == ENOENT) { + ret = EOK; + goto done; + } else if (ret != EOK) { + goto done; + } + + ret = secdb_get_cc(cc_list, secdb->sctx, secdb_key, cli_cred, &cc_list[real_count]); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed in secdb_get_cc\n"); + goto done; + } + + if (cc_list[real_count] == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to get cc [%s] and [%s]\n", + uuid_list[i], uid_list[i]); + ret = EIO; + goto done; + } + DEBUG(SSSDBG_TRACE_INTERNAL, + "Retrieved ccache [%s]\n", cc_list[real_count]->name); + real_count++; + } + + cc_list = talloc_realloc(tmp_ctx, cc_list, struct kcm_ccache *, + real_count + 1); + *_new_count = real_count; + + return EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + struct ccdb_secdb_list_state { uuid_t *uuid_list; }; +static errno_t ccdb_secdb_list_all_cc(TALLOC_CTX *mem_ctx, + struct krb5_ctx *krb5_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct kcm_ccache ***_cc_list) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + TALLOC_CTX *tmp_ctx; + errno_t ret; + const char **uid_list; + const char **uuid_list; + size_t uuid_list_count; + struct kcm_ccache **cc_list; + int new_count; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Retrieving all ccaches\n"); + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + return ret; + } + + ret = sss_sec_list_cc_uuids(tmp_ctx, secdb->sctx, &uuid_list, &uid_list, &uuid_list_count); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_TRACE_INTERNAL, "Error retrieving uid list\n"); + goto done; + } else if (ret == ENOENT) { + goto done; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "Found [%lu] ccache uuids\n", uuid_list_count); + + cc_list = talloc_zero_array(tmp_ctx, struct kcm_ccache *, uuid_list_count + 1); + if (cc_list == NULL) { + ret = ENOMEM; + goto done; + } + + /* New count is full cc list size minus getpwuid() failures */ + ret = ccdb_secdb_get_cc_for_uuid(uuid_list_count, uuid_list, uid_list, secdb, + cc_list, &new_count); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_INTERNAL, "Error retrieving cc for uuids list\n"); + ret = EIO; + goto done; + } + + cc_list[new_count] = NULL; + *_cc_list = talloc_steal(mem_ctx, cc_list); + + DEBUG(SSSDBG_TRACE_FUNC, "Retrieving all caches done\n"); + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + static struct tevent_req *ccdb_secdb_list_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct kcm_ccdb *db, @@ -1480,6 +1650,8 @@ const struct kcm_ccdb_ops ccdb_secdb_ops = { .list_send = ccdb_secdb_list_send, .list_recv = ccdb_secdb_list_recv, + .list_all_cc = ccdb_secdb_list_all_cc, + .getbyname_send = ccdb_secdb_getbyname_send, .getbyname_recv = ccdb_secdb_getbyname_recv, diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c index c6310b5852..e51a9436fa 100644 --- a/src/util/secrets/secrets.c +++ b/src/util/secrets/secrets.c @@ -22,10 +22,12 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <uuid/uuid.h> #include "config.h" #include "util/util.h" +#include "util/strtonum.h" #include "util/crypto/sss_crypto.h" #include "util/secrets/sec_pvt.h" #include "util/secrets/secrets.h" @@ -937,6 +939,93 @@ static char *local_dn_to_path(TALLOC_CTX *mem_ctx, return path; } +/* Complete list of ccache names(UUID:name) */ +errno_t sss_sec_list_cc_uuids(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sec, + const char ***_uuid_list, + const char ***_uid_list, + size_t *_uuid_list_count) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + struct ldb_dn *dn; + const struct ldb_val *name_val; + const struct ldb_val *uid_val; + static const char *attrs[] = { "distinguishedName", NULL }; + const char **uuid_list; + const char **uid_list; + size_t real_count = 0; + int ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + dn = ldb_dn_new(tmp_ctx, sec->ldb, "cn=persistent,cn=kcm"); + + ret = ldb_search(sec->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, + attrs, "%s", "(!(type=container))"); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, + "ldb_search returned [%d]: %s\n", ret, ldb_strerror(ret)); + ret = EIO; + goto done; + } + + if (res->count == 0) { + DEBUG(SSSDBG_TRACE_LIBS, "No ccaches found\n"); + ret = ENOENT; + goto done; + } + + uuid_list = talloc_zero_array(tmp_ctx, const char *, res->count); + if (uuid_list == NULL) { + ret = ENOMEM; + goto done; + } + + uid_list = talloc_zero_array(tmp_ctx, const char *, res->count); + if (uuid_list == NULL) { + ret = ENOMEM; + goto done; + } + + for (int i = 0; i < res->count; i++) { + name_val = ldb_dn_get_component_val(res->msgs[i]->dn, 0); + uid_val = ldb_dn_get_component_val(res->msgs[i]->dn, 2); + if (strcmp((const char *)name_val->data, "default") == 0) { + continue; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "uid_val: [%s]\n", uid_val->data); + uuid_list[real_count] = talloc_strdup(uuid_list, (const char *)name_val->data); + if (uuid_list[real_count] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to extract UUID\n"); + ret = ENOMEM; + goto done; + } + + uid_list[real_count] = talloc_strdup(uid_list, (const char *)uid_val->data); + if (uid_list[real_count] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to extract UUID\n"); + ret = ENOMEM; + goto done; + } + + real_count++; + } + + *_uid_list = talloc_steal(mem_ctx, uid_list); + *_uuid_list = talloc_steal(mem_ctx, uuid_list); + *_uuid_list_count = real_count; + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + errno_t sss_sec_list(TALLOC_CTX *mem_ctx, struct sss_sec_req *req, char ***_keys, diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h index f79bfaa4b9..b92dd50cfd 100644 --- a/src/util/secrets/secrets.h +++ b/src/util/secrets/secrets.h @@ -26,6 +26,7 @@ #include <stdlib.h> #include <stdbool.h> #include <talloc.h> +#include <uuid/uuid.h> #include "confdb/confdb.h" @@ -87,6 +88,12 @@ errno_t sss_sec_new_req(TALLOC_CTX *mem_ctx, errno_t sss_sec_delete(struct sss_sec_req *req); +errno_t sss_sec_list_cc_uuids(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sec_ctx, + const char ***_uuid_list, + const char ***_uid_list, + size_t *uuid_list_count); + errno_t sss_sec_list(TALLOC_CTX *mem_ctx, struct sss_sec_req *req, char ***_keys, diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c index b44e8d9025..cf96f3ffc4 100644 --- a/src/util/sss_krb5.c +++ b/src/util/sss_krb5.c @@ -1211,6 +1211,16 @@ static errno_t iobuf_get_len_bytes(TALLOC_CTX *mem_ctx, return EOK; } +errno_t get_krb5_data_from_cred(TALLOC_CTX *mem_ctx, + struct sss_iobuf *iobuf, + krb5_data *k5data) +{ + k5data->data = (char *) sss_iobuf_get_data(iobuf); + k5data->length = sss_iobuf_get_size(iobuf); + + return EOK; +} + static errno_t get_krb5_data(TALLOC_CTX *mem_ctx, struct sss_iobuf *iobuf, krb5_data *k5data) diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h index 4d9804fa88..aa1a258eb2 100644 --- a/src/util/sss_krb5.h +++ b/src/util/sss_krb5.h @@ -34,6 +34,7 @@ #include "util/sss_iobuf.h" #include "util/util.h" +#include <uuid/uuid.h> #define KRB5_CHILD_LOG_FILE "krb5_child" #define LDAP_CHILD_LOG_FILE "ldap_child" @@ -198,4 +199,8 @@ krb5_error_code sss_krb5_unmarshal_princ(TALLOC_CTX *mem_ctx, krb5_error_code sss_krb5_init_context(krb5_context *context); +errno_t get_krb5_data_from_cred(TALLOC_CTX *mem_ctx, + struct sss_iobuf *iobuf, + krb5_data *k5data); + #endif /* __SSS_KRB5_H__ */ From a2f2ab76057b99664d5bc3a1a02b8948cfbe2c51 Mon Sep 17 00:00:00 2001 From: Justin Stephenson <jstep...@redhat.com> Date: Mon, 21 Dec 2020 14:45:17 -0500 Subject: [PATCH 3/7] SECRETS: Don't hardcode SECRETS_DB_PATH Allow for overriding in cmocka tests --- src/util/secrets/secrets.c | 32 ++++++++++++++++++++++++++------ src/util/secrets/secrets.h | 5 +++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c index e51a9436fa..8546d08104 100644 --- a/src/util/secrets/secrets.c +++ b/src/util/secrets/secrets.c @@ -634,12 +634,13 @@ static int generate_master_key(const char *filename, size_t size) } static errno_t lcl_read_mkey(TALLOC_CTX *mem_ctx, + const char *dbpath, struct sss_sec_data *master_key) { int mfd; ssize_t size; errno_t ret; - const char *mkey = SECRETS_DB_PATH"/.secrets.mkey"; + const char *mkey = dbpath; master_key->data = talloc_size(mem_ctx, MKEY_SIZE); if (master_key->data == NULL) { @@ -699,11 +700,11 @@ static int set_quotas(struct sss_sec_ctx *sec_ctx, return EOK; } -errno_t sss_sec_init(TALLOC_CTX *mem_ctx, - struct sss_sec_hive_config **config_list, - struct sss_sec_ctx **_sec_ctx) +errno_t sss_sec_init_with_path(TALLOC_CTX *mem_ctx, + struct sss_sec_hive_config **config_list, + const char *dbpath, + struct sss_sec_ctx **_sec_ctx) { - const char *dbpath = SECRETS_DB_PATH"/secrets.ldb"; struct sss_sec_ctx *sec_ctx; TALLOC_CTX *tmp_ctx; errno_t ret; @@ -745,7 +746,7 @@ errno_t sss_sec_init(TALLOC_CTX *mem_ctx, goto done; } - ret = lcl_read_mkey(sec_ctx, &sec_ctx->master_key); + ret = lcl_read_mkey(sec_ctx, dbpath, &sec_ctx->master_key); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Cannot get the master key\n"); goto done; @@ -758,6 +759,25 @@ errno_t sss_sec_init(TALLOC_CTX *mem_ctx, return ret; } +errno_t sss_sec_init(TALLOC_CTX *mem_ctx, + struct sss_sec_hive_config **config_list, + struct sss_sec_ctx **_sec_ctx) +{ + const char *dbpath = SECRETS_DB_PATH"/secrets.ldb"; + errno_t ret; + + ret = sss_sec_init_with_path(mem_ctx, config_list, dbpath, _sec_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize secdb\n"); + ret = EIO; + goto done; + } + + ret = EOK; +done: + return ret; +} + static int local_db_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *basedn, diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h index b92dd50cfd..a15b99ffec 100644 --- a/src/util/secrets/secrets.h +++ b/src/util/secrets/secrets.h @@ -80,6 +80,11 @@ errno_t sss_sec_init(TALLOC_CTX *mem_ctx, struct sss_sec_hive_config **config_list, struct sss_sec_ctx **_sec_ctx); +errno_t sss_sec_init_with_path(TALLOC_CTX *mem_ctx, + struct sss_sec_hive_config **config_list, + const char *dbpath, + struct sss_sec_ctx **_sec_ctx); + errno_t sss_sec_new_req(TALLOC_CTX *mem_ctx, struct sss_sec_ctx *sec_ctx, const char *url, From fbb9b38d7ca140d2b659f29614640e53a307c532 Mon Sep 17 00:00:00 2001 From: Justin Stephenson <jstep...@redhat.com> Date: Fri, 29 Jan 2021 20:36:24 +0000 Subject: [PATCH 4/7] TESTS: Add kcm_renewals unit test --- Makefile.am | 35 ++++ src/tests/cmocka/test_kcm_renewals.c | 268 +++++++++++++++++++++++++++ 2 files changed, 303 insertions(+) create mode 100644 src/tests/cmocka/test_kcm_renewals.c diff --git a/Makefile.am b/Makefile.am index d23fb9473a..cddd51b981 100644 --- a/Makefile.am +++ b/Makefile.am @@ -326,6 +326,7 @@ if BUILD_KCM non_interactive_cmocka_based_tests += \ test_kcm_marshalling \ test_kcm_queue \ + test_kcm_renewals \ $(NULL) endif # BUILD_KCM @@ -3931,6 +3932,40 @@ test_kcm_queue_LDADD = \ libsss_sbus.la \ $(NULL) +test_kcm_renewals_SOURCES = \ + $(TEST_MOCK_RESP_OBJ) \ + src/tests/cmocka/test_kcm_renewals.c \ + src/responder/kcm/kcm_renew.c \ + src/responder/kcm/kcmsrv_ccache.c \ + src/responder/kcm/kcmsrv_ccache_key.c \ + src/responder/kcm/kcmsrv_ccache_binary.c \ + src/responder/kcm/kcmsrv_ccache_json.c \ + src/util/sss_krb5.c \ + src/util/sss_iobuf.c \ + src/util/secrets/secrets.c \ + src/util/secrets/config.c \ + src/providers/krb5/krb5_child_handler.c \ + src/providers/data_provider_opts.c \ + $(NULL) +test_kcm_renewals_CFLAGS = \ + $(AM_CFLAGS) \ + $(NULL) +test_kcm_renewals_LDFLAGS = \ + -Wl,-wrap,fstat +test_kcm_renewals_LDADD = \ + $(LIBADD_DL) \ + $(UUID_LIBS) \ + $(JANSSON_LIBS) \ + $(KRB5_LIBS) \ + $(CARES_LIBS) \ + $(CMOCKA_LIBS) \ + $(SSSD_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_test_common.la \ + libsss_iface.la \ + libsss_sbus.la \ + $(NULL) + endif # BUILD_KCM endif # HAVE_CMOCKA diff --git a/src/tests/cmocka/test_kcm_renewals.c b/src/tests/cmocka/test_kcm_renewals.c new file mode 100644 index 0000000000..b992dad3cf --- /dev/null +++ b/src/tests/cmocka/test_kcm_renewals.c @@ -0,0 +1,268 @@ +/* + Copyright (C) 2020 Red Hat + + SSSD tests: Test KCM Renewals + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "config.h" + +#include <stdio.h> +#include <popt.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "util/util.h" +#include "util/util_creds.h" +#include "tests/cmocka/common_mock.h" +#include "responder/kcm/kcmsrv_ccache.h" +#include "responder/kcm/kcm_renew.h" +#include "responder/kcm/kcmsrv_ccache_be.h" +#include "responder/kcm/kcmsrv_ccache_pvt.h" +#include "responder/kcm/kcmsrv_pvt.h" +#include "responder/kcm/kcmsrv_ccache_secdb.c" + +#define TESTS_PATH "tp_" BASE_FILE_STEM +#define TEST_CONF_DB "test_kcm_renewals_conf.ldb" +#define TEST_DB_FULL_PATH TESTS_PATH "/secrets.ldb" + +errno_t kcm_renew_all_tgts(TALLOC_CTX *mem_ctx, + struct renew_tgt_ctx *renew_tgt_ctx, + struct kcm_ccache **cc_list); + +const struct kcm_ccdb_ops ccdb_mem_ops; +const struct kcm_ccdb_ops ccdb_sec_ops; +const struct kcm_ccdb_ops ccdb_secdb_ops; + +struct test_ctx { + struct krb5_ctx *krb5_ctx; + struct tevent_context *ev; + struct kcm_ccdb *ccdb; +}; + +/* register_cli_protocol_version is required in test since it links with + * responder_common.c module + */ +struct cli_protocol_version *register_cli_protocol_version(void) +{ + static struct cli_protocol_version responder_test_cli_protocol_version[] = { + { 0, NULL, NULL } + }; + + return responder_test_cli_protocol_version; +} + +/* Wrap fstat() to ignore ownership check failure + * from lcl_read_mkey() -> check_and_open_readonly() + */ +int __real_fstat(int fd, struct stat *statbuf); + +int __wrap_fstat(int fd, struct stat *statbuf) +{ + int ret; + + ret = __real_fstat(fd, statbuf); + if (ret == 0) { + statbuf->st_uid = 0; + statbuf->st_gid = 0; + } + + return ret; +} + +/* Override perform_checks and check_fd so that fstat wrap is called */ +static errno_t perform_checks(struct stat *stat_buf, + uid_t uid, gid_t gid, + mode_t mode, mode_t mask) +{ + mode_t st_mode; + + if (mask) { + st_mode = stat_buf->st_mode & mask; + } else { + st_mode = stat_buf->st_mode & (S_IFMT|ALLPERMS); + } + + if ((mode & S_IFMT) != (st_mode & S_IFMT)) { + DEBUG(SSSDBG_TRACE_LIBS, "File is not the right type.\n"); + return EINVAL; + } + + if ((st_mode & ALLPERMS) != (mode & ALLPERMS)) { + DEBUG(SSSDBG_TRACE_LIBS, + "File has the wrong (bit masked) mode [%.7o], " + "expected [%.7o].\n", + (st_mode & ALLPERMS), (mode & ALLPERMS)); + return EINVAL; + } + + if (uid != (uid_t)(-1) && stat_buf->st_uid != uid) { + DEBUG(SSSDBG_TRACE_LIBS, "File must be owned by uid [%d].\n", uid); + return EINVAL; + } + + if (gid != (gid_t)(-1) && stat_buf->st_gid != gid) { + DEBUG(SSSDBG_TRACE_LIBS, "File must be owned by gid [%d].\n", gid); + return EINVAL; + } + + return EOK; +} + +errno_t check_fd(int fd, uid_t uid, gid_t gid, + mode_t mode, mode_t mask, + struct stat *caller_stat_buf) +{ + int ret; + struct stat local_stat_buf; + struct stat *stat_buf; + + if (caller_stat_buf == NULL) { + stat_buf = &local_stat_buf; + } else { + stat_buf = caller_stat_buf; + } + + ret = fstat(fd, stat_buf); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "fstat for [%d] failed: [%d][%s].\n", fd, ret, + strerror(ret)); + return ret; + } + + return perform_checks(stat_buf, uid, gid, mode, mask); +} + + +static int setup_kcm_renewals(void **state) +{ + struct test_ctx *tctx; + + tctx = talloc_zero(NULL, struct test_ctx); + assert_non_null(tctx); + + tctx->ev = tevent_context_init(tctx); + assert_non_null(tctx->ev); + + tctx->ccdb = talloc_zero(tctx, struct kcm_ccdb); + assert_non_null(tctx->ccdb); + tctx->ccdb->ev = tctx->ev; + + tctx->ccdb->ops = &ccdb_secdb_ops; + assert_non_null(tctx->ccdb->ops); + + *state = tctx; + return 0; +} + +static int teardown_kcm_renewals(void **state) +{ + struct test_ctx *tctx = talloc_get_type(*state, struct test_ctx); + + unlink(TEST_DB_FULL_PATH); + + rmdir(TESTS_PATH); + talloc_free(tctx); + return 0; +} + +static void test_kcm_renewals_tgt(void **state) +{ + struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); + errno_t ret; + struct ccdb_secdb *secdb = NULL; + struct renew_tgt_ctx *renew_tgt_ctx = NULL; + struct kcm_ccache **cc_list; + struct kcm_ccache *cc; + + secdb = talloc_zero(test_ctx, struct ccdb_secdb); + + assert_non_null(secdb); + + ret = mkdir(TESTS_PATH, 0700); + assert_int_equal(ret, 0); + + open(TEST_DB_FULL_PATH, O_CREAT|O_EXCL|O_WRONLY, 0600); + + ret = sss_sec_init_with_path(test_ctx->ccdb, NULL, TEST_DB_FULL_PATH, + &secdb->sctx); + + /* Create renew ctx */ + renew_tgt_ctx = talloc_zero(test_ctx, struct renew_tgt_ctx); + renew_tgt_ctx->ev = test_ctx->ev; + + /* Create cc list */ + cc_list = talloc_zero_array(test_ctx, struct kcm_ccache *, 2); + assert_non_null(cc_list); + + cc = talloc_zero(cc_list, struct kcm_ccache); + assert_non_null(cc); + + cc->name = talloc_strdup(test_ctx, "1000:1001"); + cc->owner.uid = 1000; + cc->owner.gid = 1000; + + cc_list[0] = cc; + cc_list[1] = NULL; + + ret = kcm_renew_all_tgts(test_ctx, renew_tgt_ctx, cc_list); + assert_int_equal(ret, EOK); +} + +int main(int argc, const char *argv[]) +{ + poptContext pc; + int opt; + int rv; + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_DEBUG_OPTS + POPT_TABLEEND + }; + + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_kcm_renewals_tgt, + setup_kcm_renewals, + teardown_kcm_renewals), + }; + + /* Set debug level to invalid value so we can decide if -d 0 was used. */ + debug_level = SSSDBG_INVALID; + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + return 1; + } + } + poptFreeContext(pc); + + DEBUG_CLI_INIT(debug_level); + + /* Even though normally the tests should clean up after themselves + * they might not after a failed run. Remove the old DB to be sure + */ + tests_set_cwd(); + + rv = cmocka_run_group_tests(tests, NULL, NULL); + + return rv; +} From 61d51222a75b93366950163b0b7c6f4388817537 Mon Sep 17 00:00:00 2001 From: Justin Stephenson <jstep...@redhat.com> Date: Mon, 21 Dec 2020 20:48:15 -0500 Subject: [PATCH 5/7] INTG: Add KCM Renewal integration test --- src/tests/intg/kdc.py | 2 + src/tests/intg/krb5utils.py | 15 ++++++- src/tests/intg/test_kcm.py | 78 +++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/tests/intg/kdc.py b/src/tests/intg/kdc.py index 8f82a990bc..2f14261382 100644 --- a/src/tests/intg/kdc.py +++ b/src/tests/intg/kdc.py @@ -145,6 +145,8 @@ def _format_kdc_conf(self): kadmind_port = {self.kadmin_port} database_name = {database_path} key_stash_file = {key_stash} + max_life = 7d + max_renewable_life = 14d acl_file = {self.acl_file} }} diff --git a/src/tests/intg/krb5utils.py b/src/tests/intg/krb5utils.py index 67ae430069..3da4c6a91f 100644 --- a/src/tests/intg/krb5utils.py +++ b/src/tests/intg/krb5utils.py @@ -58,8 +58,10 @@ def _run_in_env(self, args, stdin=None, extra_env=None): out, err = cmd.communicate(stdin) return cmd.returncode, out.decode('utf-8'), err.decode('utf-8') - def kinit(self, principal, password, env=None): + def kinit(self, principal, password, options=None, env=None): args = ["kinit", principal] + if options: + args.extend(options) return self._run_in_env(args, password.encode('utf-8'), env) def kvno(self, principal, env=None): @@ -115,6 +117,17 @@ def list_princs(self, env=None): return [ln for ln in outlines[2:] if len(ln) > 0] + def list_times(self, env=None): + p = self.spawn_in_env(['klist', '-A']) + output = p.stdout.read().splitlines() + for line in output: + if not line: + continue + + line_str = line.decode("utf-8") + if line_str[0].isdigit(): + return line_str + def has_principal(self, exp_principal, exp_cache=None, env=None): try: princlist = self.list_princs(env) diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py index 3a43491b96..395803bef7 100644 --- a/src/tests/intg/test_kcm.py +++ b/src/tests/intg/test_kcm.py @@ -25,6 +25,7 @@ import time import signal import sys +from datetime import datetime from requests import HTTPError import kdc @@ -33,9 +34,15 @@ from util import unindent from test_secrets import create_sssd_secrets_fixture from secrets import SecretsLocalClient +from intg.files_ops import passwd_ops_setup MAX_SECRETS = 10 +USER1 = dict(name='user1', passwd='x', uid=1000, gid=1000, + gecos='User for tests', + dir='/home/user1', + shell='/bin/bash') + class KcmTestEnv(object): def __init__(self, k5kdc, k5util): @@ -138,6 +145,30 @@ def create_sssd_conf(kcm_path, ccache_storage, max_secrets=MAX_SECRETS): """).format(**locals()) +def create_sssd_conf_renewals(kcm_path, ccache_storage, renew_lifetime, + lifetime, renew_interval, + max_secrets=MAX_SECRETS): + return unindent("""\ + [sssd] + domains = files + services = nss + + [domain/files] + id_provider = files + + [kcm] + socket_path = {kcm_path} + ccache_storage = {ccache_storage} + tgt_renewal = true + krb5_renewable_lifetime = {renew_lifetime} + krb5_lifetime = {lifetime} + krb5_renew_interval = {renew_interval} + + [secrets] + max_secrets = {max_secrets} + """).format(**locals()) + + def common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf): kcm_socket_include = unindent(""" [libdefaults] @@ -200,6 +231,18 @@ def setup_for_kcm_secdb(request, kdc_instance): return common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf) +@pytest.fixture +def setup_for_kcm_renewals_secdb(passwd_ops_setup, request, kdc_instance): + """ + Set up the KCM renewals backed by libsss_secrets + """ + kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") + sssd_conf = create_sssd_conf_renewals(kcm_path, "secdb", + "10d", "60s", "10s") + passwd_ops_setup.useradd(**USER1) + return common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf) + + def kcm_init_list_destroy(testenv): """ Test that kinit, kdestroy and klist work with KCM @@ -585,3 +628,38 @@ def test_kcm_secrets_quota(setup_for_kcm_sec, princ = "%s%d" % ("kcmtest", MAX_SECRETS) out, _, _ = testenv.k5util.kinit(princ, princ) assert out != 0 + + +def test_kcm_renewals(setup_for_kcm_renewals_secdb): + """ + Test that basic KCM renewal works + """ + testenv = setup_for_kcm_renewals_secdb + testenv.k5kdc.add_principal("user1", "Secret123") + + ok = testenv.k5util.has_principal("user1@KCMTEST") + assert ok is False + nprincs = testenv.k5util.num_princs() + assert nprincs == 0 + + # Renewal is only performed after half of lifetime exceeded, + # see kcm_renew_all_tgts() + options = ["-r", "15s", "-l", "15s"] + out, _, _ = testenv.k5util.kinit("user1", "Secret123", options) + assert out == 0 + nprincs = testenv.k5util.num_princs() + assert nprincs == 1 + + timestr_fmt = "%m/%d/%y %H:%M:%S" + initial_times = testenv.k5util.list_times() + + # Wait for renewal to trigger once, after renew interval + time.sleep(15) + + renewed_times = testenv.k5util.list_times() + + init_times = initial_times.split()[0] + ' ' + initial_times.split()[1] + renew_times = renewed_times.split()[0] + ' ' + renewed_times.split()[1] + dt_init = datetime.strptime(init_times, timestr_fmt) + dt_renew = datetime.strptime(renew_times, timestr_fmt) + assert dt_renew > dt_init From d0935ac27ed35e333b1905cdf78ad6dc11a9972f Mon Sep 17 00:00:00 2001 From: Justin Stephenson <jstep...@redhat.com> Date: Mon, 3 May 2021 18:14:32 +0000 Subject: [PATCH 6/7] KCM: Conditionally build KCM renewals support Use --enable-kcm-renewal, --disable-kcm-renewal or allw autodetection of MIT kerberos marshalling functions required to enable KCM renewal support. --- Makefile.am | 28 +++++++++++++++++++++------- src/external/krb5.m4 | 19 ++++++++++++++++++- src/man/Makefile.am | 6 +++++- src/man/sssd-kcm.8.xml | 4 ++-- src/responder/kcm/kcmsrv_ccache.c | 6 ++++++ src/tests/intg/Makefile.am | 7 +++++++ src/tests/intg/test_kcm.py | 6 ++++++ 7 files changed, 65 insertions(+), 11 deletions(-) diff --git a/Makefile.am b/Makefile.am index cddd51b981..4d9acaef99 100644 --- a/Makefile.am +++ b/Makefile.am @@ -326,10 +326,14 @@ if BUILD_KCM non_interactive_cmocka_based_tests += \ test_kcm_marshalling \ test_kcm_queue \ - test_kcm_renewals \ - $(NULL) + $(NULL) endif # BUILD_KCM +if BUILD_KCM_RENEWAL +non_interactive_cmocka_based_tests += test_kcm_renewals +endif # BUILD_KCM_RENEWAL + + if BUILD_SAMBA non_interactive_cmocka_based_tests += \ ad_access_filter_tests \ @@ -1791,7 +1795,6 @@ endif if BUILD_KCM sssd_kcm_SOURCES = \ src/responder/kcm/kcm.c \ - src/responder/kcm/kcm_renew.c \ src/responder/kcm/kcmsrv_cmd.c \ src/responder/kcm/kcmsrv_ccache.c \ src/responder/kcm/kcmsrv_ccache_binary.c \ @@ -1801,9 +1804,6 @@ sssd_kcm_SOURCES = \ src/responder/kcm/kcmsrv_ccache_secdb.c \ src/responder/kcm/kcmsrv_ops.c \ src/responder/kcm/kcmsrv_op_queue.c \ - src/providers/krb5/krb5_opts.c \ - src/providers/krb5/krb5_child_handler.c \ - src/providers/data_provider_opts.c \ src/util/sss_sockets.c \ src/util/sss_krb5.c \ src/util/sss_iobuf.c \ @@ -1821,7 +1821,6 @@ sssd_kcm_LDADD = \ $(KRB5_LIBS) \ $(JANSSON_LIBS) \ $(SSSD_LIBS) \ - $(CARES_LIBS) \ $(UUID_LIBS) \ $(SYSTEMD_DAEMON_LIBS) \ $(SSSD_INTERNAL_LTLIBS) \ @@ -1840,6 +1839,18 @@ sssd_kcm_LDADD += \ $(NULL) endif +if BUILD_KCM_RENEWAL +sssd_kcm_SOURCES += \ + src/responder/kcm/kcm_renew.c \ + src/providers/krb5/krb5_opts.c \ + src/providers/krb5/krb5_child_handler.c \ + src/providers/data_provider_opts.c \ + $(NULL) +sssd_kcm_LDADD += \ + $(CARES_LIBS) \ + $(NULL) +endif + endif sssd_be_SOURCES = \ @@ -3932,6 +3943,7 @@ test_kcm_queue_LDADD = \ libsss_sbus.la \ $(NULL) +if BUILD_KCM_RENEWAL test_kcm_renewals_SOURCES = \ $(TEST_MOCK_RESP_OBJ) \ src/tests/cmocka/test_kcm_renewals.c \ @@ -3945,6 +3957,7 @@ test_kcm_renewals_SOURCES = \ src/util/secrets/secrets.c \ src/util/secrets/config.c \ src/providers/krb5/krb5_child_handler.c \ + src/providers/krb5/krb5_opts.c \ src/providers/data_provider_opts.c \ $(NULL) test_kcm_renewals_CFLAGS = \ @@ -3965,6 +3978,7 @@ test_kcm_renewals_LDADD = \ libsss_iface.la \ libsss_sbus.la \ $(NULL) +endif # BUILD_KCM_RENEWAL endif # BUILD_KCM diff --git a/src/external/krb5.m4 b/src/external/krb5.m4 index b844c2fbee..1dfdbe9111 100644 --- a/src/external/krb5.m4 +++ b/src/external/krb5.m4 @@ -65,7 +65,8 @@ AC_CHECK_FUNCS([krb5_get_init_creds_opt_alloc krb5_get_error_message \ krb5_set_trace_callback \ krb5_find_authdata \ krb5_kt_have_content \ - krb5_cc_get_full_name]) + krb5_cc_get_full_name \ + krb5_unmarshal_credentials]) CFLAGS=$SAVE_CFLAGS LIBS=$SAVE_LIBS CFLAGS="$CFLAGS $KRB5_CFLAGS" @@ -112,5 +113,21 @@ AM_CONDITIONAL([BUILD_KRB5_LOCALAUTH_PLUGIN], AM_COND_IF([BUILD_KRB5_LOCALAUTH_PLUGIN], [AC_DEFINE_UNQUOTED(HAVE_KRB5_LOCALAUTH_PLUGIN, 1, [Build with krb5 localauth plugin])]) +AC_ARG_ENABLE([kcm-renewal], + [AS_HELP_STRING([--disable-kcm-renewal], + [do not build support for kcm renewals])], + [build_kcm_renewal=$enableval], + [build_kcm_renewal=yes]) + +if test x$build_kcm_renewal = xyes -a x$ac_cv_func_krb5_unmarshal_credentials != xyes +then + AC_MSG_WARN([krb5 unmarshalling function not available, fallback to building without KCM renewals]) +fi + +AM_CONDITIONAL([BUILD_KCM_RENEWAL], + [test x$build_kcm_renewal = xyes -a x$ac_cv_func_krb5_unmarshal_credentials = xyes]) +AM_COND_IF([BUILD_KCM_RENEWAL], + [AC_DEFINE_UNQUOTED(HAVE_KCM_RENEWAL, 1, [Build with kcm renewals])]) + CFLAGS=$SAVE_CFLAGS LIBS=$SAVE_LIBS diff --git a/src/man/Makefile.am b/src/man/Makefile.am index c6890a792e..9eedf698ab 100644 --- a/src/man/Makefile.am +++ b/src/man/Makefile.am @@ -49,8 +49,12 @@ endif if BUILD_LOCAL_PROVIDER LOCAL_PROVIDER_CONDS = ;enable_local_provider endif +if BUILD_KCM_RENEWAL +KCM_RENEWAL_CONDS = ;enable_kcm_renewal +endif + -CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS)$(STAP_CONDS)$(LOCAL_PROVIDER_CONDS) +CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS)$(STAP_CONDS)$(LOCAL_PROVIDER_CONDS)$(KCM_RENEWAL_CONDS) #Special Rules: diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml index 5f81af7367..aa77446ce3 100644 --- a/src/man/sssd-kcm.8.xml +++ b/src/man/sssd-kcm.8.xml @@ -162,7 +162,7 @@ systemctl restart sssd-kcm.service </para> </refsect1> - <refsect1 id='renewals'> + <refsect1 id='renewals' condition="enable_kcm_renewal"> <title>RENEWALS</title> <para> The sssd-kcm service can be configured to attempt TGT @@ -285,7 +285,7 @@ systemctl restart sssd-kcm.service </para> </listitem> </varlistentry> - <varlistentry> + <varlistentry condition="enable_kcm_renewal"> <term>krb5_renew_interval (integer)</term> <listitem> <para> diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c index ea250c4af0..0fdd491704 100644 --- a/src/responder/kcm/kcmsrv_ccache.c +++ b/src/responder/kcm/kcmsrv_ccache.c @@ -282,6 +282,7 @@ errno_t kcm_cc_set_header(struct kcm_ccache *cc, return EOK; } +#ifdef HAVE_KCM_RENEWAL struct kcm_unmarshall_ctx { krb5_creds **creds; krb5_context krb_ctx; @@ -297,11 +298,15 @@ static int kcm_cc_unmarshall_destructor(struct kcm_unmarshall_ctx *kcm_uctx) return 0; } +#endif krb5_creds **kcm_cc_unmarshal(TALLOC_CTX *mem_ctx, krb5_context krb_context, struct kcm_ccache *cc) { +#ifndef HAVE_KCM_RENEWAL + return NULL; +#else TALLOC_CTX *tmp_ctx; struct kcm_cred *cred; krb5_data *cred_data; @@ -359,6 +364,7 @@ krb5_creds **kcm_cc_unmarshal(TALLOC_CTX *mem_ctx, done: talloc_free(tmp_ctx); return NULL; +#endif } errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t _uuid) diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am index 133f07423a..d9fcc2dc3c 100644 --- a/src/tests/intg/Makefile.am +++ b/src/tests/intg/Makefile.am @@ -82,6 +82,12 @@ install-data-hook: endif +if BUILD_KCM_RENEWAL +KCM_RENEW = "enabled" +else +KCM_RENEW = "disabled" +endif + cwrap-dbus-system.conf: data/cwrap-dbus-system.conf.in Makefile $(SED) -e "s!@runstatedir[@]!$(runstatedir)!" \ -e "s!@dbusservicedir[@]!$(dbusservicedir)!" \ @@ -206,6 +212,7 @@ intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service PAM_WRAPPER_PATH=$$(pkg-config --libs pam_wrapper) \ PAM_CERT_DB_PATH=$(PAM_CERT_DB_PATH) \ SOFTHSM2_CONF=$(SOFTHSM2_CONF) \ + KCM_RENEW=$(KCM_RENEW) \ DBUS_SOCK_DIR="$(DESTDIR)$(runstatedir)/dbus/" \ DBUS_SESSION_BUS_ADDRESS="unix:path=$$DBUS_SOCK_DIR/fake_socket" \ DBUS_SYSTEM_BUS_ADDRESS="unix:path=$$DBUS_SOCK_DIR/system_bus_socket" \ diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py index 395803bef7..9f70f6e347 100644 --- a/src/tests/intg/test_kcm.py +++ b/src/tests/intg/test_kcm.py @@ -61,6 +61,10 @@ def ccname(self, my_uid=None): return "KCM:%d" % my_uid +def have_kcm_renewal(): + return os.environ['KCM_RENEW'] == "enabled" + + @pytest.fixture(scope="module") def kdc_instance(request): """Kerberos server instance fixture""" @@ -630,6 +634,8 @@ def test_kcm_secrets_quota(setup_for_kcm_sec, assert out != 0 +@pytest.mark.skipif(not have_kcm_renewal(), + reason="KCM renewal disabled, skipping") def test_kcm_renewals(setup_for_kcm_renewals_secdb): """ Test that basic KCM renewal works From d34db69388a419401e414d1958fc249035993c17 Mon Sep 17 00:00:00 2001 From: Justin Stephenson <jstep...@redhat.com> Date: Tue, 4 May 2021 13:39:13 +0000 Subject: [PATCH 7/7] KCM: Disable responder idle timeout with renewals When KCM renewals are configured and enabled, disable the responder idle timeout to prevent KCM from being in a shut-down state when it should be executing TGT renewals. --- src/responder/kcm/kcm.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c index 754d1dd197..4fc4eed871 100644 --- a/src/responder/kcm/kcm.c +++ b/src/responder/kcm/kcm.c @@ -172,16 +172,6 @@ static int kcm_get_config(struct kcm_ctx *kctx) goto done; } - if (kctx->cc_be == CCDB_BE_SECRETS || kctx->cc_be == CCDB_BE_SECDB) { - ret = responder_setup_idle_timeout_config(kctx->rctx); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Cannot set up idle responder timeout [%s].\n", - CONFDB_RESPONDER_IDLE_TIMEOUT); - /* Not fatal */ - } - } - kctx->qctx = kcm_ops_queue_create(kctx, kctx); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, @@ -245,6 +235,7 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, { struct resp_ctx *rctx; struct kcm_ctx *kctx; + bool renewal_enabled = false; struct krb5_ctx *krb5_ctx = NULL; time_t renew_intv = 0; int ret; @@ -291,12 +282,19 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, goto fail; } - ret = kcm_renewals_init(ev, rctx, kctx, krb5_ctx, renew_intv); + ret = kcm_renewals_init(ev, rctx, kctx, krb5_ctx, renew_intv, &renewal_enabled); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "fatal error getting KCM renewal config\n"); goto fail; } + if (renewal_enabled) { + /* Disable resp idle timeout to allow renewals */ + rctx->idle_timeout = 0; + } else { + responder_setup_idle_timeout_config(kctx->rctx); + } + /* Set up file descriptor limits */ responder_set_fd_limit(kctx->fd_limit);
_______________________________________________ sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org Do not reply to spam on the list, report it: https://pagure.io/fedora-infrastructure