2 * PowerDNS LDAP Backend
3 * Copyright (C) 2011 Grégory Oestreicher <greg@kamago.net>
4 * Copyright (C) 2003-2007 Norbert Sendetzky <norbert@linuxnetworks.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <pdns/logger.hh>
22 #include "ldapauthenticator_p.hh"
23 #include "ldaputils.hh"
25 /*****************************
27 * LdapSimpleAuthenticator
29 ****************************/
31 LdapSimpleAuthenticator::LdapSimpleAuthenticator( const std::string
& dn
, const std::string
& pw
, int tmout
)
32 : binddn( dn
), bindpw( pw
), timeout( tmout
)
36 bool LdapSimpleAuthenticator::authenticate( LDAP
*conn
)
40 #ifdef HAVE_LDAP_SASL_BIND
44 passwd
.bv_val
= (char *)bindpw
.c_str();
45 passwd
.bv_len
= strlen( passwd
.bv_val
);
47 if( ( rc
= ldap_sasl_bind( conn
, binddn
.c_str(), LDAP_SASL_SIMPLE
, &passwd
, NULL
, NULL
, &msgid
) ) != LDAP_SUCCESS
)
49 fillLastError( conn
, rc
);
53 if( ( msgid
= ldap_bind( conn
, binddn
.c_str(), bindpw
.c_str(), LDAP_AUTH_SIMPLE
) ) == -1 )
55 fillLastError( conn
, msgid
);
60 ldapWaitResult( conn
, msgid
, timeout
, NULL
);
64 std::string
LdapSimpleAuthenticator::getError() const
69 void LdapSimpleAuthenticator::fillLastError( LDAP
* conn
, int code
)
71 lastError
= ldapGetError( conn
, code
);
74 /*****************************
76 * LdapGssapiAuthenticator
78 ****************************/
80 static int ldapGssapiAuthenticatorSaslInteractCallback( LDAP
*conn
, unsigned flags
, void *defaults
, void *in
)
85 LdapGssapiAuthenticator::LdapGssapiAuthenticator( const std::string
& kt
, const std::string
&ccache
, int tmout
)
86 : keytabFile( kt
), cCacheFile( ccache
), timeout( tmout
)
90 bool LdapGssapiAuthenticator::authenticate( LDAP
*conn
)
92 Logger
L( "LDAP GSSAPI" );
93 int code
= attemptAuth( conn
);
98 else if ( code
== -2 ) {
99 // Here it may be possible to retry after obtainting a fresh ticket
100 L
<<Logger::Debug
<< "No TGT found, trying to acquire a new one" << std::endl
;
103 if ( attemptAuth( conn
) != 0 ) {
104 L
<<Logger::Error
<< "Failed to acquire a TGT" << std::endl
;
112 std::string
LdapGssapiAuthenticator::getError() const
117 int LdapGssapiAuthenticator::attemptAuth( LDAP
*conn
)
119 Logger
L( "LDAP GSSAPI" );
120 // Create SASL defaults
121 SaslDefaults defaults
;
122 char *ldapOption
= 0;
124 ldap_get_option( conn
, LDAP_OPT_X_SASL_MECH
, ldapOption
);
126 defaults
.mech
= std::string( "GSSAPI" );
128 defaults
.mech
= std::string( ldapOption
);
129 ldap_memfree( ldapOption
);
131 ldap_get_option( conn
, LDAP_OPT_X_SASL_REALM
, ldapOption
);
133 defaults
.realm
= std::string( ldapOption
);
134 ldap_memfree( ldapOption
);
136 ldap_get_option( conn
, LDAP_OPT_X_SASL_AUTHCID
, ldapOption
);
138 defaults
.authcid
= std::string( ldapOption
);
139 ldap_memfree( ldapOption
);
141 ldap_get_option( conn
, LDAP_OPT_X_SASL_AUTHZID
, ldapOption
);
143 defaults
.authzid
= std::string( ldapOption
);
144 ldap_memfree( ldapOption
);
146 // And now try to bind
147 int rc
= ldap_sasl_interactive_bind_s( conn
, "", defaults
.mech
.c_str(),
148 NULL
, NULL
, LDAP_SASL_QUIET
,
149 ldapGssapiAuthenticatorSaslInteractCallback
, &defaults
);
150 L
<<Logger::Debug
<< "ldap_sasl_interactive_bind_s returned " << rc
<< std::endl
;
152 if ( rc
== LDAP_LOCAL_ERROR
) {
153 // This may mean that the ticket has expired, so let the caller know
154 lastError
= ldapGetError( conn
, rc
);
157 else if ( rc
!= LDAP_SUCCESS
) {
158 lastError
= ldapGetError( conn
, rc
);
165 int LdapGssapiAuthenticator::updateTgt()
167 Logger
L( "LDAP GSSAPI" );
168 krb5_error_code code
;
169 krb5_context context
;
170 krb5_creds credentials
;
172 krb5_principal principal
;
174 krb5_get_init_creds_opt
*options
;
176 if ( ( code
= krb5_init_context( &context
) ) != 0 ) {
177 L
<<Logger::Error
<< "Failed to init krb5 context" << std::endl
;
181 if ( !keytabFile
.empty() ) {
182 std::string
keytabStr( "FILE:" + keytabFile
);
183 code
= krb5_kt_resolve( context
, keytabStr
.c_str(), &keytab
);
186 code
= krb5_kt_default( context
, &keytab
);
190 L
<<Logger::Error
<< "krb5 error: " << std::string( krb5_get_error_message( context
, code
) ) << std::endl
;
194 // Extract the principal name from the keytab
195 krb5_kt_cursor cursor
;
196 if ( ( code
= krb5_kt_start_seq_get( context
, keytab
, &cursor
) ) != 0 ) {
197 L
<<Logger::Error
<< "krb5 error: " << std::string( krb5_get_error_message( context
, code
) ) << std::endl
;
198 krb5_kt_close( context
, keytab
);
202 krb5_keytab_entry entry
;
203 if ( ( code
= krb5_kt_next_entry( context
, keytab
, &entry
, &cursor
) ) == 0 ) {
204 code
= krb5_copy_principal( context
, entry
.principal
, &principal
);
205 krb5_kt_free_entry( context
, &entry
);
208 krb5_kt_end_seq_get( context
, keytab
, &cursor
);
210 L
<<Logger::Error
<< "krb5 error: " << std::string( krb5_get_error_message( context
, code
) ) << std::endl
;
211 krb5_kt_close( context
, keytab
);
212 krb5_free_principal( context
, principal
);
216 // Locate the credentials cache file
217 if ( !cCacheFile
.empty() ) {
218 std::string
cCacheStr( "FILE:" + cCacheFile
);
219 code
= krb5_cc_resolve( context
, cCacheStr
.c_str(), &ccache
);
222 code
= krb5_cc_default( context
, &ccache
);
226 L
<<Logger::Error
<< "krb5 error: " << std::string( krb5_get_error_message( context
, code
) ) << std::endl
;
227 krb5_kt_close( context
, keytab
);
228 krb5_free_principal( context
, principal
);
232 // Initialize the credentials cache file
233 if ( ( code
= krb5_cc_initialize( context
, ccache
, principal
) ) != 0 ) {
234 L
<<Logger::Error
<< "krb5 error: " << std::string( krb5_get_error_message( context
, code
) ) << std::endl
;
235 krb5_kt_close( context
, keytab
);
236 krb5_free_principal( context
, principal
);
240 if ( ( code
= krb5_get_init_creds_opt_alloc( context
, &options
) ) != 0 ) {
241 L
<<Logger::Error
<< "krb5 error: " << std::string( krb5_get_error_message( context
, code
) ) << std::endl
;
242 krb5_kt_close( context
, keytab
);
243 krb5_free_principal( context
, principal
);
246 krb5_get_init_creds_opt_set_default_flags( context
, "pdns", NULL
, options
);
248 // And finally get the TGT!
249 code
= krb5_get_init_creds_keytab( context
, &credentials
, principal
, keytab
, 0, NULL
, options
);
250 krb5_get_init_creds_opt_free( context
, options
);
251 krb5_kt_close( context
, keytab
);
252 krb5_free_principal( context
, principal
);
255 L
<<Logger::Error
<< "krb5 error: " << std::string( krb5_get_error_message( context
, code
) ) << std::endl
;
256 code
= krb5_cc_store_cred( context
, ccache
, &credentials
);
257 krb5_free_cred_contents( context
, &credentials
);
258 krb5_cc_close( context
, ccache
);
261 krb5_free_context( context
);