[prev in list] [next in list] [prev in thread] [next in thread]
List: kfm-devel
Subject: PATCH - HTTP NTLM Authentication
From: Karsten =?iso-8859-1?q?K=FCnne?= <kuenne () rentec ! com>
Date: 2004-09-22 0:10:54
Message-ID: 200409212010.59844.kuenne () rentec ! com
[Download RAW message or body]
[Attachment #2 (multipart/mixed)]
I while ago I posted a message saying that I don't intend to support NTLM.
Well, after I discovered libntlm I changed my mind :-).
This patch adds NTLM authentication to kio_http. It depends on libntlm which
you can get from http://www.josefsson.org/libntlm . This is how NTLM
authentication works:
- the server (usually IIS) offers "NTLM" (and at least in my tests also
"Negotiate" but I couldn't figure out what to do with it as it apparently
doesn't want Kerberos/GSSAPI here) in the "WWW-Authenticate" header on a 401
response.
- the client sends a NTLM type 1 message (a request) in the "Authorization"
header on the next message and it MUST NOT close the connection! (this is
important, NTLM authentication doesn't work otherwise as it is
connection-oriented and not request-oriented)
- the server then answers with 401 and sends a type 2 message (a challenge) in
the "WWW-Authenticate" header
- the client then sends a type 3 message (a response) in the "Authorization"
header on the next message on the SAME connection
- if everything was o.k., the server answers with a 200.
In order to test NTLM authentication I even set up a Windows 2000 server on my
laptop (what a pain!). So, I tested it with Windows 2000 Server SP4 (IIS 5.0)
and libntlm-0.3.3.
The patch is against CVS HEAD from today.
Karsten.
--
43rd Law of Computing:
Anything that can go wr
fortune: Segmentation violation -- Core dumped
["ntlm.diff" (text/x-diff)]
diff -Naur kioslave/http.orig/Makefile.am kioslave/http/Makefile.am
--- kioslave/http.orig/Makefile.am 2004-07-13 15:17:45.000000000 -0400
+++ kioslave/http/Makefile.am 2004-09-21 18:26:48.000000000 -0400
@@ -3,8 +3,8 @@
SUBDIRS = kcookiejar
-INCLUDES= -I$(top_srcdir)/interfaces -I$(top_srcdir)/kio/httpfilter $(all_includes) \
$(GSSAPI_INCS)
-AM_LDFLAGS = $(all_libraries) $(GSSAPI_RPATH)
+INCLUDES= -I$(top_srcdir)/interfaces -I$(top_srcdir)/kio/httpfilter $(all_includes) \
$(GSSAPI_INCS) $(NTLM_INCS) +AM_LDFLAGS = $(all_libraries) $(GSSAPI_RPATH) \
$(NTLM_RPATH)
####### Files
@@ -15,8 +15,8 @@
kio_http_la_SOURCES = http.cc
kio_http_la_METASOURCES = AUTO
-kio_http_la_LIBADD = $(LIB_KIO) $(top_builddir)/kio/httpfilter/libhttpfilter.la \
$(GSSAPI_LIBS)
-kio_http_la_LDFLAGS = $(all_libraries) $(GSSAPI_RPATH) -module $(KDE_PLUGIN)
+kio_http_la_LIBADD = $(LIB_KIO) $(top_builddir)/kio/httpfilter/libhttpfilter.la \
$(GSSAPI_LIBS) $(NTLM_LIBS) +kio_http_la_LDFLAGS = $(all_libraries) $(GSSAPI_RPATH) \
$(NTLM_RPATH) -module $(KDE_PLUGIN)
kio_http_cache_cleaner_la_SOURCES = http_cache_cleaner.cpp
kio_http_cache_cleaner_la_LIBADD = $(LIB_KIO)
diff -Naur kioslave/http.orig/configure.in.in kioslave/http/configure.in.in
--- kioslave/http.orig/configure.in.in 2004-07-16 12:11:06.000000000 -0400
+++ kioslave/http/configure.in.in 2004-09-21 18:35:58.000000000 -0400
@@ -105,3 +105,76 @@
AC_SUBST(GSSAPI_LIBS)
AC_SUBST(GSSAPI_RPATH)
+dnl -------
+dnl Test for libntlm (NTLM support)
+dnl -------
+
+AC_MSG_CHECKING(whether to enable NTLM support)
+AC_ARG_WITH(ntlm,
+[ --with-ntlm=PATH Set path for NTLM files [default=check]],
+[ case "$withval" in
+ yes)
+ with_ntlm=CHECK
+ ;;
+ esac ],
+[ with_ntlm=CHECK ]
+)dnl
+
+if test "x$with_ntlm" = "xCHECK" ; then
+ with_ntlm=NOTFOUND
+ search_incs="$kde_includes /usr/include /usr/local/include"
+ AC_FIND_FILE(ntlm.h, $search_incs, ntlm_incdir)
+ if test -r $ntlm_incdir/ntlm.h ; then
+ test "x$ntlm_incdir" != "x/usr/include" && NTLM_INCS="-I$ntlm_incdir"
+ with_ntlm=FOUND
+ fi
+ if test $with_ntlm = FOUND ; then
+ $with_ntlm=NOTFOUND
+ for ext in la so sl a dylib ; do
+ AC_FIND_FILE(libntlm.$ext, $kde_libraries /usr/lib /usr/local/lib,
+ ntlm_libdir)
+ if test -r $ntlm_libdir/libntlm.$ext ; then
+ if test "x$ntlm_libdir" != "x/usr/lib" ; then
+ NTLM_LIBS="-L$ntlm_libdir "
+ test "$USE_RPATH" = yes && NTLM_RPATH="-R $ntlm_libdir"
+ fi
+ NTLM_LIBS="${NTLM_LIBS}-lntlm"
+ with_ntlm=FOUND
+ break
+ fi
+ done
+ fi
+fi
+
+case "$with_ntlm" in
+no) AC_MSG_RESULT(no) ;;
+framework)
+ NTLM_LIBS="-Xlinker -framework -Xlinker NTLM"
+ AC_DEFINE_UNQUOTED(HAVE_LIBNTLM, 1, [Define if you have the NTLM library])
+ NTLM_SUBDIR="ntlm"
+ AC_MSG_RESULT(Apple framework)
+ ;;
+NOTFOUND) AC_MSG_RESULT(searched but not found) ;;
+*)
+ if test "x$with_ntlm" = "xFOUND" ; then
+ msg="incs=$ntlm_incdir libs=$ntlm_libdir"
+ else
+ msg="$with_ntlm"
+ NTLM_ROOT="$with_ntlm"
+ if test "x$NTLM_ROOT" != "x/usr" ; then
+ NTLM_INCS="-I${NTLM_ROOT}/include"
+ NTLM_LIBS="-L${NTLM_ROOT}/lib "
+ if test "$USE_RPATH" = "yes" ; then
+ NTLM_RPATH="-R ${NTLM_ROOT}/lib"
+ fi
+ fi
+ NTLM_LIBS="${NTLM_LIBS}-lntlm"
+ fi
+ AC_DEFINE_UNQUOTED(HAVE_LIBNTLM, 1, [Define if you have the NTLM library])
+ AC_MSG_RESULT($msg)
+ ;;
+esac
+
+AC_SUBST(NTLM_INCS)
+AC_SUBST(NTLM_LIBS)
+AC_SUBST(NTLM_RPATH)
diff -Naur kioslave/http.orig/http.cc kioslave/http/http.cc
--- kioslave/http.orig/http.cc 2004-09-15 06:06:33.000000000 -0400
+++ kioslave/http/http.cc 2004-09-21 18:26:48.000000000 -0400
@@ -76,6 +76,10 @@
#include <gssapi.h>
#endif /* GSSAPI_MIT */
+#ifdef HAVE_LIBNTLM
+#include <ntlm.h>
+#endif
+
// Catch uncompatible crap (BR86019)
#if defined(GSS_RFC_COMPLIANT_OIDS) && (GSS_RFC_COMPLIANT_OIDS == 0)
#include <gssapi/gssapi_generic.h>
@@ -2381,11 +2385,12 @@
info.username = m_request.user;
if ( checkCachedAuthentication( info ) && !info.digestInfo.isEmpty() )
{
- Authentication = info.digestInfo.startsWith("Basic") ? AUTH_Basic : \
AUTH_Digest ; + Authentication = info.digestInfo.startsWith("Basic") ? \
AUTH_Basic : info.digestInfo.startsWith("NTLM") ? AUTH_NTLM : AUTH_Digest ; \
m_state.user = info.username; m_state.passwd = info.password;
m_strRealm = info.realmValue;
- m_strAuthorization = info.digestInfo;
+ if ( Authentication != AUTH_NTLM ) // don't use the cached challenge
+ m_strAuthorization = info.digestInfo;
}
}
else
@@ -2406,6 +2411,11 @@
header += createNegotiateAuth();
break;
#endif
+#ifdef HAVE_LIBNTLM
+ case AUTH_NTLM:
+ header += createNTLMAuth();
+ break;
+#endif
case AUTH_None:
default:
break;
@@ -3407,7 +3417,14 @@
{
if ( getAuthorization() )
{
- httpCloseConnection();
+ // for NTLM Authentication we have to keep the connection open!
+ if ( (Authentication == AUTH_NTLM) && (m_prevResponseCode != 0) )
+ {
+ m_bKeepAlive = true;
+ readBody( true );
+ }
+ else
+ httpCloseConnection();
return false; // Try again.
}
@@ -4827,6 +4844,14 @@
};
}
#endif
+#ifdef HAVE_LIBNTLM
+ else if ( strncasecmp( p, "NTLM", 4 ) == 0)
+ {
+ f = AUTH_NTLM;
+ memcpy((void *)p, "NTLM", 4); // Correct for upper-case variations.
+ p += 4;
+ }
+#endif
else
{
kdWarning(7113) << "(" << m_pid << ") Unsupported or invalid authorization "
@@ -5022,6 +5047,34 @@
}
}
+#ifdef HAVE_LIBNTLM
+ if ( Authentication == AUTH_NTLM )
+ {
+ QString auth = ( m_responseCode == 401 ) ? m_strAuthorization : \
m_strProxyAuthorization; + if ( auth.length() > 4 )
+ {
+ prompt = false;
+ result = true;
+ kdDebug(7113) << "(" << m_pid << ") NTLM auth second phase, "
+ << "sending response..." << endl;
+ if ( m_responseCode == 401 )
+ {
+ info.username = m_request.user;
+ info.password = m_request.passwd;
+ info.realmValue = m_strRealm;
+ info.digestInfo = m_strAuthorization;
+ }
+ else if ( m_responseCode == 407 )
+ {
+ info.username = m_proxyURL.user();
+ info.password = m_proxyURL.pass();
+ info.realmValue = m_strProxyRealm;
+ info.digestInfo = m_strProxyAuthorization;
+ }
+ }
+ }
+#endif
+
if ( prompt )
{
switch ( m_responseCode )
@@ -5289,6 +5342,74 @@
}
#endif
+#ifdef HAVE_LIBNTLM
+QString HTTPProtocol::createNTLMAuth( bool isForProxy )
+{
+ uint len;
+ QString auth;
+ QCString user, passwd, strauth;
+ QByteArray buf;
+
+ if ( isForProxy )
+ {
+ auth = "Proxy-Authorization: NTLM ";
+ user = m_proxyURL.user().latin1();
+ passwd = m_proxyURL.pass().latin1();
+ strauth = m_strProxyAuthorization.latin1();
+ len = m_strProxyAuthorization.length();
+ }
+ else
+ {
+ auth = "Authorization: NTLM ";
+ user = m_state.user.latin1();
+ passwd = m_state.passwd.latin1();
+ strauth = m_strAuthorization.latin1();
+ len = m_strAuthorization.length();
+ }
+ kdDebug(7113) << "(" << m_pid << ") NTLM length: " << len << endl;
+ if ( user.isEmpty() || passwd.isEmpty() || len < 4 )
+ return QString::null;
+
+ if ( len > 4 )
+ {
+ // create a response
+ tSmbNtlmAuthChallenge challenge;
+ tSmbNtlmAuthResponse response;
+
+ KCodecs::base64Decode( strauth.right( len - 5 ), buf );
+ memcpy((void *)&challenge, (const void *)buf.data(), sizeof(challenge));
+ buildSmbNtlmAuthResponse(&challenge, &response, user, passwd);
+ buf.duplicate((const char *)&response, SmbLength(&response));
+ }
+ else
+ {
+ // create a request
+ tSmbNtlmAuthRequest request;
+
+ buildSmbNtlmAuthRequest(&request, user, NULL);
+ buf.duplicate((const char *)&request, SmbLength(&request));
+ }
+
+ // remove the challenge to prevent reuse
+ if ( isForProxy )
+ m_strProxyAuthorization = "NTLM";
+ else
+ m_strAuthorization = "NTLM";
+
+ auth += KCodecs::base64Encode( buf );
+ auth += "\r\n";
+
+ return auth;
+}
+#else
+
+// Dummy
+QString HTTPProtocol::createNTLMAuth( bool isForProxy )
+{
+ return QString::null;
+}
+#endif
+
QString HTTPProtocol::createBasicAuth( bool isForProxy )
{
QString auth;
@@ -5684,6 +5805,8 @@
ProxyAuthentication = AUTH_None;
else if( m_strProxyAuthorization.startsWith("Basic") )
ProxyAuthentication = AUTH_Basic;
+ else if( m_strProxyAuthorization.startsWith("NTLM") )
+ ProxyAuthentication = AUTH_NTLM;
else
ProxyAuthentication = AUTH_Digest;
}
@@ -5697,6 +5820,8 @@
m_strProxyAuthorization = info.digestInfo;
if( m_strProxyAuthorization.startsWith("Basic") )
ProxyAuthentication = AUTH_Basic;
+ else if( m_strProxyAuthorization.startsWith("NTLM") )
+ ProxyAuthentication = AUTH_NTLM;
else
ProxyAuthentication = AUTH_Digest;
}
@@ -5727,6 +5852,11 @@
case AUTH_Digest:
header += createDigestAuth( true );
break;
+#ifdef HAVE_LIBNTLM
+ case AUTH_NTLM:
+ header += createNTLMAuth( true );
+ break;
+#endif
case AUTH_None:
default:
break;
diff -Naur kioslave/http.orig/http.h kioslave/http/http.h
--- kioslave/http.orig/http.h 2004-08-01 11:46:37.000000000 -0400
+++ kioslave/http/http.h 2004-09-21 18:26:48.000000000 -0400
@@ -58,7 +58,7 @@
enum HTTP_REV {HTTP_None, HTTP_Unknown, HTTP_10, HTTP_11, SHOUTCAST};
/** Authorization method used **/
- enum HTTP_AUTH {AUTH_None, AUTH_Basic, AUTH_Digest, AUTH_Negotiate};
+ enum HTTP_AUTH {AUTH_None, AUTH_Basic, AUTH_Digest, AUTH_Negotiate, AUTH_NTLM};
/** HTTP / DAV method **/
// Removed to interfaces/kio/http.h
@@ -434,6 +434,11 @@
QString createDigestAuth( bool isForProxy = false );
/**
+ * Creates the entity-header for NTLM authentication.
+ */
+ QString createNTLMAuth( bool isForProxy = false );
+
+ /**
* Creates the entity-header for Negotiate authentication.
*/
QString createNegotiateAuth();
[Attachment #6 (application/pgp-signature)]
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic