[GIT PULL] DTLS and other improvements to openconnect

David Woodhouse dwmw2 at infradead.org
Mon Feb 3 10:48:29 EST 2014


On Mon, 2014-02-03 at 15:34 +0100, Nikos Mavrogiannopoulos wrote:
> On Mon, Feb 3, 2014 at 2:41 PM, David Woodhouse <dwmw2 at infradead.org> wrote:
> >> Still the most important addition is the support for AES-GCM, which is
> >> not only better to AES-CBC due to side-channels, but is also more
> >> UDP-friendly as it requires no padding and has a shorter nonce.
> >> They are available from:
> >> git://gitorious.org/openconnect-x/openconnect-x.git privacy-improvements
> > Please add the --pfs option to the man page too.
> 
> Updated.
> 
> > And shouldn't it affect
> > the DTLS setup too?
> 
> The DTLS channel's key depends on a key which has been established
> with PFS, so if the server does not save the session keys somewhere,
> it is ok.
> 
> > It probably also wants an openconnect_set_pfs()
> > function in the library, since we now support actually making
> > connections from the library too?
> 
> Added in a followup commit as well as its JNI counterpart.

http://www.angryflower.com/itsits.gif (in the commit comment) :)

Could also do with an update to www/changelog.xml please. Sorry, I
should have noticed that before.


Btw I also looked at your outstanding win32 patch. Here's what I have so
far, which does at least build. I didn't need to use your Makefile; on
Fedora just installing mingw32-gnutls mingw32-libxml2 mingw32-p11-kit
and mingw32-zlib, then using 'mingw32-configure' seemed to suffice.

It builds, and then fails to connect (I was just uaing --authenticate)
because the command socket is non-blocking. Could do with cleaning up
into self-contained commits (for example, *one* commit adding
closesocket(), *one* commit switching to send/recv, etc...

The short option string passed to getopt_long() will also need fixing.

diff --git a/auth.c b/auth.c
index 5e866e0..f9249b9 100644
--- a/auth.c
+++ b/auth.c
@@ -25,8 +25,10 @@
  */
 
 #include <stdio.h>
-#include <netdb.h>
-#include <unistd.h>
+#ifndef _WIN32
+# include <netdb.h>
+# include <unistd.h>
+#endif
 #include <fcntl.h>
 #include <time.h>
 #include <string.h>
diff --git a/compat.c b/compat.c
index acb97d6..dcfdcf8 100644
--- a/compat.c
+++ b/compat.c
@@ -24,6 +24,7 @@
 
 #include <string.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <ctype.h>
 
@@ -164,3 +165,33 @@ char *openconnect__strcasestr(const char *haystack, const char *needle)
 	return NULL;
 }
 #endif
