From f024b5e46b62ad49f0099ed8db8155e7ea475639 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 28 Nov 2018 21:22:22 +0100
Subject: [PATCH 22/23] KCM: Configurable quotas for the secdb ccache back end
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related:
https://pagure.io/SSSD/sssd/issue/3386
Exposes three new options for the [kcm] responder to set the global
ccache limit, the per-uid ccache limit and the payload size.
Reviewed-by: Michal Židek <mzidek@redhat.com>
---
src/confdb/confdb.h | 3 ++
src/config/cfg_rules.ini | 3 ++
src/man/sssd-kcm.8.xml | 37 +++++++++++++++
src/responder/kcm/kcmsrv_ccache_secdb.c | 61 ++++++++++++++++++++++++-
4 files changed, 103 insertions(+), 1 deletion(-)
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index d09d6b4c3..727841659 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -266,6 +266,9 @@
#define CONFDB_KCM_CONF_ENTRY "config/kcm"
#define CONFDB_KCM_SOCKET "socket_path"
#define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */
+#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"
/* 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 30040b595..59d6cc512 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -312,6 +312,9 @@ option = description
option = socket_path
option = ccache_storage
option = responder_idle_timeout
+option = max_ccaches
+option = max_uid_ccaches
+option = max_ccache_size
# Session recording
[rule/allowed_session_recording_options]
diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml
index 4e4aaa38e..2f66e56a4 100644
--- a/src/man/sssd-kcm.8.xml
+++ b/src/man/sssd-kcm.8.xml
@@ -201,6 +201,43 @@ systemctl restart sssd-kcm.service
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>max_ccaches (integer)</term>
+ <listitem>
+ <para>
+ How many credential caches does the KCM database allow
+ for all users.
+ </para>
+ <para>
+ Default: 0 (unlimited, only the per-UID quota is enforced)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>max_uid_ccaches (integer)</term>
+ <listitem>
+ <para>
+ How many credential caches does the KCM database allow
+ per UID. This is equivalent to <quote>with how many
+ principals you can kinit</quote>.
+ </para>
+ <para>
+ Default: 64
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>max_ccache_size (integer)</term>
+ <listitem>
+ <para>
+ How big can a credential cache be per ccache. Each
+ service ticket accounts into this quota.
+ </para>
+ <para>
+ Default: 65536
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index d0d9a7e4c..dc9cefb32 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -526,13 +526,72 @@ static errno_t ccdb_secdb_init(struct kcm_ccdb *db,
{
struct ccdb_secdb *secdb = NULL;
errno_t ret;
+ struct sss_sec_hive_config **kcm_section_quota;
+ struct sss_sec_quota_opt dfl_kcm_nest_level = {
+ .opt_name = CONFDB_SEC_CONTAINERS_NEST_LEVEL,
+ .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
+ };
+ struct sss_sec_quota_opt dfl_kcm_max_secrets = {
+ .opt_name = CONFDB_KCM_MAX_CCACHES,
+ .default_value = DEFAULT_SEC_KCM_MAX_SECRETS,
+ };
+ struct sss_sec_quota_opt dfl_kcm_max_uid_secrets = {
+ .opt_name = CONFDB_KCM_MAX_UID_CCACHES,
+ .default_value = DEFAULT_SEC_KCM_MAX_UID_SECRETS,
+ };
+ struct sss_sec_quota_opt dfl_kcm_max_payload_size = {
+ .opt_name = CONFDB_KCM_MAX_CCACHE_SIZE,
+ .default_value = DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE,
+ };
+
secdb = talloc_zero(db, struct ccdb_secdb);
if (secdb == NULL) {
return ENOMEM;
}
- ret = sss_sec_init(db, NULL, &secdb->sctx);
+ kcm_section_quota = talloc_zero_array(secdb,
+ struct sss_sec_hive_config *,
+ 2);
+ if (kcm_section_quota == NULL) {
+ talloc_free(secdb);
+ return ENOMEM;
+ }
+
+ kcm_section_quota[0] = talloc_zero(kcm_section_quota,
+ struct sss_sec_hive_config);
+ if (kcm_section_quota == NULL) {
+ talloc_free(secdb);
+ return ENOMEM;
+ }
+ kcm_section_quota[0]->hive_name = "kcm";
+
+ ret = sss_sec_get_quota(cdb,
+ confdb_service_path,
+ &dfl_kcm_nest_level,
+ &dfl_kcm_max_secrets,
+ &dfl_kcm_max_uid_secrets,
+ &dfl_kcm_max_payload_size,
+ &kcm_section_quota[0]->quota);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to get KCM global quotas [%d]: %s\n",
+ ret, sss_strerror(ret));
+ talloc_free(secdb);
+ return ret;
+ }
+
+ if (kcm_section_quota[0]->quota.max_uid_secrets > 0) {
+ /* Even cn=default is considered a secret that adds up to
+ * the quota. To avoid off-by-one-confusion, increase
+ * the quota by two to 1) account for the cn=default object
+ * and 2) always allow writing to cn=defaults even if we
+ * are exactly at the quota limit
+ */
+ kcm_section_quota[0]->quota.max_uid_secrets += 2;
+ }
+
+ ret = sss_sec_init(db, kcm_section_quota, &secdb->sctx);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Cannot initialize the security database\n");
--
2.20.1