openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
- fprintf(stderr, "Error fetching HTTPS response\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
if (!retried) {
retried = 1;
SSL_free(vpninfo->https_ssl);
close(vpninfo->ssl_fd);
if (openconnect_open_https(vpninfo)) {
- fprintf(stderr, "Failed to open HTTPS connection to %s\n",
- vpninfo->hostname);
+ vpninfo->progress(vpninfo, PRG_ERR,
+ "Failed to open HTTPS connection to %s\n",
+ vpninfo->hostname);
exit(1);
}
goto retry;
}
if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
- fprintf(stderr, "Got inappropriate HTTP CONNECT response: %s\n",
- buf);
+ vpninfo->progress(vpninfo, PRG_ERR,
+ "Got inappropriate HTTP CONNECT response: %s\n",
+ buf);
if (!strncmp(buf, "HTTP/1.1 401 ", 13))
exit(2);
openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536);
return -EINVAL;
}
- if (verbose)
- printf("Got CONNECT response: %s\n", buf);
+ vpninfo->progress(vpninfo, PRG_INFO,
+ "Got CONNECT response: %s\n", buf);
/* We may have advertised it, but we only do it if the server agrees */
vpninfo->deflate = 0;
new_option = malloc(sizeof(*new_option));
if (!new_option) {
- fprintf(stderr, "No memory for options\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
return -ENOMEM;
}
new_option->option = strdup(buf);
new_option->next = NULL;
if (!new_option->option || !new_option->value) {
- fprintf(stderr, "No memory for options\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
return -ENOMEM;
}
- if (verbose)
- printf("%s: %s\n", buf, colon);
+ vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
if (!strncmp(buf, "X-DTLS-", 7)) {
*next_dtls_option = new_option;
if (!strcmp(colon, "deflate"))
vpninfo->deflate = 1;
else {
- fprintf(stderr,
+ vpninfo->progress(vpninfo, PRG_ERR,
"Unknown CSTP-Content-Encoding %s\n",
colon);
return -EINVAL;
}
if (!vpninfo->vpn_addr) {
- fprintf(stderr, "No IP address received. Aborting\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "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->progress(vpninfo, PRG_ERR, "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->progress(vpninfo, PRG_ERR, "Reconnect gave different netmask (%s != %s)\n",
vpninfo->vpn_netmask, old_netmask);
return -EINVAL;
}
free(tmp->option);
free(tmp);
}
- if (verbose)
- printf("CSTP connected. DPD %d, Keepalive %d\n",
- vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
+ vpninfo->progress(vpninfo, PRG_INFO, "CSTP 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);
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->progress(vpninfo, PRG_ERR, "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->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
vpninfo->deflate = 0;
}
memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
vpninfo->inflate_strm.total_out = 0;
if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
- fprintf(stderr, "inflate failed\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
free(new);
return -EINVAL;
}
vpninfo->quit_reason = "Compression (inflate) adler32 failure";
}
- if (verbose) {
- printf("Received compressed data packet of %ld bytes\n",
- vpninfo->inflate_strm.total_out);
- }
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Received compressed data packet of %ld bytes\n",
+ vpninfo->inflate_strm.total_out);
queue_packet(&vpninfo->incoming_queue, new);
return 0;
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]);
+ vpninfo->progress(vpninfo, PRG_ERR,
+ "Unexpected packet length. SSL_read returned %d but packet is\n",
+ len);
+ vpninfo->progress(vpninfo, PRG_ERR,
+ "%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->progress(vpninfo, PRG_TRACE,
+ "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");
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Got CSTP DPD response\n");
continue;
case AC_PKT_KEEPALIVE:
- if (verbose)
- printf("Got CSTP Keepalive\n");
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Got CSTP Keepalive\n");
continue;
case AC_PKT_DATA:
- if (verbose) {
- printf("Received uncompressed data packet of %d bytes\n",
- payload_len);
- }
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "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;
case AC_PKT_COMPRESSED:
if (!vpninfo->deflate) {
- fprintf(stderr, "Compressed packet received in !deflate mode\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
goto unknown_pkt;
}
inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
continue;
case AC_PKT_TERM_SERVER:
- fprintf(stderr, "received server terminate packet\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "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->progress(vpninfo, PRG_ERR,
+ "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;
}
goto peer_dead;
return work_done;
default:
- fprintf(stderr, "SSL_write failed: %d", ret);
+ vpninfo->progress(vpninfo, PRG_ERR, "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->progress(vpninfo, PRG_ERR, "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;
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");
+ vpninfo->progress(vpninfo, PRG_ERR, "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");
+ vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
SSL_free(vpninfo->https_ssl);
vpninfo->https_ssl = NULL;
close(vpninfo->ssl_fd);
vpninfo->current_ssl_pkt = NULL;
if (make_cstp_connection(vpninfo)) {
- fprintf(stderr, "Reconnect failed\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
return 1;
}
return 1;
case KA_DPD:
- if (verbose)
- printf("Send CSTP DPD\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
vpninfo->current_ssl_pkt = &dpd_pkt;
goto handle_outgoing;
if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
break;
- if (verbose)
- printf("Send CSTP Keepalive\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
vpninfo->current_ssl_pkt = &keepalive_pkt;
goto handle_outgoing;
ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
if (ret) {
- fprintf(stderr, "deflate failed %d\n", ret);
+ vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
goto uncompr;
}
vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
- if (verbose) {
- printf("Sending compressed data packet of %d bytes\n",
- this->len);
- }
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Sending compressed data packet of %d bytes\n",
+ this->len);
+
vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
} else {
uncompr:
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->progress(vpninfo, PRG_TRACE,
+ "Sending uncompressed data packet of %d bytes\n",
+ this->len);
+
vpninfo->current_ssl_pkt = this;
}
goto handle_outgoing;
SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
free(bye_pkt);
- if (verbose)
- printf("Send BYE packet: %s\n", reason);
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Send BYE packet: %s\n", reason);
return 0;
}
dtls_method = DTLSv1_client_method();
vpninfo->dtls_ctx = SSL_CTX_new(dtls_method);
if (!vpninfo->dtls_ctx) {
- fprintf(stderr, "Initialise DTLSv1 CTX failed\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Initialise DTLSv1 CTX failed\n");
return -EINVAL;
}
/* We're going to "resume" a session which never existed. Fake it... */
vpninfo->dtls_session = SSL_SESSION_new();
if (!vpninfo->dtls_session) {
- fprintf(stderr, "Initialise DTLSv1 session failed\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Initialise DTLSv1 session failed\n");
return -EINVAL;
}
vpninfo->dtls_session->ssl_version = 0x0100; // DTLS1_BAD_VER
/* Add the generated session to the SSL */
if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) {
- printf("SSL_set_session() failed with old protocol version 0x%x\n",
- vpninfo->dtls_session->ssl_version);
- printf("Your OpenSSL may lack Cisco compatibility support\n");
- printf("See http://rt.openssl.org/Ticket/Display.html?id=1751\n");
- printf("Use the --no-dtls command line option to avoid this message\n");
+ vpninfo->progress(vpninfo, PRG_ERR,
+ "SSL_set_session() failed with old protocol version 0x%x\n"
+ "Your OpenSSL may lack Cisco compatibility support\n"
+ "See http://rt.openssl.org/Ticket/Display.html?id=1751\n"
+ "Use the --no-dtls command line option to avoid this message\n",
+ vpninfo->dtls_session->ssl_version);
return -EINVAL;
}
int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
if (ret == 1) {
- printf("Established DTLS connection\n");
+ vpninfo->progress(vpninfo, PRG_INFO, "Established DTLS connection\n");
vpninfo->dtls_state = DTLS_RUNNING;
if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
if (time(NULL) < vpninfo->new_dtls_started + 5)
return 0;
- if (verbose)
- printf("DTLS handshake timed out\n");
- } else if (verbose) {
- fprintf(stderr, "DTLS handshake failed: %d\n", ret);
- ERR_print_errors_fp(stderr);
+ vpninfo->progress(vpninfo, PRG_TRACE, "DTLS handshake timed out\n");
}
+ vpninfo->progress(vpninfo, PRG_ERR, "DTLS handshake failed: %d\n", ret);
+ ERR_print_errors_fp(stderr);
+
/* Kill the new (failed) connection... */
SSL_free(vpninfo->new_dtls_ssl);
vpninfo->pfds[vpninfo->new_dtls_pfd].fd = -1;
int i;
while (dtls_opt) {
- if (verbose)
- printf("DTLS option %s : %s\n", dtls_opt->option, dtls_opt->value);
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "DTLS option %s : %s\n",
+ dtls_opt->option, dtls_opt->value);
if (!strcmp(dtls_opt->option, "X-DTLS-Session-ID")) {
if (strlen(dtls_opt->value) != 64) {
- fprintf(stderr, "X-DTLS-Session-ID not 64 characters\n");
- fprintf(stderr, "Is: %s\n", dtls_opt->value);
+ vpninfo->progress(vpninfo, PRG_ERR, "X-DTLS-Session-ID not 64 characters\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Is: %s\n", dtls_opt->value);
return -EINVAL;
}
for (i = 0; i < 64; i += 2)
struct sockaddr_in6 *sin = (void *)vpninfo->peer_addr;
sin->sin6_port = htons(dtls_port);
} else {
- fprintf(stderr, "Unknown protocol family %d. Cannot do DTLS\n",
+ vpninfo->progress(vpninfo, PRG_ERR, "Unknown protocol family %d. Cannot do DTLS\n",
vpninfo->peer_addr->sa_family);
return -EINVAL;
}
if (connect_dtls_socket(vpninfo))
return -EINVAL;
- if (verbose)
- printf("DTLS connected. DPD %d, Keepalive %d\n",
- vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "DTLS connected. DPD %d, Keepalive %d\n",
+ vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
return 0;
}
char magic_pkt;
while ( (len = SSL_read(vpninfo->dtls_ssl, buf, sizeof(buf))) > 0 ) {
- if (verbose)
- printf("Received DTLS packet 0x%02x of %d bytes\n",
- buf[0], len);
+
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Received DTLS packet 0x%02x of %d bytes\n",
+ buf[0], len);
vpninfo->dtls_times.last_rx = time(NULL);
break;
case AC_PKT_DPD_OUT:
- if (verbose)
- printf("Got DTLS DPD request\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Got DTLS DPD request\n");
/* FIXME: What if the packet doesn't get through? */
magic_pkt = AC_PKT_DPD_RESP;
if (SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
- fprintf(stderr, "Failed to send DPD response. Expect disconnect\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to send DPD response. Expect disconnect\n");
continue;
case AC_PKT_DPD_RESP:
- if (verbose)
- printf("Got DTLS DPD response\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Got DTLS DPD response\n");
break;
case AC_PKT_KEEPALIVE:
- if (verbose)
- printf("Got DTLS Keepalive\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Got DTLS Keepalive\n");
break;
default:
* by downloading a reasonably-sized web page. Dropping the
* offending packets doesn't even seem to stall the TCP
* connection when it's the only traffic on the link. */
- fprintf(stderr, "Unknown DTLS packet type %02x, len %d\n", buf[0], len);
+ vpninfo->progress(vpninfo, PRG_ERR, "Unknown DTLS packet type %02x, len %d\n", buf[0], len);
break;
/*
vpninfo->quit_reason = "Unknown packet received";
switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
case KA_REKEY:
time(&vpninfo->dtls_times.last_rekey);
- if (verbose)
- printf("DTLS rekey due\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "DTLS rekey due\n");
if (connect_dtls_socket(vpninfo)) {
- fprintf(stderr, "DTLS rekey failed\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "DTLS rekey failed\n");
return 1;
}
work_done = 1;
case KA_DPD_DEAD:
- fprintf(stderr, "DTLS Dead Peer Detection detected dead peer!\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "DTLS Dead Peer Detection detected dead peer!\n");
/* Fall back to SSL, and start a new DTLS connection */
dtls_restart(vpninfo);
return 1;
case KA_DPD:
- if (verbose)
- printf("Send DTLS DPD\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Send DTLS DPD\n");
magic_pkt = AC_PKT_DPD_OUT;
SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
if (vpninfo->outgoing_queue)
break;
- if (verbose)
- printf("Send DTLS Keepalive\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Send DTLS Keepalive\n");
magic_pkt = AC_PKT_KEEPALIVE;
SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
/* If it's a real error, kill the DTLS connection and
requeue the packet to be sent over SSL */
if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
- fprintf(stderr, "DTLS got write error %d. Falling back to SSL\n", ret);
+ vpninfo->progress(vpninfo, PRG_ERR,
+ "DTLS got write error %d. Falling back to SSL\n", ret);
ERR_print_errors_fp(stderr);
dtls_restart(vpninfo);
vpninfo->outgoing_queue = this;
return 1;
}
time(&vpninfo->dtls_times.last_tx);
- if (verbose) {
- printf("Sent DTLS packet of %d bytes; SSL_write() returned %d\n",
- this->len, ret);
- }
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Sent DTLS packet of %d bytes; SSL_write() returned %d\n",
+ this->len, ret);
}
return work_done;
int i;
if (openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)) < 0) {
- fprintf(stderr, "Error fetching HTTPS response\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
exit(1);
}
}
if ((!http10 && strncmp(buf, "HTTP/1.1 ", 9)) || !(*result = atoi(buf+9))) {
- fprintf(stderr, "Failed to parse HTTP response '%s'\n", buf);
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to parse HTTP response '%s'\n", buf);
return -EINVAL;
}
- if (verbose || *result == 100)
- printf("Got HTTP response: %s\n", buf);
+ vpninfo->progress(vpninfo, PRG_TRACE, "Got HTTP response: %s\n", buf);
/* Eat headers... */
while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
char *colon;
- if (verbose)
- printf("%s\n", buf);
+ vpninfo->progress(vpninfo, PRG_TRACE, "%s\n", buf);
+
if (i < 0) {
- fprintf(stderr, "Error processing HTTP response\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Error processing HTTP response\n");
return -EINVAL;
}
colon = strchr(buf, ':');
if (!colon) {
- fprintf(stderr, "Ignoring unknown HTTP response line '%s'\n", buf);
+ vpninfo->progress(vpninfo, PRG_ERR, "Ignoring unknown HTTP response line '%s'\n", buf);
continue;
}
*(colon++) = 0;
if (!strcmp(buf, "Content-Length")) {
bodylen = atoi(colon);
if (bodylen < 0 || bodylen > buf_len) {
- fprintf(stderr, "Response body too large for buffer (%d > %d)\n",
+ vpninfo->progress(vpninfo, PRG_ERR, "Response body too large for buffer (%d > %d)\n",
bodylen, buf_len);
return -EINVAL;
}
*semicolon = 0;
if (!equals) {
- fprintf(stderr, "Invalid cookie offered: %s\n", buf);
+ vpninfo->progress(vpninfo, PRG_ERR, "Invalid cookie offered: %s\n", buf);
return -EINVAL;
}
*(equals++) = 0;
if (*equals) {
new = malloc(sizeof(*new));
if (!new) {
- fprintf(stderr, "No memory for allocating cookies\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "No memory for allocating cookies\n");
return -ENOMEM;
}
new->next = NULL;
if (!strcmp(colon, "chunked"))
bodylen = -1;
else {
- fprintf(stderr, "Unknown Transfer-Encoding: %s\n", colon);
+ vpninfo->progress(vpninfo, PRG_ERR, "Unknown Transfer-Encoding: %s\n", colon);
return -EINVAL;
}
}
while (done < bodylen) {
i = SSL_read(vpninfo->https_ssl, body + done, bodylen - done);
if (i < 0) {
- fprintf(stderr, "Error reading HTTP response body\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Error reading HTTP response body\n");
return -EINVAL;
}
done += i;
int chunklen, lastchunk = 0;
if (i < 0) {
- fprintf(stderr, "Error fetching chunk header\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Error fetching chunk header\n");
exit(1);
}
chunklen = strtol(buf, NULL, 16);
goto skip;
}
if (chunklen + done > buf_len) {
- fprintf(stderr, "Response body too large for buffer (%d > %d)\n",
+ vpninfo->progress(vpninfo, PRG_ERR, "Response body too large for buffer (%d > %d)\n",
chunklen + done, buf_len);
return -EINVAL;
}
while (chunklen) {
i = SSL_read(vpninfo->https_ssl, body + done, chunklen);
if (i < 0) {
- fprintf(stderr, "Error reading HTTP response body\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Error reading HTTP response body\n");
return -EINVAL;
}
chunklen -= i;
skip:
if ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
if (i < 0) {
- fprintf(stderr, "Error fetching HTTP response body\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTP response body\n");
} else {
- fprintf(stderr, "Error in chunked decoding. Expected '', got: '%s'",
+ vpninfo->progress(vpninfo, PRG_ERR, "Error in chunked decoding. Expected '', got: '%s'",
buf);
}
return -EINVAL;
char *form_name = (char *)xmlGetProp(xml_node, (unsigned char *)"name");
if (!form_name) {
- fprintf(stderr, "Form choice has no name\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Form choice has no name\n");
return -EINVAL;
}
continue;
if (strcmp(authtype, "sdi-via-proxy")) {
char *content = (char *)xmlNodeGetContent(xml_node);
- fprintf(stderr, "Unrecognised auth type %s, label '%s'\n", authtype, content);
+ vpninfo->progress(vpninfo, PRG_ERR, "Unrecognised auth type %s, label '%s'\n", authtype, content);
}
- if (verbose)
- printf("choosing %s %s\n", form_name, form_id);
+ vpninfo->progress(vpninfo, PRG_TRACE, "choosing %s %s\n", form_name, form_id);
append_opt(body, bodylen, form_name, form_id);
return 0;
}
- fprintf(stderr, "Didn't find appropriate auth-type choice\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Didn't find appropriate auth-type choice\n");
return -EINVAL;
}
token[0] = 0;
if (!ui) {
- fprintf(stderr, "Failed to create UI\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to create UI\n");
return -EINVAL;
}
if (form_error) {
continue;
}
if (strcmp((char *)xml_node->name, "input")) {
- printf("name %s not input\n", xml_node->name);
+ vpninfo->progress(vpninfo, PRG_TRACE, "name %s not input\n", xml_node->name);
continue;
}
input_type = (char *)xmlGetProp(xml_node, (unsigned char *)"type");
if (!input_type) {
- printf("No input type\n");
+ vpninfo->progress(vpninfo, PRG_INFO, "No input type in form\n");
continue;
}
input_name = (char *)xmlGetProp(xml_node, (unsigned char *)"name");
if (!input_name) {
- printf("No input name\n");
+ vpninfo->progress(vpninfo, PRG_INFO, "No input name in form\n");
continue;
}
if (!strcmp(input_type, "hidden")) {
char *value = (char *)xmlGetProp(xml_node, (unsigned char *)"value");
if (!value) {
- printf("No value for hidden input %s\n", input_name);
+ vpninfo->progress(vpninfo, PRG_INFO,
+ "No value for hidden input %s\n",
+ input_name);
continue;
}
pass_form_id = input_name;
}
- if (verbose)
- printf("Fixed options give %s\n", body);
+ vpninfo->progress(vpninfo, PRG_TRACE, "Fixed options give %s\n", body);
if (user_form_id && !vpninfo->username)
UI_add_input_string(ui, "Enter username: ", UI_INPUT_FLAG_ECHO, username, 1, 80);
ret = UI_process(ui);
if (ret) {
- fprintf(stderr, "Invalid inputs\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Invalid inputs\n");
return -EINVAL;
}
if (user_form_id)
xml_doc = xmlReadMemory(response, strlen(response), "noname.xml", NULL, 0);
if (!xml_doc) {
- fprintf(stderr, "Failed to parse server response\n");
- if (verbose)
- printf("Response was:%s\n", response);
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to parse server response\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Response was:%s\n", response);
return -EINVAL;
}
xml_node = xmlDocGetRootElement(xml_doc);
if (xml_node->type != XML_ELEMENT_NODE ||
strcmp((char *)xml_node->name, "auth")) {
- fprintf(stderr, "XML response has no \"auth\" root node\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "XML response has no \"auth\" root node\n");
xmlFreeDoc(xml_doc);
return -EINVAL;
}
form_method = (char *)xmlGetProp(xml_node, (unsigned char *)"method");
form_action = (char *)xmlGetProp(xml_node, (unsigned char *)"action");
if (strcasecmp(form_method, "POST")) {
- fprintf(stderr, "Cannot handle form method '%s'\n",
+ vpninfo->progress(vpninfo, PRG_ERR, "Cannot handle form method '%s'\n",
form_method);
xmlFreeDoc(xml_doc);
return -EINVAL;
if (success)
return 0;
- fprintf(stderr, "Response neither indicated success nor requested input\n");
- printf("Response was:\n%s\n", response);
+ vpninfo->progress(vpninfo, PRG_ERR, "Response neither indicated success nor requested input\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Response was:\n%s\n", response);
return -EINVAL;
}
sprintf(&local_sha1_ascii[i*2], "%02x", local_sha1_bin[i]);
if (strcasecmp(server_sha1, local_sha1_ascii)) {
- fprintf(stderr, "Downloaded config file did not match intended SHA1\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Downloaded config file did not match intended SHA1\n");
return -EINVAL;
}
retry:
if (!vpninfo->https_ssl && openconnect_open_https(vpninfo)) {
- fprintf(stderr, "Failed to open HTTPS connection to %s\n",
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to open HTTPS connection to %s\n",
vpninfo->hostname);
exit(1);
}
vpninfo->redirect_url = NULL;
goto retry;
} else {
- fprintf(stderr, "Relative redirect (to '%s') not supported\n",
+ vpninfo->progress(vpninfo, PRG_ERR, "Relative redirect (to '%s') not supported\n",
vpninfo->redirect_url);
return -EINVAL;
}
if (vpninfo->cookie)
return 0;
- fprintf(stderr, "Server claimed successful login, but no cookie!\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Server claimed successful login, but no cookie!\n");
return -1;
}
#include "openconnect.h"
static int write_new_config(struct openconnect_info *vpninfo, char *buf, int buflen);
+static void write_progress(struct openconnect_info *info, int level, const char *fmt, ...);
-int verbose = 0;
+int verbose = PRG_INFO;
static struct option long_options[] = {
{"certificate", 1, 0, 'c'},
{"no-dtls", 0, 0, '1'},
{"cookieonly", 0, 0, '2'},
{"printcookie", 0, 0, '3'},
+ {"quiet", 0, 0, 'q'},
{"xmlconfig", 1, 0, 'x'},
{NULL, 0, 0, 0},
};
printf(" -t, --tpm Use TPM engine for private key\n");
printf(" -u, --user=NAME Set login username\n");
printf(" -V, --version Report version number\n");
+ printf(" -q, --quiet Less output\n");
printf(" -v, --verbose More output\n");
printf(" -x, --xmlconfig=CONFIG XML config file\n");
printf(" --cookieonly Fetch webvpn cookie only; don't connect\n");
vpninfo->deflate = 1;
vpninfo->dtls_attempt_period = 60;
vpninfo->write_new_config = write_new_config;
+ vpninfo->progress = write_progress;
if (RAND_bytes(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)) != 1) {
fprintf(stderr, "Failed to initialise DTLS secret\n");
else
vpninfo->localname = "localhost";
- while ((opt = getopt_long(argc, argv, "C:c:hvdDu:i:tk:p:s:hx:V",
+ while ((opt = getopt_long(argc, argv, "C:c:hvdDu:i:tk:p:qs:hx:V",
long_options, NULL))) {
if (opt < 0)
break;
case 'u':
vpninfo->username = optarg;
break;
+ case 'q':
+ verbose = PRG_ERR;
+ break;
case 'v':
- verbose = 1;
+ verbose = PRG_TRACE;
break;
case 'V':
printf("OpenConnect version %s\n", openconnect_version);
write(config_fd, buf, buflen);
return 0;
}
+
+void write_progress(struct openconnect_info *info, int level, const char *fmt, ...)
+{
+ FILE *outf = level?stdout:stderr;
+ va_list args;
+
+ if (verbose >= level) {
+ va_start(args, fmt);
+ vfprintf(outf, fmt, args);
+ va_end(args);
+ }
+}
vpninfo->nfds++;
vpninfo->pfds = realloc(vpninfo->pfds, sizeof(struct pollfd) * vpninfo->nfds);
if (!vpninfo->pfds) {
- fprintf(stderr, "Failed to reallocate pfds\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to reallocate pfds\n");
exit(1);
}
vpninfo->pfds[vpninfo->nfds - 1].fd = fd;
if (!vpninfo->dtls_ssl && !vpninfo->new_dtls_ssl &&
vpninfo->new_dtls_started + vpninfo->dtls_attempt_period < time(NULL)) {
- if (verbose)
- printf("Attempt new DTLS connection\n");
+ vpninfo->progress(vpninfo, PRG_TRACE, "Attempt new DTLS connection\n");
connect_dtls_socket(vpninfo);
}
if (vpninfo->dtls_ssl)
if (did_work)
continue;
- if (verbose)
- printf("Did no work; sleeping for %d ms...\n", timeout);
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Did no work; sleeping for %d ms...\n", timeout);
poll(vpninfo->pfds, vpninfo->nfds, timeout);
if (vpninfo->pfds[vpninfo->ssl_pfd].revents & POLL_HUP) {
- fprintf(stderr, "Server closed connection!\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Server closed connection!\n");
/* OpenSSL doesn't seem to cope properly with this... */
exit(1);
}
}
cstp_bye(vpninfo, vpninfo->quit_reason);
- printf("Sent quit message: %s\n", vpninfo->quit_reason);
+ vpninfo->progress(vpninfo, PRG_INFO, "Sent quit message: %s\n", vpninfo->quit_reason);
if (vpninfo->vpnc_script) {
setenv("TUNDEV", vpninfo->ifname, 1);
{
time_t now, due;
- if (!ka->dpd) {
- printf("no dpd\n");
+ if (!ka->dpd)
return 0;
- }
time(&now);
due = ka->last_rx + (2 * ka->dpd);
if (now > due)
return 1;
- printf("ka_stalled in %d seconds\n", (int)(due - now));
if (*timeout > (due - now) * 1000)
*timeout = (due - now) * 1000;
return 0;
}
-int verbose = 0;
+void write_progress(struct openconnect_info *info, int level, const char *fmt, ...)
+{
+ va_list args;
+
+ if (level <= PRG_INFO) {
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ }
+}
static struct option long_options[] = {
{"reprompt", 0, 0, 'r'},
vpninfo->useragent = openconnect_create_useragent("OpenConnect VPN Agent (NetworkManager)");
vpninfo->ssl_fd = -1;
vpninfo->write_new_config = write_new_config;
+ vpninfo->progress = write_progress;
set_openssl_ui();
char *quit_reason;
- int (*write_new_config) (struct openconnect_info *vpninfo, char *buf, int buflen);
+ int (*write_new_config) (struct openconnect_info *vpninfo, char *buf, int buflen);
+
+ void __attribute__ ((format(printf, 3, 4)))
+ (*progress) (struct openconnect_info *vpninfo, int level, const char *fmt, ...);
};
+#define PRG_ERR 0
+#define PRG_INFO 1
+#define PRG_DEBUG 2
+#define PRG_TRACE 3
+
/* Packet types */
#define AC_PKT_DATA 0 /* Uncompressed data */
va_start(args, fmt);
vsnprintf(buf, 1023, fmt, args);
va_end(args);
- if (verbose)
- printf("%s", buf);
return SSL_write(ssl, buf, strlen(buf));
}
static int load_certificate(struct openconnect_info *vpninfo)
{
- if (verbose)
- printf("Using Certificate file %s\n", vpninfo->cert);
+ vpninfo->progress(vpninfo, PRG_TRACE,
+ "Using certificate file %s\n", vpninfo->cert);
+
if (!SSL_CTX_use_certificate_file(vpninfo->https_ctx, vpninfo->cert,
SSL_FILETYPE_PEM)) {
- fprintf(stderr, "Certificate failed\n");
+ vpninfo->progress(vpninfo, PRG_ERR,
+ "Load certificate failed\n");
ERR_print_errors_fp(stderr);
return -EINVAL;
}
e = ENGINE_by_id("tpm");
if (!e) {
- fprintf(stderr, "Can't load TPM engine.\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Can't load TPM engine.\n");
ERR_print_errors_fp(stderr);
return -EINVAL;
}
if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
!ENGINE_set_default_RAND(e)) {
- fprintf(stderr, "Failed to init TPM engine\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to init TPM engine\n");
ERR_print_errors_fp(stderr);
ENGINE_free(e);
return -EINVAL;
if (vpninfo->tpmpass) {
if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->tpmpass),
vpninfo->tpmpass, NULL, 0)) {
- fprintf(stderr, "Failed to set TPM SRK password\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to set TPM SRK password\n");
ERR_print_errors_fp(stderr);
}
}
key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
if (!key) {
- fprintf(stderr,
+ vpninfo->progress(vpninfo, PRG_ERR,
"Failed to load TPM private key\n");
ERR_print_errors_fp(stderr);
ENGINE_free(e);
return -EINVAL;
}
if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
- fprintf(stderr, "Add key from TPM failed\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Add key from TPM failed\n");
ERR_print_errors_fp(stderr);
ENGINE_free(e);
ENGINE_finish(e);
if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx,
vpninfo->sslkey,
SSL_FILETYPE_PEM)) {
- fprintf(stderr, "Private key failed\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Private key failed\n");
ERR_print_errors_fp(stderr);
return -EINVAL;
}
err = getaddrinfo(vpninfo->hostname, "https", &hints, &result);
if (err) {
- fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err));
+ vpninfo->progress(vpninfo, PRG_ERR, "getaddrinfo failed: %s\n", gai_strerror(err));
return -EINVAL;
}
+ vpninfo->progress(vpninfo, PRG_INFO,
+ "Attempting to connect to %s\n", vpninfo->hostname);
+
for (rp = result; rp ; rp = rp->ai_next) {
ssl_sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (ssl_sock < 0)
continue;
-
if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
/* Store the peer address we actually used, so that DTLS can
use it again later */
vpninfo->peer_addr = malloc(rp->ai_addrlen);
if (!vpninfo->peer_addr) {
- fprintf(stderr, "Failed to allocate sockaddr storage\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to allocate sockaddr storage\n");
close(ssl_sock);
return -ENOMEM;
}
freeaddrinfo(result);
if (!rp) {
- fprintf(stderr, "Failed to connect to host %s\n", vpninfo->hostname);
+ vpninfo->progress(vpninfo, PRG_ERR, "Failed to connect to host %s\n", vpninfo->hostname);
return -EINVAL;
}
fcntl(ssl_sock, F_SETFD, FD_CLOEXEC);
https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
SSL_set_bio(https_ssl, https_bio, https_bio);
+ vpninfo->progress(vpninfo, PRG_INFO,
+ "SSL negotiation with %s\n", vpninfo->hostname);
+
if (SSL_connect(https_ssl) <= 0) {
- fprintf(stderr, "SSL connection failure\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "SSL connection failure\n");
ERR_print_errors_fp(stderr);
SSL_free(https_ssl);
close(ssl_sock);
/* FIXME: Show cert details, allow user to accept (and store?) */
if (vfy != X509_V_OK) {
- fprintf(stderr, "Server certificate verify failed: %s\n",
+ vpninfo->progress(vpninfo, PRG_ERR, "Server certificate verify failed: %s\n",
X509_verify_cert_error_string(vfy));
SSL_free(https_ssl);
close(ssl_sock);
vpninfo->ssl_fd = ssl_sock;
vpninfo->https_ssl = https_ssl;
- if (verbose)
- printf("Connected to HTTPS on %s\n", vpninfo->hostname);
+ vpninfo->progress(vpninfo, PRG_INFO,
+ "Connected to HTTPS on %s\n", vpninfo->hostname);
return 0;
}
struct sockaddr_in *sin = (void *)vpninfo->peer_addr;
if (vpninfo->peer_addr->sa_family != AF_INET) {
- fprintf(stderr, "Script cannot handle anything but Legacy IP\n");
+ vpninfo->progress(vpninfo, PRG_ERR, "Script cannot handle anything but Legacy IP\n");
return -EINVAL;
}
for (i = 0; i < SHA_DIGEST_LENGTH; i++)
sprintf(&vpninfo->xmlsha1[i*2], "%02x", sha1[i]);
- if (verbose)
- printf("XML config file SHA1: %s\n", vpninfo->xmlsha1);
+ vpninfo->progress(vpninfo, PRG_TRACE, "XML config file SHA1: %s\n", vpninfo->xmlsha1);
xml_doc = xmlReadMemory(xmlfile, st.st_size, "noname.xml", NULL, 0);
if (!xml_doc) {