1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-10 01:18:15 +03:00

dns_server: Avoid ldb_dn_add_child_fmt() on untrusted input

By using the new ldb_dn_add_child_val() we ensure that the user-controlled values are
not parsed as DN seperators.

Additionally, the casefold DN is obtained before the search to trigger
a full parse of the DN before being handled to the LDB search.

This is not normally required but is done here due to the nature
of the untrusted input.

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

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
This commit is contained in:
Andrew Bartlett 2018-08-15 10:44:03 +12:00
parent aa01203ff5
commit 28e2a518ff
4 changed files with 172 additions and 22 deletions

View File

@ -776,8 +776,11 @@ static isc_result_t b9_find_zone_dn(struct dlz_bind9_data *state, const char *zo
int i;
for (i=0; zone_prefixes[i]; i++) {
const char *casefold;
struct ldb_dn *dn;
struct ldb_result *res;
struct ldb_val zone_name_val
= data_blob_string_const(zone_name);
dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
if (dn == NULL) {
@ -785,11 +788,40 @@ static isc_result_t b9_find_zone_dn(struct dlz_bind9_data *state, const char *zo
return ISC_R_NOMEMORY;
}
if (!ldb_dn_add_child_fmt(dn, "DC=%s,%s", zone_name, zone_prefixes[i])) {
/*
* This dance ensures that it is not possible to put
* (eg) an extra DC=x, into the DNS name being
* queried
*/
if (!ldb_dn_add_child_fmt(dn,
"DC=X,%s",
zone_prefixes[i])) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
ret = ldb_dn_set_component(dn,
0,
"DC",
zone_name_val);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
/*
* Check if this is a plausibly valid DN early
* (time spent here will be saved during the
* search due to an internal cache)
*/
casefold = ldb_dn_get_casefold(dn);
if (casefold == NULL) {
talloc_free(tmp_ctx);
return ISC_R_NOTFOUND;
}
ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsZone");
if (ret == LDB_SUCCESS) {
if (zone_dn != NULL) {
@ -820,19 +852,42 @@ static isc_result_t b9_find_name_dn(struct dlz_bind9_data *state, const char *na
isc_result_t result;
result = b9_find_zone_dn(state, p, mem_ctx, dn);
if (result == ISC_R_SUCCESS) {
const char *casefold;
/* we found a zone, now extend the DN to get
* the full DN
*/
bool ret;
if (p == name) {
ret = ldb_dn_add_child_fmt(*dn, "DC=@");
if (ret == false) {
talloc_free(*dn);
return ISC_R_NOMEMORY;
}
} else {
ret = ldb_dn_add_child_fmt(*dn, "DC=%.*s", (int)(p-name)-1, name);
struct ldb_val name_val
= data_blob_const(name,
(int)(p-name)-1);
if (!ldb_dn_add_child_val(*dn,
"DC",
name_val)) {
talloc_free(*dn);
return ISC_R_NOMEMORY;
}
}
if (!ret) {
talloc_free(*dn);
return ISC_R_NOMEMORY;
/*
* Check if this is a plausibly valid DN early
* (time spent here will be saved during the
* search due to an internal cache)
*/
casefold = ldb_dn_get_casefold(*dn);
if (casefold == NULL) {
return ISC_R_NOTFOUND;
}
return ISC_R_SUCCESS;
}
p = strchr(p, '.');
@ -874,19 +929,63 @@ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state,
WERROR werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
struct dnsp_DnssrvRpcRecord *records = NULL;
uint16_t num_records = 0, i;
struct ldb_val zone_name_val
= data_blob_string_const(zone);
struct ldb_val name_val
= data_blob_string_const(name);
for (i=0; zone_prefixes[i]; i++) {
int ret;
const char *casefold;
dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
if (dn == NULL) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
if (!ldb_dn_add_child_fmt(dn, "DC=%s,DC=%s,%s", name, zone, zone_prefixes[i])) {
/*
* This dance ensures that it is not possible to put
* (eg) an extra DC=x, into the DNS name being
* queried
*/
if (!ldb_dn_add_child_fmt(dn,
"DC=X,DC=X,%s",
zone_prefixes[i])) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
ret = ldb_dn_set_component(dn,
1,
"DC",
zone_name_val);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
ret = ldb_dn_set_component(dn,
0,
"DC",
name_val);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
/*
* Check if this is a plausibly valid DN early
* (time spent here will be saved during the
* search due to an internal cache)
*/
casefold = ldb_dn_get_casefold(dn);
if (casefold == NULL) {
talloc_free(tmp_ctx);
return ISC_R_NOTFOUND;
}
werr = dns_common_wildcard_lookup(state->samdb, tmp_ctx, dn,
&records, &num_records);
if (W_ERROR_IS_OK(werr)) {
@ -953,19 +1052,50 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata,
struct ldb_dn *dn;
struct ldb_result *res;
TALLOC_CTX *tmp_ctx = talloc_new(state);
struct ldb_val zone_name_val = data_blob_string_const(zone);
for (i=0; zone_prefixes[i]; i++) {
const char *casefold;
dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
if (dn == NULL) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
if (!ldb_dn_add_child_fmt(dn, "DC=%s,%s", zone, zone_prefixes[i])) {
/*
* This dance ensures that it is not possible to put
* (eg) an extra DC=x, into the DNS name being
* queried
*/
if (!ldb_dn_add_child_fmt(dn,
"DC=X,%s",
zone_prefixes[i])) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
ret = ldb_dn_set_component(dn,
0,
"DC",
zone_name_val);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ISC_R_NOMEMORY;
}
/*
* Check if this is a plausibly valid DN early
* (time spent here will be saved during the
* search due to an internal cache)
*/
casefold = ldb_dn_get_casefold(dn);
if (casefold == NULL) {
return ISC_R_NOTFOUND;
}
ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
attrs, "objectClass=dnsNode");
if (ret == LDB_SUCCESS) {
@ -1118,8 +1248,18 @@ static bool b9_has_soa(struct dlz_bind9_data *state, struct ldb_dn *dn, const ch
WERROR werr;
struct dnsp_DnssrvRpcRecord *records = NULL;
uint16_t num_records = 0, i;
struct ldb_val zone_name_val
= data_blob_string_const(zone);
if (!ldb_dn_add_child_fmt(dn, "DC=@,DC=%s", zone)) {
/*
* This dance ensures that it is not possible to put
* (eg) an extra DC=x, into the DNS name being
* queried
*/
if (!ldb_dn_add_child_val(dn,
"DC",
zone_name_val)) {
talloc_free(tmp_ctx);
return false;
}

View File

@ -1059,7 +1059,6 @@ WERROR dns_common_name2dn(struct ldb_context *samdb,
struct ldb_val host_part;
WERROR werr;
bool ok;
int ret;
const char *casefold = NULL;
if (name == NULL) {
@ -1116,17 +1115,11 @@ WERROR dns_common_name2dn(struct ldb_context *samdb,
return WERR_NOT_ENOUGH_MEMORY;
}
ok = ldb_dn_add_child_fmt(dn, "DC=X");
if (ok == false) {
TALLOC_FREE(dn);
return WERR_NOT_ENOUGH_MEMORY;
}
host_part = data_blob_const(name, host_part_len);
ret = ldb_dn_set_component(dn, 0, "DC", host_part);
if (ret != LDB_SUCCESS) {
ok = ldb_dn_add_child_val(dn, "DC", host_part);
if (ok == false) {
TALLOC_FREE(dn);
return WERR_NOT_ENOUGH_MEMORY;
}

View File

@ -383,6 +383,7 @@ WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
struct ldb_result *res;
struct ldb_dn *dn;
char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
struct ldb_val name_val = data_blob_string_const(name);
int ret;
ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
@ -400,7 +401,7 @@ WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
dn = ldb_dn_copy(mem_ctx, z->zone_dn);
W_ERROR_HAVE_NO_MEMORY(dn);
if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
return WERR_NOT_ENOUGH_MEMORY;
}
@ -1018,6 +1019,7 @@ WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
struct dnsp_DnssrvRpcRecord *dns_rec;
struct dnsp_soa soa;
char *tmpstr, *server_fqdn, *soa_email;
struct ldb_val name_val = data_blob_string_const(zone->name);
/* We only support primary zones for now */
if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
@ -1043,7 +1045,12 @@ WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
if(!ldb_dn_add_child_fmt(dn, "DC=%s,CN=MicrosoftDNS", zone->name)) {
if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
talloc_free(tmp_ctx);
return WERR_NOT_ENOUGH_MEMORY;
}
if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
talloc_free(tmp_ctx);
return WERR_NOT_ENOUGH_MEMORY;
}

View File

@ -371,6 +371,8 @@ struct ldb_dn *dnsserver_name_to_dn(TALLOC_CTX *mem_ctx, struct dnsserver_zone *
{
struct ldb_dn *dn;
bool ret;
struct ldb_val name_val =
data_blob_string_const(name);
dn = ldb_dn_copy(mem_ctx, z->zone_dn);
if (dn == NULL) {
@ -378,9 +380,17 @@ struct ldb_dn *dnsserver_name_to_dn(TALLOC_CTX *mem_ctx, struct dnsserver_zone *
}
if (strcasecmp(name, z->name) == 0) {
ret = ldb_dn_add_child_fmt(dn, "DC=@");
} else {
ret = ldb_dn_add_child_fmt(dn, "DC=%s", name);
if (!ret) {
talloc_free(dn);
return NULL;
}
return dn;
}
ret = ldb_dn_add_child_val(dn,
"DC",
name_val);
if (!ret) {
talloc_free(dn);
return NULL;