/
ssl.c
1157 lines (1012 loc) · 28.7 KB
1
/*
2
* OpenConnect (SSL + DTLS) VPN client
3
*
4
* Copyright © 2008-2015 Intel Corporation.
5
*
6
7
8
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public License
10
* version 2.1, as published by the Free Software Foundation.
11
*
12
* This program is distributed in the hope that it will be useful, but
13
14
15
* 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.
16
*/
17
18
19
#include <config.h>
20
#include <sys/types.h>
21
#include <sys/stat.h>
22
#include <unistd.h>
23
#include <fcntl.h>
24
#include <string.h>
25
#include <stdio.h>
26
#include <errno.h>
27
#include <stdlib.h>
28
#include <stdarg.h>
29
#include <time.h>
30
#if defined(__linux__) || defined(__ANDROID__)
31
#include <sys/vfs.h>
32
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__APPLE__)
33
34
#include <sys/param.h>
#include <sys/mount.h>
35
#elif defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
36
#include <sys/statvfs.h>
37
#elif defined(__GNU__)
38
#include <sys/statfs.h>
39
#endif
40
41
#include "openconnect-internal.h"
42
43
44
45
46
#ifdef ANDROID_KEYSTORE
#include <sys/un.h>
#endif
47
48
49
50
51
/* OSX < 1.6 doesn't have AI_NUMERICSERV */
#ifndef AI_NUMERICSERV
#define AI_NUMERICSERV 0
#endif
52
53
54
55
/* GNU Hurd doesn't yet declare IPV6_TCLASS */
#ifndef IPV6_TCLASS
#if defined(__GNU__)
#define IPV6_TCLASS 61
56
57
#elif defined(__APPLE__)
#define IPV6_TCLASS 36
58
59
60
#endif
#endif
61
62
63
64
65
66
67
68
static inline int connect_pending()
{
#ifdef _WIN32
return WSAGetLastError() == WSAEWOULDBLOCK;
#else
return errno == EINPROGRESS;
#endif
}
69
70
71
72
73
74
75
/* Windows is interminably horrid, and has disjoint errno spaces.
* So if we return a positive value, that's a WSA Error and should
* be handled with openconnect__win32_strerror(). But if we return a
* negative value, that's a normal errno and should be handled with
* strerror(). No, you can't just pass the latter value (negated) to
* openconnect__win32_strerror() because it gives nonsense results. */
76
77
78
79
80
static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd,
const struct sockaddr *addr, socklen_t addrlen)
{
struct sockaddr_storage peer;
socklen_t peerlen = sizeof(peer);
81
fd_set wr_set, rd_set, ex_set;
82
int maxfd = sockfd;
83
int err;
84
85
set_sock_nonblock(sockfd);
86
87
if (vpninfo->protect_socket)
vpninfo->protect_socket(vpninfo->cbdata, sockfd);
88
89
90
91
92
93
94
95
if (connect(sockfd, addr, addrlen) < 0 && !connect_pending()) {
#ifdef _WIN32
return WSAGetLastError();
#else
return -errno;
#endif
}
96
97
98
99
do {
FD_ZERO(&wr_set);
FD_ZERO(&rd_set);
100
FD_ZERO(&ex_set);
101
FD_SET(sockfd, &wr_set);
102
103
104
#ifdef _WIN32 /* Windows indicates failure this way, not in wr_set */
FD_SET(sockfd, &ex_set);
#endif
105
cmd_fd_set(vpninfo, &rd_set, &maxfd);
106
select(maxfd + 1, &rd_set, &wr_set, &ex_set, NULL);
107
108
if (is_cancel_pending(vpninfo, &rd_set)) {
vpn_progress(vpninfo, PRG_ERR, _("Socket connect cancelled\n"));
109
return -EINTR;
110
}
111
112
} while (!FD_ISSET(sockfd, &wr_set) && !FD_ISSET(sockfd, &ex_set) &&
!vpninfo->got_pause_cmd);
113
114
115
/* Check whether connect() succeeded or failed by using
getpeername(). See http://cr.yp.to/docs/connect.html */
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
if (!getpeername(sockfd, (void *)&peer, &peerlen))
return 0;
#ifdef _WIN32 /* On Windows, use getsockopt() to determine the error.
* We don't ddo this on Windows because it just reports
* -ENOTCONN, which we already knew. */
err = WSAGetLastError();
if (err == WSAENOTCONN) {
socklen_t errlen = sizeof(err);
getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
(void *)&err, &errlen);
}
#else
err = -errno;
if (err == -ENOTCONN) {
int ch;
if (read(sockfd, &ch, 1) < 0)
err = -errno;
/* It should *always* fail! */
138
}
139
140
#endif
return err;
141
142
}
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* checks whether the provided string is an IP or a hostname.
*/
unsigned string_is_hostname(const char *str)
{
struct in_addr buf;
/* We don't use inet_pton() because an IPv6 literal is likely to
be encased in []. So just check for a colon, which shouldn't
occur in hostnames anyway. */
if (!str || inet_aton(str, &buf) || strchr(str, ':'))
return 0;
return 1;
}
158
159
160
161
162
163
164
165
166
167
168
static int match_sockaddr(struct sockaddr *a, struct sockaddr *b)
{
if (a->sa_family == AF_INET) {
struct sockaddr_in *a4 = (void *)a;
struct sockaddr_in *b4 = (void *)b;
return (a4->sin_addr.s_addr == b4->sin_addr.s_addr) &&
(a4->sin_port == b4->sin_port);
} else if (a->sa_family == AF_INET6) {
struct sockaddr_in6 *a6 = (void *)a;
struct sockaddr_in6 *b6 = (void *)b;
169
170
return !memcmp(&a6->sin6_addr, &b6->sin6_addr, sizeof(a6->sin6_addr)) &&
a6->sin6_port == b6->sin6_port;
171
172
173
174
} else
return 0;
}
175
int connect_https_socket(struct openconnect_info *vpninfo)
176
{
177
int ssl_sock = -1;
178
179
int err;
180
181
182
if (!vpninfo->port)
vpninfo->port = 443;
183
184
185
186
187
/* If we're talking to a server which told us it has dynamic DNS, don't
just re-use its previous IP address. If we're talking to a proxy, we
can use *its* previous IP address. We expect it'll re-do the DNS
lookup for the server anyway. */
if (vpninfo->peer_addr && (!vpninfo->is_dyndns || vpninfo->proxy)) {
188
reconnect:
189
190
191
192
193
194
#ifdef SOCK_CLOEXEC
ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_IP);
if (ssl_sock < 0)
#endif
{
ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
195
196
197
198
199
200
if (ssl_sock < 0) {
#ifdef _WIN32
err = WSAGetLastError();
#else
err = -errno;
#endif
201
goto reconn_err;
202
}
203
set_fd_cloexec(ssl_sock);
204
}
205
206
207
err = cancellable_connect(vpninfo, ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen);
if (err) {
char *errstr;
208
reconn_err:
209
210
211
212
213
214
#ifdef _WIN32
if (err > 0)
errstr = openconnect__win32_strerror(err);
else
#endif
errstr = strerror(-err);
215
if (vpninfo->proxy) {
216
vpn_progress(vpninfo, PRG_ERR,
217
_("Failed to reconnect to proxy %s: %s\n"),
218
vpninfo->proxy, errstr);
219
} else {
220
vpn_progress(vpninfo, PRG_ERR,
221
_("Failed to reconnect to host %s: %s\n"),
222
vpninfo->hostname, errstr);
223
}
224
225
226
227
#ifdef _WIN32
if (err > 0)
free(errstr);
#endif
228
if (ssl_sock >= 0)
229
closesocket(ssl_sock);
230
231
ssl_sock = -EINVAL;
goto out;
232
}
233
234
} else {
struct addrinfo hints, *result, *rp;
235
char *hostname;
236
char port[6];
237
238
239
240
241
242
243
244
245
246
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
247
248
249
250
/* The 'port' variable is a string because it's easier
this way than if we pass NULL to getaddrinfo() and
then try to fill in the numeric value into
different types of returned sockaddr_in{6,}. */
251
#ifdef LIBPROXY_HDR
252
if (vpninfo->proxy_factory) {
253
struct oc_text_buf *url_buf = buf_alloc();
254
255
256
char **proxies;
int i = 0;
257
258
free(vpninfo->proxy_type);
vpninfo->proxy_type = NULL;
259
260
261
free(vpninfo->proxy);
vpninfo->proxy = NULL;
262
263
264
265
266
267
buf_append(url_buf, "https://%s", vpninfo->hostname);
if (vpninfo->port != 443)
buf_append(url_buf, ":%d", vpninfo->port);
buf_append(url_buf, "/%s", vpninfo->urlpath?:"");
if (buf_error(url_buf)) {
buf_free(url_buf);
268
269
270
ssl_sock = -ENOMEM;
goto out;
}
271
272
proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
273
url_buf->data);
274
i = 0;
275
while (proxies && proxies[i]) {
276
277
278
279
if (!vpninfo->proxy &&
(!strncmp(proxies[i], "http://", 7) ||
!strncmp(proxies[i], "socks://", 8) ||
!strncmp(proxies[i], "socks5://", 9)))
280
internal_parse_url(proxies[i], &vpninfo->proxy_type,
281
282
&vpninfo->proxy, &vpninfo->proxy_port,
NULL, 0);
283
284
i++;
}
285
buf_free(url_buf);
286
287
free(proxies);
if (vpninfo->proxy)
288
vpn_progress(vpninfo, PRG_DEBUG,
289
290
_("Proxy from libproxy: %s://%s:%d/\n"),
vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
291
292
}
#endif
293
294
if (vpninfo->proxy) {
hostname = vpninfo->proxy;
295
snprintf(port, 6, "%d", vpninfo->proxy_port);
296
297
} else {
hostname = vpninfo->hostname;
298
snprintf(port, 6, "%d", vpninfo->port);
299
300
}
301
if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
302
hostname = strndup(hostname + 1, strlen(hostname) - 2);
303
304
305
306
if (!hostname) {
ssl_sock = -ENOMEM;
goto out;
}
307
308
309
hints.ai_flags |= AI_NUMERICHOST;
}
310
311
312
313
if (vpninfo->getaddrinfo_override)
err = vpninfo->getaddrinfo_override(vpninfo->cbdata, hostname, port, &hints, &result);
else
err = getaddrinfo(hostname, port, &hints, &result);
314
315
if (err) {
316
317
318
vpn_progress(vpninfo, PRG_ERR,
_("getaddrinfo failed for host '%s': %s\n"),
hostname, gai_strerror(err));
319
320
if (hints.ai_flags & AI_NUMERICHOST)
free(hostname);
321
ssl_sock = -EINVAL;
322
323
324
325
326
327
328
/* If we were just retrying for dynamic DNS, reconnct using
the previously-known IP address */
if (vpninfo->peer_addr) {
vpn_progress(vpninfo, PRG_ERR,
_("Reconnecting to DynDNS server using previously cached IP address\n"));
goto reconnect;
}
329
goto out;
330
}
331
332
if (hints.ai_flags & AI_NUMERICHOST)
free(hostname);
333
334
for (rp = result; rp ; rp = rp->ai_next) {
335
336
char host[80];
337
host[0] = 0;
338
339
if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
sizeof(host), NULL, 0, NI_NUMERICHOST))
340
vpn_progress(vpninfo, PRG_DEBUG, vpninfo->proxy_type ?
341
_("Attempting to connect to proxy %s%s%s:%s\n") :
342
_("Attempting to connect to server %s%s%s:%s\n"),
343
rp->ai_family == AF_INET6 ? "[" : "",
344
host,
345
rp->ai_family == AF_INET6 ? "]" : "",
346
port);
347
348
349
350
351
ssl_sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (ssl_sock < 0)
continue;
352
set_fd_cloexec(ssl_sock);
353
354
err = cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen);
if (!err) {
355
356
/* Store the peer address we actually used, so that DTLS can
use it again later */
357
358
359
360
361
free(vpninfo->ip_info.gateway_addr);
vpninfo->ip_info.gateway_addr = NULL;
if (host[0]) {
vpninfo->ip_info.gateway_addr = strdup(host);
362
363
364
365
366
vpn_progress(vpninfo, PRG_INFO, _("Connected to %s%s%s:%s\n"),
rp->ai_family == AF_INET6 ? "[" : "",
host,
rp->ai_family == AF_INET6 ? "]" : "",
port);
367
}
368
369
370
free(vpninfo->peer_addr);
vpninfo->peer_addrlen = 0;
371
372
vpninfo->peer_addr = malloc(rp->ai_addrlen);
if (!vpninfo->peer_addr) {
373
374
vpn_progress(vpninfo, PRG_ERR,
_("Failed to allocate sockaddr storage\n"));
375
closesocket(ssl_sock);
376
377
ssl_sock = -ENOMEM;
goto out;
378
379
380
}
vpninfo->peer_addrlen = rp->ai_addrlen;
memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
381
382
383
384
385
386
387
388
389
390
391
/* If no proxy, ensure that we output *this* IP address in
* authentication results because we're going to need to
* reconnect to the *same* server from the rotation. And with
* some trick DNS setups, it might possibly be a "rotation"
* even if we only got one result from getaddrinfo() this
* time.
*
* If there's a proxy, we're kind of screwed; we can't know
* which IP address we connected to. Perhaps we ought to do
* the DNS lookup locally and connect to a specific IP? */
if (!vpninfo->proxy && host[0]) {
392
char *p = malloc(strlen(host) + 3);
393
if (p) {
394
395
free(vpninfo->unique_hostname);
vpninfo->unique_hostname = p;
396
397
398
399
400
401
if (rp->ai_family == AF_INET6)
*p++ = '[';
memcpy(p, host, strlen(host));
p += strlen(host);
if (rp->ai_family == AF_INET6)
*p++ = ']';
402
*p = 0;
403
404
}
}
405
406
break;
}
407
408
409
410
411
412
413
414
415
if (host[0]) {
char *errstr;
#ifdef _WIN32
if (err > 0)
errstr = openconnect__win32_strerror(err);
else
#endif
errstr = strerror(-err);
416
417
418
419
vpn_progress(vpninfo, PRG_INFO, _("Failed to connect to %s%s%s:%s: %s\n"),
rp->ai_family == AF_INET6 ? "[" : "",
host,
rp->ai_family == AF_INET6 ? "]" : "",
420
421
422
423
424
425
port, errstr);
#ifdef _WIN32
if (err > 0)
free(errstr);
#endif
}
426
closesocket(ssl_sock);
427
ssl_sock = -1;
428
429
430
431
432
433
434
435
436
437
/* If we're in DynDNS mode but this *was* the cached IP address,
* don't bother falling back to it if it didn't work. */
if (vpninfo->peer_addr && vpninfo->peer_addrlen == rp->ai_addrlen &&
match_sockaddr(vpninfo->peer_addr, rp->ai_addr)) {
vpn_progress(vpninfo, PRG_TRACE,
_("Forgetting non-functional previous peer address\n"));
free(vpninfo->peer_addr);
vpninfo->peer_addr = 0;
vpninfo->peer_addrlen = 0;
438
439
free(vpninfo->ip_info.gateway_addr);
vpninfo->ip_info.gateway_addr = NULL;
440
}
441
442
}
freeaddrinfo(result);
443
444
if (ssl_sock < 0) {
445
446
447
vpn_progress(vpninfo, PRG_ERR,
_("Failed to connect to host %s\n"),
vpninfo->proxy?:vpninfo->hostname);
448
ssl_sock = -EINVAL;
449
450
451
452
453
if (vpninfo->peer_addr) {
vpn_progress(vpninfo, PRG_ERR,
_("Reconnecting to DynDNS server using previously cached IP address\n"));
goto reconnect;
}
454
goto out;
455
}
456
457
}
458
if (vpninfo->proxy) {
459
err = process_proxy(vpninfo, ssl_sock);
460
if (err) {
461
closesocket(ssl_sock);
462
463
464
465
466
467
if (err == -EAGAIN) {
/* Proxy authentication failed and we need to retry */
vpn_progress(vpninfo, PRG_DEBUG,
_("Reconnecting to proxy %s\n"), vpninfo->proxy);
goto reconnect;
}
468
ssl_sock = err;
469
470
}
}
471
472
473
out:
/* If proxy processing returned -EAGAIN to reconnect before attempting
further auth, and we failed to reconnect, we have to clean up here. */
474
clear_auth_states(vpninfo, vpninfo->proxy_auth, 1);
475
476
477
return ssl_sock;
}
478
479
480
481
482
483
484
485
486
487
488
int __attribute__ ((format (printf, 2, 3)))
openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...)
{
char buf[1024];
va_list args;
buf[1023] = 0;
va_start(args, fmt);
vsnprintf(buf, 1023, fmt, args);
va_end(args);
489
return vpninfo->ssl_write(vpninfo, buf, strlen(buf));
490
491
492
}
493
494
int __attribute__ ((format(printf, 4, 5)))
request_passphrase(struct openconnect_info *vpninfo, const char *label,
495
496
497
498
499
500
501
502
503
504
505
506
507
508
char **response, const char *fmt, ...)
{
struct oc_auth_form f;
struct oc_form_opt o;
char buf[1024];
va_list args;
int ret;
buf[1023] = 0;
memset(&f, 0, sizeof(f));
va_start(args, fmt);
vsnprintf(buf, 1023, fmt, args);
va_end(args);
509
f.auth_id = (char *)label;
510
511
512
513
f.opts = &o;
o.next = NULL;
o.type = OC_FORM_OPT_PASSWORD;
514
o.name = (char *)label;
515
o.label = buf;
516
o._value = NULL;
517
518
ret = process_auth_form(vpninfo, &f);
519
if (!ret) {
520
*response = o._value;
521
522
523
524
525
526
return 0;
}
return -EIO;
}
527
#if defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
528
int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
529
530
{
struct statvfs buf;
531
532
char *sslkey = openconnect_utf8_to_legacy(vpninfo, vpninfo->sslkey);
int err = 0;
533
534
535
if (statvfs(sslkey, &buf)) {
err = -errno;
536
537
vpn_progress(vpninfo, PRG_ERR, _("statvfs: %s\n"),
strerror(errno));
538
} else if (asprintf(&vpninfo->cert_password, "%lx", buf.f_fsid) == -1)
539
540
541
542
543
err = -ENOMEM;
if (sslkey != vpninfo->sslkey)
free(sslkey);
return err;
544
}
545
546
#elif defined(_WIN32)
#include <fileapi.h>
547
548
typedef BOOL WINAPI (*GVIBH)(HANDLE, LPWSTR, DWORD, LPDWORD, LPDWORD, LPDWORD, LPWSTR, DWORD);
549
550
int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
{
551
HANDLE h;
552
DWORD serial;
553
554
HINSTANCE kernlib;
GVIBH func = NULL;
555
int success;
556
int fd;
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
/* Some versions of Windows don't have this so don't use standard
load-time linking or it'll cause failures. */
kernlib = LoadLibraryA("Kernel32.dll");
if (!kernlib) {
notsupp:
vpn_progress(vpninfo, PRG_ERR,
_("Could not obtain file system ID for passphrase\n"));
return -EOPNOTSUPP;
}
func = (GVIBH)GetProcAddress(kernlib, "GetVolumeInformationByHandleW");
FreeLibrary(kernlib);
if (!func)
goto notsupp;
572
fd = openconnect_open_utf8(vpninfo, vpninfo->sslkey, O_RDONLY);
573
574
575
576
577
578
if (fd == -1) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to open private key file '%s': %s\n"),
vpninfo->sslkey, strerror(errno));
return -ENOENT;
}
579
580
h = (HANDLE)_get_osfhandle(fd);
581
success = func(h, NULL, 0, &serial, NULL, NULL, NULL, 0);
582
close(fd);
583
584
if (!success)
585
586
return -EIO;
587
if (asprintf(&vpninfo->cert_password, "%lx", serial) == -1)
588
589
return -ENOMEM;
590
return 0;
591
}
592
#elif defined(HAVE_STATFS)
593
int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
594
{
595
char *sslkey = openconnect_utf8_to_legacy(vpninfo, vpninfo->sslkey);
596
597
598
struct statfs buf;
unsigned *fsid = (unsigned *)&buf.f_fsid;
unsigned long long fsid64;
599
int err = 0;
600
601
602
if (statfs(sslkey, &buf)) {
err = -errno;
603
604
vpn_progress(vpninfo, PRG_ERR, _("statfs: %s\n"),
strerror(errno));
605
return -err;
606
607
608
} else {
fsid64 = ((unsigned long long)fsid[0] << 32) | fsid[1];
609
if (asprintf(&vpninfo->cert_password, "%llx", fsid64) == -1)
610
err = -ENOMEM;
611
}
612
613
614
615
616
if (sslkey != vpninfo->sslkey)
free(sslkey);
return err;
617
}
618
619
620
621
622
#else
int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
{
return -EOPNOTSUPP;
}
623
#endif
624
625
#if defined(OPENCONNECT_OPENSSL)
626
627
/* We put this here rather than in openssl.c because it might be needed
for OpenSSL DTLS support even when GnuTLS is being used for HTTPS */
628
int openconnect_print_err_cb(const char *str, size_t len, void *ptr)
629
630
631
632
633
634
635
{
struct openconnect_info *vpninfo = ptr;
vpn_progress(vpninfo, PRG_ERR, "%s", str);
return 0;
}
#endif
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
#ifdef FAKE_ANDROID_KEYSTORE
char *keystore_strerror(int err)
{
return (char *)strerror(-err);
}
int keystore_fetch(const char *key, unsigned char **result)
{
unsigned char *data;
struct stat st;
int fd;
int ret;
fd = open(key, O_RDONLY);
if (fd < 0)
return -errno;
if (fstat(fd, &st)) {
ret = -errno;
goto out_fd;
}
659
data = malloc(st.st_size + 1);
660
661
662
663
664
665
666
667
668
669
if (!data) {
ret = -ENOMEM;
goto out_fd;
}
if (read(fd, data, st.st_size) != st.st_size) {
ret = -EIO;
free(data);
goto out_fd;
}
670
671
data[st.st_size] = 0;
672
673
674
675
676
677
*result = data;
ret = st.st_size;
out_fd:
close(fd);
return ret;
}
678
#elif defined(ANDROID_KEYSTORE)
679
680
681
682
683
684
685
686
687
688
689
690
691
/* keystore.h isn't in the NDK so we need to define these */
#define NO_ERROR 1
#define LOCKED 2
#define UNINITIALIZED 3
#define SYSTEM_ERROR 4
#define PROTOCOL_ERROR 5
#define PERMISSION_DENIED 6
#define KEY_NOT_FOUND 7
#define VALUE_CORRUPTED 8
#define UNDEFINED_ACTION 9
#define WRONG_PASSWORD 10
const char *keystore_strerror(int err)
692
693
694
{
switch (-err) {
case NO_ERROR: return _("No error");
695
case LOCKED: return _("Keystore locked");
696
697
698
699
700
701
702
case UNINITIALIZED: return _("Keystore uninitialized");
case SYSTEM_ERROR: return _("System error");
case PROTOCOL_ERROR: return _("Protocol error");
case PERMISSION_DENIED: return _("Permission denied");
case KEY_NOT_FOUND: return _("Key not found");
case VALUE_CORRUPTED: return _("Value corrupted");
case UNDEFINED_ACTION: return _("Undefined action");
703
704
705
706
case WRONG_PASSWORD:
case WRONG_PASSWORD+1:
case WRONG_PASSWORD+2:
case WRONG_PASSWORD+3: return _("Wrong password");
707
708
709
710
711
712
713
714
default: return _("Unknown error");
}
}
/* Returns length, or a negative errno in its own namespace (handled by its
own strerror function above). The numbers are from Android's keystore.h */
int keystore_fetch(const char *key, unsigned char **result)
{
715
716
struct sockaddr_un sa = { AF_UNIX, "/dev/socket/keystore" };
socklen_t sl = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path) + 1;
717
718
unsigned char *data, *p;
unsigned char buf[3];
719
int len, fd;
720
721
int ret = -SYSTEM_ERROR;
722
fd = socket(AF_UNIX, SOCK_STREAM, 0);
723
724
725
if (fd < 0)
return -SYSTEM_ERROR;
726
727
728
729
if (connect(fd, (void *)&sa, sl)) {
close(fd);
return -SYSTEM_ERROR;
}
730
731
len = strlen(key);
buf[0] = 'g';
732
store_be16(buf + 1, len);
733
734
735
736
737
738
739
740
741
742
743
744
if (send(fd, buf, 3, 0) != 3 || send(fd, key, len, 0) != len ||
shutdown(fd, SHUT_WR) || recv(fd, buf, 1, 0) != 1)
goto out;
if (buf[0] != NO_ERROR) {
/* Should never be zero */
ret = buf[0] ? -buf[0] : -PROTOCOL_ERROR;
goto out;
}
if (recv(fd, buf, 2, 0) != 2)
goto out;
745
len = load_be16(buf);
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
data = malloc(len);
if (!data)
goto out;
p = data;
ret = len;
while (len) {
int got = recv(fd, p, len, 0);
if (got <= 0) {
free(data);
ret = -PROTOCOL_ERROR;
goto out;
}
len -= got;
p += got;
}
*result = data;
out:
close(fd);
return ret;
}
#endif
769
770
771
void cmd_fd_set(struct openconnect_info *vpninfo, fd_set *fds, int *maxfd)
{
772
773
774
775
if (vpninfo->cmd_fd != -1) {
FD_SET(vpninfo->cmd_fd, fds);
if (vpninfo->cmd_fd > *maxfd)
*maxfd = vpninfo->cmd_fd;
776
777
778
}
}
779
780
781
782
783
784
785
786
787
788
789
790
void check_cmd_fd(struct openconnect_info *vpninfo, fd_set *fds)
{
char cmd;
if (vpninfo->cmd_fd == -1 || !FD_ISSET(vpninfo->cmd_fd, fds))
return;
if (vpninfo->cmd_fd_write == -1) {
/* legacy openconnect_set_cancel_fd() users */
vpninfo->got_cancel_cmd = 1;
return;
}
791
#ifdef _WIN32
792
if (recv(vpninfo->cmd_fd, &cmd, 1, 0) != 1)
793
return;
794
795
796
797
#else
if (read(vpninfo->cmd_fd, &cmd, 1) != 1)
return;
#endif
798
799
switch (cmd) {
case OC_CMD_CANCEL:
800
case OC_CMD_DETACH:
801
vpninfo->got_cancel_cmd = 1;
802
vpninfo->cancel_type = cmd;
803
break;
804
805
806
case OC_CMD_PAUSE:
vpninfo->got_pause_cmd = 1;
break;
807
808
809
case OC_CMD_STATS:
if (vpninfo->stats_handler)
vpninfo->stats_handler(vpninfo->cbdata, &vpninfo->stats);
810
811
812
}
}
813
814
int is_cancel_pending(struct openconnect_info *vpninfo, fd_set *fds)
{
815
check_cmd_fd(vpninfo, fds);
816
return vpninfo->got_cancel_cmd || vpninfo->got_pause_cmd;
817
818
819
820
821
822
}
void poll_cmd_fd(struct openconnect_info *vpninfo, int timeout)
{
fd_set rd_set;
int maxfd = 0;
823
time_t expiration = time(NULL) + timeout, now = 0;
824
825
while (now < expiration && !vpninfo->got_cancel_cmd && !vpninfo->got_pause_cmd) {
826
struct timeval tv;
827
828
829
now = time(NULL);
tv.tv_sec = now >= expiration ? 0 : expiration - now;
830
tv.tv_usec = 0;
831
832
833
834
835
FD_ZERO(&rd_set);
cmd_fd_set(vpninfo, &rd_set, &maxfd);
select(maxfd + 1, &rd_set, NULL, NULL, &tv);
check_cmd_fd(vpninfo, &rd_set);
836
}
837
}
838
839
#ifdef _WIN32
840
841
#include <io.h>
#include <sys/stat.h>
842
int openconnect_open_utf8(struct openconnect_info *vpninfo, const char *fname, int mode)
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
{
wchar_t *fname_w;
int nr_chars = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0);
int fd;
if (!nr_chars) {
errno = EINVAL;
return -1;
}
fname_w = malloc(nr_chars * sizeof(wchar_t));
if (!fname_w) {
errno = ENOMEM;
return -1;
}
MultiByteToWideChar(CP_UTF8, 0, fname, -1, fname_w, nr_chars);
859
fd = _wopen(fname_w, mode, _S_IREAD | _S_IWRITE);
860
861
862
863
864
free(fname_w);
return fd;
}
#else
865
int openconnect_open_utf8(struct openconnect_info *vpninfo, const char *fname, int mode)
866
867
868
869
{
char *legacy_fname = openconnect_utf8_to_legacy(vpninfo, fname);
int fd;
870
fd = open(legacy_fname, mode, 0644);
871
872
873
874
875
876
877
if (legacy_fname != fname)
free(legacy_fname);
return fd;
}
#endif
878
879
FILE *openconnect_fopen_utf8(struct openconnect_info *vpninfo, const char *fname,
const char *mode)
880
881
{
int fd;
882
883
884
885
886
887
888
889
890
891
892
893
894
int flags;
if (!strcmp(mode, "r"))
flags = O_RDONLY|O_CLOEXEC;
else if (!strcmp(mode, "rb"))
flags = O_RDONLY|O_CLOEXEC|O_BINARY;
else if (!strcmp(mode, "w"))
flags = O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC;
else if (!strcmp(mode, "wb"))
flags = O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC|O_BINARY;
else {
/* This should never happen, but if we forget and start using other
modes without implementing proper mode->flags conversion, complain! */
895
vpn_progress(vpninfo, PRG_ERR,
896
_("openconnect_fopen_utf8() used with unsupported mode '%s'\n"),
897
898
899
900
mode);
return NULL;
}
901
fd = openconnect_open_utf8(vpninfo, fname, flags);
902
903
904
905
906
if (fd == -1)
return NULL;
return fdopen(fd, mode);
}
907
908
909
int udp_sockaddr(struct openconnect_info *vpninfo, int port)
{
910
free(vpninfo->dtls_addr);
911
912
913
914
915
916
917
918
919
vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
if (!vpninfo->dtls_addr)
return -ENOMEM;
memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
if (vpninfo->peer_addr->sa_family == AF_INET) {
struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
sin->sin_port = htons(port);
920
921
vpninfo->dtls_tos_proto = IPPROTO_IP;
vpninfo->dtls_tos_optname = IP_TOS;
922
923
924
} else if (vpninfo->peer_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
sin->sin6_port = htons(port);
925
#if defined(IPV6_TCLASS)
926
927
vpninfo->dtls_tos_proto = IPPROTO_IPV6;
vpninfo->dtls_tos_optname = IPV6_TCLASS;
928
#endif
929
930
931
932
933
934
935
} else {
vpn_progress(vpninfo, PRG_ERR,
_("Unknown protocol family %d. Cannot create UDP server address\n"),
vpninfo->peer_addr->sa_family);
return -EINVAL;
}
936
937
938
939
940
/* in case DTLS TOS copy is disabled, reset the optname value */
/* so that the copy won't be applied in dtls.c / dtls_mainloop() */
if (!vpninfo->dtls_pass_tos)
vpninfo->dtls_tos_optname = 0;
941
942
return 0;
}
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
int udp_connect(struct openconnect_info *vpninfo)
{
int fd, sndbuf;
fd = socket(vpninfo->peer_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0) {
vpn_perror(vpninfo, _("Open UDP socket"));
return -EINVAL;
}
if (vpninfo->protect_socket)
vpninfo->protect_socket(vpninfo->cbdata, fd);
sndbuf = vpninfo->ip_info.mtu * 2;
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *)&sndbuf, sizeof(sndbuf));
if (vpninfo->dtls_local_port) {
union {
struct sockaddr_in in;
struct sockaddr_in6 in6;
} dtls_bind_addr;
int dtls_bind_addrlen;
memset(&dtls_bind_addr, 0, sizeof(dtls_bind_addr));
if (vpninfo->peer_addr->sa_family == AF_INET) {
struct sockaddr_in *addr = &dtls_bind_addr.in;
dtls_bind_addrlen = sizeof(*addr);
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = INADDR_ANY;
addr->sin_port = htons(vpninfo->dtls_local_port);
} else if (vpninfo->peer_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *addr = &dtls_bind_addr.in6;
dtls_bind_addrlen = sizeof(*addr);
addr->sin6_family = AF_INET6;
addr->sin6_addr = in6addr_any;
addr->sin6_port = htons(vpninfo->dtls_local_port);
} else {
vpn_progress(vpninfo, PRG_ERR,
_("Unknown protocol family %d. Cannot use UDP transport\n"),
vpninfo->peer_addr->sa_family);
vpninfo->dtls_attempt_period = 0;
closesocket(fd);
return -EINVAL;
}
if (bind(fd, (struct sockaddr *)&dtls_bind_addr, dtls_bind_addrlen)) {
vpn_perror(vpninfo, _("Bind UDP socket"));
closesocket(fd);
return -EINVAL;
}
}
if (connect(fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) {
vpn_perror(vpninfo, _("Connect UDP socket\n"));
closesocket(fd);
return -EINVAL;
}