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>