<commit_before>/**
 * @file  reIn2p3SysRule.c
 *
 */

/*** Copyright (c) 2007 Data Intensive Cyberinfrastructure Foundation. All rights reserved.    ***
 *** For full copyright notice please refer to files in the COPYRIGHT directory                ***/
/* Written by <NAME> of CCIN2P3 and copyright assigned to Data Intensive Cyberinfrastructure Foundation */

#include "reIn2p3SysRule.hpp"
#include "genQuery.hpp"
#include "phyBundleColl.hpp"
#ifndef windows_platform
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "irods_stacktrace.hpp"
static pthread_mutex_t my_mutex;
#endif

#include "irods_get_full_path_for_config_file.hpp"
#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>

short threadIsAlive[MAX_NSERVERS];

int rodsMonPerfLog( char *serverName, char *resc, char *output, ruleExecInfo_t *rei ) {

    char condstr[MAX_NAME_LEN], fname[MAX_NAME_LEN], msg[MAX_MESSAGE_SIZE], splc[MAX_VALUE][MAX_NAME_LEN],
         splresc[MAX_VALUE][MAX_NAME_LEN], spldsk[MAX_VALUE][MAX_NAME_LEN], splmb[MAX_VALUE][MAX_NAME_LEN],
         monStatus[MAX_NAME_LEN], suffix[MAX_VALUE], *result;
    const char *delim1 = "#";
    const char *delim2 = ",";
    int indx, timestamp, rc1 = 0, rc2 = 0, rc3 = 0, rc4 = 0;
    FILE *foutput;
    time_t tps;
    generalRowInsertInp_t generalRowInsertInp;
    generalAdminInp_t generalAdminInp1, generalAdminInp2;
    genQueryInp_t genQueryInp;
    struct tm *now;

    genQueryOut_t *genQueryOut = NULL;
    tps = time( NULL );
    now = localtime( &tps );

    /* a quick test in order to see if the resource is up or down (needed to update the "status" metadata) */
    if ( strcmp( output, MON_OUTPUT_NO_ANSWER ) == 0 ) {
        strncpy( monStatus, RESC_AUTO_DOWN, MAX_NAME_LEN );
    }
    else {
        strncpy( monStatus, RESC_AUTO_UP, MAX_NAME_LEN );
    }

    strSplit( output, delim1, splc );
    strSplit( resc, delim2, splresc );
    strSplit( splc[4], delim2, spldsk );
    strSplit( splc[7], delim2, splmb );
    indx = 0;
    while ( strcmp( splresc[indx], "" ) != 0 ) {
        if ( strcmp( monStatus, RESC_AUTO_DOWN ) == 0 ) {
            rstrcpy( spldsk[indx], "-1", MAX_NAME_LEN );
            rstrcpy( splmb[indx], "-1", MAX_NAME_LEN );
        }
        sprintf( msg, "server=%s resource=%s cpu=%s, mem=%s, swp=%s, rql=%s, dsk=%s, nin=%s, nout=%s, dskAv(MB)=%s\n",
                 serverName, splresc[indx], splc[0], splc[1], splc[2],
                 splc[3], spldsk[indx], splc[5], splc[6], splmb[indx] );
        sprintf( suffix, "%d.%d.%d", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday );
        sprintf( fname, "%s.%s", OUTPUT_MON_PERF, suffix );
        /* retrieve the system time */
        timestamp = time( &tps );

        /* log the result into the database as well */
        generalRowInsertInp.tableName = "serverload";
        generalRowInsertInp.arg1 = serverName;
        generalRowInsertInp.arg2 = splresc[indx];
        generalRowInsertInp.arg3 = splc[0];
        generalRowInsertInp.arg4 = splc[1];
        generalRowInsertInp.arg5 = splc[2];
        generalRowInsertInp.arg6 = splc[3];
        generalRowInsertInp.arg7 = spldsk[indx];
        generalRowInsertInp.arg8 = splc[5];
        generalRowInsertInp.arg9 = splc[6];
        /* prepare DB request to modify resource metadata: freespace and status */
        generalAdminInp1.arg0 = "modify";
        generalAdminInp1.arg1 = "resource";
        generalAdminInp1.arg2 = splresc[indx];
        generalAdminInp1.arg3 = "freespace";
        generalAdminInp1.arg4 = splmb[indx];
        generalAdminInp2.arg0 = "modify";
        generalAdminInp2.arg1 = "resource";
        generalAdminInp2.arg2 = splresc[indx];
        generalAdminInp2.arg3 = "status";
        generalAdminInp2.arg4 = monStatus;
        memset( &genQueryInp, 0, sizeof( genQueryInp ) );
        addInxIval( &genQueryInp.selectInp, COL_R_RESC_STATUS, 1 );
        snprintf( condstr, MAX_NAME_LEN, "= '%s'", splresc[indx] );
        addInxVal( &genQueryInp.sqlCondInp, COL_R_RESC_NAME, condstr );
        genQueryInp.maxRows = MAX_SQL_ROWS;
#ifndef windows_platform
        pthread_mutex_lock( &my_mutex );
#endif
        /* append to the output log file */
        foutput = fopen( fname, "a" );
        if ( foutput != NULL ) {
            fprintf( foutput, "time=%i %s", timestamp, msg );
            // fclose(foutput); // JMC cppcheck - nullptr // cannot close it here. it is used later - hcj
        }

        rc1 = rsGeneralRowInsert( rei->rsComm, &generalRowInsertInp );
        rc2 = rsGeneralAdmin( rei->rsComm, &generalAdminInp1 );
        rc3 = rsGenQuery( rei->rsComm, &genQueryInp, &genQueryOut );
        if ( rc3 >= 0 ) {
            result = genQueryOut->sqlResult[0].value;
            if ( strcmp( result, "\0" ) == 0 || ( strncmp( result, "auto-", 5 ) == 0 && strcmp( result, monStatus ) != 0 ) ) {
                rc4 = rsGeneralAdmin( rei->rsComm, &generalAdminInp2 );
            }
        }
        else {
            rodsLog( LOG_ERROR, "msiServerMonPerf: unable to retrieve the status metadata for the resource %s", splresc[indx] );
        }
#ifndef windows_platform
        pthread_mutex_unlock( &my_mutex );
#endif
        if ( foutput != NULL && rc1 != 0 ) {
            fprintf( foutput, "time=%i : unable to insert the entries for server %s into the iCAT\n",
                     timestamp, serverName );
            fclose( foutput );
        }
        if ( rc2 != 0 ) {
            rodsLog( LOG_ERROR, "msiServerMonPerf: unable to register the free space metadata for the resource %s", splresc[indx] );
        }
        if ( rc4 != 0 ) {
            rodsLog( LOG_ERROR, "msiServerMonPerf: unable to register the status metadata for the resource %s", splresc[indx] );
        }
        indx += 1;
    }

    clearGenQueryInp( &genQueryInp );
    freeGenQueryOut( &genQueryOut );

    return 0;
}