+
+#ifndef HAVE_SETENV
+int openconnect__setenv(const char *name, const char *value, int overwrite)
+{
+	char buf[128];
+	
+	snprintf(buf, sizeof(buf), "%s=%s", name, value);
+	putenv(buf);
+	return 0;
+}
+#endif
+
+#ifndef HAVE_UNSETENV
+void openconnect__unsetenv(const char *name)
+{
+	char buf[128];
+	
+	snprintf(buf, sizeof(buf), "%s=", name);
+	putenv(buf);
+}
+#endif
+
+#ifndef HAVE_INET_ATON
+int
+openconnect__inet_aton(const char *cp, struct in_addr *addr)
+{
+  addr->s_addr = inet_addr(cp);
+  return (addr->s_addr == 0xffffffff) ? 0 : 1;
+}
+#endif
diff --git a/configure.ac b/configure.ac
index efb90f0..a6d9d8d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,6 +14,12 @@ AC_PREREQ([2.59c], [], [AC_SUBST([htmldir], [m4_ifset([AC_PACKAGE_TARNAME],
 
 AC_PREREQ([2.60], [], [AC_SUBST([localedir], ['$(datadir)/locale'])])
 
+case "$host" in
+  *mingw32* | *mingw64*)
+    have_win=yes
+  ;;
+esac
+
 # Upstream's pkg.m4 (since 0.27) offers this now, but define our own
 # compatible version in case the local version of pkgconfig isn't new enough.
 # https://bugs.freedesktop.org/show_bug.cgi?id=48743
@@ -92,6 +98,7 @@ case $host_os in
     ;;
 esac
 
+AC_CHECK_FUNC(pipe2, [AC_DEFINE(HAVE_PIPE2, 1)], [])
 AC_CHECK_FUNC(fdevname_r, [AC_DEFINE(HAVE_FDEVNAME_R, 1)], [])
 AC_CHECK_FUNC(getline, [AC_DEFINE(HAVE_GETLINE, 1)], [symver_getline="openconnect__getline;"])
 AC_CHECK_FUNC(strcasestr, [AC_DEFINE(HAVE_STRCASESTR, 1)], [])
@@ -141,10 +148,22 @@ AS_COMPILER_FLAGS(WFLAGS,
          -Wwrite-strings")
 AC_SUBST(WFLAGS, [$WFLAGS])
 
-AC_CHECK_FUNC(socket, [], AC_CHECK_LIB(socket, socket, [], AC_ERROR(Cannot find socket() function)))
-AC_CHECK_FUNC(inet_aton, [], AC_CHECK_LIB(nsl, inet_aton, [], AC_ERROR(Cannot find inet_aton() function)))
+if test "$have_win" = yes;then
+	LIBS="$LIBS -lws2_32"
+	AC_SUBST([HAVE_SOCKET], 1)
+	AC_SUBST([INET_ATON], 1)
+else
+	AC_CHECK_FUNC(socket, [], AC_CHECK_LIB(socket, socket, [], AC_ERROR(Cannot find socket() function)))
+	AC_CHECK_FUNC(inet_aton, [], AC_CHECK_LIB(nsl, inet_aton, [], AC_ERROR(Cannot find inet_aton() function)))
+fi
 AC_CHECK_FUNC(__android_log_vprint, [], AC_CHECK_LIB(log, __android_log_vprint, [], []))
 
+AC_CHECK_FUNC(setenv, [AC_DEFINE(HAVE_SETENV, 1)], [symver_setenv="openconnect__setenv;"])
+AC_CHECK_FUNC(unsetenv, [AC_DEFINE(HAVE_UNSETENV, 1)], [symver_unsetenv="openconnect__unsetenv;"])
+
+AC_CHECK_FUNCS([asprintf mmap getpwnam fork fcntl sigaction inet_aton])
+AC_CHECK_HEADERS([sys/utsname.h termios.h poll.h sys/select.h])
+
 AC_ENABLE_SHARED
 AC_DISABLE_STATIC
 
diff --git a/cstp.c b/cstp.c
index 29371fe..b223082 100644
--- a/cstp.c
+++ b/cstp.c
@@ -23,7 +23,6 @@
  *   Boston, MA 02110-1301 USA
  */
 
-#include <netdb.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <time.h>
@@ -33,9 +32,16 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
+#ifdef _WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
 #include <netinet/tcp.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif
 #include <stdarg.h>
 
 #include "openconnect-internal.h"
diff --git a/dtls.c b/dtls.c
index eede71c..f7ff53a 100644
--- a/dtls.c
+++ b/dtls.c
@@ -24,10 +24,16 @@
 
 #include <errno.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
+#ifdef _WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif
 #include <unistd.h>
-#include <netinet/in.h>
 #include <fcntl.h>
 #include <string.h>
 #include <errno.h>
@@ -381,6 +387,12 @@ static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
 
 	gnutls_transport_set_ptr(dtls_ssl,
 				 (gnutls_transport_ptr_t)(long) dtls_fd);
+#ifdef _WIN32
+	gnutls_transport_set_pull_function(dtls_ssl, system_read);
+	gnutls_transport_set_push_function(dtls_ssl, system_write);
+	gnutls_transport_set_errno_function(dtls_ssl, neterrno);
+#endif
+
 	gnutls_record_disable_padding(dtls_ssl);
 	master_secret.data = vpninfo->dtls_secret;
 	master_secret.size = sizeof(vpninfo->dtls_secret);
@@ -500,7 +512,7 @@ int connect_dtls_socket(struct openconnect_info *vpninfo)
 		vpninfo->protect_socket(vpninfo->cbdata, dtls_fd);
 
 	sndbuf = vpninfo->ip_info.mtu * 2;
-	setsockopt(dtls_fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
+	setsockopt(dtls_fd, SOL_SOCKET, SO_SNDBUF, (void *)&sndbuf, sizeof(sndbuf));
 
 	if (vpninfo->dtls_local_port) {
 		union {
@@ -527,29 +539,31 @@ int connect_dtls_socket(struct openconnect_info *vpninfo)
 				     _("Unknown protocol family %d. Cannot do DTLS\n"),
 				     vpninfo->peer_addr->sa_family);
 			vpninfo->dtls_attempt_period = 0;
-			close(dtls_fd);
+			closesocket(dtls_fd);
 			return -EINVAL;
 		}
 
 		if (bind(dtls_fd, (struct sockaddr *)&dtls_bind_addr, dtls_bind_addrlen)) {
 			perror(_("Bind UDP socket for DTLS"));
-			close(dtls_fd);
+			closesocket(dtls_fd);
 			return -EINVAL;
 		}
 	}
 
 	if (connect(dtls_fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) {
 		perror(_("UDP (DTLS) connect:\n"));
-		close(dtls_fd);
+		closesocket(dtls_fd);
 		return -EINVAL;
 	}
 
+#ifdef HAVE_FCNTL
 	fcntl(dtls_fd, F_SETFD, FD_CLOEXEC);
 	fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
+#endif
 
 	ret = start_dtls_handshake(vpninfo, dtls_fd);
 	if (ret) {
-		close(dtls_fd);
+		closesocket(dtls_fd);
 		return ret;
 	}
 
@@ -569,7 +583,7 @@ void dtls_close(struct openconnect_info *vpninfo, int kill_handshake_too)
 {
 	if (vpninfo->dtls_ssl) {
 		DTLS_FREE(vpninfo->dtls_ssl);
-		close(vpninfo->dtls_fd);
+		closesocket(vpninfo->dtls_fd);
 		FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
 		FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
 		FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
@@ -578,7 +592,7 @@ void dtls_close(struct openconnect_info *vpninfo, int kill_handshake_too)
 	}
 	if (kill_handshake_too && vpninfo->new_dtls_ssl) {
 		DTLS_FREE(vpninfo->new_dtls_ssl);
-		close(vpninfo->new_dtls_fd);
+		closesocket(vpninfo->new_dtls_fd);
 		FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
 		FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
 		vpninfo->new_dtls_ssl = NULL;
diff --git a/gnutls.c b/gnutls.c
index 810053f..0d6ec8a 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -24,15 +24,17 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <unistd.h>
+#ifndef _WIN32
+# include <sys/socket.h>
+# include <netdb.h>
+# include <unistd.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+#endif
 #include <fcntl.h>
 #include <string.h>
 #include <ctype.h>
 #include <stdio.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
 #include <errno.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -210,12 +212,17 @@ static int check_certificate_expiry(struct openconnect_info *vpninfo, gnutls_x50
 		reason = _("Client certificate expires soon at");
 
 	if (reason) {
-		struct tm tm;
 		char buf[80];
+#ifdef _WIN32
+		struct tm *tm = gmtime(&expires);
+		strftime(buf, 80, "%a, %d %b %Y %H:%M:%S %Z", tm);
+#else
+		struct tm tm;
 
 		gmtime_r(&expires, &tm);
 		strftime(buf, 80, "%a, %d %b %Y %T %Z", &tm);
-
+#endif
+		
 		vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, buf);
 	}
 	return 0;
@@ -1852,7 +1859,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 					gnutls_free(datum.data);
 					gnutls_certificate_free_credentials(vpninfo->https_cred);
 					vpninfo->https_cred = NULL;
-					close(ssl_sock);
+					closesocket(ssl_sock);
 					return -ENOMEM;
 				}
 				err = gnutls_x509_crt_list_import(certs, &nr_certs, &datum,
@@ -1873,7 +1880,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 						     gnutls_strerror(err));
 					gnutls_certificate_free_credentials(vpninfo->https_cred);
 					vpninfo->https_cred = NULL;
-					close(ssl_sock);
+					closesocket(ssl_sock);
 					return -EINVAL;
 				}
 			}
@@ -1889,7 +1896,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 					     vpninfo->cafile, gnutls_strerror(err));
 				gnutls_certificate_free_credentials(vpninfo->https_cred);
 				vpninfo->https_cred = NULL;
-				close(ssl_sock);
+				closesocket(ssl_sock);
 				return -EINVAL;
 			}
 		}
@@ -1901,7 +1908,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 					     _("Loading certificate failed. Aborting.\n"));
 				gnutls_certificate_free_credentials(vpninfo->https_cred);
 				vpninfo->https_cred = NULL;
