Cope with lack of gnutls_certificate_set_key() in GnuTLS 2.12
[platform/upstream/openconnect.git] / library.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2012 Intel Corporation.
5  *
6  * Authors: 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 <string.h>
26 #include <errno.h>
27 #include <stdlib.h>
28
29 #include "openconnect-internal.h"
30
31 struct openconnect_info *openconnect_vpninfo_new (char *useragent,
32                                                   openconnect_validate_peer_cert_vfn validate_peer_cert,
33                                                   openconnect_write_new_config_vfn write_new_config,
34                                                   openconnect_process_auth_form_vfn process_auth_form,
35                                                   openconnect_progress_vfn progress,
36                                                   void *privdata)
37 {
38         struct openconnect_info *vpninfo = calloc (sizeof(*vpninfo), 1);
39
40         vpninfo->mtu = 1406;
41         vpninfo->ssl_fd = -1;
42         vpninfo->cert_expire_warning = 60 * 86400;
43         vpninfo->useragent = openconnect_create_useragent (useragent);
44         vpninfo->validate_peer_cert = validate_peer_cert;
45         vpninfo->write_new_config = write_new_config;
46         vpninfo->process_auth_form = process_auth_form;
47         vpninfo->progress = progress;
48         vpninfo->cbdata = privdata?:vpninfo;
49         vpninfo->cancel_fd = -1;
50
51 #ifdef ENABLE_NLS
52         bindtextdomain("openconnect", LOCALEDIR);
53 #endif
54
55         return vpninfo;
56 }
57
58 static void free_optlist (struct vpn_option *opt)
59 {
60         struct vpn_option *next;
61
62         for (; opt; opt = next) {
63                 next = opt->next;
64                 free(opt->option);
65                 free(opt->value);
66                 free(opt);
67         }
68 }
69
70 void openconnect_vpninfo_free (struct openconnect_info *vpninfo)
71 {
72         openconnect_reset_ssl(vpninfo);
73         free_optlist(vpninfo->cookies);
74         free_optlist(vpninfo->cstp_options);
75         free_optlist(vpninfo->dtls_options);
76         free(vpninfo->hostname);
77         free(vpninfo->urlpath);
78         free(vpninfo->redirect_url);
79         free(vpninfo->proxy_type);
80         free(vpninfo->proxy);
81         free(vpninfo->csd_scriptname);
82         free(vpninfo->csd_stuburl);
83         /* These are const in openconnect itself, but for consistency of
84            the library API we do take ownership of the strings we're given,
85            and thus we have to free them too. */
86         free((void *)vpninfo->cafile);
87         if (vpninfo->cert != vpninfo->sslkey)
88                 free((void *)vpninfo->sslkey);
89         free((void *)vpninfo->cert);
90         if (vpninfo->peer_cert) {
91 #if defined (OPENCONNECT_OPENSSL)
92                 X509_free(vpninfo->peer_cert);
93 #elif defined (OPENCONNECT_GNUTLS)
94                 gnutls_x509_crt_deinit(vpninfo->peer_cert);
95 #endif
96                 vpninfo->peer_cert = NULL;
97         }
98         free(vpninfo->useragent);
99         /* No need to free deflate streams; they weren't initialised */
100         free(vpninfo);
101 }
102
103 char *openconnect_get_hostname (struct openconnect_info *vpninfo)
104 {
105         return vpninfo->hostname;
106 }
107
108 void openconnect_set_hostname (struct openconnect_info *vpninfo, char *hostname)
109 {
110         vpninfo->hostname = hostname;
111 }
112
113 char *openconnect_get_urlpath (struct openconnect_info *vpninfo)
114 {
115         return vpninfo->urlpath;
116 }
117
118 void openconnect_set_urlpath (struct openconnect_info *vpninfo, char *urlpath)
119 {
120         vpninfo->urlpath = urlpath;
121 }
122
123 void openconnect_set_xmlsha1 (struct openconnect_info *vpninfo, const char *xmlsha1, int size)
124 {
125         if (size != sizeof (vpninfo->xmlsha1))
126                 return;
127
128         memcpy (&vpninfo->xmlsha1, xmlsha1, size);
129 }
130
131 void openconnect_set_cafile (struct openconnect_info *vpninfo, char *cafile)
132 {
133         vpninfo->cafile = cafile;
134 }
135
136 void openconnect_setup_csd (struct openconnect_info *vpninfo, uid_t uid, int silent, char *wrapper)
137 {
138         vpninfo->uid_csd = uid;
139         vpninfo->uid_csd_given = silent?2:1;
140         vpninfo->csd_wrapper = wrapper;
141 }
142
143 void openconnect_set_client_cert (struct openconnect_info *vpninfo, char *cert, char *sslkey)
144 {
145         vpninfo->cert = cert;
146         if (sslkey)
147                 vpninfo->sslkey = sslkey;
148         else
149                 vpninfo->sslkey = cert;
150 }
151
152 OPENCONNECT_X509 *openconnect_get_peer_cert (struct openconnect_info *vpninfo)
153 {
154         return vpninfo->peer_cert;
155 }
156
157 int openconnect_get_port (struct openconnect_info *vpninfo)
158 {
159         return vpninfo->port;
160 }
161
162 char *openconnect_get_cookie (struct openconnect_info *vpninfo)
163 {
164         return vpninfo->cookie;
165 }
166
167 void openconnect_clear_cookie (struct openconnect_info *vpninfo)
168 {
169         if (vpninfo->cookie)
170                 memset(vpninfo->cookie, 0, strlen(vpninfo->cookie));
171 }
172
173 void openconnect_reset_ssl (struct openconnect_info *vpninfo)
174 {
175         openconnect_close_https(vpninfo, 1);
176         if (vpninfo->peer_addr) {
177                 free(vpninfo->peer_addr);
178                 vpninfo->peer_addr = NULL;
179         }
180 }
181
182 int openconnect_parse_url (struct openconnect_info *vpninfo, char *url)
183 {
184         char *scheme = NULL;
185         int ret;
186
187         if (vpninfo->peer_addr) {
188                 free(vpninfo->peer_addr);
189                 vpninfo->peer_addr = NULL;
190         }
191
192         free(vpninfo->hostname);
193         vpninfo->hostname = NULL;
194         free(vpninfo->urlpath);
195         vpninfo->urlpath = NULL;
196
197         ret = internal_parse_url (url, &scheme, &vpninfo->hostname,
198                                   &vpninfo->port, &vpninfo->urlpath, 443);
199
200         if (ret) {
201                 vpn_progress(vpninfo, PRG_ERR,
202                              _("Failed to parse server URL '%s'\n"),
203                              url);
204                 return ret;
205         }
206         if (scheme && strcmp(scheme, "https")) {
207                 vpn_progress(vpninfo, PRG_ERR,
208                              _("Only https:// permitted for server URL\n"));
209                 ret = -EINVAL;
210         }
211         free(scheme);
212         return ret;
213 }
214
215 void openconnect_set_cert_expiry_warning (struct openconnect_info *vpninfo,
216                                           int seconds)
217 {
218         vpninfo->cert_expire_warning = seconds;
219 }
220
221 void openconnect_set_cancel_fd (struct openconnect_info *vpninfo, int fd)
222 {
223         vpninfo->cancel_fd = fd;
224 }
225
226 const char *openconnect_get_version (void)
227 {
228         return openconnect_version_str;
229 }
230
231 int openconnect_has_pkcs11_support(void)
232 {
233 #if defined (OPENCONNECT_GNUTLS) && defined (HAVE_P11KIT)
234         return 1;
235 #else
236         return 0;
237 #endif
238 }
239
240 #if defined (OPENCONNECT_OPENSSL) && defined (HAVE_ENGINE)
241 #include <openssl/engine.h>
242 #endif
243 int openconnect_has_tss_blob_support(void)
244 {
245 #if defined (OPENCONNECT_OPENSSL) && defined (HAVE_ENGINE)
246         ENGINE *e;
247
248         ENGINE_load_builtin_engines();
249
250         e = ENGINE_by_id("tpm");
251         if (e) {
252                 ENGINE_free(e);
253                 return 1;
254         }
255 #elif defined (OPENCONNECT_GNUTLS) && defined (HAVE_TROUSERS)
256         return 1;
257 #endif
258         return 0;
259 }