Commit 80069291 authored by David Woodhouse's avatar David Woodhouse

Initial SSPI support for NTLM under Windows

Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent dcbe8c69
......@@ -153,7 +153,7 @@ AC_SUBST(WFLAGS, [$WFLAGS])
if test "$have_win" = yes; then
# Checking "properly" for __attribute__((dllimport,stdcall)) functions is non-trivial
LIBS="$LIBS -lws2_32 -lshlwapi"
LIBS="$LIBS -lws2_32 -lshlwapi -lsecur32"
else
AC_CHECK_FUNC(socket, [], AC_CHECK_LIB(socket, socket, [], AC_ERROR(Cannot find socket() function)))
fi
......
......@@ -42,7 +42,90 @@
#define NTLM_MANUAL 3 /* SSO challenge/response sent or skipped; manual next */
#define NTLM_MANUAL_REQ 4 /* manual type1 packet sent */
#ifndef _WIN32
#ifdef _WIN32
static int ntlm_sspi(struct openconnect_info *vpninfo, struct oc_text_buf *buf, char *challenge)
{
SECURITY_STATUS status;
SecBufferDesc input_desc, output_desc;
SecBuffer in_token, out_token;
ULONG ret_flags;
if (challenge) {
int token_len;
input_desc.cBuffers = 1;
input_desc.pBuffers = &in_token;
input_desc.ulVersion = SECBUFFER_VERSION;
in_token.BufferType = SECBUFFER_TOKEN;
token_len = openconnect_base64_decode((unsigned char **)&in_token.pvBuffer, challenge);
if (token_len < 0)
return token_len;
in_token.cbBuffer = token_len;
}
output_desc.cBuffers = 1;
output_desc.pBuffers = &out_token;
output_desc.ulVersion = SECBUFFER_VERSION;
out_token.BufferType = SECBUFFER_TOKEN;
out_token.cbBuffer = 0;
out_token.pvBuffer = NULL;
status = InitializeSecurityContext(&vpninfo->ntlm_sspi_cred, challenge ? &vpninfo->ntlm_sspi_ctx : NULL, (SEC_CHAR *)"",
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,
&output_desc, &ret_flags, NULL);
if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
vpn_progress(vpninfo, PRG_ERR,
_("InitializeSecurityContext() failed: %lx\n"), status);
return -EIO;
}
buf_append(buf, "Proxy-Authorization: NTLM ");
buf_append_base64(buf, out_token.pvBuffer, out_token.cbBuffer);
buf_append(buf, "\r\n");
FreeContextBuffer(out_token.pvBuffer);
return 0;
}
static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
SECURITY_STATUS status;
int ret;
status = AcquireCredentialsHandle(NULL, (SEC_CHAR *)"NTLM", SECPKG_CRED_OUTBOUND,
NULL, NULL, NULL, NULL, &vpninfo->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);
if (ret)
FreeCredentialsHandle(&vpninfo->ntlm_sspi_cred);
return ret;
}
static int ntlm_helper_challenge(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
return ntlm_sspi(vpninfo, buf, vpninfo->auth[AUTH_TYPE_NTLM].challenge);
}
void cleanup_ntlm_auth(struct openconnect_info *vpninfo)
{
if (vpninfo->auth[AUTH_TYPE_NTLM].state == NTLM_SSO_REQ) {
FreeCredentialsHandle(&vpninfo->ntlm_sspi_cred);
DeleteSecurityContext(&vpninfo->ntlm_sspi_ctx);
}
}
#else /* !_WIN32 */
static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
char *username;
......@@ -153,13 +236,18 @@ static int ntlm_helper_challenge(struct openconnect_info *vpninfo, struct oc_tex
}
helperbuf[len - 1] = 0;
buf_append(buf, "Proxy-Authorization: NTLM %s\r\n", helperbuf + 3);
close(vpninfo->ntlm_helper_fd);
vpninfo->ntlm_helper_fd = -1;
vpn_progress(vpninfo, PRG_INFO, _("Attempting HTTP NTLM authentication to proxy (single-sign-on)\n"));
return 0;
}
void cleanup_ntlm_auth(struct openconnect_info *vpninfo)
{
if (vpninfo->auth[AUTH_TYPE_NTLM].state == NTLM_SSO_REQ) {
close(vpninfo->ntlm_helper_fd);
vpninfo->ntlm_helper_fd = -1;}
}
#endif /* !_WIN32 */
/*
......@@ -963,7 +1051,6 @@ int ntlm_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf
{
if (vpninfo->auth[AUTH_TYPE_NTLM].state == AUTH_AVAILABLE) {
vpninfo->auth[AUTH_TYPE_NTLM].state = NTLM_MANUAL;
#ifndef _WIN32
/* 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;
......@@ -972,11 +1059,12 @@ int ntlm_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf
}
if (vpninfo->auth[AUTH_TYPE_NTLM].state == NTLM_SSO_REQ) {
int ret;
vpninfo->auth[AUTH_TYPE_NTLM].state = NTLM_MANUAL;
ret = ntlm_helper_challenge(vpninfo, 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;
if (!ret || ret == -EAGAIN)
return ret;
#endif
}
if (vpninfo->auth[AUTH_TYPE_NTLM].state == NTLM_MANUAL && vpninfo->proxy_user &&
vpninfo->proxy_pass) {
......@@ -994,10 +1082,3 @@ int ntlm_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf
vpninfo->auth[AUTH_TYPE_NTLM].state = AUTH_FAILED;
return -EAGAIN;
}
void cleanup_ntlm_auth(struct openconnect_info *vpninfo)
{
if (vpninfo->auth[AUTH_TYPE_NTLM].state == NTLM_SSO_REQ) {
close(vpninfo->ntlm_helper_fd);
vpninfo->ntlm_helper_fd = -1;}
}
......@@ -25,6 +25,10 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#ifndef SECURITY_WIN32
#define SECURITY_WIN32 1
#endif
#include <security.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
......@@ -207,7 +211,12 @@ struct openconnect_info {
gss_name_t gss_target_name;
gss_ctx_id_t gss_context;
#endif
#ifdef _WIN32
CredHandle ntlm_sspi_cred;
CtxtHandle ntlm_sspi_ctx;
#else
int ntlm_helper_fd;
#endif
int authmethods_set;
char *localname;
......
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