X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source4%2Fdns_server%2Fdns_server.c;h=9128c626cb9f1c59b7b0985705a758ca34814984;hb=87bf24407ab39941d7a827c982bbc13cd09e9321;hp=6b78b6d568eec1b690a05711a140411765f83812;hpb=f3e44c390c0082e585aec83372cdcdde19d76016;p=vlendec%2Fsamba-autobuild%2F.git diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c index 6b78b6d568e..9128c626cb9 100644 --- a/source4/dns_server/dns_server.c +++ b/source4/dns_server/dns_server.c @@ -45,8 +45,14 @@ #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" +#include "libds/common/roles.h" -NTSTATUS server_service_dns_init(void); +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_DNS + +NTSTATUS server_service_dns_init(TALLOC_CTX *); /* hold information about one dns socket */ struct dns_socket { @@ -111,26 +117,29 @@ static void dns_process_done(struct tevent_req *subreq); static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct dns_server *dns, + const struct tsocket_address *remote_address, + const struct tsocket_address *local_address, DATA_BLOB *in) { struct tevent_req *req, *subreq; 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; if (in->length < 12) { - tevent_req_werror(req, WERR_INVALID_PARAM); + tevent_req_werror(req, WERR_INVALID_PARAMETER); 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,31 +150,41 @@ 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); - if (!W_ERROR_IS_OK(ret)) { - DEBUG(0, ("Bailing out early!\n")); - state->dns_err = werr_to_dns_err(ret); - tevent_req_done(req); + if (state->in_packet.operation & DNS_FLAG_REPLY) { + DEBUG(1, ("Won't reply to replies.\n")); + tevent_req_werror(req, WERR_INVALID_PARAMETER); 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)) { + state->state.local_address = local_address; + state->state.remote_address = remote_address; + + if (forwarder && *forwarder && **forwarder) { state->state.flags |= DNS_FLAG_RECURSION_AVAIL; } state->out_packet = state->in_packet; + ret = dns_verify_tsig(dns, state, &state->state, + &state->out_packet, in); + if (!W_ERROR_IS_OK(ret)) { + state->dns_err = werr_to_dns_err(ret); + tevent_req_done(req); + return tevent_req_post(req, ev); + } + switch (state->in_packet.operation & DNS_OPCODE) { case DNS_OPCODE_QUERY: subreq = dns_server_process_query_send( - state, ev, dns, &state->state, &state->in_packet); + state, ev, dns, + &state->state, &state->in_packet); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -221,9 +240,15 @@ static WERROR dns_process_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, if (tevent_req_is_werror(req, &ret)) { return ret; } - if (state->dns_err != DNS_RCODE_OK) { + if ((state->dns_err != DNS_RCODE_OK) && + (state->dns_err != DNS_RCODE_NXDOMAIN) && + (state->dns_err != DNS_RCODE_NOTAUTH)) + { goto drop; } + if (state->dns_err != DNS_RCODE_OK) { + state->out_packet.operation |= state->dns_err; + } state->out_packet.operation |= state->state.flags; if (state->state.sign) { @@ -235,6 +260,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); @@ -249,7 +278,7 @@ static WERROR dns_process_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, drop: *out = data_blob_talloc(mem_ctx, state->in->data, state->in->length); if (out->data == NULL) { - return WERR_NOMEM; + return WERR_NOT_ENOUGH_MEMORY; } out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */ out->data[3] |= state->dns_err; @@ -310,6 +339,8 @@ static void dns_tcp_call_loop(struct tevent_req *subreq) call->in.length -= 2; subreq = dns_process_send(call, dns->task->event_ctx, dns, + dns_conn->conn->remote_address, + dns_conn->conn->local_address, &call->in); if (subreq == NULL) { dns_tcp_terminate_connection( @@ -511,6 +542,8 @@ static void dns_udp_call_loop(struct tevent_req *subreq) tsocket_address_string(call->src, call))); subreq = dns_process_send(call, dns->task->event_ctx, dns, + call->src, + sock->dns_socket->local_address, &call->in); if (subreq == NULL) { TALLOC_FREE(call); @@ -565,10 +598,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 */ @@ -610,7 +642,8 @@ static NTSTATUS dns_add_socket(struct dns_server *dns, &dns_tcp_stream_ops, "ip", address, &port, lpcfg_socket_options(dns->task->lp_ctx), - dns_socket); + dns_socket, + dns->task->process_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to bind to %s:%u TCP - %s\n", address, port, nt_errstr(status))); @@ -650,31 +683,45 @@ 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, - struct interface *ifaces) +static NTSTATUS dns_startup_interfaces(struct dns_server *dns, + struct interface *ifaces, + const struct model_ops *model_ops) { - const struct model_ops *model_ops; int num_interfaces; TALLOC_CTX *tmp_ctx = talloc_new(dns); NTSTATUS status; int i; - /* within the dns task we want to be a single process, so - ask for the single process model ops and pass these to the - stream_setup_socket() call. */ - model_ops = process_model_startup("single"); - if (!model_ops) { - DEBUG(0,("Can't find 'single' process model_ops\n")); - return NT_STATUS_INTERNAL_ERROR; - } + if (ifaces != NULL) { + num_interfaces = iface_list_count(ifaces); - num_interfaces = iface_list_count(ifaces); + for (i=0; isamdb, dns, NULL, &new_list); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + 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 +813,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]"); @@ -769,62 +838,90 @@ 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, task->model_ops); + 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; } } -NTSTATUS server_service_dns_init(void) +NTSTATUS server_service_dns_init(TALLOC_CTX *ctx) { - return register_server_service("dns", dns_task_init); + struct service_details details = { + .inhibit_fork_on_accept = true, + .inhibit_pre_fork = true, + }; + return register_server_service(ctx, "dns", dns_task_init, &details); }