From c256566aa97e040a9b3007c779b1006d20462ccb Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Fri, 31 Aug 2012 13:41:19 +0200 Subject: s4 dns: Store TKEYs in a ringbuffer This stops us from potentially being DoSed by tons of TKEYs Autobuild-User(master): Kai Blin Autobuild-Date(master): Fri Aug 31 22:46:01 CEST 2012 on sn-devel-104 --- source4/dns_server/dns_query.c | 125 ++++++++++++++++++++++------------------ source4/dns_server/dns_server.c | 27 +++++++++ source4/dns_server/dns_server.h | 11 +++- 3 files changed, 106 insertions(+), 57 deletions(-) (limited to 'source4') diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index e9c3a24b56..530b7b22bd 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -36,7 +36,6 @@ #include "auth/auth.h" #include "auth/credentials/credentials.h" #include "auth/gensec/gensec.h" -#include "lib/util/dlinklist.h" static WERROR create_response_rr(const struct dns_name_question *question, const struct dnsp_DnssrvRpcRecord *rec, @@ -321,19 +320,73 @@ static WERROR handle_question(struct dns_server *dns, return WERR_OK; } -static NTSTATUS create_new_tkey(TALLOC_CTX *mem_ctx, - struct dns_server *dns, - struct dns_server_tkey **tkey, - const char* name) +static NTSTATUS accept_gss_ticket(TALLOC_CTX *mem_ctx, + struct dns_server *dns, + struct dns_server_tkey *tkey, + const DATA_BLOB *key, + DATA_BLOB *reply, + uint16_t *dns_auth_error) +{ + NTSTATUS status; + + status = gensec_update(tkey->gensec, mem_ctx, dns->task->event_ctx, + *key, reply); + + if (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) { + *dns_auth_error = DNS_RCODE_OK; + return status; + } + + if (NT_STATUS_IS_OK(status)) { + + status = gensec_session_info(tkey->gensec, tkey, &tkey->session_info); + if (!NT_STATUS_IS_OK(status)) { + *dns_auth_error = DNS_RCODE_BADKEY; + return status; + } + *dns_auth_error = DNS_RCODE_OK; + } + + return status; +} + +static struct dns_server_tkey *find_tkey(struct dns_server_tkey_store *store, + const char *name) +{ + struct dns_server_tkey *tkey = NULL; + uint16_t i = 0; + + do { + struct dns_server_tkey *tmp_key = store->tkeys[i]; + + i++; + i %= TKEY_BUFFER_SIZE; + + if (tmp_key == NULL) { + continue; + } + if (dns_name_equal(name, tmp_key->name)) { + tkey = tmp_key; + break; + } + } while (i != 0); + + return tkey; +} + +static NTSTATUS create_tkey(struct dns_server *dns, + const char* name, + struct dns_server_tkey **tkey) { NTSTATUS status; - struct dns_server_tkey *k = talloc_zero(mem_ctx, struct dns_server_tkey); + struct dns_server_tkey_store *store = dns->tkeys; + struct dns_server_tkey *k = talloc_zero(store, struct dns_server_tkey); if (k == NULL) { return NT_STATUS_NO_MEMORY; } - k->name = talloc_strdup(mem_ctx, name); + k->name = talloc_strdup(k, name); if (k->name == NULL) { return NT_STATUS_NO_MEMORY; @@ -363,52 +416,16 @@ static NTSTATUS create_new_tkey(TALLOC_CTX *mem_ctx, return status; } - *tkey = k; - return NT_STATUS_OK; -} - -static NTSTATUS accept_gss_ticket(TALLOC_CTX *mem_ctx, - struct dns_server *dns, - struct dns_server_tkey *tkey, - const DATA_BLOB *key, - DATA_BLOB *reply, - uint16_t *dns_auth_error) -{ - NTSTATUS status; - - status = gensec_update(tkey->gensec, mem_ctx, dns->task->event_ctx, - *key, reply); - - if (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) { - *dns_auth_error = DNS_RCODE_OK; - return status; + if (store->tkeys[store->next_idx] != NULL) { + TALLOC_FREE(store->tkeys[store->next_idx]); } - if (NT_STATUS_IS_OK(status)) { + store->tkeys[store->next_idx] = k; + (store->next_idx)++; + store->next_idx %= store->size; - status = gensec_session_info(tkey->gensec, tkey, &tkey->session_info); - if (!NT_STATUS_IS_OK(status)) { - *dns_auth_error = DNS_RCODE_BADKEY; - return status; - } - *dns_auth_error = DNS_RCODE_OK; - } - - return status; -} - -static struct dns_server_tkey *find_tkey(struct dns_server *dns, - const char *name) -{ - struct dns_server_tkey *tkey = NULL; - - for (tkey = dns->tkeys; tkey != NULL; tkey = tkey->next) { - if (dns_name_equal(name, tkey->name)) { - break; - } - } - - return tkey; + *tkey = k; + return NT_STATUS_OK; } static WERROR handle_tkey(struct dns_server *dns, @@ -470,7 +487,7 @@ static WERROR handle_tkey(struct dns_server *dns, DATA_BLOB key; DATA_BLOB reply; - tkey = find_tkey(dns, in->questions[0].name); + tkey = find_tkey(dns->tkeys, in->questions[0].name); if (tkey != NULL && tkey->complete) { /* TODO: check if the key is still valid */ DEBUG(1, ("Rejecting tkey negotiation for already established key\n")); @@ -479,14 +496,12 @@ static WERROR handle_tkey(struct dns_server *dns, } if (tkey == NULL) { - status = create_new_tkey(dns, dns, &tkey, - in->questions[0].name); + status = create_tkey(dns, in->questions[0].name, + &tkey); if (!NT_STATUS_IS_OK(status)) { ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY; return ntstatus_to_werror(status); } - - DLIST_ADD_END(dns->tkeys, tkey, NULL); } key.data = in_tkey->rdata.tkey_record.key_data; diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c index 70fb6a262d..887fc8ee1d 100644 --- a/source4/dns_server/dns_server.c +++ b/source4/dns_server/dns_server.c @@ -683,6 +683,27 @@ static int dns_server_sort_zones(struct ldb_message **m1, struct ldb_message **m return 0; } +static struct dns_server_tkey_store *tkey_store_init(TALLOC_CTX *mem_ctx, + uint16_t size) +{ + struct dns_server_tkey_store *buffer = talloc_zero(mem_ctx, + struct dns_server_tkey_store); + + if (buffer == NULL) { + return NULL; + } + + buffer->size = size; + buffer->next_idx = 0; + + buffer->tkeys = talloc_zero_array(buffer, struct dns_server_tkey *, size); + if (buffer->tkeys == NULL) { + TALLOC_FREE(buffer); + } + + return buffer; +} + static void dns_task_init(struct task_server *task) { struct dns_server *dns; @@ -738,6 +759,12 @@ static void dns_task_init(struct task_server *task) return; } + dns->tkeys = tkey_store_init(dns, TKEY_BUFFER_SIZE); + if (!dns->tkeys) { + task_server_terminate(task, "Failed to allocate tkey storage\n", true); + return; + } + dns->samdb = samdb_connect(dns, dns->task->event_ctx, dns->task->lp_ctx, system_session(dns->task->lp_ctx), 0); if (!dns->samdb) { diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h index c2fe6cf9e8..42ae0ba660 100644 --- a/source4/dns_server/dns_server.h +++ b/source4/dns_server/dns_server.h @@ -34,7 +34,6 @@ struct dns_server_zone { }; struct dns_server_tkey { - struct dns_server_tkey *prev, *next; const char *name; enum dns_tkey_mode mode; struct auth_session_info *session_info; @@ -42,11 +41,19 @@ struct dns_server_tkey { bool complete; }; +#define TKEY_BUFFER_SIZE 128 + +struct dns_server_tkey_store { + struct dns_server_tkey **tkeys; + uint16_t next_idx; + uint16_t size; +}; + struct dns_server { struct task_server *task; struct ldb_context *samdb; struct dns_server_zone *zones; - struct dns_server_tkey *tkeys; + struct dns_server_tkey_store *tkeys; struct cli_credentials *server_credentials; }; -- cgit