Navigation Menu

Skip to content

Commit

Permalink
Start making HTTP authentication less proxy-specific
Browse files Browse the repository at this point in the history
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Feb 19, 2015
1 parent de42bfc commit 021bddd
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 58 deletions.
13 changes: 7 additions & 6 deletions digest.c
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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:
Expand Down
22 changes: 12 additions & 10 deletions gssapi.c
Expand Up @@ -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... */
Expand All @@ -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. */
Expand All @@ -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;
Expand Down
38 changes: 21 additions & 17 deletions http.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand All @@ -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;
}

Expand All @@ -1408,25 +1410,27 @@ 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

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)
Expand All @@ -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;
}
Expand All @@ -1462,7 +1466,7 @@ static int proxy_authorization(struct openconnect_info *vpninfo, struct oc_text_
static int handle_auth_proto(struct openconnect_info *vpninfo,
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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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, ',');
Expand All @@ -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;
}
}
Expand Down
49 changes: 28 additions & 21 deletions ntlm.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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"));
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
8 changes: 4 additions & 4 deletions openconnect-internal.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 021bddd

Please sign in to comment.