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