int igsiServersideAuth() { int status; #if defined(GSI_AUTH) char clientName[500]; genQueryInp_t genQueryInp; genQueryOut_t *genQueryOut; char condition1[MAX_NAME_LEN]; char condition2[MAX_NAME_LEN]; char *tResult; int privLevel; int clientPrivLevel; int noNameMode; int statusRule; #ifdef GSI_DEBUG char *getVar; getVar = getenv( "X509_CERT_DIR" ); if ( getVar != NULL ) { printf( "X509_CERT_DIR:%s\n", getVar ); } #endif gsiAuthReqStatus = 1; status = igsiEstablishContextServerside( rsComm, clientName, 500 ); #ifdef GSI_DEBUG if ( status == 0 ) { printf( "clientName:%s\n", clientName ); } #endif memset( &genQueryInp, 0, sizeof( genQueryInp_t ) ); noNameMode = 0; if ( strlen( rsComm->clientUser.userName ) > 0 ) { /* regular mode */ snprintf( condition1, MAX_NAME_LEN, "='%s'", clientName ); addInxVal( &genQueryInp.sqlCondInp, COL_USER_DN, condition1 ); snprintf( condition2, MAX_NAME_LEN, "='%s'", rsComm->clientUser.userName ); addInxVal( &genQueryInp.sqlCondInp, COL_USER_NAME, condition2 ); addInxIval( &genQueryInp.selectInp, COL_USER_ID, 1 ); addInxIval( &genQueryInp.selectInp, COL_USER_TYPE, 1 ); addInxIval( &genQueryInp.selectInp, COL_USER_ZONE, 1 ); genQueryInp.maxRows = 2; status = rsGenQuery( rsComm, &genQueryInp, &genQueryOut ); } else { /* The client isn't providing the rodsUserName so query on just the DN. If it returns just one row, set the clientUser to the returned irods user name. */ noNameMode = 1; memset( &genQueryInp, 0, sizeof( genQueryInp_t ) ); snprintf( condition1, MAX_NAME_LEN, "='%s'", clientName ); addInxVal( &genQueryInp.sqlCondInp, COL_USER_DN, condition1 ); addInxIval( &genQueryInp.selectInp, COL_USER_ID, 1 ); addInxIval( &genQueryInp.selectInp, COL_USER_TYPE, 1 ); addInxIval( &genQueryInp.selectInp, COL_USER_NAME, 1 ); addInxIval( &genQueryInp.selectInp, COL_USER_ZONE, 1 ); genQueryInp.maxRows = 2; status = rsGenQuery( rsComm, &genQueryInp, &genQueryOut ); if ( status == CAT_NO_ROWS_FOUND ) { /* not found */ /* execute the rule acGetUserByDN. By default this is a no-op but at some sites can be configured to run a process to determine a user by DN (for VO support) or possibly create the user. The stdout of the process is the irodsUserName to use. The corresponding rule would be something like this: acGetUserByDN(*arg,*OUT)||msiExecCmd(t,"*arg",null,null,null,*OUT)|nop */ ruleExecInfo_t rei; char *args[2]; msParamArray_t *myMsParamArray; msParamArray_t myInOutParamArray; memset( ( char* )&rei, 0, sizeof( rei ) ); rei.rsComm = rsComm; rei.uoic = &rsComm->clientUser; rei.uoip = &rsComm->proxyUser; args[0] = clientName; char out[200] = "*cmdOutput"; args[1] = out; rei.inOutMsParamArray = myInOutParamArray; myMsParamArray = ( msParamArray_t * ) malloc( sizeof( msParamArray_t ) ); memset( myMsParamArray, 0, sizeof( msParamArray_t ) ); statusRule = applyRuleArgPA( "acGetUserByDN", args, 2, myMsParamArray, &rei, NO_SAVE_REI ); #ifdef GSI_DEBUG printf( "acGetUserByDN status=%d\n", statusRule ); int i; for ( i = 0; i < myMsParamArray->len; i++ ) { char *r; msParam_t *myP; myP = myMsParamArray->msParam[i]; r = myP->label; printf( "l1=%s\n", r ); } #endif /* Try the query again, whether or not the rule succeeded, to see if the user has been added. */ memset( &genQueryInp, 0, sizeof( genQueryInp_t ) ); snprintf( condition1, MAX_NAME_LEN, "='%s'", clientName ); addInxVal( &genQueryInp.sqlCondInp, COL_USER_DN, condition1 ); addInxIval( &genQueryInp.selectInp, COL_USER_ID, 1 ); addInxIval( &genQueryInp.selectInp, COL_USER_TYPE, 1 ); addInxIval( &genQueryInp.selectInp, COL_USER_NAME, 1 ); addInxIval( &genQueryInp.selectInp, COL_USER_ZONE, 1 ); genQueryInp.maxRows = 2; status = rsGenQuery( rsComm, &genQueryInp, &genQueryOut ); } if ( status == 0 ) { char *myBuf; strncpy( rsComm->clientUser.userName, genQueryOut->sqlResult[2].value, NAME_LEN ); strncpy( rsComm->proxyUser.userName, genQueryOut->sqlResult[2].value, NAME_LEN ); strncpy( rsComm->clientUser.rodsZone, genQueryOut->sqlResult[3].value, NAME_LEN ); strncpy( rsComm->proxyUser.rodsZone, genQueryOut->sqlResult[3].value, NAME_LEN ); myBuf = ( char * )malloc( NAME_LEN * 2 ); snprintf( myBuf, NAME_LEN * 2, "%s=%s", SP_CLIENT_USER, rsComm->clientUser.userName ); putenv( myBuf ); free( myBuf ); // JMC cppcheck - leak } } if ( status == CAT_NO_ROWS_FOUND || genQueryOut == NULL ) { status = GSI_DN_DOES_NOT_MATCH_USER; rodsLog( LOG_NOTICE, "igsiServersideAuth: DN mismatch, user=%s, Certificate DN=%s, status=%d", rsComm->clientUser.userName, clientName, status ); snprintf( gsiAuthReqErrorMsg, sizeof gsiAuthReqErrorMsg, "igsiServersideAuth: DN mismatch, user=%s, Certificate DN=%s, status=%d", rsComm->clientUser.userName, clientName, status ); gsiAuthReqError = status; return status; } if ( status < 0 ) { rodsLog( LOG_NOTICE, "igsiServersideAuth: rsGenQuery failed, status = %d", status ); snprintf( gsiAuthReqErrorMsg, sizeof gsiAuthReqErrorMsg, "igsiServersideAuth: rsGenQuery failed, status = %d", status ); gsiAuthReqError = status; return status; } if ( noNameMode == 0 ) { if ( genQueryOut == NULL || genQueryOut->rowCnt < 1 ) { gsiAuthReqError = GSI_NO_MATCHING_DN_FOUND; return GSI_NO_MATCHING_DN_FOUND; } if ( genQueryOut->rowCnt > 1 ) { gsiAuthReqError = GSI_MULTIPLE_MATCHING_DN_FOUND; return GSI_MULTIPLE_MATCHING_DN_FOUND; } if ( genQueryOut->attriCnt != 3 ) { gsiAuthReqError = GSI_QUERY_INTERNAL_ERROR; return GSI_QUERY_INTERNAL_ERROR; } } else { if ( genQueryOut == NULL || genQueryOut->rowCnt < 1 ) { gsiAuthReqError = GSI_NO_MATCHING_DN_FOUND; return GSI_NO_MATCHING_DN_FOUND; } if ( genQueryOut->rowCnt > 1 ) { gsiAuthReqError = GSI_MULTIPLE_MATCHING_DN_FOUND; return GSI_MULTIPLE_MATCHING_DN_FOUND; } if ( genQueryOut->attriCnt != 4 ) { gsiAuthReqError = GSI_QUERY_INTERNAL_ERROR; return GSI_QUERY_INTERNAL_ERROR; } } #ifdef GSI_DEBUG printf( "Results=%d\n", genQueryOut->rowCnt ); #endif tResult = genQueryOut->sqlResult[0].value; #ifdef GSI_DEBUG printf( "0:%s\n", tResult ); #endif tResult = genQueryOut->sqlResult[1].value; #ifdef GSI_DEBUG printf( "1:%s\n", tResult ); #endif privLevel = LOCAL_USER_AUTH; clientPrivLevel = LOCAL_USER_AUTH; if ( strcmp( tResult, "rodsadmin" ) == 0 ) { privLevel = LOCAL_PRIV_USER_AUTH; clientPrivLevel = LOCAL_PRIV_USER_AUTH; } status = chkProxyUserPriv( rsComm, privLevel ); if ( status < 0 ) { return status; } rsComm->proxyUser.authInfo.authFlag = privLevel; rsComm->clientUser.authInfo.authFlag = clientPrivLevel; if ( noNameMode ) { /* We didn't before, but now have an irodsUserName */ int status2, status3; rodsServerHost_t *rodsServerHost = NULL; status2 = getAndConnRcatHost( rsComm, MASTER_RCAT, rsComm->myEnv.rodsZone, &rodsServerHost ); if ( status2 >= 0 && rodsServerHost->localFlag == REMOTE_HOST && rodsServerHost->conn != NULL ) { /* If the IES is remote */ status3 = rcDisconnect( rodsServerHost->conn ); /* disconnect*/ /* And clear out the connection information so getAndConnRcatHost will reconnect. This may leak some memory but only happens at most once in an agent: */ rodsServerHost->conn = NULL; /* And reconnect (with irodsUserName here and in the IES): */ status3 = getAndConnRcatHost( rsComm, MASTER_RCAT, rsComm->myEnv.rodsZone, &rodsServerHost ); if ( status3 ) { rodsLog( LOG_ERROR, "igsiServersideAuth failed in getAndConnRcatHost, status = %d", status3 ); return status3; } } } return status; #else status = GSI_NOT_BUILT_INTO_SERVER; rodsLog( LOG_ERROR, "igsiServersideAuth failed GSI_NOT_BUILT_INTO_SERVER, status = %d", status ); return status; #endif }
int rsAuthResponse (rsComm_t *rsComm, authResponseInp_t *authResponseInp) { int status; char *bufp; authCheckInp_t authCheckInp; authCheckOut_t *authCheckOut = NULL; rodsServerHost_t *rodsServerHost; char digest[RESPONSE_LEN+2]; char md5Buf[CHALLENGE_LEN+MAX_PASSWORD_LEN+2]; char serverId[MAX_PASSWORD_LEN+2]; MD5_CTX context; bufp = _rsAuthRequestGetChallenge(); /* need to do NoLogin because it could get into inf loop for cross * zone auth */ status = getAndConnRcatHostNoLogin (rsComm, SLAVE_RCAT, rsComm->proxyUser.rodsZone, &rodsServerHost); if (status < 0) { return(status); } memset (&authCheckInp, 0, sizeof (authCheckInp)); authCheckInp.challenge = bufp; authCheckInp.response = authResponseInp->response; authCheckInp.username = authResponseInp->username; if (rodsServerHost->localFlag == LOCAL_HOST) { status = rsAuthCheck (rsComm, &authCheckInp, &authCheckOut); } else { status = rcAuthCheck (rodsServerHost->conn, &authCheckInp, &authCheckOut); /* not likely we need this connection again */ rcDisconnect(rodsServerHost->conn); rodsServerHost->conn = NULL; } if (status < 0) { rodsLog (LOG_NOTICE, "rsAuthResponse: rxAuthCheck failed, status = %d", status); return (status); } if (rodsServerHost->localFlag != LOCAL_HOST) { if (authCheckOut->serverResponse == NULL) { rodsLog(LOG_NOTICE, "Warning, cannot authenticate remote server, no serverResponse field"); if (requireServerAuth) { rodsLog(LOG_NOTICE, "Authentication disallowed, no serverResponse field"); return(REMOTE_SERVER_AUTH_NOT_PROVIDED); } } else { char *cp; int OK, len, i; if (*authCheckOut->serverResponse == '\0') { rodsLog(LOG_NOTICE, "Warning, cannot authenticate remote server, serverResponse field is empty"); if (requireServerAuth) { rodsLog(LOG_NOTICE, "Authentication disallowed, empty serverResponse"); return(REMOTE_SERVER_AUTH_EMPTY); } } else { char username2[NAME_LEN+2]; char userZone[NAME_LEN+2]; memset(md5Buf, 0, sizeof(md5Buf)); strncpy(md5Buf, authCheckInp.challenge, CHALLENGE_LEN); parseUserName(authResponseInp->username, username2, userZone); getZoneServerId(userZone, serverId); len = strlen(serverId); if (len <= 0) { rodsLog (LOG_NOTICE, "rsAuthResponse: Warning, cannot authenticate the remote server, no RemoteZoneSID defined in server.config", status); if (requireServerAuth) { rodsLog(LOG_NOTICE, "Authentication disallowed, no RemoteZoneSID defined"); return(REMOTE_SERVER_SID_NOT_DEFINED); } } else { strncpy(md5Buf+CHALLENGE_LEN, serverId, len); MD5Init (&context); MD5Update (&context, (unsigned char*)md5Buf, CHALLENGE_LEN+MAX_PASSWORD_LEN); MD5Final ((unsigned char*)digest, &context); for (i=0;i<RESPONSE_LEN;i++) { if (digest[i]=='\0') digest[i]++; /* make sure 'string' doesn't end early*/ } cp = authCheckOut->serverResponse; OK=1; for (i=0;i<RESPONSE_LEN;i++) { if (*cp++ != digest[i]) OK=0; } rodsLog(LOG_DEBUG, "serverResponse is OK/Not: %d", OK); if (OK==0) { rodsLog(LOG_NOTICE, "Server response incorrect, authentication disallowed"); return(REMOTE_SERVER_AUTHENTICATION_FAILURE); } } } } } /* Set the clientUser zone if it is null. */ if (strlen(rsComm->clientUser.rodsZone)==0) { zoneInfo_t *tmpZoneInfo; status = getLocalZoneInfo (&tmpZoneInfo); if (status < 0) { free (authCheckOut); return status; } strncpy(rsComm->clientUser.rodsZone, tmpZoneInfo->zoneName, NAME_LEN); } /* have to modify privLevel if the icat is a foreign icat because * a local user in a foreign zone is not a local user in this zone * and vice vera for a remote user */ if (rodsServerHost->rcatEnabled == REMOTE_ICAT) { /* proxy is easy because rodsServerHost is based on proxy user */ if (authCheckOut->privLevel == LOCAL_PRIV_USER_AUTH) authCheckOut->privLevel = REMOTE_PRIV_USER_AUTH; else if (authCheckOut->privLevel == LOCAL_PRIV_USER_AUTH) authCheckOut->privLevel = REMOTE_PRIV_USER_AUTH; /* adjust client user */ if (strcmp (rsComm->proxyUser.userName, rsComm->clientUser.userName) == 0) { authCheckOut->clientPrivLevel = authCheckOut->privLevel; } else { zoneInfo_t *tmpZoneInfo; status = getLocalZoneInfo (&tmpZoneInfo); if (status < 0) { free (authCheckOut); return status; } if (strcmp (tmpZoneInfo->zoneName, rsComm->clientUser.rodsZone) == 0) { /* client is from local zone */ if (authCheckOut->clientPrivLevel == REMOTE_PRIV_USER_AUTH) { authCheckOut->clientPrivLevel = LOCAL_PRIV_USER_AUTH; } else if (authCheckOut->clientPrivLevel == REMOTE_USER_AUTH) { authCheckOut->clientPrivLevel = LOCAL_USER_AUTH; } } else { /* client is from remote zone */ if (authCheckOut->clientPrivLevel == LOCAL_PRIV_USER_AUTH) { authCheckOut->clientPrivLevel = REMOTE_USER_AUTH; } else if (authCheckOut->clientPrivLevel == LOCAL_USER_AUTH) { authCheckOut->clientPrivLevel = REMOTE_USER_AUTH; } } } } else if (strcmp (rsComm->proxyUser.userName, rsComm->clientUser.userName) == 0) { authCheckOut->clientPrivLevel = authCheckOut->privLevel; } status = chkProxyUserPriv (rsComm, authCheckOut->privLevel); if (status < 0) { free (authCheckOut); return status; } rodsLog(LOG_NOTICE, "rsAuthResponse set proxy authFlag to %d, client authFlag to %d, user:%s proxy:%s client:%s", authCheckOut->privLevel, authCheckOut->clientPrivLevel, authCheckInp.username, rsComm->proxyUser.userName, rsComm->clientUser.userName); if (strcmp (rsComm->proxyUser.userName, rsComm->clientUser.userName) != 0) { rsComm->proxyUser.authInfo.authFlag = authCheckOut->privLevel; rsComm->clientUser.authInfo.authFlag = authCheckOut->clientPrivLevel; } else { /* proxyUser and clientUser are the same */ rsComm->proxyUser.authInfo.authFlag = rsComm->clientUser.authInfo.authFlag = authCheckOut->privLevel; } /*** Added by RAJA Nov 16 2010 **/ if (authCheckOut->serverResponse != NULL) free(authCheckOut->serverResponse); /*** Added by RAJA Nov 16 2010 **/ free (authCheckOut); return (status); }