Updated FSF street address and preparations for a release candidate.
[gnupg.git] / util / http.c
index 531f6a8..33349dc 100644 (file)
@@ -15,7 +15,8 @@
  *
  * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
@@ -72,7 +73,8 @@ static int send_request( HTTP_HD hd, const char *proxy );
 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);
+static int connect_server( const char *server, ushort port, unsigned int flags,
+                          const char *srvtag );
 static int write_server( int sock, const char *data, size_t length );
 
 #ifdef _WIN32
@@ -107,6 +109,40 @@ init_sockets (void)
 }
 #endif /*_WIN32*/
 
+static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                        "abcdefghijklmnopqrstuvwxyz"
+                        "0123456789+/";
+
+/****************
+ * create a radix64 encoded string.
+ */
+
+/* TODO: This is a duplicate of code in g10/armor.c.  Better to use a
+   single copy in strgutil.c */
+static char *
+make_radix64_string( const byte *data, size_t len )
+{
+    char *buffer, *p;
+
+    buffer = p = m_alloc( (len+2)/3*4 + 1 );
+    for( ; len >= 3 ; len -= 3, data += 3 ) {
+       *p++ = bintoasc[(data[0] >> 2) & 077];
+       *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
+       *p++ = bintoasc[(((data[1]<<2)&074)|((data[2]>>6)&03))&077];
+       *p++ = bintoasc[data[2]&077];
+    }
+    if( len == 2 ) {
+       *p++ = bintoasc[(data[0] >> 2) & 077];
+       *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
+       *p++ = bintoasc[((data[1]<<2)&074)];
+    }
+    else if( len == 1 ) {
+       *p++ = bintoasc[(data[0] >> 2) & 077];
+       *p++ = bintoasc[(data[0] <<4)&060];
+    }
+    *p = 0;
+    return buffer;
+}
 
 int
 http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
@@ -275,13 +311,12 @@ do_parse_uri( PARSED_URI uri, int only_local_part )
        *p2++ = 0;
        strlwr( p );
        uri->scheme = p;
-        uri->port = 80;
-       if( !strcmp( uri->scheme, "http" ) )
-           ;
-       else if( !strcmp( uri->scheme, "x-hkp" ) ) /* same as HTTP */
-           uri->port = 11371;
+       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 */
+         return G10ERR_INVALID_URI; /* Unsupported scheme */
 
        p = p2;
 
@@ -294,6 +329,15 @@ do_parse_uri( PARSED_URI uri, int only_local_part )
            p++;
            if( (p2 = strchr(p, '/')) )
                *p2++ = 0;
+
+           /* Check for username/password encoding */
+           if((p3=strchr(p,'@')))
+             {
+               uri->auth=p;
+               *p3++='\0';
+               p=p3;
+             }
+
            strlwr( p );
            uri->host = p;
            if( (p3=strchr( p, ':' )) ) {
@@ -465,6 +509,7 @@ send_request( HTTP_HD hd, const char *proxy )
     byte *request, *p;
     ushort port;
     int rc;
+    char *auth=NULL;
 
     server = *hd->uri->host? hd->uri->host : "localhost";
     port   = hd->uri->port?  hd->uri->port : 80;
@@ -481,35 +526,61 @@ send_request( HTTP_HD hd, const char *proxy )
            return G10ERR_NETWORK;
          }
        hd->sock = connect_server( *uri->host? uri->host : "localhost",
-                                  uri->port? uri->port : 80, 0 );
+                                  uri->port? uri->port : 80, 0, NULL );
+       if(uri->auth)
+         {
+           char *x=make_radix64_string(uri->auth,strlen(uri->auth));
+           auth=m_alloc(50+strlen(x));
+           sprintf(auth,"Proxy-Authorization: Basic %s\r\n",x);
+           m_free(x);
+         }
+
        release_parsed_uri( uri );
       }
     else
-      hd->sock = connect_server( server, port, hd->flags );
+      {
+       hd->sock = connect_server( server, port, hd->flags, hd->uri->scheme );
+       if(hd->uri->auth)
+         {
+           char *x=make_radix64_string(hd->uri->auth,strlen(hd->uri->auth));
+           auth=m_alloc(50+strlen(x));
+           sprintf(auth,"Authorization: Basic %s\r\n",x);
+           m_free(x);
+         }
+      }
 
     if( hd->sock == -1 )
        return G10ERR_NETWORK;
 
     p = build_rel_path( hd->uri );
