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:
parent
418cd93f4c
commit
00002b8df9
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
@ -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\)
|
||||
|
@ -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\)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user