92b7c25350922aa19284e840dfba69a2e4788d88
[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         /* No need to free deflate streams; they weren't initialised */
99         free(vpninfo);
100 }
101
102 char *openconnect_get_hostname (struct openconnect_info *vpninfo)
103 {
104         return vpninfo->hostname;
105 }
106
107 void openconnect_set_hostname (struct openconnect_info *vpninfo, char *hostname)
108 {
109         vpninfo->hostname = hostname;
110 }
111
112 char *openconnect_get_urlpath (struct openconnect_info *vpninfo)
113 {
114         return vpninfo->urlpath;
115 }
116
117 void openconnect_set_urlpath (struct openconnect_info *vpninfo, char *urlpath)
118 {
119         vpninfo->urlpath = urlpath;
120 }
121
122 void openconnect_set_xmlsha1 (struct openconnect_info *vpninfo, const char *xmlsha1, int size)
123 {
124         if (size != sizeof (vpninfo->xmlsha1))
125                 return;
126
127         memcpy (&vpninfo->xmlsha1, xmlsha1, size);
128 }
129
130 void openconnect_set_cafile (struct openconnect_info *vpninfo, char *cafile)
131 {
132         vpninfo->cafile = cafile;
133 }
134
135 void openconnect_setup_csd (struct openconnect_info *vpninfo, uid_t uid, int silent, char *wrapper)
136 {
137         vpninfo->uid_csd = uid;
138         vpninfo->uid_csd_given = silent?2:1;
139         vpninfo->csd_wrapper = wrapper;
140 }
141
142 void openconnect_set_client_cert (struct openconnect_info *vpninfo, char *cert, char *sslkey)
143 {
144         vpninfo->cert = cert;
145         if (sslkey)
146                 vpninfo->sslkey = sslkey;
147         else
148                 vpninfo->sslkey = cert;
149 }
150
151 OPENCONNECT_X509 *openconnect_get_peer_cert (struct openconnect_info *vpninfo)
152 {
153         return vpninfo->peer_cert;
154 }
155
156 int openconnect_get_port (struct openconnect_info *vpninfo)
157 {
158         return vpninfo->port;
159 }
160
161 char *openconnect_get_cookie (struct openconnect_info *vpninfo)
162 {
163         return vpninfo->cookie;
164 }
165
166 void openconnect_clear_cookie (struct openconnect_info *vpninfo)
167 {
168         if (vpninfo->cookie)
169                 memset(vpninfo->cookie, 0, strlen(vpninfo->cookie));
170 }
171
172 void openconnect_reset_ssl (struct openconnect_info *vpninfo)
173 {
174         openconnect_close_https(vpninfo, 1);
175         if (vpninfo->peer_addr) {
176                 free(vpninfo->peer_addr);
177                 vpninfo->peer_addr = NULL;
178         }
179 }
180
181 int openconnect_parse_url (struct openconnect_info *vpninfo, char *url)
182 {
183         char *scheme = NULL;
184         int ret;
185
186         if (vpninfo->peer_addr) {
187                 free(vpninfo->peer_addr);
188                 vpninfo->peer_addr = NULL;
189         }
190
191         free(vpninfo->hostname);
192         vpninfo->hostname = NULL;
193         free(vpninfo->urlpath);
194         vpninfo->urlpath = NULL;
195
196         ret = internal_parse_url (url, &scheme, &vpninfo->hostname,
197                                   &vpninfo->port, &vpninfo->urlpath, 443);
198
199         if (ret) {
200                 vpn_progress(vpninfo, PRG_ERR,
201                              _("Failed to parse server URL '%s'\n"),
202                              url);
203                 return ret;
204         }
205         if (scheme && strcmp(scheme, "https")) {
206                 vpn_progress(vpninfo, PRG_ERR,
207                              _("Only https:// permitted for server URL\n"));
208                 ret = -EINVAL;
209         }
210         free(scheme);
211         return ret;
212 }
213
214 void openconnect_set_cert_expiry_warning (struct openconnect_info *vpninfo,
215                                           int seconds)
216 {
217         vpninfo->cert_expire_warning = seconds;
218 }
219
220 void openconnect_set_cancel_fd (struct openconnect_info *vpninfo, int fd)
221 {
222         vpninfo->cancel_fd = fd;
223 }
224
225 const char *openconnect_get_version (void)
226 {
227         return openconnect_version_str;
228 }