Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Move NTLM out into ntlm.c
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Jun 19, 2014
1 parent 82b7efb commit 988cfc1
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 168 deletions.
2 changes: 1 addition & 1 deletion Makefile.am
Expand Up @@ -19,7 +19,7 @@ openconnect_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFL
openconnect_LDADD = libopenconnect.la $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(LIBINTL)

library_srcs = ssl.c http.c auth.c library.c compat.c dtls.c cstp.c \
mainloop.c script.c
mainloop.c script.c ntlm.c
lib_srcs_gnutls = gnutls.c gnutls_pkcs12.c gnutls_tpm.c
lib_srcs_openssl = openssl.c

Expand Down
167 changes: 0 additions & 167 deletions http.c
Expand Up @@ -29,7 +29,6 @@
#include <stdarg.h>
#ifndef _WIN32
#include <pwd.h>
#include <sys/wait.h>
#endif

#include "openconnect-internal.h"
Expand Down Expand Up @@ -1550,174 +1549,8 @@ static void b64_frag(struct oc_text_buf *buf, int len, unsigned char *in)
buf_append(buf, "%s", b64);
}

/* State in vpninfo->proxy_auth_state */
#define AUTH_FAILED -1 /* Failed */
#define AUTH_UNSEEN 0 /* Server has not offered it */
#define AUTH_AVAILABLE 1 /* Server has offered it, we have not tried it */
#define AUTH_IN_PROGRESS 2 /* In-progress attempt */


#define NTLM_SSO_REQ 2 /* SSO type1 packet sent */
#define NTLM_MANUAL 3 /* SSO challenge/response sent or skipped; manual next */
#define NTLM_MANUAL_REQ 4 /* manual type1 packet sent */

#ifndef _WIN32
static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
char *username;
int pipefd[2];
pid_t pid;
char helperbuf[MAX_BUF_LEN];
int len;

if (access("/usr/bin/ntlm_auth", X_OK))
return -errno;

username = vpninfo->proxy_user;
if (!username)
username = getenv("NTLMUSER");
if (!username)
username = getenv("USER");
if (!username)
return -EINVAL;

#ifdef SOCK_CLOEXEC
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, pipefd))
#endif
{
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd))
return -errno;
set_fd_cloexec(pipefd[0]);
set_fd_cloexec(pipefd[1]);
}
pid = fork();
if (pid == -1)
return -errno;

if (!pid) {
int i;
char *p;
const char *argv[9];

/* Fork again to detach grandchild */
if (fork())
exit(1);

close(pipefd[1]);
/* The duplicated fd does not have O_CLOEXEC */
dup2(pipefd[0], 0);
dup2(pipefd[0], 1);
/* Should we leave stderr open? */
for (i = 3; i < 1024 ; i++)
close(i);


i = 0;
argv[i++] = "/usr/bin/ntlm_auth";
argv[i++] = "--helper-protocol";
argv[i++] = "ntlmssp-client-1";
argv[i++] = "--use-cached-creds";
argv[i++] = "--username";
p = strchr(username, '\\');
if (p) {
argv[i++] = p+1;
argv[i++] = "--domain";
argv[i++] = strndup(username, p - username);
} else
argv[i++] = username;
argv[i++] = NULL;

execv(argv[0], (char **)argv);
exit(1);
}
waitpid(pid, NULL, 0);
close(pipefd[0]);

if (write(pipefd[1], "YR\n", 3) != 3) {
close(pipefd[1]);
return -EIO;
}

len = read(pipefd[1], helperbuf, sizeof(helperbuf));
if (len < 4 || helperbuf[0] != 'Y' || helperbuf[1] != 'R' ||
helperbuf[2] != ' ' || helperbuf[len - 1] != '\n') {
close(pipefd[1]);
return -EIO;
}
helperbuf[len - 1] = 0;
buf_append(buf, "Proxy-Authorization: NTLM %s\r\n", helperbuf + 3);
vpninfo->ntlm_helper_fd = pipefd[1];
return 0;
}

