1 |
--- openconnect-3.02/http.c.orig 2013-02-15 18:06:00.434118116 -0500 |
2 |
+++ openconnect-3.02/http.c 2013-02-15 18:16:59.784672829 -0500 |
3 |
@@ -33,6 +33,7 @@ |
4 |
#include <pwd.h> |
5 |
#include <sys/stat.h> |
6 |
#include <sys/types.h> |
7 |
+#include <stdarg.h> |
8 |
|
9 |
#include <openssl/ssl.h> |
10 |
#include <openssl/err.h> |
11 |
@@ -43,6 +44,85 @@ |
12 |
static int proxy_write(int fd, unsigned char *buf, size_t len); |
13 |
|
14 |
#define MAX_BUF_LEN 131072 |
15 |
+#define BUF_CHUNK_SIZE 4096 |
16 |
+ |
17 |
+struct oc_text_buf { |
18 |
+ char *data; |
19 |
+ int pos; |
20 |
+ int buf_len; |
21 |
+ int error; |
22 |
+}; |
23 |
+ |
24 |
+static struct oc_text_buf *buf_alloc(void) |
25 |
+{ |
26 |
+ return calloc(1, sizeof(struct oc_text_buf)); |
27 |
+} |
28 |
+ |
29 |
+static void buf_append(struct oc_text_buf *buf, const char *fmt, ...) |
30 |
+{ |
31 |
+ va_list ap; |
32 |
+ |
33 |
+ if (!buf || buf->error) |
34 |
+ return; |
35 |
+ |
36 |
+ if (!buf->data) { |
37 |
+ buf->data = malloc(BUF_CHUNK_SIZE); |
38 |
+ if (!buf->data) { |
39 |
+ buf->error = -ENOMEM; |
40 |
+ return; |
41 |
+ } |
42 |
+ buf->buf_len = BUF_CHUNK_SIZE; |
43 |
+ } |
44 |
+ |
45 |
+ while (1) { |
46 |
+ int max_len = buf->buf_len - buf->pos, ret; |
47 |
+ |
48 |
+ va_start(ap, fmt); |
49 |
+ ret = vsnprintf(buf->data + buf->pos, max_len, fmt, ap); |
50 |
+ va_end(ap); |
51 |
+ if (ret < 0) { |
52 |
+ buf->error = -EIO; |
53 |
+ break; |
54 |
+ } else if (ret < max_len) { |
55 |
+ buf->pos += ret; |
56 |
+ break; |
57 |
+ } else { |
58 |
+ int new_buf_len = buf->buf_len + BUF_CHUNK_SIZE; |
59 |
+ |
60 |
+ if (new_buf_len > MAX_BUF_LEN) { |
61 |
+ /* probably means somebody is messing with us */ |
62 |
+ buf->error = -E2BIG; |
63 |
+ break; |
64 |
+ } |
65 |
+ |
66 |
+ buf->data = realloc(buf->data, new_buf_len); |
67 |
+ if (!buf->data) { |
68 |
+ buf->error = -ENOMEM; |
69 |
+ break; |
70 |
+ } |
71 |
+ buf->buf_len = new_buf_len; |
72 |
+ } |
73 |
+ } |
74 |
+} |
75 |
+ |
76 |
+static int buf_error(struct oc_text_buf *buf) |
77 |
+{ |
78 |
+ return buf ? buf->error : -ENOMEM; |
79 |
+} |
80 |
+ |
81 |
+static int buf_free(struct oc_text_buf *buf) |
82 |
+{ |
83 |
+ int error = buf_error(buf); |
84 |
+ |
85 |
+ if (buf) { |
86 |
+ if (buf->data) |
87 |
+ free(buf->data); |
88 |
+ free(buf); |
89 |
+ } |
90 |
+ |
91 |
+ return error; |
92 |
+} |
93 |
+ |
94 |
/* |
95 |
* We didn't really want to have to do this for ourselves -- one might have |
96 |
* thought that it would be available in a library somewhere. But neither |
97 |
@@ -320,7 +400,7 @@ static int fetch_config(struct openconne |
98 |
char *server_sha1) |
99 |
{ |
100 |
struct vpn_option *opt; |
101 |
- char buf[MAX_BUF_LEN]; |
102 |
+ struct oc_text_buf *buf; |
103 |
char *config_buf = NULL; |
104 |
int result, buflen; |
105 |
unsigned char local_sha1_bin[SHA_DIGEST_LENGTH]; |
106 |
@@ -328,21 +408,31 @@ static int fetch_config(struct openconne |
107 |
EVP_MD_CTX c; |
108 |
int i; |
109 |
|
110 |
- sprintf(buf, "GET %s%s HTTP/1.1\r\n", fu, bu); |
111 |
- sprintf(buf + strlen(buf), "Host: %s\r\n", vpninfo->hostname); |
112 |
- sprintf(buf + strlen(buf), "User-Agent: %s\r\n", vpninfo->useragent); |
113 |
- sprintf(buf + strlen(buf), "Accept: */*\r\n"); |
114 |
- sprintf(buf + strlen(buf), "Accept-Encoding: identity\r\n"); |
115 |
+ buf = buf_alloc(); |
116 |
+ buf_append(buf, "GET %s%s HTTP/1.1\r\n", fu, bu); |
117 |
+ buf_append(buf, "Host: %s\r\n", vpninfo->hostname); |
118 |
+ buf_append(buf, "User-Agent: %s\r\n", vpninfo->useragent); |
119 |
+ buf_append(buf, "Accept: */*\r\n"); |
120 |
+ buf_append(buf, "Accept-Encoding: identity\r\n"); |
121 |
|
122 |
if (vpninfo->cookies) { |
123 |
- sprintf(buf + strlen(buf), "Cookie: "); |
124 |
+ buf_append(buf, "Cookie: "); |
125 |
for (opt = vpninfo->cookies; opt; opt = opt->next) |
126 |
- sprintf(buf + strlen(buf), "%s=%s%s", opt->option, |
127 |
+ buf_append(buf, "%s=%s%s", opt->option, |
128 |
opt->value, opt->next ? "; " : "\r\n"); |
129 |
} |
130 |
- sprintf(buf + strlen(buf), "X-Transcend-Version: 1\r\n\r\n"); |
131 |
+ buf_append(buf, "X-Transcend-Version: 1\r\n\r\n"); |
132 |
+ |
133 |
+ if (buf_error(buf)) |
134 |
+ return buf_free(buf); |
135 |
|
136 |
- SSL_write(vpninfo->https_ssl, buf, strlen(buf)); |
137 |
+ if (SSL_write(vpninfo->https_ssl, buf->data, buf->pos) != buf->pos) { |
138 |
+ vpn_progress(vpninfo, PRG_ERR, |
139 |
+ _("Failed to send GET request for new config\n")); |
140 |
+ buf_free(buf); |
141 |
+ return -EIO; |
142 |
+ } |
143 |
+ buf_free(buf); |
144 |
|
145 |
buflen = process_http_response(vpninfo, &result, NULL, &config_buf); |
146 |
if (buflen < 0) { |
147 |
@@ -591,7 +681,7 @@ int internal_parse_url(char *url, char * |
148 |
int openconnect_obtain_cookie(struct openconnect_info *vpninfo) |
149 |
{ |
150 |
struct vpn_option *opt, *next; |
151 |
- char buf[MAX_BUF_LEN]; |
152 |
+ struct oc_text_buf *buf; |
153 |
char *form_buf = NULL; |
154 |
int result, buflen; |
155 |
char request_body[2048]; |
156 |
@@ -618,27 +708,26 @@ int openconnect_obtain_cookie(struct ope |
157 |
* |
158 |
* So we process the HTTP for ourselves... |
159 |
*/ |
160 |
- sprintf(buf, "%s /%s HTTP/1.1\r\n", method, vpninfo->urlpath ?: ""); |
161 |
- sprintf(buf + strlen(buf), "Host: %s\r\n", vpninfo->hostname); |
162 |
- sprintf(buf + strlen(buf), "User-Agent: %s\r\n", vpninfo->useragent); |
163 |
- sprintf(buf + strlen(buf), "Accept: */*\r\n"); |
164 |
- sprintf(buf + strlen(buf), "Accept-Encoding: identity\r\n"); |
165 |
+ buf = buf_alloc(); |
166 |
+ buf_append(buf, "%s /%s HTTP/1.1\r\n", method, vpninfo->urlpath ?: ""); |
167 |
+ buf_append(buf, "Host: %s\r\n", vpninfo->hostname); |
168 |
+ buf_append(buf, "User-Agent: %s\r\n", vpninfo->useragent); |
169 |
+ buf_append(buf, "Accept: */*\r\n"); |
170 |
+ buf_append(buf, "Accept-Encoding: identity\r\n"); |
171 |
|
172 |
if (vpninfo->cookies) { |
173 |
- sprintf(buf + strlen(buf), "Cookie: "); |
174 |
+ buf_append(buf, "Cookie: "); |
175 |
for (opt = vpninfo->cookies; opt; opt = opt->next) |
176 |
- sprintf(buf + strlen(buf), "%s=%s%s", opt->option, |
177 |
- opt->value, opt->next ? "; " : "\r\n"); |
178 |
+ buf_append(buf, "%s=%s%s", opt->option, |
179 |
+ opt->value, opt->next ? "; " : "\r\n"); |
180 |
} |
181 |
if (request_body_type) { |
182 |
- sprintf(buf + strlen(buf), "Content-Type: %s\r\n", |
183 |
- request_body_type); |
184 |
- sprintf(buf + strlen(buf), "Content-Length: %zd\r\n", |
185 |
- strlen(request_body)); |
186 |
+ buf_append(buf, "Content-Type: %s\r\n", request_body_type); |
187 |
+ buf_append(buf, "Content-Length: %zd\r\n", strlen(request_body)); |
188 |
} |
189 |
- sprintf(buf + strlen(buf), "X-Transcend-Version: 1\r\n\r\n"); |
190 |
+ buf_append(buf, "X-Transcend-Version: 1\r\n\r\n"); |
191 |
if (request_body_type) |
192 |
- sprintf(buf + strlen(buf), "%s", request_body); |
193 |
+ buf_append(buf, "%s", request_body); |
194 |
|
195 |
if (vpninfo->port == 443) |
196 |
vpninfo->progress(vpninfo, PRG_INFO, "%s https://%s/%s\n", |
197 |
@@ -649,7 +738,13 @@ int openconnect_obtain_cookie(struct ope |
198 |
method, vpninfo->hostname, vpninfo->port, |
199 |
vpninfo->urlpath ?: ""); |
200 |
|
201 |
- SSL_write(vpninfo->https_ssl, buf, strlen(buf)); |
202 |
+ if (buf_error(buf)) |
203 |
+ return buf_free(buf); |
204 |
+ |
205 |
+ result = SSL_write(vpninfo->https_ssl, buf->data, buf->pos); |
206 |
+ buf_free(buf); |
207 |
+ if (result < 0) |
208 |
+ return result; |
209 |
|
210 |
buflen = process_http_response(vpninfo, &result, NULL, &form_buf); |
211 |
if (buflen < 0) { |
212 |
@@ -1010,21 +1105,28 @@ static int process_socks_proxy(struct op |
213 |
static int process_http_proxy(struct openconnect_info *vpninfo, int ssl_sock) |
214 |
{ |
215 |
char buf[MAX_BUF_LEN]; |
216 |
+ struct oc_text_buf *reqbuf; |
217 |
int buflen, result; |
218 |
|
219 |
- sprintf(buf, "CONNECT %s:%d HTTP/1.1\r\n", vpninfo->hostname, vpninfo->port); |
220 |
- sprintf(buf + strlen(buf), "Host: %s\r\n", vpninfo->hostname); |
221 |
- sprintf(buf + strlen(buf), "User-Agent: %s\r\n", vpninfo->useragent); |
222 |
- sprintf(buf + strlen(buf), "Proxy-Connection: keep-alive\r\n"); |
223 |
- sprintf(buf + strlen(buf), "Connection: keep-alive\r\n"); |
224 |
- sprintf(buf + strlen(buf), "Accept-Encoding: identity\r\n"); |
225 |
- sprintf(buf + strlen(buf), "\r\n"); |
226 |
+ reqbuf = buf_alloc(); |
227 |
+ buf_append(reqbuf, "CONNECT %s:%d HTTP/1.1\r\n", vpninfo->hostname, vpninfo->port); |
228 |
+ buf_append(reqbuf, "Host: %s\r\n", vpninfo->hostname); |
229 |
+ buf_append(reqbuf, "User-Agent: %s\r\n", vpninfo->useragent); |
230 |
+ buf_append(reqbuf, "Proxy-Connection: keep-alive\r\n"); |
231 |
+ buf_append(reqbuf, "Connection: keep-alive\r\n"); |
232 |
+ buf_append(reqbuf, "Accept-Encoding: identity\r\n"); |
233 |
+ buf_append(reqbuf, "\r\n"); |
234 |
+ |
235 |
+ if (buf_error(reqbuf)) |
236 |
+ return buf_free(reqbuf); |
237 |
|
238 |
vpninfo->progress(vpninfo, PRG_INFO, "Requesting HTTP proxy connection to %s:%d\n", |
239 |
vpninfo->hostname, vpninfo->port); |
240 |
|
241 |
- if (proxy_write(ssl_sock, (unsigned char *)buf, strlen(buf))) { |
242 |
- result = -errno; |
243 |
+ result = proxy_write(ssl_sock, (unsigned char *)reqbuf->data, reqbuf->pos); |
244 |
+ buf_free(reqbuf); |
245 |
+ |
246 |
+ if (result) { |
247 |
vpninfo->progress(vpninfo, PRG_ERR, "Sending proxy request failed: %s\n", |
248 |
strerror(errno)); |
249 |
return result; |