From 0504065948eec9bd65296d5956b5863d9af06e41 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 22 Sep 2015 12:10:00 +1200 Subject: [PATCH] dns_server: Put more code in common This will allow a python module to be written to modify DNS entries in sam.ldb directly Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam --- source4/dns_server/dns_server.c | 66 +--------- source4/dns_server/dns_server.h | 9 +- source4/dns_server/dns_utils.c | 88 +------------ source4/dns_server/dnsserver_common.c | 170 ++++++++++++++++++++++++++ source4/dns_server/dnsserver_common.h | 18 ++- 5 files changed, 195 insertions(+), 156 deletions(-) diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c index 66ab738eb43..45d28a77e6b 100644 --- a/source4/dns_server/dns_server.c +++ b/source4/dns_server/dns_server.c @@ -725,27 +725,6 @@ static NTSTATUS dns_startup_interfaces(struct dns_server *dns, return NT_STATUS_OK; } -static int dns_server_sort_zones(struct ldb_message **m1, struct ldb_message **m2) -{ - const char *n1, *n2; - size_t l1, l2; - - n1 = ldb_msg_find_attr_as_string(*m1, "name", NULL); - n2 = ldb_msg_find_attr_as_string(*m2, "name", NULL); - - l1 = strlen(n1); - l2 = strlen(n2); - - /* If the string lengths are not equal just sort by length */ - if (l1 != l2) { - /* If m1 is the larger zone name, return it first */ - return l2 - l1; - } - - /*TODO: We need to compare DNs here, we want the DomainDNSZones first */ - return 0; -} - static struct dns_server_tkey_store *tkey_store_init(TALLOC_CTX *mem_ctx, uint16_t size) { @@ -769,51 +748,14 @@ static struct dns_server_tkey_store *tkey_store_init(TALLOC_CTX *mem_ctx, static NTSTATUS dns_server_reload_zones(struct dns_server *dns) { - int ret; - static const char * const attrs[] = { "name", NULL}; - struct ldb_result *res; - int i; + NTSTATUS status; struct dns_server_zone *new_list = NULL; struct dns_server_zone *old_list = NULL; struct dns_server_zone *old_zone; - - // TODO: this search does not work against windows - ret = dsdb_search(dns->samdb, dns, &res, NULL, LDB_SCOPE_SUBTREE, - attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, "(objectClass=dnsZone)"); - if (ret != LDB_SUCCESS) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - TYPESAFE_QSORT(res->msgs, res->count, dns_server_sort_zones); - - for (i=0; i < res->count; i++) { - struct dns_server_zone *z; - - z = talloc_zero(dns, struct dns_server_zone); - if (z == NULL) { - return NT_STATUS_NO_MEMORY; - } - - z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL); - z->dn = talloc_move(z, &res->msgs[i]->dn); - /* - * Ignore the RootDNSServers zone and zones that we don't support yet - * RootDNSServers should never be returned (Windows DNS server don't) - * ..TrustAnchors should never be returned as is, (Windows returns - * TrustAnchors) and for the moment we don't support DNSSEC so we'd better - * not return this zone. - */ - if ((strcmp(z->name, "RootDNSServers") == 0) || - (strcmp(z->name, "..TrustAnchors") == 0)) - { - DEBUG(10, ("Ignoring zone %s\n", z->name)); - talloc_free(z); - continue; - } - DLIST_ADD_END(new_list, z, NULL); + status = dns_common_zones(dns->samdb, dns, &new_list); + if (!NT_STATUS_IS_OK(status)) { + return status; } - - old_list = dns->zones; dns->zones = new_list; while ((old_zone = DLIST_TAIL(old_list)) != NULL) { DLIST_REMOVE(old_list, old_zone); diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h index 64b716a2542..e5c15ec1532 100644 --- a/source4/dns_server/dns_server.h +++ b/source4/dns_server/dns_server.h @@ -24,15 +24,9 @@ #include "librpc/gen_ndr/dns.h" #include "librpc/gen_ndr/ndr_dnsp.h" +#include "dnsserver_common.h" struct tsocket_address; - -struct dns_server_zone { - struct dns_server_zone *prev, *next; - const char *name; - struct ldb_dn *dn; -}; - struct dns_server_tkey { const char *name; enum dns_tkey_mode mode; @@ -87,7 +81,6 @@ WERROR dns_server_process_update(struct dns_server *dns, struct dns_res_rec **updates, uint16_t *update_count, struct dns_res_rec **additional, uint16_t *arcount); -bool dns_name_match(const char *zone, const char *name, size_t *host_part_len); bool dns_name_equal(const char *name1, const char *name2); bool dns_records_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2); diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index 28412eb7681..3092633346e 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -33,47 +33,6 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_DNS -bool dns_name_match(const char *zone, const char *name, size_t *host_part_len) -{ - size_t zl = strlen(zone); - size_t nl = strlen(name); - ssize_t zi, ni; - static const size_t fixup = 'a' - 'A'; - - if (zl > nl) { - return false; - } - - for (zi = zl, ni = nl; zi >= 0; zi--, ni--) { - char zc = zone[zi]; - char nc = name[ni]; - - /* convert to lower case */ - if (zc >= 'A' && zc <= 'Z') { - zc += fixup; - } - if (nc >= 'A' && nc <= 'Z') { - nc += fixup; - } - - if (zc != nc) { - return false; - } - } - - if (ni >= 0) { - if (name[ni] != '.') { - return false; - } - - ni--; - } - - *host_part_len = ni+1; - - return true; -} - /* Names are equal if they match and there's nothing left over */ bool dns_name_equal(const char *name1, const char *name2) { @@ -218,51 +177,10 @@ const char *dns_get_authoritative_zone(struct dns_server *dns, WERROR dns_name2dn(struct dns_server *dns, TALLOC_CTX *mem_ctx, const char *name, - struct ldb_dn **_dn) + struct ldb_dn **dn) { - struct ldb_dn *base; - struct ldb_dn *dn; - const struct dns_server_zone *z; - size_t host_part_len = 0; - - if (name == NULL) { - return DNS_ERR(FORMAT_ERROR); - } - - /*TODO: Check if 'name' is a valid DNS name */ - - if (strcmp(name, "") == 0) { - base = ldb_get_default_basedn(dns->samdb); - dn = ldb_dn_copy(mem_ctx, base); - ldb_dn_add_child_fmt(dn, "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System"); - *_dn = dn; - return WERR_OK; - } - - for (z = dns->zones; z != NULL; z = z->next) { - bool match; - - match = dns_name_match(z->name, name, &host_part_len); - if (match) { - break; - } - } - - if (z == NULL) { - return DNS_ERR(NAME_ERROR); - } - - if (host_part_len == 0) { - dn = ldb_dn_copy(mem_ctx, z->dn); - ldb_dn_add_child_fmt(dn, "DC=@"); - *_dn = dn; - return WERR_OK; - } - - dn = ldb_dn_copy(mem_ctx, z->dn); - ldb_dn_add_child_fmt(dn, "DC=%*.*s", (int)host_part_len, (int)host_part_len, name); - *_dn = dn; - return WERR_OK; + return dns_common_name2dn(dns->samdb, dns->zones, + mem_ctx, name, dn); } WERROR dns_generate_options(struct dns_server *dns, diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index c49d6ec87a6..7199ef721d8 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -5,6 +5,7 @@ Copyright (C) 2010 Kai Blin Copyright (C) 2014 Stefan Metzmacher + Copyright (C) 2015 Andrew Bartlett This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,6 +31,7 @@ #include "dsdb/samdb/samdb.h" #include "dsdb/common/util.h" #include "dns_server/dnsserver_common.h" +#include "lib/util/dlinklist.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_DNS @@ -340,3 +342,171 @@ WERROR dns_common_replace(struct ldb_context *samdb, return WERR_OK; } + +bool dns_name_match(const char *zone, const char *name, size_t *host_part_len) +{ + size_t zl = strlen(zone); + size_t nl = strlen(name); + ssize_t zi, ni; + static const size_t fixup = 'a' - 'A'; + + if (zl > nl) { + return false; + } + + for (zi = zl, ni = nl; zi >= 0; zi--, ni--) { + char zc = zone[zi]; + char nc = name[ni]; + + /* convert to lower case */ + if (zc >= 'A' && zc <= 'Z') { + zc += fixup; + } + if (nc >= 'A' && nc <= 'Z') { + nc += fixup; + } + + if (zc != nc) { + return false; + } + } + + if (ni >= 0) { + if (name[ni] != '.') { + return false; + } + + ni--; + } + + *host_part_len = ni+1; + + return true; +} + +WERROR dns_common_name2dn(struct ldb_context *samdb, + struct dns_server_zone *zones, + TALLOC_CTX *mem_ctx, + const char *name, + struct ldb_dn **_dn) +{ + struct ldb_dn *base; + struct ldb_dn *dn; + const struct dns_server_zone *z; + size_t host_part_len = 0; + + if (name == NULL) { + return DNS_ERR(FORMAT_ERROR); + } + + /*TODO: Check if 'name' is a valid DNS name */ + + if (strcmp(name, "") == 0) { + base = ldb_get_default_basedn(samdb); + dn = ldb_dn_copy(mem_ctx, base); + ldb_dn_add_child_fmt(dn, "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System"); + *_dn = dn; + return WERR_OK; + } + + for (z = zones; z != NULL; z = z->next) { + bool match; + + match = dns_name_match(z->name, name, &host_part_len); + if (match) { + break; + } + } + + if (z == NULL) { + return DNS_ERR(NAME_ERROR); + } + + if (host_part_len == 0) { + dn = ldb_dn_copy(mem_ctx, z->dn); + ldb_dn_add_child_fmt(dn, "DC=@"); + *_dn = dn; + return WERR_OK; + } + + dn = ldb_dn_copy(mem_ctx, z->dn); + ldb_dn_add_child_fmt(dn, "DC=%*.*s", (int)host_part_len, (int)host_part_len, name); + *_dn = dn; + return WERR_OK; +} + +static int dns_common_sort_zones(struct ldb_message **m1, struct ldb_message **m2) +{ + const char *n1, *n2; + size_t l1, l2; + + n1 = ldb_msg_find_attr_as_string(*m1, "name", NULL); + n2 = ldb_msg_find_attr_as_string(*m2, "name", NULL); + + l1 = strlen(n1); + l2 = strlen(n2); + + /* If the string lengths are not equal just sort by length */ + if (l1 != l2) { + /* If m1 is the larger zone name, return it first */ + return l2 - l1; + } + + /*TODO: We need to compare DNs here, we want the DomainDNSZones first */ + return 0; +} + +NTSTATUS dns_common_zones(struct ldb_context *samdb, + TALLOC_CTX *mem_ctx, + struct dns_server_zone **zones_ret) +{ + int ret; + static const char * const attrs[] = { "name", NULL}; + struct ldb_result *res; + int i; + struct dns_server_zone *new_list = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + // TODO: this search does not work against windows + ret = dsdb_search(samdb, frame, &res, NULL, LDB_SCOPE_SUBTREE, + attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, "(objectClass=dnsZone)"); + if (ret != LDB_SUCCESS) { + TALLOC_FREE(frame); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + TYPESAFE_QSORT(res->msgs, res->count, dns_common_sort_zones); + + for (i=0; i < res->count; i++) { + struct dns_server_zone *z; + + z = talloc_zero(mem_ctx, struct dns_server_zone); + if (z == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL); + talloc_steal(z, z->name); + z->dn = talloc_move(z, &res->msgs[i]->dn); + /* + * Ignore the RootDNSServers zone and zones that we don't support yet + * RootDNSServers should never be returned (Windows DNS server don't) + * ..TrustAnchors should never be returned as is, (Windows returns + * TrustAnchors) and for the moment we don't support DNSSEC so we'd better + * not return this zone. + */ + if ((strcmp(z->name, "RootDNSServers") == 0) || + (strcmp(z->name, "..TrustAnchors") == 0)) + { + DEBUG(10, ("Ignoring zone %s\n", z->name)); + talloc_free(z); + continue; + } + DLIST_ADD_END(new_list, z, NULL); + } + + *zones_ret = new_list; + TALLOC_FREE(frame); + return NT_STATUS_OK; +} diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h index becd243f6a9..ad91f617be7 100644 --- a/source4/dns_server/dnsserver_common.h +++ b/source4/dns_server/dnsserver_common.h @@ -26,6 +26,14 @@ uint8_t werr_to_dns_err(WERROR werr); #define DNS_ERR(err_str) WERR_DNS_ERROR_RCODE_##err_str struct ldb_message_element; +struct ldb_context; +struct dnsp_DnssrvRpcRecord; + +struct dns_server_zone { + struct dns_server_zone *prev, *next; + const char *name; + struct ldb_dn *dn; +}; WERROR dns_common_extract(const struct ldb_message_element *el, TALLOC_CTX *mem_ctx, @@ -46,5 +54,13 @@ WERROR dns_common_replace(struct ldb_context *samdb, uint32_t serial, struct dnsp_DnssrvRpcRecord *records, uint16_t rec_count); - +bool dns_name_match(const char *zone, const char *name, size_t *host_part_len); +WERROR dns_common_name2dn(struct ldb_context *samdb, + struct dns_server_zone *zones, + TALLOC_CTX *mem_ctx, + const char *name, + struct ldb_dn **_dn); +NTSTATUS dns_common_zones(struct ldb_context *samdb, + TALLOC_CTX *mem_ctx, + struct dns_server_zone **zones_ret); #endif /* __DNSSERVER_COMMON_H__ */ -- 2.34.1