<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/


#include "condor_common.h"

#if !defined(SKIP_AUTHENTICATION) && defined(HAVE_EXT_GLOBUS)

#include "condor_auth_x509.h"
#include "authentication.h"
#include "condor_config.h"
#include "CondorError.h"
#include "setenv.h"
#include "globus_utils.h"
#include "condor_gssapi_openssl.h"
#include "ipv6_hostname.h"
#include "condor_sinful.h"
#include "condor_attributes.h"

#if defined(HAVE_EXT_VOMS)
extern "C" {
	#include "voms/voms_apic.h"
}
#endif

#define USER_NAME_MAX 256

const char STR_DAEMON_NAME_FORMAT[]="$$(FULL_HOST_NAME)";
StringList * getDaemonList(char const *param_name,char const *fqh);


#ifdef WIN32
HashTable<MyString, MyString> * Condor_Auth_X509::GridMap = 0;
#endif

bool Condor_Auth_X509::m_globusActivated = false;

Condor_Auth_X509::GlobusMappingTable *Condor_Auth_X509::m_mapping = NULL;

//----------------------------------------------------------------------
// Implementation
//----------------------------------------------------------------------

Condor_Auth_X509 :: Condor_Auth_X509(ReliSock * sock)
    : Condor_Auth_Base (sock, CAUTH_GSI),
      credential_handle(GSS_C_NO_CREDENTIAL),
      context_handle   (GSS_C_NO_CONTEXT),
      m_gss_server_name(NULL),
      m_client_name(GSS_C_NO_NAME),
      token_status     (0),
      ret_flags        (0),
      m_state          (GetClientPre),
      m_status         (1)
{
#ifdef WIN32
	ParseMapFile();
#endif
	if ( !m_globusActivated ) {
		// The Globus callout module is a system-wide setting.  There are several
		// cases where a user may not want it to apply to Condor by default
		// (for example, if it causes crashes when mixed with Condor libs!).
		// Setting GSI_AUTHZ_CONF=/dev/null works for disabling the callouts.
		std::string gsi_authz_conf;
		if (param(gsi_authz_conf, "GSI_AUTHZ_CONF")) {
			if (setenv("GSI_AUTHZ_CONF", gsi_authz_conf.c_str(), 1)) {
				dprintf(D_ALWAYS, "Failed to set the GSI_AUTHZ_CONF environment variable.\n");
				EXCEPT("Failed to set the GSI_AUTHZ_CONF environment variable.");
			}
		}
		if ( activate_globus_gsi() < 0 ) {
			dprintf( D_ALWAYS, "Can't initialize GSI, authentication will fail: %s\n", x509_error_string() );
		} else {
			m_globusActivated = true;
		}
	}
}

Condor_Auth_X509 ::  ~Condor_Auth_X509()
{
	if ( !m_globusActivated ) {
		return;
	}
    // Delete context handle if exist

	OM_uint32 minor_status = 0;

    if (context_handle) {
        (*gss_delete_sec_context_ptr)(&minor_status,&context_handle,GSS_C_NO_BUFFER);
    }

    if (credential_handle != GSS_C_NO_CREDENTIAL) {
        (*gss_release_cred_ptr)(&minor_status, &credential_handle);
    }

	if( m_gss_server_name != NULL ) {
		(*gss_release_name_ptr)( &minor_status, &m_gss_server_name );
	}
	(*gss_release_name_ptr)(&minor_status, &m_client_name);
}

