summaryrefslogtreecommitdiffstats
path: root/tdeioslave/ldap
diff options
context:
space:
mode:
Diffstat (limited to 'tdeioslave/ldap')
-rw-r--r--tdeioslave/ldap/CMakeLists.txt37
-rw-r--r--tdeioslave/ldap/ConfigureChecks.cmake21
-rw-r--r--tdeioslave/ldap/LICENSE16
-rw-r--r--tdeioslave/ldap/Makefile.am22
-rw-r--r--tdeioslave/ldap/configure.in.in111
-rw-r--r--tdeioslave/ldap/kio_ldap.cpp1154
-rw-r--r--tdeioslave/ldap/kio_ldap.h65
-rw-r--r--tdeioslave/ldap/ldap.protocol17
-rw-r--r--tdeioslave/ldap/ldaps.protocol17
9 files changed, 1460 insertions, 0 deletions
diff --git a/tdeioslave/ldap/CMakeLists.txt b/tdeioslave/ldap/CMakeLists.txt
new file mode 100644
index 000000000..ebf162205
--- /dev/null
+++ b/tdeioslave/ldap/CMakeLists.txt
@@ -0,0 +1,37 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include( ConfigureChecks.cmake )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES ldap.protocol ldaps.protocol DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kio_ldap (module) #########################
+
+tde_add_kpart( kio_ldap AUTOMOC
+ SOURCES kio_ldap.cpp
+ LINK kabc-shared ${LDAP_LIBRARIES}
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/tdeioslave/ldap/ConfigureChecks.cmake b/tdeioslave/ldap/ConfigureChecks.cmake
new file mode 100644
index 000000000..9515a3d69
--- /dev/null
+++ b/tdeioslave/ldap/ConfigureChecks.cmake
@@ -0,0 +1,21 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+check_include_file( ldap.h HAVE_LDAP_H )
+
+if( HAVE_LDAP_H )
+ set( LDAP_LIBRARIES ldap )
+ check_library_exists( ${LDAP_LIBRARIES} ldap_initialize "" HAVE_LDAP )
+endif( )
+
+if( NOT HAVE_LDAP_H OR NOT HAVE_LDAP )
+ tde_message_fatal( "ldap is requested, but was not found on your system." )
+endif( )
diff --git a/tdeioslave/ldap/LICENSE b/tdeioslave/ldap/LICENSE
new file mode 100644
index 000000000..d28a48f92
--- /dev/null
+++ b/tdeioslave/ldap/LICENSE
@@ -0,0 +1,16 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/tdeioslave/ldap/Makefile.am b/tdeioslave/ldap/Makefile.am
new file mode 100644
index 000000000..ca66e1b17
--- /dev/null
+++ b/tdeioslave/ldap/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am of tdebase/tdeioslave/ldap
+
+INCLUDES = $(all_includes) $(LDAP_INCS)
+AM_CXXFLAGS = -DLDAP_DEPRECATED
+AM_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LDAP_RPATH)
+LDADD = $(LIB_KIO) $(LDAP_LIBS)
+
+####### Files
+
+kde_module_LTLIBRARIES = kio_ldap.la
+
+kio_ldap_la_SOURCES = kio_ldap.cpp
+kio_ldap_la_LIBADD = $(LIB_KIO) $(LDAP_LIBS) $(LIB_KABC)
+kio_ldap_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LDAP_RPATH) -module $(KDE_PLUGIN)
+
+noinst_HEADERS = kio_ldap.h
+
+kdelnk_DATA = ldap.protocol ldaps.protocol
+kdelnkdir = $(kde_servicesdir)
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/tdeio_ldap.pot
diff --git a/tdeioslave/ldap/configure.in.in b/tdeioslave/ldap/configure.in.in
new file mode 100644
index 000000000..a4257d3db
--- /dev/null
+++ b/tdeioslave/ldap/configure.in.in
@@ -0,0 +1,111 @@
+AC_MSG_CHECKING(for LDAP support)
+AC_ARG_WITH(ldap,
+AC_HELP_STRING([--with-ldap=PATH],[Set path for LDAP files [default=check]]),
+[ case "$withval" in
+ yes)
+ with_ldap=CHECK
+ ;;
+ esac ],
+[ with_ldap=CHECK ]
+)dnl
+
+if test "x$with_ldap" = "xCHECK" ; then
+ with_ldap=NOTFOUND
+ search_incs="$kde_includes /usr/include /usr/local/include"
+ AC_FIND_FILE(ldap.h, $search_incs, ldap_incdir)
+ if test -r $ldap_incdir/ldap.h ; then
+ test "x$ldap_incdir" != "x/usr/include" && LDAP_INCS="-I$ldap_incdir"
+ with_ldap=FOUND
+ fi
+ if test $with_ldap = FOUND ; then
+ with_ldap=NOTFOUND
+ for ext in la so sl a dylib ; do
+ AC_FIND_FILE(libldap.$ext, $kde_libraries /usr/lib /usr/local/lib /usr/lib64,
+ ldap_libdir)
+ if test -r $ldap_libdir/libldap.$ext ; then
+ if test "x$ldap_libdir" != "x/usr/lib" ; then
+ LDAP_LIBS="-L$ldap_libdir "
+ test "$USE_RPATH" = yes && LDAP_RPATH="-R $ldap_libdir"
+ fi
+ LDAP_LIBS="${LDAP_LIBS}-lldap"
+ with_ldap=FOUND
+ break
+ fi
+ done
+ fi
+fi
+
+case "$with_ldap" in
+no) AC_MSG_RESULT(no) ;;
+framework)
+ LDAP_LIBS="-Xlinker -framework -Xlinker LDAP"
+ AC_DEFINE_UNQUOTED(HAVE_LIBLDAP, 1, [Define if you have LDAP libraries])
+ LDAP_SUBDIR="ldap"
+ AC_MSG_RESULT(Apple framework)
+ ;;
+FOUND)
+ AC_MSG_RESULT(incs=$ldap_incdir libs=$ldap_libdir)
+ ;;
+NOTFOUND) AC_MSG_RESULT(searched but not found) ;;
+*)
+ AC_MSG_RESULT($with_ldap)
+ ;;
+esac
+
+LIB_LBER=
+KDE_CHECK_LIB(lber, ber_alloc, [LIB_LBER=-llber], [], -L$ldap_libdir)
+AC_SUBST(LIB_LBER)
+
+AC_MSG_CHECKING(whether LDAP support can be compiled)
+
+ if test "x$with_ldap" != "xFOUND" ; then
+ LDAP_ROOT="$with_ldap"
+ if test "x$LDAP_ROOT" != "x/usr" ; then
+ LDAP_INCS="-I${LDAP_ROOT}/include"
+ LDAP_LIBS="-L${LDAP_ROOT}/lib "
+ if test "$USE_RPATH" = "yes" ; then
+ LDAP_RPATH="-R ${LDAP_ROOT}/lib"
+ fi
+ fi
+ LDAP_LIBS="${LDAP_LIBS}-lldap"
+ fi
+ LDAP_LIBS="${LDAP_LIBS} ${LIB_LBER} ${LIBRESOLV}"
+
+ kde_safe_LIBS="$LIBS"
+ kde_safe_CFLAGS="$CFLAGS"
+ LIBS="$LIBS $all_libraries $LDAP_LIBS $KRB4_LIBS $X_EXTRA_LIBS"
+ CFLAGS="$CFLAGS $all_includes $LDAP_INCS $KRB4_INCS"
+ AC_LANG_SAVE
+ AC_LANG_C
+ AC_TRY_LINK(dnl
+ [
+ #include <ldap.h>
+ #if LDAP_API_VERSION < 2004
+ #error LDAP version too old, please upgrade to a library supporting API 2004 or higher
+ #endif
+ ],
+ [
+ LDAP *ldap;
+ ],
+ , with_ldap=no
+ )
+ AC_LANG_RESTORE
+ CFLAGS=$kde_safe_CFLAGS
+ LIBS=$kde_safe_LIBS
+ if test "$with_ldap" = "no" ; then
+ LDAP_INCS=
+ LDAP_LIBS=
+ LDAP_RPATH=
+ LDAP_SUBDIR=
+ AC_MSG_RESULT(no (but first try gave $msg))
+ else
+ AC_DEFINE_UNQUOTED(HAVE_LIBLDAP, 1, [Define if you have LDAP libraries])
+ LDAP_SUBDIR="ldap"
+ AC_MSG_RESULT(yes)
+ fi
+
+AC_SUBST(LDAP_INCS)
+AC_SUBST(LDAP_LIBS)
+AC_SUBST(LDAP_RPATH)
+
+AM_CONDITIONAL(include_tdeioslave_ldap, test -n "$LDAP_SUBDIR")
diff --git a/tdeioslave/ldap/kio_ldap.cpp b/tdeioslave/ldap/kio_ldap.cpp
new file mode 100644
index 000000000..d4a29f1d4
--- /dev/null
+++ b/tdeioslave/ldap/kio_ldap.cpp
@@ -0,0 +1,1154 @@
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include <kdebug.h>
+#include <kinstance.h>
+#include <klocale.h>
+
+#ifdef HAVE_SASL_SASL_H //prefer libsasl2
+#include <sasl/sasl.h>
+#else
+#ifdef HAVE_SASL_H
+#include <sasl.h>
+#endif
+#endif
+#include <kabc/ldif.h>
+
+#include "kio_ldap.h"
+
+using namespace TDEIO;
+using namespace KABC;
+
+extern "C" { int KDE_EXPORT kdemain(int argc, char **argv); }
+
+/**
+ * The main program.
+ */
+int kdemain( int argc, char **argv )
+{
+ TDEInstance instance( "kio_ldap" );
+
+ kdDebug(7125) << "Starting " << getpid() << endl;
+
+ if ( argc != 4 ) {
+ kdError() << "Usage kio_ldap protocol pool app" << endl;
+ return -1;
+ }
+
+ // let the protocol class do its work
+ LDAPProtocol slave( argv[1], argv[ 2 ], argv[ 3 ] );
+ slave.dispatchLoop();
+
+ kdDebug( 7125 ) << "Done" << endl;
+ return 0;
+}
+
+/**
+ * Initialize the ldap slave
+ */
+LDAPProtocol::LDAPProtocol( const TQCString &protocol, const TQCString &pool,
+ const TQCString &app ) : SlaveBase( protocol, pool, app )
+{
+ mLDAP = 0; mTLS = 0; mVer = 3; mAuthSASL = false;
+ mRealm = ""; mBindName = "";
+ mTimeLimit = mSizeLimit = 0;
+ kdDebug(7125) << "LDAPProtocol::LDAPProtocol (" << protocol << ")" << endl;
+}
+
+LDAPProtocol::~LDAPProtocol()
+{
+ closeConnection();
+}
+
+void LDAPProtocol::LDAPErr( const KURL &url, int err )
+{
+
+ char *errmsg = 0;
+ if ( mLDAP ) {
+ if ( err == LDAP_SUCCESS ) ldap_get_option( mLDAP, LDAP_OPT_ERROR_NUMBER, &err );
+ if ( err != LDAP_SUCCESS ) ldap_get_option( mLDAP, LDAP_OPT_ERROR_STRING, &errmsg );
+ }
+ if ( err == LDAP_SUCCESS ) return;
+ kdDebug(7125) << "error code: " << err << " msg: " << ldap_err2string(err) <<
+ " Additonal error message: '" << errmsg << "'" << endl;
+ TQString msg;
+ TQString extraMsg;
+ if ( errmsg ) {
+ if ( errmsg[0] )
+ extraMsg = i18n("\nAdditional info: ") + TQString::fromUtf8( errmsg );
+ free( errmsg );
+ }
+ msg = url.prettyURL();
+ if ( !extraMsg.isEmpty() ) msg += extraMsg;
+
+ /* FIXME: No need to close on all errors */
+ closeConnection();
+
+ switch (err) {
+/* FIXME: is it worth mapping the following error codes to kio errors?
+
+ LDAP_OPERATIONS_ERROR
+ LDAP_STRONG_AUTH_REQUIRED
+ LDAP_PROTOCOL_ERROR
+ LDAP_TIMELIMIT_EXCEEDED
+ LDAP_SIZELIMIT_EXCEEDED
+ LDAP_COMPARE_FALSE
+ LDAP_COMPARE_TRUE
+ LDAP_PARTIAL_RESULTS
+ LDAP_NO_SUCH_ATTRIBUTE
+ LDAP_UNDEFINED_TYPE
+ LDAP_INAPPROPRIATE_MATCHING
+ LDAP_CONSTRAINT_VIOLATION
+ LDAP_INVALID_SYNTAX
+ LDAP_NO_SUCH_OBJECT
+ LDAP_ALIAS_PROBLEM
+ LDAP_INVALID_DN_SYNTAX
+ LDAP_IS_LEAF
+ LDAP_ALIAS_DEREF_PROBLEM
+ LDAP_INAPPROPRIATE_AUTH
+ LDAP_BUSY
+ LDAP_UNAVAILABLE
+ LDAP_UNWILLING_TO_PERFORM
+ LDAP_LOOP_DETECT
+ LDAP_NAMING_VIOLATION
+ LDAP_OBJECT_CLASS_VIOLATION
+ LDAP_NOT_ALLOWED_ON_NONLEAF
+ LDAP_NOT_ALLOWED_ON_RDN
+ LDAP_NO_OBJECT_CLASS_MODS
+ LDAP_OTHER
+ LDAP_LOCAL_ERROR
+ LDAP_ENCODING_ERROR
+ LDAP_DECODING_ERROR
+ LDAP_FILTER_ERROR
+*/
+ case LDAP_AUTH_UNKNOWN:
+ case LDAP_INVALID_CREDENTIALS:
+ case LDAP_STRONG_AUTH_NOT_SUPPORTED:
+ error(ERR_COULD_NOT_AUTHENTICATE, msg);
+ break;
+ case LDAP_ALREADY_EXISTS:
+ error(ERR_FILE_ALREADY_EXIST, msg);
+ break;
+ case LDAP_INSUFFICIENT_ACCESS:
+ error(ERR_ACCESS_DENIED, msg);
+ break;
+ case LDAP_CONNECT_ERROR:
+ case LDAP_SERVER_DOWN:
+ error(ERR_COULD_NOT_CONNECT,msg);
+ break;
+ case LDAP_TIMEOUT:
+ error(ERR_SERVER_TIMEOUT,msg);
+ break;
+ case LDAP_PARAM_ERROR:
+ error(ERR_INTERNAL,msg);
+ break;
+ case LDAP_NO_MEMORY:
+ error(ERR_OUT_OF_MEMORY,msg);
+ break;
+
+ default:
+ error( ERR_SLAVE_DEFINED,
+ i18n( "LDAP server returned the error: %1 %2\nThe LDAP URL was: %3" ).
+ arg( ldap_err2string(err)).arg( extraMsg ).arg( url.prettyURL() ) );
+ }
+}
+
+void LDAPProtocol::controlsFromMetaData( LDAPControl ***serverctrls,
+ LDAPControl ***clientctrls )
+{
+ TQString oid; bool critical; TQByteArray value;
+ int i = 0;
+ while ( hasMetaData( TQString::fromLatin1("SERVER_CTRL%1").arg(i) ) ) {
+ TQCString val = metaData( TQString::fromLatin1("SERVER_CTRL%1").arg(i) ).utf8();
+ LDIF::splitControl( val, oid, critical, value );
+ kdDebug(7125) << "server ctrl #" << i << " value: " << val <<
+ " oid: " << oid << " critical: " << critical << " value: " <<
+ TQString(TQString::fromUtf8( value, value.size() )) << endl;
+ addControlOp( serverctrls, oid, value, critical );
+ i++;
+ }
+ i = 0;
+ while ( hasMetaData( TQString::fromLatin1("CLIENT_CTRL%1").arg(i) ) ) {
+ TQCString val = metaData( TQString::fromLatin1("CLIENT_CTRL%1").arg(i) ).utf8();
+ LDIF::splitControl( val, oid, critical, value );
+ kdDebug(7125) << "client ctrl #" << i << " value: " << val <<
+ " oid: " << oid << " critical: " << critical << " value: " <<
+ TQString(TQString::fromUtf8( value, value.size() )) << endl;
+ addControlOp( clientctrls, oid, value, critical );
+ i++;
+ }
+}
+
+int LDAPProtocol::asyncSearch( LDAPUrl &usrc )
+{
+ char **attrs = 0;
+ int msgid;
+ LDAPControl **serverctrls = 0, **clientctrls = 0;
+
+ int count = usrc.attributes().count();
+ if ( count > 0 ) {
+ attrs = static_cast<char**>( malloc((count+1) * sizeof(char*)) );
+ for (int i=0; i<count; i++)
+ attrs[i] = strdup( (*usrc.attributes().at(i)).utf8() );
+ attrs[count] = 0;
+ }
+
+ int retval, scope = LDAP_SCOPE_BASE;
+ switch ( usrc.scope() ) {
+ case LDAPUrl::Base:
+ scope = LDAP_SCOPE_BASE;
+ break;
+ case LDAPUrl::One:
+ scope = LDAP_SCOPE_ONELEVEL;
+ break;
+ case LDAPUrl::Sub:
+ scope = LDAP_SCOPE_SUBTREE;
+ break;
+ }
+
+ controlsFromMetaData( &serverctrls, &clientctrls );
+
+ kdDebug(7125) << "asyncSearch() dn=\"" << usrc.dn() << "\" scope=" <<
+ usrc.scope() << " filter=\"" << usrc.filter() << "\" attrs=" << usrc.attributes() <<
+ endl;
+ retval = ldap_search_ext( mLDAP, usrc.dn().utf8(), scope,
+ usrc.filter().isEmpty() ? TQCString() : usrc.filter().utf8(), attrs, 0,
+ serverctrls, clientctrls,
+ 0, mSizeLimit, &msgid );
+
+ ldap_controls_free( serverctrls );
+ ldap_controls_free( clientctrls );
+
+ // free the attributes list again
+ if ( count > 0 ) {
+ for ( int i=0; i<count; i++ ) free( attrs[i] );
+ free(attrs);
+ }
+
+ if ( retval == 0 ) retval = msgid;
+ return retval;
+}
+
+TQCString LDAPProtocol::LDAPEntryAsLDIF( LDAPMessage *message )
+{
+ TQCString result;
+ char *name;
+ struct berval **bvals;
+ BerElement *entry;
+ TQByteArray tmp;
+
+ char *dn = ldap_get_dn( mLDAP, message );
+ if ( dn == NULL ) return TQCString( "" );
+ tmp.setRawData( dn, strlen( dn ) );
+ result += LDIF::assembleLine( "dn", tmp ) + '\n';
+ tmp.resetRawData( dn, strlen( dn ) );
+ ldap_memfree( dn );
+
+ // iterate over the attributes
+ name = ldap_first_attribute(mLDAP, message, &entry);
+ while ( name != 0 )
+ {
+ // print the values
+ bvals = ldap_get_values_len(mLDAP, message, name);
+ if ( bvals ) {
+
+ for ( int i = 0; bvals[i] != 0; i++ ) {
+ char* val = bvals[i]->bv_val;
+ unsigned long len = bvals[i]->bv_len;
+ tmp.setRawData( val, len );
+ result += LDIF::assembleLine( TQString::fromUtf8( name ), tmp, 76 ) + '\n';
+ tmp.resetRawData( val, len );
+ }
+ ldap_value_free_len(bvals);
+ }
+ ldap_memfree( name );
+ // next attribute
+ name = ldap_next_attribute(mLDAP, message, entry);
+ }
+ return result;
+}
+
+void LDAPProtocol::addControlOp( LDAPControl ***pctrls, const TQString &oid,
+ const TQByteArray &value, bool critical )
+{
+ LDAPControl **ctrls;
+ LDAPControl *ctrl = (LDAPControl *) malloc( sizeof( LDAPControl ) );
+
+ ctrls = *pctrls;
+
+ kdDebug(7125) << "addControlOp: oid:'" << oid << "' val: '" <<
+ TQString(TQString::fromUtf8(value, value.size())) << "'" << endl;
+ int vallen = value.size();
+ ctrl->ldctl_value.bv_len = vallen;
+ if ( vallen ) {
+ ctrl->ldctl_value.bv_val = (char*) malloc( vallen );
+ memcpy( ctrl->ldctl_value.bv_val, value.data(), vallen );
+ } else {
+ ctrl->ldctl_value.bv_val = 0;
+ }
+ ctrl->ldctl_iscritical = critical;
+ ctrl->ldctl_oid = strdup( oid.utf8() );
+
+ uint i = 0;
+
+ if ( ctrls == 0 ) {
+ ctrls = (LDAPControl **) malloc ( 2 * sizeof( LDAPControl* ) );
+ ctrls[ 0 ] = 0;
+ ctrls[ 1 ] = 0;
+ } else {
+ while ( ctrls[ i ] != 0 ) i++;
+ ctrls[ i + 1 ] = 0;
+ ctrls = (LDAPControl **) realloc( ctrls, (i + 2) * sizeof( LDAPControl * ) );
+ }
+ ctrls[ i ] = ctrl;
+
+ *pctrls = ctrls;
+}
+
+void LDAPProtocol::addModOp( LDAPMod ***pmods, int mod_type, const TQString &attr,
+ const TQByteArray &value )
+{
+// kdDebug(7125) << "type: " << mod_type << " attr: " << attr <<
+// " value: " << TQString::fromUtf8(value,value.size()) <<
+// " size: " << value.size() << endl;
+ LDAPMod **mods;
+
+ mods = *pmods;
+
+ uint i = 0;
+
+ if ( mods == 0 ) {
+ mods = (LDAPMod **) malloc ( 2 * sizeof( LDAPMod* ) );
+ mods[ 0 ] = (LDAPMod*) malloc( sizeof( LDAPMod ) );
+ mods[ 1 ] = 0;
+ memset( mods[ 0 ], 0, sizeof( LDAPMod ) );
+ } else {
+ while( mods[ i ] != 0 &&
+ ( strcmp( attr.utf8(),mods[i]->mod_type ) != 0 ||
+ ( mods[ i ]->mod_op & ~LDAP_MOD_BVALUES ) != mod_type ) ) i++;
+
+ if ( mods[ i ] == 0 ) {
+ mods = ( LDAPMod ** )realloc( mods, (i + 2) * sizeof( LDAPMod * ) );
+ if ( mods == 0 ) {
+ kdError() << "addModOp: realloc" << endl;
+ return;
+ }
+ mods[ i + 1 ] = 0;
+ mods[ i ] = ( LDAPMod* ) malloc( sizeof( LDAPMod ) );
+ memset( mods[ i ], 0, sizeof( LDAPMod ) );
+ }
+ }
+
+ mods[ i ]->mod_op = mod_type | LDAP_MOD_BVALUES;
+ if ( mods[ i ]->mod_type == 0 ) mods[ i ]->mod_type = strdup( attr.utf8() );
+
+ *pmods = mods;
+
+ int vallen = value.size();
+ if ( vallen == 0 ) return;
+ BerValue *berval;
+ berval = ( BerValue* ) malloc( sizeof( BerValue ) );
+ berval -> bv_val = (char*) malloc( vallen );
+ berval -> bv_len = vallen;
+ memcpy( berval -> bv_val, value.data(), vallen );
+
+ if ( mods[ i ] -> mod_vals.modv_bvals == 0 ) {
+ mods[ i ]->mod_vals.modv_bvals = ( BerValue** ) malloc( sizeof( BerValue* ) * 2 );
+ mods[ i ]->mod_vals.modv_bvals[ 0 ] = berval;
+ mods[ i ]->mod_vals.modv_bvals[ 1 ] = 0;
+ kdDebug(7125) << "addModOp: new bervalue struct " << endl;
+ } else {
+ uint j = 0;
+ while ( mods[ i ]->mod_vals.modv_bvals[ j ] != 0 ) j++;
+ mods[ i ]->mod_vals.modv_bvals = ( BerValue ** )
+ realloc( mods[ i ]->mod_vals.modv_bvals, (j + 2) * sizeof( BerValue* ) );
+ if ( mods[ i ]->mod_vals.modv_bvals == 0 ) {
+ kdError() << "addModOp: realloc" << endl;
+ return;
+ }
+ mods[ i ]->mod_vals.modv_bvals[ j ] = berval;
+ mods[ i ]->mod_vals.modv_bvals[ j+1 ] = 0;
+ kdDebug(7125) << j << ". new bervalue " << endl;
+ }
+}
+
+void LDAPProtocol::LDAPEntry2UDSEntry( const TQString &dn, UDSEntry &entry,
+ const LDAPUrl &usrc, bool dir )
+{
+ UDSAtom atom;
+
+ int pos;
+ entry.clear();
+ atom.m_uds = UDS_NAME;
+ atom.m_long = 0;
+ TQString name = dn;
+ if ( (pos = name.find(",")) > 0 )
+ name = name.left( pos );
+ if ( (pos = name.find("=")) > 0 )
+ name.remove( 0, pos+1 );
+ name.replace(' ', "_");
+ if ( !dir ) name += ".ldif";
+ atom.m_str = name;
+ entry.append( atom );
+
+ // the file type
+ atom.m_uds = UDS_FILE_TYPE;
+ atom.m_str = "";
+ atom.m_long = dir ? S_IFDIR : S_IFREG;
+ entry.append( atom );
+
+ // the mimetype
+ if (!dir) {
+ atom.m_uds = UDS_MIME_TYPE;
+ atom.m_long = 0;
+ atom.m_str = "text/plain";
+ entry.append( atom );
+ }
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = dir ? 0500 : 0400;
+ entry.append( atom );
+
+ // the url
+ atom.m_uds = UDS_URL;
+ atom.m_long = 0;
+ LDAPUrl url;
+ url=usrc;
+
+ url.setPath("/"+dn);
+ url.setScope( dir ? LDAPUrl::One : LDAPUrl::Base );
+ atom.m_str = url.prettyURL();
+ entry.append( atom );
+}
+
+void LDAPProtocol::changeCheck( LDAPUrl &url )
+{
+ bool critical;
+ bool tls = ( url.hasExtension( "x-tls" ) );
+ int ver = 3;
+ if ( url.hasExtension( "x-ver" ) )
+ ver = url.extension( "x-ver", critical).toInt();
+ bool authSASL = url.hasExtension( "x-sasl" );
+ TQString mech;
+ if ( url.hasExtension( "x-mech" ) )
+ mech = url.extension( "x-mech", critical).upper();
+ TQString realm;
+ if ( url.hasExtension( "x-realm" ) )
+ mech = url.extension( "x-realm", critical).upper();
+ TQString bindname;
+ if ( url.hasExtension( "bindname" ) )
+ bindname = url.extension( "bindname", critical).upper();
+ int timelimit = 0;
+ if ( url.hasExtension( "x-timelimit" ) )
+ timelimit = url.extension( "x-timelimit", critical).toInt();
+ int sizelimit = 0;
+ if ( url.hasExtension( "x-sizelimit" ) )
+ sizelimit = url.extension( "x-sizelimit", critical).toInt();
+
+ if ( !authSASL && bindname.isEmpty() ) bindname = mUser;
+
+ if ( tls != mTLS || ver != mVer || authSASL != mAuthSASL || mech != mMech ||
+ mRealm != realm || mBindName != bindname || mTimeLimit != timelimit ||
+ mSizeLimit != sizelimit ) {
+ closeConnection();
+ mTLS = tls;
+ mVer = ver;
+ mAuthSASL = authSASL;
+ mMech = mech;
+ mRealm = realm;
+ mBindName = bindname;
+ mTimeLimit = timelimit;
+ mSizeLimit = sizelimit;
+ kdDebug(7125) << "parameters changed: tls = " << mTLS <<
+ " version: " << mVer << "SASLauth: " << mAuthSASL << endl;
+ openConnection();
+ if ( mAuthSASL ) {
+ url.setUser( mUser );
+ } else {
+ url.setUser( mBindName );
+ }
+ } else {
+ if ( !mLDAP ) openConnection();
+ }
+}
+
+void LDAPProtocol::setHost( const TQString& host, int port,
+ const TQString& user, const TQString& password )
+{
+
+ if( mHost != host || mPort != port || mUser != user || mPassword != password )
+ closeConnection();
+
+ mHost = host;
+ if( port > 0 )
+ mPort = port;
+ else {
+ struct servent *pse;
+ if ( (pse = getservbyname(mProtocol, "tcp")) == NULL )
+ if ( mProtocol == "ldaps" )
+ mPort = 636;
+ else
+ mPort = 389;
+ else
+ mPort = ntohs( pse->s_port );
+ }
+ mUser = user;
+ mPassword = password;
+
+ kdDebug(7125) << "setHost: " << host << " port: " << port << " user: " <<
+ mUser << " pass: [protected]" << endl;
+}
+
+static int kldap_sasl_interact( LDAP *, unsigned, void *slave, void *in )
+{
+ return ((LDAPProtocol*) slave)->saslInteract( in );
+}
+
+void LDAPProtocol::fillAuthInfo( AuthInfo &info )
+{
+ info.url.setProtocol( mProtocol );
+ info.url.setHost( mHost );
+ info.url.setPort( mPort );
+ info.url.setUser( mUser );
+ info.caption = i18n("LDAP Login");
+ info.comment = TQString::fromLatin1( mProtocol ) + "://" + mHost + ":" +
+ TQString::number( mPort );
+ info.commentLabel = i18n("site:");
+ info.username = mAuthSASL ? mUser : mBindName;
+ info.password = mPassword;
+ info.keepPassword = true;
+}
+
+int LDAPProtocol::saslInteract( void *in )
+{
+#if defined HAVE_SASL_H || defined HAVE_SASL_SASL_H
+ AuthInfo info;
+ fillAuthInfo( info );
+
+ sasl_interact_t *interact = ( sasl_interact_t * ) in;
+
+ //some mechanisms do not require username && pass, so it doesn't need a popup
+ //window for getting this info
+ for ( ; interact->id != SASL_CB_LIST_END; interact++ ) {
+ if ( interact->id == SASL_CB_AUTHNAME ||
+ interact->id == SASL_CB_PASS ) {
+
+ if ( info.username.isEmpty() || info.password.isEmpty() ) {
+
+ const bool cached = checkCachedAuthentication( info );
+
+ if ( ! ( ( mFirstAuth && cached ) ||
+ ( mFirstAuth ?
+ openPassDlg( info ) :
+ openPassDlg( info, i18n("Invalid authorization information.") ) ) ) ) {
+ kdDebug(7125) << "Dialog cancelled!" << endl;
+ mCancel = true;
+ return LDAP_USER_CANCELLED;
+ }
+ mUser = info.username;
+ mPassword = info.password;
+ }
+ break;
+ }
+ }
+
+ interact = ( sasl_interact_t * ) in;
+ TQString value;
+
+ while( interact->id != SASL_CB_LIST_END ) {
+ value = "";
+ switch( interact->id ) {
+ case SASL_CB_GETREALM:
+ value = mRealm;
+ kdDebug(7125) << "SASL_REALM=" << mRealm << endl;
+ break;
+ case SASL_CB_AUTHNAME:
+ value = mUser;
+ kdDebug(7125) << "SASL_AUTHNAME=" << mUser << endl;
+ break;
+ case SASL_CB_PASS:
+ value = mPassword;
+ kdDebug(7125) << "SASL_PASSWD=[hidden]" << endl;
+ break;
+ case SASL_CB_USER:
+ value = mBindName;
+ kdDebug(7125) << "SASL_AUTHZID=" << mBindName << endl;
+ break;
+ }
+ if ( value.isEmpty() ) {
+ interact->result = NULL;
+ interact->len = 0;
+ } else {
+ interact->result = strdup( value.utf8() );
+ interact->len = strlen( (const char *) interact->result );
+ }
+ interact++;
+ }
+
+#endif
+ return LDAP_SUCCESS;
+}
+
+void LDAPProtocol::openConnection()
+{
+ if ( mLDAP ) return;
+
+ int version,ret;
+
+ version = ( mVer == 2 ) ? LDAP_VERSION2 : LDAP_VERSION3;
+
+ KURL Url;
+ Url.setProtocol( mProtocol );
+ Url.setHost( mHost );
+ Url.setPort( mPort );
+
+ AuthInfo info;
+ fillAuthInfo( info );
+///////////////////////////////////////////////////////////////////////////
+ kdDebug(7125) << "OpenConnection to " << mHost << ":" << mPort << endl;
+
+ ret = ldap_initialize( &mLDAP, Url.htmlURL().utf8() );
+ if ( ret != LDAP_SUCCESS ) {
+ LDAPErr( Url, ret );
+ return;
+ }
+
+ if ( (ldap_set_option( mLDAP, LDAP_OPT_PROTOCOL_VERSION, &version )) !=
+ LDAP_OPT_SUCCESS ) {
+
+ closeConnection();
+ error( ERR_UNSUPPORTED_ACTION,
+ i18n("Cannot set LDAP protocol version %1").arg(version) );
+ return;
+ }
+
+ if ( mTLS ) {
+ kdDebug(7125) << "start TLS" << endl;
+ if ( ( ret = ldap_start_tls_s( mLDAP, NULL, NULL ) ) != LDAP_SUCCESS ) {
+ LDAPErr( Url );
+ return;
+ }
+ }
+
+ if ( mSizeLimit ) {
+ kdDebug(7125) << "sizelimit: " << mSizeLimit << endl;
+ if ( ldap_set_option( mLDAP, LDAP_OPT_SIZELIMIT, &mSizeLimit ) != LDAP_SUCCESS ) {
+ closeConnection();
+ error( ERR_UNSUPPORTED_ACTION,
+ i18n("Cannot set size limit."));
+ return;
+ }
+ }
+
+ if ( mTimeLimit ) {
+ kdDebug(7125) << "timelimit: " << mTimeLimit << endl;
+ if ( ldap_set_option( mLDAP, LDAP_OPT_TIMELIMIT, &mTimeLimit ) != LDAP_SUCCESS ) {
+ closeConnection();
+ error( ERR_UNSUPPORTED_ACTION,
+ i18n("Cannot set time limit."));
+ return;
+ }
+ }
+
+#if !defined HAVE_SASL_H && !defined HAVE_SASL_SASL_H
+ if ( mAuthSASL ) {
+ closeConnection();
+ error( ERR_SLAVE_DEFINED,
+ i18n("SASL authentication not compiled into the ldap ioslave.") );
+ return;
+ }
+#endif
+
+ bool auth = false;
+ TQString mechanism = mMech.isEmpty() ? "DIGEST-MD5" : mMech;
+ mFirstAuth = true; mCancel = false;
+
+ const bool cached = checkCachedAuthentication( info );
+
+ ret = LDAP_SUCCESS;
+ while (!auth) {
+ if ( !mAuthSASL && (
+ ( mFirstAuth &&
+ !( mBindName.isEmpty() && mPassword.isEmpty() ) && //For anonymous bind
+ ( mBindName.isEmpty() || mPassword.isEmpty() ) ) || !mFirstAuth ) )
+ {
+ if ( ( mFirstAuth && cached ) ||
+ ( mFirstAuth ?
+ openPassDlg( info ) :
+ openPassDlg( info, i18n("Invalid authorization information.") ) ) ) {
+
+ mBindName = info.username;
+ mPassword = info.password;
+ } else {
+ kdDebug(7125) << "Dialog cancelled!" << endl;
+ error( ERR_USER_CANCELED, TQString::null );
+ closeConnection();
+ return;
+ }
+ }
+ kdDebug(7125) << "user: " << mUser << " bindname: " << mBindName << endl;
+ ret =
+#if defined HAVE_SASL_H || defined HAVE_SASL_SASL_H
+ mAuthSASL ?
+ ldap_sasl_interactive_bind_s( mLDAP, NULL, mechanism.utf8(),
+ NULL, NULL, LDAP_SASL_INTERACTIVE, &kldap_sasl_interact, this ) :
+#endif
+ ldap_simple_bind_s( mLDAP, mBindName.utf8(), mPassword.utf8() );
+
+ mFirstAuth = false;
+ if ( ret != LDAP_INVALID_CREDENTIALS &&
+ ret != LDAP_INSUFFICIENT_ACCESS &&
+ ret != LDAP_INAPPROPRIATE_AUTH ) {
+ kdDebug(7125) << "ldap_bind retval: " << ret << endl;
+ auth = true;
+ if ( ret != LDAP_SUCCESS ) {
+ if ( mCancel )
+ error( ERR_USER_CANCELED, TQString::null );
+ else
+ LDAPErr( Url );
+ closeConnection();
+ return;
+ }
+ }
+ }
+
+ kdDebug(7125) << "connected!" << endl;
+ connected();
+}
+
+void LDAPProtocol::closeConnection()
+{
+ if (mLDAP) ldap_unbind(mLDAP);
+ mLDAP = 0;
+ kdDebug(7125) << "connection closed!" << endl;
+}
+
+/**
+ * Get the information contained in the URL.
+ */
+void LDAPProtocol::get( const KURL &_url )
+{
+ kdDebug(7125) << "get(" << _url << ")" << endl;
+
+ LDAPUrl usrc(_url);
+ int ret, id;
+ LDAPMessage *msg,*entry;
+
+ changeCheck( usrc );
+ if ( !mLDAP ) {
+ finished();
+ return;
+ }
+
+ if ( (id = asyncSearch( usrc )) == -1 ) {
+ LDAPErr( _url );
+ return;
+ }
+
+ // tell the mimetype
+ mimeType("text/plain");
+ // collect the result
+ TQCString result;
+ filesize_t processed_size = 0;
+ TQByteArray array;
+
+ while( true ) {
+ ret = ldap_result( mLDAP, id, 0, NULL, &msg );
+ if ( ret == -1 ) {
+ LDAPErr( _url );
+ return;
+ }
+ kdDebug(7125) << " ldap_result: " << ret << endl;
+ if ( ret == LDAP_RES_SEARCH_RESULT ) break;
+ if ( ret != LDAP_RES_SEARCH_ENTRY ) continue;
+
+ entry = ldap_first_entry( mLDAP, msg );
+ while ( entry ) {
+ result = LDAPEntryAsLDIF(entry);
+ result += '\n';
+ uint len = result.length();
+ processed_size += len;
+ array.setRawData( result.data(), len );
+ data(array);
+ processedSize( processed_size );
+ array.resetRawData( result.data(), len );
+
+ entry = ldap_next_entry( mLDAP, entry );
+ }
+ LDAPErr( _url );
+
+ ldap_msgfree(msg);
+ // tell the length
+ }
+
+ totalSize(processed_size);
+
+ array.resize(0);
+ // tell we are finished
+ data(array);
+
+ // tell we are finished
+ finished();
+}
+
+/**
+ * Test if the url contains a directory or a file.
+ */
+void LDAPProtocol::stat( const KURL &_url )
+{
+ kdDebug(7125) << "stat(" << _url << ")" << endl;
+
+ TQStringList att,saveatt;
+ LDAPUrl usrc(_url);
+ LDAPMessage *msg;
+ int ret, id;
+
+ changeCheck( usrc );
+ if ( !mLDAP ) {
+ finished();
+ return;
+ }
+
+ // look how many entries match
+ saveatt = usrc.attributes();
+ att.append( "dn" );
+ usrc.setAttributes( att );
+ if ( _url.query().isEmpty() ) usrc.setScope( LDAPUrl::One );
+
+ if ( (id = asyncSearch( usrc )) == -1 ) {
+ LDAPErr( _url );
+ return;
+ }
+
+ kdDebug(7125) << "stat() getting result" << endl;
+ do {
+ ret = ldap_result( mLDAP, id, 0, NULL, &msg );
+ if ( ret == -1 ) {
+ LDAPErr( _url );
+ return;
+ }
+ if ( ret == LDAP_RES_SEARCH_RESULT ) {
+ ldap_msgfree( msg );
+ error( ERR_DOES_NOT_EXIST, _url.prettyURL() );
+ return;
+ }
+ } while ( ret != LDAP_RES_SEARCH_ENTRY );
+
+ ldap_msgfree( msg );
+ ldap_abandon( mLDAP, id );
+
+ usrc.setAttributes( saveatt );
+
+ UDSEntry uds;
+ bool critical;
+ LDAPEntry2UDSEntry( usrc.dn(), uds, usrc, usrc.extension("x-dir", critical) != "base" );
+
+ statEntry( uds );
+ // we are done
+ finished();
+}
+
+/**
+ * Deletes one entry;
+ */
+void LDAPProtocol::del( const KURL &_url, bool )
+{
+ kdDebug(7125) << "del(" << _url << ")" << endl;
+
+ LDAPUrl usrc(_url);
+ int ret;
+
+ changeCheck( usrc );
+ if ( !mLDAP ) {
+ finished();
+ return;
+ }
+
+ kdDebug(7125) << " del: " << usrc.dn().utf8() << endl ;
+
+ if ( (ret = ldap_delete_s( mLDAP,usrc.dn().utf8() )) != LDAP_SUCCESS ) {
+ LDAPErr( _url );
+ return;
+ }
+ finished();
+}
+
+#define FREELDAPMEM { \
+ ldap_mods_free( lmod, 1 ); \
+ ldap_controls_free( serverctrls ); \
+ ldap_controls_free( clientctrls ); \
+ lmod = 0; serverctrls = 0; clientctrls = 0; \
+ }
+
+void LDAPProtocol::put( const KURL &_url, int, bool overwrite, bool )
+{
+ kdDebug(7125) << "put(" << _url << ")" << endl;
+
+ LDAPUrl usrc(_url);
+
+ changeCheck( usrc );
+ if ( !mLDAP ) {
+ finished();
+ return;
+ }
+
+ LDAPMod **lmod = 0;
+ LDAPControl **serverctrls = 0, **clientctrls = 0;
+ TQByteArray buffer;
+ int result = 0;
+ LDIF::ParseVal ret;
+ LDIF ldif;
+ ret = LDIF::MoreData;
+ int ldaperr;
+
+
+ do {
+ if ( ret == LDIF::MoreData ) {
+ dataReq(); // Request for data
+ result = readData( buffer );
+ ldif.setLDIF( buffer );
+ }
+ if ( result < 0 ) {
+ //error
+ FREELDAPMEM;
+ return;
+ }
+ if ( result == 0 ) {
+ kdDebug(7125) << "EOF!" << endl;
+ ldif.endLDIF();
+ }
+ do {
+
+ ret = ldif.nextItem();
+ kdDebug(7125) << "nextitem: " << ret << endl;
+
+ switch ( ret ) {
+ case LDIF::None:
+ case LDIF::NewEntry:
+ case LDIF::MoreData:
+ break;
+ case LDIF::EndEntry:
+ ldaperr = LDAP_SUCCESS;
+ switch ( ldif.entryType() ) {
+ case LDIF::Entry_None:
+ error( ERR_INTERNAL, i18n("The LDIF parser failed.") );
+ FREELDAPMEM;
+ return;
+ case LDIF::Entry_Del:
+ kdDebug(7125) << "kio_ldap_del" << endl;
+ controlsFromMetaData( &serverctrls, &clientctrls );
+ ldaperr = ldap_delete_ext_s( mLDAP, ldif.dn().utf8(),
+ serverctrls, clientctrls );
+ FREELDAPMEM;
+ break;
+ case LDIF::Entry_Modrdn:
+ kdDebug(7125) << "kio_ldap_modrdn olddn:" << ldif.dn() <<
+ " newRdn: " << ldif.newRdn() <<
+ " newSuperior: " << ldif.newSuperior() <<
+ " deloldrdn: " << ldif.delOldRdn() << endl;
+ controlsFromMetaData( &serverctrls, &clientctrls );
+ ldaperr = ldap_rename_s( mLDAP, ldif.dn().utf8(), ldif.newRdn().utf8(),
+ ldif.newSuperior().isEmpty() ? TQCString() : ldif.newSuperior().utf8(),
+ ldif.delOldRdn(), serverctrls, clientctrls );
+
+ FREELDAPMEM;
+ break;
+ case LDIF::Entry_Mod:
+ kdDebug(7125) << "kio_ldap_mod" << endl;
+ if ( lmod ) {
+ controlsFromMetaData( &serverctrls, &clientctrls );
+ ldaperr = ldap_modify_ext_s( mLDAP, ldif.dn().utf8(), lmod,
+ serverctrls, clientctrls );
+ FREELDAPMEM;
+ }
+ break;
+ case LDIF::Entry_Add:
+ kdDebug(7125) << "kio_ldap_add " << ldif.dn() << endl;
+ if ( lmod ) {
+ controlsFromMetaData( &serverctrls, &clientctrls );
+ ldaperr = ldap_add_ext_s( mLDAP, ldif.dn().utf8(), lmod,
+ serverctrls, clientctrls );
+ if ( ldaperr == LDAP_ALREADY_EXISTS && overwrite ) {
+ kdDebug(7125) << ldif.dn() << " already exists, delete first" << endl;
+ ldaperr = ldap_delete_s( mLDAP, ldif.dn().utf8() );
+ if ( ldaperr == LDAP_SUCCESS )
+ ldaperr = ldap_add_ext_s( mLDAP, ldif.dn().utf8(), lmod,
+ serverctrls, clientctrls );
+ }
+ FREELDAPMEM;
+ }
+ break;
+ }
+ if ( ldaperr != LDAP_SUCCESS ) {
+ kdDebug(7125) << "put ldap error: " << ldap_err2string(ldaperr) << endl;
+ LDAPErr( _url );
+ FREELDAPMEM;
+ return;
+ }
+ break;
+ case LDIF::Item:
+ switch ( ldif.entryType() ) {
+ case LDIF::Entry_Mod: {
+ int modtype = 0;
+ switch ( ldif.modType() ) {
+ case LDIF::Mod_None:
+ modtype = 0;
+ break;
+ case LDIF::Mod_Add:
+ modtype = LDAP_MOD_ADD;
+ break;
+ case LDIF::Mod_Replace:
+ modtype = LDAP_MOD_REPLACE;
+ break;
+ case LDIF::Mod_Del:
+ modtype = LDAP_MOD_DELETE;
+ break;
+ }
+ addModOp( &lmod, modtype, ldif.attr(), ldif.val() );
+ break;
+ }
+ case LDIF::Entry_Add:
+ if ( ldif.val().size() > 0 )
+ addModOp( &lmod, 0, ldif.attr(), ldif.val() );
+ break;
+ default:
+ error( ERR_INTERNAL, i18n("The LDIF parser failed.") );
+ FREELDAPMEM;
+ return;
+ }
+ break;
+ case LDIF::Control:
+ addControlOp( &serverctrls, ldif.oid(), ldif.val(), ldif.critical() );
+ break;
+ case LDIF::Err:
+ error( ERR_SLAVE_DEFINED,
+ i18n( "Invalid LDIF file in line %1." ).arg( ldif.lineNo() ) );
+ FREELDAPMEM;
+ return;
+ }
+ } while ( ret != LDIF::MoreData );
+ } while ( result > 0 );
+
+ FREELDAPMEM;
+ finished();
+}
+
+/**
+ * List the contents of a directory.
+ */
+void LDAPProtocol::listDir( const KURL &_url )
+{
+ int ret, ret2, id, id2;
+ unsigned long total=0;
+ char *dn;
+ TQStringList att,saveatt;
+ LDAPMessage *entry,*msg,*entry2,*msg2;
+ LDAPUrl usrc(_url),usrc2;
+ bool critical;
+ bool isSub = ( usrc.extension( "x-dir", critical ) == "sub" );
+
+ kdDebug(7125) << "listDir(" << _url << ")" << endl;
+
+ changeCheck( usrc );
+ if ( !mLDAP ) {
+ finished();
+ return;
+ }
+ usrc2 = usrc;
+
+ saveatt = usrc.attributes();
+ // look up the entries
+ if ( isSub ) {
+ att.append("dn");
+ usrc.setAttributes(att);
+ }
+ if ( _url.query().isEmpty() ) usrc.setScope( LDAPUrl::One );
+
+ if ( (id = asyncSearch( usrc )) == -1 ) {
+ LDAPErr( _url );
+ return;
+ }
+
+ usrc.setAttributes( "" );
+ usrc.setExtension( "x-dir", "base" );
+ // publish the results
+ UDSEntry uds;
+
+ while( true ) {
+ ret = ldap_result( mLDAP, id, 0, NULL, &msg );
+ if ( ret == -1 ) {
+ LDAPErr( _url );
+ return;
+ }
+ if ( ret == LDAP_RES_SEARCH_RESULT ) break;
+ if ( ret != LDAP_RES_SEARCH_ENTRY ) continue;
+ kdDebug(7125) << " ldap_result: " << ret << endl;
+
+ entry = ldap_first_entry( mLDAP, msg );
+ while( entry ) {
+
+ total++;
+ uds.clear();
+
+ dn = ldap_get_dn( mLDAP, entry );
+ kdDebug(7125) << "dn: " << dn << endl;
+ LDAPEntry2UDSEntry( TQString::fromUtf8(dn), uds, usrc );
+ listEntry( uds, false );
+// processedSize( total );
+ kdDebug(7125) << " total: " << total << " " << usrc.prettyURL() << endl;
+
+ // publish the sub-directories (if dirmode==sub)
+ if ( isSub ) {
+ usrc2.setDn( TQString::fromUtf8( dn ) );
+ usrc2.setScope( LDAPUrl::One );
+ usrc2.setAttributes( att );
+ usrc2.setFilter( TQString::null );
+ kdDebug(7125) << "search2 " << dn << endl;
+ if ( (id2 = asyncSearch( usrc2 )) != -1 ) {
+ while ( true ) {
+ kdDebug(7125) << " next result " << endl;
+ ret2 = ldap_result( mLDAP, id2, 0, NULL, &msg2 );
+ if ( ret2 == -1 ) break;
+ if ( ret2 == LDAP_RES_SEARCH_RESULT ) {
+ ldap_msgfree( msg2 );
+ break;
+ }
+ if ( ret2 == LDAP_RES_SEARCH_ENTRY ) {
+ entry2=ldap_first_entry( mLDAP, msg2 );
+ if ( entry2 ) {
+ usrc2.setAttributes( saveatt );
+ usrc2.setFilter( usrc.filter() );
+ LDAPEntry2UDSEntry( TQString::fromUtf8( dn ), uds, usrc2, true );
+ listEntry( uds, false );
+ total++;
+ }
+ ldap_msgfree( msg2 );
+ ldap_abandon( mLDAP, id2 );
+ break;
+ }
+ }
+ }
+ }
+ free( dn );
+
+ entry = ldap_next_entry( mLDAP, entry );
+ }
+ LDAPErr( _url );
+ ldap_msgfree( msg );
+ }
+
+// totalSize( total );
+
+ uds.clear();
+ listEntry( uds, true );
+ // we are done
+ finished();
+}
diff --git a/tdeioslave/ldap/kio_ldap.h b/tdeioslave/ldap/kio_ldap.h
new file mode 100644
index 000000000..f3bd61fe5
--- /dev/null
+++ b/tdeioslave/ldap/kio_ldap.h
@@ -0,0 +1,65 @@
+#ifndef __LDAP_H__
+#define __LDAP_H__
+
+#include <tqstring.h>
+#include <tqvaluelist.h>
+
+#include <tdeio/slavebase.h>
+#include <tdeio/authinfo.h>
+
+#define LDAP_DEPRECATED 1 /* Needed for ldap_simple_bind_s with openldap >= 2.3.x */
+#include <lber.h>
+#include <ldap.h>
+#include <kabc/ldapurl.h>
+
+class LDAPProtocol : public TDEIO::SlaveBase
+{
+ public:
+ LDAPProtocol( const TQCString &protocol, const TQCString &pool, const TQCString &app );
+ virtual ~LDAPProtocol();
+
+ virtual void setHost( const TQString& host, int port,
+ const TQString& user, const TQString& pass );
+
+ virtual void openConnection();
+ virtual void closeConnection();
+
+ virtual void get( const KURL& url );
+ virtual void stat( const KURL& url );
+ virtual void listDir( const KURL& url );
+ virtual void del( const KURL& url, bool isfile );
+ virtual void put( const KURL& url, int permissions, bool overwrite, bool resume );
+
+ int saslInteract( void *in );
+
+ private:
+
+ TQString mHost;
+ int mPort;
+ TQString mUser;
+ TQString mPassword;
+ LDAP *mLDAP;
+ int mVer, mSizeLimit, mTimeLimit;
+ bool mTLS;
+ bool mAuthSASL;
+ TQString mMech,mRealm,mBindName;
+ bool mCancel, mFirstAuth;
+
+ void controlsFromMetaData( LDAPControl ***serverctrls,
+ LDAPControl ***clientctrls );
+ void addControlOp( LDAPControl ***pctrls, const TQString &oid,
+ const TQByteArray &value, bool critical );
+ void addModOp( LDAPMod ***pmods, int mod_type,
+ const TQString &attr, const TQByteArray &value );
+ void LDAPEntry2UDSEntry( const TQString &dn, TDEIO::UDSEntry &entry,
+ const KABC::LDAPUrl &usrc, bool dir=false );
+ int asyncSearch( KABC::LDAPUrl &usrc );
+
+ TQCString LDAPEntryAsLDIF( LDAPMessage *msg );
+ void LDAPErr( const KURL &url, int err = LDAP_SUCCESS );
+ void changeCheck( KABC::LDAPUrl &url );
+
+ void fillAuthInfo( TDEIO::AuthInfo &info );
+};
+
+#endif
diff --git a/tdeioslave/ldap/ldap.protocol b/tdeioslave/ldap/ldap.protocol
new file mode 100644
index 000000000..3e1e77b4b
--- /dev/null
+++ b/tdeioslave/ldap/ldap.protocol
@@ -0,0 +1,17 @@
+[Protocol]
+exec=kio_ldap
+protocol=ldap
+input=none
+output=filesystem
+listing=Name,
+reading=true
+source=true
+writing=true
+#makedir=true
+deleting=true
+#linking=true
+#moving=true
+mimetype=text/plain
+determineMimetypeFromExtension=false
+DocPath=tdeioslave/ldap.html
+Icon=kaddressbook
diff --git a/tdeioslave/ldap/ldaps.protocol b/tdeioslave/ldap/ldaps.protocol
new file mode 100644
index 000000000..1dd927506
--- /dev/null
+++ b/tdeioslave/ldap/ldaps.protocol
@@ -0,0 +1,17 @@
+[Protocol]
+exec=kio_ldap
+protocol=ldaps
+input=none
+output=filesystem
+listing=Name,
+reading=true
+source=true
+writing=true
+#makedir=true
+deleting=true
+#linking=true
+#moving=true
+mimetype=text/plain
+determineMimetypeFromExtension=false
+DocPath=tdeioslave/ldap.html
+Icon=kaddressbook