X-Git-Url: http://git.samba.org/samba.git/?p=sfrench%2Fsamba-autobuild%2F.git;a=blobdiff_plain;f=source4%2Fdns_server%2Fdns_server.c;h=a2dc15195bf7e8ddd6d6703b7bd34900e789289b;hp=25873c2bf4c8a6e7c45a6e11667ee687817d3be6;hb=773cfba9af34e64b96e843b1b60afa5a0b0dec32;hpb=02c9e18094f68d9014fe56c4d1b1c51fd22bd1b5 diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c index 25873c2bf4c..a2dc15195bf 100644 --- a/source4/dns_server/dns_server.c +++ b/source4/dns_server/dns_server.c @@ -42,6 +42,15 @@ #include "dsdb/common/util.h" #include "auth/session.h" #include "lib/util/dlinklist.h" +#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" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_DNS NTSTATUS server_service_dns_init(void); @@ -93,101 +102,180 @@ static void dns_tcp_send(struct stream_connection *conn, uint16_t flags) dns_tcp_terminate_connection(dnsconn, "dns_tcp_send: called"); } -static NTSTATUS dns_process(struct dns_server *dns, - TALLOC_CTX *mem_ctx, - DATA_BLOB *in, - DATA_BLOB *out) +struct dns_process_state { + DATA_BLOB *in; + struct dns_server *dns; + struct dns_name_packet in_packet; + struct dns_request_state state; + uint16_t dns_err; + struct dns_name_packet out_packet; + DATA_BLOB out; +}; + +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, + DATA_BLOB *in) { + struct tevent_req *req, *subreq; + struct dns_process_state *state; enum ndr_err_code ndr_err; WERROR ret; - struct dns_name_packet *in_packet; - struct dns_name_packet *out_packet; - struct dns_res_rec *answers = NULL, *nsrecs = NULL, *additional = NULL; - uint16_t num_answers = 0 , num_nsrecs = 0, num_additional = 0; - - if (in->length < 12) { - return NT_STATUS_INVALID_PARAMETER; + 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; - in_packet = talloc_zero(mem_ctx, struct dns_name_packet); - /* TODO: We don't really need an out_packet. */ - out_packet = talloc_zero(mem_ctx, struct dns_name_packet); + state->dns = dns; - if (in_packet == NULL) return NT_STATUS_NO_MEMORY; - if (out_packet == NULL) return NT_STATUS_NO_MEMORY; + if (in->length < 12) { + tevent_req_werror(req, WERR_INVALID_PARAM); + return tevent_req_post(req, ev); + } + dump_data_dbgc(DBGC_DNS, 8, in->data, in->length); - dump_data(2, in->data, in->length); + ndr_err = ndr_pull_struct_blob( + in, state, &state->in_packet, + (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet); - ndr_err = ndr_pull_struct_blob(in, in_packet, in_packet, - (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - TALLOC_FREE(in_packet); - DEBUG(0, ("Failed to parse packet %d!\n", ndr_err)); - *out = *in; - - out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */ - out->data[3] |= DNS_RCODE_FORMERR; + state->dns_err = DNS_RCODE_FORMERR; + tevent_req_done(req); + return tevent_req_post(req, ev); + } + if (DEBUGLVLC(DBGC_DNS, 8)) { + NDR_PRINT_DEBUGC(DBGC_DNS, dns_name_packet, &state->in_packet); + } - return NT_STATUS_OK; + ret = dns_verify_tsig(dns, state, &state->state, &state->in_packet, in); + if (!W_ERROR_IS_OK(ret)) { + 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 (DEBUGLVL(2)) { - NDR_PRINT_DEBUG(dns_name_packet, in_packet); + + 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); } - *out_packet = *in_packet; - out_packet->operation |= DNS_FLAG_REPLY; - switch (in_packet->operation & DNS_OPCODE) { - case DNS_OPCODE_QUERY: + state->state.flags = state->in_packet.operation; + state->state.flags |= DNS_FLAG_REPLY; + + + if (forwarder && *forwarder) { + state->state.flags |= DNS_FLAG_RECURSION_AVAIL; + } - ret = dns_server_process_query(dns, out_packet, in_packet, - &answers, &num_answers, - &nsrecs, &num_nsrecs, - &additional, &num_additional); + state->out_packet = state->in_packet; - break; + 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); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, dns_process_done, req); + return req; case DNS_OPCODE_UPDATE: - ret = dns_server_process_update(dns, out_packet, in_packet, - &answers, &num_answers, - &nsrecs, &num_nsrecs, - &additional, &num_additional); + ret = dns_server_process_update( + dns, &state->state, state, &state->in_packet, + &state->out_packet.answers, &state->out_packet.ancount, + &state->out_packet.nsrecs, &state->out_packet.nscount, + &state->out_packet.additional, + &state->out_packet.arcount); break; default: ret = WERR_DNS_ERROR_RCODE_NOT_IMPLEMENTED; - break; } + if (!W_ERROR_IS_OK(ret)) { + state->dns_err = werr_to_dns_err(ret); + } + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +static void dns_process_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct dns_process_state *state = tevent_req_data( + req, struct dns_process_state); + WERROR ret; - if (W_ERROR_IS_OK(ret)) { - out_packet->ancount = num_answers; - out_packet->answers = answers; + ret = dns_server_process_query_recv( + subreq, state, + &state->out_packet.answers, &state->out_packet.ancount, + &state->out_packet.nsrecs, &state->out_packet.nscount, + &state->out_packet.additional, &state->out_packet.arcount); + TALLOC_FREE(subreq); - out_packet->nscount = num_nsrecs; - out_packet->nsrecs = nsrecs; + if (!W_ERROR_IS_OK(ret)) { + state->dns_err = werr_to_dns_err(ret); + } + tevent_req_done(req); +} - out_packet->arcount = num_additional; - out_packet->additional = additional; - } else { - out_packet->operation |= werr_to_dns_err(ret); +static WERROR dns_process_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + DATA_BLOB *out) +{ + struct dns_process_state *state = tevent_req_data( + req, struct dns_process_state); + enum ndr_err_code ndr_err; + WERROR ret; + + if (tevent_req_is_werror(req, &ret)) { + return ret; + } + if ((state->dns_err != DNS_RCODE_OK) && + (state->dns_err != DNS_RCODE_NXDOMAIN)) { + goto drop; + } + if (state->dns_err != DNS_RCODE_OK) { + state->out_packet.operation |= state->dns_err; } + state->out_packet.operation |= state->state.flags; - if (DEBUGLVL(2)) { - NDR_PRINT_DEBUG(dns_name_packet, out_packet); + if (state->state.sign) { + ret = dns_sign_tsig(state->dns, mem_ctx, &state->state, + &state->out_packet, 0); + if (!W_ERROR_IS_OK(ret)) { + state->dns_err = DNS_RCODE_SERVFAIL; + goto drop; + } } - ndr_err = ndr_push_struct_blob(out, out_packet, out_packet, - (ndr_push_flags_fn_t)ndr_push_dns_name_packet); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - TALLOC_FREE(in_packet); - TALLOC_FREE(out_packet); - DEBUG(0, ("Failed to push packet %d!\n", ndr_err)); - *out = *in; - out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */ - out->data[3] |= DNS_RCODE_SERVFAIL; + if (DEBUGLVLC(DBGC_DNS, 8)) { + NDR_PRINT_DEBUGC(DBGC_DNS, dns_name_packet, &state->out_packet); + } - return NT_STATUS_OK; + ndr_err = ndr_push_struct_blob( + out, mem_ctx, &state->out_packet, + (ndr_push_flags_fn_t)ndr_push_dns_name_packet); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(1, ("Failed to push packet: %s!\n", + ndr_errstr(ndr_err))); + state->dns_err = DNS_RCODE_SERVFAIL; + goto drop; } + return WERR_OK; - dump_data(2, out->data, out->length); - return NT_STATUS_OK; +drop: + *out = data_blob_talloc(mem_ctx, state->in->data, state->in->length); + if (out->data == NULL) { + return WERR_NOMEM; + } + out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */ + out->data[3] |= state->dns_err; + return WERR_OK; } struct dns_tcp_call { @@ -198,12 +286,14 @@ struct dns_tcp_call { struct iovec out_iov[2]; }; +static void dns_tcp_call_process_done(struct tevent_req *subreq); static void dns_tcp_call_writev_done(struct tevent_req *subreq); static void dns_tcp_call_loop(struct tevent_req *subreq) { struct dns_tcp_connection *dns_conn = tevent_req_callback_data(subreq, struct dns_tcp_connection); + struct dns_server *dns = dns_conn->dns_socket->dns; struct dns_tcp_call *call; NTSTATUS status; @@ -233,27 +323,62 @@ static void dns_tcp_call_loop(struct tevent_req *subreq) return; } - DEBUG(10,("Received krb5 TCP packet of length %lu from %s\n", + DEBUG(10,("Received DNS TCP packet of length %lu from %s\n", (long) call->in.length, tsocket_address_string(dns_conn->conn->remote_address, call))); /* skip length header */ - call->in.data += 4; - call->in.length -= 4; + call->in.data += 2; + call->in.length -= 2; - /* Call dns */ - status = dns_process(dns_conn->dns_socket->dns, call, &call->in, &call->out); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("dns_process returned %s\n", nt_errstr(status))); + subreq = dns_process_send(call, dns->task->event_ctx, dns, + &call->in); + if (subreq == NULL) { + dns_tcp_terminate_connection( + dns_conn, "dns_tcp_call_loop: dns_process_send " + "failed\n"); + return; + } + tevent_req_set_callback(subreq, dns_tcp_call_process_done, call); + + /* + * The dns tcp pdu's has the length as 2 byte (initial_read_size), + * packet_full_request_u16 provides the pdu length then. + */ + subreq = tstream_read_pdu_blob_send(dns_conn, + dns_conn->conn->event.ctx, + dns_conn->tstream, + 2, /* initial_read_size */ + packet_full_request_u16, + dns_conn); + if (subreq == NULL) { + dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: " + "no memory for tstream_read_pdu_blob_send"); + return; + } + tevent_req_set_callback(subreq, dns_tcp_call_loop, dns_conn); +} + +static void dns_tcp_call_process_done(struct tevent_req *subreq) +{ + struct dns_tcp_call *call = tevent_req_callback_data(subreq, + struct dns_tcp_call); + struct dns_tcp_connection *dns_conn = call->dns_conn; + WERROR err; + + err = dns_process_recv(subreq, call, &call->out); + TALLOC_FREE(subreq); + if (!W_ERROR_IS_OK(err)) { + DEBUG(1, ("dns_process returned %s\n", win_errstr(err))); dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: process function failed"); return; } /* First add the length of the out buffer */ - RSIVAL(call->out_hdr, 0, call->out.length); + RSSVAL(call->out_hdr, 0, call->out.length); call->out_iov[0].iov_base = (char *) call->out_hdr; - call->out_iov[0].iov_len = 4; + call->out_iov[0].iov_len = 2; call->out_iov[1].iov_base = (char *) call->out.data; call->out_iov[1].iov_len = call->out.length; @@ -269,23 +394,6 @@ static void dns_tcp_call_loop(struct tevent_req *subreq) return; } tevent_req_set_callback(subreq, dns_tcp_call_writev_done, call); - - /* - * The krb5 tcp pdu's has the length as 4 byte (initial_read_size), - * packet_full_request_u32 provides the pdu length then. - */ - subreq = tstream_read_pdu_blob_send(dns_conn, - dns_conn->conn->event.ctx, - dns_conn->tstream, - 4, /* initial_read_size */ - packet_full_request_u32, - dns_conn); - if (subreq == NULL) { - dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: " - "no memory for tstream_read_pdu_blob_send"); - return; - } - tevent_req_set_callback(subreq, dns_tcp_call_loop, dns_conn); } static void dns_tcp_call_writev_done(struct tevent_req *subreq) @@ -358,14 +466,14 @@ static void dns_tcp_accept(struct stream_connection *conn) conn->private_data = dns_conn; /* - * The krb5 tcp pdu's has the length as 4 byte (initial_read_size), - * packet_full_request_u32 provides the pdu length then. + * The dns tcp pdu's has the length as 2 byte (initial_read_size), + * packet_full_request_u16 provides the pdu length then. */ subreq = tstream_read_pdu_blob_send(dns_conn, dns_conn->conn->event.ctx, dns_conn->tstream, - 4, /* initial_read_size */ - packet_full_request_u32, + 2, /* initial_read_size */ + packet_full_request_u16, dns_conn); if (subreq == NULL) { dns_tcp_terminate_connection(dns_conn, "dns_tcp_accept: " @@ -383,28 +491,31 @@ static const struct stream_server_ops dns_tcp_stream_ops = { }; struct dns_udp_call { + struct dns_udp_socket *sock; struct tsocket_address *src; DATA_BLOB in; DATA_BLOB out; }; +static void dns_udp_call_process_done(struct tevent_req *subreq); static void dns_udp_call_sendto_done(struct tevent_req *subreq); static void dns_udp_call_loop(struct tevent_req *subreq) { struct dns_udp_socket *sock = tevent_req_callback_data(subreq, struct dns_udp_socket); + struct dns_server *dns = sock->dns_socket->dns; struct dns_udp_call *call; uint8_t *buf; ssize_t len; int sys_errno; - NTSTATUS status; call = talloc(sock, struct dns_udp_call); if (call == NULL) { talloc_free(call); goto done; } + call->sock = sock; len = tdgram_recvfrom_recv(subreq, &sys_errno, call, &buf, &call->src); @@ -421,26 +532,13 @@ static void dns_udp_call_loop(struct tevent_req *subreq) (long)call->in.length, tsocket_address_string(call->src, call))); - /* Call dns_process */ - status = dns_process(sock->dns_socket->dns, call, &call->in, &call->out); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(call); - DEBUG(0, ("dns_process returned %s\n", nt_errstr(status))); - goto done; - } - - subreq = tdgram_sendto_queue_send(call, - sock->dns_socket->dns->task->event_ctx, - sock->dgram, - sock->send_queue, - call->out.data, - call->out.length, - call->src); + subreq = dns_process_send(call, dns->task->event_ctx, dns, + &call->in); if (subreq == NULL) { - talloc_free(call); + TALLOC_FREE(call); goto done; } - tevent_req_set_callback(subreq, dns_udp_call_sendto_done, call); + tevent_req_set_callback(subreq, dns_udp_call_process_done, call); done: subreq = tdgram_recvfrom_send(sock, @@ -455,14 +553,43 @@ done: tevent_req_set_callback(subreq, dns_udp_call_loop, sock); } +static void dns_udp_call_process_done(struct tevent_req *subreq) +{ + struct dns_udp_call *call = tevent_req_callback_data( + subreq, struct dns_udp_call); + struct dns_udp_socket *sock = call->sock; + struct dns_server *dns = sock->dns_socket->dns; + WERROR err; + + err = dns_process_recv(subreq, call, &call->out); + TALLOC_FREE(subreq); + if (!W_ERROR_IS_OK(err)) { + DEBUG(1, ("dns_process returned %s\n", win_errstr(err))); + TALLOC_FREE(call); + return; + } + + subreq = tdgram_sendto_queue_send(call, + dns->task->event_ctx, + sock->dgram, + sock->send_queue, + call->out.data, + call->out.length, + call->src); + if (subreq == NULL) { + talloc_free(call); + return; + } + tevent_req_set_callback(subreq, dns_udp_call_sendto_done, call); + +} 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 */ @@ -544,7 +671,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; @@ -562,13 +689,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; isize = size; + buffer->next_idx = 0; + + buffer->tkeys = talloc_zero_array(buffer, struct dns_server_tkey *, size); + if (buffer->tkeys == NULL) { + TALLOC_FREE(buffer); + } + + return buffer; +} + +static NTSTATUS dns_server_reload_zones(struct dns_server *dns) { - const char *n1, *n2; - size_t l1, l2; + NTSTATUS status; + struct dns_server_zone *new_list = NULL; + struct dns_server_zone *old_list = NULL; + struct dns_server_zone *old_zone; + status = dns_common_zones(dns->samdb, dns, &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); + } - n1 = ldb_msg_find_attr_as_string(*m1, "name", NULL); - n2 = ldb_msg_find_attr_as_string(*m2, "name", NULL); + return NT_STATUS_OK; +} - l1 = strlen(n1); - l2 = strlen(n2); +/** + * 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; - /* If the string lengths are not equal just sort by length */ - if (l1 != l2) { - /* If m1 is the larger zone name, return it first */ - return l2 - l1; + 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; } - /*TODO: We need to compare DNs here, we want the DomainDNSZones first */ - return 0; + 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: @@ -614,16 +805,18 @@ static void dns_task_init(struct task_server *task) case ROLE_DOMAIN_MEMBER: task_server_terminate(task, "dns: no DNS required in member server configuration", false); return; - case ROLE_DOMAIN_CONTROLLER: + case ROLE_ACTIVE_DIRECTORY_DC: /* Yes, we want a DNS */ 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]"); @@ -635,6 +828,14 @@ 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) { + task_server_terminate(task, "Failed to init server credentials\n", true); + return; + } dns->samdb = samdb_connect(dns, dns->task->event_ctx, dns->task->lp_ctx, system_session(dns->task->lp_ctx), 0); @@ -643,36 +844,76 @@ static void dns_task_init(struct task_server *task) 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); - return; - } + cli_credentials_set_conf(dns->server_credentials, task->lp_ctx); - TYPESAFE_QSORT(res->msgs, res->count, dns_server_sort_zones); + 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); - for (i=0; i < res->count; i++) { - struct dns_server_zone *z; - - z = talloc_zero(dns, struct dns_server_zone); - if (z == NULL) { + 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; + } + } - z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL); - z->dn = talloc_move(z, &res->msgs[i]->dn); + dns->tkeys = tkey_store_init(dns, TKEY_BUFFER_SIZE); + if (!dns->tkeys) { + task_server_terminate(task, "Failed to allocate tkey storage\n", true); + return; + } - DLIST_ADD_END(dns->zones, z, NULL); + status = dns_server_reload_zones(dns); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, "dns: failed to load DNS zones", true); + return; } - status = dns_startup_interfaces(dns, task->lp_ctx, ifaces); + status = dns_startup_interfaces(dns, ifaces); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "dns failed to setup interfaces", true); return; } + + /* 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 = 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 reload handler", true); + return; + } } NTSTATUS server_service_dns_init(void)