int Authentication::authenticate_inner( char *hostAddr, const char* auth_methods, CondorError* errstack, int timeout) { #if defined(SKIP_AUTHENTICATION) dprintf(D_ALWAYS, "Skipping....\n"); /* errstack->push ( "AUTHENTICATE", AUTHENTICATE_ERR_NOT_BUILT, "this condor was built with SKIP_AUTHENTICATION"); */ return 0; #else Condor_Auth_Base * auth = NULL; int auth_timeout_time = time(0) + timeout; if (IsDebugVerbose(D_SECURITY)) { if (hostAddr) { dprintf ( D_SECURITY, "AUTHENTICATE: in authenticate( addr == '%s', " "methods == '%s')\n", hostAddr, auth_methods); } else { dprintf ( D_SECURITY, "AUTHENTICATE: in authenticate( addr == NULL, " "methods == '%s')\n", auth_methods); } } MyString methods_to_try = auth_methods; auth_status = CAUTH_NONE; method_used = NULL; while (auth_status == CAUTH_NONE ) { if (timeout>0 && auth_timeout_time <= time(0)) { dprintf(D_SECURITY, "AUTHENTICATE: exceeded %ds timeout\n", timeout); errstack->pushf( "AUTHENTICATE", AUTHENTICATE_ERR_TIMEOUT, "exceeded %ds timeout during authentication", timeout ); break; } if (IsDebugVerbose(D_SECURITY)) { dprintf(D_SECURITY, "AUTHENTICATE: can still try these methods: %s\n", methods_to_try.Value()); } int firm = handshake(methods_to_try); if ( firm < 0 ) { dprintf(D_ALWAYS, "AUTHENTICATE: handshake failed!\n"); errstack->push( "AUTHENTICATE", AUTHENTICATE_ERR_HANDSHAKE_FAILED, "Failure performing handshake" ); break; } char* method_name = NULL; switch ( firm ) { #if defined(HAVE_EXT_GLOBUS) case CAUTH_GSI: auth = new Condor_Auth_X509(mySock); method_name = strdup("GSI"); break; #endif /* HAVE_EXT_GLOBUS */ #ifdef HAVE_EXT_OPENSSL case CAUTH_SSL: auth = new Condor_Auth_SSL(mySock); method_name = strdup("SSL"); break; #endif #if defined(HAVE_EXT_KRB5) case CAUTH_KERBEROS: auth = new Condor_Auth_Kerberos(mySock); method_name = strdup("KERBEROS"); break; #endif #ifdef HAVE_EXT_OPENSSL // 3DES is the prequisite for passwd auth case CAUTH_PASSWORD: auth = new Condor_Auth_Passwd(mySock); method_name = strdup("PASSWORD"); break; #endif #if defined(WIN32) case CAUTH_NTSSPI: auth = new Condor_Auth_SSPI(mySock); method_name = strdup("NTSSPI"); break; #else case CAUTH_FILESYSTEM: auth = new Condor_Auth_FS(mySock); method_name = strdup("FS"); break; case CAUTH_FILESYSTEM_REMOTE: auth = new Condor_Auth_FS(mySock, 1); method_name = strdup("FS_REMOTE"); break; #endif /* !defined(WIN32) */ case CAUTH_CLAIMTOBE: auth = new Condor_Auth_Claim(mySock); method_name = strdup("CLAIMTOBE"); break; case CAUTH_ANONYMOUS: auth = new Condor_Auth_Anonymous(mySock); method_name = strdup("ANONYMOUS"); break; case CAUTH_NONE: dprintf(D_SECURITY|D_FULLDEBUG,"AUTHENTICATE: no available authentication methods succeeded!\n"); errstack->push("AUTHENTICATE", AUTHENTICATE_ERR_OUT_OF_METHODS, "Failed to authenticate with any method"); return 0; default: dprintf(D_ALWAYS,"AUTHENTICATE: unsupported method: %i, failing.\n", firm); errstack->pushf("AUTHENTICATE", AUTHENTICATE_ERR_OUT_OF_METHODS, "Failure. Unsupported method: %i", firm); return 0; } if (IsDebugVerbose(D_SECURITY)) { dprintf(D_SECURITY, "AUTHENTICATE: will try to use %d (%s)\n", firm, (method_name?method_name:"?!?") ); } //------------------------------------------ // Now authenticate //------------------------------------------ bool auth_rc = auth->authenticate(hostAddr, errstack); // check to see if the auth IP is the same as the socket IP if( auth_rc ) { char const *sockip = mySock->peer_ip_str(); char const *authip = auth->getRemoteHost() ; auth_rc = !sockip || !authip || !strcmp(sockip,authip); if (!auth_rc && !param_boolean( "DISABLE_AUTHENTICATION_IP_CHECK", false)) { errstack->pushf("AUTHENTICATE", AUTHENTICATE_ERR_METHOD_FAILED, "authenticated remote host does not match connection address (%s vs %s)", authip, sockip ); dprintf (D_ALWAYS, "AUTHENTICATE: ERROR: authenticated remot ehost does not match connection address (%s vs %s); configure DISABLE_AUTHENTICATION_IP_CHECK=TRUE if this check should be skipped\n",authip,sockip); } } if( !auth_rc ) { delete auth; auth = NULL; errstack->pushf("AUTHENTICATE", AUTHENTICATE_ERR_METHOD_FAILED, "Failed to authenticate using %s", method_name ); //if authentication failed, try again after removing from client tries if ( mySock->isClient() ) { // need to remove this item from the MyString!! perhaps there is a // better way to do this... anyways, 'firm' is equal to the bit value // of a particular method, so we'll just convert each item in the list // and keep it if it's not that particular bit. StringList meth_iter( methods_to_try.Value() ); meth_iter.rewind(); MyString new_list; char *tmp = NULL; while( (tmp = meth_iter.next()) ) { int that_bit = SecMan::getAuthBitmask( tmp ); // keep if this isn't the failed method. if (firm != that_bit) { // and of course, keep the comma's correct. if (new_list.Length() > 0) { new_list += ","; } new_list += tmp; } } // trust the copy constructor. :) methods_to_try = new_list; } dprintf(D_SECURITY,"AUTHENTICATE: method %d (%s) failed.\n", firm, (method_name?method_name:"?!?")); } else { // authentication succeeded. store the object (we may call upon // its wrapper functions) and set the auth_status of this sock to // the bitmask method we used and the method_used to the string // name. (string name is obtained above because there is currently // no bitmask -> string map) authenticator_ = auth; auth_status = authenticator_->getMode(); if (method_name) { method_used = strdup(method_name); } else { method_used = NULL; } } free (method_name); } //if none of the methods succeeded, we fall thru to default "none" from above int retval = ( auth_status != CAUTH_NONE ); if (IsDebugVerbose(D_SECURITY)) { dprintf(D_SECURITY, "AUTHENTICATE: auth_status == %i (%s)\n", auth_status, (method_used?method_used:"?!?") ); } dprintf(D_SECURITY, "Authentication was a %s.\n", retval == 1 ? "Success" : "FAILURE" ); // at this point, all methods have set the raw authenticated name available // via getAuthenticatedName(). if(authenticator_) { dprintf (D_SECURITY, "ZKM: setting default map to %s\n", authenticator_->getRemoteFQU()?authenticator_->getRemoteFQU():"(null)"); } // check to see if CERTIFICATE_MAPFILE was defined. if so, use it. if // not, do nothing. the user and domain have been filled in by the // authentication method itself, so just leave that alone. char * cert_map_file = param("CERTIFICATE_MAPFILE"); bool use_mapfile = (cert_map_file != NULL); if (cert_map_file) { free(cert_map_file); cert_map_file = 0; } // if successful so far, invoke the security MapFile. the output of that // is the "canonical user". if that has an '@' sign, split it up on the // last '@' and set the user and domain. if there is more than one '@', // the user will contain the leftovers after the split and the domain // always has none. if (retval && use_mapfile) { const char * name_to_map = authenticator_->getAuthenticatedName(); if (name_to_map) { dprintf (D_SECURITY, "ZKM: name to map is '%s'\n", name_to_map); dprintf (D_SECURITY, "ZKM: pre-map: current user is '%s'\n", authenticator_->getRemoteUser()?authenticator_->getRemoteUser():"(null)"); dprintf (D_SECURITY, "ZKM: pre-map: current domain is '%s'\n", authenticator_->getRemoteDomain()?authenticator_->getRemoteDomain():"(null)"); map_authentication_name_to_canonical_name(auth_status, method_used, name_to_map); } else { dprintf (D_SECURITY, "ZKM: name to map is null, not mapping.\n"); } } // for now, let's be a bit more verbose and print this to D_SECURITY. // yeah, probably all of the log lines that start with ZKM: should be // updated. oh, i wish there were a D_ZKM, but alas, we're out of bits. if( authenticator_ ) { dprintf (D_SECURITY, "ZKM: post-map: current user is '%s'\n", authenticator_->getRemoteUser()?authenticator_->getRemoteUser():"(null)"); dprintf (D_SECURITY, "ZKM: post-map: current domain is '%s'\n", authenticator_->getRemoteDomain()?authenticator_->getRemoteDomain():"(null)"); dprintf (D_SECURITY, "ZKM: post-map: current FQU is '%s'\n", authenticator_->getRemoteFQU()?authenticator_->getRemoteFQU():"(null)"); } mySock->allow_one_empty_message(); return ( retval ); #endif /* SKIP_AUTHENTICATION */ }
int Authentication::authenticate_continue( CondorError* errstack, bool non_blocking ) { // Check for continuations; int firm = -1; bool do_handshake = true; if (m_continue_handshake) { firm = handshake_continue(m_methods_to_try, non_blocking); if ( firm == -2 ) { dprintf(D_SECURITY, "AUTHENTICATE: handshake would still block\n"); return 2; } m_continue_handshake = false; do_handshake = false; } int auth_rc = 0; bool do_authenticate = true; if (m_continue_auth) { auth_rc = m_auth->authenticate_continue(errstack, non_blocking); if (auth_rc == 2 ) { dprintf(D_SECURITY, "AUTHENTICATE: auth would still block\n"); return 2; } m_continue_auth = false; do_authenticate = false; goto authenticate; } m_auth = NULL; while (auth_status == CAUTH_NONE ) { if (m_auth_timeout_time>0 && m_auth_timeout_time <= time(0)) { dprintf(D_SECURITY, "AUTHENTICATE: exceeded deadline %ld\n", m_auth_timeout_time); errstack->pushf( "AUTHENTICATE", AUTHENTICATE_ERR_TIMEOUT, "exceeded %ld deadline during authentication", m_auth_timeout_time ); break; } if (IsDebugVerbose(D_SECURITY)) { dprintf(D_SECURITY, "AUTHENTICATE: can still try these methods: %s\n", m_methods_to_try.c_str()); } if (do_handshake) { firm = handshake(m_methods_to_try, non_blocking); } do_handshake = true; if ( firm == -2 ) { dprintf(D_SECURITY, "AUTHENTICATE: handshake would block\n"); m_continue_handshake = true; return 2; } if ( firm < 0 ) { dprintf(D_ALWAYS, "AUTHENTICATE: handshake failed!\n"); errstack->push( "AUTHENTICATE", AUTHENTICATE_ERR_HANDSHAKE_FAILED, "Failure performing handshake" ); break; } m_method_name = ""; switch ( firm ) { #if defined(HAVE_EXT_GLOBUS) case CAUTH_GSI: m_auth = new Condor_Auth_X509(mySock); m_method_name = "GSI"; break; #endif /* HAVE_EXT_GLOBUS */ #ifdef HAVE_EXT_OPENSSL case CAUTH_SSL: m_auth = new Condor_Auth_SSL(mySock); m_method_name = "SSL"; break; #endif #if defined(HAVE_EXT_KRB5) case CAUTH_KERBEROS: m_auth = new Condor_Auth_Kerberos(mySock); m_method_name = "KERBEROS"; break; #endif #ifdef HAVE_EXT_OPENSSL // 3DES is the prequisite for passwd auth case CAUTH_PASSWORD: m_auth = new Condor_Auth_Passwd(mySock); m_method_name = "PASSWORD"; break; #endif #if defined(WIN32) case CAUTH_NTSSPI: m_auth = new Condor_Auth_SSPI(mySock); m_method_name = "NTSSPI"; break; #else case CAUTH_FILESYSTEM: m_auth = new Condor_Auth_FS(mySock); m_method_name = "FS"; break; case CAUTH_FILESYSTEM_REMOTE: m_auth = new Condor_Auth_FS(mySock, 1); m_method_name = "FS_REMOTE"; break; #endif /* !defined(WIN32) */ case CAUTH_CLAIMTOBE: m_auth = new Condor_Auth_Claim(mySock); m_method_name = "CLAIMTOBE"; break; case CAUTH_ANONYMOUS: m_auth = new Condor_Auth_Anonymous(mySock); m_method_name = "ANONYMOUS"; break; case CAUTH_NONE: dprintf(D_SECURITY|D_FULLDEBUG,"AUTHENTICATE: no available authentication methods succeeded!\n"); errstack->push("AUTHENTICATE", AUTHENTICATE_ERR_OUT_OF_METHODS, "Failed to authenticate with any method"); return 0; default: dprintf(D_ALWAYS,"AUTHENTICATE: unsupported method: %i, failing.\n", firm); errstack->pushf("AUTHENTICATE", AUTHENTICATE_ERR_OUT_OF_METHODS, "Failure. Unsupported method: %i", firm); return 0; } if (IsDebugVerbose(D_SECURITY)) { dprintf(D_SECURITY, "AUTHENTICATE: will try to use %d (%s)\n", firm, (m_method_name.size()?m_method_name.c_str():"?!?") ); } // We have just picked a new method, so we definitely want to // make this value true. We log a message only if we changed // it. if(!do_authenticate) { do_authenticate = true; if (IsDebugVerbose(D_SECURITY)) { dprintf(D_SECURITY, "AUTHENTICATE: forcing do_authenticate to true.\n"); } } //------------------------------------------ // Now authenticate //------------------------------------------ authenticate: // Re-check deadline as handshake could have taken awhile. if (m_auth_timeout_time>0 && m_auth_timeout_time <= time(0)) { dprintf(D_SECURITY, "AUTHENTICATE: exceeded deadline %ld\n", m_auth_timeout_time); errstack->pushf( "AUTHENTICATE", AUTHENTICATE_ERR_TIMEOUT, "exceeded %ld deadline during authentication", m_auth_timeout_time ); break; } if (IsDebugVerbose(D_SECURITY)) { dprintf (D_SECURITY, "AUTHENTICATE: do_authenticate is %i.\n", do_authenticate); } if (do_authenticate) { auth_rc = m_auth->authenticate(m_host_addr.c_str(), errstack, non_blocking); if (auth_rc == 2) { m_continue_auth = true; return 2; } } // check to see if the auth IP is the same as the socket IP if( auth_rc ) { char const *sockip = mySock->peer_ip_str(); char const *authip = m_auth->getRemoteHost() ; auth_rc = !sockip || !authip || !strcmp(sockip,authip); if (!auth_rc && !param_boolean( "DISABLE_AUTHENTICATION_IP_CHECK", false)) { errstack->pushf("AUTHENTICATE", AUTHENTICATE_ERR_METHOD_FAILED, "authenticated remote host does not match connection address (%s vs %s)", authip, sockip ); dprintf (D_ALWAYS, "AUTHENTICATE: ERROR: authenticated remot ehost does not match connection address (%s vs %s); configure DISABLE_AUTHENTICATION_IP_CHECK=TRUE if this check should be skipped\n",authip,sockip); } } if( !auth_rc ) { delete m_auth; m_auth = NULL; errstack->pushf("AUTHENTICATE", AUTHENTICATE_ERR_METHOD_FAILED, "Failed to authenticate using %s", m_method_name.c_str() ); //if authentication failed, try again after removing from client tries if ( mySock->isClient() ) { // need to remove this item from the MyString!! perhaps there is a // better way to do this... anyways, 'firm' is equal to the bit value // of a particular method, so we'll just convert each item in the list // and keep it if it's not that particular bit. StringList meth_iter( m_methods_to_try.c_str() ); meth_iter.rewind(); MyString new_list; char *tmp = NULL; while( (tmp = meth_iter.next()) ) { int that_bit = SecMan::getAuthBitmask( tmp ); // keep if this isn't the failed method. if (firm != that_bit) { // and of course, keep the comma's correct. if (new_list.Length() > 0) { new_list += ","; } new_list += tmp; } } // trust the copy constructor. :) m_methods_to_try = new_list; } dprintf(D_SECURITY,"AUTHENTICATE: method %d (%s) failed.\n", firm, (m_method_name.size()?m_method_name.c_str():"?!?")); } else { // authentication succeeded. store the object (we may call upon // its wrapper functions) and set the auth_status of this sock to // the bitmask method we used and the method_used to the string // name. (string name is obtained above because there is currently // no bitmask -> string map) authenticator_ = m_auth; m_auth = NULL; auth_status = authenticator_->getMode(); if (m_method_name.size()) { method_used = strdup(m_method_name.c_str()); } else { method_used = NULL; } } } return authenticate_finish(errstack); }