diff --git a/davmail-setup.nsi b/davmail-setup.nsi
index 2329f713..0cb9825e 100644
--- a/davmail-setup.nsi
+++ b/davmail-setup.nsi
@@ -92,6 +92,7 @@ Section "MainSection" SEC01
File "dist\lib\commons-logging-1.0.4.jar"
File "dist\lib\htmlcleaner-2.1.jar"
File "dist\lib\jackrabbit-webdav-1.4.jar"
+ File "dist\lib\jcifs-1.3.14.jar"
File "dist\lib\jdom-1.0.jar"
File "dist\lib\log4j-1.2.15.jar"
File "dist\lib\mail-1.4.1.jar"
@@ -162,6 +163,7 @@ no_quest:
Delete "$INSTDIR\lib\commons-logging-1.0.4.jar"
Delete "$INSTDIR\lib\htmlcleaner-2.1.jar"
Delete "$INSTDIR\lib\jackrabbit-webdav-1.4.jar"
+ Delete "$INSTDIR\lib\jcifs-1.3.14.jar"
Delete "$INSTDIR\lib\jdom-1.0.jar"
Delete "$INSTDIR\lib\log4j-1.2.15.jar"
Delete "$INSTDIR\lib\mail-1.4.1.jar"
diff --git a/davmail.jsmooth b/davmail.jsmooth
index 1b1a471c..83967a1c 100644
--- a/davmail.jsmooth
+++ b/davmail.jsmooth
@@ -15,6 +15,7 @@
dist\lib\commons-logging-1.0.4.jar
dist\lib\htmlcleaner-2.1.jar
dist\lib\jackrabbit-webdav-1.4.jar
+dist\lib\jcifs-1.3.14.jar
dist\lib\jdom-1.0.jar
dist\lib\log4j-1.2.15.jar
dist\lib\mail-1.4.1.jar
diff --git a/davmailconsole.jsmooth b/davmailconsole.jsmooth
index d9cc0a2f..72b6367e 100644
--- a/davmailconsole.jsmooth
+++ b/davmailconsole.jsmooth
@@ -8,22 +8,23 @@
jview
dist\davmail.jar
-dist\lib\activation-1.1.jar
-dist\lib\commons-codec-1.3.jar
-dist\lib\commons-collections-3.1.jar
-dist\lib\commons-httpclient-3.1.jar
-dist\lib\commons-logging-1.0.4.jar
-dist\lib\htmlcleaner-2.1.jar
-dist\lib\jackrabbit-webdav-1.4.jar
-dist\lib\jdom-1.0.jar
-dist\lib\log4j-1.2.15.jar
-dist\lib\mail-1.4.1.jar
-dist\lib\slf4j-api-1.3.1.jar
-dist\lib\slf4j-log4j12-1.3.1.jar
-dist\lib\stax-api-1.0.1.jar
-dist\lib\swt-3.5-win32-x86.jar
-dist\lib\wstx-asl-3.2.7.jar
-dist\lib\xercesImpl-2.8.1.jar
+dist\lib\activation-1.1.jar
+dist\lib\commons-codec-1.3.jar
+dist\lib\commons-collections-3.1.jar
+dist\lib\commons-httpclient-3.1.jar
+dist\lib\commons-logging-1.0.4.jar
+dist\lib\htmlcleaner-2.1.jar
+dist\lib\jackrabbit-webdav-1.4.jar
+dist\lib\jcifs-1.3.14.jar
+dist\lib\jdom-1.0.jar
+dist\lib\log4j-1.2.15.jar
+dist\lib\mail-1.4.1.jar
+dist\lib\slf4j-api-1.3.1.jar
+dist\lib\slf4j-log4j12-1.3.1.jar
+dist\lib\stax-api-1.0.1.jar
+dist\lib\swt-3.5-win32-x86.jar
+dist\lib\wstx-asl-3.2.7.jar
+dist\lib\xercesImpl-2.8.1.jar
false
dist\davmailconsole.exe
src\java\tray32.png
diff --git a/davmailservice.jsmooth b/davmailservice.jsmooth
index 4ac06801..f587cafa 100644
--- a/davmailservice.jsmooth
+++ b/davmailservice.jsmooth
@@ -15,6 +15,7 @@
dist\lib\commons-logging-1.0.4.jar
dist\lib\htmlcleaner-2.1.jar
dist\lib\jackrabbit-webdav-1.4.jar
+dist\lib\jcifs-1.3.14.jar
dist\lib\jdom-1.0.jar
dist\lib\log4j-1.2.15.jar
dist\lib\mail-1.4.1.jar
diff --git a/lib/jcifs-1.3.14.jar b/lib/jcifs-1.3.14.jar
new file mode 100644
index 00000000..c3d7f4e9
Binary files /dev/null and b/lib/jcifs-1.3.14.jar differ
diff --git a/pom.xml b/pom.xml
index 64d4317b..463e85c9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -242,6 +242,11 @@
wstx-asl
3.2.7
+
+ org.samba.jcifs
+ jcifs
+ 1.3.14
+
diff --git a/src/java/davmail/http/DavGatewayHttpClientFacade.java b/src/java/davmail/http/DavGatewayHttpClientFacade.java
index ea0aed08..e7169d0b 100644
--- a/src/java/davmail/http/DavGatewayHttpClientFacade.java
+++ b/src/java/davmail/http/DavGatewayHttpClientFacade.java
@@ -410,6 +410,9 @@ public final class DavGatewayHttpClientFacade {
* @param httpClient HttpClient instance
*/
public static void addNTLM(HttpClient httpClient) {
+ // register the jcifs based NTLMv2 implementation
+ AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, NTLMv2Scheme.class);
+
ArrayList authPrefs = new ArrayList();
authPrefs.add(AuthPolicy.NTLM);
authPrefs.add(AuthPolicy.DIGEST);
diff --git a/src/java/davmail/http/NTLMv2Scheme.java b/src/java/davmail/http/NTLMv2Scheme.java
new file mode 100644
index 00000000..b4c17f8a
--- /dev/null
+++ b/src/java/davmail/http/NTLMv2Scheme.java
@@ -0,0 +1,198 @@
+/*
+ * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
+ * Copyright (C) 2010 Mickael Guessant
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package davmail.http;
+
+import jcifs.ntlmssp.NtlmFlags;
+import jcifs.ntlmssp.Type1Message;
+import jcifs.ntlmssp.Type2Message;
+import jcifs.ntlmssp.Type3Message;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.NTCredentials;
+import org.apache.commons.httpclient.auth.*;
+import org.apache.commons.httpclient.util.EncodingUtil;
+
+import java.io.IOException;
+
+/**
+ * NTLMv2 scheme implementation.
+ */
+public class NTLMv2Scheme implements AuthScheme {
+ private static final int UNINITIATED = 0;
+ private static final int INITIATED = 1;
+ private static final int TYPE1_MSG_GENERATED = 2;
+ private static final int TYPE2_MSG_RECEIVED = 3;
+ private static final int TYPE3_MSG_GENERATED = 4;
+ private static final int FAILED = Integer.MAX_VALUE;
+
+ private Type2Message type2Message;
+ /**
+ * Authentication process state
+ */
+ private int state;
+
+ /**
+ * Processes the NTLM challenge.
+ *
+ * @param challenge the challenge string
+ * @throws MalformedChallengeException is thrown if the authentication challenge
+ * is malformed
+ */
+ public void processChallenge(final String challenge) throws MalformedChallengeException {
+ String authScheme = AuthChallengeParser.extractScheme(challenge);
+ if (!authScheme.equalsIgnoreCase(getSchemeName())) {
+ throw new MalformedChallengeException("Invalid NTLM challenge: " + challenge);
+ }
+ int spaceIndex = challenge.indexOf(' ');
+ if (spaceIndex != -1) {
+ try {
+ type2Message = new Type2Message(Base64.decodeBase64(EncodingUtil.getBytes(
+ challenge.substring(spaceIndex, challenge.length()).trim(), "ASCII")));
+ } catch (IOException e) {
+ throw new MalformedChallengeException("Invalid NTLM challenge: " + challenge, e);
+ }
+ this.state = TYPE2_MSG_RECEIVED;
+ } else {
+ this.type2Message = null;
+ if (this.state == UNINITIATED) {
+ this.state = INITIATED;
+ } else {
+ this.state = FAILED;
+ }
+ }
+ }
+
+
+ /**
+ * Returns textual designation of the NTLM authentication scheme.
+ *
+ * @return ntlm
+ */
+ public String getSchemeName() {
+ return "ntlm";
+ }
+
+ /**
+ * Not used with NTLM.
+ *
+ * @return null
+ */
+ public String getParameter(String s) {
+ return null;
+ }
+
+ /**
+ * Not used with NTLM.
+ *
+ * @return null
+ */
+ public String getRealm() {
+ return null;
+ }
+
+ /**
+ * Deprecated.
+ *
+ * @deprecated
+ */
+ public String getID() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * NTLM is connection based.
+ *
+ * @return true
+ */
+ public boolean isConnectionBased() {
+ return true;
+ }
+
+ /**
+ * Tests if the NTLM authentication process has been completed.
+ *
+ * @return true if authorization has been processed
+ */
+ public boolean isComplete() {
+ return state == TYPE3_MSG_GENERATED || state == FAILED;
+ }
+
+ /**
+ * Not implemented.
+ *
+ * @param credentials user credentials
+ * @param method method name
+ * @param uri URI
+ * @return an NTLM authorization string
+ * @throws InvalidCredentialsException if authentication credentials
+ * are not valid or not applicable for this authentication scheme
+ * @throws AuthenticationException if authorization string cannot
+ * be generated due to an authentication failure
+ * @deprecated
+ */
+ public String authenticate(final Credentials credentials, String method, String uri) throws AuthenticationException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Produces NTLM authorization string for the given set of
+ * {@link Credentials}.
+ *
+ * @param credentials The set of credentials to be used for authentication
+ * @param httpMethod The method being authenticated
+ * @return an NTLM authorization string
+ * @throws InvalidCredentialsException if authentication credentials
+ * are not valid or not applicable for this authentication scheme
+ * @throws AuthenticationException if authorization string cannot
+ * be generated due to an authentication failure
+ */
+ public String authenticate(Credentials credentials, HttpMethod httpMethod) throws AuthenticationException {
+ if (this.state == UNINITIATED) {
+ throw new IllegalStateException("NTLM authentication process has not been initiated");
+ }
+
+ NTCredentials ntcredentials;
+ try {
+ ntcredentials = (NTCredentials) credentials;
+ } catch (ClassCastException e) {
+ throw new InvalidCredentialsException(
+ "Credentials cannot be used for NTLM authentication: "
+ + credentials.getClass().getName());
+ }
+ String response;
+ if (this.state == INITIATED || this.state == FAILED) {
+ int flags = NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 | NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
+ NtlmFlags.NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED | NtlmFlags.NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED |
+ NtlmFlags.NTLMSSP_NEGOTIATE_NTLM | NtlmFlags.NTLMSSP_REQUEST_TARGET |
+ NtlmFlags.NTLMSSP_NEGOTIATE_OEM | NtlmFlags.NTLMSSP_NEGOTIATE_UNICODE;
+ Type1Message type1Message = new Type1Message(flags, ntcredentials.getDomain(), ntcredentials.getHost());
+ response = EncodingUtil.getAsciiString(Base64.encodeBase64(type1Message.toByteArray()));
+ this.state = TYPE1_MSG_GENERATED;
+ } else {
+ Type3Message type3Message = new Type3Message(type2Message, ntcredentials.getPassword(),
+ ntcredentials.getDomain(), ntcredentials.getUserName(), ntcredentials.getHost(), 0);
+ response = EncodingUtil.getAsciiString(Base64.encodeBase64(type3Message.toByteArray()));
+ this.state = TYPE3_MSG_GENERATED;
+ }
+ return "NTLM " + response;
+ }
+
+
+}