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