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

Generated by: LCOV version 1.11