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; }
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; }
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; }
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; }