library.c 6.22 KB
Newer Older
1 2 3
/*
 * OpenConnect (SSL + DTLS) VPN client
 *
David Woodhouse's avatar
David Woodhouse committed
4
 * Copyright © 2008-2012 Intel Corporation.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * Authors: David Woodhouse <dwmw2@infradead.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to:
 *
 *   Free Software Foundation, Inc.
 *   51 Franklin Street, Fifth Floor,
 *   Boston, MA 02110-1301 USA
 */

25
#include <string.h>
26
#include <errno.h>
27
#include <stdlib.h>
28

29 30
#include "openconnect-internal.h"

31
struct openconnect_info *openconnect_vpninfo_new (char *useragent,
32 33 34 35 36
						  openconnect_validate_peer_cert_vfn validate_peer_cert,
						  openconnect_write_new_config_vfn write_new_config,
						  openconnect_process_auth_form_vfn process_auth_form,
						  openconnect_progress_vfn progress,
						  void *privdata)
37 38 39 40 41
{
	struct openconnect_info *vpninfo = calloc (sizeof(*vpninfo), 1);

	vpninfo->mtu = 1406;
	vpninfo->ssl_fd = -1;
42
	vpninfo->cert_expire_warning = 60 * 86400;
43 44 45 46 47
	vpninfo->useragent = openconnect_create_useragent (useragent);
	vpninfo->validate_peer_cert = validate_peer_cert;
	vpninfo->write_new_config = write_new_config;
	vpninfo->process_auth_form = process_auth_form;
	vpninfo->progress = progress;
48
	vpninfo->cbdata = privdata?:vpninfo;
49
	vpninfo->cancel_fd = -1;
50

51 52 53 54
#ifdef ENABLE_NLS
	bindtextdomain("openconnect", LOCALEDIR);
#endif

55 56 57
	return vpninfo;
}

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
static void free_optlist (struct vpn_option *opt)
{
	struct vpn_option *next;

	for (; opt; opt = next) {
		next = opt->next;
		free(opt->option);
		free(opt->value);
		free(opt);
	}
}

void openconnect_vpninfo_free (struct openconnect_info *vpninfo)
{
	openconnect_reset_ssl(vpninfo);
	free_optlist(vpninfo->cookies);
	free_optlist(vpninfo->cstp_options);
	free_optlist(vpninfo->dtls_options);
	free(vpninfo->hostname);
	free(vpninfo->urlpath);
	free(vpninfo->redirect_url);
	free(vpninfo->proxy_type);
	free(vpninfo->proxy);
	free(vpninfo->csd_scriptname);
	free(vpninfo->csd_stuburl);
	/* These are const in openconnect itself, but for consistency of
	   the library API we do take ownership of the strings we're given,
	   and thus we have to free them too. */
	free((void *)vpninfo->cafile);
	if (vpninfo->cert != vpninfo->sslkey)
		free((void *)vpninfo->sslkey);
89
	free((void *)vpninfo->cert);
90 91
	if (vpninfo->peer_cert) {
#if defined (OPENCONNECT_OPENSSL)
92
		X509_free(vpninfo->peer_cert);
93 94 95 96 97
#elif defined (OPENCONNECT_GNUTLS)
		gnutls_x509_crt_deinit(vpninfo->peer_cert);
#endif
		vpninfo->peer_cert = NULL;
	}
David Woodhouse's avatar
David Woodhouse committed
98
	free(vpninfo->useragent);
99 100 101 102
	/* No need to free deflate streams; they weren't initialised */
	free(vpninfo);
}

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
char *openconnect_get_hostname (struct openconnect_info *vpninfo)
{
	return vpninfo->hostname;
}

void openconnect_set_hostname (struct openconnect_info *vpninfo, char *hostname)
{
	vpninfo->hostname = hostname;
}

char *openconnect_get_urlpath (struct openconnect_info *vpninfo)
{
	return vpninfo->urlpath;
}

void openconnect_set_urlpath (struct openconnect_info *vpninfo, char *urlpath)
{
	vpninfo->urlpath = urlpath;
}

