Skip to content

Latest commit

 

History

History
373 lines (326 loc) · 9.64 KB

ssl.c

File metadata and controls

373 lines (326 loc) · 9.64 KB
 
Sep 22, 2008
Sep 22, 2008
1
/*
Nov 20, 2008
Nov 20, 2008
2
* OpenConnect (SSL + DTLS) VPN client
Sep 22, 2008
Sep 22, 2008
3
*
May 13, 2012
May 13, 2012
4
* Copyright © 2008-2012 Intel Corporation.
Sep 22, 2008
Sep 22, 2008
5
*
Nov 20, 2008
Nov 20, 2008
6
7
8
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
Oct 4, 2008
Oct 4, 2008
9
* modify it under the terms of the GNU Lesser General Public License
Nov 20, 2008
Nov 20, 2008
10
* version 2.1, as published by the Free Software Foundation.
Sep 22, 2008
Sep 22, 2008
11
*
Nov 20, 2008
Nov 20, 2008
12
* This program is distributed in the hope that it will be useful, but
Oct 4, 2008
Oct 4, 2008
13
14
15
16
17
18
19
20
21
22
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to:
*
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
Sep 22, 2008
Sep 22, 2008
23
*/
Jun 1, 2009
Jun 1, 2009
24
25
#include <sys/types.h>
Sep 22, 2008
Sep 22, 2008
26
#include <sys/socket.h>
Jun 1, 2012
Jun 1, 2012
27
28
#include <netinet/in.h>
#include <arpa/inet.h>
Sep 22, 2008
Sep 22, 2008
29
30
#include <netdb.h>
#include <unistd.h>
Sep 22, 2008
Sep 22, 2008
31
#include <fcntl.h>
Jun 1, 2009
Jun 1, 2009
32
#include <string.h>
Nov 6, 2009
Nov 6, 2009
33
#include <stdio.h>
May 29, 2012
May 29, 2012
34
#include <errno.h>
May 29, 2012
May 29, 2012
35
#include <stdlib.h>
May 31, 2012
May 31, 2012
36
#include <stdarg.h>
Jun 1, 2009
Jun 1, 2009
37
38
#if defined(__linux__)
#include <sys/vfs.h>
Apr 9, 2010
Apr 9, 2010
39
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__APPLE__)
Jun 1, 2009
Jun 1, 2009
40
41
#include <sys/param.h>
#include <sys/mount.h>
May 7, 2010
May 7, 2010
42
#elif defined (__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
Nov 6, 2009
Nov 6, 2009
43
#include <sys/statvfs.h>
Aug 16, 2011
Aug 16, 2011
44
45
#elif defined (__GNU__)
#include <sys/statfs.h>
Jun 1, 2009
Jun 1, 2009
46
#endif
Sep 22, 2008
Sep 22, 2008
47
Mar 9, 2011
Mar 9, 2011
48
#include "openconnect-internal.h"
Sep 22, 2008
Sep 22, 2008
49
Feb 23, 2010
Feb 23, 2010
50
51
52
53
54
/* OSX < 1.6 doesn't have AI_NUMERICSERV */
#ifndef AI_NUMERICSERV
#define AI_NUMERICSERV 0
#endif
May 12, 2012
May 12, 2012
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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);
fd_set wr_set, rd_set;
int maxfd = sockfd;
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
if (connect(sockfd, addr, addrlen) < 0 && errno != EINPROGRESS)
return -1;
FD_ZERO(&wr_set);
FD_ZERO(&rd_set);
FD_SET(sockfd, &wr_set);
if (vpninfo->cancel_fd != -1) {
FD_SET(vpninfo->cancel_fd, &rd_set);
if (vpninfo->cancel_fd > sockfd)
maxfd = vpninfo->cancel_fd;
}
/* Later we'll render this whole exercise non-pointless by
including a 'cancelfd' here too. */
select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
if (vpninfo->cancel_fd != -1 && FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
May 18, 2012
May 18, 2012
81
vpn_progress(vpninfo, PRG_ERR, _("Socket connect cancelled\n"));
May 12, 2012
May 12, 2012
82
83
84
85
86
87
88
89
90
errno = EINTR;
return -1;
}
/* Check whether connect() succeeded or failed by using
getpeername(). See http://cr.yp.to/docs/connect.html */
return getpeername(sockfd, (void *)&peer, &peerlen);
}
May 29, 2012
May 29, 2012
91
int connect_https_socket(struct openconnect_info *vpninfo)
Sep 22, 2008
Sep 22, 2008
92
{
Jun 3, 2009
Jun 3, 2009
93
int ssl_sock = -1;
Sep 22, 2008
Sep 22, 2008
94
95
int err;
Dec 23, 2009
Dec 23, 2009
96
97
98
if (!vpninfo->port)
vpninfo->port = 443;
Dec 7, 2009
Dec 7, 2009
99
if (vpninfo->peer_addr) {
May 17, 2012
May 17, 2012
100
101
102
103
104
105
106
107
108
109
110
#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);
if (ssl_sock < 0)
goto reconn_err;
fcntl(ssl_sock, F_SETFD, fcntl(ssl_sock, F_GETFD) | FD_CLOEXEC);
}
if (cancellable_connect(vpninfo, ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen)) {
Dec 7, 2009
Dec 7, 2009
111
reconn_err:
Sep 22, 2011
Sep 22, 2011
112
113
114
115
116
117
118
119
120
if (vpninfo->proxy) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to reconnect to proxy %s\n"),
vpninfo->proxy);
} else {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to reconnect to host %s\n"),
vpninfo->hostname);
}
Dec 7, 2009
Dec 7, 2009
121
return -EINVAL;
Sep 22, 2008
Sep 22, 2008
122
}
Dec 7, 2009
Dec 7, 2009
123
124
125
} else {
struct addrinfo hints, *result, *rp;
Jan 1, 2010
Jan 1, 2010
126
char *hostname;
Dec 23, 2009
Dec 23, 2009
127
char port[6];
Dec 7, 2009
Dec 7, 2009
128
129
130
131
132
133
134
135
136
137
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;
Jan 1, 2010
Jan 1, 2010
138
139
140
141
/* 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,}. */
Sep 22, 2011
Sep 22, 2011
142
#ifdef LIBPROXY_HDR
Jan 2, 2010
Jan 2, 2010
143
144
145
146
147
if (vpninfo->proxy_factory) {
char *url;
char **proxies;
int i = 0;
Jan 2, 2010
Jan 2, 2010
148
149
free(vpninfo->proxy_type);
vpninfo->proxy_type = NULL;
Jan 2, 2010
Jan 2, 2010
150
151
152
153
free(vpninfo->proxy);
vpninfo->proxy = NULL;
if (vpninfo->port == 443)
Jan 5, 2010
Jan 5, 2010
154
155
i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
vpninfo->urlpath?:"");
Jan 2, 2010
Jan 2, 2010
156
else
Jan 5, 2010
Jan 5, 2010
157
158
159
160
i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
vpninfo->port, vpninfo->urlpath?:"");
if (i == -1)
return -ENOMEM;
Jan 2, 2010
Jan 2, 2010
161
162
163
164
proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
url);
Dec 3, 2011
Dec 3, 2011
165
i = 0;
Jan 2, 2010
Jan 2, 2010
166
while (proxies && proxies[i]) {
Jan 2, 2010
Jan 2, 2010
167
168
169
170
if (!vpninfo->proxy &&
(!strncmp(proxies[i], "http://", 7) ||
!strncmp(proxies[i], "socks://", 8) ||
!strncmp(proxies[i], "socks5://", 9)))
Mar 9, 2011
Mar 9, 2011
171
internal_parse_url(proxies[i], &vpninfo->proxy_type,
Jan 2, 2010
Jan 2, 2010
172
173
&vpninfo->proxy, &vpninfo->proxy_port,
NULL, 0);
Jan 2, 2010
Jan 2, 2010
174
175
176
177
178
i++;
}
free(url);
free(proxies);
if (vpninfo->proxy)
Sep 22, 2011
Sep 22, 2011
179
180
181
vpn_progress(vpninfo, PRG_TRACE,
_("Proxy from libproxy: %s://%s:%d/\n"),
vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
Jan 2, 2010
Jan 2, 2010
182
183
}
#endif
Jan 1, 2010
Jan 1, 2010
184
185
if (vpninfo->proxy) {
hostname = vpninfo->proxy;
Feb 22, 2010
Feb 22, 2010
186
snprintf(port, 6, "%d", vpninfo->proxy_port);
Jan 1, 2010
Jan 1, 2010
187
188
} else {
hostname = vpninfo->hostname;
Feb 22, 2010
Feb 22, 2010
189
snprintf(port, 6, "%d", vpninfo->port);
Jan 1, 2010
Jan 1, 2010
190
191
}
Jan 1, 2010
Jan 1, 2010
192
if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
Jan 24, 2010
Jan 24, 2010
193
194
195
196
/* Solaris has no strndup(). */
int len = strlen(hostname) - 2;
char *new_hostname = malloc(len + 1);
if (!new_hostname)
Jan 1, 2010
Jan 1, 2010
197
return -ENOMEM;
Jan 24, 2010
Jan 24, 2010
198
199
200
201
memcpy(new_hostname, hostname + 1, len);
new_hostname[len] = 0;
hostname = new_hostname;
Jan 1, 2010
Jan 1, 2010
202
203
204
hints.ai_flags |= AI_NUMERICHOST;
}
Jan 1, 2010
Jan 1, 2010
205
err = getaddrinfo(hostname, port, &hints, &result);
Jan 1, 2010
Jan 1, 2010
206
207
208
if (hints.ai_flags & AI_NUMERICHOST)
free(hostname);
Dec 7, 2009
Dec 7, 2009
209
if (err) {
Sep 22, 2011
Sep 22, 2011
210
211
212
vpn_progress(vpninfo, PRG_ERR,
_("getaddrinfo failed for host '%s': %s\n"),
hostname, gai_strerror(err));
Dec 7, 2009
Dec 7, 2009
213
214
215
216
return -EINVAL;
}
for (rp = result; rp ; rp = rp->ai_next) {
Jan 1, 2010
Jan 1, 2010
217
218
219
220
char host[80];
if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
sizeof(host), NULL, 0, NI_NUMERICHOST))
Jun 27, 2011
Jun 27, 2011
221
vpn_progress(vpninfo, PRG_INFO,
Sep 22, 2011
Sep 22, 2011
222
223
224
225
226
_("Attempting to connect to %s%s%s:%s\n"),
rp->ai_family == AF_INET6?"[":"",
host,
rp->ai_family == AF_INET6?"]":"",
port);
Jan 1, 2010
Jan 1, 2010
227
Dec 7, 2009
Dec 7, 2009
228
229
230
231
ssl_sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (ssl_sock < 0)
continue;
May 12, 2012
May 12, 2012
232
if (cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
Dec 7, 2009
Dec 7, 2009
233
234
235
236
/* Store the peer address we actually used, so that DTLS can
use it again later */
vpninfo->peer_addr = malloc(rp->ai_addrlen);
if (!vpninfo->peer_addr) {
Sep 22, 2011
Sep 22, 2011
237
238
vpn_progress(vpninfo, PRG_ERR,
_("Failed to allocate sockaddr storage\n"));
Dec 7, 2009
Dec 7, 2009
239
240
241
242
243
244
245
246
247
248
249
250
251
close(ssl_sock);
return -ENOMEM;
}
vpninfo->peer_addrlen = rp->ai_addrlen;
memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
break;
}
close(ssl_sock);
ssl_sock = -1;
}
freeaddrinfo(result);
if (ssl_sock < 0) {
Sep 22, 2011
Sep 22, 2011
252
253
254
vpn_progress(vpninfo, PRG_ERR,
_("Failed to connect to host %s\n"),
vpninfo->proxy?:vpninfo->hostname);
Dec 7, 2009
Dec 7, 2009
255
256
return -EINVAL;
}
Sep 22, 2008
Sep 22, 2008
257
258
}
Jan 1, 2010
Jan 1, 2010
259
if (vpninfo->proxy) {
Jan 2, 2010
Jan 2, 2010
260
err = process_proxy(vpninfo, ssl_sock);
Jan 1, 2010
Jan 1, 2010
261
262
263
264
265
266
if (err) {
close(ssl_sock);
return err;
}
}
May 29, 2012
May 29, 2012
267
268
269
return ssl_sock;
}
May 31, 2012
May 31, 2012
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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);
return openconnect_SSL_write(vpninfo, buf, strlen(buf));
}
Jun 4, 2012
Jun 4, 2012
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
int request_passphrase(struct openconnect_info *vpninfo,
char **response, const char *fmt, ...)
{
struct oc_auth_form f;
struct oc_form_opt o;
char buf[1024];
va_list args;
int ret;
if (!vpninfo->process_auth_form)
return -EINVAL;
buf[1023] = 0;
memset(&f, 0, sizeof(f));
va_start(args, fmt);
vsnprintf(buf, 1023, fmt, args);
va_end(args);
f.auth_id = (char *)"ssl_certificate";
f.opts = &o;
o.next = NULL;
o.type = OC_FORM_OPT_PASSWORD;
o.name = (char *)"passphrase";
o.label = buf;
o.value = NULL;
Jun 8, 2012
Jun 8, 2012
312
ret = vpninfo->process_auth_form(vpninfo->cbdata, &f);
Jun 4, 2012
Jun 4, 2012
313
314
315
316
317
318
319
320
if (!ret) {
*response = o.value;
return 0;
}
return -EIO;
}
May 7, 2010
May 7, 2010
321
#if defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
Nov 16, 2010
Nov 16, 2010
322
int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
Nov 3, 2009
Nov 3, 2009
323
324
325
326
327
{
struct statvfs buf;
if (statvfs(vpninfo->sslkey, &buf)) {
int err = errno;
Sep 22, 2011
Sep 22, 2011
328
329
vpn_progress(vpninfo, PRG_ERR, _("statvfs: %s\n"),
strerror(errno));
Nov 3, 2009
Nov 3, 2009
330
331
return -err;
}
Nov 6, 2009
Nov 6, 2009
332
333
if (asprintf(&vpninfo->cert_password, "%lx", buf.f_fsid))
return -ENOMEM;
Nov 3, 2009
Nov 3, 2009
334
335
336
return 0;
}
#else
Nov 16, 2010
Nov 16, 2010
337
int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
May 28, 2009
May 28, 2009
338
339
340
341
342
343
344
{
struct statfs buf;
unsigned *fsid = (unsigned *)&buf.f_fsid;
unsigned long long fsid64;
if (statfs(vpninfo->sslkey, &buf)) {
int err = errno;
Sep 22, 2011
Sep 22, 2011
345
346
vpn_progress(vpninfo, PRG_ERR, _("statfs: %s\n"),
strerror(errno));
May 28, 2009
May 28, 2009
347
348
349
return -err;
}
fsid64 = ((unsigned long long)fsid[0] << 32) | fsid[1];
Nov 6, 2009
Nov 6, 2009
350
351
352
if (asprintf(&vpninfo->cert_password, "%llx", fsid64))
return -ENOMEM;
May 28, 2009
May 28, 2009
353
354
return 0;
}
Nov 3, 2009
Nov 3, 2009
355
#endif
Jun 11, 2012
Jun 11, 2012
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#if defined(OPENCONNECT_OPENSSL) || defined (DTLS_OPENSSL)
/* 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 */
#include <openssl/err.h>
static int print_err(const char *str, size_t len, void *ptr)
{
struct openconnect_info *vpninfo = ptr;
vpn_progress(vpninfo, PRG_ERR, "%s", str);
return 0;
}
void openconnect_report_ssl_errors(struct openconnect_info *vpninfo)
{
ERR_print_errors_cb(print_err, vpninfo);
}
#endif