mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 16:57:00 +08:00
Replaced the username cookie with a compact auth option.
That option performs authentication of username, password in a single go for clients that request Connection: Close.
This commit is contained in:
@@ -62,6 +62,18 @@ static const char login_msg_user[] =
|
||||
"</form></auth>\n"
|
||||
"</config-auth>";
|
||||
|
||||
static const char login_msg_compact[] =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<config-auth client=\"vpn\" type=\"auth-request\">\n"
|
||||
"<version who=\"sg\">0.1(1)</version>\n"
|
||||
"<auth id=\"main\">\n"
|
||||
"<message>Please enter your username and password</message>\n"
|
||||
"<form method=\"post\" action=\"/auth\">\n"
|
||||
"<input type=\"text\" name=\"username\" label=\"Username:\" />\n"
|
||||
"<input type=\"password\" name=\"password\" label=\"Password:\" />\n"
|
||||
"</form></auth>\n"
|
||||
"</config-auth>";
|
||||
|
||||
static const char login_msg_no_user[] =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<config-auth client=\"vpn\" type=\"auth-request\">\n"
|
||||
@@ -75,9 +87,9 @@ static const char login_msg_no_user[] =
|
||||
int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
|
||||
{
|
||||
int ret;
|
||||
struct http_req_st *req = &ws->req;
|
||||
char login_msg[MAX_MSG_SIZE + sizeof(login_msg_user)];
|
||||
unsigned int lsize;
|
||||
char *u;
|
||||
|
||||
tls_cork(ws->session);
|
||||
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
|
||||
@@ -92,17 +104,26 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
if (ws->auth_state == S_AUTH_REQ) {
|
||||
/* only ask password */
|
||||
if (pmsg == NULL)
|
||||
pmsg = "Please enter password";
|
||||
lsize =
|
||||
snprintf(login_msg, sizeof(login_msg), login_msg_no_user,
|
||||
pmsg);
|
||||
#ifdef ANYCONNECT_CLIENT_COMPAT
|
||||
if (req && req->needs_compact_auth != 0) {
|
||||
lsize = snprintf(login_msg, sizeof(login_msg), "%s", login_msg_compact);
|
||||
} else {
|
||||
/* ask for username only */
|
||||
lsize = snprintf(login_msg, sizeof(login_msg), login_msg_user);
|
||||
#endif
|
||||
if (ws->auth_state == S_AUTH_REQ) {
|
||||
/* only ask password */
|
||||
if (pmsg == NULL)
|
||||
pmsg = "Please enter password";
|
||||
lsize =
|
||||
snprintf(login_msg, sizeof(login_msg), login_msg_no_user,
|
||||
pmsg);
|
||||
} else {
|
||||
/* ask for username only */
|
||||
lsize = snprintf(login_msg, sizeof(login_msg), "%s", login_msg_user);
|
||||
}
|
||||
|
||||
#ifdef ANYCONNECT_CLIENT_COMPAT
|
||||
}
|
||||
#endif
|
||||
|
||||
ret =
|
||||
tls_printf(ws->session, "Content-Length: %u\r\n",
|
||||
@@ -110,21 +131,6 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef ANYCONNECT_CLIENT_COMPAT
|
||||
if (ws->username[0] != 0) {
|
||||
/* This is to make sure that some cisco clients that
|
||||
* like to connect for each request, don't lose the
|
||||
* username */
|
||||
u = escape_url(ws->username, strlen(ws->username), NULL);
|
||||
ret = tls_printf(ws->session, "Set-Cookie: ocuser=%s\r\n", u);
|
||||
|
||||
free(u);
|
||||
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n");
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
@@ -536,8 +542,6 @@ int read_user_pass(worker_st * ws, char *body, unsigned body_length,
|
||||
char *p;
|
||||
|
||||
if (memmem(body, body_length, "<?xml", 5) != 0) {
|
||||
oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", body_length,
|
||||
body);
|
||||
|
||||
if (username != NULL) {
|
||||
/* body should contain <username>test</username><password>test</password> */
|
||||
@@ -683,25 +687,24 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
|
||||
char tmp_user[MAX_USERNAME_SIZE];
|
||||
char tmp_group[MAX_USERNAME_SIZE];
|
||||
char msg[MAX_MSG_SIZE];
|
||||
unsigned complete_auth = 0;
|
||||
unsigned compact_auth = 0;
|
||||
|
||||
oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)req->body_length,
|
||||
req->body);
|
||||
restart:
|
||||
|
||||
if (ws->auth_state == S_AUTH_INACTIVE) {
|
||||
AuthInitMsg ireq = AUTH_INIT_MSG__INIT;
|
||||
|
||||
|
||||
#ifdef ANYCONNECT_CLIENT_COMPAT
|
||||
if (req->ocuser_cookie_set != 0) {
|
||||
/* the client has provided the username in a different
|
||||
* session and reconnected here to provide the password.
|
||||
* So we read the username from the cookie, start auth
|
||||
* and continue reading the password.
|
||||
if (req->needs_compact_auth != 0) {
|
||||
/* the client uses Connection: Close and needs to
|
||||
* be asked the username and password in one go.
|
||||
*/
|
||||
complete_auth = 1;
|
||||
ireq.user_name = ws->username;
|
||||
ireq.tls_auth_ok = tls_has_session_cert(ws);
|
||||
} else {
|
||||
compact_auth = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
|
||||
ret =
|
||||
read_user_pass(ws, req->body, req->body_length,
|
||||
@@ -736,10 +739,6 @@ restart:
|
||||
ireq.cert_group_name = tmp_group;
|
||||
}
|
||||
|
||||
#ifdef ANYCONNECT_CLIENT_COMPAT
|
||||
}
|
||||
#endif
|
||||
|
||||
ireq.hostname = req->hostname;
|
||||
|
||||
ret = send_msg_to_main(ws, AUTH_INIT,
|
||||
@@ -799,7 +798,8 @@ restart:
|
||||
ws->auth_state = S_AUTH_REQ;
|
||||
|
||||
#ifdef ANYCONNECT_CLIENT_COMPAT
|
||||
if (complete_auth != 0) {
|
||||
if (compact_auth != 0) {
|
||||
compact_auth = 0; /* avoid infinite loop */
|
||||
goto restart;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <gettime.h>
|
||||
#include <common.h>
|
||||
#include <html.h>
|
||||
#include <c-strcase.h>
|
||||
#include <worker-bandwidth.h>
|
||||
|
||||
#include <vpn.h>
|
||||
@@ -110,6 +111,8 @@ const static struct known_urls_st known_urls[] = {
|
||||
|
||||
LL("/profiles", get_config_handler, NULL),
|
||||
LL("/+CSCOT+/translation-table", get_string_handler, NULL),
|
||||
LL("/+CSCOT+/oem-customization", get_string_handler, NULL),
|
||||
LL("/logout", get_empty_handler, NULL),
|
||||
#endif
|
||||
{NULL, 0, 0, NULL, NULL}
|
||||
};
|
||||
@@ -167,6 +170,7 @@ int url_cb(http_parser * parser, const char *at, size_t length)
|
||||
}
|
||||
|
||||
#define STR_HDR_COOKIE "Cookie"
|
||||
#define STR_HDR_CONNECTION "Connection"
|
||||
#define STR_HDR_MS "X-DTLS-Master-Secret"
|
||||
#define STR_HDR_CS "X-DTLS-CipherSuite"
|
||||
#define STR_HDR_DMTU "X-DTLS-MTU"
|
||||
@@ -186,6 +190,7 @@ static void value_check(struct worker_st *ws, struct http_req_st *req)
|
||||
uint8_t *p;
|
||||
char *token;
|
||||
char *str;
|
||||
char strtmp[16];
|
||||
|
||||
if (req->value.length <= 0)
|
||||
return;
|
||||
@@ -292,30 +297,22 @@ static void value_check(struct worker_st *ws, struct http_req_st *req)
|
||||
case HEADER_DTLS_MTU:
|
||||
req->dtls_mtu = atoi((char *)req->value.data);
|
||||
break;
|
||||
case HEADER_COOKIE:
|
||||
case HEADER_CONNECTION:
|
||||
length = req->value.length;
|
||||
|
||||
#ifdef ANYCONNECT_CLIENT_COMPAT
|
||||
if (ws->username[0] == 0) {
|
||||
p = memmem(req->value.data, length, "ocuser=", 7);
|
||||
if (p != NULL) {
|
||||
char *u;
|
||||
if (length > sizeof(strtmp)-1)
|
||||
break;
|
||||
|
||||
p += 7;
|
||||
length -= 7;
|
||||
u = unescape_url((char *)p, length, NULL);
|
||||
if (u == NULL)
|
||||
break;
|
||||
memcpy(strtmp, req->value.data, length);
|
||||
strtmp[length] = 0;
|
||||
|
||||
snprintf(ws->username, sizeof(ws->username),
|
||||
"%s", u);
|
||||
free(u);
|
||||
req->ocuser_cookie_set = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
if (c_strcasecmp(strtmp, "close") == 0) {
|
||||
oclog(ws, LOG_INFO, "client needs compact auth");
|
||||
req->needs_compact_auth = 1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case HEADER_COOKIE:
|
||||
length = req->value.length;
|
||||
|
||||
p = memmem(req->value.data, length, "webvpn=", 7);
|
||||
if (p == NULL || length <= 7) {
|
||||
@@ -393,6 +390,10 @@ static void header_check(struct http_req_st *req)
|
||||
strncmp((char *)req->header.data, STR_HDR_ATYPE,
|
||||
req->header.length) == 0) {
|
||||
req->next_header = HEADER_CSTP_ATYPE;
|
||||
} else if (req->header.length == sizeof(STR_HDR_CONNECTION) - 1 &&
|
||||
strncmp((char *)req->header.data, STR_HDR_CONNECTION,
|
||||
req->header.length) == 0) {
|
||||
req->next_header = HEADER_CONNECTION;
|
||||
} else {
|
||||
req->next_header = 0;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ enum {
|
||||
HEADER_CSTP_ATYPE,
|
||||
HEADER_DTLS_MTU,
|
||||
HEADER_DTLS_CIPHERSUITE,
|
||||
HEADER_CONNECTION,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -76,7 +77,12 @@ struct http_req_st {
|
||||
unsigned int next_header;
|
||||
unsigned char cookie[COOKIE_SIZE];
|
||||
unsigned int cookie_set;
|
||||
unsigned int ocuser_cookie_set;
|
||||
/* some CISCO clients reconnect for each request
|
||||
* and is impossible to keep state for them. For
|
||||
* that we ask username and password in one go for
|
||||
* them.
|
||||
*/
|
||||
unsigned int needs_compact_auth;
|
||||
unsigned char master_secret[TLS_MASTER_SIZE];
|
||||
unsigned int master_secret_set;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user