1 /***************************************
2   $Header: /home/amb/CVS/wwwoffle/src/ssl.c,v 1.33 2010-01-19 19:53:29 amb Exp $
3 
4   WWWOFFLE - World Wide Web Offline Explorer - Version 2.9f.
5   SSL (Secure Socket Layer) Tunneling functions.
6   ******************/ /******************
7   Written by Andrew M. Bishop
8 
9   This file Copyright 1998-2010 Andrew M. Bishop
10   It may be distributed under the GNU Public License, version 2, or
11   any higher version.  See section COPYING of the GNU Public license
12   for conditions under which this file may be redistributed.
13   ***************************************/
14 
15 
16 #include "autoconfig.h"
17 
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #if TIME_WITH_SYS_TIME
25 # include <sys/time.h>
26 # include <time.h>
27 #else
28 # if HAVE_SYS_TIME_H
29 #  include <sys/time.h>
30 # else
31 #  include <time.h>
32 # endif
33 #endif
34 
35 #include <errno.h>
36 
37 #include "wwwoffle.h"
38 #include "io.h"
39 #include "misc.h"
40 #include "errors.h"
41 #include "config.h"
42 #include "sockets.h"
43 #include "proto.h"
44 
45 
46 /*+ Set to the name of the proxy if there is one. +*/
47 static URL /*@null@*/ /*@only@*/ *proxyUrl=NULL;
48 
49 /*+ The file descriptor of the server. +*/
50 static int server=-1;
51 
52 
53 /*++++++++++++++++++++++++++++++++++++++
54   Open a connection to get a URL using SSL tunnelling.
55 
56   char *SSL_Open Returns NULL on success, a useful message on error.
57 
58   URL *Url The URL to open (used for host only).
59   ++++++++++++++++++++++++++++++++++++++*/
60 
SSL_Open(URL * Url)61 char *SSL_Open(URL *Url)
62 {
63  char *msg=NULL;
64  char *proxy=NULL;
65  char *server_host=NULL;
66  int server_port=-1;
67 
68  /* Sort out the host. */
69 
70  if(!IsLocalNetHost(Url->host))
71     proxy=ConfigStringURL(SSLProxy,Url);
72 
73  if(proxy)
74    {
75     if(proxyUrl)
76        FreeURL(proxyUrl);
77     proxyUrl=NULL;
78 
79     proxyUrl=CreateURL("http",proxy,"/",NULL,NULL,NULL);
80     server_host=proxyUrl->host;
81     server_port=proxyUrl->port;
82    }
83  else
84    {
85     server_host=Url->host;
86     server_port=Url->port;
87    }
88 
89  if(server_port==-1)
90     server_port=DefaultPort(Url);
91 
92  /* Open the connection. */
93 
94  server=-1;
95 
96  if(server_port)
97    {
98     server=OpenClientSocket(server_host,server_port);
99 
100     if(server==-1)
101        msg=GetPrintMessage(Warning,"Cannot open the https (SSL) connection to %s port %d; [%!s].",server_host,server_port);
102     else
103       {
104        init_io(server);
105        configure_io_timeout(server,ConfigInteger(SocketTimeout),ConfigInteger(SocketTimeout));
106       }
107    }
108  else
109     msg=GetPrintMessage(Warning,"No port given for the https (SSL) connection to %s.",server_host);
110 
111  return(msg);
112 }
113 
114 
115 /*++++++++++++++++++++++++++++++++++++++
116   Write to the server to request the URL and reply to the client.
117 
118   char *SSL_Request Returns NULL on success, a useful message on error.
119 
120   int client The client socket.
121 
122   URL *Url The URL to get (used for host only).
123 
124   Header *request_head The head of the HTTP request for the URL.
125   ++++++++++++++++++++++++++++++++++++++*/
126 
SSL_Request(int client,URL * Url,Header * request_head)127 char *SSL_Request(int client,URL *Url,Header *request_head)
128 {
129  char *msg=NULL;
130 
131  if(proxyUrl)
132    {
133     char *head;
134 
135     ModifyRequest(Url,request_head);
136 
137     MakeRequestProxyAuthorised(proxyUrl,request_head);
138 
139     ChangeURLInHeader(request_head,Url->hostport);
140 
141     head=HeaderString(request_head);
142 
143     PrintMessage(ExtraDebug,"Outgoing Request Head (to https (SSL) proxy)\n%s",head);
144 
145     if(write_string(server,head)==-1)
146        msg=GetPrintMessage(Warning,"Failed to write to remote https (SSL) proxy; [%!s].");
147 
148     free(head);
149    }
150  else
151     write_string(client,"HTTP/1.0 200 WWWOFFLE SSL OK\r\n\r\n");
152 
153  return(msg);
154 }
155 
156 
157 /*++++++++++++++++++++++++++++++++++++++
158   Perform the transfer between client and proxy/server.
159 
160   int client The client socket.
161   ++++++++++++++++++++++++++++++++++++++*/
162 
SSL_Transfer(int client)163 void SSL_Transfer(int client)
164 {
165  int nfd=client>server?client+1:server+1;
166  fd_set readfd;
167  struct timeval tv;
168  int n,nc,ns;
169  char buffer[IO_BUFFER_SIZE];
170 
171  while(1)
172    {
173     nc=ns=0;
174 
175     FD_ZERO(&readfd);
176 
177     FD_SET(server,&readfd);
178     FD_SET(client,&readfd);
179 
180     tv.tv_sec=ConfigInteger(SocketTimeout);
181     tv.tv_usec=0;
182 
183     n=select(nfd,&readfd,NULL,NULL,&tv);
184 
185     if(n<0 && errno==EINTR)
186        continue;
187     else if(n<=0)
188        return;
189 
190     if(FD_ISSET(client,&readfd))
191       {
192        nc=read_data(client,buffer,IO_BUFFER_SIZE);
193        if(nc>0)
194           write_data(server,buffer,nc);
195       }
196     if(FD_ISSET(server,&readfd))
197       {
198        ns=read_data(server,buffer,IO_BUFFER_SIZE);
199        if(ns>0)
200           write_data(client,buffer,ns);
201       }
202 
203     if(nc==0 && ns==0)
204        return;
205    }
206 }
207 
208 
209 /*++++++++++++++++++++++++++++++++++++++
210   Close a connection opened using SSL.
211 
212   int SSL_Close Return 0 on success, -1 on error.
213   ++++++++++++++++++++++++++++++++++++++*/
214 
SSL_Close(void)215 int SSL_Close(void)
216 {
217  unsigned long r,w;
218 
219  finish_tell_io(server,&r,&w);
220 
221  PrintMessage(Inform,"Server bytes; %d Read, %d Written.",r,w); /* Used in audit-usage.pl */
222 
223  if(proxyUrl)
224     FreeURL(proxyUrl);
225  proxyUrl=NULL;
226 
227  return(CloseSocket(server));
228 }
229