LCOV - code coverage report
Current view: top level - dirmngr - http.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 7 1116 0.6 %
Date: 2016-11-29 15:00:56 Functions: 1 53 1.9 %

          Line data    Source code
       1             : /* http.c  -  HTTP protocol handler
       2             :  * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, 2009, 2010,
       3             :  *               2011 Free Software Foundation, Inc.
       4             :  * Copyright (C) 2014 Werner Koch
       5             :  * Copyright (C) 2015 g10 Code GmbH
       6             :  *
       7             :  * This file is part of GnuPG.
       8             :  *
       9             :  * This file is free software; you can redistribute it and/or modify
      10             :  * it under the terms of either
      11             :  *
      12             :  *   - the GNU Lesser General Public License as published by the Free
      13             :  *     Software Foundation; either version 3 of the License, or (at
      14             :  *     your option) any later version.
      15             :  *
      16             :  * or
      17             :  *
      18             :  *   - the GNU General Public License as published by the Free
      19             :  *     Software Foundation; either version 2 of the License, or (at
      20             :  *     your option) any later version.
      21             :  *
      22             :  * or both in parallel, as here.
      23             :  *
      24             :  * This file is distributed in the hope that it will be useful,
      25             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      26             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      27             :  * GNU General Public License for more details.
      28             :  *
      29             :  * You should have received a copy of the GNU General Public License
      30             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      31             :  */
      32             : 
      33             : /* Simple HTTP client implementation.  We try to keep the code as
      34             :    self-contained as possible.  There are some contraints however:
      35             : 
      36             :   - estream is required.  We now require estream because it provides a
      37             :     very useful and portable asprintf implementation and the fopencookie
      38             :     function.
      39             :   - stpcpy is required
      40             :   - fixme: list other requirements.
      41             : 
      42             : 
      43             :   - With HTTP_USE_NTBTLS or HTTP_USE_GNUTLS support for https is
      44             :     provided (this also requires estream).
      45             : 
      46             :   - With HTTP_NO_WSASTARTUP the socket initialization is not done
      47             :     under Windows.  This is useful if the socket layer has already
      48             :     been initialized elsewhere.  This also avoids the installation of
      49             :     an exit handler to cleanup the socket layer.
      50             : */
      51             : 
      52             : #ifdef HAVE_CONFIG_H
      53             : # include <config.h>
      54             : #endif
      55             : #include <stdio.h>
      56             : #include <stdlib.h>
      57             : #include <stdarg.h>
      58             : #include <string.h>
      59             : #include <ctype.h>
      60             : #include <errno.h>
      61             : #include <unistd.h>
      62             : 
      63             : #ifdef HAVE_W32_SYSTEM
      64             : # ifdef HAVE_WINSOCK2_H
      65             : #  include <winsock2.h>
      66             : # endif
      67             : # include <windows.h>
      68             : #else /*!HAVE_W32_SYSTEM*/
      69             : # include <sys/types.h>
      70             : # include <sys/socket.h>
      71             : # include <sys/time.h>
      72             : # include <time.h>
      73             : # include <netinet/in.h>
      74             : # include <arpa/inet.h>
      75             : # include <netdb.h>
      76             : #endif /*!HAVE_W32_SYSTEM*/
      77             : 
      78             : #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
      79             : # undef USE_NPTH
      80             : #endif
      81             : 
      82             : #ifdef USE_NPTH
      83             : # include <npth.h>
      84             : #endif
      85             : 
      86             : #if defined (HTTP_USE_GNUTLS) && defined (HTTP_USE_NTBTLS)
      87             : # error Both, HTTP_USE_GNUTLS and HTTP_USE_NTBTLS, are defined.
      88             : #endif
      89             : 
      90             : #ifdef HTTP_USE_NTBTLS
      91             : # include <ntbtls.h>
      92             : #elif HTTP_USE_GNUTLS
      93             : # include <gnutls/gnutls.h>
      94             : # include <gnutls/x509.h>
      95             : #endif /*HTTP_USE_GNUTLS*/
      96             : 
      97             : #include <assuan.h>  /* We need the socket wrapper.  */
      98             : 
      99             : #include "util.h"
     100             : #include "i18n.h"
     101             : #include "dns-stuff.h"
     102             : #include "http.h"
     103             : 
     104             : 
     105             : #ifdef USE_NPTH
     106             : # define my_select(a,b,c,d,e)  npth_select ((a), (b), (c), (d), (e))
     107             : # define my_accept(a,b,c)      npth_accept ((a), (b), (c))
     108             : #else
     109             : # define my_select(a,b,c,d,e)  select ((a), (b), (c), (d), (e))
     110             : # define my_accept(a,b,c)      accept ((a), (b), (c))
     111             : #endif
     112             : 
     113             : #ifdef HAVE_W32_SYSTEM
     114             : #define sock_close(a)  closesocket(a)
     115             : #else
     116             : #define sock_close(a)  close(a)
     117             : #endif
     118             : 
     119             : #ifndef EAGAIN
     120             : #define EAGAIN  EWOULDBLOCK
     121             : #endif
     122             : #ifndef INADDR_NONE  /* Slowaris is missing that.  */
     123             : #define INADDR_NONE  ((unsigned long)(-1))
     124             : #endif /*INADDR_NONE*/
     125             : 
     126             : #define HTTP_PROXY_ENV           "http_proxy"
     127             : #define MAX_LINELEN 20000  /* Max. length of a HTTP header line. */
     128             : #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz"   \
     129             :                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
     130             :                         "01234567890@"                 \
     131             :                         "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
     132             : 
     133             : #if HTTP_USE_NTBTLS
     134             : typedef ntbtls_t         tls_session_t;
     135             : # define USE_TLS 1
     136             : #elif HTTP_USE_GNUTLS
     137             : typedef gnutls_session_t tls_session_t;
     138             : # define USE_TLS 1
     139             : #else
     140             : typedef void *tls_session_t;
     141             : # undef USE_TLS
     142             : #endif
     143             : 
     144             : static gpg_err_code_t do_parse_uri (parsed_uri_t uri, int only_local_part,
     145             :                                     int no_scheme_check, int force_tls);
     146             : static gpg_error_t parse_uri (parsed_uri_t *ret_uri, const char *uri,
     147             :                               int no_scheme_check, int force_tls);
     148             : static int remove_escapes (char *string);
     149             : static int insert_escapes (char *buffer, const char *string,
     150             :                            const char *special);
     151             : static uri_tuple_t parse_tuple (char *string);
     152             : static gpg_error_t send_request (http_t hd, const char *httphost,
     153             :                                  const char *auth,const char *proxy,
     154             :                                  const char *srvtag,strlist_t headers);
     155             : static char *build_rel_path (parsed_uri_t uri);
     156             : static gpg_error_t parse_response (http_t hd);
     157             : 
     158             : static assuan_fd_t connect_server (const char *server, unsigned short port,
     159             :                                    unsigned int flags, const char *srvtag,
     160             :                                    int *r_host_not_found);
     161             : static gpg_error_t write_server (int sock, const char *data, size_t length);
     162             : 
     163             : static gpgrt_ssize_t cookie_read (void *cookie, void *buffer, size_t size);
     164             : static gpgrt_ssize_t cookie_write (void *cookie,
     165             :                                    const void *buffer, size_t size);
     166             : static int cookie_close (void *cookie);
     167             : 
     168             : 
     169             : /* A socket object used to a allow ref counting of sockets.  */
     170             : struct my_socket_s
     171             : {
     172             :   assuan_fd_t fd; /* The actual socket - shall never be ASSUAN_INVALID_FD.  */
     173             :   int refcount;   /* Number of references to this socket.  */
     174             : };
     175             : typedef struct my_socket_s *my_socket_t;
     176             : 
     177             : 
     178             : /* Cookie function structure and cookie object.  */
     179             : static es_cookie_io_functions_t cookie_functions =
     180             :   {
     181             :     cookie_read,
     182             :     cookie_write,
     183             :     NULL,
     184             :     cookie_close
     185             :   };
     186             : 
     187             : struct cookie_s
     188             : {
     189             :   /* Socket object or NULL if already closed. */
     190             :   my_socket_t sock;
     191             : 
     192             :   /* The session object or NULL if not used. */
     193             :   http_session_t session;
     194             : 
     195             :   /* True if TLS is to be used.  */
     196             :   int use_tls;
     197             : 
     198             :   /* The remaining content length and a flag telling whether to use
     199             :      the content length.  */
     200             :   uint64_t content_length;
     201             :   unsigned int content_length_valid:1;
     202             : };
     203             : typedef struct cookie_s *cookie_t;
     204             : 
     205             : /* The session object. */
     206             : struct http_session_s
     207             : {
     208             :   int refcount;    /* Number of references to this object.  */
     209             : #ifdef HTTP_USE_GNUTLS
     210             :   gnutls_certificate_credentials_t certcred;
     211             : #endif /*HTTP_USE_GNUTLS*/
     212             : #ifdef USE_TLS
     213             :   tls_session_t tls_session;
     214             :   struct {
     215             :     int done;      /* Verifciation has been done.  */
     216             :     int rc;        /* TLS verification return code.  */
     217             :     unsigned int status; /* Verification status.  */
     218             :   } verify;
     219             :   char *servername; /* Malloced server name.  */
     220             : #endif /*USE_TLS*/
     221             :   /* A callback function to log details of TLS certifciates.  */
     222             :   void (*cert_log_cb) (http_session_t, gpg_error_t, const char *,
     223             :                        const void **, size_t *);
     224             : };
     225             : 
     226             : 
     227             : /* An object to save header lines. */
     228             : struct header_s
     229             : {
     230             :   struct header_s *next;
     231             :   char *value;    /* The value of the header (malloced).  */
     232             :   char name[1];   /* The name of the header (canonicalized). */
     233             : };
     234             : typedef struct header_s *header_t;
     235             : 
     236             : 
     237             : /* Our handle context. */
     238             : struct http_context_s
     239             : {
     240             :   unsigned int status_code;
     241             :   my_socket_t sock;
     242             :   unsigned int in_data:1;
     243             :   unsigned int is_http_0_9:1;
     244             :   estream_t fp_read;
     245             :   estream_t fp_write;
     246             :   void *write_cookie;
     247             :   void *read_cookie;
     248             :   http_session_t session;
     249             :   parsed_uri_t uri;
     250             :   http_req_t req_type;
     251             :   char *buffer;          /* Line buffer. */
     252             :   size_t buffer_size;
     253             :   unsigned int flags;
     254             :   header_t headers;      /* Received headers. */
     255             : };
     256             : 
     257             : 
     258             : /* The global callback for the verification function.  */
     259             : static gpg_error_t (*tls_callback) (http_t, http_session_t, int);
     260             : 
     261             : /* The list of files with trusted CA certificates.  */
     262             : static strlist_t tls_ca_certlist;
     263             : 
     264             : /* The global callback for net activity.  */
     265             : static void (*netactivity_cb)(void);
     266             : 
     267             : 
     268             : 
     269             : #if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
     270             : 
     271             : #if GNUPG_MAJOR_VERSION == 1
     272             : #define REQ_WINSOCK_MAJOR  1
     273             : #define REQ_WINSOCK_MINOR  1
     274             : #else
     275             : #define REQ_WINSOCK_MAJOR  2
     276             : #define REQ_WINSOCK_MINOR  2
     277             : #endif
     278             : 
     279             : 
     280             : static void
     281             : deinit_sockets (void)
     282             : {
     283             :   WSACleanup();
     284             : }
     285             : 
     286             : static void
     287             : init_sockets (void)
     288             : {
     289             :   static int initialized;
     290             :   static WSADATA wsdata;
     291             : 
     292             :   if (initialized)
     293             :     return;
     294             : 
     295             :   if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR, REQ_WINSOCK_MAJOR), &wsdata ) )
     296             :     {
     297             :       log_error ("error initializing socket library: ec=%d\n",
     298             :                  (int)WSAGetLastError () );
     299             :       return;
     300             :     }
     301             :   if ( LOBYTE(wsdata.wVersion) != REQ_WINSOCK_MAJOR
     302             :        || HIBYTE(wsdata.wVersion) != REQ_WINSOCK_MINOR )
     303             :     {
     304             :       log_error ("socket library version is %x.%x - but %d.%d needed\n",
     305             :                  LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion),
     306             :                  REQ_WINSOCK_MAJOR, REQ_WINSOCK_MINOR);
     307             :       WSACleanup();
     308             :       return;
     309             :     }
     310             :   atexit ( deinit_sockets );
     311             :   initialized = 1;
     312             : }
     313             : #endif /*HAVE_W32_SYSTEM && !HTTP_NO_WSASTARTUP*/
     314             : 
     315             : 
     316             : /* Create a new socket object.  Returns NULL and closes FD if not
     317             :    enough memory is available.  */
     318             : static my_socket_t
     319           0 : _my_socket_new (int lnr, assuan_fd_t fd)
     320             : {
     321             :   my_socket_t so;
     322             : 
     323           0 :   so = xtrymalloc (sizeof *so);
     324           0 :   if (!so)
     325             :     {
     326           0 :       int save_errno = errno;
     327           0 :       assuan_sock_close (fd);
     328           0 :       gpg_err_set_errno (save_errno);
     329           0 :       return NULL;
     330             :     }
     331           0 :   so->fd = fd;
     332           0 :   so->refcount = 1;
     333             :   /* log_debug ("http.c:socket_new(%d): object %p for fd %d created\n", */
     334             :   /*            lnr, so, so->fd); */
     335             :   (void)lnr;
     336           0 :   return so;
     337             : }
     338             : #define my_socket_new(a) _my_socket_new (__LINE__, (a))
     339             : 
     340             : /* Bump up the reference counter for the socket object SO.  */
     341             : static my_socket_t
     342           0 : _my_socket_ref (int lnr, my_socket_t so)
     343             : {
     344           0 :   so->refcount++;
     345             :   /* log_debug ("http.c:socket_ref(%d) object %p for fd %d refcount now %d\n", */
     346             :   /*            lnr, so, so->fd, so->refcount); */
     347             :   (void)lnr;
     348           0 :   return so;
     349             : }
     350             : #define my_socket_ref(a) _my_socket_ref (__LINE__,(a))
     351             : 
     352             : 
     353             : /* Bump down the reference counter for the socket object SO.  If SO
     354             :    has no more references, close the socket and release the
     355             :    object.  */
     356             : static void
     357           0 : _my_socket_unref (int lnr, my_socket_t so,
     358             :                   void (*preclose)(void*), void *preclosearg)
     359             : {
     360           0 :   if (so)
     361             :     {
     362           0 :       so->refcount--;
     363             :       /* log_debug ("http.c:socket_unref(%d): object %p for fd %d ref now %d\n", */
     364             :       /*            lnr, so, so->fd, so->refcount); */
     365             :       (void)lnr;
     366           0 :       if (!so->refcount)
     367             :         {
     368           0 :           if (preclose)
     369           0 :             preclose (preclosearg);
     370           0 :           assuan_sock_close (so->fd);
     371           0 :           xfree (so);
     372             :         }
     373             :     }
     374           0 : }
     375             : #define my_socket_unref(a,b,c) _my_socket_unref (__LINE__,(a),(b),(c))
     376             : 
     377             : 
     378             : #ifdef HTTP_USE_GNUTLS
     379             : static ssize_t
     380           0 : my_gnutls_read (gnutls_transport_ptr_t ptr, void *buffer, size_t size)
     381             : {
     382           0 :   my_socket_t sock = ptr;
     383             : #if USE_NPTH
     384           0 :   return npth_read (sock->fd, buffer, size);
     385             : #else
     386           0 :   return read (sock->fd, buffer, size);
     387             : #endif
     388             : }
     389             : static ssize_t
     390           0 : my_gnutls_write (gnutls_transport_ptr_t ptr, const void *buffer, size_t size)
     391             : {
     392           0 :   my_socket_t sock = ptr;
     393             : #if USE_NPTH
     394           0 :   return npth_write (sock->fd, buffer, size);
     395             : #else
     396           0 :   return write (sock->fd, buffer, size);
     397             : #endif
     398             : }
     399             : #endif /*HTTP_USE_GNUTLS*/
     400             : 
     401             : 
     402             : 
     403             : 
     404             : /* This notification function is called by estream whenever stream is
     405             :    closed.  Its purpose is to mark the closing in the handle so
     406             :    that a http_close won't accidentally close the estream.  The function
     407             :    http_close removes this notification so that it won't be called if
     408             :    http_close was used before an es_fclose.  */
     409             : static void
     410           0 : fp_onclose_notification (estream_t stream, void *opaque)
     411             : {
     412           0 :   http_t hd = opaque;
     413             : 
     414           0 :   if (hd->fp_read && hd->fp_read == stream)
     415           0 :     hd->fp_read = NULL;
     416           0 :   else if (hd->fp_write && hd->fp_write == stream)
     417           0 :     hd->fp_write = NULL;
     418           0 : }
     419             : 
     420             : 
     421             : /*
     422             :  * Helper function to create an HTTP header with hex encoded data.  A
     423             :  * new buffer is returned.  This buffer is the concatenation of the
     424             :  * string PREFIX, the hex-encoded DATA of length LEN and the string
     425             :  * SUFFIX.  On error NULL is returned and ERRNO set.
     426             :  */
     427             : static char *
     428           0 : make_header_line (const char *prefix, const char *suffix,
     429             :                   const void *data, size_t len )
     430             : {
     431             :   static unsigned char bintoasc[] =
     432             :     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     433             :     "abcdefghijklmnopqrstuvwxyz"
     434             :     "0123456789+/";
     435           0 :   const unsigned char *s = data;
     436             :   char *buffer, *p;
     437             : 
     438           0 :   buffer = xtrymalloc (strlen (prefix) + (len+2)/3*4 + strlen (suffix) + 1);
     439           0 :   if (!buffer)
     440           0 :     return NULL;
     441           0 :   p = stpcpy (buffer, prefix);
     442           0 :   for ( ; len >= 3 ; len -= 3, s += 3 )
     443             :     {
     444           0 :       *p++ = bintoasc[(s[0] >> 2) & 077];
     445           0 :       *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
     446           0 :       *p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077];
     447           0 :       *p++ = bintoasc[s[2]&077];
     448           0 :       *p = 0;
     449             :     }
     450           0 :   if ( len == 2 )
     451             :     {
     452           0 :       *p++ = bintoasc[(s[0] >> 2) & 077];
     453           0 :       *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
     454           0 :       *p++ = bintoasc[((s[1]<<2)&074)];
     455           0 :       *p++ = '=';
     456             :     }
     457           0 :   else if ( len == 1 )
     458             :     {
     459           0 :       *p++ = bintoasc[(s[0] >> 2) & 077];
     460           0 :       *p++ = bintoasc[(s[0] <<4)&060];
     461           0 :       *p++ = '=';
     462           0 :       *p++ = '=';
     463             :     }
     464           0 :   *p = 0;
     465           0 :   strcpy (p, suffix);
     466           0 :   return buffer;
     467             : }
     468             : 
     469             : 
     470             : 
     471             : 
     472             : /* Register a non-standard global TLS callback function.  If no
     473             :    verification is desired a callback needs to be registered which
     474             :    always returns NULL.  */
     475             : void
     476           0 : http_register_tls_callback (gpg_error_t (*cb)(http_t, http_session_t, int))
     477             : {
     478           0 :   tls_callback = cb;
     479           0 : }
     480             : 
     481             : 
     482             : /* Register a CA certificate for future use.  The certificate is
     483             :    expected to be in FNAME.  PEM format is assume if FNAME has a
     484             :    suffix of ".pem".  If FNAME is NULL the list of CA files is
     485             :    removed.  */
     486             : void
     487           0 : http_register_tls_ca (const char *fname)
     488             : {
     489             :   strlist_t sl;
     490             : 
     491           0 :   if (!fname)
     492             :     {
     493           0 :       free_strlist (tls_ca_certlist);
     494           0 :       tls_ca_certlist = NULL;
     495             :     }
     496             :   else
     497             :     {
     498             :       /* Warn if we can't access right now, but register it anyway in
     499             :          case it becomes accessible later */
     500           0 :       if (access (fname, F_OK))
     501           0 :         log_info (_("can't access '%s': %s\n"), fname,
     502             :                   gpg_strerror (gpg_error_from_syserror()));
     503           0 :       sl = add_to_strlist (&tls_ca_certlist, fname);
     504           0 :       if (*sl->d && !strcmp (sl->d + strlen (sl->d) - 4, ".pem"))
     505           0 :         sl->flags = 1;
     506             :     }
     507           0 : }
     508             : 
     509             : 
     510             : /* Register a callback which is called every time the HTTP mode has
     511             :  * made a successful connection to some server.  */
     512             : void
     513           0 : http_register_netactivity_cb (void (*cb)(void))
     514             : {
     515           0 :   netactivity_cb = cb;
     516           0 : }
     517             : 
     518             : 
     519             : /* Call the netactivity callback if any.  */
     520             : static void
     521           0 : notify_netactivity (void)
     522             : {
     523           0 :   if (netactivity_cb)
     524           0 :     netactivity_cb ();
     525           0 : }
     526             : 
     527             : 
     528             : 
     529             : #ifdef USE_TLS
     530             : /* Free the TLS session associated with SESS, if any.  */
     531             : static void
     532           0 : close_tls_session (http_session_t sess)
     533             : {
     534           0 :   if (sess->tls_session)
     535             :     {
     536             : # ifdef HTTP_USE_GNUTLS
     537           0 :       my_socket_t sock = gnutls_transport_get_ptr (sess->tls_session);
     538           0 :       my_socket_unref (sock, NULL, NULL);
     539           0 :       gnutls_deinit (sess->tls_session);
     540           0 :       if (sess->certcred)
     541           0 :         gnutls_certificate_free_credentials (sess->certcred);
     542             : # endif /*HTTP_USE_GNUTLS*/
     543           0 :       xfree (sess->servername);
     544           0 :       sess->tls_session = NULL;
     545             :     }
     546           0 : }
     547             : #endif /*USE_TLS*/
     548             : 
     549             : 
     550             : /* Release a session.  Take care not to release it while it is being
     551             :    used by a http context object.  */
     552             : static void
     553           0 : session_unref (int lnr, http_session_t sess)
     554             : {
     555           0 :   if (!sess)
     556           0 :     return;
     557             : 
     558           0 :   sess->refcount--;
     559             :   /* log_debug ("http.c:session_unref(%d): sess %p ref now %d\n", */
     560             :   /*            lnr, sess, sess->refcount); */
     561             :   (void)lnr;
     562           0 :   if (sess->refcount)
     563           0 :     return;
     564             : 
     565             : #ifdef USE_TLS
     566           0 :   close_tls_session (sess);
     567             : #endif /*USE_TLS*/
     568             : 
     569           0 :   xfree (sess);
     570             : }
     571             : #define http_session_unref(a) session_unref (__LINE__, (a))
     572             : 
     573             : void
     574           0 : http_session_release (http_session_t sess)
     575             : {
     576           0 :   http_session_unref (sess);
     577           0 : }
     578             : 
     579             : 
     580             : /* Create a new session object which is currently used to enable TLS
     581             :  * support.  It may eventually allow reusing existing connections.
     582             :  * Valid values for FLAGS are:
     583             :  *   HTTP_FLAG_TRUST_DEF - Use the CAs set with http_register_tls_ca
     584             :  *   HTTP_FLAG_TRUST_SYS - Also use the CAs defined by the system
     585             :  */
     586             : gpg_error_t
     587           0 : http_session_new (http_session_t *r_session, const char *tls_priority,
     588             :                   const char *intended_hostname, unsigned int flags)
     589             : {
     590             :   gpg_error_t err;
     591             :   http_session_t sess;
     592             : 
     593           0 :   *r_session = NULL;
     594             : 
     595           0 :   sess = xtrycalloc (1, sizeof *sess);
     596           0 :   if (!sess)
     597           0 :     return gpg_error_from_syserror ();
     598           0 :   sess->refcount = 1;
     599             : 
     600             : #if HTTP_USE_NTBTLS
     601             :   {
     602             :     (void)tls_priority;
     603             : 
     604             :     err = ntbtls_new (&sess->tls_session, NTBTLS_CLIENT);
     605             :     if (err)
     606             :       {
     607             :         log_error ("ntbtls_new failed: %s\n", gpg_strerror (err));
     608             :         goto leave;
     609             :       }
     610             :   }
     611             : #elif HTTP_USE_GNUTLS
     612             :   {
     613             :     const char *errpos;
     614             :     int rc;
     615             :     strlist_t sl;
     616           0 :     int add_system_cas = !!(flags & HTTP_FLAG_TRUST_SYS);
     617             :     int is_hkps_pool;
     618             : 
     619           0 :     rc = gnutls_certificate_allocate_credentials (&sess->certcred);
     620           0 :     if (rc < 0)
     621             :       {
     622           0 :         log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
     623             :                    gnutls_strerror (rc));
     624           0 :         err = gpg_error (GPG_ERR_GENERAL);
     625           0 :         goto leave;
     626             :       }
     627             : 
     628           0 :     is_hkps_pool = (intended_hostname
     629           0 :                     && !ascii_strcasecmp (intended_hostname,
     630             :                                           "hkps.pool.sks-keyservers.net"));
     631             : 
     632             :     /* If the user has not specified a CA list, and they are looking
     633             :      * for the hkps pool from sks-keyservers.net, then default to
     634             :      * Kristian's certificate authority:  */
     635           0 :     if (!tls_ca_certlist && is_hkps_pool)
     636             :       {
     637           0 :         char *pemname = make_filename_try (gnupg_datadir (),
     638             :                                            "sks-keyservers.netCA.pem", NULL);
     639           0 :         if (!pemname)
     640             :           {
     641           0 :             err = gpg_error_from_syserror ();
     642           0 :             log_error ("setting CA from file '%s' failed: %s\n",
     643             :                        pemname, gpg_strerror (err));
     644             :           }
     645             :         else
     646             :           {
     647           0 :             rc = gnutls_certificate_set_x509_trust_file
     648             :               (sess->certcred, pemname, GNUTLS_X509_FMT_PEM);
     649           0 :             if (rc < 0)
     650           0 :               log_info ("setting CA from file '%s' failed: %s\n",
     651             :                         pemname, gnutls_strerror (rc));
     652           0 :             xfree (pemname);
     653             :           }
     654             :       }
     655             : 
     656             :     /* Add configured certificates to the session.  */
     657           0 :     if ((flags & HTTP_FLAG_TRUST_DEF))
     658             :       {
     659           0 :         for (sl = tls_ca_certlist; sl; sl = sl->next)
     660             :           {
     661           0 :             rc = gnutls_certificate_set_x509_trust_file
     662           0 :               (sess->certcred, sl->d,
     663           0 :                (sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
     664           0 :             if (rc < 0)
     665           0 :               log_info ("setting CA from file '%s' failed: %s\n",
     666           0 :                         sl->d, gnutls_strerror (rc));
     667             :           }
     668           0 :         if (!tls_ca_certlist && !is_hkps_pool)
     669           0 :           add_system_cas = 1;
     670             :       }
     671             : 
     672             :     /* Add system certificates to the session.  */
     673           0 :     if (add_system_cas)
     674             :       {
     675             : #if GNUTLS_VERSION_NUMBER >= 0x030014
     676             :         static int shown;
     677             : 
     678           0 :         rc = gnutls_certificate_set_x509_system_trust (sess->certcred);
     679           0 :         if (rc < 0)
     680           0 :           log_info ("setting system CAs failed: %s\n", gnutls_strerror (rc));
     681           0 :         else if (!shown)
     682             :           {
     683           0 :             shown = 1;
     684           0 :             log_info ("number of system provided CAs: %d\n", rc);
     685             :           }
     686             : #endif /* gnutls >= 3.0.20 */
     687             :       }
     688             : 
     689           0 :     rc = gnutls_init (&sess->tls_session, GNUTLS_CLIENT);
     690           0 :     if (rc < 0)
     691             :       {
     692           0 :         log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
     693           0 :         err = gpg_error (GPG_ERR_GENERAL);
     694           0 :         goto leave;
     695             :       }
     696             :     /* A new session has the transport ptr set to (void*(-1), we need
     697             :        it to be NULL.  */
     698           0 :     gnutls_transport_set_ptr (sess->tls_session, NULL);
     699             : 
     700           0 :     rc = gnutls_priority_set_direct (sess->tls_session,
     701             :                                      tls_priority? tls_priority : "NORMAL",
     702             :                                      &errpos);
     703           0 :     if (rc < 0)
     704             :       {
     705           0 :         log_error ("gnutls_priority_set_direct failed at '%s': %s\n",
     706             :                    errpos, gnutls_strerror (rc));
     707           0 :         err = gpg_error (GPG_ERR_GENERAL);
     708           0 :         goto leave;
     709             :       }
     710             : 
     711           0 :     rc = gnutls_credentials_set (sess->tls_session,
     712           0 :                                  GNUTLS_CRD_CERTIFICATE, sess->certcred);
     713           0 :     if (rc < 0)
     714             :       {
     715           0 :         log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
     716           0 :         err = gpg_error (GPG_ERR_GENERAL);
     717           0 :         goto leave;
     718             :       }
     719             :   }
     720             : #else /*!HTTP_USE_GNUTLS*/
     721             :   {
     722             :     (void)tls_priority;
     723             :   }
     724             : #endif /*!HTTP_USE_GNUTLS*/
     725             : 
     726             :   /* log_debug ("http.c:session_new: sess %p created\n", sess); */
     727           0 :   err = 0;
     728             : 
     729             : #if USE_TLS
     730             :  leave:
     731             : #endif /*USE_TLS*/
     732           0 :   if (err)
     733           0 :     http_session_unref (sess);
     734             :   else
     735           0 :     *r_session = sess;
     736             : 
     737           0 :   return err;
     738             : }
     739             : 
     740             : 
     741             : /* Increment the reference count for session SESS.  Passing NULL for
     742             :    SESS is allowed. */
     743             : http_session_t
     744           0 : http_session_ref (http_session_t sess)
     745             : {
     746           0 :   if (sess)
     747             :     {
     748           0 :       sess->refcount++;
     749             :       /* log_debug ("http.c:session_ref: sess %p ref now %d\n", sess, */
     750             :       /*            sess->refcount); */
     751             :     }
     752           0 :   return sess;
     753             : }
     754             : 
     755             : 
     756             : void
     757           0 : http_session_set_log_cb (http_session_t sess,
     758             :                          void (*cb)(http_session_t, gpg_error_t,
     759             :                                     const char *hostname,
     760             :                                     const void **certs, size_t *certlens))
     761             : {
     762           0 :   sess->cert_log_cb = cb;
     763           0 : }
     764             : 
     765             : 
     766             : 
     767             : 
     768             : /* Start a HTTP retrieval and on success store at R_HD a context
     769             :    pointer for completing the request and to wait for the response.
     770             :    If HTTPHOST is not NULL it is used for the Host header instead of a
     771             :    Host header derived from the URL. */
     772             : gpg_error_t
     773           0 : http_open (http_t *r_hd, http_req_t reqtype, const char *url,
     774             :            const char *httphost,
     775             :            const char *auth, unsigned int flags, const char *proxy,
     776             :            http_session_t session, const char *srvtag, strlist_t headers)
     777             : {
     778             :   gpg_error_t err;
     779             :   http_t hd;
     780             : 
     781           0 :   *r_hd = NULL;
     782             : 
     783           0 :   if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST))
     784           0 :     return gpg_err_make (default_errsource, GPG_ERR_INV_ARG);
     785             : 
     786             :   /* Create the handle. */
     787           0 :   hd = xtrycalloc (1, sizeof *hd);
     788           0 :   if (!hd)
     789           0 :     return gpg_error_from_syserror ();
     790           0 :   hd->req_type = reqtype;
     791           0 :   hd->flags = flags;
     792           0 :   hd->session = http_session_ref (session);
     793             : 
     794           0 :   err = parse_uri (&hd->uri, url, 0, !!(flags & HTTP_FLAG_FORCE_TLS));
     795           0 :   if (!err)
     796           0 :     err = send_request (hd, httphost, auth, proxy, srvtag, headers);
     797             : 
     798           0 :   if (err)
     799             :     {
     800           0 :       my_socket_unref (hd->sock, NULL, NULL);
     801           0 :       if (hd->fp_read)
     802           0 :         es_fclose (hd->fp_read);
     803           0 :       if (hd->fp_write)
     804           0 :         es_fclose (hd->fp_write);
     805           0 :       http_session_unref (hd->session);
     806           0 :       xfree (hd);
     807             :     }
     808             :   else
     809           0 :     *r_hd = hd;
     810           0 :   return err;
     811             : }
     812             : 
     813             : 
     814             : /* This function is useful to connect to a generic TCP service using
     815             :    this http abstraction layer.  This has the advantage of providing
     816             :    service tags and an estream interface.  */
     817             : gpg_error_t
     818           0 : http_raw_connect (http_t *r_hd, const char *server, unsigned short port,
     819             :                   unsigned int flags, const char *srvtag)
     820             : {
     821           0 :   gpg_error_t err = 0;
     822             :   http_t hd;
     823             :   cookie_t cookie;
     824             :   int hnf;
     825             : 
     826           0 :   *r_hd = NULL;
     827             : 
     828           0 :   if ((flags & HTTP_FLAG_FORCE_TOR))
     829             :     {
     830             :       int mode;
     831             : 
     832           0 :       if (assuan_sock_get_flag (ASSUAN_INVALID_FD, "tor-mode", &mode) || !mode)
     833             :         {
     834           0 :           log_error ("Tor support is not available\n");
     835           0 :           return gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
     836             :         }
     837             :     }
     838             : 
     839             :   /* Create the handle. */
     840           0 :   hd = xtrycalloc (1, sizeof *hd);
     841           0 :   if (!hd)
     842           0 :     return gpg_error_from_syserror ();
     843           0 :   hd->req_type = HTTP_REQ_OPAQUE;
     844           0 :   hd->flags = flags;
     845             : 
     846             :   /* Connect.  */
     847             :   {
     848             :     assuan_fd_t sock;
     849             : 
     850           0 :     sock = connect_server (server, port, hd->flags, srvtag, &hnf);
     851           0 :     if (sock == ASSUAN_INVALID_FD)
     852             :       {
     853           0 :         err = gpg_err_make (default_errsource,
     854           0 :                             (hnf? GPG_ERR_UNKNOWN_HOST
     855             :                              : gpg_err_code_from_syserror ()));
     856           0 :         xfree (hd);
     857           0 :         return err;
     858             :       }
     859           0 :     hd->sock = my_socket_new (sock);
     860           0 :     if (!hd->sock)
     861             :       {
     862           0 :         err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
     863           0 :         xfree (hd);
     864           0 :         return err;
     865             :       }
     866             :   }
     867             : 
     868             :   /* Setup estreams for reading and writing.  */
     869           0 :   cookie = xtrycalloc (1, sizeof *cookie);
     870           0 :   if (!cookie)
     871             :     {
     872           0 :       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
     873           0 :       goto leave;
     874             :     }
     875           0 :   cookie->sock = my_socket_ref (hd->sock);
     876           0 :   hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
     877           0 :   if (!hd->fp_write)
     878             :     {
     879           0 :       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
     880           0 :       my_socket_unref (cookie->sock, NULL, NULL);
     881           0 :       xfree (cookie);
     882           0 :       goto leave;
     883             :     }
     884           0 :   hd->write_cookie = cookie; /* Cookie now owned by FP_WRITE.  */
     885             : 
     886           0 :   cookie = xtrycalloc (1, sizeof *cookie);
     887           0 :   if (!cookie)
     888             :     {
     889           0 :       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
     890           0 :       goto leave;
     891             :     }
     892           0 :   cookie->sock = my_socket_ref (hd->sock);
     893           0 :   hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
     894           0 :   if (!hd->fp_read)
     895             :     {
     896           0 :       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
     897           0 :       my_socket_unref (cookie->sock, NULL, NULL);
     898           0 :       xfree (cookie);
     899           0 :       goto leave;
     900             :     }
     901           0 :   hd->read_cookie = cookie; /* Cookie now owned by FP_READ.  */
     902             : 
     903             :   /* Register close notification to interlock the use of es_fclose in
     904             :      http_close and in user code.  */
     905           0 :   err = es_onclose (hd->fp_write, 1, fp_onclose_notification, hd);
     906           0 :   if (!err)
     907           0 :     err = es_onclose (hd->fp_read, 1, fp_onclose_notification, hd);
     908             : 
     909             :  leave:
     910           0 :   if (err)
     911             :     {
     912           0 :       if (hd->fp_read)
     913           0 :         es_fclose (hd->fp_read);
     914           0 :       if (hd->fp_write)
     915           0 :         es_fclose (hd->fp_write);
     916           0 :       my_socket_unref (hd->sock, NULL, NULL);
     917           0 :       xfree (hd);
     918             :     }
     919             :   else
     920           0 :     *r_hd = hd;
     921           0 :   return err;
     922             : }
     923             : 
     924             : 
     925             : 
     926             : 
     927             : void
     928           0 : http_start_data (http_t hd)
     929             : {
     930           0 :   if (!hd->in_data)
     931             :     {
     932           0 :       es_fputs ("\r\n", hd->fp_write);
     933           0 :       es_fflush (hd->fp_write);
     934           0 :       hd->in_data = 1;
     935             :     }
     936             :   else
     937           0 :     es_fflush (hd->fp_write);
     938           0 : }
     939             : 
     940             : 
     941             : gpg_error_t
     942           0 : http_wait_response (http_t hd)
     943             : {
     944             :   gpg_error_t err;
     945             :   cookie_t cookie;
     946             : 
     947             :   /* Make sure that we are in the data. */
     948           0 :   http_start_data (hd);
     949             : 
     950             :   /* Close the write stream.  Note that the reference counted socket
     951             :      object keeps the actual system socket open.  */
     952           0 :   cookie = hd->write_cookie;
     953           0 :   if (!cookie)
     954           0 :     return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
     955             : 
     956           0 :   es_fclose (hd->fp_write);
     957           0 :   hd->fp_write = NULL;
     958             :   /* The close has released the cookie and thus we better set it to NULL.  */
     959           0 :   hd->write_cookie = NULL;
     960             : 
     961             :   /* Shutdown one end of the socket is desired.  As per HTTP/1.0 this
     962             :      is not required but some very old servers (e.g. the original pksd
     963             :      keyserver didn't worked without it.  */
     964           0 :   if ((hd->flags & HTTP_FLAG_SHUTDOWN))
     965           0 :     shutdown (hd->sock->fd, 1);
     966           0 :   hd->in_data = 0;
     967             : 
     968             :   /* Create a new cookie and a stream for reading.  */
     969           0 :   cookie = xtrycalloc (1, sizeof *cookie);
     970           0 :   if (!cookie)
     971           0 :     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
     972           0 :   cookie->sock = my_socket_ref (hd->sock);
     973           0 :   cookie->session = http_session_ref (hd->session);
     974           0 :   cookie->use_tls = hd->uri->use_tls;
     975             : 
     976           0 :   hd->read_cookie = cookie;
     977           0 :   hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
     978           0 :   if (!hd->fp_read)
     979             :     {
     980           0 :       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
     981           0 :       my_socket_unref (cookie->sock, NULL, NULL);
     982           0 :       http_session_unref (cookie->session);
     983           0 :       xfree (cookie);
     984           0 :       hd->read_cookie = NULL;
     985           0 :       return err;
     986             :     }
     987             : 
     988           0 :   err = parse_response (hd);
     989             : 
     990           0 :   if (!err)
     991           0 :     err = es_onclose (hd->fp_read, 1, fp_onclose_notification, hd);
     992             : 
     993           0 :   return err;
     994             : }
     995             : 
     996             : 
     997             : /* Convenience function to send a request and wait for the response.
     998             :    Closes the handle on error.  If PROXY is not NULL, this value will
     999             :    be used as an HTTP proxy and any enabled $http_proxy gets
    1000             :    ignored. */
    1001             : gpg_error_t
    1002           0 : http_open_document (http_t *r_hd, const char *document,
    1003             :                     const char *auth, unsigned int flags, const char *proxy,
    1004             :                     http_session_t session,
    1005             :                     const char *srvtag, strlist_t headers)
    1006             : {
    1007             :   gpg_error_t err;
    1008             : 
    1009           0 :   err = http_open (r_hd, HTTP_REQ_GET, document, NULL, auth, flags,
    1010             :                    proxy, session, srvtag, headers);
    1011           0 :   if (err)
    1012           0 :     return err;
    1013             : 
    1014           0 :   err = http_wait_response (*r_hd);
    1015           0 :   if (err)
    1016           0 :     http_close (*r_hd, 0);
    1017             : 
    1018           0 :   return err;
    1019             : }
    1020             : 
    1021             : 
    1022             : void
    1023           0 : http_close (http_t hd, int keep_read_stream)
    1024             : {
    1025           0 :   if (!hd)
    1026           0 :     return;
    1027             : 
    1028             :   /* First remove the close notifications for the streams.  */
    1029           0 :   if (hd->fp_read)
    1030           0 :     es_onclose (hd->fp_read, 0, fp_onclose_notification, hd);
    1031           0 :   if (hd->fp_write)
    1032           0 :     es_onclose (hd->fp_write, 0, fp_onclose_notification, hd);
    1033             : 
    1034             :   /* Now we can close the streams.  */
    1035           0 :   my_socket_unref (hd->sock, NULL, NULL);
    1036           0 :   if (hd->fp_read && !keep_read_stream)
    1037           0 :     es_fclose (hd->fp_read);
    1038           0 :   if (hd->fp_write)
    1039           0 :     es_fclose (hd->fp_write);
    1040           0 :   http_session_unref (hd->session);
    1041           0 :   http_release_parsed_uri (hd->uri);
    1042           0 :   while (hd->headers)
    1043             :     {
    1044           0 :       header_t tmp = hd->headers->next;
    1045           0 :       xfree (hd->headers->value);
    1046           0 :       xfree (hd->headers);
    1047           0 :       hd->headers = tmp;
    1048             :     }
    1049           0 :   xfree (hd->buffer);
    1050           0 :   xfree (hd);
    1051             : }
    1052             : 
    1053             : 
    1054             : estream_t
    1055           0 : http_get_read_ptr (http_t hd)
    1056             : {
    1057           0 :   return hd?hd->fp_read:NULL;
    1058             : }
    1059             : 
    1060             : estream_t
    1061           0 : http_get_write_ptr (http_t hd)
    1062             : {
    1063           0 :   return hd?hd->fp_write:NULL;
    1064             : }
    1065             : 
    1066             : unsigned int
    1067           0 : http_get_status_code (http_t hd)
    1068             : {
    1069           0 :   return hd?hd->status_code:0;
    1070             : }
    1071             : 
    1072             : /* Return information pertaining to TLS.  If TLS is not in use for HD,
    1073             :    NULL is returned.  WHAT is used ask for specific information:
    1074             : 
    1075             :      (NULL) := Only check whether TLS is is use.  Returns an
    1076             :                unspecified string if TLS is in use.  That string may
    1077             :                even be the empty string.
    1078             :  */
    1079             : const char *
    1080           0 : http_get_tls_info (http_t hd, const char *what)
    1081             : {
    1082             :   (void)what;
    1083             : 
    1084           0 :   if (!hd)
    1085           0 :     return NULL;
    1086             : 
    1087           0 :   return hd->uri->use_tls? "":NULL;
    1088             : }
    1089             : 
    1090             : 
    1091             : 
    1092             : static gpg_error_t
    1093           0 : parse_uri (parsed_uri_t *ret_uri, const char *uri,
    1094             :            int no_scheme_check, int force_tls)
    1095             : {
    1096             :   gpg_err_code_t ec;
    1097             : 
    1098           0 :   *ret_uri = xtrycalloc (1, sizeof **ret_uri + strlen (uri));
    1099           0 :   if (!*ret_uri)
    1100           0 :     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1101           0 :   strcpy ((*ret_uri)->buffer, uri);
    1102           0 :   ec = do_parse_uri (*ret_uri, 0, no_scheme_check, force_tls);
    1103           0 :   if (ec)
    1104             :     {
    1105           0 :       xfree (*ret_uri);
    1106           0 :       *ret_uri = NULL;
    1107             :     }
    1108           0 :   return gpg_err_make (default_errsource, ec);
    1109             : }
    1110             : 
    1111             : 
    1112             : /*
    1113             :  * Parse an URI and put the result into the newly allocated RET_URI.
    1114             :  * On success the caller must use http_release_parsed_uri() to
    1115             :  * releases the resources.  If NO_SCHEME_CHECK is set, the function
    1116             :  * tries to parse the URL in the same way it would do for an HTTP
    1117             :  * style URI.
    1118             :  */
    1119             : gpg_error_t
    1120           0 : http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
    1121             :                 int no_scheme_check)
    1122             : {
    1123           0 :   return parse_uri (ret_uri, uri, no_scheme_check, 0);
    1124             : }
    1125             : 
    1126             : 
    1127             : void
    1128           6 : http_release_parsed_uri (parsed_uri_t uri)
    1129             : {
    1130           6 :   if (uri)
    1131             :     {
    1132             :       uri_tuple_t r, r2;
    1133             : 
    1134           7 :       for (r = uri->query; r; r = r2)
    1135             :         {
    1136           1 :           r2 = r->next;
    1137           1 :           xfree (r);
    1138             :         }
    1139           6 :       xfree (uri);
    1140             :     }
    1141           6 : }
    1142             : 
    1143             : 
    1144             : static gpg_err_code_t
    1145           0 : do_parse_uri (parsed_uri_t uri, int only_local_part,
    1146             :               int no_scheme_check, int force_tls)
    1147             : {
    1148             :   uri_tuple_t *tail;
    1149             :   char *p, *p2, *p3, *pp;
    1150             :   int n;
    1151             : 
    1152           0 :   p = uri->buffer;
    1153           0 :   n = strlen (uri->buffer);
    1154             : 
    1155             :   /* Initialize all fields to an empty string or an empty list. */
    1156           0 :   uri->scheme = uri->host = uri->path = p + n;
    1157           0 :   uri->port = 0;
    1158           0 :   uri->params = uri->query = NULL;
    1159           0 :   uri->use_tls = 0;
    1160           0 :   uri->is_http = 0;
    1161           0 :   uri->opaque = 0;
    1162           0 :   uri->v6lit = 0;
    1163           0 :   uri->onion = 0;
    1164             : 
    1165             :   /* A quick validity check. */
    1166           0 :   if (strspn (p, VALID_URI_CHARS) != n)
    1167           0 :     return GPG_ERR_BAD_URI;     /* Invalid characters found. */
    1168             : 
    1169           0 :   if (!only_local_part)
    1170             :     {
    1171             :       /* Find the scheme. */
    1172           0 :       if (!(p2 = strchr (p, ':')) || p2 == p)
    1173           0 :         return GPG_ERR_BAD_URI; /* No scheme. */
    1174           0 :       *p2++ = 0;
    1175           0 :       for (pp=p; *pp; pp++)
    1176           0 :        *pp = tolower (*(unsigned char*)pp);
    1177           0 :       uri->scheme = p;
    1178           0 :       if (!strcmp (uri->scheme, "http") && !force_tls)
    1179             :         {
    1180           0 :           uri->port = 80;
    1181           0 :           uri->is_http = 1;
    1182             :         }
    1183           0 :       else if (!strcmp (uri->scheme, "hkp") && !force_tls)
    1184             :         {
    1185           0 :           uri->port = 11371;
    1186           0 :           uri->is_http = 1;
    1187             :         }
    1188             : #ifdef USE_TLS
    1189           0 :       else if (!strcmp (uri->scheme, "https") || !strcmp (uri->scheme,"hkps")
    1190           0 :                || (force_tls && (!strcmp (uri->scheme, "http")
    1191           0 :                                  || !strcmp (uri->scheme,"hkp"))))
    1192             :         {
    1193           0 :           uri->port = 443;
    1194           0 :           uri->is_http = 1;
    1195           0 :           uri->use_tls = 1;
    1196             :         }
    1197             : #endif /*USE_TLS*/
    1198           0 :       else if (!no_scheme_check)
    1199           0 :         return GPG_ERR_INV_URI; /* Unsupported scheme */
    1200             : 
    1201           0 :       p = p2;
    1202             : 
    1203           0 :       if (*p == '/' && p[1] == '/' ) /* There seems to be a hostname. */
    1204             :         {
    1205           0 :           p += 2;
    1206           0 :           if ((p2 = strchr (p, '/')))
    1207           0 :             *p2++ = 0;
    1208             : 
    1209             :           /* Check for username/password encoding */
    1210           0 :           if ((p3 = strchr (p, '@')))
    1211             :             {
    1212           0 :               uri->auth = p;
    1213           0 :               *p3++ = '\0';
    1214           0 :               p = p3;
    1215             :             }
    1216             : 
    1217           0 :           for (pp=p; *pp; pp++)
    1218           0 :             *pp = tolower (*(unsigned char*)pp);
    1219             : 
    1220             :           /* Handle an IPv6 literal */
    1221           0 :           if( *p == '[' && (p3=strchr( p, ']' )) )
    1222             :             {
    1223           0 :               *p3++ = '\0';
    1224             :               /* worst case, uri->host should have length 0, points to \0 */
    1225           0 :               uri->host = p + 1;
    1226           0 :               uri->v6lit = 1;
    1227           0 :               p = p3;
    1228             :             }
    1229             :           else
    1230           0 :             uri->host = p;
    1231             : 
    1232           0 :           if ((p3 = strchr (p, ':')))
    1233             :             {
    1234           0 :               *p3++ = '\0';
    1235           0 :               uri->port = atoi (p3);
    1236             :             }
    1237             : 
    1238           0 :           if ((n = remove_escapes (uri->host)) < 0)
    1239           0 :             return GPG_ERR_BAD_URI;
    1240           0 :           if (n != strlen (uri->host))
    1241           0 :             return GPG_ERR_BAD_URI;     /* Hostname incudes a Nul. */
    1242           0 :           p = p2 ? p2 : NULL;
    1243             :         }
    1244           0 :       else if (uri->is_http)
    1245           0 :         return GPG_ERR_INV_URI; /* No Leading double slash for HTTP.  */
    1246             :       else
    1247             :         {
    1248           0 :           uri->opaque = 1;
    1249           0 :           uri->path = p;
    1250           0 :           if (is_onion_address (uri->path))
    1251           0 :             uri->onion = 1;
    1252           0 :           return 0;
    1253             :         }
    1254             : 
    1255             :     } /* End global URI part. */
    1256             : 
    1257             :   /* Parse the pathname part if any.  */
    1258           0 :   if (p && *p)
    1259             :     {
    1260             :       /* TODO: Here we have to check params. */
    1261             : 
    1262             :       /* Do we have a query part? */
    1263           0 :       if ((p2 = strchr (p, '?')))
    1264           0 :         *p2++ = 0;
    1265             : 
    1266           0 :       uri->path = p;
    1267           0 :       if ((n = remove_escapes (p)) < 0)
    1268           0 :         return GPG_ERR_BAD_URI;
    1269           0 :       if (n != strlen (p))
    1270           0 :         return GPG_ERR_BAD_URI; /* Path includes a Nul. */
    1271           0 :       p = p2 ? p2 : NULL;
    1272             : 
    1273             :       /* Parse a query string if any.  */
    1274           0 :       if (p && *p)
    1275             :         {
    1276           0 :           tail = &uri->query;
    1277             :           for (;;)
    1278             :             {
    1279             :               uri_tuple_t elem;
    1280             : 
    1281           0 :               if ((p2 = strchr (p, '&')))
    1282           0 :                 *p2++ = 0;
    1283           0 :               if (!(elem = parse_tuple (p)))
    1284           0 :                 return GPG_ERR_BAD_URI;
    1285           0 :               *tail = elem;
    1286           0 :               tail = &elem->next;
    1287             : 
    1288           0 :               if (!p2)
    1289           0 :                 break; /* Ready. */
    1290           0 :               p = p2;
    1291           0 :             }
    1292             :         }
    1293             :     }
    1294             : 
    1295           0 :   if (is_onion_address (uri->host))
    1296           0 :     uri->onion = 1;
    1297             : 
    1298           0 :   return 0;
    1299             : }
    1300             : 
    1301             : 
    1302             : /*
    1303             :  * Remove all %xx escapes; this is done in-place.  Returns: New length
    1304             :  * of the string.
    1305             :  */
    1306             : static int
    1307           0 : remove_escapes (char *string)
    1308             : {
    1309           0 :   int n = 0;
    1310             :   unsigned char *p, *s;
    1311             : 
    1312           0 :   for (p = s = (unsigned char*)string; *s; s++)
    1313             :     {
    1314           0 :       if (*s == '%')
    1315             :         {
    1316           0 :           if (s[1] && s[2] && isxdigit (s[1]) && isxdigit (s[2]))
    1317             :             {
    1318           0 :               s++;
    1319           0 :               *p = *s >= '0' && *s <= '9' ? *s - '0' :
    1320           0 :                 *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
    1321           0 :               *p <<= 4;
    1322           0 :               s++;
    1323           0 :               *p |= *s >= '0' && *s <= '9' ? *s - '0' :
    1324           0 :                 *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
    1325           0 :               p++;
    1326           0 :               n++;
    1327             :             }
    1328             :           else
    1329             :             {
    1330           0 :               *p++ = *s++;
    1331           0 :               if (*s)
    1332           0 :                 *p++ = *s++;
    1333           0 :               if (*s)
    1334           0 :                 *p++ = *s++;
    1335           0 :               if (*s)
    1336           0 :                 *p = 0;
    1337           0 :               return -1; /* Bad URI. */
    1338             :             }
    1339             :         }
    1340             :       else
    1341             :         {
    1342           0 :           *p++ = *s;
    1343           0 :           n++;
    1344             :         }
    1345             :     }
    1346           0 :   *p = 0; /* Make sure to keep a string terminator. */
    1347           0 :   return n;
    1348             : }
    1349             : 
    1350             : 
    1351             : /* If SPECIAL is NULL this function escapes in forms mode.  */
    1352             : static size_t
    1353           0 : escape_data (char *buffer, const void *data, size_t datalen,
    1354             :              const char *special)
    1355             : {
    1356           0 :   int forms = !special;
    1357             :   const unsigned char *s;
    1358           0 :   size_t n = 0;
    1359             : 
    1360           0 :   if (forms)
    1361           0 :     special = "%;?&=";
    1362             : 
    1363           0 :   for (s = data; datalen; s++, datalen--)
    1364             :     {
    1365           0 :       if (forms && *s == ' ')
    1366             :         {
    1367           0 :           if (buffer)
    1368           0 :             *buffer++ = '+';
    1369           0 :           n++;
    1370             :         }
    1371           0 :       else if (forms && *s == '\n')
    1372             :         {
    1373           0 :           if (buffer)
    1374           0 :             memcpy (buffer, "%0D%0A", 6);
    1375           0 :           n += 6;
    1376             :         }
    1377           0 :       else if (forms && *s == '\r' && datalen > 1 && s[1] == '\n')
    1378             :         {
    1379           0 :           if (buffer)
    1380           0 :             memcpy (buffer, "%0D%0A", 6);
    1381           0 :           n += 6;
    1382           0 :           s++;
    1383           0 :           datalen--;
    1384             :         }
    1385           0 :       else if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
    1386             :         {
    1387           0 :           if (buffer)
    1388           0 :             *(unsigned char*)buffer++ = *s;
    1389           0 :           n++;
    1390             :         }
    1391             :       else
    1392             :         {
    1393           0 :           if (buffer)
    1394             :             {
    1395           0 :               snprintf (buffer, 4, "%%%02X", *s);
    1396           0 :               buffer += 3;
    1397             :             }
    1398           0 :           n += 3;
    1399             :         }
    1400             :     }
    1401           0 :   return n;
    1402             : }
    1403             : 
    1404             : 
    1405             : static int
    1406           0 : insert_escapes (char *buffer, const char *string,
    1407             :                 const char *special)
    1408             : {
    1409           0 :   return escape_data (buffer, string, strlen (string), special);
    1410             : }
    1411             : 
    1412             : 
    1413             : /* Allocate a new string from STRING using standard HTTP escaping as
    1414             :    well as escaping of characters given in SPECIALS.  A common pattern
    1415             :    for SPECIALS is "%;?&=". However it depends on the needs, for
    1416             :    example "+" and "/: often needs to be escaped too.  Returns NULL on
    1417             :    failure and sets ERRNO.  If SPECIAL is NULL a dedicated forms
    1418             :    encoding mode is used. */
    1419             : char *
    1420           0 : http_escape_string (const char *string, const char *specials)
    1421             : {
    1422             :   int n;
    1423             :   char *buf;
    1424             : 
    1425           0 :   n = insert_escapes (NULL, string, specials);
    1426           0 :   buf = xtrymalloc (n+1);
    1427           0 :   if (buf)
    1428             :     {
    1429           0 :       insert_escapes (buf, string, specials);
    1430           0 :       buf[n] = 0;
    1431             :     }
    1432           0 :   return buf;
    1433             : }
    1434             : 
    1435             : /* Allocate a new string from {DATA,DATALEN} using standard HTTP
    1436             :    escaping as well as escaping of characters given in SPECIALS.  A
    1437             :    common pattern for SPECIALS is "%;?&=".  However it depends on the
    1438             :    needs, for example "+" and "/: often needs to be escaped too.
    1439             :    Returns NULL on failure and sets ERRNO.  If SPECIAL is NULL a
    1440             :    dedicated forms encoding mode is used. */
    1441             : char *
    1442           0 : http_escape_data (const void *data, size_t datalen, const char *specials)
    1443             : {
    1444             :   int n;
    1445             :   char *buf;
    1446             : 
    1447           0 :   n = escape_data (NULL, data, datalen, specials);
    1448           0 :   buf = xtrymalloc (n+1);
    1449           0 :   if (buf)
    1450             :     {
    1451           0 :       escape_data (buf, data, datalen, specials);
    1452           0 :       buf[n] = 0;
    1453             :     }
    1454           0 :   return buf;
    1455             : }
    1456             : 
    1457             : 
    1458             : static uri_tuple_t
    1459           0 : parse_tuple (char *string)
    1460             : {
    1461           0 :   char *p = string;
    1462             :   char *p2;
    1463             :   int n;
    1464             :   uri_tuple_t tuple;
    1465             : 
    1466           0 :   if ((p2 = strchr (p, '=')))
    1467           0 :     *p2++ = 0;
    1468           0 :   if ((n = remove_escapes (p)) < 0)
    1469           0 :     return NULL; /* Bad URI. */
    1470           0 :   if (n != strlen (p))
    1471           0 :     return NULL; /* Name with a Nul in it. */
    1472           0 :   tuple = xtrycalloc (1, sizeof *tuple);
    1473           0 :   if (!tuple)
    1474           0 :     return NULL; /* Out of core. */
    1475           0 :   tuple->name = p;
    1476           0 :   if (!p2) /* We have only the name, so we assume an empty value string. */
    1477             :     {
    1478           0 :       tuple->value = p + strlen (p);
    1479           0 :       tuple->valuelen = 0;
    1480           0 :       tuple->no_value = 1; /* Explicitly mark that we have seen no '='. */
    1481             :     }
    1482             :   else /* Name and value. */
    1483             :     {
    1484           0 :       if ((n = remove_escapes (p2)) < 0)
    1485             :         {
    1486           0 :           xfree (tuple);
    1487           0 :           return NULL; /* Bad URI. */
    1488             :         }
    1489           0 :       tuple->value = p2;
    1490           0 :       tuple->valuelen = n;
    1491             :     }
    1492           0 :   return tuple;
    1493             : }
    1494             : 
    1495             : 
    1496             : /* Return true if STRING is likely "hostname:port" or only "hostname".  */
    1497             : static int
    1498           0 : is_hostname_port (const char *string)
    1499             : {
    1500           0 :   int colons = 0;
    1501             : 
    1502           0 :   if (!string || !*string)
    1503           0 :     return 0;
    1504           0 :   for (; *string; string++)
    1505             :     {
    1506           0 :       if (*string == ':')
    1507             :         {
    1508           0 :           if (colons)
    1509           0 :             return 0;
    1510           0 :           if (!string[1])
    1511           0 :             return 0;
    1512           0 :           colons++;
    1513             :         }
    1514           0 :       else if (!colons && strchr (" \t\f\n\v_@[]/", *string))
    1515           0 :         return 0; /* Invalid characters in hostname. */
    1516           0 :       else if (colons && !digitp (string))
    1517           0 :         return 0; /* Not a digit in the port.  */
    1518             :     }
    1519           0 :   return 1;
    1520             : }
    1521             : 
    1522             : 
    1523             : /*
    1524             :  * Send a HTTP request to the server
    1525             :  * Returns 0 if the request was successful
    1526             :  */
    1527             : static gpg_error_t
    1528           0 : send_request (http_t hd, const char *httphost, const char *auth,
    1529             :               const char *proxy, const char *srvtag, strlist_t headers)
    1530             : {
    1531             :   gpg_error_t err;
    1532             :   const char *server;
    1533             :   char *request, *p;
    1534             :   unsigned short port;
    1535           0 :   const char *http_proxy = NULL;
    1536           0 :   char *proxy_authstr = NULL;
    1537           0 :   char *authstr = NULL;
    1538             :   int sock;
    1539             :   int hnf;
    1540             : 
    1541           0 :   if (hd->uri->use_tls && !hd->session)
    1542             :     {
    1543           0 :       log_error ("TLS requested but no session object provided\n");
    1544           0 :       return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
    1545             :     }
    1546             : #ifdef USE_TLS
    1547           0 :   if (hd->uri->use_tls && !hd->session->tls_session)
    1548             :     {
    1549           0 :       log_error ("TLS requested but no GNUTLS context available\n");
    1550           0 :       return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
    1551             :     }
    1552             : #endif /*USE_TLS*/
    1553             : 
    1554           0 :   if ((hd->flags & HTTP_FLAG_FORCE_TOR))
    1555             :     {
    1556             :       int mode;
    1557             : 
    1558           0 :       if (assuan_sock_get_flag (ASSUAN_INVALID_FD, "tor-mode", &mode) || !mode)
    1559             :         {
    1560           0 :           log_error ("Tor support is not available\n");
    1561           0 :           return gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
    1562             :         }
    1563             :     }
    1564             : 
    1565           0 :   server = *hd->uri->host ? hd->uri->host : "localhost";
    1566           0 :   port = hd->uri->port ? hd->uri->port : 80;
    1567             : 
    1568             :   /* Try to use SNI.  */
    1569             : #ifdef USE_TLS
    1570           0 :   if (hd->uri->use_tls)
    1571             :     {
    1572             : # if HTTP_USE_GNUTLS
    1573             :       int rc;
    1574             : # endif
    1575             : 
    1576           0 :       xfree (hd->session->servername);
    1577           0 :       hd->session->servername = xtrystrdup (httphost? httphost : server);
    1578           0 :       if (!hd->session->servername)
    1579             :         {
    1580           0 :           err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1581           0 :           return err;
    1582             :         }
    1583             : 
    1584             : # if HTTP_USE_NTBTLS
    1585             :       err = ntbtls_set_hostname (hd->session->tls_session,
    1586             :                                  hd->session->servername);
    1587             :       if (err)
    1588             :         {
    1589             :           log_info ("ntbtls_set_hostname failed: %s\n", gpg_strerror (err));
    1590             :           return err;
    1591             :         }
    1592             : # elif HTTP_USE_GNUTLS
    1593           0 :       rc = gnutls_server_name_set (hd->session->tls_session,
    1594             :                                    GNUTLS_NAME_DNS,
    1595           0 :                                    hd->session->servername,
    1596           0 :                                    strlen (hd->session->servername));
    1597           0 :       if (rc < 0)
    1598           0 :         log_info ("gnutls_server_name_set failed: %s\n", gnutls_strerror (rc));
    1599             : # endif /*HTTP_USE_GNUTLS*/
    1600             :     }
    1601             : #endif /*USE_TLS*/
    1602             : 
    1603           0 :   if ( (proxy && *proxy)
    1604           0 :        || ( (hd->flags & HTTP_FLAG_TRY_PROXY)
    1605           0 :             && (http_proxy = getenv (HTTP_PROXY_ENV))
    1606           0 :             && *http_proxy ))
    1607           0 :     {
    1608             :       parsed_uri_t uri;
    1609             :       int save_errno;
    1610             : 
    1611           0 :       if (proxy)
    1612           0 :         http_proxy = proxy;
    1613             : 
    1614           0 :       err = parse_uri (&uri, http_proxy, 0, 0);
    1615           0 :       if (gpg_err_code (err) == GPG_ERR_INV_URI
    1616           0 :           && is_hostname_port (http_proxy))
    1617             :         {
    1618             :           /* Retry assuming a "hostname:port" string.  */
    1619           0 :           char *tmpname = strconcat ("http://", http_proxy, NULL);
    1620           0 :           if (tmpname && !parse_uri (&uri, tmpname, 0, 0))
    1621           0 :             err = 0;
    1622           0 :           xfree (tmpname);
    1623             :         }
    1624             : 
    1625           0 :       if (err)
    1626             :         ;
    1627           0 :       else if (!strcmp (uri->scheme, "http") || !strcmp (uri->scheme, "socks4"))
    1628             :         ;
    1629           0 :       else if (!strcmp (uri->scheme, "socks5h"))
    1630           0 :         err = gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
    1631             :       else
    1632           0 :         err = gpg_err_make (default_errsource, GPG_ERR_INV_URI);
    1633             : 
    1634           0 :       if (err)
    1635             :         {
    1636           0 :           log_error ("invalid HTTP proxy (%s): %s\n",
    1637             :                      http_proxy, gpg_strerror (err));
    1638           0 :           return gpg_err_make (default_errsource, GPG_ERR_CONFIGURATION);
    1639             :         }
    1640             : 
    1641           0 :       if (uri->auth)
    1642             :         {
    1643           0 :           remove_escapes (uri->auth);
    1644           0 :           proxy_authstr = make_header_line ("Proxy-Authorization: Basic ",
    1645             :                                             "\r\n",
    1646           0 :                                             uri->auth, strlen(uri->auth));
    1647           0 :           if (!proxy_authstr)
    1648             :             {
    1649           0 :               err = gpg_err_make (default_errsource,
    1650             :                                   gpg_err_code_from_syserror ());
    1651           0 :               http_release_parsed_uri (uri);
    1652           0 :               return err;
    1653             :             }
    1654             :         }
    1655             : 
    1656           0 :       sock = connect_server (*uri->host ? uri->host : "localhost",
    1657           0 :                              uri->port ? uri->port : 80,
    1658             :                              hd->flags, srvtag, &hnf);
    1659           0 :       save_errno = errno;
    1660           0 :       http_release_parsed_uri (uri);
    1661           0 :       if (sock == ASSUAN_INVALID_FD)
    1662           0 :         gpg_err_set_errno (save_errno);
    1663             :     }
    1664             :   else
    1665             :     {
    1666           0 :       sock = connect_server (server, port, hd->flags, srvtag, &hnf);
    1667             :     }
    1668             : 
    1669           0 :   if (sock == ASSUAN_INVALID_FD)
    1670             :     {
    1671           0 :       xfree (proxy_authstr);
    1672           0 :       return gpg_err_make (default_errsource,
    1673           0 :                            (hnf? GPG_ERR_UNKNOWN_HOST
    1674             :                                : gpg_err_code_from_syserror ()));
    1675             :     }
    1676           0 :   hd->sock = my_socket_new (sock);
    1677           0 :   if (!hd->sock)
    1678             :     {
    1679           0 :       xfree (proxy_authstr);
    1680           0 :       return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1681             :     }
    1682             : 
    1683             : 
    1684             : 
    1685             : #if HTTP_USE_NTBTLS
    1686             :   if (hd->uri->use_tls)
    1687             :     {
    1688             :       my_socket_ref (hd->sock);
    1689             : 
    1690             :       while ((err = ntbtls_handshake (hd->session->tls_session)))
    1691             :         {
    1692             :           switch (err)
    1693             :             {
    1694             :             default:
    1695             :               log_info ("TLS handshake failed: %s <%s>\n",
    1696             :                         gpg_strerror (err), gpg_strsource (err));
    1697             :               xfree (proxy_authstr);
    1698             :               return err;
    1699             :             }
    1700             :         }
    1701             : 
    1702             :       hd->session->verify.done = 0;
    1703             :       if (tls_callback)
    1704             :         err = tls_callback (hd, hd->session, 0);
    1705             :       else
    1706             :         err = http_verify_server_credentials (hd->session);
    1707             :       if (err)
    1708             :         {
    1709             :           log_info ("TLS connection authentication failed: %s <%s>\n",
    1710             :                     gpg_strerror (err), gpg_strsource (err));
    1711             :           xfree (proxy_authstr);
    1712             :           return err;
    1713             :         }
    1714             :     }
    1715             : #elif HTTP_USE_GNUTLS
    1716           0 :   if (hd->uri->use_tls)
    1717             :     {
    1718             :       int rc;
    1719             : 
    1720           0 :       my_socket_ref (hd->sock);
    1721           0 :       gnutls_transport_set_ptr (hd->session->tls_session, hd->sock);
    1722           0 :       gnutls_transport_set_pull_function (hd->session->tls_session,
    1723             :                                           my_gnutls_read);
    1724           0 :       gnutls_transport_set_push_function (hd->session->tls_session,
    1725             :                                           my_gnutls_write);
    1726             : 
    1727             :       do
    1728             :         {
    1729           0 :           rc = gnutls_handshake (hd->session->tls_session);
    1730             :         }
    1731           0 :       while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
    1732           0 :       if (rc < 0)
    1733             :         {
    1734           0 :           if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED
    1735           0 :               || rc == GNUTLS_E_FATAL_ALERT_RECEIVED)
    1736           0 :             {
    1737             :               gnutls_alert_description_t alertno;
    1738             :               const char *alertstr;
    1739             : 
    1740           0 :               alertno = gnutls_alert_get (hd->session->tls_session);
    1741           0 :               alertstr = gnutls_alert_get_name (alertno);
    1742           0 :               log_info ("TLS handshake failed: %s (alert %d)\n",
    1743             :                         alertstr, (int)alertno);
    1744           0 :               if (alertno == GNUTLS_A_UNRECOGNIZED_NAME && server)
    1745           0 :                 log_info ("  (sent server name '%s')\n", server);
    1746             :             }
    1747             :           else
    1748           0 :             log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc));
    1749           0 :           xfree (proxy_authstr);
    1750           0 :           return gpg_err_make (default_errsource, GPG_ERR_NETWORK);
    1751             :         }
    1752             : 
    1753           0 :       hd->session->verify.done = 0;
    1754           0 :       if (tls_callback)
    1755           0 :         err = tls_callback (hd, hd->session, 0);
    1756             :       else
    1757           0 :         err = http_verify_server_credentials (hd->session);
    1758           0 :       if (err)
    1759             :         {
    1760           0 :           log_info ("TLS connection authentication failed: %s\n",
    1761             :                     gpg_strerror (err));
    1762           0 :           xfree (proxy_authstr);
    1763           0 :           return err;
    1764             :         }
    1765             :     }
    1766             : #endif /*HTTP_USE_GNUTLS*/
    1767             : 
    1768           0 :   if (auth || hd->uri->auth)
    1769             :     {
    1770             :       char *myauth;
    1771             : 
    1772           0 :       if (auth)
    1773             :         {
    1774           0 :           myauth = xtrystrdup (auth);
    1775           0 :           if (!myauth)
    1776             :             {
    1777           0 :               xfree (proxy_authstr);
    1778           0 :               return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1779             :             }
    1780           0 :           remove_escapes (myauth);
    1781             :         }
    1782             :       else
    1783             :         {
    1784           0 :           remove_escapes (hd->uri->auth);
    1785           0 :           myauth = hd->uri->auth;
    1786             :         }
    1787             : 
    1788           0 :       authstr = make_header_line ("Authorization: Basic ", "\r\n",
    1789             :                                   myauth, strlen (myauth));
    1790           0 :       if (auth)
    1791           0 :         xfree (myauth);
    1792             : 
    1793           0 :       if (!authstr)
    1794             :         {
    1795           0 :           xfree (proxy_authstr);
    1796           0 :           return gpg_err_make (default_errsource,
    1797             :                                gpg_err_code_from_syserror ());
    1798             :         }
    1799             :     }
    1800             : 
    1801           0 :   p = build_rel_path (hd->uri);
    1802           0 :   if (!p)
    1803           0 :     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1804             : 
    1805           0 :   if (http_proxy && *http_proxy)
    1806             :     {
    1807           0 :       request = es_bsprintf
    1808             :         ("%s %s://%s:%hu%s%s HTTP/1.0\r\n%s%s",
    1809           0 :          hd->req_type == HTTP_REQ_GET ? "GET" :
    1810           0 :          hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
    1811           0 :          hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
    1812           0 :          hd->uri->use_tls? "https" : "http",
    1813             :          httphost? httphost : server,
    1814           0 :          port, *p == '/' ? "" : "/", p,
    1815             :          authstr ? authstr : "",
    1816             :          proxy_authstr ? proxy_authstr : "");
    1817             :     }
    1818             :   else
    1819             :     {
    1820             :       char portstr[35];
    1821             : 
    1822           0 :       if (port == 80)
    1823           0 :         *portstr = 0;
    1824             :       else
    1825           0 :         snprintf (portstr, sizeof portstr, ":%u", port);
    1826             : 
    1827           0 :       request = es_bsprintf
    1828             :         ("%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
    1829           0 :          hd->req_type == HTTP_REQ_GET ? "GET" :
    1830           0 :          hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
    1831           0 :          hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
    1832           0 :          *p == '/' ? "" : "/", p,
    1833             :          httphost? httphost : server,
    1834             :          portstr,
    1835             :          authstr? authstr:"");
    1836             :     }
    1837           0 :   xfree (p);
    1838           0 :   if (!request)
    1839             :     {
    1840           0 :       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1841           0 :       xfree (authstr);
    1842           0 :       xfree (proxy_authstr);
    1843           0 :       return err;
    1844             :     }
    1845             : 
    1846             :   /* log_debug ("request:\n%s\nEND request\n", request); */
    1847             : 
    1848             :   /* First setup estream so that we can write even the first line
    1849             :      using estream.  This is also required for the sake of gnutls. */
    1850             :   {
    1851             :     cookie_t cookie;
    1852             : 
    1853           0 :     cookie = xtrycalloc (1, sizeof *cookie);
    1854           0 :     if (!cookie)
    1855             :       {
    1856           0 :         err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1857           0 :         goto leave;
    1858             :       }
    1859           0 :     cookie->sock = my_socket_ref (hd->sock);
    1860           0 :     hd->write_cookie = cookie;
    1861           0 :     cookie->use_tls = hd->uri->use_tls;
    1862           0 :     cookie->session = http_session_ref (hd->session);
    1863             : 
    1864           0 :     hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
    1865           0 :     if (!hd->fp_write)
    1866             :       {
    1867           0 :         err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1868           0 :         my_socket_unref (cookie->sock, NULL, NULL);
    1869           0 :         xfree (cookie);
    1870           0 :         hd->write_cookie = NULL;
    1871             :       }
    1872           0 :     else if (es_fputs (request, hd->fp_write) || es_fflush (hd->fp_write))
    1873           0 :       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
    1874             :     else
    1875           0 :       err = 0;
    1876             : 
    1877           0 :   if (!err)
    1878             :     {
    1879           0 :       for (;headers; headers=headers->next)
    1880             :         {
    1881           0 :           if ((es_fputs (headers->d, hd->fp_write) || es_fflush (hd->fp_write))
    1882           0 :               || (es_fputs("\r\n",hd->fp_write) || es_fflush(hd->fp_write)))
    1883             :             {
    1884           0 :               err = gpg_err_make (default_errsource,
    1885             :                                   gpg_err_code_from_syserror ());
    1886           0 :               break;
    1887             :             }
    1888             :         }
    1889             :     }
    1890             :   }
    1891             : 
    1892             :  leave:
    1893           0 :   es_free (request);
    1894           0 :   xfree (authstr);
    1895           0 :   xfree (proxy_authstr);
    1896             : 
    1897           0 :   return err;
    1898             : }
    1899             : 
    1900             : 
    1901             : /*
    1902             :  * Build the relative path from the parsed URI.  Minimal
    1903             :  * implementation.  May return NULL in case of memory failure; errno
    1904             :  * is then set accordingly.
    1905             :  */
    1906             : static char *
    1907           0 : build_rel_path (parsed_uri_t uri)
    1908             : {
    1909             :   uri_tuple_t r;
    1910             :   char *rel_path, *p;
    1911             :   int n;
    1912             : 
    1913             :   /* Count the needed space. */
    1914           0 :   n = insert_escapes (NULL, uri->path, "%;?&");
    1915             :   /* TODO: build params. */
    1916           0 :   for (r = uri->query; r; r = r->next)
    1917             :     {
    1918           0 :       n++; /* '?'/'&' */
    1919           0 :       n += insert_escapes (NULL, r->name, "%;?&=");
    1920           0 :       if (!r->no_value)
    1921             :         {
    1922           0 :           n++; /* '=' */
    1923           0 :           n += insert_escapes (NULL, r->value, "%;?&=");
    1924             :         }
    1925             :     }
    1926           0 :   n++;
    1927             : 
    1928             :   /* Now allocate and copy. */
    1929           0 :   p = rel_path = xtrymalloc (n);
    1930           0 :   if (!p)
    1931           0 :     return NULL;
    1932           0 :   n = insert_escapes (p, uri->path, "%;?&");
    1933           0 :   p += n;
    1934             :   /* TODO: add params. */
    1935           0 :   for (r = uri->query; r; r = r->next)
    1936             :     {
    1937           0 :       *p++ = r == uri->query ? '?' : '&';
    1938           0 :       n = insert_escapes (p, r->name, "%;?&=");
    1939           0 :       p += n;
    1940           0 :       if (!r->no_value)
    1941             :         {
    1942           0 :           *p++ = '=';
    1943             :           /* TODO: Use valuelen. */
    1944           0 :           n = insert_escapes (p, r->value, "%;?&=");
    1945           0 :           p += n;
    1946             :         }
    1947             :     }
    1948           0 :   *p = 0;
    1949           0 :   return rel_path;
    1950             : }
    1951             : 
    1952             : 
    1953             : /* Transform a header name into a standard capitalized format; e.g.
    1954             :    "Content-Type".  Conversion stops at the colon.  As usual we don't
    1955             :    use the localized versions of ctype.h. */
    1956             : static void
    1957           0 : capitalize_header_name (char *name)
    1958             : {
    1959           0 :   int first = 1;
    1960             : 
    1961           0 :   for (; *name && *name != ':'; name++)
    1962             :     {
    1963           0 :       if (*name == '-')
    1964           0 :         first = 1;
    1965           0 :       else if (first)
    1966             :         {
    1967           0 :           if (*name >= 'a' && *name <= 'z')
    1968           0 :             *name = *name - 'a' + 'A';
    1969           0 :           first = 0;
    1970             :         }
    1971           0 :       else if (*name >= 'A' && *name <= 'Z')
    1972           0 :         *name = *name - 'A' + 'a';
    1973             :     }
    1974           0 : }
    1975             : 
    1976             : 
    1977             : /* Store an HTTP header line in LINE away.  Line continuation is
    1978             :    supported as well as merging of headers with the same name. This
    1979             :    function may modify LINE. */
    1980             : static gpg_err_code_t
    1981           0 : store_header (http_t hd, char *line)
    1982             : {
    1983             :   size_t n;
    1984             :   char *p, *value;
    1985             :   header_t h;
    1986             : 
    1987           0 :   n = strlen (line);
    1988           0 :   if (n && line[n-1] == '\n')
    1989             :     {
    1990           0 :       line[--n] = 0;
    1991           0 :       if (n && line[n-1] == '\r')
    1992           0 :         line[--n] = 0;
    1993             :     }
    1994           0 :   if (!n)  /* we are never called to hit this. */
    1995           0 :     return GPG_ERR_BUG;
    1996           0 :   if (*line == ' ' || *line == '\t')
    1997             :     {
    1998             :       /* Continuation. This won't happen too often as it is not
    1999             :          recommended.  We use a straightforward implementaion. */
    2000           0 :       if (!hd->headers)
    2001           0 :         return GPG_ERR_PROTOCOL_VIOLATION;
    2002           0 :       n += strlen (hd->headers->value);
    2003           0 :       p = xtrymalloc (n+1);
    2004           0 :       if (!p)
    2005           0 :         return gpg_err_code_from_syserror ();
    2006           0 :       strcpy (stpcpy (p, hd->headers->value), line);
    2007           0 :       xfree (hd->headers->value);
    2008           0 :       hd->headers->value = p;
    2009           0 :       return 0;
    2010             :     }
    2011             : 
    2012           0 :   capitalize_header_name (line);
    2013           0 :   p = strchr (line, ':');
    2014           0 :   if (!p)
    2015           0 :     return GPG_ERR_PROTOCOL_VIOLATION;
    2016           0 :   *p++ = 0;
    2017           0 :   while (*p == ' ' || *p == '\t')
    2018           0 :     p++;
    2019           0 :   value = p;
    2020             : 
    2021           0 :   for (h=hd->headers; h; h = h->next)
    2022           0 :     if ( !strcmp (h->name, line) )
    2023           0 :       break;
    2024           0 :   if (h)
    2025             :     {
    2026             :       /* We have already seen a line with that name.  Thus we assume
    2027             :          it is a comma separated list and merge them.  */
    2028           0 :       p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1);
    2029           0 :       if (!p)
    2030           0 :         return gpg_err_code_from_syserror ();
    2031           0 :       strcpy (stpcpy (stpcpy (p, h->value), ","), value);
    2032           0 :       xfree (h->value);
    2033           0 :       h->value = p;
    2034           0 :       return 0;
    2035             :     }
    2036             : 
    2037             :   /* Append a new header. */
    2038           0 :   h = xtrymalloc (sizeof *h + strlen (line));
    2039           0 :   if (!h)
    2040           0 :     return gpg_err_code_from_syserror ();
    2041           0 :   strcpy (h->name, line);
    2042           0 :   h->value = xtrymalloc (strlen (value)+1);
    2043           0 :   if (!h->value)
    2044             :     {
    2045           0 :       xfree (h);
    2046           0 :       return gpg_err_code_from_syserror ();
    2047             :     }
    2048           0 :   strcpy (h->value, value);
    2049           0 :   h->next = hd->headers;
    2050           0 :   hd->headers = h;
    2051             : 
    2052           0 :   return 0;
    2053             : }
    2054             : 
    2055             : 
    2056             : /* Return the header NAME from the last response.  The returned value
    2057             :    is valid as along as HD has not been closed and no other request
    2058             :    has been send. If the header was not found, NULL is returned.  NAME
    2059             :    must be canonicalized, that is the first letter of each dash
    2060             :    delimited part must be uppercase and all other letters lowercase.  */
    2061             : const char *
    2062           0 : http_get_header (http_t hd, const char *name)
    2063             : {
    2064             :   header_t h;
    2065             : 
    2066           0 :   for (h=hd->headers; h; h = h->next)
    2067           0 :     if ( !strcmp (h->name, name) )
    2068           0 :       return h->value;
    2069           0 :   return NULL;
    2070             : }
    2071             : 
    2072             : 
    2073             : /* Return a newly allocated and NULL terminated array with pointers to
    2074             :    header names.  The array must be released with xfree() and its
    2075             :    content is only values as long as no other request has been
    2076             :    send.  */
    2077             : const char **
    2078           0 : http_get_header_names (http_t hd)
    2079             : {
    2080             :   const char **array;
    2081             :   size_t n;
    2082             :   header_t h;
    2083             : 
    2084           0 :   for (n=0, h = hd->headers; h; h = h->next)
    2085           0 :     n++;
    2086           0 :   array = xtrycalloc (n+1, sizeof *array);
    2087           0 :   if (array)
    2088             :     {
    2089           0 :       for (n=0, h = hd->headers; h; h = h->next)
    2090           0 :         array[n++] = h->name;
    2091             :     }
    2092             : 
    2093           0 :   return array;
    2094             : }
    2095             : 
    2096             : 
    2097             : /*
    2098             :  * Parse the response from a server.
    2099             :  * Returns: Errorcode and sets some files in the handle
    2100             :  */
    2101             : static gpg_err_code_t
    2102           0 : parse_response (http_t hd)
    2103             : {
    2104             :   char *line, *p, *p2;
    2105             :   size_t maxlen, len;
    2106           0 :   cookie_t cookie = hd->read_cookie;
    2107             :   const char *s;
    2108             : 
    2109             :   /* Delete old header lines.  */
    2110           0 :   while (hd->headers)
    2111             :     {
    2112           0 :       header_t tmp = hd->headers->next;
    2113           0 :       xfree (hd->headers->value);
    2114           0 :       xfree (hd->headers);
    2115           0 :       hd->headers = tmp;
    2116             :     }
    2117             : 
    2118             :   /* Wait for the status line. */
    2119             :   do
    2120             :     {
    2121           0 :       maxlen = MAX_LINELEN;
    2122           0 :       len = es_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
    2123           0 :       line = hd->buffer;
    2124           0 :       if (!line)
    2125           0 :         return gpg_err_code_from_syserror (); /* Out of core. */
    2126           0 :       if (!maxlen)
    2127           0 :         return GPG_ERR_TRUNCATED; /* Line has been truncated. */
    2128           0 :       if (!len)
    2129           0 :         return GPG_ERR_EOF;
    2130             : 
    2131           0 :       if ((hd->flags & HTTP_FLAG_LOG_RESP))
    2132           0 :         log_info ("RESP: '%.*s'\n",
    2133           0 :                   (int)strlen(line)-(*line&&line[1]?2:0),line);
    2134             :     }
    2135           0 :   while (!*line);
    2136             : 
    2137           0 :   if ((p = strchr (line, '/')))
    2138           0 :     *p++ = 0;
    2139           0 :   if (!p || strcmp (line, "HTTP"))
    2140           0 :     return 0; /* Assume http 0.9. */
    2141             : 
    2142           0 :   if ((p2 = strpbrk (p, " \t")))
    2143             :     {
    2144           0 :       *p2++ = 0;
    2145           0 :       p2 += strspn (p2, " \t");
    2146             :     }
    2147           0 :   if (!p2)
    2148           0 :     return 0; /* Also assume http 0.9. */
    2149           0 :   p = p2;
    2150             :   /* TODO: Add HTTP version number check. */
    2151           0 :   if ((p2 = strpbrk (p, " \t")))
    2152           0 :     *p2++ = 0;
    2153           0 :   if (!isdigit ((unsigned int)p[0]) || !isdigit ((unsigned int)p[1])
    2154           0 :       || !isdigit ((unsigned int)p[2]) || p[3])
    2155             :     {
    2156             :       /* Malformed HTTP status code - assume http 0.9. */
    2157           0 :       hd->is_http_0_9 = 1;
    2158           0 :       hd->status_code = 200;
    2159           0 :       return 0;
    2160             :     }
    2161           0 :   hd->status_code = atoi (p);
    2162             : 
    2163             :   /* Skip all the header lines and wait for the empty line. */
    2164             :   do
    2165             :     {
    2166           0 :       maxlen = MAX_LINELEN;
    2167           0 :       len = es_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
    2168           0 :       line = hd->buffer;
    2169           0 :       if (!line)
    2170           0 :         return gpg_err_code_from_syserror (); /* Out of core. */
    2171             :       /* Note, that we can silently ignore truncated lines. */
    2172           0 :       if (!len)
    2173           0 :         return GPG_ERR_EOF;
    2174             :       /* Trim line endings of empty lines. */
    2175           0 :       if ((*line == '\r' && line[1] == '\n') || *line == '\n')
    2176           0 :         *line = 0;
    2177           0 :       if ((hd->flags & HTTP_FLAG_LOG_RESP))
    2178           0 :         log_info ("RESP: '%.*s'\n",
    2179           0 :                   (int)strlen(line)-(*line&&line[1]?2:0),line);
    2180           0 :       if (*line)
    2181             :         {
    2182           0 :           gpg_err_code_t ec = store_header (hd, line);
    2183           0 :           if (ec)
    2184           0 :             return ec;
    2185             :         }
    2186             :     }
    2187           0 :   while (len && *line);
    2188             : 
    2189           0 :   cookie->content_length_valid = 0;
    2190           0 :   if (!(hd->flags & HTTP_FLAG_IGNORE_CL))
    2191             :     {
    2192           0 :       s = http_get_header (hd, "Content-Length");
    2193           0 :       if (s)
    2194             :         {
    2195           0 :           cookie->content_length_valid = 1;
    2196           0 :           cookie->content_length = string_to_u64 (s);
    2197             :         }
    2198             :     }
    2199             : 
    2200           0 :   return 0;
    2201             : }
    2202             : 
    2203             : #if 0
    2204             : static int
    2205             : start_server ()
    2206             : {
    2207             :   struct sockaddr_in mya;
    2208             :   struct sockaddr_in peer;
    2209             :   int fd, client;
    2210             :   fd_set rfds;
    2211             :   int addrlen;
    2212             :   int i;
    2213             : 
    2214             :   if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
    2215             :     {
    2216             :       log_error ("socket() failed: %s\n", strerror (errno));
    2217             :       return -1;
    2218             :     }
    2219             :   i = 1;
    2220             :   if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (byte *) & i, sizeof (i)))
    2221             :     log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno));
    2222             : 
    2223             :   mya.sin_family = AF_INET;
    2224             :   memset (&mya.sin_addr, 0, sizeof (mya.sin_addr));
    2225             :   mya.sin_port = htons (11371);
    2226             : 
    2227             :   if (bind (fd, (struct sockaddr *) &mya, sizeof (mya)))
    2228             :     {
    2229             :       log_error ("bind to port 11371 failed: %s\n", strerror (errno));
    2230             :       sock_close (fd);
    2231             :       return -1;
    2232             :     }
    2233             : 
    2234             :   if (listen (fd, 5))
    2235             :     {
    2236             :       log_error ("listen failed: %s\n", strerror (errno));
    2237             :       sock_close (fd);
    2238             :       return -1;
    2239             :     }
    2240             : 
    2241             :   for (;;)
    2242             :     {
    2243             :       FD_ZERO (&rfds);
    2244             :       FD_SET (fd, &rfds);
    2245             : 
    2246             :       if (my_select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
    2247             :         continue;               /* ignore any errors */
    2248             : 
    2249             :       if (!FD_ISSET (fd, &rfds))
    2250             :         continue;
    2251             : 
    2252             :       addrlen = sizeof peer;
    2253             :       client = my_accept (fd, (struct sockaddr *) &peer, &addrlen);
    2254             :       if (client == -1)
    2255             :         continue;               /* oops */
    2256             : 
    2257             :       log_info ("connect from %s\n", inet_ntoa (peer.sin_addr));
    2258             : 
    2259             :       fflush (stdout);
    2260             :       fflush (stderr);
    2261             :       if (!fork ())
    2262             :         {
    2263             :           int c;
    2264             :           FILE *fp;
    2265             : 
    2266             :           fp = fdopen (client, "r");
    2267             :           while ((c = getc (fp)) != EOF)
    2268             :             putchar (c);
    2269             :           fclose (fp);
    2270             :           exit (0);
    2271             :         }
    2272             :       sock_close (client);
    2273             :     }
    2274             : 
    2275             : 
    2276             :   return 0;
    2277             : }
    2278             : #endif
    2279             : 
    2280             : /* Actually connect to a server.  Returns the file descriptor or -1 on
    2281             :    error.  ERRNO is set on error. */
    2282             : static assuan_fd_t
    2283           0 : connect_server (const char *server, unsigned short port,
    2284             :                 unsigned int flags, const char *srvtag, int *r_host_not_found)
    2285             : {
    2286             :   gpg_error_t err;
    2287           0 :   assuan_fd_t sock = ASSUAN_INVALID_FD;
    2288           0 :   int srvcount = 0;
    2289           0 :   int hostfound = 0;
    2290           0 :   int anyhostaddr = 0;
    2291             :   int srv, connected;
    2292           0 :   int last_errno = 0;
    2293           0 :   struct srventry *serverlist = NULL;
    2294             :   int ret;
    2295             : 
    2296           0 :   *r_host_not_found = 0;
    2297             : #if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
    2298             :   init_sockets ();
    2299             : #endif /*Windows*/
    2300             : 
    2301             :   /* Onion addresses require special treatment.  */
    2302           0 :   if (is_onion_address (server))
    2303             :     {
    2304             : #ifdef ASSUAN_SOCK_TOR
    2305             : 
    2306           0 :       sock = assuan_sock_connect_byname (server, port, 0, NULL,
    2307             :                                          ASSUAN_SOCK_TOR);
    2308           0 :       if (sock == ASSUAN_INVALID_FD)
    2309             :         {
    2310           0 :           if (errno == EHOSTUNREACH)
    2311           0 :             *r_host_not_found = 1;
    2312           0 :           log_error ("can't connect to '%s': %s\n", server, strerror (errno));
    2313             :         }
    2314             :       else
    2315           0 :         notify_netactivity ();
    2316           0 :       return sock;
    2317             : 
    2318             : #else /*!ASSUAN_SOCK_TOR*/
    2319             : 
    2320             :       gpg_err_set_errno (ENETUNREACH);
    2321             :       return -1; /* Out of core.  */
    2322             : 
    2323             : #endif /*!HASSUAN_SOCK_TOR*/
    2324             :     }
    2325             : 
    2326             : #ifdef USE_DNS_SRV
    2327             :   /* Do the SRV thing */
    2328           0 :   if (srvtag)
    2329             :     {
    2330             :       /* We're using SRV, so append the tags. */
    2331           0 :       if (1 + strlen (srvtag) + 6 + strlen (server) + 1
    2332             :           <= DIMof (struct srventry, target))
    2333             :         {
    2334           0 :           char *srvname = xtrymalloc (DIMof (struct srventry, target));
    2335             : 
    2336           0 :           if (!srvname) /* Out of core */
    2337             :             {
    2338           0 :               serverlist = NULL;
    2339           0 :               srvcount = 0;
    2340             :             }
    2341             :           else
    2342             :             {
    2343           0 :               stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
    2344             :                               "._tcp."), server);
    2345           0 :               srvcount = getsrv (srvname, &serverlist);
    2346           0 :               xfree (srvname);
    2347             :             }
    2348             :         }
    2349             :     }
    2350             : #else
    2351             :   (void)flags;
    2352             :   (void)srvtag;
    2353             : #endif /*USE_DNS_SRV*/
    2354             : 
    2355           0 :   if (!serverlist)
    2356             :     {
    2357             :       /* Either we're not using SRV, or the SRV lookup failed.  Make
    2358             :          up a fake SRV record. */
    2359           0 :       serverlist = xtrycalloc (1, sizeof *serverlist);
    2360           0 :       if (!serverlist)
    2361           0 :         return -1; /* Out of core.  */
    2362           0 :       serverlist->port = port;
    2363           0 :       strncpy (serverlist->target, server, DIMof (struct srventry, target));
    2364           0 :       serverlist->target[DIMof (struct srventry, target)-1] = '\0';
    2365           0 :       srvcount = 1;
    2366             :     }
    2367             : 
    2368           0 :   connected = 0;
    2369           0 :   for (srv=0; srv < srvcount && !connected; srv++)
    2370             :     {
    2371             :       dns_addrinfo_t aibuf, ai;
    2372             : 
    2373           0 :       err = resolve_dns_name (serverlist[srv].target, port, 0, SOCK_STREAM,
    2374             :                               &aibuf, NULL);
    2375           0 :       if (err)
    2376             :         {
    2377           0 :           log_info ("resolving '%s' failed: %s\n",
    2378           0 :                     serverlist[srv].target, gpg_strerror (err));
    2379           0 :           continue; /* Not found - try next one. */
    2380             :         }
    2381           0 :       hostfound = 1;
    2382             : 
    2383           0 :       for (ai = aibuf; ai && !connected; ai = ai->next)
    2384             :         {
    2385           0 :           if (ai->family == AF_INET && (flags & HTTP_FLAG_IGNORE_IPv4))
    2386           0 :             continue;
    2387           0 :           if (ai->family == AF_INET6 && (flags & HTTP_FLAG_IGNORE_IPv6))
    2388           0 :             continue;
    2389             : 
    2390           0 :           if (sock != ASSUAN_INVALID_FD)
    2391           0 :             assuan_sock_close (sock);
    2392           0 :           sock = assuan_sock_new (ai->family, ai->socktype, ai->protocol);
    2393           0 :           if (sock == ASSUAN_INVALID_FD)
    2394             :             {
    2395           0 :               int save_errno = errno;
    2396           0 :               log_error ("error creating socket: %s\n", strerror (errno));
    2397           0 :               free_dns_addrinfo (aibuf);
    2398           0 :               xfree (serverlist);
    2399           0 :               errno = save_errno;
    2400           0 :               return ASSUAN_INVALID_FD;
    2401             :             }
    2402             : 
    2403           0 :           anyhostaddr = 1;
    2404           0 :           ret = assuan_sock_connect (sock, ai->addr, ai->addrlen);
    2405           0 :           if (ret)
    2406           0 :             last_errno = errno;
    2407             :           else
    2408             :             {
    2409           0 :               connected = 1;
    2410           0 :               notify_netactivity ();
    2411             :             }
    2412             :         }
    2413           0 :       free_dns_addrinfo (aibuf);
    2414             :     }
    2415             : 
    2416           0 :   xfree (serverlist);
    2417             : 
    2418           0 :   if (!connected)
    2419             :     {
    2420           0 :       if (!hostfound)
    2421           0 :         log_error ("can't connect to '%s': %s\n",
    2422             :                    server, "host not found");
    2423           0 :       else if (!anyhostaddr)
    2424           0 :         log_error ("can't connect to '%s': %s\n",
    2425             :                    server, "no IP address for host");
    2426             :       else
    2427             :         {
    2428             : #ifdef HAVE_W32_SYSTEM
    2429             :         log_error ("can't connect to '%s': ec=%d\n",
    2430             :                    server, (int)WSAGetLastError());
    2431             : #else
    2432           0 :         log_error ("can't connect to '%s': %s\n",
    2433             :                    server, strerror (last_errno));
    2434             : #endif
    2435             :         }
    2436           0 :       if (!hostfound || (hostfound && !anyhostaddr))
    2437           0 :         *r_host_not_found = 1;
    2438           0 :       if (sock != ASSUAN_INVALID_FD)
    2439           0 :         assuan_sock_close (sock);
    2440           0 :       gpg_err_set_errno (last_errno);
    2441           0 :       return ASSUAN_INVALID_FD;
    2442             :     }
    2443           0 :   return sock;
    2444             : }
    2445             : 
    2446             : 
    2447             : static gpg_error_t
    2448           0 : write_server (int sock, const char *data, size_t length)
    2449             : {
    2450             :   int nleft;
    2451             :   int nwritten;
    2452             : 
    2453           0 :   nleft = length;
    2454           0 :   while (nleft > 0)
    2455             :     {
    2456             : #if defined(HAVE_W32_SYSTEM)
    2457             : # if defined(USE_NPTH)
    2458             :       npth_unprotect ();
    2459             : # endif
    2460             :       nwritten = send (sock, data, nleft, 0);
    2461             : # if defined(USE_NPTH)
    2462             :       npth_protect ();
    2463             : # endif
    2464             :       if ( nwritten == SOCKET_ERROR )
    2465             :         {
    2466             :           log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
    2467             :           return gpg_error (GPG_ERR_NETWORK);
    2468             :         }
    2469             : #else /*!HAVE_W32_SYSTEM*/
    2470             : # ifdef USE_NPTH
    2471           0 :       nwritten = npth_write (sock, data, nleft);
    2472             : # else
    2473           0 :       nwritten = write (sock, data, nleft);
    2474             : # endif
    2475           0 :       if (nwritten == -1)
    2476             :         {
    2477           0 :           if (errno == EINTR)
    2478           0 :             continue;
    2479           0 :           if (errno == EAGAIN)
    2480             :             {
    2481             :               struct timeval tv;
    2482             : 
    2483           0 :               tv.tv_sec = 0;
    2484           0 :               tv.tv_usec = 50000;
    2485           0 :               my_select (0, NULL, NULL, NULL, &tv);
    2486           0 :               continue;
    2487             :             }
    2488           0 :           log_info ("network write failed: %s\n", strerror (errno));
    2489           0 :           return gpg_error_from_syserror ();
    2490             :         }
    2491             : #endif /*!HAVE_W32_SYSTEM*/
    2492           0 :       nleft -= nwritten;
    2493           0 :       data += nwritten;
    2494             :     }
    2495             : 
    2496           0 :   return 0;
    2497             : }
    2498             : 
    2499             : 
    2500             : 
    2501             : /* Read handler for estream.  */
    2502             : static gpgrt_ssize_t
    2503           0 : cookie_read (void *cookie, void *buffer, size_t size)
    2504             : {
    2505           0 :   cookie_t c = cookie;
    2506             :   int nread;
    2507             : 
    2508           0 :   if (c->content_length_valid)
    2509             :     {
    2510           0 :       if (!c->content_length)
    2511           0 :         return 0; /* EOF */
    2512           0 :       if (c->content_length < size)
    2513           0 :         size = c->content_length;
    2514             :     }
    2515             : 
    2516             : #ifdef HTTP_USE_GNUTLS
    2517           0 :   if (c->use_tls && c->session && c->session->tls_session)
    2518             :     {
    2519             :     again:
    2520           0 :       nread = gnutls_record_recv (c->session->tls_session, buffer, size);
    2521           0 :       if (nread < 0)
    2522             :         {
    2523           0 :           if (nread == GNUTLS_E_INTERRUPTED)
    2524           0 :             goto again;
    2525           0 :           if (nread == GNUTLS_E_AGAIN)
    2526             :             {
    2527             :               struct timeval tv;
    2528             : 
    2529           0 :               tv.tv_sec = 0;
    2530           0 :               tv.tv_usec = 50000;
    2531           0 :               my_select (0, NULL, NULL, NULL, &tv);
    2532           0 :               goto again;
    2533             :             }
    2534           0 :           if (nread == GNUTLS_E_REHANDSHAKE)
    2535           0 :             goto again; /* A client is allowed to just ignore this request. */
    2536           0 :           if (nread == GNUTLS_E_PREMATURE_TERMINATION)
    2537             :             {
    2538             :               /* The server terminated the connection.  Close the TLS
    2539             :                  session, and indicate EOF using a short read.  */
    2540           0 :               close_tls_session (c->session);
    2541           0 :               return 0;
    2542             :             }
    2543           0 :           log_info ("TLS network read failed: %s\n", gnutls_strerror (nread));
    2544           0 :           gpg_err_set_errno (EIO);
    2545           0 :           return -1;
    2546             :         }
    2547             :     }
    2548             :   else
    2549             : #endif /*HTTP_USE_GNUTLS*/
    2550             :     {
    2551             :       do
    2552             :         {
    2553             : #ifdef HAVE_W32_SYSTEM
    2554             :           /* Under Windows we need to use recv for a socket.  */
    2555             : # if defined(USE_NPTH)
    2556             :           npth_unprotect ();
    2557             : # endif
    2558             :           nread = recv (c->sock->fd, buffer, size, 0);
    2559             : # if defined(USE_NPTH)
    2560             :           npth_protect ();
    2561             : # endif
    2562             : 
    2563             : #else /*!HAVE_W32_SYSTEM*/
    2564             : 
    2565             : # ifdef USE_NPTH
    2566           0 :           nread = npth_read (c->sock->fd, buffer, size);
    2567             : # else
    2568           0 :           nread = read (c->sock->fd, buffer, size);
    2569             : # endif
    2570             : 
    2571             : #endif /*!HAVE_W32_SYSTEM*/
    2572             :         }
    2573           0 :       while (nread == -1 && errno == EINTR);
    2574             :     }
    2575             : 
    2576           0 :   if (c->content_length_valid && nread > 0)
    2577             :     {
    2578           0 :       if (nread < c->content_length)
    2579           0 :         c->content_length -= nread;
    2580             :       else
    2581           0 :         c->content_length = 0;
    2582             :     }
    2583             : 
    2584           0 :   return (gpgrt_ssize_t)nread;
    2585             : }
    2586             : 
    2587             : /* Write handler for estream.  */
    2588             : static gpgrt_ssize_t
    2589           0 : cookie_write (void *cookie, const void *buffer_arg, size_t size)
    2590             : {
    2591           0 :   const char *buffer = buffer_arg;
    2592           0 :   cookie_t c = cookie;
    2593           0 :   int nwritten = 0;
    2594             : 
    2595             : #ifdef HTTP_USE_GNUTLS
    2596           0 :   if (c->use_tls && c->session && c->session->tls_session)
    2597           0 :     {
    2598           0 :       int nleft = size;
    2599           0 :       while (nleft > 0)
    2600             :         {
    2601           0 :           nwritten = gnutls_record_send (c->session->tls_session,
    2602             :                                          buffer, nleft);
    2603           0 :           if (nwritten <= 0)
    2604             :             {
    2605           0 :               if (nwritten == GNUTLS_E_INTERRUPTED)
    2606           0 :                 continue;
    2607           0 :               if (nwritten == GNUTLS_E_AGAIN)
    2608             :                 {
    2609             :                   struct timeval tv;
    2610             : 
    2611           0 :                   tv.tv_sec = 0;
    2612           0 :                   tv.tv_usec = 50000;
    2613           0 :                   my_select (0, NULL, NULL, NULL, &tv);
    2614           0 :                   continue;
    2615             :                 }
    2616           0 :               log_info ("TLS network write failed: %s\n",
    2617             :                         gnutls_strerror (nwritten));
    2618           0 :               gpg_err_set_errno (EIO);
    2619           0 :               return -1;
    2620             :             }
    2621           0 :           nleft -= nwritten;
    2622           0 :           buffer += nwritten;
    2623             :         }
    2624             :     }
    2625             :   else
    2626             : #endif /*HTTP_USE_GNUTLS*/
    2627             :     {
    2628           0 :       if ( write_server (c->sock->fd, buffer, size) )
    2629             :         {
    2630           0 :           gpg_err_set_errno (EIO);
    2631           0 :           nwritten = -1;
    2632             :         }
    2633             :       else
    2634           0 :         nwritten = size;
    2635             :     }
    2636             : 
    2637           0 :   return (gpgrt_ssize_t)nwritten;
    2638             : }
    2639             : 
    2640             : 
    2641             : #ifdef HTTP_USE_GNUTLS
    2642             : /* Wrapper for gnutls_bye used by my_socket_unref.  */
    2643             : static void
    2644           0 : send_gnutls_bye (void *opaque)
    2645             : {
    2646           0 :   tls_session_t tls_session = opaque;
    2647             :   int ret;
    2648             : 
    2649             :  again:
    2650             :   do
    2651           0 :     ret = gnutls_bye (tls_session, GNUTLS_SHUT_RDWR);
    2652           0 :   while (ret == GNUTLS_E_INTERRUPTED);
    2653           0 :   if (ret == GNUTLS_E_AGAIN)
    2654             :     {
    2655             :       struct timeval tv;
    2656             : 
    2657           0 :       tv.tv_sec = 0;
    2658           0 :       tv.tv_usec = 50000;
    2659           0 :       my_select (0, NULL, NULL, NULL, &tv);
    2660           0 :       goto again;
    2661             :     }
    2662           0 : }
    2663             : #endif /*HTTP_USE_GNUTLS*/
    2664             : 
    2665             : /* Close handler for estream.  */
    2666             : static int
    2667           0 : cookie_close (void *cookie)
    2668             : {
    2669           0 :   cookie_t c = cookie;
    2670             : 
    2671           0 :   if (!c)
    2672           0 :     return 0;
    2673             : 
    2674             : #ifdef HTTP_USE_GNUTLS
    2675           0 :   if (c->use_tls && c->session && c->session->tls_session)
    2676           0 :     my_socket_unref (c->sock, send_gnutls_bye, c->session->tls_session);
    2677             :   else
    2678             : #endif /*HTTP_USE_GNUTLS*/
    2679           0 :     if (c->sock)
    2680           0 :       my_socket_unref (c->sock, NULL, NULL);
    2681             : 
    2682           0 :   if (c->session)
    2683           0 :     http_session_unref (c->session);
    2684           0 :   xfree (c);
    2685           0 :   return 0;
    2686             : }
    2687             : 
    2688             : 
    2689             : 
    2690             : 
    2691             : /* Verify the credentials of the server.  Returns 0 on success and
    2692             :    store the result in the session object.  */
    2693             : gpg_error_t
    2694           0 : http_verify_server_credentials (http_session_t sess)
    2695             : {
    2696             : #if HTTP_USE_NTBTLS
    2697             :   (void)sess;
    2698             :   return 0;  /* FIXME!! */
    2699             : #elif HTTP_USE_GNUTLS
    2700             :   static const char const errprefix[] = "TLS verification of peer failed";
    2701             :   int rc;
    2702             :   unsigned int status;
    2703             :   const char *hostname;
    2704             :   const gnutls_datum_t *certlist;
    2705             :   unsigned int certlistlen;
    2706             :   gnutls_x509_crt_t cert;
    2707           0 :   gpg_error_t err = 0;
    2708             : 
    2709           0 :   sess->verify.done = 1;
    2710           0 :   sess->verify.status = 0;
    2711           0 :   sess->verify.rc = GNUTLS_E_CERTIFICATE_ERROR;
    2712             : 
    2713           0 :   if (gnutls_certificate_type_get (sess->tls_session) != GNUTLS_CRT_X509)
    2714             :     {
    2715           0 :       log_error ("%s: %s\n", errprefix, "not an X.509 certificate");
    2716           0 :       sess->verify.rc = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
    2717           0 :       return gpg_error (GPG_ERR_GENERAL);
    2718             :     }
    2719             : 
    2720           0 :   rc = gnutls_certificate_verify_peers2 (sess->tls_session, &status);
    2721           0 :   if (rc)
    2722             :     {
    2723           0 :       log_error ("%s: %s\n", errprefix, gnutls_strerror (rc));
    2724           0 :       if (!err)
    2725           0 :         err = gpg_error (GPG_ERR_GENERAL);
    2726             :     }
    2727           0 :   else if (status)
    2728             :     {
    2729           0 :       log_error ("%s: status=0x%04x\n", errprefix, status);
    2730             : #if GNUTLS_VERSION_NUMBER >= 0x030104
    2731             :       {
    2732             :         gnutls_datum_t statusdat;
    2733             : 
    2734           0 :         if (!gnutls_certificate_verification_status_print
    2735             :             (status, GNUTLS_CRT_X509, &statusdat, 0))
    2736             :           {
    2737           0 :             log_info ("%s: %s\n", errprefix, statusdat.data);
    2738           0 :             gnutls_free (statusdat.data);
    2739             :           }
    2740             :       }
    2741             : #endif /*gnutls >= 3.1.4*/
    2742             : 
    2743           0 :       sess->verify.status = status;
    2744           0 :       if (!err)
    2745           0 :         err = gpg_error (GPG_ERR_GENERAL);
    2746             :     }
    2747             : 
    2748           0 :   hostname = sess->servername;
    2749           0 :   if (!hostname || !strchr (hostname, '.'))
    2750             :     {
    2751           0 :       log_error ("%s: %s\n", errprefix, "hostname missing");
    2752           0 :       if (!err)
    2753           0 :         err = gpg_error (GPG_ERR_GENERAL);
    2754             :     }
    2755             : 
    2756           0 :   certlist = gnutls_certificate_get_peers (sess->tls_session, &certlistlen);
    2757           0 :   if (!certlistlen)
    2758             :     {
    2759           0 :       log_error ("%s: %s\n", errprefix, "server did not send a certificate");
    2760           0 :       if (!err)
    2761           0 :         err = gpg_error (GPG_ERR_GENERAL);
    2762             : 
    2763             :       /* Need to stop here.  */
    2764           0 :       if (err)
    2765           0 :         return err;
    2766             :     }
    2767             : 
    2768           0 :   rc = gnutls_x509_crt_init (&cert);
    2769           0 :   if (rc < 0)
    2770             :     {
    2771           0 :       if (!err)
    2772           0 :         err = gpg_error (GPG_ERR_GENERAL);
    2773           0 :       if (err)
    2774           0 :         return err;
    2775             :     }
    2776             : 
    2777           0 :   rc = gnutls_x509_crt_import (cert, &certlist[0], GNUTLS_X509_FMT_DER);
    2778           0 :   if (rc < 0)
    2779             :     {
    2780           0 :       log_error ("%s: %s: %s\n", errprefix, "error importing certificate",
    2781             :                  gnutls_strerror (rc));
    2782           0 :       if (!err)
    2783           0 :         err = gpg_error (GPG_ERR_GENERAL);
    2784             :     }
    2785             : 
    2786           0 :   if (!gnutls_x509_crt_check_hostname (cert, hostname))
    2787             :     {
    2788           0 :       log_error ("%s: %s\n", errprefix, "hostname does not match");
    2789           0 :       if (!err)
    2790           0 :         err = gpg_error (GPG_ERR_GENERAL);
    2791             :     }
    2792             : 
    2793           0 :   gnutls_x509_crt_deinit (cert);
    2794             : 
    2795           0 :   if (!err)
    2796           0 :     sess->verify.rc = 0;
    2797             : 
    2798           0 :   if (sess->cert_log_cb)
    2799             :     {
    2800             :       const void *bufarr[10];
    2801             :       size_t buflenarr[10];
    2802             :       size_t n;
    2803             : 
    2804           0 :       for (n = 0; n < certlistlen && n < DIM (bufarr)-1; n++)
    2805             :         {
    2806           0 :           bufarr[n] = certlist[n].data;
    2807           0 :           buflenarr[n] = certlist[n].size;
    2808             :         }
    2809           0 :       bufarr[n] = NULL;
    2810           0 :       buflenarr[n] = 0;
    2811           0 :       sess->cert_log_cb (sess, err, hostname, bufarr, buflenarr);
    2812             :     }
    2813             : 
    2814           0 :   return err;
    2815             : #else /*!HTTP_USE_GNUTLS*/
    2816             :   (void)sess;
    2817             :   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
    2818             : #endif
    2819             : }
    2820             : 
    2821             : /* Return the first query variable with the specified key.  If there
    2822             :    is no such variable, return NULL.  */
    2823             : struct uri_tuple_s *
    2824           0 : uri_query_lookup (parsed_uri_t uri, const char *key)
    2825             : {
    2826             :   struct uri_tuple_s *t;
    2827             : 
    2828           0 :   for (t = uri->query; t; t = t->next)
    2829           0 :     if (strcmp (t->name, key) == 0)
    2830           0 :       return t;
    2831             : 
    2832           0 :   return NULL;
    2833             : }

Generated by: LCOV version 1.11