diff -durN ocserv-1.1.6.orig/src/Makefile.am ocserv-1.1.6/src/Makefile.am
--- ocserv-1.1.6.orig/src/Makefile.am 2022-02-27 23:34:34.653439020 +1300
+++ ocserv-1.1.6/src/Makefile.am 2022-03-01 21:54:16.144350358 +1300
@@ -75,7 +75,7 @@
html.c html.h http-heads.h worker.c worker.h worker-auth.c \
worker-bandwidth.c worker-bandwidth.h worker-http.c worker-http-handlers.c \
worker-kkdcp.c worker-misc.c worker-privs.c worker-proxyproto.c \
- worker-resume.c worker-vpn.c
+ worker-resume.c worker-vpn.c worker-svc.c
ocserv_worker_LDADD = $(CORE_LDADD)
diff -durN ocserv-1.1.6.orig/src/Makefile.in ocserv-1.1.6/src/Makefile.in
--- ocserv-1.1.6.orig/src/Makefile.in 2022-02-27 23:34:34.653439020 +1300
+++ ocserv-1.1.6/src/Makefile.in 2022-03-01 21:54:16.148350129 +1300
@@ -323,7 +323,7 @@
worker-bandwidth.c worker-bandwidth.h worker-http.c \
worker-http-handlers.c worker-kkdcp.c worker-misc.c \
worker-privs.c worker-proxyproto.c worker-resume.c \
- worker-vpn.c worker-latency.c worker-latency.h
+ worker-vpn.c worker-svc.c worker-latency.c worker-latency.h
@LOCAL_HTTP_PARSER_TRUE@am__objects_11 = http-parser/ocserv_worker-http_parser.$(OBJEXT)
@ENABLE_COMPRESSION_TRUE@am__objects_12 = ocserv_worker-lzs.$(OBJEXT)
@HAVE_GSSAPI_TRUE@am__objects_13 = \
@@ -358,7 +358,8 @@
ocserv_worker-worker-privs.$(OBJEXT) \
ocserv_worker-worker-proxyproto.$(OBJEXT) \
ocserv_worker-worker-resume.$(OBJEXT) \
- ocserv_worker-worker-vpn.$(OBJEXT) $(am__objects_15)
+ ocserv_worker-worker-vpn.$(OBJEXT) \
+ ocserv_worker-worker-svc.$(OBJEXT) $(am__objects_15)
ocserv_worker_OBJECTS = $(am_ocserv_worker_OBJECTS)
@ENABLE_LATENCY_SUPPORT_TRUE@am__DEPENDENCIES_7 = \
@ENABLE_LATENCY_SUPPORT_TRUE@ $(am__DEPENDENCIES_1)
@@ -446,6 +447,7 @@
./$(DEPDIR)/ocserv_worker-worker-privs.Po \
./$(DEPDIR)/ocserv_worker-worker-proxyproto.Po \
./$(DEPDIR)/ocserv_worker-worker-resume.Po \
+ ./$(DEPDIR)/ocserv_worker-worker-svc.Po \
./$(DEPDIR)/ocserv_worker-worker-vpn.Po \
./$(DEPDIR)/ocserv_worker-worker.Po ./$(DEPDIR)/proc-search.Po \
./$(DEPDIR)/route-add.Po ./$(DEPDIR)/sec-mod-auth.Po \
@@ -1333,7 +1335,7 @@
worker.c worker.h worker-auth.c worker-bandwidth.c \
worker-bandwidth.h worker-http.c worker-http-handlers.c \
worker-kkdcp.c worker-misc.c worker-privs.c \
- worker-proxyproto.c worker-resume.c worker-vpn.c \
+ worker-proxyproto.c worker-resume.c worker-vpn.c worker-svc.c \
$(am__append_8)
ocserv_worker_LDADD = $(CORE_LDADD) $(am__append_9)
noinst_LIBRARIES = libipc.a libcommon.a libccan.a $(am__append_17) \
@@ -1825,6 +1827,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocserv_worker-worker-privs.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocserv_worker-worker-proxyproto.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocserv_worker-worker-resume.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocserv_worker-worker-svc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocserv_worker-worker-vpn.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocserv_worker-worker.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc-search.Po@am__quote@ # am--include-marker
@@ -2766,6 +2769,20 @@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ocserv_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ocserv_worker-worker-vpn.obj `if test -f 'worker-vpn.c'; then $(CYGPATH_W) 'worker-vpn.c'; else $(CYGPATH_W) '$(srcdir)/worker-vpn.c'; fi`
+ocserv_worker-worker-svc.o: worker-svc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ocserv_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ocserv_worker-worker-svc.o -MD -MP -MF $(DEPDIR)/ocserv_worker-worker-svc.Tpo -c -o ocserv_worker-worker-svc.o `test -f 'worker-svc.c' || echo '$(srcdir)/'`worker-svc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ocserv_worker-worker-svc.Tpo $(DEPDIR)/ocserv_worker-worker-svc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='worker-svc.c' object='ocserv_worker-worker-svc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ocserv_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ocserv_worker-worker-svc.o `test -f 'worker-svc.c' || echo '$(srcdir)/'`worker-svc.c
+
+ocserv_worker-worker-svc.obj: worker-svc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ocserv_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ocserv_worker-worker-svc.obj -MD -MP -MF $(DEPDIR)/ocserv_worker-worker-svc.Tpo -c -o ocserv_worker-worker-svc.obj `if test -f 'worker-svc.c'; then $(CYGPATH_W) 'worker-svc.c'; else $(CYGPATH_W) '$(srcdir)/worker-svc.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ocserv_worker-worker-svc.Tpo $(DEPDIR)/ocserv_worker-worker-svc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='worker-svc.c' object='ocserv_worker-worker-svc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ocserv_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ocserv_worker-worker-svc.obj `if test -f 'worker-svc.c'; then $(CYGPATH_W) 'worker-svc.c'; else $(CYGPATH_W) '$(srcdir)/worker-svc.c'; fi`
+
ocserv_worker-worker-latency.o: worker-latency.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ocserv_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ocserv_worker-worker-latency.o -MD -MP -MF $(DEPDIR)/ocserv_worker-worker-latency.Tpo -c -o ocserv_worker-worker-latency.o `test -f 'worker-latency.c' || echo '$(srcdir)/'`worker-latency.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ocserv_worker-worker-latency.Tpo $(DEPDIR)/ocserv_worker-worker-latency.Po
@@ -2989,6 +3006,7 @@
-rm -f ./$(DEPDIR)/ocserv_worker-worker-privs.Po
-rm -f ./$(DEPDIR)/ocserv_worker-worker-proxyproto.Po
-rm -f ./$(DEPDIR)/ocserv_worker-worker-resume.Po
+ -rm -f ./$(DEPDIR)/ocserv_worker-worker-svc.Po
-rm -f ./$(DEPDIR)/ocserv_worker-worker-vpn.Po
-rm -f ./$(DEPDIR)/ocserv_worker-worker.Po
-rm -f ./$(DEPDIR)/proc-search.Po
@@ -3149,6 +3167,7 @@
-rm -f ./$(DEPDIR)/ocserv_worker-worker-privs.Po
-rm -f ./$(DEPDIR)/ocserv_worker-worker-proxyproto.Po
-rm -f ./$(DEPDIR)/ocserv_worker-worker-resume.Po
+ -rm -f ./$(DEPDIR)/ocserv_worker-worker-svc.Po
-rm -f ./$(DEPDIR)/ocserv_worker-worker-vpn.Po
-rm -f ./$(DEPDIR)/ocserv_worker-worker.Po
-rm -f ./$(DEPDIR)/proc-search.Po
diff -durN ocserv-1.1.6.orig/src/worker.h ocserv-1.1.6/src/worker.h
--- ocserv-1.1.6.orig/src/worker.h 2022-02-27 23:34:34.653439020 +1300
+++ ocserv-1.1.6/src/worker.h 2022-03-01 21:54:16.148350129 +1300
@@ -91,7 +91,8 @@
AGENT_UNKNOWN,
AGENT_OPENCONNECT_V3,
AGENT_OPENCONNECT,
- AGENT_ANYCONNECT
+ AGENT_ANYCONNECT,
+ AGENT_SVC_IPPHONE
};
typedef int (*decompress_fn)(void* dst, int maxDstSize, const void* src, int src_size);
@@ -337,6 +338,8 @@
int get_cert_der_handler(worker_st * ws, unsigned http_ver);
int get_ca_handler(worker_st * ws, unsigned http_ver);
int get_ca_der_handler(worker_st * ws, unsigned http_ver);
+int get_svc_handler(worker_st *server, unsigned http_ver);
+int post_svc_handler(worker_st *server, unsigned http_ver);
int response_404(worker_st *ws, unsigned http_ver);
int get_empty_handler(worker_st *server, unsigned http_ver);
diff -durN ocserv-1.1.6.orig/src/worker-http.c ocserv-1.1.6/src/worker-http.c
--- ocserv-1.1.6.orig/src/worker-http.c 2022-02-27 23:34:34.653439020 +1300
+++ ocserv-1.1.6/src/worker-http.c 2022-03-01 21:54:16.148350129 +1300
@@ -75,6 +75,7 @@
LL("/+CSCOT+/", get_string_handler, NULL),
LL("/logout", get_empty_handler, NULL),
#endif
+ LL("/svc", get_svc_handler, post_svc_handler),
{NULL, 0, 0, NULL, NULL}
};
@@ -419,6 +420,9 @@
} else if (strncasecmp(req->user_agent, "AnyConnect", 10) == 0) {
oclog(ws, LOG_DEBUG, "Detected Cisco AnyConnect");
req->user_agent_type = AGENT_ANYCONNECT;
+ } else if (strncasecmp(req->user_agent, "Cisco SVC IPPhone Client", 24) == 0) {
+ oclog(ws, LOG_DEBUG, "Detected Cisco SVC IPPhone Client");
+ req->user_agent_type = AGENT_SVC_IPPHONE;
} else {
oclog(ws, LOG_DEBUG, "Unknown client (%s)", req->user_agent);
}
diff -durN ocserv-1.1.6.orig/src/worker-svc.c ocserv-1.1.6/src/worker-svc.c
--- ocserv-1.1.6.orig/src/worker-svc.c 1970-01-01 12:00:00.000000000 +1200
+++ ocserv-1.1.6/src/worker-svc.c 2022-09-02 23:01:46.889506645 +1200
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2021 Gareth Palmer
+ *
+ * This file is part of ocserv.
+ *
+ * ocserv is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * ocserv is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include "html.h"
+#include
+#include
+
+
+static const char svc_login_body[] =
+ "\n"
+ "\n"
+ "SSL VPN Service\n"
+ "Please enter your username and password.\n"
+ "\n"
+ "\n";
+
+static const char svc_success_body[] =
+ "\n"
+ "\n"
+ "\n";
+
+int get_svc_handler(worker_st *ws, unsigned http_ver)
+{
+ int ret;
+ str_st str;
+
+ str_init(&str, ws);
+
+ oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 200 OK");
+ cstp_cork(ws);
+
+ ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver);
+ if (ret < 0)
+ return -1;
+
+ ret = str_append_printf(&str, svc_login_body, ws->req.url);
+ if (ret < 0)
+ goto fail;
+
+ ret = cstp_puts(ws, "Content-Type: text/xml\r\n");
+ if (ret < 0)
+ goto fail;
+
+ ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned int)str.length);
+ if (ret < 0)
+ goto fail;
+
+ ret = cstp_puts(ws, "Set-Cookie: webvpn=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; secure\r\n");
+ if (ret < 0)
+ goto fail;
+
+ ret = cstp_puts(ws, "Set-Cookie: webvpnc=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; secure\r\n");
+ if (ret < 0)
+ goto fail;
+
+ ret = cstp_puts(ws, "Set-Cookie: webvpnlogin=1; secure\r\n");
+ if (ret < 0)
+ goto fail;
+
+ ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n");
+ if (ret < 0)
+ goto fail;
+
+ /* end of headers */
+ ret = cstp_puts(ws, "\r\n");
+ if (ret < 0)
+ goto fail;
+
+ ret = cstp_send(ws, str.data, str.length);
+ if (ret < 0)
+ goto fail;
+
+ ret = cstp_uncork(ws);
+ if (ret < 0)
+ goto fail;
+
+ ret = 0;
+
+fail:
+ str_clear(&str);
+ if (ret < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int parse_post_body(worker_st *ws, char **password)
+{
+ char *username, *field, *value, *delim;
+ int field_len, value_len;
+
+ *password = NULL;
+
+ if (ws->req.body_length == 0)
+ return -1;
+
+ oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)ws->req.body_length,
+ ws->req.body);
+
+ /* body should be "username=foo&password=bar&Login=Login" */
+ field = ws->req.body;
+ do {
+ delim = field;
+ field_len = 0;
+
+ while (*delim != 0) {
+ if (*delim == '=')
+ break;
+ delim++;
+ field_len++;
+ }
+
+ if (*delim != '=')
+ break;
+ delim++;
+
+ value = delim;
+ value_len = 0;
+
+ while (*delim != 0) {
+ if (*delim == '&')
+ break;
+ delim++;
+ value_len++;
+ }
+
+ if (strncasecmp(field, "username", field_len) == 0) {
+ username = unescape_url(ws->req.body,
+ value, value_len, NULL);
+ strlcpy(ws->username, username, sizeof(ws->username));
+ talloc_free(username);
+ } else if (strncasecmp(field, "password", field_len) == 0) {
+ talloc_free(*password);
+ *password = unescape_url(ws->req.body,
+ value, value_len, NULL);
+ }
+
+ if (*delim != '&')
+ break;
+ delim++;
+
+ field = delim;
+ } while (*field != 0);
+
+ if (ws->username[0] == '\0') {
+ talloc_free(*password);
+ oclog(ws, LOG_HTTP_DEBUG, "missing username in request");
+ return -1;
+ } else if (*password == NULL) {
+ oclog(ws, LOG_HTTP_DEBUG, "missing password in request");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int get_cert_info(worker_st *ws)
+{
+ const gnutls_datum_t *raw;
+ unsigned int ncerts;
+ gnutls_x509_crt_t cert;
+ char cert_username[MAX_USERNAME_SIZE], cert_group[MAX_GROUPNAME_SIZE];
+ size_t cert_username_len, cert_group_len;
+ int ret = -1;
+
+ if (ws->cert_auth_ok == 0)
+ return -1;
+
+ raw = gnutls_certificate_get_peers(ws->session, &ncerts);
+ if (raw == NULL)
+ return -1;
+
+ ret = gnutls_x509_crt_init(&cert);
+ if (ret < 0) {
+ oclog(ws, LOG_ERR, "certificate init error: %s",
+ gnutls_strerror(ret));
+ goto fail;
+ }
+
+ ret = gnutls_x509_crt_import(cert, raw, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ oclog(ws, LOG_ERR, "certificate import error: %s",
+ gnutls_strerror(ret));
+ goto fail;
+ }
+
+ cert_username_len = sizeof(cert_username);
+ ret = gnutls_x509_crt_get_dn_by_oid(cert, WSCONFIG(ws)->cert_user_oid, 0,
+ 0, cert_username, &cert_username_len);
+ if (ret < 0) {
+ if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ oclog(ws, LOG_ERR,
+ "certificate's username exceed the maximum buffer size (%u)",
+ (unsigned)sizeof(cert_username));
+ else if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ oclog(ws, LOG_ERR, "the certificate's DN does not contain OID %s; "
+ "cannot determine username", WSCONFIG(ws)->cert_user_oid);
+ else
+ oclog(ws, LOG_ERR, "cannot obtain username from certificate: %s",
+ gnutls_strerror(ret));
+
+ goto fail;
+ }
+
+ strlcpy(ws->cert_username, cert_username, sizeof(ws->cert_username));
+
+ if (WSCONFIG(ws)->cert_group_oid) {
+ cert_group_len = sizeof(cert_group);
+ ret = gnutls_x509_crt_get_dn_by_oid(cert, WSCONFIG(ws)->cert_group_oid, 0,
+ 0, cert_group, &cert_group_len);
+ if (ret < 0) {
+ if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ oclog(ws, LOG_ERR,
+ "certificate's group exceed the maximum buffer size (%u)",
+ (unsigned)sizeof(cert_group));
+ else if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ oclog(ws, LOG_ERR, "the certificate's DN does not contain OID %s; "
+ "cannot determine group", WSCONFIG(ws)->cert_group_oid);
+ else
+ oclog(ws, LOG_ERR, "cannot obtain group from certificate: %s",
+ gnutls_strerror(ret));
+
+ goto fail;
+ }
+
+ ws->cert_groups = talloc_realloc(ws, ws->cert_groups, char *, 1);
+ if (ws->cert_groups == NULL) {
+ oclog(ws, LOG_ERR, "cannot allocate memory for cert groups");
+ goto fail;
+ }
+
+ ws->cert_groups[0] = talloc_size(ws->cert_groups, cert_group_len + 1);
+ if (ws->cert_groups[0] == NULL) {
+ oclog(ws, LOG_ERR, "cannot allocate memory for cert group");
+ goto fail;
+ }
+
+ strlcpy(ws->cert_groups[0], cert_group, cert_group_len);
+ ws->cert_groups_size = 1;
+ }
+
+fail:
+ gnutls_x509_crt_deinit(cert);
+ return ret;
+}
+
+static int recv_auth_reply(worker_st *ws, int sd)
+{
+ int ret;
+ SecAuthReplyMsg *rep = NULL;
+ PROTOBUF_ALLOCATOR(pa, ws);
+
+ ret = recv_msg(ws, sd, CMD_SEC_AUTH_REPLY,
+ (void *)&rep, (unpack_func)sec_auth_reply_msg__unpack,
+ WSCONFIG(ws)->auth_timeout);
+ if (ret < 0) {
+ oclog(ws, LOG_ERR, "error receiving auth reply message");
+ return ret;
+ }
+
+ oclog(ws, LOG_DEBUG, "received auth reply message (value: %u)",
+ (unsigned)rep->reply);
+
+ switch (rep->reply) {
+ case AUTH__REP__MSG:
+ if (rep->has_sid && rep->sid.len == sizeof(ws->sid)) {
+ memcpy(ws->sid, rep->sid.data, sizeof(ws->sid));
+ ws->sid_set = 1;
+ }
+
+ ret = ERR_AUTH_CONTINUE;
+ break;
+ case AUTH__REP__OK:
+ if (rep->user_name == NULL) {
+ ret = ERR_AUTH_FAIL;
+ break;
+ }
+
+ strlcpy(ws->username, rep->user_name, sizeof(ws->username));
+
+ if (rep->has_sid && rep->sid.len == sizeof(ws->sid)) {
+ memcpy(ws->sid, rep->sid.data, sizeof(ws->sid));
+ ws->sid_set = 1;
+ }
+
+ if (rep->has_sid == 0
+ || rep->sid.len != sizeof(ws->cookie)
+ || rep->dtls_session_id.len != sizeof(ws->session_id)) {
+ ret = ERR_AUTH_FAIL;
+ break;
+ }
+
+ memcpy(ws->cookie, rep->sid.data, rep->sid.len);
+ ws->cookie_set = 1;
+
+ memcpy(ws->session_id, rep->dtls_session_id.data,
+ rep->dtls_session_id.len);
+
+ ret = ERR_SUCCESS;
+ break;
+ case AUTH__REP__FAILED:
+ default:
+ if (rep->reply != AUTH__REP__FAILED)
+ oclog(ws, LOG_ERR, "unexpected auth reply %u",
+ (unsigned)rep->reply);
+ ret = ERR_AUTH_FAIL;
+ break;
+ }
+
+ sec_auth_reply_msg__free_unpacked(rep, &pa);
+ return ret;
+}
+
+static int client_auth(worker_st *ws, char *password)
+{
+ int ret = -1, sd = -1;
+ SecAuthInitMsg init = SEC_AUTH_INIT_MSG__INIT;
+ SecAuthContMsg cont = SEC_AUTH_CONT_MSG__INIT;
+
+ if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
+ ws->groupname[0] = '\0';
+ init.user_name = ws->username;
+ init.auth_type |= AUTH_TYPE_USERNAME_PASS;
+ } else if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE) {
+ init.tls_auth_ok = ws->cert_auth_ok;
+ init.cert_user_name = ws->cert_username;
+ init.cert_group_names = ws->cert_groups;
+ init.n_cert_group_names = ws->cert_groups_size;
+ init.auth_type |= AUTH_TYPE_CERTIFICATE;
+ }
+ init.vhost = ws->vhost->name;
+ init.ip = ws->remote_ip_str;
+ init.our_ip = ws->our_ip_str;
+ init.session_start_time = ws->session_start_time;
+ init.hmac.data = (uint8_t*)ws->sec_auth_init_hmac;
+ init.hmac.len = sizeof(ws->sec_auth_init_hmac);
+
+ if (ws->req.user_agent[0] != 0)
+ init.user_agent = ws->req.user_agent;
+
+ if (ws->req.devtype[0] != 0)
+ init.device_type = ws->req.devtype;
+
+ if (ws->req.devplatform[0] != 0)
+ init.device_platform = ws->req.devplatform;
+
+ sd = connect_to_secmod(ws);
+ if (sd == -1) {
+ oclog(ws, LOG_ERR, "failed connecting to sec mod");
+ goto fail;
+ }
+
+ ret = send_msg_to_secmod(ws, sd, CMD_SEC_AUTH_INIT, &init,
+ (pack_size_func)sec_auth_init_msg__get_packed_size,
+ (pack_func)sec_auth_init_msg__pack);
+ if (ret < 0) {
+ oclog(ws, LOG_ERR, "failed sending auth init message to sec mod");
+ goto fail;
+ }
+
+ ws->auth_state = S_AUTH_INIT;
+
+ ret = recv_auth_reply(ws, sd);
+ if (ret != ERR_AUTH_CONTINUE) {
+ oclog(ws, LOG_ERR, "not in auth continue state: %d", ret);
+ goto fail;
+ }
+
+ close(sd);
+
+ cont.ip = ws->remote_ip_str;
+ if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS)
+ cont.password = password;
+
+ if (ws->sid_set != 0) {
+ cont.sid.data = ws->sid;
+ cont.sid.len = sizeof(ws->sid);
+ }
+
+ sd = connect_to_secmod(ws);
+ if (sd == -1) {
+ oclog(ws, LOG_ERR, "failed connecting to sec mod");
+ goto fail;
+ }
+
+ ret = send_msg_to_secmod(ws, sd, CMD_SEC_AUTH_CONT, &cont,
+ (pack_size_func)sec_auth_cont_msg__get_packed_size,
+ (pack_func)sec_auth_cont_msg__pack);
+ if (ret < 0) {
+ oclog(ws, LOG_ERR, "failed sending auth cont message to sec mod");
+ goto fail;
+ }
+
+ ret = recv_auth_reply(ws, sd);
+ if (ret != ERR_SUCCESS) {
+ oclog(ws, LOG_ERR, "failed authentication for '%s'",
+ ws->username);
+ goto fail;
+ }
+
+fail:
+ if (sd != -1)
+ close(sd);
+
+ return ret;
+}
+
+int post_svc_handler(worker_st *ws, unsigned http_ver)
+{
+ char *password = NULL;
+ int ret = -1;
+ char cookie[BASE64_ENCODE_RAW_LENGTH(sizeof(ws->cookie)) + 1];
+
+ if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
+ /* fail if username or password is missing */
+ ret = parse_post_body(ws, &password);
+ if (ret < 0)
+ return get_svc_handler(ws, http_ver);
+ } else if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE) {
+ ret = get_cert_info(ws);
+ }
+
+ if (ret >= 0)
+ ret = client_auth(ws, password);
+ talloc_free(password);
+
+ if (ret < 0) {
+ oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 401 Unauthorized");
+ cstp_printf(ws, "HTTP/1.%d 401 Authentication failed\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n", http_ver);
+
+ cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED);
+ exit_worker(ws);
+ return -1;
+ }
+
+ ws->auth_state = S_AUTH_COOKIE;
+ oclog(ws, LOG_HTTP_DEBUG, "user '%s' obtained cookie", ws->username);
+
+ oc_base64_encode((char *)ws->cookie, sizeof(ws->cookie),
+ cookie, sizeof(cookie));
+
+ /* reply */
+ oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 200 OK");
+
+ cstp_cork(ws);
+ ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver);
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_puts(ws, "Connection: Keep-Alive\r\n");
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_puts(ws, "Content-Type: text/xml\r\n");
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_printf(ws, "Content-Length: %u\r\n",
+ (unsigned int)sizeof(svc_success_body) - 1);
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_printf(ws, "Set-Cookie: webvpn=%s; secure\r\n", cookie);
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_printf(ws,
+ "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s; path=/; secure\r\n",
+ WSPCONFIG(ws)->cert_hash);
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_puts(ws, "Set-Cookie: webvpnlogin=1; secure\r\n");
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n");
+ if (ret < 0)
+ return -1;
+
+ /* end of headers */
+ ret = cstp_puts(ws, "\r\n");
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_puts(ws, svc_success_body);
+ if (ret < 0)
+ return -1;
+
+ ret = cstp_uncork(ws);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}