From 109ed7ca1a82420798efdc6a9b019675a5bd0f4f Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 7 Jun 2017 17:20:43 +0200 Subject: [PATCH 93/93] SECRETS: Support 0 as unlimited for the quotas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a special value for all the quota-like settings that means 'no limit'. Because the responder also had a global limit on the size of the accepted body (64kiB), this patch also removes the hardcoded limit and instead keep track of the biggest quota value on startup. Reviewed-by: Simo Sorce Reviewed-by: Fabiano FidĂȘncio --- src/man/sssd-secrets.5.xml | 3 +- src/responder/secrets/local.c | 16 ++++++++++ src/responder/secrets/secsrv.c | 15 ++++++++++ src/responder/secrets/secsrv.h | 1 + src/responder/secrets/secsrv_cmd.c | 6 +++- src/responder/secrets/secsrv_private.h | 2 +- src/tests/intg/test_secrets.py | 55 ++++++++++++++++++++++++++++++++++ 7 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml index c74894c62ed70764ca680c3b1cfe7f903d280277..d43dcf21c6174f0e0780a76d831a1fd957358b51 100644 --- a/src/man/sssd-secrets.5.xml +++ b/src/man/sssd-secrets.5.xml @@ -173,7 +173,8 @@ systemctl enable sssd-secrets.service The following options affect only the secrets hive - and therefore should be set in a per-hive subsection. + and therefore should be set in a per-hive subsection. Setting the + option to 0 means "unlimited". diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c index 5e491ba98fdc5612db0c303258513302c1f1d9e3..5a8b67731137dd2597211dedf817b8a92a62aa05 100644 --- a/src/responder/secrets/local.c +++ b/src/responder/secrets/local.c @@ -397,6 +397,10 @@ static int local_db_check_containers_nest_level(struct local_db_req *lc_req, { int nest_level; + if (lc_req->quota->containers_nest_level == 0) { + return EOK; + } + /* We need do not care for the synthetic containers that constitute the * base path (cn=,cn=user,cn=secrets). */ nest_level = ldb_dn_get_comp_num(leaf_dn) - 3; @@ -456,6 +460,10 @@ static int local_db_check_peruid_number_of_secrets(TALLOC_CTX *mem_ctx, struct ldb_dn *cli_basedn = NULL; int ret; + if (lc_req->quota->max_uid_secrets == 0) { + return EOK; + } + tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return ENOMEM; @@ -501,6 +509,10 @@ static int local_db_check_number_of_secrets(TALLOC_CTX *mem_ctx, struct ldb_dn *dn; int ret; + if (lc_req->quota->max_secrets == 0) { + return EOK; + } + tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) return ENOMEM; @@ -538,6 +550,10 @@ static int local_check_max_payload_size(struct local_db_req *lc_req, { int max_payload_size; + if (lc_req->quota->max_payload_size == 0) { + return EOK; + } + max_payload_size = lc_req->quota->max_payload_size * 1024; /* kb */ if (payload_size > max_payload_size) { DEBUG(SSSDBG_OP_FAILURE, diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c index 36b257c463ccaa1f552b2b4985932dc0d3b125aa..2b661b165ef0c174557f53012b2dbaa236a6e359 100644 --- a/src/responder/secrets/secsrv.c +++ b/src/responder/secrets/secsrv.c @@ -146,6 +146,16 @@ static int sec_get_hive_config(struct sec_ctx *sctx, goto done; } + if (hive_config->quota.max_payload_size == 0 + || (sctx->max_payload_size != 0 + && hive_config->quota.max_payload_size > sctx->max_payload_size)) { + /* If the quota is unlimited or it's larger than what + * we already have, save the total limit so we know how much to + * accept from clients + */ + sctx->max_payload_size = hive_config->quota.max_payload_size; + } + ret = EOK; done: @@ -168,6 +178,11 @@ static int sec_get_config(struct sec_ctx *sctx) goto fail; } + /* Set the global max_payload to ridiculously small value so that either 0 (unlimited) + * or any sensible value overwrite it + */ + 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() diff --git a/src/responder/secrets/secsrv.h b/src/responder/secrets/secsrv.h index afdd731fbd44d7bb280ffc0e55db9c39a926bf22..3023116402f8540dcf4436dcc0b6ea030d892468 100644 --- a/src/responder/secrets/secsrv.h +++ b/src/responder/secrets/secsrv.h @@ -49,6 +49,7 @@ struct sec_ctx { struct sec_hive_config sec_config; struct sec_hive_config kcm_config; + int max_payload_size; struct provider_handle **providers; }; diff --git a/src/responder/secrets/secsrv_cmd.c b/src/responder/secrets/secsrv_cmd.c index b88680c3d7c3105d160de5c78e6d981b852318b9..fa5970504d9f67c6341ebd8276da76f0b608fd55 100644 --- a/src/responder/secrets/secsrv_cmd.c +++ b/src/responder/secrets/secsrv_cmd.c @@ -178,7 +178,8 @@ static void sec_append_string(TALLOC_CTX *memctx, char **dest, static bool sec_too_much_data(struct sec_req_ctx *req, size_t length) { req->total_size += length; - if (req->total_size > SEC_REQUEST_MAX_SIZE) { + if (req->max_payload_size > 0 + && req->total_size > req->max_payload_size) { DEBUG(SSSDBG_FATAL_FAILURE, "Request too big, aborting client!\n"); return true; @@ -513,6 +514,8 @@ static void sec_recv(struct cli_ctx *cctx) { struct sec_proto_ctx *prctx; struct sec_req_ctx *req; + struct sec_ctx *sec_ctx = talloc_get_type(cctx->rctx->pvt_ctx, + struct sec_ctx); char buffer[SEC_PACKET_MAX_RECV_SIZE]; struct sec_data data = { buffer, SEC_PACKET_MAX_RECV_SIZE }; @@ -531,6 +534,7 @@ static void sec_recv(struct cli_ctx *cctx) return; } req->cctx = cctx; + req->max_payload_size = sec_ctx->max_payload_size; cctx->state_ctx = req; http_parser_init(&prctx->parser, HTTP_REQUEST); prctx->parser.data = req; diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h index 2e68628f61a0a8e79cd48fb5a510221e6fc36c70..c4a0c5745e8db092d28cf1ef9cb397af0c7314cb 100644 --- a/src/responder/secrets/secsrv_private.h +++ b/src/responder/secrets/secsrv_private.h @@ -75,6 +75,7 @@ struct sec_req_ctx { bool complete; size_t total_size; + size_t max_payload_size; char *request_url; char *mapped_path; @@ -151,7 +152,6 @@ bool sec_req_has_header(struct sec_req_ctx *req, const char *name, const char *value); /* secsrv_cmd.c */ -#define SEC_REQUEST_MAX_SIZE 65536 #define SEC_PACKET_MAX_RECV_SIZE 8192 int sec_send_data(int fd, struct sec_data *data); diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py index 957a0a8ff9ce5e966b77ddf048eefc282b2711b6..15caa69582ea6fe5031df8150343412f0e68bd5e 100644 --- a/src/tests/intg/test_secrets.py +++ b/src/tests/intg/test_secrets.py @@ -545,3 +545,58 @@ def test_per_uid_limit(setup_for_uid_limit, secrets_cli): # FIXME - at this point, it would be nice to test that another UID can # still store secrets, but sadly socket_wrapper doesn't allow us to fake # UIDs yet + + +@pytest.fixture +def setup_for_unlimited_quotas(request): + conf = unindent("""\ + [sssd] + domains = local + services = nss + + [domain/local] + id_provider = local + + [secrets] + debug_level = 10 + + [secrets/secrets] + max_secrets = 0 + max_uid_secrets = 0 + max_payload_size = 0 + containers_nest_level = 0 + """).format(**locals()) + + create_conf_fixture(request, conf) + create_sssd_secrets_fixture(request) + return None + + +def test_unlimited_quotas(setup_for_unlimited_quotas, secrets_cli): + """ + Test that setting quotas to zero disabled any checks and lets + store whatever. + """ + cli = secrets_cli + + # test much larger amount of secrets that we allow by default + sec_value = "value" + for i in range(2048): + cli.set_secret(str(i), sec_value) + + # test a much larger secret size than the default one + KILOBYTE = 1024 + payload_size = 32 * KILOBYTE + + sec_value = "x" * payload_size + cli.set_secret("foo", sec_value) + + fooval = cli.get_secret("foo") + assert fooval == sec_value + + # test a deep secret nesting structure + DEFAULT_CONTAINERS_NEST_LEVEL = 128 + container = "mycontainer" + for i in range(DEFAULT_CONTAINERS_NEST_LEVEL): + container += "%s/" % str(i) + cli.create_container(container) -- 2.14.1