Introduce semi-opaque OPENCONNECT_X509 type in library API
[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_with_cbdata (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 struct openconnect_info *openconnect_vpninfo_new (char *useragent,
59                                                   openconnect_validate_peer_cert_fn validate_peer_cert,
60                                                   openconnect_write_new_config_fn write_new_config,
61                                                   openconnect_process_auth_form_fn process_auth_form,
62                                                   openconnect_progress_fn progress)
63 {
64         return openconnect_vpninfo_new_with_cbdata (useragent,
65                                                     (void *)validate_peer_cert,
66                                                     (void *)write_new_config,
67                                                     (void *)process_auth_form,
68                                                     (void *)progress, NULL);
69 }
70
71 static void free_optlist (struct vpn_option *opt)
72 {
73         struct vpn_option *next;
74
75         for (; opt; opt = next) {
76                 next = opt->next;
77                 free(opt->option);
78                 free(opt->value);
79                 free(opt);
80         }
81 }
82
83 void openconnect_vpninfo_free (struct openconnect_info *vpninfo)
84 {
85         openconnect_reset_ssl(vpninfo);
86         free_optlist(vpninfo->cookies);
87         free_optlist(vpninfo->cstp_options);
88         free_optlist(vpninfo->dtls_options);
89         free(vpninfo->hostname);
90         free(vpninfo->urlpath);
91         free(vpninfo->redirect_url);
92         free(vpninfo->proxy_type);
93         free(vpninfo->proxy);
94         free(vpninfo->csd_scriptname);
95         free(vpninfo->csd_stuburl);
96         /* These are const in openconnect itself, but for consistency of
97            the library API we do take ownership of the strings we're given,
98            and thus we have to free them too. */
99         free((void *)vpninfo->cafile);
100         if (vpninfo->cert != vpninfo->sslkey)
101                 free((void *)vpninfo->sslkey);
102         free((void *)vpninfo->cert);
103         if (vpninfo->peer_cert)
104                 X509_free(vpninfo->peer_cert);
105         /* No need to free deflate streams; they weren't initialised */
106         free(vpninfo);
107 }
108
109 char *openconnect_get_hostname (struct openconnect_info *vpninfo)
110 {
111         return vpninfo->hostname;
112 }
113
114 void openconnect_set_hostname (struct openconnect_info *vpninfo, char *hostname)
115 {
116         vpninfo->hostname = hostname;
117 }
118
119 char *openconnect_get_urlpath (struct openconnect_info *vpninfo)
120 {
121         return vpninfo->urlpath;
122 }
123
124 void openconnect_set_urlpath (struct openconnect_info *vpninfo, char *urlpath)
125 {
126         vpninfo->urlpath = urlpath;
127 }
128
129 void openconnect_set_xmlsha1 (struct openconnect_info *vpninfo, char *xmlsha1, int size)
130 {
131         if (size != sizeof (vpninfo->xmlsha1))
132                 return;
133
134         memcpy (&vpninfo->xmlsha1, xmlsha1, size);
135 }
136
137 void openconnect_set_cafile (struct openconnect_info *vpninfo, char *cafile)
138 {
139         vpninfo->cafile = cafile;
140 }
141
142 void openconnect_setup_csd (struct openconnect_info *vpninfo, uid_t uid, int silent, char *wrapper)
143 {
144         vpninfo->uid_csd = uid;
145         vpninfo->uid_csd_given = silent?2:1;
146         vpninfo->csd_wrapper = wrapper;
147 }
148
149 void openconnect_set_client_cert (struct openconnect_info *vpninfo, char *cert, char *sslkey)
150 {
151         vpninfo->cert = cert;
152         if (sslkey)
153                 vpninfo->sslkey = sslkey;
154         else
155                 vpninfo->sslkey = cert;
156 }
157
158 OPENCONNECT_X509 *openconnect_get_peer_cert (struct openconnect_info *vpninfo)
159 {
160         return vpninfo->peer_cert;
161 }
162
163 int openconnect_get_port (struct openconnect_info *vpninfo)
164 {
165         return vpninfo->port;
166 }
167
168 char *openconnect_get_cookie (struct openconnect_info *vpninfo)
169 {
170         return vpninfo->cookie;
171 }
172
173 void openconnect_clear_cookie (struct openconnect_info *vpninfo)
174 {
175         if (vpninfo->cookie)
176                 memset(vpninfo->cookie, 0, strlen(vpninfo->cookie));
177 }
178
179 void openconnect_reset_ssl (struct openconnect_info *vpninfo)
180 {
181         openconnect_close_https(vpninfo);
182         if (vpninfo->peer_addr) {
183                 free(vpninfo->peer_addr);
184                 vpninfo->peer_addr = NULL;
185         }
186         if (vpninfo->https_ctx) {
187                 SSL_CTX_free(vpninfo->https_ctx);
188                 vpninfo->https_ctx = NULL;
189         }
190 }
191
192 int openconnect_parse_url (struct openconnect_info *vpninfo, char *url)
193 {
194         char *scheme = NULL;
195         int ret;
196
197         if (vpninfo->peer_addr) {
198                 free(vpninfo->peer_addr);
199                 vpninfo->peer_addr = NULL;
200         }
201
202         free(vpninfo->hostname);
203         vpninfo->hostname = NULL;
204         free(vpninfo->urlpath);
205         vpninfo->urlpath = NULL;
206
207         ret = internal_parse_url (url, &scheme, &vpninfo->hostname,
208                                   &vpninfo->port, &vpninfo->urlpath, 443);
209
210         if (ret) {
211                 vpn_progress(vpninfo, PRG_ERR,
212                              _("Failed to parse server URL '%s'\n"),
213                              url);
214                 return ret;
215         }
216         if (scheme && strcmp(scheme, "https")) {
217                 vpn_progress(vpninfo, PRG_ERR,
218                              _("Only https:// permitted for server URL\n"));
219                 ret = -EINVAL;
220         }
221         free(scheme);
222         return ret;
223 }
224
225 void openconnect_set_cert_expiry_warning (struct openconnect_info *vpninfo,
226                                           int seconds)
227 {
228         vpninfo->cert_expire_warning = seconds;
229 }
230
231 void openconnect_set_cancel_fd (struct openconnect_info *vpninfo, int fd)
232 {
233         vpninfo->cancel_fd = fd;
234 }
235
236 const char *openconnect_get_version (void)
237 {
238         return openconnect_version_str;
239 }