Add instruction about the use of --libdir
[pdns-ldap-backend/landonf.git] / src / ldapbackend.cc
blobe8307886ee63c379d74afb975c4937b0eadd9295
1 #include "exceptions.hh"
2 #include "ldapauthenticator_p.hh"
3 #include "ldapbackend.hh"
4 #include <cstdlib>
8 unsigned int ldap_host_index = 0;
12 LdapBackend::LdapBackend( const string &suffix )
14 string hoststr;
15 unsigned int i, idx;
16 vector<string> hosts;
18 try
20 m_msgid = 0;
21 m_qname = "";
22 m_pldap = NULL;
23 m_authenticator = NULL;
24 m_qlog = arg().mustDo( "query-logging" );
25 m_default_ttl = arg().asNum( "default-ttl" );
26 m_myname = "[LdapBackend]";
28 setArgPrefix( "ldap" + suffix );
30 m_getdn = false;
31 m_reconnect_attempts = getArgAsNum( "reconnect-attempts" );
32 m_list_fcnt = &LdapBackend::list_simple;
33 m_lookup_fcnt = &LdapBackend::lookup_simple;
34 m_prepare_fcnt = &LdapBackend::prepare_simple;
36 if( getArg( "method" ) == "tree" )
38 m_lookup_fcnt = &LdapBackend::lookup_tree;
41 if( getArg( "method" ) == "strict" || mustDo( "disable-ptrrecord" ) )
43 m_list_fcnt = &LdapBackend::list_strict;
44 m_lookup_fcnt = &LdapBackend::lookup_strict;
45 m_prepare_fcnt = &LdapBackend::prepare_strict;
48 stringtok( hosts, getArg( "host" ), ", " );
49 idx = ldap_host_index++ % hosts.size();
50 hoststr = hosts[idx];
52 for( i = 1; i < hosts.size(); i++ )
54 hoststr += " " + hosts[ ( idx + i ) % hosts.size() ];
57 L << Logger::Info << m_myname << " LDAP servers = " << hoststr << endl;
59 m_pldap = new PowerLDAP( hoststr.c_str(), LDAP_PORT, mustDo( "starttls" ) );
60 m_pldap->setOption( LDAP_OPT_DEREF, LDAP_DEREF_ALWAYS );
62 string bindmethod = getArg( "bindmethod" );
63 if ( bindmethod == "gssapi" ) {
64 setenv( "KRB5CCNAME", getArg( "krb5-ccache" ).c_str(), 1 );
65 m_authenticator = new LdapGssapiAuthenticator( getArg( "krb5-keytab" ), getArg( "krb5-ccache" ), getArgAsNum( "timeout" ) );
67 else {
68 m_authenticator = new LdapSimpleAuthenticator( getArg( "binddn" ), getArg( "secret" ), getArgAsNum( "timeout" ) );
70 m_pldap->bind( m_authenticator );
72 L << Logger::Notice << m_myname << " Ldap connection succeeded" << endl;
73 return;
75 catch( LDAPTimeout &lt )
77 L << Logger::Error << m_myname << " Ldap connection to server failed because of timeout" << endl;
79 catch( LDAPException &le )
81 L << Logger::Error << m_myname << " Ldap connection to server failed: " << le.what() << endl;
83 catch( std::exception &e )
85 L << Logger::Error << m_myname << " Caught STL exception: " << e.what() << endl;
88 if( m_pldap != NULL ) { delete( m_pldap ); }
89 throw( AhuException( "Unable to connect to ldap server" ) );
94 LdapBackend::~LdapBackend()
96 delete( m_pldap );
97 delete( m_authenticator );
98 L << Logger::Notice << m_myname << " Ldap connection closed" << endl;
103 bool LdapBackend::reconnect()
105 int attempts = m_reconnect_attempts;
106 bool connected = false;
107 while ( !connected && attempts > 0 ) {
108 L << Logger::Debug << m_myname << " Reconnection attempts left: " << attempts << endl;
109 connected = m_pldap->connect();
110 if ( !connected )
111 Utility::usleep( 250 );
112 --attempts;
115 if ( connected )
116 m_pldap->bind( m_authenticator );
118 return connected;
123 bool LdapBackend::list( const string& target, int domain_id )
127 m_qname = target;
128 m_axfrqlen = target.length();
129 m_adomain = m_adomains.end(); // skip loops in get() first time
131 return (this->*m_list_fcnt)( target, domain_id );
133 catch( LDAPTimeout &lt )
135 L << Logger::Warning << m_myname << " Unable to get zone " + target + " from LDAP directory: " << lt.what() << endl;
136 throw( DBException( "LDAP server timeout" ) );
138 catch( LDAPNoConnection &lnc )
140 L << Logger::Warning << m_myname << " Connection to LDAP lost, trying to reconnect" << endl;
141 if ( reconnect() )
142 this->list( target, domain_id );
143 else
144 throw AhuException( "Failed to reconnect to LDAP server" );
146 catch( LDAPException &le )
148 L << Logger::Error << m_myname << " Unable to get zone " + target + " from LDAP directory: " << le.what() << endl;
149 throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
151 catch( std::exception &e )
153 L << Logger::Error << m_myname << " Caught STL exception for target " << target << ": " << e.what() << endl;
154 throw( DBException( "STL exception" ) );
157 return false;
162 inline bool LdapBackend::list_simple( const string& target, int domain_id )
164 string dn;
165 string filter;
166 string qesc;
169 dn = getArg( "basedn" );
170 qesc = toLower( m_pldap->escape( target ) );
172 // search for SOARecord of target
173 filter = strbind( ":target:", "&(associatedDomain=" + qesc + ")(sOARecord=*)", getArg( "filter-axfr" ) );
174 m_msgid = m_pldap->search( dn, LDAP_SCOPE_SUBTREE, filter, (const char**) ldap_attrany );
175 m_pldap->getSearchEntry( m_msgid, m_result, true );
177 if( m_result.count( "dn" ) && !m_result["dn"].empty() )
179 if( !mustDo( "basedn-axfr-override" ) )
181 dn = m_result["dn"][0];
183 m_result.erase( "dn" );
186 prepare();
187 filter = strbind( ":target:", "associatedDomain=*." + qesc, getArg( "filter-axfr" ) );
188 DLOG( L << Logger::Debug << m_myname << " Search = basedn: " << dn << ", filter: " << filter << endl );
189 m_msgid = m_pldap->search( dn, LDAP_SCOPE_SUBTREE, filter, (const char**) ldap_attrany );
191 return true;
196 inline bool LdapBackend::list_strict( const string& target, int domain_id )
198 if( target.size() > 13 && target.substr( target.size() - 13, 13 ) == ".in-addr.arpa" ||
199 target.size() > 9 && target.substr( target.size() - 9, 9 ) == ".ip6.arpa" )
201 L << Logger::Warning << m_myname << " Request for reverse zone AXFR, but this is not supported in strict mode" << endl;
202 return false; // AXFR isn't supported in strict mode. Use simple mode and additional PTR records
205 return list_simple( target, domain_id );
210 void LdapBackend::lookup( const QType &qtype, const string &qname, DNSPacket *dnspkt, int zoneid )
214 m_axfrqlen = 0;
215 m_qname = qname;
216 m_adomain = m_adomains.end(); // skip loops in get() first time
218 if( m_qlog ) { L.log( "Query: '" + qname + "|" + qtype.getName() + "'", Logger::Error ); }
219 (this->*m_lookup_fcnt)( qtype, qname, dnspkt, zoneid );
221 catch( LDAPTimeout &lt )
223 L << Logger::Warning << m_myname << " Unable to search LDAP directory: " << lt.what() << endl;
224 throw( DBException( "LDAP server timeout" ) );
226 catch( LDAPNoConnection &lnc )
228 L << Logger::Warning << m_myname << " Connection to LDAP lost, trying to reconnect" << endl;
229 if ( reconnect() )
230 this->lookup( qtype, qname, dnspkt, zoneid );
231 else
232 throw AhuException( "Failed to reconnect to LDAP server" );
234 catch( LDAPException &le )
236 L << Logger::Error << m_myname << " Unable to search LDAP directory: " << le.what() << endl;
237 throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
239 catch( std::exception &e )
241 L << Logger::Error << m_myname << " Caught STL exception for qname " << qname << ": " << e.what() << endl;
242 throw( DBException( "STL exception" ) );
248 void LdapBackend::lookup_simple( const QType &qtype, const string &qname, DNSPacket *dnspkt, int zoneid )
250 string filter, attr, qesc;
251 const char** attributes = ldap_attrany + 1; // skip associatedDomain
252 const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL };
255 qesc = toLower( m_pldap->escape( qname ) );
256 filter = "associatedDomain=" + qesc;
258 if( qtype.getCode() != QType::ANY )
260 attr = qtype.getName() + "Record";
261 filter = "&(" + filter + ")(" + attr + "=*)";
262 attronly[0] = attr.c_str();
263 attributes = attronly;
266 filter = strbind( ":target:", filter, getArg( "filter-lookup" ) );
268 DLOG( L << Logger::Debug << m_myname
269 << " Search = basedn: " << getArg( "basedn" )
270 << ", filter: " << filter << ", qtype: "
271 << qtype.getName() << endl );
272 m_msgid = m_pldap->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE, filter, attributes );
277 void LdapBackend::lookup_strict( const QType &qtype, const string &qname, DNSPacket *dnspkt, int zoneid )
279 int len;
280 vector<string> parts;
281 string filter, attr, qesc;
282 const char** attributes = ldap_attrany + 1; // skip associatedDomain
283 const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL };
286 qesc = toLower( m_pldap->escape( qname ) );
287 stringtok( parts, qesc, "." );
288 len = qesc.length();
290 if( parts.size() == 6 && len > 13 && qesc.substr( len - 13, 13 ) == ".in-addr.arpa" ) // IPv4 reverse lookups
292 filter = "aRecord=" + ptr2ip4( parts );
293 attronly[0] = "associatedDomain";
294 attributes = attronly;
296 else if( parts.size() == 34 && len > 9 && ( qesc.substr( len - 9, 9 ) == ".ip6.arpa" ) ) // IPv6 reverse lookups
298 filter = "aAAARecord=" + ptr2ip6( parts );
299 attronly[0] = "associatedDomain";
300 attributes = attronly;
302 else // IPv4 and IPv6 lookups
304 filter = "associatedDomain=" + qesc;
305 if( qtype.getCode() != QType::ANY )
307 attr = qtype.getName() + "Record";
308 filter = "&(" + filter + ")(" + attr + "=*)";
309 attronly[0] = attr.c_str();
310 attributes = attronly;
314 filter = strbind( ":target:", filter, getArg( "filter-lookup" ) );
316 DLOG( L << Logger::Debug << m_myname
317 << " Search = basedn: " << getArg( "basedn" )
318 << ", filter: " << filter
319 << ", qtype: " << qtype.getName() << endl );
320 m_msgid = m_pldap->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE, filter, attributes );
325 void LdapBackend::lookup_tree( const QType &qtype, const string &qname, DNSPacket *dnspkt, int zoneid )
327 string filter, attr, qesc, dn;
328 const char** attributes = ldap_attrany + 1; // skip associatedDomain
329 const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL };
330 vector<string>::reverse_iterator i;
331 vector<string> parts;
334 qesc = toLower( m_pldap->escape( qname ) );
335 filter = "associatedDomain=" + qesc;
337 if( qtype.getCode() != QType::ANY )
339 attr = qtype.getName() + "Record";
340 filter = "&(" + filter + ")(" + attr + "=*)";
341 attronly[0] = attr.c_str();
342 attributes = attronly;
345 filter = strbind( ":target:", filter, getArg( "filter-lookup" ) );
347 stringtok( parts, toLower( qname ), "." );
348 for( i = parts.rbegin(); i != parts.rend(); i++ )
350 dn = "dc=" + *i + "," + dn;
353 DLOG( L << Logger::Debug << m_myname
354 << " Search = basedn: " << dn + getArg( "basedn" )
355 << ", filter: " << filter
356 << ", qtype: " << qtype.getName() << endl );
357 m_msgid = m_pldap->search( dn + getArg( "basedn" ), LDAP_SCOPE_BASE, filter, attributes );
361 inline bool LdapBackend::prepare()
363 m_adomains.clear();
364 m_ttl = m_default_ttl;
365 m_last_modified = 0;
367 if( m_result.count( "dNSTTL" ) && !m_result["dNSTTL"].empty() )
369 char* endptr;
371 m_ttl = (uint32_t) strtol( m_result["dNSTTL"][0].c_str(), &endptr, 10 );
372 if( *endptr != '\0' )
374 L << Logger::Warning << m_myname << " Invalid time to life for " << m_qname << ": " << m_result["dNSTTL"][0] << endl;
375 m_ttl = m_default_ttl;
377 m_result.erase( "dNSTTL" );
380 if( m_result.count( "modifyTimestamp" ) && !m_result["modifyTimestamp"].empty() )
382 if( ( m_last_modified = str2tstamp( m_result["modifyTimestamp"][0] ) ) == 0 )
384 L << Logger::Warning << m_myname << " Invalid modifyTimestamp for " << m_qname << ": " << m_result["modifyTimestamp"][0] << endl;
386 m_result.erase( "modifyTimestamp" );
389 if( !(this->*m_prepare_fcnt)() )
391 return false;
394 m_adomain = m_adomains.begin();
395 m_attribute = m_result.begin();
396 m_value = m_attribute->second.begin();
398 return true;
403 inline bool LdapBackend::prepare_simple()
405 if( !m_axfrqlen ) // request was a normal lookup()
407 m_adomains.push_back( m_qname );
409 else // request was a list() for AXFR
411 if( m_result.count( "associatedDomain" ) )
413 vector<string>::iterator i;
414 for( i = m_result["associatedDomain"].begin(); i != m_result["associatedDomain"].end(); i++ ) {
415 if( i->size() >= m_axfrqlen && i->substr( i->size() - m_axfrqlen, m_axfrqlen ) == m_qname ) {
416 m_adomains.push_back( *i );
419 m_result.erase( "associatedDomain" );
423 return true;
428 inline bool LdapBackend::prepare_strict()
430 if( !m_axfrqlen ) // request was a normal lookup()
432 m_adomains.push_back( m_qname );
433 if( m_result.count( "associatedDomain" ) )
435 m_result["PTRRecord"] = m_result["associatedDomain"];
436 m_result.erase( "associatedDomain" );
439 else // request was a list() for AXFR
441 if( m_result.count( "associatedDomain" ) )
443 vector<string>::iterator i;
444 for( i = m_result["associatedDomain"].begin(); i != m_result["associatedDomain"].end(); i++ ) {
445 if( i->size() >= m_axfrqlen && i->substr( i->size() - m_axfrqlen, m_axfrqlen ) == m_qname ) {
446 m_adomains.push_back( *i );
449 m_result.erase( "associatedDomain" );
453 return true;
458 bool LdapBackend::get( DNSResourceRecord &rr )
460 QType qt;
461 vector<string> parts;
462 string attrname, content, qstr;
469 while( m_adomain != m_adomains.end() )
471 while( m_attribute != m_result.end() )
473 attrname = m_attribute->first;
474 qstr = attrname.substr( 0, attrname.length() - 6 ); // extract qtype string from ldap attribute name
475 qt = const_cast<char*>(toUpper( qstr ).c_str());
477 while( m_value != m_attribute->second.end() )
479 content = *m_value;
481 rr.qtype = qt;
482 rr.qname = *m_adomain;
483 rr.priority = 0;
484 rr.ttl = m_ttl;
485 rr.last_modified = m_last_modified;
487 if( qt.getCode() == QType::MX || qt.getCode() == QType::SRV ) // Priority, e.g. 10 smtp.example.com
489 char* endptr;
490 string::size_type first = content.find_first_of( " " );
492 if( first == string::npos )
494 L << Logger::Warning << m_myname << " Invalid " << attrname << " without priority for " << m_qname << ": " << content << endl;
495 m_value++;
496 continue;
499 rr.priority = (uint16_t) strtoul( (content.substr( 0, first )).c_str(), &endptr, 10 );
500 if( *endptr != '\0' )
502 L << Logger::Warning << m_myname << " Invalid " << attrname << " without priority for " << m_qname << ": " << content << endl;
503 m_value++;
504 continue;
507 content = content.substr( first + 1, content.length() - first - 1 );
510 rr.content = content;
511 m_value++;
513 DLOG( L << Logger::Debug << m_myname
514 << " Record = qname: " << rr.qname
515 << ", qtype: " << (rr.qtype).getName()
516 << ", priority: " << rr.priority
517 << ", ttl: " << rr.ttl
518 << ", content: " << rr.content << endl );
519 return true;
522 m_attribute++;
523 m_value = m_attribute->second.begin();
525 m_adomain++;
526 m_attribute = m_result.begin();
527 m_value = m_attribute->second.begin();
530 while( m_pldap->getSearchEntry( m_msgid, m_result, m_getdn ) && prepare() );
532 catch( LDAPTimeout &lt )
534 L << Logger::Warning << m_myname << " Search failed: " << lt.what() << endl;
535 throw( DBException( "LDAP server timeout" ) );
537 catch( LDAPException &le )
539 L << Logger::Error << m_myname << " Search failed: " << le.what() << endl;
540 throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
542 catch( std::exception &e )
544 L << Logger::Error << m_myname << " Caught STL exception for " << m_qname << ": " << e.what() << endl;
545 throw( DBException( "STL exception" ) );
548 return false;
553 void LdapBackend::getUpdatedMasters( vector<DomainInfo>* domains )
555 string filter;
556 int msgid;
557 PowerLDAP::sentry_t result;
558 const char* attronly[] = {
559 "associatedDomain",
560 NULL
565 // First get all domains on which we are master.
566 filter = strbind( ":target:", "&(SOARecord=*)(PdnsDomainId=*)", getArg( "filter-axfr" ) );
567 msgid = m_pldap->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE, filter, attronly );
569 catch( LDAPTimeout &lt )
571 L << Logger::Warning << m_myname << " Unable to search LDAP directory: " << lt.what() << endl;
572 throw( DBException( "LDAP server timeout" ) );
574 catch( LDAPNoConnection &lnc )
576 L << Logger::Warning << m_myname << " Connection to LDAP lost, trying to reconnect" << endl;
577 if ( reconnect() )
578 this->getUpdatedMasters( domains );
579 else
580 throw AhuException( "Failed to reconnect to LDAP server" );
582 catch( LDAPException &le )
584 L << Logger::Error << m_myname << " Unable to search LDAP directory: " << le.what() << endl;
585 throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
587 catch( std::exception &e )
589 throw( DBException( "STL exception" ) );
592 while( m_pldap->getSearchEntry( msgid, result ) ) {
593 if( !result.count( "associatedDomain" ) || result["associatedDomain"].empty() )
594 continue;
596 DomainInfo di;
597 if ( !getDomainInfo( result["associatedDomain"][0], di ) )
598 continue;
600 di.backend = this;
602 if( di.notified_serial < di.serial )
603 domains->push_back( di );
609 void LdapBackend::setNotified( uint32_t id, uint32_t serial )
611 string filter;
612 int msgid;
613 PowerLDAP::sresult_t results;
614 PowerLDAP::sentry_t entry;
615 const char* attronly[] = { "associatedDomain", NULL };
619 // Try to find the notified domain
620 filter = strbind( ":target:", "PdnsDomainId=" + boost::lexical_cast<string>( id ), getArg( "filter-axfr" ) );
621 msgid = m_pldap->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE, filter, attronly );
622 m_pldap->getSearchResults( msgid, results, true );
624 catch( LDAPTimeout &lt )
626 L << Logger::Warning << m_myname << " Unable to search LDAP directory: " << lt.what() << endl;
627 throw( DBException( "LDAP server timeout" ) );
629 catch( LDAPNoConnection &lnc )
631 L << Logger::Warning << m_myname << " Connection to LDAP lost, trying to reconnect" << endl;
632 if ( reconnect() )
633 this->setNotified( id, serial );
634 else
635 throw AhuException( "Failed to reconnect to LDAP server" );
637 catch( LDAPException &le )
639 L << Logger::Error << m_myname << " Unable to search LDAP directory: " << le.what() << endl;
640 throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
642 catch( std::exception &e )
644 throw( DBException( "STL exception" ) );
647 if ( results.empty() )
648 throw AhuException( "No results found when trying to update domain notified_serial for ID " + boost::lexical_cast<string>( id ) );
650 entry = results.front();
651 string dn = entry["dn"][0];
652 string serialStr = boost::lexical_cast<string>( serial );
653 LDAPMod *mods[2];
654 LDAPMod mod;
655 char *vals[2];
657 mod.mod_op = LDAP_MOD_REPLACE;
658 mod.mod_type = (char*)"PdnsDomainNotifiedSerial";
659 vals[0] = const_cast<char*>( serialStr.c_str() );
660 vals[1] = NULL;
661 mod.mod_values = vals;
663 mods[0] = &mod;
664 mods[1] = NULL;
668 m_pldap->modify( dn, mods );
670 catch( LDAPNoConnection &lnc )
672 L << Logger::Warning << m_myname << " Connection to LDAP lost, trying to reconnect" << endl;
673 if ( reconnect() )
674 this->setNotified( id, serial );
675 else
676 throw AhuException( "Failed to reconnect to LDAP server" );
678 catch( LDAPException &le )
680 L << Logger::Error << m_myname << " Unable to search LDAP directory: " << le.what() << endl;
681 throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
683 catch( std::exception &e )
685 throw( DBException( "STL exception" ) );
691 bool LdapBackend::getDomainInfo( const string& domain, DomainInfo& di )
693 string filter;
694 SOAData sd;
695 int msgid;
696 PowerLDAP::sentry_t result;
697 const char* attronly[] = {
698 "sOARecord",
699 "PdnsDomainId",
700 "PdnsDomainNotifiedSerial",
701 "PdnsDomainLastCheck",
702 "PdnsDomainMaster",
703 "PdnsDomainType",
704 NULL
709 // search for SOARecord of domain
710 filter = "(&(associatedDomain=" + toLower( m_pldap->escape( domain ) ) + ")(SOARecord=*))";
711 m_msgid = m_pldap->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE, filter, attronly );
712 m_pldap->getSearchEntry( msgid, result );
714 catch( LDAPTimeout &lt )
716 L << Logger::Warning << m_myname << " Unable to search LDAP directory: " << lt.what() << endl;
717 throw( DBException( "LDAP server timeout" ) );
719 catch( LDAPNoConnection &lnc )
721 L << Logger::Warning << m_myname << " Connection to LDAP lost, trying to reconnect" << endl;
722 if ( reconnect() )
723 this->getDomainInfo( domain, di );
724 else
725 throw AhuException( "Failed to reconnect to LDAP server" );
727 catch( LDAPException &le )
729 L << Logger::Error << m_myname << " Unable to search LDAP directory: " << le.what() << endl;
730 throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
732 catch( std::exception &e )
734 throw( DBException( "STL exception" ) );
737 if( result.count( "sOARecord" ) && !result["sOARecord"].empty() )
739 sd.serial = 0;
740 fillSOAData( result["sOARecord"][0], sd );
742 if ( result.count( "PdnsDomainId" ) && !result["PdnsDomainId"].empty() )
743 di.id = boost::lexical_cast<int>( result["PdnsDomainId"][0] );
744 else
745 di.id = 0;
747 di.serial = sd.serial;
748 di.zone = domain;
750 if( result.count( "PdnsDomainLastCheck" ) && !result["PdnsDomainLastCheck"].empty() )
751 di.last_check = boost::lexical_cast<time_t>( result["PdnsDomainLastCheck"][0] );
752 else
753 di.last_check = 0;
755 if ( result.count( "PdnsDomainNotifiedSerial" ) && !result["PdnsDomainNotifiedSerial"].empty() )
756 di.notified_serial = boost::lexical_cast<uint32_t>( result["PdnsDomainNotifiedSerial"][0] );
757 else
758 di.notified_serial = 0;
760 if ( result.count( "PdnsDomainMaster" ) && !result["PdnsDomainMaster"].empty() )
761 di.masters = result["PdnsDomainMaster"];
763 if ( result.count( "PdnsDomainType" ) && !result["PdnsDomainType"].empty() ) {
764 string kind = result["PdnsDomainType"][0];
765 if ( kind == "master" )
766 di.kind = DomainInfo::Master;
767 else if ( kind == "slave" )
768 di.kind = DomainInfo::Slave;
769 else
770 di.kind = DomainInfo::Native;
772 else {
773 di.kind = DomainInfo::Native;
776 return true;
779 return false;
786 class LdapFactory : public BackendFactory
788 public:
790 LdapFactory() : BackendFactory( "ldap" ) {}
792 void declareArguments( const string &suffix="" )
794 declare( suffix, "host", "One or more LDAP server with ports or LDAP URIs (separated by spaces)","ldap://127.0.0.1:389/" );
795 declare( suffix, "starttls", "Use TLS to encrypt connection (unused for LDAP URIs)", "no" );
796 declare( suffix, "basedn", "Search root in ldap tree (must be set)","" );
797 declare( suffix, "basedn-axfr-override", "Override base dn for AXFR subtree search", "no" );
798 declare( suffix, "bindmethod", "Bind method to use (simple or gssapi)", "simple" );
799 declare( suffix, "binddn", "User dn for non anonymous binds","" );
800 declare( suffix, "secret", "User password for non anonymous binds", "" );
801 declare( suffix, "krb5-keytab", "The keytab to use for GSSAPI authentication", "" );
802 declare( suffix, "krb5-ccache", "The credentials cache used for GSSAPI authentication", "" );
803 declare( suffix, "timeout", "Seconds before connecting to server fails", "5" );
804 declare( suffix, "method", "How to search entries (simple, strict or tree)", "simple" );
805 declare( suffix, "filter-axfr", "LDAP filter for limiting AXFR results", "(:target:)" );
806 declare( suffix, "filter-lookup", "LDAP filter for limiting IP or name lookups", "(:target:)" );
807 declare( suffix, "disable-ptrrecord", "Deprecated, use ldap-method=strict instead", "no" );
808 declare( suffix, "reconnect-attempts", "Number of attempts to re-establish a lost LDAP connection", "5" );
812 DNSBackend* make( const string &suffix="" )
814 return new LdapBackend( suffix );
822 class LdapLoader
824 LdapFactory factory;
826 public:
828 LdapLoader()
830 BackendMakers().report( &factory );
831 L << Logger::Info << " [LdapBackend] This is the ldap module version "VERSION" ("__DATE__", "__TIME__") reporting" << endl;
836 static LdapLoader ldaploader;