Move ui and cstp stuff out of ssl.c
authorDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 4 Oct 2008 18:02:53 +0000 (19:02 +0100)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 4 Oct 2008 18:02:53 +0000 (19:02 +0100)
Makefile
anyconnect.h
main.c
ssl.c
ssl_ui.c [new file with mode: 0644]

index bc1766e..754c14e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ XML2_LDFLAGS += $(shell xml2-config --libs)
 CFLAGS := $(OPT_FLAGS) $(SSL_CFLAGS) $(XML2_CFLAGS) $(EXTRA_CFLAGS)
 LDFLAGS := $(SSL_LDFLAGS) $(XML2_LDFLAGS) $(EXTRA_LDFLAGS)
 
-OBJECTS := main.o tun.o dtls.o ssl.o mainloop.o xml.o http.o
+OBJECTS := main.o tun.o dtls.o ssl.o mainloop.o xml.o http.o cstp.o ssl_ui.o
 
 all: anyconnect
 
index cee2176..a5dceed 100644 (file)
@@ -162,6 +162,7 @@ int connect_dtls_socket(struct anyconnect_info *vpninfo);
 int make_cstp_connection(struct anyconnect_info *vpninfo);
 int cstp_mainloop(struct anyconnect_info *vpninfo, int *timeout);
 int cstp_bye(struct anyconnect_info *vpninfo, char *reason);
+
 /* ssl.c */
 void vpn_init_openssl(void);
 int  __attribute__ ((format (printf, 2, 3)))
@@ -189,3 +190,6 @@ int process_http_response(struct anyconnect_info *vpninfo, int *result,
                          int (*header_cb)(struct anyconnect_info *, char *, char *),
                          char *body, int buf_len);
 int obtain_cookie(struct anyconnect_info *vpninfo);
+
+/* ssl_ui.c */
+int set_openssl_ui(void);
diff --git a/main.c b/main.c
index 2ae93d3..8bd13c4 100644 (file)
--- a/main.c
+++ b/main.c
@@ -207,6 +207,8 @@ int main(int argc, char **argv)
                vpninfo->hostname = strdup(argv[optind]);
        vpninfo->urlpath = strdup("/");
 
+       set_openssl_ui();
+
        if (!vpninfo->cookie && obtain_cookie(vpninfo)) {
                fprintf(stderr, "Failed to obtain WebVPN cookie\n");
                exit(1);
diff --git a/ssl.c b/ssl.c
index 374d1a5..472e1fb 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -24,7 +24,6 @@
 #include <netdb.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <time.h>
 
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 
 #include "anyconnect.h"
 
-/*
- * Data packets are encapsulated in the SSL stream as follows:
- * 
- * 0000: Magic "STF\x1"
- * 0004: Big-endian 16-bit length (not including 8-byte header)
- * 0006: Byte packet type (see anyconnect.h)
- * 0008: data payload
- */
-
-static char data_hdr[8] = {
-       'S', 'T', 'F', 1,
-       0, 0,           /* Length */
-       AC_PKT_DATA,    /* Type */
-       0               /* Unknown */
-};
-
 /* Helper functions for reading/writing lines over SSL.
    We could use cURL for the HTTP stuff, but it's overkill */
 
@@ -100,44 +83,8 @@ int my_SSL_gets(SSL *ssl, char *buf, size_t len)
 }
 
 
