1 #include "exceptions.hh"
2 #include "ldapauthenticator.hh"
3 #include "ldaputils.hh"
4 #include "powerldap.hh"
5 #include <pdns/misc.hh>
10 PowerLDAP::PowerLDAP( const string
& hosts
, uint16_t port
, bool tls
)
19 void PowerLDAP::ensureConnect()
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
)
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
) );
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
) ) );
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()
83 catch( LDAPException
&le
)
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
)
113 #ifdef HAVE_LDAP_SASL_BIND
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
) );
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
) );
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
)
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
)
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
);
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();
183 throw LDAPException( "PowerLDAP::search(): Error waiting for LDAP result: " + getError( err_code
) );
188 case LDAP_RES_SEARCH_REFERENCE
:
189 ldap_msgfree( result
);
191 case LDAP_RES_SEARCH_RESULT
:
193 ldap_msgfree( result
);
195 case LDAP_RES_SEARCH_ENTRY
:
196 m_results
.push_back( result
);
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
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
)
222 struct berval
** berval
;
223 vector
<string
> values
;
228 if ( m_results
.empty() )
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() );
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
)
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
);
272 ldap_msgfree( result
);
277 void PowerLDAP::getSearchResults( int msgid
, sresult_t
& result
, bool dn
, int timeout
)
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
)
298 string::const_iterator i
;
300 for( i
= str
.begin(); i
!= str
.end(); i
++ )
302 if( *i
== '*' || *i
== '\\' ) {