int strSplit( char *s, const char *ct, char splchain[MAX_VALUE][MAX_NAME_LEN] ) {
    /**********************************************
     * cut out character strings                   *
     ***********************************************/
    int i;
    char cs[MAX_NAME_LEN];

    if ( s != NULL && ct != NULL ) {
        for ( i = 0; ( rstrcpy( cs, strtok( s, ct ), MAX_NAME_LEN ) ); i++ ) {
            /* store the adress returned by strtok */
            rstrcpy( splchain[i], cs, MAX_NAME_LEN );
            s = NULL;
        }
    }
    return 0;
}

int getListOfResc( rsComm_t *rsComm, char serverList[MAX_VALUE][MAX_NAME_LEN], int nservers,
                   monInfo_t monList[MAX_NSERVERS], int *nlist ) {
    /**********************************************************
     * search in the database, the list of resources with      *
     * their associated server. If config file exist, restrict *
     * the list to serverList                                  *
     ***********************************************************/
    int i, j, k, index[MAX_NSERVERS], l, status;
    genQueryInp_t genQueryInp;
    genQueryOut_t *genQueryOut = NULL;
    char condStr[MAX_NAME_LEN];

    memset( &genQueryInp, 0, sizeof( genQueryInp_t ) );
    memset( &index, -1, MAX_NSERVERS * sizeof( int ) );
    genQueryInp.maxRows = MAX_SQL_ROWS;

    //clearGenQueryInp( &genQueryInp );
    addInxIval( &genQueryInp.selectInp, COL_R_LOC, 1 );
    addInxIval( &genQueryInp.selectInp, COL_R_RESC_NAME, 1 );
    addInxIval( &genQueryInp.selectInp, COL_R_TYPE_NAME, 1 );
    addInxIval( &genQueryInp.selectInp, COL_R_VAULT_PATH, 1 );
    addInxVal( &genQueryInp.sqlCondInp, COL_R_LOC, "!='EMPTY_RESC_HOST'" );
    addInxVal( &genQueryInp.sqlCondInp, COL_R_VAULT_PATH, "!='EMPTY_RESC_PATH'" );
    snprintf( condStr, MAX_NAME_LEN, "!='%s'", BUNDLE_RESC );
    addInxVal( &genQueryInp.sqlCondInp, COL_R_RESC_NAME, condStr );

    status = rsGenQuery( rsComm, &genQueryInp, &genQueryOut );
    if ( status < 0 ) {
        irods::log( ERROR( status, "rsGenQuery failed." ) );
    }
    if ( genQueryOut->rowCnt > 0 ) {
        l = 0;
        for ( i = 0; i < genQueryOut->attriCnt; i++ ) {
            for ( j = 0; j < genQueryOut->rowCnt; j++ ) {
                char *tResult;
                tResult = genQueryOut->sqlResult[i].value;
                tResult += j * genQueryOut->sqlResult[i].len;
                switch ( i ) {
                case 0:
                    if ( nservers >= 0 ) {
                        for ( k = 0; k < nservers; k++ ) {
                            if ( strcmp( serverList[k], tResult ) == 0 ) {
                                index[j] = l;
                                l++;
                            }
                        }
                    }
                    else {
                        index[j] = l;
                        l++;
                    }
                    if ( index[j] != -1 ) {
                        rstrcpy( monList[index[j]].serverName, tResult, LONG_NAME_LEN );
                    }
                    break;
                case 1:
                    if ( index[j] != -1 ) {
                        rstrcpy( monList[index[j]].rescName, tResult, MAX_NAME_LEN );
                    }
                    break;
                case 2:
                    if ( index[j] != -1 ) {
                        rstrcpy( monList[index[j]].rescType, tResult, LONG_NAME_LEN );
                    }
                    break;
                case 3:
                    if ( index[j] != -1 ) {
                        rstrcpy( monList[index[j]].vaultPath, tResult, LONG_NAME_LEN );
                    }
                    break;
                }
            }
        }
        ( *nlist ) = l;
        clearGenQueryInp( &genQueryInp );
        freeGenQueryOut( &genQueryOut );
        return 0;
    }
    return -1;
}

