--nextPart1497749.NnXUpAMZ93 Content-Type: multipart/mixed; boundary="Boundary-01=_OMMUBvv/Vc/uEDd" Content-Transfer-Encoding: 7bit Content-Disposition: inline --Boundary-01=_OMMUBvv/Vc/uEDd Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline I while ago I posted a message saying that I don't intend to support NTLM.= =20 Well, after I discovered libntlm I changed my mind :-). This patch adds NTLM authentication to kio_http. It depends on libntlm whic= h=20 you can get from http://www.josefsson.org/libntlm . This is how NTLM=20 authentication works: =2D the server (usually IIS) offers "NTLM" (and at least in my tests also=20 "Negotiate" but I couldn't figure out what to do with it as it apparently=20 doesn't want Kerberos/GSSAPI here) in the "WWW-Authenticate" header on a 40= 1=20 response. =2D the client sends a NTLM type 1 message (a request) in the "Authorizatio= n"=20 header on the next message and it MUST NOT close the connection! (this is=20 important, NTLM authentication doesn't work otherwise as it is=20 connection-oriented and not request-oriented) =2D the server then answers with 401 and sends a type 2 message (a challeng= e) in=20 the "WWW-Authenticate" header =2D the client then sends a type 3 message (a response) in the "Authorizati= on"=20 header on the next message on the SAME connection =2D 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=20 laptop (what a pain!). So, I tested it with Windows 2000 Server SP4 (IIS 5.= 0)=20 and libntlm-0.3.3. The patch is against CVS HEAD from today. Karsten. =2D-=20 43rd Law of Computing: Anything that can go wr fortune: Segmentation violation -- Core dumped --Boundary-01=_OMMUBvv/Vc/uEDd Content-Type: text/x-diff; charset="us-ascii"; name="ntlm.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="ntlm.diff" diff -Naur kioslave/http.orig/Makefile.am kioslave/http/Makefile.am =2D-- 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 @@ =20 SUBDIRS =3D kcookiejar =20 =2DINCLUDES=3D -I$(top_srcdir)/interfaces -I$(top_srcdir)/kio/httpfilter $(= all_includes) $(GSSAPI_INCS) =2DAM_LDFLAGS =3D $(all_libraries) $(GSSAPI_RPATH) +INCLUDES=3D -I$(top_srcdir)/interfaces -I$(top_srcdir)/kio/httpfilter $(al= l_includes) $(GSSAPI_INCS) $(NTLM_INCS) +AM_LDFLAGS =3D $(all_libraries) $(GSSAPI_RPATH) $(NTLM_RPATH) =20 ####### Files =20 @@ -15,8 +15,8 @@ =20 kio_http_la_SOURCES =3D http.cc kio_http_la_METASOURCES =3D AUTO =2Dkio_http_la_LIBADD =3D $(LIB_KIO) $(top_builddir)/kio/httpfilter/libhttp= filter.la $(GSSAPI_LIBS) =2Dkio_http_la_LDFLAGS =3D $(all_libraries) $(GSSAPI_RPATH) -module $(KDE_P= LUGIN) +kio_http_la_LIBADD =3D $(LIB_KIO) $(top_builddir)/kio/httpfilter/libhttpfi= lter.la $(GSSAPI_LIBS) $(NTLM_LIBS) +kio_http_la_LDFLAGS =3D $(all_libraries) $(GSSAPI_RPATH) $(NTLM_RPATH) -mo= dule $(KDE_PLUGIN) =20 kio_http_cache_cleaner_la_SOURCES =3D http_cache_cleaner.cpp kio_http_cache_cleaner_la_LIBADD =3D $(LIB_KIO) diff -Naur kioslave/http.orig/configure.in.in kioslave/http/configure.in.in =2D-- 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) =20 +dnl ------- +dnl Test for libntlm (NTLM support) +dnl ------- + +AC_MSG_CHECKING(whether to enable NTLM support) +AC_ARG_WITH(ntlm, +[ --with-ntlm=3DPATH Set path for NTLM files [default=3Dcheck]], +[ case "$withval" in + yes) + with_ntlm=3DCHECK + ;; + esac ], +[ with_ntlm=3DCHECK ] +)dnl + +if test "x$with_ntlm" =3D "xCHECK" ; then + with_ntlm=3DNOTFOUND + search_incs=3D"$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" !=3D "x/usr/include" && NTLM_INCS=3D"-I$ntlm_incd= ir" + with_ntlm=3DFOUND + fi + if test $with_ntlm =3D FOUND ; then + $with_ntlm=3DNOTFOUND + 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" !=3D "x/usr/lib" ; then + NTLM_LIBS=3D"-L$ntlm_libdir " + test "$USE_RPATH" =3D yes && NTLM_RPATH=3D"-R $ntlm_libdir" + fi + NTLM_LIBS=3D"${NTLM_LIBS}-lntlm" + with_ntlm=3DFOUND + break + fi + done + fi +fi + +case "$with_ntlm" in +no) AC_MSG_RESULT(no) ;; +framework) + NTLM_LIBS=3D"-Xlinker -framework -Xlinker NTLM" + AC_DEFINE_UNQUOTED(HAVE_LIBNTLM, 1, [Define if you have the NTLM library= ]) + NTLM_SUBDIR=3D"ntlm" + AC_MSG_RESULT(Apple framework) + ;; +NOTFOUND) AC_MSG_RESULT(searched but not found) ;; +*) + if test "x$with_ntlm" =3D "xFOUND" ; then + msg=3D"incs=3D$ntlm_incdir libs=3D$ntlm_libdir" + else + msg=3D"$with_ntlm" + NTLM_ROOT=3D"$with_ntlm" + if test "x$NTLM_ROOT" !=3D "x/usr" ; then + NTLM_INCS=3D"-I${NTLM_ROOT}/include" + NTLM_LIBS=3D"-L${NTLM_ROOT}/lib " + if test "$USE_RPATH" =3D "yes" ; then + NTLM_RPATH=3D"-R ${NTLM_ROOT}/lib" + fi + fi + NTLM_LIBS=3D"${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 =2D-- 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 #endif /* GSSAPI_MIT */ =20 +#ifdef HAVE_LIBNTLM +#include +#endif + // Catch uncompatible crap (BR86019) #if defined(GSS_RFC_COMPLIANT_OIDS) && (GSS_RFC_COMPLIANT_OIDS =3D=3D 0) #include @@ -2381,11 +2385,12 @@ info.username =3D m_request.user; if ( checkCachedAuthentication( info ) && !info.digestInfo.isEmpty()= ) { =2D Authentication =3D info.digestInfo.startsWith("Basic") ? AUTH_Ba= sic : AUTH_Digest ; + Authentication =3D info.digestInfo.startsWith("Basic") ? AUTH_Basi= c : info.digestInfo.startsWith("NTLM") ? AUTH_NTLM : AUTH_Digest ; m_state.user =3D info.username; m_state.passwd =3D info.password; m_strRealm =3D info.realmValue; =2D m_strAuthorization =3D info.digestInfo; + if ( Authentication !=3D AUTH_NTLM ) // don't use the cached chall= enge + m_strAuthorization =3D info.digestInfo; } } else @@ -2406,6 +2411,11 @@ header +=3D createNegotiateAuth(); break; #endif +#ifdef HAVE_LIBNTLM + case AUTH_NTLM: + header +=3D createNTLMAuth(); + break; +#endif case AUTH_None: default: break; @@ -3407,7 +3417,14 @@ { if ( getAuthorization() ) { =2D httpCloseConnection(); + // for NTLM Authentication we have to keep the connection open! + if ( (Authentication =3D=3D AUTH_NTLM) && (m_prevResponseCode != =3D 0) ) + { + m_bKeepAlive =3D true; + readBody( true ); + } + else + httpCloseConnection(); return false; // Try again. } =20 @@ -4827,6 +4844,14 @@ }; } #endif +#ifdef HAVE_LIBNTLM + else if ( strncasecmp( p, "NTLM", 4 ) =3D=3D 0) + { + f =3D AUTH_NTLM; + memcpy((void *)p, "NTLM", 4); // Correct for upper-case variations. + p +=3D 4; + } +#endif else { kdWarning(7113) << "(" << m_pid << ") Unsupported or invalid authoriza= tion " @@ -5022,6 +5047,34 @@ } } =20 +#ifdef HAVE_LIBNTLM + if ( Authentication =3D=3D AUTH_NTLM ) + { + QString auth =3D ( m_responseCode =3D=3D 401 ) ? m_strAuthorization = : m_strProxyAuthorization; + if ( auth.length() > 4 ) + { + prompt =3D false; + result =3D true; + kdDebug(7113) << "(" << m_pid << ") NTLM auth second phase, " + << "sending response..." << endl; + if ( m_responseCode =3D=3D 401 ) + { + info.username =3D m_request.user; + info.password =3D m_request.passwd; + info.realmValue =3D m_strRealm; + info.digestInfo =3D m_strAuthorization; + } + else if ( m_responseCode =3D=3D 407 ) + { + info.username =3D m_proxyURL.user(); + info.password =3D m_proxyURL.pass(); + info.realmValue =3D m_strProxyRealm; + info.digestInfo =3D m_strProxyAuthorization; + } + } + } +#endif + if ( prompt ) { switch ( m_responseCode ) @@ -5289,6 +5342,74 @@ } #endif =20 +#ifdef HAVE_LIBNTLM +QString HTTPProtocol::createNTLMAuth( bool isForProxy ) +{ + uint len; + QString auth; + QCString user, passwd, strauth; + QByteArray buf; + + if ( isForProxy ) + { + auth =3D "Proxy-Authorization: NTLM "; + user =3D m_proxyURL.user().latin1(); + passwd =3D m_proxyURL.pass().latin1(); + strauth =3D m_strProxyAuthorization.latin1(); + len =3D m_strProxyAuthorization.length(); + } + else + { + auth =3D "Authorization: NTLM "; + user =3D m_state.user.latin1(); + passwd =3D m_state.passwd.latin1(); + strauth =3D m_strAuthorization.latin1(); + len =3D 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 =3D "NTLM"; + else + m_strAuthorization =3D "NTLM"; + + auth +=3D KCodecs::base64Encode( buf ); + auth +=3D "\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 =3D AUTH_None; else if( m_strProxyAuthorization.startsWith("Basic") ) ProxyAuthentication =3D AUTH_Basic; + else if( m_strProxyAuthorization.startsWith("NTLM") ) + ProxyAuthentication =3D AUTH_NTLM; else ProxyAuthentication =3D AUTH_Digest; } @@ -5697,6 +5820,8 @@ m_strProxyAuthorization =3D info.digestInfo; if( m_strProxyAuthorization.startsWith("Basic") ) ProxyAuthentication =3D AUTH_Basic; + else if( m_strProxyAuthorization.startsWith("NTLM") ) + ProxyAuthentication =3D AUTH_NTLM; else ProxyAuthentication =3D AUTH_Digest; } @@ -5727,6 +5852,11 @@ case AUTH_Digest: header +=3D createDigestAuth( true ); break; +#ifdef HAVE_LIBNTLM + case AUTH_NTLM: + header +=3D createNTLMAuth( true ); + break; +#endif case AUTH_None: default: break; diff -Naur kioslave/http.orig/http.h kioslave/http/http.h =2D-- 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}; =20 /** Authorization method used **/ =2D enum HTTP_AUTH {AUTH_None, AUTH_Basic, AUTH_Digest, AUTH_Negotiate}; + enum HTTP_AUTH {AUTH_None, AUTH_Basic, AUTH_Digest, AUTH_Negotiate, AU= TH_NTLM}; =20 /** HTTP / DAV method **/ // Removed to interfaces/kio/http.h @@ -434,6 +434,11 @@ QString createDigestAuth( bool isForProxy =3D false ); =20 /** + * Creates the entity-header for NTLM authentication. + */ + QString createNTLMAuth( bool isForProxy =3D false ); + + /** * Creates the entity-header for Negotiate authentication. */ QString createNegotiateAuth(); --Boundary-01=_OMMUBvv/Vc/uEDd-- --nextPart1497749.NnXUpAMZ93 Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQBBUMMT6/OfRf0i9j8RAsnOAJ49Etx/IaxNvCpfrbH6NskDneiDlACgsdUy Q2elTZmLhae6KXWaWDnyQ1g= =vJOb -----END PGP SIGNATURE----- --nextPart1497749.NnXUpAMZ93--