Obsolete option --no-sig-create-check.
[gnupg.git] / util / http.c
index b5dc682..2f630ae 100644 (file)
@@ -1,12 +1,12 @@
 /* http.c  -  HTTP protocol handler
- * Copyright (C) 1999, 2001, 2002, 2003, 2004,
- *               2005 Free Software Foundation, Inc.
+ * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ *               2009, 2012 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -15,9 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -70,12 +68,13 @@ static int remove_escapes( byte *string );
 static int insert_escapes( byte *buffer, const byte *string,
                                         const byte *special );
 static URI_TUPLE parse_tuple( byte *string );
-static int send_request( HTTP_HD hd, const char *auth, const char *proxy );
+static int send_request( HTTP_HD hd, const char *auth, const char *proxy,
+                        struct http_srv *srv, STRLIST headers);
 static byte *build_rel_path( PARSED_URI uri );
 static int parse_response( HTTP_HD hd );
 
 static int connect_server( const char *server, ushort port, unsigned int flags,
-                          const char *srvtag );
+                          struct http_srv *srv );
 static int write_server( int sock, const char *data, size_t length );
 
 #ifdef _WIN32
@@ -95,7 +94,7 @@ init_sockets (void)
         return;
 
     if( WSAStartup( 0x0101, &wsdata ) ) {
-        log_error ("error initializing socket library: ec=%d\n", 
+        log_error ("error initializing socket library: ec=%d\n",
                     (int)WSAGetLastError () );
         return;
     }
@@ -150,7 +149,8 @@ make_radix64_string( const byte *data, size_t len )
 
 int
 http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
-          char *auth, unsigned int flags, const char *proxy )
+          char *auth, unsigned int flags, const char *proxy,
+          struct http_srv *srv, STRLIST headers )
 {
     int rc;
 
@@ -166,7 +166,7 @@ http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
 
     rc = parse_uri( &hd->uri, url );
     if( !rc ) {
-       rc = send_request( hd, auth, proxy );
+        rc = send_request( hd, auth, proxy, srv, headers );
        if( !rc ) {
            hd->fp_write = iobuf_sockopen( hd->sock , "w" );
            if( hd->fp_write )
@@ -205,15 +205,19 @@ http_wait_response( HTTP_HD hd, unsigned int *ret_status )
     http_start_data( hd ); /* make sure that we are in the data */
 
 #if 0
-    hd->sock = dup( hd->sock ); 
+    hd->sock = dup( hd->sock );
     if( hd->sock == -1 )
        return G10ERR_GENERAL;
 #endif
     iobuf_ioctl (hd->fp_write, 1, 1, NULL); /* keep the socket open */
     iobuf_close (hd->fp_write);
     hd->fp_write = NULL;
-    if ( !(hd->flags & HTTP_FLAG_NO_SHUTDOWN) )
-        shutdown( hd->sock, 1 );
+    /* We do not want the shutdown code anymore.  It used to be there
+       to support old versions of pksd.  These versions are anyway
+       unusable and the latest releases haven been fixed to properly
+       handle HTTP 1.0. */
+    /* if ( !(hd->flags & HTTP_FLAG_NO_SHUTDOWN) ) */
+    /*     shutdown( hd->sock, 1 ); */
     hd->in_data = 0;
 
     hd->fp_read = iobuf_sockopen( hd->sock , "r" );
@@ -230,11 +234,13 @@ http_wait_response( HTTP_HD hd, unsigned int *ret_status )
 
 int
 http_open_document( HTTP_HD hd, const char *document, char *auth,
-                   unsigned int flags, const char *proxy )
+                   unsigned int flags, const char *proxy, struct http_srv *srv,
+                   STRLIST headers )
 {
     int rc;
 
-    rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy );
+    rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy, srv,
+                  headers );
     if( rc )
        return rc;
 
@@ -317,8 +323,6 @@ do_parse_uri( PARSED_URI uri, int only_local_part )
        uri->scheme = p;
        if(strcmp(uri->scheme,"http")==0)
          uri->port = 80;
-       else if(strcmp(uri->scheme,"hkp")==0)
-         uri->port = 11371;
        else
          return G10ERR_INVALID_URI; /* Unsupported scheme */
 
@@ -343,16 +347,27 @@ do_parse_uri( PARSED_URI uri, int only_local_part )
              }
 
            strlwr( p );
-           uri->host = p;
-           if( (p3=strchr( p, ':' )) ) {
-               *p3++ = 0;
+
+           /* Handle a host of [IP] so that [IP:V6]:port works */
+           if( *p == '[' && (p3=strchr( p, ']' )) )
+             {
+               *p3++ = '\0';
+               /* worst case, uri->host should have length 0, points to \0 */
+               uri->host = p + 1;
+               p = p3;
+             }
+           else
+             uri->host = p;
+
+           if( (p3=strchr( p, ':' )) )
+             {
+               *p3++ = '\0';
                uri->port = atoi( p3 );
-           }
+             }
 
-           uri->host = p;
            if( (n = remove_escapes( uri->host )) < 0 )
                return G10ERR_BAD_URI;
-           if( n != strlen( p ) )
+           if( n != strlen( uri->host ) )
                return G10ERR_BAD_URI; /* hostname with a Nul in it */
            p = p2 ? p2 : NULL;
        }
@@ -507,7 +522,8 @@ parse_tuple( byte *string )
  * Returns 0 if the request was successful
  */
 static int
-send_request( HTTP_HD hd, const char *auth, const char *proxy )
+send_request( HTTP_HD hd, const char *auth, const char *proxy,
+             struct http_srv *srv, STRLIST headers )
 {
     const byte *server;
     byte *request, *p;
@@ -530,7 +546,7 @@ send_request( HTTP_HD hd, const char *auth, const char *proxy )
            return G10ERR_NETWORK;
          }
        hd->sock = connect_server( *uri->host? uri->host : "localhost",
-                                  uri->port? uri->port : 80, 0, NULL );
+                                  uri->port? uri->port : 80, 0, srv );
        if(uri->auth)
          {
            char *x;
@@ -544,7 +560,7 @@ send_request( HTTP_HD hd, const char *auth, const char *proxy )
        release_parsed_uri( uri );
       }
     else
-      hd->sock = connect_server( server, port, hd->flags, hd->uri->scheme );
+      hd->sock = connect_server( server, port, hd->flags, srv );
 
     if(auth || hd->uri->auth)
       {
@@ -574,7 +590,7 @@ send_request( HTTP_HD hd, const char *auth, const char *proxy )
     request=xmalloc(strlen(server)*2 + strlen(p)
                    + (authstr?strlen(authstr):0)
                    + (proxy_authstr?strlen(proxy_authstr):0) + 65);
-    if( proxy )
+    if( proxy && *proxy )
       sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
               hd->req_type == HTTP_REQ_GET ? "GET" :
               hd->req_type == HTTP_REQ_HEAD? "HEAD":
@@ -583,22 +599,37 @@ send_request( HTTP_HD hd, const char *auth, const char *proxy )
               authstr?authstr:"",proxy_authstr?proxy_authstr:"" );
     else
       {
-       char portstr[15];
+       char portstr[35];
 
-       if(port!=80)
+       if(port == 80 || (srv && srv->used_server))
+         *portstr = 0;
+       else
          sprintf(portstr,":%u",port);
 
        sprintf( request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
                 hd->req_type == HTTP_REQ_GET ? "GET" :
                 hd->req_type == HTTP_REQ_HEAD? "HEAD":
                 hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
-                *p == '/'? "":"/", p, server, (port!=80)?portstr:"",
+                *p == '/'? "":"/", p, server, portstr,
                 authstr?authstr:"");
       }
 
     xfree(p);
 
     rc = write_server( hd->sock, request, strlen(request) );
+
+    if(rc==0)
+      for(;headers;headers=headers->next)
+       {
+         rc = write_server( hd->sock, headers->d, strlen(headers->d) );
+         if(rc)
+           break;
+
+         rc = write_server( hd->sock, "\r\n", 2 );
+         if(rc)
+           break;
+       }
+
     xfree( request );
     xfree(proxy_authstr);
     xfree(authstr);
@@ -713,7 +744,7 @@ parse_response( HTTP_HD hd )
 
 #ifdef TEST
 static int
-start_server()
+start_server(void)
 {
     struct sockaddr_in mya;
     struct sockaddr_in peer;
@@ -786,10 +817,16 @@ start_server()
 
 static int
 connect_server( const char *server, ushort port, unsigned int flags,
-               const char *srvtag )
+               struct http_srv *srv )
 {
-  int sock=-1,srv,srvcount=0,connected=0,hostfound=0;
-  struct srventry *srvlist=NULL;
+  int sock = -1;
+  int srvcount = 0;
+  int connected = 0;
+  int hostfound = 0;
+  int chosen = -1;
+  int fakesrv = 0;
+  struct srventry *srvlist = NULL;
+  int srvindex;
 
 #ifdef _WIN32
   unsigned long inaddr;
@@ -809,9 +846,9 @@ connect_server( const char *server, ushort port, unsigned int flags,
          return -1;
        }
 
-      addr.sin_family=AF_INET; 
+      addr.sin_family=AF_INET;
       addr.sin_port=htons(port);
-      memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));      
+      memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));
 
       if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
        return sock;