-    request = m_alloc( strlen(server)*2 + strlen(p) + 50 );
-    if( proxy ) {
-       sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n",
-                         hd->req_type == HTTP_REQ_GET ? "GET" :
-                         hd->req_type == HTTP_REQ_HEAD? "HEAD":
-                         hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
-                         server, port,  *p == '/'? "":"/", p );
-    }
-    else {
-       sprintf( request, "%s %s%s HTTP/1.0\r\nHost: %s\r\n",
-                         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);
-    }
+
+    request=m_alloc(strlen(server)*2 + strlen(p) + (auth?strlen(auth):0) + 65);
+    if( proxy )
+      sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\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",
+              server, port,  *p == '/'? "":"/", p, auth?auth:"" );
+    else
+      {
+       char portstr[15];
+
+       if(port!=80)
+         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:"",
+                auth?auth:"");
+      }
+
     m_free(p);
 
     rc = write_server( hd->sock, request, strlen(request) );
     m_free( request );
+    m_free(auth);
 
     return rc;
 }
@@ -693,7 +764,8 @@ start_server()
 
 
 static int
-connect_server( const char *server, ushort port, unsigned int flags )
+connect_server( const char *server, ushort port, unsigned int flags,
+               const char *srvtag )
 {
   int sock=-1,srv,srvcount=0,connected=0,hostfound=0;
   struct srventry *srvlist=NULL;
@@ -704,7 +776,7 @@ connect_server( const char *server, ushort port, unsigned int flags )
   init_sockets();
   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
      try inet_addr first on that platform only. */
-  if((inaddr=inet_addr(server))!=SOCKET_ERROR)
+  if((inaddr=inet_addr(server))!=INADDR_NONE)
     {
       struct sockaddr_in addr;
 
@@ -718,6 +790,7 @@ connect_server( const char *server, ushort port, unsigned int flags )
 
       addr.sin_family=AF_INET; 
       addr.sin_port=htons(port);
+      memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));      
 
       if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
        return sock;
@@ -731,15 +804,19 @@ connect_server( const char *server, ushort port, unsigned int flags )
 
 #ifdef USE_DNS_SRV
   /* Do the SRV thing */
-  if(flags&HTTP_FLAG_TRY_SRV)
+  if(flags&HTTP_FLAG_TRY_SRV && srvtag)
     {
       /* We're using SRV, so append the tags */
-      char srvname[MAXDNAME];
+      if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME)
+       {
+         char srvname[MAXDNAME];
 
-      strcpy(srvname,"_hkp._tcp.");
-      strncat(srvname,server,MAXDNAME-11);
-      srvname[MAXDNAME-1]='\0';
-      srvcount=getsrv(srvname,&srvlist);
+         strcpy(srvname,"_");
+         strcat(srvname,srvtag);
+         strcat(srvname,"._tcp.");
+         strcat(srvname,server);
+         srvcount=getsrv(srvname,&srvlist);
+       }
     }
 #endif
 
@@ -750,6 +827,7 @@ connect_server( const char *server, ushort port, unsigned int flags )
       srvlist=m_alloc_clear(sizeof(struct srventry));
       srvlist->port=port;
       strncpy(srvlist->target,server,MAXDNAME);
+      srvlist->target[MAXDNAME-1]='\0';
       srvcount=1;
     }
 
@@ -782,6 +860,8 @@ connect_server( const char *server, ushort port, unsigned int flags )
              connected=1;
              break;
            }
+
+         sock_close(sock);
        }
 
       freeaddrinfo(res);
@@ -803,6 +883,8 @@ connect_server( const char *server, ushort port, unsigned int flags )
       if((host=gethostbyname(srvlist[srv].target))==NULL)
        continue;
 
+      hostfound=1;
+
       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
        {
          log_error("error creating socket: %s\n",strerror(errno));
@@ -810,11 +892,23 @@ 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);
+         return -1;
+       }
+
       addr.sin_port=htons(srvlist[srv].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);
+             return -1;
+           }
+
          memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
 
          if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
@@ -828,6 +922,8 @@ connect_server( const char *server, ushort port, unsigned int flags )
 
       if(host->h_addr_list[i])
        break;
+
+      sock_close(sock);
     }
 #endif /* !HAVE_GETADDRINFO */
 
@@ -835,6 +931,7 @@ connect_server( const char *server, ushort port, unsigned int flags )
 
   if(!connected)
     {
+      int err=errno;
 #ifdef _WIN32
       if(hostfound)
        log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
@@ -842,12 +939,13 @@ connect_server( const char *server, ushort port, unsigned int flags )
        log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
 #else
       if(hostfound)
-       log_error("%s: %s\n",server,strerror(errno));
+       log_error("%s: %s\n",server,strerror(err));
       else
        log_error("%s: Host not found\n",server);
 #endif
       if(sock!=-1)
        sock_close(sock);
+      errno=err;
       return -1;
     }