void *startMonScript( void *arg ) {
    /***********************************************************
     * launch Perl script on each server, retrieve the result  *
     * and give it to the rodsMonPerfLog function in order to  *
     * insert it into the database .                           *
     **********************************************************/
    char *output;
    msParam_t msp1, msp2, msp3, msp4, msp5, msout;
    int thrid,  status;
    int retval;

    thrInp_t *tinput = ( thrInp_t* )arg;
#ifndef windows_platform
    pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
    pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
#endif
    fillStrInMsParam( &msp1, tinput->cmd );
    fillStrInMsParam( &msp2, tinput->cmdArgv );
    fillStrInMsParam( &msp3, tinput->execAddr );
    fillStrInMsParam( &msp4, tinput->hintPath );
    fillIntInMsParam( &msp5, tinput->addPathToArgv );
    thrid = tinput->threadId;

    threadIsAlive[thrid] = 0;
    status = msiExecCmd( &msp1, &msp2, &msp3, &msp4, &msp5, &msout, &( tinput->rei ) );

    if ( status < 0 ) {
        char noanswer[MAXSTR] = MON_OUTPUT_NO_ANSWER;
        rodsLogError( LOG_ERROR, status, "Call to msiExecCmd failed in msiServerMonPerf. " );
        rodsMonPerfLog( tinput->execAddr, tinput->rescName, noanswer, &( tinput->rei ) );
        threadIsAlive[thrid] = 1;
        retval = -1;
#ifndef windows_platform
        pthread_exit( ( void * )&retval );
#endif
    }

    /* if (&msout != NULL) { */
    /* write into the irodsMonPerf log file */
    if ( ( char * )( *( ( execCmdOut_t * ) msout.inOutStruct ) ).stdoutBuf.buf != NULL ) {
        output = ( char * )( *( ( execCmdOut_t * ) msout.inOutStruct ) ).stdoutBuf.buf;
        rodsMonPerfLog( tinput->execAddr, tinput->rescName, output, &( tinput->rei ) );
    }
    else {
        char noanswer[MAXSTR] = MON_OUTPUT_NO_ANSWER;
        rodsLog( LOG_ERROR, "Server monitoring: no output for the server %s, status = %i \n", tinput->execAddr, status );
        rodsMonPerfLog( tinput->execAddr, tinput->rescName, noanswer, &( tinput->rei ) );
        threadIsAlive[thrid] = 1;
        retval = -1;
#ifndef windows_platform
        pthread_exit( ( void * )&retval );
#endif
    }
    /*}
      else {
      char noanswer[MAXSTR] = MON_OUTPUT_NO_ANSWER;
      rodsLog(LOG_ERROR, "Server monitoring: problem with the server %s, status = %i \n", tinput->execAddr, status);
      rodsMonPerfLog(tinput->execAddr, tinput->rescName, noanswer,
      &(tinput->rei));
      threadIsAlive[thrid] = 1;
      retval = -1;
      #ifndef windows_platform
      pthread_exit((void *)&retval);
      #endif
      } */

    threadIsAlive[thrid] = 1;

    retval = 0;
#ifndef windows_platform
    pthread_exit( ( void * )&retval );
#endif
}

