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 4048 : uint8_t werr_to_dns_err(WERROR werr)
44 : {
45 4048 : if (W_ERROR_EQUAL(WERR_OK, werr)) {
46 4038 : 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 6705 : 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 6705 : *records = NULL;
86 6705 : *num_records = 0;
87 :
88 6705 : recs = talloc_zero_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
89 : el->num_values);
90 6705 : if (recs == NULL) {
91 0 : return WERR_NOT_ENOUGH_MEMORY;
92 : }
93 26936 : for (ri = 0; ri < el->num_values; ri++) {
94 6 : bool am_rodc;
95 6 : int ret;
96 20231 : const char *dnsHostName = NULL;
97 20231 : struct ldb_val *v = &el->values[ri];
98 6 : enum ndr_err_code ndr_err;
99 20231 : ndr_err = ndr_pull_struct_blob(v, recs, &recs[ri],
100 : (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
101 20231 : 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 20231 : if (recs[ri].wType != DNS_TYPE_SOA) {
112 17359 : continue;
113 : }
114 :
115 2884 : ret = samdb_rodc(samdb, &am_rodc);
116 2884 : 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 2884 : if (am_rodc) {
123 12 : continue;
124 : }
125 :
126 2872 : ret = samdb_dns_host_name(samdb, &dnsHostName);
127 2872 : 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 2872 : recs[ri].data.soa.mname = talloc_strdup(recs, dnsHostName);
133 : }
134 :
135 6705 : *records = recs;
136 6705 : *num_records = el->num_values;
137 6705 : 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 7346 : 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 7346 : 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 7346 : WERROR werr = WERR_OK;
159 7346 : struct ldb_message *msg = NULL;
160 6 : struct ldb_message_element *el;
161 :
162 7346 : *records = NULL;
163 7346 : *num_records = 0;
164 :
165 7346 : 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 6080 : ret = dsdb_search_one(samdb, mem_ctx, &msg, dn,
172 : LDB_SCOPE_BASE, attrs, 0,
173 : "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))");
174 : }
175 7346 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
176 665 : werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
177 665 : goto exit;
178 : }
179 6681 : 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 6681 : if (tombstoned != NULL) {
187 946 : *tombstoned = ldb_msg_find_attr_as_bool(msg,
188 : "dNSTombstoned", false);
189 : }
190 :
191 6681 : el = ldb_msg_find_element(msg, "dnsRecord");
192 6681 : 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 6679 : werr = dns_common_extract(samdb, el, mem_ctx, records, num_records);
238 6679 : TALLOC_FREE(msg);
239 6679 : if (!W_ERROR_IS_OK(werr)) {
240 0 : goto exit;
241 : }
242 :
243 6675 : werr = WERR_OK;
244 7346 : exit:
245 7346 : 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 7346 : 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 2139 : for (x = 0; x < name->length; x++) {
314 1980 : 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 1980 : 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 8 : matched = x;
447 8 : 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 2748 : 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 2748 : const struct timeval start = timeval_current();
556 0 : int ret;
557 2748 : WERROR werr = WERR_OK;
558 2748 : struct ldb_message *msg = NULL;
559 2748 : struct ldb_message_element *el = NULL;
560 2748 : const struct ldb_val *name = NULL;
561 :
562 2748 : *records = NULL;
563 2748 : *num_records = 0;
564 :
565 2748 : name = ldb_dn_get_rdn_val(dn);
566 2748 : 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 2748 : 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 2597 : werr = dns_name_check(
583 : mem_ctx,
584 2597 : strlen((const char*)name->data),
585 2597 : (const char*) name->data);
586 2597 : 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 2597 : werr = dns_common_lookup(samdb,
595 : mem_ctx,
596 : dn,
597 : records,
598 : num_records,
599 : NULL);
600 2597 : if (!W_ERROR_EQUAL(werr, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
601 2438 : 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 2748 : exit:
628 2748 : 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 2748 : 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 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 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 13478 : WERROR dns_name_check(TALLOC_CTX *mem_ctx, size_t len, const char *name)
666 : {
667 17 : size_t i;
668 13478 : unsigned int labels = 0;
669 13478 : unsigned int label_len = 0;
670 :
671 13478 : if (len == 0) {
672 38 : return WERR_DS_INVALID_DN_SYNTAX;
673 : }
674 :
675 13440 : if (len > 1 && name[0] == '.') {
676 120 : return WERR_DS_INVALID_DN_SYNTAX;
677 : }
678 :
679 13320 : if ((len - 1) > DNS_MAX_DOMAIN_LENGTH) {
680 0 : return WERR_DS_INVALID_DN_SYNTAX;
681 : }
682 :
683 373295 : for (i = 0; i < len - 1; i++) {
684 360015 : if (name[i] == '.' && name[i+1] == '.') {
685 40 : return WERR_DS_INVALID_DN_SYNTAX;
686 : }
687 359975 : if (name[i] == '.') {
688 38050 : labels++;
689 38050 : if (labels > DNS_MAX_LABELS) {
690 0 : return WERR_DS_INVALID_DN_SYNTAX;
691 : }
692 38001 : label_len = 0;
693 : } else {
694 321925 : label_len++;
695 321925 : if (label_len > DNS_MAX_LABEL_LENGTH) {
696 0 : return WERR_DS_INVALID_DN_SYNTAX;
697 : }
698 : }
699 : }
700 :
701 13280 : 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) {
1038 19 : DBG_ERR("tombstone record has %u neighbour "
1039 : "records.\n",
1040 : rec_count - 1);
1041 : }
1042 26 : was_tombstoned = true;
1043 : }
1044 201 : continue;
1045 : }
1046 :
1047 4434 : if (zoneinfo->fAging == 1 && records[i].dwTimeStamp != 0) {
1048 658 : t = unix_to_dns_timestamp(time(NULL));
1049 658 : if (t - records[i].dwTimeStamp >
1050 658 : zoneinfo->dwNoRefreshInterval) {
1051 130 : records[i].dwTimeStamp = t;
1052 : }
1053 : }
1054 :
1055 4434 : records[i].dwSerial = serial;
1056 4434 : ndr_err = ndr_push_struct_blob(v, el->values, &records[i],
1057 : (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
1058 4434 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1059 0 : DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n"));
1060 0 : werr = DNS_ERR(SERVER_FAILURE);
1061 0 : goto exit;
1062 : }
1063 4434 : el->num_values++;
1064 : }
1065 :
1066 2114 : if (needs_add) {
1067 : /*
1068 : * This is a new dnsNode, which simplifies everything as we
1069 : * know there is nothing to delete or change. We add the
1070 : * records and get out.
1071 : */
1072 318 : if (el->num_values == 0) {
1073 28 : werr = WERR_OK;
1074 28 : goto exit;
1075 : }
1076 :
1077 290 : ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
1078 290 : if (ret != LDB_SUCCESS) {
1079 0 : werr = DNS_ERR(SERVER_FAILURE);
1080 0 : goto exit;
1081 : }
1082 :
1083 290 : ret = ldb_add(samdb, msg);
1084 290 : if (ret != LDB_SUCCESS) {
1085 0 : werr = DNS_ERR(SERVER_FAILURE);
1086 0 : goto exit;
1087 : }
1088 :
1089 290 : werr = WERR_OK;
1090 290 : goto exit;
1091 : }
1092 :
1093 1796 : if (el->num_values == 0) {
1094 : /*
1095 : * We get here if there are no records or all the records were
1096 : * tombstones.
1097 : */
1098 26 : struct dnsp_DnssrvRpcRecord tbs;
1099 811 : struct ldb_val *v = &el->values[el->num_values];
1100 26 : enum ndr_err_code ndr_err;
1101 26 : struct timeval tv;
1102 :
1103 811 : if (was_tombstoned) {
1104 : /*
1105 : * This is already a tombstoned object.
1106 : * Just leave it instead of updating the time stamp.
1107 : */
1108 7 : werr = WERR_OK;
1109 7 : goto exit;
1110 : }
1111 :
1112 804 : tv = timeval_current();
1113 830 : tbs = (struct dnsp_DnssrvRpcRecord) {
1114 : .wType = DNS_TYPE_TOMBSTONE,
1115 : .dwSerial = serial,
1116 804 : .data.EntombedTime = timeval_to_nttime(&tv),
1117 : };
1118 :
1119 804 : ndr_err = ndr_push_struct_blob(v, el->values, &tbs,
1120 : (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
1121 804 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1122 0 : DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n"));
1123 0 : werr = DNS_ERR(SERVER_FAILURE);
1124 0 : goto exit;
1125 : }
1126 804 : el->num_values++;
1127 :
1128 804 : become_tombstoned = true;
1129 : }
1130 :
1131 1789 : if (was_tombstoned || become_tombstoned) {
1132 823 : ret = ldb_msg_append_fmt(msg, LDB_FLAG_MOD_REPLACE,
1133 : "dNSTombstoned", "%s",
1134 : become_tombstoned ? "TRUE" : "FALSE");
1135 823 : if (ret != LDB_SUCCESS) {
1136 0 : werr = DNS_ERR(SERVER_FAILURE);
1137 0 : goto exit;
1138 : }
1139 : }
1140 :
1141 1789 : ret = ldb_modify(samdb, msg);
1142 1789 : if (ret != LDB_SUCCESS) {
1143 2 : NTSTATUS nt = dsdb_ldb_err_to_ntstatus(ret);
1144 2 : werr = ntstatus_to_werror(nt);
1145 2 : goto exit;
1146 : }
1147 :
1148 1758 : werr = WERR_OK;
1149 2116 : exit:
1150 2116 : talloc_free(msg);
1151 2116 : DNS_COMMON_LOG_OPERATION(
1152 : win_errstr(werr),
1153 : &start,
1154 : NULL,
1155 : dn == NULL ? NULL : ldb_dn_get_linearized(dn),
1156 29 : NULL);
1157 2116 : return werr;
1158 : }
1159 :
1160 26899 : bool dns_name_match(const char *zone, const char *name, size_t *host_part_len)
1161 : {
1162 26899 : size_t zl = strlen(zone);
1163 26899 : size_t nl = strlen(name);
1164 20 : ssize_t zi, ni;
1165 20 : static const size_t fixup = 'a' - 'A';
1166 :
1167 26899 : if (zl > nl) {
1168 6992 : return false;
1169 : }
1170 :
1171 565671 : for (zi = zl, ni = nl; zi >= 0; zi--, ni--) {
1172 549054 : char zc = zone[zi];
1173 549054 : char nc = name[ni];
1174 :
1175 : /* convert to lower case */
1176 549054 : if (zc >= 'A' && zc <= 'Z') {
1177 2024 : zc += fixup;
1178 : }
1179 549054 : if (nc >= 'A' && nc <= 'Z') {
1180 52237 : nc += fixup;
1181 : }
1182 :
1183 549054 : if (zc != nc) {
1184 3280 : return false;
1185 : }
1186 : }
1187 :
1188 16617 : if (ni >= 0) {
1189 10951 : if (name[ni] != '.') {
1190 0 : return false;
1191 : }
1192 :
1193 10951 : ni--;
1194 : }
1195 :
1196 16617 : *host_part_len = ni+1;
1197 :
1198 16617 : return true;
1199 : }
1200 :
1201 8563 : WERROR dns_common_name2dn(struct ldb_context *samdb,
1202 : struct dns_server_zone *zones,
1203 : TALLOC_CTX *mem_ctx,
1204 : const char *name,
1205 : struct ldb_dn **_dn)
1206 : {
1207 10 : struct ldb_dn *base;
1208 10 : struct ldb_dn *dn;
1209 10 : const struct dns_server_zone *z;
1210 8563 : size_t host_part_len = 0;
1211 10 : struct ldb_val host_part;
1212 10 : WERROR werr;
1213 10 : bool ok;
1214 8563 : const char *casefold = NULL;
1215 :
1216 8563 : if (name == NULL) {
1217 0 : return DNS_ERR(FORMAT_ERROR);
1218 : }
1219 :
1220 8563 : if (strcmp(name, "") == 0) {
1221 0 : base = ldb_get_default_basedn(samdb);
1222 0 : dn = ldb_dn_copy(mem_ctx, base);
1223 0 : ok = ldb_dn_add_child_fmt(dn,
1224 : "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System");
1225 0 : if (ok == false) {
1226 0 : TALLOC_FREE(dn);
1227 0 : return WERR_NOT_ENOUGH_MEMORY;
1228 : }
1229 :
1230 0 : *_dn = dn;
1231 0 : return WERR_OK;
1232 : }
1233 :
1234 : /* Check non-empty names */
1235 8563 : werr = dns_name_check(mem_ctx, strlen(name), name);
1236 8563 : if (!W_ERROR_IS_OK(werr)) {
1237 0 : return werr;
1238 : }
1239 :
1240 14272 : for (z = zones; z != NULL; z = z->next) {
1241 20 : bool match;
1242 :
1243 14260 : match = dns_name_match(z->name, name, &host_part_len);
1244 14260 : if (match) {
1245 8541 : break;
1246 : }
1247 : }
1248 :
1249 8563 : if (z == NULL) {
1250 12 : return DNS_ERR(NAME_ERROR);
1251 : }
1252 :
1253 8551 : if (host_part_len == 0) {
1254 4046 : dn = ldb_dn_copy(mem_ctx, z->dn);
1255 4046 : ok = ldb_dn_add_child_fmt(dn, "DC=@");
1256 4046 : if (! ok) {
1257 0 : TALLOC_FREE(dn);
1258 0 : return WERR_NOT_ENOUGH_MEMORY;
1259 : }
1260 4046 : *_dn = dn;
1261 4046 : return WERR_OK;
1262 : }
1263 :
1264 4505 : dn = ldb_dn_copy(mem_ctx, z->dn);
1265 4505 : if (dn == NULL) {
1266 0 : TALLOC_FREE(dn);
1267 0 : return WERR_NOT_ENOUGH_MEMORY;
1268 : }
1269 :
1270 4505 : host_part = data_blob_const(name, host_part_len);
1271 :
1272 4505 : ok = ldb_dn_add_child_val(dn, "DC", host_part);
1273 :
1274 4505 : if (ok == false) {
1275 0 : TALLOC_FREE(dn);
1276 0 : return WERR_NOT_ENOUGH_MEMORY;
1277 : }
1278 :
1279 : /*
1280 : * Check the new DN here for validity, so as to catch errors
1281 : * early
1282 : */
1283 4505 : ok = ldb_dn_validate(dn);
1284 4505 : if (ok == false) {
1285 0 : TALLOC_FREE(dn);
1286 0 : return DNS_ERR(NAME_ERROR);
1287 : }
1288 :
1289 : /*
1290 : * The value from this check is saved in the DN, and doing
1291 : * this here allows an easy return here.
1292 : */
1293 4505 : casefold = ldb_dn_get_casefold(dn);
1294 4505 : if (casefold == NULL) {
1295 0 : TALLOC_FREE(dn);
1296 0 : return DNS_ERR(NAME_ERROR);
1297 : }
1298 :
1299 4505 : *_dn = dn;
1300 4505 : return WERR_OK;
1301 : }
1302 :
1303 :
1304 : /*
1305 : see if two dns records match
1306 : */
1307 :
1308 :
1309 9091 : bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1,
1310 : struct dnsp_DnssrvRpcRecord *rec2)
1311 : {
1312 0 : int i;
1313 0 : struct in6_addr rec1_in_addr6;
1314 0 : struct in6_addr rec2_in_addr6;
1315 :
1316 9091 : if (rec1->wType != rec2->wType) {
1317 1900 : return false;
1318 : }
1319 :
1320 : /* see if the data matches */
1321 7191 : switch (rec1->wType) {
1322 2047 : case DNS_TYPE_A:
1323 2047 : return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
1324 1243 : case DNS_TYPE_AAAA: {
1325 0 : int ret;
1326 :
1327 1243 : ret = inet_pton(AF_INET6, rec1->data.ipv6, &rec1_in_addr6);
1328 1243 : if (ret != 1) {
1329 0 : return false;
1330 : }
1331 1243 : ret = inet_pton(AF_INET6, rec2->data.ipv6, &rec2_in_addr6);
1332 1243 : if (ret != 1) {
1333 0 : return false;
1334 : }
1335 :
1336 1243 : return memcmp(&rec1_in_addr6, &rec2_in_addr6, sizeof(rec1_in_addr6)) == 0;
1337 : }
1338 210 : case DNS_TYPE_CNAME:
1339 210 : return samba_dns_name_equal(rec1->data.cname,
1340 : rec2->data.cname);
1341 1966 : case DNS_TYPE_TXT:
1342 1966 : if (rec1->data.txt.count != rec2->data.txt.count) {
1343 234 : return false;
1344 : }
1345 3013 : for (i = 0; i < rec1->data.txt.count; i++) {
1346 2008 : if (strcmp(rec1->data.txt.str[i], rec2->data.txt.str[i]) != 0) {
1347 727 : return false;
1348 : }
1349 : }
1350 1005 : return true;
1351 276 : case DNS_TYPE_PTR:
1352 276 : return samba_dns_name_equal(rec1->data.ptr, rec2->data.ptr);
1353 271 : case DNS_TYPE_NS:
1354 271 : return samba_dns_name_equal(rec1->data.ns, rec2->data.ns);
1355 :
1356 935 : case DNS_TYPE_SRV:
1357 1831 : return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
1358 896 : rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
1359 2690 : rec1->data.srv.wPort == rec2->data.srv.wPort &&
1360 859 : samba_dns_name_equal(rec1->data.srv.nameTarget,
1361 : rec2->data.srv.nameTarget);
1362 :
1363 243 : case DNS_TYPE_MX:
1364 474 : return rec1->data.mx.wPriority == rec2->data.mx.wPriority &&
1365 231 : samba_dns_name_equal(rec1->data.mx.nameTarget,
1366 : rec2->data.mx.nameTarget);
1367 :
1368 0 : case DNS_TYPE_SOA:
1369 0 : return samba_dns_name_equal(rec1->data.soa.mname,
1370 0 : rec2->data.soa.mname) &&
1371 0 : samba_dns_name_equal(rec1->data.soa.rname,
1372 0 : rec2->data.soa.rname) &&
1373 0 : rec1->data.soa.serial == rec2->data.soa.serial &&
1374 0 : rec1->data.soa.refresh == rec2->data.soa.refresh &&
1375 0 : rec1->data.soa.retry == rec2->data.soa.retry &&
1376 0 : rec1->data.soa.expire == rec2->data.soa.expire &&
1377 0 : rec1->data.soa.minimum == rec2->data.soa.minimum;
1378 0 : case DNS_TYPE_TOMBSTONE:
1379 0 : return true;
1380 0 : default:
1381 0 : break;
1382 : }
1383 :
1384 0 : return false;
1385 : }
1386 :
1387 :
1388 12719 : static int dns_common_sort_zones(struct ldb_message **m1, struct ldb_message **m2)
1389 : {
1390 70 : const char *n1, *n2;
1391 70 : size_t l1, l2;
1392 :
1393 12719 : n1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
1394 12719 : n2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
1395 12719 : if (n1 == NULL || n2 == NULL) {
1396 0 : if (n1 != NULL) {
1397 0 : return -1;
1398 0 : } else if (n2 != NULL) {
1399 0 : return 1;
1400 : } else {
1401 0 : return 0;
1402 : }
1403 : }
1404 12719 : l1 = strlen(n1);
1405 12719 : l2 = strlen(n2);
1406 :
1407 : /* If the string lengths are not equal just sort by length */
1408 12719 : if (l1 != l2) {
1409 : /* If m1 is the larger zone name, return it first */
1410 10811 : return l2 - l1;
1411 : }
1412 :
1413 : /*TODO: We need to compare DNs here, we want the DomainDNSZones first */
1414 1894 : return 0;
1415 : }
1416 :
1417 1969 : NTSTATUS dns_common_zones(struct ldb_context *samdb,
1418 : TALLOC_CTX *mem_ctx,
1419 : struct ldb_dn *base_dn,
1420 : struct dns_server_zone **zones_ret)
1421 : {
1422 1969 : const struct timeval start = timeval_current();
1423 14 : int ret;
1424 14 : static const char * const attrs[] = { "name", NULL};
1425 14 : struct ldb_result *res;
1426 14 : int i;
1427 1969 : struct dns_server_zone *new_list = NULL;
1428 1969 : TALLOC_CTX *frame = talloc_stackframe();
1429 1969 : NTSTATUS result = NT_STATUS_OK;
1430 :
1431 1969 : if (base_dn) {
1432 : /* This search will work against windows */
1433 93 : ret = dsdb_search(samdb, frame, &res,
1434 : base_dn, LDB_SCOPE_SUBTREE,
1435 : attrs, 0, "(objectClass=dnsZone)");
1436 : } else {
1437 : /* TODO: this search does not work against windows */
1438 1876 : ret = dsdb_search(samdb, frame, &res, NULL,
1439 : LDB_SCOPE_SUBTREE,
1440 : attrs,
1441 : DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
1442 : "(objectClass=dnsZone)");
1443 : }
1444 1969 : if (ret != LDB_SUCCESS) {
1445 0 : TALLOC_FREE(frame);
1446 0 : result = NT_STATUS_INTERNAL_DB_CORRUPTION;
1447 0 : goto exit;
1448 : }
1449 :
1450 1969 : TYPESAFE_QSORT(res->msgs, res->count, dns_common_sort_zones);
1451 :
1452 10850 : for (i=0; i < res->count; i++) {
1453 56 : struct dns_server_zone *z;
1454 :
1455 8881 : z = talloc_zero(mem_ctx, struct dns_server_zone);
1456 8881 : if (z == NULL) {
1457 0 : TALLOC_FREE(frame);
1458 0 : result = NT_STATUS_NO_MEMORY;
1459 0 : goto exit;
1460 : }
1461 :
1462 8881 : z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
1463 8881 : talloc_steal(z, z->name);
1464 8881 : z->dn = talloc_move(z, &res->msgs[i]->dn);
1465 : /*
1466 : * Ignore the RootDNSServers zone and zones that we don't support yet
1467 : * RootDNSServers should never be returned (Windows DNS server don't)
1468 : * ..TrustAnchors should never be returned as is, (Windows returns
1469 : * TrustAnchors) and for the moment we don't support DNSSEC so we'd better
1470 : * not return this zone.
1471 : */
1472 8881 : if ((strcmp(z->name, "RootDNSServers") == 0) ||
1473 5085 : (strcmp(z->name, "..TrustAnchors") == 0))
1474 : {
1475 3796 : DEBUG(10, ("Ignoring zone %s\n", z->name));
1476 3796 : talloc_free(z);
1477 3796 : continue;
1478 : }
1479 5113 : DLIST_ADD_END(new_list, z);
1480 : }
1481 :
1482 1969 : *zones_ret = new_list;
1483 1969 : TALLOC_FREE(frame);
1484 1955 : result = NT_STATUS_OK;
1485 1969 : exit:
1486 1969 : DNS_COMMON_LOG_OPERATION(
1487 : nt_errstr(result),
1488 : &start,
1489 : NULL,
1490 : base_dn == NULL ? NULL : ldb_dn_get_linearized(base_dn),
1491 14 : NULL);
1492 1969 : return result;
1493 : }
1494 :
1495 : /*
1496 : see if two DNS names are the same
1497 : */
1498 27657 : bool samba_dns_name_equal(const char *name1, const char *name2)
1499 : {
1500 27657 : size_t len1 = strlen(name1);
1501 27657 : size_t len2 = strlen(name2);
1502 :
1503 27657 : if (len1 > 0 && name1[len1 - 1] == '.') {
1504 2750 : len1--;
1505 : }
1506 27657 : if (len2 > 0 && name2[len2 - 1] == '.') {
1507 6003 : len2--;
1508 : }
1509 27657 : if (len1 != len2) {
1510 15768 : return false;
1511 : }
1512 11889 : return strncasecmp(name1, name2, len1) == 0;
1513 : }
1514 :
1515 :
1516 : /*
1517 : * Convert unix time to a DNS timestamp
1518 : * uint32 hours in the NTTIME epoch
1519 : *
1520 : * This uses unix_to_nt_time() which can return special flag NTTIMEs like
1521 : * UINT64_MAX (0xFFF...) or NTTIME_MAX (0x7FF...), which will convert to
1522 : * distant future timestamps; or 0 as a flag value, meaning a 1601 timestamp,
1523 : * which is used to indicate a record does not expire.
1524 : *
1525 : * As we don't generally check for these special values in NTTIME conversions,
1526 : * we also don't check here, but for the benefit of people encountering these
1527 : * timestamps and searching for their origin, here is a list:
1528 : *
1529 : ** TIME_T_MAX
1530 : *
1531 : * Even if time_t is 32 bit, this will become NTTIME_MAX (a.k.a INT64_MAX,
1532 : * 0x7fffffffffffffff) in 100ns units. That translates to 256204778 hours
1533 : * since 1601, which converts back to 9223372008000000000 or
1534 : * 0x7ffffff9481f1000. It will present as 30828-09-14 02:00:00, around 48
1535 : * minutes earlier than NTTIME_MAX.
1536 : *
1537 : ** 0, the start of the unix epoch, 1970-01-01 00:00:00
1538 : *
1539 : * This is converted into 0 in the Windows epoch, 1601-01-01 00:00:00 which is
1540 : * clearly the same whether you count in 100ns units or hours. In DNS record
1541 : * timestamps this is a flag meaning the record will never expire.
1542 : *
1543 : ** (time_t)-1, such as what *might* mean 1969-12-31 23:59:59
1544 : *
1545 : * This becomes (NTTIME)-1ULL a.k.a. UINT64_MAX, 0xffffffffffffffff thence
1546 : * 512409557 in hours since 1601. That in turn is 0xfffffffaf2028800 or
1547 : * 18446744052000000000 in NTTIME (rounded to the hour), which might be
1548 : * presented as -21709551616 or -0x50dfd7800, because NTTIME is not completely
1549 : * dedicated to being unsigned. If it gets shown as a year, it will be around
1550 : * 60055.
1551 : *
1552 : ** Other negative time_t values (e.g. 1969-05-29).
1553 : *
1554 : * The meaning of these is somewhat undefined, but in any case they will
1555 : * translate perfectly well into the same dates in NTTIME.
1556 : *
1557 : ** Notes
1558 : *
1559 : * There are dns timestamps that exceed the range of NTTIME (up to 488356 AD),
1560 : * but it is not possible for this function to produce them.
1561 : *
1562 : * It is plausible that it was at midnight on 1601-01-01, in London, that
1563 : * Shakespeare wrote:
1564 : *
1565 : * The time is out of joint. O cursed spite
1566 : * That ever I was born to set it right!
1567 : *
1568 : * and this is why we have this epoch and time zone.
1569 : */
1570 1994 : uint32_t unix_to_dns_timestamp(time_t t)
1571 : {
1572 2 : NTTIME nt;
1573 1994 : unix_to_nt_time(&nt, t);
1574 1994 : nt /= NTTIME_TO_HOURS;
1575 1994 : return (uint32_t) nt;
1576 : }
1577 :
1578 : /*
1579 : * Convert a DNS timestamp into NTTIME.
1580 : *
1581 : * Because DNS timestamps cover a longer time period than NTTIME, and these
1582 : * would wrap to an arbitrary NTTIME, we saturate at NTTIME_MAX and return an
1583 : * error in this case.
1584 : */
1585 76 : NTSTATUS dns_timestamp_to_nt_time(NTTIME *_nt, uint32_t t)
1586 : {
1587 76 : NTTIME nt = t;
1588 76 : if (nt > NTTIME_MAX / NTTIME_TO_HOURS) {
1589 2 : *_nt = NTTIME_MAX;
1590 2 : return NT_STATUS_INTEGER_OVERFLOW;
1591 : }
1592 74 : *_nt = nt * NTTIME_TO_HOURS;
1593 74 : return NT_STATUS_OK;
1594 : }
|