Prevent potential side effects and use local variables here
[pdns-ldap-backend/landonf.git] / src / powerldap.cc
blob4274cd61003c8b5612c35182b7c48fb69f4da614
1 #include "exceptions.hh"
2 #include "ldapauthenticator.hh"
3 #include "ldaputils.hh"
4 #include "powerldap.hh"
5 #include <pdns/misc.hh>
6 #include <sys/time.h>
10 PowerLDAP::PowerLDAP( const string& hosts, uint16_t port, bool tls )
12 d_ld = 0;
13 d_hosts = hosts;
14 d_port = port;
15 d_tls = tls;
16 ensureConnect();
19 void PowerLDAP::ensureConnect()
21 int err;
23 if(d_ld) {
24 ldap_unbind_ext( d_ld, NULL, NULL );
27 #ifdef HAVE_LDAP_INITIALIZE
28 if( ( err = ldap_initialize( &d_ld, d_hosts.c_str() ) ) != LDAP_SUCCESS )
30 string ldapuris;
31 vector<string> uris;
32 stringtok( uris, d_hosts );
34 for( size_t i = 0; i < uris.size(); i++ )
36 ldapuris += " ldap://" + uris[i];
39 if( ( err = ldap_initialize( &d_ld, ldapuris.c_str() ) ) != LDAP_SUCCESS )
41 throw LDAPException( "Error initializing LDAP connection to '" + ldapuris + ": " + getError( err ) );
44 #else
45 if( ( d_ld = ldap_init( d_hosts.c_str(), d_port ) ) == NULL )
47 throw LDAPException( "Error initializing LDAP connection to '" + d_hosts + "': " + string( strerror( errno ) ) );
49 #endif
51 int protocol = LDAP_VERSION3;
52 if( ldap_set_option( d_ld, LDAP_OPT_PROTOCOL_VERSION, &protocol ) != LDAP_OPT_SUCCESS )
54 protocol = LDAP_VERSION2;
55 if( ldap_set_option( d_ld, LDAP_OPT_PROTOCOL_VERSION, &protocol ) != LDAP_OPT_SUCCESS )
57 ldap_unbind_ext( d_ld, NULL, NULL );
58 throw LDAPException( "Couldn't set protocol version to LDAPv3 or LDAPv2" );
62 if( d_tls && ( err = ldap_start_tls_s( d_ld, NULL, NULL ) ) != LDAP_SUCCESS )
64 ldap_unbind_ext( d_ld, NULL, NULL );
65 throw LDAPException( "Couldn't perform STARTTLS: " + getError( err ) );
70 PowerLDAP::~PowerLDAP()
72 ldap_unbind_ext( d_ld, NULL, NULL );
76 bool PowerLDAP::connect()
78 try
80 ensureConnect();
81 return true;
83 catch( LDAPException &le )
85 return false;
90 void PowerLDAP::setOption( int option, int value )
92 ldapSetOption( d_ld, option, (void*) &value );
96 void PowerLDAP::getOption( int option, int *value )
98 ldapGetOption( d_ld, option, (void*) value );
102 void PowerLDAP::bind( LdapAuthenticator* authenticator )
104 if ( !authenticator->authenticate( d_ld ) )
105 throw LDAPException( "Failed to bind to LDAP server: " + authenticator->getError() );
109 void PowerLDAP::bind( const string& ldapbinddn, const string& ldapsecret, int method, int timeout )
111 int msgid;
113 #ifdef HAVE_LDAP_SASL_BIND
114 int rc;
115 struct berval passwd;
117 passwd.bv_val = (char *)ldapsecret.c_str();
118 passwd.bv_len = strlen( passwd.bv_val );
120 if( ( rc = ldap_sasl_bind( d_ld, ldapbinddn.c_str(), LDAP_SASL_SIMPLE, &passwd, NULL, NULL, &msgid ) ) != LDAP_SUCCESS )
122 throw LDAPException( "Failed to bind to LDAP server: " + getError( rc ) );
124 #else
125 if( ( msgid = ldap_bind( d_ld, ldapbinddn.c_str(), ldapsecret.c_str(), method ) ) == -1 )
127 throw LDAPException( "Failed to bind to LDAP server: " + getError( msgid ) );
129 #endif
131 waitResult( msgid, timeout, NULL );
136 * Deprecated, use PowerLDAP::bind() instead
139 void PowerLDAP::simpleBind( const string& ldapbinddn, const string& ldapsecret )
141 this->bind( ldapbinddn, ldapsecret, LDAP_AUTH_SIMPLE, 30 );
145 void PowerLDAP::modify( const string &dn, LDAPMod *mods[], LDAPControl **scontrols, LDAPControl **ccontrols )
147 int rc;
149 rc = ldap_modify_ext_s( d_ld, dn.c_str(), mods, scontrols, ccontrols );
150 if ( rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR )
151 throw LDAPNoConnection();
152 else if ( rc != LDAP_SUCCESS )
153 throw LDAPException( "Error modifying LDAP entry " + dn + ": " + getError( rc ) );
157 int PowerLDAP::search( const string& base, int scope, const string& filter, const char** attr )
159 int msgid, rc;
160 bool finished = false;
162 while ( !m_results.empty() ) {
163 ldap_msgfree( m_results.front() );
164 m_results.pop_front();
167 rc = ldap_search_ext( d_ld, base.c_str(), scope, filter.c_str(), const_cast<char**> (attr), 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid );
168 if ( rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR )
169 throw LDAPNoConnection();
170 else if ( rc != LDAP_SUCCESS )
171 throw LDAPException( "Starting LDAP search: " + getError( rc ) );
173 while ( !finished ) {
174 LDAPMessage *result = NULL;
175 int i = waitResult( msgid, 5, &result );
176 switch ( i ) {
177 case -1:
178 int err_code;
179 ldapGetOption( d_ld, LDAP_OPT_ERROR_NUMBER, &err_code );
180 if ( err_code == LDAP_SERVER_DOWN || err_code == LDAP_CONNECT_ERROR )
181 throw LDAPNoConnection();
182 else
183 throw LDAPException( "PowerLDAP::search(): Error waiting for LDAP result: " + getError( err_code ) );
184 break;
185 case 0:
186 throw LDAPTimeout();
187 break;
188 case LDAP_RES_SEARCH_REFERENCE:
189 ldap_msgfree( result );
190 break;
191 case LDAP_RES_SEARCH_RESULT:
192 finished = true;
193 ldap_msgfree( result );
194 break;
195 case LDAP_RES_SEARCH_ENTRY:
196 m_results.push_back( result );
197 break;
201 return msgid;
206 * Function waits for a result, returns its type and optionally stores the result.
207 * If the result is returned, the caller is responsible for freeing it with
208 * ldap_msgfree!
211 int PowerLDAP::waitResult( int msgid, int timeout, LDAPMessage** result )
213 return ldapWaitResult( d_ld, msgid, timeout, result );
217 bool PowerLDAP::getSearchEntry( int msgid, sentry_t& entry, bool dn, int timeout )
219 int i;
220 char* attr;
221 BerElement* ber;
222 struct berval** berval;
223 vector<string> values;
224 LDAPMessage* result;
225 LDAPMessage* object;
228 if ( m_results.empty() )
229 return false;
231 result = m_results.front();
232 m_results.pop_front();
234 if( ( object = ldap_first_entry( d_ld, result ) ) == NULL )
236 ldap_msgfree( result );
237 throw LDAPException( "Couldn't get first result entry: " + getError() );
240 entry.clear();
242 if( dn )
244 attr = ldap_get_dn( d_ld, object );
245 values.push_back( string( attr ) );
246 ldap_memfree( attr );
247 entry["dn"] = values;
250 if( ( attr = ldap_first_attribute( d_ld, object, &ber ) ) != NULL )
254 if( ( berval = ldap_get_values_len( d_ld, object, attr ) ) != NULL )
256 values.clear();
257 for( i = 0; i < ldap_count_values_len( berval ); i++ )
259 values.push_back( berval[i]->bv_val ); // use berval[i]->bv_len for non string values?
262 entry[attr] = values;
263 ldap_value_free_len( berval );
265 ldap_memfree( attr );
267 while( ( attr = ldap_next_attribute( d_ld, object, ber ) ) != NULL );
269 ber_free( ber, 0 );
272 ldap_msgfree( result );
273 return true;
277 void PowerLDAP::getSearchResults( int msgid, sresult_t& result, bool dn, int timeout )
279 sentry_t entry;
281 result.clear();
282 while( getSearchEntry( msgid, entry, dn, timeout ) )
284 result.push_back( entry );
289 const string PowerLDAP::getError( int rc )
291 return ldapGetError( d_ld, rc );
295 const string PowerLDAP::escape( const string& str )
297 string a;
298 string::const_iterator i;
300 for( i = str.begin(); i != str.end(); i++ )
302 if( *i == '*' || *i == '\\' ) {
303 a += '\\';
305 a += *i;
308 return a;