int checkHostAccessControl( char *username, char *hostclient, char *groupsname ) {

    //char *configDir;
    //char* hostControlAccessFile[LONG_NAME_LEN];
    char grouplist[MAX_SQL_ROWS][MAXSTR];
    const char *delim = " \t\n";
    char *eltstr, tempArr[NFIELDS][MAXLEN];

    /* try to open the HostControlAccess if it exists. */
    //configDir = getConfigDir();
    //snprintf( hostControlAccessFile, LONG_NAME_LEN, "%s/%s", configDir,HOST_ACCESS_CONTROL_FILE );

    std::string cfg_file;
    irods::error ret = irods::get_full_path_for_config_file( HOST_ACCESS_CONTROL_FILE, cfg_file );
    if ( !ret.ok() ) {
        irods::log( PASS( ret ) );
        return ret.code();
    }

    FILE *fp = fopen( cfg_file.c_str(), "r" );
    if ( fp == NULL ) {
        rodsLog( LOG_NOTICE,
                 "hostAuthCheck: can't open HostControlAccess file %s", cfg_file.c_str() );
        return UNIX_FILE_OPEN_ERR - errno;
    }
    /* parse the list of groups for the user from the groupsname char */
    int nelt = 0;
    strncpy( grouplist[0], strtok( groupsname, delim ), MAXSTR );
    while ( ( eltstr = strtok( NULL, delim ) ) ) {
        nelt++;
        strncpy( grouplist[nelt], eltstr, MAXSTR );
    }
    /* parse HostControlAccess and check if <user,IP,group> is allowed to access this server. */
    while ( !feof( fp ) ) {
        int indxc = 0;
        char line[MAX_NAME_LEN];
        if ( fgets( line, MAXLEN, fp ) ) {
            if ( line[0] != '#' && line[0] != '\n' ) {  /* Comment or empty line, ignore */
                eltstr = strtok( line, delim );
                strncpy( tempArr[indxc], eltstr, MAXSTR );
                while ( ( eltstr = strtok( NULL, delim ) ) ) {
                    indxc++;
                    strncpy( tempArr[indxc], eltstr, MAXSTR );
                }
                if ( ( indxc + 1 ) == NFIELDS ) {
                    boost::system::error_code error_code;
                    boost::asio::ip::address_v4 IPEntry( boost::asio::ip::address_v4::from_string( tempArr[2], error_code ) );
                    if ( error_code.value() ) {
                        continue;
                    }
                    boost::asio::ip::address_v4 subnetEntry( boost::asio::ip::address_v4::from_string( tempArr[3], error_code ) );
                    if ( error_code.value() ) {
                        continue;
                    }
                    boost::asio::ip::address_v4 visitorIP( boost::asio::ip::address_v4::from_string( hostclient, error_code ) );
                    if ( error_code.value() ) {
                        continue;
                    }
                    /* check through if one of the group does correspond to the one allowed */
                    int groupok = 1;
                    for ( int i = 0; i <= nelt; i++ ) {
                        if ( strcmp( tempArr[1], grouplist[i] ) == 0 ) {
                            groupok = 0;
                            break;
                        }
                    }
                    if ( strcmp( tempArr[1], "all" ) == 0 || groupok == 0 ) {
                        if ( strcmp( tempArr[0], "all" ) == 0 || strcmp( tempArr[0], username ) == 0 ) {
                            /* check if <client, group, clientIP> match this entry of the control access file.
                             * Get out immediately from this function: client is allowed to proceed. */
                            if ( ( visitorIP.to_ulong() ^ IPEntry.to_ulong() ) & ~subnetEntry.to_ulong() == 0 ) {
                                fclose( fp );    // JMC cppcheck - resource
                                return 0;
                            }
                        }
                    }
                }
            }
        }
    }
    fclose( fp ); // JMC cppcheck - resource
    return -1;
}

/**
 * \fn msiCheckHostAccessControl (ruleExecInfo_t *rei)
 *
 * \brief  This microservice sets the access control policy. It checks the
 *  access control by host and user based on the the policy given in the
 *  HostAccessControl file.
 *
 * \module core
 *
 * \since pre-2.1
 *
 * \author <NAME>
 * \date 2007-09
 *
 * \note  This microservice controls access to the iRODS service
 *  based on the information in the host based access configuration file:<commit_msg>[#858] fixed warning about parentheses<commit_after>/**
 * @file  reIn2p3SysRule.c
 *
 */

