1 #include "exceptions.hh"
2 #include "ldapauthenticator_p.hh"
3 #include "ldapbackend.hh"
8 unsigned int ldap_host_index
= 0;
12 LdapBackend::LdapBackend( const string
&suffix
)
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
);
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();
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" ) );
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
;
75 catch( LDAPTimeout
<
)
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()
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();
111 Utility::usleep( 250 );
116 m_pldap
->bind( m_authenticator
);
123 bool LdapBackend::list( const string
& target
, int domain_id
)
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
<
)
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
;
142 this->list( target
, domain_id
);
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" ) );
162 inline bool LdapBackend::list_simple( const string
& target
, int domain_id
)
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" );
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
);
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
)
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
<
)
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
;
230 this->lookup( qtype
, qname
, dnspkt
, zoneid
);
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
)
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
, "." );
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()
364 m_ttl
= m_default_ttl
;
367 if( m_result
.count( "dNSTTL" ) && !m_result
["dNSTTL"].empty() )
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
)() )
394 m_adomain
= m_adomains
.begin();
395 m_attribute
= m_result
.begin();
396 m_value
= m_attribute
->second
.begin();
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" );
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" );
458 bool LdapBackend::get( DNSResourceRecord
&rr
)
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() )
482 rr
.qname
= *m_adomain
;
485 rr
.last_modified
= m_last_modified
;
487 if( qt
.getCode() == QType::MX
|| qt
.getCode() == QType::SRV
) // Priority, e.g. 10 smtp.example.com
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
;
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
;
507 content
= content
.substr( first
+ 1, content
.length() - first
- 1 );
510 rr
.content
= content
;
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
);
523 m_value
= m_attribute
->second
.begin();
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
<
)
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" ) );
553 void LdapBackend::getUpdatedMasters( vector
<DomainInfo
>* domains
)
557 PowerLDAP::sentry_t result
;
558 const char* attronly
[] = {
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
<
)
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
;
578 this->getUpdatedMasters( domains
);
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() )
597 if ( !getDomainInfo( result
["associatedDomain"][0], di
) )
602 if( di
.notified_serial
< di
.serial
)
603 domains
->push_back( di
);
609 void LdapBackend::setNotified( uint32_t id
, uint32_t serial
)
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
<
)
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
;
633 this->setNotified( id
, serial
);
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
);
657 mod
.mod_op
= LDAP_MOD_REPLACE
;
658 mod
.mod_type
= (char*)"PdnsDomainNotifiedSerial";
659 vals
[0] = const_cast<char*>( serialStr
.c_str() );
661 mod
.mod_values
= vals
;
668 m_pldap
->modify( dn
, mods
);
670 catch( LDAPNoConnection
&lnc
)
672 L
<< Logger::Warning
<< m_myname
<< " Connection to LDAP lost, trying to reconnect" << endl
;
674 this->setNotified( id
, serial
);
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
)
696 PowerLDAP::sentry_t result
;
697 const char* attronly
[] = {
700 "PdnsDomainNotifiedSerial",
701 "PdnsDomainLastCheck",
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
<
)
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
;
723 this->getDomainInfo( domain
, di
);
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() )
740 fillSOAData( result
["sOARecord"][0], sd
);
742 if ( result
.count( "PdnsDomainId" ) && !result
["PdnsDomainId"].empty() )
743 di
.id
= boost::lexical_cast
<int>( result
["PdnsDomainId"][0] );
747 di
.serial
= sd
.serial
;
750 if( result
.count( "PdnsDomainLastCheck" ) && !result
["PdnsDomainLastCheck"].empty() )
751 di
.last_check
= boost::lexical_cast
<time_t>( result
["PdnsDomainLastCheck"][0] );
755 if ( result
.count( "PdnsDomainNotifiedSerial" ) && !result
["PdnsDomainNotifiedSerial"].empty() )
756 di
.notified_serial
= boost::lexical_cast
<uint32_t>( result
["PdnsDomainNotifiedSerial"][0] );
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
;
770 di
.kind
= DomainInfo::Native
;
773 di
.kind
= DomainInfo::Native
;
786 class LdapFactory
: public BackendFactory
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
);
830 BackendMakers().report( &factory
);
831 L
<< Logger::Info
<< " [LdapBackend] This is the ldap module version "VERSION
" ("__DATE__
", "__TIME__
") reporting" << endl
;
836 static LdapLoader ldaploader
;