X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Fdns_server%2Fdlz_bind9.c;h=d43b40478a6ee95b6146a49759265b78856e6cee;hb=faa3423d1a26eb6103389b234add0f1e8d0dfc08;hp=c3c4172a1732857a6f1490f585ecc88147ef3d76;hpb=f52afa955ecdf856b730a0855bf001293fdd8f0c;p=samba.git diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index c3c4172a173..d43b40478a6 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -36,14 +36,20 @@ #include "gen_ndr/server_id.h" #include "messaging/messaging.h" #include "lib/cmdline/popt_common.h" +#include "lib/util/dlinklist.h" #include "dlz_minimal.h" - +#include "dns_server/dnsserver_common.h" struct b9_options { const char *url; const char *debug; }; +struct b9_zone { + char *name; + struct b9_zone *prev, *next; +}; + struct dlz_bind9_data { struct b9_options options; struct ldb_context *samdb; @@ -51,6 +57,7 @@ struct dlz_bind9_data { struct loadparm_context *lp; int *transaction_token; uint32_t soa_serial; + struct b9_zone *zonelist; /* Used for dynamic update */ struct smb_krb5_context *smb_krb5_ctx; @@ -203,7 +210,7 @@ static bool b9_format(struct dlz_bind9_data *state, } default: - state->log(ISC_LOG_ERROR, "samba b9_putrr: unhandled record type %u", + state->log(ISC_LOG_ERROR, "samba_dlz b9_format: unhandled record type %u", rec->wType); return false; } @@ -372,14 +379,15 @@ static bool b9_parse(struct dlz_bind9_data *state, break; default: - state->log(ISC_LOG_ERROR, "samba b9_parse: unhandled record type %u", + state->log(ISC_LOG_ERROR, "samba_dlz b9_parse: unhandled record type %u", rec->wType); return false; } /* we should be at the end of the buffer now */ if (strtok_r(NULL, "\t ", &saveptr) != NULL) { - state->log(ISC_LOG_ERROR, "samba b9_parse: expected data at end of string for '%s'"); + state->log(ISC_LOG_ERROR, "samba_dlz b9_parse: unexpected data at end of string for '%s'", + rdatastr); return false; } @@ -387,7 +395,7 @@ static bool b9_parse(struct dlz_bind9_data *state, } /* - send a resource recond to bind9 + send a resource record to bind9 */ static isc_result_t b9_putrr(struct dlz_bind9_data *state, void *handle, struct dnsp_DnssrvRpcRecord *rec, @@ -427,7 +435,7 @@ static isc_result_t b9_putrr(struct dlz_bind9_data *state, /* - send a named resource recond to bind9 + send a named resource record to bind9 */ static isc_result_t b9_putnamedrr(struct dlz_bind9_data *state, void *handle, const char *name, @@ -458,7 +466,7 @@ static isc_result_t b9_putnamedrr(struct dlz_bind9_data *state, parse options */ static isc_result_t parse_options(struct dlz_bind9_data *state, - unsigned int argc, char *argv[], + unsigned int argc, const char **argv, struct b9_options *options) { int opt; @@ -469,7 +477,7 @@ static isc_result_t parse_options(struct dlz_bind9_data *state, { NULL } }; - pc = poptGetContext("dlz_bind9", argc, (const char **)argv, long_options, + pc = poptGetContext("dlz_bind9", argc, argv, long_options, POPT_CONTEXT_KEEP_FIRST); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { @@ -563,7 +571,7 @@ static int dlz_state_debug_unregister(struct dlz_bind9_data *state) called to initialise the driver */ _PUBLIC_ isc_result_t dlz_create(const char *dlzname, - unsigned int argc, char *argv[], + unsigned int argc, const char **argv, void **dbdata, ...) { struct dlz_bind9_data *state; @@ -622,7 +630,7 @@ _PUBLIC_ isc_result_t dlz_create(const char *dlzname, lpcfg_do_global_parameter(state->lp, "log level", "0"); } - if (smb_krb5_init_context(state, state->ev_ctx, state->lp, &state->smb_krb5_ctx) != 0) { + if (smb_krb5_init_context(state, state->lp, &state->smb_krb5_ctx) != 0) { result = ISC_R_NOMEMORY; goto failed; } @@ -784,7 +792,13 @@ static isc_result_t b9_find_name_dn(struct dlz_bind9_data *state, const char *na /* see if we handle a given zone */ +#if DLZ_DLOPEN_VERSION < 3 _PUBLIC_ isc_result_t dlz_findzonedb(void *dbdata, const char *name) +#else +_PUBLIC_ isc_result_t dlz_findzonedb(void *dbdata, const char *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) +#endif { struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data); return b9_find_zone_dn(state, name, NULL, NULL); @@ -800,11 +814,10 @@ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state, const char **types) { TALLOC_CTX *tmp_ctx = talloc_new(state); - const char *attrs[] = { "dnsRecord", NULL }; - int ret = LDB_SUCCESS, i; - struct ldb_result *res; - struct ldb_message_element *el; struct ldb_dn *dn; + WERROR werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST; + struct dnsp_DnssrvRpcRecord *records = NULL; + uint16_t num_records = 0, i; for (i=0; zone_prefixes[i]; i++) { dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb)); @@ -818,38 +831,21 @@ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state, return ISC_R_NOMEMORY; } - ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, - attrs, "objectClass=dnsNode"); - if (ret == LDB_SUCCESS) { + werr = dns_common_lookup(state->samdb, tmp_ctx, dn, + &records, &num_records, NULL); + if (W_ERROR_IS_OK(werr)) { break; } } - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ISC_R_NOTFOUND; - } - - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL || el->num_values == 0) { + if (!W_ERROR_IS_OK(werr)) { talloc_free(tmp_ctx); return ISC_R_NOTFOUND; } - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec; - enum ndr_err_code ndr_err; + for (i=0; i < num_records; i++) { isc_result_t result; - ndr_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(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(tmp_ctx); - return ISC_R_FAILURE; - } - - result = b9_putrr(state, lookup, &rec, types); + result = b9_putrr(state, lookup, &records[i], types); if (result != ISC_R_SUCCESS) { talloc_free(tmp_ctx); return result; @@ -863,7 +859,7 @@ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state, /* lookup one record */ -#ifdef BIND_VERSION_9_8 +#if DLZ_DLOPEN_VERSION == 1 _PUBLIC_ isc_result_t dlz_lookup(const char *zone, const char *name, void *dbdata, dns_sdlzlookup_t *lookup) #else @@ -884,7 +880,9 @@ _PUBLIC_ isc_result_t dlz_lookup(const char *zone, const char *name, _PUBLIC_ isc_result_t dlz_allowzonexfr(void *dbdata, const char *name, const char *client) { /* just say yes for all our zones for now */ - return dlz_findzonedb(dbdata, name); + struct dlz_bind9_data *state = talloc_get_type( + dbdata, struct dlz_bind9_data); + return b9_find_zone_dn(state, name, NULL, NULL); } /* @@ -928,6 +926,9 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata, TALLOC_CTX *el_ctx = talloc_new(tmp_ctx); const char *rdn, *name; const struct ldb_val *v; + WERROR werr; + struct dnsp_DnssrvRpcRecord *recs = NULL; + uint16_t num_recs = 0; el = ldb_msg_find_element(res->msgs[i], "dnsRecord"); if (el == NULL || el->num_values == 0) { @@ -961,24 +962,24 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata, return ISC_R_NOMEMORY; } - for (j=0; jnum_values; j++) { - struct dnsp_DnssrvRpcRecord rec; - enum ndr_err_code ndr_err; - isc_result_t result; + werr = dns_common_extract(el, el_ctx, &recs, &num_recs); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); + talloc_free(el_ctx); + continue; + } - ndr_err = ndr_pull_struct_blob(&el->values[j], el_ctx, &rec, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - continue; - } + for (j=0; j < num_recs; j++) { + isc_result_t result; - result = b9_putnamedrr(state, allnodes, name, &rec); + result = b9_putnamedrr(state, allnodes, name, &recs[j]); if (result != ISC_R_SUCCESS) { continue; } } + + talloc_free(el_ctx); } talloc_free(tmp_ctx); @@ -1056,39 +1057,25 @@ _PUBLIC_ void dlz_closeversion(const char *zone, isc_boolean_t commit, */ static bool b9_has_soa(struct dlz_bind9_data *state, struct ldb_dn *dn, const char *zone) { - const char *attrs[] = { "dnsRecord", NULL }; - struct ldb_result *res; - struct ldb_message_element *el; TALLOC_CTX *tmp_ctx = talloc_new(state); - int ret, i; + WERROR werr; + struct dnsp_DnssrvRpcRecord *records = NULL; + uint16_t num_records = 0, i; if (!ldb_dn_add_child_fmt(dn, "DC=@,DC=%s", zone)) { talloc_free(tmp_ctx); return false; } - ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, - attrs, "objectClass=dnsNode"); - if (ret != LDB_SUCCESS) { + werr = dns_common_lookup(state->samdb, tmp_ctx, dn, + &records, &num_records, NULL); + if (!W_ERROR_IS_OK(werr)) { talloc_free(tmp_ctx); return false; } - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL) { - talloc_free(tmp_ctx); - return false; - } - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec; - enum ndr_err_code ndr_err; - - ndr_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(ndr_err)) { - continue; - } - if (rec.wType == DNS_TYPE_SOA) { + for (i=0; i < num_records; i++) { + if (records[i].wType == DNS_TYPE_SOA) { talloc_free(tmp_ctx); return true; } @@ -1098,10 +1085,51 @@ static bool b9_has_soa(struct dlz_bind9_data *state, struct ldb_dn *dn, const ch return false; } +static bool b9_zone_add(struct dlz_bind9_data *state, const char *name) +{ + struct b9_zone *zone; + + zone = talloc_zero(state, struct b9_zone); + if (zone == NULL) { + return false; + } + + zone->name = talloc_strdup(zone, name); + if (zone->name == NULL) { + talloc_free(zone); + return false; + } + + DLIST_ADD(state->zonelist, zone); + return true; +} + +static bool b9_zone_exists(struct dlz_bind9_data *state, const char *name) +{ + struct b9_zone *zone = state->zonelist; + bool found = false; + + while (zone != NULL) { + if (strcasecmp(name, zone->name) == 0) { + found = true; + break; + } + zone = zone->next; + } + + return found; +} + + /* configure a writeable zone */ +#if DLZ_DLOPEN_VERSION < 3 _PUBLIC_ isc_result_t dlz_configure(dns_view_t *view, void *dbdata) +#else +_PUBLIC_ isc_result_t dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb, + void *dbdata) +#endif { struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data); TALLOC_CTX *tmp_ctx; @@ -1146,6 +1174,11 @@ _PUBLIC_ isc_result_t dlz_configure(dns_view_t *view, void *dbdata) if (zone == NULL) { continue; } + /* Ignore zones that are not handled in BIND */ + if ((strcmp(zone, "RootDNSServers") == 0) || + (strcmp(zone, "..TrustAnchors") == 0)) { + continue; + } zone_dn = ldb_dn_copy(tmp_ctx, dn); if (zone_dn == NULL) { talloc_free(tmp_ctx); @@ -1155,7 +1188,23 @@ _PUBLIC_ isc_result_t dlz_configure(dns_view_t *view, void *dbdata) if (!b9_has_soa(state, zone_dn, zone)) { continue; } + + if (b9_zone_exists(state, zone)) { + state->log(ISC_LOG_WARNING, "samba_dlz: Ignoring duplicate zone '%s' from '%s'", + zone, ldb_dn_get_linearized(zone_dn)); + continue; + } + + if (!b9_zone_add(state, zone)) { + talloc_free(tmp_ctx); + return ISC_R_NOMEMORY; + } + +#if DLZ_DLOPEN_VERSION < 3 result = state->writeable_zone(view, zone); +#else + result = state->writeable_zone(view, dlzdb, zone); +#endif if (result != ISC_R_SUCCESS) { state->log(ISC_LOG_ERROR, "samba_dlz: Failed to configure zone '%s'", zone); @@ -1250,7 +1299,7 @@ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const return ISC_FALSE; } - nt_status = gensec_update(gensec_ctx, tmp_ctx, state->ev_ctx, ap_req, &ap_req); + nt_status = gensec_update_ev(gensec_ctx, tmp_ctx, state->ev_ctx, ap_req, &ap_req); if (!NT_STATUS_IS_OK(nt_status)) { state->log(ISC_LOG_ERROR, "samba_dlz: spnego update failed"); talloc_free(tmp_ctx); @@ -1315,46 +1364,6 @@ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const return ISC_TRUE; } - -/* - add a new record - */ -static isc_result_t b9_add_record(struct dlz_bind9_data *state, const char *name, - struct ldb_dn *dn, - struct dnsp_DnssrvRpcRecord *rec) -{ - struct ldb_message *msg; - enum ndr_err_code ndr_err; - struct ldb_val v; - int ret; - - msg = ldb_msg_new(rec); - if (msg == NULL) { - return ISC_R_NOMEMORY; - } - msg->dn = dn; - ret = ldb_msg_add_string(msg, "objectClass", "dnsNode"); - if (ret != LDB_SUCCESS) { - return ISC_R_FAILURE; - } - - ndr_err = ndr_push_struct_blob(&v, rec, rec, (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ISC_R_FAILURE; - } - ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL); - if (ret != LDB_SUCCESS) { - return ISC_R_FAILURE; - } - - ret = ldb_add(state->samdb, msg); - if (ret != LDB_SUCCESS) { - return ISC_R_FAILURE; - } - - return ISC_R_SUCCESS; -} - /* see if two DNS names are the same */ @@ -1379,6 +1388,8 @@ static bool b9_record_match(struct dlz_bind9_data *state, { bool status; int i; + struct in6_addr rec1_in_addr6; + struct in6_addr rec2_in_addr6; if (rec1->wType != rec2->wType) { return false; @@ -1393,7 +1404,9 @@ static bool b9_record_match(struct dlz_bind9_data *state, case DNS_TYPE_A: return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0; case DNS_TYPE_AAAA: - return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0; + inet_pton(AF_INET6, rec1->data.ipv6, &rec1_in_addr6); + inet_pton(AF_INET6, rec2->data.ipv6, &rec2_in_addr6); + return memcmp(&rec1_in_addr6, &rec2_in_addr6, sizeof(rec1_in_addr6)) == 0; case DNS_TYPE_CNAME: return dns_name_equal(rec1->data.cname, rec2->data.cname); case DNS_TYPE_TXT: @@ -1431,7 +1444,7 @@ static bool b9_record_match(struct dlz_bind9_data *state, rec1->data.soa.expire == rec2->data.soa.expire && rec1->data.soa.minimum == rec2->data.soa.minimum; default: - state->log(ISC_LOG_ERROR, "samba b9_putrr: unhandled record type %u", + state->log(ISC_LOG_ERROR, "samba_dlz b9_record_match: unhandled record type %u", rec1->wType); break; } @@ -1451,7 +1464,7 @@ static bool b9_set_session_info(struct dlz_bind9_data *state, const char *name) return false; } - /* Do not use client credentials, if we not updating the client specified name */ + /* Do not use client credentials, if we're not updating the client specified name */ if (strcmp(state->update_name, name) != 0) { return true; } @@ -1482,12 +1495,14 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo struct dnsp_DnssrvRpcRecord *rec; struct ldb_dn *dn; isc_result_t result; - struct ldb_result *res; - const char *attrs[] = { "dnsRecord", NULL }; - int ret, i; - struct ldb_message_element *el; - enum ndr_err_code ndr_err; + bool tombstoned = false; + bool needs_add = false; + struct dnsp_DnssrvRpcRecord *recs = NULL; + uint16_t num_recs = 0; + uint16_t first = 0; + uint16_t i; NTTIME t; + WERROR werr; if (state->transaction_token != (void*)version) { state->log(ISC_LOG_INFO, "samba_dlz: bad transaction version"); @@ -1504,7 +1519,6 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo t /= 3600; /* convert to hours */ rec->rank = DNS_RANK_ZONE; - rec->dwSerial = state->soa_serial; rec->dwTimeStamp = (uint32_t)t; if (!b9_parse(state, rdatastr, rec)) { @@ -1521,70 +1535,55 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo } /* get any existing records */ - ret = ldb_search(state->samdb, rec, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - if (!b9_set_session_info(state, name)) { - talloc_free(rec); - return ISC_R_FAILURE; - } - result = b9_add_record(state, name, dn, rec); - b9_reset_session_info(state); + werr = dns_common_lookup(state->samdb, rec, dn, + &recs, &num_recs, &tombstoned); + if (W_ERROR_EQUAL(werr, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) { + needs_add = true; + werr = WERR_OK; + } + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(rec); - if (result == ISC_R_SUCCESS) { - state->log(ISC_LOG_INFO, "samba_dlz: added %s %s", name, rdatastr); - } - return result; + return ISC_R_FAILURE; } - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL) { - ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", LDB_FLAG_MOD_ADD, &el); - if (ret != LDB_SUCCESS) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to add dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; - } + if (tombstoned) { + /* + * we need to keep the existing tombstone record + * and ignore it + */ + first = num_recs; } /* there are existing records. We need to see if this will * replace a record or add to it */ - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec2; - - ndr_err = ndr_pull_struct_blob(&el->values[i], rec, &rec2, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; - } - - if (b9_record_match(state, rec, &rec2)) { + for (i=first; i < num_recs; i++) { + if (b9_record_match(state, rec, &recs[i])) { break; } } - if (i == el->num_values) { + if (i == UINT16_MAX) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to already %u dnsRecord values for %s", + i, ldb_dn_get_linearized(dn)); + talloc_free(rec); + return ISC_R_FAILURE; + } + + if (i == num_recs) { /* adding a new value */ - el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1); - if (el->values == NULL) { + recs = talloc_realloc(rec, recs, + struct dnsp_DnssrvRpcRecord, + num_recs + 1); + if (recs == NULL) { talloc_free(rec); return ISC_R_NOMEMORY; } - el->num_values++; - } - - ndr_err = ndr_push_struct_blob(&el->values[i], rec, rec, - (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to push dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; + num_recs++; } + recs[i] = *rec; if (!b9_set_session_info(state, name)) { talloc_free(rec); @@ -1592,12 +1591,15 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo } /* modify the record */ - el->flags = LDB_FLAG_MOD_REPLACE; - ret = ldb_modify(state->samdb, res->msgs[0]); + werr = dns_common_replace(state->samdb, rec, dn, + needs_add, + state->soa_serial, + recs, num_recs); b9_reset_session_info(state); - if (ret != LDB_SUCCESS) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s", - ldb_dn_get_linearized(dn), ldb_errstring(state->samdb)); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to %s %s - %s", + needs_add ? "add" : "modify", + ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(rec); return ISC_R_FAILURE; } @@ -1617,11 +1619,10 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo struct dnsp_DnssrvRpcRecord *rec; struct ldb_dn *dn; isc_result_t result; - struct ldb_result *res; - const char *attrs[] = { "dnsRecord", NULL }; - int ret, i; - struct ldb_message_element *el; - enum ndr_err_code ndr_err; + struct dnsp_DnssrvRpcRecord *recs = NULL; + uint16_t num_recs = 0; + uint16_t i; + WERROR werr; if (state->transaction_token != (void*)version) { state->log(ISC_LOG_ERROR, "samba_dlz: bad transaction version"); @@ -1647,64 +1648,40 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo } /* get the existing records */ - ret = ldb_search(state->samdb, rec, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { + werr = dns_common_lookup(state->samdb, rec, dn, + &recs, &num_recs, NULL); + if (!W_ERROR_IS_OK(werr)) { talloc_free(rec); return ISC_R_NOTFOUND; } - /* there are existing records. We need to see if any match - */ - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL || el->num_values == 0) { - state->log(ISC_LOG_ERROR, "samba_dlz: no dnsRecord attribute for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; - } - - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec2; - - ndr_err = ndr_pull_struct_blob(&el->values[i], rec, &rec2, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; - } - - if (b9_record_match(state, rec, &rec2)) { + for (i=0; i < num_recs; i++) { + if (b9_record_match(state, rec, &recs[i])) { + recs[i] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; break; } } - if (i == el->num_values) { + if (i == num_recs) { talloc_free(rec); return ISC_R_NOTFOUND; } - if (i < el->num_values-1) { - memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i)); - } - el->num_values--; - if (!b9_set_session_info(state, name)) { talloc_free(rec); return ISC_R_FAILURE; } - if (el->num_values == 0) { - el->flags = LDB_FLAG_MOD_DELETE; - } else { - el->flags = LDB_FLAG_MOD_REPLACE; - } - ret = ldb_modify(state->samdb, res->msgs[0]); - + /* modify the record */ + werr = dns_common_replace(state->samdb, rec, dn, + false,/* needs_add */ + state->soa_serial, + recs, num_recs); b9_reset_session_info(state); - if (ret != LDB_SUCCESS) { + if (!W_ERROR_IS_OK(werr)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s", - ldb_dn_get_linearized(dn), ldb_errstring(state->samdb)); + ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(rec); return ISC_R_FAILURE; } @@ -1725,13 +1702,12 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * TALLOC_CTX *tmp_ctx; struct ldb_dn *dn; isc_result_t result; - struct ldb_result *res; - const char *attrs[] = { "dnsRecord", NULL }; - int ret, i; - struct ldb_message_element *el; - enum ndr_err_code ndr_err; enum dns_record_type dns_type; bool found = false; + struct dnsp_DnssrvRpcRecord *recs = NULL; + uint16_t num_recs = 0; + uint16_t ri = 0; + WERROR werr; if (state->transaction_token != (void*)version) { state->log(ISC_LOG_ERROR, "samba_dlz: bad transaction version"); @@ -1753,41 +1729,22 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * } /* get the existing records */ - ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { + werr = dns_common_lookup(state->samdb, tmp_ctx, dn, + &recs, &num_recs, NULL); + if (!W_ERROR_IS_OK(werr)) { talloc_free(tmp_ctx); return ISC_R_NOTFOUND; } - /* there are existing records. We need to see if any match the type - */ - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL || el->num_values == 0) { - talloc_free(tmp_ctx); - return ISC_R_NOTFOUND; - } - - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec2; - - ndr_err = ndr_pull_struct_blob(&el->values[i], tmp_ctx, &rec2, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(tmp_ctx); - return ISC_R_FAILURE; + for (ri=0; ri < num_recs; ri++) { + if (dns_type != recs[ri].wType) { + continue; } - if (dns_type == rec2.wType) { - if (i < el->num_values-1) { - memmove(&el->values[i], &el->values[i+1], - sizeof(el->values[0])*((el->num_values-1)-i)); - } - el->num_values--; - i--; - found = true; - } + found = true; + recs[ri] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; } if (!found) { @@ -1800,17 +1757,15 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * return ISC_R_FAILURE; } - if (el->num_values == 0) { - el->flags = LDB_FLAG_MOD_DELETE; - } else { - el->flags = LDB_FLAG_MOD_REPLACE; - } - ret = ldb_modify(state->samdb, res->msgs[0]); - + /* modify the record */ + werr = dns_common_replace(state->samdb, tmp_ctx, dn, + false,/* needs_add */ + state->soa_serial, + recs, num_recs); b9_reset_session_info(state); - if (ret != LDB_SUCCESS) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to delete type %s in %s - %s", - type, ldb_dn_get_linearized(dn), ldb_errstring(state->samdb)); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(tmp_ctx); return ISC_R_FAILURE; }