/*** Copyright (c) 2007 Data Intensive Cyberinfrastructure Foundation. All rights reserved.    ***
 *** For full copyright notice please refer to files in the COPYRIGHT directory                ***/
/* Written by <NAME> of CCIN2P3 and copyright assigned to Data Intensive Cyberinfrastructure Foundation */

#include "reIn2p3SysRule.hpp"
#include "genQuery.hpp"
#include "phyBundleColl.hpp"
#ifndef windows_platform
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "irods_stacktrace.hpp"
static pthread_mutex_t my_mutex;
#endif

#include "irods_get_full_path_for_config_file.hpp"
#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>

short threadIsAlive[MAX_NSERVERS];

int rodsMonPerfLog( char *serverName, char *resc, char *output, ruleExecInfo_t *rei ) {

    char condstr[MAX_NAME_LEN], fname[MAX_NAME_LEN], msg[MAX_MESSAGE_SIZE], splc[MAX_VALUE][MAX_NAME_LEN],
         splresc[MAX_VALUE][MAX_NAME_LEN], spldsk[MAX_VALUE][MAX_NAME_LEN], splmb[MAX_VALUE][MAX_NAME_LEN],
         monStatus[MAX_NAME_LEN], suffix[MAX_VALUE], *result;
    const char *delim1 = "#";
    const char *delim2 = ",";
    int indx, timestamp, rc1 = 0, rc2 = 0, rc3 = 0, rc4 = 0;
    FILE *foutput;
    time_t tps;
    generalRowInsertInp_t generalRowInsertInp;
    generalAdminInp_t generalAdminInp1, generalAdminInp2;
    genQueryInp_t genQueryInp;
    struct tm *now;

    genQueryOut_t *genQueryOut = NULL;
    tps = time( NULL );
    now = localtime( &tps );

    /* a quick test in order to see if the resource is up or down (needed to update the "status" metadata) */
    if ( strcmp( output, MON_OUTPUT_NO_ANSWER ) == 0 ) {
        strncpy( monStatus, RESC_AUTO_DOWN, MAX_NAME_LEN );
    }
    else {
        strncpy( monStatus, RESC_AUTO_UP, MAX_NAME_LEN );
    }

    strSplit( output, delim1, splc );
    strSplit( resc, delim2, splresc );
    strSplit( splc[4], delim2, spldsk );
    strSplit( splc[7], delim2, splmb );
    indx = 0;
    while ( strcmp( splresc[indx], "" ) != 0 ) {
        if ( strcmp( monStatus, RESC_AUTO_DOWN ) == 0 ) {
            rstrcpy( spldsk[indx], "-1", MAX_NAME_LEN );
            rstrcpy( splmb[indx], "-1", MAX_NAME_LEN );
        }
        sprintf( msg, "server=%s resource=%s cpu=%s, mem=%s, swp=%s, rql=%s, dsk=%s, nin=%s, nout=%s, dskAv(MB)=%s\n",
                 serverName, splresc[indx], splc[0], splc[1], splc[2],
                 splc[3], spldsk[indx], splc[5], splc[6], splmb[indx] );
        sprintf( suffix, "%d.%d.%d", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday );
        sprintf( fname, "%s.%s", OUTPUT_MON_PERF, suffix );
        /* retrieve the system time */
        timestamp = time( &tps );

        /* log the result into the database as well */
        generalRowInsertInp.tableName = "serverload";
        generalRowInsertInp.arg1 = serverName;
        generalRowInsertInp.arg2 = splresc[indx];
        generalRowInsertInp.arg3 = splc[0];
        generalRowInsertInp.arg4 = splc[1];
        generalRowInsertInp.arg5 = splc[2];
        generalRowInsertInp.arg6 = splc[3];
        generalRowInsertInp.arg7 = spldsk[indx];
        generalRowInsertInp.arg8 = splc[5];
        generalRowInsertInp.arg9 = splc[6];
        /* prepare DB request to modify resource metadata: freespace and status */
        generalAdminInp1.arg0 = "modify";
        generalAdminInp1.arg1 = "resource";
        generalAdminInp1.arg2 = splresc[indx];
        generalAdminInp1.arg3 = "freespace";
        generalAdminInp1.arg4 = splmb[indx];
        generalAdminInp2.arg0 = "modify";
        generalAdminInp2.arg1 = "resource";
        generalAdminInp2.arg2 = splresc[indx];
        generalAdminInp2.arg3 = "status";
        generalAdminInp2.arg4 = monStatus;
        memset( &genQueryInp, 0, sizeof( genQueryInp ) );
        addInxIval( &genQueryInp.selectInp, COL_R_RESC_STATUS, 1 );
        snprintf( condstr, MAX_NAME_LEN, "= '%s'", splresc[indx] );
        addInxVal( &genQueryInp.sqlCondInp, COL_R_RESC_NAME, condstr );
        genQueryInp.maxRows = MAX_SQL_ROWS;
#ifndef windows_platform
        pthread_mutex_lock( &my_mutex );
#endif
        /* append to the output log file */
        foutput = fopen( fname, "a" );
        if ( foutput != NULL ) {
            fprintf( foutput, "time=%i %s", timestamp, msg );
            // fclose(foutput); // JMC cppcheck - nullptr // cannot close it here. it is used later - hcj
        }

        rc1 = rsGeneralRowInsert( rei->rsComm, &generalRowInsertInp );
        rc2 = rsGeneralAdmin( rei->rsComm, &generalAdminInp1 );
        rc3 = rsGenQuery( rei->rsComm, &genQueryInp, &genQueryOut );
        if ( rc3 >= 0 ) {
            result = genQueryOut->sqlResult[0].value;
            if ( strcmp( result, "\0" ) == 0 || ( strncmp( result, "auto-", 5 ) == 0 && strcmp( result, monStatus ) != 0 ) ) {
                rc4 = rsGeneralAdmin( rei->rsComm, &generalAdminInp2 );
            }
        }
        else {
            rodsLog( LOG_ERROR, "msiServerMonPerf: unable to retrieve the status metadata for the resource %s", splresc[indx] );
        }
#ifndef windows_platform
        pthread_mutex_unlock( &my_mutex );
#endif
        if ( foutput != NULL && rc1 != 0 ) {
            fprintf( foutput, "time=%i : unable to insert the entries for server %s into the iCAT\n",
                     timestamp, serverName );
            fclose( foutput );
        }
        if ( rc2 != 0 ) {
            rodsLog( LOG_ERROR, "msiServerMonPerf: unable to register the free space metadata for the resource %s", splresc[indx] );
        }
        if ( rc4 != 0 ) {
            rodsLog( LOG_ERROR, "msiServerMonPerf: unable to register the status metadata for the resource %s", splresc[indx] );
        }
        indx += 1;
    }

    clearGenQueryInp( &genQueryInp );
    freeGenQueryOut( &genQueryOut );

    return 0;
}

