auth: Move <auth> node parsing into a separate function
[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 #ifdef LIBSTOKEN_HDR
30 #include LIBSTOKEN_HDR
31 #endif
32
33 #include "openconnect-internal.h"
34
35 struct openconnect_info *openconnect_vpninfo_new (char *useragent,
36                                                   openconnect_validate_peer_cert_vfn validate_peer_cert,
37                                                   openconnect_write_new_config_vfn write_new_config,
38                                                   openconnect_process_auth_form_vfn process_auth_form,
39                                                   openconnect_progress_vfn progress,
40                                                   void *privdata)
41 {
42         struct openconnect_info *vpninfo = calloc (sizeof(*vpninfo), 1);
43
44         vpninfo->ssl_fd = -1;
45         vpninfo->cert_expire_warning = 60 * 86400;
46         vpninfo->useragent = openconnect_create_useragent (useragent);
47         vpninfo->validate_peer_cert = validate_peer_cert;
48         vpninfo->write_new_config = write_new_config;
49         vpninfo->process_auth_form = process_auth_form;
50         vpninfo->progress = progress;
51         vpninfo->cbdata = privdata?:vpninfo;
52         vpninfo->cancel_fd = -1;
53 #ifdef __APPLE__
54         vpninfo->csd_xmltag = "csdMac";
55 #else
56         vpninfo->csd_xmltag = "csdLinux";
57 #endif
58
59 #ifdef ENABLE_NLS
60         bindtextdomain("openconnect", LOCALEDIR);
61 #endif
62
63         return vpninfo;
64 }
65
66 static void free_optlist (struct vpn_option *opt)
67 {
68         struct vpn_option *next;
69
70         for (; opt; opt = next) {
71                 next = opt->next;
72                 free(opt->option);
73                 free(opt->value);
74                 free(opt);
75         }
76 }
77
78 void openconnect_vpninfo_free (struct openconnect_info *vpninfo)
79 {
80         openconnect_close_https(vpninfo, 1);
81         free(vpninfo->peer_addr);
82         free_optlist(vpninfo->cookies);
83         free_optlist(vpninfo->cstp_options);
84         free_optlist(vpninfo->dtls_options);
85         free(vpninfo->hostname);
86         free(vpninfo->urlpath);
87         free(vpninfo->redirect_url);
88         free(vpninfo->proxy_type);
89         free(vpninfo->proxy);
90         if (vpninfo->csd_scriptname) {
91                 unlink(vpninfo->csd_scriptname);
92                 free(vpninfo->csd_scriptname);
93         }
94         free(vpninfo->csd_stuburl);
95         /* These are const in openconnect itself, but for consistency of
96            the library API we do take ownership of the strings we're given,
97            and thus we have to free them too. */
98         free((void *)vpninfo->cafile);
99         if (vpninfo->cert != vpninfo->sslkey)
100                 free((void *)vpninfo->sslkey);
101         free((void *)vpninfo->cert);
102         if (vpninfo->peer_cert) {
103 #if defined (OPENCONNECT_OPENSSL)
104                 X509_free(vpninfo->peer_cert);
105 #elif defined (OPENCONNECT_GNUTLS)
106                 gnutls_x509_crt_deinit(vpninfo->peer_cert);
107 #endif
108                 vpninfo->peer_cert = NULL;
109         }
110         free(vpninfo->useragent);
111 #ifdef LIBSTOKEN_HDR
112         if (vpninfo->stoken_pin)
113                 free(vpninfo->stoken_pin);
114         if (vpninfo->stoken_ctx)
115                 stoken_destroy(vpninfo->stoken_ctx);
116 #endif
117         /* No need to free deflate streams; they weren't initialised */
118         free(vpninfo);
119 }
120
121 char *openconnect_get_hostname (struct openconnect_info *vpninfo)
122 {
123         return vpninfo->hostname;
124 }
125
126 void openconnect_set_hostname (struct openconnect_info *vpninfo, char *hostname)
127 {
128         vpninfo->hostname = hostname;
129 }
130
131 char *openconnect_get_urlpath (struct openconnect_info *vpninfo)
132 {
133         return vpninfo->urlpath;
134 }
135
136 void openconnect_set_urlpath (struct openconnect_info *vpninfo, char *urlpath)
137 {
138         vpninfo->urlpath = urlpath;
139 }
140
141 void openconnect_set_xmlsha1 (struct openconnect_info *vpninfo, const char *xmlsha1, int size)
142 {
143         if (size != sizeof (vpninfo->xmlsha1))
144                 return;
145
146         memcpy (&vpninfo->xmlsha1, xmlsha1, size);
147 }
148
149 void openconnect_set_cafile (struct openconnect_info *vpninfo, char *cafile)
150 {
151         vpninfo->cafile = cafile;
152 }
153
154 void openconnect_setup_csd (struct openconnect_info *vpninfo, uid_t uid, int silent, char *wrapper)
155 {
156         vpninfo->uid_csd = uid;
157         vpninfo->uid_csd_given = silent?2:1;
158         vpninfo->csd_wrapper = wrapper;
159 }
160
161 void openconnect_set_client_cert (struct openconnect_info *vpninfo, char *cert, char *sslkey)
162 {
163         vpninfo->cert = cert;
164         if (sslkey)
165                 vpninfo->sslkey = sslkey;
166         else
167                 vpninfo->sslkey = cert;
168 }
169
170 OPENCONNECT_X509 *openconnect_get_peer_cert (struct openconnect_info *vpninfo)
171 {
172         return vpninfo->peer_cert;
173 }
174
175 int openconnect_get_port (struct openconnect_info *vpninfo)
176 {
177         return vpninfo->port;
178 }
179
180 char *openconnect_get_cookie (struct openconnect_info *vpninfo)
181 {
182         return vpninfo->cookie;
183 }
184
185 void openconnect_clear_cookie (struct openconnect_info *vpninfo)
186 {
187         if (vpninfo->cookie)
188                 memset(vpninfo->cookie, 0, strlen(vpninfo->cookie));
189 }
190
191 void openconnect_reset_ssl (struct openconnect_info *vpninfo)
192 {
193         openconnect_close_https(vpninfo, 0);
194         if (vpninfo->peer_addr) {
195                 free(vpninfo->peer_addr);
196                 vpninfo->peer_addr = NULL;
197         }
198 }
199
200 int openconnect_parse_url (struct openconnect_info *vpninfo, char *url)
201 {
202         char *scheme = NULL;
203         int ret;
204
205         if (vpninfo->peer_addr) {
206                 free(vpninfo->peer_addr);
207                 vpninfo->peer_addr = NULL;
208         }
209
210         free(vpninfo->hostname);
211         vpninfo->hostname = NULL;
212         free(vpninfo->urlpath);
213         vpninfo->urlpath = NULL;
214
215         ret = internal_parse_url (url, &scheme, &vpninfo->hostname,
216                                   &vpninfo->port, &vpninfo->urlpath, 443);
217
218         if (ret) {
219                 vpn_progress(vpninfo, PRG_ERR,
220                              _("Failed to parse server URL '%s'\n"),
221                              url);
222                 return ret;
223         }
224         if (scheme && strcmp(scheme, "https")) {
225                 vpn_progress(vpninfo, PRG_ERR,
226                              _("Only https:// permitted for server URL\n"));
227                 ret = -EINVAL;
228         }
229         free(scheme);
230         return ret;
231 }
232
233 void openconnect_set_cert_expiry_warning (struct openconnect_info *vpninfo,
234                                           int seconds)
235 {
236         vpninfo->cert_expire_warning = seconds;
237 }
238
239 void openconnect_set_cancel_fd (struct openconnect_info *vpninfo, int fd)
240 {
241         vpninfo->cancel_fd = fd;
242 }
243
244 const char *openconnect_get_version (void)
245 {
246         return openconnect_version_str;
247 }
248
249 int openconnect_has_pkcs11_support(void)
250 {
251 #if defined (OPENCONNECT_GNUTLS) && defined (HAVE_P11KIT)
252         return 1;
253 #else
254         return 0;
255 #endif
256 }
257
258 #if defined (OPENCONNECT_OPENSSL) && defined (HAVE_ENGINE)
259 #include <openssl/engine.h>
260 #endif
261 int openconnect_has_tss_blob_support(void)
262 {
263 #if defined (OPENCONNECT_OPENSSL) && defined (HAVE_ENGINE)
264         ENGINE *e;
265
266         ENGINE_load_builtin_engines();
267
268         e = ENGINE_by_id("tpm");
269         if (e) {
270                 ENGINE_free(e);
271                 return 1;
272         }
273 #elif defined (OPENCONNECT_GNUTLS) && defined (HAVE_TROUSERS)
274         return 1;
275 #endif
276         return 0;
277 }
278
279 int openconnect_has_stoken_support(void)
280 {
281 #ifdef LIBSTOKEN_HDR
282         return 1;
283 #else
284         return 0;
285 #endif
286 }
287
288 /*
289  * Enable software token generation if use_stoken == 1.
290  *
291  * If token_str is not NULL, try to parse the string.  Otherwise, try to read
292  * the token data from ~/.stokenrc
293  *
294  * Return value:
295  *  = -EOPNOTSUPP, if libstoken is not available
296  *  = -EINVAL, if the token string is invalid (token_str was provided)
297  *  = -ENOENT, if ~/.stokenrc is missing (token_str was NULL)
298  *  = -EIO, for other libstoken failures
299  *  = 0, on success
300  */
301 int openconnect_set_stoken_mode (struct openconnect_info *vpninfo,
302                                  int use_stoken, const char *token_str)
303 {
304 #ifdef LIBSTOKEN_HDR
305         int ret;
306
307         vpninfo->use_stoken = 0;
308         if (!use_stoken)
309                 return 0;
310
311         if (!vpninfo->stoken_ctx) {
312                 vpninfo->stoken_ctx = stoken_new();
313                 if (!vpninfo->stoken_ctx)
314                         return -EIO;
315         }
316
317         ret = token_str ?
318               stoken_import_string(vpninfo->stoken_ctx, token_str) :
319               stoken_import_rcfile(vpninfo->stoken_ctx, NULL);
320         if (ret)
321                 return ret;
322
323         vpninfo->use_stoken = 1;
324         return 0;
325 #else
326         return -EOPNOTSUPP;
327 #endif
328 }