123
void openconnect_set_xmlsha1 (struct openconnect_info *vpninfo, const char *xmlsha1, int size)
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
{
	if (size != sizeof (vpninfo->xmlsha1))
		return;

	memcpy (&vpninfo->xmlsha1, xmlsha1, size);
}

void openconnect_set_cafile (struct openconnect_info *vpninfo, char *cafile)
{
	vpninfo->cafile = cafile;
}

void openconnect_setup_csd (struct openconnect_info *vpninfo, uid_t uid, int silent, char *wrapper)
{
	vpninfo->uid_csd = uid;
	vpninfo->uid_csd_given = silent?2:1;
	vpninfo->csd_wrapper = wrapper;
}

void openconnect_set_client_cert (struct openconnect_info *vpninfo, char *cert, char *sslkey)
{
	vpninfo->cert = cert;
	if (sslkey)
		vpninfo->sslkey = sslkey;
	else
		vpninfo->sslkey = cert;
}

152
OPENCONNECT_X509 *openconnect_get_peer_cert (struct openconnect_info *vpninfo)
153
{
154
	return vpninfo->peer_cert;
155 156 157 158 159 160 161 162 163 164 165 166 167 168
}

int openconnect_get_port (struct openconnect_info *vpninfo)
{
	return vpninfo->port;
}

char *openconnect_get_cookie (struct openconnect_info *vpninfo)
{
	return vpninfo->cookie;
}

void openconnect_clear_cookie (struct openconnect_info *vpninfo)
{
169 170
	if (vpninfo->cookie)
		memset(vpninfo->cookie, 0, strlen(vpninfo->cookie));
171 172 173 174
}

void openconnect_reset_ssl (struct openconnect_info *vpninfo)
{
175
	openconnect_close_https(vpninfo, 1);
176
	if (vpninfo->peer_addr) {
177 178 179 180 181 182 183
		free(vpninfo->peer_addr);
		vpninfo->peer_addr = NULL;
	}
}

int openconnect_parse_url (struct openconnect_info *vpninfo, char *url)
{
184 185 186
	char *scheme = NULL;
	int ret;

187 188 189 190 191
	if (vpninfo->peer_addr) {
		free(vpninfo->peer_addr);
		vpninfo->peer_addr = NULL;
	}

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	free(vpninfo->hostname);
	vpninfo->hostname = NULL;
	free(vpninfo->urlpath);
	vpninfo->urlpath = NULL;

	ret = internal_parse_url (url, &scheme, &vpninfo->hostname,
				  &vpninfo->port, &vpninfo->urlpath, 443);

	if (ret) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("Failed to parse server URL '%s'\n"),
			     url);
		return ret;
	}
	if (scheme && strcmp(scheme, "https")) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("Only https:// permitted for server URL\n"));
		ret = -EINVAL;
	}
	free(scheme);
	return ret;
213
}
214

215 216 217 218 219 220
void openconnect_set_cert_expiry_warning (struct openconnect_info *vpninfo,
					  int seconds)
{
	vpninfo->cert_expire_warning = seconds;
}

221 222 223 224 225
void openconnect_set_cancel_fd (struct openconnect_info *vpninfo, int fd)
{
	vpninfo->cancel_fd = fd;
}

226 227
const char *openconnect_get_version (void)
{
228
	return openconnect_version_str;
229
}
230 231 232 233 234 235 236 237 238

int openconnect_has_pkcs11_support(void)
{
#if defined (OPENCONNECT_GNUTLS) && defined (HAVE_P11KIT)
	return 1;
#else
	return 0;
#endif
}
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

#if defined (OPENCONNECT_OPENSSL) && defined (HAVE_ENGINE)
#include <openssl/engine.h>
#endif
int openconnect_has_tss_blob_support(void)
{
#if defined (OPENCONNECT_OPENSSL) && defined (HAVE_ENGINE)
	ENGINE *e;

	ENGINE_load_builtin_engines();

	e = ENGINE_by_id("tpm");
	if (e) {
		ENGINE_free(e);
		return 1;
	}
255 256
#elif defined (OPENCONNECT_GNUTLS) && defined (HAVE_TROUSERS)
	return 1;
257 258 259
#endif
	return 0;
}