From 4ea5a56ace17e5e68859bb3e6a16ea790fdc6303 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 23 Sep 2014 15:25:41 +0200 Subject: [PATCH] Allow the CSTP layer to operate without TLS That also introduces a unix domain socket under which connections to the server can occur. --- doc/sample.config | 4 + src/config.c | 2 + src/main.c | 74 +++++++++++--- src/main.h | 2 +- src/ocserv-args.def | 4 + src/tlslib.c | 166 ++++++++++++++++++++---------- src/tlslib.h | 58 +++++++++-- src/vpn.h | 8 ++ src/worker-auth.c | 48 ++++----- src/worker-extras.c | 72 ++++++------- src/worker-vpn.c | 240 ++++++++++++++++++++++++-------------------- src/worker.h | 1 + 12 files changed, 435 insertions(+), 244 deletions(-) diff --git a/doc/sample.config b/doc/sample.config index c32dd983..a232fd1b 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -49,6 +49,10 @@ max-same-clients = 2 tcp-port = 443 udp-port = 443 +# Accept connections using a socket file. The connections are +# forwarded without SSL/TLS. +unix-conn-file = /var/run/ocserv-conn.socket + # Keepalive in seconds keepalive = 32400 diff --git a/src/config.c b/src/config.c index bc7a0b17..02f2ab13 100644 --- a/src/config.c +++ b/src/config.c @@ -82,6 +82,7 @@ static struct cfg_options available_options[] = { { .name = "disconnect-script", .type = OPTION_STRING, .mandatory = 0 }, { .name = "pid-file", .type = OPTION_STRING, .mandatory = 0 }, { .name = "socket-file", .type = OPTION_STRING, .mandatory = 1 }, + { .name = "unix-conn-file", .type = OPTION_STRING, .mandatory = 0 }, { .name = "occtl-socket-file", .type = OPTION_STRING, .mandatory = 0 }, { .name = "banner", .type = OPTION_STRING, .mandatory = 0 }, { .name = "use-seccomp", .type = OPTION_BOOLEAN, .mandatory = 0 }, @@ -436,6 +437,7 @@ unsigned force_cert_auth; if (reload == 0 && pid_file[0] == 0) READ_STATIC_STRING("pid-file", pid_file); + READ_STRING("unix-conn-file", config->unix_conn_file); READ_STRING("socket-file", config->socket_file_prefix); READ_STRING("occtl-socket-file", config->occtl_socket_file); if (config->occtl_socket_file == NULL) diff --git a/src/main.c b/src/main.c index d7b589bf..1f5c439f 100644 --- a/src/main.c +++ b/src/main.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #ifdef HAVE_MALLOC_TRIM # include /* for malloc_trim() */ @@ -90,7 +92,7 @@ static void add_listener(void *pool, struct listen_list_st *list, tmp = talloc_zero(pool, struct listener_st); tmp->fd = fd; tmp->family = family; - tmp->socktype = socktype; + tmp->sock_type = socktype; tmp->protocol = protocol; tmp->addr_len = addr_len; @@ -135,12 +137,13 @@ int val; static int _listen_ports(void *pool, struct cfg_st* config, - struct addrinfo *res, struct listen_list_st *list) + struct addrinfo *res, struct listen_list_st *list, int udp) { struct addrinfo *ptr; - int s, y; + int s, y, e, ret; const char* type = NULL; char buf[512]; + struct sockaddr_un sa; for (ptr = res; ptr != NULL; ptr = ptr->ai_next) { if (ptr->ai_family != AF_INET && ptr->ai_family != AF_INET6) @@ -193,7 +196,7 @@ int _listen_ports(void *pool, struct cfg_st* config, } if (ptr->ai_socktype == SOCK_STREAM) { - if (listen(s, 10) < 0) { + if (listen(s, 1024) < 0) { perror("listen() failed"); force_close(s); return -1; @@ -202,11 +205,55 @@ int _listen_ports(void *pool, struct cfg_st* config, set_common_socket_options(s); - add_listener(pool, list, s, ptr->ai_family, ptr->ai_socktype, + add_listener(pool, list, s, ptr->ai_family, ptr->ai_socktype==SOCK_STREAM?SOCK_TYPE_TCP:SOCK_TYPE_UDP, ptr->ai_protocol, ptr->ai_addr, ptr->ai_addrlen); } - + + /* open the UNIX domain socket to accept connections */ + if (udp == 0 && config->unix_conn_file) { + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", config->unix_conn_file); + remove(sa.sun_path); + + if (config->foreground != 0) + fprintf(stderr, "listening (UNIX) on %s...\n", + sa.sun_path); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s == -1) { + e = errno; + fprintf(stderr, "could not create socket '%s': %s", sa.sun_path, + strerror(e)); + return -1; + } + + umask(066); + ret = bind(s, (struct sockaddr *)&sa, SUN_LEN(&sa)); + if (ret == -1) { + e = errno; + fprintf(stderr, "could not bind socket '%s': %s", sa.sun_path, + strerror(e)); + return -1; + } + + ret = chown(sa.sun_path, config->uid, config->gid); + if (ret == -1) { + e = errno; + fprintf(stderr, "could not chown socket '%s': %s", sa.sun_path, + strerror(e)); + } + + ret = listen(s, 1024); + if (ret == -1) { + e = errno; + fprintf(stderr, "could not listen to socket '%s': %s", + sa.sun_path, strerror(e)); + exit(1); + } + add_listener(pool, list, s, AF_UNIX, SOCK_TYPE_UNIX, 0, (struct sockaddr *)&sa, sizeof(sa)); + } fflush(stderr); return 0; @@ -280,7 +327,7 @@ listen_ports(void *pool, struct cfg_st* config, config->udp_port = ntohs(((struct sockaddr_in6*)&tmp_sock)->sin6_port); } - add_listener(pool, list, fd, family, type, 0, (struct sockaddr*)&tmp_sock, tmp_sock_len); + add_listener(pool, list, fd, family, type==SOCK_STREAM?SOCK_TYPE_TCP:SOCK_TYPE_UDP, 0, (struct sockaddr*)&tmp_sock, tmp_sock_len); } if (list->total == 0) { @@ -317,7 +364,7 @@ listen_ports(void *pool, struct cfg_st* config, return -1; } - ret = _listen_ports(pool, config, res, list); + ret = _listen_ports(pool, config, res, list, 0); if (ret < 0) { return -1; } @@ -347,7 +394,7 @@ listen_ports(void *pool, struct cfg_st* config, return -1; } - ret = _listen_ports(pool, config, res, list); + ret = _listen_ports(pool, config, res, list, 1); if (ret < 0) { return -1; } @@ -371,7 +418,7 @@ int s, y, e; force_close(l->fd); l->fd = -1; - s = socket(l->family, l->socktype, l->protocol); + s = socket(l->family, SOCK_DGRAM, l->protocol); if (s < 0) { perror("socket() failed"); return -1; @@ -1039,8 +1086,10 @@ int main(int argc, char** argv) /* Check for new connections to accept */ list_for_each(&s->listen_list.head, ltmp, list) { set = FD_ISSET(ltmp->fd, &rd_set); - if (set && ltmp->socktype == SOCK_STREAM) { + if (set && (ltmp->sock_type == SOCK_TYPE_TCP || ltmp->sock_type == SOCK_TYPE_UNIX)) { /* connection on TCP port */ + int stype = ltmp->sock_type; + ws->remote_addr_len = sizeof(ws->remote_addr); fd = accept(ltmp->fd, (void*)&ws->remote_addr, &ws->remote_addr_len); if (fd < 0) { @@ -1095,6 +1144,7 @@ int main(int argc, char** argv) ws->tun_fd = -1; ws->udp_fd = -1; ws->conn_fd = fd; + ws->conn_type = stype; ws->creds = &creds; /* Drop privileges after this point */ @@ -1132,7 +1182,7 @@ fork_failed: if (s->config->rate_limit_ms > 0) ms_sleep(s->config->rate_limit_ms); - } else if (set && ltmp->socktype == SOCK_DGRAM) { + } else if (set && ltmp->sock_type == SOCK_TYPE_UDP) { /* connection on UDP port */ ret = forward_udp_to_owner(s, ltmp); if (ret < 0) { diff --git a/src/main.h b/src/main.h index ffc31f4f..1cd2a561 100644 --- a/src/main.h +++ b/src/main.h @@ -52,7 +52,7 @@ extern unsigned int need_maintenance; struct listener_st { struct list_node list; int fd; - int socktype; + sock_type_t sock_type; struct sockaddr_storage addr; /* local socket address */ socklen_t addr_len; diff --git a/src/ocserv-args.def b/src/ocserv-args.def index fd5215bd..b3e5c0ab 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -124,6 +124,10 @@ max-same-clients = 2 tcp-port = 3333 udp-port = 3333 +# Accept connections using a socket file. The connections are +# forwarded without SSL/TLS. +#unix-conn-file = /var/run/ocserv-conn.socket + # Keepalive in seconds keepalive = 32400 diff --git a/src/tlslib.c b/src/tlslib.c index 5d30b2d0..cfc2fc73 100644 --- a/src/tlslib.c +++ b/src/tlslib.c @@ -41,56 +41,64 @@ #include #include #include +#include +#include +#include +#include #include -ssize_t tls_send(gnutls_session_t session, const void *data, +void cstp_cork(worker_st *ws) +{ + if (ws->session) { + gnutls_record_cork(ws->session); + } else { +#ifdef __linux__ + int state = 1; + setsockopt(ws->conn_fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)); +#endif + } +} + +int cstp_uncork(worker_st *ws) +{ + if (ws->session) { + return gnutls_record_uncork(ws->session, GNUTLS_RECORD_WAIT); + } else { +#ifdef __linux__ + int state = 0; + setsockopt(ws->conn_fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)); +#endif + return 0; + } +} + + +ssize_t cstp_send(worker_st *ws, const void *data, size_t data_size) { int ret; int left = data_size; const uint8_t* p = data; - while(left > 0) { - ret = gnutls_record_send(session, p, data_size); - if (ret < 0 && (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED)) { - return ret; - } + if (ws->session != NULL) { + while(left > 0) { + ret = gnutls_record_send(ws->session, p, data_size); + if (ret < 0 && (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED)) { + return ret; + } - if (ret > 0) { - left -= ret; - p += ret; + if (ret > 0) { + left -= ret; + p += ret; + } } + return data_size; + } else { + return force_write(ws->conn_fd, data, data_size); } - - return data_size; } -/* Same as tls_send() but will not retry on EAGAIN errors */ -ssize_t tls_send_nb(gnutls_session_t session, const void *data, - size_t data_size) -{ - int ret; - int left = data_size; - const uint8_t* p = data; - - while(left > 0) { - ret = gnutls_record_send(session, p, data_size); - if (ret < 0 && ret != GNUTLS_E_INTERRUPTED) { - if (ret == GNUTLS_E_AGAIN) - return data_size; - return ret; - } - - if (ret > 0) { - left -= ret; - p += ret; - } - } - - return data_size; -} - -ssize_t tls_send_file(gnutls_session_t session, const char *file) +ssize_t cstp_send_file(worker_st *ws, const char *file) { FILE* fp; char buf[512]; @@ -102,8 +110,8 @@ int ret; return GNUTLS_E_FILE_ERROR; while ( (len = fread( buf, 1, sizeof(buf), fp)) > 0) { - ret = tls_send(session, buf, len); - GNUTLS_FATAL_ERR(ret); + ret = cstp_send(ws, buf, len); + FATAL_ERR(ws, ret); total += ret; } @@ -113,13 +121,30 @@ int ret; return total; } -ssize_t tls_recv(gnutls_session_t session, void *data, size_t data_size) +ssize_t cstp_recv(worker_st *ws, void *data, size_t data_size) { int ret; - do { - ret = gnutls_record_recv(session, data, data_size); - } while (ret < 0 && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)); + if (ws->session != NULL) { + do { + ret = gnutls_record_recv(ws->session, data, data_size); + } while (ret < 0 && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)); + } else { + ret = force_read_timeout(ws->conn_fd, data, data_size, 10); + } + + return ret; +} + +ssize_t cstp_recv_nb(worker_st *ws, void *data, size_t data_size) +{ + int ret; + + if (ws->session != NULL) { + ret = gnutls_record_recv(ws->session, data, data_size); + } else { + ret = recv(ws->conn_fd, data, data_size, 0); + } return ret; } @@ -132,6 +157,9 @@ unsigned tls_has_session_cert(struct worker_st * ws) unsigned int list_size = 0; const gnutls_datum_t * certs; + if (ws->session == NULL) + return 0; + if (ws->cert_auth_ok) return 1; @@ -147,7 +175,7 @@ unsigned tls_has_session_cert(struct worker_st * ws) } int __attribute__ ((format(printf, 2, 3))) - tls_printf(gnutls_session_t session, const char *fmt, ...) + cstp_printf(worker_st *ws, const char *fmt, ...) { char buf[1024]; va_list args; @@ -158,21 +186,57 @@ int __attribute__ ((format(printf, 2, 3))) va_start(args, fmt); s = vsnprintf(buf, 1023, fmt, args); va_end(args); - return tls_send(session, buf, s); + return cstp_send(ws, buf, s); } -void tls_close(gnutls_session_t session) +void cstp_close(worker_st *ws) { - gnutls_bye(session, GNUTLS_SHUT_WR); - gnutls_deinit(session); + if (ws->session) { + gnutls_bye(ws->session, GNUTLS_SHUT_WR); + gnutls_deinit(ws->session); + } else { + force_close(ws->conn_fd); + } } -void tls_fatal_close(gnutls_session_t session, +void cstp_fatal_close(worker_st *ws, gnutls_alert_description_t a) { - gnutls_alert_send(session, GNUTLS_AL_FATAL, a); - gnutls_deinit(session); + if (ws->session) { + gnutls_alert_send(ws->session, GNUTLS_AL_FATAL, a); + gnutls_deinit(ws->session); + } else { + force_close(ws->conn_fd); + } +} + +ssize_t dtls_send(worker_st *ws, const void *data, + size_t data_size) +{ + int ret; + int left = data_size; + const uint8_t* p = data; + + while(left > 0) { + ret = gnutls_record_send(ws->dtls_session, p, data_size); + if (ret < 0 && (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED)) { + return ret; + } + + if (ret > 0) { + left -= ret; + p += ret; + } + } + + return data_size; +} + +void dtls_close(worker_st *ws) +{ + gnutls_bye(ws->dtls_session, GNUTLS_SHUT_WR); + gnutls_deinit(ws->dtls_session); } static size_t rehash(const void *_e, void *unused) diff --git a/src/tlslib.h b/src/tlslib.h index c5bd828b..a3cc1954 100644 --- a/src/tlslib.h +++ b/src/tlslib.h @@ -25,6 +25,7 @@ #include #include #include +#include typedef struct { @@ -32,6 +33,7 @@ typedef struct unsigned int entries; } tls_sess_db_st; +#if 0 #define tls_puts(s, str) tls_send(s, str, sizeof(str)-1) int __attribute__ ((format(printf, 2, 3))) @@ -47,6 +49,9 @@ ssize_t tls_send_nb(gnutls_session_t session, const void *data, void tls_cork(gnutls_session_t session); int tls_uncork(gnutls_session_t session); +ssize_t tls_send_file(gnutls_session_t session, const char *file); +#endif + typedef struct tls_st { gnutls_certificate_credentials_t xcred; gnutls_priority_t cprio; @@ -58,18 +63,8 @@ void tls_global_init(struct tls_st *creds); void tls_global_deinit(struct tls_st *creds); void tls_load_certs(struct main_server_st* s, struct tls_st *creds); -ssize_t tls_send_file(gnutls_session_t session, const char *file); size_t tls_get_overhead(gnutls_protocol_t, gnutls_cipher_algorithm_t, gnutls_mac_algorithm_t); -#define GNUTLS_FATAL_ERR(x) \ - if (x < 0 && gnutls_error_is_fatal (x) != 0) { \ - if (syslog_open) \ - syslog(LOG_ERR, "GnuTLS error (at %s:%d): %s", __FILE__, __LINE__, gnutls_strerror(x)); \ - else \ - fprintf(stderr, "GnuTLS error (at %s:%d): %s\n", __FILE__, __LINE__, gnutls_strerror(x)); \ - exit(1); \ - } - #define GNUTLS_FATAL_ERR_CMD(x, CMD) \ if (x < 0 && gnutls_error_is_fatal (x) != 0) { \ if (syslog_open) \ @@ -79,6 +74,29 @@ size_t tls_get_overhead(gnutls_protocol_t, gnutls_cipher_algorithm_t, gnutls_mac CMD; \ } +#define GNUTLS_FATAL_ERR(x) GNUTLS_FATAL_ERR_CMD(x, exit(1)) + +#define FATAL_ERR_CMD(ws, x, CMD) \ + if (ws->session != NULL) { \ + if (x < 0 && gnutls_error_is_fatal (x) != 0) { \ + if (syslog_open) \ + syslog(LOG_ERR, "GnuTLS error (at %s:%d): %s", __FILE__, __LINE__, gnutls_strerror(x)); \ + else \ + fprintf(stderr, "GnuTLS error (at %s:%d): %s\n", __FILE__, __LINE__, gnutls_strerror(x)); \ + CMD; \ + } \ + } else { \ + if (x < 0 && errno != EINTR && errno != EAGAIN) { \ + if (syslog_open) \ + syslog(LOG_ERR, "socket error (at %s:%d): %s", __FILE__, __LINE__, strerror(errno)); \ + else \ + fprintf(stderr, "socket error (at %s:%d): %s\n", __FILE__, __LINE__, strerror(errno)); \ + CMD; \ + } \ + } + +#define FATAL_ERR(ws, x) FATAL_ERR_CMD(ws, x, exit(1)) + #define GNUTLS_S_FATAL_ERR(session, x) \ if (x < 0 && gnutls_error_is_fatal (x) != 0) { \ if (syslog_open) { \ @@ -120,4 +138,24 @@ void tls_cache_init(void *pool, tls_sess_db_st* db); void tls_cache_deinit(tls_sess_db_st* db); void *calc_sha1_hash(void *pool, char* file, unsigned cert); +/* TLS API */ +int __attribute__ ((format(printf, 2, 3))) + cstp_printf(struct worker_st *ws, const char *fmt, ...); +void cstp_close(struct worker_st *ws); +void cstp_fatal_close(struct worker_st *ws, + gnutls_alert_description_t a); +ssize_t cstp_recv(struct worker_st *ws, void *data, size_t data_size); +ssize_t cstp_recv_nb(struct worker_st *ws, void *data, size_t data_size); +ssize_t cstp_send_file(struct worker_st *ws, const char *file); +ssize_t cstp_send(struct worker_st *ws, const void *data, + size_t data_size); +#define cstp_puts(s, str) cstp_send(s, str, sizeof(str)-1) + +void cstp_cork(struct worker_st *ws); +int cstp_uncork(struct worker_st *ws); + +/* DTLS API */ +void dtls_close(struct worker_st *ws); +ssize_t dtls_send(struct worker_st *ws, const void *data, size_t data_size); + #endif diff --git a/src/vpn.h b/src/vpn.h index d5446df6..d718184e 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -44,6 +44,12 @@ # define _ATTR_PACKED #endif +typedef enum { + SOCK_TYPE_TCP, + SOCK_TYPE_UDP, + SOCK_TYPE_UNIX +} sock_type_t; + #define DEBUG_BASIC 1 #define DEBUG_HTTP 2 #define DEBUG_TRANSFERRED 5 @@ -181,6 +187,8 @@ struct cfg_st { char *name; /* server name */ unsigned int port; unsigned int udp_port; + char* unix_conn_file; + char *pin_file; char *srk_pin_file; char **cert; diff --git a/src/worker-auth.c b/src/worker-auth.c index 263edb23..632d32d3 100644 --- a/src/worker-auth.c +++ b/src/worker-auth.c @@ -152,12 +152,12 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) str_init(&str, ws); - tls_cork(ws->session); - ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver); + cstp_cork(ws); + ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n"); + ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; @@ -166,7 +166,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) sizeof(context)); ret = - tls_printf(ws->session, + cstp_printf(ws, "Set-Cookie: webvpncontext=%s; Max-Age=%u; Secure\r\n", context, (unsigned)MAX_AUTH_SECS); if (ret < 0) @@ -175,7 +175,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) oclog(ws, LOG_DEBUG, "sent sid: %s", context); } - ret = tls_puts(ws->session, "Content-Type: text/xml\r\n"); + ret = cstp_puts(ws, "Content-Type: text/xml\r\n"); if (ret < 0) { ret = -1; goto cleanup; @@ -315,33 +315,33 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) } ret = - tls_printf(ws->session, "Content-Length: %u\r\n", + cstp_printf(ws, "Content-Length: %u\r\n", (unsigned int)str.length); if (ret < 0) { ret = -1; goto cleanup; } - ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n"); + ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) { ret = -1; goto cleanup; } - ret = tls_puts(ws->session, "\r\n"); + ret = cstp_puts(ws, "\r\n"); if (ret < 0) { ret = -1; goto cleanup; } - ret = tls_send(ws->session, str.data, str.length); + ret = cstp_send(ws, str.data, str.length); if (ret < 0) { ret = -1; goto cleanup; } - ret = tls_uncork(ws->session); + ret = cstp_uncork(ws); if (ret < 0) { ret = -1; goto cleanup; @@ -869,17 +869,17 @@ int post_common_handler(worker_st * ws, unsigned http_ver) (char *)str_cookie, str_cookie_size); /* reply */ - tls_cork(ws->session); + cstp_cork(ws); - ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver); + ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n"); + ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Content-Type: text/xml\r\n"); + ret = cstp_puts(ws, "Content-Type: text/xml\r\n"); if (ret < 0) return -1; @@ -898,16 +898,16 @@ int post_common_handler(worker_st * ws, unsigned http_ver) size += success_msg_head_size + success_msg_foot_size; - ret = tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned)size); + ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned)size); if (ret < 0) return -1; - ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n"); + ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; ret = - tls_printf(ws->session, + cstp_printf(ws, "Set-Cookie: webvpn=%s; Secure\r\n", str_cookie); if (ret < 0) @@ -915,21 +915,21 @@ int post_common_handler(worker_st * ws, unsigned http_ver) #ifdef ANYCONNECT_CLIENT_COMPAT ret = - tls_puts(ws->session, + cstp_puts(ws, "Set-Cookie: webvpnc=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; Secure\r\n"); if (ret < 0) return -1; if (ws->config->xml_config_file) { ret = - tls_printf(ws->session, + cstp_printf(ws, "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s&lu:/+CSCOT+/translation-table?textdomain%%3DAnyConnect%%26type%%3Dmanifest&fu:profiles%%2F%s&fh:%s; path=/; Secure\r\n", ws->config->cert_hash, ws->config->xml_config_file, ws->config->xml_config_hash); } else { ret = - tls_printf(ws->session, + cstp_printf(ws, "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s; path=/; Secure\r\n", ws->config->cert_hash); } @@ -939,12 +939,12 @@ int post_common_handler(worker_st * ws, unsigned http_ver) #endif ret = - tls_printf(ws->session, + cstp_printf(ws, "\r\n%s%s%s", success_msg_head, msg, success_msg_foot); if (ret < 0) return -1; - ret = tls_uncork(ws->session); + ret = cstp_uncork(ws); if (ret < 0) return -1; @@ -1262,9 +1262,9 @@ int post_auth_handler(worker_st * ws, unsigned http_ver) if (sd != -1) close(sd); - tls_printf(ws->session, + cstp_printf(ws, "HTTP/1.1 401 Unauthorized\r\nX-Reason: %s\r\n\r\n", reason); - tls_fatal_close(ws->session, GNUTLS_A_ACCESS_DENIED); + cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED); exit(1); } diff --git a/src/worker-extras.c b/src/worker-extras.c index d378ce8e..a8de2718 100644 --- a/src/worker-extras.c +++ b/src/worker-extras.c @@ -49,47 +49,47 @@ struct stat st; oclog(ws, LOG_HTTP_DEBUG, "requested config: %s", ws->req.url); if (ws->config->xml_config_file == NULL) { oclog(ws, LOG_INFO, "requested config but no config file is set"); - tls_printf(ws->session, "HTTP/1.%u 404 Not found\r\n", http_ver); + cstp_printf(ws, "HTTP/1.%u 404 Not found\r\n", http_ver); return -1; } ret = stat( ws->config->xml_config_file, &st); if (ret == -1) { oclog(ws, LOG_INFO, "cannot load config file '%s'", ws->config->xml_config_file); - tls_printf(ws->session, "HTTP/1.%u 404 Not found\r\n", http_ver); + cstp_printf(ws, "HTTP/1.%u 404 Not found\r\n", http_ver); return -1; } - tls_cork(ws->session); - ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver); + cstp_cork(ws); + ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n"); + ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Content-Type: text/xml\r\n"); + ret = cstp_puts(ws, "Content-Type: text/xml\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n"); + ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; - ret = tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned)st.st_size); + ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned)st.st_size); if (ret < 0) return -1; - ret = tls_puts(ws->session, "\r\n"); + ret = cstp_puts(ws, "\r\n"); if (ret < 0) return -1; - ret = tls_uncork(ws->session); + ret = cstp_uncork(ws); if (ret < 0) return -1; - ret = tls_send_file(ws->session, ws->config->xml_config_file); + ret = cstp_send_file(ws, ws->config->xml_config_file); if (ret < 0) { oclog(ws, LOG_ERR, "error sending file '%s': %s", ws->config->xml_config_file, gnutls_strerror(ret)); return -1; @@ -116,32 +116,32 @@ int len; len = sizeof(XML_START)-1; } - tls_cork(ws->session); - ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver); + cstp_cork(ws); + ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n"); + ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Content-Type: text/xml\r\n"); + ret = cstp_puts(ws, "Content-Type: text/xml\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n"); + ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; - ret = tls_printf(ws->session, "Content-Length: %d\r\n\r\n", len); + ret = cstp_printf(ws, "Content-Length: %d\r\n\r\n", len); if (ret < 0) return -1; - ret = tls_send(ws->session, data, len); + ret = cstp_send(ws, data, len); if (ret < 0) return -1; - ret = tls_uncork(ws->session); + ret = cstp_uncork(ws); if (ret < 0) return -1; @@ -162,32 +162,32 @@ int len; data = SH_SCRIPT; len = sizeof(SH_SCRIPT)-1; - tls_cork(ws->session); - ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver); + cstp_cork(ws); + ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n"); + ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Content-Type: application/x-shellscript\r\n"); + ret = cstp_puts(ws, "Content-Type: application/x-shellscript\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n"); + ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; - ret = tls_printf(ws->session, "Content-Length: %d\r\n\r\n", len); + ret = cstp_printf(ws, "Content-Length: %d\r\n\r\n", len); if (ret < 0) return -1; - ret = tls_send(ws->session, data, len); + ret = cstp_send(ws, data, len); if (ret < 0) return -1; - ret = tls_uncork(ws->session); + ret = cstp_uncork(ws); if (ret < 0) return -1; @@ -198,36 +198,36 @@ int get_empty_handler(worker_st *ws, unsigned http_ver) { int ret; - tls_cork(ws->session); - ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver); + cstp_cork(ws); + ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n"); + ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "Content-Type: text/html\r\n"); + ret = cstp_puts(ws, "Content-Type: text/html\r\n"); if (ret < 0) return -1; - ret = tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned int)sizeof(empty_msg)-1); + ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned int)sizeof(empty_msg)-1); if (ret < 0) return -1; - ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n"); + ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; - ret = tls_puts(ws->session, "\r\n"); + ret = cstp_puts(ws, "\r\n"); if (ret < 0) return -1; - ret = tls_send(ws->session, empty_msg, sizeof(empty_msg)-1); + ret = cstp_send(ws, empty_msg, sizeof(empty_msg)-1); if (ret < 0) return -1; - ret = tls_uncork(ws->session); + ret = cstp_uncork(ws); if (ret < 0) return -1; diff --git a/src/worker-vpn.c b/src/worker-vpn.c index a842976c..f0142f22 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -674,7 +674,7 @@ void vpn_server(struct worker_st *ws) unsigned char buf[2048]; int ret; ssize_t nparsed, nrecvd; - gnutls_session_t session; + gnutls_session_t session = NULL; http_parser parser; http_parser_settings settings; url_handler_fn fn; @@ -705,33 +705,38 @@ void vpn_server(struct worker_st *ws) else ws->proto = AF_INET6; - /* initialize the session */ - ret = gnutls_init(&session, GNUTLS_SERVER); - GNUTLS_FATAL_ERR(ret); + if (ws->conn_type != SOCK_TYPE_UNIX) { + /* initialize the session */ + ret = gnutls_init(&session, GNUTLS_SERVER); + GNUTLS_FATAL_ERR(ret); - ret = gnutls_priority_set(session, ws->creds->cprio); - GNUTLS_FATAL_ERR(ret); + ret = gnutls_priority_set(session, ws->creds->cprio); + GNUTLS_FATAL_ERR(ret); - ret = - gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, - ws->creds->xcred); - GNUTLS_FATAL_ERR(ret); + ret = + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, + ws->creds->xcred); + GNUTLS_FATAL_ERR(ret); - gnutls_certificate_server_set_request(session, ws->config->cert_req); - gnutls_transport_set_ptr(session, + gnutls_certificate_server_set_request(session, ws->config->cert_req); + + gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) (long)ws->conn_fd); - set_resume_db_funcs(session); - gnutls_session_set_ptr(session, ws); - gnutls_db_set_ptr(session, ws); - gnutls_db_set_cache_expiration(session, TLS_SESSION_EXPIRATION_TIME(ws->config)); + set_resume_db_funcs(session); + gnutls_session_set_ptr(session, ws); + gnutls_db_set_ptr(session, ws); + gnutls_db_set_cache_expiration(session, TLS_SESSION_EXPIRATION_TIME(ws->config)); - gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); - do { - ret = gnutls_handshake(session); - } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); - GNUTLS_S_FATAL_ERR(session, ret); + gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); + do { + ret = gnutls_handshake(session); + } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + GNUTLS_S_FATAL_ERR(session, ret); - oclog(ws, LOG_DEBUG, "TLS handshake completed"); + oclog(ws, LOG_DEBUG, "TLS handshake completed"); + } else { + oclog(ws, LOG_DEBUG, "Accepted unix connection"); + } memset(&settings, 0, sizeof(settings)); @@ -757,7 +762,7 @@ void vpn_server(struct worker_st *ws) http_req_reset(ws); /* parse as we go */ do { - nrecvd = tls_recv(session, buf, sizeof(buf)); + nrecvd = cstp_recv_nb(ws, buf, sizeof(buf)); if (nrecvd <= 0) { if (nrecvd == 0) goto finish; @@ -781,7 +786,7 @@ void vpn_server(struct worker_st *ws) fn = get_url_handler(ws->req.url); if (fn == NULL) { oclog(ws, LOG_HTTP_DEBUG, "unexpected URL %s", ws->req.url); - tls_puts(session, "HTTP/1.1 404 Not found\r\n\r\n"); + cstp_puts(ws, "HTTP/1.1 404 Not found\r\n\r\n"); goto finish; } ret = fn(ws, parser.http_minor); @@ -793,8 +798,8 @@ void vpn_server(struct worker_st *ws) /* continue reading */ oclog(ws, LOG_HTTP_DEBUG, "HTTP POST %s", ws->req.url); while (ws->req.message_complete == 0) { - nrecvd = tls_recv(session, buf, sizeof(buf)); - GNUTLS_FATAL_ERR(nrecvd); + nrecvd = cstp_recv_nb(ws, buf, sizeof(buf)); + FATAL_ERR(ws, nrecvd); nparsed = http_parser_execute(&parser, &settings, (void *)buf, @@ -810,7 +815,7 @@ void vpn_server(struct worker_st *ws) if (fn == NULL) { oclog(ws, LOG_HTTP_DEBUG, "unexpected POST URL %s", ws->req.url); - tls_puts(session, "HTTP/1.1 404 Not found\r\n\r\n"); + cstp_puts(ws, "HTTP/1.1 404 Not found\r\n\r\n"); goto finish; } @@ -829,12 +834,12 @@ void vpn_server(struct worker_st *ws) } else { oclog(ws, LOG_HTTP_DEBUG, "unexpected HTTP method %s", http_method_str(parser.method)); - tls_printf(session, "HTTP/1.%u 404 Nah, go away\r\n\r\n", + cstp_printf(ws, "HTTP/1.%u 404 Nah, go away\r\n\r\n", parser.http_minor); } finish: - tls_close(session); + cstp_close(ws); } static @@ -907,7 +912,7 @@ int mtu_not_ok(worker_st * ws) if (ws->last_good_mtu == min) { oclog(ws, LOG_INFO, "could not calculate a sufficient MTU. Disabling DTLS."); - tls_close(ws->dtls_session); + dtls_close(ws); ws->udp_state = UP_DISABLED; return -1; } @@ -979,7 +984,7 @@ int periodic_check(worker_st * ws, unsigned mtu_overhead, time_t now, (int)(now - ws->last_msg_udp), dpd); ws->buffer[0] = AC_PKT_DPD_OUT; - ret = tls_send(ws->dtls_session, ws->buffer, 1); + ret = dtls_send(ws, ws->buffer, 1); GNUTLS_FATAL_ERR_CMD(ret, exit_worker(ws)); if (now - ws->last_msg_udp > DPD_MAX_TRIES * dpd) { @@ -1001,8 +1006,8 @@ int periodic_check(worker_st * ws, unsigned mtu_overhead, time_t now, ws->buffer[6] = AC_PKT_DPD_OUT; ws->buffer[7] = 0; - ret = tls_send(ws->session, ws->buffer, 8); - GNUTLS_FATAL_ERR_CMD(ret, exit_worker(ws)); + ret = cstp_send(ws, ws->buffer, 8); + FATAL_ERR_CMD(ws, ret, exit_worker(ws)); if (now - ws->last_msg_tcp > DPD_MAX_TRIES * dpd) { oclog(ws, LOG_ERR, @@ -1085,7 +1090,7 @@ static int dtls_mainloop(worker_st * ws, struct timespec *tnow) } #endif ret = - tls_recv_nb(ws->dtls_session, ws->buffer, ws->buffer_size); + gnutls_record_recv(ws->dtls_session, ws->buffer, ws->buffer_size); oclog(ws, LOG_TRANSFER_DEBUG, "received %d byte(s) (DTLS)", ret); @@ -1202,8 +1207,8 @@ static int tls_mainloop(struct worker_st *ws, struct timespec *tnow) { int ret, l; - ret = tls_recv_nb(ws->session, ws->buffer, ws->buffer_size); - GNUTLS_FATAL_ERR_CMD(ret, exit_worker(ws)); + ret = cstp_recv_nb(ws, ws->buffer, ws->buffer_size); + FATAL_ERR_CMD(ws, ret, exit_worker(ws)); if (ret == 0) { /* disconnect */ oclog(ws, LOG_DEBUG, "client disconnected"); @@ -1285,7 +1290,7 @@ static int tun_mainloop(struct worker_st *ws, struct timespec *tnow) ws->buffer[7] = AC_PKT_DATA; - ret = tls_send(ws->dtls_session, ws->buffer + 7, l + 1); + ret = dtls_send(ws, ws->buffer + 7, l + 1); GNUTLS_FATAL_ERR_CMD(ret, exit_worker(ws)); if (ret == GNUTLS_E_LARGE_PACKET) { @@ -1310,8 +1315,8 @@ static int tun_mainloop(struct worker_st *ws, struct timespec *tnow) ws->buffer[6] = AC_PKT_DATA; ws->buffer[7] = 0; - ret = tls_send(ws->session, ws->buffer, l + 8); - GNUTLS_FATAL_ERR_CMD(ret, exit_worker(ws)); + ret = cstp_send(ws, ws->buffer, l + 8); + FATAL_ERR_CMD(ws, ret, exit_worker(ws)); } ws->last_nc_msg = tnow->tv_sec; } @@ -1384,9 +1389,9 @@ static int connect_handler(worker_st * ws) /* we must be in S_AUTH_COOKIE state */ if (ws->auth_state != S_AUTH_COOKIE || ws->cookie_set == 0) { oclog(ws, LOG_WARNING, "no cookie found"); - tls_puts(ws->session, + cstp_puts(ws, "HTTP/1.1 503 Service Unavailable\r\n\r\n"); - tls_fatal_close(ws->session, GNUTLS_A_ACCESS_DENIED); + cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED); exit_worker(ws); } @@ -1396,31 +1401,31 @@ static int connect_handler(worker_st * ws) if (ret < 0) { oclog(ws, LOG_WARNING, "failed cookie authentication attempt"); if (ret == ERR_AUTH_FAIL) { - tls_puts(ws->session, + cstp_puts(ws, "HTTP/1.1 401 Unauthorized\r\n\r\n"); - tls_puts(ws->session, + cstp_puts(ws, "X-Reason: Cookie is not acceptable\r\n\r\n"); } else { - tls_puts(ws->session, + cstp_puts(ws, "HTTP/1.1 503 Service Unavailable\r\n\r\n"); } - tls_fatal_close(ws->session, GNUTLS_A_ACCESS_DENIED); + cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED); exit_worker(ws); } ws->auth_state = S_AUTH_COMPLETE; if (strcmp(req->url, "/CSCOSSLC/tunnel") != 0) { oclog(ws, LOG_INFO, "bad connect request: '%s'\n", req->url); - tls_puts(ws->session, "HTTP/1.1 404 Nah, go away\r\n\r\n"); - tls_fatal_close(ws->session, GNUTLS_A_ACCESS_DENIED); + cstp_puts(ws, "HTTP/1.1 404 Nah, go away\r\n\r\n"); + cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED); exit_worker(ws); } if (ws->config->network.name[0] == 0) { oclog(ws, LOG_ERR, "no networks are configured; rejecting client"); - tls_puts(ws->session, "HTTP/1.1 503 Service Unavailable\r\n"); - tls_puts(ws->session, + cstp_puts(ws, "HTTP/1.1 503 Service Unavailable\r\n"); + cstp_puts(ws, "X-Reason: Server configuration error\r\n\r\n"); return -1; } @@ -1429,8 +1434,8 @@ static int connect_handler(worker_st * ws) if (ret < 0) { oclog(ws, LOG_ERR, "no networks are configured; rejecting client"); - tls_puts(ws->session, "HTTP/1.1 503 Service Unavailable\r\n"); - tls_puts(ws->session, + cstp_puts(ws, "HTTP/1.1 503 Service Unavailable\r\n"); + cstp_puts(ws, "X-Reason: Server configuration error\r\n\r\n"); return -1; } @@ -1440,14 +1445,14 @@ static int connect_handler(worker_st * ws) alarm(0); http_req_deinit(ws); - tls_cork(ws->session); - ret = tls_puts(ws->session, "HTTP/1.1 200 CONNECTED\r\n"); + cstp_cork(ws); + ret = cstp_puts(ws, "HTTP/1.1 200 CONNECTED\r\n"); SEND_ERR(ret); - ret = tls_puts(ws->session, "X-CSTP-Version: 1\r\n"); + ret = cstp_puts(ws, "X-CSTP-Version: 1\r\n"); SEND_ERR(ret); - ret = tls_puts(ws->session, "X-Server-Version: "PACKAGE_STRING"\r\n"); + ret = cstp_puts(ws, "X-Server-Version: "PACKAGE_STRING"\r\n"); SEND_ERR(ret); if (req->is_mobile) { @@ -1458,14 +1463,14 @@ static int connect_handler(worker_st * ws) oclog(ws, LOG_DEBUG, "suggesting DPD of %d secs", ws->config->dpd); if (ws->config->dpd > 0) { ret = - tls_printf(ws->session, "X-CSTP-DPD: %u\r\n", + cstp_printf(ws, "X-CSTP-DPD: %u\r\n", ws->config->dpd); SEND_ERR(ret); } if (ws->config->default_domain) { ret = - tls_printf(ws->session, "X-CSTP-Default-Domain: %s\r\n", + cstp_printf(ws, "X-CSTP-Default-Domain: %s\r\n", ws->config->default_domain); SEND_ERR(ret); } @@ -1481,13 +1486,13 @@ static int connect_handler(worker_st * ws) if (ws->vinfo.ipv4 && req->no_ipv4 == 0) { oclog(ws, LOG_DEBUG, "sending IPv4 %s", ws->vinfo.ipv4); ret = - tls_printf(ws->session, "X-CSTP-Address: %s\r\n", + cstp_printf(ws, "X-CSTP-Address: %s\r\n", ws->vinfo.ipv4); SEND_ERR(ret); if (ws->vinfo.ipv4_netmask) { ret = - tls_printf(ws->session, "X-CSTP-Netmask: %s\r\n", + cstp_printf(ws, "X-CSTP-Netmask: %s\r\n", ws->vinfo.ipv4_netmask); SEND_ERR(ret); } @@ -1505,20 +1510,20 @@ static int connect_handler(worker_st * ws) oclog(ws, LOG_DEBUG, "sending IPv6 %s", ws->vinfo.ipv6); if (ws->full_ipv6 && ws->vinfo.ipv6_prefix) { ret = - tls_printf(ws->session, + cstp_printf(ws, "X-CSTP-Address-IP6: %s/%u\r\n", ws->vinfo.ipv6, ws->vinfo.ipv6_prefix); SEND_ERR(ret); } else { ret = - tls_printf(ws->session, "X-CSTP-Address: %s\r\n", + cstp_printf(ws, "X-CSTP-Address: %s\r\n", ws->vinfo.ipv6); SEND_ERR(ret); } if (ws->vinfo.ipv6_network && ws->vinfo.ipv6_prefix != 0) { ret = - tls_printf(ws->session, + cstp_printf(ws, "X-CSTP-Netmask: %s/%u\r\n", ws->vinfo.ipv6_network, ws->vinfo.ipv6_prefix); SEND_ERR(ret); @@ -1532,7 +1537,7 @@ static int connect_handler(worker_st * ws) continue; ret = - tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", + cstp_printf(ws, "X-CSTP-DNS: %s\r\n", ws->vinfo.dns[i]); SEND_ERR(ret); } @@ -1544,7 +1549,7 @@ static int connect_handler(worker_st * ws) continue; ret = - tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", + cstp_printf(ws, "X-CSTP-NBNS: %s\r\n", ws->vinfo.nbns[i]); SEND_ERR(ret); } @@ -1553,7 +1558,7 @@ static int connect_handler(worker_st * ws) oclog(ws, LOG_DEBUG, "adding split DNS %s", ws->config->split_dns[i]); ret = - tls_printf(ws->session, "X-CSTP-Split-DNS: %s\r\n", + cstp_printf(ws, "X-CSTP-Split-DNS: %s\r\n", ws->config->split_dns[i]); SEND_ERR(ret); } @@ -1572,11 +1577,11 @@ static int connect_handler(worker_st * ws) oclog(ws, LOG_DEBUG, "adding route %s", ws->vinfo.routes[i]); if (ip6 != 0 && ws->full_ipv6) { - ret = tls_printf(ws->session, + ret = cstp_printf(ws, "X-CSTP-Split-Include-IP6: %s\r\n", ws->vinfo.routes[i]); } else { - ret = tls_printf(ws->session, + ret = cstp_printf(ws, "X-CSTP-Split-Include: %s\r\n", ws->vinfo.routes[i]); } @@ -1596,11 +1601,11 @@ static int connect_handler(worker_st * ws) oclog(ws, LOG_DEBUG, "adding private route %s", ws->routes[i]); if (ip6 != 0 && ws->full_ipv6) { - ret = tls_printf(ws->session, + ret = cstp_printf(ws, "X-CSTP-Split-Include-IP6: %s\r\n", ws->routes[i]); } else { - ret = tls_printf(ws->session, + ret = cstp_printf(ws, "X-CSTP-Split-Include: %s\r\n", ws->routes[i]); } @@ -1609,22 +1614,22 @@ static int connect_handler(worker_st * ws) } ret = - tls_printf(ws->session, "X-CSTP-Keepalive: %u\r\n", + cstp_printf(ws, "X-CSTP-Keepalive: %u\r\n", ws->config->keepalive); SEND_ERR(ret); if (ws->config->idle_timeout > 0) { ret = - tls_printf(ws->session, + cstp_printf(ws, "X-CSTP-Idle-Timeout: %u\r\n", (unsigned)ws->config->idle_timeout); } else { - ret = tls_puts(ws->session, "X-CSTP-Idle-Timeout: none\r\n"); + ret = cstp_puts(ws, "X-CSTP-Idle-Timeout: none\r\n"); } SEND_ERR(ret); ret = - tls_puts(ws->session, + cstp_puts(ws, "X-CSTP-Smartcard-Removal-Disconnect: true\r\n"); SEND_ERR(ret); @@ -1632,23 +1637,23 @@ static int connect_handler(worker_st * ws) unsigned method; ret = - tls_printf(ws->session, "X-CSTP-Rekey-Time: %u\r\n", + cstp_printf(ws, "X-CSTP-Rekey-Time: %u\r\n", (unsigned)(ws->config->rekey_time)); SEND_ERR(ret); /* if the peer isn't patched for safe renegotiation, always * require him to open a new tunnel. */ - if (gnutls_safe_renegotiation_status(ws->session) != 0) + if (ws->session != NULL && gnutls_safe_renegotiation_status(ws->session) != 0) method = ws->config->rekey_method; else method = REKEY_METHOD_NEW_TUNNEL; - ret = tls_printf(ws->session, "X-CSTP-Rekey-Method: %s\r\n", + ret = cstp_printf(ws, "X-CSTP-Rekey-Method: %s\r\n", (method == REKEY_METHOD_SSL) ? "ssl" : "new-tunnel"); SEND_ERR(ret); } else { - ret = tls_puts(ws->session, "X-CSTP-Rekey-Method: none\r\n"); + ret = cstp_puts(ws, "X-CSTP-Rekey-Method: none\r\n"); SEND_ERR(ret); } @@ -1656,14 +1661,14 @@ static int connect_handler(worker_st * ws) char *url = replace_vals(ws, ws->config->proxy_url); if (url != NULL) { ret = - tls_printf(ws->session, "X-CSTP-MSIE-Proxy-Pac-URL: %s\r\n", + cstp_printf(ws, "X-CSTP-MSIE-Proxy-Pac-URL: %s\r\n", url); SEND_ERR(ret); talloc_free(url); } } - ret = tls_puts(ws->session, "X-CSTP-Session-Timeout: none\r\n" + ret = cstp_puts(ws, "X-CSTP-Session-Timeout: none\r\n" "X-CSTP-Disconnected-Timeout: none\r\n" "X-CSTP-Keep: true\r\n" "X-CSTP-TCP-Keepalive: true\r\n" @@ -1677,7 +1682,7 @@ static int connect_handler(worker_st * ws) if (h) { oclog(ws, LOG_DEBUG, "adding custom header '%s'", h); ret = - tls_printf(ws->session, "%s\r\n", h); + cstp_printf(ws, "%s\r\n", h); SEND_ERR(ret); talloc_free(h); } @@ -1709,15 +1714,21 @@ static int connect_handler(worker_st * ws) } } - ret = tls_printf(ws->session, "X-CSTP-Base-MTU: %u\r\n", ws->vinfo.mtu); + ret = cstp_printf(ws, "X-CSTP-Base-MTU: %u\r\n", ws->vinfo.mtu); SEND_ERR(ret); oclog(ws, LOG_DEBUG, "CSTP Base MTU is %u bytes", ws->vinfo.mtu); /* calculate TLS channel MTU */ - ws->crypto_overhead = CSTP_OVERHEAD + - tls_get_overhead(gnutls_protocol_get_version(ws->session), - gnutls_cipher_get(ws->session), - gnutls_mac_get(ws->session)); + if (ws->session == NULL) { + /* wild guess */ + ws->crypto_overhead = CSTP_OVERHEAD + + tls_get_overhead(GNUTLS_TLS1_0, GNUTLS_CIPHER_AES_128_CBC, GNUTLS_MAC_SHA1); + } else { + ws->crypto_overhead = CSTP_OVERHEAD + + tls_get_overhead(gnutls_protocol_get_version(ws->session), + gnutls_cipher_get(ws->session), + gnutls_mac_get(ws->session)); + } /* plaintext MTU is the device MTU minus the overhead * of the CSTP protocol. */ @@ -1744,46 +1755,46 @@ static int connect_handler(worker_st * ws) p += 2; } ret = - tls_printf(ws->session, "X-DTLS-Session-ID: %s\r\n", + cstp_printf(ws, "X-DTLS-Session-ID: %s\r\n", ws->buffer); SEND_ERR(ret); if (ws->config->dpd > 0) { ret = - tls_printf(ws->session, "X-DTLS-DPD: %u\r\n", + cstp_printf(ws, "X-DTLS-DPD: %u\r\n", ws->config->dpd); SEND_ERR(ret); } ret = - tls_printf(ws->session, "X-DTLS-Port: %u\r\n", + cstp_printf(ws, "X-DTLS-Port: %u\r\n", ws->config->udp_port); SEND_ERR(ret); if (ws->config->rekey_time > 0) { ret = - tls_printf(ws->session, "X-DTLS-Rekey-Time: %u\r\n", + cstp_printf(ws, "X-DTLS-Rekey-Time: %u\r\n", (unsigned)(ws->config->rekey_time + 10)); SEND_ERR(ret); /* This is our private extension */ if (ws->config->rekey_method == REKEY_METHOD_SSL) { ret = - tls_puts(ws->session, + cstp_puts(ws, "X-DTLS-Rekey-Method: ssl\r\n"); SEND_ERR(ret); } } ret = - tls_printf(ws->session, "X-DTLS-Keepalive: %u\r\n", + cstp_printf(ws, "X-DTLS-Keepalive: %u\r\n", ws->config->keepalive); SEND_ERR(ret); oclog(ws, LOG_DEBUG, "DTLS ciphersuite: %s", ws->req.selected_ciphersuite->oc_name); ret = - tls_printf(ws->session, "X-DTLS-CipherSuite: %s\r\n", + cstp_printf(ws, "X-DTLS-CipherSuite: %s\r\n", ws->req.selected_ciphersuite->oc_name); SEND_ERR(ret); @@ -1815,7 +1826,7 @@ static int connect_handler(worker_st * ws) ws->vinfo.mtu - proto_overhead - ws->crypto_overhead); ret = - tls_printf(ws->session, "X-DTLS-MTU: %u\r\n", ws->conn_mtu); + cstp_printf(ws, "X-DTLS-MTU: %u\r\n", ws->conn_mtu); SEND_ERR(ret); oclog(ws, LOG_DEBUG, "suggesting DTLS MTU %u", ws->conn_mtu); @@ -1833,7 +1844,7 @@ static int connect_handler(worker_st * ws) } /* hack for openconnect. It uses only a single MTU value */ - ret = tls_printf(ws->session, "X-CSTP-MTU: %u\r\n", ws->conn_mtu); + ret = cstp_printf(ws, "X-CSTP-MTU: %u\r\n", ws->conn_mtu); SEND_ERR(ret); if (ws->buffer_size <= ws->conn_mtu + CSTP_OVERHEAD) { @@ -1847,15 +1858,15 @@ static int connect_handler(worker_st * ws) if (ws->config->banner) { ret = - tls_printf(ws->session, "X-CSTP-Banner: %s\r\n", + cstp_printf(ws, "X-CSTP-Banner: %s\r\n", ws->config->banner); SEND_ERR(ret); } - ret = tls_puts(ws->session, "\r\n"); + ret = cstp_puts(ws, "\r\n"); SEND_ERR(ret); - ret = tls_uncork(ws->session); + ret = cstp_uncork(ws); SEND_ERR(ret); /* start dead peer detection */ @@ -1896,12 +1907,15 @@ static int connect_handler(worker_st * ws) oclog(ws, LOG_TRANSFER_DEBUG, "sending disconnect message in TLS channel"); - ret = tls_send(ws->session, ws->buffer, 8); - GNUTLS_FATAL_ERR_CMD(ret, exit_worker(ws)); + ret = cstp_send(ws, ws->buffer, 8); + FATAL_ERR_CMD(ws, ret, exit_worker(ws)); goto exit; } - tls_pending = gnutls_record_check_pending(ws->session); + if (ws->session != NULL) + tls_pending = gnutls_record_check_pending(ws->session); + else + tls_pending = 0; if (ws->dtls_session != NULL && ws->udp_state > UP_WAIT_FD) { dtls_pending = @@ -1979,10 +1993,10 @@ static int connect_handler(worker_st * ws) return 0; exit: - tls_close(ws->session); + cstp_close(ws); /*gnutls_deinit(ws->session); */ if (ws->udp_state == UP_ACTIVE && ws->dtls_session) { - tls_close(ws->dtls_session); + dtls_close(ws); /*gnutls_deinit(ws->dtls_session); */ } @@ -2009,31 +2023,37 @@ static int parse_data(struct worker_st *ws, gnutls_session_t ts, /* the interfac break; case AC_PKT_DPD_OUT: if (ws->session == ts) { - ret = tls_send(ts, "STF\x01\x00\x00\x04\x00", 8); + ret = cstp_send(ws, "STF\x01\x00\x00\x04\x00", 8); oclog(ws, LOG_TRANSFER_DEBUG, "received TLS DPD; sent response (%d bytes)", ret); + + if (ret < 0) { + oclog(ws, LOG_ERR, "could not send data: %d", ret); + return -1; + } } else { /* Use DPD for MTU discovery in DTLS */ ws->buffer[0] = AC_PKT_DPD_RESP; - ret = tls_send(ts, ws->buffer, 1); + ret = dtls_send(ws, ws->buffer, 1); if (ret == GNUTLS_E_LARGE_PACKET) { mtu_not_ok(ws); - ret = tls_send(ts, ws->buffer, 1); + ret = dtls_send(ws, ws->buffer, 1); } oclog(ws, LOG_TRANSFER_DEBUG, "received DTLS DPD; sent response (%d bytes)", ret); + + if (ret < 0) { + oclog(ws, LOG_ERR, "could not send TLS data: %s", + gnutls_strerror(ret)); + return -1; + } } - if (ret < 0) { - oclog(ws, LOG_ERR, "could not send TLS data: %s", - gnutls_strerror(ret)); - return -1; - } break; case AC_PKT_DISCONN: oclog(ws, LOG_DEBUG, "received BYE packet; exiting"); diff --git a/src/worker.h b/src/worker.h index 2b93ed03..cfa90177 100644 --- a/src/worker.h +++ b/src/worker.h @@ -142,6 +142,7 @@ typedef struct worker_st { int cmd_fd; int conn_fd; + sock_type_t conn_type; /* AF_UNIX or something else */ http_parser *parser; struct cfg_st *config;