535996036d312855abdd6f0791fd7fc6e6594454
[ddiss/samba.git] / source4 / rpc_server / dnsserver / dnsdata.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    DNS Server
5
6    Copyright (C) Amitay Isaacs 2011
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "dnsserver.h"
24 #include "lib/replace/system/network.h"
25 #include "librpc/gen_ndr/ndr_dnsp.h"
26 #include "librpc/gen_ndr/ndr_dnsserver.h"
27
28
29 struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4)
30 {
31         struct IP4_ARRAY *ret;
32
33         if (!ip4) {
34                 return NULL;
35         }
36
37         ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
38         if (!ret) {
39                 return ret;
40         }
41
42         ret->AddrCount = ip4->AddrCount;
43         if (ip4->AddrCount > 0) {
44                 ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount);
45                 if (ret->AddrArray) {
46                         memcpy(ret->AddrArray, ip4->AddrArray,
47                                 sizeof(unsigned int) * ip4->AddrCount);
48                 } else {
49                         talloc_free(ret);
50                         return NULL;
51                 }
52         }
53         return ret;
54 }
55
56
57 struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
58                                                         struct IP4_ARRAY *ip4)
59 {
60         struct DNS_ADDR_ARRAY *ret;
61         int i;
62
63         if (!ip4) {
64                 return NULL;
65         }
66
67         ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
68         if (!ret) {
69                 return ret;
70         }
71
72         ret->MaxCount = ip4->AddrCount;
73         ret->AddrCount = ip4->AddrCount;
74         ret->Family = AF_INET;
75         if (ip4->AddrCount > 0) {
76                 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount);
77                 if (ret->AddrArray) {
78                         for (i=0; i<ip4->AddrCount; i++) {
79                                 ret->AddrArray[i].MaxSa[0] = 0x02;
80                                 ret->AddrArray[i].MaxSa[3] = 53;
81                                 memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray,
82                                         sizeof(unsigned int));
83                                 ret->AddrArray[i].DnsAddrUserDword[0] = 6;
84                         }
85
86                 } else {
87                         talloc_free(ret);
88                         return NULL;
89                 }
90         }
91         return ret;
92 }
93
94
95 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
96                                                 struct DNS_ADDR_ARRAY *addr)
97 {
98         struct DNS_ADDR_ARRAY *ret;
99
100         if (!addr) {
101                 return NULL;
102         }
103
104         ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
105         if (!ret) {
106                 return ret;
107         }
108
109         ret->MaxCount = addr->MaxCount;
110         ret->AddrCount = addr->AddrCount;
111         ret->Family = addr->Family;
112         if (addr->AddrCount > 0) {
113                 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
114                 if (ret->AddrArray) {
115                         memcpy(ret->AddrArray, addr->AddrArray,
116                                 sizeof(struct DNS_ADDR) * addr->AddrCount);
117                 } else {
118                         talloc_free(ret);
119                         return NULL;
120                 }
121         }
122         return ret;
123 }
124
125
126 int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
127 {
128         char *str = NULL, *ptr, **list;
129         int count = 0;
130
131         if (name == NULL) {
132                 return 0;
133         }
134
135         str = talloc_strdup(tmp_ctx, name);
136         if (!str) {
137                 goto failed;
138         }
139
140         list = talloc_zero_array(tmp_ctx, char *, 0);
141         if (!list) {
142                 goto failed;
143         }
144
145         ptr = strtok(str, ".");
146         while (ptr != NULL) {
147                 count++;
148                 list = talloc_realloc(tmp_ctx, list, char *, count);
149                 if (!list) {
150                         goto failed;
151                 }
152                 list[count-1] = talloc_strdup(tmp_ctx, ptr);
153                 if (list[count-1] == NULL) {
154                         goto failed;
155                 }
156                 ptr = strtok(NULL, ".");
157         }
158
159         talloc_free(str);
160
161         *components = list;
162         return count;
163
164 failed:
165         if (str) {
166                 talloc_free(str);
167         }
168         return -1;
169 }
170
171
172 char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
173 {
174         char **nlist, **zlist;
175         char *prefix;
176         int ncount, zcount, i, match;
177
178         /*
179          * If node_name is "@", return the zone_name
180          * If node_name is ".", return NULL
181          * If there is no '.' in node_name, return the node_name as is.
182          *
183          * If node_name does not have zone_name in it, return the node_name as is.
184          *
185          * If node_name has additional components as compared to zone_name
186          *  return only the additional components as a prefix.
187          *
188          */
189         if (strcmp(node_name, "@") == 0) {
190                 prefix = talloc_strdup(tmp_ctx, zone_name);
191         } else if (strcmp(node_name, ".") == 0) {
192                 prefix = NULL;
193         } else if (strchr(node_name, '.') == NULL) {
194                 prefix = talloc_strdup(tmp_ctx, node_name);
195         } else {
196                 zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
197                 ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
198                 if (zcount < 0 || ncount < 0) {
199                         return NULL;
200                 }
201
202                 if (ncount < zcount) {
203                         prefix = talloc_strdup(tmp_ctx, node_name);
204                 } else {
205                         match = 0;
206                         for (i=1; i<=zcount; i++) {
207                                 if (strcmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
208                                         break;
209                                 }
210                                 match++;
211                         }
212
213                         if (match == ncount) {
214                                 prefix = talloc_strdup(tmp_ctx, zone_name);
215                         } else {
216                                 prefix = talloc_strdup(tmp_ctx, nlist[0]);
217                                 if (prefix != NULL) {
218                                         for (i=1; i<ncount-match; i++) {
219                                                 prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
220                                                 if (prefix == NULL) {
221                                                         break;
222                                                 }
223                                         }
224                                 }
225                         }
226                 }
227
228                 talloc_free(zlist);
229                 talloc_free(nlist);
230         }
231
232         return prefix;
233 }
234
235
236 void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
237                                 struct DNS_RPC_RECORD *dns)
238 {
239         int len;
240
241         ZERO_STRUCTP(dns);
242
243         dns->wDataLength = dnsp->wDataLength;
244         dns->wType = dnsp->wType;
245         dns->dwFlags = dnsp->rank;
246         dns->dwSerial = dnsp->dwSerial;
247         dns->dwTtlSeconds = dnsp->dwTtlSeconds;
248         dns->dwTimeStamp = dnsp->dwTimeStamp;
249
250         switch (dnsp->wType) {
251
252         case DNS_TYPE_TOMBSTONE:
253                 dns->data.timestamp = dnsp->data.timestamp;
254                 break;
255
256         case DNS_TYPE_A:
257                 dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
258                 break;
259
260         case DNS_TYPE_NS:
261                 len = strlen(dnsp->data.ns);
262                 if (dnsp->data.ns[len-1] == '.') {
263                         dns->data.name.len = len;
264                         dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
265                 } else {
266                         dns->data.name.len = len+1;
267                         dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
268                 }
269                 break;
270
271         case DNS_TYPE_CNAME:
272                 len = strlen(dnsp->data.cname);
273                 if (dnsp->data.cname[len-1] == '.') {
274                         dns->data.name.len = len;
275                         dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
276                 } else {
277                         dns->data.name.len = len+1;
278                         dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
279                 }
280                 break;
281
282         case DNS_TYPE_SOA:
283                 dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
284                 dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
285                 dns->data.soa.dwRetry = dnsp->data.soa.retry;
286                 dns->data.soa.dwExpire = dnsp->data.soa.expire;
287                 dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
288
289                 len = strlen(dnsp->data.soa.mname);
290                 if (dnsp->data.soa.mname[len-1] == '.') {
291                         dns->data.soa.NamePrimaryServer.len = len;
292                         dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
293                 } else {
294                         dns->data.soa.NamePrimaryServer.len = len+1;
295                         dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
296                 }
297
298                 len = strlen(dnsp->data.soa.rname);
299                 if (dnsp->data.soa.rname[len-1] == '.') {
300                         dns->data.soa.ZoneAdministratorEmail.len = len;
301                         dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
302                 } else {
303                         dns->data.soa.ZoneAdministratorEmail.len = len+1;
304                         dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
305                 }
306                 break;
307
308         case DNS_TYPE_PTR:
309                 dns->data.ptr.len = strlen(dnsp->data.ptr);
310                 dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
311                 break;
312
313         case DNS_TYPE_MX:
314                 dns->data.mx.wPreference = dnsp->data.mx.wPriority;
315                 len = strlen(dnsp->data.mx.nameTarget);
316                 if (dnsp->data.mx.nameTarget[len-1] == '.') {
317                         dns->data.mx.nameExchange.len = len;
318                         dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
319                 } else {
320                         dns->data.mx.nameExchange.len = len+1;
321                         dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
322                 }
323                 break;
324
325         case DNS_TYPE_TXT:
326                 dns->data.name.len = strlen(dnsp->data.txt);
327                 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.txt);
328                 break;
329
330         case DNS_TYPE_AAAA:
331                 dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
332                 break;
333
334         case DNS_TYPE_SRV:
335                 dns->data.srv.wPriority = dnsp->data.srv.wPriority;
336                 dns->data.srv.wWeight = dnsp->data.srv.wWeight;
337                 dns->data.srv.wPort = dnsp->data.srv.wPort;
338                 len = strlen(dnsp->data.srv.nameTarget);
339                 if (dnsp->data.srv.nameTarget[len-1] == '.') {
340                         dns->data.srv.nameTarget.len = len;
341                         dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
342                 } else {
343                         dns->data.srv.nameTarget.len = len+1;
344                         dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
345                 }
346                 break;
347
348         default:
349                 memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA));
350                 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType));
351         }
352
353 }
354
355
356 struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns)
357 {
358         int len;
359         struct dnsp_DnssrvRpcRecord *dnsp;
360
361         dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
362         if (dnsp == NULL) {
363                 return NULL;
364         }
365
366         dnsp->wDataLength = dns->wDataLength;
367         dnsp->wType = dns->wType;
368         dnsp->version = 5;
369         dnsp->rank = dns->dwFlags & 0x000000FF;
370         dnsp->dwSerial = dns->dwSerial;
371         dnsp->dwTtlSeconds = dns->dwTtlSeconds;
372         dnsp->dwTimeStamp = dns->dwTimeStamp;
373
374         switch (dns->wType) {
375
376         case DNS_TYPE_TOMBSTONE:
377                 dnsp->data.timestamp = dns->data.timestamp;
378                 break;
379
380         case DNS_TYPE_A:
381                 dnsp->data.ipv4 = talloc_strdup(mem_ctx, dns->data.ipv4);
382                 break;
383
384         case DNS_TYPE_NS:
385                 len = dns->data.name.len;
386                 if (dns->data.name.str[len-1] == '.') {
387                         dnsp->data.ns = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
388                 } else {
389                         dnsp->data.ns = talloc_strdup(mem_ctx, dns->data.name.str);
390                 }
391                 break;
392
393         case DNS_TYPE_CNAME:
394                 len = dns->data.name.len;
395                 if (dns->data.name.str[len-1] == '.') {
396                         dnsp->data.cname = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
397                 } else {
398                         dnsp->data.cname = talloc_strdup(mem_ctx, dns->data.name.str);
399                 }
400                 break;
401
402         case DNS_TYPE_SOA:
403                 dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
404                 dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
405                 dnsp->data.soa.retry = dns->data.soa.dwRetry;
406                 dnsp->data.soa.expire = dns->data.soa.dwExpire;
407                 dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
408
409                 len = dns->data.soa.NamePrimaryServer.len;
410                 if (dns->data.soa.NamePrimaryServer.str[len-1] == '.') {
411                         dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str);
412                 } else {
413                         dnsp->data.soa.mname = talloc_strndup(mem_ctx, dns->data.soa.NamePrimaryServer.str, len-1);
414                 }
415
416                 len = dns->data.soa.ZoneAdministratorEmail.len;
417                 if (dns->data.soa.ZoneAdministratorEmail.str[len-1] == '.') {
418                         dnsp->data.soa.rname = talloc_strndup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str, len-1);
419                 } else {
420                         dnsp->data.soa.rname = talloc_strdup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str);
421                 }
422                 break;
423
424         case DNS_TYPE_PTR:
425                 dnsp->data.ptr = talloc_strdup(mem_ctx, dns->data.ptr.str);
426                 break;
427
428         case DNS_TYPE_MX:
429                 dnsp->data.mx.wPriority = dns->data.mx.wPreference;
430                 len = dns->data.mx.nameExchange.len;
431                 if (dns->data.mx.nameExchange.str[len-1] == '.') {
432                         dnsp->data.mx.nameTarget = talloc_strndup(mem_ctx, dns->data.mx.nameExchange.str, len-1);
433                 } else {
434                         dnsp->data.mx.nameTarget = talloc_strdup(mem_ctx, dns->data.mx.nameExchange.str);
435                 }
436                 break;
437
438         case DNS_TYPE_TXT:
439                 dnsp->data.txt = talloc_strdup(mem_ctx, dns->data.name.str);
440                 break;
441
442         case DNS_TYPE_AAAA:
443                 dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
444                 break;
445
446         case DNS_TYPE_SRV:
447                 dnsp->data.srv.wPriority = dns->data.srv.wPriority;
448                 dnsp->data.srv.wWeight = dns->data.srv.wWeight;
449                 dnsp->data.srv.wPort = dns->data.srv.wPort;
450
451                 len = dns->data.srv.nameTarget.len;
452                 if (dns->data.srv.nameTarget.str[len-1] == '.') {
453                         dnsp->data.srv.nameTarget = talloc_strndup(mem_ctx, dns->data.srv.nameTarget.str, len-1);
454                 } else {
455                         dnsp->data.srv.nameTarget = talloc_strdup(mem_ctx, dns->data.srv.nameTarget.str);
456                 }
457                 break;
458
459         default:
460                 memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
461                 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType));
462
463         }
464
465         return dnsp;
466 }
467
468
469 /* Intialize tree with given name as the root */
470 static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
471 {
472         struct dns_tree *tree;
473
474         tree = talloc_zero(mem_ctx, struct dns_tree);
475         if (tree == NULL) {
476                 return NULL;
477         }
478
479         tree->name = talloc_strdup(tree, name);
480         if (tree->name == NULL) {
481                 talloc_free(tree);
482                 return NULL;
483         }
484
485         tree->data = data;
486
487         return tree;
488 }
489
490
491 /* Add a child one level below */
492 static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
493 {
494         struct dns_tree *node;
495
496         node = talloc_zero(tree, struct dns_tree);
497         if (node == NULL) {
498                 return NULL;
499         }
500
501         node->name = talloc_strdup(tree, name);
502         if (node->name == NULL) {
503                 talloc_free(node);
504                 return NULL;
505         }
506         node->level = tree->level + 1;
507         node->num_children = 0;
508         node->children = NULL;
509         node->data = data;
510
511         if (tree->num_children == 0) {
512                 tree->children = talloc_zero(tree, struct dns_tree *);
513         } else {
514                 tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
515                                                 tree->num_children+1);
516         }
517         if (tree->children == NULL) {
518                 talloc_free(node);
519                 return NULL;
520         }
521         tree->children[tree->num_children] = node;
522         tree->num_children++;
523
524         return node;
525 }
526
527 /* Find a node that matches the name components */
528 static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
529 {
530         struct dns_tree *node, *next;
531         int i, j, start;
532
533         *match_count = -1;
534
535         if (strcmp(tree->name, "@") == 0) {
536                 start = 0;
537         } else {
538                 if (strcmp(tree->name, nlist[ncount-1]) != 0) {
539                         return NULL;
540                 }
541                 start = 1;
542                 *match_count = 0;
543         }
544
545         node = tree;
546         for (i=start; i<ncount; i++) {
547                 if (node->num_children == 0) {
548                         break;
549                 }
550                 next = NULL;
551                 for (j=0; j<node->num_children; j++) {
552                         if (strcmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
553                                 next = node->children[j];
554                                 *match_count = i;
555                                 break;
556                         }
557                 }
558                 if (next == NULL) {
559                         break;
560                 } else {
561                         node = next;
562                 }
563         }
564
565         return node;
566 }
567
568 /* Build a 2-level tree for resulting dns names */
569 struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
570 {
571         struct dns_tree *root, *base, *tree, *node;
572         const char *ptr;
573         int rootcount, ncount;
574         char **nlist;
575         int i, level, match_count;
576
577         rootcount = dns_split_name_components(mem_ctx, name, &nlist);
578         if (rootcount <= 0) {
579                 return NULL;
580         }
581
582         root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
583         if (root == NULL) {
584                 return NULL;
585         }
586
587         tree = root;
588         for (i=rootcount-2; i>=0; i--) {
589                 tree = dns_tree_add(tree, nlist[i], NULL);
590                 if (tree == NULL) {
591                         goto failed;
592                 }
593         }
594
595         base = tree;
596
597         /* Add all names in the result in a tree */
598         for (i=0; i<res->count; i++) {
599                 ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
600
601                 if (strcmp(ptr, "@") == 0) {
602                         base->data = res->msgs[i];
603                         continue;
604                 } else if (strcmp(ptr, name) == 0) {
605                         base->data = res->msgs[i];
606                         continue;
607                 }
608
609                 ncount = dns_split_name_components(root, ptr, &nlist);
610                 if (ncount < 0) {
611                         goto failed;
612                 }
613
614                 /* Find matching node */
615                 tree = dns_tree_find(root, ncount, nlist, &match_count);
616                 if (tree == NULL) {
617                         goto failed;
618                 }
619
620                 /* Add missing name components */
621                 for (level=match_count+1; level<ncount; level++) {
622                         if (tree->level == rootcount+1) {
623                                 break;
624                         }
625                         if (level == ncount-1) {
626                                 node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
627                         } else {
628                                 node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
629                         }
630                         if (node == NULL) {
631                                 goto failed;
632                         }
633                         tree = node;
634                 }
635
636                 talloc_free(nlist);
637         }
638
639         /* Mark the base record, so it can be found easily */
640         base->level = -1;
641
642         return root;
643
644 failed:
645         talloc_free(root);
646         return NULL;
647 }
648
649
650 static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
651 {
652         int i;
653         char **ptr = *add_names;
654         int count = *add_count;
655
656         for (i=0; i<count; i++) {
657                 if (strcmp(ptr[i], name) == 0) {
658                         return;
659                 }
660         }
661
662         ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
663         if (ptr == NULL) {
664                 return;
665         }
666
667         ptr[count] = talloc_strdup(mem_ctx, name);
668         if (ptr[count] == NULL) {
669                 return;
670         }
671
672         *add_names = ptr;
673         *add_count = count+1;
674 }
675
676
677 static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
678 {
679         if (add_names == NULL) {
680                 return;
681         }
682
683         switch (rec->wType) {
684
685         case DNS_TYPE_NS:
686                 _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
687                 break;
688
689         case DNS_TYPE_CNAME:
690                 _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
691                 break;
692
693         case DNS_TYPE_SOA:
694                 _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
695                 break;
696
697         case DNS_TYPE_MX:
698                 _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
699                 break;
700
701         case DNS_TYPE_SRV:
702                 _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
703                 break;
704
705         default:
706                 break;
707         }
708 }
709
710
711 WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
712                                 struct dnsserver_zone *z,
713                                 enum dns_record_type record_type,
714                                 unsigned int select_flag,
715                                 const char *branch_name,
716                                 struct ldb_message *msg,
717                                 int num_children,
718                                 struct DNS_RPC_RECORDS_ARRAY *recs,
719                                 char ***add_names,
720                                 int *add_count)
721 {
722         struct ldb_message_element *el;
723         const char *ptr;
724         int i, j;
725         bool found;
726
727         if (recs->count == 0) {
728                 recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
729         } else {
730                 recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
731         }
732         if (recs->rec == NULL) {
733                 return WERR_NOMEM;
734         }
735         i = recs->count;
736         recs->rec[i].wLength = 0;
737         recs->rec[i].wRecordCount = 0;
738         recs->rec[i].dwChildCount = num_children;
739
740         /* The base records returned with empty name */
741         /* Children records returned with names */
742         if (branch_name == NULL) {
743                 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
744                 recs->rec[i].dnsNodeName.len = 0;
745         } else {
746                 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
747                 recs->rec[i].dnsNodeName.len = strlen(branch_name);
748         }
749         recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
750         recs->count++;
751
752         /* Allow empty records */
753         if (msg == NULL) {
754                 return WERR_OK;
755         }
756
757         ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
758         el = ldb_msg_find_element(msg, "dnsRecord");
759         if (el == NULL || el->values == 0) {
760                 return WERR_OK;
761         }
762
763         /* Add RR records */
764         for (j=0; j<el->num_values; j++) {
765                 struct dnsp_DnssrvRpcRecord dnsp_rec;
766                 struct DNS_RPC_RECORD *dns_rec;
767                 enum ndr_err_code ndr_err;
768
769                 ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
770                                         (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
771                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
772                         DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn)));
773                         return WERR_INTERNAL_DB_ERROR;
774                 }
775
776                 /* Match the records based on search criteria */
777                 if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
778                         found = false;
779
780                         if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
781                                 if (dnsp_rec.rank == DNS_RANK_ZONE) {
782                                         found = true;
783                                 }
784                         }
785                         if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
786                                 if (dnsp_rec.rank == DNS_RANK_ZONE) {
787                                         found = true;
788                                 }
789                         }
790                         if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
791                                 if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
792                                         found = true;
793                                 }
794                         }
795                         if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
796                                 if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
797                                         found = true;
798                                 }
799                         }
800
801                         if (found) {
802                                 recs->rec[i].records = talloc_realloc(recs,
803                                                         recs->rec[i].records,
804                                                         struct DNS_RPC_RECORD,
805                                                         recs->rec[i].wRecordCount+1);
806                                 if (recs->rec[i].records == NULL) {
807                                         return WERR_NOMEM;
808                                 }
809
810                                 dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
811                                 dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
812
813                                 /* Fix record flags */
814                                 if (strcmp(ptr, "@") == 0) {
815                                         dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
816
817                                         if (dnsp_rec.rank == DNS_RANK_ZONE) {
818                                                 dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
819                                         }
820                                 }
821
822                                 if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
823                                         dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
824                                 }
825
826                                 recs->rec[i].wRecordCount++;
827
828                                 dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
829                         }
830                 }
831         }
832
833         return WERR_OK;
834 }
835
836
837 int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
838                                 char *search_name)
839 {
840         const char *name1, *name2;
841         const char *ptr1, *ptr2;
842
843         name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
844         name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
845         if (name1 == NULL || name2 == NULL) {
846                 return 0;
847         }
848
849         /* '@' record and the search_name record gets preference */
850         if (name1[0] == '@') {
851                 return -1;
852         }
853         if (search_name && strcmp(name1, search_name) == 0) {
854                 return -1;
855         }
856
857         if (name2[0] == '@') {
858                 return 1;
859         }
860         if (search_name && strcmp(name2, search_name) == 0) {
861                 return 1;
862         }
863
864         /* Compare the last components of names.
865          * If search_name is not NULL, compare the second last components of names */
866         ptr1 = strrchr(name1, '.');
867         if (ptr1 == NULL) {
868                 ptr1 = name1;
869         } else {
870                 if (search_name && strcmp(ptr1+1, search_name) == 0) {
871                         ptr1--;
872                         while (ptr1 != name1) {
873                                 ptr1--;
874                                 if (*ptr1 == '.') {
875                                         break;
876                                 }
877                         }
878                 }
879                 if (*ptr1 == '.') {
880                         ptr1 = &ptr1[1];
881                 }
882         }
883
884         ptr2 = strrchr(name2, '.');
885         if (ptr2 == NULL) {
886                 ptr2 = name2;
887         } else {
888                 if (search_name && strcmp(ptr2+1, search_name) == 0) {
889                         ptr2--;
890                         while (ptr2 != name2) {
891                                 ptr2--;
892                                 if (*ptr2 == '.') {
893                                         break;
894                                 }
895                         }
896                 }
897                 if (*ptr2 == '.') {
898                         ptr2 = &ptr2[1];
899                 }
900         }
901
902         return strcasecmp(ptr1, ptr2);
903 }
904
905
906 bool dns_name_equal(const char *name1, const char *name2)
907 {
908         size_t len1 = strlen(name1);
909         size_t len2 = strlen(name2);
910
911         if (name1[len1-1] == '.') len1--;
912         if (name2[len2-1] == '.') len2--;
913         if (len1 != len2) {
914                 return false;
915         }
916         return strncasecmp(name1, name2, len1) == 0;
917 }
918
919
920 bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
921 {
922         if (rec1->wType != rec2->wType) {
923                 return false;
924         }
925
926         switch(rec1->wType) {
927         case DNS_TYPE_TOMBSTONE:
928                 return true;
929
930         case DNS_TYPE_A:
931                 return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
932
933         case DNS_TYPE_NS:
934                 return dns_name_equal(rec1->data.ns, rec1->data.ns);
935
936         case DNS_TYPE_CNAME:
937                 return dns_name_equal(rec1->data.cname, rec1->data.cname);
938
939         case DNS_TYPE_SOA:
940                 return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) == 0 &&
941                         dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) == 0 &&
942                         rec1->data.soa.serial == rec2->data.soa.serial &&
943                         rec1->data.soa.refresh == rec2->data.soa.refresh &&
944                         rec1->data.soa.retry == rec2->data.soa.retry &&
945                         rec1->data.soa.expire == rec2->data.soa.expire &&
946                         rec1->data.soa.minimum == rec2->data.soa.minimum;
947
948         case DNS_TYPE_PTR:
949                 return dns_name_equal(rec1->data.ptr, rec2->data.ptr);
950
951         case DNS_TYPE_MX:
952                 return rec1->data.mx.wPriority == rec2->data.srv.wPriority &&
953                         dns_name_equal(rec1->data.mx.nameTarget, rec2->data.srv.nameTarget);
954
955         case DNS_TYPE_TXT:
956                 return strcmp(rec1->data.txt, rec2->data.txt) == 0;
957
958         case DNS_TYPE_AAAA:
959                 return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;
960
961         case DNS_TYPE_SRV:
962                 return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
963                         rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
964                         rec1->data.srv.wPort == rec2->data.srv.wPort &&
965                         dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget);
966
967         default:
968                 DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType));
969                 break;
970         }
971
972         return false;
973 }