static int ntlm_helper_challenge(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
char helperbuf[MAX_BUF_LEN];
int len;

if (!vpninfo->ntlm_auth.challenge ||
write(vpninfo->ntlm_helper_fd, "TT ", 3) != 3 ||
write(vpninfo->ntlm_helper_fd, vpninfo->ntlm_auth.challenge,
strlen(vpninfo->ntlm_auth.challenge)) != strlen(vpninfo->ntlm_auth.challenge) ||
write(vpninfo->ntlm_helper_fd, "\n", 1) != 1) {
err:
close(vpninfo->ntlm_helper_fd);
vpninfo->ntlm_helper_fd = -1;
return -EIO;
}
len = read(vpninfo->ntlm_helper_fd, helperbuf, sizeof(helperbuf));
if (len < 4 || helperbuf[0] != 'K' || helperbuf[1] != 'K' ||
helperbuf[2] != ' ' || helperbuf[len - 1] != '\n') {
goto err;
}
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;

}
#endif /* !_WIN32 */

static int ntlm_manual_challenge(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
vpn_progress(vpninfo, PRG_INFO, _("Attempting HTTP NTLM authentication to proxy (manual)\n"));
return -EIO;
}

static int ntlm_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
if (vpninfo->ntlm_auth.state == AUTH_AVAILABLE) {
vpninfo->ntlm_auth.state = NTLM_MANUAL;
#ifndef _WIN32
if (!ntlm_helper_spawn(vpninfo, buf)) {
vpninfo->ntlm_auth.state = NTLM_SSO_REQ;
return 0;
}
}
if (vpninfo->ntlm_auth.state == NTLM_SSO_REQ) {
vpninfo->ntlm_auth.state = NTLM_MANUAL;
if (!ntlm_helper_challenge(vpninfo, buf))
return 0;
#endif
}
if (vpninfo->ntlm_auth.state == NTLM_MANUAL && vpninfo->proxy_user &&
vpninfo->proxy_pass) {
buf_append(buf, "Proxy-Authorization: NTLM %s\r\n",
"TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
vpninfo->ntlm_auth.state = NTLM_MANUAL_REQ;
return 0;
}
if (vpninfo->ntlm_auth.state == NTLM_MANUAL_REQ) {
vpninfo->ntlm_auth.state = AUTH_FAILED;
return ntlm_manual_challenge(vpninfo, buf);

}
return -EINVAL;
}

/* Generate Proxy-Authorization: header for request if appropriate */
static int proxy_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
Expand Down
194 changes: 194 additions & 0 deletions ntlm.c
@@ -0,0 +1,194 @@
/*
* OpenConnect (SSL + DTLS) VPN client
*
* Copyright © 2008-2014 Intel Corporation.
*
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/

#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#ifndef _WIN32
#include <sys/wait.h>
#endif

#include "openconnect-internal.h"


#define NTLM_SSO_REQ 2 /* SSO type1 packet sent */
#define NTLM_MANUAL 3 /* SSO challenge/response sent or skipped; manual next */
#define NTLM_MANUAL_REQ 4 /* manual type1 packet sent */

#ifndef _WIN32
static int ntlm_helper_spawn(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
char *username;
int pipefd[2];
pid_t pid;
char helperbuf[4096];
int len;

if (access("/usr/bin/ntlm_auth", X_OK))
return -errno;

username = vpninfo->proxy_user;
if (!username)
username = getenv("NTLMUSER");
if (!username)
username = getenv("USER");
if (!username)
return -EINVAL;

#ifdef SOCK_CLOEXEC
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, pipefd))
#endif
{
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd))
return -errno;
set_fd_cloexec(pipefd[0]);
set_fd_cloexec(pipefd[1]);
}
pid = fork();
if (pid == -1)
return -errno;

