diff options
author | Stefan Metzmacher <metze@samba.org> | 2014-07-31 10:44:41 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2014-08-26 09:13:06 +0200 |
commit | bb3ca930cc57964487bd23a74f4caabd1616a8bf (patch) | |
tree | 602a3475c44ee10aca47e055df61ff79115db29a /source4/dns_server/dnsserver_common.c | |
parent | a0a81ab01cb1d509b04f9af25177c8e0941b43aa (diff) | |
download | samba-bb3ca930cc57964487bd23a74f4caabd1616a8bf.tar.gz |
s4:dns_server: add DNS_TYPE_TOMBSTONE support to dns_common_replace()
Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749
Pair-Programmed-With: Michael Adam <obnox@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Michael Adam <obnox@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'source4/dns_server/dnsserver_common.c')
-rw-r--r-- | source4/dns_server/dnsserver_common.c | 81 |
1 files changed, 77 insertions, 4 deletions
diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index 28667343471..c49d6ec87a6 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -190,6 +190,22 @@ WERROR dns_common_lookup(struct ldb_context *samdb, return WERR_OK; } +static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1, + const struct dnsp_DnssrvRpcRecord *r2) +{ + if (r1->wType != r2->wType) { + /* + * The records are sorted with higher types first + */ + return r2->wType - r1->wType; + } + + /* + * Then we need to sort from the oldest to newest timestamp + */ + return r1->dwTimeStamp - r2->dwTimeStamp; +} + WERROR dns_common_replace(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, @@ -202,6 +218,8 @@ WERROR dns_common_replace(struct ldb_context *samdb, uint16_t i; int ret; struct ldb_message *msg = NULL; + bool was_tombstoned = false; + bool become_tombstoned = false; msg = ldb_msg_new(mem_ctx); W_ERROR_HAVE_NO_MEMORY(msg); @@ -213,17 +231,30 @@ WERROR dns_common_replace(struct ldb_context *samdb, return DNS_ERR(SERVER_FAILURE); } - el->values = talloc_zero_array(el, struct ldb_val, rec_count); + /* + * we have at least one value, + * which might be used for the tombstone marker + */ + el->values = talloc_zero_array(el, struct ldb_val, MAX(1, rec_count)); if (rec_count > 0) { W_ERROR_HAVE_NO_MEMORY(el->values); + + /* + * We store a sorted list with the high wType values first + * that's what windows does. It also simplifies the + * filtering of DNS_TYPE_TOMBSTONE records + */ + TYPESAFE_QSORT(records, rec_count, rec_cmp); } for (i = 0; i < rec_count; i++) { - static const struct dnsp_DnssrvRpcRecord zero; struct ldb_val *v = &el->values[el->num_values]; enum ndr_err_code ndr_err; - if (memcmp(&records[i], &zero, sizeof(zero)) == 0) { + if (records[i].wType == DNS_TYPE_TOMBSTONE) { + if (records[i].data.timestamp != 0) { + was_tombstoned = true; + } continue; } @@ -256,7 +287,49 @@ WERROR dns_common_replace(struct ldb_context *samdb, } if (el->num_values == 0) { - el->flags = LDB_FLAG_MOD_DELETE; + struct dnsp_DnssrvRpcRecord tbs; + struct ldb_val *v = &el->values[el->num_values]; + enum ndr_err_code ndr_err; + struct timeval tv; + + if (was_tombstoned) { + /* + * This is already a tombstoned object. + * Just leave it instead of updating the time stamp. + */ + return WERR_OK; + } + + tv = timeval_current(); + tbs = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + .dwSerial = serial, + .data.timestamp = timeval_to_nttime(&tv), + }; + + ndr_err = ndr_push_struct_blob(v, el->values, &tbs, + (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n")); + return DNS_ERR(SERVER_FAILURE); + } + el->num_values++; + + become_tombstoned = true; + } + + if (was_tombstoned || become_tombstoned) { + ret = ldb_msg_add_empty(msg, "dNSTombstoned", + LDB_FLAG_MOD_REPLACE, NULL); + if (ret != LDB_SUCCESS) { + return DNS_ERR(SERVER_FAILURE); + } + + ret = ldb_msg_add_fmt(msg, "dNSTombstoned", "%s", + become_tombstoned ? "TRUE" : "FALSE"); + if (ret != LDB_SUCCESS) { + return DNS_ERR(SERVER_FAILURE); + } } ret = ldb_modify(samdb, msg); |