-				close(ssl_sock);
+				closesocket(ssl_sock);
 				return err;
 			}
 		}
@@ -1927,13 +1934,18 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 			     gnutls_strerror(err));
 		gnutls_deinit(vpninfo->https_sess);
 		vpninfo->https_sess = NULL;
-		close(ssl_sock);
+		closesocket(ssl_sock);
 		return -EIO;
 	}
 
 	gnutls_record_disable_padding(vpninfo->https_sess);
 	gnutls_credentials_set(vpninfo->https_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);
 	gnutls_transport_set_ptr(vpninfo->https_sess, /* really? */(gnutls_transport_ptr_t)(long) ssl_sock);
+#ifdef _WIN32
+	gnutls_transport_set_pull_function(vpninfo->https_sess, system_read);
+	gnutls_transport_set_push_function(vpninfo->https_sess, system_write);
+	gnutls_transport_set_errno_function(vpninfo->https_sess, neterrno);
+#endif
 
 	vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
 		     vpninfo->hostname);
@@ -1957,7 +1969,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 				vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
 				gnutls_deinit(vpninfo->https_sess);
 				vpninfo->https_sess = NULL;
-				close(ssl_sock);
+				closesocket(ssl_sock);
 				return -EINTR;
 			}
 		} else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) {
@@ -1965,7 +1977,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 							 gnutls_strerror(err));
 			gnutls_deinit(vpninfo->https_sess);
 			vpninfo->https_sess = NULL;
