2222#include "userinput.h"
2323#include "log.h"
2424
25+ #include <assert.h>
2526#include <ctype.h>
2627#include <string.h>
2728#include <stdarg.h>
3031#include <unistd.h>
3132#include <arpa/inet.h>
3233
33- #define BUFSZ 0x10000
34+ static const uint32_t HTTP_BUFFER_SIZE = 0x8000 ;
35+
3436
3537/*
3638 * URL-encodes a string for HTTP requests.
@@ -58,6 +60,7 @@ static void url_encode(char *dest, const char *str)
5860 * dest = '\0' ;
5961}
6062
63+
6164/*
6265 * Sends data to the HTTP server.
6366 *
@@ -68,13 +71,13 @@ static void url_encode(char *dest, const char *str)
6871int http_send (struct tunnel * tunnel , const char * request , ...)
6972{
7073 va_list args ;
71- char buffer [BUFSZ ];
72- char logbuffer [BUFSZ ];
74+ char buffer [HTTP_BUFFER_SIZE ];
75+ char logbuffer [HTTP_BUFFER_SIZE ];
7376 int length ;
7477 int n = 0 ;
7578
7679 va_start (args , request );
77- length = vsnprintf (buffer , BUFSZ , request , args );
80+ length = vsnprintf (buffer , HTTP_BUFFER_SIZE , request , args );
7881 va_end (args );
7982 strcpy (logbuffer , buffer );
8083 if (loglevel <= OFV_LOG_DEBUG_DETAILS && tunnel -> config -> password [0 ] != '\0' ) {
@@ -96,7 +99,7 @@ int http_send(struct tunnel *tunnel, const char *request, ...)
9699
97100 if (length < 0 )
98101 return ERR_HTTP_INVALID ;
99- else if (length >= BUFSZ )
102+ else if (length >= HTTP_BUFFER_SIZE )
100103 return ERR_HTTP_TOO_LONG ;
101104
102105 log_debug_details ("%s:\n%s\n" , __func__ , logbuffer );
@@ -113,6 +116,7 @@ int http_send(struct tunnel *tunnel, const char *request, ...)
113116 return 1 ;
114117}
115118
119+
116120static const char * find_header (
117121 const char * res ,
118122 const char * header ,
@@ -135,6 +139,7 @@ static const char *find_header(
135139 return NULL ;
136140}
137141
142+
138143/*
139144 * Receives data from the HTTP server.
140145 *
@@ -150,75 +155,87 @@ int http_receive(
150155 uint32_t * response_size
151156)
152157{
153- uint32_t res_size = BUFSZ ;
154- char * buffer , * res ;
155- int n = 0 ;
156- int bytes_read = 0 ;
157- int header_size = 0 ;
158- int content_size = 0 ;
158+ uint32_t capacity = HTTP_BUFFER_SIZE ;
159+ char * buffer ;
160+ uint32_t bytes_read = 0 ;
161+ uint32_t header_size = 0 ;
162+ uint32_t content_size = 0 ;
159163 int chunked = 0 ;
160164
161- buffer = malloc (res_size );
165+ buffer = malloc (capacity );
162166 if (buffer == NULL )
163167 return ERR_HTTP_NO_MEM ;
164168
165- do {
166- n = safe_ssl_read (tunnel -> ssl_handle ,
167- (uint8_t * ) buffer + bytes_read ,
168- BUFSZ - 1 - bytes_read );
169- if (n > 0 ) {
170- log_debug_details ("%s:\n%s\n" , __func__ , buffer );
171- const char * eoh ;
172-
173- bytes_read += n ;
174-
175- if (!header_size ) {
176- /* Did we see the header end? Then get the body size. */
177- eoh = memmem (buffer , bytes_read , "\r\n\r\n" , 4 );
178- if (eoh ) {
179- const char * header ;
180-
181- header = find_header (
182- buffer ,
183- "Content-Length: " , BUFSZ );
184- header_size = eoh - buffer + 4 ;
185- if (header )
186- content_size = atoi (header );
187-
188- if (find_header (buffer ,
189- "Transfer-Encoding: chunked" ,
190- BUFSZ ))
191- chunked = 1 ;
192- }
169+ while (1 ) {
170+ int n ;
171+
172+ while ((n = safe_ssl_read (tunnel -> ssl_handle ,
173+ (uint8_t * ) buffer + bytes_read ,
174+ capacity - bytes_read )) == ERR_SSL_AGAIN )
175+ ;
176+ if (n < 0 ) {
177+ log_error ("Error reading from SSL connection (%s).\n" ,
178+ err_ssl_str (n ));
179+ free (buffer );
180+ return ERR_HTTP_SSL ;
181+ }
182+ bytes_read += n ;
183+
184+ log_debug_details ("%s:\n%s\n" , __func__ , buffer );
185+
186+ if (!header_size ) {
187+ /* Have we reached the end of the HTTP header? */
188+ static const char EOH [4 ] = "\r\n\r\n" ;
189+ const char * eoh = memmem (buffer , bytes_read ,
190+ EOH , sizeof (EOH ));
191+
192+ if (eoh ) {
193+ header_size = eoh - buffer + sizeof (EOH );
194+
195+ /* Get the body size. */
196+ const char * header = find_header (buffer ,
197+ "Content-Length: " ,
198+ header_size );
199+
200+ if (header )
201+ content_size = atoi (header );
202+
203+ if (find_header (buffer ,
204+ "Transfer-Encoding: chunked" ,
205+ header_size ))
206+ chunked = 1 ;
193207 }
208+ }
194209
195- if (header_size ) {
196- /* We saw the whole header, is the body done as well? */
197- if (chunked ) {
198- /* Last chunk terminator. Done naively. */
199- if (bytes_read >= 7 &&
200- !memcmp (& buffer [bytes_read - 7 ],
201- "\r\n0\r\n\r\n" , 7 ))
202- break ;
203- } else {
204- if (bytes_read >= header_size + content_size )
205- break ;
206- }
210+ if (header_size ) {
211+ /* Have we reached the end of the HTTP body? */
212+ if (chunked ) {
213+ static const char EOB [7 ] = "\r\n0\r\n\r\n" ;
214+
215+ /* Last chunk terminator. Done naively. */
216+ if (bytes_read >= sizeof (EOB ) &&
217+ !memcmp (& buffer [bytes_read - sizeof (EOB )],
218+ EOB , sizeof (EOB )))
219+ break ;
220+ } else {
221+ if (bytes_read >= header_size + content_size )
222+ break ;
207223 }
224+ }
208225
209- if (bytes_read == BUFSZ - 1 ) {
210- log_warn ("Response too big\n" );
226+ /* expand the buffer if necessary */
227+ if (bytes_read == capacity ) {
228+ char * new_buffer ;
229+
230+ assert (UINT32_MAX / capacity >= 2 );
231+ capacity *= 2 ;
232+ new_buffer = realloc (buffer , capacity );
233+ if (new_buffer == NULL ) {
211234 free (buffer );
212- return ERR_HTTP_SSL ;
235+ return ERR_HTTP_NO_MEM ;
213236 }
237+ buffer = new_buffer ;
214238 }
215- } while (n >= 0 );
216-
217- if (!header_size ) {
218- log_debug ("Error reading from SSL connection (%s).\n" ,
219- err_ssl_str (n ));
220- free (buffer );
221- return ERR_HTTP_SSL ;
222239 }
223240
224241 if (memmem (& buffer [header_size ], bytes_read - header_size ,
@@ -231,23 +248,26 @@ int http_receive(
231248
232249 if (response == NULL ) {
233250 free (buffer );
234- return 1 ;
235- }
251+ } else {
252+ char * tmp ;
253+
254+ assert (capacity < UINT32_MAX );
255+ capacity = bytes_read + 1 ;
256+ tmp = realloc (buffer , capacity );
257+ if (tmp == NULL ) {
258+ free (buffer );
259+ return ERR_HTTP_NO_MEM ;
260+ }
261+ tmp [bytes_read ] = '\0' ;
262+ * response = tmp ;
236263
237- res_size = bytes_read + 1 ;
238- res = realloc (buffer , res_size );
239- if (res == NULL ) {
240- free (buffer );
241- return ERR_HTTP_NO_MEM ;
264+ if (response_size != NULL )
265+ * response_size = capacity ;
242266 }
243- res [bytes_read ] = '\0' ;
244-
245- * response = res ;
246- if (response_size != NULL )
247- * response_size = res_size ;
248267 return 1 ;
249268}
250269
270+
251271static int do_http_request (struct tunnel * tunnel ,
252272 const char * method ,
253273 const char * uri ,
@@ -276,6 +296,8 @@ static int do_http_request(struct tunnel *tunnel,
276296
277297 return http_receive (tunnel , response , response_size );
278298}
299+
300+
279301/*
280302 * Sends and receives data from the HTTP server.
281303 *
@@ -307,6 +329,7 @@ static int http_request(struct tunnel *tunnel, const char *method,
307329 return ret ;
308330}
309331
332+
310333/*
311334 * Read value for key from a string like "key1=value1&key2=value2".
312335 * The `key` arg is supposed to contains the final "=".
@@ -351,6 +374,7 @@ static int get_value_from_response(const char *buf, const char *key,
351374 return ret ;
352375}
353376
377+
354378static int get_auth_cookie (
355379 struct tunnel * tunnel ,
356380 char * buf ,
@@ -390,6 +414,7 @@ static int get_auth_cookie(
390414 return ret ;
391415}
392416
417+
393418static void delay_otp (struct tunnel * tunnel )
394419{
395420 if (tunnel -> config -> otp_delay > 0 ) {
@@ -398,8 +423,8 @@ static void delay_otp(struct tunnel *tunnel)
398423 }
399424}
400425
401- static
402- int try_otp_auth (
426+
427+ static int try_otp_auth (
403428 struct tunnel * tunnel ,
404429 const char * buffer ,
405430 char * * res ,
@@ -555,6 +580,7 @@ int try_otp_auth(
555580#undef SPACE_AVAILABLE
556581}
557582
583+
558584/*
559585 * Authenticates to gateway by sending username and password.
560586 *
@@ -684,11 +710,13 @@ int auth_log_in(struct tunnel *tunnel)
684710 return ret ;
685711}
686712
713+
687714int auth_log_out (struct tunnel * tunnel )
688715{
689716 return http_request (tunnel , "GET" , "/remote/logout" , "" , NULL , NULL );
690717}
691718
719+
692720int auth_request_vpn_allocation (struct tunnel * tunnel )
693721{
694722 int ret = http_request (tunnel , "GET" , "/remote/index" , "" , NULL , NULL );
@@ -699,6 +727,7 @@ int auth_request_vpn_allocation(struct tunnel *tunnel)
699727 return http_request (tunnel , "GET" , "/remote/fortisslvpn" , "" , NULL , NULL );
700728}
701729
730+
702731static int parse_xml_config (struct tunnel * tunnel , const char * buffer )
703732{
704733 const char * val ;
@@ -778,8 +807,8 @@ static int parse_xml_config(struct tunnel *tunnel, const char *buffer)
778807 return 1 ;
779808}
780809
781- static
782- int parse_config (struct tunnel * tunnel , const char * buffer )
810+
811+ static int parse_config (struct tunnel * tunnel , const char * buffer )
783812{
784813 const char * c , * end ;
785814
@@ -828,6 +857,7 @@ int parse_config(struct tunnel *tunnel, const char *buffer)
828857 return 1 ;
829858}
830859
860+
831861int auth_get_config (struct tunnel * tunnel )
832862{
833863 char * buffer ;
0 commit comments