summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Blin <kai@samba.org>2012-08-31 13:41:19 +0200
committerKai Blin <kai@samba.org>2012-08-31 22:46:01 +0200
commitc256566aa97e040a9b3007c779b1006d20462ccb (patch)
treeaf9c0d5a21bf0fde7d27f704b9308f61e088ae0f
parente4505fc27bf31dbf922635fac19ea52a2a002bd4 (diff)
downloadsamba-c256566aa97e040a9b3007c779b1006d20462ccb.tar.gz
samba-c256566aa97e040a9b3007c779b1006d20462ccb.tar.bz2
samba-c256566aa97e040a9b3007c779b1006d20462ccb.zip
s4 dns: Store TKEYs in a ringbuffer
This stops us from potentially being DoSed by tons of TKEYs Autobuild-User(master): Kai Blin <kai@samba.org> Autobuild-Date(master): Fri Aug 31 22:46:01 CEST 2012 on sn-devel-104
-rw-r--r--source4/dns_server/dns_query.c125
-rw-r--r--source4/dns_server/dns_server.c27
-rw-r--r--source4/dns_server/dns_server.h11
3 files changed, 106 insertions, 57 deletions
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;
};