s4 dns: Store TKEYs in a ringbuffer
authorKai Blin <kai@samba.org>
Fri, 31 Aug 2012 11:41:19 +0000 (13:41 +0200)
committerKai Blin <kai@samba.org>
Fri, 31 Aug 2012 20:46:01 +0000 (22:46 +0200)
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

source4/dns_server/dns_query.c
source4/dns_server/dns_server.c
source4/dns_server/dns_server.h

index e9c3a24b561c9aed005fc043d04f76d4783d26a7..530b7b22bd5e66ae2892d12fd8571a9b1b0700eb 100644 (file)
@@ -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;
index 70fb6a262dd99cfa9528ec20ac5c7aa276e576a7..887fc8ee1d6391109e628e78729c79aa5c587cca 100644 (file)
@@ -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) {
index c2fe6cf9e8f9e18e9a2c9e2eddbf25c552390887..42ae0ba660c24bdca1eb1baf9e259c05f932ebbc 100644 (file)
@@ -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;
 };