Be explicit when we're connecting to a proxy not directly to a VPN server
[platform/upstream/openconnect.git] / ssl.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2012 Intel Corporation.
5  *
6  * Author: David Woodhouse <dwmw2@infradead.org>
7  *
8  * 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  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to:
19  *
20  *   Free Software Foundation, Inc.
21  *   51 Franklin Street, Fifth Floor,
22  *   Boston, MA 02110-1301 USA
23  */
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <netdb.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #if defined(__linux__) || defined(ANDROID)
39 #include <sys/vfs.h>
40 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__APPLE__)
41 #include <sys/param.h>
42 #include <sys/mount.h>
43 #elif defined (__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
44 #include <sys/statvfs.h>
45 #elif defined (__GNU__)
46 #include <sys/statfs.h>
47 #endif
48
49 #include "openconnect-internal.h"
50
51 /* OSX < 1.6 doesn't have AI_NUMERICSERV */
52 #ifndef AI_NUMERICSERV
53 #define AI_NUMERICSERV 0
54 #endif
55
56 static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd,
57                                const struct sockaddr *addr, socklen_t addrlen)
58 {
59         struct sockaddr_storage peer;
60         socklen_t peerlen = sizeof(peer);
61         fd_set wr_set, rd_set;
62         int maxfd = sockfd;
63
64         fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
65
66         if (connect(sockfd, addr, addrlen) < 0 && errno != EINPROGRESS)
67                 return -1;
68
69         FD_ZERO(&wr_set);
70         FD_ZERO(&rd_set);
71         FD_SET(sockfd, &wr_set);
72         if (vpninfo->cancel_fd != -1) {
73                 FD_SET(vpninfo->cancel_fd, &rd_set);
74                 if (vpninfo->cancel_fd > sockfd)
75                         maxfd = vpninfo->cancel_fd;
76         }
77         
78         /* Later we'll render this whole exercise non-pointless by
79            including a 'cancelfd' here too. */
80         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
81         if (vpninfo->cancel_fd != -1 && FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
82                 vpn_progress(vpninfo, PRG_ERR, _("Socket connect cancelled\n"));
83                 errno = EINTR;
84                 return -1;
85         }
86                 
87         /* Check whether connect() succeeded or failed by using
88            getpeername(). See http://cr.yp.to/docs/connect.html */
89         return getpeername(sockfd, (void *)&peer, &peerlen);
90 }
91
92 int connect_https_socket(struct openconnect_info *vpninfo)
93 {
94         int ssl_sock = -1;
95         int err;
96
97         if (!vpninfo->port)
98                 vpninfo->port = 443;
99
100         if (vpninfo->peer_addr) {
101 #ifdef SOCK_CLOEXEC
102                 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_IP);
103                 if (ssl_sock < 0)
104 #endif
105                 {
106                         ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
107                         if (ssl_sock < 0)
108                                 goto reconn_err;
109                         fcntl(ssl_sock, F_SETFD, fcntl(ssl_sock, F_GETFD) | FD_CLOEXEC);
110                 }
111                 if (cancellable_connect(vpninfo, ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen)) {
112                 reconn_err:
113                         if (vpninfo->proxy) {
114                                 vpn_progress(vpninfo, PRG_ERR, 
115                                              _("Failed to reconnect to proxy %s\n"),
116                                              vpninfo->proxy);
117                         } else {
118                                 vpn_progress(vpninfo, PRG_ERR, 
119                                              _("Failed to reconnect to host %s\n"),
120                                              vpninfo->hostname);
121                         }
122                         return -EINVAL;
123                 }
124                 
125         } else {
126                 struct addrinfo hints, *result, *rp;
127                 char *hostname;
128                 char port[6];
129
130                 memset(&hints, 0, sizeof(struct addrinfo));
131                 hints.ai_family = AF_UNSPEC;
132                 hints.ai_socktype = SOCK_STREAM;
133                 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
134                 hints.ai_protocol = 0;
135                 hints.ai_canonname = NULL;
136                 hints.ai_addr = NULL;
137                 hints.ai_next = NULL;
138
139                 /* The 'port' variable is a string because it's easier
140                    this way than if we pass NULL to getaddrinfo() and
141                    then try to fill in the numeric value into
142                    different types of returned sockaddr_in{6,}. */
143 #ifdef LIBPROXY_HDR
144                 if (vpninfo->proxy_factory) {
145                         char *url;
146                         char **proxies;
147                         int i = 0;
148
149                         free(vpninfo->proxy_type);
150                         vpninfo->proxy_type = NULL;
151                         free(vpninfo->proxy);
152                         vpninfo->proxy = NULL;
153
154                         if (vpninfo->port == 443)
155                                 i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
156                                              vpninfo->urlpath?:"");
157                         else
158                                 i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
159                                              vpninfo->port, vpninfo->urlpath?:"");
160                         if (i == -1)
161                                 return -ENOMEM;
162
163                         proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
164                                                                url);
165
166                         i = 0;
167                         while (proxies && proxies[i]) {
168                                 if (!vpninfo->proxy &&
169                                     (!strncmp(proxies[i], "http://", 7) ||
170                                      !strncmp(proxies[i], "socks://", 8) ||
171                                      !strncmp(proxies[i], "socks5://", 9)))
172                                         internal_parse_url(proxies[i], &vpninfo->proxy_type,
173                                                   &vpninfo->proxy, &vpninfo->proxy_port,
174                                                   NULL, 0);
175                                 i++;
176                         }
177                         free(url);
178                         free(proxies);
179                         if (vpninfo->proxy)
180                                 vpn_progress(vpninfo, PRG_TRACE,
181                                              _("Proxy from libproxy: %s://%s:%d/\n"),
182                                              vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
183                 }
184 #endif
185                 if (vpninfo->proxy) {
186                         hostname = vpninfo->proxy;
187                         snprintf(port, 6, "%d", vpninfo->proxy_port);
188                 } else {
189                         hostname = vpninfo->hostname;
190                         snprintf(port, 6, "%d", vpninfo->port);
191                 }
192
193                 if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
194                         /* Solaris has no strndup(). */
195                         int len = strlen(hostname) - 2;
196                         char *new_hostname = malloc(len + 1);
197                         if (!new_hostname)
198                                 return -ENOMEM;
199                         memcpy(new_hostname, hostname + 1, len);
200                         new_hostname[len] = 0;
201
202                         hostname = new_hostname;
203                         hints.ai_flags |= AI_NUMERICHOST;
204                 }
205
206                 err = getaddrinfo(hostname, port, &hints, &result);
207                 if (hints.ai_flags & AI_NUMERICHOST)
208                         free(hostname);
209
210                 if (err) {
211                         vpn_progress(vpninfo, PRG_ERR,
212                                      _("getaddrinfo failed for host '%s': %s\n"),
213                                      hostname, gai_strerror(err));
214                         return -EINVAL;
215                 }
216
217                 for (rp = result; rp ; rp = rp->ai_next) {
218                         char host[80];
219
220                         if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
221                                          sizeof(host), NULL, 0, NI_NUMERICHOST))
222                                 vpn_progress(vpninfo, PRG_INFO, vpninfo->proxy_type?
223                                                      _("Attempting to connect to proxy %s%s%s:%s\n"):
224                                                      _("Attempting to connect to server %s%s%s:%s\n"),
225                                              rp->ai_family == AF_INET6?"[":"",
226                                              host,
227                                              rp->ai_family == AF_INET6?"]":"",
228                                              port);
229
230                         ssl_sock = socket(rp->ai_family, rp->ai_socktype,
231                                           rp->ai_protocol);
232                         if (ssl_sock < 0)
233                                 continue;
234                         if (cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
235                                 /* Store the peer address we actually used, so that DTLS can
236                                    use it again later */
237                                 vpninfo->peer_addr = malloc(rp->ai_addrlen);
238                                 if (!vpninfo->peer_addr) {
239                                         vpn_progress(vpninfo, PRG_ERR,
240                                                      _("Failed to allocate sockaddr storage\n"));
241                                         close(ssl_sock);
242                                         return -ENOMEM;
243                                 }
244                                 vpninfo->peer_addrlen = rp->ai_addrlen;
245                                 memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
246                                 break;
247                         }
248                         close(ssl_sock);
249                         ssl_sock = -1;
250                 }
251                 freeaddrinfo(result);
252                 
253                 if (ssl_sock < 0) {
254                         vpn_progress(vpninfo, PRG_ERR,
255                                      _("Failed to connect to host %s\n"),
256                                      vpninfo->proxy?:vpninfo->hostname);
257                         return -EINVAL;
258                 }
259         }
260
261         if (vpninfo->proxy) {
262                 err = process_proxy(vpninfo, ssl_sock);
263                 if (err) {
264                         close(ssl_sock);
265                         return err;
266                 }
267         }
268
269         return ssl_sock;
270 }
271
272 int  __attribute__ ((format (printf, 2, 3)))
273     openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...)
274 {
275         char buf[1024];
276         va_list args;
277
278         buf[1023] = 0;
279
280         va_start(args, fmt);
281         vsnprintf(buf, 1023, fmt, args);
282         va_end(args);
283         return openconnect_SSL_write(vpninfo, buf, strlen(buf));
284
285 }
286
287 int request_passphrase(struct openconnect_info *vpninfo, const char *label,
288                        char **response, const char *fmt, ...)
289 {
290         struct oc_auth_form f;
291         struct oc_form_opt o;
292         char buf[1024];
293         va_list args;
294         int ret;
295
296         if (!vpninfo->process_auth_form)
297                 return -EINVAL;
298
299         buf[1023] = 0;
300         memset(&f, 0, sizeof(f));
301         va_start(args, fmt);
302         vsnprintf(buf, 1023, fmt, args);
303         va_end(args);
304
305         f.auth_id = (char *)label;
306         f.opts = &o;
307
308         o.next = NULL;
309         o.type = OC_FORM_OPT_PASSWORD;
310         o.name = (char *)label;
311         o.label = buf;
312         o.value = NULL;
313
314         ret = vpninfo->process_auth_form(vpninfo->cbdata, &f);
315         if (!ret) {
316                 *response = o.value;
317                 return 0;
318         }
319
320         return -EIO;
321 }
322
323 #if defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
324 int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
325 {
326         struct statvfs buf;
327
328         if (statvfs(vpninfo->sslkey, &buf)) {
329                 int err = errno;
330                 vpn_progress(vpninfo, PRG_ERR, _("statvfs: %s\n"),
331                              strerror(errno));
332                 return -err;
333         }
334         if (asprintf(&vpninfo->cert_password, "%lx", buf.f_fsid))
335                 return -ENOMEM;
336         return 0;
337 }
338 #else
339 int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
340 {
341         struct statfs buf;
342         unsigned *fsid = (unsigned *)&buf.f_fsid;
343         unsigned long long fsid64;
344
345         if (statfs(vpninfo->sslkey, &buf)) {
346                 int err = errno;
347                 vpn_progress(vpninfo, PRG_ERR, _("statfs: %s\n"),
348                              strerror(errno));
349                 return -err;
350         }
351         fsid64 = ((unsigned long long)fsid[0] << 32) | fsid[1];
352
353         if (asprintf(&vpninfo->cert_password, "%llx", fsid64))
354                 return -ENOMEM;
355         return 0;
356 }
357 #endif
358
359 #if defined(OPENCONNECT_OPENSSL) || defined (DTLS_OPENSSL)
360 /* We put this here rather than in openssl.c because it might be needed
361    for OpenSSL DTLS support even when GnuTLS is being used for HTTPS */
362 int openconnect_print_err_cb(const char *str, size_t len, void *ptr)
363 {
364         struct openconnect_info *vpninfo = ptr;
365
366         vpn_progress(vpninfo, PRG_ERR, "%s", str);
367         return 0;
368 }
369 #endif
370
371 #ifdef FAKE_ANDROID_KEYSTORE
372 char *keystore_strerror(int err)
373 {
374         return (char *)strerror(-err);
375 }
376
377 int keystore_fetch(const char *key, unsigned char **result)
378 {
379         unsigned char *data;
380         struct stat st;
381         int fd;
382         int ret;
383
384         fd = open(key, O_RDONLY);
385         if (fd < 0)
386                 return -errno;
387
388         if (fstat(fd, &st)) {
389                 ret = -errno;
390                 goto out_fd;
391         }
392
393         data = malloc(st.st_size + 1);
394         if (!data) {
395                 ret = -ENOMEM;
396                 goto out_fd;
397         }
398
399         if (read(fd, data, st.st_size) != st.st_size) {
400                 ret = -EIO;
401                 free(data);
402                 goto out_fd;
403         }
404
405         data[st.st_size] = 0;
406         *result = data;
407         ret = st.st_size;
408  out_fd:
409         close(fd);
410         return ret;
411 }
412 #elif defined (ANDROID_KEYSTORE)
413 #include <cutils/sockets.h>
414 #include <keystore.h>
415 char *keystore_strerror(int err)
416 {
417         switch (-err) {
418         case NO_ERROR:          return _("No error");
419         case LOCKED:            return _("Keystore ocked");
420         case UNINITIALIZED:     return _("Keystore uninitialized");
421         case SYSTEM_ERROR:      return _("System error");
422         case PROTOCOL_ERROR:    return _("Protocol error");
423         case PERMISSION_DENIED: return _("Permission denied");
424         case KEY_NOT_FOUND:     return _("Key not found");
425         case VALUE_CORRUPTED:   return _("Value corrupted");
426         case UNDEFINED_ACTION:  return _("Undefined action");
427         case WRONG_PASSWORD_0:
428         case WRONG_PASSWORD_1:
429         case WRONG_PASSWORD_2:
430         case WRONG_PASSWORD_3:  return _("Wrong password");
431         default:                return _("Unknown error");
432         }
433 }
434
435 /* Returns length, or a negative errno in its own namespace (handled by its
436    own strerror function above). The numbers are from Android's keystore.h */
437 int keystore_fetch(const char *key, unsigned char **result)
438 {
439         unsigned char *data, *p;
440         unsigned char buf[3];
441         int len, fd, ofs;
442         int ret = -SYSTEM_ERROR;
443
444         fd = socket_local_client("keystore",
445                                  ANDROID_SOCKET_NAMESPACE_RESERVED,
446                                  SOCK_STREAM);
447         if (fd < 0)
448                 return -SYSTEM_ERROR;
449
450         len = strlen(key);
451         buf[0] = 'g';
452         buf[1] = len >> 8;
453         buf[2] = len & 0xff;
454
455         if (send(fd, buf, 3, 0) != 3 || send(fd, key, len, 0) != len ||
456             shutdown(fd, SHUT_WR) || recv(fd, buf, 1, 0) != 1)
457                 goto out;
458
459         if (buf[0] != NO_ERROR) {
460                 /* Should never be zero */
461                 ret = buf[0] ? -buf[0] : -PROTOCOL_ERROR;
462                 goto out;
463         }
464         if (recv(fd, buf, 2, 0) != 2)
465                 goto out;
466         len = (buf[0] << 8) + buf[1];
467         data = malloc(len);
468         if (!data)
469                 goto out;
470         p  = data;
471         ret = len;
472         while (len) {
473                 int got = recv(fd, p, len, 0);
474                 if (got <= 0) {
475                         free(data);
476                         ret = -PROTOCOL_ERROR;
477                         goto out;
478                 }
479                 len -= got;
480                 p += got;
481         }
482
483         *result = data;
484
485  out:
486         close(fd);
487         return ret;
488 }
489 #endif