Skip to content

Commit

Permalink
Move internal auth state in http_auth_state.
Browse files Browse the repository at this point in the history
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
Nikos Mavrogiannopoulos authored and David Woodhouse committed Feb 24, 2015
1 parent 04fb5a3 commit ef3e9ca
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 95 deletions.
40 changes: 21 additions & 19 deletions gssapi.c
Expand Up @@ -54,7 +54,8 @@ static const gss_OID_desc gss_mech_spnego = {
(void *)&spnego_OID
};

static int gssapi_setup(struct openconnect_info *vpninfo, const char *service, int proxy)
static int gssapi_setup(struct openconnect_info *vpninfo, struct http_auth_state *auth_state,
const char *service, int proxy)
{
OM_uint32 major, minor;
gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
Expand All @@ -67,7 +68,7 @@ static int gssapi_setup(struct openconnect_info *vpninfo, const char *service, i
token.value = name;

major = gss_import_name(&minor, &token, (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
&vpninfo->gss_target_name[proxy]);
&auth_state->gss_target_name);
free(name);
if (GSS_ERROR(major)) {
vpn_progress(vpninfo, PRG_ERR,
Expand All @@ -90,7 +91,7 @@ int gssapi_authorization(struct openconnect_info *vpninfo, int proxy,
gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
gss_OID mech = GSS_C_NO_OID;

if (auth_state->state == AUTH_AVAILABLE && gssapi_setup(vpninfo, "HTTP", proxy)) {
if (auth_state->state == AUTH_AVAILABLE && gssapi_setup(vpninfo, auth_state, "HTTP", proxy)) {
auth_state->state = AUTH_FAILED;
return -EIO;
}
Expand All @@ -109,8 +110,8 @@ int gssapi_authorization(struct openconnect_info *vpninfo, int proxy,
}

major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL,
&vpninfo->gss_context[proxy],
vpninfo->gss_target_name[proxy],
&auth_state->gss_context,
auth_state->gss_target_name,
(gss_OID)&gss_mech_spnego,
GSS_C_MUTUAL_FLAG, GSS_C_INDEFINITE,
GSS_C_NO_CHANNEL_BINDINGS, &in,
Expand All @@ -128,7 +129,7 @@ int gssapi_authorization(struct openconnect_info *vpninfo, int proxy,
print_gss_err(vpninfo, "gss_init_sec_context()", mech, major, minor);
fail_gssapi:
auth_state->state = AUTH_FAILED;
cleanup_gssapi_auth(vpninfo, proxy, auth_state);
cleanup_gssapi_auth(vpninfo, auth_state);
/* If we were *trying*, then -EAGAIN. Else -ENOENT to let another
auth method try without having to reconnect first. */
return in.value ? -EAGAIN : -ENOENT;
Expand All @@ -145,20 +146,20 @@ int gssapi_authorization(struct openconnect_info *vpninfo, int proxy,
}

/* auth_state is NULL when called from socks_gssapi_auth() */
void cleanup_gssapi_auth(struct openconnect_info *vpninfo, int proxy,
void cleanup_gssapi_auth(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state)
{
OM_uint32 minor;

if (vpninfo->gss_target_name[proxy] != GSS_C_NO_NAME)
gss_release_name(&minor, &vpninfo->gss_target_name[proxy]);
if (auth_state->gss_target_name != GSS_C_NO_NAME)
gss_release_name(&minor, &auth_state->gss_target_name);

if (vpninfo->gss_context[proxy] != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&minor, &vpninfo->gss_context[proxy], GSS_C_NO_BUFFER);
if (auth_state->gss_context != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&minor, &auth_state->gss_context, GSS_C_NO_BUFFER);

/* Shouldn't be necessary, but make sure... */
vpninfo->gss_target_name[proxy] = GSS_C_NO_NAME;
vpninfo->gss_context[proxy] = GSS_C_NO_CONTEXT;
auth_state->gss_target_name = GSS_C_NO_NAME;
auth_state->gss_context = GSS_C_NO_CONTEXT;
}

int socks_gssapi_auth(struct openconnect_info *vpninfo)
Expand All @@ -170,16 +171,17 @@ int socks_gssapi_auth(struct openconnect_info *vpninfo)
unsigned char *pktbuf;
int i;
int ret = -EIO;
struct http_auth_state *auth_state = &vpninfo->proxy_auth[AUTH_TYPE_GSSAPI];

if (gssapi_setup(vpninfo, "rcmd", 1))
if (gssapi_setup(vpninfo, auth_state, "rcmd", 1))
return -EIO;

pktbuf = malloc(65538);
if (!pktbuf)
return -ENOMEM;
while (1) {
major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &vpninfo->gss_context[1],
vpninfo->gss_target_name[1], (gss_OID)&gss_mech_spnego,
major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &auth_state->gss_context,
auth_state->gss_target_name, (gss_OID)&gss_mech_spnego,
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_DELEG_FLAG | GSS_C_SEQUENCE_FLAG,
GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &in, &mech,
&out, NULL, NULL);
Expand Down Expand Up @@ -267,7 +269,7 @@ int socks_gssapi_auth(struct openconnect_info *vpninfo)
in.value = pktbuf;
in.length = 1;

major = gss_wrap(&minor, vpninfo->gss_context[1], 0,
major = gss_wrap(&minor, auth_state->gss_context, 0,
GSS_C_QOP_DEFAULT, &in, NULL, &out);
if (major != GSS_S_COMPLETE) {
print_gss_err(vpninfo, "gss_wrap()", mech, major, minor);
Expand Down Expand Up @@ -313,7 +315,7 @@ int socks_gssapi_auth(struct openconnect_info *vpninfo)
_("Got GSSAPI protection response of %zu bytes: %02x %02x %02x %02x\n"),
in.length, pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3]);

major = gss_unwrap(&minor, vpninfo->gss_context[1], &in, &out, NULL, GSS_C_QOP_DEFAULT);
major = gss_unwrap(&minor, auth_state->gss_context, &in, &out, NULL, GSS_C_QOP_DEFAULT);
if (major != GSS_S_COMPLETE) {
print_gss_err(vpninfo, "gss_unwrap()", mech, major, minor);
goto err;
Expand Down Expand Up @@ -344,7 +346,7 @@ int socks_gssapi_auth(struct openconnect_info *vpninfo)
ret = 0;
}
err:
cleanup_gssapi_auth(vpninfo, 1, NULL);
cleanup_gssapi_auth(vpninfo, NULL);
free(pktbuf);

return ret;
Expand Down
17 changes: 6 additions & 11 deletions http.c
Expand Up @@ -1445,7 +1445,7 @@ struct auth_method {
int state_index;
const char *name;
int (*authorization)(struct openconnect_info *, int, struct http_auth_state *, struct oc_text_buf *);
void (*cleanup)(struct openconnect_info *, int, struct http_auth_state *);
void (*cleanup)(struct openconnect_info *, struct http_auth_state *);
} auth_methods[] = {
#if defined(HAVE_GSSAPI) || defined(_WIN32)
{ AUTH_TYPE_GSSAPI, "Negotiate", gssapi_authorization, cleanup_gssapi_auth },
Expand Down Expand Up @@ -1531,21 +1531,16 @@ static int proxy_hdrs(struct openconnect_info *vpninfo, char *hdr, char *val)
return 0;
}

static void clear_auth_state(struct openconnect_info *vpninfo, int proxy,
static void clear_auth_state(struct openconnect_info *vpninfo, struct http_auth_state *auth_states,
struct auth_method *method, int reset)
{
struct http_auth_state *auth;
if (proxy)
auth = &vpninfo->proxy_auth[method->state_index];
else
auth = &vpninfo->http_auth[method->state_index];

struct http_auth_state *auth = &auth_states[method->state_index];
/* The 'reset' argument is set when we're connected successfully,
to fully reset the state to allow another connection to start
again. Otherwise, we need to remember which auth methods have
been tried and should not be attempted again. */
if (reset && method->cleanup)
method->cleanup(vpninfo, proxy, auth);
method->cleanup(vpninfo, auth);

free(auth->challenge);
auth->challenge = NULL;
Expand Down Expand Up @@ -1587,7 +1582,7 @@ static int process_http_proxy(struct openconnect_info *vpninfo)
}
/* Forget existing challenges */
for (i = 0; i < sizeof(auth_methods) / sizeof(auth_methods[0]); i++)
clear_auth_state(vpninfo, 1, &auth_methods[i], 0);
clear_auth_state(vpninfo, vpninfo->proxy_auth, &auth_methods[i], 0);
}
buf_append(reqbuf, "\r\n");

Expand Down Expand Up @@ -1633,7 +1628,7 @@ void cleanup_proxy_auth(struct openconnect_info *vpninfo)
int i;

for (i = 0; i < sizeof(auth_methods) / sizeof(auth_methods[0]); i++)
clear_auth_state(vpninfo, 1, &auth_methods[i], 1);
clear_auth_state(vpninfo, vpninfo->proxy_auth, &auth_methods[i], 1);
}

int process_proxy(struct openconnect_info *vpninfo, int ssl_sock)
Expand Down
50 changes: 25 additions & 25 deletions ntlm.c
Expand Up @@ -43,7 +43,7 @@
#define NTLM_MANUAL_REQ 4 /* manual type1 packet sent */

#ifdef _WIN32
static int ntlm_sspi(struct openconnect_info *vpninfo, struct oc_text_buf *buf, const char *challenge)
static int ntlm_sspi(struct openconnect_info *vpninfo, struct http_auth_state *auth_state, struct oc_text_buf *buf, const char *challenge)
{
SECURITY_STATUS status;
SecBufferDesc input_desc, output_desc;
Expand Down Expand Up @@ -72,13 +72,13 @@ static int ntlm_sspi(struct openconnect_info *vpninfo, struct oc_text_buf *buf,
out_token.cbBuffer = 0;
out_token.pvBuffer = NULL;

status = InitializeSecurityContextW(&vpninfo->ntlm_sspi_cred,
challenge ? &vpninfo->ntlm_sspi_ctx : NULL,
status = InitializeSecurityContextW(&auth_state->ntlm_sspi_cred,
challenge ? &auth_state->ntlm_sspi_ctx : NULL,
(SEC_WCHAR *)L"",
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION,
0, SECURITY_NETWORK_DREP,
challenge ? &input_desc : NULL,
0, &vpninfo->ntlm_sspi_ctx,
0, &auth_state->ntlm_sspi_ctx,
&output_desc, &ret_flags, NULL);

if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
Expand All @@ -96,24 +96,24 @@ static int ntlm_sspi(struct openconnect_info *vpninfo, struct oc_text_buf *buf,
return 0;
}

static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct http_auth_state *auth_state, struct oc_text_buf *buf)
{
SECURITY_STATUS status;
int ret;

status = AcquireCredentialsHandleW(NULL, (SEC_WCHAR *)L"NTLM",
SECPKG_CRED_OUTBOUND, NULL, NULL,
NULL, NULL,
&vpninfo->ntlm_sspi_cred, NULL);
&auth_state->ntlm_sspi_cred, NULL);
if (status != SEC_E_OK) {
vpn_progress(vpninfo, PRG_ERR,
_("AcquireCredentialsHandle() failed: %lx\n"), status);
return -EIO;
}

ret = ntlm_sspi(vpninfo, buf, NULL);
ret = ntlm_sspi(vpninfo, auth_state, buf, NULL);
if (ret)
FreeCredentialsHandle(&vpninfo->ntlm_sspi_cred);
FreeCredentialsHandle(&auth_state->ntlm_sspi_cred);

return ret;
}
Expand All @@ -122,21 +122,21 @@ 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, auth_state->challenge);
return ntlm_sspi(vpninfo, auth_state, buf, auth_state->challenge);
}

void cleanup_ntlm_auth(struct openconnect_info *vpninfo, int proxy,
void cleanup_ntlm_auth(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state)
{
if (auth_state->state == NTLM_SSO_REQ) {
FreeCredentialsHandle(&vpninfo->ntlm_sspi_cred);
DeleteSecurityContext(&vpninfo->ntlm_sspi_ctx);
FreeCredentialsHandle(&auth_state->ntlm_sspi_cred);
DeleteSecurityContext(&auth_state->ntlm_sspi_ctx);
}
}

#else /* !_WIN32 */

static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct http_auth_state *auth_state, struct oc_text_buf *buf)
{
char *username;
int pipefd[2];
Expand Down Expand Up @@ -220,7 +220,7 @@ static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_bu
}
helperbuf[len - 1] = 0;
buf_append(buf, "Proxy-Authorization: NTLM %s\r\n", helperbuf + 3);
vpninfo->ntlm_helper_fd = pipefd[1];
auth_state->ntlm_helper_fd = pipefd[1];
return 0;
}

Expand All @@ -232,17 +232,17 @@ static int ntlm_helper_challenge(struct openconnect_info *vpninfo,
int len;

if (!auth_state->challenge ||
write(vpninfo->ntlm_helper_fd, "TT ", 3) != 3 ||
write(vpninfo->ntlm_helper_fd, auth_state->challenge,
write(auth_state->ntlm_helper_fd, "TT ", 3) != 3 ||
write(auth_state->ntlm_helper_fd, auth_state->challenge,
strlen(auth_state->challenge)) != strlen(auth_state->challenge) ||
write(vpninfo->ntlm_helper_fd, "\n", 1) != 1) {
write(auth_state->ntlm_helper_fd, "\n", 1) != 1) {
err:
vpn_progress(vpninfo, PRG_ERR, _("Error communicating with ntlm_auth helper\n"));
close(vpninfo->ntlm_helper_fd);
vpninfo->ntlm_helper_fd = -1;
close(auth_state->ntlm_helper_fd);
auth_state->ntlm_helper_fd = -1;
return -EAGAIN;
}
len = read(vpninfo->ntlm_helper_fd, helperbuf, sizeof(helperbuf));
len = read(auth_state->ntlm_helper_fd, helperbuf, sizeof(helperbuf));
/* Accept both 'KK' and 'AF'. It should be the latter but see
https://bugzilla.samba.org/show_bug.cgi?id=10691 */
if (len < 4 || (!(helperbuf[0] == 'K' && helperbuf[1] == 'K') &&
Expand All @@ -258,12 +258,12 @@ static int ntlm_helper_challenge(struct openconnect_info *vpninfo,

}

void cleanup_ntlm_auth(struct openconnect_info *vpninfo, int proxy,
void cleanup_ntlm_auth(struct openconnect_info *vpninfo,
struct http_auth_state *auth_state)
{
if (auth_state->state == NTLM_SSO_REQ) {
close(vpninfo->ntlm_helper_fd);
vpninfo->ntlm_helper_fd = -1;
close(auth_state->ntlm_helper_fd);
auth_state->ntlm_helper_fd = -1;
}
}
#endif /* !_WIN32 */
Expand Down Expand Up @@ -986,7 +986,7 @@ int ntlm_authorization(struct openconnect_info *vpninfo, int proxy,
if (auth_state->state == AUTH_AVAILABLE) {
auth_state->state = NTLM_MANUAL;
/* Don't attempt automatic NTLM auth if we were given a password */
if (!pass && !ntlm_helper_spawn(vpninfo, buf)) {
if (!pass && !ntlm_helper_spawn(vpninfo, auth_state, buf)) {
auth_state->state = NTLM_SSO_REQ;
return 0;
}
Expand All @@ -995,7 +995,7 @@ int ntlm_authorization(struct openconnect_info *vpninfo, int proxy,
int ret;
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, proxy, auth_state);
cleanup_ntlm_auth(vpninfo, auth_state);
auth_state->state = NTLM_MANUAL;
if (ret == -EAGAIN) {
/* Don't let it reset our state when it reconnects */
Expand Down
40 changes: 25 additions & 15 deletions openconnect-internal.h
Expand Up @@ -216,6 +216,29 @@ struct oc_text_buf {
struct http_auth_state {
int state;
char *challenge;
union {
#ifdef HAVE_GSSAPI
struct {
gss_name_t gss_target_name;
gss_ctx_id_t gss_context;
};
#endif
#ifdef _WIN32
struct {
CredHandle ntlm_sspi_cred;
CtxtHandle ntlm_sspi_ctx;
};
struct {
CredHandle sspi_cred;
CtxtHandle sspi_ctx;
SEC_WCHAR *sspi_target_name;
};
#else
struct {
int ntlm_helper_fd;
};
#endif
};
};

struct vpn_proto {
Expand Down Expand Up @@ -354,19 +377,6 @@ struct openconnect_info {
int http_close_during_auth;
struct http_auth_state http_auth[MAX_AUTH_TYPES];
struct http_auth_state proxy_auth[MAX_AUTH_TYPES];
#ifdef HAVE_GSSAPI
gss_name_t gss_target_name[2];
gss_ctx_id_t gss_context[2];
#endif
#ifdef _WIN32
CredHandle ntlm_sspi_cred;
CtxtHandle ntlm_sspi_ctx;
CredHandle sspi_cred[2];
CtxtHandle sspi_ctx[2];
SEC_WCHAR *sspi_target_name[2];
#else
int ntlm_helper_fd;
#endif
int authmethods_set;

char *localname;
Expand Down Expand Up @@ -949,11 +959,11 @@ void http_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b

/* ntlm.c */
int ntlm_authorization(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state, struct oc_text_buf *buf);
void cleanup_ntlm_auth(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state);
void cleanup_ntlm_auth(struct openconnect_info *vpninfo, struct http_auth_state *auth_state);

/* gssapi.c */
int gssapi_authorization(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state, struct oc_text_buf *buf);
void cleanup_gssapi_auth(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state);
void cleanup_gssapi_auth(struct openconnect_info *vpninfo, struct http_auth_state *auth_state);
int socks_gssapi_auth(struct openconnect_info *vpninfo);

/* digest.c */
Expand Down

0 comments on commit ef3e9ca

Please sign in to comment.