* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <krb5.h>
#include <pdns/logger.hh>
#include "ldapauthenticator_p.hh"
#include "ldaputils.hh"
LdapGssapiAuthenticator::LdapGssapiAuthenticator( const std::string& kt, const std::string &ccache, int tmout )
: logPrefix( "[LDAP GSSAPI] " ), keytabFile( kt ), cCacheFile( ccache ), timeout( tmout )
{
+ krb5_error_code code;
+
+ if ( ( code = krb5_init_context( &m_context ) ) != 0 )
+ throw PDNSException( logPrefix + std::string( "Failed to initialize krb5 context" ) );
+
+ // Locate the credentials cache file
+ if ( !cCacheFile.empty() ) {
+ std::string cCacheStr( "FILE:" + cCacheFile );
+ code = krb5_cc_resolve( m_context, cCacheStr.c_str(), &m_ccache );
+ }
+ else {
+ code = krb5_cc_default( m_context, &m_ccache );
+ }
+
+ if ( code != 0 )
+ throw PDNSException( logPrefix +
+ std::string( "krb5 error when locating the credentials cache file: " ) +
+ std::string( krb5_get_error_message( m_context, code ) ) );
+}
+
+LdapGssapiAuthenticator::~LdapGssapiAuthenticator()
+{
+ krb5_free_context( m_context );
}
bool LdapGssapiAuthenticator::authenticate( LDAP *conn )
{
// Create SASL defaults
SaslDefaults defaults;
- char *ldapOption = 0;
+ char *ldapOption = nullptr;
ldap_get_option( conn, LDAP_OPT_X_SASL_MECH, ldapOption );
if ( !ldapOption )
else
defaults.mech = std::string( ldapOption );
ldap_memfree( ldapOption );
+ ldapOption = nullptr;
ldap_get_option( conn, LDAP_OPT_X_SASL_REALM, ldapOption );
if ( ldapOption )
defaults.realm = std::string( ldapOption );
ldap_memfree( ldapOption );
+ ldapOption = nullptr;
ldap_get_option( conn, LDAP_OPT_X_SASL_AUTHCID, ldapOption );
if ( ldapOption )
defaults.authcid = std::string( ldapOption );
ldap_memfree( ldapOption );
+ ldapOption = nullptr;
ldap_get_option( conn, LDAP_OPT_X_SASL_AUTHZID, ldapOption );
if ( ldapOption )
defaults.authzid = std::string( ldapOption );
ldap_memfree( ldapOption );
+ ldapOption = nullptr;
// And now try to bind
int rc = ldap_sasl_interactive_bind_s( conn, "", defaults.mech.c_str(),
int LdapGssapiAuthenticator::updateTgt()
{
krb5_error_code code;
- krb5_context context;
krb5_creds credentials;
krb5_keytab keytab;
krb5_principal principal;
- krb5_ccache ccache;
krb5_get_init_creds_opt *options;
- if ( ( code = krb5_init_context( &context ) ) != 0 ) {
- g_log<<Logger::Error << logPrefix << "Failed to init krb5 context" << std::endl;
- return code;
- }
-
if ( !keytabFile.empty() ) {
std::string keytabStr( "FILE:" + keytabFile );
- code = krb5_kt_resolve( context, keytabStr.c_str(), &keytab );
+ code = krb5_kt_resolve( m_context, keytabStr.c_str(), &keytab );
}
else {
- code = krb5_kt_default( context, &keytab );
+ code = krb5_kt_default( m_context, &keytab );
}
if ( code != 0 ) {
- g_log<<Logger::Error << logPrefix << "krb5 error when locating the keytab file: " << std::string( krb5_get_error_message( context, code ) ) << std::endl;
+ g_log<<Logger::Error << logPrefix << "krb5 error when locating the keytab file: " << std::string( krb5_get_error_message( m_context, code ) ) << std::endl;
return code;
}
// Extract the principal name from the keytab
krb5_kt_cursor cursor;
- if ( ( code = krb5_kt_start_seq_get( context, keytab, &cursor ) ) != 0 ) {
- g_log<<Logger::Error << logPrefix << "krb5 error when initiating keytab search: " << std::string( krb5_get_error_message( context, code ) ) << std::endl;
- krb5_kt_close( context, keytab );
+ if ( ( code = krb5_kt_start_seq_get( m_context, keytab, &cursor ) ) != 0 ) {
+ g_log<<Logger::Error << logPrefix << "krb5 error when initiating keytab search: " << std::string( krb5_get_error_message( m_context, code ) ) << std::endl;
+ krb5_kt_close( m_context, keytab );
return code;
}
krb5_keytab_entry entry;
- if ( ( code = krb5_kt_next_entry( context, keytab, &entry, &cursor ) ) == 0 ) {
- code = krb5_copy_principal( context, entry.principal, &principal );
- krb5_kt_free_entry( context, &entry );
+ if ( ( code = krb5_kt_next_entry( m_context, keytab, &entry, &cursor ) ) == 0 ) {
+ code = krb5_copy_principal( m_context, entry.principal, &principal );
+ krb5_kt_free_entry( m_context, &entry );
}
- krb5_kt_end_seq_get( context, keytab, &cursor );
+ krb5_kt_end_seq_get( m_context, keytab, &cursor );
if ( code != 0 ) {
- g_log<<Logger::Error << logPrefix << "krb5 error when extracting principal information: " << std::string( krb5_get_error_message( context, code ) ) << std::endl;
- krb5_kt_close( context, keytab );
- krb5_free_principal( context, principal );
+ g_log<<Logger::Error << logPrefix << "krb5 error when extracting principal information: " << std::string( krb5_get_error_message( m_context, code ) ) << std::endl;
+ krb5_kt_close( m_context, keytab );
+ krb5_free_principal( m_context, principal );
return code;
}
- // Locate the credentials cache file
- if ( !cCacheFile.empty() ) {
- std::string cCacheStr( "FILE:" + cCacheFile );
- code = krb5_cc_resolve( context, cCacheStr.c_str(), &ccache );
+ if ( ( code = krb5_get_init_creds_opt_alloc( m_context, &options ) ) != 0 ) {
+ L<<Logger::Error << logPrefix << "krb5 error when allocating credentials cache structure: " << std::string( krb5_get_error_message( m_context, code ) ) << std::endl;
+ krb5_kt_close( m_context, keytab );
+ krb5_free_principal( m_context, principal );
+ return code;
}
- else {
- code = krb5_cc_default( context, &ccache );
+ krb5_get_init_creds_opt_set_default_flags( m_context, "pdns", krb5_principal_get_realm( m_context, principal ), options );
+
+ // Get the ticket
+ code = krb5_get_init_creds_keytab( m_context, &credentials, principal, keytab, 0, NULL, options );
+ if ( code ) {
+ L<<Logger::Error << d_logPrefix << "krb5 error when getting the TGT: " << std::string( krb5_get_error_message( d_context, code ) ) << std::endl;
+ krb5_get_init_creds_opt_free( d_context, options );
+ krb5_free_cred_contents( d_context, &credentials );
+ krb5_kt_close( d_context, keytab );
+ krb5_free_principal( d_context, principal );
+ return code;
}
- if ( code != 0 ) {
- g_log<<Logger::Error << logPrefix << "krb5 error when locating the credentials cache file: " << std::string( krb5_get_error_message( context, code ) ) << std::endl;
- krb5_kt_close( context, keytab );
- krb5_free_principal( context, principal );
+ krb5_get_init_creds_opt_free( m_context, options );
+ krb5_kt_close( m_context, keytab );
+
+ // Use a temporary cache to get the initial credentials. This will be moved to the user-configured one later.
+ krb5_ccache tmp_ccache = NULL;
+
+ code = krb5_cc_new_unique( m_context, krb5_cc_get_type( m_context, m_ccache ), NULL, &tmp_ccache );
+ if ( code ) {
+ g_log<<Logger::Error<< d_logPrefix << "krb5 error when creating the temporary cache file: " << std::string( krb5_get_error_message( d_context, code ) ) << std::endl;
+ krb5_free_cred_contents( d_context, &credentials );
+ krb5_free_principal( d_context, principal );
return code;
}
- // Initialize the credentials cache file
- if ( ( code = krb5_cc_initialize( context, ccache, principal ) ) != 0 ) {
- g_log<<Logger::Error << logPrefix << "krb5 error when initializing the credentials cache file: " << std::string( krb5_get_error_message( context, code ) ) << std::endl;
- krb5_kt_close( context, keytab );
- krb5_free_principal( context, principal );
+ code = krb5_cc_initialize( m_context, tmp_ccache, principal );
+ if ( code ) {
+ g_log<<Logger::Error<< logPrefix << "krb5 error when initializing the temporary cache file: " << std::string( krb5_get_error_message( m_context, code ) ) << std::endl;
+ krb5_free_cred_contents( m_context, &credentials );
+ krb5_free_principal( m_context, principal );
return code;
}
- if ( ( code = krb5_get_init_creds_opt_alloc( context, &options ) ) != 0 ) {
- g_log<<Logger::Error << logPrefix << "krb5 error when allocating credentials cache structure: " << std::string( krb5_get_error_message( context, code ) ) << std::endl;
- krb5_kt_close( context, keytab );
- krb5_free_principal( context, principal );
+ code = krb5_cc_store_cred( m_context, tmp_ccache, &credentials );
+ if ( code ) {
+ g_log<<Logger::Error << logPrefix << "krb5 error when storing the ticket in the credentials cache: " << std::string( krb5_get_error_message( m_context, code ) ) << std::endl;
+ krb5_cc_close( m_context, tmp_ccache );
+ krb5_free_cred_contents( m_context, &credentials );
+ krb5_free_principal( m_context, principal );
return code;
}
- krb5_get_init_creds_opt_set_default_flags( context, "pdns", NULL, options );
-
- // And finally get the TGT!
- code = krb5_get_init_creds_keytab( context, &credentials, principal, keytab, 0, NULL, options );
- krb5_get_init_creds_opt_free( context, options );
- krb5_kt_close( context, keytab );
- krb5_free_principal( context, principal );
-
- if ( code == 0 ) {
- code = krb5_cc_store_cred( context, ccache, &credentials );
- krb5_free_cred_contents( context, &credentials );
- krb5_cc_close( context, ccache );
- }
- else {
- g_log<<Logger::Error << logPrefix << "krb5 error when getting the TGT: " << std::string( krb5_get_error_message( context, code ) ) << std::endl;
+
+ code = krb5_cc_move( m_context, tmp_ccache, m_ccache );
+ if ( code ) {
+ g_log<<Logger::Error << logPrefix << "krb5 error when moving the credentials cache: " << std::string( krb5_get_error_message( m_context, code ) ) << std::endl;
+ krb5_free_cred_contents( m_context, &credentials );
+ krb5_free_principal( m_context, principal );
+ return code;
}
- krb5_free_context( context );
+ krb5_cc_close( m_context, tmp_ccache );
+ krb5_free_cred_contents( m_context, &credentials );
+ krb5_free_principal( m_context, principal );
+
+ L<<Logger::Debug << logPrefix << "done getting TGT, will return " << code << std::endl;
return code;
}