-/* OpenSSL UI method calls. These are just stubs, to show how it's done */
-/* While we can set user data on the calls from the TPM setup, we can't
-   set it on the calls for PEM certificate passphrases, AFAICT. */
-static int ui_open(UI *ui)
-{
-       /* Fall through to default OpenSSL UI */
-       return UI_method_get_opener(UI_OpenSSL())(ui);
-}
-
-static int ui_read(UI *ui, UI_STRING *uis)
-{
-       /* Fall through to default OpenSSL UI */
-       return UI_method_get_reader(UI_OpenSSL())(ui, uis);
-}
-static int ui_write(UI *ui, UI_STRING *uis)
-{
-       /* Fall through to default OpenSSL UI */
-       return UI_method_get_writer(UI_OpenSSL())(ui, uis);
-
-}
-static int ui_close(UI *ui)
-{
-       /* Fall through to default OpenSSL UI */
-       return UI_method_get_closer(UI_OpenSSL())(ui);
-}
-
 static int load_certificate(struct anyconnect_info *vpninfo)
 {
-       UI_METHOD *ui_method = UI_create_method("AnyConnect VPN UI");
-
-       /* Set up a UI method of our own for password/passphrase requests */
-       UI_method_set_opener(ui_method, ui_open);
-       UI_method_set_reader(ui_method, ui_read);
-       UI_method_set_writer(ui_method, ui_write);
-       UI_method_set_closer(ui_method, ui_close);
-
-       UI_set_default_method(ui_method);
-
        if (verbose)
                printf("Using Certificate file %s\n", vpninfo->cert);
        if (!SSL_CTX_use_certificate_file(vpninfo->https_ctx, vpninfo->cert,
@@ -309,558 +256,3 @@ void vpn_init_openssl(void)
        OpenSSL_add_all_algorithms ();
 }
 
-
-static int start_cstp_connection(struct anyconnect_info *vpninfo)
-{
-       char buf[65536];
-       int i;
-       int retried = 0;
-       struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
-       struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
-       struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
-       struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
-       const char *old_addr = vpninfo->vpn_addr;
-       const char *old_netmask = vpninfo->vpn_netmask;
-
-       /* Clear old options which will be overwritten */
-       vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
-       vpninfo->cstp_options = vpninfo->dtls_options = NULL;
-       for (i=0; i<3; i++)
-               vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
-
- retry:
-       my_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
-       my_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
-       my_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
-       my_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
-       my_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
-       my_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
-       if (vpninfo->deflate)
-               my_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
-       my_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
-       /* To enable IPv6, send 'IPv6,IPv4'.
-          We don't know how most of that works yet though. */
-       my_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv4\r\n");
-       my_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
-       for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
-               my_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
-       my_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
-
-       if (my_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
-               fprintf(stderr, "Error fetching HTTPS response\n");
-               if (!retried) {
-                       retried = 1;
-                       SSL_free(vpninfo->https_ssl);
-                       close(vpninfo->ssl_fd);
-               
-                       if (open_https(vpninfo)) {
-                               fprintf(stderr, "Failed to open HTTPS connection to %s\n",
-                                       vpninfo->hostname);
-                               exit(1);
-                       }
-                       goto retry;
-               }
-               return -EINVAL;
-       }
-
-       if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
-               fprintf(stderr, "Got inappropriate HTTP CONNECT response: %s\n",
-                       buf);
-               if (!strncmp(buf, "HTTP/1.1 401 ", 13))
-                       exit(2);
-               my_SSL_gets(vpninfo->https_ssl, buf, 65536);
-               return -EINVAL;
-       }
-
-       if (verbose)
-               printf("Got CONNECT response: %s\n", buf);
-
-       /* We may have advertised it, but we only do it if the server agrees */
-       vpninfo->deflate = 0;
-
-       while ((i=my_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
-               struct vpn_option *new_option;
-               char *colon = strchr(buf, ':');
-               if (!colon)
-                       continue;
-
-               *colon = 0;
-               colon++;
-               if (*colon == ' ')
-                       colon++;
-
-               if (strncmp(buf, "X-DTLS-", 7) &&
-                   strncmp(buf, "X-CSTP-", 7))
-                       continue;
-
-               new_option = malloc(sizeof(*new_option));
-               if (!new_option) {
-                       fprintf(stderr, "No memory for options\n");
-                       return -ENOMEM;
-               }
-               new_option->option = strdup(buf);
-               new_option->value = strdup(colon);
-               new_option->next = NULL;
-
-               if (!new_option->option || !new_option->value) {
-                       fprintf(stderr, "No memory for options\n");
-                       return -ENOMEM;
-               }
-
-               if (verbose)
-                       printf("%s: %s\n", buf, colon);
-
-               if (!strncmp(buf, "X-DTLS-", 7)) {
-                       *next_dtls_option = new_option;
-                       next_dtls_option = &new_option->next;
-                       continue;
-               }
-               /* CSTP options... */
-               *next_cstp_option = new_option;
-               next_cstp_option = &new_option->next;
-
-
-               if (!strcmp(buf + 7, "Keepalive")) {
-                       vpninfo->ssl_times.keepalive = atol(colon);
-               } else if (!strcmp(buf + 7, "DPD")) {
-                       vpninfo->ssl_times.dpd = atol(colon);
-               } else if (!strcmp(buf + 7, "Content-Encoding")) {
-                       if (!strcmp(colon, "deflate"))
-                               vpninfo->deflate = 1;
-                       else {
-                               fprintf(stderr, 
-                                       "Unknown CSTP-Content-Encoding %s\n",
-                                       colon);
-                               return -EINVAL;
-                       }
-               } else if (!strcmp(buf + 7, "MTU")) {
-                       vpninfo->mtu = atol(colon);
-               } else if (!strcmp(buf + 7, "Address")) {
-                       vpninfo->vpn_addr = new_option->value;
-               } else if (!strcmp(buf + 7, "Netmask")) {
-                       vpninfo->vpn_netmask = new_option->value;
-               } else if (!strcmp(buf + 7, "DNS")) {
-                       int j;
-                       for (j = 0; j < 3; j++) {
-                               if (!vpninfo->vpn_dns[j]) {
-                                       vpninfo->vpn_dns[j] = new_option->value;
-                                       break;
-                               }
-                       }
-               } else if (!strcmp(buf + 7, "NBNS")) {
-                       int j;
-                       for (j = 0; j < 3; j++) {
-                               if (!vpninfo->vpn_nbns[j]) {
-                                       vpninfo->vpn_nbns[j] = new_option->value;
-                                       break;
-                               }
-                       }
-               } else if (!strcmp(buf + 7, "Default-Domain")) {
-                       vpninfo->vpn_domain = new_option->value;
-               }
-       }
-
-       if (!vpninfo->vpn_addr) {
-               fprintf(stderr, "No IP address received. Aborting\n");
-               return -EINVAL;
-       }
-       if (!vpninfo->vpn_netmask)
-               vpninfo->vpn_netmask = "255.255.255.255";
-       if (old_addr) {
-               if (strcmp(old_addr, vpninfo->vpn_addr)) {
-                       fprintf(stderr, "Reconnect gave different IP address (%s != %s)\n",
-                               vpninfo->vpn_addr, old_addr);
-                       return -EINVAL;
-               }
-       }
-       if (old_netmask) {
-               if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
-                       fprintf(stderr, "Reconnect gave different netmask (%s != %s)\n",
-                               vpninfo->vpn_netmask, old_netmask);
-                       return -EINVAL;
-               }
-       }
-
-       while (old_dtls_opts) {
-               struct vpn_option *tmp = old_dtls_opts;
-               old_dtls_opts = old_dtls_opts->next;
-               free(tmp->value);
-               free(tmp->option);
-               free(tmp);
-       }
-       while (old_cstp_opts) {
-               struct vpn_option *tmp = old_cstp_opts;
-               old_cstp_opts = old_cstp_opts->next;
-               free(tmp->value);
-               free(tmp->option);
-               free(tmp);
-       }
-       if (verbose)
-               printf("SSL connected. DPD %d, Keepalive %d\n",
-                      vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
-
-       BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl),1);
-       BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl),1);
-
-       fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
-       vpninfo->ssl_pfd = vpn_add_pollfd(vpninfo, vpninfo->ssl_fd, POLLIN|POLLHUP|POLLERR);
-
-       vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
-       return 0;
-}
-
-
-int make_cstp_connection(struct anyconnect_info *vpninfo)
-{
-       if (!vpninfo->https_ssl && open_https(vpninfo))
-               exit(1);
-
-       if (vpninfo->deflate) {
-               vpninfo->deflate_adler32 = 1;
-               vpninfo->inflate_adler32 = 1;
-
-               if (inflateInit2(&vpninfo->inflate_strm, -12) ||
-                   deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
-                                Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
-                       fprintf(stderr, "Compression setup failed\n");
-                       vpninfo->deflate = 0;
-               }
-
-               if (!vpninfo->deflate_pkt) {
-                       vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
-                       if (!vpninfo->deflate_pkt) {
-                               fprintf(stderr, "Allocation of deflate buffer failed\n");
-                               vpninfo->deflate = 0;
-                       }
-                       memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
-                       memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
-                       vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
-               }
-       }
-
-       if (start_cstp_connection(vpninfo))
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static int inflate_and_queue_packet(struct anyconnect_info *vpninfo, int type, void *buf, int len)
-{
-       struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
-
-       if (!new)
-               return -ENOMEM;
-
-       new->type = type;
-       new->next = NULL;
-
-       vpninfo->inflate_strm.next_in = buf;
-       vpninfo->inflate_strm.avail_in = len - 4;
-
-       vpninfo->inflate_strm.next_out = new->data;
-       vpninfo->inflate_strm.avail_out = vpninfo->mtu;
-       vpninfo->inflate_strm.total_out = 0;
-
-       if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
-               fprintf(stderr, "inflate failed\n");
-               free(new);
-               return -EINVAL;
-       }
-
-       new->len = vpninfo->inflate_strm.total_out;
-
-       vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
-                                          new->data, new->len);
-
-       if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *)(buf + len - 4))) {
-               vpninfo->quit_reason = "Compression (inflate) adler32 failure";
-       }
-
-       if (verbose) {
-               printf("Received compressed data packet of %ld bytes\n",
-                      vpninfo->inflate_strm.total_out);
-       }
-
-       queue_packet(&vpninfo->incoming_queue, new);
-       return 0;
-}
-
-static struct pkt keepalive_pkt = {
-       .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
-};
-
-static struct pkt dpd_pkt = {
-       .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
-};
-
-static struct pkt dpd_resp_pkt = {
-       .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
-};
-
-int cstp_mainloop(struct anyconnect_info *vpninfo, int *timeout)
-{
-       unsigned char buf[16384];
-       int len, ret;
-       int work_done = 0;
-
-       /* FIXME: The poll() handling here is fairly simplistic. Actually,
-          if the SSL connection stalls it could return a WANT_WRITE error
-          on _either_ of the SSL_read() or SSL_write() calls. In that case,
-          we should probably remove POLLIN from the events we're looking for,
-          and add POLLOUT. As it is, though, it'll just chew CPU time in that
-          fairly unlikely situation, until the write backlog clears. */
-       while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
-               int payload_len;
-
-               if (buf[0] != 'S' || buf[1] != 'T' ||
-                   buf[2] != 'F' || buf[3] != 1 || buf[7])
-                       goto unknown_pkt;
-
-               payload_len = (buf[4] << 8) + buf[5];
-               if (len != 8 + payload_len) {
-                       printf("Unexpected packet length. SSL_read returned %d but packet is\n",
-                              len);
-                       printf("%02x %02x %02x %02x %02x %02x %02x %02x\n",
-                              buf[0], buf[1], buf[2], buf[3],
-                              buf[4], buf[5], buf[6], buf[7]);
-                       continue;
-               }
-               vpninfo->ssl_times.last_rx = time(NULL);
-               switch(buf[6]) {
-               case AC_PKT_DPD_OUT:
-                       if (verbose)
-                               printf("Got CSTP DPD request\n");
-                       vpninfo->owe_ssl_dpd_response = 1;
-                       continue;
-
-               case AC_PKT_DPD_RESP:
-                       if (verbose)
-                               printf("Got CSTP DPD response\n");
-                       continue;
-
-               case AC_PKT_KEEPALIVE:
-                       if (verbose)
-                               printf("Got CSTP Keepalive\n");
-                       continue;
-
-               case AC_PKT_DATA:
-                       if (verbose) {
-                               printf("Received uncompressed data packet of %d bytes\n",
-                                      payload_len);
-                       }
-                       queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
-                                        payload_len);
-                       work_done = 1;
-                       continue;
-
-               case AC_PKT_COMPRESSED:
-                       if (!vpninfo->deflate) {
-                               fprintf(stderr, "Compressed packet received in !deflate mode\n");
-                               goto unknown_pkt;
-                       }
-                       inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
-                       work_done = 1;
-                       continue;
-
-               case AC_PKT_TERM_SERVER:
-                       fprintf(stderr, "received server terminate packet\n");
-                       vpninfo->quit_reason = "Server request";
-                       return 1;
-               }
-
-       unknown_pkt:
-               printf("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                      buf[0], buf[1], buf[2], buf[3],
-                      buf[4], buf[5], buf[6], buf[7]);
-               vpninfo->quit_reason = "Unknown packet received";
-               return 1;
-       }
-
-
-       /* If SSL_write() fails we are expected to try again. With exactly
-          the same data, at exactly the same location. So we keep the 
-          packet we had before.... */
-       if (vpninfo->current_ssl_pkt) {
-       handle_outgoing:
-               vpninfo->ssl_times.last_tx = time(NULL);
-               vpninfo->pfds[vpninfo->ssl_pfd].events &= ~POLLOUT;
-               ret = SSL_write(vpninfo->https_ssl,
-                               vpninfo->current_ssl_pkt->hdr,
-                               vpninfo->current_ssl_pkt->len + 8);
-               if (ret <= 0) {
-                       ret = SSL_get_error(vpninfo->https_ssl, ret);
-                       switch (ret) {
-                       case SSL_ERROR_WANT_WRITE:
-                               /* Waiting for the socket to become writable -- it's
-                                  probably stalled, and/or the buffers are full */
-                               vpninfo->pfds[vpninfo->ssl_pfd].events |= POLLOUT;
-                       case SSL_ERROR_WANT_READ:
-                               if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
-                                       goto peer_dead;
-                               return work_done;
-                       default:
-                               fprintf(stderr, "SSL_write failed: %d", ret);
-                               ERR_print_errors_fp(stderr);
-                               vpninfo->quit_reason = "SSL write error";
-                               return 1;
-                       }
-               }
-               if (ret != vpninfo->current_ssl_pkt->len + 8) {
-                       fprintf(stderr, "SSL wrote too few bytes! Asked for %d, sent %d\n",
-                               vpninfo->current_ssl_pkt->len + 8, ret);
-                       vpninfo->quit_reason = "Internal error";
-                       return 1;
-               }
-               /* Don't free the 'special' packets */
-               if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
-                   vpninfo->current_ssl_pkt != &dpd_pkt &&
-                   vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
-                   vpninfo->current_ssl_pkt != &keepalive_pkt)
-                       free(vpninfo->current_ssl_pkt);
-
-               vpninfo->current_ssl_pkt = NULL;
-       }
-
-       if (vpninfo->owe_ssl_dpd_response) {
-               vpninfo->owe_ssl_dpd_response = 0;
-               vpninfo->current_ssl_pkt = &dpd_resp_pkt;
-               goto handle_outgoing;
-       }
-
-       switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
-       case KA_REKEY:
-               /* Not that this will ever happen; we don't even process
-                  the setting when we're asked for it. */
-               fprintf(stderr, "CSTP rekey due but we don't know how\n");
-               time(&vpninfo->ssl_times.last_rekey);
-               work_done = 1;
-               break;
-
-       case KA_DPD_DEAD:
-       peer_dead:
-               fprintf(stderr, "CSTP Dead Peer Detection detected dead peer!\n");
-               SSL_free(vpninfo->https_ssl);
-               vpninfo->https_ssl = NULL;
-               close(vpninfo->ssl_fd);
-
-               /* It's already deflated in the old stream. Extremely 
-                  non-trivial to reconstitute it; just throw it away */
-               if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
-                       vpninfo->current_ssl_pkt = NULL;
-
-               if (make_cstp_connection(vpninfo)) {
-                       fprintf(stderr, "Reconnect failed\n");
-                       vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
-                       return 1;
-               }
-               /* I think we can leave DTLS to its own devices; when we reconnect
-                  with the same master secret, we do seem to get the same sessid */
-               return 1;
-
-       case KA_DPD:
-               if (verbose)
-                       printf("Send CSTP DPD\n");
-
-               vpninfo->current_ssl_pkt = &dpd_pkt;
-               goto handle_outgoing;
-
-       case KA_KEEPALIVE:
-               /* No need to send an explicit keepalive
-                  if we have real data to send */
-               if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
-                       break;
-
-               if (verbose)
-                       printf("Send CSTP Keepalive\n");
-
-               vpninfo->current_ssl_pkt = &keepalive_pkt;
-               goto handle_outgoing;
-
-       case KA_NONE:
-               ;
-       }
-
-       /* Service outgoing packet queue, if no DTLS */
-       while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
-               struct pkt *this = vpninfo->outgoing_queue;
-               vpninfo->outgoing_queue = this->next;
-
-               if (vpninfo->deflate) {
-                       unsigned char *adler;
-                       int ret;
-
-                       vpninfo->deflate_strm.next_in = this->data;
-                       vpninfo->deflate_strm.avail_in = this->len;
-                       vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
-                       vpninfo->deflate_strm.avail_out = 2040;
-                       vpninfo->deflate_strm.total_out = 0;
-
-                       ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
-                       if (ret) {
-                               fprintf(stderr, "deflate failed %d\n", ret);
-                               goto uncompr;
-                       }
-
-                       vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
-                       vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
-
-                       /* Add ongoing adler32 to tail of compressed packet */
-                       vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
-                                                          this->data, this->len);
-
-                       adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
-                       *(adler++) =  vpninfo->deflate_adler32 >> 24;
-                       *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
-                       *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
-                       *(adler)   =  vpninfo->deflate_adler32 & 0xff;
-
-                       vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
-
-                       if (verbose) {
-                               printf("Sending compressed data packet of %d bytes\n",
-                                      this->len);
-                       }
-                       vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
-               } else {
-               uncompr:
-                       memcpy(this->hdr, data_hdr, 8);
-                       this->hdr[4] = this->len >> 8;
-                       this->hdr[5] = this->len & 0xff;
-
-                       if (verbose) {
-                               printf("Sending uncompressed data packet of %d bytes\n",
-                                      this->len);
-                       }
-                       vpninfo->current_ssl_pkt = this;
-               }
-               goto handle_outgoing;
-       }
-
-       /* Work is not done if we just got rid of packets off the queue */
-       return work_done;
-}
-
-int cstp_bye(struct anyconnect_info *vpninfo, char *reason)
-{
-       unsigned char *bye_pkt;
-       int reason_len = strlen(reason);
-       bye_pkt = malloc(reason_len + 8);
-       if (!bye_pkt)
-               return -ENOMEM;
-       
-       memcpy(bye_pkt, data_hdr, 8);
-       memcpy(bye_pkt + 8, reason, strlen(reason));
-
-       bye_pkt[4] = reason_len >> 8;
-       bye_pkt[5] = reason_len & 0xff;
-       bye_pkt[6] = 5;
-
-       SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
-       free(bye_pkt);
-
-       if (verbose)
-               printf("Send BYE packet: %s\n", reason);
-
-       return 0;
-}
diff --git a/ssl_ui.c b/ssl_ui.c
new file mode 100644 (file)
index 0000000..60d72b7
--- /dev/null
+++ b/ssl_ui.c
@@ -0,0 +1,66 @@
+/*
+ * Open AnyConnect (SSL + DTLS) client
+ *
+ * © 2008 David Woodhouse <dwmw2@infradead.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ */
+#include <openssl/ssl.h>
+#include <openssl/ui.h>
+
+/* OpenSSL UI method calls. These are just stubs, to show how it's done */
+/* While we can set user data on the calls from the TPM setup, we can't
+   set it on the calls for PEM certificate passphrases, AFAICT. */
+static int ui_open(UI *ui)
+{
+       /* Fall through to default OpenSSL UI */
+       return UI_method_get_opener(UI_OpenSSL())(ui);
+}
+
+static int ui_read(UI *ui, UI_STRING *uis)
+{
+       /* Fall through to default OpenSSL UI */
+       return UI_method_get_reader(UI_OpenSSL())(ui, uis);
+}
+static int ui_write(UI *ui, UI_STRING *uis)
+{
+       /* Fall through to default OpenSSL UI */
+       return UI_method_get_writer(UI_OpenSSL())(ui, uis);
+
+}
+static int ui_close(UI *ui)
+{
+       /* Fall through to default OpenSSL UI */
+       return UI_method_get_closer(UI_OpenSSL())(ui);
+}
+
+int set_openssl_ui(void)
+{
+       UI_METHOD *ui_method = UI_create_method("AnyConnect VPN UI");
+
+       /* Set up a UI method of our own for password/passphrase requests */
+       UI_method_set_opener(ui_method, ui_open);
+       UI_method_set_reader(ui_method, ui_read);
+       UI_method_set_writer(ui_method, ui_write);
+       UI_method_set_closer(ui_method, ui_close);
+
+       UI_set_default_method(ui_method);
+
+       return 0;
+}
+