Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : DNS server utils
5 :
6 : Copyright (C) 2010 Kai Blin
7 : Copyright (C) 2014 Stefan Metzmacher
8 : Copyright (C) 2015 Andrew Bartlett
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "libcli/util/ntstatus.h"
26 : #include "libcli/util/werror.h"
27 : #include "librpc/ndr/libndr.h"
28 : #include "librpc/gen_ndr/ndr_dns.h"
29 : #include "librpc/gen_ndr/ndr_dnsp.h"
30 : #include <ldb.h>
31 : #include "dsdb/samdb/samdb.h"
32 : #include "dsdb/common/util.h"
33 : #include "dns_server/dnsserver_common.h"
34 : #include "rpc_server/dnsserver/dnsserver.h"
35 : #include "lib/util/dlinklist.h"
36 : #include "system/network.h"
37 :
38 : #undef DBGC_CLASS
39 : #define DBGC_CLASS DBGC_DNS
40 :
41 : #undef strncasecmp
42 :
43 4023 : uint8_t werr_to_dns_err(WERROR werr)
44 : {
45 4023 : if (W_ERROR_EQUAL(WERR_OK, werr)) {
46 4013 : return DNS_RCODE_OK;
47 304 : } else if (W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR), werr)) {
48 294 : return DNS_RCODE_FORMERR;
49 292 : } else if (W_ERROR_EQUAL(DNS_ERR(SERVER_FAILURE), werr)) {
50 282 : return DNS_RCODE_SERVFAIL;
51 292 : } else if (W_ERROR_EQUAL(DNS_ERR(NAME_ERROR), werr)) {
52 282 : return DNS_RCODE_NXDOMAIN;
53 179 : } else if (W_ERROR_EQUAL(WERR_DNS_ERROR_NAME_DOES_NOT_EXIST, werr)) {
54 169 : return DNS_RCODE_NXDOMAIN;
55 173 : } else if (W_ERROR_EQUAL(DNS_ERR(NOT_IMPLEMENTED), werr)) {
56 163 : return DNS_RCODE_NOTIMP;
57 165 : } else if (W_ERROR_EQUAL(DNS_ERR(REFUSED), werr)) {
58 155 : return DNS_RCODE_REFUSED;
59 56 : } else if (W_ERROR_EQUAL(DNS_ERR(YXDOMAIN), werr)) {
60 46 : return DNS_RCODE_YXDOMAIN;
61 56 : } else if (W_ERROR_EQUAL(DNS_ERR(YXRRSET), werr)) {
62 46 : return DNS_RCODE_YXRRSET;
63 56 : } else if (W_ERROR_EQUAL(DNS_ERR(NXRRSET), werr)) {
64 46 : return DNS_RCODE_NXRRSET;
65 20 : } else if (W_ERROR_EQUAL(DNS_ERR(NOTAUTH), werr)) {
66 10 : return DNS_RCODE_NOTAUTH;
67 16 : } else if (W_ERROR_EQUAL(DNS_ERR(NOTZONE), werr)) {
68 6 : return DNS_RCODE_NOTZONE;
69 10 : } else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) {
70 0 : return DNS_RCODE_BADKEY;
71 : }
72 10 : DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr)));
73 10 : return DNS_RCODE_SERVFAIL;
74 : }
75 :
76 6655 : WERROR dns_common_extract(struct ldb_context *samdb,
77 : const struct ldb_message_element *el,
78 : TALLOC_CTX *mem_ctx,
79 : struct dnsp_DnssrvRpcRecord **records,
80 : uint16_t *num_records)
81 : {
82 4 : uint16_t ri;
83 4 : struct dnsp_DnssrvRpcRecord *recs;
84 :
85 6655 : *records = NULL;
86 6655 : *num_records = 0;
87 :
88 6655 : recs = talloc_zero_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
89 : el->num_values);
90 6655 : if (recs == NULL) {
91 0 : return WERR_NOT_ENOUGH_MEMORY;
92 : }
93 26761 : for (ri = 0; ri < el->num_values; ri++) {
94 6 : bool am_rodc;
95 6 : int ret;
96 20106 : const char *dnsHostName = NULL;
97 20106 : struct ldb_val *v = &el->values[ri];
98 6 : enum ndr_err_code ndr_err;
99 20106 : ndr_err = ndr_pull_struct_blob(v, recs, &recs[ri],
100 : (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
101 20106 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
102 0 : TALLOC_FREE(recs);
103 0 : DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n"));
104 0 : return DNS_ERR(SERVER_FAILURE);
105 : }
106 :
107 : /*
108 : * In AD, except on an RODC (where we should list a random RWDC,
109 : * we should over-stamp the MNAME with our own hostname
110 : */
111 20106 : if (recs[ri].wType != DNS_TYPE_SOA) {
112 17259 : continue;
113 : }
114 :
115 2859 : ret = samdb_rodc(samdb, &am_rodc);
116 2859 : if (ret != LDB_SUCCESS) {
117 0 : DEBUG(0, ("Failed to confirm we are not an RODC: %s\n",
118 : ldb_errstring(samdb)));
119 0 : return DNS_ERR(SERVER_FAILURE);
120 : }
121 :
122 2859 : if (am_rodc) {
123 12 : continue;
124 : }
125 :
126 2847 : ret = samdb_dns_host_name(samdb, &dnsHostName);
127 2847 : if (ret != LDB_SUCCESS || dnsHostName == NULL) {
128 0 : DEBUG(0, ("Failed to get dnsHostName from rootDSE\n"));
129 0 : return DNS_ERR(SERVER_FAILURE);
130 : }
131 :
132 2847 : recs[ri].data.soa.mname = talloc_strdup(recs, dnsHostName);
133 : }
134 :
135 6655 : *records = recs;
136 6655 : *num_records = el->num_values;
137 6655 : return WERR_OK;
138 : }
139 :
140 : /*
141 : * Lookup a DNS record, performing an exact match.
142 : * i.e. DNS wild card records are not considered.
143 : */
144 7296 : WERROR dns_common_lookup(struct ldb_context *samdb,
145 : TALLOC_CTX *mem_ctx,
146 : struct ldb_dn *dn,
147 : struct dnsp_DnssrvRpcRecord **records,
148 : uint16_t *num_records,
149 : bool *tombstoned)
150 : {
151 7296 : const struct timeval start = timeval_current();
152 6 : static const char * const attrs[] = {
153 : "dnsRecord",
154 : "dNSTombstoned",
155 : NULL
156 : };
157 6 : int ret;
158 7296 : WERROR werr = WERR_OK;
159 7296 : struct ldb_message *msg = NULL;
160 6 : struct ldb_message_element *el;
161 :
162 7296 : *records = NULL;
163 7296 : *num_records = 0;
164 :
165 7296 : if (tombstoned != NULL) {
166 1266 : *tombstoned = false;
167 1266 : ret = dsdb_search_one(samdb, mem_ctx, &msg, dn,
168 : LDB_SCOPE_BASE, attrs, 0,
169 : "(objectClass=dnsNode)");
170 : } else {
171 6030 : ret = dsdb_search_one(samdb, mem_ctx, &msg, dn,
172 : LDB_SCOPE_BASE, attrs, 0,
173 : "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))");
174 : }
175 7296 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
176 665 : werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
177 665 : goto exit;
178 : }
179 6631 : if (ret != LDB_SUCCESS) {
180 : /* TODO: we need to check if there's a glue record we need to
181 : * create a referral to */
182 0 : werr = DNS_ERR(NAME_ERROR);
183 0 : goto exit;
184 : }
185 :
186 6631 : if (tombstoned != NULL) {
187 946 : *tombstoned = ldb_msg_find_attr_as_bool(msg,
188 : "dNSTombstoned", false);
189 : }
190 :
191 6631 : el = ldb_msg_find_element(msg, "dnsRecord");
192 6631 : if (el == NULL) {
193 2 : TALLOC_FREE(msg);
194 : /*
195 : * records produced by older Samba releases
196 : * keep dnsNode objects without dnsRecord and
197 : * without setting dNSTombstoned=TRUE.
198 : *
199 : * We just pretend they're tombstones.
200 : */
201 2 : if (tombstoned != NULL) {
202 0 : struct dnsp_DnssrvRpcRecord *recs;
203 2 : recs = talloc_array(mem_ctx,
204 : struct dnsp_DnssrvRpcRecord,
205 : 1);
206 2 : if (recs == NULL) {
207 0 : werr = WERR_NOT_ENOUGH_MEMORY;
208 0 : goto exit;
209 : }
210 2 : recs[0] = (struct dnsp_DnssrvRpcRecord) {
211 : .wType = DNS_TYPE_TOMBSTONE,
212 : /*
213 : * A value of timestamp != 0
214 : * indicated that the object was already
215 : * a tombstone, this will be used
216 : * in dns_common_replace()
217 : */
218 : .data.EntombedTime = 1,
219 : };
220 :
221 2 : *tombstoned = true;
222 2 : *records = recs;
223 2 : *num_records = 1;
224 2 : werr = WERR_OK;
225 2 : goto exit;
226 : } else {
227 : /*
228 : * Because we are not looking for a tombstone
229 : * in this codepath, we just pretend it does
230 : * not exist at all.
231 : */
232 0 : werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
233 0 : goto exit;
234 : }
235 : }
236 :
237 6629 : werr = dns_common_extract(samdb, el, mem_ctx, records, num_records);
238 6629 : TALLOC_FREE(msg);
239 6629 : if (!W_ERROR_IS_OK(werr)) {
240 0 : goto exit;
241 : }
242 :
243 6625 : werr = WERR_OK;
244 7296 : exit:
245 7296 : DNS_COMMON_LOG_OPERATION(
246 : win_errstr(werr),
247 : &start,
248 : NULL,
249 : dn == NULL ? NULL : ldb_dn_get_linearized(dn),
250 6 : NULL);
251 7296 : return werr;
252 : }
253 :
254 : /*
255 : * Build an ldb_parse_tree node for an equality check
256 : *
257 : * Note: name is assumed to have been validated by dns_name_check
258 : * so will be zero terminated and of a reasonable size.
259 : */
260 409 : static struct ldb_parse_tree *build_equality_operation(
261 : TALLOC_CTX *mem_ctx,
262 : bool add_asterix, /* prepend an '*' to the name */
263 : const uint8_t *name, /* the value being matched */
264 : const char *attr, /* the attribute to check name against */
265 : size_t size) /* length of name */
266 : {
267 :
268 409 : struct ldb_parse_tree *el = NULL; /* Equality node being built */
269 409 : struct ldb_val *value = NULL; /* Value the attr will be compared
270 : with */
271 409 : size_t length = 0; /* calculated length of the value
272 : including option '*' prefix and
273 : '\0' string terminator */
274 :
275 409 : el = talloc(mem_ctx, struct ldb_parse_tree);
276 409 : if (el == NULL) {
277 0 : DBG_ERR("Unable to allocate ldb_parse_tree\n");
278 0 : return NULL;
279 : }
280 :
281 409 : el->operation = LDB_OP_EQUALITY;
282 409 : el->u.equality.attr = talloc_strdup(mem_ctx, attr);
283 409 : value = &el->u.equality.value;
284 409 : length = (add_asterix) ? size + 2 : size + 1;
285 409 : value->data = talloc_zero_array(el, uint8_t, length);
286 409 : if (value->data == NULL) {
287 0 : DBG_ERR("Unable to allocate value->data\n");
288 0 : TALLOC_FREE(el);
289 0 : return NULL;
290 : }
291 :
292 409 : value->length = length;
293 409 : if (add_asterix) {
294 250 : value->data[0] = '*';
295 250 : if (name != NULL) {
296 91 : memcpy(&value->data[1], name, size);
297 : }
298 159 : } else if (name != NULL) {
299 159 : memcpy(value->data, name, size);
300 : }
301 409 : return el;
302 : }
303 :
304 : /*
305 : * Determine the number of levels in name
306 : * essentially the number of '.'s in the name + 1
307 : *
308 : * name is assumed to have been validated by dns_name_check
309 : */
310 159 : static unsigned int number_of_labels(const struct ldb_val *name) {
311 159 : int x = 0;
312 159 : unsigned int labels = 1;
313 2157 : for (x = 0; x < name->length; x++) {
314 1998 : if (name->data[x] == '.') {
315 91 : labels++;
316 : }
317 : }
318 159 : return labels;
319 : }
320 : /*
321 : * Build a query that matches the target name, and any possible
322 : * DNS wild card entries
323 : *
324 : * Builds a parse tree equivalent to the example query.
325 : *
326 : * x.y.z -> (|(name=x.y.z)(name=\2a.y.z)(name=\2a.z)(name=\2a))
327 : *
328 : * The attribute 'name' is used as this is what the LDB index is on
329 : * (the RDN, being 'dc' in this use case, does not have an index in
330 : * the AD schema).
331 : *
332 : * Returns NULL if unable to build the query.
333 : *
334 : * The first component of the DN is assumed to be the name being looked up
335 : * and also that it has been validated by dns_name_check
336 : *
337 : */
338 : #define BASE "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE))(|(a=b)(c=d)))"
339 159 : static struct ldb_parse_tree *build_wildcard_query(
340 : TALLOC_CTX *mem_ctx,
341 : struct ldb_dn *dn)
342 : {
343 159 : const struct ldb_val *name = NULL; /* The DNS name being
344 : queried */
345 159 : const char *attr = "name"; /* The attribute name */
346 159 : struct ldb_parse_tree *query = NULL; /* The constructed query
347 : parse tree*/
348 159 : struct ldb_parse_tree *wildcard_query = NULL; /* The parse tree for the
349 : name and wild card
350 : entries */
351 159 : int labels = 0; /* The number of labels in the name */
352 :
353 159 : name = ldb_dn_get_rdn_val(dn);
354 159 : if (name == NULL) {
355 0 : DBG_ERR("Unable to get domain name value\n");
356 0 : return NULL;
357 : }
358 159 : labels = number_of_labels(name);
359 :
360 159 : query = ldb_parse_tree(mem_ctx, BASE);
361 159 : if (query == NULL) {
362 0 : DBG_ERR("Unable to parse query %s\n", BASE);
363 0 : return NULL;
364 : }
365 :
366 : /*
367 : * The 3rd element of BASE is a place holder which is replaced with
368 : * the actual wild card query
369 : */
370 159 : wildcard_query = query->u.list.elements[2];
371 159 : TALLOC_FREE(wildcard_query->u.list.elements);
372 :
373 159 : wildcard_query->u.list.num_elements = labels + 1;
374 159 : wildcard_query->u.list.elements = talloc_array(
375 : wildcard_query,
376 : struct ldb_parse_tree *,
377 : labels + 1);
378 : /*
379 : * Build the wild card query
380 : */
381 : {
382 159 : int x = 0; /* current character in the name */
383 159 : int l = 0; /* current equality operator index in elements */
384 159 : struct ldb_parse_tree *el = NULL; /* Equality operator being
385 : built */
386 159 : bool add_asterix = true; /* prepend an '*' to the value */
387 409 : for (l = 0, x = 0; l < labels && x < name->length; l++) {
388 250 : unsigned int size = name->length - x;
389 250 : add_asterix = (name->data[x] == '.');
390 250 : el = build_equality_operation(
391 : mem_ctx,
392 : add_asterix,
393 250 : &name->data[x],
394 : attr,
395 : size);
396 250 : if (el == NULL) {
397 0 : return NULL; /* Reason will have been logged */
398 : }
399 250 : wildcard_query->u.list.elements[l] = el;
400 :
401 : /* skip to the start of the next label */
402 250 : x++;
403 1998 : for (;x < name->length && name->data[x] != '.'; x++);
404 : }
405 :
406 : /* Add the base level "*" only query */
407 159 : el = build_equality_operation(mem_ctx, true, NULL, attr, 0);
408 159 : if (el == NULL) {
409 0 : TALLOC_FREE(query);
410 0 : return NULL; /* Reason will have been logged */
411 : }
412 159 : wildcard_query->u.list.elements[l] = el;
413 : }
414 159 : return query;
415 : }
416 :
417 : /*
418 : * Scan the list of records matching a dns wildcard query and return the
419 : * best match.
420 : *
421 : * The best match is either an exact name match, or the longest wild card
422 : * entry returned
423 : *
424 : * i.e. name = a.b.c candidates *.b.c, *.c, - *.b.c would be selected
425 : * name = a.b.c candidates a.b.c, *.b.c, *.c - a.b.c would be selected
426 : */
427 8 : static struct ldb_message *get_best_match(struct ldb_dn *dn,
428 : struct ldb_result *result)
429 : {
430 8 : int matched = 0; /* Index of the current best match in result */
431 8 : size_t length = 0; /* The length of the current candidate */
432 8 : const struct ldb_val *target = NULL; /* value we're looking for */
433 8 : const struct ldb_val *candidate = NULL; /* current candidate value */
434 8 : int x = 0;
435 :
436 8 : target = ldb_dn_get_rdn_val(dn);
437 20 : for(x = 0; x < result->count; x++) {
438 12 : candidate = ldb_dn_get_rdn_val(result->msgs[x]->dn);
439 12 : if (strncasecmp((char *) target->data,
440 12 : (char *) candidate->data,
441 12 : target->length) == 0) {
442 : /* Exact match stop searching and return */
443 0 : return result->msgs[x];
444 : }
445 12 : if (candidate->length > length) {
446 10 : matched = x;
447 10 : length = candidate->length;
448 : }
449 : }
450 8 : return result->msgs[matched];
451 : }
452 :
453 : /*
454 : * Look up a DNS entry, if an exact match does not exist, return the
455 : * closest matching DNS wildcard entry if available
456 : *
457 : * Returns: LDB_ERR_NO_SUCH_OBJECT If no matching record exists
458 : * LDB_ERR_OPERATIONS_ERROR If the query fails
459 : * LDB_SUCCESS If a matching record was retrieved
460 : *
461 : */
462 159 : static int dns_wildcard_lookup(struct ldb_context *samdb,
463 : TALLOC_CTX *mem_ctx,
464 : struct ldb_dn *dn,
465 : struct ldb_message **msg)
466 : {
467 0 : static const char * const attrs[] = {
468 : "dnsRecord",
469 : "dNSTombstoned",
470 : NULL
471 : };
472 159 : struct ldb_dn *parent = NULL; /* The parent dn */
473 159 : struct ldb_result *result = NULL; /* Results of the search */
474 0 : int ret; /* Return code */
475 159 : struct ldb_parse_tree *query = NULL; /* The query to run */
476 159 : struct ldb_request *request = NULL; /* LDB request for the query op */
477 159 : struct ldb_message *match = NULL; /* the best matching DNS record */
478 159 : TALLOC_CTX *frame = talloc_stackframe();
479 :
480 159 : parent = ldb_dn_get_parent(frame, dn);
481 159 : if (parent == NULL) {
482 0 : DBG_ERR("Unable to extract parent from dn\n");
483 0 : TALLOC_FREE(frame);
484 0 : return LDB_ERR_OPERATIONS_ERROR;
485 : }
486 :
487 159 : query = build_wildcard_query(frame, dn);
488 159 : if (query == NULL) {
489 0 : TALLOC_FREE(frame);
490 0 : return LDB_ERR_OPERATIONS_ERROR;
491 : }
492 :
493 159 : result = talloc_zero(mem_ctx, struct ldb_result);
494 159 : if (result == NULL) {
495 0 : TALLOC_FREE(frame);
496 0 : DBG_ERR("Unable to allocate ldb_result\n");
497 0 : return LDB_ERR_OPERATIONS_ERROR;
498 : }
499 :
500 159 : ret = ldb_build_search_req_ex(&request,
501 : samdb,
502 : frame,
503 : parent,
504 : LDB_SCOPE_SUBTREE,
505 : query,
506 : attrs,
507 : NULL,
508 : result,
509 : ldb_search_default_callback,
510 : NULL);
511 159 : if (ret != LDB_SUCCESS) {
512 0 : TALLOC_FREE(frame);
513 0 : DBG_ERR("ldb_build_search_req_ex returned %d\n", ret);
514 0 : return ret;
515 : }
516 :
517 159 : ret = ldb_request(samdb, request);
518 159 : if (ret != LDB_SUCCESS) {
519 0 : TALLOC_FREE(frame);
520 0 : return ret;
521 : }
522 :
523 159 : ret = ldb_wait(request->handle, LDB_WAIT_ALL);
524 159 : if (ret != LDB_SUCCESS) {
525 10 : TALLOC_FREE(frame);
526 10 : return ret;
527 : }
528 :
529 149 : if (result->count == 0) {
530 141 : TALLOC_FREE(frame);
531 141 : return LDB_ERR_NO_SUCH_OBJECT;
532 : }
533 :
534 8 : match = get_best_match(dn, result);
535 8 : if (match == NULL) {
536 0 : TALLOC_FREE(frame);
537 0 : return LDB_ERR_OPERATIONS_ERROR;
538 : }
539 :
540 8 : *msg = talloc_move(mem_ctx, &match);
541 8 : TALLOC_FREE(frame);
542 8 : return LDB_SUCCESS;
543 : }
544 :
545 : /*
546 : * Lookup a DNS record, will match DNS wild card records if an exact match
547 : * is not found.
548 : */
549 2723 : WERROR dns_common_wildcard_lookup(struct ldb_context *samdb,
550 : TALLOC_CTX *mem_ctx,
551 : struct ldb_dn *dn,
552 : struct dnsp_DnssrvRpcRecord **records,
553 : uint16_t *num_records)
554 : {
555 2723 : const struct timeval start = timeval_current();
556 0 : int ret;
557 2723 : WERROR werr = WERR_OK;
558 2723 : struct ldb_message *msg = NULL;
559 2723 : struct ldb_message_element *el = NULL;
560 2723 : const struct ldb_val *name = NULL;
561 :
562 2723 : *records = NULL;
563 2723 : *num_records = 0;
564 :
565 2723 : name = ldb_dn_get_rdn_val(dn);
566 2723 : if (name == NULL) {
567 0 : werr = DNS_ERR(NAME_ERROR);
568 0 : goto exit;
569 : }
570 :
571 : /* Don't look for a wildcard for @ */
572 2723 : if (name->length == 1 && name->data[0] == '@') {
573 151 : werr = dns_common_lookup(samdb,
574 : mem_ctx,
575 : dn,
576 : records,
577 : num_records,
578 : NULL);
579 151 : goto exit;
580 : }
581 :
582 2572 : werr = dns_name_check(
583 : mem_ctx,
584 2572 : strlen((const char*)name->data),
585 2572 : (const char*) name->data);
586 2572 : if (!W_ERROR_IS_OK(werr)) {
587 0 : goto exit;
588 : }
589 :
590 : /*
591 : * Do a point search first, then fall back to a wildcard
592 : * lookup if it does not exist
593 : */
594 2572 : werr = dns_common_lookup(samdb,
595 : mem_ctx,
596 : dn,
597 : records,
598 : num_records,
599 : NULL);
600 2572 : if (!W_ERROR_EQUAL(werr, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
601 2413 : goto exit;
602 : }
603 :
604 159 : ret = dns_wildcard_lookup(samdb, mem_ctx, dn, &msg);
605 159 : if (ret == LDB_ERR_OPERATIONS_ERROR) {
606 0 : werr = DNS_ERR(SERVER_FAILURE);
607 0 : goto exit;
608 : }
609 159 : if (ret != LDB_SUCCESS) {
610 151 : werr = DNS_ERR(NAME_ERROR);
611 151 : goto exit;
612 : }
613 :
614 8 : el = ldb_msg_find_element(msg, "dnsRecord");
615 8 : if (el == NULL) {
616 0 : werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
617 0 : goto exit;
618 : }
619 :
620 8 : werr = dns_common_extract(samdb, el, mem_ctx, records, num_records);
621 8 : TALLOC_FREE(msg);
622 8 : if (!W_ERROR_IS_OK(werr)) {
623 0 : goto exit;
624 : }
625 :
626 8 : werr = WERR_OK;
627 2723 : exit:
628 2723 : DNS_COMMON_LOG_OPERATION(
629 : win_errstr(werr),
630 : &start,
631 : NULL,
632 : dn == NULL ? NULL : ldb_dn_get_linearized(dn),
633 0 : NULL);
634 2723 : return werr;
635 : }
636 :
637 5751 : static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1,
638 : const struct dnsp_DnssrvRpcRecord *r2)
639 : {
640 5751 : if (r1->wType != r2->wType) {
641 : /*
642 : * The records are sorted with higher types first,
643 : * which puts tombstones (type 0) last.
644 : */
645 480 : return NUMERIC_CMP(r2->wType, r1->wType);
646 : }
647 : /*
648 : * Then we need to sort from the oldest to newest timestamp.
649 : *
650 : * Note that dwTimeStamp == 0 (never expiring) records come first,
651 : * then the ones whose expiry is soonest.
652 : */
653 5271 : return NUMERIC_CMP(r1->dwTimeStamp, r2->dwTimeStamp);
654 : }
655 :
656 : /*
657 : * Check for valid DNS names. These are names which:
658 : * - are non-empty
659 : * - do not start with a dot
660 : * - do not have any empty labels
661 : * - have no more than 127 labels
662 : * - are no longer than 253 characters
663 : * - none of the labels exceed 63 characters
664 : */
665 13403 : WERROR dns_name_check(TALLOC_CTX *mem_ctx, size_t len, const char *name)
666 : {
667 17 : size_t i;
668 13403 : unsigned int labels = 0;
669 13403 : unsigned int label_len = 0;
670 :
671 13403 : if (len == 0) {
672 38 : return WERR_DS_INVALID_DN_SYNTAX;
673 : }
674 :
675 13365 : if (len > 1 && name[0] == '.') {
676 120 : return WERR_DS_INVALID_DN_SYNTAX;
677 : }
678 :
679 13245 : if ((len - 1) > DNS_MAX_DOMAIN_LENGTH) {
680 0 : return WERR_DS_INVALID_DN_SYNTAX;
681 : }
682 :
683 371473 : for (i = 0; i < len - 1; i++) {
684 358268 : if (name[i] == '.' && name[i+1] == '.') {
685 40 : return WERR_DS_INVALID_DN_SYNTAX;
686 : }
687 358228 : if (name[i] == '.') {
688 37847 : labels++;
689 37847 : if (labels > DNS_MAX_LABELS) {
690 0 : return WERR_DS_INVALID_DN_SYNTAX;
691 : }
692 37798 : label_len = 0;
693 : } else {
694 320381 : label_len++;
695 320381 : if (label_len > DNS_MAX_LABEL_LENGTH) {
696 0 : return WERR_DS_INVALID_DN_SYNTAX;
697 : }
698 : }
699 : }
700 :
701 13205 : return WERR_OK;
702 : }
703 :
704 2116 : static WERROR check_name_list(TALLOC_CTX *mem_ctx, uint16_t rec_count,
705 : struct dnsp_DnssrvRpcRecord *records)
706 : {
707 29 : WERROR werr;
708 29 : uint16_t i;
709 29 : size_t len;
710 29 : struct dnsp_DnssrvRpcRecord record;
711 :
712 2116 : werr = WERR_OK;
713 6751 : for (i = 0; i < rec_count; i++) {
714 4637 : record = records[i];
715 :
716 4637 : switch (record.wType) {
717 :
718 35 : case DNS_TYPE_NS:
719 35 : len = strlen(record.data.ns);
720 35 : werr = dns_name_check(mem_ctx, len, record.data.ns);
721 35 : break;
722 40 : case DNS_TYPE_CNAME:
723 40 : len = strlen(record.data.cname);
724 40 : werr = dns_name_check(mem_ctx, len, record.data.cname);
725 40 : break;
726 85 : case DNS_TYPE_SOA:
727 85 : len = strlen(record.data.soa.mname);
728 85 : werr = dns_name_check(mem_ctx, len, record.data.soa.mname);
729 85 : if (!W_ERROR_IS_OK(werr)) {
730 0 : break;
731 : }
732 85 : len = strlen(record.data.soa.rname);
733 85 : werr = dns_name_check(mem_ctx, len, record.data.soa.rname);
734 85 : break;
735 33 : case DNS_TYPE_PTR:
736 33 : len = strlen(record.data.ptr);
737 33 : werr = dns_name_check(mem_ctx, len, record.data.ptr);
738 33 : break;
739 34 : case DNS_TYPE_MX:
740 34 : len = strlen(record.data.mx.nameTarget);
741 34 : werr = dns_name_check(mem_ctx, len, record.data.mx.nameTarget);
742 34 : break;
743 651 : case DNS_TYPE_SRV:
744 651 : len = strlen(record.data.srv.nameTarget);
745 651 : werr = dns_name_check(mem_ctx, len,
746 : record.data.srv.nameTarget);
747 651 : break;
748 : /*
749 : * In the default case, the record doesn't have a DN, so it
750 : * must be ok.
751 : */
752 3759 : default:
753 3759 : break;
754 : }
755 :
756 4637 : if (!W_ERROR_IS_OK(werr)) {
757 2 : return werr;
758 : }
759 : }
760 :
761 2114 : return WERR_OK;
762 : }
763 :
764 1274 : bool dns_name_is_static(struct dnsp_DnssrvRpcRecord *records,
765 : uint16_t rec_count)
766 : {
767 1274 : int i = 0;
768 4637 : for (i = 0; i < rec_count; i++) {
769 3518 : if (records[i].wType == DNS_TYPE_TOMBSTONE) {
770 23 : continue;
771 : }
772 :
773 3495 : if (records[i].wType == DNS_TYPE_SOA ||
774 3492 : records[i].dwTimeStamp == 0) {
775 155 : return true;
776 : }
777 : }
778 1119 : return false;
779 : }
780 :
781 : /*
782 : * Helper function to copy a dnsp_ip4_array struct to an IP4_ARRAY struct.
783 : * The new structure and it's data are allocated on the supplied talloc context
784 : */
785 4 : static struct IP4_ARRAY *copy_ip4_array(TALLOC_CTX *ctx,
786 : const char *name,
787 : struct dnsp_ip4_array array)
788 : {
789 :
790 4 : struct IP4_ARRAY *ip4_array = NULL;
791 4 : unsigned int i;
792 :
793 4 : ip4_array = talloc_zero(ctx, struct IP4_ARRAY);
794 4 : if (ip4_array == NULL) {
795 0 : DBG_ERR("Out of memory copying property [%s]\n", name);
796 0 : return NULL;
797 : }
798 :
799 4 : ip4_array->AddrCount = array.addrCount;
800 4 : if (ip4_array->AddrCount == 0) {
801 0 : return ip4_array;
802 : }
803 :
804 4 : ip4_array->AddrArray =
805 2 : talloc_array(ip4_array, uint32_t, ip4_array->AddrCount);
806 2 : if (ip4_array->AddrArray == NULL) {
807 0 : TALLOC_FREE(ip4_array);
808 0 : DBG_ERR("Out of memory copying property [%s] values\n", name);
809 0 : return NULL;
810 : }
811 :
812 10 : for (i = 0; i < ip4_array->AddrCount; i++) {
813 8 : ip4_array->AddrArray[i] = array.addrArray[i];
814 : }
815 :
816 0 : return ip4_array;
817 : }
818 :
819 42860 : bool dns_zoneinfo_load_zone_property(struct dnsserver_zoneinfo *zoneinfo,
820 : struct dnsp_DnsProperty *prop)
821 : {
822 42860 : switch (prop->id) {
823 6122 : case DSPROPERTY_ZONE_TYPE:
824 6122 : zoneinfo->dwZoneType = prop->data.zone_type;
825 6122 : break;
826 6124 : case DSPROPERTY_ZONE_ALLOW_UPDATE:
827 6124 : zoneinfo->fAllowUpdate = prop->data.allow_update_flag;
828 6124 : break;
829 6122 : case DSPROPERTY_ZONE_NOREFRESH_INTERVAL:
830 6122 : zoneinfo->dwNoRefreshInterval = prop->data.norefresh_hours;
831 6122 : break;
832 6122 : case DSPROPERTY_ZONE_REFRESH_INTERVAL:
833 6122 : zoneinfo->dwRefreshInterval = prop->data.refresh_hours;
834 6122 : break;
835 6122 : case DSPROPERTY_ZONE_AGING_STATE:
836 6122 : zoneinfo->fAging = prop->data.aging_enabled;
837 6122 : break;
838 2 : case DSPROPERTY_ZONE_SCAVENGING_SERVERS:
839 2 : zoneinfo->aipScavengeServers = copy_ip4_array(
840 : zoneinfo, "ZONE_SCAVENGING_SERVERS", prop->data.servers);
841 2 : if (zoneinfo->aipScavengeServers == NULL) {
842 0 : return false;
843 : }
844 0 : break;
845 6122 : case DSPROPERTY_ZONE_AGING_ENABLED_TIME:
846 6122 : zoneinfo->dwAvailForScavengeTime =
847 6122 : prop->data.next_scavenging_cycle_hours;
848 6122 : break;
849 2 : case DSPROPERTY_ZONE_MASTER_SERVERS:
850 2 : zoneinfo->aipLocalMasters = copy_ip4_array(
851 : zoneinfo, "ZONE_MASTER_SERVERS", prop->data.master_servers);
852 2 : if (zoneinfo->aipLocalMasters == NULL) {
853 0 : return false;
854 : }
855 0 : break;
856 6103 : case DSPROPERTY_ZONE_EMPTY:
857 : case DSPROPERTY_ZONE_SECURE_TIME:
858 : case DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME:
859 : case DSPROPERTY_ZONE_AUTO_NS_SERVERS:
860 : case DSPROPERTY_ZONE_DCPROMO_CONVERT:
861 : case DSPROPERTY_ZONE_SCAVENGING_SERVERS_DA:
862 : case DSPROPERTY_ZONE_MASTER_SERVERS_DA:
863 : case DSPROPERTY_ZONE_NS_SERVERS_DA:
864 : case DSPROPERTY_ZONE_NODE_DBFLAGS:
865 6103 : break;
866 : }
867 42723 : return true;
868 : }
869 2134 : WERROR dns_get_zone_properties(struct ldb_context *samdb,
870 : TALLOC_CTX *mem_ctx,
871 : struct ldb_dn *zone_dn,
872 : struct dnsserver_zoneinfo *zoneinfo)
873 : {
874 :
875 29 : int ret, i;
876 2134 : struct dnsp_DnsProperty *prop = NULL;
877 2134 : struct ldb_message_element *element = NULL;
878 2134 : const char *const attrs[] = {"dNSProperty", NULL};
879 2134 : struct ldb_result *res = NULL;
880 29 : enum ndr_err_code err;
881 :
882 2134 : ret = ldb_search(samdb,
883 : mem_ctx,
884 : &res,
885 : zone_dn,
886 : LDB_SCOPE_BASE,
887 : attrs,
888 : "(objectClass=dnsZone)");
889 2134 : if (ret != LDB_SUCCESS) {
890 0 : DBG_ERR("dnsserver: Failed to find DNS zone: %s\n",
891 : ldb_dn_get_linearized(zone_dn));
892 0 : return DNS_ERR(SERVER_FAILURE);
893 : }
894 :
895 2134 : element = ldb_msg_find_element(res->msgs[0], "dNSProperty");
896 2134 : if (element == NULL) {
897 295 : return DNS_ERR(NOTZONE);
898 : }
899 :
900 14702 : for (i = 0; i < element->num_values; i++) {
901 133 : bool valid_property;
902 12863 : prop = talloc_zero(mem_ctx, struct dnsp_DnsProperty);
903 12863 : if (prop == NULL) {
904 0 : return WERR_NOT_ENOUGH_MEMORY;
905 : }
906 12996 : err = ndr_pull_struct_blob(
907 12863 : &(element->values[i]),
908 : mem_ctx,
909 : prop,
910 : (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty);
911 12863 : if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
912 : /*
913 : * If we can't pull it, then there is no valid
914 : * data to load into the zone, so ignore this
915 : * as Microsoft does. Windows can load an
916 : * invalid property with a zero length into
917 : * the dnsProperty attribute.
918 : */
919 2 : continue;
920 : }
921 :
922 133 : valid_property =
923 12861 : dns_zoneinfo_load_zone_property(zoneinfo, prop);
924 12861 : if (!valid_property) {
925 0 : return DNS_ERR(SERVER_FAILURE);
926 : }
927 : }
928 :
929 1839 : return WERR_OK;
930 : }
931 :
932 2116 : WERROR dns_common_replace(struct ldb_context *samdb,
933 : TALLOC_CTX *mem_ctx,
934 : struct ldb_dn *dn,
935 : bool needs_add,
936 : uint32_t serial,
937 : struct dnsp_DnssrvRpcRecord *records,
938 : uint16_t rec_count)
939 : {
940 2116 : const struct timeval start = timeval_current();
941 29 : struct ldb_message_element *el;
942 29 : uint16_t i;
943 29 : int ret;
944 29 : WERROR werr;
945 2116 : struct ldb_message *msg = NULL;
946 2116 : bool was_tombstoned = false;
947 2116 : bool become_tombstoned = false;
948 2116 : struct ldb_dn *zone_dn = NULL;
949 2116 : struct dnsserver_zoneinfo *zoneinfo = NULL;
950 29 : uint32_t t;
951 :
952 2116 : msg = ldb_msg_new(mem_ctx);
953 2116 : W_ERROR_HAVE_NO_MEMORY(msg);
954 :
955 2116 : msg->dn = dn;
956 :
957 2116 : zone_dn = ldb_dn_copy(mem_ctx, dn);
958 2116 : if (zone_dn == NULL) {
959 0 : werr = WERR_NOT_ENOUGH_MEMORY;
960 0 : goto exit;
961 : }
962 2116 : if (!ldb_dn_remove_child_components(zone_dn, 1)) {
963 0 : werr = DNS_ERR(SERVER_FAILURE);
964 0 : goto exit;
965 : }
966 2116 : zoneinfo = talloc(mem_ctx, struct dnsserver_zoneinfo);
967 2116 : if (zoneinfo == NULL) {
968 0 : werr = WERR_NOT_ENOUGH_MEMORY;
969 0 : goto exit;
970 : }
971 2116 : werr = dns_get_zone_properties(samdb, mem_ctx, zone_dn, zoneinfo);
972 2116 : if (W_ERROR_EQUAL(DNS_ERR(NOTZONE), werr)) {
973 : /*
974 : * We only got zoneinfo for aging so if we didn't find any
975 : * properties then just disable aging and keep going.
976 : */
977 289 : zoneinfo->fAging = 0;
978 1827 : } else if (!W_ERROR_IS_OK(werr)) {
979 0 : goto exit;
980 : }
981 :
982 2116 : werr = check_name_list(mem_ctx, rec_count, records);
983 2116 : if (!W_ERROR_IS_OK(werr)) {
984 2 : goto exit;
985 : }
986 :
987 2114 : ret = ldb_msg_add_empty(msg, "dnsRecord", LDB_FLAG_MOD_REPLACE, &el);
988 2114 : if (ret != LDB_SUCCESS) {
989 0 : werr = DNS_ERR(SERVER_FAILURE);
990 0 : goto exit;
991 : }
992 :
993 : /*
994 : * we have at least one value,
995 : * which might be used for the tombstone marker
996 : */
997 2114 : el->values = talloc_zero_array(el, struct ldb_val, MAX(1, rec_count));
998 2114 : if (el->values == NULL) {
999 0 : werr = WERR_NOT_ENOUGH_MEMORY;
1000 0 : goto exit;
1001 : }
1002 :
1003 2114 : if (rec_count > 1) {
1004 : /*
1005 : * We store a sorted list with the high wType values first
1006 : * that's what windows does. It also simplifies the
1007 : * filtering of DNS_TYPE_TOMBSTONE records
1008 : */
1009 829 : TYPESAFE_QSORT(records, rec_count, rec_cmp);
1010 : }
1011 :
1012 6749 : for (i = 0; i < rec_count; i++) {
1013 4635 : struct ldb_val *v = &el->values[el->num_values];
1014 4 : enum ndr_err_code ndr_err;
1015 :
1016 4635 : if (records[i].wType == DNS_TYPE_TOMBSTONE) {
1017 : /*
1018 : * There are two things that could be going on here.
1019 : *
1020 : * 1. We use a tombstone with EntombedTime == 0 for
1021 : * passing deletion messages through the stack, and
1022 : * this is the place we filter them out to perform
1023 : * that deletion.
1024 : *
1025 : * 2. This node is tombstoned, with no records except
1026 : * for a single tombstone, and it is just waiting to
1027 : * disappear. In this case, unless the caller has
1028 : * added a record, rec_count should be 1, and
1029 : * el->num_values will end up at 0, and we will make
1030 : * no changes. But if the caller has added a record,
1031 : * we need to un-tombstone the node.
1032 : *
1033 : * It is not possible to add an explicit tombstone
1034 : * record.
1035 : */
1036 201 : if (records[i].data.EntombedTime != 0) {
1037 26 : if (rec_count != 1 && DEBUGLVL(DBGLVL_NOTICE)) {
1038 0 : DBG_NOTICE("tombstone record [%u] has "
1039 : "%u neighbour records.\n",
1040 : i, rec_count - 1);
1041 0 : NDR_PRINT_DEBUG(dnsp_DnssrvRpcRecord, &records[i]);
1042 : }
1043 26 : was_tombstoned = true;
1044 : }
1045 201 : continue;
1046 : }
1047 :
1048 4434 : if (zoneinfo->fAging == 1 && records[i].dwTimeStamp != 0) {
1049 658 : t = unix_to_dns_timestamp(time(NULL));
1050 658 : if (t - records[i].dwTimeStamp >
1051 658 : zoneinfo->dwNoRefreshInterval) {
1052 130 : records[i].dwTimeStamp = t;
1053 : }
1054 : }
1055 :
1056 4434 : records[i].dwSerial = serial;
1057 4434 : ndr_err = ndr_push_struct_blob(v, el->values, &records[i],
1058 : (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
1059 4434 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1060 0 : DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n"));
1061 0 : werr = DNS_ERR(SERVER_FAILURE);
1062 0 : goto exit;
1063 : }
1064 4434 : el->num_values++;
1065 : }
1066 :
1067 2114 : if (needs_add) {
1068 : /*
1069 : * This is a new dnsNode, which simplifies everything as we
1070 : * know there is nothing to delete or change. We add the
1071 : * records and get out.
1072 : */
1073 318 : if (el->num_values == 0) {
1074 28 : werr = WERR_OK;
1075 28 : goto exit;
1076 : }
1077 :
1078 290 : ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
1079 290 : if (ret != LDB_SUCCESS) {
1080 0 : werr = DNS_ERR(SERVER_FAILURE);
1081 0 : goto exit;
1082 : }
1083 :
1084 290 : ret = ldb_add(samdb, msg);
1085 290 : if (ret != LDB_SUCCESS) {
1086 0 : werr = DNS_ERR(SERVER_FAILURE);
1087 0 : goto exit;
1088 : }
1089 :
1090 290 : werr = WERR_OK;
1091 290 : goto exit;
1092 : }
1093 :
1094 1796 : if (el->num_values == 0) {
1095 : /*
1096 : * We get here if there are no records or all the records were
1097 : * tombstones.
1098 : */
1099 26 : struct dnsp_DnssrvRpcRecord tbs;
1100 811 : struct ldb_val *v = &el->values[el->num_values];
1101 26 : enum ndr_err_code ndr_err;
1102 26 : struct timeval tv;
1103 :
1104 811 : if (was_tombstoned) {
1105 : /*
1106 : * This is already a tombstoned object.
1107 : * Just leave it instead of updating the time stamp.
1108 : */
1109 7 : werr = WERR_OK;
1110 7 : goto exit;
1111 : }
1112 :
1113 804 : tv = timeval_current();
1114 830 : tbs = (struct dnsp_DnssrvRpcRecord) {
1115 : .wType = DNS_TYPE_TOMBSTONE,
1116 : .dwSerial = serial,
1117 804 : .data.EntombedTime = timeval_to_nttime(&tv),
1118 : };
1119 :
1120 804 : ndr_err = ndr_push_struct_blob(v, el->values, &tbs,
1121 : (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
1122 804 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1123 0 : DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n"));
1124 0 : werr = DNS_ERR(SERVER_FAILURE);
1125 0 : goto exit;
1126 : }
1127 804 : el->num_values++;
1128 :
1129 804 : become_tombstoned = true;
1130 : }
1131 :
1132 1789 : if (was_tombstoned || become_tombstoned) {
1133 823 : ret = ldb_msg_append_fmt(msg, LDB_FLAG_MOD_REPLACE,
1134 : "dNSTombstoned", "%s",
1135 : become_tombstoned ? "TRUE" : "FALSE");
1136 823 : if (ret != LDB_SUCCESS) {
1137 0 : werr = DNS_ERR(SERVER_FAILURE);
1138 0 : goto exit;
1139 : }
1140 : }
1141 :
1142 1789 : ret = ldb_modify(samdb, msg);
1143 1789 : if (ret != LDB_SUCCESS) {
1144 2 : NTSTATUS nt = dsdb_ldb_err_to_ntstatus(ret);
1145 2 : werr = ntstatus_to_werror(nt);
1146 2 : goto exit;
1147 : }
1148 :
1149 1758 : werr = WERR_OK;
1150 2116 : exit:
1151 2116 : talloc_free(msg);
1152 2116 : DNS_COMMON_LOG_OPERATION(
1153 : win_errstr(werr),
1154 : &start,
1155 : NULL,
1156 : dn == NULL ? NULL : ldb_dn_get_linearized(dn),
1157 29 : NULL);
1158 2116 : return werr;
1159 : }
1160 :
1161 26748 : bool dns_name_match(const char *zone, const char *name, size_t *host_part_len)
1162 : {
1163 26748 : size_t zl = strlen(zone);
1164 26748 : size_t nl = strlen(name);
1165 20 : ssize_t zi, ni;
1166 20 : static const size_t fixup = 'a' - 'A';
1167 :
1168 26748 : if (zl > nl) {
1169 6907 : return false;
1170 : }
1171 :
1172 563749 : for (zi = zl, ni = nl; zi >= 0; zi--, ni--) {
1173 547232 : char zc = zone[zi];
1174 547232 : char nc = name[ni];
1175 :
1176 : /* convert to lower case */
1177 547232 : if (zc >= 'A' && zc <= 'Z') {
1178 2024 : zc += fixup;
1179 : }
1180 547232 : if (nc >= 'A' && nc <= 'Z') {
1181 53341 : nc += fixup;
1182 : }
1183 :
1184 547232 : if (zc != nc) {
1185 3314 : return false;
1186 : }
1187 : }
1188 :
1189 16517 : if (ni >= 0) {
1190 10876 : if (name[ni] != '.') {
1191 0 : return false;
1192 : }
1193 :
1194 10876 : ni--;
1195 : }
1196 :
1197 16517 : *host_part_len = ni+1;
1198 :
1199 16517 : return true;
1200 : }
1201 :
1202 8513 : WERROR dns_common_name2dn(struct ldb_context *samdb,
1203 : struct dns_server_zone *zones,
1204 : TALLOC_CTX *mem_ctx,
1205 : const char *name,
1206 : struct ldb_dn **_dn)
1207 : {
1208 10 : struct ldb_dn *base;
1209 10 : struct ldb_dn *dn;
1210 10 : const struct dns_server_zone *z;
1211 8513 : size_t host_part_len = 0;
1212 10 : struct ldb_val host_part;
1213 10 : WERROR werr;
1214 10 : bool ok;
1215 8513 : const char *casefold = NULL;
1216 :
1217 8513 : if (name == NULL) {
1218 0 : return DNS_ERR(FORMAT_ERROR);
1219 : }
1220 :
1221 8513 : if (strcmp(name, "") == 0) {
1222 0 : base = ldb_get_default_basedn(samdb);
1223 0 : dn = ldb_dn_copy(mem_ctx, base);
1224 0 : ok = ldb_dn_add_child_fmt(dn,
1225 : "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System");
1226 0 : if (ok == false) {
1227 0 : TALLOC_FREE(dn);
1228 0 : return WERR_NOT_ENOUGH_MEMORY;
1229 : }
1230 :
1231 0 : *_dn = dn;
1232 0 : return WERR_OK;
1233 : }
1234 :
1235 : /* Check non-empty names */
1236 8513 : werr = dns_name_check(mem_ctx, strlen(name), name);
1237 8513 : if (!W_ERROR_IS_OK(werr)) {
1238 0 : return werr;
1239 : }
1240 :
1241 14197 : for (z = zones; z != NULL; z = z->next) {
1242 20 : bool match;
1243 :
1244 14185 : match = dns_name_match(z->name, name, &host_part_len);
1245 14185 : if (match) {
1246 8491 : break;
1247 : }
1248 : }
1249 :
1250 8513 : if (z == NULL) {
1251 12 : return DNS_ERR(NAME_ERROR);
1252 : }
1253 :
1254 8501 : if (host_part_len == 0) {
1255 4021 : dn = ldb_dn_copy(mem_ctx, z->dn);
1256 4021 : ok = ldb_dn_add_child_fmt(dn, "DC=@");
1257 4021 : if (! ok) {
1258 0 : TALLOC_FREE(dn);
1259 0 : return WERR_NOT_ENOUGH_MEMORY;
1260 : }
1261 4021 : *_dn = dn;
1262 4021 : return WERR_OK;
1263 : }
1264 :
1265 4480 : dn = ldb_dn_copy(mem_ctx, z->dn);
1266 4480 : if (dn == NULL) {
1267 0 : TALLOC_FREE(dn);
1268 0 : return WERR_NOT_ENOUGH_MEMORY;
1269 : }
1270 :
1271 4480 : host_part = data_blob_const(name, host_part_len);
1272 :
1273 4480 : ok = ldb_dn_add_child_val(dn, "DC", host_part);
1274 :
1275 4480 : if (ok == false) {
1276 0 : TALLOC_FREE(dn);
1277 0 : return WERR_NOT_ENOUGH_MEMORY;
1278 : }
1279 :
1280 : /*
1281 : * Check the new DN here for validity, so as to catch errors
1282 : * early
1283 : */
1284 4480 : ok = ldb_dn_validate(dn);
1285 4480 : if (ok == false) {
1286 0 : TALLOC_FREE(dn);
1287 0 : return DNS_ERR(NAME_ERROR);
1288 : }
1289 :
1290 : /*
1291 : * The value from this check is saved in the DN, and doing
1292 : * this here allows an easy return here.
1293 : */
1294 4480 : casefold = ldb_dn_get_casefold(dn);
1295 4480 : if (casefold == NULL) {
1296 0 : TALLOC_FREE(dn);
1297 0 : return DNS_ERR(NAME_ERROR);
1298 : }
1299 :
1300 4480 : *_dn = dn;
1301 4480 : return WERR_OK;
1302 : }
1303 :
1304 :
1305 : /*
1306 : see if two dns records match
1307 : */
1308 :
1309 :
1310 9091 : bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1,
1311 : struct dnsp_DnssrvRpcRecord *rec2)
1312 : {
1313 0 : int i;
1314 0 : struct in6_addr rec1_in_addr6;
1315 0 : struct in6_addr rec2_in_addr6;
1316 :
1317 9091 : if (rec1->wType != rec2->wType) {
1318 1900 : return false;
1319 : }
1320 :
1321 : /* see if the data matches */
1322 7191 : switch (rec1->wType) {
1323 2047 : case DNS_TYPE_A:
1324 2047 : return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
1325 1243 : case DNS_TYPE_AAAA: {
1326 0 : int ret;
1327 :
1328 1243 : ret = inet_pton(AF_INET6, rec1->data.ipv6, &rec1_in_addr6);
1329 1243 : if (ret != 1) {
1330 0 : return false;
1331 : }
1332 1243 : ret = inet_pton(AF_INET6, rec2->data.ipv6, &rec2_in_addr6);
1333 1243 : if (ret != 1) {
1334 0 : return false;
1335 : }
1336 :
1337 1243 : return memcmp(&rec1_in_addr6, &rec2_in_addr6, sizeof(rec1_in_addr6)) == 0;
1338 : }
1339 210 : case DNS_TYPE_CNAME:
1340 210 : return samba_dns_name_equal(rec1->data.cname,
1341 : rec2->data.cname);
1342 1966 : case DNS_TYPE_TXT:
1343 1966 : if (rec1->data.txt.count != rec2->data.txt.count) {
1344 234 : return false;
1345 : }
1346 3013 : for (i = 0; i < rec1->data.txt.count; i++) {
1347 2008 : if (strcmp(rec1->data.txt.str[i], rec2->data.txt.str[i]) != 0) {
1348 727 : return false;
1349 : }
1350 : }
1351 1005 : return true;
1352 276 : case DNS_TYPE_PTR:
1353 276 : return samba_dns_name_equal(rec1->data.ptr, rec2->data.ptr);
1354 271 : case DNS_TYPE_NS:
1355 271 : return samba_dns_name_equal(rec1->data.ns, rec2->data.ns);
1356 :
1357 935 : case DNS_TYPE_SRV:
1358 1831 : return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
1359 896 : rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
1360 2690 : rec1->data.srv.wPort == rec2->data.srv.wPort &&
1361 859 : samba_dns_name_equal(rec1->data.srv.nameTarget,
1362 : rec2->data.srv.nameTarget);
1363 :
1364 243 : case DNS_TYPE_MX:
1365 474 : return rec1->data.mx.wPriority == rec2->data.mx.wPriority &&
1366 231 : samba_dns_name_equal(rec1->data.mx.nameTarget,
1367 : rec2->data.mx.nameTarget);
1368 :
1369 0 : case DNS_TYPE_SOA:
1370 0 : return samba_dns_name_equal(rec1->data.soa.mname,
1371 0 : rec2->data.soa.mname) &&
1372 0 : samba_dns_name_equal(rec1->data.soa.rname,
1373 0 : rec2->data.soa.rname) &&
1374 0 : rec1->data.soa.serial == rec2->data.soa.serial &&
1375 0 : rec1->data.soa.refresh == rec2->data.soa.refresh &&
1376 0 : rec1->data.soa.retry == rec2->data.soa.retry &&
1377 0 : rec1->data.soa.expire == rec2->data.soa.expire &&
1378 0 : rec1->data.soa.minimum == rec2->data.soa.minimum;
1379 0 : case DNS_TYPE_TOMBSTONE:
1380 0 : return true;
1381 0 : default:
1382 0 : break;
1383 : }
1384 :
1385 0 : return false;
1386 : }
1387 :
1388 :
1389 12559 : static int dns_common_sort_zones(struct ldb_message **m1, struct ldb_message **m2)
1390 : {
1391 70 : const char *n1, *n2;
1392 70 : size_t l1, l2;
1393 :
1394 12559 : n1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
1395 12559 : n2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
1396 12559 : if (n1 == NULL || n2 == NULL) {
1397 0 : if (n1 != NULL) {
1398 0 : return -1;
1399 0 : } else if (n2 != NULL) {
1400 0 : return 1;
1401 : } else {
1402 0 : return 0;
1403 : }
1404 : }
1405 12559 : l1 = strlen(n1);
1406 12559 : l2 = strlen(n2);
1407 :
1408 : /* If the string lengths are not equal just sort by length */
1409 12559 : if (l1 != l2) {
1410 : /* If m1 is the larger zone name, return it first */
1411 10650 : return NUMERIC_CMP(l2, l1);
1412 : }
1413 :
1414 : /*TODO: We need to compare DNs here, we want the DomainDNSZones first */
1415 1895 : return 0;
1416 : }
1417 :
1418 1970 : NTSTATUS dns_common_zones(struct ldb_context *samdb,
1419 : TALLOC_CTX *mem_ctx,
1420 : struct ldb_dn *base_dn,
1421 : struct dns_server_zone **zones_ret)
1422 : {
1423 1970 : const struct timeval start = timeval_current();
1424 14 : int ret;
1425 14 : static const char * const attrs[] = { "name", NULL};
1426 14 : struct ldb_result *res;
1427 14 : int i;
1428 1970 : struct dns_server_zone *new_list = NULL;
1429 1970 : TALLOC_CTX *frame = talloc_stackframe();
1430 1970 : NTSTATUS result = NT_STATUS_OK;
1431 :
1432 1970 : if (base_dn) {
1433 : /* This search will work against windows */
1434 93 : ret = dsdb_search(samdb, frame, &res,
1435 : base_dn, LDB_SCOPE_SUBTREE,
1436 : attrs, 0, "(objectClass=dnsZone)");
1437 : } else {
1438 : /* TODO: this search does not work against windows */
1439 1877 : ret = dsdb_search(samdb, frame, &res, NULL,
1440 : LDB_SCOPE_SUBTREE,
1441 : attrs,
1442 : DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
1443 : "(objectClass=dnsZone)");
1444 : }
1445 1970 : if (ret != LDB_SUCCESS) {
1446 0 : TALLOC_FREE(frame);
1447 0 : result = NT_STATUS_INTERNAL_DB_CORRUPTION;
1448 0 : goto exit;
1449 : }
1450 :
1451 1970 : TYPESAFE_QSORT(res->msgs, res->count, dns_common_sort_zones);
1452 :
1453 10855 : for (i=0; i < res->count; i++) {
1454 56 : struct dns_server_zone *z;
1455 :
1456 8885 : z = talloc_zero(mem_ctx, struct dns_server_zone);
1457 8885 : if (z == NULL) {
1458 0 : TALLOC_FREE(frame);
1459 0 : result = NT_STATUS_NO_MEMORY;
1460 0 : goto exit;
1461 : }
1462 :
1463 8885 : z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
1464 8885 : talloc_steal(z, z->name);
1465 8885 : z->dn = talloc_move(z, &res->msgs[i]->dn);
1466 : /*
1467 : * Ignore the RootDNSServers zone and zones that we don't support yet
1468 : * RootDNSServers should never be returned (Windows DNS server don't)
1469 : * ..TrustAnchors should never be returned as is, (Windows returns
1470 : * TrustAnchors) and for the moment we don't support DNSSEC so we'd better
1471 : * not return this zone.
1472 : */
1473 8885 : if ((strcmp(z->name, "RootDNSServers") == 0) ||
1474 5087 : (strcmp(z->name, "..TrustAnchors") == 0))
1475 : {
1476 3798 : DEBUG(10, ("Ignoring zone %s\n", z->name));
1477 3798 : talloc_free(z);
1478 3798 : continue;
1479 : }
1480 5115 : DLIST_ADD_END(new_list, z);
1481 : }
1482 :
1483 1970 : *zones_ret = new_list;
1484 1970 : TALLOC_FREE(frame);
1485 1956 : result = NT_STATUS_OK;
1486 1970 : exit:
1487 1970 : DNS_COMMON_LOG_OPERATION(
1488 : nt_errstr(result),
1489 : &start,
1490 : NULL,
1491 : base_dn == NULL ? NULL : ldb_dn_get_linearized(base_dn),
1492 14 : NULL);
1493 1970 : return result;
1494 : }
1495 :
1496 : /*
1497 : see if two DNS names are the same
1498 : */
1499 30522 : bool samba_dns_name_equal(const char *name1, const char *name2)
1500 : {
1501 30522 : size_t len1 = strlen(name1);
1502 30522 : size_t len2 = strlen(name2);
1503 :
1504 30522 : if (len1 > 0 && name1[len1 - 1] == '.') {
1505 2694 : len1--;
1506 : }
1507 30522 : if (len2 > 0 && name2[len2 - 1] == '.') {
1508 7451 : len2--;
1509 : }
1510 30522 : if (len1 != len2) {
1511 18491 : return false;
1512 : }
1513 12031 : return strncasecmp(name1, name2, len1) == 0;
1514 : }
1515 :
1516 :
1517 : /*
1518 : * Convert unix time to a DNS timestamp
1519 : * uint32 hours in the NTTIME epoch
1520 : *
1521 : * This uses unix_to_nt_time() which can return special flag NTTIMEs like
1522 : * UINT64_MAX (0xFFF...) or NTTIME_MAX (0x7FF...), which will convert to
1523 : * distant future timestamps; or 0 as a flag value, meaning a 1601 timestamp,
1524 : * which is used to indicate a record does not expire.
1525 : *
1526 : * As we don't generally check for these special values in NTTIME conversions,
1527 : * we also don't check here, but for the benefit of people encountering these
1528 : * timestamps and searching for their origin, here is a list:
1529 : *
1530 : ** TIME_T_MAX
1531 : *
1532 : * Even if time_t is 32 bit, this will become NTTIME_MAX (a.k.a INT64_MAX,
1533 : * 0x7fffffffffffffff) in 100ns units. That translates to 256204778 hours
1534 : * since 1601, which converts back to 9223372008000000000 or
1535 : * 0x7ffffff9481f1000. It will present as 30828-09-14 02:00:00, around 48
1536 : * minutes earlier than NTTIME_MAX.
1537 : *
1538 : ** 0, the start of the unix epoch, 1970-01-01 00:00:00
1539 : *
1540 : * This is converted into 0 in the Windows epoch, 1601-01-01 00:00:00 which is
1541 : * clearly the same whether you count in 100ns units or hours. In DNS record
1542 : * timestamps this is a flag meaning the record will never expire.
1543 : *
1544 : ** (time_t)-1, such as what *might* mean 1969-12-31 23:59:59
1545 : *
1546 : * This becomes (NTTIME)-1ULL a.k.a. UINT64_MAX, 0xffffffffffffffff thence
1547 : * 512409557 in hours since 1601. That in turn is 0xfffffffaf2028800 or
1548 : * 18446744052000000000 in NTTIME (rounded to the hour), which might be
1549 : * presented as -21709551616 or -0x50dfd7800, because NTTIME is not completely
1550 : * dedicated to being unsigned. If it gets shown as a year, it will be around
1551 : * 60055.
1552 : *
1553 : ** Other negative time_t values (e.g. 1969-05-29).
1554 : *
1555 : * The meaning of these is somewhat undefined, but in any case they will
1556 : * translate perfectly well into the same dates in NTTIME.
1557 : *
1558 : ** Notes
1559 : *
1560 : * There are dns timestamps that exceed the range of NTTIME (up to 488356 AD),
1561 : * but it is not possible for this function to produce them.
1562 : *
1563 : * It is plausible that it was at midnight on 1601-01-01, in London, that
1564 : * Shakespeare wrote:
1565 : *
1566 : * The time is out of joint. O cursed spite
1567 : * That ever I was born to set it right!
1568 : *
1569 : * and this is why we have this epoch and time zone.
1570 : */
1571 1995 : uint32_t unix_to_dns_timestamp(time_t t)
1572 : {
1573 2 : NTTIME nt;
1574 1995 : unix_to_nt_time(&nt, t);
1575 1995 : nt /= NTTIME_TO_HOURS;
1576 1995 : return (uint32_t) nt;
1577 : }
1578 :
1579 : /*
1580 : * Convert a DNS timestamp into NTTIME.
1581 : *
1582 : * Because DNS timestamps cover a longer time period than NTTIME, and these
1583 : * would wrap to an arbitrary NTTIME, we saturate at NTTIME_MAX and return an
1584 : * error in this case.
1585 : */
1586 77 : NTSTATUS dns_timestamp_to_nt_time(NTTIME *_nt, uint32_t t)
1587 : {
1588 77 : NTTIME nt = t;
1589 77 : if (nt > NTTIME_MAX / NTTIME_TO_HOURS) {
1590 2 : *_nt = NTTIME_MAX;
1591 2 : return NT_STATUS_INTEGER_OVERFLOW;
1592 : }
1593 75 : *_nt = nt * NTTIME_TO_HOURS;
1594 75 : return NT_STATUS_OK;
1595 : }
|