python:tests: Store keys as bytes rather than as lists of ints
[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 "dns_server/dnsserver_common.h"
25 #include "lib/replace/system/network.h"
26 #include "librpc/gen_ndr/ndr_dnsp.h"
27 #include "librpc/gen_ndr/ndr_dnsserver.h"
28
29
30 struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4)
31 {
32         struct IP4_ARRAY *ret;
33
34         if (!ip4) {
35                 return NULL;
36         }
37
38         ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
39         if (!ret) {
40                 return ret;
41         }
42
43         ret->AddrCount = ip4->AddrCount;
44         if (ip4->AddrCount > 0) {
45                 ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount);
46                 if (ret->AddrArray) {
47                         memcpy(ret->AddrArray, ip4->AddrArray,
48                                 sizeof(unsigned int) * ip4->AddrCount);
49                 } else {
50                         talloc_free(ret);
51                         return NULL;
52                 }
53         }
54         return ret;
55 }
56
57
58 struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
59                                                         struct IP4_ARRAY *ip4)
60 {
61         struct DNS_ADDR_ARRAY *ret;
62         int i;
63
64         if (!ip4) {
65                 return NULL;
66         }
67
68         ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
69         if (!ret) {
70                 return ret;
71         }
72
73         ret->MaxCount = ip4->AddrCount;
74         ret->AddrCount = ip4->AddrCount;
75         ret->Family = AF_INET;
76         if (ip4->AddrCount > 0) {
77                 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount);
78                 if (ret->AddrArray) {
79                         for (i=0; i<ip4->AddrCount; i++) {
80                                 ret->AddrArray[i].MaxSa[0] = 0x02;
81                                 ret->AddrArray[i].MaxSa[3] = 53;
82                                 memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray,
83                                         sizeof(unsigned int));
84                                 ret->AddrArray[i].DnsAddrUserDword[0] = 6;
85                         }
86
87                 } else {
88                         talloc_free(ret);
89                         return NULL;
90                 }
91         }
92         return ret;
93 }
94
95 struct IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
96                                               struct DNS_ADDR_ARRAY *ip)
97 {
98         struct IP4_ARRAY *ret;
99         size_t i, count, curr;
100
101         if (ip == NULL) {
102                 return NULL;
103         }
104         /* We must only return IPv4 addresses.
105            The passed DNS_ADDR_ARRAY may contain:
106            - only ipv4 addresses
107            - only ipv6 addresses
108            - a mixture of both
109            - an empty array
110         */
111         ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
112         if (!ret) {
113                 return ret;
114         }
115         if (ip->AddrCount == 0 || ip->Family == AF_INET6) {
116                 ret->AddrCount = 0;
117                 return ret;
118         }
119         /* Now only ipv4 addresses or a mixture are left */
120         count = 0;
121         for (i = 0; i < ip->AddrCount; i++) {
122                 if (ip->AddrArray[i].MaxSa[0] == 0x02) {
123                         /* Is ipv4 */
124                         count++;
125                 }
126         }
127         if (count == 0) {
128                 /* should not happen */
129                 ret->AddrCount = 0;
130                 return ret;
131         }
132         ret->AddrArray = talloc_zero_array(mem_ctx, uint32_t, count);
133         if (ret->AddrArray) {
134                 curr = 0;
135                 for (i = 0; i < ip->AddrCount; i++) {
136                         if (ip->AddrArray[i].MaxSa[0] == 0x02) {
137                                 /* Is ipv4 */
138                                 memcpy(&ret->AddrArray[curr],
139                                        &ip->AddrArray[i].MaxSa[4],
140                                        sizeof(uint32_t));
141                                 curr++;
142                         }
143                 }
144         } else {
145                 talloc_free(ret);
146                 return NULL;
147         }
148         ret->AddrCount = curr;
149         return ret;
150 }
151
152 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
153                                                 struct DNS_ADDR_ARRAY *addr)
154 {
155         struct DNS_ADDR_ARRAY *ret;
156
157         if (!addr) {
158                 return NULL;
159         }
160
161         ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
162         if (!ret) {
163                 return ret;
164         }
165
166         ret->MaxCount = addr->MaxCount;
167         ret->AddrCount = addr->AddrCount;
168         ret->Family = addr->Family;
169         if (addr->AddrCount > 0) {
170                 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
171                 if (ret->AddrArray) {
172                         memcpy(ret->AddrArray, addr->AddrArray,
173                                 sizeof(struct DNS_ADDR) * addr->AddrCount);
174                 } else {
175                         talloc_free(ret);
176                         return NULL;
177                 }
178         }
179         return ret;
180 }
181
182
183 int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
184 {
185         char *str = NULL, *ptr, **list;
186         int count = 0;
187
188         if (name == NULL) {
189                 return 0;
190         }
191
192         str = talloc_strdup(tmp_ctx, name);
193         if (!str) {
194                 goto failed;
195         }
196
197         list = talloc_zero_array(tmp_ctx, char *, 0);
198         if (!list) {
199                 goto failed;
200         }
201
202         ptr = strtok(str, ".");
203         while (ptr != NULL) {
204                 count++;
205                 list = talloc_realloc(tmp_ctx, list, char *, count);
206                 if (!list) {
207                         goto failed;
208                 }
209                 list[count-1] = talloc_strdup(tmp_ctx, ptr);
210                 if (list[count-1] == NULL) {
211                         goto failed;
212                 }
213                 ptr = strtok(NULL, ".");
214         }
215
216         talloc_free(str);
217
218         *components = list;
219         return count;
220
221 failed:
222         TALLOC_FREE(str);
223         return -1;
224 }
225
226
227 char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
228 {
229         char **nlist, **zlist;
230         char *prefix;
231         int ncount, zcount, i, match;
232
233         /*
234          * If node_name is "@", return the zone_name
235          * If node_name is ".", return NULL
236          * If there is no '.' in node_name, return the node_name as is.
237          *
238          * If node_name does not have zone_name in it, return the node_name as is.
239          *
240          * If node_name has additional components as compared to zone_name
241          *  return only the additional components as a prefix.
242          *
243          */
244         if (strcmp(node_name, "@") == 0) {
245                 prefix = talloc_strdup(tmp_ctx, zone_name);
246         } else if (strcmp(node_name, ".") == 0) {
247                 prefix = NULL;
248         } else if (strchr(node_name, '.') == NULL) {
249                 prefix = talloc_strdup(tmp_ctx, node_name);
250         } else {
251                 zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
252                 ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
253                 if (zcount < 0 || ncount < 0) {
254                         return NULL;
255                 }
256
257                 if (ncount < zcount) {
258                         prefix = talloc_strdup(tmp_ctx, node_name);
259                 } else {
260                         match = 0;
261                         for (i=1; i<=zcount; i++) {
262                                 if (strcasecmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
263                                         break;
264                                 }
265                                 match++;
266                         }
267
268                         if (match == ncount) {
269                                 prefix = talloc_strdup(tmp_ctx, zone_name);
270                         } else {
271                                 prefix = talloc_strdup(tmp_ctx, nlist[0]);
272                                 if (prefix != NULL) {
273                                         for (i=1; i<ncount-match; i++) {
274                                                 prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
275                                                 if (prefix == NULL) {
276                                                         break;
277                                                 }
278                                         }
279                                 }
280                         }
281                 }
282
283                 talloc_free(zlist);
284                 talloc_free(nlist);
285         }
286
287         return prefix;
288 }
289
290
291 void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
292                                 struct DNS_RPC_RECORD *dns)
293 {
294         int i, len;
295
296         ZERO_STRUCTP(dns);
297
298         dns->wDataLength = dnsp->wDataLength;
299         dns->wType = dnsp->wType;
300         dns->dwFlags = dnsp->rank;
301         dns->dwSerial = dnsp->dwSerial;
302         dns->dwTtlSeconds = dnsp->dwTtlSeconds;
303         dns->dwTimeStamp = dnsp->dwTimeStamp;
304
305         switch (dnsp->wType) {
306
307         case DNS_TYPE_TOMBSTONE:
308                 dns->data.timestamp = dnsp->data.timestamp;
309                 break;
310
311         case DNS_TYPE_A:
312                 dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
313                 break;
314
315         case DNS_TYPE_NS:
316                 len = strlen(dnsp->data.ns);
317                 if (dnsp->data.ns[len-1] == '.') {
318                         dns->data.name.len = len;
319                         dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
320                 } else {
321                         dns->data.name.len = len+1;
322                         dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
323                 }
324                 break;
325
326         case DNS_TYPE_CNAME:
327                 len = strlen(dnsp->data.cname);
328                 if (dnsp->data.cname[len-1] == '.') {
329                         dns->data.name.len = len;
330                         dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
331                 } else {
332                         dns->data.name.len = len+1;
333                         dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
334                 }
335                 break;
336
337         case DNS_TYPE_SOA:
338                 dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
339                 dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
340                 dns->data.soa.dwRetry = dnsp->data.soa.retry;
341                 dns->data.soa.dwExpire = dnsp->data.soa.expire;
342                 dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
343
344                 len = strlen(dnsp->data.soa.mname);
345                 if (dnsp->data.soa.mname[len-1] == '.') {
346                         dns->data.soa.NamePrimaryServer.len = len;
347                         dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
348                 } else {
349                         dns->data.soa.NamePrimaryServer.len = len+1;
350                         dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
351                 }
352
353                 len = strlen(dnsp->data.soa.rname);
354                 if (dnsp->data.soa.rname[len-1] == '.') {
355                         dns->data.soa.ZoneAdministratorEmail.len = len;
356                         dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
357                 } else {
358                         dns->data.soa.ZoneAdministratorEmail.len = len+1;
359                         dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
360                 }
361                 break;
362
363         case DNS_TYPE_PTR:
364                 dns->data.ptr.len = strlen(dnsp->data.ptr);
365                 dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
366                 break;
367
368         case DNS_TYPE_MX:
369                 dns->data.mx.wPreference = dnsp->data.mx.wPriority;
370                 len = strlen(dnsp->data.mx.nameTarget);
371                 if (dnsp->data.mx.nameTarget[len-1] == '.') {
372                         dns->data.mx.nameExchange.len = len;
373                         dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
374                 } else {
375                         dns->data.mx.nameExchange.len = len+1;
376                         dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
377                 }
378                 break;
379
380         case DNS_TYPE_TXT:
381                 dns->data.txt.count = dnsp->data.txt.count;
382                 dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
383                 for (i=0; i<dnsp->data.txt.count; i++) {
384                         dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
385                         dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
386                 }
387                 break;
388
389         case DNS_TYPE_AAAA:
390                 dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
391                 break;
392
393         case DNS_TYPE_SRV:
394                 dns->data.srv.wPriority = dnsp->data.srv.wPriority;
395                 dns->data.srv.wWeight = dnsp->data.srv.wWeight;
396                 dns->data.srv.wPort = dnsp->data.srv.wPort;
397                 len = strlen(dnsp->data.srv.nameTarget);
398                 if (dnsp->data.srv.nameTarget[len-1] == '.') {
399                         dns->data.srv.nameTarget.len = len;
400                         dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
401                 } else {
402                         dns->data.srv.nameTarget.len = len+1;
403                         dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
404                 }
405                 break;
406
407         default:
408                 memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA));
409                 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType));
410         }
411
412 }
413
414 WERROR dns_to_dnsp_convert(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns,
415                            struct dnsp_DnssrvRpcRecord **out_dnsp, bool check_name)
416 {
417         WERROR res;
418         int i, len;
419         const char *name;
420         char *talloc_res = NULL;
421         struct dnsp_DnssrvRpcRecord *dnsp = NULL;
422
423         dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
424         if (dnsp == NULL) {
425                 return WERR_NOT_ENOUGH_MEMORY;
426         }
427
428         dnsp->wDataLength = dns->wDataLength;
429         dnsp->wType = dns->wType;
430         dnsp->version = 5;
431         dnsp->rank = dns->dwFlags & 0x000000FF;
432         dnsp->dwSerial = dns->dwSerial;
433         dnsp->dwTtlSeconds = dns->dwTtlSeconds;
434         dnsp->dwTimeStamp = dns->dwTimeStamp;
435
436         switch (dns->wType) {
437
438         case DNS_TYPE_TOMBSTONE:
439                 dnsp->data.timestamp = dns->data.timestamp;
440                 break;
441
442         case DNS_TYPE_A:
443                 talloc_res = talloc_strdup(mem_ctx, dns->data.ipv4);
444                 if (talloc_res == NULL) {
445                         goto fail_nomemory;
446                 }
447                 dnsp->data.ipv4 = talloc_res;
448                 break;
449
450         case DNS_TYPE_NS:
451                 name = dns->data.name.str;
452                 len = dns->data.name.len;
453
454                 if (check_name) {
455                         res = dns_name_check(mem_ctx, len, name);
456                         if (!W_ERROR_IS_OK(res)) {
457                                 return res;
458                         }
459                 }
460
461                 if (len > 0 && name[len-1] == '.') {
462                         talloc_res = talloc_strndup(mem_ctx, name, len-1);
463                         if (talloc_res == NULL) {
464                                 goto fail_nomemory;
465                         }
466                         dnsp->data.ns = talloc_res;
467                 } else {
468                         talloc_res = talloc_strdup(mem_ctx, name);
469                         if (talloc_res == NULL) {
470                                 goto fail_nomemory;
471                         }
472                         dnsp->data.ns = talloc_res;
473                 }
474
475                 break;
476
477         case DNS_TYPE_CNAME:
478                 name = dns->data.name.str;
479                 len = dns->data.name.len;
480
481                 if (check_name) {
482                         res = dns_name_check(mem_ctx, len, name);
483                         if (!W_ERROR_IS_OK(res)) {
484                                 return res;
485                         }
486                 }
487
488                 if (len > 0 && name[len-1] == '.') {
489                         talloc_res = talloc_strndup(mem_ctx, name, len-1);
490                         if (talloc_res == NULL) {
491                                 goto fail_nomemory;
492                         }
493                         dnsp->data.cname = talloc_res;
494                 } else {
495                         talloc_res = talloc_strdup(mem_ctx, name);
496                         if (talloc_res == NULL) {
497                                 goto fail_nomemory;
498                         }
499                         dnsp->data.cname = talloc_res;
500                 }
501
502                 break;
503
504         case DNS_TYPE_SOA:
505                 dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
506                 dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
507                 dnsp->data.soa.retry = dns->data.soa.dwRetry;
508                 dnsp->data.soa.expire = dns->data.soa.dwExpire;
509                 dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
510
511                 name = dns->data.soa.NamePrimaryServer.str;
512                 len = dns->data.soa.NamePrimaryServer.len;
513
514                 if (check_name) {
515                         res = dns_name_check(mem_ctx, len, name);
516                         if (!W_ERROR_IS_OK(res)) {
517                                 return res;
518                         }
519                 }
520
521                 if (len > 0 && name[len-1] == '.') {
522                         talloc_res = talloc_strndup(mem_ctx, name, len-1);
523                         if (talloc_res == NULL) {
524                                 goto fail_nomemory;
525                         }
526                         dnsp->data.soa.mname = talloc_res;
527                 } else {
528                         talloc_res = talloc_strdup(mem_ctx, name);
529                         if (talloc_res == NULL) {
530                                 goto fail_nomemory;
531                         }
532                         dnsp->data.soa.mname = talloc_res;
533                 }
534
535                 name = dns->data.soa.ZoneAdministratorEmail.str;
536                 len = dns->data.soa.ZoneAdministratorEmail.len;
537
538                 res = dns_name_check(mem_ctx, len, name);
539                 if (!W_ERROR_IS_OK(res)) {
540                         return res;
541                 }
542
543                 if (len > 0 && name[len-1] == '.') {
544                         talloc_res = talloc_strndup(mem_ctx, name, len-1);
545                         if (talloc_res == NULL) {
546                                 goto fail_nomemory;
547                         }
548                         dnsp->data.soa.rname = talloc_res;
549                 } else {
550                         talloc_res = talloc_strdup(mem_ctx, name);
551                         if (talloc_res == NULL) {
552                                 goto fail_nomemory;
553                         }
554                         dnsp->data.soa.rname = talloc_res;
555                 }
556
557                 break;
558
559         case DNS_TYPE_PTR:
560                 name = dns->data.ptr.str;
561                 len = dns->data.ptr.len;
562
563                 if (check_name) {
564                         res = dns_name_check(mem_ctx, len, name);
565                         if (!W_ERROR_IS_OK(res)) {
566                                 return res;
567                         }
568                 }
569
570                 talloc_res = talloc_strdup(mem_ctx, name);
571                 if (talloc_res == NULL) {
572                         goto fail_nomemory;
573                 }
574                 dnsp->data.ptr = talloc_res;
575
576                 break;
577
578         case DNS_TYPE_MX:
579                 dnsp->data.mx.wPriority = dns->data.mx.wPreference;
580
581                 name = dns->data.mx.nameExchange.str;
582                 len = dns->data.mx.nameExchange.len;
583
584                 if (check_name) {
585                         res = dns_name_check(mem_ctx, len, name);
586                         if (!W_ERROR_IS_OK(res)) {
587                                 return res;
588                         }
589                 }
590
591                 if (len > 0 && name[len-1] == '.') {
592                         talloc_res = talloc_strndup(mem_ctx, name, len-1);
593                         if (talloc_res == NULL) {
594                                 goto fail_nomemory;
595                         }
596                         dnsp->data.mx.nameTarget = talloc_res;
597                 } else {
598                         talloc_res = talloc_strdup(mem_ctx, name);
599                         if (talloc_res == NULL) {
600                                 goto fail_nomemory;
601                         }
602                         dnsp->data.mx.nameTarget = talloc_res;
603                 }
604
605                 break;
606
607         case DNS_TYPE_TXT:
608                 dnsp->data.txt.count = dns->data.txt.count;
609                 dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
610                 for (i=0; i<dns->data.txt.count; i++) {
611                         talloc_res = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
612                         if (talloc_res == NULL) {
613                                 goto fail_nomemory;
614                         }
615                         dnsp->data.txt.str[i] = talloc_res;
616                 }
617                 break;
618
619         case DNS_TYPE_AAAA:
620                 dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
621                 break;
622
623         case DNS_TYPE_SRV:
624                 dnsp->data.srv.wPriority = dns->data.srv.wPriority;
625                 dnsp->data.srv.wWeight = dns->data.srv.wWeight;
626                 dnsp->data.srv.wPort = dns->data.srv.wPort;
627
628                 name = dns->data.srv.nameTarget.str;
629                 len = dns->data.srv.nameTarget.len;
630
631                 if (check_name) {
632                         res = dns_name_check(mem_ctx, len, name);
633                         if (!W_ERROR_IS_OK(res)) {
634                                 return res;
635                         }
636                 }
637
638                 if (len > 0 && name[len-1] == '.') {
639                         talloc_res = talloc_strndup(mem_ctx, name, len-1);
640                         if (talloc_res == NULL) {
641                                 goto fail_nomemory;
642                         }
643                         dnsp->data.srv.nameTarget = talloc_res;
644                 } else {
645                         talloc_res = talloc_strdup(mem_ctx, name);
646                         if (talloc_res == NULL) {
647                                 goto fail_nomemory;
648                         }
649                         dnsp->data.srv.nameTarget = talloc_res;
650                 }
651
652                 break;
653
654         default:
655                 memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
656                 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType));
657         }
658
659         *out_dnsp = dnsp;
660         return WERR_OK;
661
662 fail_nomemory:
663         return WERR_NOT_ENOUGH_MEMORY;
664 }
665
666 /* Intialize tree with given name as the root */
667 static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
668 {
669         struct dns_tree *tree;
670
671         tree = talloc_zero(mem_ctx, struct dns_tree);
672         if (tree == NULL) {
673                 return NULL;
674         }
675
676         tree->name = talloc_strdup(tree, name);
677         if (tree->name == NULL) {
678                 talloc_free(tree);
679                 return NULL;
680         }
681
682         tree->data = data;
683
684         return tree;
685 }
686
687
688 /* Add a child one level below */
689 static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
690 {
691         struct dns_tree *node;
692
693         node = talloc_zero(tree, struct dns_tree);
694         if (node == NULL) {
695                 return NULL;
696         }
697
698         node->name = talloc_strdup(tree, name);
699         if (node->name == NULL) {
700                 talloc_free(node);
701                 return NULL;
702         }
703         node->level = tree->level + 1;
704         node->num_children = 0;
705         node->children = NULL;
706         node->data = data;
707
708         if (tree->num_children == 0) {
709                 tree->children = talloc_zero(tree, struct dns_tree *);
710         } else {
711                 tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
712                                                 tree->num_children+1);
713         }
714         if (tree->children == NULL) {
715                 talloc_free(node);
716                 return NULL;
717         }
718         tree->children[tree->num_children] = node;
719         tree->num_children++;
720
721         return node;
722 }
723
724 /* Find a node that matches the name components */
725 static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
726 {
727         struct dns_tree *node, *next;
728         int i, j, start;
729
730         *match_count = -1;
731
732         if (strcmp(tree->name, "@") == 0) {
733                 start = 0;
734         } else {
735                 if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
736                         return NULL;
737                 }
738                 start = 1;
739                 *match_count = 0;
740         }
741
742         node = tree;
743         for (i=start; i<ncount; i++) {
744                 if (node->num_children == 0) {
745                         break;
746                 }
747                 next = NULL;
748                 for (j=0; j<node->num_children; j++) {
749                         if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
750                                 next = node->children[j];
751                                 *match_count = i;
752                                 break;
753                         }
754                 }
755                 if (next == NULL) {
756                         break;
757                 } else {
758                         node = next;
759                 }
760         }
761
762         return node;
763 }
764
765 /* Build a 2-level tree for resulting dns names */
766 struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
767 {
768         struct dns_tree *root, *base, *tree, *node;
769         const char *ptr;
770         int rootcount, ncount;
771         char **nlist;
772         int i, level, match_count;
773
774         rootcount = dns_split_name_components(mem_ctx, name, &nlist);
775         if (rootcount <= 0) {
776                 return NULL;
777         }
778
779         root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
780         if (root == NULL) {
781                 talloc_free(nlist);
782                 return NULL;
783         }
784
785         tree = root;
786         for (i=rootcount-2; i>=0; i--) {
787                 tree = dns_tree_add(tree, nlist[i], NULL);
788                 if (tree == NULL) {
789                         goto failed;
790                 }
791         }
792
793         base = tree;
794
795         /* Add all names in the result in a tree */
796         for (i=0; i<res->count; i++) {
797                 ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
798                 if (ptr == NULL) {
799                         DBG_ERR("dnsserver: dns record has no name (%s)",
800                                 ldb_dn_get_linearized(res->msgs[i]->dn));
801                         goto failed;
802                 }
803
804                 if (strcmp(ptr, "@") == 0) {
805                         base->data = res->msgs[i];
806                         continue;
807                 } else if (strcasecmp(ptr, name) == 0) {
808                         base->data = res->msgs[i];
809                         continue;
810                 }
811
812                 ncount = dns_split_name_components(root, ptr, &nlist);
813                 if (ncount < 0) {
814                         goto failed;
815                 }
816
817                 /* Find matching node */
818                 tree = dns_tree_find(root, ncount, nlist, &match_count);
819                 if (tree == NULL) {
820                         goto failed;
821                 }
822
823                 /* If the node is on leaf, then add record data */
824                 if (match_count+1 == ncount) {
825                         tree->data = res->msgs[i];
826                 }
827
828                 /* Add missing name components */
829                 for (level=match_count+1; level<ncount; level++) {
830                         if (tree->level == rootcount+1) {
831                                 break;
832                         }
833                         if (level == ncount-1) {
834                                 node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
835                         } else {
836                                 node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
837                         }
838                         if (node == NULL) {
839                                 goto failed;
840                         }
841                         tree = node;
842                 }
843
844                 talloc_free(nlist);
845         }
846
847         /* Mark the base record, so it can be found easily */
848         base->level = -1;
849
850         return root;
851
852 failed:
853         talloc_free(nlist);
854         talloc_free(root);
855         return NULL;
856 }
857
858
859 static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
860 {
861         int i;
862         char **ptr = *add_names;
863         int count = *add_count;
864
865         for (i=0; i<count; i++) {
866                 if (strcasecmp(ptr[i], name) == 0) {
867                         return;
868                 }
869         }
870
871         ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
872         if (ptr == NULL) {
873                 return;
874         }
875
876         ptr[count] = talloc_strdup(mem_ctx, name);
877         if (ptr[count] == NULL) {
878                 talloc_free(ptr);
879                 return;
880         }
881
882         *add_names = ptr;
883         *add_count = count+1;
884 }
885
886
887 static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
888 {
889         if (add_names == NULL) {
890                 return;
891         }
892
893         switch (rec->wType) {
894
895         case DNS_TYPE_NS:
896                 _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
897                 break;
898
899         case DNS_TYPE_CNAME:
900                 _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
901                 break;
902
903         case DNS_TYPE_SOA:
904                 _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
905                 break;
906
907         case DNS_TYPE_MX:
908                 _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
909                 break;
910
911         case DNS_TYPE_SRV:
912                 _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
913                 break;
914
915         default:
916                 break;
917         }
918 }
919
920
921 WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
922                                 struct dnsserver_zone *z,
923                                 enum dns_record_type record_type,
924                                 unsigned int select_flag,
925                                 const char *branch_name,
926                                 struct ldb_message *msg,
927                                 int num_children,
928                                 struct DNS_RPC_RECORDS_ARRAY *recs,
929                                 char ***add_names,
930                                 int *add_count)
931 {
932         struct ldb_message_element *el;
933         const char *ptr;
934         int i, j;
935         bool found;
936
937         if (recs->count == 0) {
938                 recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
939         } else {
940                 recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
941         }
942         if (recs->rec == NULL) {
943                 return WERR_NOT_ENOUGH_MEMORY;
944         }
945         i = recs->count;
946         recs->rec[i].wLength = 0;
947         recs->rec[i].wRecordCount = 0;
948         recs->rec[i].dwChildCount = num_children;
949         recs->rec[i].dwFlags = 0;
950
951         /* The base records returned with empty name */
952         /* Children records returned with names */
953         if (branch_name == NULL) {
954                 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
955                 recs->rec[i].dnsNodeName.len = 0;
956         } else {
957                 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
958                 recs->rec[i].dnsNodeName.len = strlen(branch_name);
959         }
960         recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
961         recs->count++;
962
963         /* Allow empty records */
964         if (msg == NULL) {
965                 return WERR_OK;
966         }
967
968         /* Do not return RR records, if the node has children */
969         if (branch_name != NULL && num_children > 0) {
970                 return WERR_OK;
971         }
972
973         ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
974         if (ptr == NULL) {
975                 DBG_ERR("dnsserver: dns record has no name (%s)",
976                         ldb_dn_get_linearized(msg->dn));
977                 return WERR_INTERNAL_DB_ERROR;
978         }
979
980         el = ldb_msg_find_element(msg, "dnsRecord");
981         if (el == NULL || el->values == 0) {
982                 return WERR_OK;
983         }
984
985         /* Add RR records */
986         for (j=0; j<el->num_values; j++) {
987                 struct dnsp_DnssrvRpcRecord dnsp_rec;
988                 struct DNS_RPC_RECORD *dns_rec;
989                 enum ndr_err_code ndr_err;
990
991                 ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
992                                         (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
993                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
994                         DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn)));
995                         return WERR_INTERNAL_DB_ERROR;
996                 }
997
998                 /* Match the records based on search criteria */
999                 if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
1000                         found = false;
1001
1002                         if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
1003                                 if (dnsp_rec.rank == DNS_RANK_ZONE) {
1004                                         found = true;
1005                                 } else if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
1006                                         /*
1007                                          * If branch_name is NULL, we're
1008                                          * explicitly asked to also return
1009                                          * DNS_RANK_NS_GLUE records
1010                                          */
1011                                         if (branch_name == NULL) {
1012                                                 found = true;
1013                                         }
1014                                 }
1015                         }
1016                         if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
1017                                 if (dnsp_rec.rank == DNS_RANK_ZONE) {
1018                                         found = true;
1019                                 }
1020                         }
1021                         if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
1022                                 if (dnsp_rec.rank == DNS_RANK_GLUE) {
1023                                         found = true;
1024                                 }
1025                         }
1026                         if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
1027                                 if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
1028                                         found = true;
1029                                 }
1030                         }
1031
1032                         if (found) {
1033                                 recs->rec[i].records = talloc_realloc(recs,
1034                                                         recs->rec[i].records,
1035                                                         struct DNS_RPC_RECORD,
1036                                                         recs->rec[i].wRecordCount+1);
1037                                 if (recs->rec[i].records == NULL) {
1038                                         return WERR_NOT_ENOUGH_MEMORY;
1039                                 }
1040
1041                                 dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
1042                                 dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
1043
1044                                 /* Fix record flags */
1045                                 if (strcmp(ptr, "@") == 0) {
1046                                         dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
1047
1048                                         if (dnsp_rec.rank == DNS_RANK_ZONE) {
1049                                                 dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
1050                                         }
1051                                 }
1052
1053                                 if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
1054                                         dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
1055                                 }
1056
1057                                 recs->rec[i].wRecordCount++;
1058
1059                                 dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
1060                         }
1061                 }
1062         }
1063
1064         return WERR_OK;
1065 }
1066
1067
1068 int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
1069                                 char *search_name)
1070 {
1071         const char *name1, *name2;
1072         const char *ptr1, *ptr2;
1073
1074         name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
1075         name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
1076         if (name1 == NULL || name2 == NULL) {
1077                 return 0;
1078         }
1079
1080         /* '@' record and the search_name record gets preference */
1081         if (name1[0] == '@') {
1082                 return -1;
1083         }
1084         if (search_name && strcasecmp(name1, search_name) == 0) {
1085                 return -1;
1086         }
1087
1088         if (name2[0] == '@') {
1089                 return 1;
1090         }
1091         if (search_name && strcasecmp(name2, search_name) == 0) {
1092                 return 1;
1093         }
1094
1095         /* Compare the last components of names.
1096          * If search_name is not NULL, compare the second last components of names */
1097         ptr1 = strrchr(name1, '.');
1098         if (ptr1 == NULL) {
1099                 ptr1 = name1;
1100         } else {
1101                 if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
1102                         ptr1--;
1103                         while (ptr1 != name1) {
1104                                 ptr1--;
1105                                 if (*ptr1 == '.') {
1106                                         break;
1107                                 }
1108                         }
1109                 }
1110                 if (*ptr1 == '.') {
1111                         ptr1 = &ptr1[1];
1112                 }
1113         }
1114
1115         ptr2 = strrchr(name2, '.');
1116         if (ptr2 == NULL) {
1117                 ptr2 = name2;
1118         } else {
1119                 if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
1120                         ptr2--;
1121                         while (ptr2 != name2) {
1122                                 ptr2--;
1123                                 if (*ptr2 == '.') {
1124                                         break;
1125                                 }
1126                         }
1127                 }
1128                 if (*ptr2 == '.') {
1129                         ptr2 = &ptr2[1];
1130                 }
1131         }
1132
1133         return strcasecmp(ptr1, ptr2);
1134 }
1135
1136 bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
1137 {
1138         bool status;
1139         int i;
1140
1141         if (rec1->wType != rec2->wType) {
1142                 return false;
1143         }
1144
1145         switch(rec1->wType) {
1146         case DNS_TYPE_TOMBSTONE:
1147                 return true;
1148
1149         case DNS_TYPE_A:
1150                 return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
1151
1152         case DNS_TYPE_NS:
1153                 return dns_name_equal(rec1->data.ns, rec2->data.ns);
1154
1155         case DNS_TYPE_CNAME:
1156                 return dns_name_equal(rec1->data.cname, rec2->data.cname);
1157
1158         case DNS_TYPE_SOA:
1159                 return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) &&
1160                         dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) &&
1161                         rec1->data.soa.serial == rec2->data.soa.serial &&
1162                         rec1->data.soa.refresh == rec2->data.soa.refresh &&
1163                         rec1->data.soa.retry == rec2->data.soa.retry &&
1164                         rec1->data.soa.expire == rec2->data.soa.expire &&
1165                         rec1->data.soa.minimum == rec2->data.soa.minimum;
1166
1167         case DNS_TYPE_PTR:
1168                 return dns_name_equal(rec1->data.ptr, rec2->data.ptr);
1169
1170         case DNS_TYPE_MX:
1171                 return rec1->data.mx.wPriority == rec2->data.mx.wPriority &&
1172                         dns_name_equal(rec1->data.mx.nameTarget, rec2->data.mx.nameTarget);
1173
1174         case DNS_TYPE_TXT:
1175                 if (rec1->data.txt.count != rec2->data.txt.count) {
1176                         return false;
1177                 }
1178                 status = true;
1179                 for (i=0; i<rec1->data.txt.count; i++) {
1180                         status = status && (strcmp(rec1->data.txt.str[i],
1181                                                    rec2->data.txt.str[i]) == 0);
1182                 }
1183                 return status;
1184
1185         case DNS_TYPE_AAAA:
1186                 return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;
1187
1188         case DNS_TYPE_SRV:
1189                 return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
1190                         rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
1191                         rec1->data.srv.wPort == rec2->data.srv.wPort &&
1192                         dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget);
1193
1194         default:
1195                 DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType));
1196                 break;
1197         }
1198
1199         return false;
1200 }