/*
* OpenConnect (SSL + DTLS) VPN client
*
- * Copyright © 2008-2011 Intel Corporation.
+ * Copyright © 2008-2012 Intel Corporation.
*
* Authors: David Woodhouse <dwmw2@infradead.org>
*
*/
#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef LIBSTOKEN_HDR
+#include LIBSTOKEN_HDR
+#endif
+
+#include <libxml/tree.h>
#include "openconnect-internal.h"
-struct openconnect_info *openconnect_vpninfo_new_with_cbdata (char *useragent,
+struct openconnect_info *openconnect_vpninfo_new (char *useragent,
openconnect_validate_peer_cert_vfn validate_peer_cert,
openconnect_write_new_config_vfn write_new_config,
openconnect_process_auth_form_vfn process_auth_form,
{
struct openconnect_info *vpninfo = calloc (sizeof(*vpninfo), 1);
- vpninfo->mtu = 1406;
vpninfo->ssl_fd = -1;
vpninfo->cert_expire_warning = 60 * 86400;
vpninfo->useragent = openconnect_create_useragent (useragent);
vpninfo->process_auth_form = process_auth_form;
vpninfo->progress = progress;
vpninfo->cbdata = privdata?:vpninfo;
+ vpninfo->cancel_fd = -1;
+ openconnect_set_reported_os(vpninfo, NULL);
#ifdef ENABLE_NLS
bindtextdomain("openconnect", LOCALEDIR);
return vpninfo;
}
-struct openconnect_info *openconnect_vpninfo_new (char *useragent,
- openconnect_validate_peer_cert_fn validate_peer_cert,
- openconnect_write_new_config_fn write_new_config,
- openconnect_process_auth_form_fn process_auth_form,
- openconnect_progress_fn progress)
+int openconnect_set_reported_os (struct openconnect_info *vpninfo, const char *os)
{
- return openconnect_vpninfo_new_with_cbdata (useragent,
- (void *)validate_peer_cert,
- (void *)write_new_config,
- (void *)process_auth_form,
- (void *)progress, NULL);
+ if (!os) {
+#if defined(__APPLE__)
+ os = "mac";
+#else
+ os = sizeof(long) > 4 ? "linux-64" : "linux";
+#endif
+ }
+
+ /* FIXME: is there a special platname for 64-bit Windows? */
+ if (!strcmp(os, "mac"))
+ vpninfo->csd_xmltag = "csdMac";
+ else if (!strcmp(os, "linux") || !strcmp(os, "linux-64"))
+ vpninfo->csd_xmltag = "csdLinux";
+ else if (!strcmp(os, "win"))
+ vpninfo->csd_xmltag = "csd";
+ else
+ return -EINVAL;
+
+ vpninfo->platname = os;
+ return 0;
}
static void free_optlist (struct vpn_option *opt)
void openconnect_vpninfo_free (struct openconnect_info *vpninfo)
{
- openconnect_reset_ssl(vpninfo);
+ openconnect_close_https(vpninfo, 1);
+ free(vpninfo->peer_addr);
free_optlist(vpninfo->cookies);
free_optlist(vpninfo->cstp_options);
free_optlist(vpninfo->dtls_options);
free(vpninfo->redirect_url);
free(vpninfo->proxy_type);
free(vpninfo->proxy);
- free(vpninfo->csd_scriptname);
+
+ if (vpninfo->csd_scriptname) {
+ unlink(vpninfo->csd_scriptname);
+ free(vpninfo->csd_scriptname);
+ }
+ free(vpninfo->csd_token);
+ free(vpninfo->csd_ticket);
free(vpninfo->csd_stuburl);
+ free(vpninfo->csd_starturl);
+ free(vpninfo->csd_waiturl);
+ free(vpninfo->csd_preurl);
+ if (vpninfo->opaque_srvdata)
+ xmlFreeNode(vpninfo->opaque_srvdata);
+
/* 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. */
if (vpninfo->cert != vpninfo->sslkey)
free((void *)vpninfo->sslkey);
free((void *)vpninfo->cert);
+ if (vpninfo->peer_cert) {
+#if defined (OPENCONNECT_OPENSSL)
+ X509_free(vpninfo->peer_cert);
+#elif defined (OPENCONNECT_GNUTLS)
+ gnutls_x509_crt_deinit(vpninfo->peer_cert);
+#endif
+ vpninfo->peer_cert = NULL;
+ }
+ free(vpninfo->useragent);
+#ifdef LIBSTOKEN_HDR
+ if (vpninfo->stoken_pin)
+ free(vpninfo->stoken_pin);
+ if (vpninfo->stoken_ctx)
+ stoken_destroy(vpninfo->stoken_ctx);
+#endif
/* No need to free deflate streams; they weren't initialised */
free(vpninfo);
}
vpninfo->urlpath = urlpath;
}
-void openconnect_set_xmlsha1 (struct openconnect_info *vpninfo, char *xmlsha1, int size)
+void openconnect_set_xmlsha1 (struct openconnect_info *vpninfo, const char *xmlsha1, int size)
{
if (size != sizeof (vpninfo->xmlsha1))
return;
vpninfo->sslkey = cert;
}
-struct x509_st *openconnect_get_peer_cert (struct openconnect_info *vpninfo)
+OPENCONNECT_X509 *openconnect_get_peer_cert (struct openconnect_info *vpninfo)
{
- return SSL_get_peer_certificate(vpninfo->https_ssl);
+ return vpninfo->peer_cert;
}
int openconnect_get_port (struct openconnect_info *vpninfo)
void openconnect_reset_ssl (struct openconnect_info *vpninfo)
{
- if (vpninfo->https_ssl) {
- openconnect_close_https(vpninfo);
- }
+ openconnect_close_https(vpninfo, 0);
if (vpninfo->peer_addr) {
free(vpninfo->peer_addr);
vpninfo->peer_addr = NULL;
}
- if (vpninfo->https_ctx) {
- SSL_CTX_free(vpninfo->https_ctx);
- vpninfo->https_ctx = NULL;
- }
}
int openconnect_parse_url (struct openconnect_info *vpninfo, char *url)
{
+ char *scheme = NULL;
+ int ret;
+
if (vpninfo->peer_addr) {
free(vpninfo->peer_addr);
vpninfo->peer_addr = NULL;
}
- return internal_parse_url (url, NULL, &vpninfo->hostname,
- &vpninfo->port, &vpninfo->urlpath, 443);
+ 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;
}
void openconnect_set_cert_expiry_warning (struct openconnect_info *vpninfo,
vpninfo->cert_expire_warning = seconds;
}
+void openconnect_set_cancel_fd (struct openconnect_info *vpninfo, int fd)
+{
+ vpninfo->cancel_fd = fd;
+}
+
const char *openconnect_get_version (void)
{
- return openconnect_version;
+ return openconnect_version_str;
+}
+
+int openconnect_has_pkcs11_support(void)
+{
+#if defined (OPENCONNECT_GNUTLS) && defined (HAVE_P11KIT)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+#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;
+ }
+#elif defined (OPENCONNECT_GNUTLS) && defined (HAVE_TROUSERS)
+ return 1;
+#endif
+ return 0;
+}
+
+int openconnect_has_stoken_support(void)
+{
+#ifdef LIBSTOKEN_HDR
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/*
+ * Enable software token generation if use_stoken == 1.
+ *
+ * If token_str is not NULL, try to parse the string. Otherwise, try to read
+ * the token data from ~/.stokenrc
+ *
+ * Return value:
+ * = -EOPNOTSUPP, if libstoken is not available
+ * = -EINVAL, if the token string is invalid (token_str was provided)
+ * = -ENOENT, if ~/.stokenrc is missing (token_str was NULL)
+ * = -EIO, for other libstoken failures
+ * = 0, on success
+ */
+int openconnect_set_stoken_mode (struct openconnect_info *vpninfo,
+ int use_stoken, const char *token_str)
+{
+#ifdef LIBSTOKEN_HDR
+ int ret;
+
+ vpninfo->use_stoken = 0;
+ if (!use_stoken)
+ return 0;
+
+ if (!vpninfo->stoken_ctx) {
+ vpninfo->stoken_ctx = stoken_new();
+ if (!vpninfo->stoken_ctx)
+ return -EIO;
+ }
+
+ ret = token_str ?
+ stoken_import_string(vpninfo->stoken_ctx, token_str) :
+ stoken_import_rcfile(vpninfo->stoken_ctx, NULL);
+ if (ret)
+ return ret;
+
+ vpninfo->use_stoken = 1;
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
}