@@ -825,15 +862,15 @@ connect_server( const char *server, ushort port, unsigned int flags,
 
 #ifdef USE_DNS_SRV
   /* Do the SRV thing */
-  if(flags&HTTP_FLAG_TRY_SRV && srvtag)
+  if(srv && srv->srvtag)
     {
       /* We're using SRV, so append the tags */
-      if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME)
+      if(1+strlen(srv->srvtag)+6+strlen(server)+1<=MAXDNAME)
        {
          char srvname[MAXDNAME];
 
          strcpy(srvname,"_");
-         strcat(srvname,srvtag);
+         strcat(srvname,srv->srvtag);
          strcat(srvname,"._tcp.");
          strcat(srvname,server);
          srvcount=getsrv(srvname,&srvlist);
@@ -845,24 +882,27 @@ connect_server( const char *server, ushort port, unsigned int flags,
     {
       /* Either we're not using SRV, or the SRV lookup failed.  Make
         up a fake SRV record. */
-      srvlist=xmalloc_clear(sizeof(struct srventry));
+      srvlist=calloc(1,sizeof(struct srventry));
+      if(!srvlist)
+       return -1;
       srvlist->port=port;
       strncpy(srvlist->target,server,MAXDNAME);
       srvlist->target[MAXDNAME-1]='\0';
-      srvcount=1;
+      srvcount = 1;
+      fakesrv = 1;
     }
 
 #ifdef HAVE_GETADDRINFO
 
-  for(srv=0;srv<srvcount;srv++)
+  for(srvindex=0;srvindex<srvcount;srvindex++)
     {
       struct addrinfo hints,*res,*ai;
       char portstr[6];
 
-      sprintf(portstr,"%u",srvlist[srv].port);
+      sprintf(portstr,"%u",srvlist[srvindex].port);
       memset(&hints,0,sizeof(hints));
       hints.ai_socktype=SOCK_STREAM;
-      if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)==0)
+      if(getaddrinfo(srvlist[srvindex].target,portstr,&hints,&res)==0)
        hostfound=1;
       else
        continue;
@@ -879,6 +919,7 @@ connect_server( const char *server, ushort port, unsigned int flags,
          if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
            {
              connected=1;
+             chosen = srvindex;
              break;
            }
 
@@ -893,7 +934,7 @@ connect_server( const char *server, ushort port, unsigned int flags,
 
 #else /* !HAVE_GETADDRINFO */
 
-  for(srv=0;srv<srvcount;srv++)
+  for(srvindex=0; srvindex < srvcount; srvindex++)
     {
       int i=0;
       struct hostent *host=NULL;
@@ -901,7 +942,7 @@ connect_server( const char *server, ushort port, unsigned int flags,
 
       memset(&addr,0,sizeof(addr));
 
-      if((host=gethostbyname(srvlist[srv].target))==NULL)
+      if((host=gethostbyname(srvlist[srvindex].target))==NULL)
        continue;
 
       hostfound=1;
@@ -915,18 +956,18 @@ connect_server( const char *server, ushort port, unsigned int flags,
       addr.sin_family=host->h_addrtype;
       if(addr.sin_family!=AF_INET)
        {
-         log_error("%s: unknown address family\n",srvlist[srv].target);
+         log_error("%s: unknown address family\n",srvlist[srvindex].target);
          return -1;
        }
 
-      addr.sin_port=htons(srvlist[srv].port);
+      addr.sin_port=htons(srvlist[srvindex].port);
 
       /* Try all A records until one responds. */
       while(host->h_addr_list[i])
        {
          if(host->h_length!=4)
            {
-             log_error("%s: illegal address length\n",srvlist[srv].target);
+             log_error("%s: illegal address length\n",srvlist[srvindex].target);
              return -1;
            }
 
@@ -935,6 +976,7 @@ connect_server( const char *server, ushort port, unsigned int flags,
          if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
            {
              connected=1;
+             chosen = srvindex;
              break;
            }
 
@@ -948,7 +990,13 @@ connect_server( const char *server, ushort port, unsigned int flags,
     }
 #endif /* !HAVE_GETADDRINFO */
 
-  xfree(srvlist);
+  if(!fakesrv && chosen > -1 && srv)
+    {
+      srv->used_server = strdup (srvlist[chosen].target);
+      srv->used_port = srvlist[chosen].port;
+    }
+
+  free(srvlist);
 
   if(!connected)
     {
@@ -981,7 +1029,7 @@ write_server( int sock, const char *data, size_t length )
 
     nleft = length;
     while( nleft > 0 ) {
-#ifdef _WIN32  
+#ifdef _WIN32
         int nwritten;
 
         nwritten = send (sock, data, nleft, 0);
@@ -1062,7 +1110,7 @@ main(int argc, char **argv)
     }
     release_parsed_uri( uri ); uri = NULL;
 
-    rc = http_open_document( &hd, *argv, 0, NULL );
+    rc = http_open_document( &hd, *argv, NULL, 0, NULL, NULL, NULL );
     if( rc ) {
        log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
        return 1;