Commit 021bddd2 authored by David Woodhouse's avatar David Woodhouse

Start making HTTP authentication less proxy-specific

Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent de42bfcb
......@@ -78,7 +78,8 @@ static void buf_append_md5(struct oc_text_buf *buf, void *data, int len)
buf_append(buf, "%02x", md5[i]);
}
int digest_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *hdrbuf)
int digest_authorization(struct openconnect_info *vpninfo, struct http_auth_state *auth_state,
struct oc_text_buf *hdrbuf)
{
char *chall;
int ret = -EINVAL;
......@@ -93,15 +94,15 @@ int digest_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *h
if (!vpninfo->proxy_user || !vpninfo->proxy_pass)
return -EINVAL;
if (vpninfo->auth[AUTH_TYPE_DIGEST].state < AUTH_AVAILABLE)
if (auth_state->state < AUTH_AVAILABLE)
return -EINVAL;
if (vpninfo->auth[AUTH_TYPE_DIGEST].state == AUTH_IN_PROGRESS) {
vpninfo->auth[AUTH_TYPE_DIGEST].state = AUTH_FAILED;
if (auth_state->state == AUTH_IN_PROGRESS) {
auth_state->state = AUTH_FAILED;
return -EAGAIN;
}
chall = vpninfo->auth[AUTH_TYPE_DIGEST].challenge;
chall = auth_state->challenge;
if (!chall)
return -EINVAL;
......@@ -237,7 +238,7 @@ int digest_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *h
ret = 0;
vpninfo->auth[AUTH_TYPE_DIGEST].state = AUTH_IN_PROGRESS;
auth_state->state = AUTH_IN_PROGRESS;
vpn_progress(vpninfo, PRG_INFO,
_("Attempting Digest authentication to proxy\n"));
err:
......
......@@ -80,25 +80,27 @@ static int gssapi_setup(struct openconnect_info *vpninfo, const char *service)
#define GSSAPI_CONTINUE 2
#define GSSAPI_COMPLETE 3
int gssapi_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *hdrbuf)
int gssapi_authorization(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state,
struct oc_text_buf *hdrbuf)
{
OM_uint32 major, minor;
gss_buffer_desc in = GSS_C_EMPTY_BUFFER;
gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
gss_OID mech = GSS_C_NO_OID;
if (vpninfo->auth[AUTH_TYPE_GSSAPI].state == AUTH_AVAILABLE && gssapi_setup(vpninfo, "HTTP")) {
vpninfo->auth[AUTH_TYPE_GSSAPI].state = AUTH_FAILED;
if (auth_state->state == AUTH_AVAILABLE && gssapi_setup(vpninfo, "HTTP")) {
auth_state->state = AUTH_FAILED;
return -EIO;
}
if (vpninfo->auth[AUTH_TYPE_GSSAPI].challenge && *vpninfo->auth[AUTH_TYPE_GSSAPI].challenge) {
if (auth_state->challenge && *auth_state->challenge) {
int len = -EINVAL;
in.value = openconnect_base64_decode(&len, vpninfo->auth[AUTH_TYPE_GSSAPI].challenge);
in.value = openconnect_base64_decode(&len, auth_state->challenge);
if (!in.value)
return len;
in.length = len;
} else if (vpninfo->auth[AUTH_TYPE_GSSAPI].state > AUTH_AVAILABLE) {
} else if (auth_state->state > AUTH_AVAILABLE) {
/* This indicates failure. We were trying, but got an empty
'Proxy-Authorization: Negotiate' header back from the server
implying that we should start again... */
......@@ -113,15 +115,15 @@ int gssapi_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *h
free(in.value);
if (major == GSS_S_COMPLETE)
vpninfo->auth[AUTH_TYPE_GSSAPI].state = GSSAPI_COMPLETE;
auth_state->state = GSSAPI_COMPLETE;
else if (major == GSS_S_CONTINUE_NEEDED)
vpninfo->auth[AUTH_TYPE_GSSAPI].state = GSSAPI_CONTINUE;
auth_state->state = GSSAPI_CONTINUE;
else {
vpn_progress(vpninfo, PRG_ERR,
_("Error generating GSSAPI response:\n"));
print_gss_err(vpninfo, "gss_init_sec_context()", mech, major, minor);
fail_gssapi:
vpninfo->auth[AUTH_TYPE_GSSAPI].state = AUTH_FAILED;
auth_state->state = AUTH_FAILED;
cleanup_gssapi_auth(vpninfo);
/* If we were *trying*, then -EAGAIN. Else -ENOENT to let another
auth method try without having to reconnect first. */
......@@ -132,7 +134,7 @@ int gssapi_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *h
buf_append(hdrbuf, "\r\n");
gss_release_buffer(&minor, &out);
if (!vpninfo->auth[AUTH_TYPE_GSSAPI].challenge)
if (!auth_state->challenge)
vpn_progress(vpninfo, PRG_INFO,
_("Attempting GSSAPI authentication to proxy\n"));
return 0;
......
......@@ -1118,11 +1118,11 @@ static int process_socks_proxy(struct openconnect_info *vpninfo)
buf[2 + nr_auth_methods++] = SOCKS_AUTH_NONE;
#if defined(HAVE_GSSAPI) || defined(_WIN32)
if (vpninfo->auth[AUTH_TYPE_GSSAPI].state != AUTH_DISABLED &&
if (vpninfo->proxy_auth[AUTH_TYPE_GSSAPI].state != AUTH_DISABLED &&
!vpninfo->proxy_user && !vpninfo->proxy_pass)
buf[2 + nr_auth_methods++] = SOCKS_AUTH_GSSAPI;
#endif
if (vpninfo->auth[AUTH_TYPE_BASIC].state != AUTH_DISABLED &&
if (vpninfo->proxy_auth[AUTH_TYPE_BASIC].state != AUTH_DISABLED &&
vpninfo->proxy_user && vpninfo->proxy_pass)
buf[2 + nr_auth_methods++] = SOCKS_AUTH_PASSWORD;
......@@ -1376,7 +1376,9 @@ void buf_append_base64(struct oc_text_buf *buf, const void *bytes, int len)
buf->data[buf->pos] = 0;
}
static int basic_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *hdrbuf)
static int basic_authorization(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state,
struct oc_text_buf *hdrbuf)
{
struct oc_text_buf *text;
......@@ -1386,12 +1388,12 @@ static int basic_authorization(struct openconnect_info *vpninfo, struct oc_text_
if (!vpninfo->authmethods_set) {
vpn_progress(vpninfo, PRG_ERR,
_("Proxy requested Basic authentication which is disabled by default\n"));
vpninfo->auth[AUTH_TYPE_BASIC].state = AUTH_FAILED;
auth_state->state = AUTH_FAILED;
return -EINVAL;
}
if (vpninfo->auth[AUTH_TYPE_BASIC].state == AUTH_IN_PROGRESS) {
vpninfo->auth[AUTH_TYPE_BASIC].state = AUTH_FAILED;
if (auth_state->state == AUTH_IN_PROGRESS) {
auth_state->state = AUTH_FAILED;
return -EAGAIN;
}
......@@ -1408,17 +1410,19 @@ static int basic_authorization(struct openconnect_info *vpninfo, struct oc_text_
buf_free(text);
vpn_progress(vpninfo, PRG_INFO, _("Attempting HTTP Basic authentication to proxy\n"));
vpninfo->auth[AUTH_TYPE_BASIC].state = AUTH_IN_PROGRESS;
auth_state->state = AUTH_IN_PROGRESS;
return 0;
}
#if !defined(HAVE_GSSAPI) && !defined(_WIN32)
static int no_gssapi_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *hdrbuf)
static int no_gssapi_authorization(struct openconnect_info *vpninfo,
struct http_auth_State *auth_state,
struct oc_text_buf *hdrbuf)
{
/* This comes last so just complain. We're about to bail. */
vpn_progress(vpninfo, PRG_ERR,
_("This version of OpenConnect was built without GSSAPI support\n"));
vpninfo->auth[AUTH_TYPE_GSSAPI].state = AUTH_FAILED;
auth_state->state = AUTH_FAILED;
return -ENOENT;
}
#endif
......@@ -1426,7 +1430,7 @@ static int no_gssapi_authorization(struct openconnect_info *vpninfo, struct oc_t
struct auth_method {
int state_index;
const char *name;
int (*authorization)(struct openconnect_info *, struct oc_text_buf *);
int (*authorization)(struct openconnect_info *, struct http_auth_state *, struct oc_text_buf *);
void (*cleanup)(struct openconnect_info *);
} auth_methods[] = {
#if defined(HAVE_GSSAPI) || defined(_WIN32)
......@@ -1447,9 +1451,9 @@ static int proxy_authorization(struct openconnect_info *vpninfo, struct oc_text_
int i;
for (i = 0; i < sizeof(auth_methods) / sizeof(auth_methods[0]); i++) {
int index = auth_methods[i].state_index;
if (vpninfo->auth[index].state > AUTH_UNSEEN) {
ret = auth_methods[i].authorization(vpninfo, buf);
struct http_auth_state *auth_state = &vpninfo->proxy_auth[auth_methods[i].state_index];
if (auth_state->state > AUTH_UNSEEN) {
ret = auth_methods[i].authorization(vpninfo, auth_state, buf);
if (ret == -EAGAIN || !ret)
return ret;
}
......@@ -1460,9 +1464,9 @@ static int proxy_authorization(struct openconnect_info *vpninfo, struct oc_text_
/* Returns non-zero if it matched */
static int handle_auth_proto(struct openconnect_info *vpninfo,
struct auth_method *method, char *hdr)
struct auth_method *method, char *hdr)
{
struct http_auth_state *auth = &vpninfo->auth[method->state_index];
struct http_auth_state *auth = &vpninfo->proxy_auth[method->state_index];
int l = strlen(method->name);
if (auth->state <= AUTH_FAILED)
......@@ -1511,7 +1515,7 @@ static int proxy_hdrs(struct openconnect_info *vpninfo, char *hdr, char *val)
static void clear_auth_state(struct openconnect_info *vpninfo,
struct auth_method *method, int reset)
{
struct http_auth_state *auth = &vpninfo->auth[method->state_index];
struct http_auth_state *auth = &vpninfo->proxy_auth[method->state_index];
/* The 'reset' argument is set when we're connected successfully,
to fully reset the state to allow another connection to start
......@@ -1642,7 +1646,7 @@ int openconnect_set_proxy_auth(struct openconnect_info *vpninfo, const char *met
const char *p;
for (i = 0; i < sizeof(auth_methods) / sizeof(auth_methods[0]); i++)
vpninfo->auth[auth_methods[i].state_index].state = AUTH_DISABLED;
vpninfo->proxy_auth[auth_methods[i].state_index].state = AUTH_DISABLED;
while (methods) {
p = strchr(methods, ',');
......@@ -1656,7 +1660,7 @@ int openconnect_set_proxy_auth(struct openconnect_info *vpninfo, const char *met
if (strprefix_match(methods, len, auth_methods[i].name) ||
(auth_methods[i].state_index == AUTH_TYPE_GSSAPI &&
strprefix_match(methods, len, "gssapi"))) {
vpninfo->auth[auth_methods[i].state_index].state = AUTH_UNSEEN;
vpninfo->proxy_auth[auth_methods[i].state_index].state = AUTH_UNSEEN;
break;
}
}
......
......@@ -118,9 +118,11 @@ static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_bu
return ret;
}
static int ntlm_helper_challenge(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
static int ntlm_helper_challenge(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state,
struct oc_text_buf *buf)
{
return ntlm_sspi(vpninfo, buf, vpninfo->auth[AUTH_TYPE_NTLM].challenge);
return ntlm_sspi(vpninfo, buf, auth_state->challenge);
}
void cleanup_ntlm_auth(struct openconnect_info *vpninfo)
......@@ -221,15 +223,17 @@ static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_bu
return 0;
}
static int ntlm_helper_challenge(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
static int ntlm_helper_challenge(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state,
struct oc_text_buf *buf)
{
char helperbuf[4096];
int len;
if (!vpninfo->auth[AUTH_TYPE_NTLM].challenge ||
if (!auth_state->challenge ||
write(vpninfo->ntlm_helper_fd, "TT ", 3) != 3 ||
write(vpninfo->ntlm_helper_fd, vpninfo->auth[AUTH_TYPE_NTLM].challenge,
strlen(vpninfo->auth[AUTH_TYPE_NTLM].challenge)) != strlen(vpninfo->auth[AUTH_TYPE_NTLM].challenge) ||
write(vpninfo->ntlm_helper_fd, auth_state->challenge,
strlen(auth_state->challenge)) != strlen(auth_state->challenge) ||
write(vpninfo->ntlm_helper_fd, "\n", 1) != 1) {
err:
vpn_progress(vpninfo, PRG_ERR, _("Error communicating with ntlm_auth helper\n"));
......@@ -841,7 +845,9 @@ static void ntlm_set_string_binary(struct oc_text_buf *buf, int offset,
buf_append_bytes(buf, data, len);
}
static int ntlm_manual_challenge(struct openconnect_info *vpninfo, struct oc_text_buf *hdrbuf)
static int ntlm_manual_challenge(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state,
struct oc_text_buf *hdrbuf)
{
struct oc_text_buf *resp;
char *user;
......@@ -850,14 +856,14 @@ static int ntlm_manual_challenge(struct openconnect_info *vpninfo, struct oc_tex
int token_len = -EINVAL;
int ntlmver;
if (!vpninfo->auth[AUTH_TYPE_NTLM].challenge)
if (!auth_state->challenge)
return -EINVAL;
if (ntlm_nt_hash (vpninfo->proxy_pass, (char *) hash))
return -EINVAL;
token = openconnect_base64_decode(&token_len,
vpninfo->auth[AUTH_TYPE_NTLM].challenge);
auth_state->challenge);
if (!token)
return token_len;
......@@ -956,22 +962,23 @@ static int ntlm_manual_challenge(struct openconnect_info *vpninfo, struct oc_tex
return 0;
}
int ntlm_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
int ntlm_authorization(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state, struct oc_text_buf *buf)
{
if (vpninfo->auth[AUTH_TYPE_NTLM].state == AUTH_AVAILABLE) {
vpninfo->auth[AUTH_TYPE_NTLM].state = NTLM_MANUAL;
if (auth_state->state == AUTH_AVAILABLE) {
auth_state->state = NTLM_MANUAL;
/* Don't attempt automatic NTLM auth if we were given a password */
if (!vpninfo->proxy_pass && !ntlm_helper_spawn(vpninfo, buf)) {
vpninfo->auth[AUTH_TYPE_NTLM].state = NTLM_SSO_REQ;
auth_state->state = NTLM_SSO_REQ;
return 0;
}
}
if (vpninfo->auth[AUTH_TYPE_NTLM].state == NTLM_SSO_REQ) {
if (auth_state->state == NTLM_SSO_REQ) {
int ret;
ret = ntlm_helper_challenge(vpninfo, buf);
ret = ntlm_helper_challenge(vpninfo, auth_state, buf);
/* Clean up after it. We're done here, whether it worked or not */
cleanup_ntlm_auth(vpninfo);
vpninfo->auth[AUTH_TYPE_NTLM].state = NTLM_MANUAL;
auth_state->state = NTLM_MANUAL;
if (ret == -EAGAIN) {
/* Don't let it reset our state when it reconnects */
vpninfo->proxy_close_during_auth = 1;
......@@ -980,19 +987,19 @@ int ntlm_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf
if (!ret)
return ret;
}
if (vpninfo->auth[AUTH_TYPE_NTLM].state == NTLM_MANUAL && vpninfo->proxy_user &&
if (auth_state->state == NTLM_MANUAL && vpninfo->proxy_user &&
vpninfo->proxy_pass) {
buf_append(buf, "Proxy-Authorization: NTLM %s\r\n",
"TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
vpninfo->auth[AUTH_TYPE_NTLM].state = NTLM_MANUAL_REQ;
auth_state->state = NTLM_MANUAL_REQ;
return 0;
}
if (vpninfo->auth[AUTH_TYPE_NTLM].state == NTLM_MANUAL_REQ &&
!ntlm_manual_challenge(vpninfo, buf)) {
if (auth_state->state == NTLM_MANUAL_REQ &&
!ntlm_manual_challenge(vpninfo, auth_state, buf)) {
/* Leave the state as it is. If we come back there'll be no
challenge string and we'll fail then. */
return 0;
}
vpninfo->auth[AUTH_TYPE_NTLM].state = AUTH_FAILED;
auth_state->state = AUTH_FAILED;
return -EAGAIN;
}
......@@ -351,7 +351,7 @@ struct openconnect_info {
char *proxy_user;
char *proxy_pass;
int proxy_close_during_auth;
struct http_auth_state auth[MAX_AUTH_TYPES];
struct http_auth_state proxy_auth[MAX_AUTH_TYPES];
#ifdef HAVE_GSSAPI
gss_name_t gss_target_name;
gss_ctx_id_t gss_context;
......@@ -946,16 +946,16 @@ int handle_redirect(struct openconnect_info *vpninfo);
void http_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
/* ntlm.c */
int ntlm_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
int ntlm_authorization(struct openconnect_info *vpninfo, struct http_auth_state *auth_state, struct oc_text_buf *buf);
void cleanup_ntlm_auth(struct openconnect_info *vpninfo);
/* gssapi.c */
int gssapi_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
int gssapi_authorization(struct openconnect_info *vpninfo, struct http_auth_state *auth_state, struct oc_text_buf *buf);
void cleanup_gssapi_auth(struct openconnect_info *vpninfo);
int socks_gssapi_auth(struct openconnect_info *vpninfo);
/* digest.c */
int digest_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
int digest_authorization(struct openconnect_info *vpninfo, struct http_auth_state *auth_state, struct oc_text_buf *buf);
/* library.c */
void nuke_opt_values(struct oc_form_opt *opt);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment