char *str = NULL, *ptr, **list;
int count = 0;
+ if (name == NULL) {
+ return 0;
+ }
+
str = talloc_strdup(tmp_ctx, name);
if (!str) {
goto failed;
} else {
match = 0;
for (i=1; i<=zcount; i++) {
- if (strcmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
+ if (strcasecmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
break;
}
match++;
void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
struct DNS_RPC_RECORD *dns)
{
- int len;
+ int i, len;
ZERO_STRUCTP(dns);
break;
case DNS_TYPE_TXT:
- dns->data.name.len = strlen(dnsp->data.txt);
- dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.txt);
+ dns->data.txt.count = dnsp->data.txt.count;
+ dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
+ for (i=0; i<dnsp->data.txt.count; i++) {
+ dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
+ dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
+ }
break;
case DNS_TYPE_AAAA:
struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns)
{
- int len;
+ int i, len;
struct dnsp_DnssrvRpcRecord *dnsp;
dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
len = dns->data.soa.NamePrimaryServer.len;
if (dns->data.soa.NamePrimaryServer.str[len-1] == '.') {
- dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str);
- } else {
dnsp->data.soa.mname = talloc_strndup(mem_ctx, dns->data.soa.NamePrimaryServer.str, len-1);
+ } else {
+ dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str);
}
len = dns->data.soa.ZoneAdministratorEmail.len;
break;
case DNS_TYPE_TXT:
- dnsp->data.txt = talloc_strdup(mem_ctx, dns->data.name.str);
+ dnsp->data.txt.count = dns->data.txt.count;
+ dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
+ for (i=0; i<dns->data.txt.count; i++) {
+ dnsp->data.txt.str[i] = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
+ }
break;
case DNS_TYPE_AAAA:
}
+/* Intialize tree with given name as the root */
+static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
+{
+ struct dns_tree *tree;
+
+ tree = talloc_zero(mem_ctx, struct dns_tree);
+ if (tree == NULL) {
+ return NULL;
+ }
+
+ tree->name = talloc_strdup(tree, name);
+ if (tree->name == NULL) {
+ talloc_free(tree);
+ return NULL;
+ }
+
+ tree->data = data;
+
+ return tree;
+}
+
+
+/* Add a child one level below */
+static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
+{
+ struct dns_tree *node;
+
+ node = talloc_zero(tree, struct dns_tree);
+ if (node == NULL) {
+ return NULL;
+ }
+
+ node->name = talloc_strdup(tree, name);
+ if (node->name == NULL) {
+ talloc_free(node);
+ return NULL;
+ }
+ node->level = tree->level + 1;
+ node->num_children = 0;
+ node->children = NULL;
+ node->data = data;
+
+ if (tree->num_children == 0) {
+ tree->children = talloc_zero(tree, struct dns_tree *);
+ } else {
+ tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
+ tree->num_children+1);
+ }
+ if (tree->children == NULL) {
+ talloc_free(node);
+ return NULL;
+ }
+ tree->children[tree->num_children] = node;
+ tree->num_children++;
+
+ return node;
+}
+
+/* Find a node that matches the name components */
+static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
+{
+ struct dns_tree *node, *next;
+ int i, j, start;
+
+ *match_count = -1;
+
+ if (strcmp(tree->name, "@") == 0) {
+ start = 0;
+ } else {
+ if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
+ return NULL;
+ }
+ start = 1;
+ *match_count = 0;
+ }
+
+ node = tree;
+ for (i=start; i<ncount; i++) {
+ if (node->num_children == 0) {
+ break;
+ }
+ next = NULL;
+ for (j=0; j<node->num_children; j++) {
+ if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
+ next = node->children[j];
+ *match_count = i;
+ break;
+ }
+ }
+ if (next == NULL) {
+ break;
+ } else {
+ node = next;
+ }
+ }
+
+ return node;
+}
+
+/* Build a 2-level tree for resulting dns names */
+struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
+{
+ struct dns_tree *root, *base, *tree, *node;
+ const char *ptr;
+ int rootcount, ncount;
+ char **nlist;
+ int i, level, match_count;
+
+ rootcount = dns_split_name_components(mem_ctx, name, &nlist);
+ if (rootcount <= 0) {
+ return NULL;
+ }
+
+ root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
+ if (root == NULL) {
+ return NULL;
+ }
+
+ tree = root;
+ for (i=rootcount-2; i>=0; i--) {
+ tree = dns_tree_add(tree, nlist[i], NULL);
+ if (tree == NULL) {
+ goto failed;
+ }
+ }
+
+ base = tree;
+
+ /* Add all names in the result in a tree */
+ for (i=0; i<res->count; i++) {
+ ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
+
+ if (strcmp(ptr, "@") == 0) {
+ base->data = res->msgs[i];
+ continue;
+ } else if (strcasecmp(ptr, name) == 0) {
+ base->data = res->msgs[i];
+ continue;
+ }
+
+ ncount = dns_split_name_components(root, ptr, &nlist);
+ if (ncount < 0) {
+ goto failed;
+ }
+
+ /* Find matching node */
+ tree = dns_tree_find(root, ncount, nlist, &match_count);
+ if (tree == NULL) {
+ goto failed;
+ }
+
+ /* If the node is on leaf, then add record data */
+ if (match_count+1 == ncount) {
+ tree->data = res->msgs[i];
+ }
+
+ /* Add missing name components */
+ for (level=match_count+1; level<ncount; level++) {
+ if (tree->level == rootcount+1) {
+ break;
+ }
+ if (level == ncount-1) {
+ node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
+ } else {
+ node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
+ }
+ if (node == NULL) {
+ goto failed;
+ }
+ tree = node;
+ }
+
+ talloc_free(nlist);
+ }
+
+ /* Mark the base record, so it can be found easily */
+ base->level = -1;
+
+ return root;
+
+failed:
+ talloc_free(root);
+ return NULL;
+}
+
+
static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
{
int i;
int count = *add_count;
for (i=0; i<count; i++) {
- if (strcmp(ptr[i], name) == 0) {
+ if (strcasecmp(ptr[i], name) == 0) {
return;
}
}
unsigned int select_flag,
const char *branch_name,
struct ldb_message *msg,
+ int num_children,
struct DNS_RPC_RECORDS_ARRAY *recs,
char ***add_names,
int *add_count)
{
- const char *nodename;
struct ldb_message_element *el;
+ const char *ptr;
int i, j;
- bool found, node_is_rootzone;
+ bool found;
- /* Check if we already have created record for the branch */
- found = false;
- if (branch_name == NULL) {
- i = 0;
- if (recs->count > 0) {
- found = true;
- }
+ if (recs->count == 0) {
+ recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
} else {
- for (i=0; i<recs->count; i++) {
- if (strcmp(branch_name, recs->rec[i].dnsNodeName.str) == 0) {
- found = true;
- break;
- }
- }
+ recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
}
+ if (recs->rec == NULL) {
+ return WERR_NOMEM;
+ }
+ i = recs->count;
+ recs->rec[i].wLength = 0;
+ recs->rec[i].wRecordCount = 0;
+ recs->rec[i].dwChildCount = num_children;
- /* If not, add empty record */
- if (!found) {
- if (recs->count == 0) {
- recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
- } else {
- recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
- }
- if (recs->rec == NULL) {
- return WERR_NOMEM;
- }
- i = recs->count;
- recs->rec[i].wLength = 0;
- recs->rec[i].wRecordCount = 0;
- recs->rec[i].dwChildCount = 0;
-
- /* The base records returned with empty name */
- /* Children records returned with names */
- if (branch_name == NULL) {
- recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
- recs->rec[i].dnsNodeName.len = 0;
- } else {
- recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
- recs->rec[i].dnsNodeName.len = strlen(branch_name);
- }
- recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
- recs->count++;
+ /* The base records returned with empty name */
+ /* Children records returned with names */
+ if (branch_name == NULL) {
+ recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
+ recs->rec[i].dnsNodeName.len = 0;
+ } else {
+ recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
+ recs->rec[i].dnsNodeName.len = strlen(branch_name);
}
+ recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
+ recs->count++;
/* Allow empty records */
if (msg == NULL) {
return WERR_OK;
}
- nodename = ldb_msg_find_attr_as_string(msg, "name", NULL);
-
- if (strcmp(nodename, "@") == 0) {
- node_is_rootzone = true;
- } else {
- node_is_rootzone = false;
-
- /* child record */
- if (branch_name != NULL) {
- if (branch_name[strlen(branch_name)-1] != '.'
- && strcmp(nodename, branch_name) != 0) {
- recs->rec[i].dwChildCount++;
- return WERR_OK;
- }
- }
+ /* Do not return RR records, if the node has children */
+ if (branch_name != NULL && num_children > 0) {
+ return WERR_OK;
}
+ ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
el = ldb_msg_find_element(msg, "dnsRecord");
if (el == NULL || el->values == 0) {
- DEBUG(0, ("dnsserver: Missing dnsRecord for %s\n", ldb_dn_get_linearized(msg->dn)));
return WERR_OK;
}
- /* branch level record */
+ /* Add RR records */
for (j=0; j<el->num_values; j++) {
struct dnsp_DnssrvRpcRecord dnsp_rec;
struct DNS_RPC_RECORD *dns_rec;
dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
/* Fix record flags */
- if (node_is_rootzone) {
- dns_rec->dwFlags |= (DNS_RPC_FLAG_ZONE_ROOT | DNS_RPC_FLAG_AUTH_ZONE_ROOT);
+ if (strcmp(ptr, "@") == 0) {
+ dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
+
+ if (dnsp_rec.rank == DNS_RANK_ZONE) {
+ dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
+ }
}
if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
if (name1[0] == '@') {
return -1;
}
- if (search_name && strcmp(name1, search_name) == 0) {
+ if (search_name && strcasecmp(name1, search_name) == 0) {
return -1;
}
if (name2[0] == '@') {
return 1;
}
- if (search_name && strcmp(name2, search_name) == 0) {
+ if (search_name && strcasecmp(name2, search_name) == 0) {
return 1;
}
if (ptr1 == NULL) {
ptr1 = name1;
} else {
- if (search_name && strcmp(ptr1+1, search_name) == 0) {
+ if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
ptr1--;
while (ptr1 != name1) {
ptr1--;
if (ptr2 == NULL) {
ptr2 = name2;
} else {
- if (search_name && strcmp(ptr2+1, search_name) == 0) {
+ if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
ptr2--;
while (ptr2 != name2) {
ptr2--;
bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
{
+ bool status;
+ int i;
+
if (rec1->wType != rec2->wType) {
return false;
}
return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
case DNS_TYPE_NS:
- return dns_name_equal(rec1->data.ns, rec1->data.ns);
+ return dns_name_equal(rec1->data.ns, rec2->data.ns);
case DNS_TYPE_CNAME:
- return dns_name_equal(rec1->data.cname, rec1->data.cname);
+ return dns_name_equal(rec1->data.cname, rec2->data.cname);
case DNS_TYPE_SOA:
- return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) == 0 &&
- dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) == 0 &&
+ return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) &&
+ dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) &&
rec1->data.soa.serial == rec2->data.soa.serial &&
rec1->data.soa.refresh == rec2->data.soa.refresh &&
rec1->data.soa.retry == rec2->data.soa.retry &&
rec1->data.soa.minimum == rec2->data.soa.minimum;
case DNS_TYPE_PTR:
- return strcmp(rec1->data.ptr, rec2->data.ptr) == 0;
+ return dns_name_equal(rec1->data.ptr, rec2->data.ptr);
case DNS_TYPE_MX:
- return rec1->data.mx.wPriority == rec2->data.srv.wPriority &&
- dns_name_equal(rec1->data.mx.nameTarget, rec2->data.srv.nameTarget);
+ return rec1->data.mx.wPriority == rec2->data.mx.wPriority &&
+ dns_name_equal(rec1->data.mx.nameTarget, rec2->data.mx.nameTarget);
case DNS_TYPE_TXT:
- return strcmp(rec1->data.txt, rec2->data.txt) == 0;
+ if (rec1->data.txt.count != rec2->data.txt.count) {
+ return false;
+ }
+ status = true;
+ for (i=0; i<rec1->data.txt.count; i++) {
+ status = status && (strcmp(rec1->data.txt.str[i],
+ rec2->data.txt.str[i]) == 0);
+ }
+ return status;
case DNS_TYPE_AAAA:
return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;