Example #1
0
int Condor_Auth_X509::nameGssToLocal(const char * GSSClientname) 
{
	//this might need to change with SSLK5 stuff
	//just extract username from /CN=<username>@<domain,etc>
	OM_uint32 major_status;
	char *tmp_user = NULL;
	char local_user[USER_NAME_MAX];

// windows gsi does not currently include this function.  we use it on
// unix, but implement our own on windows for now.
#ifdef WIN32
	major_status = condor_gss_assist_gridmap(GSSClientname, &tmp_user);
#else
// Switched the unix map function to _map_and_authorize, which allows access
// to the Globus callout infrastructure.
        char condor_str[] = "condor";
	major_status = globus_gss_assist_map_and_authorize(
            context_handle,
            condor_str, // Requested service name
            NULL, // Requested user name; NULL for non-specified
            local_user,
            USER_NAME_MAX-1); // Leave one space at end of buffer, just-in-case
        // Defensive programming: to protect against buffer overruns in the
        // unknown globus mapping module, make sure we are at least nul-term'd
        local_user[USER_NAME_MAX-1] = '\0';
#endif

	if (tmp_user) {
		strcpy( local_user, tmp_user );
		free(tmp_user);
		tmp_user = NULL;
	}

	if ( major_status != GSS_S_COMPLETE) {
		setRemoteUser("gsi");
		setRemoteDomain( UNMAPPED_DOMAIN );
		return 0;
	}

	MyString user;
	MyString domain;
	Authentication::split_canonical_name( local_user, user, domain );
    
	setRemoteUser  (user.Value());
	setRemoteDomain(domain.Value());
	setAuthenticatedName(GSSClientname);
	return 1;
}
int Condor_Auth_Anonymous :: authenticate(const char * /* remoteHost */, CondorError* /* errstack */, bool /*non_blocking*/)
{
    int retval = 0;
    
    // very simple for right now, server just set the remote user to
    // be anonymous directly
    if ( mySock_->isClient() ) {
        mySock_->decode();
        mySock_->code( retval );
        mySock_->end_of_message();
    } 
    else { //server side
        setRemoteUser( STR_ANONYMOUS );
		setAuthenticatedName( STR_ANONYMOUS );
        mySock_->encode();
        retval = 1;
        mySock_->code( retval );
        mySock_->end_of_message();
    }
    
    return retval;
}
int
Condor_Auth_Passwd::authenticate(const char * /* remoteHost */, 
								 CondorError* /* errstack */ )
{
    int client_status = AUTH_PW_A_OK;
    int server_status = AUTH_PW_A_OK;
	int ret_value = -1;
    
    struct msg_t_buf t_client;
    struct msg_t_buf t_server;

		// In order to create the shared keys used by the client and
		// the server in this protocol, we take a single shared secret
		// and hmac it twice with two different keys.  The original
		// password buffer and the two generated keys are stored in
		// the sk_buf structure.
    struct sk_buf sk;

	int tmp_rv;

		// Initialize these structures (with NULLs)
    init_t_buf(&t_client);
    init_t_buf(&t_server);
    init_sk(&sk);
	dprintf(D_SECURITY, "PW.\n");

	if ( mySock_->isClient() ) {
			// ** client side authentication **
        
			// Get my name, password and setup the shared keys based
			// on this data.  The server will do the same when it
			// learns my name.
		dprintf(D_SECURITY, "PW: getting name.\n");
        t_client.a = fetchLogin();

			// We complete the entire protocol even if there's an
			// error, but there's no point trying to actually do any
			// work.  This is protocol step (a).
		dprintf(D_SECURITY, "PW: Generating ra.\n");
	        
        if(client_status == AUTH_PW_A_OK) {
			t_client.ra = Condor_Crypt_Base::randomKey(AUTH_PW_KEY_LEN);
			if(!t_client.ra) {
				dprintf(D_SECURITY, "Malloc error in random key?\n");
				client_status = AUTH_PW_ERROR;
			}
        }
        
			// This differs from the protocol description in the book
			// only that the client also sends its name "A".  The
			// protocol doesn't mention how the peers know who they're
			// talking to.  This is also protocol step (a).
		dprintf(D_SECURITY, "PW: Client sending.\n");
        client_status = client_send_one(client_status, &t_client);

		if(client_status == AUTH_PW_ABORT) {
			goto client_abort;
		}
			// This is protocol step (b).
		dprintf(D_SECURITY, "PW: Client receiving.\n");
        server_status = client_receive(&client_status, &t_server);
		if(client_status == AUTH_PW_ABORT) {
			goto client_abort;
		}

			// Now that we've received the server's name, we can go
			// ahead and setup the keys.
		if(client_status == AUTH_PW_A_OK && server_status == AUTH_PW_A_OK) {
			sk.shared_key = fetchPassword(t_client.a, t_server.b);
			dprintf(D_SECURITY, "PW: Client setting keys.\n");
			if(!setup_shared_keys(&sk)) {
				client_status = AUTH_PW_ERROR;
			}
		}

			// This is protocol step (c).
		if(client_status == AUTH_PW_A_OK
		   && server_status == AUTH_PW_A_OK) {
			dprintf(D_SECURITY, "PW: Client checking T.\n");
			client_status = client_check_t_validity(&t_client, &t_server, &sk);
		}

			// Are we copying the data into the t_client struct?
			// This is protocol step (d).  Server does (e).
		dprintf(D_SECURITY, "PW: CLient sending two.\n");
        client_status = client_send_two(client_status, &t_client, &sk);
		if(client_status == AUTH_PW_ABORT) {
			goto client_abort;
		}

	client_abort:
			// This is protocol step (f).
		if(client_status == AUTH_PW_A_OK
		   && server_status == AUTH_PW_A_OK
		   && set_session_key(&t_client, &sk)) {
			dprintf(D_SECURITY, "PW: CLient set session key.\n");
			ret_value = 1;
		} else {
			ret_value = 0;
		}
	}
	else {
			// ** server side authentication **
		
			// First we get the client's name and ra, protocol step
			// (a).
		dprintf(D_SECURITY, "PW: Server receiving 1.\n");
		client_status = server_receive_one(&server_status, &t_client);
		if(client_status == AUTH_PW_ABORT || server_status == AUTH_PW_ABORT) {
			goto server_abort;
		}

			// Then we do the key setup, and generate the random string.
		if(client_status == AUTH_PW_A_OK && server_status == AUTH_PW_A_OK) {
			t_server.b = fetchLogin();
			dprintf(D_SECURITY, "PW: Server fetching password.\n");
			sk.shared_key = fetchPassword(t_client.a, t_server.b);
			if(!setup_shared_keys(&sk)) {
				server_status = AUTH_PW_ERROR;
			} else {
				dprintf(D_SECURITY, "PW: Server generating rb.\n");
		//server_status = server_gen_rand_rb(&t_server);
	            t_server.rb = Condor_Crypt_Base::randomKey(AUTH_PW_KEY_LEN);
				if(t_client.a) {
					t_server.a = strdup(t_client.a);
				} else {
					t_server.a = NULL;
				}
				t_server.ra = (unsigned char *)malloc(AUTH_PW_KEY_LEN);
				if(!t_server.ra || !t_server.rb) {
					dprintf(D_SECURITY, "Malloc error 1.\n"); 
					server_status = AUTH_PW_ERROR;
				} else {
					memcpy(t_server.ra, t_client.ra, AUTH_PW_KEY_LEN);
				}
			}
		}

			// Protocol message (2), step (b).
		dprintf(D_SECURITY, "PW: Server sending.\n");
		tmp_rv = server_send(server_status, &t_server, &sk);
		if(server_status == AUTH_PW_A_OK) {
			server_status = tmp_rv;
		}
		if(server_status == AUTH_PW_ABORT) {
			goto server_abort;
		}

			// Protocol step (d)
		dprintf(D_SECURITY, "PW: Server receiving 2.\n");
		if(t_server.a) {
			t_client.a = strdup(t_server.a);
		} else { 
			t_client.a = NULL;
		}
        if(server_status == AUTH_PW_A_OK) {
			t_client.rb = (unsigned char *)malloc(AUTH_PW_KEY_LEN);
			if(!t_client.rb) {
				dprintf(D_SECURITY, "Malloc_error.\n");
				server_status = AUTH_PW_ERROR;
			} else {
				memcpy(t_client.rb, t_server.rb, AUTH_PW_KEY_LEN);
			}
		} else {
			t_client.rb = NULL;
		}
		client_status = server_receive_two(&server_status, &t_client);

		if(server_status == AUTH_PW_A_OK
		   && client_status == AUTH_PW_A_OK) {
				// Protocol step (e)
			dprintf(D_SECURITY, "PW: Server checking hk.\n");
			server_status = server_check_hk_validity(&t_client, 
													 &t_server, &sk);
		}
		
	server_abort:
				// protocol step (f)
		if(client_status == AUTH_PW_A_OK
		   && server_status == AUTH_PW_A_OK
		   && set_session_key(&t_server, &sk)) {
			dprintf(D_SECURITY, "PW: Server set session key.\n");
			ret_value = 1;
		} else {
			ret_value = 0;
		}
		
	}

		//ret_value is 1 for success, 0 for failure.
	if ( ret_value == 1 ) {
			// if all is good, set the remote user and domain names
		char *login, *domain;
		if ( mySock_->isClient() ) {
			login = t_server.b;	// server is remote to client
		} else {
			login = t_client.a; // client is remote to server
		}
		ASSERT(login);
		domain = strchr(login,'@');
		if (domain) {
			*domain='\0';
			domain++;
		}

		setRemoteUser(login);
		setRemoteDomain(domain);
	}

	destroy_t_buf(&t_client);
	destroy_t_buf(&t_server);
	destroy_sk(&sk);

		//return 1 for success, 0 for failure. Server should send
		//sucess/failure back to client so client can know what to
		//return.
	return ret_value;
}
Example #4
0
int Condor_Auth_Claim :: authenticate(const char * /* remoteHost */, CondorError* /* errstack */, bool /*non_blocking*/)
{

	const char * pszFunction = "Condor_Auth_Claim :: authenticate";

	int retval = 0;
	int fail = 0;

	if ( mySock_->isClient() ) {

		MyString myUser;
		bool error_getting_name = false;

		// get our user name in condor priv
		// (which is what we want to use for daemons. for
		//  tools and daemons not started as root, this will
		//  just give us the username that we were invoked
		//  as, which is also what we want)
		priv_state priv = set_condor_priv();
		char* tmpOwner = NULL; 
		char* tmpSwitchUser = param("SEC_CLAIMTOBE_USER");
		if(tmpSwitchUser) {
			tmpOwner = tmpSwitchUser;
			dprintf(D_ALWAYS, "SEC_CLAIMTOBE_USER to %s!\n", tmpSwitchUser);
		} else {
			tmpOwner = my_username();
		}
		// remove temptation to use this variable to see if we were
		// specifying the claim to be user
		tmpSwitchUser = NULL;
		set_priv(priv);
		if ( !tmpOwner ) {
			//send 0
			if (!mySock_->code( retval )) { 
				dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
					pszFunction, __LINE__);
				return fail; 
			}
			error_getting_name = true;
		}
		else {
			myUser = tmpOwner;
			free(tmpOwner);

			// check SEC_CLAIMTOBE_INCLUDE_DOMAIN. this knob exists (and defaults
			// to false) to provide backwards compatibility. it will be removed
			// completely in the development (6.9) series
			if (param_boolean("SEC_CLAIMTOBE_INCLUDE_DOMAIN", false)) {
				char* tmpDomain = param("UID_DOMAIN");
				if ( !tmpDomain ) {
					//send 0
					if (!mySock_->code( retval )) { 
						dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
							pszFunction, __LINE__);
						return fail; 
					}
					error_getting_name = true;
				}
				else {
					myUser += "@";
					myUser += tmpDomain;
					free(tmpDomain);
				}
			}
		}

		if (!error_getting_name) {

			//send 1 and then our username
			mySock_->encode();
			retval = 1;
			char* tmpUser = strdup(myUser.Value());
			ASSERT(tmpUser);
			if (!mySock_->code( retval ) || 
			    !mySock_->code( tmpUser ))
			{
				free(tmpUser);
				dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
					pszFunction, __LINE__);
				return fail; 
			}
			//setRemoteUser(tmpUser); // <-- IS THIS NEEDED????
			free(tmpUser);
			if (!mySock_->end_of_message()) { 
				dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
					pszFunction, __LINE__);
				return fail;
			}
			mySock_->decode();
			if (!mySock_->code( retval )) {
				dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
					pszFunction, __LINE__);
				return fail; 
			}
		}

	} else { //server side

		mySock_->decode();
		if (!mySock_->code( retval )) { 
			dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
				pszFunction, __LINE__);
			return fail; 
		}

		//if 1, receive user and send back ok
		if( retval == 1 ) {

			char* tmpUser = NULL;
			if (!mySock_->code( tmpUser ) ||
			    !mySock_->end_of_message())
			{
				dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
					pszFunction, __LINE__);
				if (tmpUser != NULL)
				{
					free(tmpUser);
				}
				return fail;
			}

			if( tmpUser ) {

				MyString myUser = tmpUser;

				// check SEC_CLAIMTOBE_INCLUDE_DOMAIN. this knob exists (and defaults
				// to false) to provide backwards compatibility. it will be removed
				// completely in the development (6.9) series
				if (param_boolean("SEC_CLAIMTOBE_INCLUDE_DOMAIN", false)) {
					// look for an '@' char in the name we received.
					// if present (newer clients), set the domain using
					// the given component. if not present (older clients),
					// use UID_DOMAIN from our config
					char* tmpDomain = NULL;
					char* at = strchr(tmpUser, '@');
					if ( at ) {
						*at = '\0';
						if (*(at + 1) != '\0') {
							tmpDomain = strdup(at + 1);
						}
					}
					if (!tmpDomain) {
						tmpDomain = param("UID_DOMAIN");
					}
					ASSERT(tmpDomain);
					setRemoteDomain(tmpDomain);
					myUser.formatstr("%s@%s", tmpUser, tmpDomain);
					free(tmpDomain);
				}
				setRemoteUser(tmpUser);
				setAuthenticatedName(myUser.Value());
				free(tmpUser);
				retval = 1;
			} else {
				// tmpUser is NULL; failure
				retval = 0;
			}

			mySock_->encode();
			if (!mySock_->code( retval )) { 
				dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
					pszFunction, __LINE__);
				return fail;
			}
		}
	}
    
	if (!mySock_->end_of_message()) { 
		dprintf(D_SECURITY, "Protocol failure at %s, %d!\n", 
			pszFunction, __LINE__);
		return fail; 
	}

	return retval;
}
int Condor_Auth_X509::authenticate_server_gss(CondorError* errstack)
{
    char *    GSSClientname;
    int       status = 0;
    OM_uint32 major_status = 0;
    OM_uint32 minor_status = 0;

    priv_state priv;
    
    priv = set_root_priv();
    
    major_status = globus_gss_assist_accept_sec_context(&minor_status,
                                                        &context_handle, 
                                                        credential_handle,
                                                        &GSSClientname,
                                                        &ret_flags, NULL,
                                                        /* don't need user_to_user */
                                                        &token_status,
                                                        NULL,     /* don't delegate credential */
                                                        relisock_gsi_get, 
                                                        (void *) mySock_,
                                                        relisock_gsi_put, 
                                                        (void *) mySock_
                                                        );
    
    set_priv(priv);
    
    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 {
		// store the raw subject name for later mapping
		setAuthenticatedName(GSSClientname);
		setRemoteUser("gsi");
		setRemoteDomain( UNMAPPED_DOMAIN );

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

			// get the voms attributes from the peer
			globus_gsi_cred_handle_t peer_cred = context_handle->peer_cred_handle->cred_handle;

			char * voms_fqan = NULL;
			int voms_err = extract_VOMS_info(peer_cred, 1, NULL, NULL, &voms_fqan);
			if (!voms_err) {
				setFQAN(voms_fqan);
				free(voms_fqan);
			} else {
				// complain!
				dprintf(D_SECURITY, "ZKM: VOMS FQAN not present (error %i), ignoring.\n", voms_err);
			}
		}

		// XXX FIXME ZKM
		// i am making failure to be mapped a non-fatal error at this point.
		status = 1;

        mySock_->encode();
        if (!mySock_->code(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");
            status = 0;
        }

        if (status != 0) {
            // Now, see if client likes me or not
            mySock_->decode();
            if (!mySock_->code(status) || !mySock_->end_of_message()) {
				errstack->push("GSI", GSI_ERR_COMMUNICATIONS_ERROR,
					"Failed to authenticate with client.  Unable to receive status");
                dprintf(D_SECURITY, "Unable to receive client confirmation.\n");
                status = 0;
            }
            else {
                if (status == 0) {
					errstack->push("GSI", GSI_ERR_COMMUNICATIONS_ERROR,
						"Failed to authenticate with client.  Client does not trust our certificate.  "
						"You may want to check the GSI_DAEMON_NAME in the condor_config");
                    dprintf(D_SECURITY, "Client rejected my certificate. Please check the GSI_DAEMON_NAME parameter in Condor's config file.\n");
                }
            }
        }
        
        if (GSSClientname) {
            free(GSSClientname);
        }
    }
    return (status == 0) ? FALSE : TRUE;
}
int Condor_Auth_X509::authenticate_client_gss(CondorError* errstack)
{
    OM_uint32	major_status = 0;
    OM_uint32	minor_status = 0;
    int         status = 0;

    priv_state priv = PRIV_UNKNOWN;
    
    if (isDaemon()) {
        priv = set_root_priv();
    }
    
    char target_str[] = "GSI-NO-TARGET";
    major_status = globus_gss_assist_init_sec_context(&minor_status,
                                                      credential_handle,
                                                      &context_handle,
                                                      target_str,
                                                      GSS_C_MUTUAL_FLAG,
                                                      &ret_flags, 
                                                      &token_status,
                                                      relisock_gsi_get, 
                                                      (void *) mySock_,
                                                      relisock_gsi_put, 
                                                      (void *) mySock_
                                                      );
    
    if (isDaemon()) {
        set_priv(priv);
    }

    if (major_status != GSS_S_COMPLETE)	{
		if (major_status == 655360 && minor_status == 6) {
			errstack->pushf("GSI", GSI_ERR_AUTHENTICATION_FAILED,
				"Failed to authenticate.  Globus is reporting error (%u:%u).  "
				"This indicates that it was unable to find the issuer "
				"certificate for your credential", (unsigned)major_status, (unsigned)minor_status);
		} else if (major_status == 655360 && minor_status == 9) {
			errstack->pushf("GSI", GSI_ERR_AUTHENTICATION_FAILED,
				"Failed to authenticate.  Globus is reporting error (%u:%u).  "
				"This indicates that it was unable to verify the server's "
				"credential", (unsigned)major_status, (unsigned)minor_status);
		} else if (major_status == 655360 && minor_status == 11) {
			errstack->pushf("GSI", GSI_ERR_AUTHENTICATION_FAILED,
				"Failed to authenticate.  Globus is reporting error (%u:%u).  "
				"This indicates that it was unable verify the server's "
				"credentials because a signing policy file was not found or "
				"could not be read.", (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");
        // Following four lines of code is added to temporarily
        // resolve a bug (I belive so) in Globus's GSI code.
        // basically, if client calls init_sec_context with
        // mutual authentication and it returns with a mismatched
        // target principal, init_sec_context will return without
        // sending the server any token. The sever, therefore,
        // hangs on waiting for the token (or until the timeout
        // occurs). This code will force the server to break out
        // the loop.
        status = 0;
        mySock_->encode();
        mySock_->code(status);
        mySock_->end_of_message();
    }
    else {
        // Now, wait for final signal
        mySock_->decode();
        if (!mySock_->code(status) || !mySock_->end_of_message()) {
			errstack->push("GSI", GSI_ERR_COMMUNICATIONS_ERROR,
					"Failed to authenticate with server.  Unable to receive server status");
            dprintf(D_SECURITY, "Unable to receive final confirmation for GSI Authentication!\n");
        }
        if (status == 0) {
			errstack->push("GSI", GSI_ERR_AUTHENTICATION_FAILED,
				"Failed to get authorization from server.  Either the server "
				"does not trust your certificate, or you are not in the server's "
				"authorization file (grid-mapfile)");
            dprintf(D_SECURITY, "Server is unable to authorize my user name. Check the GRIDMAP file on the server side.\n");
            goto clear; 
        }

        char * server = get_server_info();

		// store the raw subject name for later mapping
		setAuthenticatedName(server);

		// Default to user name "gsi@unmapped".
		// Later on, if configured, we will invoke the callout in nameGssToLocal.
		setRemoteUser("gsi");
		setRemoteDomain( UNMAPPED_DOMAIN );

		// extract and store VOMS attributes
		if (param_boolean("USE_VOMS_ATTRIBUTES", true)) {

			// get the voms attributes from the peer
			globus_gsi_cred_handle_t peer_cred = context_handle->peer_cred_handle->cred_handle;

			char * voms_fqan = NULL;
			int voms_err = extract_VOMS_info(peer_cred, 1, NULL, NULL, &voms_fqan);
			if (!voms_err) {
				setFQAN(voms_fqan);
				free(voms_fqan);
			} else {
				// complain!
				dprintf(D_SECURITY, "ZKM: VOMS FQAN not present (error %i), ignoring.\n", voms_err);
			}
		}

        std::string fqh = get_full_hostname(mySock_->peer_addr());
        StringList * daemonNames = getDaemonList("GSI_DAEMON_NAME",fqh.c_str());

        // Now, let's see if the name is in the list, I am not using
        // anycase here, so if the host name and what we are looking for
        // are in different cases, then we will run into problems.
		if( daemonNames ) {
			status = daemonNames->contains_withwildcard(server) == TRUE? 1 : 0;

			if( !status ) {
				errstack->pushf("GSI", GSI_ERR_UNAUTHORIZED_SERVER,
								"Failed to authenticate because the subject '%s' is not currently trusted by you.  "
								"If it should be, add it to GSI_DAEMON_NAME or undefine GSI_DAEMON_NAME.", server);
				dprintf(D_SECURITY,
						"GSI_DAEMON_NAME is defined and the server %s is not specified in the GSI_DAEMON_NAME parameter\n",
						server);
			}
		}
		else {
			status = CheckServerName(fqh.c_str(),mySock_->peer_ip_str(),mySock_,errstack);
		}

        if (status) {
            dprintf(D_SECURITY, "valid GSS connection established to %s\n", server);            
        }

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

        delete [] server;
        delete daemonNames;
    }
 clear:
    return (status == 0) ? FALSE : TRUE;
}
int Condor_Auth_X509::nameGssToLocal(const char * GSSClientname) 
{
	//this might need to change with SSLK5 stuff
	//just extract username from /CN=<username>@<domain,etc>
	OM_uint32 major_status = GSS_S_COMPLETE;
	char *tmp_user = NULL;
	char local_user[USER_NAME_MAX];

// windows gsi does not currently include this function.  we use it on
// unix, but implement our own on windows for now.
#ifdef WIN32
	major_status = condor_gss_assist_gridmap(GSSClientname, &tmp_user);
#else
// Switched the unix map function to _map_and_authorize, which allows access
// to the Globus callout infrastructure.

	if (m_mapping == NULL) {
		// Size of hash table is purposely initialized small to prevent this
		// from hogging memory.  This will, of course, grow at large sites.
		m_mapping = new GlobusMappingTable(53, hashFuncString, updateDuplicateKeys);
	}
	const char *auth_name_to_map;
	const char *fqan = getFQAN();
	if (fqan && fqan[0]) {
		auth_name_to_map = fqan;
	}
	else {
		auth_name_to_map = GSSClientname;
	}

	globus_mapping_entry_ptr value;
	time_t now = 0;
	time_t gsi_cache_expiry = param_integer("GSS_ASSIST_GRIDMAP_CACHE_EXPIRATION", 0);
	if (gsi_cache_expiry && (m_mapping->lookup(auth_name_to_map, value) == 0)) {
		now = time(NULL);
		if (now < value->expiry_time) {
			dprintf(D_SECURITY, "Using Globus mapping result from the cache.\n");
			if (value->name.size()) {
				tmp_user = strdup(value->name.c_str());
			}
			else {
				major_status = GSS_S_FAILURE;
			}
		}
	}

	if ((tmp_user == NULL) && (major_status == GSS_S_COMPLETE)) {
		char condor_str[] = "condor";
		major_status = globus_gss_assist_map_and_authorize(
			context_handle,
			condor_str, // Requested service name
			NULL, // Requested user name; NULL for non-specified
			local_user,
			USER_NAME_MAX-1); // Leave one space at end of buffer, just-in-case
		// Defensive programming: to protect against buffer overruns in the
		// unknown globus mapping module, make sure we are at least nul-term'd
		local_user[USER_NAME_MAX-1] = '\0';

		// More defensive programming: There is a bug in LCMAPS, (which is possibly
		// called by a globus callout) that sometimes returns with the euid set to
		// root (!?!).  As a safeguard, We check for that here and return to the
		// condor euid.  This is done "outside" of the condor priv stack since this
		// is essentially undoing a side effect of the library call, not
		// intentionally changing priv state.
		if (geteuid() == 0) {
			dprintf(D_ALWAYS, "WARNING: globus returned with euid 0\n");
			// attempt to undo
			if (seteuid(get_condor_uid())) {
				// complain loudly, but continue
				dprintf(D_ALWAYS, "ERROR: something has gone terribly wrong: errno %i\n", errno);
			}
		}

		if (now == 0) { now = time(NULL); }
		value.reset(new globus_mapping_entry_t);
		value->expiry_time = now + gsi_cache_expiry;
		// The special name of "" indicates failed mapping.
		if (major_status == GSS_S_COMPLETE) {
			value->name = local_user;
		}
		m_mapping->insert(auth_name_to_map, value);
	}
#endif

	if (tmp_user) {
		strcpy( local_user, tmp_user );
		free(tmp_user);
		tmp_user = NULL;
	}

	if ( major_status != GSS_S_COMPLETE) {
		setRemoteUser("gsi");
		setRemoteDomain( UNMAPPED_DOMAIN );
		return 0;
	}

	MyString user;
	MyString domain;
	Authentication::split_canonical_name( local_user, user, domain );
    
	setRemoteUser  (user.Value());
	setRemoteDomain(domain.Value());
	setAuthenticatedName(GSSClientname);
	return 1;
}
Example #8
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);

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

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

			// get the voms attributes from the peer
			globus_gsi_cred_handle_t peer_cred = context_handle->peer_cred_handle->cred_handle;

			char * voms_fqan = NULL;
			int voms_err = extract_VOMS_info(peer_cred, 1, NULL, NULL, &voms_fqan);
			if (!voms_err) {
				setFQAN(voms_fqan);
				free(voms_fqan);
			} else {
				// complain!
				dprintf(D_SECURITY, "ZKM: VOMS FQAN not present (error %i), ignoring.\n", voms_err);
			}
		}

		// 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;
}
Example #9
0
int 
Condor_Auth_SSPI::sspi_server_auth(CredHandle& cred,CtxtHandle& srvCtx)
{
    int rc;
    SecPkgInfo *secPackInfo;
    int it_worked = FALSE;		// assume failure
    
    dprintf(D_FULLDEBUG, "sspi_server_auth() entered\n" );
    
    rc = (pf->QuerySecurityPackageInfo)( "NTLM", &secPackInfo );
    
    TimeStamp useBefore;
    
    rc = (pf->AcquireCredentialsHandle)( NULL, "NTLM", SECPKG_CRED_INBOUND,
                                         NULL, NULL, NULL, NULL, &cred, &useBefore );
    
    // input and output buffers
    SecBufferDesc obd, ibd;
    SecBuffer ob, ib;
    
    DWORD ctxAttr;
    
    bool haveContext = false;
    
    while ( 1 )
	{
            // prepare to get the server's response
            ibd.ulVersion = SECBUFFER_VERSION;
            ibd.cBuffers = 1;
            ibd.pBuffers = &ib; // just one buffer
            ib.BufferType = SECBUFFER_TOKEN; // preping a token here
            
            // receive the client's POD
            ib.pvBuffer = NULL;
            mySock_->decode();
            if ( !mySock_->code(ib.cbBuffer) ||
                 !mySock_->end_of_message() ||
                 !(ib.pvBuffer = LocalAlloc( 0, ib.cbBuffer )) ||
                 !mySock_->get_bytes((char *) ib.pvBuffer, ib.cbBuffer) ||
                 !mySock_->end_of_message() )
		{
                    dprintf(D_ALWAYS,
                            "ERROR sspi_server_auth() failed to received client POD\n");
                    if ( ib.pvBuffer ) {
                        LocalFree( ib.pvBuffer );
                        ib.pvBuffer = NULL;
                    }
                    (pf->FreeContextBuffer)( secPackInfo );			
                    return 0;
		}
            
            // by now we have an input buffer
            
            obd.ulVersion = SECBUFFER_VERSION;
            obd.cBuffers = 1;
            obd.pBuffers = &ob; // just one buffer
            ob.BufferType = SECBUFFER_TOKEN; // preping a token here
            ob.cbBuffer = secPackInfo->cbMaxToken;
            ob.pvBuffer = LocalAlloc( 0, ob.cbBuffer );
            
            rc = (pf->AcceptSecurityContext)( &cred, 
                                              haveContext? &srvCtx: NULL,
                                              &ibd, 
                                              0, 
                                              SECURITY_NATIVE_DREP, 
                                              &srvCtx, &obd, &ctxAttr,
                                              &useBefore );
            
            if ( ib.pvBuffer != NULL )
		{
                    LocalFree( ib.pvBuffer );
                    ib.pvBuffer = NULL;
		}
            
            if ( rc == SEC_I_COMPLETE_AND_CONTINUE || rc == SEC_I_COMPLETE_NEEDED )
		{
                    if ( pf->CompleteAuthToken != NULL ) // only if implemented
                        (pf->CompleteAuthToken)( &srvCtx, &obd );
                    if ( rc == SEC_I_COMPLETE_NEEDED )
                        rc = SEC_E_OK;
                    else if ( rc == SEC_I_COMPLETE_AND_CONTINUE )
                        rc = SEC_I_CONTINUE_NEEDED;
		}
            
            // send the output buffer off to the server
            if ( ob.cbBuffer != 0 )
		{
                    mySock_->encode();
                    if ( !mySock_->code(ob.cbBuffer) ||
                         !mySock_->end_of_message() ||
                         !mySock_->put_bytes( (const char *) ob.pvBuffer, ob.cbBuffer ) ||
                         !mySock_->end_of_message() ) 
			{
                            dprintf(D_ALWAYS,
                                    "ERROR sspi_server_auth() failed to send output blob\n");
                            LocalFree( ob.pvBuffer );
                            ob.pvBuffer = NULL;
                            (pf->FreeContextBuffer)( secPackInfo );			
                            return 0;
			}
		}
            LocalFree( ob.pvBuffer );
            ob.pvBuffer = NULL;
            
            if ( rc != SEC_I_CONTINUE_NEEDED )
                break;
            
            haveContext = true;
            
            // loop back for another round
            dprintf(D_FULLDEBUG,"sspi_server_auth() looping\n");
	}
    
    // we arrive here as soon as InitializeSecurityContext()
    // returns != SEC_I_CONTINUE_NEEDED.
    
    if ( rc != SEC_E_OK ) {
        dprintf( D_ALWAYS,"sspi_server_auth(): Oops! ASC() returned %d!\n", 
                 rc );
    }
    
    // now we try to use the context to Impersonate and thereby get the login
    rc = (pf->ImpersonateSecurityContext)( &srvCtx );

	char buf[256];
	char *dom = NULL;
	DWORD bufsiz = sizeof buf;

    if ( rc != SEC_E_OK ) {
        dprintf( D_ALWAYS,
                 "sspi_server_auth(): Failed to impersonate (returns %d)!\n",
					 rc );
    } else {

		// PLEASE READ: We're now running in the context of the
		// client we're impersonating. This means dprintf()'ing is
		// OFF LIMITS until we RevertSecurityContext(), since the
		// dprintf() will likely fail because the client 
		// probably will not have write access to the log file.

        GetUserName( buf, &bufsiz );
		dom = my_domainname();

		// revert as soon as possible.
	   	(pf->RevertSecurityContext)( &srvCtx );

		// Ok, safe to dprintf() now...

		it_worked = TRUE;

		setRemoteUser(buf);
		setRemoteDomain(dom);

		// set authenticated name used for mapping
		MyString auth_name;
		auth_name = buf;
		if(dom) {
			auth_name += "@";
			auth_name += dom;
		}
		setAuthenticatedName(auth_name.Value());

		dprintf( D_FULLDEBUG, "sspi_server_auth(): user name is: \"%s\"\n", buf );
		if (dom) {
			dprintf( D_FULLDEBUG, "sspi_server_auth(): domain name is: \"%s\"\n", dom);
			free(dom);
		}
    }

    (pf->FreeContextBuffer)( secPackInfo );

    dprintf( D_FULLDEBUG,"sspi_server_auth() exiting\n" );

    // return success (1) or failure (0) 
	return it_worked;
}
int Condor_Auth_Kerberos :: map_kerberos_name(krb5_principal * princ_to_map)
{
    krb5_error_code code;
    char *          client = NULL;

    //------------------------------------------
    // Decode the client name
    //------------------------------------------    
    if ((code = krb5_unparse_name(krb_context_, 
                                 *princ_to_map, 
                                 &client))){
    	dprintf(D_ALWAYS, "%s\n", error_message(code));
		return FALSE;
    } 
    else {
		dprintf( D_SECURITY, "KERBEROS: krb5_unparse_name: %s\n", client );

		char * user = 0;
		char * at_sign = strchr(client, '@');

		// first, see if the principal up to the @ sign is the same as
		// STR_KERBEROS_SERVER_PRINCIPAL
		char * server_princ = param(STR_KERBEROS_SERVER_PRINCIPAL);
		if (server_princ) {
			dprintf ( D_SECURITY, "KERBEROS: param server princ: %s\n", server_princ );
			if (strcmp(client, server_princ) == 0) {
				user = param(STR_KERBEROS_SERVER_USER);
				if (user) {
					dprintf ( D_SECURITY, "KERBEROS: mapped to user: %s\n", user );
				}
			}
		}

		if (!user) {
			dprintf ( D_SECURITY, "KERBEROS: no user yet determined, will grab up to slash\n" );
			char * tmp;
			if ((tmp = strchr( client, '/')) == NULL) {
				tmp = at_sign;
			}
			int user_len = tmp - client;
			user = (char*) malloc( user_len + 1 );
			ASSERT( user );
			strncpy ( user, client, user_len );
			user[user_len] = '\0';
			dprintf ( D_SECURITY, "KERBEROS: picked user: %s\n", user );
		}

		char * service = 0;
		service = param(STR_KERBEROS_SERVER_SERVICE);
		if (!service) {
			service = strdup(STR_DEFAULT_CONDOR_SERVICE);
		}
		// hack for now - map the "host" user to the condor user
		if ((strcmp(user, service) == 0)) {
			free(user);
			user = param(STR_KERBEROS_SERVER_USER);
			if (!user) {
				user = strdup(STR_DEFAULT_CONDOR_USER);
			}
			dprintf ( D_SECURITY, "KERBEROS: remapping '%s' to '%s'\n", service, user );
		}
 		setRemoteUser(user);
		setAuthenticatedName(client);
		free(user);
		user = 0;
		free(service);
		service = 0;
		free(server_princ);

		if (!map_domain_name(at_sign+1)) {
			return FALSE;
		}

		dprintf(D_SECURITY, "Client is %s@%s\n", getRemoteUser(), getRemoteDomain());
	}

	return TRUE;
}