URL: https://github.com/SSSD/sssd/pull/705
Author: jhrozek
 Title: #705: KCM: Add configurable quotas
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/705/head:pr705
git checkout pr705
From e2b8f44bc0418bc531c7e372306f057b275ef9df Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Fri, 5 Oct 2018 13:17:14 +0200
Subject: [PATCH 1/8] MAN: Get rid of sssd-secrets reference

Related:
https://pagure.io/SSSD/sssd/issue/3685

There were some stray references to the secrets responder in the
sssd-kcm manual page.
---
 src/man/sssd-kcm.8.xml | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml
index fff8b0a16d..90b9ad09c2 100644
--- a/src/man/sssd-kcm.8.xml
+++ b/src/man/sssd-kcm.8.xml
@@ -58,11 +58,9 @@
                 </listitem>
                 <listitem>
                     <para>
-                        the SSSD implementation stores the ccaches in the SSSD
-                        <citerefentry>
-                            <refentrytitle>sssd-secrets</refentrytitle><manvolnum>5</manvolnum>
-                        </citerefentry>
-                        secrets store, allowing the ccaches to survive KCM server restarts or machine reboots.
+                        the SSSD implementation stores the ccaches in a database,
+                        typically located at <replaceable>/var/lib/sss/secrets</replaceable>
+                        allowing the ccaches to survive KCM server restarts or machine reboots.
                     </para>
                 </listitem>
             </itemizedlist>

From 1161664d427f34a2428a8cb86f8494aac9472da3 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Fri, 30 Nov 2018 13:15:58 +0100
Subject: [PATCH 2/8] MAN: Document that it is enough to systemctl restart
 sssd-kcm.service lately

Related:
https://pagure.io/SSSD/sssd/issue/3862

We forgot to amend the man page after implementing the sssd-kcm service
reload.
---
 src/man/sssd-kcm.8.xml | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml
index 90b9ad09c2..4e4aaa38ea 100644
--- a/src/man/sssd-kcm.8.xml
+++ b/src/man/sssd-kcm.8.xml
@@ -162,12 +162,17 @@ systemctl restart sssd-kcm.service
         <title>CONFIGURATION OPTIONS</title>
         <para>
             The KCM service is configured in the <quote>kcm</quote>
-            section of the sssd.conf file. Please note that currently,
-            is it not sufficient to restart the sssd-kcm service, because
-            the sssd configuration is only parsed and read to an internal
-            configuration database by the sssd service. Therefore you
-            must restart the sssd service if you change anything in the
-            <quote>kcm</quote> section of sssd.conf.
+            section of the sssd.conf file. Please note that because
+            the KCM service is typically socket-activated, it is
+            enough to just restart the <quote>sssd-kcm</quote> service
+            after changing options in the <quote>kcm</quote> section
+            of sssd.conf:
+            <programlisting>
+systemctl restart sssd-kcm.service
+            </programlisting>
+        </para>
+        <para>
+            The KCM service is configured in the <quote>kcm</quote>
             For a detailed syntax reference, refer to the <quote>FILE FORMAT</quote> section of the
             <citerefentry>
                 <refentrytitle>sssd.conf</refentrytitle>

From 7294fd022eb397e22dc345846a6cbb067d3a27bc Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Mon, 26 Nov 2018 13:44:08 +0100
Subject: [PATCH 3/8] SECRETS: Use different option names from secrets and KCM
 for quota options

Related:
https://pagure.io/SSSD/sssd/issue/3386

With the separate secrets responder, the quotas for the /secrets and
/kcm hives were configurable in a sub-section of the [secrets] sssd.conf
section using the same option -- the /secrets vs. /kcm distinction was
made using the subsection name.

With the standalone KCM responder writing directly to the database, it
makes sense to have options with more descriptive names better suitable
for the KCM usage. For that we need the options for secrets quotas and
kcm quotas to be named differently.

For now, the patch only passes the option name to sss_sec_get_quota()
and sss_sec_get_hive_config() together with the default value in an
instance of a new structure sss_sec_quota_opt. The secrets responder
still uses the same option names for backwards compatibility.
---
 src/responder/secrets/secsrv.c | 70 ++++++++++++++++++++++++++--------
 src/util/secrets/config.c      | 40 +++++++++----------
 src/util/secrets/secrets.h     | 21 ++++++----
 3 files changed, 88 insertions(+), 43 deletions(-)

diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c
index 2de93dedc5..e783e231d3 100644
--- a/src/responder/secrets/secsrv.c
+++ b/src/responder/secrets/secsrv.c
@@ -47,6 +47,39 @@ static void adjust_global_quota(struct sec_ctx *sctx,
 static int sec_get_config(struct sec_ctx *sctx)
 {
     int ret;
+    struct sss_sec_quota_opt dfl_sec_nest_level = {
+        .opt_name = CONFDB_SEC_CONTAINERS_NEST_LEVEL,
+        .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
+    };
+    struct sss_sec_quota_opt dfl_sec_max_secrets = {
+        .opt_name = CONFDB_SEC_MAX_SECRETS,
+        .default_value = DEFAULT_SEC_MAX_SECRETS,
+    };
+    struct sss_sec_quota_opt dfl_sec_max_uid_secrets = {
+        .opt_name = CONFDB_SEC_MAX_UID_SECRETS,
+        .default_value = DEFAULT_SEC_MAX_UID_SECRETS,
+    };
+    struct sss_sec_quota_opt dfl_sec_max_payload_size = {
+        .opt_name = CONFDB_SEC_MAX_PAYLOAD_SIZE,
+        .default_value = DEFAULT_SEC_MAX_PAYLOAD_SIZE,
+    };
+
+    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_SEC_MAX_SECRETS,
+        .default_value = DEFAULT_SEC_KCM_MAX_SECRETS,
+    };
+    struct sss_sec_quota_opt dfl_kcm_max_uid_secrets = {
+        .opt_name = CONFDB_SEC_MAX_UID_SECRETS,
+        .default_value = DEFAULT_SEC_KCM_MAX_UID_SECRETS,
+    };
+    struct sss_sec_quota_opt dfl_kcm_max_payload_size = {
+        .opt_name = CONFDB_SEC_MAX_PAYLOAD_SIZE,
+        .default_value = DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE,
+    };
 
     ret = confdb_get_int(sctx->rctx->cdb,
                          sctx->rctx->confdb_service_path,
@@ -65,15 +98,12 @@ static int sec_get_config(struct sec_ctx *sctx)
     sctx->max_payload_size = 1;
 
     /* Read the global quota first -- this should be removed in a future release */
-    /* Note that this sets the defaults for the sec_config quota to be used
-     * in sec_get_hive_config()
-     */
     ret = sss_sec_get_quota(sctx->rctx->cdb,
                             sctx->rctx->confdb_service_path,
-                            DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
-                            DEFAULT_SEC_MAX_SECRETS,
-                            DEFAULT_SEC_MAX_UID_SECRETS,
-                            DEFAULT_SEC_MAX_PAYLOAD_SIZE,
+                            &dfl_sec_nest_level,
+                            &dfl_sec_max_secrets,
+                            &dfl_sec_max_uid_secrets,
+                            &dfl_sec_max_payload_size,
                             &sctx->sec_config.quota);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
@@ -81,13 +111,23 @@ static int sec_get_config(struct sec_ctx *sctx)
         goto fail;
     }
 
+    /* Use the global quota values as defaults for the secrets/secrets section */
+    dfl_sec_nest_level.default_value = \
+                                sctx->sec_config.quota.containers_nest_level;
+    dfl_sec_max_secrets.default_value = \
+                                sctx->sec_config.quota.max_secrets;
+    dfl_sec_max_uid_secrets.default_value = \
+                                sctx->sec_config.quota.max_uid_secrets;
+    dfl_sec_max_payload_size.default_value = \
+                                sctx->sec_config.quota.max_payload_size;
+
     /* Read the per-hive configuration */
     ret = sss_sec_get_hive_config(sctx->rctx->cdb,
                                  "secrets",
-                                 sctx->sec_config.quota.containers_nest_level,
-                                 sctx->sec_config.quota.max_secrets,
-                                 sctx->sec_config.quota.max_uid_secrets,
-                                 sctx->sec_config.quota.max_payload_size,
+                                 &dfl_sec_nest_level,
+                                 &dfl_sec_max_secrets,
+                                 &dfl_sec_max_uid_secrets,
+                                 &dfl_sec_max_payload_size,
                                  &sctx->sec_config);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
@@ -98,10 +138,10 @@ static int sec_get_config(struct sec_ctx *sctx)
 
     ret = sss_sec_get_hive_config(sctx->rctx->cdb,
                                   "kcm",
-                                  DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
-                                  DEFAULT_SEC_KCM_MAX_SECRETS,
-                                  DEFAULT_SEC_KCM_MAX_UID_SECRETS,
-                                  DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE,
+                                  &dfl_kcm_nest_level,
+                                  &dfl_kcm_max_secrets,
+                                  &dfl_kcm_max_uid_secrets,
+                                  &dfl_kcm_max_payload_size,
                                   &sctx->kcm_config);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
diff --git a/src/util/secrets/config.c b/src/util/secrets/config.c
index cb286121f4..f5dac0b21a 100644
--- a/src/util/secrets/config.c
+++ b/src/util/secrets/config.c
@@ -24,10 +24,10 @@
 
 errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
                           const char *section_config_path,
-                          int default_max_containers_nest_level,
-                          int default_max_num_secrets,
-                          int default_max_num_uid_secrets,
-                          int default_max_payload,
+                          struct sss_sec_quota_opt *dfl_max_containers_nest_level,
+                          struct sss_sec_quota_opt *dfl_max_num_secrets,
+                          struct sss_sec_quota_opt *dfl_max_num_uid_secrets,
+                          struct sss_sec_quota_opt *dfl_max_payload,
                           struct sss_sec_quota *quota)
 {
     int ret;
@@ -38,8 +38,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
 
     ret = confdb_get_int(cdb,
                          section_config_path,
-                         CONFDB_SEC_CONTAINERS_NEST_LEVEL,
-                         default_max_containers_nest_level,
+                         dfl_max_containers_nest_level->opt_name,
+                         dfl_max_containers_nest_level->default_value,
                          &quota->containers_nest_level);
 
     if (ret != EOK) {
@@ -51,8 +51,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
 
     ret = confdb_get_int(cdb,
                          section_config_path,
-                         CONFDB_SEC_MAX_SECRETS,
-                         default_max_num_secrets,
+                         dfl_max_num_secrets->opt_name,
+                         dfl_max_num_secrets->default_value,
                          &quota->max_secrets);
 
     if (ret != EOK) {
@@ -64,8 +64,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
 
     ret = confdb_get_int(cdb,
                          section_config_path,
-                         CONFDB_SEC_MAX_UID_SECRETS,
-                         default_max_num_uid_secrets,
+                         dfl_max_num_uid_secrets->opt_name,
+                         dfl_max_num_uid_secrets->default_value,
                          &quota->max_uid_secrets);
 
     if (ret != EOK) {
@@ -77,8 +77,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
 
     ret = confdb_get_int(cdb,
                          section_config_path,
-                         CONFDB_SEC_MAX_PAYLOAD_SIZE,
-                         default_max_payload,
+                         dfl_max_payload->opt_name,
+                         dfl_max_payload->default_value,
                          &quota->max_payload_size);
 
     if (ret != EOK) {
@@ -93,10 +93,10 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
 
 errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb,
                                 const char *hive_name,
-                                int default_max_containers_nest_level,
-                                int default_max_num_secrets,
-                                int default_max_num_uid_secrets,
-                                int default_max_payload,
+                                struct sss_sec_quota_opt *dfl_max_containers_nest_level,
+                                struct sss_sec_quota_opt *dfl_max_num_secrets,
+                                struct sss_sec_quota_opt *dfl_max_num_uid_secrets,
+                                struct sss_sec_quota_opt *dfl_max_payload,
                                 struct sss_sec_hive_config *hive_config)
 {
     int ret;
@@ -122,10 +122,10 @@ errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb,
 
     ret = sss_sec_get_quota(cdb,
                             confdb_section,
-                            default_max_containers_nest_level,
-                            default_max_num_secrets,
-                            default_max_num_uid_secrets,
-                            default_max_payload,
+                            dfl_max_containers_nest_level,
+                            dfl_max_num_secrets,
+                            dfl_max_num_uid_secrets,
+                            dfl_max_payload,
                             &hive_config->quota);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE,
diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
index 01abfe5425..31164bd865 100644
--- a/src/util/secrets/secrets.h
+++ b/src/util/secrets/secrets.h
@@ -47,6 +47,11 @@ struct sss_sec_ctx;
 
 struct sss_sec_req;
 
+struct sss_sec_quota_opt {
+    const char *opt_name;
+    int default_value;
+};
+
 struct sss_sec_quota {
     int max_secrets;
     int max_uid_secrets;
@@ -98,18 +103,18 @@ bool sss_sec_req_is_list(struct sss_sec_req *req);
 
 errno_t sss_sec_get_quota(struct confdb_ctx *cdb,
                           const char *section_config_path,
-                          int default_max_containers_nest_level,
-                          int default_max_num_secrets,
-                          int default_max_num_uid_secrets,
-                          int default_max_payload,
+                          struct sss_sec_quota_opt *dfl_max_containers_nest_level,
+                          struct sss_sec_quota_opt *dfl_max_num_secrets,
+                          struct sss_sec_quota_opt *dfl_max_num_uid_secrets,
+                          struct sss_sec_quota_opt *dfl_max_payload,
                           struct sss_sec_quota *quota);
 
 errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb,
                                 const char *hive_name,
-                                int default_max_containers_nest_level,
-                                int default_max_num_secrets,
-                                int default_max_num_uid_secrets,
-                                int default_max_payload,
+                                struct sss_sec_quota_opt *dfl_max_containers_nest_level,
+                                struct sss_sec_quota_opt *dfl_max_num_secrets,
+                                struct sss_sec_quota_opt *dfl_max_num_uid_secrets,
+                                struct sss_sec_quota_opt *dfl_max_payload,
                                 struct sss_sec_hive_config *hive_config);
 
 #endif /* __SECRETS_H_ */

From 477ee8c803a97400995cb2fb8160304f621bc66d Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Fri, 30 Nov 2018 13:34:22 +0100
Subject: [PATCH 4/8] SECRETS: Don't limit the global number of ccaches

Related:
https://pagure.io/SSSD/sssd/issue/3386

In the KCM context, the global number of ccaches would limit the number
of users who can store their ccaches in the KCM deamon.

In more detail, the options have the following semantics with KCM:
    - DEFAULT_SEC_KCM_MAX_SECRETS - global number of secrets, would
    cover both how many ccaches can a user store, but this is better
    served with DEFAULT_SEC_KCM_MAX_UID_SECRETS

    - DEFAULT_SEC_KCM_MAX_UID_SECRETS - how many 'principals' can a user
    kinit with

    - DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE - the payload size of service
    tickets

With the above in mind, I think the most important limits are
max_uid_secrets to limit and the payload size to constraint how much
space can a user occupy and it doesn't make much sense to limit the
global quota.
---
 src/util/secrets/secrets.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
index 31164bd865..9cf3975162 100644
--- a/src/util/secrets/secrets.h
+++ b/src/util/secrets/secrets.h
@@ -39,7 +39,7 @@
  * but the secret size must be large because one secret in the /kcm
  * hive holds the whole ccache which consists of several credentials
  */
-#define DEFAULT_SEC_KCM_MAX_SECRETS      256
+#define DEFAULT_SEC_KCM_MAX_SECRETS      0          /* unlimited */
 #define DEFAULT_SEC_KCM_MAX_UID_SECRETS  64
 #define DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE 65536
 

From 63cc03d3ef835078af76801500739d8cfd3b0965 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Wed, 28 Nov 2018 21:24:08 +0100
Subject: [PATCH 5/8] KCM: Pass confdb context to the ccache db initialization

Resolves:
https://pagure.io/SSSD/sssd/issue/3386

The libsecrets back end needs to read the quota options from confdb,
therefore it needs to know the section and access the confdb handle.

These parameters are unused for other ccache back end types, but they
are harmless and IMO it makes more sense to keep the ccache back end
abstract.
---
 src/responder/kcm/kcm.c                   | 14 ++++++++++++--
 src/responder/kcm/kcmsrv_ccache.c         |  4 +++-
 src/responder/kcm/kcmsrv_ccache.h         |  2 ++
 src/responder/kcm/kcmsrv_ccache_be.h      |  4 +++-
 src/responder/kcm/kcmsrv_ccache_mem.c     |  4 +++-
 src/responder/kcm/kcmsrv_ccache_secdb.c   |  6 +++---
 src/responder/kcm/kcmsrv_ccache_secrets.c |  4 +++-
 7 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
index 005dd168f8..045c7801fa 100644
--- a/src/responder/kcm/kcm.c
+++ b/src/responder/kcm/kcm.c
@@ -170,6 +170,8 @@ static int kcm_data_destructor(void *ptr)
 
 static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx,
                                            struct tevent_context *ev,
+                                           struct confdb_ctx *cdb,
+                                           const char *confdb_service_path,
                                            enum kcm_ccdb_be cc_be)
 {
     struct kcm_resp_ctx *kcm_data;
@@ -181,7 +183,11 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
-    kcm_data->db = kcm_ccdb_init(kcm_data, ev, cc_be);
+    kcm_data->db = kcm_ccdb_init(kcm_data,
+                                 ev,
+                                 cdb,
+                                 confdb_service_path,
+                                 cc_be);
     if (kcm_data->db == NULL) {
         talloc_free(kcm_data);
         return NULL;
@@ -235,7 +241,11 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    kctx->kcm_data = kcm_data_setup(kctx, ev, kctx->cc_be);
+    kctx->kcm_data = kcm_data_setup(kctx,
+                                    ev,
+                                    kctx->rctx->cdb,
+                                    kctx->rctx->confdb_service_path,
+                                    kctx->cc_be);
     if (kctx->kcm_data == NULL) {
         DEBUG(SSSDBG_FATAL_FAILURE,
               "fatal error initializing responder data\n");
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
index af2bcf8bb5..2009c71e04 100644
--- a/src/responder/kcm/kcmsrv_ccache.c
+++ b/src/responder/kcm/kcmsrv_ccache.c
@@ -227,6 +227,8 @@ struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd)
 
 struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
                                struct tevent_context *ev,
+                               struct confdb_ctx *cdb,
+                               const char *confdb_service_path,
                                enum kcm_ccdb_be cc_be)
 {
     errno_t ret;
@@ -268,7 +270,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
-    ret = ccdb->ops->init(ccdb);
+    ret = ccdb->ops->init(ccdb, cdb, confdb_service_path);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize ccache database\n");
         talloc_free(ccdb);
diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
index 0fd33325f0..199b75b16c 100644
--- a/src/responder/kcm/kcmsrv_ccache.h
+++ b/src/responder/kcm/kcmsrv_ccache.h
@@ -125,6 +125,8 @@ struct kcm_ccdb;
  */
 struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
                                struct tevent_context *ev,
+                               struct confdb_ctx *cdb,
+                               const char *confdb_service_path,
                                enum kcm_ccdb_be cc_be);
 
 /*
diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h
index 7315f64353..166af3a764 100644
--- a/src/responder/kcm/kcmsrv_ccache_be.h
+++ b/src/responder/kcm/kcmsrv_ccache_be.h
@@ -30,7 +30,9 @@
 #include "responder/kcm/kcmsrv_ccache.h"
 
 typedef errno_t
-(*ccdb_init_fn)(struct kcm_ccdb *db);
+(*ccdb_init_fn)(struct kcm_ccdb *db,
+                struct confdb_ctx *cdb,
+                const char *confdb_service_path);
 
 typedef struct tevent_req *
 (*ccdb_nextid_send_fn)(TALLOC_CTX *mem_ctx,
diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c
index 38bc2050d9..35955b2f4a 100644
--- a/src/responder/kcm/kcmsrv_ccache_mem.c
+++ b/src/responder/kcm/kcmsrv_ccache_mem.c
@@ -151,7 +151,9 @@ static int ccwrap_destructor(void *ptr)
     return 0;
 }
 
-static errno_t ccdb_mem_init(struct kcm_ccdb *db)
+static errno_t ccdb_mem_init(struct kcm_ccdb *db,
+                             struct confdb_ctx *cdb,
+                             const char *confdb_service_path)
 {
     struct ccdb_mem *memdb = NULL;
 
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index a61d7b15be..5ccb21aa73 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -520,7 +520,9 @@ static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx,
     return ret;
 }
 
-static errno_t ccdb_secdb_init(struct kcm_ccdb *db)
+static errno_t ccdb_secdb_init(struct kcm_ccdb *db,
+                               struct confdb_ctx *cdb,
+                               const char *confdb_service_path)
 {
     struct ccdb_secdb *secdb = NULL;
     errno_t ret;
@@ -530,8 +532,6 @@ static errno_t ccdb_secdb_init(struct kcm_ccdb *db)
         return ENOMEM;
     }
 
-    /* TODO: read configuration from the config file, adjust quotas */
-
     ret = sss_sec_init(db, NULL, &secdb->sctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c
index 4c52497d45..7b019fdedc 100644
--- a/src/responder/kcm/kcmsrv_ccache_secrets.c
+++ b/src/responder/kcm/kcmsrv_ccache_secrets.c
@@ -659,7 +659,9 @@ static errno_t sec_get_ccache_recv(struct tevent_req *req,
 /*
  * The actual sssd-secrets back end
  */
-static errno_t ccdb_sec_init(struct kcm_ccdb *db)
+static errno_t ccdb_sec_init(struct kcm_ccdb *db,
+                             struct confdb_ctx *cdb,
+                             const char *confdb_service_path)
 {
     struct ccdb_sec *secdb = NULL;
 

From e8139244e91bee778f745cd7e5e3edaa3d49907b Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Wed, 28 Nov 2018 21:22:22 +0100
Subject: [PATCH 6/8] KCM: Configurable quotas for the secdb ccache back end

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.
---
 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 741d4bc47d..612d3181d9 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 e38d114ae6..f01473bf5a 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 4e4aaa38ea..2f66e56a4a 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 5ccb21aa73..26ee1032d7 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");

From 600fb784fa312f7e5ef79d07541aae85081df443 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Tue, 27 Nov 2018 11:39:18 +0100
Subject: [PATCH 7/8] MULTIHOST: Do not use the deprecated namespace

This issue was causing warnings with the current pytest versions as
installed from pip.

See:
https://docs.pytest.org/en/latest/deprecations.html#pytest-namespace
---
 src/tests/multihost/basic/conftest.py | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/tests/multihost/basic/conftest.py b/src/tests/multihost/basic/conftest.py
index 65e2d641b7..a9e9cf0a61 100644
--- a/src/tests/multihost/basic/conftest.py
+++ b/src/tests/multihost/basic/conftest.py
@@ -17,13 +17,13 @@
 import ldap
 
 
-def pytest_namespace():
-    return {'num_masters': 1,
-            'num_ad': 0,
-            'num_atomic': 0,
-            'num_replicas': 0,
-            'num_clients': 0,
-            'num_others': 0}
+def pytest_configure():
+    pytest.num_masters = 1
+    pytest.num_ad = 0
+    pytest.num_atomic = 0
+    pytest.num_replicas = 0
+    pytest.num_clients = 0
+    pytest.num_others = 0
 
 
 @pytest.fixture(scope="class")

From c4f4252964df4372210702928196fd8139f01ed0 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Mon, 26 Nov 2018 21:10:21 +0100
Subject: [PATCH 8/8] TESTS: Add tests for the configurable quotas

Related:
https://pagure.io/SSSD/sssd/issue/3386
---
 src/tests/multihost/basic/conftest.py |  8 +++
 src/tests/multihost/basic/test_kcm.py | 97 +++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/src/tests/multihost/basic/conftest.py b/src/tests/multihost/basic/conftest.py
index a9e9cf0a61..fd12c1b5bb 100644
--- a/src/tests/multihost/basic/conftest.py
+++ b/src/tests/multihost/basic/conftest.py
@@ -397,6 +397,14 @@ def create_posix_usersgroups(session_multihost):
         assert ret == 'Success'
 
 
+@pytest.fixture(scope='session')
+def create_many_user_principals(session_multihost):
+    krb = krb5srv(session_multihost.master[0], 'EXAMPLE.TEST')
+    for i in range(1, 65):
+        username = "user%04d" % i
+        krb.add_principal(username, 'user', 'Secret123')
+
+
 @pytest.fixture(scope="session", autouse=True)
 def setup_session(request, session_multihost,
                   package_install,
diff --git a/src/tests/multihost/basic/test_kcm.py b/src/tests/multihost/basic/test_kcm.py
index 7202dcb4ae..85caedfbcf 100644
--- a/src/tests/multihost/basic/test_kcm.py
+++ b/src/tests/multihost/basic/test_kcm.py
@@ -3,6 +3,7 @@
 import paramiko
 import pytest
 import os
+import time
 from utils_config import set_param, remove_section
 
 
@@ -139,3 +140,99 @@ def test_kdestroy_retval(self, multihost, enable_kcm):
         assert exit_status == 0
 
         ssh.close()
+
+    def test_kcm_peruid_quota(self,
+                              multihost,
+                              enable_kcm,
+                              create_many_user_principals):
+        """
+        Make sure the quota limits a client, but only that client
+        """
+        ssh_foo2 = SSHClient(multihost.master[0].sys_hostname,
+                             username='foo2', password='Secret123')
+        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
+                             username='foo3', password='Secret123')
+
+        # The loop would request 63 users, plus there is foo3 we authenticated
+        # earlier, so this should exactly deplete the quota, but should succeed
+        for i in range(1, 64):
+            username = "user%04d" % i
+            (_, _, exit_status) = ssh_foo3.execute_cmd('kinit %s' % username,
+                                                       stdin='Secret123')
+            assert exit_status == 0
+
+        # this kinit should be exactly one over the peruid limit
+        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
+                                                   stdin='Secret123')
+        assert exit_status != 0
+
+        # Since this is a per-uid limit, another user should be able to kinit
+        # just fine
+        (_, _, exit_status) = ssh_foo2.execute_cmd('kinit user0064',
+                                                   stdin='Secret123')
+        assert exit_status == 0
+
+        # kdestroy as the original user, the quota should allow a subsequent
+        # kinit
+        ssh_foo3.execute_cmd('kdestroy -A')
+        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
+                                                   stdin='Secret123')
+        assert exit_status == 0
+
+        ssh_foo2.close()
+        ssh_foo3.close()
+
+    def test_kcm_peruid_quota_increase(self,
+                                       multihost,
+                                       enable_kcm,
+                                       create_many_user_principals):
+        """
+        Increasing the peruid quota allows a client to store more
+        data
+        """
+        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
+                             username='foo3', password='Secret123')
+
+        # The loop would request 63 users, plus there is foo3 we authenticated
+        # earlier, so this should exactly deplete the quota, but should succeed
+        for i in range(1, 64):
+            username = "user%04d" % i
+            (_, _, exit_status) = ssh_foo3.execute_cmd('kinit %s' % username,
+                                                       stdin='Secret123')
+            assert exit_status == 0
+
+        # this kinit should be exactly one over the peruid limit
+        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
+                                                   stdin='Secret123')
+        assert exit_status != 0
+
+        set_param(multihost, 'kcm', 'max_uid_ccaches', '65')
+        self._restart_kcm(multihost)
+
+        # Now the kinit should work as we increased the limit
+        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
+                                                   stdin='Secret123')
+        assert exit_status == 0
+
+        ssh.execute_cmd('kdestroy -A')
+        ssh_foo3.close()
+
+    def test_kcm_payload_low_quota(self,
+                                   multihost,
+                                   enable_kcm):
+        """
+        Set a prohibitive quota for the per-ccache payload limit and
+        make sure it gets enforced
+        """
+
+        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
+                             username='foo3', password='Secret123')
+        ssh_foo3.execute_cmd('kdestroy -A')
+        ssh_foo3.close()
+
+        set_param(multihost, 'kcm', 'max_ccache_size', '1')
+        self._restart_kcm(multihost)
+
+        with pytest.raises(paramiko.ssh_exception.AuthenticationException):
+            ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
+                                 username='foo3', password='Secret123')
_______________________________________________
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://getfedora.org/code-of-conduct.html
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org

Reply via email to