LCOV - code coverage report
Current view: top level - source4/dns_server - dns_query.c (source / functions) Hit Total Coverage
Test: coverage report for douglas-v4-17-lts-2026-07-29 28d1e15b Lines: 432 590 73.2 %
Date: 2026-07-29 02:26:30 Functions: 21 21 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    DNS server handler for queries
       5             : 
       6             :    Copyright (C) 2010 Kai Blin  <kai@samba.org>
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "samba/service_task.h"
      24             : #include "libcli/util/werror.h"
      25             : #include "librpc/ndr/libndr.h"
      26             : #include "librpc/gen_ndr/ndr_dns.h"
      27             : #include "librpc/gen_ndr/ndr_dnsp.h"
      28             : #include <ldb.h>
      29             : #include "param/param.h"
      30             : #include "dsdb/samdb/samdb.h"
      31             : #include "dsdb/common/util.h"
      32             : #include "dns_server/dns_server.h"
      33             : #include "libcli/dns/libdns.h"
      34             : #include "lib/util/dlinklist.h"
      35             : #include "lib/util/util_net.h"
      36             : #include "lib/util/tevent_werror.h"
      37             : #include "auth/auth.h"
      38             : #include "auth/credentials/credentials.h"
      39             : #include "auth/gensec/gensec.h"
      40             : 
      41             : #undef DBGC_CLASS
      42             : #define DBGC_CLASS DBGC_DNS
      43             : #define MAX_Q_RECURSION_DEPTH 20
      44             : 
      45             : struct forwarder_string {
      46             :         const char *forwarder;
      47             :         struct forwarder_string *prev, *next;
      48             : };
      49             : 
      50       49633 : static WERROR add_response_rr(const char *name,
      51             :                               const struct dnsp_DnssrvRpcRecord *rec,
      52             :                               struct dns_res_rec **answers)
      53             : {
      54       49633 :         struct dns_res_rec *ans = *answers;
      55       49633 :         uint16_t ai = talloc_array_length(ans);
      56             :         enum ndr_err_code ndr_err;
      57             : 
      58       49633 :         if (ai == UINT16_MAX) {
      59           0 :                 return WERR_BUFFER_OVERFLOW;
      60             :         }
      61             : 
      62             :         /*
      63             :          * "ans" is always non-NULL and thus its own talloc context
      64             :          */
      65       49633 :         ans = talloc_realloc(ans, ans, struct dns_res_rec, ai+1);
      66       49633 :         if (ans == NULL) {
      67           0 :                 return WERR_NOT_ENOUGH_MEMORY;
      68             :         }
      69             : 
      70       49633 :         ZERO_STRUCT(ans[ai]);
      71             : 
      72       49633 :         switch (rec->wType) {
      73        6504 :         case DNS_QTYPE_CNAME:
      74        6504 :                 ans[ai].rdata.cname_record = talloc_strdup(ans, rec->data.cname);
      75        6504 :                 W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.cname_record);
      76        6504 :                 break;
      77        4299 :         case DNS_QTYPE_A:
      78        4299 :                 ans[ai].rdata.ipv4_record = talloc_strdup(ans, rec->data.ipv4);
      79        4299 :                 W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.ipv4_record);
      80        4299 :                 break;
      81        3898 :         case DNS_QTYPE_AAAA:
      82        3898 :                 ans[ai].rdata.ipv6_record = talloc_strdup(ans, rec->data.ipv6);
      83        3898 :                 W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.ipv6_record);
      84        3898 :                 break;
      85         477 :         case DNS_TYPE_NS:
      86         477 :                 ans[ai].rdata.ns_record = talloc_strdup(ans, rec->data.ns);
      87         477 :                 W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.ns_record);
      88         477 :                 break;
      89        2408 :         case DNS_QTYPE_SRV:
      90        2408 :                 ans[ai].rdata.srv_record.priority = rec->data.srv.wPriority;
      91        2408 :                 ans[ai].rdata.srv_record.weight   = rec->data.srv.wWeight;
      92        2408 :                 ans[ai].rdata.srv_record.port     = rec->data.srv.wPort;
      93        2497 :                 ans[ai].rdata.srv_record.target   = talloc_strdup(
      94          89 :                         ans, rec->data.srv.nameTarget);
      95        2408 :                 W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.srv_record.target);
      96        2408 :                 break;
      97       31752 :         case DNS_QTYPE_SOA:
      98       32062 :                 ans[ai].rdata.soa_record.mname   = talloc_strdup(
      99         310 :                         ans, rec->data.soa.mname);
     100       31752 :                 W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.soa_record.mname);
     101       32062 :                 ans[ai].rdata.soa_record.rname   = talloc_strdup(
     102         310 :                         ans, rec->data.soa.rname);
     103       31752 :                 W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.soa_record.rname);
     104       31752 :                 ans[ai].rdata.soa_record.serial  = rec->data.soa.serial;
     105       31752 :                 ans[ai].rdata.soa_record.refresh = rec->data.soa.refresh;
     106       31752 :                 ans[ai].rdata.soa_record.retry   = rec->data.soa.retry;
     107       31752 :                 ans[ai].rdata.soa_record.expire  = rec->data.soa.expire;
     108       31752 :                 ans[ai].rdata.soa_record.minimum = rec->data.soa.minimum;
     109       31752 :                 break;
     110           0 :         case DNS_QTYPE_PTR:
     111           0 :                 ans[ai].rdata.ptr_record = talloc_strdup(ans, rec->data.ptr);
     112           0 :                 W_ERROR_HAVE_NO_MEMORY(ans[ai].rdata.ptr_record);
     113           0 :                 break;
     114           2 :         case DNS_QTYPE_MX:
     115           2 :                 ans[ai].rdata.mx_record.preference = rec->data.mx.wPriority;
     116           3 :                 ans[ai].rdata.mx_record.exchange = talloc_strdup(
     117           1 :                         ans, rec->data.mx.nameTarget);
     118           2 :                 if (ans[ai].rdata.mx_record.exchange == NULL) {
     119           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     120             :                 }
     121           2 :                 break;
     122         293 :         case DNS_QTYPE_TXT:
     123         293 :                 ndr_err = ndr_dnsp_string_list_copy(ans,
     124             :                                                     &rec->data.txt,
     125         293 :                                                     &ans[ai].rdata.txt_record.txt);
     126         293 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     127           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     128             :                 }
     129         293 :                 break;
     130           0 :         default:
     131           0 :                 DEBUG(0, ("Got unhandled type %u query.\n", rec->wType));
     132           0 :                 return DNS_ERR(NOT_IMPLEMENTED);
     133             :         }
     134             : 
     135       49633 :         ans[ai].name = talloc_strdup(ans, name);
     136       49633 :         W_ERROR_HAVE_NO_MEMORY(ans[ai].name);
     137       49633 :         ans[ai].rr_type = (enum dns_qtype)rec->wType;
     138       49633 :         ans[ai].rr_class = DNS_QCLASS_IN;
     139       49633 :         ans[ai].ttl = rec->dwTtlSeconds;
     140       49633 :         ans[ai].length = UINT16_MAX;
     141             : 
     142       49633 :         *answers = ans;
     143             : 
     144       49633 :         return WERR_OK;
     145             : }
     146             : 
     147           8 : static WERROR add_dns_res_rec(struct dns_res_rec **pdst,
     148             :                               const struct dns_res_rec *src)
     149             : {
     150           8 :         struct dns_res_rec *dst = *pdst;
     151           8 :         uint16_t di = talloc_array_length(dst);
     152             :         enum ndr_err_code ndr_err;
     153             : 
     154           8 :         if (di == UINT16_MAX) {
     155           0 :                 return WERR_BUFFER_OVERFLOW;
     156             :         }
     157             : 
     158           8 :         dst = talloc_realloc(dst, dst, struct dns_res_rec, di+1);
     159           8 :         if (dst == NULL) {
     160           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     161             :         }
     162             : 
     163           8 :         ZERO_STRUCT(dst[di]);
     164             : 
     165          16 :         dst[di] = (struct dns_res_rec) {
     166           8 :                 .name = talloc_strdup(dst, src->name),
     167           8 :                 .rr_type = src->rr_type,
     168           8 :                 .rr_class = src->rr_class,
     169           8 :                 .ttl = src->ttl,
     170           8 :                 .length = src->length
     171             :         };
     172             : 
     173           8 :         if (dst[di].name == NULL) {
     174           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     175             :         }
     176             : 
     177           8 :         switch (src->rr_type) {
     178           8 :         case DNS_QTYPE_CNAME:
     179          12 :                 dst[di].rdata.cname_record = talloc_strdup(
     180           4 :                         dst, src->rdata.cname_record);
     181           8 :                 if (dst[di].rdata.cname_record == NULL) {
     182           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     183             :                 }
     184           8 :                 break;
     185           0 :         case DNS_QTYPE_A:
     186           0 :                 dst[di].rdata.ipv4_record = talloc_strdup(
     187           0 :                         dst, src->rdata.ipv4_record);
     188           0 :                 if (dst[di].rdata.ipv4_record == NULL) {
     189           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     190             :                 }
     191           0 :                 break;
     192           0 :         case DNS_QTYPE_AAAA:
     193           0 :                 dst[di].rdata.ipv6_record = talloc_strdup(
     194           0 :                         dst, src->rdata.ipv6_record);
     195           0 :                 if (dst[di].rdata.ipv6_record == NULL) {
     196           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     197             :                 }
     198           0 :                 break;
     199           0 :         case DNS_TYPE_NS:
     200           0 :                 dst[di].rdata.ns_record = talloc_strdup(
     201           0 :                         dst, src->rdata.ns_record);
     202           0 :                 if (dst[di].rdata.ns_record == NULL) {
     203           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     204             :                 }
     205           0 :                 break;
     206           0 :         case DNS_QTYPE_SRV:
     207           0 :                 dst[di].rdata.srv_record = (struct dns_srv_record) {
     208           0 :                         .priority = src->rdata.srv_record.priority,
     209           0 :                         .weight   = src->rdata.srv_record.weight,
     210           0 :                         .port     = src->rdata.srv_record.port,
     211           0 :                         .target   = talloc_strdup(
     212           0 :                                 dst, src->rdata.srv_record.target)
     213             :                 };
     214           0 :                 if (dst[di].rdata.srv_record.target == NULL) {
     215           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     216             :                 }
     217           0 :                 break;
     218           0 :         case DNS_QTYPE_SOA:
     219           0 :                 dst[di].rdata.soa_record = (struct dns_soa_record) {
     220           0 :                         .mname   = talloc_strdup(
     221           0 :                                 dst, src->rdata.soa_record.mname),
     222           0 :                         .rname   = talloc_strdup(
     223           0 :                                 dst, src->rdata.soa_record.rname),
     224           0 :                         .serial  = src->rdata.soa_record.serial,
     225           0 :                         .refresh = src->rdata.soa_record.refresh,
     226           0 :                         .retry   = src->rdata.soa_record.retry,
     227           0 :                         .expire  = src->rdata.soa_record.expire,
     228           0 :                         .minimum = src->rdata.soa_record.minimum
     229             :                 };
     230             : 
     231           0 :                 if ((dst[di].rdata.soa_record.mname == NULL) ||
     232           0 :                     (dst[di].rdata.soa_record.rname == NULL)) {
     233           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     234             :                 }
     235             : 
     236           0 :                 break;
     237           0 :         case DNS_QTYPE_PTR:
     238           0 :                 dst[di].rdata.ptr_record = talloc_strdup(
     239           0 :                         dst, src->rdata.ptr_record);
     240           0 :                 if (dst[di].rdata.ptr_record == NULL) {
     241           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     242             :                 }
     243           0 :                 break;
     244           0 :         case DNS_QTYPE_MX:
     245           0 :                 dst[di].rdata.mx_record = (struct dns_mx_record) {
     246           0 :                         .preference = src->rdata.mx_record.preference,
     247           0 :                         .exchange   = talloc_strdup(
     248           0 :                                 src, src->rdata.mx_record.exchange)
     249             :                 };
     250             : 
     251           0 :                 if (dst[di].rdata.mx_record.exchange == NULL) {
     252           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     253             :                 }
     254           0 :                 break;
     255           0 :         case DNS_QTYPE_TXT:
     256           0 :                 ndr_err = ndr_dnsp_string_list_copy(dst,
     257             :                                                     &src->rdata.txt_record.txt,
     258           0 :                                                     &dst[di].rdata.txt_record.txt);
     259           0 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     260           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     261             :                 }
     262           0 :                 break;
     263           0 :         default:
     264           0 :                 DBG_WARNING("Got unhandled type %u query.\n", src->rr_type);
     265           0 :                 return DNS_ERR(NOT_IMPLEMENTED);
     266             :         }
     267             : 
     268           8 :         *pdst = dst;
     269             : 
     270           8 :         return WERR_OK;
     271             : }
     272             : 
     273             : struct ask_forwarder_state {
     274             :         struct dns_name_packet *reply;
     275             : };
     276             : 
     277             : static void ask_forwarder_done(struct tevent_req *subreq);
     278             : 
     279          38 : static struct tevent_req *ask_forwarder_send(
     280             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     281             :         const char *forwarder, struct dns_name_question *question)
     282             : {
     283             :         struct tevent_req *req, *subreq;
     284             :         struct ask_forwarder_state *state;
     285             : 
     286          38 :         req = tevent_req_create(mem_ctx, &state, struct ask_forwarder_state);
     287          38 :         if (req == NULL) {
     288           0 :                 return NULL;
     289             :         }
     290             : 
     291          38 :         subreq = dns_cli_request_send(state, ev, forwarder,
     292             :                                       question->name, question->question_class,
     293             :                                       question->question_type);
     294          38 :         if (tevent_req_nomem(subreq, req)) {
     295           0 :                 return tevent_req_post(req, ev);
     296             :         }
     297          38 :         tevent_req_set_callback(subreq, ask_forwarder_done, req);
     298          38 :         return req;
     299             : }
     300             : 
     301          38 : static void ask_forwarder_done(struct tevent_req *subreq)
     302             : {
     303          38 :         struct tevent_req *req = tevent_req_callback_data(
     304             :                 subreq, struct tevent_req);
     305          38 :         struct ask_forwarder_state *state = tevent_req_data(
     306             :                 req, struct ask_forwarder_state);
     307             :         int ret;
     308             : 
     309          38 :         ret = dns_cli_request_recv(subreq, state, &state->reply);
     310          38 :         TALLOC_FREE(subreq);
     311             : 
     312          38 :         if (ret != 0) {
     313          20 :                 tevent_req_werror(req, unix_to_werror(ret));
     314          20 :                 return;
     315             :         }
     316             : 
     317          18 :         tevent_req_done(req);
     318             : }
     319             : 
     320          38 : static WERROR ask_forwarder_recv(
     321             :         struct tevent_req *req, TALLOC_CTX *mem_ctx,
     322             :         struct dns_res_rec **answers, uint16_t *ancount,
     323             :         struct dns_res_rec **nsrecs, uint16_t *nscount,
     324             :         struct dns_res_rec **additional, uint16_t *arcount)
     325             : {
     326          38 :         struct ask_forwarder_state *state = tevent_req_data(
     327             :                 req, struct ask_forwarder_state);
     328          38 :         struct dns_name_packet *in_packet = state->reply;
     329             :         WERROR err;
     330             : 
     331          38 :         if (tevent_req_is_werror(req, &err)) {
     332          20 :                 return err;
     333             :         }
     334             : 
     335          18 :         *ancount = in_packet->ancount;
     336          18 :         *answers = talloc_move(mem_ctx, &in_packet->answers);
     337             : 
     338          18 :         *nscount = in_packet->nscount;
     339          18 :         *nsrecs = talloc_move(mem_ctx, &in_packet->nsrecs);
     340             : 
     341          18 :         *arcount = in_packet->arcount;
     342          18 :         *additional = talloc_move(mem_ctx, &in_packet->additional);
     343             : 
     344          18 :         return WERR_OK;
     345             : }
     346             : 
     347       31391 : static WERROR add_zone_authority_record(struct dns_server *dns,
     348             :                                         TALLOC_CTX *mem_ctx,
     349             :                                         const struct dns_name_question *question,
     350             :                                         struct dns_res_rec **nsrecs)
     351             : {
     352       31391 :         const char *zone = NULL;
     353             :         struct dnsp_DnssrvRpcRecord *recs;
     354       31391 :         struct dns_res_rec *ns = *nsrecs;
     355             :         uint16_t rec_count;
     356       31391 :         struct ldb_dn *dn = NULL;
     357             :         unsigned int ri;
     358             :         WERROR werror;
     359             : 
     360       31391 :         zone = dns_get_authoritative_zone(dns, question->name);
     361       31391 :         DEBUG(10, ("Creating zone authority record for '%s'\n", zone));
     362             : 
     363       31391 :         werror = dns_name2dn(dns, mem_ctx, zone, &dn);
     364       31391 :         if (!W_ERROR_IS_OK(werror)) {
     365           0 :                 return werror;
     366             :         }
     367             : 
     368       31391 :         werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count);
     369       31391 :         if (!W_ERROR_IS_OK(werror)) {
     370           6 :                 return werror;
     371             :         }
     372             : 
     373      117064 :         for (ri = 0; ri < rec_count; ri++) {
     374       85679 :                 if (recs[ri].wType == DNS_TYPE_SOA) {
     375       31385 :                         werror = add_response_rr(zone, &recs[ri], &ns);
     376       31385 :                         if (!W_ERROR_IS_OK(werror)) {
     377           0 :                                 return werror;
     378             :                         }
     379             :                 }
     380             :         }
     381             : 
     382       31385 :         *nsrecs = ns;
     383             : 
     384       31385 :         return WERR_OK;
     385             : }
     386             : 
     387             : static struct tevent_req *handle_authoritative_send(
     388             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     389             :         struct dns_server *dns, const char *forwarder,
     390             :         struct dns_name_question *question,
     391             :         struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
     392             :         size_t cname_depth);
     393             : static WERROR handle_authoritative_recv(struct tevent_req *req);
     394             : 
     395             : struct handle_dnsrpcrec_state {
     396             :         struct dns_res_rec **answers;
     397             :         struct dns_res_rec **nsrecs;
     398             : };
     399             : 
     400             : static void handle_dnsrpcrec_gotauth(struct tevent_req *subreq);
     401             : static void handle_dnsrpcrec_gotforwarded(struct tevent_req *subreq);
     402             : 
     403       29901 : static struct tevent_req *handle_dnsrpcrec_send(
     404             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     405             :         struct dns_server *dns, const char *forwarder,
     406             :         const struct dns_name_question *question,
     407             :         struct dnsp_DnssrvRpcRecord *rec,
     408             :         struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
     409             :         size_t cname_depth)
     410             : {
     411             :         struct tevent_req *req, *subreq;
     412             :         struct handle_dnsrpcrec_state *state;
     413             :         struct dns_name_question *new_q;
     414             :         bool resolve_cname;
     415             :         WERROR werr;
     416             : 
     417       29901 :         req = tevent_req_create(mem_ctx, &state,
     418             :                                 struct handle_dnsrpcrec_state);
     419       29901 :         if (req == NULL) {
     420           0 :                 return NULL;
     421             :         }
     422       29901 :         state->answers = answers;
     423       29901 :         state->nsrecs = nsrecs;
     424             : 
     425       29901 :         if (cname_depth >= MAX_Q_RECURSION_DEPTH) {
     426           2 :                 tevent_req_done(req);
     427           2 :                 return tevent_req_post(req, ev);
     428             :         }
     429             : 
     430       42789 :         resolve_cname = ((rec->wType == DNS_TYPE_CNAME) &&
     431        9767 :                          ((question->question_type == DNS_QTYPE_A) ||
     432        3263 :                           (question->question_type == DNS_QTYPE_AAAA)));
     433             : 
     434       29899 :         if (!resolve_cname) {
     435       46309 :                 if ((question->question_type != DNS_QTYPE_ALL) &&
     436       23471 :                     (rec->wType !=
     437       23471 :                      (enum dns_record_type) question->question_type)) {
     438       11651 :                         tevent_req_done(req);
     439       11651 :                         return tevent_req_post(req, ev);
     440             :                 }
     441             : 
     442       11830 :                 werr = add_response_rr(question->name, rec, state->answers);
     443       11830 :                 if (tevent_req_werror(req, werr)) {
     444           0 :                         return tevent_req_post(req, ev);
     445             :                 }
     446             : 
     447       11830 :                 tevent_req_done(req);
     448       11830 :                 return tevent_req_post(req, ev);
     449             :         }
     450             : 
     451        6418 :         werr = add_response_rr(question->name, rec, state->answers);
     452        6418 :         if (tevent_req_werror(req, werr)) {
     453           0 :                 return tevent_req_post(req, ev);
     454             :         }
     455             : 
     456        6418 :         new_q = talloc(state, struct dns_name_question);
     457        6418 :         if (tevent_req_nomem(new_q, req)) {
     458           0 :                 return tevent_req_post(req, ev);
     459             :         }
     460             : 
     461        6418 :         *new_q = (struct dns_name_question) {
     462        6418 :                 .question_type = question->question_type,
     463        6418 :                 .question_class = question->question_class,
     464        6418 :                 .name = rec->data.cname
     465             :         };
     466             : 
     467        6418 :         if (dns_authoritative_for_zone(dns, new_q->name)) {
     468       19162 :                 subreq = handle_authoritative_send(
     469             :                         state, ev, dns, forwarder, new_q,
     470       12784 :                         state->answers, state->nsrecs,
     471             :                         cname_depth + 1);
     472        6406 :                 if (tevent_req_nomem(subreq, req)) {
     473           0 :                         return tevent_req_post(req, ev);
     474             :                 }
     475        6406 :                 tevent_req_set_callback(subreq, handle_dnsrpcrec_gotauth, req);
     476        6406 :                 return req;
     477             :         }
     478             : 
     479          12 :         subreq = ask_forwarder_send(state, ev, forwarder, new_q);
     480          12 :         if (tevent_req_nomem(subreq, req)) {
     481           0 :                 return tevent_req_post(req, ev);
     482             :         }
     483          12 :         tevent_req_set_callback(subreq, handle_dnsrpcrec_gotforwarded, req);
     484             : 
     485          12 :         return req;
     486             : }
     487             : 
     488        6406 : static void handle_dnsrpcrec_gotauth(struct tevent_req *subreq)
     489             : {
     490        6406 :         struct tevent_req *req = tevent_req_callback_data(
     491             :                 subreq, struct tevent_req);
     492             :         WERROR werr;
     493             : 
     494        6406 :         werr = handle_authoritative_recv(subreq);
     495        6406 :         TALLOC_FREE(subreq);
     496        6406 :         if (tevent_req_werror(req, werr)) {
     497           7 :                 return;
     498             :         }
     499        6399 :         tevent_req_done(req);
     500             : }
     501             : 
     502          12 : static void handle_dnsrpcrec_gotforwarded(struct tevent_req *subreq)
     503             : {
     504          12 :         struct tevent_req *req = tevent_req_callback_data(
     505             :                 subreq, struct tevent_req);
     506          12 :         struct handle_dnsrpcrec_state *state = tevent_req_data(
     507             :                 req, struct handle_dnsrpcrec_state);
     508             :         struct dns_res_rec *answers, *nsrecs, *additional;
     509          12 :         uint16_t ancount = 0;
     510          12 :         uint16_t nscount = 0;
     511          12 :         uint16_t arcount = 0;
     512             :         uint16_t i;
     513             :         WERROR werr;
     514             : 
     515          12 :         werr = ask_forwarder_recv(subreq, state, &answers, &ancount,
     516             :                                   &nsrecs, &nscount, &additional, &arcount);
     517          12 :         if (tevent_req_werror(req, werr)) {
     518           6 :                 return;
     519             :         }
     520             : 
     521          16 :         for (i=0; i<ancount; i++) {
     522           8 :                 werr = add_dns_res_rec(state->answers, &answers[i]);
     523           8 :                 if (tevent_req_werror(req, werr)) {
     524           0 :                         return;
     525             :                 }
     526             :         }
     527             : 
     528           8 :         for (i=0; i<nscount; i++) {
     529           0 :                 werr = add_dns_res_rec(state->nsrecs, &nsrecs[i]);
     530           0 :                 if (tevent_req_werror(req, werr)) {
     531           0 :                         return;
     532             :                 }
     533             :         }
     534             : 
     535           8 :         tevent_req_done(req);
     536             : }
     537             : 
     538       29901 : static WERROR handle_dnsrpcrec_recv(struct tevent_req *req)
     539             : {
     540       29901 :         return tevent_req_simple_recv_werror(req);
     541             : }
     542             : 
     543             : struct handle_authoritative_state {
     544             :         struct tevent_context *ev;
     545             :         struct dns_server *dns;
     546             :         struct dns_name_question *question;
     547             :         const char *forwarder;
     548             : 
     549             :         struct dnsp_DnssrvRpcRecord *recs;
     550             :         uint16_t rec_count;
     551             :         uint16_t recs_done;
     552             : 
     553             :         struct dns_res_rec **answers;
     554             :         struct dns_res_rec **nsrecs;
     555             : 
     556             :         size_t cname_depth;
     557             : };
     558             : 
     559             : static void handle_authoritative_done(struct tevent_req *subreq);
     560             : 
     561       37835 : static struct tevent_req *handle_authoritative_send(
     562             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     563             :         struct dns_server *dns, const char *forwarder,
     564             :         struct dns_name_question *question,
     565             :         struct dns_res_rec **answers, struct dns_res_rec **nsrecs,
     566             :         size_t cname_depth)
     567             : {
     568             :         struct tevent_req *req, *subreq;
     569             :         struct handle_authoritative_state *state;
     570       37835 :         struct ldb_dn *dn = NULL;
     571             :         WERROR werr;
     572             : 
     573       37835 :         req = tevent_req_create(mem_ctx, &state,
     574             :                                 struct handle_authoritative_state);
     575       37835 :         if (req == NULL) {
     576           0 :                 return NULL;
     577             :         }
     578       37835 :         state->ev = ev;
     579       37835 :         state->dns = dns;
     580       37835 :         state->question = question;
     581       37835 :         state->forwarder = forwarder;
     582       37835 :         state->answers = answers;
     583       37835 :         state->nsrecs = nsrecs;
     584       37835 :         state->cname_depth = cname_depth;
     585             : 
     586       37835 :         werr = dns_name2dn(dns, state, question->name, &dn);
     587       37835 :         if (tevent_req_werror(req, werr)) {
     588           0 :                 return tevent_req_post(req, ev);
     589             :         }
     590       37835 :         werr = dns_lookup_records_wildcard(dns, state, dn, &state->recs,
     591       37835 :                                            &state->rec_count);
     592       37835 :         TALLOC_FREE(dn);
     593       37835 :         if (tevent_req_werror(req, werr)) {
     594       20452 :                 return tevent_req_post(req, ev);
     595             :         }
     596             : 
     597       17383 :         if (state->rec_count == 0) {
     598           0 :                 tevent_req_werror(req, DNS_ERR(NAME_ERROR));
     599           0 :                 return tevent_req_post(req, ev);
     600             :         }
     601             : 
     602      119821 :         subreq = handle_dnsrpcrec_send(
     603       51529 :                 state, state->ev, state->dns, state->forwarder,
     604       34456 :                 state->question, &state->recs[state->recs_done],
     605       34456 :                 state->answers, state->nsrecs,
     606       17383 :                 state->cname_depth);
     607       17383 :         if (tevent_req_nomem(subreq, req)) {
     608           0 :                 return tevent_req_post(req, ev);
     609             :         }
     610       17383 :         tevent_req_set_callback(subreq, handle_authoritative_done, req);
     611       17383 :         return req;
     612             : }
     613             : 
     614       29901 : static void handle_authoritative_done(struct tevent_req *subreq)
     615             : {
     616       29901 :         struct tevent_req *req = tevent_req_callback_data(
     617             :                 subreq, struct tevent_req);
     618       29901 :         struct handle_authoritative_state *state = tevent_req_data(
     619             :                 req, struct handle_authoritative_state);
     620             :         WERROR werr;
     621             : 
     622       29901 :         werr = handle_dnsrpcrec_recv(subreq);
     623       29901 :         TALLOC_FREE(subreq);
     624       29901 :         if (tevent_req_werror(req, werr)) {
     625       17391 :                 return;
     626             :         }
     627             : 
     628       29890 :         state->recs_done += 1;
     629             : 
     630       29890 :         if (state->recs_done == state->rec_count) {
     631       17372 :                 tevent_req_done(req);
     632       17372 :                 return;
     633             :         }
     634             : 
     635       36812 :         subreq = handle_dnsrpcrec_send(
     636             :                 state, state->ev, state->dns, state->forwarder,
     637       24665 :                 state->question, &state->recs[state->recs_done],
     638             :                 state->answers, state->nsrecs,
     639             :                 state->cname_depth);
     640       12518 :         if (tevent_req_nomem(subreq, req)) {
     641           0 :                 return;
     642             :         }
     643       12518 :         tevent_req_set_callback(subreq, handle_authoritative_done, req);
     644             : }
     645             : 
     646       37835 : static WERROR handle_authoritative_recv(struct tevent_req *req)
     647             : {
     648             :         WERROR werr;
     649             : 
     650       37835 :         if (tevent_req_is_werror(req, &werr)) {
     651       20463 :                 return werr;
     652             :         }
     653             : 
     654       17372 :         return WERR_OK;
     655             : }
     656             : 
     657         205 : static NTSTATUS create_tkey(TALLOC_CTX *mem_ctx,
     658             :                             struct dns_server *dns,
     659             :                             const char* name,
     660             :                             const char* algorithm,
     661             :                             const struct tsocket_address *remote_address,
     662             :                             const struct tsocket_address *local_address,
     663             :                             struct dns_server_tkey **tkey)
     664             : {
     665             :         NTSTATUS status;
     666         205 :         struct dns_server_tkey *k = NULL;
     667             : 
     668         205 :         k = talloc_zero(mem_ctx, struct dns_server_tkey);
     669         205 :         if (k == NULL) {
     670           0 :                 goto nomem;
     671             :         }
     672             : 
     673         205 :         k->name = talloc_strdup(k, name);
     674             : 
     675         205 :         if (k->name  == NULL) {
     676           0 :                 goto nomem;
     677             :         }
     678             : 
     679         205 :         k->algorithm = talloc_strdup(k, algorithm);
     680         205 :         if (k->algorithm == NULL) {
     681           0 :                 goto nomem;
     682             :         }
     683             : 
     684             :         /*
     685             :          * We only allow SPNEGO/KRB5 currently
     686             :          * and rely on the backend to be RPC/IPC free.
     687             :          *
     688             :          * It allows gensec_update() not to block.
     689             :          */
     690         754 :         status = samba_server_gensec_krb5_start(k,
     691         205 :                                                 dns->task->event_ctx,
     692         205 :                                                 dns->task->msg_ctx,
     693         205 :                                                 dns->task->lp_ctx,
     694             :                                                 dns->server_credentials,
     695             :                                                 "dns",
     696             :                                                 &k->gensec);
     697         205 :         if (!NT_STATUS_IS_OK(status)) {
     698           0 :                 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
     699           0 :                 goto fail;
     700             :         }
     701             : 
     702         205 :         gensec_want_feature(k->gensec, GENSEC_FEATURE_SIGN);
     703             : 
     704         205 :         status = gensec_set_remote_address(k->gensec,
     705             :                                            remote_address);
     706         205 :         if (!NT_STATUS_IS_OK(status)) {
     707           0 :                 DEBUG(1, ("Failed to set remote address into GENSEC: %s\n",
     708             :                           nt_errstr(status)));
     709           0 :                 goto fail;
     710             :         }
     711             : 
     712         205 :         status = gensec_set_local_address(k->gensec,
     713             :                                           local_address);
     714         205 :         if (!NT_STATUS_IS_OK(status)) {
     715           0 :                 DEBUG(1, ("Failed to set local address into GENSEC: %s\n",
     716             :                           nt_errstr(status)));
     717           0 :                 goto fail;
     718             :         }
     719             : 
     720         205 :         status = gensec_start_mech_by_oid(k->gensec, GENSEC_OID_SPNEGO);
     721             : 
     722         205 :         if (!NT_STATUS_IS_OK(status)) {
     723           0 :                 DEBUG(1, ("Failed to start GENSEC server code: %s\n",
     724             :                           nt_errstr(status)));
     725           0 :                 goto fail;
     726             :         }
     727             : 
     728         205 :         *tkey = k;
     729         205 :         return NT_STATUS_OK;
     730             : 
     731           0 : nomem:
     732           0 :         status = NT_STATUS_NO_MEMORY;
     733           0 : fail:
     734           0 :         TALLOC_FREE(k);
     735           0 :         *tkey = NULL;
     736           0 :         return status;
     737             : }
     738             : 
     739         205 : static void add_tkey(struct dns_server_tkey_store *store,
     740             :                      struct dns_server_tkey **tkey)
     741             : {
     742         205 :         TALLOC_FREE(store->tkeys[store->next_idx]);
     743             : 
     744         205 :         store->tkeys[store->next_idx] = talloc_move(store->tkeys, tkey);
     745             : 
     746         205 :         (store->next_idx)++;
     747         205 :         store->next_idx %= store->size;
     748         205 : }
     749             : 
     750         205 : static NTSTATUS accept_gss_ticket(TALLOC_CTX *mem_ctx,
     751             :                                   struct dns_server *dns,
     752             :                                   struct dns_server_tkey *tkey,
     753             :                                   const DATA_BLOB *key,
     754             :                                   DATA_BLOB *reply,
     755             :                                   uint16_t *dns_auth_error)
     756             : {
     757             :         NTSTATUS status;
     758             : 
     759             :         /*
     760             :          * We use samba_server_gensec_krb5_start(),
     761             :          * which only allows SPNEGO/KRB5 currently
     762             :          * and makes sure the backend to be RPC/IPC free.
     763             :          *
     764             :          * See gensec_gssapi_update_internal() as
     765             :          * GENSEC_SERVER.
     766             :          *
     767             :          * It allows gensec_update() not to block.
     768             :          *
     769             :          * If that changes in future we need to use
     770             :          * gensec_update_send/recv here!
     771             :          */
     772         205 :         status = gensec_update(tkey->gensec, mem_ctx,
     773             :                                *key, reply);
     774             : 
     775         205 :         if (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) {
     776           0 :                 *dns_auth_error = DNS_RCODE_OK;
     777           0 :                 return status;
     778             :         }
     779             : 
     780         205 :         if (NT_STATUS_IS_OK(status)) {
     781             : 
     782         205 :                 status = gensec_session_info(tkey->gensec, tkey, &tkey->session_info);
     783         205 :                 if (!NT_STATUS_IS_OK(status)) {
     784           0 :                         *dns_auth_error = DNS_RCODE_BADKEY;
     785           0 :                         return status;
     786             :                 }
     787         205 :                 *dns_auth_error = DNS_RCODE_OK;
     788             :         }
     789             : 
     790         205 :         return status;
     791             : }
     792             : 
     793         205 : static WERROR handle_tkey(struct dns_server *dns,
     794             :                           TALLOC_CTX *mem_ctx,
     795             :                           const struct dns_name_packet *in,
     796             :                           struct dns_request_state *state,
     797             :                           struct dns_res_rec **answers,
     798             :                           uint16_t *ancount)
     799             : {
     800         205 :         struct dns_res_rec *in_tkey = NULL;
     801             :         struct dns_res_rec *ret_tkey;
     802             :         uint16_t i;
     803             : 
     804         205 :         for (i = 0; i < in->arcount; i++) {
     805         205 :                 if (in->additional[i].rr_type == DNS_QTYPE_TKEY) {
     806         205 :                         in_tkey = &in->additional[i];
     807         205 :                         break;
     808             :                 }
     809             :         }
     810             : 
     811             :         /* If this is a TKEY query, it should have a TKEY RR.
     812             :          * Behaviour is not really specified in RFC 2930 or RFC 3645, but
     813             :          * FORMAT_ERROR seems to be what BIND uses .*/
     814         205 :         if (in_tkey == NULL) {
     815           0 :                 return DNS_ERR(FORMAT_ERROR);
     816             :         }
     817             : 
     818         205 :         ret_tkey = talloc_zero(mem_ctx, struct dns_res_rec);
     819         205 :         if (ret_tkey == NULL) {
     820           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     821             :         }
     822             : 
     823         205 :         ret_tkey->name = talloc_strdup(ret_tkey, in_tkey->name);
     824         205 :         if (ret_tkey->name == NULL) {
     825           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     826             :         }
     827             : 
     828         205 :         ret_tkey->rr_type = DNS_QTYPE_TKEY;
     829         205 :         ret_tkey->rr_class = DNS_QCLASS_ANY;
     830         205 :         ret_tkey->length = UINT16_MAX;
     831             : 
     832         205 :         ret_tkey->rdata.tkey_record.algorithm = talloc_strdup(ret_tkey,
     833             :                         in_tkey->rdata.tkey_record.algorithm);
     834         205 :         if (ret_tkey->rdata.tkey_record.algorithm  == NULL) {
     835           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     836             :         }
     837             : 
     838         205 :         ret_tkey->rdata.tkey_record.inception = in_tkey->rdata.tkey_record.inception;
     839         205 :         ret_tkey->rdata.tkey_record.expiration = in_tkey->rdata.tkey_record.expiration;
     840         205 :         ret_tkey->rdata.tkey_record.mode = in_tkey->rdata.tkey_record.mode;
     841             : 
     842         205 :         switch (in_tkey->rdata.tkey_record.mode) {
     843           0 :         case DNS_TKEY_MODE_DH:
     844             :                 /* FIXME: According to RFC 2930, we MUST support this, but we don't.
     845             :                  * Still, claim it's a bad key instead of a bad mode */
     846           0 :                 ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
     847           0 :                 break;
     848         205 :         case DNS_TKEY_MODE_GSSAPI: {
     849             :                 NTSTATUS status;
     850             :                 struct dns_server_tkey *tkey;
     851             :                 DATA_BLOB key;
     852             :                 DATA_BLOB reply;
     853         205 :                 bool created = false;
     854             : 
     855         205 :                 tkey = dns_find_tkey(dns->tkeys, in->questions[0].name);
     856         205 :                 if (tkey != NULL && tkey->complete) {
     857             :                         /* TODO: check if the key is still valid */
     858           0 :                         DEBUG(1, ("Rejecting tkey negotiation for already established key\n"));
     859           0 :                         ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADNAME;
     860         205 :                         break;
     861             :                 }
     862             : 
     863         205 :                 if (tkey == NULL) {
     864         388 :                         status = create_tkey(
     865             :                                 mem_ctx,
     866             :                                 dns,
     867         205 :                                 in->questions[0].name,
     868             :                                 in_tkey->rdata.tkey_record.algorithm,
     869             :                                 state->remote_address,
     870             :                                 state->local_address,
     871             :                                 &tkey);
     872         205 :                         if (!NT_STATUS_IS_OK(status)) {
     873           0 :                                 ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
     874           0 :                                 return ntstatus_to_werror(status);
     875             :                         }
     876         205 :                         created = true;
     877             :                 }
     878             : 
     879         205 :                 key.data = in_tkey->rdata.tkey_record.key_data;
     880         205 :                 key.length = in_tkey->rdata.tkey_record.key_size;
     881             : 
     882         205 :                 status = accept_gss_ticket(ret_tkey, dns, tkey, &key, &reply,
     883             :                                            &ret_tkey->rdata.tkey_record.error);
     884         205 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
     885           0 :                         DEBUG(1, ("More processing required\n"));
     886           0 :                         ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
     887         205 :                 } else if (NT_STATUS_IS_OK(status)) {
     888         205 :                         DBG_DEBUG("Tkey handshake completed\n");
     889         205 :                         ret_tkey->rdata.tkey_record.key_size = reply.length;
     890         205 :                         ret_tkey->rdata.tkey_record.key_data = talloc_memdup(ret_tkey,
     891             :                                                                 reply.data,
     892             :                                                                 reply.length);
     893         205 :                         if (ret_tkey->rdata.tkey_record.key_data == NULL) {
     894           0 :                                 return WERR_NOT_ENOUGH_MEMORY;
     895             :                         }
     896         205 :                         state->sign = true;
     897         205 :                         state->key_name = talloc_strdup(state->mem_ctx, tkey->name);
     898         205 :                         if (state->key_name == NULL) {
     899           0 :                                 return WERR_NOT_ENOUGH_MEMORY;
     900             :                         }
     901         205 :                         if (created) {
     902         205 :                                 add_tkey(dns->tkeys, &tkey);
     903             :                         }
     904             :                 } else {
     905           0 :                         DEBUG(1, ("GSS key negotiation returned %s\n", nt_errstr(status)));
     906           0 :                         ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
     907             :                 }
     908             : 
     909         205 :                 break;
     910             :                 }
     911           0 :         case DNS_TKEY_MODE_DELETE:
     912             :                 /* TODO: implement me */
     913           0 :                 DEBUG(1, ("Should delete tkey here\n"));
     914           0 :                 ret_tkey->rdata.tkey_record.error = DNS_RCODE_OK;
     915           0 :                 break;
     916           0 :         case DNS_TKEY_MODE_NULL:
     917             :         case DNS_TKEY_MODE_SERVER:
     918             :         case DNS_TKEY_MODE_CLIENT:
     919             :         case DNS_TKEY_MODE_LAST:
     920             :                 /* We don't have to implement these, return a mode error */
     921           0 :                 ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADMODE;
     922           0 :                 break;
     923           0 :         default:
     924           0 :                 DEBUG(1, ("Unsupported TKEY mode %d\n",
     925             :                       in_tkey->rdata.tkey_record.mode));
     926             :         }
     927             : 
     928         205 :         *answers = ret_tkey;
     929         205 :         *ancount = 1;
     930             : 
     931         205 :         return WERR_OK;
     932             : }
     933             : 
     934             : struct dns_server_process_query_state {
     935             :         struct tevent_context *ev;
     936             :         struct dns_server *dns;
     937             :         struct dns_name_question *question;
     938             : 
     939             :         struct dns_res_rec *answers;
     940             :         uint16_t ancount;
     941             :         struct dns_res_rec *nsrecs;
     942             :         uint16_t nscount;
     943             :         struct dns_res_rec *additional;
     944             :         uint16_t arcount;
     945             :         struct forwarder_string *forwarders;
     946             : };
     947             : 
     948             : static void dns_server_process_query_got_auth(struct tevent_req *subreq);
     949             : static void dns_server_process_query_got_response(struct tevent_req *subreq);
     950             : 
     951       31623 : struct tevent_req *dns_server_process_query_send(
     952             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     953             :         struct dns_server *dns, struct dns_request_state *req_state,
     954             :         const struct dns_name_packet *in)
     955             : {
     956             :         struct tevent_req *req, *subreq;
     957             :         struct dns_server_process_query_state *state;
     958       31623 :         const char **forwarders = NULL;
     959             :         unsigned int i;
     960             : 
     961       31623 :         req = tevent_req_create(mem_ctx, &state,
     962             :                                 struct dns_server_process_query_state);
     963       31623 :         if (req == NULL) {
     964           0 :                 return NULL;
     965             :         }
     966       31623 :         if (in->qdcount != 1) {
     967           4 :                 tevent_req_werror(req, DNS_ERR(FORMAT_ERROR));
     968           4 :                 return tevent_req_post(req, ev);
     969             :         }
     970             : 
     971             :         /* Windows returns NOT_IMPLEMENTED on this as well */
     972       31619 :         if (in->questions[0].question_class == DNS_QCLASS_NONE) {
     973           4 :                 tevent_req_werror(req, DNS_ERR(NOT_IMPLEMENTED));
     974           4 :                 return tevent_req_post(req, ev);
     975             :         }
     976             : 
     977       31615 :         if (in->questions[0].question_type == DNS_QTYPE_TKEY) {
     978             :                 WERROR err;
     979             : 
     980         388 :                 err = handle_tkey(dns, state, in, req_state,
     981         388 :                                   &state->answers, &state->ancount);
     982         205 :                 if (tevent_req_werror(req, err)) {
     983           0 :                         return tevent_req_post(req, ev);
     984             :                 }
     985         205 :                 tevent_req_done(req);
     986         205 :                 return tevent_req_post(req, ev);
     987             :         }
     988             : 
     989       31410 :         state->dns = dns;
     990       31410 :         state->ev = ev;
     991       31410 :         state->question = &in->questions[0];
     992             : 
     993       31410 :         forwarders = lpcfg_dns_forwarder(dns->task->lp_ctx);
     994       32270 :         for (i = 0; forwarders != NULL && forwarders[i] != NULL; i++) {
     995         860 :                 struct forwarder_string *f = talloc_zero(state,
     996             :                                                          struct forwarder_string);
     997         860 :                 f->forwarder = forwarders[i];
     998         860 :                 DLIST_ADD_END(state->forwarders, f);
     999             :         }
    1000             : 
    1001       31410 :         if (dns_authoritative_for_zone(dns, in->questions[0].name)) {
    1002             : 
    1003       31391 :                 req_state->flags |= DNS_FLAG_AUTHORITATIVE;
    1004             : 
    1005             :                 /*
    1006             :                  * Initialize the response arrays, so that we can use
    1007             :                  * them as their own talloc contexts when doing the
    1008             :                  * realloc
    1009             :                  */
    1010       31391 :                 state->answers = talloc_array(state, struct dns_res_rec, 0);
    1011       31391 :                 if (tevent_req_nomem(state->answers, req)) {
    1012           0 :                         return tevent_req_post(req, ev);
    1013             :                 }
    1014       31391 :                 state->nsrecs = talloc_array(state, struct dns_res_rec, 0);
    1015       31391 :                 if (tevent_req_nomem(state->nsrecs, req)) {
    1016           0 :                         return tevent_req_post(req, ev);
    1017             :                 }
    1018             : 
    1019       62473 :                 subreq = handle_authoritative_send(
    1020             :                         state, ev, dns, (forwarders == NULL ? NULL : forwarders[0]),
    1021       62473 :                         &in->questions[0], &state->answers, &state->nsrecs,
    1022             :                         0); /* cname_depth */
    1023       31391 :                 if (tevent_req_nomem(subreq, req)) {
    1024           0 :                         return tevent_req_post(req, ev);
    1025             :                 }
    1026       31391 :                 tevent_req_set_callback(
    1027             :                         subreq, dns_server_process_query_got_auth, req);
    1028       31391 :                 return req;
    1029             :         }
    1030             : 
    1031          27 :         if ((req_state->flags & DNS_FLAG_RECURSION_DESIRED) &&
    1032          16 :             (req_state->flags & DNS_FLAG_RECURSION_AVAIL)) {
    1033          16 :                 DEBUG(5, ("Not authoritative for '%s', forwarding\n",
    1034             :                           in->questions[0].name));
    1035             : 
    1036          16 :                 subreq = ask_forwarder_send(state, ev,
    1037             :                                             (forwarders == NULL ? NULL : forwarders[0]),
    1038           8 :                                             &in->questions[0]);
    1039          16 :                 if (tevent_req_nomem(subreq, req)) {
    1040           0 :                         return tevent_req_post(req, ev);
    1041             :                 }
    1042          16 :                 tevent_req_set_callback(
    1043             :                         subreq, dns_server_process_query_got_response, req);
    1044          16 :                 return req;
    1045             :         }
    1046             : 
    1047           3 :         tevent_req_werror(req, DNS_ERR(NAME_ERROR));
    1048           3 :         return tevent_req_post(req, ev);
    1049             : }
    1050             : 
    1051          26 : static void dns_server_process_query_got_response(struct tevent_req *subreq)
    1052             : {
    1053          26 :         struct tevent_req *req = tevent_req_callback_data(
    1054             :                 subreq, struct tevent_req);
    1055          26 :         struct dns_server_process_query_state *state = tevent_req_data(
    1056             :                 req, struct dns_server_process_query_state);
    1057             :         WERROR werr;
    1058             : 
    1059          26 :         werr = ask_forwarder_recv(subreq, state,
    1060             :                                   &state->answers, &state->ancount,
    1061             :                                   &state->nsrecs, &state->nscount,
    1062             :                                   &state->additional, &state->arcount);
    1063          26 :         TALLOC_FREE(subreq);
    1064             : 
    1065             :         /* If you get an error, attempt a different forwarder */
    1066          26 :         if (!W_ERROR_IS_OK(werr)) {
    1067          16 :                 if (state->forwarders != NULL) {
    1068          16 :                         DLIST_REMOVE(state->forwarders, state->forwarders);
    1069             :                 }
    1070             : 
    1071             :                 /* If you have run out of forwarders, simply finish */
    1072          16 :                 if (state->forwarders == NULL) {
    1073           6 :                         tevent_req_werror(req, werr);
    1074          11 :                         return;
    1075             :                 }
    1076             : 
    1077          10 :                 DEBUG(5, ("DNS query returned %s, trying another forwarder.\n",
    1078             :                           win_errstr(werr)));
    1079          15 :                 subreq = ask_forwarder_send(state, state->ev,
    1080          10 :                                             state->forwarders->forwarder,
    1081             :                                             state->question);
    1082             : 
    1083          10 :                 if (tevent_req_nomem(subreq, req)) {
    1084           0 :                         return;
    1085             :                 }
    1086             : 
    1087          10 :                 tevent_req_set_callback(subreq,
    1088             :                                         dns_server_process_query_got_response,
    1089             :                                         req);
    1090          10 :                 return;
    1091             :         }
    1092             : 
    1093          10 :         tevent_req_done(req);
    1094             : }
    1095             : 
    1096       31429 : static void dns_server_process_query_got_auth(struct tevent_req *subreq)
    1097             : {
    1098       31429 :         struct tevent_req *req = tevent_req_callback_data(
    1099             :                 subreq, struct tevent_req);
    1100       31429 :         struct dns_server_process_query_state *state = tevent_req_data(
    1101             :                 req, struct dns_server_process_query_state);
    1102             :         WERROR werr;
    1103             :         WERROR werr2;
    1104             : 
    1105       31429 :         werr = handle_authoritative_recv(subreq);
    1106       31429 :         TALLOC_FREE(subreq);
    1107             : 
    1108             :         /* If you get an error, attempt a different forwarder */
    1109       31429 :         if (!W_ERROR_IS_OK(werr)) {
    1110       20456 :                 if (state->forwarders != NULL) {
    1111          72 :                         DLIST_REMOVE(state->forwarders, state->forwarders);
    1112             :                 }
    1113             : 
    1114             :                 /* If you have run out of forwarders, simply finish */
    1115       20456 :                 if (state->forwarders == NULL) {
    1116       40807 :                         werr2 = add_zone_authority_record(state->dns,
    1117             :                                                           state,
    1118       20418 :                                                           state->question,
    1119             :                                                           &state->nsrecs);
    1120       20418 :                         if (tevent_req_werror(req, werr2)) {
    1121           6 :                                 DBG_WARNING("Failed to add SOA record: %s\n",
    1122             :                                             win_errstr(werr2));
    1123       20460 :                                 return;
    1124             :                         }
    1125             : 
    1126       20412 :                         state->ancount = talloc_array_length(state->answers);
    1127       20412 :                         state->nscount = talloc_array_length(state->nsrecs);
    1128       20412 :                         state->arcount = talloc_array_length(state->additional);
    1129             : 
    1130       20412 :                         tevent_req_werror(req, werr);
    1131       20412 :                         return;
    1132             :                 }
    1133             : 
    1134          38 :                 DEBUG(5, ("Error: %s, trying a different forwarder.\n",
    1135             :                           win_errstr(werr)));
    1136          57 :                 subreq = handle_authoritative_send(state, state->ev, state->dns,
    1137          38 :                                                    state->forwarders->forwarder,
    1138             :                                                    state->question, &state->answers,
    1139             :                                                    &state->nsrecs,
    1140             :                                                    0); /* cname_depth */
    1141             : 
    1142          38 :                 if (tevent_req_nomem(subreq, req)) {
    1143           0 :                         return;
    1144             :                 }
    1145             : 
    1146          38 :                 tevent_req_set_callback(subreq,
    1147             :                                         dns_server_process_query_got_auth,
    1148             :                                         req);
    1149          38 :                 return;
    1150             :         }
    1151             : 
    1152       21666 :         werr2 = add_zone_authority_record(state->dns,
    1153             :                                           state,
    1154       10973 :                                           state->question,
    1155             :                                           &state->nsrecs);
    1156       10973 :         if (tevent_req_werror(req, werr2)) {
    1157           0 :                 DBG_WARNING("Failed to add SOA record: %s\n",
    1158             :                                 win_errstr(werr2));
    1159           0 :                 return;
    1160             :         }
    1161             : 
    1162       10973 :         state->ancount = talloc_array_length(state->answers);
    1163       10973 :         state->nscount = talloc_array_length(state->nsrecs);
    1164       10973 :         state->arcount = talloc_array_length(state->additional);
    1165             : 
    1166       10973 :         tevent_req_done(req);
    1167             : }
    1168             : 
    1169       31623 : WERROR dns_server_process_query_recv(
    1170             :         struct tevent_req *req, TALLOC_CTX *mem_ctx,
    1171             :         struct dns_res_rec **answers,    uint16_t *ancount,
    1172             :         struct dns_res_rec **nsrecs,     uint16_t *nscount,
    1173             :         struct dns_res_rec **additional, uint16_t *arcount)
    1174             : {
    1175       31623 :         struct dns_server_process_query_state *state = tevent_req_data(
    1176             :                 req, struct dns_server_process_query_state);
    1177       31623 :         WERROR err = WERR_OK;
    1178             : 
    1179       31623 :         if (tevent_req_is_werror(req, &err)) {
    1180             : 
    1181       20448 :                 if ((!W_ERROR_EQUAL(err, DNS_ERR(NAME_ERROR))) &&
    1182          20 :                     (!W_ERROR_EQUAL(err, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST))) {
    1183          14 :                         return err;
    1184             :                 }
    1185             :         }
    1186       31609 :         *answers = talloc_move(mem_ctx, &state->answers);
    1187       31609 :         *ancount = state->ancount;
    1188       31609 :         *nsrecs = talloc_move(mem_ctx, &state->nsrecs);
    1189       31609 :         *nscount = state->nscount;
    1190       31609 :         *additional = talloc_move(mem_ctx, &state->additional);
    1191       31609 :         *arcount = state->arcount;
    1192       31609 :         return err;
    1193             : }

Generated by: LCOV version 1.13