LCOV - code coverage report
Current view: top level - source4/libcli/resolve - dns_ex.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 97 326 29.8 %
Date: 2024-04-21 15:09:00 Functions: 4 10 40.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    async getaddrinfo()/dns_lookup() name resolution module
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2005
       7             :    Copyright (C) Stefan Metzmacher 2008
       8             :    Copyright (C) Matthieu Patou 2011
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : /*
      25             :   this module uses a fork() per getaddrinfo() or dns_looup() call.
      26             :   At first that might seem crazy, but it is actually very fast,
      27             :   and solves many of the tricky problems of keeping a child
      28             :   hanging around in a librar (like what happens when the parent forks).
      29             :   We use a talloc destructor to ensure that the child is cleaned up
      30             :   when we have finished with this name resolution.
      31             : */
      32             : 
      33             : #include "includes.h"
      34             : #include "system/network.h"
      35             : #include "system/filesys.h"
      36             : #include "lib/socket/socket.h"
      37             : #include "libcli/composite/composite.h"
      38             : #include "librpc/gen_ndr/ndr_nbt.h"
      39             : #include "libcli/resolve/resolve.h"
      40             : #include "lib/util/util_net.h"
      41             : #include "lib/addns/dnsquery.h"
      42             : #include "lib/addns/dns.h"
      43             : #include "lib/util/sys_rw.h"
      44             : #include "lib/util/smb_strtox.h"
      45             : #include <arpa/nameser.h>
      46             : #include <resolv.h>
      47             : 
      48             : struct dns_ex_state {
      49             :         bool do_fallback;
      50             :         uint32_t flags;
      51             :         uint16_t port;
      52             :         struct nbt_name name;
      53             :         struct socket_address **addrs;
      54             :         char **names;
      55             :         pid_t child;
      56             :         int child_fd;
      57             :         struct tevent_fd *fde;
      58             :         struct tevent_context *event_ctx;
      59             : };
      60             : 
      61             : /*
      62             :   kill off a wayward child if needed. This allows us to stop an async
      63             :   name resolution without leaving a potentially blocking call running
      64             :   in a child
      65             : */
      66           1 : static int dns_ex_destructor(struct dns_ex_state *state)
      67             : {
      68           0 :         int status;
      69             : 
      70           1 :         kill(state->child, SIGTERM);
      71           1 :         if (waitpid(state->child, &status, WNOHANG) == 0) {
      72           1 :                 kill(state->child, SIGKILL);
      73           1 :                 waitpid(state->child, &status, 0);
      74             :         }
      75             : 
      76           1 :         return 0;
      77             : }
      78             : 
      79             : struct dns_records_container {
      80             :         char **list;
      81             :         uint32_t count;
      82             : };
      83             : 
      84           0 : static int reply_to_addrs(TALLOC_CTX *mem_ctx, uint32_t *a_num,
      85             :                           char ***cur_addrs, uint32_t total,
      86             :                           struct dns_request *reply, int port)
      87             : {
      88           0 :         char addrstr[INET6_ADDRSTRLEN];
      89           0 :         struct dns_rrec *rr;
      90           0 :         char **addrs;
      91           0 :         uint32_t i;
      92           0 :         const char *addr;
      93             : 
      94             :         /* at most we over-allocate here, but not by much */
      95           0 :         addrs = talloc_realloc(mem_ctx, *cur_addrs, char *,
      96             :                                 total + reply->num_answers);
      97           0 :         if (!addrs) {
      98           0 :                 return 0;
      99             :         }
     100           0 :         *cur_addrs = addrs;
     101             : 
     102           0 :         for (i = 0; i < reply->num_answers; i++) {
     103           0 :                 rr = reply->answers[i];
     104             : 
     105             :                 /* we are only interested in the IN class */
     106           0 :                 if (rr->r_class != DNS_CLASS_IN) {
     107           0 :                         continue;
     108             :                 }
     109             : 
     110           0 :                 if (rr->type == QTYPE_NS) {
     111             :                         /*
     112             :                          * After the record for NS will come the A or AAAA
     113             :                          * record of the NS.
     114             :                          */
     115           0 :                         break;
     116             :                 }
     117             : 
     118             :                 /* verify we actually have a record here */
     119           0 :                 if (!rr->data) {
     120           0 :                         continue;
     121             :                 }
     122             : 
     123             :                 /* we are only interested in A and AAAA records */
     124           0 :                 switch (rr->type) {
     125           0 :                 case QTYPE_A:
     126           0 :                         addr = inet_ntop(AF_INET,
     127           0 :                                          (struct in_addr *)rr->data,
     128             :                                          addrstr, sizeof(addrstr));
     129           0 :                         if (addr == NULL) {
     130           0 :                                 continue;
     131             :                         }
     132           0 :                         break;
     133           0 :                 case QTYPE_AAAA:
     134             : #ifdef HAVE_IPV6
     135           0 :                         addr = inet_ntop(AF_INET6,
     136           0 :                                          (struct in6_addr *)rr->data,
     137             :                                          addrstr, sizeof(addrstr));
     138             : #else
     139             :                         addr = NULL;
     140             : #endif
     141           0 :                         if (addr == NULL) {
     142           0 :                                 continue;
     143             :                         }
     144           0 :                         break;
     145           0 :                 default:
     146           0 :                         continue;
     147             :                 }
     148             : 
     149           0 :                 addrs[total] = talloc_asprintf(addrs, "%s@%u/%s",
     150             :                                                 addrstr, port,
     151           0 :                                                 rr->name->pLabelList->label);
     152           0 :                 if (addrs[total]) {
     153           0 :                         total++;
     154           0 :                         if (rr->type == QTYPE_A) {
     155           0 :                                 (*a_num)++;
     156             :                         }
     157             :                 }
     158             :         }
     159             : 
     160           0 :         return total;
     161             : }
     162             : 
     163           0 : static DNS_ERROR dns_lookup(TALLOC_CTX *mem_ctx, const char* name,
     164             :                             uint16_t q_type, struct dns_request **reply)
     165             : {
     166           0 :         int len, rlen;
     167           0 :         uint8_t *answer;
     168           0 :         bool loop;
     169           0 :         struct dns_buffer buf;
     170           0 :         DNS_ERROR err;
     171             : 
     172             :         /* give space for a good sized answer by default */
     173           0 :         answer = NULL;
     174           0 :         len = 1500;
     175           0 :         do {
     176           0 :                 answer = talloc_realloc(mem_ctx, answer, uint8_t, len);
     177           0 :                 if (!answer) {
     178           0 :                         return ERROR_DNS_NO_MEMORY;
     179             :                 }
     180           0 :                 rlen = res_search(name, DNS_CLASS_IN, q_type, answer, len);
     181           0 :                 if (rlen == -1) {
     182           0 :                         if (len >= 65535) {
     183           0 :                                 return ERROR_DNS_SOCKET_ERROR;
     184             :                         }
     185             :                         /* retry once with max packet size */
     186           0 :                         len = 65535;
     187           0 :                         loop = true;
     188           0 :                 } else if (rlen > len) {
     189           0 :                         len = rlen;
     190           0 :                         loop = true;
     191             :                 } else {
     192           0 :                         loop = false;
     193             :                 }
     194           0 :         } while(loop);
     195             : 
     196           0 :         buf.data = answer;
     197           0 :         buf.size = rlen;
     198           0 :         buf.offset = 0;
     199           0 :         buf.error = ERROR_DNS_SUCCESS;
     200             : 
     201           0 :         err = dns_unmarshall_request(mem_ctx, &buf, reply);
     202             : 
     203           0 :         TALLOC_FREE(answer);
     204           0 :         return err;
     205             : }
     206             : 
     207           0 : static struct dns_records_container get_a_aaaa_records(TALLOC_CTX *mem_ctx,
     208             :                                                         const char* name,
     209             :                                                         int port)
     210             : {
     211           0 :         struct dns_request *reply;
     212           0 :         struct dns_records_container ret;
     213           0 :         char **addrs = NULL;
     214           0 :         uint32_t a_num, total;
     215           0 :         uint16_t qtype;
     216           0 :         TALLOC_CTX *tmp_ctx;
     217           0 :         DNS_ERROR err;
     218             : 
     219           0 :         memset(&ret, 0, sizeof(struct dns_records_container));
     220             : 
     221           0 :         tmp_ctx = talloc_new(mem_ctx);
     222           0 :         if (!tmp_ctx) {
     223           0 :                 return ret;
     224             :         }
     225             : 
     226           0 :         qtype = QTYPE_AAAA;
     227             : 
     228             :         /* this is the blocking call we are going to lots of trouble
     229             :            to avoid them in the parent */
     230           0 :         err = dns_lookup(tmp_ctx, name, qtype, &reply);
     231           0 :         if (!ERR_DNS_IS_OK(err)) {
     232           0 :                 qtype = QTYPE_A;
     233           0 :                 err = dns_lookup(tmp_ctx, name, qtype, &reply);
     234           0 :                 if (!ERR_DNS_IS_OK(err)) {
     235           0 :                         goto done;
     236             :                 }
     237             :         }
     238             : 
     239           0 :         a_num = total = 0;
     240           0 :         total = reply_to_addrs(tmp_ctx, &a_num, &addrs, total, reply, port);
     241             : 
     242           0 :         if (qtype == QTYPE_AAAA && a_num == 0) {
     243             :                 /*
     244             :                 * DNS server didn't returned A when asked for AAAA records.
     245             :                 * Most of the server do it, let's ask for A specifically.
     246             :                 */
     247           0 :                 err = dns_lookup(tmp_ctx, name, QTYPE_A, &reply);
     248           0 :                 if (ERR_DNS_IS_OK(err)) {
     249             :                         /*
     250             :                          * Ignore an error here and just return any AAAA
     251             :                          * records we already got. This may be an IPv6-only
     252             :                          * config.
     253             :                          */
     254           0 :                         total = reply_to_addrs(tmp_ctx, &a_num, &addrs, total,
     255             :                                         reply, port);
     256             :                 }
     257             :         }
     258             : 
     259           0 :         if (total) {
     260           0 :                 talloc_steal(mem_ctx, addrs);
     261           0 :                 ret.count = total;
     262           0 :                 ret.list = addrs;
     263             :         }
     264             : 
     265           0 : done:
     266           0 :         TALLOC_FREE(tmp_ctx);
     267           0 :         return ret;
     268             : }
     269             : 
     270           0 : static struct dns_records_container get_srv_records(TALLOC_CTX *mem_ctx,
     271             :                                                         const char* name)
     272             : {
     273           0 :         struct dns_records_container ret = {0};
     274           0 :         char **addrs = NULL;
     275           0 :         struct dns_rr_srv *dclist;
     276           0 :         NTSTATUS status;
     277           0 :         size_t total;
     278           0 :         size_t i;
     279           0 :         size_t count = 0;
     280             : 
     281           0 :         memset(&ret, 0, sizeof(struct dns_records_container));
     282             :         /* this is the blocking call we are going to lots of trouble
     283             :            to avoid them in the parent */
     284           0 :         status = ads_dns_lookup_srv(mem_ctx, name, &dclist, &count);
     285           0 :         if (!NT_STATUS_IS_OK(status)) {
     286           0 :                 return ret;
     287             :         }
     288           0 :         total = 0;
     289           0 :         if (count == 0) {
     290           0 :                 return ret;
     291             :         }
     292             : 
     293             :         /* Loop over all returned records and pick the records */
     294           0 :         for (i = 0; i < count; i++) {
     295           0 :                 struct dns_records_container c;
     296           0 :                 const char* tmp_str;
     297             : 
     298           0 :                 tmp_str = dclist[i].hostname;
     299           0 :                 if (strchr(tmp_str, '.') && tmp_str[strlen(tmp_str)-1] != '.') {
     300             :                         /* we are asking for a fully qualified name, but the
     301             :                         name doesn't end in a '.'. We need to prevent the
     302             :                         DNS library trying the search domains configured in
     303             :                         resolv.conf */
     304           0 :                         tmp_str = talloc_asprintf(mem_ctx, "%s.", tmp_str);
     305             :                 }
     306             : 
     307           0 :                 c = get_a_aaaa_records(mem_ctx, tmp_str, dclist[i].port);
     308             : 
     309             :                 /* wrap check */
     310           0 :                 if (total + c.count < total) {
     311             :                         /* possibly could just break here instead? */
     312           0 :                         TALLOC_FREE(addrs);
     313           0 :                         return ret;
     314             :                 }
     315           0 :                 total += c.count;
     316           0 :                 if (addrs == NULL) {
     317           0 :                         addrs = c.list;
     318             :                 } else {
     319           0 :                         unsigned j;
     320             : 
     321           0 :                         addrs = talloc_realloc(mem_ctx, addrs, char*, total);
     322           0 :                         for (j=0; j < c.count; j++) {
     323           0 :                                 addrs[total - j - 1] = talloc_steal(addrs, c.list[j]);
     324             :                         }
     325             :                 }
     326             :         }
     327             : 
     328           0 :         if (total) {
     329           0 :                 ret.count = total;
     330           0 :                 ret.list = addrs;
     331             :         }
     332             : 
     333           0 :         return ret;
     334             : }
     335             : /*
     336             :   the blocking child
     337             : */
     338           0 : static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
     339             : {
     340           0 :         bool first;
     341           0 :         bool do_srv = (state->flags & RESOLVE_NAME_FLAG_DNS_SRV);
     342           0 :         struct dns_records_container c;
     343           0 :         char* addrs = NULL;
     344           0 :         unsigned int i;
     345             : 
     346           0 :         if (strchr(state->name.name, '.') && state->name.name[strlen(state->name.name)-1] != '.') {
     347             :                 /* we are asking for a fully qualified name, but the
     348             :                    name doesn't end in a '.'. We need to prevent the
     349             :                    DNS library trying the search domains configured in
     350             :                    resolv.conf */
     351           0 :                 state->name.name = talloc_strdup_append(discard_const_p(char, state->name.name),
     352             :                                                         ".");
     353             :         }
     354             : 
     355             : 
     356           0 :         if (do_srv) {
     357           0 :                 c = get_srv_records(state, state->name.name);
     358             :         } else {
     359           0 :                 c = get_a_aaaa_records(state, state->name.name, state->port);
     360             :         }
     361             : 
     362             :         /* This line in critical - if we return without writing to the
     363             :          * pipe, this is the signal that the name did not exist */
     364           0 :         if (c.count == 0) {
     365           0 :                 goto done;
     366             :         }
     367             : 
     368           0 :         addrs = talloc_strdup(state, "");
     369           0 :         if (!addrs) {
     370           0 :                 goto done;
     371             :         }
     372           0 :         first = true;
     373             : 
     374           0 :         for (i=0; i < c.count; i++) {
     375           0 :                 addrs = talloc_asprintf_append_buffer(addrs, "%s%s",
     376             :                                                         first?"":",",
     377           0 :                                                         c.list[i]);
     378           0 :                 first = false;
     379             :         }
     380             : 
     381           0 :         if (addrs) {
     382           0 :                 DEBUG(11, ("Addrs = %s\n", addrs));
     383           0 :                 sys_write_v(fd, addrs, talloc_get_size(addrs));
     384             :         }
     385             : 
     386           0 : done:
     387           0 :         close(fd);
     388           0 : }
     389             : 
     390             : /*
     391             :   the blocking child
     392             : */
     393           0 : static void run_child_getaddrinfo(struct dns_ex_state *state, int fd)
     394             : {
     395           0 :         int ret;
     396           0 :         struct addrinfo hints;
     397           0 :         struct addrinfo *res;
     398           0 :         struct addrinfo *res_list = NULL;
     399           0 :         char *addrs;
     400           0 :         bool first;
     401             : 
     402           0 :         ZERO_STRUCT(hints);
     403           0 :         hints.ai_socktype = SOCK_STREAM;
     404           0 :         hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
     405             : 
     406           0 :         ret = getaddrinfo(state->name.name, "0", &hints, &res_list);
     407             :         /* try to fallback in case of error */
     408           0 :         if (state->do_fallback) {
     409           0 :                 switch (ret) {
     410             : #ifdef EAI_NODATA
     411           0 :                 case EAI_NODATA:
     412             : #endif
     413             :                 case EAI_FAIL:
     414             :                         /* Linux returns EAI_NODATA on non-RFC1034-compliant names. FreeBSD returns EAI_FAIL */
     415             :                 case EAI_NONAME:
     416             :                         /* getaddrinfo() doesn't handle CNAME or non-RFC1034 compatible records */
     417           0 :                         run_child_dns_lookup(state, fd);
     418           0 :                         return;
     419           0 :                 default:
     420           0 :                         break;
     421             :                 }
     422             :         }
     423           0 :         if (ret != 0) {
     424           0 :                 goto done;
     425             :         }
     426             : 
     427           0 :         addrs = talloc_strdup(state, "");
     428           0 :         if (!addrs) {
     429           0 :                 goto done;
     430             :         }
     431           0 :         first = true;
     432           0 :         for (res = res_list; res; res = res->ai_next) {
     433           0 :                 char addrstr[INET6_ADDRSTRLEN];
     434           0 :                 if (!print_sockaddr_len(addrstr, sizeof(addrstr), (struct sockaddr *)res->ai_addr, res->ai_addrlen)) {
     435           0 :                         continue;
     436             :                 }
     437           0 :                 addrs = talloc_asprintf_append_buffer(addrs, "%s%s@%u/%s",
     438             :                                                       first?"":",",
     439             :                                                       addrstr,
     440           0 :                                                       state->port,
     441             :                                                       state->name.name);
     442           0 :                 if (!addrs) {
     443           0 :                         goto done;
     444             :                 }
     445           0 :                 first = false;
     446             :         }
     447             : 
     448           0 :         if (addrs) {
     449           0 :                 sys_write_v(fd, addrs, talloc_get_size(addrs));
     450             :         }
     451           0 : done:
     452           0 :         if (res_list) {
     453           0 :                 freeaddrinfo(res_list);
     454             :         }
     455           0 :         close(fd);
     456             : }
     457             : 
     458             : /*
     459             :   handle a read event on the pipe
     460             : */
     461       54083 : static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, 
     462             :                          uint16_t flags, void *private_data)
     463             : {
     464       54083 :         struct composite_context *c = talloc_get_type(private_data, struct composite_context);
     465       54083 :         struct dns_ex_state *state = talloc_get_type(c->private_data,
     466             :                                      struct dns_ex_state);
     467        1529 :         char *address;
     468        1529 :         uint32_t num_addrs, i;
     469        1529 :         char **addrs;
     470        1529 :         int ret;
     471        1529 :         int status;
     472       54083 :         int value = 0;
     473             : 
     474             :         /* if we get any event from the child then we know that we
     475             :            won't need to kill it off */
     476       54083 :         talloc_set_destructor(state, NULL);
     477             : 
     478       54083 :         if (ioctl(state->child_fd, FIONREAD, &value) != 0) {
     479           0 :                 value = 8192;
     480             :         }
     481             : 
     482       54083 :         address = talloc_array(state, char, value+1);
     483       54083 :         if (address) {
     484             :                 /* yes, we don't care about EAGAIN or other niceities
     485             :                    here. They just can't happen with this parent/child
     486             :                    relationship, and even if they did then giving an error is
     487             :                    the right thing to do */
     488       55612 :                 ret = read(state->child_fd, address, value);
     489             :         } else {
     490           0 :                 ret = -1;
     491             :         }
     492       54083 :         if (waitpid(state->child, &status, WNOHANG) == 0) {
     493       53896 :                 kill(state->child, SIGKILL);
     494       53896 :                 waitpid(state->child, &status, 0);
     495             :         }
     496             : 
     497       54083 :         if (ret <= 0) {
     498             :                 /* The check for ret == 0 here is important, if the
     499             :                  * name does not exist, then no bytes are written to
     500             :                  * the pipe */
     501        4524 :                 DEBUG(3,("dns child failed to find name '%s' of type %s\n",
     502             :                          state->name.name, (state->flags & RESOLVE_NAME_FLAG_DNS_SRV)?"SRV":"A"));
     503        4524 :                 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     504        4524 :                 return;
     505             :         }
     506             : 
     507             :         /* ensure the address looks good */
     508       49559 :         address[ret] = 0;
     509             : 
     510       49559 :         addrs = str_list_make(state, address, ",");
     511       49559 :         if (composite_nomem(addrs, c)) return;
     512             : 
     513       49559 :         num_addrs = str_list_length((const char * const *)addrs);
     514             : 
     515       49559 :         state->addrs = talloc_array(state, struct socket_address *,
     516             :                                     num_addrs+1);
     517       49559 :         if (composite_nomem(state->addrs, c)) return;
     518             : 
     519       49559 :         state->names = talloc_array(state, char *, num_addrs+1);
     520       49559 :         if (composite_nomem(state->names, c)) return;
     521             : 
     522      145595 :         for (i=0; i < num_addrs; i++) {
     523       96036 :                 uint32_t port = 0;
     524       96036 :                 char *p = strrchr(addrs[i], '@');
     525        3058 :                 char *n;
     526       96036 :                 int error = 0;
     527             : 
     528       96036 :                 if (!p) {
     529           0 :                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     530           0 :                         return;
     531             :                 }
     532             : 
     533       96036 :                 *p = '\0';
     534       96036 :                 p++;
     535             : 
     536       96036 :                 n = strrchr(p, '/');
     537       96036 :                 if (!n) {
     538           0 :                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     539           0 :                         return;
     540             :                 }
     541             : 
     542       96036 :                 *n = '\0';
     543       96036 :                 n++;
     544             : 
     545       96036 :                 if (strcmp(addrs[i], "0.0.0.0") == 0) {
     546           0 :                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     547           0 :                         return;
     548             :                 }
     549       96036 :                 port = smb_strtoul(p, NULL, 10, &error, SMB_STR_STANDARD);
     550       96036 :                 if (port > UINT16_MAX || error != 0) {
     551           0 :                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     552           0 :                         return;
     553             :                 }
     554      189014 :                 state->addrs[i] = socket_address_from_strings(state->addrs,
     555             :                                                               "ip",
     556       92978 :                                                               addrs[i],
     557             :                                                               port);
     558       96036 :                 if (composite_nomem(state->addrs[i], c)) return;
     559             : 
     560       96036 :                 state->names[i] = talloc_strdup(state->names, n);
     561       96036 :                 if (composite_nomem(state->names[i], c)) return;
     562             :         }
     563       49559 :         state->addrs[i] = NULL;
     564       49559 :         state->names[i] = NULL;
     565             : 
     566       49559 :         composite_done(c);
     567             : }
     568             : 
     569             : /*
     570             :   getaddrinfo() or dns_lookup() name resolution method - async send
     571             :  */
     572       54084 : struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
     573             :                                                    struct tevent_context *event_ctx,
     574             :                                                    void *privdata,
     575             :                                                    uint32_t flags,
     576             :                                                    uint16_t port,
     577             :                                                    struct nbt_name *name,
     578             :                                                    bool do_fallback)
     579             : {
     580        1529 :         struct composite_context *c;
     581        1529 :         struct dns_ex_state *state;
     582       54084 :         int fd[2] = { -1, -1 };
     583        1529 :         int ret;
     584             : 
     585       54084 :         c = composite_create(mem_ctx, event_ctx);
     586       54084 :         if (c == NULL) return NULL;
     587             : 
     588       54084 :         if (flags & RESOLVE_NAME_FLAG_FORCE_NBT) {
     589           0 :                 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     590           0 :                 return c;
     591             :         }
     592             : 
     593       54084 :         state = talloc_zero(c, struct dns_ex_state);
     594       54084 :         if (composite_nomem(state, c)) return c;
     595       54084 :         c->private_data = state;
     596             : 
     597       54084 :         c->status = nbt_name_dup(state, name, &state->name);
     598       54084 :         if (!composite_is_ok(c)) return c;
     599             : 
     600             :         /* setup a pipe to chat to our child */
     601       54084 :         ret = pipe(fd);
     602       54084 :         if (ret == -1) {
     603           0 :                 composite_error(c, map_nt_error_from_unix_common(errno));
     604           0 :                 return c;
     605             :         }
     606             : 
     607       54084 :         state->do_fallback = do_fallback;
     608       54084 :         state->flags = flags;
     609       54084 :         state->port = port;
     610             : 
     611       54084 :         state->child_fd = fd[0];
     612       54084 :         state->event_ctx = c->event_ctx;
     613             : 
     614             :         /* we need to put the child in our event context so
     615             :            we know when the dns_lookup() has finished */
     616       54084 :         state->fde = tevent_add_fd(c->event_ctx, c, state->child_fd, TEVENT_FD_READ,
     617             :                                   pipe_handler, c);
     618       54084 :         if (composite_nomem(state->fde, c)) {
     619           0 :                 close(fd[0]);
     620           0 :                 close(fd[1]);
     621           0 :                 return c;
     622             :         }
     623       54084 :         tevent_fd_set_auto_close(state->fde);
     624             : 
     625       54084 :         state->child = fork();
     626       54084 :         if (state->child == (pid_t)-1) {
     627           0 :                 composite_error(c, map_nt_error_from_unix_common(errno));
     628           0 :                 return c;
     629             :         }
     630             : 
     631       54084 :         if (state->child == 0) {
     632           0 :                 close(fd[0]);
     633           0 :                 if (state->flags & RESOLVE_NAME_FLAG_FORCE_DNS) {
     634           0 :                         run_child_dns_lookup(state, fd[1]);
     635             :                 } else {
     636           0 :                         run_child_getaddrinfo(state, fd[1]);
     637             :                 }
     638           0 :                 _exit(0);
     639             :         }
     640       54084 :         close(fd[1]);
     641             : 
     642             :         /* cleanup wayward children */
     643       54084 :         talloc_set_destructor(state, dns_ex_destructor);
     644             : 
     645       54084 :         return c;
     646             : }
     647             : 
     648             : /*
     649             :   getaddrinfo() or dns_lookup() name resolution method - recv side
     650             : */
     651       54083 : NTSTATUS resolve_name_dns_ex_recv(struct composite_context *c, 
     652             :                                   TALLOC_CTX *mem_ctx,
     653             :                                   struct socket_address ***addrs,
     654             :                                   char ***names)
     655             : {
     656        1529 :         NTSTATUS status;
     657             : 
     658       54083 :         status = composite_wait(c);
     659             : 
     660       54083 :         if (NT_STATUS_IS_OK(status)) {
     661       49559 :                 struct dns_ex_state *state = talloc_get_type(c->private_data,
     662             :                                              struct dns_ex_state);
     663       49559 :                 *addrs = talloc_steal(mem_ctx, state->addrs);
     664       49559 :                 if (names) {
     665       49272 :                         *names = talloc_steal(mem_ctx, state->names);
     666             :                 }
     667             :         }
     668             : 
     669       54083 :         talloc_free(c);
     670       54083 :         return status;
     671             : }

Generated by: LCOV version 1.14