LCOV - code coverage report
Current view: top level - dirmngr - dns-stuff.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 34 643 5.3 %
Date: 2016-12-01 18:37:21 Functions: 4 25 16.0 %

          Line data    Source code
       1             : /* dns-stuff.c - DNS related code including CERT RR (rfc-4398)
       2             :  * Copyright (C) 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2005, 2006, 2009, 2015. 2016 Werner Koch
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * This file is free software; you can redistribute it and/or modify
       8             :  * it under the terms of either
       9             :  *
      10             :  *   - the GNU Lesser General Public License as published by the Free
      11             :  *     Software Foundation; either version 3 of the License, or (at
      12             :  *     your option) any later version.
      13             :  *
      14             :  * or
      15             :  *
      16             :  *   - the GNU General Public License as published by the Free
      17             :  *     Software Foundation; either version 2 of the License, or (at
      18             :  *     your option) any later version.
      19             :  *
      20             :  * or both in parallel, as here.
      21             :  *
      22             :  * This file is distributed in the hope that it will be useful,
      23             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      24             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      25             :  * GNU General Public License for more details.
      26             :  *
      27             :  * You should have received a copy of the GNU General Public License
      28             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      29             :  */
      30             : 
      31             : #include <config.h>
      32             : #include <sys/types.h>
      33             : #ifdef HAVE_W32_SYSTEM
      34             : # ifdef HAVE_WINSOCK2_H
      35             : #  include <winsock2.h>
      36             : # endif
      37             : # include <windows.h>
      38             : #else
      39             : # if HAVE_SYSTEM_RESOLVER
      40             : #  include <netinet/in.h>
      41             : #  include <arpa/nameser.h>
      42             : #  include <resolv.h>
      43             : # endif
      44             : # include <netdb.h>
      45             : #endif
      46             : #include <string.h>
      47             : #include <unistd.h>
      48             : #ifdef USE_ADNS
      49             : # include <adns.h>
      50             : #endif
      51             : 
      52             : #if !defined(HAVE_GETADDRINFO) && !defined(USE_ADNS)
      53             : # error Either getaddrinfo or the ADNS library is required.
      54             : #endif
      55             : 
      56             : #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
      57             : # undef USE_NPTH
      58             : #endif
      59             : #ifdef USE_NPTH
      60             : # include <npth.h>
      61             : #endif
      62             : 
      63             : #include "util.h"
      64             : #include "host2net.h"
      65             : #include "dns-stuff.h"
      66             : 
      67             : #ifdef USE_NPTH
      68             : # define my_unprotect()        npth_unprotect ()
      69             : # define my_protect()          npth_protect ()
      70             : #else
      71             : # define my_unprotect()        do { } while(0)
      72             : # define my_protect()          do { } while(0)
      73             : #endif
      74             : 
      75             : /* We allow the use of 0 instead of AF_UNSPEC - check this assumption.  */
      76             : #if AF_UNSPEC != 0
      77             : # error AF_UNSPEC does not have the value 0
      78             : #endif
      79             : 
      80             : /* Windows does not support the AI_ADDRCONFIG flag - use zero instead.  */
      81             : #ifndef AI_ADDRCONFIG
      82             : # define AI_ADDRCONFIG 0
      83             : #endif
      84             : 
      85             : /* Provide a replacement function for older ADNS versions.  */
      86             : #ifndef HAVE_ADNS_FREE
      87             : # define adns_free(a) free ((a))
      88             : #endif
      89             : 
      90             : /* Not every installation has gotten around to supporting SRVs or
      91             :    CERTs yet... */
      92             : #ifndef T_SRV
      93             : #define T_SRV 33
      94             : #endif
      95             : #ifndef T_CERT
      96             : # define T_CERT 37
      97             : #endif
      98             : 
      99             : /* ADNS has no support for CERT yet. */
     100             : #define my_adns_r_cert 37
     101             : 
     102             : 
     103             : /* The default nameserver used with ADNS in Tor mode.  */
     104             : #define DEFAULT_NAMESERVER "8.8.8.8"
     105             : 
     106             : /* If set force the use of the standard resolver.  */
     107             : static int standard_resolver;
     108             : 
     109             : /* If set Tor mode shall be used.  */
     110             : static int tor_mode;
     111             : 
     112             : /* A string with the nameserver IP address used with Tor.
     113             :   (40 should be sufficient for v6 but we add some extra for a scope.) */
     114             : static char tor_nameserver[40+20];
     115             : 
     116             : /* A string to hold the credentials presented to Tor.  */
     117             : #ifdef USE_ADNS
     118             : static char tor_credentials[50];
     119             : #endif
     120             : 
     121             : 
     122             : /* Calling this function with YES set to True forces the use of the
     123             :  * standard resolver even if dirmngr has been built with support for
     124             :  * an alternative resolver.  */
     125             : void
     126           0 : enable_standard_resolver (int yes)
     127             : {
     128           0 :   standard_resolver = yes;
     129           0 : }
     130             : 
     131             : 
     132             : /* Return true if the standard resolver is used.  */
     133             : int
     134           0 : standard_resolver_p (void)
     135             : {
     136           0 :   return standard_resolver;
     137             : }
     138             : 
     139             : 
     140             : /* Sets the module in Tor mode.  Returns 0 is this is possible or an
     141             :    error code.  */
     142             : gpg_error_t
     143           0 : enable_dns_tormode (int new_circuit)
     144             : {
     145             :   (void) new_circuit;
     146             : 
     147             : #ifdef USE_ADNS
     148             : # if HAVE_ADNS_IF_TORMODE
     149             :    if (!*tor_credentials || new_circuit)
     150             :      {
     151             :        static unsigned int counter;
     152             : 
     153             :        gpgrt_snprintf (tor_credentials, sizeof tor_credentials,
     154             :                        "dirmngr-%lu:p%u",
     155             :                        (unsigned long)getpid (), counter);
     156             :        counter++;
     157             :      }
     158             :    tor_mode = 1;
     159             :    return 0;
     160             : # endif
     161             : #endif
     162             : 
     163           0 :   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     164             : }
     165             : 
     166             : 
     167             : /* Change the default IP address of the nameserver to IPADDR.  The
     168             :    address needs to be a numerical IP address and will be used for the
     169             :    next DNS query.  Note that this is only used in Tor mode.  */
     170             : void
     171           0 : set_dns_nameserver (const char *ipaddr)
     172             : {
     173           0 :   strncpy (tor_nameserver, ipaddr? ipaddr : DEFAULT_NAMESERVER,
     174             :            sizeof tor_nameserver -1);
     175           0 :   tor_nameserver[sizeof tor_nameserver -1] = 0;
     176           0 : }
     177             : 
     178             : 
     179             : /* Free an addressinfo linked list as returned by resolve_dns_name.  */
     180             : void
     181           0 : free_dns_addrinfo (dns_addrinfo_t ai)
     182             : {
     183           0 :   while (ai)
     184             :     {
     185           0 :       dns_addrinfo_t next = ai->next;
     186           0 :       xfree (ai);
     187           0 :       ai = next;
     188             :     }
     189           0 : }
     190             : 
     191             : 
     192             : static gpg_error_t
     193           0 : map_eai_to_gpg_error (int ec)
     194             : {
     195             :   gpg_error_t err;
     196             : 
     197           0 :   switch (ec)
     198             :     {
     199           0 :     case EAI_AGAIN:     err = gpg_error (GPG_ERR_EAGAIN); break;
     200           0 :     case EAI_BADFLAGS:  err = gpg_error (GPG_ERR_INV_FLAG); break;
     201           0 :     case EAI_FAIL:      err = gpg_error (GPG_ERR_SERVER_FAILED); break;
     202           0 :     case EAI_MEMORY:    err = gpg_error (GPG_ERR_ENOMEM); break;
     203             : #ifdef EAI_NODATA
     204           0 :     case EAI_NODATA:    err = gpg_error (GPG_ERR_NO_DATA); break;
     205             : #endif
     206           0 :     case EAI_NONAME:    err = gpg_error (GPG_ERR_NO_NAME); break;
     207           0 :     case EAI_SERVICE:   err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
     208           0 :     case EAI_FAMILY:    err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
     209           0 :     case EAI_SOCKTYPE:  err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
     210             : #ifndef HAVE_W32_SYSTEM
     211             : # ifdef EAI_ADDRFAMILY
     212           0 :     case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
     213             : # endif
     214           0 :     case EAI_SYSTEM:    err = gpg_error_from_syserror (); break;
     215             : #endif
     216           0 :     default:            err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
     217             :     }
     218           0 :   return err;
     219             : }
     220             : 
     221             : #ifdef USE_ADNS
     222             : static gpg_error_t
     223           1 : map_adns_status_to_gpg_error (adns_status status)
     224             : {
     225             :   gpg_err_code_t ec;
     226             : 
     227             :   switch (status)
     228             :     {
     229             :     /* case adns_s_netunreach: ec = GPG_ERR_ENETUNREACH; break; */
     230           1 :     default: ec = GPG_ERR_GENERAL; break;
     231             :     }
     232           1 :   return gpg_error (ec);
     233             : }
     234             : #endif /*USE_ADNS*/
     235             : 
     236             : 
     237             : #ifdef USE_ADNS
     238             : /* Init ADNS and store the new state at R_STATE.  Returns 0 on
     239             :    success; prints an error message and returns an error code on
     240             :    failure.  */
     241             : static gpg_error_t
     242           1 : my_adns_init (adns_state *r_state)
     243             : {
     244           1 :   gpg_error_t err = 0;
     245             :   int ret;
     246             : 
     247           1 :   if (tor_mode)
     248             :     {
     249             :       char *cfgstr;
     250             : 
     251           0 :       if (!*tor_nameserver)
     252           0 :         set_dns_nameserver (NULL);
     253             : 
     254           0 :       cfgstr = xtryasprintf ("nameserver %s\n"
     255             :                              "options adns_tormode adns_sockscred:%s",
     256             :                              tor_nameserver, tor_credentials);
     257           0 :       if (!cfgstr)
     258           0 :         err = gpg_error_from_syserror ();
     259             :       else
     260             :         {
     261           0 :           ret = adns_init_strcfg (r_state, adns_if_debug /*adns_if_noerrprint*/, NULL, cfgstr);
     262           0 :           if (ret)
     263           0 :             err = gpg_error_from_errno (ret);
     264           0 :           xfree (cfgstr);
     265             :         }
     266             :     }
     267             :   else
     268             :     {
     269           1 :       ret = adns_init (r_state, adns_if_noerrprint, NULL);
     270           1 :       if (ret)
     271           0 :         err = gpg_error_from_errno (ret);
     272             :     }
     273             : 
     274           1 :   if (err)
     275             :     {
     276           0 :       log_error ("error initializing adns: %s\n", gpg_strerror (err));
     277           0 :       return err;
     278             :     }
     279           1 :   return 0;
     280             : }
     281             : #endif /*USE_ADNS*/
     282             : 
     283             : 
     284             : #ifdef USE_ADNS
     285             : /* Resolve a name using the ADNS library.  See resolve_dns_name for
     286             :    the description.  */
     287             : static gpg_error_t
     288           0 : resolve_name_adns (const char *name, unsigned short port,
     289             :                    int want_family, int want_socktype,
     290             :                    dns_addrinfo_t *r_dai, char **r_canonname)
     291             : {
     292           0 :   gpg_error_t err = 0;
     293             :   int ret;
     294           0 :   dns_addrinfo_t daihead = NULL;
     295             :   dns_addrinfo_t dai;
     296             :   adns_state state;
     297           0 :   adns_answer *answer = NULL;
     298             :   int count;
     299             : 
     300             :   (void)want_family;
     301             : 
     302           0 :   *r_dai = NULL;
     303           0 :   if (r_canonname)
     304           0 :     *r_canonname = NULL;
     305             : 
     306           0 :   if (want_socktype != SOCK_STREAM && want_socktype != SOCK_DGRAM)
     307           0 :     return gpg_error (GPG_ERR_ESOCKTNOSUPPORT);
     308             : 
     309           0 :   err = my_adns_init (&state);
     310           0 :   if (err)
     311           0 :     return err;
     312             : 
     313           0 :   my_unprotect ();
     314           0 :   ret = adns_synchronous (state, name, adns_r_addr,
     315             :                           adns_qf_quoteok_query, &answer);
     316           0 :   my_protect ();
     317           0 :   if (ret)
     318             :     {
     319           0 :       err = gpg_error (gpg_err_code_from_errno (ret));
     320           0 :       log_error ("DNS query failed: %s\n", gpg_strerror (err));
     321           0 :       goto leave;
     322             :     }
     323             : 
     324           0 :   err = gpg_error (GPG_ERR_NOT_FOUND);
     325           0 :   if (answer->status != adns_s_ok || answer->type != adns_r_addr)
     326             :     {
     327           0 :       err = map_adns_status_to_gpg_error (answer->status);
     328           0 :       if (gpg_err_code (err) == GPG_ERR_GENERAL)
     329           0 :         err = gpg_error (GPG_ERR_NOT_FOUND);
     330           0 :       log_error ("DNS query returned an error: %s (%s)\n",
     331           0 :                  adns_strerror (answer->status),
     332           0 :                  adns_errabbrev (answer->status));
     333           0 :       goto leave;
     334             :     }
     335             : 
     336           0 :   if (r_canonname && answer->cname)
     337             :     {
     338           0 :       *r_canonname = xtrystrdup (answer->cname);
     339           0 :       if (!*r_canonname)
     340             :         {
     341           0 :           err = gpg_error_from_syserror ();
     342           0 :           goto leave;
     343             :         }
     344             :     }
     345             : 
     346           0 :   for (count = 0; count < answer->nrrs; count++)
     347             :     {
     348             :       int len;
     349             :       adns_rr_addr *addr;
     350             : 
     351           0 :       len  = answer->rrs.addr[count].len;
     352           0 :       addr = &answer->rrs.addr[count];
     353           0 :       if (addr->addr.sa.sa_family != AF_INET6
     354           0 :           && addr->addr.sa.sa_family != AF_INET)
     355           0 :         continue;
     356             : 
     357           0 :       dai = xtrymalloc (sizeof *dai + len - 1);
     358           0 :       if (!dai)
     359             :         {
     360           0 :           err = gpg_error_from_syserror ();
     361           0 :           goto leave;
     362             :         }
     363           0 :       dai->family = addr->addr.sa.sa_family;
     364           0 :       dai->socktype = want_socktype == SOCK_STREAM? SOCK_STREAM : SOCK_DGRAM;
     365           0 :       dai->protocol = want_socktype == SOCK_STREAM? IPPROTO_TCP : IPPROTO_UDP;
     366           0 :       dai->addrlen = len;
     367           0 :       memcpy (dai->addr, &addr->addr.sa, len);
     368           0 :       ((struct sockaddr_in *) dai->addr)->sin_port = htons (port);
     369           0 :       dai->next = daihead;
     370           0 :       daihead = dai;
     371           0 :       err = 0;
     372             :     }
     373             : 
     374             :  leave:
     375           0 :   adns_free (answer);
     376           0 :   adns_finish (state);
     377           0 :   if (err)
     378             :     {
     379           0 :       if (r_canonname)
     380             :         {
     381           0 :           xfree (*r_canonname);
     382           0 :           *r_canonname = NULL;
     383             :         }
     384           0 :       free_dns_addrinfo (daihead);
     385             :     }
     386             :   else
     387           0 :     *r_dai = daihead;
     388           0 :   return err;
     389             : }
     390             : #endif /*USE_ADNS*/
     391             : 
     392             : 
     393             : /* Resolve a name using the standard system function.  */
     394             : static gpg_error_t
     395           0 : resolve_name_standard (const char *name, unsigned short port,
     396             :                        int want_family, int want_socktype,
     397             :                        dns_addrinfo_t *r_dai, char **r_canonname)
     398             : {
     399           0 :   gpg_error_t err = 0;
     400           0 :   dns_addrinfo_t daihead = NULL;
     401             :   dns_addrinfo_t dai;
     402           0 :   struct addrinfo *aibuf = NULL;
     403             :   struct addrinfo hints, *ai;
     404             :   char portstr[21];
     405             :   int ret;
     406             : 
     407           0 :   *r_dai = NULL;
     408           0 :   if (r_canonname)
     409           0 :     *r_canonname = NULL;
     410             : 
     411           0 :   memset (&hints, 0, sizeof hints);
     412           0 :   hints.ai_family = want_family;
     413           0 :   hints.ai_socktype = want_socktype;
     414           0 :   hints.ai_flags = AI_ADDRCONFIG;
     415           0 :   if (r_canonname)
     416           0 :     hints.ai_flags |= AI_CANONNAME;
     417             : 
     418           0 :   if (port)
     419           0 :     snprintf (portstr, sizeof portstr, "%hu", port);
     420             :   else
     421           0 :     *portstr = 0;
     422             : 
     423             :   /* We can't use the the AI_IDN flag because that does the conversion
     424             :      using the current locale.  However, GnuPG always used UTF-8.  To
     425             :      support IDN we would need to make use of the libidn API.  */
     426           0 :   ret = getaddrinfo (name, *portstr? portstr : NULL, &hints, &aibuf);
     427           0 :   if (ret)
     428             :     {
     429           0 :       aibuf = NULL;
     430           0 :       err = map_eai_to_gpg_error (ret);
     431           0 :       if (gpg_err_code (err) == GPG_ERR_NO_NAME)
     432             :         {
     433             :           /* There seems to be a bug in the glibc getaddrinfo function
     434             :              if the CNAME points to a long list of A and AAAA records
     435             :              in which case the function return NO_NAME.  Let's do the
     436             :              CNAME redirection again.  */
     437             :           char *cname;
     438             : 
     439           0 :           if (get_dns_cname (name, &cname))
     440           0 :             goto leave; /* Still no success.  */
     441             : 
     442           0 :           ret = getaddrinfo (cname, *portstr? portstr : NULL, &hints, &aibuf);
     443           0 :           xfree (cname);
     444           0 :           if (ret)
     445             :             {
     446           0 :               aibuf = NULL;
     447           0 :               err = map_eai_to_gpg_error (ret);
     448           0 :               goto leave;
     449             :             }
     450           0 :           err = 0; /* Yep, now it worked.  */
     451             :         }
     452             :       else
     453           0 :         goto leave;
     454             :     }
     455             : 
     456           0 :   if (r_canonname && aibuf && aibuf->ai_canonname)
     457             :     {
     458           0 :       *r_canonname = xtrystrdup (aibuf->ai_canonname);
     459           0 :       if (!*r_canonname)
     460             :         {
     461           0 :           err = gpg_error_from_syserror ();
     462           0 :           goto leave;
     463             :         }
     464             :     }
     465             : 
     466           0 :   for (ai = aibuf; ai; ai = ai->ai_next)
     467             :     {
     468           0 :       if (ai->ai_family != AF_INET6 && ai->ai_family != AF_INET)
     469           0 :         continue;
     470             : 
     471           0 :       dai = xtrymalloc (sizeof *dai + ai->ai_addrlen - 1);
     472           0 :       dai->family = ai->ai_family;
     473           0 :       dai->socktype = ai->ai_socktype;
     474           0 :       dai->protocol = ai->ai_protocol;
     475           0 :       dai->addrlen = ai->ai_addrlen;
     476           0 :       memcpy (dai->addr, ai->ai_addr, ai->ai_addrlen);
     477           0 :       dai->next = daihead;
     478           0 :       daihead = dai;
     479             :     }
     480             : 
     481             :  leave:
     482           0 :   if (aibuf)
     483           0 :     freeaddrinfo (aibuf);
     484           0 :   if (err)
     485             :     {
     486           0 :       if (r_canonname)
     487             :         {
     488           0 :           xfree (*r_canonname);
     489           0 :           *r_canonname = NULL;
     490             :         }
     491           0 :       free_dns_addrinfo (daihead);
     492             :     }
     493             :   else
     494           0 :     *r_dai = daihead;
     495           0 :   return err;
     496             : }
     497             : 
     498             : 
     499             : /* Resolve an address using the standard system function.  */
     500             : static gpg_error_t
     501           0 : resolve_addr_standard (const struct sockaddr *addr, int addrlen,
     502             :                        unsigned int flags, char **r_name)
     503             : {
     504             :   gpg_error_t err;
     505             :   int ec;
     506             :   char *buffer, *p;
     507             :   int buflen;
     508             : 
     509           0 :   *r_name = NULL;
     510             : 
     511           0 :   buflen = NI_MAXHOST;
     512           0 :   buffer = xtrymalloc (buflen + 2 + 1);
     513           0 :   if (!buffer)
     514           0 :     return gpg_error_from_syserror ();
     515             : 
     516           0 :   if ((flags & DNS_NUMERICHOST) || tor_mode)
     517           0 :     ec = EAI_NONAME;
     518             :   else
     519           0 :     ec = getnameinfo (addr, addrlen, buffer, buflen, NULL, 0, NI_NAMEREQD);
     520             : 
     521           0 :   if (!ec && *buffer == '[')
     522           0 :     ec = EAI_FAIL;  /* A name may never start with a bracket.  */
     523           0 :   else if (ec == EAI_NONAME)
     524             :     {
     525           0 :       p = buffer;
     526           0 :       if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
     527             :         {
     528           0 :           *p++ = '[';
     529           0 :           buflen -= 2;
     530             :         }
     531           0 :       ec = getnameinfo (addr, addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
     532           0 :       if (!ec && addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
     533           0 :         strcat (buffer, "]");
     534             :     }
     535             : 
     536           0 :   if (ec)
     537           0 :     err = map_eai_to_gpg_error (ec);
     538             :   else
     539             :     {
     540           0 :       p = xtryrealloc (buffer, strlen (buffer)+1);
     541           0 :       if (!p)
     542           0 :         err = gpg_error_from_syserror ();
     543             :       else
     544             :         {
     545           0 :           buffer = p;
     546           0 :           err = 0;
     547             :         }
     548             :     }
     549             : 
     550           0 :   if (err)
     551           0 :     xfree (buffer);
     552             :   else
     553           0 :     *r_name = buffer;
     554             : 
     555           0 :   return err;
     556             : }
     557             : 
     558             : 
     559             : /* This a wrapper around getaddrinfo with slightly different semantics.
     560             :    NAME is the name to resolve.
     561             :    PORT is the requested port or 0.
     562             :    WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
     563             :    WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
     564             : 
     565             :    On success the result is stored in a linked list with the head
     566             :    stored at the address R_AI; the caller must call gpg_addrinfo_free
     567             :    on this.  If R_CANONNAME is not NULL the official name of the host
     568             :    is stored there as a malloced string; if that name is not available
     569             :    NULL is stored.  */
     570             : gpg_error_t
     571           0 : resolve_dns_name (const char *name, unsigned short port,
     572             :                   int want_family, int want_socktype,
     573             :                   dns_addrinfo_t *r_ai, char **r_canonname)
     574             : {
     575             : #ifdef USE_ADNS
     576           0 :   if (!standard_resolver)
     577           0 :     return resolve_name_adns (name, port, want_family, want_socktype,
     578             :                               r_ai, r_canonname);
     579             : #endif
     580           0 :   return resolve_name_standard (name, port, want_family, want_socktype,
     581             :                                 r_ai, r_canonname);
     582             : }
     583             : 
     584             : 
     585             : gpg_error_t
     586           0 : resolve_dns_addr (const struct sockaddr *addr, int addrlen,
     587             :                   unsigned int flags, char **r_name)
     588             : {
     589           0 :   return resolve_addr_standard (addr, addrlen, flags, r_name);
     590             : }
     591             : 
     592             : 
     593             : /* Check whether NAME is an IP address.  Returns true if it is either
     594             :    an IPv6 or IPv4 numerical address.  */
     595             : int
     596           0 : is_ip_address (const char *name)
     597             : {
     598             :   const char *s;
     599             :   int ndots, dblcol, n;
     600             : 
     601           0 :   if (*name == '[')
     602           0 :     return 1; /* yes: A legal DNS name may not contain this character;
     603             :                  this mut be bracketed v6 address.  */
     604           0 :   if (*name == '.')
     605           0 :     return 0; /* No.  A leading dot is not a valid IP address.  */
     606             : 
     607             :   /* Check whether this is a v6 address.  */
     608           0 :   ndots = n = dblcol = 0;
     609           0 :   for (s=name; *s; s++)
     610             :     {
     611           0 :       if (*s == ':')
     612             :         {
     613           0 :           ndots++;
     614           0 :           if (s[1] == ':')
     615             :             {
     616           0 :               ndots++;
     617           0 :               if (dblcol)
     618           0 :                 return 0; /* No: Only one "::" allowed.  */
     619           0 :               dblcol++;
     620           0 :               if (s[1])
     621           0 :                 s++;
     622             :             }
     623           0 :           n = 0;
     624             :         }
     625           0 :       else if (*s == '.')
     626           0 :         goto legacy;
     627           0 :       else if (!strchr ("0123456789abcdefABCDEF", *s))
     628           0 :         return 0; /* No: Not a hex digit.  */
     629           0 :       else if (++n > 4)
     630           0 :         return 0; /* To many digits in a group.  */
     631             :     }
     632           0 :   if (ndots > 7)
     633           0 :     return 0; /* No: Too many colons.  */
     634           0 :   else if (ndots > 1)
     635           0 :     return 1; /* Yes: At least 2 colons indicate an v6 address.  */
     636             : 
     637             :  legacy:
     638             :   /* Check whether it is legacy IP address.  */
     639           0 :   ndots = n = 0;
     640           0 :   for (s=name; *s; s++)
     641             :     {
     642           0 :       if (*s == '.')
     643             :         {
     644           0 :           if (s[1] == '.')
     645           0 :             return 0; /* No:  Douple dot. */
     646           0 :           if (atoi (s+1) > 255)
     647           0 :             return 0; /* No:  Ipv4 byte value too large.  */
     648           0 :           ndots++;
     649           0 :           n = 0;
     650             :         }
     651           0 :       else if (!strchr ("0123456789", *s))
     652           0 :         return 0; /* No: Not a digit.  */
     653           0 :       else if (++n > 3)
     654           0 :         return 0; /* No: More than 3 digits.  */
     655             :     }
     656           0 :   return !!(ndots == 3);
     657             : }
     658             : 
     659             : 
     660             : /* Return true if NAME is an onion address.  */
     661             : int
     662           0 : is_onion_address (const char *name)
     663             : {
     664             :   size_t len;
     665             : 
     666           0 :   len = name? strlen (name) : 0;
     667           0 :   if (len < 8 || strcmp (name + len - 6, ".onion"))
     668           0 :     return 0;
     669             :   /* Note that we require at least 2 characters before the suffix.  */
     670           0 :   return 1;  /* Yes.  */
     671             : }
     672             : 
     673             : 
     674             : #ifdef USE_ADNS
     675             : /* ADNS version of get_dns_cert.  */
     676             : static gpg_error_t
     677           1 : get_dns_cert_adns (const char *name, int want_certtype,
     678             :                    void **r_key, size_t *r_keylen,
     679             :                    unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
     680             : {
     681             :   gpg_error_t err;
     682             :   int ret;
     683             :   adns_state state;
     684           1 :   adns_answer *answer = NULL;
     685             :   unsigned int ctype;
     686             :   int count;
     687             : 
     688           1 :   err = my_adns_init (&state);
     689           1 :   if (err)
     690           0 :     return err;
     691             : 
     692           0 :   my_unprotect ();
     693           1 :   ret = adns_synchronous (state, name,
     694             :                           (adns_r_unknown
     695           0 :                            | (want_certtype < DNS_CERTTYPE_RRBASE
     696             :                               ? my_adns_r_cert
     697           0 :                               : (want_certtype - DNS_CERTTYPE_RRBASE))),
     698             :                           adns_qf_quoteok_query, &answer);
     699           0 :   my_protect ();
     700           1 :   if (ret)
     701             :     {
     702           0 :       err = gpg_error (gpg_err_code_from_errno (ret));
     703             :       /* log_error ("DNS query failed: %s\n", gpg_strerror (err)); */
     704           0 :       adns_finish (state);
     705           0 :       return err;
     706             :     }
     707           1 :   if (answer->status != adns_s_ok)
     708             :     {
     709             :       /* log_error ("DNS query returned an error: %s (%s)\n", */
     710             :       /*            adns_strerror (answer->status), */
     711             :       /*            adns_errabbrev (answer->status)); */
     712           1 :       err = map_adns_status_to_gpg_error (answer->status);
     713           1 :       if (gpg_err_code (err) == GPG_ERR_GENERAL)
     714           1 :         err = gpg_error (GPG_ERR_NOT_FOUND);
     715           1 :       goto leave;
     716             :     }
     717             : 
     718           0 :   err = gpg_error (GPG_ERR_NOT_FOUND);
     719           0 :   for (count = 0; count < answer->nrrs; count++)
     720             :     {
     721           0 :       int datalen = answer->rrs.byteblock[count].len;
     722           0 :       const unsigned char *data = answer->rrs.byteblock[count].data;
     723             : 
     724             :       /* First check for our generic RR hack.  */
     725           0 :       if (datalen
     726           0 :           && want_certtype >= DNS_CERTTYPE_RRBASE
     727           0 :           && ((want_certtype - DNS_CERTTYPE_RRBASE)
     728           0 :               == (answer->type & ~adns_r_unknown)))
     729             :         {
     730             :           /* Found the requested record - return it.  */
     731           0 :           *r_key = xtrymalloc (datalen);
     732           0 :           if (!*r_key)
     733           0 :             err = gpg_error_from_syserror ();
     734             :           else
     735             :             {
     736           0 :               memcpy (*r_key, data, datalen);
     737           0 :               *r_keylen = datalen;
     738           0 :               err = 0;
     739             :             }
     740           0 :           goto leave;
     741             :         }
     742             : 
     743           0 :       if (datalen < 5)
     744           0 :         continue;  /* Truncated CERT record - skip.  */
     745             : 
     746           0 :       ctype = buf16_to_uint (data);
     747             :       /* (key tag and algorithm fields are not required.) */
     748           0 :       data += 5;
     749           0 :       datalen -= 5;
     750             : 
     751           0 :       if (want_certtype && want_certtype != ctype)
     752             :         ; /* Not of the requested certtype.  */
     753           0 :       else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key && r_keylen)
     754             :         {
     755             :           /* CERT type is PGP.  Gpg checks for a minimum length of 11,
     756             :              thus we do the same.  */
     757           0 :           *r_key = xtrymalloc (datalen);
     758           0 :           if (!*r_key)
     759           0 :             err = gpg_error_from_syserror ();
     760             :           else
     761             :             {
     762           0 :               memcpy (*r_key, data, datalen);
     763           0 :               *r_keylen = datalen;
     764           0 :               err = 0;
     765             :             }
     766           0 :           goto leave;
     767             :         }
     768           0 :       else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
     769           0 :                && datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
     770             :         {
     771             :           /* CERT type is IPGP.  We made sure that the data is
     772             :              plausible and that the caller requested this
     773             :              information.  */
     774           0 :           *r_fprlen = data[0];
     775           0 :           if (*r_fprlen)
     776             :             {
     777           0 :               *r_fpr = xtrymalloc (*r_fprlen);
     778           0 :               if (!*r_fpr)
     779             :                 {
     780           0 :                   err = gpg_error_from_syserror ();
     781           0 :                   goto leave;
     782             :                 }
     783           0 :               memcpy (*r_fpr, data + 1, *r_fprlen);
     784             :             }
     785             :           else
     786           0 :             *r_fpr = NULL;
     787             : 
     788           0 :           if (datalen > *r_fprlen + 1)
     789             :             {
     790           0 :               *r_url = xtrymalloc (datalen - (*r_fprlen + 1) + 1);
     791           0 :               if (!*r_url)
     792             :                 {
     793           0 :                   err = gpg_error_from_syserror ();
     794           0 :                   xfree (*r_fpr);
     795           0 :                   *r_fpr = NULL;
     796           0 :                   goto leave;
     797             :                 }
     798           0 :               memcpy (*r_url,
     799           0 :                       data + (*r_fprlen + 1), datalen - (*r_fprlen + 1));
     800           0 :               (*r_url)[datalen - (*r_fprlen + 1)] = '\0';
     801             :             }
     802             :           else
     803           0 :             *r_url = NULL;
     804             : 
     805           0 :           err = 0;
     806           0 :           goto leave;
     807             :         }
     808             :     }
     809             : 
     810             :  leave:
     811           1 :   adns_free (answer);
     812           1 :   adns_finish (state);
     813           1 :   return err;
     814             : }
     815             : #endif /*!USE_ADNS */
     816             : 
     817             : 
     818             : /* Standard resolver version of get_dns_cert.  */
     819             : static gpg_error_t
     820           0 : get_dns_cert_standard (const char *name, int want_certtype,
     821             :                        void **r_key, size_t *r_keylen,
     822             :                        unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
     823             : {
     824             : #ifdef HAVE_SYSTEM_RESOLVER
     825             :   gpg_error_t err;
     826             :   unsigned char *answer;
     827             :   int r;
     828             :   u16 count;
     829             : 
     830             :   /* Allocate a 64k buffer which is the limit for an DNS response.  */
     831           0 :   answer = xtrymalloc (65536);
     832           0 :   if (!answer)
     833           0 :     return gpg_error_from_syserror ();
     834             : 
     835           0 :   err = gpg_error (GPG_ERR_NOT_FOUND);
     836           0 :   r = res_query (name, C_IN,
     837             :                  (want_certtype < DNS_CERTTYPE_RRBASE
     838             :                   ? T_CERT
     839             :                   : (want_certtype - DNS_CERTTYPE_RRBASE)),
     840             :                  answer, 65536);
     841             :   /* Not too big, not too small, no errors and at least 1 answer. */
     842           0 :   if (r >= sizeof (HEADER) && r <= 65536
     843           0 :       && (((HEADER *)(void *) answer)->rcode) == NOERROR
     844           0 :       && (count = ntohs (((HEADER *)(void *) answer)->ancount)))
     845             :     {
     846             :       int rc;
     847             :       unsigned char *pt, *emsg;
     848             : 
     849           0 :       emsg = &answer[r];
     850             : 
     851           0 :       pt = &answer[sizeof (HEADER)];
     852             : 
     853             :       /* Skip over the query */
     854             : 
     855           0 :       rc = dn_skipname (pt, emsg);
     856           0 :       if (rc == -1)
     857             :         {
     858           0 :           err = gpg_error (GPG_ERR_INV_OBJ);
     859           0 :           goto leave;
     860             :         }
     861           0 :       pt += rc + QFIXEDSZ;
     862             : 
     863             :       /* There are several possible response types for a CERT request.
     864             :          We're interested in the PGP (a key) and IPGP (a URI) types.
     865             :          Skip all others.  TODO: A key is better than a URI since
     866             :          we've gone through all this bother to fetch it, so favor that
     867             :          if we have both PGP and IPGP? */
     868             : 
     869           0 :       while (count-- > 0 && pt < emsg)
     870             :         {
     871             :           u16 type, class, dlen, ctype;
     872             : 
     873           0 :           rc = dn_skipname (pt, emsg);  /* the name we just queried for */
     874           0 :           if (rc == -1)
     875             :             {
     876           0 :               err = gpg_error (GPG_ERR_INV_OBJ);
     877           0 :               goto leave;
     878             :             }
     879             : 
     880           0 :           pt += rc;
     881             : 
     882             :           /* Truncated message? 15 bytes takes us to the point where
     883             :              we start looking at the ctype. */
     884           0 :           if ((emsg - pt) < 15)
     885           0 :             break;
     886             : 
     887           0 :           type = buf16_to_u16 (pt);
     888           0 :           pt += 2;
     889             : 
     890           0 :           class = buf16_to_u16 (pt);
     891           0 :           pt += 2;
     892             : 
     893           0 :           if (class != C_IN)
     894           0 :             break;
     895             : 
     896             :           /* ttl */
     897           0 :           pt += 4;
     898             : 
     899             :           /* data length */
     900           0 :           dlen = buf16_to_u16 (pt);
     901           0 :           pt += 2;
     902             : 
     903             :           /* Check the type and parse.  */
     904           0 :           if (want_certtype >= DNS_CERTTYPE_RRBASE
     905           0 :               && type == (want_certtype - DNS_CERTTYPE_RRBASE)
     906           0 :               && r_key)
     907             :             {
     908           0 :               *r_key = xtrymalloc (dlen);
     909           0 :               if (!*r_key)
     910           0 :                 err = gpg_error_from_syserror ();
     911             :               else
     912             :                 {
     913           0 :                   memcpy (*r_key, pt, dlen);
     914           0 :                   *r_keylen = dlen;
     915           0 :                   err = 0;
     916             :                 }
     917           0 :               goto leave;
     918             :             }
     919           0 :           else if (want_certtype >= DNS_CERTTYPE_RRBASE)
     920             :             {
     921             :               /* We did not found the requested RR.  */
     922           0 :               pt += dlen;
     923             :             }
     924           0 :           else if (type == T_CERT)
     925             :             {
     926             :               /* We got a CERT type.   */
     927           0 :               ctype = buf16_to_u16 (pt);
     928           0 :               pt += 2;
     929             : 
     930             :               /* Skip the CERT key tag and algo which we don't need. */
     931           0 :               pt += 3;
     932             : 
     933           0 :               dlen -= 5;
     934             : 
     935             :               /* 15 bytes takes us to here */
     936           0 :               if (want_certtype && want_certtype != ctype)
     937             :                 ; /* Not of the requested certtype.  */
     938           0 :               else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen)
     939             :                 {
     940             :                   /* PGP type */
     941           0 :                   *r_key = xtrymalloc (dlen);
     942           0 :                   if (!*r_key)
     943           0 :                     err = gpg_error_from_syserror ();
     944             :                   else
     945             :                     {
     946           0 :                       memcpy (*r_key, pt, dlen);
     947           0 :                       *r_keylen = dlen;
     948           0 :                       err = 0;
     949             :                     }
     950           0 :                   goto leave;
     951             :                 }
     952           0 :               else if (ctype == DNS_CERTTYPE_IPGP
     953           0 :                        && dlen && dlen < 1023 && dlen >= pt[0] + 1)
     954             :                 {
     955             :                   /* IPGP type */
     956           0 :                   *r_fprlen = pt[0];
     957           0 :                   if (*r_fprlen)
     958             :                     {
     959           0 :                       *r_fpr = xtrymalloc (*r_fprlen);
     960           0 :                       if (!*r_fpr)
     961             :                         {
     962           0 :                           err = gpg_error_from_syserror ();
     963           0 :                           goto leave;
     964             :                         }
     965           0 :                       memcpy (*r_fpr, &pt[1], *r_fprlen);
     966             :                     }
     967             :                   else
     968           0 :                     *r_fpr = NULL;
     969             : 
     970           0 :                   if (dlen > *r_fprlen + 1)
     971             :                     {
     972           0 :                       *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
     973           0 :                       if (!*r_fpr)
     974             :                         {
     975           0 :                           err = gpg_error_from_syserror ();
     976           0 :                           xfree (*r_fpr);
     977           0 :                           *r_fpr = NULL;
     978           0 :                           goto leave;
     979             :                         }
     980           0 :                       memcpy (*r_url, &pt[*r_fprlen + 1],
     981           0 :                               dlen - (*r_fprlen + 1));
     982           0 :                       (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
     983             :                     }
     984             :                   else
     985           0 :                     *r_url = NULL;
     986             : 
     987           0 :                   err = 0;
     988           0 :                   goto leave;
     989             :                 }
     990             : 
     991             :               /* No subtype matches, so continue with the next answer. */
     992           0 :               pt += dlen;
     993             :             }
     994             :           else
     995             :             {
     996             :               /* Not a requested type - might be a CNAME. Try next item.  */
     997           0 :               pt += dlen;
     998             :             }
     999             :         }
    1000             :     }
    1001             : 
    1002             :  leave:
    1003           0 :   xfree (answer);
    1004           0 :   return err;
    1005             : 
    1006             : #else /*!HAVE_SYSTEM_RESOLVER*/
    1007             : 
    1008             :   (void)name;
    1009             :   (void)want_certtype;
    1010             :   (void)r_key;
    1011             :   (void)r_keylen;
    1012             :   (void)r_fpr;
    1013             :   (void)r_fprlen;
    1014             :   (void)r_url;
    1015             :   return gpg_error (GPG_ERR_NOT_SUPPORTED);
    1016             : 
    1017             : #endif /*!HAVE_SYSTEM_RESOLVER*/
    1018             : }
    1019             : 
    1020             : 
    1021             : /* Returns 0 on success or an error code.  If a PGP CERT record was
    1022             :    found, the malloced data is returned at (R_KEY, R_KEYLEN) and
    1023             :    the other return parameters are set to NULL/0.  If an IPGP CERT
    1024             :    record was found the fingerprint is stored as an allocated block at
    1025             :    R_FPR and its length at R_FPRLEN; an URL is is allocated as a
    1026             :    string and returned at R_URL.  If WANT_CERTTYPE is 0 this function
    1027             :    returns the first CERT found with a supported type; it is expected
    1028             :    that only one CERT record is used.  If WANT_CERTTYPE is one of the
    1029             :    supported certtypes only records with this certtype are considered
    1030             :    and the first found is returned.  (R_KEY,R_KEYLEN) are optional. */
    1031             : gpg_error_t
    1032           1 : get_dns_cert (const char *name, int want_certtype,
    1033             :               void **r_key, size_t *r_keylen,
    1034             :               unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
    1035             : {
    1036           1 :   if (r_key)
    1037           1 :     *r_key = NULL;
    1038           1 :   if (r_keylen)
    1039           1 :     *r_keylen = 0;
    1040           1 :   *r_fpr = NULL;
    1041           1 :   *r_fprlen = 0;
    1042           1 :   *r_url = NULL;
    1043             : 
    1044             : #ifdef USE_ADNS
    1045           1 :   if (!standard_resolver)
    1046           1 :     return get_dns_cert_adns (name, want_certtype, r_key, r_keylen,
    1047             :                               r_fpr, r_fprlen, r_url);
    1048             : #endif /*!USE_ADNS */
    1049           0 :   return get_dns_cert_standard (name, want_certtype, r_key, r_keylen,
    1050             :                                 r_fpr, r_fprlen, r_url);
    1051             : }
    1052             : 
    1053             : 
    1054             : static int
    1055           0 : priosort(const void *a,const void *b)
    1056             : {
    1057           0 :   const struct srventry *sa=a,*sb=b;
    1058           0 :   if(sa->priority>sb->priority)
    1059           0 :     return 1;
    1060           0 :   else if(sa->priority<sb->priority)
    1061           0 :     return -1;
    1062             :   else
    1063           0 :     return 0;
    1064             : }
    1065             : 
    1066             : 
    1067             : #ifdef USE_ADNS
    1068             : /* ADNS based helper for getsrv.  */
    1069             : static int
    1070           0 : getsrv_adns (const char *name, struct srventry **list)
    1071             : {
    1072           0 :   int srvcount = 0;
    1073             :   u16 count;
    1074             :   int rc;
    1075             :   adns_state state;
    1076           0 :   adns_answer *answer = NULL;
    1077             : 
    1078           0 :   if (my_adns_init (&state))
    1079           0 :     return -1;
    1080             : 
    1081           0 :   my_unprotect ();
    1082           0 :   rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query,
    1083             :                          &answer);
    1084           0 :   my_protect ();
    1085           0 :   if (rc)
    1086             :     {
    1087           0 :       log_error ("DNS query failed: %s\n", strerror (rc));
    1088           0 :       adns_finish (state);
    1089           0 :       return -1;
    1090             :     }
    1091           0 :   if (answer->status != adns_s_ok
    1092           0 :       || answer->type != adns_r_srv || !answer->nrrs)
    1093             :     {
    1094           0 :         log_error ("DNS query returned an error or no records: %s (%s)\n",
    1095           0 :                    adns_strerror (answer->status),
    1096           0 :                    adns_errabbrev (answer->status));
    1097           0 :         adns_free (answer);
    1098           0 :         adns_finish (state);
    1099           0 :         return 0;
    1100             :     }
    1101             : 
    1102           0 :   for (count = 0; count < answer->nrrs; count++)
    1103             :     {
    1104           0 :       struct srventry *srv = NULL;
    1105             :       struct srventry *newlist;
    1106             : 
    1107           0 :       if (strlen (answer->rrs.srvha[count].ha.host) >= sizeof srv->target)
    1108             :         {
    1109           0 :           log_info ("hostname in SRV record too long - skipped\n");
    1110           0 :           continue;
    1111             :         }
    1112             : 
    1113           0 :       newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
    1114           0 :       if (!newlist)
    1115             :         {
    1116           0 :           xfree (*list);
    1117           0 :           *list = NULL;
    1118           0 :           return -1;
    1119             :         }
    1120           0 :       *list = newlist;
    1121           0 :       memset (&(*list)[srvcount], 0, sizeof(struct srventry));
    1122           0 :       srv = &(*list)[srvcount];
    1123           0 :       srvcount++;
    1124             : 
    1125           0 :       srv->priority = answer->rrs.srvha[count].priority;
    1126           0 :       srv->weight   = answer->rrs.srvha[count].weight;
    1127           0 :       srv->port     = answer->rrs.srvha[count].port;
    1128           0 :       strcpy (srv->target, answer->rrs.srvha[count].ha.host);
    1129             :     }
    1130             : 
    1131           0 :   adns_free (answer);
    1132           0 :   adns_finish (state);
    1133             : 
    1134           0 :   return srvcount;
    1135             : }
    1136             : #endif /*USE_ADNS*/
    1137             : 
    1138             : 
    1139             : /* Standard resolver based helper for getsrv.  */
    1140             : static int
    1141           0 : getsrv_standard (const char *name, struct srventry **list)
    1142             : {
    1143             : #ifdef HAVE_SYSTEM_RESOLVER
    1144             :   union {
    1145             :     unsigned char ans[2048];
    1146             :     HEADER header[1];
    1147             :   } res;
    1148           0 :   unsigned char *answer = res.ans;
    1149           0 :   HEADER *header = res.header;
    1150             :   unsigned char *pt, *emsg;
    1151             :   int r, rc;
    1152             :   u16 dlen;
    1153           0 :   int srvcount=0;
    1154             :   u16 count;
    1155             : 
    1156             :   /* Do not allow a query using the standard resolver in Tor mode.  */
    1157           0 :   if (tor_mode)
    1158           0 :     return -1;
    1159             : 
    1160           0 :   my_unprotect ();
    1161           0 :   r = res_query (name, C_IN, T_SRV, answer, sizeof answer);
    1162           0 :   my_protect ();
    1163           0 :   if (r < sizeof (HEADER) || r > sizeof answer
    1164           0 :       || header->rcode != NOERROR || !(count=ntohs (header->ancount)))
    1165           0 :     return 0; /* Error or no record found.  */
    1166             : 
    1167           0 :   emsg = &answer[r];
    1168           0 :   pt = &answer[sizeof(HEADER)];
    1169             : 
    1170             :   /* Skip over the query */
    1171           0 :   rc = dn_skipname (pt, emsg);
    1172           0 :   if (rc == -1)
    1173           0 :     goto fail;
    1174             : 
    1175           0 :   pt += rc + QFIXEDSZ;
    1176             : 
    1177           0 :   while (count-- > 0 && pt < emsg)
    1178             :     {
    1179           0 :       struct srventry *srv = NULL;
    1180             :       u16 type, class;
    1181             :       struct srventry *newlist;
    1182             : 
    1183           0 :       newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
    1184           0 :       if (!newlist)
    1185           0 :         goto fail;
    1186           0 :       *list = newlist;
    1187           0 :       memset (&(*list)[srvcount], 0, sizeof(struct srventry));
    1188           0 :       srv = &(*list)[srvcount];
    1189           0 :       srvcount++;
    1190             : 
    1191           0 :       rc = dn_skipname (pt, emsg); /* The name we just queried for.  */
    1192           0 :       if (rc == -1)
    1193           0 :         goto fail;
    1194           0 :       pt += rc;
    1195             : 
    1196             :       /* Truncated message? */
    1197           0 :       if ((emsg-pt) < 16)
    1198           0 :         goto fail;
    1199             : 
    1200           0 :       type = buf16_to_u16 (pt);
    1201           0 :       pt += 2;
    1202             :       /* We asked for SRV and got something else !? */
    1203           0 :       if (type != T_SRV)
    1204           0 :         goto fail;
    1205             : 
    1206           0 :       class = buf16_to_u16 (pt);
    1207           0 :       pt += 2;
    1208             :       /* We asked for IN and got something else !? */
    1209           0 :       if (class != C_IN)
    1210           0 :         goto fail;
    1211             : 
    1212           0 :       pt += 4; /* ttl */
    1213           0 :       dlen = buf16_to_u16 (pt);
    1214           0 :       pt += 2;
    1215             : 
    1216           0 :       srv->priority = buf16_to_ushort (pt);
    1217           0 :       pt += 2;
    1218           0 :       srv->weight = buf16_to_ushort (pt);
    1219           0 :       pt += 2;
    1220           0 :       srv->port = buf16_to_ushort (pt);
    1221           0 :       pt += 2;
    1222             : 
    1223             :       /* Get the name.  2782 doesn't allow name compression, but
    1224             :        * dn_expand still works to pull the name out of the packet. */
    1225           0 :       rc = dn_expand (answer, emsg, pt, srv->target, sizeof srv->target);
    1226           0 :       if (rc == 1 && srv->target[0] == 0) /* "." */
    1227             :         {
    1228           0 :           xfree(*list);
    1229           0 :           *list = NULL;
    1230           0 :           return 0;
    1231             :         }
    1232           0 :       if (rc == -1)
    1233           0 :         goto fail;
    1234           0 :       pt += rc;
    1235             :       /* Corrupt packet? */
    1236           0 :       if (dlen != rc+6)
    1237           0 :         goto fail;
    1238             :     }
    1239             : 
    1240           0 :   return srvcount;
    1241             : 
    1242             :  fail:
    1243           0 :   xfree (*list);
    1244           0 :   *list = NULL;
    1245           0 :   return -1;
    1246             : 
    1247             : #else /*!HAVE_SYSTEM_RESOLVER*/
    1248             : 
    1249             :   (void)name;
    1250             :   (void)list;
    1251             :   return -1;
    1252             : 
    1253             : #endif /*!HAVE_SYSTEM_RESOLVER*/
    1254             : }
    1255             : 
    1256             : 
    1257             : int
    1258           0 : getsrv (const char *name, struct srventry **list)
    1259             : {
    1260             :   int srvcount;
    1261             :   int i;
    1262             : 
    1263           0 :   *list = NULL;
    1264             : 
    1265             :   if (0)
    1266             :     ;
    1267             : #ifdef USE_ADNS
    1268           0 :   else if (!standard_resolver)
    1269           0 :     srvcount = getsrv_adns (name, list);
    1270             : #endif /*!USE_ADNS*/
    1271             :   else
    1272           0 :     srvcount = getsrv_standard (name, list);
    1273             : 
    1274           0 :   if (srvcount <= 0)
    1275           0 :     return srvcount;
    1276             : 
    1277             :   /* Now we have an array of all the srv records. */
    1278             : 
    1279             :   /* Order by priority */
    1280           0 :   qsort(*list,srvcount,sizeof(struct srventry),priosort);
    1281             : 
    1282             :   /* For each priority, move the zero-weighted items first. */
    1283           0 :   for (i=0; i < srvcount; i++)
    1284             :     {
    1285             :       int j;
    1286             : 
    1287           0 :       for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
    1288             :         {
    1289           0 :           if((*list)[j].weight==0)
    1290             :             {
    1291             :               /* Swap j with i */
    1292           0 :               if(j!=i)
    1293             :                 {
    1294             :                   struct srventry temp;
    1295             : 
    1296           0 :                   memcpy (&temp,&(*list)[j],sizeof(struct srventry));
    1297           0 :                   memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
    1298           0 :                   memcpy (&(*list)[i],&temp,sizeof(struct srventry));
    1299             :                 }
    1300             : 
    1301           0 :               break;
    1302             :             }
    1303             :         }
    1304             :     }
    1305             : 
    1306             :   /* Run the RFC-2782 weighting algorithm.  We don't need very high
    1307             :      quality randomness for this, so regular libc srand/rand is
    1308             :      sufficient.  */
    1309             : 
    1310             :   {
    1311             :     static int done;
    1312           0 :     if (!done)
    1313             :       {
    1314           0 :         done = 1;
    1315           0 :         srand (time (NULL)*getpid());
    1316             :       }
    1317             :   }
    1318             : 
    1319           0 :   for (i=0; i < srvcount; i++)
    1320             :     {
    1321             :       int j;
    1322           0 :       float prio_count=0,chose;
    1323             : 
    1324           0 :       for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
    1325             :         {
    1326           0 :           prio_count+=(*list)[j].weight;
    1327           0 :           (*list)[j].run_count=prio_count;
    1328             :         }
    1329             : 
    1330           0 :       chose=prio_count*rand()/RAND_MAX;
    1331             : 
    1332           0 :       for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
    1333             :         {
    1334           0 :           if (chose<=(*list)[j].run_count)
    1335             :             {
    1336             :               /* Swap j with i */
    1337           0 :               if(j!=i)
    1338             :                 {
    1339             :                   struct srventry temp;
    1340             : 
    1341           0 :                   memcpy(&temp,&(*list)[j],sizeof(struct srventry));
    1342           0 :                   memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
    1343           0 :                   memcpy(&(*list)[i],&temp,sizeof(struct srventry));
    1344             :                 }
    1345           0 :               break;
    1346             :             }
    1347             :         }
    1348             :     }
    1349             : 
    1350           0 :   return srvcount;
    1351             : }
    1352             : 
    1353             : 
    1354             : #ifdef USE_ADNS
    1355             : /* ADNS version of get_dns_cname.  */
    1356             : gpg_error_t
    1357           0 : get_dns_cname_adns (const char *name, char **r_cname)
    1358             : {
    1359             :   gpg_error_t err;
    1360             :   int rc;
    1361             :   adns_state state;
    1362           0 :   adns_answer *answer = NULL;
    1363             : 
    1364           0 :   if (my_adns_init (&state))
    1365           0 :     return gpg_error (GPG_ERR_GENERAL);
    1366             : 
    1367           0 :   my_unprotect ();
    1368           0 :   rc = adns_synchronous (state, name, adns_r_cname, adns_qf_quoteok_query,
    1369             :                          &answer);
    1370           0 :   my_protect ();
    1371           0 :   if (rc)
    1372             :     {
    1373           0 :       err = gpg_error (gpg_err_code_from_errno (rc));
    1374           0 :       log_error ("DNS query failed: %s\n", gpg_strerror (err));
    1375           0 :       adns_finish (state);
    1376           0 :       return err;
    1377             :     }
    1378           0 :   if (answer->status != adns_s_ok
    1379           0 :       || answer->type != adns_r_cname || answer->nrrs != 1)
    1380             :     {
    1381           0 :       err = map_adns_status_to_gpg_error (answer->status);
    1382           0 :       log_error ("DNS query returned an error or no records: %s (%s)\n",
    1383           0 :                  adns_strerror (answer->status),
    1384           0 :                  adns_errabbrev (answer->status));
    1385           0 :       adns_free (answer);
    1386           0 :       adns_finish (state);
    1387           0 :       return err;
    1388             :     }
    1389           0 :   *r_cname = xtrystrdup (answer->rrs.str[0]);
    1390           0 :   if (!*r_cname)
    1391           0 :     err = gpg_error_from_syserror ();
    1392             :   else
    1393           0 :     err = 0;
    1394             : 
    1395           0 :   adns_free (answer);
    1396           0 :   adns_finish (state);
    1397           0 :   return err;
    1398             : }
    1399             : #endif /*USE_ADNS*/
    1400             : 
    1401             : 
    1402             : /* Standard resolver version of get_dns_cname.  */
    1403             : gpg_error_t
    1404           0 : get_dns_cname_standard (const char *name, char **r_cname)
    1405             : {
    1406             : #ifdef HAVE_SYSTEM_RESOLVER
    1407             :   gpg_error_t err;
    1408             :   int rc;
    1409             :   union {
    1410             :     unsigned char ans[2048];
    1411             :     HEADER header[1];
    1412             :   } res;
    1413           0 :   unsigned char *answer = res.ans;
    1414           0 :   HEADER *header = res.header;
    1415             :   unsigned char *pt, *emsg;
    1416             :   int r;
    1417             :   char *cname;
    1418           0 :   int cnamesize = 1025;
    1419             :   u16 count;
    1420             : 
    1421             :   /* Do not allow a query using the standard resolver in Tor mode.  */
    1422           0 :   if (tor_mode)
    1423           0 :     return -1;
    1424             : 
    1425           0 :   r = res_query (name, C_IN, T_CERT, answer, sizeof answer);
    1426           0 :   if (r < sizeof (HEADER) || r > sizeof answer)
    1427           0 :     return gpg_error (GPG_ERR_SERVER_FAILED);
    1428           0 :   if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
    1429           0 :     return gpg_error (GPG_ERR_NO_NAME); /* Error or no record found.  */
    1430           0 :   if (count != 1)
    1431           0 :     return gpg_error (GPG_ERR_SERVER_FAILED);
    1432             : 
    1433           0 :   emsg = &answer[r];
    1434           0 :   pt = &answer[sizeof(HEADER)];
    1435           0 :   rc = dn_skipname (pt, emsg);
    1436           0 :   if (rc == -1)
    1437           0 :     return gpg_error (GPG_ERR_SERVER_FAILED);
    1438             : 
    1439           0 :   pt += rc + QFIXEDSZ;
    1440           0 :   if (pt >= emsg)
    1441           0 :     return gpg_error (GPG_ERR_SERVER_FAILED);
    1442             : 
    1443           0 :   rc = dn_skipname (pt, emsg);
    1444           0 :   if (rc == -1)
    1445           0 :     return gpg_error (GPG_ERR_SERVER_FAILED);
    1446           0 :   pt += rc + 2 + 2 + 4;
    1447           0 :   if (pt+2 >= emsg)
    1448           0 :     return gpg_error (GPG_ERR_SERVER_FAILED);
    1449           0 :   pt += 2;  /* Skip rdlen */
    1450             : 
    1451           0 :   cname = xtrymalloc (cnamesize);
    1452           0 :   if (!cname)
    1453           0 :     return gpg_error_from_syserror ();
    1454             : 
    1455           0 :   rc = dn_expand (answer, emsg, pt, cname, cnamesize -1);
    1456           0 :   if (rc == -1)
    1457             :     {
    1458           0 :       xfree (cname);
    1459           0 :       return gpg_error (GPG_ERR_SERVER_FAILED);
    1460             :     }
    1461           0 :   *r_cname = xtryrealloc (cname, strlen (cname)+1);
    1462           0 :   if (!*r_cname)
    1463             :     {
    1464           0 :       err = gpg_error_from_syserror ();
    1465           0 :       xfree (cname);
    1466           0 :       return err;
    1467             :     }
    1468           0 :   return 0;
    1469             : 
    1470             : #else /*!HAVE_SYSTEM_RESOLVER*/
    1471             : 
    1472             :   (void)name;
    1473             :   (void)r_cname;
    1474             :   return -1;
    1475             : 
    1476             : #endif /*!HAVE_SYSTEM_RESOLVER*/
    1477             : }
    1478             : 
    1479             : 
    1480             : gpg_error_t
    1481           0 : get_dns_cname (const char *name, char **r_cname)
    1482             : {
    1483           0 :   *r_cname = NULL;
    1484             : 
    1485             : #ifdef USE_ADNS
    1486           0 :   if (!standard_resolver)
    1487           0 :     return get_dns_cname_adns (name, r_cname);
    1488             : #endif /*!USE_ADNS*/
    1489             : 
    1490           0 :   return get_dns_cname_standard (name, r_cname);
    1491             : }

Generated by: LCOV version 1.11