X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Fdns_server%2Fdns_server.c;h=3e18287bfa1b8747c29d6bd852bee9a0f3bf8ec5;hb=4fb29e9347271acd66833d471a84e39a525f4f18;hp=d9851b1566927f382675507025b0a5b8debaf557;hpb=53f602c3744c0952f3385a39d5984d5a47b9905c;p=obnox%2Fsamba%2Fsamba-obnox.git diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c index d9851b15669..3e18287bfa1 100644 --- a/source4/dns_server/dns_server.c +++ b/source4/dns_server/dns_server.c @@ -45,6 +45,11 @@ #include "lib/util/tevent_werror.h" #include "auth/auth.h" #include "auth/credentials/credentials.h" +#include "librpc/gen_ndr/ndr_irpc.h" +#include "lib/messaging/irpc.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_DNS NTSTATUS server_service_dns_init(void); @@ -117,11 +122,12 @@ static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx, struct dns_process_state *state; enum ndr_err_code ndr_err; WERROR ret; - + const char *forwarder = lpcfg_dns_forwarder(dns->task->lp_ctx); req = tevent_req_create(mem_ctx, &state, struct dns_process_state); if (req == NULL) { return NULL; } + state->state.mem_ctx = state; state->in = in; state->dns = dns; @@ -130,7 +136,7 @@ static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx, tevent_req_werror(req, WERR_INVALID_PARAM); return tevent_req_post(req, ev); } - dump_data(8, in->data, in->length); + dump_data_dbgc(DBGC_DNS, 8, in->data, in->length); ndr_err = ndr_pull_struct_blob( in, state, &state->in_packet, @@ -141,22 +147,29 @@ static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx, tevent_req_done(req); return tevent_req_post(req, ev); } - if (DEBUGLVL(8)) { - NDR_PRINT_DEBUG(dns_name_packet, &state->in_packet); + if (DEBUGLVLC(DBGC_DNS, 8)) { + NDR_PRINT_DEBUGC(DBGC_DNS, dns_name_packet, &state->in_packet); } ret = dns_verify_tsig(dns, state, &state->state, &state->in_packet, in); if (!W_ERROR_IS_OK(ret)) { - DEBUG(0, ("Bailing out early!\n")); + DEBUG(1, ("Failed to verify TSIG!\n")); state->dns_err = werr_to_dns_err(ret); tevent_req_done(req); return tevent_req_post(req, ev); } + if (state->in_packet.operation & DNS_FLAG_REPLY) { + DEBUG(1, ("Won't reply to replies.\n")); + tevent_req_werror(req, WERR_INVALID_PARAM); + return tevent_req_post(req, ev); + } + state->state.flags = state->in_packet.operation; state->state.flags |= DNS_FLAG_REPLY; - if (lpcfg_dns_recursive_queries(dns->task->lp_ctx)) { + + if (forwarder && *forwarder) { state->state.flags |= DNS_FLAG_RECURSION_AVAIL; } @@ -235,6 +248,10 @@ static WERROR dns_process_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, } } + if (DEBUGLVLC(DBGC_DNS, 8)) { + NDR_PRINT_DEBUGC(DBGC_DNS, dns_name_packet, &state->out_packet); + } + ndr_err = ndr_push_struct_blob( out, mem_ctx, &state->out_packet, (ndr_push_flags_fn_t)ndr_push_dns_name_packet); @@ -565,10 +582,9 @@ static void dns_udp_call_sendto_done(struct tevent_req *subreq) { struct dns_udp_call *call = tevent_req_callback_data(subreq, struct dns_udp_call); - ssize_t ret; int sys_errno; - ret = tdgram_sendto_queue_recv(subreq, &sys_errno); + tdgram_sendto_queue_recv(subreq, &sys_errno); /* We don't care about errors */ @@ -650,7 +666,7 @@ static NTSTATUS dns_add_socket(struct dns_server *dns, /* setup our listening sockets on the configured network interfaces */ -static NTSTATUS dns_startup_interfaces(struct dns_server *dns, struct loadparm_context *lp_ctx, +static NTSTATUS dns_startup_interfaces(struct dns_server *dns, struct interface *ifaces) { const struct model_ops *model_ops; @@ -668,13 +684,36 @@ static NTSTATUS dns_startup_interfaces(struct dns_server *dns, struct loadparm_c return NT_STATUS_INTERNAL_ERROR; } - num_interfaces = iface_list_count(ifaces); + if (ifaces != NULL) { + num_interfaces = iface_list_count(ifaces); - for (i=0; isamdb, dns, &res, NULL, LDB_SCOPE_SUBTREE, + attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, "(objectClass=dnsZone)"); + if (ret != LDB_SUCCESS) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + TYPESAFE_QSORT(res->msgs, res->count, dns_server_sort_zones); + + for (i=0; i < res->count; i++) { + struct dns_server_zone *z; + + z = talloc_zero(dns, struct dns_server_zone); + if (z == NULL) { + return NT_STATUS_NO_MEMORY; + } + + z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL); + z->dn = talloc_move(z, &res->msgs[i]->dn); + /* + * Ignore the RootDNSServers zone and zones that we don't support yet + * RootDNSServers should never be returned (Windows DNS server don't) + * ..TrustAnchors should never be returned as is, (Windows returns + * TrustAnchors) and for the moment we don't support DNSSEC so we'd better + * not return this zone. + */ + if ((strcmp(z->name, "RootDNSServers") == 0) || + (strcmp(z->name, "..TrustAnchors") == 0)) + { + DEBUG(10, ("Ignoring zone %s\n", z->name)); + talloc_free(z); + continue; + } + DLIST_ADD_END(new_list, z, NULL); + } + + old_list = dns->zones; + dns->zones = new_list; + while ((old_zone = DLIST_TAIL(old_list)) != NULL) { + DLIST_REMOVE(old_list, old_zone); + talloc_free(old_zone); + } + + return NT_STATUS_OK; +} + +/** + * Called when the internal DNS server should reload the zones from DB, for + * example, when zones are added or deleted through RPC or replicated by + * inbound DRS. + */ +static NTSTATUS dns_reload_zones(struct irpc_message *msg, + struct dnssrv_reload_dns_zones *r) +{ + struct dns_server *dns; + + dns = talloc_get_type(msg->private_data, struct dns_server); + if (dns == NULL) { + r->out.result = NT_STATUS_INTERNAL_ERROR; + return NT_STATUS_INTERNAL_ERROR; + } + + r->out.result = dns_server_reload_zones(dns); + + return NT_STATUS_OK; +} + static void dns_task_init(struct task_server *task) { struct dns_server *dns; NTSTATUS status; - struct interface *ifaces; + struct interface *ifaces = NULL; int ret; - struct ldb_result *res; - static const char * const attrs[] = { "name", NULL}; - unsigned int i; + static const char * const attrs_none[] = { NULL}; + struct ldb_message *dns_acc; + char *hostname_lower; + char *dns_spn; switch (lpcfg_server_role(task->lp_ctx)) { case ROLE_STANDALONE: @@ -746,11 +863,13 @@ static void dns_task_init(struct task_server *task) break; } - load_interface_list(task, task->lp_ctx, &ifaces); + if (lpcfg_interfaces(task->lp_ctx) && lpcfg_bind_interfaces_only(task->lp_ctx)) { + load_interface_list(task, task->lp_ctx, &ifaces); - if (iface_list_count(ifaces) == 0) { - task_server_terminate(task, "dns: no network interfaces configured", false); - return; + if (iface_list_count(ifaces) == 0) { + task_server_terminate(task, "dns: no network interfaces configured", false); + return; + } } task_server_set_title(task, "task[dns]"); @@ -762,6 +881,8 @@ static void dns_task_init(struct task_server *task) } dns->task = task; + /*FIXME: Make this a configurable option */ + dns->max_payload = 4096; dns->server_credentials = cli_credentials_init(dns); if (!dns->server_credentials) { @@ -769,57 +890,81 @@ static void dns_task_init(struct task_server *task) return; } - cli_credentials_set_conf(dns->server_credentials, task->lp_ctx); - status = cli_credentials_set_machine_account(dns->server_credentials, task->lp_ctx); - if (!NT_STATUS_IS_OK(status)) { - task_server_terminate(task, - talloc_asprintf(task, "Failed to obtain server credentials, perhaps a standalone server?: %s\n", - nt_errstr(status)), - true); + dns->samdb = samdb_connect(dns, dns->task->event_ctx, dns->task->lp_ctx, + system_session(dns->task->lp_ctx), 0); + if (!dns->samdb) { + task_server_terminate(task, "dns: samdb_connect failed", true); return; } + cli_credentials_set_conf(dns->server_credentials, task->lp_ctx); + + hostname_lower = strlower_talloc(dns, lpcfg_netbios_name(task->lp_ctx)); + dns_spn = talloc_asprintf(dns, "DNS/%s.%s", + hostname_lower, + lpcfg_dnsdomain(task->lp_ctx)); + TALLOC_FREE(hostname_lower); + + ret = dsdb_search_one(dns->samdb, dns, &dns_acc, + ldb_get_default_basedn(dns->samdb), LDB_SCOPE_SUBTREE, + attrs_none, 0, "(servicePrincipalName=%s)", + dns_spn); + if (ret == LDB_SUCCESS) { + TALLOC_FREE(dns_acc); + if (!dns_spn) { + task_server_terminate(task, "dns: talloc_asprintf failed", true); + return; + } + status = cli_credentials_set_stored_principal(dns->server_credentials, task->lp_ctx, dns_spn); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, + talloc_asprintf(task, "Failed to obtain server credentials for DNS, " + "despite finding it in the samdb! %s\n", + nt_errstr(status)), + true); + return; + } + } else { + TALLOC_FREE(dns_spn); + status = cli_credentials_set_machine_account(dns->server_credentials, task->lp_ctx); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, + talloc_asprintf(task, "Failed to obtain server credentials, perhaps a standalone server?: %s\n", + nt_errstr(status)), + true); + return; + } + } + dns->tkeys = tkey_store_init(dns, TKEY_BUFFER_SIZE); if (!dns->tkeys) { task_server_terminate(task, "Failed to allocate tkey storage\n", true); return; } - dns->samdb = samdb_connect(dns, dns->task->event_ctx, dns->task->lp_ctx, - system_session(dns->task->lp_ctx), 0); - if (!dns->samdb) { - task_server_terminate(task, "dns: samdb_connect failed", true); + status = dns_server_reload_zones(dns); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, "dns: failed to load DNS zones", true); return; } - // TODO: this search does not work against windows - ret = dsdb_search(dns->samdb, dns, &res, NULL, LDB_SCOPE_SUBTREE, - attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, "(objectClass=dnsZone)"); - if (ret != LDB_SUCCESS) { - task_server_terminate(task, - "dns: failed to look up root DNS zones", - true); + status = dns_startup_interfaces(dns, ifaces); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, "dns failed to setup interfaces", true); return; } - TYPESAFE_QSORT(res->msgs, res->count, dns_server_sort_zones); - - for (i=0; i < res->count; i++) { - struct dns_server_zone *z; - - z = talloc_zero(dns, struct dns_server_zone); - if (z == NULL) { - } - - z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL); - z->dn = talloc_move(z, &res->msgs[i]->dn); - - DLIST_ADD_END(dns->zones, z, NULL); + /* Setup the IRPC interface and register handlers */ + status = irpc_add_name(task->msg_ctx, "dnssrv"); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, "dns: failed to register IRPC name", true); + return; } - status = dns_startup_interfaces(dns, task->lp_ctx, ifaces); + status = IRPC_REGISTER(task->msg_ctx, irpc, DNSSRV_RELOAD_DNS_ZONES, + dns_reload_zones, dns); if (!NT_STATUS_IS_OK(status)) { - task_server_terminate(task, "dns failed to setup interfaces", true); + task_server_terminate(task, "dns: failed to setup reload handler", true); return; } }