X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Frpc_server%2Fdnsserver%2Fdnsdata.c;h=fb2547ff7ecc4c858e7c477339c3ce97d73a213b;hb=cc103a8187317047347a679e42b076de7d69d181;hp=e1b7f356ff528fd1433de1697c8db6fcb2ae77ee;hpb=c1b45afcf254ed0bbb36b125e440a2731c253e63;p=samba.git diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c index e1b7f356ff5..fb2547ff7ec 100644 --- a/source4/rpc_server/dnsserver/dnsdata.c +++ b/source4/rpc_server/dnsserver/dnsdata.c @@ -128,6 +128,10 @@ int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***com char *str = NULL, *ptr, **list; int count = 0; + if (name == NULL) { + return 0; + } + str = talloc_strdup(tmp_ctx, name); if (!str) { goto failed; @@ -200,7 +204,7 @@ char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char } 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++; @@ -232,7 +236,7 @@ char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char 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); @@ -319,8 +323,12 @@ void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp, 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; idata.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: @@ -351,7 +359,7 @@ void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp, 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); @@ -404,9 +412,9 @@ struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RP 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; @@ -432,7 +440,11 @@ struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RP 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; idata.txt.count; i++) { + dnsp->data.txt.str[i] = talloc_strdup(mem_ctx, dns->data.txt.str[i].str); + } break; case DNS_TYPE_AAAA: @@ -462,6 +474,192 @@ struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RP } +/* 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; inum_children == 0) { + break; + } + next = NULL; + for (j=0; jnum_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; icount; 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; levellevel == 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; @@ -469,7 +667,7 @@ static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_nam int count = *add_count; for (i=0; icount > 0) { - found = true; - } + if (recs->count == 0) { + recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS); } else { - for (i=0; icount; 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; jnum_values; j++) { struct dnsp_DnssrvRpcRecord dnsp_rec; struct DNS_RPC_RECORD *dns_rec; @@ -661,8 +829,12 @@ WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx, 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) { @@ -696,14 +868,14 @@ int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m 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; } @@ -713,7 +885,7 @@ int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m 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--; @@ -731,7 +903,7 @@ int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m 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--; @@ -765,6 +937,9 @@ bool dns_name_equal(const char *name1, const char *name2) bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2) { + bool status; + int i; + if (rec1->wType != rec2->wType) { return false; } @@ -777,14 +952,14 @@ bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRe 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 && @@ -792,14 +967,22 @@ bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRe 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; idata.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;