Several updates to handle URLs requested by the cisco client.

This commit is contained in:
Nikos Mavrogiannopoulos
2013-03-01 19:52:10 +01:00
parent 27b3378d40
commit 41e8d020b5
14 changed files with 346 additions and 145 deletions
+1 -1
View File
@@ -4,5 +4,5 @@ dist_man_MANS = ocserv.1
ocserv.1: ../src/ocserv-args.def ocserv.1: ../src/ocserv-args.def
-sed 's/@subheading \(.*\)/@*\n@var{\1}\n@*/' $< > "$<".tmp && \ -sed 's/@subheading \(.*\)/@*\n@var{\1}\n@*/' $< > "$<".tmp && \
-@AUTOGEN@ -DMAN_SECTION=1 -Tagman-cmd.tpl "$<".tmp && \ @AUTOGEN@ -DMAN_SECTION=1 -Tagman-cmd.tpl "$<".tmp && \
rm -f "$<".tmp rm -f "$<".tmp
+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<AnyConnectProfile xmlns="http://schemas.xmlsoap.org/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.xmlsoap.org/encoding/ AnyConnectProfile.xsd">
<ClientInitialization>
<UseStartBeforeLogon UserControllable="false">false</UseStartBeforeLogon>
<StrictCertificateTrust>false</StrictCertificateTrust>
<RestrictPreferenceCaching>false</RestrictPreferenceCaching>
<RestrictTunnelProtocols>IPSec</RestrictTunnelProtocols>
<BypassDownloader>true</BypassDownloader>
<CertEnrollmentPin>pinAllowed</CertEnrollmentPin>
<CertificateMatch>
<KeyUsage>
<MatchKey>Digital_Signature</MatchKey>
</KeyUsage>
<ExtendedKeyUsage>
<ExtendedMatchKey>ClientAuth</ExtendedMatchKey>
</ExtendedKeyUsage>
</CertificateMatch>
<BackupServerList>
<HostAddress>10.100.2.17</HostAddress>
</BackupServerList>
</ClientInitialization>
<ServerList>
<HostEntry>
<HostName>VPN Server</HostName>
<HostAddress>10.100.2.17</HostAddress>
</HostEntry>
</ServerList>
</AnyConnectProfile>
+10 -2
View File
@@ -4,6 +4,14 @@
#auth = "certificate" #auth = "certificate"
auth = "pam" auth = "pam"
# A banner to be displayed on clients
#banner = "Welcome"
# Client config xml. The variable $GROUP will be replaced by
# the user's group name. This file must be accessible from inside
# the worker's chroot. It is not used by the openconnect client.
user-profile = ../doc/profile.xml
# Use listen-host to limit to specific IPs or to the IPs of a provided hostname. # Use listen-host to limit to specific IPs or to the IPs of a provided hostname.
#listen-host = [IP|HOSTNAME] #listen-host = [IP|HOSTNAME]
@@ -16,8 +24,8 @@ max-clients = 16
max-same-clients = 2 max-same-clients = 2
# TCP and UDP port number # TCP and UDP port number
tcp-port = 3333 tcp-port = 443
udp-port = 3333 udp-port = 443
# Keepalive in seconds # Keepalive in seconds
keepalive = 32400 keepalive = 32400
+1 -1
View File
@@ -28,4 +28,4 @@ ocserv_LDADD += $(LIBGNUTLS_LIBS) $(GDBM_LIBS) $(PAM_LIBS) $(LIBUTIL) \
$(LIBSECCOMP) $(LIBWRAP) $(LIBSECCOMP) $(LIBWRAP)
ocserv-args.c ocserv-args.h: $(srcdir)/ocserv-args.def ocserv-args.c ocserv-args.h: $(srcdir)/ocserv-args.def
-@AUTOGEN@ $< @AUTOGEN@ $<
+14
View File
@@ -30,6 +30,7 @@
#include <autoopts/options.h> #include <autoopts/options.h>
#include <vpn.h> #include <vpn.h>
#include <tlslib.h>
#define DEFAULT_CFG_FILE "/etc/ocserv.conf" #define DEFAULT_CFG_FILE "/etc/ocserv.conf"
@@ -146,6 +147,7 @@ unsigned j;
READ_STRING("server-key", config->key, 1); READ_STRING("server-key", config->key, 1);
READ_STRING("pin-file", config->pin_file, 0); READ_STRING("pin-file", config->pin_file, 0);
READ_STRING("srk-pin-file", config->srk_pin_file, 0); READ_STRING("srk-pin-file", config->srk_pin_file, 0);
READ_STRING("user-profile", config->xml_config_file, 0);
READ_STRING("ca-cert", config->ca, 0); READ_STRING("ca-cert", config->ca, 0);
READ_STRING("crl", config->crl, 0); READ_STRING("crl", config->crl, 0);
@@ -208,6 +210,7 @@ unsigned j;
READ_MULTI_LINE("route", config->network.routes, config->network.routes_size, 0); READ_MULTI_LINE("route", config->network.routes, config->network.routes_size, 0);
} }
/* sanity checks on config */ /* sanity checks on config */
static void check_cfg( struct cfg_st *config) static void check_cfg( struct cfg_st *config)
{ {
@@ -231,6 +234,14 @@ static void check_cfg( struct cfg_st *config)
exit(1); exit(1);
} }
if (config->cert) {
config->cert_hash = calc_sha1_hash(config->cert, 1);
}
if (config->xml_config_file) {
config->xml_config_hash = calc_sha1_hash(config->xml_config_file, 0);
}
if (config->keepalive == 0) if (config->keepalive == 0)
config->keepalive = 3600; config->keepalive = 3600;
@@ -280,6 +291,9 @@ void reload_cfg_file(struct cfg_st* config)
{ {
unsigned i; unsigned i;
DEL(config->xml_config_file);
DEL(config->xml_config_hash);
DEL(config->cert_hash);
DEL(config->banner); DEL(config->banner);
DEL(config->name); DEL(config->name);
DEL(config->cert); DEL(config->cert);
+6 -4
View File
@@ -485,7 +485,7 @@ static void check_other_work(main_server_st *s)
if (reload_conf != 0) { if (reload_conf != 0) {
mslog(s, NULL, LOG_INFO, "HUP signal was received; reloading configuration"); mslog(s, NULL, LOG_INFO, "HUP signal was received; reloading configuration");
reload_cfg_file(s->config); reload_cfg_file(s->config);
tls_global_reinit(s); tls_global_init_certs(s);
reload_conf = 0; reload_conf = 0;
} }
@@ -559,6 +559,9 @@ int main(int argc, char** argv)
signal(SIGCHLD, handle_children); signal(SIGCHLD, handle_children);
signal(SIGALRM, handle_alarm); signal(SIGALRM, handle_alarm);
/* Initialize GnuTLS */
tls_global_init(&s);
/* load configuration */ /* load configuration */
ret = cmd_parser(argc, argv, &config); ret = cmd_parser(argc, argv, &config);
if (ret < 0) { if (ret < 0) {
@@ -601,11 +604,10 @@ int main(int argc, char** argv)
allow_severity = LOG_DAEMON|LOG_INFO; allow_severity = LOG_DAEMON|LOG_INFO;
deny_severity = LOG_DAEMON|LOG_WARNING; deny_severity = LOG_DAEMON|LOG_WARNING;
#endif #endif
memset(&ws, 0, sizeof(ws));
/* Initialize GnuTLS */ /* Initialize GnuTLS */
tls_global_init(&s); tls_global_init_certs(&s);
memset(&ws, 0, sizeof(ws));
if (config.foreground == 0) { if (config.foreground == 0) {
if (daemon(0, 0) == -1) { if (daemon(0, 0) == -1) {
+4 -4
View File
@@ -2,7 +2,7 @@
* *
* DO NOT EDIT THIS FILE (ocserv-args.c) * DO NOT EDIT THIS FILE (ocserv-args.c)
* *
* It has been AutoGen-ed February 27, 2013 at 07:03:11 PM by AutoGen 5.16 * It has been AutoGen-ed March 1, 2013 at 07:46:59 PM by AutoGen 5.16
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *
@@ -66,7 +66,7 @@ extern FILE * option_usage_fp;
* ocserv option static const strings * ocserv option static const strings
*/ */
static char const ocserv_opt_strs[1840] = static char const ocserv_opt_strs[1840] =
/* 0 */ "ocserv 0.0.1\n" /* 0 */ "ocserv 0.0.2\n"
"Copyright (C) 2013 Nikos Mavrogiannopoulos, all rights reserved.\n" "Copyright (C) 2013 Nikos Mavrogiannopoulos, all rights reserved.\n"
"This is free software. It is licensed for use, modification and\n" "This is free software. It is licensed for use, modification and\n"
"redistribution under the terms of the\n" "redistribution under the terms of the\n"
@@ -99,7 +99,7 @@ static char const ocserv_opt_strs[1840] =
/* 1129 */ "Output version information and exit\0" /* 1129 */ "Output version information and exit\0"
/* 1165 */ "version\0" /* 1165 */ "version\0"
/* 1173 */ "OCSERV\0" /* 1173 */ "OCSERV\0"
/* 1180 */ "ocserv - OpenConnect server - Ver. 0.0.1\n" /* 1180 */ "ocserv - OpenConnect server - Ver. 0.0.2\n"
"USAGE: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\0" "USAGE: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\0"
/* 1279 */ "openconnect-devel@lists.infradead.org\0" /* 1279 */ "openconnect-devel@lists.infradead.org\0"
/* 1317 */ "\n\n\0" /* 1317 */ "\n\n\0"
@@ -111,7 +111,7 @@ static char const ocserv_opt_strs[1840] =
"authentication. Authenticated users are assigned an unprivileged worker\n" "authentication. Authenticated users are assigned an unprivileged worker\n"
"process and obtain a networking (tun) device and IP from a configurable\n" "process and obtain a networking (tun) device and IP from a configurable\n"
"pool of addresses.\n\0" "pool of addresses.\n\0"
/* 1752 */ "ocserv 0.0.1\0" /* 1752 */ "ocserv 0.0.2\0"
/* 1765 */ "Usage: ocserv [options] -c [config]\n" /* 1765 */ "Usage: ocserv [options] -c [config]\n"
"ocserv --help for usage instructions.\n"; "ocserv --help for usage instructions.\n";
+5
View File
@@ -82,6 +82,11 @@ auth = "pam"
# A banner to be displayed on clients # A banner to be displayed on clients
#banner = "Welcome" #banner = "Welcome"
# Client profile xml. A sample file exists in doc/profile.xml.
# This file must be accessible from inside the worker's chroot.
# It is not used by the openconnect client.
#user-profile = /path/to/file.xml
# Use listen-host to limit to specific IPs or to the IPs of a provided hostname. # Use listen-host to limit to specific IPs or to the IPs of a provided hostname.
#listen-host = [IP|HOSTNAME] #listen-host = [IP|HOSTNAME]
+3 -3
View File
@@ -2,7 +2,7 @@
* *
* DO NOT EDIT THIS FILE (ocserv-args.h) * DO NOT EDIT THIS FILE (ocserv-args.h)
* *
* It has been AutoGen-ed February 27, 2013 at 07:03:10 PM by AutoGen 5.16 * It has been AutoGen-ed March 1, 2013 at 07:46:59 PM by AutoGen 5.16
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *
@@ -76,8 +76,8 @@ typedef enum {
} teOptIndex; } teOptIndex;
#define OPTION_CT 7 #define OPTION_CT 7
#define OCSERV_VERSION "0.0.1" #define OCSERV_VERSION "0.0.2"
#define OCSERV_FULL_VERSION "ocserv 0.0.1" #define OCSERV_FULL_VERSION "ocserv 0.0.2"
/* /*
* Interface defines for all options. Replace "n" with the UPPER_CASED * Interface defines for all options. Replace "n" with the UPPER_CASED
+64 -7
View File
@@ -19,6 +19,7 @@
#include <config.h> #include <config.h>
#include <gnutls/gnutls.h> #include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <gnutls/pkcs11.h> #include <gnutls/pkcs11.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
@@ -333,25 +334,24 @@ void tls_global_init(main_server_st* s)
int ret; int ret;
gnutls_global_set_audit_log_function(tls_audit_log_func); gnutls_global_set_audit_log_function(tls_audit_log_func);
if (s->config->tls_debug) {
gnutls_global_set_log_function(tls_log_func);
gnutls_global_set_log_level(9);
}
ret = gnutls_global_init(); ret = gnutls_global_init();
GNUTLS_FATAL_ERR(ret); GNUTLS_FATAL_ERR(ret);
tls_global_reinit(s);
return; return;
} }
/* reload key files etc. */ /* reload key files etc. */
void tls_global_reinit(main_server_st* s) void tls_global_init_certs(main_server_st* s)
{ {
int ret; int ret;
const char* perr; const char* perr;
if (s->config->tls_debug) {
gnutls_global_set_log_function(tls_log_func);
gnutls_global_set_log_level(9);
}
if (s->creds.xcred != NULL) if (s->creds.xcred != NULL)
gnutls_certificate_free_credentials(s->creds.xcred); gnutls_certificate_free_credentials(s->creds.xcred);
@@ -468,3 +468,60 @@ int tls_uncork(gnutls_session_t session)
return 0; return 0;
#endif #endif
} }
void *calc_sha1_hash(char* file, unsigned cert)
{
int ret;
gnutls_datum_t data;
uint8_t digest[20];
char * retval;
gnutls_x509_crt_t crt;
ret = gnutls_load_file(file, &data);
if (ret < 0) {
fprintf(stderr, "Cannot open file '%s': %s\n", file, gnutls_strerror(ret));
exit(1);
}
if (cert != 0) {
ret = gnutls_x509_crt_init(&crt);
GNUTLS_FATAL_ERR(ret);
ret = gnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_PEM);
if (ret == GNUTLS_E_BASE64_DECODING_ERROR)
ret = gnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_DER);
GNUTLS_FATAL_ERR(ret);
gnutls_free(data.data);
ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &data);
GNUTLS_FATAL_ERR(ret);
gnutls_x509_crt_deinit(crt);
}
ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, data.data, data.size, digest);
gnutls_free(data.data);
if (ret < 0) {
fprintf(stderr, "Error calculating hash of '%s': %s\n", file, gnutls_strerror(ret));
exit(1);
}
size_t ret_size = sizeof(digest)*2+1;
retval = malloc(ret_size);
if (retval == NULL) {
fprintf(stderr, "Memory error\n");
exit(1);
}
data.data = digest;
data.size = sizeof(digest);
ret = gnutls_hex_encode(&data, retval, &ret_size);
if (ret < 0) {
fprintf(stderr, "Error in hex encode: %s\n", gnutls_strerror(ret));
exit(1);
}
retval[ret_size] = 0;
return retval;
}
+15 -1
View File
@@ -20,7 +20,7 @@ int tls_uncork(gnutls_session_t session);
void tls_global_init(struct main_server_st* s); void tls_global_init(struct main_server_st* s);
int tls_global_init_client(struct worker_st* ws); int tls_global_init_client(struct worker_st* ws);
void tls_global_reinit(struct main_server_st* s); void tls_global_init_certs(struct main_server_st* s);
ssize_t tls_send_file(gnutls_session_t session, const char *file); ssize_t tls_send_file(gnutls_session_t session, const char *file);
@@ -33,6 +33,19 @@ ssize_t tls_send_file(gnutls_session_t session, const char *file);
exit(1); \ exit(1); \
} }
#define GNUTLS_S_FATAL_ERR(session, x) \
if (x < 0 && gnutls_error_is_fatal (x) != 0) { \
if (syslog_open) { \
if (ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { \
syslog(LOG_ERR, "GnuTLS error (at %s:%d): %s: %s", __FILE__, __LINE__, gnutls_strerror(x), gnutls_alert_get_name(gnutls_alert_get(session))); \
} else { \
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); \
}
void tls_close(gnutls_session_t session); void tls_close(gnutls_session_t session);
void tls_fatal_close(gnutls_session_t session, void tls_fatal_close(gnutls_session_t session,
@@ -66,5 +79,6 @@ typedef struct
void tls_cache_init(hash_db_st** db); void tls_cache_init(hash_db_st** db);
void tls_cache_deinit(hash_db_st* db); void tls_cache_deinit(hash_db_st* db);
void *calc_sha1_hash(char* file, unsigned cert);
#endif #endif
+5
View File
@@ -60,6 +60,8 @@ struct cfg_st {
char *pin_file; char *pin_file;
char *srk_pin_file; char *srk_pin_file;
char *cert; char *cert;
char *cert_hash;
char *key; char *key;
char *ca; char *ca;
char *crl; char *crl;
@@ -88,6 +90,9 @@ struct cfg_st {
char *connect_script; char *connect_script;
char *disconnect_script; char *disconnect_script;
char *xml_config_file;
char *xml_config_hash;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
+72 -115
View File
@@ -341,19 +341,84 @@ struct cmd_auth_cookie_req_st areq;
return recv_auth_reply(ws); return recv_auth_reply(ws);
} }
int post_common_handler(worker_st *ws, unsigned http_ver)
{
int ret, size;
char str_cookie[2*COOKIE_SIZE+1];
char *p;
unsigned i;
char msg[MAX_BANNER_SIZE+32];
p = str_cookie;
for (i=0;i<sizeof(ws->cookie);i++) {
sprintf(p, "%.2x", (unsigned int)ws->cookie[i]);
p+=2;
}
/* reply */
tls_cork(ws->session);
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n");
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Content-Type: text/xml\r\n");
if (ret < 0)
return -1;
if (ws->config->banner) {
size = snprintf(msg, sizeof(msg), "<banner>%s</banner>", ws->config->banner);
if (size <= 0)
return -1;
} else {
msg[0] = 0;
size = 0;
}
size += (sizeof(SUCCESS_MSG_HEAD)-1) + (sizeof(SUCCESS_MSG_FOOT)-1);
ret = tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned)size);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n");
if (ret < 0)
return -1;
ret = tls_printf(ws->session, "Set-Cookie: webvpn=%s;Max-Age=%u\r\n", str_cookie, (unsigned)ws->config->cookie_validity);
if (ret < 0)
return -1;
if (ws->config->xml_config_file) {
ret = tls_printf(ws->session, "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s&lu:/+CSCOT+/translation-table?textdomain%%3DAnyConnect%%26type%%3Dmanifest&fu:profiles%%2Fprofile.xml&fh:%s\r\n", ws->config->cert_hash,ws->config->xml_config_hash);
if (ret < 0)
return -1;
}
ret = tls_printf(ws->session, "\r\n"SUCCESS_MSG_HEAD"%s"SUCCESS_MSG_FOOT, msg);
if (ret < 0)
return -1;
ret = tls_uncork(ws->session);
if (ret < 0)
return -1;
return 0;
}
int post_old_auth_handler(worker_st *ws, unsigned http_ver) int post_old_auth_handler(worker_st *ws, unsigned http_ver)
{ {
int ret, size; int ret;
struct http_req_st *req = &ws->req; struct http_req_st *req = &ws->req;
const char* reason = "Authentication failed"; const char* reason = "Authentication failed";
char str_cookie[2*COOKIE_SIZE+1];
char * username = NULL; char * username = NULL;
char * password = NULL; char * password = NULL;
char *p; char *p;
unsigned int i;
struct cmd_auth_req_st areq; struct cmd_auth_req_st areq;
char msg[MAX_BANNER_SIZE+32];
memset(&areq, 0, sizeof(areq)); memset(&areq, 0, sizeof(areq));
@@ -412,59 +477,7 @@ char msg[MAX_BANNER_SIZE+32];
oclog(ws, LOG_INFO, "User '%s' logged in", ws->username); oclog(ws, LOG_INFO, "User '%s' logged in", ws->username);
p = str_cookie; return post_common_handler(ws, http_ver);;
for (i=0;i<sizeof(ws->cookie);i++) {
sprintf(p, "%.2x", (unsigned int)ws->cookie[i]);
p+=2;
}
/* reply */
tls_cork(ws->session);
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n");
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Content-Type: text/xml\r\n");
if (ret < 0)
return -1;
if (ws->config->banner) {
size = snprintf(msg, sizeof(msg), "<banner>%s</banner>", ws->config->banner);
if (size <= 0)
return -1;
} else {
msg[0] = 0;
size = 0;
}
size += (sizeof(SUCCESS_MSG_HEAD)-1) + (sizeof(SUCCESS_MSG_FOOT)-1);
ret = tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned)size);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n");
if (ret < 0)
return -1;
ret = tls_printf(ws->session, "Set-Cookie: webvpn=%s;Max-Age=%u\r\n", str_cookie, (unsigned)ws->config->cookie_validity);
if (ret < 0)
return -1;
ret = tls_printf(ws->session, "\r\n"SUCCESS_MSG_HEAD"%s"SUCCESS_MSG_FOOT, msg);
if (ret < 0)
return -1;
ret = tls_uncork(ws->session);
if (ret < 0)
return -1;
return 0;
auth_fail: auth_fail:
tls_printf(ws->session, tls_printf(ws->session,
@@ -480,16 +493,13 @@ auth_fail:
int post_new_auth_handler(worker_st *ws, unsigned http_ver) int post_new_auth_handler(worker_st *ws, unsigned http_ver)
{ {
int ret, size; int ret;
struct http_req_st *req = &ws->req; struct http_req_st *req = &ws->req;
const char* reason = "Authentication failed"; const char* reason = "Authentication failed";
char str_cookie[2*COOKIE_SIZE+1];
char * username = NULL; char * username = NULL;
char * password = NULL; char * password = NULL;
char *p; char *p;
unsigned int i;
struct cmd_auth_req_st areq; struct cmd_auth_req_st areq;
char msg[MAX_BANNER_SIZE+32];
memset(&areq, 0, sizeof(areq)); memset(&areq, 0, sizeof(areq));
@@ -544,60 +554,7 @@ char msg[MAX_BANNER_SIZE+32];
oclog(ws, LOG_INFO, "User '%s' logged in", ws->username); oclog(ws, LOG_INFO, "User '%s' logged in", ws->username);
p = str_cookie; return post_common_handler(ws, http_ver);;
for (i=0;i<sizeof(ws->cookie);i++) {
sprintf(p, "%.2x", (unsigned int)ws->cookie[i]);
p+=2;
}
/* reply */
tls_cork(ws->session);
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n");
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Content-Type: text/xml\r\n");
if (ret < 0)
return -1;
if (ws->config->banner) {
size = snprintf(msg, sizeof(msg), "<banner>%s</banner>", ws->config->banner);
if (size <= 0)
return -1;
} else {
msg[0] = 0;
size = 0;
}
size += (sizeof(SUCCESS_MSG_HEAD)-1) + (sizeof(SUCCESS_MSG_FOOT)-1);
ret = tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned)size);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n");
if (ret < 0)
return -1;
ret = tls_printf(ws->session, "Set-Cookie: webvpn=%s;Max-Age=%u\r\n", str_cookie, (unsigned)ws->config->cookie_validity);
if (ret < 0)
return -1;
ret = tls_printf(ws->session, "\r\n"SUCCESS_MSG_HEAD"%s"SUCCESS_MSG_FOOT, msg);
if (ret < 0)
return -1;
ret = tls_uncork(ws->session);
if (ret < 0)
return -1;
return 0;
ask_auth: ask_auth:
return get_auth_handler(ws, http_ver); return get_auth_handler(ws, http_ver);
+113 -5
View File
@@ -81,23 +81,128 @@ static int connect_handler(worker_st *ws);
typedef int (*url_handler_fn)(worker_st*, unsigned http_ver); typedef int (*url_handler_fn)(worker_st*, unsigned http_ver);
struct known_urls_st { struct known_urls_st {
const char* url; const char* url;
unsigned url_size;
url_handler_fn get_handler; url_handler_fn get_handler;
url_handler_fn post_handler; url_handler_fn post_handler;
}; };
int get_config_handler(worker_st *ws, unsigned http_ver)
{
int ret;
struct stat st;
oclog(ws, LOG_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);
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);
return -1;
}
tls_cork(ws->session);
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n");
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Content-Type: text/xml\r\n");
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "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);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "\r\n");
if (ret < 0)
return -1;
ret = tls_uncork(ws->session);
if (ret < 0)
return -1;
ret = tls_send_file(ws->session, 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;
}
return 0;
}
int get_cscot_handler(worker_st *ws, unsigned http_ver)
{
int ret;
oclog(ws, LOG_DEBUG, "requested CSCOT: %s", ws->req.url);
tls_cork(ws->session);
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Connection: Keep-Alive\r\n");
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "Content-Type: text/xml\r\n");
if (ret < 0)
return -1;
ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n");
if (ret < 0)
return -1;
#define MANIFEST "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<vpn rev=\"1.0\">\n" \
"</vpn>\n"
ret = tls_printf(ws->session, "Content-Length: %u\r\n\r\n", (unsigned)sizeof(MANIFEST)-1);
if (ret < 0)
return -1;
ret = tls_puts(ws->session, MANIFEST);
if (ret < 0)
return -1;
ret = tls_uncork(ws->session);
if (ret < 0)
return -1;
return 0;
}
#define LL(x,y,z) {x, sizeof(x)-1, y, z}
struct known_urls_st known_urls[] = { struct known_urls_st known_urls[] = {
{"/", get_auth_handler, post_new_auth_handler}, LL("/", get_auth_handler, post_new_auth_handler),
{"/auth", get_auth_handler, post_old_auth_handler}, LL("/auth", get_auth_handler, post_old_auth_handler),
{NULL, NULL} LL("/profiles", get_config_handler, NULL),
LL("/+CSCOT+/translation-table", get_cscot_handler, NULL),
{NULL, 0, NULL, NULL}
}; };
static url_handler_fn get_url_handler(const char* url) static url_handler_fn get_url_handler(const char* url)
{ {
struct known_urls_st *p; struct known_urls_st *p;
unsigned len = strlen(url);
p = known_urls; p = known_urls;
do { do {
if (p->url != NULL && strcmp(p->url, url)==0) if (p->url != NULL && (
(len == p->url_size && strcmp(p->url, url)==0) ||
(len >= p->url_size && strncmp(p->url, url, p->url_size)==0 &&
(url[p->url_size] == '/' || url[p->url_size] == '?'))))
return p->get_handler; return p->get_handler;
p++; p++;
} while(p->url != NULL); } while(p->url != NULL);
@@ -409,7 +514,7 @@ void vpn_server(struct worker_st* ws)
do { do {
ret = gnutls_handshake(session); ret = gnutls_handshake(session);
} while (ret < 0 && gnutls_error_is_fatal(ret) == 0); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
GNUTLS_FATAL_ERR(ret); GNUTLS_S_FATAL_ERR(session, ret);
oclog(ws, LOG_DEBUG, "TLS handshake completed"); oclog(ws, LOG_DEBUG, "TLS handshake completed");
@@ -988,6 +1093,9 @@ unsigned mtu_overhead, tls_mtu = 0;
hsk_restart: hsk_restart:
ret = gnutls_handshake(ws->dtls_session); ret = gnutls_handshake(ws->dtls_session);
if (ret < 0 && gnutls_error_is_fatal(ret) != 0) { if (ret < 0 && gnutls_error_is_fatal(ret) != 0) {
if (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
oclog(ws, LOG_ERR, "error in DTLS handshake: %s: %s\n", gnutls_strerror(ret), gnutls_alert_get_name(gnutls_alert_get(ws->dtls_session)));
else
oclog(ws, LOG_ERR, "error in DTLS handshake: %s\n", gnutls_strerror(ret)); oclog(ws, LOG_ERR, "error in DTLS handshake: %s\n", gnutls_strerror(ret));
ws->udp_state = UP_DISABLED; ws->udp_state = UP_DISABLED;
break; break;