-			close(ssl_sock);
+			closesocket(ssl_sock);
 			return -EIO;
 		} else {
 			/* non-fatal error or warning. Ignore it and continue */
@@ -1994,7 +2006,7 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
 		vpninfo->https_sess = NULL;
 	}
 	if (vpninfo->ssl_fd != -1) {
-		close(vpninfo->ssl_fd);
+		closesocket(vpninfo->ssl_fd);
 		FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
 		FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
 		FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
diff --git a/http.c b/http.c
index cff4519..07e1d6a 100644
--- a/http.c
+++ b/http.c
@@ -23,13 +23,15 @@
  *   Boston, MA 02110-1301 USA
  */
 
-#include <netdb.h>
-#include <unistd.h>
+#ifndef _WIN32
+# include <netdb.h>
+# include <unistd.h>
+# include <pwd.h>
+#endif
 #include <fcntl.h>
 #include <time.h>
 #include <string.h>
 #include <ctype.h>
-#include <pwd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <errno.h>
@@ -529,6 +531,7 @@ static int fetch_config(struct openconnect_info *vpninfo, char *fu, char *bu,
 
 static int run_csd_script(struct openconnect_info *vpninfo, char *buf, int buflen)
 {
+#ifndef _WIN32
 	char fname[64];
 	int fd, ret;
 
@@ -658,7 +661,7 @@ out:
 	vpninfo->csd_scriptname = strdup(fname);
 
 	http_add_cookie(vpninfo, "sdesktop", vpninfo->csd_token);
-
+#endif
 	return 0;
 }
 
@@ -1329,7 +1332,7 @@ static int proxy_write(struct openconnect_info *vpninfo, int fd,
 		if (!FD_ISSET(fd, &wr_set))
 			continue;
 
-		i = write(fd, buf + count, len - count);
+		i = send(fd, (void *)&buf[count], len - count, 0);
 		if (i < 0)
 			return -errno;
 
@@ -1360,7 +1363,7 @@ static int proxy_read(struct openconnect_info *vpninfo, int fd,
 		if (!FD_ISSET(fd, &rd_set))
 			continue;
 
-		i = read(fd, buf + count, len - count);
+		i = recv(fd, (void *)&buf[count], len - count, 0);
 		if (i < 0)
 			return -errno;
 
diff --git a/library.c b/library.c
index b1295de..3e27be5 100644
--- a/library.c
+++ b/library.c
@@ -367,10 +367,15 @@ void openconnect_set_cancel_fd(struct openconnect_info *vpninfo, int fd)
 	vpninfo->cmd_fd = fd;
 }
 
+
 int openconnect_setup_cmd_pipe(struct openconnect_info *vpninfo)
 {
 	int pipefd[2];
 
+#ifdef HAVE_PIPE2
+	if (pipe2(pipefd, O_NONBLOCK))
+	    return -EIO;
+#else
 	if (pipe(pipefd) < 0)
 		return -EIO;
 	if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) ||
@@ -379,6 +384,7 @@ int openconnect_setup_cmd_pipe(struct openconnect_info *vpninfo)
 		close(pipefd[1]);
 		return -EIO;
 	}
+#endif
 	vpninfo->cmd_fd = pipefd[0];
 	vpninfo->cmd_fd_write = pipefd[1];
 	return vpninfo->cmd_fd_write;
diff --git a/main.c b/main.c
index 1c9e5f6..759b62f 100644
--- a/main.c
+++ b/main.c
@@ -32,7 +32,7 @@
 #include <stdio.h>
 #ifdef __ANDROID__
 #include <android/log.h>
-#else
+#elif !defined(_WIN32)
 #include <syslog.h>
 #endif
 #include <stdarg.h>
@@ -45,16 +45,24 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
+#ifdef HAVE_GETPWNAM
 #include <pwd.h>
+#endif
+#ifdef HAVE_SYS_UTSNAME_H
 #include <sys/utsname.h>
+#endif
 #include <sys/types.h>
+#ifdef HAVE_TERMIOS_H
 #include <termios.h>
+#endif
 #ifdef LIBPROXY_HDR
 #include LIBPROXY_HDR
 #endif
 #include <getopt.h>
 #include <time.h>
-
+#ifdef _WIN32
+#include <conio.h>
+#endif
 #include "openconnect-internal.h"
 
 static int write_new_config(void *_vpninfo,
@@ -139,7 +147,9 @@ enum {
 #endif
 
 static struct option long_options[] = {
+#ifdef HAVE_FORK
 	OPTION("background", 0, 'b'),
+#endif
 	OPTION("pfs", 0, OPT_PFS),
 	OPTION("pid-file", 1, OPT_PIDFILE),
 	OPTION("certificate", 1, 'c'),
@@ -153,9 +163,14 @@ static struct option long_options[] = {
 	OPTION("interface", 1, 'i'),
 	OPTION("mtu", 1, 'm'),
 	OPTION("base-mtu", 1, OPT_BASEMTU),
+#ifdef HAVE_GETPWNAM
 	OPTION("setuid", 1, 'U'),
+	OPTION("csd-user", 1, OPT_CSD_USER),
+#endif
 	OPTION("script", 1, 's'),
+#ifndef _WIN32
 	OPTION("script-tun", 0, 'S'),
+#endif
 	OPTION("syslog", 0, 'l'),
 	OPTION("timestamp", 0, OPT_TIMESTAMP),
 	OPTION("key-password", 1, 'p'),
@@ -181,7 +196,6 @@ static struct option long_options[] = {
 	OPTION("servercert", 1, OPT_SERVERCERT),
 	OPTION("key-password-from-fsid", 0, OPT_KEY_PASSWORD_FROM_FSID),
 	OPTION("useragent", 1, OPT_USERAGENT),
-	OPTION("csd-user", 1, OPT_CSD_USER),
 	OPTION("csd-wrapper", 1, OPT_CSD_WRAPPER),
 	OPTION("disable-ipv6", 0, OPT_DISABLE_IPV6),
 	OPTION("no-proxy", 0, OPT_NO_PROXY),
@@ -255,7 +269,9 @@ static void usage(void)
 	printf(_("Open client for Cisco AnyConnect VPN, version %s\n\n"), openconnect_version_str);
 	print_build_opts();
 	printf("      --config=CONFIGFILE         %s\n", _("Read options from config file"));
+#ifdef HAVE_FORK
 	printf("  -b, --background                %s\n", _("Continue in background after startup"));
+#endif
 	printf("      --pid-file=PIDFILE          %s\n", _("Write the daemon's PID to this file"));
 	printf("  -c, --certificate=CERT          %s\n", _("Use SSL client certificate CERT"));
 	printf("  -e, --cert-expire-warning=DAYS  %s\n", _("Warn when certificate lifetime < DAYS"));
@@ -329,16 +345,17 @@ static void usage(void)
 
 static void read_stdin(char **string, int hidden)
 {
-	struct termios t;
 	char *c = malloc(1025), *ret;
-	int fd = fileno(stdin);
 
 	if (!c) {
 		fprintf(stderr, _("Allocation failure for string from stdin\n"));
 		exit(1);
 	}
-
+#ifndef _WIN32
 	if (hidden) {
+		int fd = fileno(stdin);
+		struct termios t;
+
 		tcgetattr(fd, &t);
 		t.c_lflag &= ~ECHO;
 		tcsetattr(fd, TCSANOW, &t);
@@ -349,6 +366,7 @@ static void read_stdin(char **string, int hidden)
 		tcsetattr(fd, TCSANOW, &t);
 		fprintf(stderr, "\n");
 	} else
+#endif
 		ret = fgets(c, 1025, stdin);
 
 	if (!ret) {
@@ -366,6 +384,7 @@ static void read_stdin(char **string, int hidden)
 static int sig_cmd_fd;
 static int sig_caught;
 
+#ifdef HAVE_SIGACTION
 static void handle_sigint(int sig)
 {
 	char x = OC_CMD_CANCEL;
@@ -383,6 +402,7 @@ static void handle_sigusr(int sig)
 	else if (sig == SIGUSR2)
 		verbose = PRG_INFO;
 }
+#endif /* SIGACTION */
 
 static FILE *config_file = NULL;
 static int config_line_num = 0;
@@ -427,7 +447,11 @@ static int next_option(int argc, char **argv, char **config_arg)
  next:
 	if (!config_file) {
 		opt = getopt_long(argc, argv,
+#ifdef HAVE_FORK
+				  "b"
+#endif
 				  "bC:c:Dde:g:hi:k:lm:P:p:Q:qSs:U:u:Vvx:",
+
 				  long_options, NULL);
 
 		*config_arg = optarg;
@@ -511,16 +535,16 @@ static int next_option(int argc, char **argv, char **config_arg)
 int main(int argc, char **argv)
 {
 	struct openconnect_info *vpninfo;
-	struct utsname utsbuf;
-	struct sigaction sa;
 	int use_syslog = 0;
 	char *urlpath = NULL;
 	char *proxy = getenv("https_proxy");
-	int script_tun = 0;
 	char *vpnc_script = NULL, *ifname = NULL;
 	const struct oc_ip_info *ip_info;
 	int autoproxy = 0;
+#ifndef _WIN32
+	int script_tun = 0;
 	uid_t uid = getuid();
+#endif
 	int opt;
 	char *pidfile = NULL;
 	int use_dtls = 1;
@@ -544,6 +568,17 @@ int main(int argc, char **argv)
 
 	openconnect_init_ssl();
 
+#ifdef _WIN32
+	{
+		WSADATA data;
+		if (WSAStartup (MAKEWORD(1, 1), &data) != 0) {
+			fprintf(stderr, _("ERROR: Cannot initialize sockets\n"));
+			exit(1);
+		}
+
+	}
+#endif
+
 	vpninfo = openconnect_vpninfo_new((char *)"Open AnyConnect VPN Agent",
 		validate_peer_cert, NULL, process_auth_form_cb, write_progress, NULL);
 	if (!vpninfo) {
@@ -552,10 +587,13 @@ int main(int argc, char **argv)
 	}
 
 	vpninfo->cbdata = vpninfo;
+#ifdef HAVE_SYS_UTSNAME
+	struct utsname utsbuf;
 	if (!uname(&utsbuf)) {
 		free(vpninfo->localname);
 		vpninfo->localname = xstrdup(utsbuf.nodename);
 	}
+#endif
 
 	while ((opt = next_option(argc, argv, &config_arg))) {
 
@@ -628,9 +666,11 @@ int main(int argc, char **argv)
 		case OPT_AUTHGROUP:
 			authgroup = keep_config_arg();
 			break;
+#ifdef HAVE_FORK
 		case 'b':
 			background = 1;
 			break;
+#endif
 		case 'C':
 			vpninfo->cookie = keep_config_arg();
 			break;
@@ -704,13 +744,16 @@ int main(int argc, char **argv)
 		case 's':
 			vpnc_script = xstrdup(config_arg);
 			break;
+#ifndef _WIN32
 		case 'S':
 			script_tun = 1;
 			break;
+#endif
 		case 'u':
 			free(username);
 			username = strdup(config_arg);
 			break;
+#ifdef HAVE_GETPWNAM
 		case 'U': {
 			char *strend;
 			uid = strtol(config_arg, &strend, 0);
@@ -740,6 +783,7 @@ int main(int argc, char **argv)
 			vpninfo->uid_csd_given = 1;
 			break;
 		}
+#endif
 		case OPT_CSD_WRAPPER:
 			vpninfo->csd_wrapper = keep_config_arg();
 			break;
@@ -826,6 +870,13 @@ int main(int argc, char **argv)
 		usage();
 	}
 
+#ifdef _WIN32
+	if (!(cookieonly & 1) && vpninfo->ifname == NULL) {
+		fprintf(stderr, _("The --interface option is mandatory on windows\n"));
+		usage();
+	}
+#endif
+
 	if (!vpninfo->sslkey)
 		vpninfo->sslkey = vpninfo->cert;
 
@@ -847,7 +898,7 @@ int main(int argc, char **argv)
 		exit(1);
 
 	if (use_syslog) {
-#ifndef __ANDROID__
+#if !defined (__ANDROID__) && !defined(_WIN32)
 		openlog("openconnect", LOG_PID, LOG_DAEMON);
 #endif
 		vpninfo->progress = syslog_progress;
@@ -859,6 +910,9 @@ int main(int argc, char **argv)
 		exit(1);
 	}
 
+#ifdef HAVE_SIGACTION
+	{
+	struct sigaction sa;
 	memset(&sa, 0, sizeof(sa));
 
 	sa.sa_handler = handle_sigusr;
@@ -869,6 +923,8 @@ int main(int argc, char **argv)
 	sigaction(SIGTERM, &sa, NULL);
 	sigaction(SIGINT, &sa, NULL);
 	sigaction(SIGHUP, &sa, NULL);
+	}
+#endif
 
 	if (vpninfo->sslkey && do_passphrase_from_fsid)
 		openconnect_passphrase_from_fsid(vpninfo);
@@ -934,18 +990,22 @@ int main(int argc, char **argv)
 
 	if (!vpnc_script)
 		vpnc_script = xstrdup(DEFAULT_VPNCSCRIPT);
+#ifndef _WIN32
 	if (script_tun) {
 		if (openconnect_setup_tun_script(vpninfo, vpnc_script)) {
 			fprintf(stderr, _("Set up tun script failed\n"));
 			openconnect_vpninfo_free(vpninfo);
 			exit(1);
 		}
-	} else if (openconnect_setup_tun_device(vpninfo, vpnc_script, ifname)) {
+	} else
+#endif
+	if (openconnect_setup_tun_device(vpninfo, vpnc_script, ifname)) {
 		fprintf(stderr, _("Set up tun device failed\n"));
 		openconnect_vpninfo_free(vpninfo);
 		exit(1);
 	}
 
+#ifndef _WIN32
 	if (uid != getuid()) {
 		if (setuid(uid)) {
 			fprintf(stderr, _("Failed to set uid %ld\n"),
@@ -954,6 +1014,7 @@ int main(int argc, char **argv)
 			exit(1);
 		}
 	}
+#endif
 
 	if (use_dtls && openconnect_setup_dtls(vpninfo, 60))
 		fprintf(stderr, _("Set up DTLS failed; using SSL instead\n"));
@@ -975,6 +1036,7 @@ int main(int argc, char **argv)
 			     _("See http://www.infradead.org/openconnect/vpnc-script.html\n"));
 	}
 
+#ifdef HAVE_FORK
 	if (background) {
 		int pid;
 
@@ -1004,12 +1066,14 @@ int main(int argc, char **argv)
 		if (fp)
 			fclose(fp);
 	}
+#endif /* !HAVE_FORK */
 	ret = openconnect_mainloop(vpninfo, reconnect_timeout, RECONNECT_INTERVAL_MIN);
 	if (fp)
 		unlink(pidfile);
 
 	if (sig_caught) {
-		vpn_progress(vpninfo, PRG_INFO, _("Caught signal: %s\n"), strsignal(sig_caught));
+		vpn_progress(vpninfo, PRG_INFO, _("Caught signal: %s\n"),
+			     strsignal(sig_caught));
 		ret = 0;
 	} else if (ret == -EPERM)
 		ret = 2;
@@ -1093,7 +1157,7 @@ void syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
 		va_end(args2);
 	}
 }
-#else /* !__ANDROID__ */
+#elif !defined(_WIN32) /* !__ANDROID__ */
 void syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
 {
 	int priority = level ? LOG_INFO : LOG_NOTICE;
@@ -1105,6 +1169,11 @@ void syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
 		va_end(args);
 	}
 }
+#else
+void syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
+{
+	return;
+}
 #endif
 
 struct accepted_cert {
diff --git a/mainloop.c b/mainloop.c
index 053c81b..8135674 100644
--- a/mainloop.c
+++ b/mainloop.c
@@ -23,9 +23,13 @@
  */
 
 #include <errno.h>
+#ifdef HAVE_POLL_H
 #include <poll.h>
+#endif
 #include <limits.h>
+#ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
+#endif
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 632c2db..208f894 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -54,8 +54,15 @@
 
 #include <zlib.h>
 #include <stdint.h>
-#include <sys/socket.h>
-#include <sys/select.h>
+#ifndef _WIN32
+# include <sys/socket.h>
+# include <sys/select.h>
+#else
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define socklen_t int
+int asprintf (char **resultp, const char *format, ...);
+#endif
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -347,6 +354,56 @@ ssize_t openconnect__getline(char **lineptr, size_t *n, FILE *stream);
 char *openconnect__strcasestr(const char *haystack, const char *needle);
 #endif
 
+#ifndef HAVE_SETENV
+#define setenv openconnect__setenv
+int openconnect__setenv(const char *name, const char *value, int overwrite);
+#endif
+#ifndef HAVE_UNSETENV
+#define unsetenv openconnect__unsetenv
+void openconnect__unsetenv(const char *name);
+#endif
+
+#ifndef HAVE_INET_ATON
+#define inet_aton openconnect__inet_aton
+int openconnect__inet_aton(const char *cp, struct in_addr *addr);
+#endif
+
+#ifndef _WIN32
+# define neterrno() errno
+# define closesocket close
+# define socket(domain,type,proto) WSASocket(domain,type,proto,NULL,0,0)
+#else
+# include <errno.h>
+#define HAVE_PIPE2
+#define O_NONBLOCK 0/* XXX */ 
+#define pipe2(fds, flags) _pipe(fds, 4096, _O_BINARY|(flags))
+#define strsignal(sig) "<unknown>"
+static inline ssize_t
+system_write(gnutls_transport_ptr ptr, const void *data, size_t data_size)
+{
+	return send((long)ptr, data, data_size, 0);
+}
+
+static inline ssize_t
+system_read(gnutls_transport_ptr_t ptr, void *data, size_t data_size)
+{
+	return recv((long)ptr, data, data_size, 0);
+}
+
+static inline int neterrno()
+{
+int err = WSAGetLastError();
+  
+	if (err == WSAEWOULDBLOCK)
+  		return EAGAIN;
+	else if (err == WSAEINTR)
+  		return EINTR;
+	else if (err == WSAEINPROGRESS)
+		return EINPROGRESS;
+	return 0;
+}
+#endif
+
 /* I always coded as if it worked like this. Now it does. */
 #define realloc_inplace(p, size) do {			\
 	void *__realloc_old = p;			\
diff --git a/openconnect.h b/openconnect.h
index 0950162..7dc67db 100644
--- a/openconnect.h
+++ b/openconnect.h
@@ -31,6 +31,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#ifdef _WIN32
+#define uid_t unsigned
+#endif
+
 #define OPENCONNECT_API_VERSION_MAJOR 3
 #define OPENCONNECT_API_VERSION_MINOR 1
 
diff --git a/openssl.c b/openssl.c
index f8a6eb1..be157ef 100644
--- a/openssl.c
+++ b/openssl.c
@@ -1285,7 +1285,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 					     _("Loading certificate failed. Aborting.\n"));
 				SSL_CTX_free(vpninfo->https_ctx);
 				vpninfo->https_ctx = NULL;
-				close(ssl_sock);
+				closesocket(ssl_sock);
 				return err;
 			}
 			check_certificate_expiry(vpninfo);
@@ -1318,7 +1318,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 			if (!b) {
 				SSL_CTX_free(vpninfo->https_ctx);
 				vpninfo->https_ctx = NULL;
-				close(ssl_sock);
+				closesocket(ssl_sock);
 				return -EINVAL;
 			}
 
@@ -1332,7 +1332,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 				openconnect_report_ssl_errors(vpninfo);
 				SSL_CTX_free(vpninfo->https_ctx);
 				vpninfo->https_ctx = NULL;
-				close(ssl_sock);
+				closesocket(ssl_sock);
 				return -ENOENT;
 			}
 
@@ -1356,7 +1356,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 				openconnect_report_ssl_errors(vpninfo);
 				SSL_CTX_free(vpninfo->https_ctx);
 				vpninfo->https_ctx = NULL;
-				close(ssl_sock);
+				closesocket(ssl_sock);
 				return -EINVAL;
 			}
 		}
@@ -1388,7 +1388,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 			vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
 			openconnect_report_ssl_errors(vpninfo);
 			SSL_free(https_ssl);
-			close(ssl_sock);
+			closesocket(ssl_sock);
 			return -EINVAL;
 		}
 
@@ -1397,14 +1397,14 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
 		if (is_cancel_pending(vpninfo, &rd_set)) {
 			vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
 			SSL_free(https_ssl);
-			close(ssl_sock);
+			closesocket(ssl_sock);
 			return -EINVAL;
 		}
 	}
 
 	if (verify_peer(vpninfo, https_ssl)) {
 		SSL_free(https_ssl);
-		close(ssl_sock);
+		closesocket(ssl_sock);
 		return -EINVAL;
 	}
 
@@ -1432,7 +1432,7 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
 		vpninfo->https_ssl = NULL;
 	}
 	if (vpninfo->ssl_fd != -1) {
-		close(vpninfo->ssl_fd);
+		closesocket(vpninfo->ssl_fd);
 		FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
 		FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
 		FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
diff --git a/ssl.c b/ssl.c
index 61d55b8..a6bfb66 100644
--- a/ssl.c
+++ b/ssl.c
@@ -23,11 +23,17 @@
  */
 
 #include <sys/types.h>
-#include <sys/socket.h>
+
+#ifdef _WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif
 #include <sys/stat.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
@@ -58,6 +64,16 @@
 #define AI_NUMERICSERV 0
 #endif
 
+static inline int set_nonblock(int sockfd)
+{
+#ifdef _WIN32
+	unsigned long mode = 0;
+	return ioctlsocket(sockfd, FIONBIO, &mode);
+#else
+	return fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
+#endif
+}
+
 static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd,
 			       const struct sockaddr *addr, socklen_t addrlen)
 {
@@ -66,27 +82,30 @@ static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd,
 	fd_set wr_set, rd_set;
 	int maxfd = sockfd;
 
-	fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
+	set_nonblock(sockfd);
 	if (vpninfo->protect_socket)
 		vpninfo->protect_socket(vpninfo->cbdata, sockfd);
 
-	if (connect(sockfd, addr, addrlen) < 0 && errno != EINPROGRESS)
+	if (connect(sockfd, addr, addrlen) < 0 && neterrno() != EINPROGRESS)
 		return -1;
 
 	do {
+		printf("into loop\n");
 		FD_ZERO(&wr_set);
 		FD_ZERO(&rd_set);
 		FD_SET(sockfd, &wr_set);
 		cmd_fd_set(vpninfo, &rd_set, &maxfd);
-
+		printf("will select...\n");
 		select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
+		printf("done select...\n");
 		if (is_cancel_pending(vpninfo, &rd_set)) {
 			vpn_progress(vpninfo, PRG_ERR, _("Socket connect cancelled\n"));
 			errno = EINTR;
 			return -1;
 		}
+		printf("no cancel pending. Again...\n");
 	} while (!FD_ISSET(sockfd, &wr_set) && !vpninfo->got_pause_cmd);
-
+	printf("try getpeername\n");
 	/* Check whether connect() succeeded or failed by using
 	   getpeername(). See http://cr.yp.to/docs/connect.html */
 	return getpeername(sockfd, (void *)&peer, &peerlen);
@@ -109,7 +128,9 @@ int connect_https_socket(struct openconnect_info *vpninfo)
 			ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
 			if (ssl_sock < 0)
 				goto reconn_err;
+#ifndef _WIN32
 			fcntl(ssl_sock, F_SETFD, fcntl(ssl_sock, F_GETFD) | FD_CLOEXEC);
+#endif
 		}
 		if (cancellable_connect(vpninfo, ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen)) {
 		reconn_err:
@@ -123,7 +144,7 @@ int connect_https_socket(struct openconnect_info *vpninfo)
 					     vpninfo->hostname);
 			}
 			if (ssl_sock >= 0)
