resetting manifest requested domain to floor
[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                         if (ssl_sock >= 0)
123                                 close(ssl_sock);
124                         return -EINVAL;
125                 }
126         } else {
127                 struct addrinfo hints, *result, *rp;
128                 char *hostname;
129                 char port[6];
130
131                 memset(&hints, 0, sizeof(struct addrinfo));
132                 hints.ai_family = AF_UNSPEC;
133                 hints.ai_socktype = SOCK_STREAM;
134                 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
135                 hints.ai_protocol = 0;
136                 hints.ai_canonname = NULL;
137                 hints.ai_addr = NULL;
138                 hints.ai_next = NULL;
139
140                 /* The 'port' variable is a string because it's easier
141                    this way than if we pass NULL to getaddrinfo() and
142                    then try to fill in the numeric value into
143                    different types of returned sockaddr_in{6,}. */
144 #ifdef LIBPROXY_HDR
145                 if (vpninfo->proxy_factory) {
146                         char *url;
147                         char **proxies;
148                         int i = 0;
149
150                         free(vpninfo->proxy_type);
151                         vpninfo->proxy_type = NULL;
152                         free(vpninfo->proxy);
153                         vpninfo->proxy = NULL;
154
155                         if (vpninfo->port == 443)
156                                 i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
157                                              vpninfo->urlpath?:"");
158                         else
159                                 i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
160                                              vpninfo->port, vpninfo->urlpath?:"");
161                         if (i == -1)
162                                 return -ENOMEM;
163
164                         proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
165                                                                url);
166
167                         i = 0;
168                         while (proxies && proxies[i]) {
169                                 if (!vpninfo->proxy &&
170                                     (!strncmp(proxies[i], "http://", 7) ||
171                                      !strncmp(proxies[i], "socks://", 8) ||
172                                      !strncmp(proxies[i], "socks5://", 9)))
173                                         internal_parse_url(proxies[i], &vpninfo->proxy_type,
174                                                   &vpninfo->proxy, &vpninfo->proxy_port,
175                                                   NULL, 0);
176                                 i++;
177                         }
178                         free(url);
179                         free(proxies);
180                         if (vpninfo->proxy)
181                                 vpn_progress(vpninfo, PRG_TRACE,
182                                              _("Proxy from libproxy: %s://%s:%d/\n"),
183                                              vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
184                 }
185 #endif
186                 if (vpninfo->proxy) {
187                         hostname = vpninfo->proxy;
188                         snprintf(port, 6, "%d", vpninfo->proxy_port);
189                 } else {
190                         hostname = vpninfo->hostname;
191                         snprintf(port, 6, "%d", vpninfo->port);
192                 }
193
194                 if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
195                         /* Solaris has no strndup(). */
196                         int len = strlen(hostname) - 2;
197                         char *new_hostname = malloc(len + 1);
198                         if (!new_hostname)
199                                 return -ENOMEM;
200                         memcpy(new_hostname, hostname + 1, len);
201                         new_hostname[len] = 0;
202
203                         hostname = new_hostname;
204                         hints.ai_flags |= AI_NUMERICHOST;
205                 }
206
207                 err = getaddrinfo(hostname, port, &hints, &result);
208
209                 if (err) {
210                         vpn_progress(vpninfo, PRG_ERR,
211                                      _("getaddrinfo failed for host '%s': %s\n"),
212                                      hostname, gai_strerror(err));
213                         if (hints.ai_flags & AI_NUMERICHOST)
214                                 free(hostname);
215                         return -EINVAL;
216                 }
217                 if (hints.ai_flags & AI_NUMERICHOST)
218                         free(hostname);
219
220                 for (rp = result; rp ; rp = rp->ai_next) {
221                         char host[80];
222
223                         host[0] = 0;
224                         if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
225                                          sizeof(host), NULL, 0, NI_NUMERICHOST))
226                                 vpn_progress(vpninfo, PRG_INFO, vpninfo->proxy_type?
227                                                      _("Attempting to connect to proxy %s%s%s:%s\n"):
228                                                      _("Attempting to connect to server %s%s%s:%s\n"),
229                                              rp->ai_family == AF_INET6?"[":"",
230                                              host,
231                                              rp->ai_family == AF_INET6?"]":"",
232                                              port);
233
234                         ssl_sock = socket(rp->ai_family, rp->ai_socktype,
235                                           rp->ai_protocol);
236                         if (ssl_sock < 0)
237                                 continue;
238                         if (cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
239                                 /* Store the peer address we actually used, so that DTLS can
240                                    use it again later */
241                                 vpninfo->peer_addr = malloc(rp->ai_addrlen);
242                                 if (!vpninfo->peer_addr) {
243                                         vpn_progress(vpninfo, PRG_ERR,
244                                                      _("Failed to allocate sockaddr storage\n"));
245                                         close(ssl_sock);
246                                         return -ENOMEM;
247                                 }
248                                 vpninfo->peer_addrlen = rp->ai_addrlen;
249                                 memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
250                                 /* If no proxy, and if more than one address for the hostname,
251                                    ensure that we output the same IP address in authentication
252                                    results (from libopenconnect or --authenticate). */
253                                 if (!vpninfo->proxy && (rp != result || rp->ai_next) && host[0]) {
254                                         char *p = malloc(strlen(host) + 3);
255                                         if (p) {
256                                                 free(vpninfo->hostname);
257                                                 vpninfo->hostname = p;
258                                                 if (rp->ai_family == AF_INET6)
259                                                         *p++ = '[';
260                                                 memcpy(p, host, strlen(host));
261                                                 p += strlen(host);
262                                                 if (rp->ai_family == AF_INET6)
263                                                         *p++ = ']';
264                                                 *p = 0;
265                                         }
266                                 }
267                                 break;
268                         }
269                         close(ssl_sock);
270                         ssl_sock = -1;
271                 }
272                 freeaddrinfo(result);
273                 
274                 if (ssl_sock < 0) {
275                         vpn_progress(vpninfo, PRG_ERR,
276                                      _("Failed to connect to host %s\n"),
277                                      vpninfo->proxy?:vpninfo->hostname);
278                         return -EINVAL;
279                 }
280         }
281
282         if (vpninfo->proxy) {
283                 err = process_proxy(vpninfo, ssl_sock);
284                 if (err) {
285                         close(ssl_sock);
286                         return err;
287                 }
288         }
289
290         return ssl_sock;
291 }
292
293 int  __attribute__ ((format (printf, 2, 3)))
294     openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...)
295 {
296         char buf[1024];
297         va_list args;
298
299         buf[1023] = 0;
300
301         va_start(args, fmt);
302         vsnprintf(buf, 1023, fmt, args);
303         va_end(args);
304         return openconnect_SSL_write(vpninfo, buf, strlen(buf));
305
306 }
307
308 int request_passphrase(struct openconnect_info *vpninfo, const char *label,
309                        char **response, const char *fmt, ...)
310 {
311         struct oc_auth_form f;
312         struct oc_form_opt o;
313         char buf[1024];
314         va_list args;
315         int ret;
316
317         if (!vpninfo->process_auth_form)
318                 return -EINVAL;
319
320         buf[1023] = 0;
321         memset(&f, 0, sizeof(f));
322         va_start(args, fmt);
323         vsnprintf(buf, 1023, fmt, args);
324         va_end(args);
325
326         f.auth_id = (char *)label;
327         f.opts = &o;
328
329         o.next = NULL;
330         o.type = OC_FORM_OPT_PASSWORD;
331         o.name = (char *)label;
332         o.label = buf;
333         o.value = NULL;
334
335         ret = vpninfo->process_auth_form(vpninfo->cbdata, &f);
336         if (!ret) {
337                 *response = o.value;
338                 return 0;
339         }
340
341         return -EIO;
342 }
343
344 #if defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
345 int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
346 {
347         struct statvfs buf;
348
349         if (statvfs(vpninfo->sslkey, &buf)) {
350                 int err = errno;
351                 vpn_progress(vpninfo, PRG_ERR, _("statvfs: %s\n"),
352                              strerror(errno));
353                 return -err;
354         }
355         if (asprintf(&vpninfo->cert_password, "%lx", buf.f_fsid))
356                 return -ENOMEM;
357         return 0;
358 }
359 #else
360 int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
361 {
362         struct statfs buf;
363         unsigned *fsid = (unsigned *)&buf.f_fsid;
364         unsigned long long fsid64;
365
366         if (statfs(vpninfo->sslkey, &buf)) {
367                 int err = errno;
368                 vpn_progress(vpninfo, PRG_ERR, _("statfs: %s\n"),
369                              strerror(errno));
370                 return -err;
371         }
372         fsid64 = ((unsigned long long)fsid[0] << 32) | fsid[1];
373
374         if (asprintf(&vpninfo->cert_password, "%llx", fsid64))
375                 return -ENOMEM;
376         return 0;
377 }
378 #endif
379
380 #if defined(OPENCONNECT_OPENSSL) || defined (DTLS_OPENSSL)
381 /* We put this here rather than in openssl.c because it might be needed
382    for OpenSSL DTLS support even when GnuTLS is being used for HTTPS */
383 int openconnect_print_err_cb(const char *str, size_t len, void *ptr)
384 {
385         struct openconnect_info *vpninfo = ptr;
386
387         vpn_progress(vpninfo, PRG_ERR, "%s", str);
388         return 0;
389 }
390 #endif
391
392 #ifdef FAKE_ANDROID_KEYSTORE
393 char *keystore_strerror(int err)
394 {
395         return (char *)strerror(-err);
396 }
397
398 int keystore_fetch(const char *key, unsigned char **result)
399 {
400         unsigned char *data;
401         struct stat st;
402         int fd;
403         int ret;
404
405         fd = open(key, O_RDONLY);
406         if (fd < 0)
407                 return -errno;
408
409         if (fstat(fd, &st)) {
410                 ret = -errno;
411                 goto out_fd;
412         }
413
414         data = malloc(st.st_size + 1);
415         if (!data) {
416                 ret = -ENOMEM;
417                 goto out_fd;
418         }
419
420         if (read(fd, data, st.st_size) != st.st_size) {
421                 ret = -EIO;
422                 free(data);
423                 goto out_fd;
424         }
425
426         data[st.st_size] = 0;
427         *result = data;
428         ret = st.st_size;
429  out_fd:
430         close(fd);
431         return ret;
432 }
433 #elif defined (ANDROID_KEYSTORE)
434 #include <cutils/sockets.h>
435 #include <keystore.h>
436 char *keystore_strerror(int err)
437 {
438         switch (-err) {
439         case NO_ERROR:          return _("No error");
440         case LOCKED:            return _("Keystore locked");
441         case UNINITIALIZED:     return _("Keystore uninitialized");
442         case SYSTEM_ERROR:      return _("System error");
443         case PROTOCOL_ERROR:    return _("Protocol error");
444         case PERMISSION_DENIED: return _("Permission denied");
445         case KEY_NOT_FOUND:     return _("Key not found");
446         case VALUE_CORRUPTED:   return _("Value corrupted");
447         case UNDEFINED_ACTION:  return _("Undefined action");
448         case WRONG_PASSWORD_0:
449         case WRONG_PASSWORD_1:
450         case WRONG_PASSWORD_2:
451         case WRONG_PASSWORD_3:  return _("Wrong password");
452         default:                return _("Unknown error");
453         }
454 }
455
456 /* Returns length, or a negative errno in its own namespace (handled by its
457    own strerror function above). The numbers are from Android's keystore.h */
458 int keystore_fetch(const char *key, unsigned char **result)
459 {
460         unsigned char *data, *p;
461         unsigned char buf[3];
462         int len, fd, ofs;
463         int ret = -SYSTEM_ERROR;
464
465         fd = socket_local_client("keystore",
466                                  ANDROID_SOCKET_NAMESPACE_RESERVED,
467                                  SOCK_STREAM);
468         if (fd < 0)
469                 return -SYSTEM_ERROR;
470
471         len = strlen(key);
472         buf[0] = 'g';
473         buf[1] = len >> 8;
474         buf[2] = len & 0xff;
475
476         if (send(fd, buf, 3, 0) != 3 || send(fd, key, len, 0) != len ||
477             shutdown(fd, SHUT_WR) || recv(fd, buf, 1, 0) != 1)
478                 goto out;
479
480         if (buf[0] != NO_ERROR) {
481                 /* Should never be zero */
482                 ret = buf[0] ? -buf[0] : -PROTOCOL_ERROR;
483                 goto out;
484         }
485         if (recv(fd, buf, 2, 0) != 2)
486                 goto out;
487         len = (buf[0] << 8) + buf[1];
488         data = malloc(len);
489         if (!data)
490                 goto out;
491         p  = data;
492         ret = len;
493         while (len) {
494                 int got = recv(fd, p, len, 0);
495                 if (got <= 0) {
496                         free(data);
497                         ret = -PROTOCOL_ERROR;
498                         goto out;
499                 }
500                 len -= got;
501                 p += got;
502         }
503
504         *result = data;
505
506  out:
507         close(fd);
508         return ret;
509 }
510 #endif