int strSplit( char *s, const char *ct, char splchain[MAX_VALUE][MAX_NAME_LEN] ) {
    /**********************************************
     * cut out character strings                   *
     ***********************************************/
    int i;
    char cs[MAX_NAME_LEN];

    if ( s != NULL && ct != NULL ) {
        for ( i = 0; ( rstrcpy( cs, strtok( s, ct ), MAX_NAME_LEN ) ); i++ ) {
            /* store the adress returned by strtok */
            rstrcpy( splchain[i], cs, MAX_NAME_LEN );
            s = NULL;
        }
    }
    return 0;
}

int getListOfResc( rsComm_t *rsComm, char serverList[MAX_VALUE][MAX_NAME_LEN], int nservers,
                   monInfo_t monList[MAX_NSERVERS], int *nlist ) {
    /**********************************************************
     * search in the database, the list of resources with      *
     * their associated server. If config file exist, restrict *
     * the list to serverList                                  *
     ***********************************************************/
    int i, j, k, index[MAX_NSERVERS], l, status;
    genQueryInp_t genQueryInp;
    genQueryOut_t *genQueryOut = NULL;
    char condStr[MAX_NAME_LEN];

    memset( &genQueryInp, 0, sizeof( genQueryInp_t ) );
    memset( &index, -1, MAX_NSERVERS * sizeof( int ) );
    genQueryInp.maxRows = MAX_SQL_ROWS;

    //clearGenQueryInp( &genQueryInp );
    addInxIval( &genQueryInp.selectInp, COL_R_LOC, 1 );
    addInxIval( &genQueryInp.selectInp, COL_R_RESC_NAME, 1 );
    addInxIval( &genQueryInp.selectInp, COL_R_TYPE_NAME, 1 );
    addInxIval( &genQueryInp.selectInp, COL_R_VAULT_PATH, 1 );
    addInxVal( &genQueryInp.sqlCondInp, COL_R_LOC, "!='EMPTY_RESC_HOST'" );
    addInxVal( &genQueryInp.sqlCondInp, COL_R_VAULT_PATH, "!='EMPTY_RESC_PATH'" );
    snprintf( condStr, MAX_NAME_LEN, "!='%s'", BUNDLE_RESC );
    addInxVal( &genQueryInp.sqlCondInp, COL_R_RESC_NAME, condStr );

    status = rsGenQuery( rsComm, &genQueryInp, &genQueryOut );
    if ( status < 0 ) {
        irods::log( ERROR( status, "rsGenQuery failed." ) );
    }
    if ( genQueryOut->rowCnt > 0 ) {
        l = 0;
        for ( i = 0; i < genQueryOut->attriCnt; i++ ) {
            for ( j = 0; j < genQueryOut->rowCnt; j++ ) {
                char *tResult;
                tResult = genQueryOut->sqlResult[i].value;
                tResult += j * genQueryOut->sqlResult[i].len;
                switch ( i ) {
                case 0:
                    if ( nservers >= 0 ) {
                        for ( k = 0; k < nservers; k++ ) {
                            if ( strcmp( serverList[k], tResult ) == 0 ) {
                                index[j] = l;
                                l++;
                            }
                        }
                    }
                    else {
                        index[j] = l;
                        l++;
                    }
                    if ( index[j] != -1 ) {
                        rstrcpy( monList[index[j]].serverName, tResult, LONG_NAME_LEN );
                    }
                    break;
                case 1:
                    if ( index[j] != -1 ) {
                        rstrcpy( monList[index[j]].rescName, tResult, MAX_NAME_LEN );
                    }
                    break;
                case 2:
                    if ( index[j] != -1 ) {
                        rstrcpy( monList[index[j]].rescType, tResult, LONG_NAME_LEN );
                    }
                    break;
                case 3:
                    if ( index[j] != -1 ) {
                        rstrcpy( monList[index[j]].vaultPath, tResult, LONG_NAME_LEN );
                    }
                    break;
                }
            }
        }
        ( *nlist ) = l;
        clearGenQueryInp( &genQueryInp );
        freeGenQueryOut( &genQueryOut );
        return 0;
    }
    return -1;
}

