1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-30 06:50:24 +03:00

dns: custom match rule for DNS records to be tombstoned

A custom match rule for records to be tombstoned by the scavenging process.
Needed because DNS records are a multi-valued attribute on name records, so
without a custom match rule we'd have entire zones into memory to search for
expired records.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=10812

Signed-off-by: Aaron Haslett <aaronhaslett@catalyst.net.nz>
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
Aaron Haslett 2018-07-02 13:48:06 +12:00 committed by Andrew Bartlett
parent 418cd93f4c
commit 00002b8df9
6 changed files with 187 additions and 1 deletions

View File

@ -26,6 +26,7 @@
#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,
@ -327,6 +328,125 @@ static int ldb_comparator_trans(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
*
@ -448,7 +568,8 @@ static int dsdb_match_for_expunge(struct ldb_context *ldb,
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);
@ -469,5 +590,18 @@ int ldb_register_samba_matching_rules(struct ldb_context *ldb)
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;
}

View File

@ -25,5 +25,6 @@
/* This rule provides recursive search of a link attribute */
#define SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL "1.2.840.113556.1.4.1941"
#define DSDB_MATCH_FOR_EXPUNGE "1.3.6.1.4.1.7165.4.5.2"
#define DSDB_MATCH_FOR_DNS_TO_TOMBSTONE_TIME "1.3.6.1.4.1.7165.4.5.3"
#endif /* _LDB_MATCHING_RULES_H_ */

View File

@ -1091,6 +1091,52 @@ class TestZones(DNSTest):
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

View File

@ -44,12 +44,15 @@ samba.tests.dns.__main__.TestZones.test_aging_update_disabled\(rodc:local\)
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\)

View File

@ -4,3 +4,4 @@
# Will be removed once the tests are implemented.
#
samba.tests.dns.__main__.TestZones.test_basic_scavenging\(fl2003dc:local\)
samba.tests.dns.__main__.TestZones.test_dns_tombstone_custom_match_rule\(fl2003dc:local\)

View File

@ -246,6 +246,7 @@
# ldap extended matches
#Allocated: SAMBA_LDAP_MATCH_ALWAYS_FALSE 1.3.6.1.4.1.7165.4.5.1
#Allocated: DSDB_MATCH_FOR_EXPUNGE 1.3.6.1.4.1.7165.4.5.2
#Allocated: DSDB_MATCH_FOR_DNS_TO_TOMBSTONE_TIME 1.3.6.1.4.1.7165.4.5.3
#Allocated: (middleName) attributeID: 1.3.6.1.4.1.7165.4.255.1