-				close(ssl_sock);
+				closesocket(ssl_sock);
 			return -EINVAL;
 		}
 	} else {
@@ -238,7 +259,9 @@ int connect_https_socket(struct openconnect_info *vpninfo)
 					  rp->ai_protocol);
 			if (ssl_sock < 0)
 				continue;
+#ifndef _WIN32
 			fcntl(ssl_sock, F_SETFD, fcntl(ssl_sock, F_GETFD) | FD_CLOEXEC);
+#endif
 			if (cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
 				/* Store the peer address we actually used, so that DTLS can
 				   use it again later */
@@ -246,7 +269,7 @@ int connect_https_socket(struct openconnect_info *vpninfo)
 				if (!vpninfo->peer_addr) {
 					vpn_progress(vpninfo, PRG_ERR,
 						     _("Failed to allocate sockaddr storage\n"));
-					close(ssl_sock);
+					closesocket(ssl_sock);
 					return -ENOMEM;
 				}
 				vpninfo->peer_addrlen = rp->ai_addrlen;
@@ -270,7 +293,7 @@ int connect_https_socket(struct openconnect_info *vpninfo)
 				}
 				break;
 			}
-			close(ssl_sock);
+			closesocket(ssl_sock);
 			ssl_sock = -1;
 		}
 		freeaddrinfo(result);