int Condor_Auth_X509 :: authenticate(const char * /* remoteHost */, CondorError* errstack, bool non_blocking)
{
    int status = 1;
    int reply = 0;
	token_status = 0;
	m_state = GetClientPre;

    //don't just return TRUE if isAuthenticated() == TRUE, since 
    //we should BALANCE calls of Authenticate() on client/server side
    //just like end_of_message() calls must balance!
    
    if ( !authenticate_self_gss(errstack) ) {
        dprintf( D_SECURITY, "authenticate: user creds not established\n" );
        status = 0;
		// If I failed, notify the other side.
		if (mySock_->isClient()) {
			// Tell the other side, abort
			mySock_->encode();
			if (!mySock_->code(status)) {
        		dprintf( D_SECURITY, "authenticate: and the remote side hung up on us.\n" );
			}
			mySock_->end_of_message();
		}
		else {
			// I am server, first wait for the other side
			mySock_->decode();
			if (!mySock_->code(reply)) {
        		dprintf( D_SECURITY, "authenticate: the client side hung up on us.\n" );
			}
			mySock_->end_of_message();

			if (reply == 1) { 
				// The other side was okay, tell them the bad news
				mySock_->encode();
				if (!mySock_->code(status)) {
					dprintf(D_SECURITY,"authenticate: the client hung up before authenticatiation\n");
				}
				mySock_->end_of_message();
			}
		}
    }
    else {
		// wait to see if the other side is okay
		if (mySock_->isClient()) {
			// Tell the other side, that I am fine, then wait for answer
			mySock_->encode();
			if (!mySock_->code(status)) {
				dprintf(D_SECURITY, "authenticate: the service hung up before authentication\n");
			}
			mySock_->end_of_message();

			mySock_->decode();
			if (!mySock_->code(reply)) {
				dprintf(D_SECURITY, "authenticate: the service hung up before authentication reply could be sent\n");
			}
			mySock_->end_of_message();
			if (reply == 0) {   // The other side failed, abort
				errstack->push("GSI", GSI_ERR_REMOTE_SIDE_FAILED,
						"Failed to authenticate because the remote (server) "
						"side was not able to acquire its credentials.");

				return 0;
			}
		}
		else {
			m_state = GetClientPre;
			CondorAuthX509Retval tmp_status = authenticate_server_pre(errstack, non_blocking);
			if ((tmp_status == Fail) || (tmp_status == WouldBlock)) {
				return static_cast<int>(tmp_status);
			}
		}

		int gsi_auth_timeout = param_integer("GSI_AUTHENTICATION_TIMEOUT",-1);
		int old_timeout=0;
		if (gsi_auth_timeout>=0) {
			old_timeout = mySock_->timeout(gsi_auth_timeout); 
		}
        
		if ( mySock_->isClient() ) {
			status = authenticate_client_gss(errstack);
		} else {
			CondorAuthX509Retval rc = authenticate_server_gss(errstack, non_blocking);
			if ( rc == Continue ) {
				rc = authenticate_server_gss_post( errstack, non_blocking );
			}
			status = static_cast<int>( rc );
		}

		if (gsi_auth_timeout>=0) {
			mySock_->timeout(old_timeout); //put it back to what it was before
		}
    }
    
    return( status );
}

int Condor_Auth_X509 :: wrap(const char*  data_in,
                             int    length_in, 
                             char*& data_out, 
                             int&   length_out)
{
    OM_uint32 major_status;
    OM_uint32 minor_status;

    gss_buffer_desc input_token_desc  = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    input_token       = &input_token_desc;
    gss_buffer_desc output_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    output_token      = &output_token_desc;
    
    if (!m_globusActivated || !isValid())
        return FALSE;	
    
    input_token->value  = (void *)data_in;
    input_token->length = length_in;
    
    major_status = (*gss_wrap_ptr)(&minor_status,
                            context_handle,
                            0,
                            GSS_C_QOP_DEFAULT,
                            input_token,
                            NULL,
                            output_token);
    
    data_out = (char*)output_token -> value;
    length_out = output_token -> length;

	// return TRUE on success
    return (major_status == GSS_S_COMPLETE);
}
    
int Condor_Auth_X509 :: unwrap(const char*  data_in,
                               int    length_in, 
                               char*& data_out, 
                               int&   length_out)
{
    OM_uint32 major_status;
    OM_uint32 minor_status;
    
    gss_buffer_desc input_token_desc  = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    input_token       = &input_token_desc;
    gss_buffer_desc output_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    output_token      = &output_token_desc;
    
    if (!m_globusActivated || !isValid()) {
        return FALSE;
    }
    
    input_token -> value = (void *)data_in;
    input_token -> length = length_in;
    
    major_status = (*gss_unwrap_ptr)(&minor_status,
                              context_handle,
                              input_token,
                              output_token,
                              NULL,
                              NULL);
    
    
    data_out = (char*)output_token -> value;
    length_out = output_token -> length;

	// return TRUE on success
    return (major_status == GSS_S_COMPLETE);
}

