]>
git.ipfire.org Git - thirdparty/pdns.git/blob - modules/ldapbackend/ldapbackend.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 * originally authored by Norbert Sendetzky
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of version 2 of the GNU General Public License as
8 * published by the Free Software Foundation.
10 * In addition, for the avoidance of any doubt, permission is granted to
11 * link this program with OpenSSL and to (re)distribute the binaries
12 * produced as the result of such linking.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "exceptions.hh"
27 #include "ldapauthenticator_p.hh"
28 #include "ldapbackend.hh"
31 unsigned int ldap_host_index
= 0;
33 LdapBackend::LdapBackend( const string
&suffix
)
45 m_authenticator
= NULL
;
49 m_qlog
= arg().mustDo( "query-logging" );
50 m_default_ttl
= arg().asNum( "default-ttl" );
51 m_myname
= "[LdapBackend]";
53 setArgPrefix( "ldap" + suffix
);
56 m_reconnect_attempts
= getArgAsNum( "reconnect-attempts" );
57 m_list_fcnt
= &LdapBackend::list_simple
;
58 m_lookup_fcnt
= &LdapBackend::lookup_simple
;
59 m_prepare_fcnt
= &LdapBackend::prepare_simple
;
61 if( getArg( "method" ) == "tree" )
63 m_lookup_fcnt
= &LdapBackend::lookup_tree
;
66 if( getArg( "method" ) == "strict" || mustDo( "disable-ptrrecord" ) )
68 m_list_fcnt
= &LdapBackend::list_strict
;
69 m_lookup_fcnt
= &LdapBackend::lookup_strict
;
70 m_prepare_fcnt
= &LdapBackend::prepare_strict
;
73 stringtok( hosts
, getArg( "host" ), ", " );
74 idx
= ldap_host_index
++ % hosts
.size();
77 for( i
= 1; i
< hosts
.size(); i
++ )
79 hoststr
+= " " + hosts
[ ( idx
+ i
) % hosts
.size() ];
82 g_log
<< Logger::Info
<< m_myname
<< " LDAP servers = " << hoststr
<< endl
;
84 m_pldap
= new PowerLDAP( hoststr
.c_str(), LDAP_PORT
, mustDo( "starttls" ), getArgAsNum( "timeout" ) );
85 m_pldap
->setOption( LDAP_OPT_DEREF
, LDAP_DEREF_ALWAYS
);
87 string bindmethod
= getArg( "bindmethod" );
88 if ( bindmethod
== "gssapi" ) {
89 setenv( "KRB5CCNAME", getArg( "krb5-ccache" ).c_str(), 1 );
90 m_authenticator
= new LdapGssapiAuthenticator( getArg( "krb5-keytab" ), getArg( "krb5-ccache" ), getArgAsNum( "timeout" ) );
93 m_authenticator
= new LdapSimpleAuthenticator( getArg( "binddn" ), getArg( "secret" ), getArgAsNum( "timeout" ) );
95 m_pldap
->bind( m_authenticator
);
97 g_log
<< Logger::Notice
<< m_myname
<< " Ldap connection succeeded" << endl
;
100 catch( LDAPTimeout
<
)
102 g_log
<< Logger::Error
<< m_myname
<< " Ldap connection to server failed because of timeout" << endl
;
104 catch( LDAPException
&le
)
106 g_log
<< Logger::Error
<< m_myname
<< " Ldap connection to server failed: " << le
.what() << endl
;
108 catch( std::exception
&e
)
110 g_log
<< Logger::Error
<< m_myname
<< " Caught STL exception: " << e
.what() << endl
;
113 if( m_pldap
!= NULL
) { delete( m_pldap
); }
114 throw( PDNSException( "Unable to connect to ldap server" ) );
119 LdapBackend::~LdapBackend()
122 delete( m_authenticator
);
123 g_log
<< Logger::Notice
<< m_myname
<< " Ldap connection closed" << endl
;
128 bool LdapBackend::reconnect()
130 int attempts
= m_reconnect_attempts
;
131 bool connected
= false;
132 while ( !connected
&& attempts
> 0 ) {
133 g_log
<< Logger::Debug
<< m_myname
<< " Reconnection attempts left: " << attempts
<< endl
;
134 connected
= m_pldap
->connect();
136 Utility::usleep( 250 );
141 m_pldap
->bind( m_authenticator
);
148 bool LdapBackend::list( const DNSName
& target
, int domain_id
, bool include_disabled
)
153 m_qtype
= QType::ANY
;
154 m_axfrqlen
= target
.toStringRootDot().length();
155 m_adomain
= m_adomains
.end(); // skip loops in get() first time
157 return (this->*m_list_fcnt
)( target
, domain_id
);
159 catch( LDAPTimeout
<
)
161 g_log
<< Logger::Warning
<< m_myname
<< " Unable to get zone " << target
<< " from LDAP directory: " << lt
.what() << endl
;
162 throw( DBException( "LDAP server timeout" ) );
164 catch( LDAPNoConnection
&lnc
)
166 g_log
<< Logger::Warning
<< m_myname
<< " Connection to LDAP lost, trying to reconnect" << endl
;
168 this->list( target
, domain_id
);
170 throw PDNSException( "Failed to reconnect to LDAP server" );
172 catch( LDAPException
&le
)
174 g_log
<< Logger::Error
<< m_myname
<< " Unable to get zone " << target
<< " from LDAP directory: " << le
.what() << endl
;
175 throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
177 catch( std::exception
&e
)
179 g_log
<< Logger::Error
<< m_myname
<< " Caught STL exception for target " << target
<< ": " << e
.what() << endl
;
180 throw( DBException( "STL exception" ) );
188 inline bool LdapBackend::list_simple( const DNSName
& target
, int domain_id
)
195 dn
= getArg( "basedn" );
196 qesc
= toLower( m_pldap
->escape( target
.toStringRootDot() ) );
198 // search for SOARecord of target
199 filter
= strbind( ":target:", "&(associatedDomain=" + qesc
+ ")(sOARecord=*)", getArg( "filter-axfr" ) );
200 m_msgid
= m_pldap
->search( dn
, LDAP_SCOPE_SUBTREE
, filter
, (const char**) ldap_attrany
);
201 m_pldap
->getSearchEntry( m_msgid
, m_result
, true );
203 if( m_result
.count( "dn" ) && !m_result
["dn"].empty() )
205 if( !mustDo( "basedn-axfr-override" ) )
207 dn
= m_result
["dn"][0];
209 m_result
.erase( "dn" );
213 filter
= strbind( ":target:", "associatedDomain=*." + qesc
, getArg( "filter-axfr" ) );
214 DLOG( g_log
<< Logger::Debug
<< m_myname
<< " Search = basedn: " << dn
<< ", filter: " << filter
<< endl
);
215 m_msgid
= m_pldap
->search( dn
, LDAP_SCOPE_SUBTREE
, filter
, (const char**) ldap_attrany
);
222 inline bool LdapBackend::list_strict( const DNSName
& target
, int domain_id
)
224 if( target
.isPartOf(DNSName("in-addr.arpa")) || target
.isPartOf(DNSName("ip6.arpa")) )
226 g_log
<< Logger::Warning
<< m_myname
<< " Request for reverse zone AXFR, but this is not supported in strict mode" << endl
;
227 return false; // AXFR isn't supported in strict mode. Use simple mode and additional PTR records
230 return list_simple( target
, domain_id
);
235 void LdapBackend::lookup( const QType
&qtype
, const DNSName
&qname
, DNSPacket
*dnspkt
, int zoneid
)
241 m_adomain
= m_adomains
.end(); // skip loops in get() first time
244 if( m_qlog
) { g_log
.log( "Query: '" + qname
.toStringRootDot() + "|" + qtype
.getName() + "'", Logger::Error
); }
245 (this->*m_lookup_fcnt
)( qtype
, qname
, dnspkt
, zoneid
);
247 catch( LDAPTimeout
<
)
249 g_log
<< Logger::Warning
<< m_myname
<< " Unable to search LDAP directory: " << lt
.what() << endl
;
250 throw( DBException( "LDAP server timeout" ) );
252 catch( LDAPNoConnection
&lnc
)
254 g_log
<< Logger::Warning
<< m_myname
<< " Connection to LDAP lost, trying to reconnect" << endl
;
256 this->lookup( qtype
, qname
, dnspkt
, zoneid
);
258 throw PDNSException( "Failed to reconnect to LDAP server" );
260 catch( LDAPException
&le
)
262 g_log
<< Logger::Error
<< m_myname
<< " Unable to search LDAP directory: " << le
.what() << endl
;
263 throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
265 catch( std::exception
&e
)
267 g_log
<< Logger::Error
<< m_myname
<< " Caught STL exception for qname " << qname
<< ": " << e
.what() << endl
;
268 throw( DBException( "STL exception" ) );
274 void LdapBackend::lookup_simple( const QType
&qtype
, const DNSName
&qname
, DNSPacket
*dnspkt
, int zoneid
)
276 string filter
, attr
, qesc
;
277 const char** attributes
= ldap_attrany
+ 1; // skip associatedDomain
278 const char* attronly
[] = { NULL
, "dNSTTL", "modifyTimestamp", NULL
};
281 qesc
= toLower( m_pldap
->escape( qname
.toStringRootDot() ) );
282 filter
= "associatedDomain=" + qesc
;
284 if( qtype
.getCode() != QType::ANY
)
286 attr
= qtype
.getName() + "Record";
287 filter
= "&(" + filter
+ ")(" + attr
+ "=*)";
288 attronly
[0] = attr
.c_str();
289 attributes
= attronly
;
292 filter
= strbind( ":target:", filter
, getArg( "filter-lookup" ) );
294 DLOG( g_log
<< Logger::Debug
<< m_myname
<< " Search = basedn: " << getArg( "basedn" ) << ", filter: " << filter
<< ", qtype: " << qtype
.getName() << endl
);
295 m_msgid
= m_pldap
->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE
, filter
, attributes
);
300 void LdapBackend::lookup_strict( const QType
&qtype
, const DNSName
&qname
, DNSPacket
*dnspkt
, int zoneid
)
303 vector
<string
> parts
;
304 string filter
, attr
, qesc
;
305 const char** attributes
= ldap_attrany
+ 1; // skip associatedDomain
306 const char* attronly
[] = { NULL
, "dNSTTL", "modifyTimestamp", NULL
};
309 qesc
= toLower( m_pldap
->escape( qname
.toStringRootDot() ) );
310 stringtok( parts
, qesc
, "." );
313 if( parts
.size() == 6 && len
> 13 && qesc
.substr( len
- 13, 13 ) == ".in-addr.arpa" ) // IPv4 reverse lookups
315 filter
= "aRecord=" + ptr2ip4( parts
);
316 attronly
[0] = "associatedDomain";
317 attributes
= attronly
;
319 else if( parts
.size() == 34 && len
> 9 && ( qesc
.substr( len
- 9, 9 ) == ".ip6.arpa" ) ) // IPv6 reverse lookups
321 filter
= "aAAARecord=" + ptr2ip6( parts
);
322 attronly
[0] = "associatedDomain";
323 attributes
= attronly
;
325 else // IPv4 and IPv6 lookups
327 filter
= "associatedDomain=" + qesc
;
328 if( qtype
.getCode() != QType::ANY
)
330 attr
= qtype
.getName() + "Record";
331 filter
= "&(" + filter
+ ")(" + attr
+ "=*)";
332 attronly
[0] = attr
.c_str();
333 attributes
= attronly
;
337 filter
= strbind( ":target:", filter
, getArg( "filter-lookup" ) );
339 DLOG( g_log
<< Logger::Debug
<< m_myname
<< " Search = basedn: " << getArg( "basedn" ) << ", filter: " << filter
<< ", qtype: " << qtype
.getName() << endl
);
340 m_msgid
= m_pldap
->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE
, filter
, attributes
);
345 void LdapBackend::lookup_tree( const QType
&qtype
, const DNSName
&qname
, DNSPacket
*dnspkt
, int zoneid
)
347 string filter
, attr
, qesc
, dn
;
348 const char** attributes
= ldap_attrany
+ 1; // skip associatedDomain
349 const char* attronly
[] = { NULL
, "dNSTTL", "modifyTimestamp", NULL
};
350 vector
<string
> parts
;
353 qesc
= toLower( m_pldap
->escape( qname
.toStringRootDot() ) );
354 filter
= "associatedDomain=" + qesc
;
356 if( qtype
.getCode() != QType::ANY
)
358 attr
= qtype
.getName() + "Record";
359 filter
= "&(" + filter
+ ")(" + attr
+ "=*)";
360 attronly
[0] = attr
.c_str();
361 attributes
= attronly
;
364 filter
= strbind( ":target:", filter
, getArg( "filter-lookup" ) );
366 stringtok( parts
, toLower( qname
.toString() ), "." );
367 for(auto i
= parts
.crbegin(); i
!= parts
.crend(); i
++ )
369 dn
= "dc=" + *i
+ "," + dn
;
372 DLOG( g_log
<< Logger::Debug
<< m_myname
<< " Search = basedn: " << dn
+ getArg( "basedn" ) << ", filter: " << filter
<< ", qtype: " << qtype
.getName() << endl
);
373 m_msgid
= m_pldap
->search( dn
+ getArg( "basedn" ), LDAP_SCOPE_BASE
, filter
, attributes
);
377 inline bool LdapBackend::prepare()
380 m_ttl
= m_default_ttl
;
383 if( m_result
.count( "dNSTTL" ) && !m_result
["dNSTTL"].empty() )
387 m_ttl
= (uint32_t) strtol( m_result
["dNSTTL"][0].c_str(), &endptr
, 10 );
388 if( *endptr
!= '\0' )
390 g_log
<< Logger::Warning
<< m_myname
<< " Invalid time to live for " << m_qname
<< ": " << m_result
["dNSTTL"][0] << endl
;
391 m_ttl
= m_default_ttl
;
393 m_result
.erase( "dNSTTL" );
396 if( m_result
.count( "modifyTimestamp" ) && !m_result
["modifyTimestamp"].empty() )
398 if( ( m_last_modified
= str2tstamp( m_result
["modifyTimestamp"][0] ) ) == 0 )
400 g_log
<< Logger::Warning
<< m_myname
<< " Invalid modifyTimestamp for " << m_qname
<< ": " << m_result
["modifyTimestamp"][0] << endl
;
402 m_result
.erase( "modifyTimestamp" );
405 if( !(this->*m_prepare_fcnt
)() )
410 m_adomain
= m_adomains
.begin();
411 m_attribute
= m_result
.begin();
412 m_value
= m_attribute
->second
.begin();
419 inline bool LdapBackend::prepare_simple()
421 if( !m_axfrqlen
) // request was a normal lookup()
423 m_adomains
.push_back( m_qname
);
425 else // request was a list() for AXFR
427 if( m_result
.count( "associatedDomain" ) )
429 for(auto i
= m_result
["associatedDomain"].begin(); i
!= m_result
["associatedDomain"].end(); i
++ ) {
430 if( i
->size() >= m_axfrqlen
&& i
->substr( i
->size() - m_axfrqlen
, m_axfrqlen
) == m_qname
.toStringRootDot() /* ugh */ ) {
431 m_adomains
.push_back( DNSName(*i
) );
434 m_result
.erase( "associatedDomain" );
443 inline bool LdapBackend::prepare_strict()
445 if( !m_axfrqlen
) // request was a normal lookup()
447 m_adomains
.push_back( m_qname
);
448 if( m_result
.count( "associatedDomain" ) )
450 m_result
["PTRRecord"] = m_result
["associatedDomain"];
451 m_result
.erase( "associatedDomain" );
454 else // request was a list() for AXFR
456 if( m_result
.count( "associatedDomain" ) )
458 for(auto i
= m_result
["associatedDomain"].begin(); i
!= m_result
["associatedDomain"].end(); i
++ ) {
459 if( i
->size() >= m_axfrqlen
&& i
->substr( i
->size() - m_axfrqlen
, m_axfrqlen
) == m_qname
.toStringRootDot() /* ugh */ ) {
460 m_adomains
.push_back( DNSName(*i
) );
463 m_result
.erase( "associatedDomain" );
472 bool LdapBackend::get( DNSResourceRecord
&rr
)
475 vector
<string
> parts
;
476 string attrname
, qstr
;
483 while( m_adomain
!= m_adomains
.end() )
485 while( m_attribute
!= m_result
.end() )
487 attrname
= m_attribute
->first
;
488 qstr
= attrname
.substr( 0, attrname
.length() - 6 ); // extract qtype string from ldap attribute name
489 qt
= const_cast<char*>(toUpper( qstr
).c_str());
491 while( m_value
!= m_attribute
->second
.end() )
493 if(m_qtype
!= qt
&& m_qtype
!= QType::ANY
) {
500 rr
.qname
= *m_adomain
;
502 rr
.last_modified
= m_last_modified
;
503 rr
.content
= *m_value
;
506 DLOG( g_log
<< Logger::Debug
<< m_myname
<< " Record = qname: " << rr
.qname
<< ", qtype: " << (rr
.qtype
).getName() << ", ttl: " << rr
.ttl
<< ", content: " << rr
.content
<< endl
);
511 m_value
= m_attribute
->second
.begin();
514 m_attribute
= m_result
.begin();
515 m_value
= m_attribute
->second
.begin();
518 while( m_pldap
->getSearchEntry( m_msgid
, m_result
, m_getdn
) && prepare() );
521 catch( LDAPTimeout
<
)
523 g_log
<< Logger::Warning
<< m_myname
<< " Search failed: " << lt
.what() << endl
;
524 throw( DBException( "LDAP server timeout" ) );
526 catch( LDAPException
&le
)
528 g_log
<< Logger::Error
<< m_myname
<< " Search failed: " << le
.what() << endl
;
529 throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
531 catch( std::exception
&e
)
533 g_log
<< Logger::Error
<< m_myname
<< " Caught STL exception for " << m_qname
<< ": " << e
.what() << endl
;
534 throw( DBException( "STL exception" ) );
542 void LdapBackend::getUpdatedMasters( vector
<DomainInfo
>* domains
)
546 PowerLDAP::sentry_t result
;
547 const char* attronly
[] = {
554 // First get all domains on which we are master.
555 filter
= strbind( ":target:", "&(SOARecord=*)(PdnsDomainId=*)", getArg( "filter-axfr" ) );
556 msgid
= m_pldap
->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE
, filter
, attronly
);
558 catch( LDAPTimeout
<
)
560 g_log
<< Logger::Warning
<< m_myname
<< " Unable to search LDAP directory: " << lt
.what() << endl
;
561 throw( DBException( "LDAP server timeout" ) );
563 catch( LDAPNoConnection
&lnc
)
565 g_log
<< Logger::Warning
<< m_myname
<< " Connection to LDAP lost, trying to reconnect" << endl
;
567 this->getUpdatedMasters( domains
);
569 throw PDNSException( "Failed to reconnect to LDAP server" );
571 catch( LDAPException
&le
)
573 g_log
<< Logger::Error
<< m_myname
<< " Unable to search LDAP directory: " << le
.what() << endl
;
574 throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
576 catch( std::exception
&e
)
578 throw( DBException( "STL exception" ) );
581 while( m_pldap
->getSearchEntry( msgid
, result
) ) {
582 if( !result
.count( "associatedDomain" ) || result
["associatedDomain"].empty() )
586 if ( !getDomainInfo( DNSName( result
["associatedDomain"][0] ), di
) )
589 if( di
.notified_serial
< di
.serial
)
590 domains
->push_back( di
);
596 void LdapBackend::setNotified( uint32_t id
, uint32_t serial
)
600 PowerLDAP::sresult_t results
;
601 PowerLDAP::sentry_t entry
;
602 const char* attronly
[] = { "associatedDomain", NULL
};
606 // Try to find the notified domain
607 filter
= strbind( ":target:", "PdnsDomainId=" + std::to_string( id
), getArg( "filter-axfr" ) );
608 msgid
= m_pldap
->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE
, filter
, attronly
);
609 m_pldap
->getSearchResults( msgid
, results
, true );
611 catch( LDAPTimeout
<
)
613 g_log
<< Logger::Warning
<< m_myname
<< " Unable to search LDAP directory: " << lt
.what() << endl
;
614 throw( DBException( "LDAP server timeout" ) );
616 catch( LDAPNoConnection
&lnc
)
618 g_log
<< Logger::Warning
<< m_myname
<< " Connection to LDAP lost, trying to reconnect" << endl
;
620 this->setNotified( id
, serial
);
622 throw PDNSException( "Failed to reconnect to LDAP server" );
624 catch( LDAPException
&le
)
626 g_log
<< Logger::Error
<< m_myname
<< " Unable to search LDAP directory: " << le
.what() << endl
;
627 throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
629 catch( std::exception
&e
)
631 throw( DBException( "STL exception" ) );
634 if ( results
.empty() )
635 throw PDNSException( "No results found when trying to update domain notified_serial for ID " + std::to_string( id
) );
637 entry
= results
.front();
638 string dn
= entry
["dn"][0];
639 string serialStr
= std::to_string( serial
);
644 mod
.mod_op
= LDAP_MOD_REPLACE
;
645 mod
.mod_type
= (char*)"PdnsDomainNotifiedSerial";
646 vals
[0] = const_cast<char*>( serialStr
.c_str() );
648 mod
.mod_values
= vals
;
655 m_pldap
->modify( dn
, mods
);
657 catch( LDAPNoConnection
&lnc
)
659 g_log
<< Logger::Warning
<< m_myname
<< " Connection to LDAP lost, trying to reconnect" << endl
;
661 this->setNotified( id
, serial
);
663 throw PDNSException( "Failed to reconnect to LDAP server" );
665 catch( LDAPException
&le
)
667 g_log
<< Logger::Error
<< m_myname
<< " Unable to search LDAP directory: " << le
.what() << endl
;
668 throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
670 catch( std::exception
&e
)
672 throw( DBException( "STL exception" ) );
678 bool LdapBackend::getDomainInfo( const DNSName
& domain
, DomainInfo
& di
, bool getSerial
)
682 PowerLDAP::sentry_t result
;
683 const char* attronly
[] = {
686 "PdnsDomainNotifiedSerial",
687 "PdnsDomainLastCheck",
695 // search for SOARecord of domain
696 filter
= "(&(associatedDomain=" + toLower( m_pldap
->escape( domain
.toStringRootDot() ) ) + ")(SOARecord=*))";
697 m_msgid
= m_pldap
->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE
, filter
, attronly
);
698 m_pldap
->getSearchEntry( m_msgid
, result
);
700 catch( LDAPTimeout
<
)
702 g_log
<< Logger::Warning
<< m_myname
<< " Unable to search LDAP directory: " << lt
.what() << endl
;
703 throw( DBException( "LDAP server timeout" ) );
705 catch( LDAPNoConnection
&lnc
)
707 g_log
<< Logger::Warning
<< m_myname
<< " Connection to LDAP lost, trying to reconnect" << endl
;
709 this->getDomainInfo( domain
, di
);
711 throw PDNSException( "Failed to reconnect to LDAP server" );
713 catch( LDAPException
&le
)
715 g_log
<< Logger::Error
<< m_myname
<< " Unable to search LDAP directory: " << le
.what() << endl
;
716 throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
718 catch( std::exception
&e
)
720 throw( DBException( "STL exception" ) );
723 if( result
.count( "sOARecord" ) && !result
["sOARecord"].empty() )
726 fillSOAData( result
["sOARecord"][0], sd
);
728 if ( result
.count( "PdnsDomainId" ) && !result
["PdnsDomainId"].empty() )
729 di
.id
= std::stoi( result
["PdnsDomainId"][0] );
733 di
.serial
= sd
.serial
;
734 di
.zone
= DNSName(domain
);
736 if( result
.count( "PdnsDomainLastCheck" ) && !result
["PdnsDomainLastCheck"].empty() )
737 di
.last_check
= pdns_stou( result
["PdnsDomainLastCheck"][0] );
741 if ( result
.count( "PdnsDomainNotifiedSerial" ) && !result
["PdnsDomainNotifiedSerial"].empty() )
742 di
.notified_serial
= pdns_stou( result
["PdnsDomainNotifiedSerial"][0] );
744 di
.notified_serial
= 0;
746 if ( result
.count( "PdnsDomainMaster" ) && !result
["PdnsDomainMaster"].empty() ) {
747 for(const auto& m
: result
["PdnsDomainMaster"])
748 di
.masters
.emplace_back(m
, 53);
751 if ( result
.count( "PdnsDomainType" ) && !result
["PdnsDomainType"].empty() ) {
752 string kind
= result
["PdnsDomainType"][0];
753 if ( kind
== "master" )
754 di
.kind
= DomainInfo::Master
;
755 else if ( kind
== "slave" )
756 di
.kind
= DomainInfo::Slave
;
758 di
.kind
= DomainInfo::Native
;
761 di
.kind
= DomainInfo::Native
;
775 class LdapFactory
: public BackendFactory
779 LdapFactory() : BackendFactory( "ldap" ) {}
781 void declareArguments( const string
&suffix
="" )
783 declare( suffix
, "host", "One or more LDAP server with ports or LDAP URIs (separated by spaces)","ldap://127.0.0.1:389/" );
784 declare( suffix
, "starttls", "Use TLS to encrypt connection (unused for LDAP URIs)", "no" );
785 declare( suffix
, "basedn", "Search root in ldap tree (must be set)","" );
786 declare( suffix
, "basedn-axfr-override", "Override base dn for AXFR subtree search", "no" );
787 declare( suffix
, "bindmethod", "Bind method to use (simple or gssapi)", "simple" );
788 declare( suffix
, "binddn", "User dn for non anonymous binds","" );
789 declare( suffix
, "secret", "User password for non anonymous binds", "" );
790 declare( suffix
, "krb5-keytab", "The keytab to use for GSSAPI authentication", "" );
791 declare( suffix
, "krb5-ccache", "The credentials cache used for GSSAPI authentication", "" );
792 declare( suffix
, "timeout", "Seconds before connecting to server fails", "5" );
793 declare( suffix
, "method", "How to search entries (simple, strict or tree)", "simple" );
794 declare( suffix
, "filter-axfr", "LDAP filter for limiting AXFR results", "(:target:)" );
795 declare( suffix
, "filter-lookup", "LDAP filter for limiting IP or name lookups", "(:target:)" );
796 declare( suffix
, "disable-ptrrecord", "Deprecated, use ldap-method=strict instead", "no" );
797 declare( suffix
, "reconnect-attempts", "Number of attempts to re-establish a lost LDAP connection", "5" );
801 DNSBackend
* make( const string
&suffix
="" )
803 return new LdapBackend( suffix
);
819 BackendMakers().report( &factory
);
820 g_log
<< Logger::Info
<< "[ldapbackend] This is the ldap backend version " VERSION
822 << " (" __DATE__
" " __TIME__
")"
824 << " reporting" << endl
;
829 static LdapLoader ldaploader
;