KLDAP Library
ldapconnection.cpp
00001 /* 00002 This file is part of libkldap. 00003 Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "ldapconnection.h" 00022 #include "ldapdefs.h" 00023 #include "kldap_config.h" // SASL2_FOUND, LDAP_FOUND 00024 00025 #include <stdlib.h> 00026 #include <klocale.h> 00027 #include <kdebug.h> 00028 00029 #ifdef SASL2_FOUND 00030 #include <sasl/sasl.h> 00031 static sasl_callback_t callbacks[] = { 00032 { SASL_CB_ECHOPROMPT, NULL, NULL }, 00033 { SASL_CB_NOECHOPROMPT, NULL, NULL }, 00034 { SASL_CB_GETREALM, NULL, NULL }, 00035 { SASL_CB_USER, NULL, NULL }, 00036 { SASL_CB_AUTHNAME, NULL, NULL }, 00037 { SASL_CB_PASS, NULL, NULL }, 00038 { SASL_CB_CANON_USER, NULL, NULL }, 00039 { SASL_CB_LIST_END, NULL, NULL } 00040 }; 00041 00042 static bool ldapoperation_sasl_initialized = false; 00043 #endif 00044 00045 #ifdef LDAP_FOUND 00046 # ifndef HAVE_WINLDAP_H 00047 # include <lber.h> 00048 # include <ldap.h> 00049 #else 00050 # include <w32-ldap-help.h> 00051 #endif // HAVE_WINLDAP_H 00052 00053 #ifndef LDAP_OPT_SUCCESS 00054 #define LDAP_OPT_SUCCESS 0 00055 #endif 00056 00057 #endif 00058 00059 using namespace KLDAP; 00060 00061 class LdapConnection::LdapConnectionPrivate 00062 { 00063 public: 00064 LdapConnectionPrivate(); 00065 LdapServer mServer; 00066 QString mConnectionError; 00067 00068 #ifdef LDAP_FOUND 00069 LDAP *mLDAP; 00070 #else 00071 void *mLDAP; 00072 #endif 00073 #ifdef SASL2_FOUND 00074 sasl_conn_t *mSASLconn; 00075 #else 00076 void *mSASLconn; 00077 #endif 00078 00079 }; 00080 00081 LdapConnection::LdapConnectionPrivate::LdapConnectionPrivate() 00082 { 00083 mSASLconn = 0; 00084 #ifdef SASL2_FOUND 00085 if ( !ldapoperation_sasl_initialized ) { 00086 sasl_client_init(NULL); 00087 ldapoperation_sasl_initialized = true; 00088 } 00089 #endif 00090 } 00091 00092 LdapConnection::LdapConnection() 00093 : d( new LdapConnectionPrivate ) 00094 { 00095 d->mLDAP = 0; 00096 } 00097 00098 LdapConnection::LdapConnection( const LdapUrl &url ) 00099 : d( new LdapConnectionPrivate ) 00100 { 00101 d->mLDAP = 0; 00102 setUrl( url ); 00103 } 00104 00105 LdapConnection::LdapConnection( const LdapServer &server ) 00106 : d( new LdapConnectionPrivate ) 00107 { 00108 d->mLDAP = 0; 00109 setServer( server ); 00110 } 00111 00112 LdapConnection::~LdapConnection() 00113 { 00114 close(); 00115 delete d; 00116 } 00117 00118 void LdapConnection::setUrl( const LdapUrl &url ) 00119 { 00120 d->mServer.setUrl( url ); 00121 } 00122 00123 void LdapConnection::setServer( const LdapServer &server ) 00124 { 00125 d->mServer = server; 00126 } 00127 00128 const LdapServer &LdapConnection::server() const 00129 { 00130 return d->mServer; 00131 } 00132 00133 void *LdapConnection::handle() const 00134 { 00135 return (void *)d->mLDAP; 00136 } 00137 00138 void *LdapConnection::saslHandle() const 00139 { 00140 return (void *)d->mSASLconn; 00141 } 00142 00143 QString LdapConnection::errorString( int code ) 00144 { 00145 //No translated error messages yet 00146 #ifdef LDAP_FOUND 00147 return QString::fromUtf8( ldap_err2string( code ) ); 00148 switch ( code ) { 00149 case LDAP_OPERATIONS_ERROR: 00150 return i18n( "LDAP Operations error" ); 00151 //FIXME: 00152 /* add the LDAP error codes */ 00153 } 00154 #else 00155 return i18n( "No LDAP Support..." ); 00156 #endif 00157 } 00158 00159 QString LdapConnection::saslErrorString() const 00160 { 00161 #ifdef SASL2_FOUND 00162 const char *str; 00163 str = sasl_errdetail( d->mSASLconn ); 00164 return QString::fromLocal8Bit( str ); 00165 #else 00166 return i18n( "SASL support is not available. Please recompile libkldap with the " 00167 "Cyrus-SASL (or compatible) client libraries, or complain to your " 00168 "distribution packagers." ); 00169 #endif 00170 } 00171 00172 QString LdapConnection::connectionError() const 00173 { 00174 return d->mConnectionError; 00175 } 00176 00177 #ifdef LDAP_FOUND 00178 int LdapConnection::getOption( int option, void *value ) const 00179 { 00180 Q_ASSERT( d->mLDAP ); 00181 return ldap_get_option( d->mLDAP, option, value ); 00182 } 00183 00184 int LdapConnection::setOption( int option, void *value ) 00185 { 00186 Q_ASSERT( d->mLDAP ); 00187 return ldap_set_option( d->mLDAP, option, value ); 00188 } 00189 00190 int LdapConnection::ldapErrorCode() const 00191 { 00192 Q_ASSERT( d->mLDAP ); 00193 int err; 00194 ldap_get_option( d->mLDAP, LDAP_OPT_ERROR_NUMBER, &err ); 00195 return err; 00196 } 00197 00198 QString LdapConnection::ldapErrorString() const 00199 { 00200 Q_ASSERT( d->mLDAP ); 00201 char *errmsg; 00202 ldap_get_option( d->mLDAP, LDAP_OPT_ERROR_STRING, &errmsg ); 00203 QString msg = QString::fromLocal8Bit( errmsg ); 00204 free( errmsg ); 00205 return msg; 00206 } 00207 00208 bool LdapConnection::setSizeLimit( int sizelimit ) 00209 { 00210 Q_ASSERT( d->mLDAP ); 00211 kDebug() << "sizelimit:" << sizelimit; 00212 if ( setOption( LDAP_OPT_SIZELIMIT, &sizelimit ) != LDAP_OPT_SUCCESS ) { 00213 return false; 00214 } 00215 return true; 00216 } 00217 00218 int LdapConnection::sizeLimit() const 00219 { 00220 Q_ASSERT( d->mLDAP ); 00221 int sizelimit; 00222 if ( getOption( LDAP_OPT_SIZELIMIT, &sizelimit ) != LDAP_OPT_SUCCESS ) { 00223 return -1; 00224 } 00225 return sizelimit; 00226 } 00227 00228 bool LdapConnection::setTimeLimit( int timelimit ) 00229 { 00230 Q_ASSERT( d->mLDAP ); 00231 kDebug() << "timelimit:" << timelimit; 00232 if ( setOption( LDAP_OPT_TIMELIMIT, &timelimit ) != LDAP_OPT_SUCCESS ) { 00233 return false; 00234 } 00235 return true; 00236 } 00237 00238 int LdapConnection::timeLimit() const 00239 { 00240 Q_ASSERT( d->mLDAP ); 00241 int timelimit; 00242 if ( getOption( LDAP_OPT_TIMELIMIT, &timelimit ) != LDAP_OPT_SUCCESS ) { 00243 return -1; 00244 } 00245 return timelimit; 00246 } 00247 00248 int LdapConnection::connect() 00249 { 00250 int ret; 00251 QString url; 00252 if ( d->mLDAP ) { 00253 close(); 00254 } 00255 00256 int version = d->mServer.version(); 00257 int timeout = d->mServer.timeout(); 00258 00259 url = d->mServer.security() == LdapServer::SSL ? "ldaps" : "ldap"; 00260 url += "://"; 00261 url += d->mServer.host(); 00262 url += ':'; 00263 url += QString::number( d->mServer.port() ); 00264 kDebug() << "ldap url:" << url; 00265 #ifdef HAVE_LDAP_INITIALIZE 00266 ret = ldap_initialize( &d->mLDAP, url.toLatin1() ); 00267 #else 00268 d->mLDAP = ldap_init( d->mServer.host().toLatin1().data(), d->mServer.port() ); 00269 if ( d->mLDAP == 0 ) { 00270 ret = -1; 00271 } else { 00272 ret = LDAP_SUCCESS; 00273 } 00274 #endif 00275 if ( ret != LDAP_SUCCESS ) { 00276 d->mConnectionError = i18n( "An error occurred during the connection initialization phase." ); 00277 return ret; 00278 } 00279 00280 kDebug() << "setting version to:" << version; 00281 if ( setOption( LDAP_OPT_PROTOCOL_VERSION, &version ) != LDAP_OPT_SUCCESS ) { 00282 ret = ldapErrorCode(); 00283 d->mConnectionError = i18n( "Cannot set protocol version to %1.", version ); 00284 close(); 00285 return ret; 00286 } 00287 00288 #if defined(LDAP_OPT_TIMEOUT) 00289 kDebug() << "setting timeout to:" << timeout; 00290 00291 if ( timeout ) { 00292 if ( setOption( LDAP_OPT_TIMEOUT, &timeout ) != LDAP_OPT_SUCCESS ) { 00293 ret = ldapErrorCode(); 00294 d->mConnectionError = i18np( "Cannot set timeout to %1 second.", 00295 "Cannot set timeout to %1 seconds.", 00296 timeout ); 00297 close(); 00298 return ret; 00299 } 00300 } 00301 #endif 00302 00303 //FIXME: accessing to certificate handling would be good 00304 kDebug() << "setting security to:" << d->mServer.security(); 00305 if ( d->mServer.security() == LdapServer::TLS ) { 00306 kDebug() << "start TLS"; 00307 #ifdef HAVE_LDAP_START_TLS_S 00308 if ( ( ret = ldap_start_tls_s( d->mLDAP, NULL, NULL ) ) != LDAP_SUCCESS ) { 00309 d->mConnectionError = ldapErrorString(); 00310 close(); 00311 return ret; 00312 } 00313 #else 00314 close(); 00315 d->mConnectionError = i18n( "TLS support not available in the LDAP client libraries." ); 00316 return -1; 00317 #endif 00318 } 00319 00320 kDebug() << "setting sizelimit to:" << d->mServer.sizeLimit(); 00321 if ( d->mServer.sizeLimit() ) { 00322 if ( !setSizeLimit( d->mServer.sizeLimit() ) ) { 00323 ret = ldapErrorCode(); 00324 close(); 00325 d->mConnectionError = i18n( "Cannot set size limit." ); 00326 return ret; 00327 } 00328 } 00329 00330 kDebug() << "setting timelimit to:" << d->mServer.timeLimit(); 00331 if ( d->mServer.timeLimit() ) { 00332 if ( !setTimeLimit( d->mServer.timeLimit() ) ) { 00333 ret = ldapErrorCode(); 00334 close(); 00335 d->mConnectionError = i18n( "Cannot set time limit." ); 00336 return ret; 00337 } 00338 } 00339 00340 #ifdef SASL2_FOUND 00341 kDebug() << "initializing SASL client"; 00342 int saslresult = sasl_client_new( "ldap", d->mServer.host().toLatin1(), 00343 0, 0, callbacks, 0, &d->mSASLconn ); 00344 if ( saslresult != SASL_OK ) { 00345 d->mConnectionError = i18n( "Cannot initialize the SASL client." ); 00346 return KLDAP_SASL_ERROR; 00347 } 00348 #endif 00349 00350 return 0; 00351 } 00352 00353 void LdapConnection::close() 00354 { 00355 if ( d->mLDAP ) { 00356 #ifdef HAVE_LDAP_UNBIND_EXT 00357 ldap_unbind_ext( d->mLDAP, 0, 0 ); 00358 #else 00359 ldap_unbind( d->mLDAP ); 00360 #endif 00361 } 00362 d->mLDAP = 0; 00363 #ifdef SASL2_FOUND 00364 if ( d->mSASLconn ) { 00365 sasl_dispose( &d->mSASLconn ); 00366 d->mSASLconn = 0; 00367 } 00368 #endif 00369 kDebug() << "connection closed!"; 00370 } 00371 #else //LDAP_FOUND 00372 00373 int LdapConnection::getOption( int option, void *value ) const 00374 { 00375 kError() << "No LDAP support..."; 00376 return -1; 00377 } 00378 00379 int LdapConnection::setOption( int option, void *value ) 00380 { 00381 kError() << "No LDAP support..."; 00382 return -1; 00383 } 00384 00385 int LdapConnection::ldapErrorCode() const 00386 { 00387 kError() << "No LDAP support..."; 00388 return -1; 00389 } 00390 00391 QString LdapConnection::ldapErrorString() const 00392 { 00393 kError() << "No LDAP support..."; 00394 return QString(); 00395 } 00396 00397 bool LdapConnection::setSizeLimit( int sizelimit ) 00398 { 00399 kError() << "No LDAP support..."; 00400 return false; 00401 } 00402 00403 int LdapConnection::sizeLimit() const 00404 { 00405 kError() << "No LDAP support..."; 00406 return -1; 00407 } 00408 00409 bool LdapConnection::setTimeLimit( int timelimit ) 00410 { 00411 kError() << "No LDAP support..."; 00412 return false; 00413 } 00414 00415 int LdapConnection::timeLimit() const 00416 { 00417 kError() << "No LDAP support..."; 00418 return -1; 00419 } 00420 00421 int LdapConnection::connect( ) 00422 { 00423 d->mConnectionError = 00424 i18n( "LDAP support not compiled in. Please recompile libkldap with the " 00425 "OpenLDAP (or compatible) client libraries, or complain to your " 00426 "distribution packagers." ); 00427 kError() << "No LDAP support..."; 00428 return -1; 00429 } 00430 00431 void LdapConnection::close() 00432 { 00433 kError() << "No LDAP support..."; 00434 } 00435 00436 #endif