f752490101a0663f18c7f1bea6aaaa5d35f0af17
[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 (strcasecmp(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 i, 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.txt.count = dnsp->data.txt.count;
327                 dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
328                 for (i=0; i<dnsp->data.txt.count; i++) {
329                         dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
330                         dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
331                 }
332                 break;
333
334         case DNS_TYPE_AAAA:
335                 dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
336                 break;
337
338         case DNS_TYPE_SRV:
339                 dns->data.srv.wPriority = dnsp->data.srv.wPriority;
340                 dns->data.srv.wWeight = dnsp->data.srv.wWeight;
341                 dns->data.srv.wPort = dnsp->data.srv.wPort;
342                 len = strlen(dnsp->data.srv.nameTarget);
343                 if (dnsp->data.srv.nameTarget[len-1] == '.') {
344                         dns->data.srv.nameTarget.len = len;
345                         dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
346                 } else {
347                         dns->data.srv.nameTarget.len = len+1;
348                         dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
349                 }
350                 break;
351
352         default:
353                 memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA));
354                 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType));
355         }
356
357 }
358
359
360 struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns)
361 {
362         int i, len;
363         struct dnsp_DnssrvRpcRecord *dnsp;
364
365         dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
366         if (dnsp == NULL) {
367                 return NULL;
368         }
369
370         dnsp->wDataLength = dns->wDataLength;
371         dnsp->wType = dns->wType;
372         dnsp->version = 5;
373         dnsp->rank = dns->dwFlags & 0x000000FF;
374         dnsp->dwSerial = dns->dwSerial;
375         dnsp->dwTtlSeconds = dns->dwTtlSeconds;
376         dnsp->dwTimeStamp = dns->dwTimeStamp;
377
378         switch (dns->wType) {
379
380         case DNS_TYPE_TOMBSTONE:
381                 dnsp->data.timestamp = dns->data.timestamp;
382                 break;
383
384         case DNS_TYPE_A:
385                 dnsp->data.ipv4 = talloc_strdup(mem_ctx, dns->data.ipv4);
386                 break;
387
388         case DNS_TYPE_NS:
389                 len = dns->data.name.len;
390                 if (dns->data.name.str[len-1] == '.') {
391                         dnsp->data.ns = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
392                 } else {
393                         dnsp->data.ns = talloc_strdup(mem_ctx, dns->data.name.str);
394                 }
395                 break;
396
397         case DNS_TYPE_CNAME:
398                 len = dns->data.name.len;
399                 if (dns->data.name.str[len-1] == '.') {
400                         dnsp->data.cname = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
401                 } else {
402                         dnsp->data.cname = talloc_strdup(mem_ctx, dns->data.name.str);
403                 }
404                 break;
405
406         case DNS_TYPE_SOA:
407                 dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
408                 dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
409                 dnsp->data.soa.retry = dns->data.soa.dwRetry;
410                 dnsp->data.soa.expire = dns->data.soa.dwExpire;
411                 dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
412
413                 len = dns->data.soa.NamePrimaryServer.len;
414                 if (dns->data.soa.NamePrimaryServer.str[len-1] == '.') {
415                         dnsp->data.soa.mname = talloc_strndup(mem_ctx, dns->data.soa.NamePrimaryServer.str, len-1);
416                 } else {
417                         dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str);
418                 }
419
420                 len = dns->data.soa.ZoneAdministratorEmail.len;
421                 if (dns->data.soa.ZoneAdministratorEmail.str[len-1] == '.') {
422                         dnsp->data.soa.rname = talloc_strndup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str, len-1);
423                 } else {
424                         dnsp->data.soa.rname = talloc_strdup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str);
425                 }
426                 break;
427
428         case DNS_TYPE_PTR:
429                 dnsp->data.ptr = talloc_strdup(mem_ctx, dns->data.ptr.str);
430                 break;
431
432         case DNS_TYPE_MX:
433                 dnsp->data.mx.wPriority = dns->data.mx.wPreference;
434                 len = dns->data.mx.nameExchange.len;
435                 if (dns->data.mx.nameExchange.str[len-1] == '.') {
436                         dnsp->data.mx.nameTarget = talloc_strndup(mem_ctx, dns->data.mx.nameExchange.str, len-1);
437                 } else {
438                         dnsp->data.mx.nameTarget = talloc_strdup(mem_ctx, dns->data.mx.nameExchange.str);
439                 }
440                 break;
441
442         case DNS_TYPE_TXT:
443                 dnsp->data.txt.count = dns->data.txt.count;
444                 dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
445                 for (i=0; i<dns->data.txt.count; i++) {
446                         dnsp->data.txt.str[i] = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
447                 }
448                 break;
449
450         case DNS_TYPE_AAAA:
451                 dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
452                 break;
453
454         case DNS_TYPE_SRV:
455                 dnsp->data.srv.wPriority = dns->data.srv.wPriority;
456                 dnsp->data.srv.wWeight = dns->data.srv.wWeight;
457                 dnsp->data.srv.wPort = dns->data.srv.wPort;
458
459                 len = dns->data.srv.nameTarget.len;
460                 if (dns->data.srv.nameTarget.str[len-1] == '.') {
461                         dnsp->data.srv.nameTarget = talloc_strndup(mem_ctx, dns->data.srv.nameTarget.str, len-1);
462                 } else {
463                         dnsp->data.srv.nameTarget = talloc_strdup(mem_ctx, dns->data.srv.nameTarget.str);
464                 }
465                 break;
466
467         default:
468                 memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
469                 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType));
470
471         }
472
473         return dnsp;
474 }
475
476
477 /* Intialize tree with given name as the root */
478 static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
479 {
480         struct dns_tree *tree;
481
482         tree = talloc_zero(mem_ctx, struct dns_tree);
483         if (tree == NULL) {
484                 return NULL;
485         }
486
487         tree->name = talloc_strdup(tree, name);
488         if (tree->name == NULL) {
489                 talloc_free(tree);
490                 return NULL;
491         }
492
493         tree->data = data;
494
495         return tree;
496 }
497
498
499 /* Add a child one level below */
500 static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
501 {
502         struct dns_tree *node;
503
504         node = talloc_zero(tree, struct dns_tree);
505         if (node == NULL) {
506                 return NULL;
507         }
508
509         node->name = talloc_strdup(tree, name);
510         if (node->name == NULL) {
511                 talloc_free(node);
512                 return NULL;
513         }
514         node->level = tree->level + 1;
515         node->num_children = 0;
516         node->children = NULL;
517         node->data = data;
518
519         if (tree->num_children == 0) {
520                 tree->children = talloc_zero(tree, struct dns_tree *);
521         } else {
522                 tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
523                                                 tree->num_children+1);
524         }
525         if (tree->children == NULL) {
526                 talloc_free(node);
527                 return NULL;
528         }
529         tree->children[tree->num_children] = node;
530         tree->num_children++;
531
532         return node;
533 }
534
535 /* Find a node that matches the name components */
536 static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
537 {
538         struct dns_tree *node, *next;
539         int i, j, start;
540
541         *match_count = -1;
542
543         if (strcmp(tree->name, "@") == 0) {
544                 start = 0;
545         } else {
546                 if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
547                         return NULL;
548                 }
549                 start = 1;
550                 *match_count = 0;
551         }
552
553         node = tree;
554         for (i=start; i<ncount; i++) {
555                 if (node->num_children == 0) {
556                         break;
557                 }
558                 next = NULL;
559                 for (j=0; j<node->num_children; j++) {
560                         if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
561                                 next = node->children[j];
562                                 *match_count = i;
563                                 break;
564                         }
565                 }
566                 if (next == NULL) {
567                         break;
568                 } else {
569                         node = next;
570                 }
571         }
572
573         return node;
574 }
575
576 /* Build a 2-level tree for resulting dns names */
577 struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
578 {
579         struct dns_tree *root, *base, *tree, *node;
580         const char *ptr;
581         int rootcount, ncount;
582         char **nlist;
583         int i, level, match_count;
584
585         rootcount = dns_split_name_components(mem_ctx, name, &nlist);
586         if (rootcount <= 0) {
587                 return NULL;
588         }
589
590         root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
591         if (root == NULL) {
592                 return NULL;
593         }
594
595         tree = root;
596         for (i=rootcount-2; i>=0; i--) {
597                 tree = dns_tree_add(tree, nlist[i], NULL);
598                 if (tree == NULL) {
599                         goto failed;
600                 }
601         }
602
603         base = tree;
604
605         /* Add all names in the result in a tree */
606         for (i=0; i<res->count; i++) {
607                 ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
608
609                 if (strcmp(ptr, "@") == 0) {
610                         base->data = res->msgs[i];
611                         continue;
612                 } else if (strcasecmp(ptr, name) == 0) {
613                         base->data = res->msgs[i];
614                         continue;
615                 }
616
617                 ncount = dns_split_name_components(root, ptr, &nlist);
618                 if (ncount < 0) {
619                         goto failed;
620                 }
621
622                 /* Find matching node */
623                 tree = dns_tree_find(root, ncount, nlist, &match_count);
624                 if (tree == NULL) {
625                         goto failed;
626                 }
627
628                 /* If the node is on leaf, then add record data */
629                 if (match_count+1 == ncount) {
630                         tree->data = res->msgs[i];
631                 }
632
633                 /* Add missing name components */
634                 for (level=match_count+1; level<ncount; level++) {
635                         if (tree->level == rootcount+1) {
636                                 break;
637                         }
638                         if (level == ncount-1) {
639                                 node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
640                         } else {
641                                 node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
642                         }
643                         if (node == NULL) {
644                                 goto failed;
645                         }
646                         tree = node;
647                 }
648
649                 talloc_free(nlist);
650         }
651
652         /* Mark the base record, so it can be found easily */
653         base->level = -1;
654
655         return root;
656
657 failed:
658         talloc_free(root);
659         return NULL;
660 }
661
662
663 static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
664 {
665         int i;
666         char **ptr = *add_names;
667         int count = *add_count;
668
669         for (i=0; i<count; i++) {
670                 if (strcasecmp(ptr[i], name) == 0) {
671                         return;
672                 }
673         }
674
675         ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
676         if (ptr == NULL) {
677                 return;
678         }
679
680         ptr[count] = talloc_strdup(mem_ctx, name);
681         if (ptr[count] == NULL) {
682                 return;
683         }
684
685         *add_names = ptr;
686         *add_count = count+1;
687 }
688
689
690 static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
691 {
692         if (add_names == NULL) {
693                 return;
694         }
695
696         switch (rec->wType) {
697
698         case DNS_TYPE_NS:
699                 _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
700                 break;
701
702         case DNS_TYPE_CNAME:
703                 _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
704                 break;
705
706         case DNS_TYPE_SOA:
707                 _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
708                 break;
709
710         case DNS_TYPE_MX:
711                 _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
712                 break;
713
714         case DNS_TYPE_SRV:
715                 _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
716                 break;
717
718         default:
719                 break;
720         }
721 }
722
723
724 WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
725                                 struct dnsserver_zone *z,
726                                 enum dns_record_type record_type,
727                                 unsigned int select_flag,
728                                 const char *branch_name,
729                                 struct ldb_message *msg,
730                                 int num_children,
731                                 struct DNS_RPC_RECORDS_ARRAY *recs,
732                                 char ***add_names,
733                                 int *add_count)
734 {
735         struct ldb_message_element *el;
736         const char *ptr;
737         int i, j;
738         bool found;
739
740         if (recs->count == 0) {
741                 recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
742         } else {
743                 recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
744         }
745         if (recs->rec == NULL) {
746                 return WERR_NOMEM;
747         }
748         i = recs->count;
749         recs->rec[i].wLength = 0;
750         recs->rec[i].wRecordCount = 0;
751         recs->rec[i].dwChildCount = num_children;
752
753         /* The base records returned with empty name */
754         /* Children records returned with names */
755         if (branch_name == NULL) {
756                 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
757                 recs->rec[i].dnsNodeName.len = 0;
758         } else {
759                 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
760                 recs->rec[i].dnsNodeName.len = strlen(branch_name);
761         }
762         recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
763         recs->count++;
764
765         /* Allow empty records */
766         if (msg == NULL) {
767                 return WERR_OK;
768         }
769
770         /* Do not return RR records, if the node has children */
771         if (branch_name != NULL && num_children > 0) {
772                 return WERR_OK;
773         }
774
775         ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
776         el = ldb_msg_find_element(msg, "dnsRecord");
777         if (el == NULL || el->values == 0) {
778                 return WERR_OK;
779         }
780
781         /* Add RR records */
782         for (j=0; j<el->num_values; j++) {
783                 struct dnsp_DnssrvRpcRecord dnsp_rec;
784                 struct DNS_RPC_RECORD *dns_rec;
785                 enum ndr_err_code ndr_err;
786
787                 ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
788                                         (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
789                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
790                         DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn)));
791                         return WERR_INTERNAL_DB_ERROR;
792                 }
793
794                 /* Match the records based on search criteria */
795                 if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
796                         found = false;
797
798                         if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
799                                 if (dnsp_rec.rank == DNS_RANK_ZONE) {
800                                         found = true;
801                                 } else if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
802                                         /*
803                                          * If branch_name is NULL, we're
804                                          * explicitly asked to also return
805                                          * DNS_RANK_NS_GLUE records
806                                          */
807                                         if (branch_name == NULL) {
808                                                 found = true;
809                                         }
810                                 }
811                         }
812                         if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
813                                 if (dnsp_rec.rank == DNS_RANK_ZONE) {
814                                         found = true;
815                                 }
816                         }
817                         if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
818                                 if (dnsp_rec.rank == DNS_RANK_GLUE) {
819                                         found = true;
820                                 }
821                         }
822                         if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
823                                 if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
824                                         found = true;
825                                 }
826                         }
827
828                         if (found) {
829                                 recs->rec[i].records = talloc_realloc(recs,
830                                                         recs->rec[i].records,
831                                                         struct DNS_RPC_RECORD,
832                                                         recs->rec[i].wRecordCount+1);
833                                 if (recs->rec[i].records == NULL) {
834                                         return WERR_NOMEM;
835                                 }
836
837                                 dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
838                                 dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
839
840                                 /* Fix record flags */
841                                 if (strcmp(ptr, "@") == 0) {
842                                         dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
843
844                                         if (dnsp_rec.rank == DNS_RANK_ZONE) {
845                                                 dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
846                                         }
847                                 }
848
849                                 if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
850                                         dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
851                                 }
852
853                                 recs->rec[i].wRecordCount++;
854
855                                 dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
856                         }
857                 }
858         }
859
860         return WERR_OK;
861 }
862
863
864 int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
865                                 char *search_name)
866 {
867         const char *name1, *name2;
868         const char *ptr1, *ptr2;
869
870         name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
871         name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
872         if (name1 == NULL || name2 == NULL) {
873                 return 0;
874         }
875
876         /* '@' record and the search_name record gets preference */
877         if (name1[0] == '@') {
878                 return -1;
879         }
880         if (search_name && strcasecmp(name1, search_name) == 0) {
881                 return -1;
882         }
883
884         if (name2[0] == '@') {
885                 return 1;
886         }
887         if (search_name && strcasecmp(name2, search_name) == 0) {
888                 return 1;
889         }
890
891         /* Compare the last components of names.
892          * If search_name is not NULL, compare the second last components of names */
893         ptr1 = strrchr(name1, '.');
894         if (ptr1 == NULL) {
895                 ptr1 = name1;
896         } else {
897                 if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
898                         ptr1--;
899                         while (ptr1 != name1) {
900                                 ptr1--;
901                                 if (*ptr1 == '.') {
902                                         break;
903                                 }
904                         }
905                 }
906                 if (*ptr1 == '.') {
907                         ptr1 = &ptr1[1];
908                 }
909         }
910
911         ptr2 = strrchr(name2, '.');
912         if (ptr2 == NULL) {
913                 ptr2 = name2;
914         } else {
915                 if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
916                         ptr2--;
917                         while (ptr2 != name2) {
918                                 ptr2--;
919                                 if (*ptr2 == '.') {
920                                         break;
921                                 }
922                         }
923                 }
924                 if (*ptr2 == '.') {
925                         ptr2 = &ptr2[1];
926                 }
927         }
928
929         return strcasecmp(ptr1, ptr2);
930 }
931
932
933 bool dns_name_equal(const char *name1, const char *name2)
934 {
935         size_t len1 = strlen(name1);
936         size_t len2 = strlen(name2);
937
938         if (name1[len1-1] == '.') len1--;
939         if (name2[len2-1] == '.') len2--;
940         if (len1 != len2) {
941                 return false;
942         }
943         return strncasecmp(name1, name2, len1) == 0;
944 }
945
946
947 bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
948 {
949         bool status;
950         int i;
951
952         if (rec1->wType != rec2->wType) {
953                 return false;
954         }
955
956         switch(rec1->wType) {
957         case DNS_TYPE_TOMBSTONE:
958                 return true;
959
960         case DNS_TYPE_A:
961                 return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
962
963         case DNS_TYPE_NS:
964                 return dns_name_equal(rec1->data.ns, rec2->data.ns);
965
966         case DNS_TYPE_CNAME:
967                 return dns_name_equal(rec1->data.cname, rec2->data.cname);
968
969         case DNS_TYPE_SOA:
970                 return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) &&
971                         dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) &&
972                         rec1->data.soa.serial == rec2->data.soa.serial &&
973                         rec1->data.soa.refresh == rec2->data.soa.refresh &&
974                         rec1->data.soa.retry == rec2->data.soa.retry &&
975                         rec1->data.soa.expire == rec2->data.soa.expire &&
976                         rec1->data.soa.minimum == rec2->data.soa.minimum;
977
978         case DNS_TYPE_PTR:
979                 return dns_name_equal(rec1->data.ptr, rec2->data.ptr);
980
981         case DNS_TYPE_MX:
982                 return rec1->data.mx.wPriority == rec2->data.mx.wPriority &&
983                         dns_name_equal(rec1->data.mx.nameTarget, rec2->data.mx.nameTarget);
984
985         case DNS_TYPE_TXT:
986                 if (rec1->data.txt.count != rec2->data.txt.count) {
987                         return false;
988                 }
989                 status = true;
990                 for (i=0; i<rec1->data.txt.count; i++) {
991                         status = status && (strcmp(rec1->data.txt.str[i],
992                                                    rec2->data.txt.str[i]) == 0);
993                 }
994                 return status;
995
996         case DNS_TYPE_AAAA:
997                 return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;
998
999         case DNS_TYPE_SRV:
1000                 return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
1001                         rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
1002                         rec1->data.srv.wPort == rec2->data.srv.wPort &&
1003                         dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget);
1004
1005         default:
1006                 DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType));
1007                 break;
1008         }
1009
1010         return false;
1011 }