]> granicus.if.org Git - pdns/commitdiff
Various Kerberos improvments
authorGrégory Oestreicher <greg@kamago.net>
Wed, 12 Apr 2017 19:26:22 +0000 (21:26 +0200)
committerGrégory Oestreicher <greg@kamago.net>
Tue, 10 Apr 2018 20:02:07 +0000 (22:02 +0200)
Move Kerberos data in member variables
Use a temporary Kerberos credentials cache when getting the ticket
Add the Kerberos realm in the ticket request

modules/ldapbackend/ldapauthenticator.cc
modules/ldapbackend/ldapauthenticator_p.hh

index 77577ad47590d70aae73a54ddcce4a1e1ac19f12..c4bc6d8de519f26bfec2eaea22fe4e2da51d3027 100644 (file)
@@ -17,7 +17,6 @@
  *  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"
@@ -85,6 +84,29 @@ static int ldapGssapiAuthenticatorSaslInteractCallback( LDAP *conn, unsigned fla
 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 )
@@ -117,7 +139,7 @@ int LdapGssapiAuthenticator::attemptAuth( 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 )
@@ -125,21 +147,25 @@ int LdapGssapiAuthenticator::attemptAuth( LDAP *conn )
   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(),
@@ -163,100 +189,108 @@ int LdapGssapiAuthenticator::attemptAuth( LDAP *conn )
 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;
 }
index e3fff8c4a443a109c9fe79bf42e8970f9372d3db..0ebc8cc8393f30b1672401107e75565bc47cb464 100644 (file)
@@ -16,6 +16,7 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <krb5.h>
 #include "ldapauthenticator.hh"
 
 #ifndef LDAPAUTHENTICATOR_P_HH
@@ -47,6 +48,9 @@ class LdapGssapiAuthenticator : public LdapAuthenticator
     std::string cCacheFile;
     int timeout;
     std::string lastError;
+
+    krb5_context m_context;
+    krb5_ccache m_ccache;
     
     struct SaslDefaults {
       std::string mech;
@@ -60,6 +64,7 @@ class LdapGssapiAuthenticator : public LdapAuthenticator
   
   public:
     LdapGssapiAuthenticator( const std::string &keytab, const std::string &credsCache, int timeout );
+    ~LdapGssapiAuthenticator();
     virtual bool authenticate( LDAP *conn );
     virtual std::string getError() const;
 };