@@ -286,7 +309,7 @@ int connect_https_socket(struct openconnect_info *vpninfo)
 	if (vpninfo->proxy) {
 		err = process_proxy(vpninfo, ssl_sock);
 		if (err) {
-			close(ssl_sock);
+			closesocket(ssl_sock);
 			return err;
 		}
 	}
@@ -357,6 +380,12 @@ int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
 		return -ENOMEM;
 	return 0;
 }
+#elif defined(_WIN32)
+int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
+{
+	/* Use GetVolumeInfo()? */
+	return -EINVAL;
+}
 #else
 int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
 {
@@ -544,10 +573,12 @@ void check_cmd_fd(struct openconnect_info *vpninfo, fd_set *fds)
 		vpninfo->got_cancel_cmd = 1;
 		return;
 	}
-
-	if (read(vpninfo->cmd_fd, &cmd, 1) != 1)
+	printf("read cmdfd...\n");
+	if (read(vpninfo->cmd_fd, &cmd, 1) != 1) {
+		printf("no\n");
 		return;
-
+	}
+	printf("done\n");
 	switch (cmd) {
 	case OC_CMD_CANCEL:
 		vpninfo->got_cancel_cmd = 1;
@@ -563,7 +594,9 @@ void check_cmd_fd(struct openconnect_info *vpninfo, fd_set *fds)
 
 int is_cancel_pending(struct openconnect_info *vpninfo, fd_set *fds)
 {
+	printf("is_cancel_pending()\n");
 	check_cmd_fd(vpninfo, fds);
+	printf("answer: %d\n", vpninfo->got_cancel_cmd);
 	return vpninfo->got_cancel_cmd;
 }
 
diff --git a/tun.c b/tun.c
index 863a189..dfbdc00 100644
--- a/tun.c
+++ b/tun.c
@@ -24,18 +24,20 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
+#ifndef _WIN32
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
 #include <netdb.h>
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <net/if.h>
 #include <arpa/inet.h>
+#endif
 #include <errno.h>
 #include <ctype.h>
 #include <stdio.h>
@@ -79,7 +81,7 @@
 
 static int set_tun_mtu(struct openconnect_info *vpninfo)
 {
-#ifndef __sun__ /* We don't know how to do this on Solaris */
+#if !defined(__sun__) && !defined(_WIN32) /* We don't know how to do this on Solaris */
 	struct ifreq ifr;
 	int net_fd;
 
@@ -101,7 +103,6 @@ static int set_tun_mtu(struct openconnect_info *vpninfo)
 	return 0;
 }
 
-
 static int setenv_int(const char *opt, int value)
 {
 	char buf[16];
@@ -372,6 +373,12 @@ static void set_script_env(struct openconnect_info *vpninfo)
 	setenv_cstp_opts(vpninfo);
 }
 
+#ifdef _WIN32
+#define WIFEXITED(w)    (((w) & 0xffffff00) == 0)
+#define WIFSIGNALED(w)  (!WIFEXITED(w))
+#define WEXITSTATUS(w)  (w)
+#endif
+
 int script_config_tun(struct openconnect_info *vpninfo, const char *reason)
 {
 	int ret;
@@ -388,12 +395,14 @@ int script_config_tun(struct openconnect_info *vpninfo, const char *reason)
 			     vpninfo->vpnc_script, reason, strerror(e));
 		return -e;
 	}
