Skip to content

Latest commit

 

History

History
1455 lines (1263 loc) · 35.1 KB

http.c

File metadata and controls

1455 lines (1263 loc) · 35.1 KB
 
Oct 1, 2008
Oct 1, 2008
1
/*
Nov 20, 2008
Nov 20, 2008
2
* OpenConnect (SSL + DTLS) VPN client
Oct 1, 2008
Oct 1, 2008
3
*
Jan 26, 2015
Jan 26, 2015
4
* Copyright © 2008-2015 Intel Corporation.
Apr 9, 2009
Apr 9, 2009
5
* Copyright © 2008 Nick Andrew <nick@nick-andrew.net>
Oct 1, 2008
Oct 1, 2008
6
*
Nov 20, 2008
Nov 20, 2008
7
8
9
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
Oct 4, 2008
Oct 4, 2008
10
* modify it under the terms of the GNU Lesser General Public License
Nov 20, 2008
Nov 20, 2008
11
* version 2.1, as published by the Free Software Foundation.
Oct 1, 2008
Oct 1, 2008
12
*
Nov 20, 2008
Nov 20, 2008
13
* This program is distributed in the hope that it will be useful, but
Oct 4, 2008
Oct 4, 2008
14
15
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
Oct 1, 2008
Oct 1, 2008
17
18
*/
Jul 1, 2014
Jul 1, 2014
19
20
#include <config.h>
Oct 1, 2008
Oct 1, 2008
21
22
23
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
Jun 1, 2009
Jun 1, 2009
24
#include <string.h>
Oct 1, 2008
Oct 1, 2008
25
#include <ctype.h>
May 29, 2012
May 29, 2012
26
27
28
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
Oct 28, 2012
Oct 28, 2012
29
#include <stdarg.h>
Oct 1, 2008
Oct 1, 2008
30
Mar 9, 2011
Mar 9, 2011
31
#include "openconnect-internal.h"
Oct 1, 2008
Oct 1, 2008
32
Jun 18, 2014
Jun 18, 2014
33
34
static int proxy_write(struct openconnect_info *vpninfo, char *buf, size_t len);
static int proxy_read(struct openconnect_info *vpninfo, char *buf, size_t len);
Feb 22, 2010
Feb 22, 2010
35
Aug 4, 2009
Aug 4, 2009
36
#define MAX_BUF_LEN 131072
Oct 28, 2012
Oct 28, 2012
37
38
#define BUF_CHUNK_SIZE 4096
Jun 19, 2014
Jun 19, 2014
39
struct oc_text_buf *buf_alloc(void)
Oct 28, 2012
Oct 28, 2012
40
41
42
43
{
return calloc(1, sizeof(struct oc_text_buf));
}
Dec 13, 2016
Dec 13, 2016
44
void buf_append_urlencoded(struct oc_text_buf *buf, const char *str)
Jul 24, 2014
Jul 24, 2014
45
46
{
while (str && *str) {
Jul 28, 2014
Jul 28, 2014
47
unsigned char c = *str;
Dec 13, 2016
Dec 13, 2016
48
if (c < 0x80 && (isalnum((int)(c)) || c=='-' || c=='_' || c=='.' || c=='~'))
Jul 24, 2014
Jul 24, 2014
49
50
buf_append_bytes(buf, str, 1);
else
Jul 28, 2014
Jul 28, 2014
51
52
buf_append(buf, "%%%02x", c);
Jul 24, 2014
Jul 24, 2014
53
54
55
56
str++;
}
}
Dec 13, 2016
Dec 13, 2016
57
58
59
60
61
62
63
64
65
void buf_append_hex(struct oc_text_buf *buf, const void *str, unsigned len)
{
const unsigned char *data = str;
unsigned i;
for (i = 0; i < len; i++)
buf_append(buf, "%02x", (unsigned)data[i]);
}
Jul 24, 2014
Jul 24, 2014
66
67
68
69
70
71
72
73
74
75
void buf_truncate(struct oc_text_buf *buf)
{
if (!buf)
return;
buf->pos = 0;
if (buf->data)
buf->data[0] = 0;
}
Jun 23, 2014
Jun 23, 2014
76
int buf_ensure_space(struct oc_text_buf *buf, int len)
Jun 20, 2014
Jun 20, 2014
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
{
int new_buf_len;
new_buf_len = (buf->pos + len + BUF_CHUNK_SIZE - 1) & ~(BUF_CHUNK_SIZE - 1);
if (new_buf_len <= buf->buf_len)
return 0;
if (new_buf_len > MAX_BUF_LEN) {
buf->error = -E2BIG;
return buf->error;
} else {
realloc_inplace(buf->data, new_buf_len);
if (!buf->data)
buf->error = -ENOMEM;
else
buf->buf_len = new_buf_len;
}
return buf->error;
}
Jun 19, 2014
Jun 19, 2014
98
99
void __attribute__ ((format (printf, 2, 3)))
buf_append(struct oc_text_buf *buf, const char *fmt, ...)
Oct 28, 2012
Oct 28, 2012
100
101
102
103
104
105
{
va_list ap;
if (!buf || buf->error)
return;
Jun 20, 2014
Jun 20, 2014
106
107
if (buf_ensure_space(buf, 1))
return;
Oct 28, 2012
Oct 28, 2012
108
109
110
111
112
113
114
115
116
117
118
119
120
while (1) {
int max_len = buf->buf_len - buf->pos, ret;
va_start(ap, fmt);
ret = vsnprintf(buf->data + buf->pos, max_len, fmt, ap);
va_end(ap);
if (ret < 0) {
buf->error = -EIO;
break;
} else if (ret < max_len) {
buf->pos += ret;
break;
Jun 20, 2014
Jun 20, 2014
121
122
} else if (buf_ensure_space(buf, ret))
break;
Oct 28, 2012
Oct 28, 2012
123
124
125
}
}
Jun 19, 2014
Jun 19, 2014
126
127
128
129
130
void buf_append_bytes(struct oc_text_buf *buf, const void *bytes, int len)
{
if (!buf || buf->error)
return;
Jun 20, 2014
Jun 20, 2014
131
if (buf_ensure_space(buf, len + 1))
Jun 19, 2014
Jun 19, 2014
132
return;
Jun 20, 2014
Jun 20, 2014
133
Jun 19, 2014
Jun 19, 2014
134
135
memcpy(buf->data + buf->pos, bytes, len);
buf->pos += len;
Jun 20, 2014
Jun 20, 2014
136
buf->data[buf->pos] = 0;
Jun 19, 2014
Jun 19, 2014
137
138
}
Jul 28, 2014
Jul 28, 2014
139
140
141
142
143
144
145
146
147
148
149
void buf_append_from_utf16le(struct oc_text_buf *buf, const void *_utf16)
{
const unsigned char *utf16 = _utf16;
unsigned char utf8[4];
int c;
if (!utf16)
return;
while (utf16[0] || utf16[1]) {
if ((utf16[1] & 0xfc) == 0xd8 && (utf16[3] & 0xfc) == 0xdc) {
Jan 26, 2015
Jan 26, 2015
150
151
c = ((load_le16(utf16) & 0x3ff) << 10)|
(load_le16(utf16 + 2) & 0x3ff);
Jul 28, 2014
Jul 28, 2014
152
153
154
c += 0x10000;
utf16 += 4;
} else {
Jan 26, 2015
Jan 26, 2015
155
c = load_le16(utf16);
Jul 28, 2014
Jul 28, 2014
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
utf16 += 2;
}
if (c < 0x80) {
utf8[0] = c;
buf_append_bytes(buf, utf8, 1);
} else if (c < 0x800) {
utf8[0] = 0xc0 | (c >> 6);
utf8[1] = 0x80 | (c & 0x3f);
buf_append_bytes(buf, utf8, 2);
} else if (c < 0x10000) {
utf8[0] = 0xe0 | (c >> 12);
utf8[1] = 0x80 | ((c >> 6) & 0x3f);
utf8[2] = 0x80 | (c & 0x3f);
buf_append_bytes(buf, utf8, 3);
} else {
utf8[0] = 0xf0 | (c >> 18);
utf8[1] = 0x80 | ((c >> 12) & 0x3f);
utf8[2] = 0x80 | ((c >> 6) & 0x3f);
utf8[3] = 0x80 | (c & 0x3f);
buf_append_bytes(buf, utf8, 4);
}
}
utf8[0] = 0;
buf_append_bytes(buf, utf8, 1);
}
Feb 4, 2015
Feb 4, 2015
183
int get_utf8char(const char **p)
Jul 28, 2014
Jul 28, 2014
184
{
Feb 4, 2015
Feb 4, 2015
185
const char *utf8 = *p;
Jul 28, 2014
Jul 28, 2014
186
unsigned char c;
Feb 4, 2015
Feb 4, 2015
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
int utfchar, nr_extra, min;
c = *(utf8++);
if (c < 128) {
utfchar = c;
nr_extra = 0;
min = 0;
} else if ((c & 0xe0) == 0xc0) {
utfchar = c & 0x1f;
nr_extra = 1;
min = 0x80;
} else if ((c & 0xf0) == 0xe0) {
utfchar = c & 0x0f;
nr_extra = 2;
min = 0x800;
} else if ((c & 0xf8) == 0xf0) {
utfchar = c & 0x07;
nr_extra = 3;
min = 0x10000;
} else {
return -EILSEQ;
}
Jul 28, 2014
Jul 28, 2014
209
Feb 4, 2015
Feb 4, 2015
210
while (nr_extra--) {
Jul 28, 2014
Jul 28, 2014
211
c = *(utf8++);
Feb 4, 2015
Feb 4, 2015
212
if ((c & 0xc0) != 0x80)
Jul 31, 2014
Jul 31, 2014
213
return -EILSEQ;
Jul 28, 2014
Jul 28, 2014
214
Feb 4, 2015
Feb 4, 2015
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
utfchar <<= 6;
utfchar |= (c & 0x3f);
}
if (utfchar > 0x10ffff || utfchar < min)
return -EILSEQ;
*p = utf8;
return utfchar;
}
int buf_append_utf16le(struct oc_text_buf *buf, const char *utf8)
{
int utfchar, len = 0;
/* Ick. Now I'm implementing my own UTF8 handling too. Perhaps it's
time to bite the bullet and start requiring something like glib? */
while (*utf8) {
utfchar = get_utf8char(&utf8);
if (utfchar < 0) {
Jul 31, 2014
Jul 31, 2014
234
if (buf)
Feb 4, 2015
Feb 4, 2015
235
236
buf->error = utfchar;
return utfchar;
Jul 31, 2014
Jul 31, 2014
237
238
239
}
if (!buf)
continue;
Jul 28, 2014
Jul 28, 2014
240
241
242
243
if (utfchar >= 0x10000) {
utfchar -= 0x10000;
if (buf_ensure_space(buf, 4))
Jul 29, 2014
Jul 29, 2014
244
return buf_error(buf);
Jan 26, 2015
Jan 26, 2015
245
246
247
store_le16(buf->data + buf->pos, (utfchar >> 10) | 0xd800);
store_le16(buf->data + buf->pos + 2, (utfchar & 0x3ff) | 0xdc00);
buf->pos += 4;
Jul 28, 2014
Jul 28, 2014
248
249
250
len += 4;
} else {
if (buf_ensure_space(buf, 2))
Jul 29, 2014
Jul 29, 2014
251
return buf_error(buf);
Jan 26, 2015
Jan 26, 2015
252
253
store_le16(buf->data + buf->pos, utfchar);
buf->pos += 2;
Jul 28, 2014
Jul 28, 2014
254
255
256
len += 2;
}
}
Jul 29, 2014
Jul 29, 2014
257
Jul 31, 2014
Jul 31, 2014
258
259
260
261
/* We were only being used for validation */
if (!buf)
return 0;
Jul 29, 2014
Jul 29, 2014
262
263
/* Ensure UTF16 is NUL-terminated */
if (buf_ensure_space(buf, 2))
Jul 31, 2014
Jul 31, 2014
264
return buf_error(buf);
Jul 29, 2014
Jul 29, 2014
265
266
buf->data[buf->pos] = buf->data[buf->pos + 1] = 0;
Jul 28, 2014
Jul 28, 2014
267
268
269
return len;
}
Jun 19, 2014
Jun 19, 2014
270
int buf_error(struct oc_text_buf *buf)
Oct 28, 2012
Oct 28, 2012
271
272
273
274
{
return buf ? buf->error : -ENOMEM;
}
Jun 19, 2014
Jun 19, 2014
275
int buf_free(struct oc_text_buf *buf)
Oct 28, 2012
Oct 28, 2012
276
277
278
279
280
281
282
283
284
285
286
287
{
int error = buf_error(buf);
if (buf) {
if (buf->data)
free(buf->data);
free(buf);
}
return error;
}
Oct 1, 2008
Oct 1, 2008
288
/*
Apr 9, 2009
Apr 9, 2009
289
* We didn't really want to have to do this for ourselves -- one might have
Oct 1, 2008
Oct 1, 2008
290
291
292
293
294
295
* thought that it would be available in a library somewhere. But neither
* cURL nor Neon have reliable cross-platform ways of either using a cert
* from the TPM, or just reading from / writing to a transport which is
* provided by their caller.
*/
Jan 26, 2015
Jan 26, 2015
296
297
int http_add_cookie(struct openconnect_info *vpninfo, const char *option,
const char *value, int replace)
Nov 6, 2009
Nov 6, 2009
298
{
Jan 15, 2014
Jan 15, 2014
299
struct oc_vpn_option *new, **this;
Nov 6, 2009
Nov 6, 2009
300
301
302
303
if (*value) {
new = malloc(sizeof(*new));
if (!new) {
Sep 22, 2011
Sep 22, 2011
304
305
vpn_progress(vpninfo, PRG_ERR,
_("No memory for allocating cookies\n"));
Nov 6, 2009
Nov 6, 2009
306
307
308
309
310
return -ENOMEM;
}
new->next = NULL;
new->option = strdup(option);
new->value = strdup(value);
Nov 6, 2009
Nov 6, 2009
311
312
313
314
315
316
if (!new->option || !new->value) {
free(new->option);
free(new->value);
free(new);
return -ENOMEM;
}
Nov 6, 2009
Nov 6, 2009
317
318
319
} else {
/* Kill cookie; don't replace it */
new = NULL;
Feb 28, 2015
Feb 28, 2015
320
321
322
/* This would be meaningless */
if (!replace)
return -EINVAL;
Nov 6, 2009
Nov 6, 2009
323
324
325
}
for (this = &vpninfo->cookies; *this; this = &(*this)->next) {
if (!strcmp(option, (*this)->option)) {
Jan 26, 2015
Jan 26, 2015
326
327
328
329
330
331
if (!replace) {
free(new->value);
free(new->option);
free(new);
return 0;
}
Nov 6, 2009
Nov 6, 2009
332
333
334
335
336
/* Replace existing cookie */
if (new)
new->next = (*this)->next;
else
new = (*this)->next;
Mar 10, 2013
Mar 10, 2013
337
Nov 6, 2009
Nov 6, 2009
338
339
340
341
342
343
344
345
346
347
348
349
350
351
free((*this)->option);
free((*this)->value);
free(*this);
*this = new;
break;
}
}
if (new && !*this) {
*this = new;
new->next = NULL;
}
return 0;
}
Jan 9, 2010
Jan 9, 2010
352
353
354
#define BODY_HTTP10 -1
#define BODY_CHUNKED -2
Jan 26, 2015
Jan 26, 2015
355
356
357
int process_http_response(struct openconnect_info *vpninfo, int connect,
int (*header_cb)(struct openconnect_info *, char *, char *),
struct oc_text_buf *body)
Oct 1, 2008
Oct 1, 2008
358
{
Aug 4, 2009
Aug 4, 2009
359
char buf[MAX_BUF_LEN];
Jan 9, 2010
Jan 9, 2010
360
361
int bodylen = BODY_HTTP10;
int closeconn = 0;
Jul 24, 2014
Jul 24, 2014
362
int result;
Oct 1, 2008
Oct 1, 2008
363
364
int i;
Jul 24, 2014
Jul 24, 2014
365
366
buf_truncate(body);
Jan 3, 2010
Jan 3, 2010
367
cont:
Jun 18, 2014
Jun 18, 2014
368
if (vpninfo->ssl_gets(vpninfo, buf, sizeof(buf)) < 0) {
Sep 22, 2011
Sep 22, 2011
369
370
vpn_progress(vpninfo, PRG_ERR,
_("Error fetching HTTPS response\n"));
May 21, 2013
May 21, 2013
371
openconnect_close_https(vpninfo, 0);
Oct 5, 2008
Oct 5, 2008
372
return -EINVAL;
Oct 1, 2008
Oct 1, 2008
373
374
}
Jan 9, 2010
Jan 9, 2010
375
if (!strncmp(buf, "HTTP/1.0 ", 9))
Oct 1, 2008
Oct 1, 2008
376
closeconn = 1;
Mar 10, 2013
Mar 10, 2013
377
Jul 24, 2014
Jul 24, 2014
378
if ((!closeconn && strncmp(buf, "HTTP/1.1 ", 9)) || !(result = atoi(buf+9))) {
Sep 22, 2011
Sep 22, 2011
379
380
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse HTTP response '%s'\n"), buf);
May 21, 2013
May 21, 2013
381
openconnect_close_https(vpninfo, 0);
Oct 1, 2008
Oct 1, 2008
382
383
384
return -EINVAL;
}
Jul 24, 2014
Jul 24, 2014
385
vpn_progress(vpninfo, (result == 200 || result == 407) ? PRG_DEBUG : PRG_INFO,
Sep 22, 2011
Sep 22, 2011
386
_("Got HTTP response: %s\n"), buf);
Oct 1, 2008
Oct 1, 2008
387
388
/* Eat headers... */
Jun 18, 2014
Jun 18, 2014
389
while ((i = vpninfo->ssl_gets(vpninfo, buf, sizeof(buf)))) {
Oct 1, 2008
Oct 1, 2008
390
391
392
char *colon;
if (i < 0) {
Sep 22, 2011
Sep 22, 2011
393
394
vpn_progress(vpninfo, PRG_ERR,
_("Error processing HTTP response\n"));
May 21, 2013
May 21, 2013
395
openconnect_close_https(vpninfo, 0);
Oct 1, 2008
Oct 1, 2008
396
397
398
399
return -EINVAL;
}
colon = strchr(buf, ':');
if (!colon) {
Sep 22, 2011
Sep 22, 2011
400
401
vpn_progress(vpninfo, PRG_ERR,
_("Ignoring unknown HTTP response line '%s'\n"), buf);
Oct 1, 2008
Oct 1, 2008
402
403
404
405
406
407
continue;
}
*(colon++) = 0;
if (*colon == ' ')
colon++;
Aug 7, 2010
Aug 7, 2010
408
409
410
411
/* Handle Set-Cookie first so that we can avoid printing the
webvpn cookie in the verbose debug output */
if (!strcasecmp(buf, "Set-Cookie")) {
char *semicolon = strchr(colon, ';');
Sep 15, 2011
Sep 15, 2011
412
413
const char *print_equals;
char *equals = strchr(colon, '=');
Aug 7, 2010
Aug 7, 2010
414
415
416
417
418
419
int ret;
if (semicolon)
*semicolon = 0;
if (!equals) {
Sep 22, 2011
Sep 22, 2011
420
421
vpn_progress(vpninfo, PRG_ERR,
_("Invalid cookie offered: %s\n"), buf);
Aug 7, 2010
Aug 7, 2010
422
423
424
425
426
return -EINVAL;
}
*(equals++) = 0;
print_equals = equals;
Nov 30, 2010
Nov 30, 2010
427
428
429
/* Don't print the webvpn cookie unless it's empty; we don't
want people posting it in public with debugging output */
if (!strcmp(colon, "webvpn") && *equals)
Sep 22, 2011
Sep 22, 2011
430
print_equals = _("<elided>");
Jun 13, 2014
Jun 13, 2014
431
vpn_progress(vpninfo, PRG_DEBUG, "%s: %s=%s%s%s\n",
Mar 10, 2013
Mar 10, 2013
432
433
buf, colon, print_equals, semicolon ? ";" : "",
semicolon ? (semicolon+1) : "");
Aug 7, 2010
Aug 7, 2010
434
Sep 25, 2011
Sep 25, 2011
435
436
437
438
439
440
441
/* The server tends to ask for the username and password as
usual, even if we've already failed because it didn't like
our cert. Thankfully it does give us this hint... */
if (!strcmp(colon, "ClientCertAuthFailed"))
vpn_progress(vpninfo, PRG_ERR,
_("SSL certificate authentication failed\n"));
Jan 26, 2015
Jan 26, 2015
442
ret = http_add_cookie(vpninfo, colon, equals, 1);
Aug 7, 2010
Aug 7, 2010
443
444
445
if (ret)
return ret;
} else {
Jun 13, 2014
Jun 13, 2014
446
vpn_progress(vpninfo, PRG_DEBUG, "%s: %s\n", buf, colon);
Aug 7, 2010
Aug 7, 2010
447
448
}
Jan 9, 2010
Jan 9, 2010
449
450
451
if (!strcasecmp(buf, "Connection")) {
if (!strcasecmp(colon, "Close"))
closeconn = 1;
Feb 28, 2010
Feb 28, 2010
452
453
454
455
456
457
#if 0
/* This might seem reasonable, but in fact it breaks
certificate authentication with some servers. If
they give an HTTP/1.0 response, even if they
explicitly give a Connection: Keep-Alive header,
just close the connection. */
Jan 9, 2010
Jan 9, 2010
458
459
else if (!strcasecmp(colon, "Keep-Alive"))
closeconn = 0;
Feb 28, 2010
Feb 28, 2010
460
#endif
Jan 9, 2010
Jan 9, 2010
461
}
Jan 9, 2010
Jan 9, 2010
462
if (!strcasecmp(buf, "Location")) {
Oct 1, 2008
Oct 1, 2008
463
464
465
466
vpninfo->redirect_url = strdup(colon);
if (!vpninfo->redirect_url)
return -ENOMEM;
}
Jan 9, 2010
Jan 9, 2010
467
if (!strcasecmp(buf, "Content-Length")) {
Oct 1, 2008
Oct 1, 2008
468
bodylen = atoi(colon);
Feb 22, 2010
Feb 22, 2010
469
if (bodylen < 0) {
Sep 22, 2011
Sep 22, 2011
470
471
472
vpn_progress(vpninfo, PRG_ERR,
_("Response body has negative size (%d)\n"),
bodylen);
May 21, 2013
May 21, 2013
473
openconnect_close_https(vpninfo, 0);
Oct 1, 2008
Oct 1, 2008
474
475
476
return -EINVAL;
}
}
Jan 9, 2010
Jan 9, 2010
477
478
if (!strcasecmp(buf, "Transfer-Encoding")) {
if (!strcasecmp(colon, "chunked"))
Jan 9, 2010
Jan 9, 2010
479
bodylen = BODY_CHUNKED;
Oct 1, 2008
Oct 1, 2008
480
else {
Sep 22, 2011
Sep 22, 2011
481
482
483
vpn_progress(vpninfo, PRG_ERR,
_("Unknown Transfer-Encoding: %s\n"),
colon);
May 21, 2013
May 21, 2013
484
openconnect_close_https(vpninfo, 0);
Oct 1, 2008
Oct 1, 2008
485
486
487
return -EINVAL;
}
}
Jun 18, 2014
Jun 18, 2014
488
if (header_cb)
Oct 1, 2008
Oct 1, 2008
489
490
491
492
header_cb(vpninfo, buf, colon);
}
/* Handle 'HTTP/1.1 100 Continue'. Not that we should ever see it */
Jul 24, 2014
Jul 24, 2014
493
if (result == 100)
Oct 1, 2008
Oct 1, 2008
494
495
goto cont;
Jun 18, 2014
Jun 18, 2014
496
/* On successful CONNECT, there is no body. Return success */
Jul 24, 2014
Jul 24, 2014
497
498
if (connect && result == 200)
return result;
Jun 18, 2014
Jun 18, 2014
499
Jan 3, 2010
Jan 3, 2010
500
/* Now the body, if there is one */
Jun 13, 2014
Jun 13, 2014
501
vpn_progress(vpninfo, PRG_DEBUG, _("HTTP body %s (%d)\n"),
Mar 10, 2013
Mar 10, 2013
502
503
bodylen == BODY_HTTP10 ? "http 1.0" :
bodylen == BODY_CHUNKED ? "chunked" : "length: ",
Sep 22, 2011
Sep 22, 2011
504
bodylen);
Jan 3, 2010
Jan 3, 2010
505
Oct 1, 2008
Oct 1, 2008
506
507
/* If we were given Content-Length, it's nice and easy... */
if (bodylen > 0) {
Jul 24, 2014
Jul 24, 2014
508
509
510
511
512
if (buf_ensure_space(body, bodylen + 1))
return buf_error(body);
while (body->pos < bodylen) {
i = vpninfo->ssl_read(vpninfo, body->data + body->pos, bodylen - body->pos);
Oct 1, 2008
Oct 1, 2008
513
if (i < 0) {
Sep 22, 2011
Sep 22, 2011
514
515
vpn_progress(vpninfo, PRG_ERR,
_("Error reading HTTP response body\n"));
May 21, 2013
May 21, 2013
516
openconnect_close_https(vpninfo, 0);
Oct 1, 2008
Oct 1, 2008
517
518
return -EINVAL;
}
Jul 24, 2014
Jul 24, 2014
519
body->pos += i;
Oct 1, 2008
Oct 1, 2008
520
}
Jan 9, 2010
Jan 9, 2010
521
522
} else if (bodylen == BODY_CHUNKED) {
/* ... else, chunked */
Jun 18, 2014
Jun 18, 2014
523
while ((i = vpninfo->ssl_gets(vpninfo, buf, sizeof(buf)))) {
Jan 9, 2010
Jan 9, 2010
524
int chunklen, lastchunk = 0;
Oct 1, 2008
Oct 1, 2008
525
526
if (i < 0) {
Sep 22, 2011
Sep 22, 2011
527
528
vpn_progress(vpninfo, PRG_ERR,
_("Error fetching chunk header\n"));
May 13, 2012
May 13, 2012
529
return i;
Jan 9, 2010
Jan 9, 2010
530
531
532
533
534
535
}
chunklen = strtol(buf, NULL, 16);
if (!chunklen) {
lastchunk = 1;
goto skip;
}
Jul 24, 2014
Jul 24, 2014
536
537
if (buf_ensure_space(body, chunklen + 1))
return buf_error(body);
Jan 9, 2010
Jan 9, 2010
538
while (chunklen) {
Jul 24, 2014
Jul 24, 2014
539
i = vpninfo->ssl_read(vpninfo, body->data + body->pos, chunklen);
Jan 9, 2010
Jan 9, 2010
540
if (i < 0) {
Sep 22, 2011
Sep 22, 2011
541
542
vpn_progress(vpninfo, PRG_ERR,
_("Error reading HTTP response body\n"));
Jan 9, 2010
Jan 9, 2010
543
544
545
return -EINVAL;
}
chunklen -= i;
Jul 24, 2014
Jul 24, 2014
546
body->pos += i;
Jan 9, 2010
Jan 9, 2010
547
548
}
skip:
Jun 18, 2014
Jun 18, 2014
549
if ((i = vpninfo->ssl_gets(vpninfo, buf, sizeof(buf)))) {
Jan 9, 2010
Jan 9, 2010
550
if (i < 0) {
Sep 22, 2011
Sep 22, 2011
551
552
vpn_progress(vpninfo, PRG_ERR,
_("Error fetching HTTP response body\n"));
Jan 9, 2010
Jan 9, 2010
553
} else {
Sep 22, 2011
Sep 22, 2011
554
555
556
vpn_progress(vpninfo, PRG_ERR,
_("Error in chunked decoding. Expected '', got: '%s'"),
buf);
Jan 9, 2010
Jan 9, 2010
557
558
}
return -EINVAL;
Oct 1, 2008
Oct 1, 2008
559
}
Feb 22, 2010
Feb 22, 2010
560
Jan 9, 2010
Jan 9, 2010
561
562
563
564
565
if (lastchunk)
break;
}
} else if (bodylen == BODY_HTTP10) {
if (!closeconn) {
Sep 22, 2011
Sep 22, 2011
566
567
vpn_progress(vpninfo, PRG_ERR,
_("Cannot receive HTTP 1.0 body without closing connection\n"));
Feb 4, 2013
Feb 4, 2013
568
openconnect_close_https(vpninfo, 0);
Oct 1, 2008
Oct 1, 2008
569
570
571
return -EINVAL;
}
Jul 24, 2014
Jul 24, 2014
572
/* HTTP 1.0 response. Just eat all we can in 4KiB chunks */
Jan 9, 2010
Jan 9, 2010
573
while (1) {
Jul 24, 2014
Jul 24, 2014
574
575
576
577
if (buf_ensure_space(body, 4096 + 1))
return buf_error(body);
i = vpninfo->ssl_read(vpninfo, body->data + body->pos, 4096);
if (i < 0) {
May 12, 2012
May 12, 2012
578
/* Error */
May 21, 2013
May 21, 2013
579
openconnect_close_https(vpninfo, 0);
May 12, 2012
May 12, 2012
580
return i;
Jul 24, 2014
Jul 24, 2014
581
} else if (!i)
Jan 9, 2010
Jan 9, 2010
582
break;
Jul 24, 2014
Jul 24, 2014
583
584
585
/* Got more data */
body->pos += i;
Jan 9, 2010
Jan 9, 2010
586
}
Oct 1, 2008
Oct 1, 2008
587
}
Jan 9, 2010
Jan 9, 2010
588
May 28, 2012
May 28, 2012
589
if (closeconn || vpninfo->no_http_keepalive)
Jun 9, 2012
Jun 9, 2012
590
openconnect_close_https(vpninfo, 0);
Feb 22, 2010
Feb 22, 2010
591
Jul 24, 2014
Jul 24, 2014
592
593
body->data[body->pos] = 0;
return result;
Oct 1, 2008
Oct 1, 2008
594
595
}
Sep 29, 2014
Sep 29, 2014
596
int internal_parse_url(const char *url, char **res_proto, char **res_host,
Mar 9, 2011
Mar 9, 2011
597
int *res_port, char **res_path, int default_port)
Dec 25, 2009
Dec 25, 2009
598
{
Sep 29, 2014
Sep 29, 2014
599
600
601
const char *orig_host, *orig_path;
char *host, *port_str;
int port, proto_len = 0;
Dec 25, 2009
Dec 25, 2009
602
Sep 29, 2014
Sep 29, 2014
603
604
605
606
orig_host = strstr(url, "://");
if (orig_host) {
proto_len = orig_host - url;
orig_host += 3;
Jan 1, 2010
Jan 1, 2010
607
Sep 29, 2014
Sep 29, 2014
608
if (strprefix_match(url, proto_len, "https"))
Jan 1, 2010
Jan 1, 2010
609
port = 443;
Sep 29, 2014
Sep 29, 2014
610
else if (strprefix_match(url, proto_len, "http"))
Jan 1, 2010
Jan 1, 2010
611
port = 80;
Sep 29, 2014
Sep 29, 2014
612
613
614
else if (strprefix_match(url, proto_len, "socks") ||
strprefix_match(url, proto_len, "socks4") ||
strprefix_match(url, proto_len, "socks5"))
Jan 1, 2010
Jan 1, 2010
615
616
617
618
619
620
port = 1080;
else
return -EPROTONOSUPPORT;
} else {
if (default_port) {
port = default_port;
Sep 29, 2014
Sep 29, 2014
621
orig_host = url;
Jan 1, 2010
Jan 1, 2010
622
623
624
} else
return -EINVAL;
}
Dec 25, 2009
Dec 25, 2009
625
Sep 29, 2014
Sep 29, 2014
626
627
628
629
630
631
632
633
orig_path = strchr(orig_host, '/');
if (orig_path) {
host = strndup(orig_host, orig_path - orig_host);
orig_path++;
} else
host = strdup(orig_host);
if (!host)
return -ENOMEM;
Dec 25, 2009
Dec 25, 2009
634
635
636
637
638
639
640
641
642
643
644
645
646
port_str = strrchr(host, ':');
if (port_str) {
char *end;
int new_port = strtol(port_str + 1, &end, 10);
if (!*end) {
*port_str = 0;
port = new_port;
}
}
if (res_proto)
Sep 29, 2014
Sep 29, 2014
647
*res_proto = proto_len ? strndup(url, proto_len) : NULL;
Dec 25, 2009
Dec 25, 2009
648
if (res_host)
Sep 29, 2014
Sep 29, 2014
649
650
651
*res_host = host;
else
free(host);
Dec 25, 2009
Dec 25, 2009
652
653
654
if (res_port)
*res_port = port;
if (res_path)
Sep 29, 2014
Sep 29, 2014
655
656
*res_path = (orig_path && *orig_path) ? strdup(orig_path) : NULL;
Dec 25, 2009
Dec 25, 2009
657
658
659
return 0;
}
Oct 10, 2014
Oct 10, 2014
660
void openconnect_clear_cookies(struct openconnect_info *vpninfo)
Oct 27, 2012
Oct 27, 2012
661
{
Jan 15, 2014
Jan 15, 2014
662
struct oc_vpn_option *opt, *next;
Oct 27, 2012
Oct 27, 2012
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
for (opt = vpninfo->cookies; opt; opt = next) {
next = opt->next;
free(opt->option);
free(opt->value);
free(opt);
}
vpninfo->cookies = NULL;
}
/* Return value:
* < 0, on error
* = 0, on success (go ahead and retry with the latest vpninfo->{hostname,urlpath,port,...})
*/
Jan 26, 2015
Jan 26, 2015
678
int handle_redirect(struct openconnect_info *vpninfo)
Oct 27, 2012
Oct 27, 2012
679
{
Oct 28, 2012
Oct 28, 2012
680
681
vpninfo->redirect_type = REDIR_TYPE_LOCAL;
Oct 27, 2012
Oct 27, 2012
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
if (!strncmp(vpninfo->redirect_url, "https://", 8)) {
/* New host. Tear down the existing connection and make a new one */
char *host;
int port;
int ret;
free(vpninfo->urlpath);
vpninfo->urlpath = NULL;
ret = internal_parse_url(vpninfo->redirect_url, NULL, &host, &port, &vpninfo->urlpath, 0);
if (ret) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse redirected URL '%s': %s\n"),
vpninfo->redirect_url, strerror(-ret));
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
return ret;
}
if (strcasecmp(vpninfo->hostname, host) || port != vpninfo->port) {
Dec 31, 2013
Dec 31, 2013
702
openconnect_set_hostname(vpninfo, host);
Oct 27, 2012
Oct 27, 2012
703
704
705
706
vpninfo->port = port;
/* Kill the existing connection, and a new one will happen */
openconnect_close_https(vpninfo, 0);
Oct 10, 2014
Oct 10, 2014
707
openconnect_clear_cookies(vpninfo);
Oct 28, 2012
Oct 28, 2012
708
vpninfo->redirect_type = REDIR_TYPE_NEWHOST;
Nov 4, 2014
Nov 4, 2014
709
710
}
free(host);
Oct 27, 2012
Oct 27, 2012
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
return 0;
} else if (strstr(vpninfo->redirect_url, "://")) {
vpn_progress(vpninfo, PRG_ERR,
_("Cannot follow redirection to non-https URL '%s'\n"),
vpninfo->redirect_url);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
return -EINVAL;
} else if (vpninfo->redirect_url[0] == '/') {
/* Absolute redirect within same host */
free(vpninfo->urlpath);
vpninfo->urlpath = strdup(vpninfo->redirect_url + 1);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
return 0;
} else {
char *lastslash = NULL;
if (vpninfo->urlpath)
lastslash = strrchr(vpninfo->urlpath, '/');
if (!lastslash) {
free(vpninfo->urlpath);
vpninfo->urlpath = vpninfo->redirect_url;
vpninfo->redirect_url = NULL;
} else {
char *oldurl = vpninfo->urlpath;
*lastslash = 0;
vpninfo->urlpath = NULL;
if (asprintf(&vpninfo->urlpath, "%s/%s",
oldurl, vpninfo->redirect_url) == -1) {
int err = -errno;
vpn_progress(vpninfo, PRG_ERR,
_("Allocating new path for relative redirect failed: %s\n"),
strerror(-err));
return err;
}
free(oldurl);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
}
return 0;
}
}
Jan 25, 2015
Jan 25, 2015
758
void dump_buf(struct openconnect_info *vpninfo, char prefix, char *buf)
May 30, 2013
May 30, 2013
759
760
761
762
763
764
765
766
767
768
769
770
771
772
{
while (*buf) {
char *eol = buf;
char eol_char = 0;
while (*eol) {
if (*eol == '\r' || *eol == '\n') {
eol_char = *eol;
*eol = 0;
break;
}
eol++;
}
Jun 13, 2014
Jun 13, 2014
773
vpn_progress(vpninfo, PRG_DEBUG, "%c %s\n", prefix, buf);
May 30, 2013
May 30, 2013
774
775
776
777
778
779
780
781
782
783
if (!eol_char)
break;
*eol = eol_char;
buf = eol + 1;
if (eol_char == '\r' && *buf == '\n')
buf++;
}
}
Oct 28, 2012
Oct 28, 2012
784
785
786
787
788
789
790
791
792
793
/* Inputs:
* method: GET or POST
* vpninfo->hostname: Host DNS name
* vpninfo->port: TCP port, typically 443
* vpninfo->urlpath: Relative path, e.g. /+webvpn+/foo.html
* request_body_type: Content type for a POST (e.g. text/html). Can be NULL.
* request_body: POST content
* form_buf: Callee-allocated buffer for server content
*
* Return value:
Jan 24, 2009
Jan 24, 2009
794
* < 0, on error
Oct 28, 2012
Oct 28, 2012
795
* >=0, on success, indicating the length of the data in *form_buf
Jan 24, 2009
Jan 24, 2009
796
*/
Jan 26, 2015
Jan 26, 2015
797
798
799
int do_https_request(struct openconnect_info *vpninfo, const char *method,
const char *request_body_type, struct oc_text_buf *request_body,
char **form_buf, int fetch_redirect)
Oct 1, 2008
Oct 1, 2008
800
{
Mar 14, 2015
Mar 14, 2015
801
struct oc_text_buf *buf = buf_alloc();
Jul 24, 2014
Jul 24, 2014
802
int result;
May 22, 2013
May 22, 2013
803
int rq_retry;
Feb 3, 2014
Feb 3, 2014
804
int rlen, pad;
Feb 24, 2015
Feb 24, 2015
805
int auth = 0;
Feb 24, 2015
Feb 24, 2015
806
int max_redirects = 10;
Oct 15, 2012
Oct 15, 2012
807
Jul 27, 2014
Jul 27, 2014
808
if (request_body_type && buf_error(request_body))
Jul 24, 2014
Jul 24, 2014
809
810
return buf_error(request_body);
May 22, 2013
May 22, 2013
811
redirected:
Feb 24, 2015
Feb 24, 2015
812
813
814
815
816
if (max_redirects-- <= 0) {
result = -EIO;
goto out;
}
Oct 28, 2012
Oct 28, 2012
817
818
vpninfo->redirect_type = REDIR_TYPE_NONE;
Oct 28, 2012
Oct 28, 2012
819
820
821
if (*form_buf) {
free(*form_buf);
*form_buf = NULL;
Nov 24, 2010
Nov 24, 2010
822
}
Oct 1, 2008
Oct 1, 2008
823
824
/*
Jan 14, 2016
Jan 14, 2016
825
826
827
828
829
830
* A long time ago, I *wanted* to use an HTTP client library like cURL
* for this. But we need a *lot* of control over the underlying SSL
* transport, and we also have to do horrid tricks like the Juniper NC
* 'GET' request that actaully behaves like a 'CONNECT'.
*
* So the world gained Yet Another HTTP Implementation. Sorry.
Oct 1, 2008
Oct 1, 2008
831
832
*
*/
Mar 14, 2015
Mar 14, 2015
833
buf_truncate(buf);
Oct 28, 2012
Oct 28, 2012
834
buf_append(buf, "%s /%s HTTP/1.1\r\n", method, vpninfo->urlpath ?: "");
Feb 24, 2015
Feb 24, 2015
835
836
837
838
839
840
841
842
if (auth) {
result = gen_authorization_hdr(vpninfo, 0, buf);
if (result)
goto out;
/* Forget existing challenges */
clear_auth_states(vpninfo, vpninfo->http_auth, 0);
}
May 16, 2016
May 16, 2016
843
844
if (vpninfo->proto->add_http_headers)
vpninfo->proto->add_http_headers(vpninfo, buf);
Oct 1, 2008
Oct 1, 2008
845
Oct 1, 2008
Oct 1, 2008
846
if (request_body_type) {
Jul 24, 2014
Jul 24, 2014
847
rlen = request_body->pos;
Feb 3, 2014
Feb 3, 2014
848
849
850
851
852
853
/* force body length to be a multiple of 64, to avoid leaking
* password length. */
pad = 64*(1+rlen/64) - rlen;
buf_append(buf, "X-Pad: %0*d\r\n", pad, 0);
Oct 28, 2012
Oct 28, 2012
854
buf_append(buf, "Content-Type: %s\r\n", request_body_type);
Feb 3, 2014
Feb 3, 2014
855
buf_append(buf, "Content-Length: %d\r\n", (int)rlen);
Oct 1, 2008
Oct 1, 2008
856
}
Oct 28, 2012
Oct 28, 2012
857
858
buf_append(buf, "\r\n");
Oct 1, 2008
Oct 1, 2008
859
if (request_body_type)
Jul 24, 2014
Jul 24, 2014
860
buf_append_bytes(buf, request_body->data, request_body->pos);
Oct 1, 2008
Oct 1, 2008
861
Dec 23, 2009
Dec 23, 2009
862
if (vpninfo->port == 443)
Jun 27, 2011
Jun 27, 2011
863
vpn_progress(vpninfo, PRG_INFO, "%s https://%s/%s\n",
Sep 22, 2011
Sep 22, 2011
864
865
method, vpninfo->hostname,
vpninfo->urlpath ?: "");
Dec 23, 2009
Dec 23, 2009
866
else
Jun 27, 2011
Jun 27, 2011
867
vpn_progress(vpninfo, PRG_INFO, "%s https://%s:%d/%s\n",
Sep 22, 2011
Sep 22, 2011
868
869
method, vpninfo->hostname, vpninfo->port,
vpninfo->urlpath ?: "");
Apr 1, 2009
Apr 1, 2009
870
Oct 28, 2012
Oct 28, 2012
871
872
873
if (buf_error(buf))
return buf_free(buf);
Feb 24, 2015
Feb 24, 2015
874
875
vpninfo->retry_on_auth_fail = 0;
May 22, 2013
May 22, 2013
876
877
878
879
880
881
882
883
retry:
if (openconnect_https_connected(vpninfo)) {
/* The session is already connected. If we get a failure on
* *sending* the request, try it again immediately with a new
* connection. */
rq_retry = 1;
} else {
rq_retry = 0;
Jun 18, 2014
Jun 18, 2014
884
if ((result = openconnect_open_https(vpninfo))) {
May 22, 2013
May 22, 2013
885
886
887
vpn_progress(vpninfo, PRG_ERR,
_("Failed to open HTTPS connection to %s\n"),
vpninfo->hostname);
Jul 18, 2014
Jul 18, 2014
888
889
890
891
/* We really don't want to return -EINVAL if we have
failed to even connect to the server, because if
we do that openconnect_obtain_cookie() might try
again without XMLPOST... with the same result. */
Feb 24, 2015
Feb 24, 2015
892
893
result = -EIO;
goto out;
May 22, 2013
May 22, 2013
894
895
896
}
}
May 30, 2013
May 30, 2013
897
898
899
if (vpninfo->dump_http_traffic)
dump_buf(vpninfo, '>', buf->data);
Jun 18, 2014
Jun 18, 2014
900
result = vpninfo->ssl_write(vpninfo, buf->data, buf->pos);
May 22, 2013
May 22, 2013
901
902
903
904
if (rq_retry && result < 0) {
openconnect_close_https(vpninfo, 0);
goto retry;
}
May 12, 2012
May 12, 2012
905
if (result < 0)
Jul 24, 2014
Jul 24, 2014
906
goto out;
Oct 1, 2008
Oct 1, 2008
907
Feb 24, 2015
Feb 24, 2015
908
result = process_http_response(vpninfo, 0, http_auth_hdrs, buf);
Jul 24, 2014
Jul 24, 2014
909
if (result < 0) {
Oct 1, 2008
Oct 1, 2008
910
/* We'll already have complained about whatever offended us */
Jul 24, 2014
Jul 24, 2014
911
goto out;
Oct 1, 2008
Oct 1, 2008
912
}
Jul 24, 2014
Jul 24, 2014
913
914
if (vpninfo->dump_http_traffic && buf->pos)
dump_buf(vpninfo, '<', buf->data);
Oct 1, 2008
Oct 1, 2008
915
Feb 24, 2015
Feb 24, 2015
916
if (result == 401 && vpninfo->try_http_auth) {
Feb 24, 2015
Feb 24, 2015
917
918
919
auth = 1;
goto redirected;
}
Oct 1, 2008
Oct 1, 2008
920
if (result != 200 && vpninfo->redirect_url) {
Oct 27, 2012
Oct 27, 2012
921
result = handle_redirect(vpninfo);
Oct 28, 2012
Oct 28, 2012
922
923
if (result == 0) {
if (!fetch_redirect)
Jul 27, 2014
Jul 27, 2014
924
goto out;
Jan 26, 2015
Jan 26, 2015
925
926
927
928
929
if (fetch_redirect == 2) {
/* Juniper requires we GET after a redirected POST */
method = "GET";
request_body_type = NULL;
}
Feb 24, 2015
Feb 24, 2015
930
931
if (vpninfo->redirect_type == REDIR_TYPE_NEWHOST)
clear_auth_states(vpninfo, vpninfo->http_auth, 1);
May 22, 2013
May 22, 2013
932
goto redirected;
Oct 28, 2012
Oct 28, 2012
933
}
Oct 28, 2012
Oct 28, 2012
934
goto out;
Oct 1, 2008
Oct 1, 2008
935
}
Jul 24, 2014
Jul 24, 2014
936
if (!buf->pos || result != 200) {
Jun 27, 2011
Jun 27, 2011
937
vpn_progress(vpninfo, PRG_ERR,
Sep 22, 2011
Sep 22, 2011
938
939
_("Unexpected %d result from server\n"),
result);
Oct 28, 2012
Oct 28, 2012
940
941
942
943
result = -EINVAL;
goto out;
}
Jul 24, 2014
Jul 24, 2014
944
945
946
*form_buf = buf->data;
buf->data = NULL;
result = buf->pos;
Oct 28, 2012
Oct 28, 2012
947
948
out:
Jul 24, 2014
Jul 24, 2014
949
buf_free(buf);
Feb 24, 2015
Feb 24, 2015
950
951
/* On success, clear out all authentication state for the next request */
clear_auth_states(vpninfo, vpninfo->http_auth, 1);
Oct 28, 2012
Oct 28, 2012
952
953
954
return result;
}
Sep 15, 2011
Sep 15, 2011
955
char *openconnect_create_useragent(const char *base)
Oct 5, 2008
Oct 5, 2008
956
{
Dec 7, 2009
Dec 7, 2009
957
958
char *uagent;
May 12, 2012
May 12, 2012
959
if (asprintf(&uagent, "%s %s", base, openconnect_version_str) < 0)
Dec 7, 2009
Dec 7, 2009
960
961
return NULL;
Oct 5, 2008
Oct 5, 2008
962
963
return uagent;
}
Jan 1, 2010
Jan 1, 2010
964
Jun 18, 2014
Jun 18, 2014
965
static int proxy_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
Jan 1, 2010
Jan 1, 2010
966
967
968
969
970
971
972
{
int i = 0;
int ret;
if (len < 2)
return -EINVAL;
Jun 18, 2014
Jun 18, 2014
973
while ((ret = proxy_read(vpninfo, (void *)(buf + i), 1)) == 1) {
Jan 1, 2010
Jan 1, 2010
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
if (buf[i] == '\n') {
buf[i] = 0;
if (i && buf[i-1] == '\r') {
buf[i-1] = 0;
i--;
}
return i;
}
i++;
if (i >= len - 1) {
buf[i] = 0;
return i;
}
}
buf[i] = 0;
return i ?: ret;
}
Jun 18, 2014
Jun 18, 2014
993
static int proxy_write(struct openconnect_info *vpninfo, char *buf, size_t len)
Jan 2, 2010
Jan 2, 2010
994
995
{
size_t count;
Jun 18, 2014
Jun 18, 2014
996
997
998
999
int fd = vpninfo->proxy_fd;
if (fd == -1)
return -EINVAL;
May 12, 2012
May 12, 2012
1000