From c03c61d42b7ec73476e2c14618d9099b8f616b2f Mon Sep 17 00:00:00 2001 From: Lukas Oyen Date: Thu, 6 Apr 2017 10:39:02 +0200 Subject: [PATCH 2/2] dlz_bind9: escalate priviledges if machine name matches record --- source4/dns_server/dlz_bind9.c | 62 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index f7f8b86..cb160d4 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -63,6 +63,7 @@ struct dlz_bind9_data { struct smb_krb5_context *smb_krb5_ctx; struct auth4_context *auth_context; struct auth_session_info *session_info; + bool is_system_session; char *update_name; /* helper functions from the dlz_dlopen driver */ @@ -736,6 +737,9 @@ _PUBLIC_ void dlz_destroy(void *dbdata) dlz_bind9_state_ref_count--; if (dlz_bind9_state_ref_count == 0) { talloc_unlink(state, state->samdb); + if (state->is_system_session) { + state->session_info = NULL; + } talloc_free(state); dlz_bind9_state = NULL; } @@ -1268,6 +1272,37 @@ static bool b9_is_tombstoned(struct ldb_result *res) { return val != NULL; } +static char *b9_dn_fqdn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn) { + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + unsigned int i; + char *fqdn = NULL; + + for (i = 0; i < ldb_dn_get_comp_num(dn); i++) { + const char *name = ldb_dn_get_component_name(dn, i); + const struct ldb_val *value = ldb_dn_get_component_val(dn, i); + if (ldb_attr_cmp(name, "dc") != 0) { + break; + } + if (fqdn) { + fqdn = talloc_asprintf(tmp_ctx, "%s.%s", fqdn, + ldb_dn_escape_value(tmp_ctx, + *value)); + } else { + fqdn = ldb_dn_escape_value(tmp_ctx, *value); + } + if (!fqdn) { + break; + } + } + + if (fqdn != NULL) { + talloc_steal(mem_ctx, fqdn); + } + + talloc_free(tmp_ctx); + return fqdn; +} + /* authorize a zone update */ @@ -1285,6 +1320,7 @@ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const NTSTATUS nt_status; struct gensec_security *gensec_ctx; struct auth_session_info *session_info; + bool is_system_session = false; struct ldb_dn *dn; isc_result_t result; struct ldb_result *res; @@ -1294,7 +1330,10 @@ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const /* Remove cached credentials, if any */ if (state->session_info) { - talloc_free(state->session_info); + if (!state->is_system_session) { + talloc_free(state->session_info); + } + state->is_system_session = false; state->session_info = NULL; } if (state->update_name) { @@ -1412,6 +1451,20 @@ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const session_info->security_token, access_mask, NULL); } + /* Univention Specific: If a machine tries to access a forward/zone + * without the proper access-rights, but the FQDN as computed from the + * DN and the actual FQDN of the requesting machine match, a + * modification is allowed and the privileges for this operation are + * escalated to `SYSTEM`. + */ + if (ldb_ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + char *fqdn = b9_dn_fqdn(tmp_ctx, dn); + if (fqdn != NULL && strcmp(fqdn, name) == 0) { + session_info = system_session(state->lp); + is_system_session = true; + ldb_ret = LDB_SUCCESS; + } + } if (ldb_ret != LDB_SUCCESS) { state->log(ISC_LOG_INFO, "samba_dlz: disallowing update of signer=%s name=%s type=%s error=%s", @@ -1427,7 +1480,12 @@ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const talloc_free(tmp_ctx); return ISC_FALSE; } - state->session_info = talloc_steal(state, session_info); + state->is_system_session = is_system_session; + if (is_system_session) { + state->session_info = session_info; + } else { + state->session_info = talloc_steal(state, session_info); + } state->log(ISC_LOG_INFO, "samba_dlz: allowing update of signer=%s name=%s tcpaddr=%s type=%s key=%s", signer, name, tcpaddr, type, key); -- 2.7.4