#include "ldb_matching_rules.h"
#include "libcli/security/security.h"
#include "dsdb/common/util.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx,
struct ldb_context *ldb,
}
+/*
+ * This rule provides match of a dns object with expired records.
+ *
+ * This allows a search filter such as:
+ *
+ * dnsRecord:1.3.6.1.4.1.7165.4.5.3:=131139216000000000
+ *
+ * This allows the caller to find records that should become a DNS
+ * tomestone, despite that information being deep within an NDR packed
+ * object
+ */
+static int dsdb_match_for_dns_to_tombstone_time(struct ldb_context *ldb,
+ const char *oid,
+ const struct ldb_message *msg,
+ const char *attribute_to_match,
+ const struct ldb_val *value_to_match,
+ bool *matched)
+{
+ TALLOC_CTX *tmp_ctx;
+ unsigned int i;
+ struct ldb_message_element *el = NULL;
+ struct auth_session_info *session_info = NULL;
+ uint64_t tombstone_time;
+ struct dnsp_DnssrvRpcRecord *rec = NULL;
+ enum ndr_err_code err;
+ *matched = false;
+
+ /* Needs to be dnsRecord, no match otherwise */
+ if (ldb_attr_cmp(attribute_to_match, "dnsRecord") != 0) {
+ return LDB_SUCCESS;
+ }
+
+ el = ldb_msg_find_element(msg, attribute_to_match);
+ if (el == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"),
+ struct auth_session_info);
+ if (session_info == NULL) {
+ return ldb_oom(ldb);
+ }
+ if (security_session_user_level(session_info, NULL)
+ != SECURITY_SYSTEM) {
+
+ DBG_ERR("unauthorised access\n");
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ /* Just check we don't allow the caller to fill our stack */
+ if (value_to_match->length >= 64) {
+ DBG_ERR("Invalid timestamp passed\n");
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ } else {
+ char *p = NULL;
+ char s[value_to_match->length+1];
+ memcpy(s, value_to_match->data, value_to_match->length);
+ s[value_to_match->length] = 0;
+ if (s[0] == '\0' || s[0] == '-') {
+ DBG_ERR("Empty timestamp passed\n");
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ tombstone_time = strtoull(s, &p, 10);
+ if (p == NULL || p == s || *p != '\0' ||
+ tombstone_time == ULLONG_MAX) {
+ DBG_ERR("Invalid timestamp string passed\n");
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ rec = talloc_zero(tmp_ctx, struct dnsp_DnssrvRpcRecord);
+ if (rec == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+ err = ndr_pull_struct_blob(
+ &(el->values[i]),
+ tmp_ctx,
+ rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)){
+ DBG_ERR("Failed to pull dns rec blob.\n");
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (rec->wType == DNS_TYPE_SOA || rec->wType == DNS_TYPE_NS) {
+ TALLOC_FREE(tmp_ctx);
+ continue;
+ }
+
+ if (rec->wType == DNS_TYPE_TOMBSTONE) {
+ TALLOC_FREE(tmp_ctx);
+ continue;
+ }
+ if (rec->dwTimeStamp == 0) {
+ TALLOC_FREE(tmp_ctx);
+ continue;
+ }
+ if (rec->dwTimeStamp > tombstone_time) {
+ TALLOC_FREE(tmp_ctx);
+ continue;
+ }
+
+ *matched = true;
+ break;
+ }
+
+ TALLOC_FREE(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+
/*
* This rule provides match of a link attribute against a 'should be expunged' criteria
*
int ldb_register_samba_matching_rules(struct ldb_context *ldb)
{
struct ldb_extended_match_rule *transitive_eval = NULL,
- *match_for_expunge = NULL;
+ *match_for_expunge = NULL,
+ *match_for_dns_to_tombstone_time = NULL;
int ret;
transitive_eval = talloc_zero(ldb, struct ldb_extended_match_rule);
return ret;
}
+ match_for_dns_to_tombstone_time = talloc_zero(
+ ldb,
+ struct ldb_extended_match_rule);
+ match_for_dns_to_tombstone_time->oid = DSDB_MATCH_FOR_DNS_TO_TOMBSTONE_TIME;
+ match_for_dns_to_tombstone_time->callback
+ = dsdb_match_for_dns_to_tombstone_time;
+ ret = ldb_register_extended_match_rule(ldb,
+ match_for_dns_to_tombstone_time);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(match_for_dns_to_tombstone_time);
+ return ret;
+ }
+
return LDB_SUCCESS;
}
self.assertEqual(len(recs), 1)
self.assertEqual(recs[0].dwTimeStamp, 0)
+ def test_dns_tombstone_custom_match_rule(self):
+ name,txt = 'agingtest', ['test txt']
+ name2,txt2 = 'agingtest2', ['test txt2']
+ name3,txt3 = 'agingtest3', ['test txt3']
+ self.create_zone(self.zone, aging_enabled=True)
+ interval = 10
+ self.set_params(NoRefreshInterval=interval, RefreshInterval=interval,
+ Aging=1, zone=self.zone,
+ AllowUpdate = dnsp.DNS_ZONE_UPDATE_UNSECURE)
+
+ self.dns_update_record(name, txt),
+
+ self.dns_update_record(name2, txt),
+ self.dns_update_record(name2, txt2),
+
+ self.dns_update_record(name3, txt),
+ self.dns_update_record(name3, txt2),
+ last_update = self.dns_update_record(name3, txt3)
+
+ # Modify txt1 of the first 2 names
+ def mod_ts(rec):
+ if rec.data.str == txt:
+ rec.dwTimeStamp -= 2
+ self.ldap_modify_dnsrecs(name, mod_ts)
+ self.ldap_modify_dnsrecs(name2, mod_ts)
+
+ recs = self.ldap_get_dns_records(name3)
+ expr = "(dnsRecord:1.3.6.1.4.1.7165.4.5.3:={})"
+ expr = expr.format(int(last_update.dwTimeStamp)-1)
+ try:
+ res = self.samdb.search(base=self.zone_dn, scope=ldb.SCOPE_SUBTREE,
+ expression=expr, attrs=["*"])
+ except ldb.LdbError as e:
+ self.fail(str(e))
+ updated_names = {str(r.get('name')) for r in res}
+ self.assertEqual(updated_names, set([name, name2]))
+
+ def test_dns_tombstone_custom_match_rule_fail(self):
+ self.create_zone(self.zone, aging_enabled=True)
+
+ # The check here is that this does not blow up on silly input
+ expr = "(dnsProperty:1.3.6.1.4.1.7165.4.5.3:=1)"
+ res = self.samdb.search(base=self.zone_dn, scope=ldb.SCOPE_SUBTREE,
+ expression=expr, attrs=["*"])
+ self.assertEquals(len(res), 0)
+
def test_basic_scavenging(self):
self.create_zone(self.zone, aging_enabled=True)
interval = 1
samba.tests.dns.__main__.TestZones.test_aging_refresh\(rodc:local\)
samba.tests.dns.__main__.TestZones.test_rpc_add_no_timestamp\(rodc:local\)
samba.tests.dns.__main__.TestZones.test_basic_scavenging\(rodc:local\)
+samba.tests.dns.__main__.TestZones.test_dns_tombstone_custom_match_rule\(rodc:local\)
+samba.tests.dns.__main__.TestZones.test_dns_tombstone_custom_match_rule_fail\(rodc:local\)
samba.tests.dns.__main__.TestZones.test_set_aging\(vampire_dc:local\)
samba.tests.dns.__main__.TestZones.test_aging_update\(vampire_dc:local\)
samba.tests.dns.__main__.TestZones.test_aging_update_disabled\(vampire_dc:local\)
samba.tests.dns.__main__.TestZones.test_aging_refresh\(vampire_dc:local\)
samba.tests.dns.__main__.TestZones.test_basic_scavenging\(vampire_dc:local\)
+samba.tests.dns.__main__.TestZones.test_dns_tombstone_custom_match_rule\(vampire_dc:local\)
samba.tests.dns.__main__.TestComplexQueries.test_cname_two_chain\(vampire_dc:local\)
samba.tests.dns.__main__.TestComplexQueries.test_one_a_query\(vampire_dc:local\)