void *startMonScript( void *arg ) {
    /***********************************************************
     * launch Perl script on each server, retrieve the result  *
     * and give it to the rodsMonPerfLog function in order to  *
     * insert it into the database .                           *
     **********************************************************/
    char *output;
    msParam_t msp1, msp2, msp3, msp4, msp5, msout;
    int thrid,  status;
    int retval;

    thrInp_t *tinput = ( thrInp_t* )arg;
#ifndef windows_platform
    pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
    pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
#endif
    fillStrInMsParam( &msp1, tinput->cmd );
    fillStrInMsParam( &msp2, tinput->cmdArgv );
    fillStrInMsParam( &msp3, tinput->execAddr );
    fillStrInMsParam( &msp4, tinput->hintPath );
    fillIntInMsParam( &msp5, tinput->addPathToArgv );
    thrid = tinput->threadId;

    threadIsAlive[thrid] = 0;
    status = msiExecCmd( &msp1, &msp2, &msp3, &msp4, &msp5, &msout, &( tinput->rei ) );

    if ( status < 0 ) {
        char noanswer[MAXSTR] = MON_OUTPUT_NO_ANSWER;
        rodsLogError( LOG_ERROR, status, "Call to msiExecCmd failed in msiServerMonPerf. " );
        rodsMonPerfLog( tinput->execAddr, tinput->rescName, noanswer, &( tinput->rei ) );
        threadIsAlive[thrid] = 1;
        retval = -1;
#ifndef windows_platform
        pthread_exit( ( void * )&retval );
#endif
    }

    /* if (&msout != NULL) { */
    /* write into the irodsMonPerf log file */
    if ( ( char * )( *( ( execCmdOut_t * ) msout.inOutStruct ) ).stdoutBuf.buf != NULL ) {
        output = ( char * )( *( ( execCmdOut_t * ) msout.inOutStruct ) ).stdoutBuf.buf;
        rodsMonPerfLog( tinput->execAddr, tinput->rescName, output, &( tinput->rei ) );
    }
    else {
        char noanswer[MAXSTR] = MON_OUTPUT_NO_ANSWER;
        rodsLog( LOG_ERROR, "Server monitoring: no output for the server %s, status = %i \n", tinput->execAddr, status );
        rodsMonPerfLog( tinput->execAddr, tinput->rescName, noanswer, &( tinput->rei ) );
        threadIsAlive[thrid] = 1;
        retval = -1;
#ifndef windows_platform
        pthread_exit( ( void * )&retval );
#endif
    }
    /*}
      else {
      char noanswer[MAXSTR] = MON_OUTPUT_NO_ANSWER;
      rodsLog(LOG_ERROR, "Server monitoring: problem with the server %s, status = %i \n", tinput->execAddr, status);
      rodsMonPerfLog(tinput->execAddr, tinput->rescName, noanswer,
      &(tinput->rei));
      threadIsAlive[thrid] = 1;
      retval = -1;
      #ifndef windows_platform
      pthread_exit((void *)&retval);
      #endif
      } */

    threadIsAlive[thrid] = 1;

    retval = 0;
#ifndef windows_platform
    pthread_exit( ( void * )&retval );
#endif
}

