LCOV - code coverage report
Current view: top level - dirmngr - http.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 7 1079 0.6 %
Date: 2015-11-05 17:10:59 Functions: 1 50 2.0 %

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

Generated by: LCOV version 1.11