Beispiel #1
0
// An entity (e.g. GlobusJob, GlobusResource object) should call this
// function when it wants to use a proxy and have it managed by
// ProxyManager. job_ad contains attributes related to the proxy to be
// used. error allows the function to return an error message if proxy
// acquisition fails. notify_tid is a timer id that
// will be signalled when something interesting happens with the proxy
// (it's about to expire or has been refreshed). A Proxy struct will be
// returned. When the Proxy is no longer needed, ReleaseProxy() should be
// called with it. If no notifications are desired, give a
// negative number for notify_tid or omit it. Note the the Proxy returned
// is a shared data-structure and shouldn't be delete'd or modified by
// the caller.
// If AcquireProxy() encounters an error, it will store an error message
// in the error parameter and return NULL. If the job ad doesn't contain
// any proxy-related attributes, AcquireProxy() will store the empty
// string in the error parameter and return NULL.
Proxy *
AcquireProxy( const ClassAd *job_ad, std::string &error,
			  TimerHandlercpp func_ptr, Service *data  )
{
	if ( proxymanager_initialized == false ) {
		error = "Internal Error: ProxyManager not initialized";
		return NULL;
	}

	int expire_time;
	Proxy *proxy = NULL;
	ProxySubject *proxy_subject = NULL;
	char *subject_name = NULL;
	char *fqan = NULL;
	char *email = NULL;
	char *first_fqan = NULL;
	std::string proxy_path;
	std::string owner;
	char *param_str = NULL;
	bool has_voms_attrs = false;

	if ( job_ad->LookupString( ATTR_OWNER, owner ) ) {
		std::string param_name;
		formatstr( param_name, "JOB_PROXY_OVERRIDE_FILE_%s", owner.c_str() );
		param_str = param( param_name.c_str() );
	}
	if ( param_str == NULL ) {
		param_str = param( "JOB_PROXY_OVERRIDE_FILE" );
	}
	if ( param_str ) {
		proxy_path = param_str;
		free( param_str );
	} else if ( job_ad->LookupString( ATTR_X509_USER_PROXY,
									  proxy_path ) == 0 ) {

		// Special handling for "use best proxy"
		job_ad->LookupString( ATTR_X509_USER_PROXY_FQAN, &fqan );
		job_ad->LookupString( ATTR_X509_USER_PROXY_FIRST_FQAN, &first_fqan );
		job_ad->LookupString( ATTR_X509_USER_PROXY_SUBJECT, &subject_name );
		job_ad->LookupString( ATTR_X509_USER_PROXY_EMAIL, &email );
		if ( subject_name ) {
			if ( fqan == NULL ) {
				fqan = strdup( subject_name );
			} else {
				has_voms_attrs = true;
			}
			if ( SubjectsByName.lookup( HashKey(fqan),
										proxy_subject ) != 0 ) {
				// We don't know about this proxy subject yet,
				// create a new ProxySubject and fill it out
				std::string tmp;
				proxy_subject = new ProxySubject;
				proxy_subject->subject_name = strdup( subject_name );
				if (email)
					proxy_subject->email = strdup( email );
				else
					proxy_subject->email = NULL;
				proxy_subject->fqan = fqan ? strdup( fqan ) : NULL;
				proxy_subject->first_fqan = first_fqan ? strdup( first_fqan ) : NULL;
				proxy_subject->has_voms_attrs = has_voms_attrs;

				// Create a master proxy for our new ProxySubject
				Proxy *new_master = new Proxy;
				new_master->id = next_proxy_id++;
				formatstr( tmp, "%s/master_proxy.%d", masterProxyDirectory,
							 new_master->id );
				new_master->proxy_filename = strdup( tmp.c_str() );
				new_master->num_references = 0;
				new_master->subject = proxy_subject;
				//SetMasterProxy( new_master, proxy );
				new_master->expiration_time = -1;
				new_master->near_expired = true;
				ProxiesByFilename.insert( HashKey(new_master->proxy_filename),
										  new_master );

				proxy_subject->master_proxy = new_master;

				SubjectsByName.insert(HashKey(proxy_subject->fqan),
									  proxy_subject);
			}
			// Now that we have a proxy_subject, return it's master proxy
			proxy = proxy_subject->master_proxy;
			proxy->num_references++;
			if ( func_ptr ) {
				Callback cb;
				cb.m_func_ptr = func_ptr;
				cb.m_data = data;
				if ( proxy->m_callbacks.IsMember( cb ) == false ) {
					proxy->m_callbacks.Append( cb );
				}
			}
			free( subject_name );
			if ( email )
				free( email );
			free( fqan );
			free( first_fqan );
			return proxy;

		}

		free( subject_name );
		free( email );
		free( fqan );
		free( first_fqan );
		//sprintf( error, "%s is not set in the job ad", ATTR_X509_USER_PROXY );
		error = "";
		return NULL;
	}

	// If Condor-C submitted the job, the proxy_path is relative to the
	// spool directory.  For the purposes of this function, extend the
	// proxy path with the ATTR_JOB_IWD
	if (proxy_path[0] != DIR_DELIM_CHAR) {
		std::string iwd;
		job_ad->LookupString(ATTR_JOB_IWD, iwd);
		if (!iwd.empty()) {
			std::stringstream ss;
			ss << iwd << DIR_DELIM_CHAR << proxy_path;
			proxy_path = ss.str();
		}
	}

	if ( ProxiesByFilename.lookup( HashKey(proxy_path.c_str()), proxy ) == 0 ) {
		// We already know about this proxy,
		// use the existing Proxy struct
		proxy->num_references++;
		if ( func_ptr ) {
			Callback cb;
			cb.m_func_ptr = func_ptr;
			cb.m_data = data;
			if ( proxy->m_callbacks.IsMember( cb ) == false ) {
				proxy->m_callbacks.Append( cb );
			}
		}
		return proxy;

	} else {

		// We don't know about this proxy yet,
		// find the proxy's expiration time and subject name
		expire_time = x509_proxy_expiration_time( proxy_path.c_str() );
		if ( expire_time < 0 ) {
			dprintf( D_ALWAYS, "Failed to get expiration time of proxy %s\n",
					 proxy_path.c_str() );
			error = "Failed to get expiration time of proxy";
			return NULL;
		}
		subject_name = x509_proxy_identity_name( proxy_path.c_str() );
		if ( subject_name == NULL ) {
			dprintf( D_ALWAYS, "Failed to get identity of proxy %s\n",
					 proxy_path.c_str() );
			error = "Failed to get identity of proxy";
			return NULL;
		}

		email = x509_proxy_email( proxy_path.c_str() );

		fqan = NULL;
#if defined(HAVE_EXT_GLOBUS)
		int rc = extract_VOMS_info_from_file( proxy_path.c_str(), 0, NULL,
											  &first_fqan, &fqan );
		if ( rc != 0 && rc != 1 ) {
			dprintf( D_ALWAYS, "Failed to get voms info of proxy %s\n",
					 proxy_path.c_str() );
			error = "Failed to get voms info of proxy";
			free( subject_name );
			free( email );
			return NULL;
		}
#endif
		if ( fqan ) {
			has_voms_attrs = true;
		} else {
			fqan = strdup( subject_name );
		}

		// Create a Proxy struct for our new proxy and populate it
		proxy = new Proxy;
		proxy->proxy_filename = strdup(proxy_path.c_str());
		proxy->num_references = 1;
		proxy->expiration_time = expire_time;
		proxy->near_expired = (expire_time - time(NULL)) <= minProxy_time;
		proxy->id = next_proxy_id++;
		if ( func_ptr ) {
			Callback cb;
			cb.m_func_ptr = func_ptr;
			cb.m_data = data;
			if ( proxy->m_callbacks.IsMember( cb ) == false ) {
				proxy->m_callbacks.Append( cb );
			}
		}

		ProxiesByFilename.insert(HashKey(proxy_path.c_str()), proxy);

		if ( SubjectsByName.lookup( HashKey(fqan), proxy_subject ) != 0 ) {
			// We don't know about this proxy subject yet,
			// create a new ProxySubject and fill it out
			std::string tmp;
			proxy_subject = new ProxySubject;
			proxy_subject->subject_name = strdup( subject_name );
			proxy_subject->email = email ? strdup( email ) : NULL;
			proxy_subject->fqan = strdup( fqan );
			proxy_subject->first_fqan = first_fqan ? strdup( first_fqan ) : NULL;
			proxy_subject->has_voms_attrs = true;

			// Create a master proxy for our new ProxySubject
			Proxy *new_master = new Proxy;
			new_master->id = next_proxy_id++;
			formatstr( tmp, "%s/master_proxy.%d", masterProxyDirectory,
						 new_master->id );
			new_master->proxy_filename = strdup( tmp.c_str() );
			new_master->num_references = 0;
			new_master->subject = proxy_subject;
			SetMasterProxy( new_master, proxy );
			ProxiesByFilename.insert( HashKey(new_master->proxy_filename),
									  new_master );

			proxy_subject->master_proxy = new_master;

			SubjectsByName.insert(HashKey(proxy_subject->fqan),
								  proxy_subject);
		}

		proxy_subject->proxies.Append( proxy );

		proxy->subject = proxy_subject;

		// If the new Proxy is longer-lived than the current master proxy for
		// this subject, copy it for the new master.
		if ( proxy->expiration_time > proxy_subject->master_proxy->expiration_time ) {
			SetMasterProxy( proxy_subject->master_proxy, proxy );
		}

		free( subject_name );
		free( email );
		free( fqan );
		free( first_fqan );
	}

		// MyProxy crap
	std::string buff;
	if ( job_ad->LookupString( ATTR_MYPROXY_HOST_NAME, buff ) ) {

		int cluster;
		int proc;

		ASSERT( job_ad->LookupInteger( ATTR_CLUSTER_ID, cluster ) );
		ASSERT( job_ad->LookupInteger( ATTR_PROC_ID, proc ) );

		MyProxyEntry * myProxyEntry =new MyProxyEntry();

		myProxyEntry->last_invoked_time=0;
		myProxyEntry->get_delegation_pid=FALSE;
		myProxyEntry->get_delegation_err_fd=-1;
		myProxyEntry->get_delegation_err_filename=NULL;
		myProxyEntry->myproxy_server_dn=NULL;
		myProxyEntry->myproxy_password=NULL;
		myProxyEntry->myproxy_credential_name=NULL;

		myProxyEntry->myproxy_host=strdup(buff.c_str());
		myProxyEntry->cluster_id = cluster;
		myProxyEntry->proc_id = proc;

		// Get optional MYPROXY_SERVER_DN attribute
		if (job_ad->LookupString (ATTR_MYPROXY_SERVER_DN, buff)) {
			myProxyEntry->myproxy_server_dn=strdup(buff.c_str());
		}

		if (job_ad->LookupString (ATTR_MYPROXY_CRED_NAME, buff)) {
			myProxyEntry->myproxy_credential_name=strdup(buff.c_str());
		}

		if (job_ad->LookupInteger (ATTR_MYPROXY_REFRESH_THRESHOLD, myProxyEntry->refresh_threshold)) {
			//myProxyEntry->refresh_threshold=atoi(buff);	// In minutes
			dprintf (D_FULLDEBUG, "MyProxy Refresh Threshold %d\n",myProxyEntry->refresh_threshold);
		} else {
			myProxyEntry->refresh_threshold = 4*60;	// default 4 hrs
			dprintf (D_FULLDEBUG, "MyProxy Refresh Threshold %d (default)\n",myProxyEntry->refresh_threshold);
		}

		if (job_ad->LookupInteger (ATTR_MYPROXY_NEW_PROXY_LIFETIME, myProxyEntry->new_proxy_lifetime)) {
			//myProxyEntry->new_proxy_lifetime=atoi(buff); // In hours
			dprintf (D_FULLDEBUG, "MyProxy New Proxy Lifetime %d\n",myProxyEntry->new_proxy_lifetime);
		} else {
			myProxyEntry->new_proxy_lifetime = 12; // default 12 hrs
			dprintf (D_FULLDEBUG, "MyProxy New Proxy Lifetime %d (default)\n",myProxyEntry->new_proxy_lifetime);
		}

		dprintf (D_FULLDEBUG,
				 "Adding new MyProxy entry for proxy %s : host=%s, cred name=%s\n",
				 proxy->proxy_filename,
				 myProxyEntry->myproxy_host,
				 (myProxyEntry->myproxy_credential_name!=NULL)?(myProxyEntry->myproxy_credential_name):"<default>");
		proxy->myproxy_entries.Prepend (myProxyEntry); // Add at the top of the list, so it'll be used first

		// See if we already have a MyProxy entry for the given host/credential name
		/*int found = FALSE;
		MyProxyEntry * currentMyProxyEntry = NULL;
		jobProxy->myproxy_entries.Rewind();
			while (jobProxy->myproxy_entries.Next (currentMyProxyEntry)) {
			if (strcmp (currentMyProxyEntry->myproxy_host, myProxyEntry->myproxy_host)) {
				continue;
			}
				if (myProxyEntry->myproxy_credential_name == NULL || myProxyEntry->myproxy_credential_name == NULL) {
				if (myProxyEntry->myproxy_credential_name != NULL || myProxyEntry->myproxy_credential_name != NULL) {
					// One credential name is NULL, the other is not
					continue;
				}
			} else {
				if (strcmp (currentMyProxyEntry->myproxy_credential_name, myProxyEntry->myproxy_credential_name))  {
					// credential names non-null and not-equal
					continue;
				}
			}

			// If we've gotten this far, we've got a match
			found = TRUE;
			break;
		}

		//... If we don't, insert it
		if (!found) {
			dprintf (D_FULLDEBUG,
					 "Adding new MyProxy entry for proxy %s : host=%s, cred name=%s\n",
					 jobProxy->proxy_filename,
					 myProxyEntry->myproxy_host,
					 (myProxyEntry->myproxy_credential_name!=NULL)?(myProxyEntry->myproxy_credential_name):"<default>");
			jobProxy->myproxy_entries.Append (myProxyEntry);
		} else {
			// No need to insert this
			delete myProxyEntry;
		}*/
	}

	return proxy;
}
Beispiel #2
0
Condor_Auth_X509::CondorAuthX509Retval
Condor_Auth_X509::authenticate_server_gss(CondorError* errstack, bool non_blocking)
{
	OM_uint32 major_status = GSS_S_COMPLETE;
	OM_uint32 minor_status = 0;

	OM_uint32				time_req;
	gss_buffer_desc			output_token_desc = GSS_C_EMPTY_BUFFER;
	gss_buffer_t			output_token = &output_token_desc;
	gss_buffer_desc         input_token_desc;
	gss_buffer_t            input_token;

    if ( !m_globusActivated ) {
        errstack->push("GSI", GSI_ERR_AUTHENTICATION_FAILED,
                       "Failed to load Globus libraries.");
        return Fail;
    }

	m_state = GSSAuth;
	do
	{
		if (non_blocking && !mySock_->readReady())
		{
			dprintf(D_NETWORK, "Returning to DC as read would block.\n");
			return WouldBlock;
		}

		input_token_desc.length = 0;
		input_token_desc.value = NULL;
		input_token = &input_token_desc;

		if ((token_status = relisock_gsi_get(
			mySock_,
			&input_token->value,
			&input_token->length)) != 0)
		{
			major_status =
				GSS_S_DEFECTIVE_TOKEN | GSS_S_CALL_INACCESSIBLE_READ;
			break;
		}

		dprintf(D_NETWORK, "gss_assist_accept_sec_context(1):inlen:%lu\n", static_cast<unsigned long>(input_token->length));

		major_status = (*gss_accept_sec_context_ptr)(
			&minor_status,
			&context_handle,
			credential_handle,
			input_token,
			GSS_C_NO_CHANNEL_BINDINGS,
			&m_client_name,
			NULL,
			output_token,
			&ret_flags,
			&time_req,
			NULL);

		dprintf(D_NETWORK, "gss_assist_accept_sec_context(2)"
			"maj:%8.8x:min:%8.8x:ret:%8.8x "
			"outlen:%lu:context:%p\n",
			(unsigned int) major_status,
			(unsigned int) minor_status,
			(unsigned int) ret_flags,
			output_token->length,
			context_handle);

		if (output_token->length != 0)
		{
			if ((token_status = relisock_gsi_put(
				mySock_,
				output_token->value,
				output_token->length)) != 0)
			{
				major_status =
				GSS_S_DEFECTIVE_TOKEN | GSS_S_CALL_INACCESSIBLE_WRITE;
			}
			(*gss_release_buffer_ptr)(&minor_status, output_token);
		}
		if (GSS_ERROR(major_status))
		{
			if (context_handle != GSS_C_NO_CONTEXT)
			{
				(*gss_delete_sec_context_ptr)(&minor_status, &context_handle, GSS_C_NO_BUFFER);
			}
			break;
		}

		if (input_token->length >0)
		{
			free(input_token->value);
			input_token->length = 0;
		}
	}
	while (major_status & GSS_S_CONTINUE_NEEDED);

	if (input_token->length >0)
	{
		free(input_token->value);
		input_token->length = 0;
	}

    m_status = 0;
    if ( (major_status != GSS_S_COMPLETE)) {
		if (major_status == 655360) {
			errstack->pushf("GSI", GSI_ERR_AUTHENTICATION_FAILED,
				"COMMON Failed to authenticate (%u:%u)", (unsigned)major_status, (unsigned)minor_status);
		} else {
			errstack->pushf("GSI", GSI_ERR_AUTHENTICATION_FAILED,
				"Failed to authenticate.  Globus is reporting error (%u:%u)",
				(unsigned)major_status, (unsigned)minor_status);
		}
        print_log(major_status,minor_status,token_status, 
                  "Condor GSI authentication failure" );
    }
    else {

		gss_buffer_desc                     tmp_buffer_desc = GSS_C_EMPTY_BUFFER;
		gss_buffer_t                        tmp_buffer = &tmp_buffer_desc;
		char * gss_name = NULL;
		major_status = (*gss_display_name_ptr)(&minor_status,
			m_client_name,
			tmp_buffer,
			NULL);
		if (major_status == GSS_S_COMPLETE)
		{
			gss_name = (char *)malloc(tmp_buffer->length+1);
			if (gss_name)
			{
				memcpy(gss_name, tmp_buffer->value, tmp_buffer->length);
				gss_name[tmp_buffer->length] = '\0';
			}
			else
			{
				errstack->pushf("GSI", GSI_ERR_AUTHENTICATION_FAILED, "Unable to allocate buffer");
				major_status = GSS_S_FAILURE;
			}
		}
		else
		{
			errstack->pushf("GSI", GSI_ERR_AUTHENTICATION_FAILED, "Unable to determine remote client name.  Globus is reporting error (%u:%u)",
				(unsigned)major_status, (unsigned)minor_status);
		}
		(*gss_release_buffer_ptr)(&minor_status, tmp_buffer);

		classad::ClassAd ad;

		// store the raw subject name for later mapping
		if (gss_name) {
			setAuthenticatedName(gss_name);
			ad.InsertAttr(ATTR_X509_USER_PROXY_SUBJECT, gss_name);
			free(gss_name);
		}
		setRemoteUser("gsi");
		setRemoteDomain( UNMAPPED_DOMAIN );

		// get handle to cred so we can extract other attributes
		globus_gsi_cred_handle_t peer_cred = context_handle->peer_cred_handle->cred_handle;

		time_t expiration = x509_proxy_expiration_time(peer_cred);
		if (expiration != -1) {
			ad.InsertAttr(ATTR_X509_USER_PROXY_EXPIRATION, expiration);
		}

		char *email_name = x509_proxy_email(peer_cred);
		if (email_name)
		{
			ad.InsertAttr(ATTR_X509_USER_PROXY_EMAIL, email_name);
			free(email_name);
		}

		if (param_boolean("USE_VOMS_ATTRIBUTES", true)) {

			// get the voms attributes from the peer

			char * voname = NULL;
			char * firstfqan = NULL;
			char * voms_fqan = NULL;
			int voms_err = extract_VOMS_info(peer_cred, 1, &voname, &firstfqan, &voms_fqan);
			if (!voms_err) {
				setFQAN(voms_fqan);
				if (voms_fqan) {ad.InsertAttr(ATTR_X509_USER_PROXY_FQAN, voms_fqan);}
				free(voms_fqan);
				if (firstfqan) {ad.InsertAttr(ATTR_X509_USER_PROXY_FIRST_FQAN, firstfqan);}
				free(firstfqan);
				if (voname) {ad.InsertAttr(ATTR_X509_USER_PROXY_VONAME, voname);}
				free(voname);
			} else {
				// complain!
				dprintf(D_SECURITY, "ZKM: VOMS FQAN not present (error %i), ignoring.\n", voms_err);
			}
		}
		mySock_->setPolicyAd(ad);

		// XXX FIXME ZKM
		// i am making failure to be mapped a non-fatal error at this point.
		m_status = (major_status == GSS_S_COMPLETE);

        mySock_->encode();
        if (!mySock_->code(m_status) || !mySock_->end_of_message()) {
			errstack->push("GSI", GSI_ERR_COMMUNICATIONS_ERROR,
				"Failed to authenticate with client.  Unable to send status");
            dprintf(D_SECURITY, "Unable to send final confirmation\n");
            m_status = 0;
        }
	}

	m_state = GetClientPost;
	return (m_status == 0) ? Fail : Continue;
}