int checkHostAccessControl( char *username, char *hostclient, char *groupsname ) {

    //char *configDir;
    //char* hostControlAccessFile[LONG_NAME_LEN];
    char grouplist[MAX_SQL_ROWS][MAXSTR];
    const char *delim = " \t\n";
    char *eltstr, tempArr[NFIELDS][MAXLEN];

    /* try to open the HostControlAccess if it exists. */
    //configDir = getConfigDir();
    //snprintf( hostControlAccessFile, LONG_NAME_LEN, "%s/%s", configDir,HOST_ACCESS_CONTROL_FILE );

    std::string cfg_file;
    irods::error ret = irods::get_full_path_for_config_file( HOST_ACCESS_CONTROL_FILE, cfg_file );
    if ( !ret.ok() ) {
        irods::log( PASS( ret ) );
        return ret.code();
    }

    FILE *fp = fopen( cfg_file.c_str(), "r" );
    if ( fp == NULL ) {
        rodsLog( LOG_NOTICE,
                 "hostAuthCheck: can't open HostControlAccess file %s", cfg_file.c_str() );
        return UNIX_FILE_OPEN_ERR - errno;
    }
    /* parse the list of groups for the user from the groupsname char */
    int nelt = 0;
    strncpy( grouplist[0], strtok( groupsname, delim ), MAXSTR );
    while ( ( eltstr = strtok( NULL, delim ) ) ) {
        nelt++;
        strncpy( grouplist[nelt], eltstr, MAXSTR );
    }
    /* parse HostControlAccess and check if <user,IP,group> is allowed to access this server. */
    while ( !feof( fp ) ) {
        int indxc = 0;
        char line[MAX_NAME_LEN];
        if ( fgets( line, MAXLEN, fp ) ) {
            if ( line[0] != '#' && line[0] != '\n' ) {  /* Comment or empty line, ignore */
                eltstr = strtok( line, delim );
                strncpy( tempArr[indxc], eltstr, MAXSTR );
                while ( ( eltstr = strtok( NULL, delim ) ) ) {
                    indxc++;
                    strncpy( tempArr[indxc], eltstr, MAXSTR );
                }
                if ( ( indxc + 1 ) == NFIELDS ) {
                    boost::system::error_code error_code;
                    boost::asio::ip::address_v4 IPEntry( boost::asio::ip::address_v4::from_string( tempArr[2], error_code ) );
                    if ( error_code.value() ) {
                        continue;
                    }
                    boost::asio::ip::address_v4 subnetEntry( boost::asio::ip::address_v4::from_string( tempArr[3], error_code ) );
                    if ( error_code.value() ) {
                        continue;
                    }
                    boost::asio::ip::address_v4 visitorIP( boost::asio::ip::address_v4::from_string( hostclient, error_code ) );
                    if ( error_code.value() ) {
                        continue;
                    }
                    /* check through if one of the group does correspond to the one allowed */
                    int groupok = 1;
                    for ( int i = 0; i <= nelt; i++ ) {
                        if ( strcmp( tempArr[1], grouplist[i] ) == 0 ) {
                            groupok = 0;
                            break;
                        }
                    }
                    if ( strcmp( tempArr[1], "all" ) == 0 || groupok == 0 ) {
                        if ( strcmp( tempArr[0], "all" ) == 0 || strcmp( tempArr[0], username ) == 0 ) {
                            /* check if <client, group, clientIP> match this entry of the control access file.
                             * Get out immediately from this function: client is allowed to proceed. */
                            if ( ( ( visitorIP.to_ulong() ^ IPEntry.to_ulong() ) & ~subnetEntry.to_ulong() ) == 0 ) {
                                fclose( fp );    // JMC cppcheck - resource
                                return 0;
                            }
                        }
                    }
                }
            }
        }
    }
    fclose( fp ); // JMC cppcheck - resource
    return -1;
}

/**
 * \fn msiCheckHostAccessControl (ruleExecInfo_t *rei)
 *
 * \brief  This microservice sets the access control policy. It checks the
 *  access control by host and user based on the the policy given in the
 *  HostAccessControl file.
 *
 * \module core
 *
 * \since pre-2.1
 *
 * \author <NAME>
 * \date 2007-09
 *
 * \note  This microservice controls access to the iRODS service
 *  based on the information in the host based access configuration file:
{'fraction_non_alphanumeric': 0.13957832933013078, 'fraction_numerical': 0.0114758473445423, 'mean_word_length': 2.0666545421478584, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 97, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1673709', 'n_tokens_mistral': 11178, 'n_tokens_neox': 10812, 'n_words': 2549}