Пример #1
0
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 */
}
Пример #2
0
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);
}