+
 	if (!WIFEXITED(ret)) {
 		vpn_progress(vpninfo, PRG_ERR,
 			     _("Script '%s' exited abnormally (%x)\n"),
 			       vpninfo->vpnc_script, ret);
 		return -EIO;
 	}
+
 	ret = WEXITSTATUS(ret);
 	if (ret) {
 		vpn_progress(vpninfo, PRG_ERR,
@@ -401,6 +410,7 @@ int script_config_tun(struct openconnect_info *vpninfo, const char *reason)
 			     vpninfo->vpnc_script, ret);
 		return -EIO;
 	}
+
 	return 0;
 }
 
@@ -635,7 +645,10 @@ static int os_setup_tun(struct openconnect_info *vpninfo)
 
 int openconnect_setup_tun_fd(struct openconnect_info *vpninfo, int tun_fd)
 {
+#ifndef _WIN32
 	fcntl(tun_fd, F_SETFD, FD_CLOEXEC);
+        fcntl(vpninfo->tun_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
+#endif
 
 	if (vpninfo->tun_fd != -1)
 		FD_CLR(vpninfo->tun_fd, &vpninfo->select_rfds);
@@ -646,11 +659,10 @@ int openconnect_setup_tun_fd(struct openconnect_info *vpninfo, int tun_fd)
 
 	FD_SET(tun_fd, &vpninfo->select_rfds);
 
-	fcntl(vpninfo->tun_fd, F_SETFL, fcntl(vpninfo->tun_fd, F_GETFL) | O_NONBLOCK);
-
 	return 0;
 }
 
+#ifndef _WIN32
 int openconnect_setup_tun_script(struct openconnect_info *vpninfo, char *tun_script)
 {
 	pid_t child;
@@ -683,6 +695,7 @@ int openconnect_setup_tun_script(struct openconnect_info *vpninfo, char *tun_scr
 
 	return openconnect_setup_tun_fd(vpninfo, fds[0]);
 }
+#endif /* !_WIN32 */
 
 int openconnect_setup_tun_device(struct openconnect_info *vpninfo, char *vpnc_script, char *ifname)
 {
@@ -810,8 +823,10 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout)
 void shutdown_tun(struct openconnect_info *vpninfo)
 {
 	if (vpninfo->script_tun) {
+#ifndef _WIN32
 		/* nuke the whole process group */
 		kill(-vpninfo->script_tun, SIGHUP);
+#endif
 	} else {
 		script_config_tun(vpninfo, "disconnect");
 #ifdef __sun__
diff --git a/xml.c b/xml.c
index 789bdbe..befdae7 100644
--- a/xml.c
+++ b/xml.c
@@ -29,30 +29,25 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#ifdef HAVE_MMAP
 #include <sys/mman.h>
+#endif
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include <string.h>
 
 #include "openconnect-internal.h"
 
-int config_lookup_host(struct openconnect_info *vpninfo, const char *host)
+static
+int load_xml_conf_file(const char* file, char** ptr, size_t* size)
 {
-	int fd, i;
 	struct stat st;
+	int fd;
 	char *xmlfile;
-	unsigned char sha1[SHA1_SIZE];
-	xmlDocPtr xml_doc;
-	xmlNode *xml_node, *xml_node2;
 
-	if (!vpninfo->xmlconfig)
-		return 0;
-
-	fd = open(vpninfo->xmlconfig, O_RDONLY);
+	fd = open(file, O_RDONLY);
 	if (fd < 0) {
 		perror(_("Open XML config file"));
-		fprintf(stderr, _("Treating host \"%s\" as a raw hostname\n"),
-			host);
 		return 0;
 	}
 
@@ -62,18 +57,64 @@ int config_lookup_host(struct openconnect_info *vpninfo, const char *host)
 		return -1;
 	}
 
+#ifdef HAVE_MMAP
 	xmlfile = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
 	if (xmlfile == MAP_FAILED) {
 		perror(_("mmap XML config file"));
 		close(fd);
 		return -1;
 	}
+#else
+	xmlfile = malloc(st.st_size);
 
-	if (openconnect_sha1(sha1, xmlfile, st.st_size)) {
-		fprintf(stderr, _("Failed to SHA1 existing file\n"));
+	if (read(fd, xmlfile, st.st_size) != st.st_size) {
+		perror(_("read XML config file"));
 		close(fd);
 		return -1;
 	}
+#endif
+	*ptr = xmlfile;
+	*size = st.st_size;
+
+	close(fd);
+	
+	return 1;
+}
+
+static
+void unload_xml_conf_file(void* ptr, size_t size)
+{
+#ifdef HAVE_MMAP
+	munmap(xmlfile, size);
+#else
+	free(ptr);
+#endif
+}
+
+int config_lookup_host(struct openconnect_info *vpninfo, const char *host)
+{
+	int i, ret;
+	size_t size;
+	char *xmlfile;
+	unsigned char sha1[SHA1_SIZE];
+	xmlDocPtr xml_doc;
+	xmlNode *xml_node, *xml_node2;
+
+	if (!vpninfo->xmlconfig)
+		return 0;
+
+	ret = load_xml_conf_file(vpninfo->xmlconfig, &xmlfile, &size);
+	if (ret <= 0) {
+		if (ret == 0)
+			fprintf(stderr, _("Treating host \"%s\" as a raw hostname\n"),
+				host);
+		return ret;
+	}
+
+	if (openconnect_sha1(sha1, xmlfile, size)) {
+		fprintf(stderr, _("Failed to SHA1 existing file\n"));
+		return -1;
+	}
 
 	for (i = 0; i < SHA1_SIZE; i++)
 		sprintf(&vpninfo->xmlsha1[i*2], "%02x", sha1[i]);
@@ -81,9 +122,10 @@ int config_lookup_host(struct openconnect_info *vpninfo, const char *host)
 	vpn_progress(vpninfo, PRG_TRACE, _("XML config file SHA1: %s\n"),
 		     vpninfo->xmlsha1);
 
-	xml_doc = xmlReadMemory(xmlfile, st.st_size, "noname.xml", NULL, 0);
-	munmap(xmlfile, st.st_size);
-	close(fd);
+	xml_doc = xmlReadMemory(xmlfile, size, "noname.xml", NULL, 0);
+
+	unload_xml_conf_file(xmlfile, size);
+
 	if (!xml_doc) {
 		fprintf(stderr, _("Failed to parse XML config file %s\n"),
 			vpninfo->xmlconfig);

-- 
dwmw2
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5745 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/openconnect-devel/attachments/20140203/2abde52f/attachment-0001.bin>


More information about the openconnect-devel mailing list