int Condor_Auth_X509 :: endTime() const
{
    OM_uint32 major_status;
	OM_uint32 minor_status;
	OM_uint32 time_rec;

	if ( !m_globusActivated ) {
		return -1;
	}<commit_msg>Correctly (if absurdly) construct the const-discarding cast to void *.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/


#include "condor_common.h"

#if !defined(SKIP_AUTHENTICATION) && defined(HAVE_EXT_GLOBUS)

#include "condor_auth_x509.h"
#include "authentication.h"
#include "condor_config.h"
#include "CondorError.h"
#include "setenv.h"
#include "globus_utils.h"
#include "condor_gssapi_openssl.h"
#include "ipv6_hostname.h"
#include "condor_sinful.h"
#include "condor_attributes.h"

#if defined(HAVE_EXT_VOMS)
extern "C" {
	#include "voms/voms_apic.h"
}
#endif

#define USER_NAME_MAX 256

const char STR_DAEMON_NAME_FORMAT[]="$$(FULL_HOST_NAME)";
StringList * getDaemonList(char const *param_name,char const *fqh);


#ifdef WIN32
HashTable<MyString, MyString> * Condor_Auth_X509::GridMap = 0;
#endif

bool Condor_Auth_X509::m_globusActivated = false;

Condor_Auth_X509::GlobusMappingTable *Condor_Auth_X509::m_mapping = NULL;

//----------------------------------------------------------------------
// Implementation
//----------------------------------------------------------------------

Condor_Auth_X509 :: Condor_Auth_X509(ReliSock * sock)
    : Condor_Auth_Base (sock, CAUTH_GSI),
      credential_handle(GSS_C_NO_CREDENTIAL),
      context_handle   (GSS_C_NO_CONTEXT),
      m_gss_server_name(NULL),
      m_client_name(GSS_C_NO_NAME),
      token_status     (0),
      ret_flags        (0),
      m_state          (GetClientPre),
      m_status         (1)
{
#ifdef WIN32
	ParseMapFile();
#endif
	if ( !m_globusActivated ) {
		// The Globus callout module is a system-wide setting.  There are several
		// cases where a user may not want it to apply to Condor by default
		// (for example, if it causes crashes when mixed with Condor libs!).
		// Setting GSI_AUTHZ_CONF=/dev/null works for disabling the callouts.
		std::string gsi_authz_conf;
		if (param(gsi_authz_conf, "GSI_AUTHZ_CONF")) {
			if (setenv("GSI_AUTHZ_CONF", gsi_authz_conf.c_str(), 1)) {
				dprintf(D_ALWAYS, "Failed to set the GSI_AUTHZ_CONF environment variable.\n");
				EXCEPT("Failed to set the GSI_AUTHZ_CONF environment variable.");
			}
		}
		if ( activate_globus_gsi() < 0 ) {
			dprintf( D_ALWAYS, "Can't initialize GSI, authentication will fail: %s\n", x509_error_string() );
		} else {
			m_globusActivated = true;
		}
	}
}

Condor_Auth_X509 ::  ~Condor_Auth_X509()
{
	if ( !m_globusActivated ) {
		return;
	}
    // Delete context handle if exist

	OM_uint32 minor_status = 0;

    if (context_handle) {
        (*gss_delete_sec_context_ptr)(&minor_status,&context_handle,GSS_C_NO_BUFFER);
    }

    if (credential_handle != GSS_C_NO_CREDENTIAL) {
        (*gss_release_cred_ptr)(&minor_status, &credential_handle);
    }

	if( m_gss_server_name != NULL ) {
		(*gss_release_name_ptr)( &minor_status, &m_gss_server_name );
	}
	(*gss_release_name_ptr)(&minor_status, &m_client_name);
}

int Condor_Auth_X509 :: authenticate(const char * /* remoteHost */, CondorError* errstack, bool non_blocking)
{
    int status = 1;
    int reply = 0;
	token_status = 0;
	m_state = GetClientPre;

    //don't just return TRUE if isAuthenticated() == TRUE, since 
    //we should BALANCE calls of Authenticate() on client/server side
    //just like end_of_message() calls must balance!
    
    if ( !authenticate_self_gss(errstack) ) {
        dprintf( D_SECURITY, "authenticate: user creds not established\n" );
        status = 0;
		// If I failed, notify the other side.
		if (mySock_->isClient()) {
			// Tell the other side, abort
			mySock_->encode();
			if (!mySock_->code(status)) {
        		dprintf( D_SECURITY, "authenticate: and the remote side hung up on us.\n" );
			}
			mySock_->end_of_message();
		}
		else {
			// I am server, first wait for the other side
			mySock_->decode();
			if (!mySock_->code(reply)) {
        		dprintf( D_SECURITY, "authenticate: the client side hung up on us.\n" );
			}
			mySock_->end_of_message();

			if (reply == 1) { 
				// The other side was okay, tell them the bad news
				mySock_->encode();
				if (!mySock_->code(status)) {
					dprintf(D_SECURITY,"authenticate: the client hung up before authenticatiation\n");
				}
				mySock_->end_of_message();
			}
		}
    }
    else {
		// wait to see if the other side is okay
		if (mySock_->isClient()) {
			// Tell the other side, that I am fine, then wait for answer
			mySock_->encode();
			if (!mySock_->code(status)) {
				dprintf(D_SECURITY, "authenticate: the service hung up before authentication\n");
			}
			mySock_->end_of_message();

			mySock_->decode();
			if (!mySock_->code(reply)) {
				dprintf(D_SECURITY, "authenticate: the service hung up before authentication reply could be sent\n");
			}
			mySock_->end_of_message();
			if (reply == 0) {   // The other side failed, abort
				errstack->push("GSI", GSI_ERR_REMOTE_SIDE_FAILED,
						"Failed to authenticate because the remote (server) "
						"side was not able to acquire its credentials.");

				return 0;
			}
		}
		else {
			m_state = GetClientPre;
			CondorAuthX509Retval tmp_status = authenticate_server_pre(errstack, non_blocking);
			if ((tmp_status == Fail) || (tmp_status == WouldBlock)) {
				return static_cast<int>(tmp_status);
			}
		}

		int gsi_auth_timeout = param_integer("GSI_AUTHENTICATION_TIMEOUT",-1);
		int old_timeout=0;
		if (gsi_auth_timeout>=0) {
			old_timeout = mySock_->timeout(gsi_auth_timeout); 
		}
        
		if ( mySock_->isClient() ) {
			status = authenticate_client_gss(errstack);
		} else {
			CondorAuthX509Retval rc = authenticate_server_gss(errstack, non_blocking);
			if ( rc == Continue ) {
				rc = authenticate_server_gss_post( errstack, non_blocking );
			}
			status = static_cast<int>( rc );
		}

		if (gsi_auth_timeout>=0) {
			mySock_->timeout(old_timeout); //put it back to what it was before
		}
    }
    
    return( status );
}

int Condor_Auth_X509 :: wrap(const char*  data_in,
                             int    length_in, 
                             char*& data_out, 
                             int&   length_out)
{
    OM_uint32 major_status;
    OM_uint32 minor_status;

    gss_buffer_desc input_token_desc  = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    input_token       = &input_token_desc;
    gss_buffer_desc output_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    output_token      = &output_token_desc;
    
    if (!m_globusActivated || !isValid())
        return FALSE;	
    
    // Yes, this is completely absurd.
    input_token->value  = const_cast<void *>(reinterpret_cast<const void *>(data_in));
    input_token->length = length_in;
    
    major_status = (*gss_wrap_ptr)(&minor_status,
                            context_handle,
                            0,
                            GSS_C_QOP_DEFAULT,
                            input_token,
                            NULL,
                            output_token);
    
    data_out = (char*)output_token -> value;
    length_out = output_token -> length;

	// return TRUE on success
    return (major_status == GSS_S_COMPLETE);
}
    
int Condor_Auth_X509 :: unwrap(const char*  data_in,
                               int    length_in, 
                               char*& data_out, 
                               int&   length_out)
{
    OM_uint32 major_status;
    OM_uint32 minor_status;
    
    gss_buffer_desc input_token_desc  = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    input_token       = &input_token_desc;
    gss_buffer_desc output_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    output_token      = &output_token_desc;
    
    if (!m_globusActivated || !isValid()) {
        return FALSE;
    }
    
    // Yes, this is completely absurd.
    input_token -> value  = const_cast<void *>(reinterpret_cast<const void *>(data_in));
    input_token -> length = length_in;
    
    major_status = (*gss_unwrap_ptr)(&minor_status,
                              context_handle,
                              input_token,
                              output_token,
                              NULL,
                              NULL);
    
    
    data_out = (char*)output_token -> value;
    length_out = output_token -> length;

	// return TRUE on success
    return (major_status == GSS_S_COMPLETE);
}

int Condor_Auth_X509 :: endTime() const
{
    OM_uint32 major_status;
	OM_uint32 minor_status;
	OM_uint32 time_rec;

	if ( !m_globusActivated ) {
		return -1;
	}
{'fraction_non_alphanumeric': 0.13026417596993478, 'fraction_numerical': 0.011495523377915332, 'mean_word_length': 2.7011658825935774, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3292073', 'n_tokens_mistral': 6516, 'n_tokens_neox': 5900, 'n_words': 1385}