if (!pid) {
int i;
char *p;
const char *argv[9];

/* Fork again to detach grandchild */
if (fork())
exit(1);

close(pipefd[1]);
/* The duplicated fd does not have O_CLOEXEC */
dup2(pipefd[0], 0);
dup2(pipefd[0], 1);
/* Should we leave stderr open? */
for (i = 3; i < 1024 ; i++)
close(i);


i = 0;
argv[i++] = "/usr/bin/ntlm_auth";
argv[i++] = "--helper-protocol";
argv[i++] = "ntlmssp-client-1";
argv[i++] = "--use-cached-creds";
argv[i++] = "--username";
p = strchr(username, '\\');
if (p) {
argv[i++] = p+1;
argv[i++] = "--domain";
argv[i++] = strndup(username, p - username);
} else
argv[i++] = username;
argv[i++] = NULL;

execv(argv[0], (char **)argv);
exit(1);
}
waitpid(pid, NULL, 0);
close(pipefd[0]);

if (write(pipefd[1], "YR\n", 3) != 3) {
close(pipefd[1]);
return -EIO;
}

len = read(pipefd[1], helperbuf, sizeof(helperbuf));
if (len < 4 || helperbuf[0] != 'Y' || helperbuf[1] != 'R' ||
helperbuf[2] != ' ' || helperbuf[len - 1] != '\n') {
close(pipefd[1]);
return -EIO;
}
helperbuf[len - 1] = 0;
buf_append(buf, "Proxy-Authorization: NTLM %s\r\n", helperbuf + 3);
vpninfo->ntlm_helper_fd = pipefd[1];
return 0;
}

static int ntlm_helper_challenge(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
char helperbuf[4096];
int len;

if (!vpninfo->ntlm_auth.challenge ||
write(vpninfo->ntlm_helper_fd, "TT ", 3) != 3 ||
write(vpninfo->ntlm_helper_fd, vpninfo->ntlm_auth.challenge,
strlen(vpninfo->ntlm_auth.challenge)) != strlen(vpninfo->ntlm_auth.challenge) ||
write(vpninfo->ntlm_helper_fd, "\n", 1) != 1) {
err:
close(vpninfo->ntlm_helper_fd);
vpninfo->ntlm_helper_fd = -1;
return -EIO;
}
len = read(vpninfo->ntlm_helper_fd, helperbuf, sizeof(helperbuf));
if (len < 4 || helperbuf[0] != 'K' || helperbuf[1] != 'K' ||
helperbuf[2] != ' ' || helperbuf[len - 1] != '\n') {
goto err;
}
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;

}
#endif /* !_WIN32 */

static int ntlm_manual_challenge(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
vpn_progress(vpninfo, PRG_INFO, _("Attempting HTTP NTLM authentication to proxy (manual)\n"));
return -EIO;
}

int ntlm_authorization(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
{
if (vpninfo->ntlm_auth.state == AUTH_AVAILABLE) {
vpninfo->ntlm_auth.state = NTLM_MANUAL;
#ifndef _WIN32
if (!ntlm_helper_spawn(vpninfo, buf)) {
vpninfo->ntlm_auth.state = NTLM_SSO_REQ;
return 0;
}
}
if (vpninfo->ntlm_auth.state == NTLM_SSO_REQ) {
vpninfo->ntlm_auth.state = NTLM_MANUAL;
if (!ntlm_helper_challenge(vpninfo, buf))
return 0;
#endif
}
if (vpninfo->ntlm_auth.state == NTLM_MANUAL && vpninfo->proxy_user &&
vpninfo->proxy_pass) {
buf_append(buf, "Proxy-Authorization: NTLM %s\r\n",
"TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
vpninfo->ntlm_auth.state = NTLM_MANUAL_REQ;
return 0;
}
if (vpninfo->ntlm_auth.state == NTLM_MANUAL_REQ) {
vpninfo->ntlm_auth.state = AUTH_FAILED;
return ntlm_manual_challenge(vpninfo, buf);

}
return -EINVAL;
}

0 comments on commit 988cfc1

Please sign in to comment.