<commit_before>/* Copyright (c) 2016, Jaguar Land Rover. All Rights Reserved.
 * 
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0. 
 */

/** @file rvi.c
 *
 * @author <NAME> &lt;<EMAIL>&gt;
 */

#include "rvi_list.h"
#include "btree.h"

#include <jansson.h>
#include <jwt.h>

#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>

#include "rvi.h"
#include <dirent.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <time.h>

#define TLS_BUFSIZE  16384 /* Maximum TLS frame size is 16K bytes */

/* *************** */
/* DATA STRUCTURES */
/* *************** */

/** @brief verbose variable */
bool verbose = false;

/** @brief RVI context */
typedef struct TRviContext {

    /* 
     * Btrees for indexing remote connections, RVI services by name, and RVI 
     * services by registrant. 
     */
    btree_t *remoteIdx;        /* Remote connections by fd */
    btree_t *serviceNameIdx;  /* Services by fully qualified service name */
    btree_t *serviceRegIdx;   /* Services by fd of registering node ---*/
                            /*  note: local services designated 0 (stdin)  */

    /* Properties set in configuration file */
    char *cadir;    /* Directory containing the trusted certificate store */
    char *creddir;  /* Directory containing base64-encoded JWT credentials */
    char *certfile; /* File containing X.509 public key certificate (PKC) */
    char *keyfile;  /* File containing corresponding private key */
    char *cafile;   /* File containing CA public key certificate(s) */
    char *id;       /* Unique device ID. Format is "domain/type/uuid", e.g.: */
                    /* genivi.org/node/839fc839-5fab-472f-87b3-a8fbbd7e3935 */

    /* List of RVI credentials loaded into memory for quick access when
     * negotiating connections */
    TRviList *creds;

    /* SSL context for spawning new sessions.  */
    /* Contains X509 certs, config settings, etc */
    SSL_CTX *sslCtx;

    TRviList *rights;
} TRviContext;

/** @brief Data for connection to remote node */
typedef struct TRviRemote {
    /** File descriptor for the connection */
    int fd;
    /** List of TRviRights structures, containing receive & invoke rights and
     * expiration */
    TRviList *rights;
    /** Pointer to data buffer for partial I/O operations */
    void *buf;
    /** Length of buffer */
    int buflen;
    /** Pointer to BIO chain from OpenSSL library */
    BIO *sbio;
} TRviRemote;

/** @brief Data for service */
typedef struct TRviService {
    /** The fully-qualified service name */
    char *name;
    /** File descriptor of remote node that registered service */
    int registrant;
    /** Callback function to execute upon service invocation */
    TRviCallback callback;
    /** Service data to be passed to the callback */
    void *data;
} TRviService;

/** Data structure for rights parsed from validated credential */
typedef struct TRviRights {
    json_t *receive;    /* json array for right(s) to receive */
    json_t *invoke;     /* json array for right(s) to invoke */
    long expiration;     /* unix epoch time for jwt's validity.end */
} TRviRights;

/* 
 * Declarations for internal functions not exposed in the API 
 */

TRviService *rviServiceCreate ( const char *name, const int registrant, 
                                    const TRviCallback callback, 
                                    const void *serviceData );

void rviServiceDestroy ( TRviService *service );

TRviRemote *rviRemoteCreate ( BIO *sbio, const int fd );

void rviRemoteDestroy ( TRviRemote *remote );

TRviRights *rviRightsCreate (   const char *rightToReceive, 
                                    const char *rightToInvoke, 
                                    long validity );

void rviRightsDestroy ( TRviRights *rights );

void rviRightsListDestroy ( TRviList *list );

void rviCredentialListDestroy ( TRviList *list );

char *rviFqsnGet( TRviHandle handle, const char *serviceName );

/* Comparison functions for constructing btrees and retrieving values */
int rviCompareFd ( void *a, void *b );

int rviCompareRegistrant ( void *a, void *b );

int rviCompareName ( void *a, void *b );

int rviComparePattern ( const char *pattern, const char *fqsn );

/* Utility functions related to OpenSSL library */
int sslVerifyCallback ( int ok, X509_STORE_CTX *store );

SSL_CTX *rviSetupClientCtx ( TRviHandle handle );

/* Additional utility functions */

int rviReadJsonConfig ( TRviHandle handle, const char * filename );

int rviReadJsonChunk( json_t **json, char *src, TRviRemote *remote);

json_t *rviGetJsonGrant ( jwt_t *jwt, const char *grant );

char *rviGetPubkeyFile( char *filename );

int rviValidateCredential( TRviHandle handle, const char *cred, X509 *cert );

int rviGetRightsFromCredential( TRviHandle handle, const char *cred, 
                           TRviList *rights );

int rviRightToReceiveError( TRviList *rlist, const char *serviceName );

int rviRightToInvokeError( TRviList *rlist, const char *serviceName );

int rviRemoveService(TRviHandle handle, const char *serviceName);

int rviReadAu( TRviHandle handle, json_t *msg, TRviRemote *remote );

int rviWriteAu( TRviHandle handle, TRviRemote *remote );

int rviReadSa( TRviHandle handle, json_t *msg, TRviRemote *remote );

int rviAllServiceAnnounce( TRviHandle handle, TRviRemote *remote );

int rviServiceAnnounce( TRviHandle handle, TRviService *service, int available );

int rviReadRcv( TRviHandle handle, json_t *msg, TRviRemote *remote );

/****************************************************************************/

/* 
 * This function compares 2 pointers to TRviRemote structures on the basis of
 * the remote's file descriptor. It is used for building the index for remote
 * connections. 
 */
int rviCompareFd ( void *a, void *b )
{
    TRviRemote *remoteA = a;
    TRviRemote *remoteB = b;

    return ( remoteA->fd - remoteB->fd );
}

/* 
 * This function compares 2 pointers to TRviService structures on the basis
 * of the registrant (i.e., file descriptor). For services registered by the
 * same remote RVI node, the service name is used to guarantee a unique
 * position in the b-tree. 
 */
int rviCompareRegistrant ( void *a, void *b )
{
    TRviService *serviceA = a;
    TRviService *serviceB = b;

    int result;
    if ((( result = ( serviceA->registrant - serviceB->registrant)) == 0 ) &&
            serviceA->name && serviceB->name ) {
        result = strcmp ( serviceA->name, serviceB->name );
    }

    return result;
}

/* 
 * This function will compare 2 pointers to TRviService structures on the
 * basis of the unique fully-qualified service name. 
 */
int rviCompareName ( void *a, void *b )
{
    TRviService *serviceA = a;
    TRviService *serviceB = b;

    return strcmp ( serviceA->name, serviceB->name );
}

/*
 * This function compares an RVI pattern to a fully-qualified service name. If
 * the service name matches the pattern, it returns RVI_OK or an error
 * otherwise.
 */
int rviComparePattern ( const char *pattern, const char *fqsn )
{
    /* Check input */
    if( !pattern || !fqsn ) { return EINVAL; }
    /* While there are bytes to compare */
    while( *pattern != '\0' && *fqsn != '\0' ) {
        /* If there's a topic wildcard... */
        if( *pattern == '+' ) {
            /* Advance topic in pattern */
            while( *pattern++ != '/' && *pattern != '\0' );
            /* Advance topic in fqsn */
            while( *fqsn++ != '/' && *fqsn != '\0' );
        }
        /* If the bytes don't match, return error */
        if( *pattern++ != *fqsn++ ) { return -1; }
    }
    /* If the pattern still has characters, the fqsn doesn't match */
    if( *pattern != '\0' ) { return -1; }

    /* Otherwise, the fqsn matches the pattern */
    return RVI_OK;
}

/* 
 * This function initializes a new service struct and sets the name,
 * registrant, and callback to the specified values. 
 *
 * If service name is null or registrant is negative, this returns NULL and
 * performs no operations. 
 */

TRviService *rviServiceCreate ( const char *name, const int registrant, 
                                    const TRviCallback callback, 
                                    const void *serviceData )
{
    /* If name is NULL or registrant is negative, there's an error */
    if ( !name || (registrant < 0) ) { return NULL; }

    /* Zero-initialize the struct */
    TRviService *service = malloc( sizeof ( TRviService ) );
    if( !service ) { return NULL; }
    memset(service, 0, sizeof ( TRviService ) );

    /* Set the service name */
    service->name = strdup ( name );

    /* Set the service registrant */<commit_msg>Remove unnecessary const from rviServiceCreate<commit_after>/* Copyright (c) 2016, Jaguar Land Rover. All Rights Reserved.
 * 
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0. 
 */

/** @file rvi.c
 *
 * @author <NAME> &lt;tjamison<EMAIL>&gt;
 */

#include "rvi_list.h"
#include "btree.h"

#include <jansson.h>
#include <jwt.h>

#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>

#include "rvi.h"
#include <dirent.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <time.h>

#define TLS_BUFSIZE  16384 /* Maximum TLS frame size is 16K bytes */

/* *************** */
/* DATA STRUCTURES */
/* *************** */

/** @brief verbose variable */
bool verbose = false;

/** @brief RVI context */
typedef struct TRviContext {

    /* 
     * Btrees for indexing remote connections, RVI services by name, and RVI 
     * services by registrant. 
     */
    btree_t *remoteIdx;        /* Remote connections by fd */
    btree_t *serviceNameIdx;  /* Services by fully qualified service name */
    btree_t *serviceRegIdx;   /* Services by fd of registering node ---*/
                            /*  note: local services designated 0 (stdin)  */

    /* Properties set in configuration file */
    char *cadir;    /* Directory containing the trusted certificate store */
    char *creddir;  /* Directory containing base64-encoded JWT credentials */
    char *certfile; /* File containing X.509 public key certificate (PKC) */
    char *keyfile;  /* File containing corresponding private key */
    char *cafile;   /* File containing CA public key certificate(s) */
    char *id;       /* Unique device ID. Format is "domain/type/uuid", e.g.: */
                    /* genivi.org/node/839fc839-5fab-472f-87b3-a8fbbd7e3935 */

    /* List of RVI credentials loaded into memory for quick access when
     * negotiating connections */
    TRviList *creds;

    /* SSL context for spawning new sessions.  */
    /* Contains X509 certs, config settings, etc */
    SSL_CTX *sslCtx;

    TRviList *rights;
} TRviContext;

/** @brief Data for connection to remote node */
typedef struct TRviRemote {
    /** File descriptor for the connection */
    int fd;
    /** List of TRviRights structures, containing receive & invoke rights and
     * expiration */
    TRviList *rights;
    /** Pointer to data buffer for partial I/O operations */
    void *buf;
    /** Length of buffer */
    int buflen;
    /** Pointer to BIO chain from OpenSSL library */
    BIO *sbio;
} TRviRemote;

/** @brief Data for service */
typedef struct TRviService {
    /** The fully-qualified service name */
    char *name;
    /** File descriptor of remote node that registered service */
    int registrant;
    /** Callback function to execute upon service invocation */
    TRviCallback callback;
    /** Service data to be passed to the callback */
    void *data;
} TRviService;

/** Data structure for rights parsed from validated credential */
typedef struct TRviRights {
    json_t *receive;    /* json array for right(s) to receive */
    json_t *invoke;     /* json array for right(s) to invoke */
    long expiration;     /* unix epoch time for jwt's validity.end */
} TRviRights;

/* 
 * Declarations for internal functions not exposed in the API 
 */

TRviService *rviServiceCreate ( const char *name, const int registrant, 
                                    const TRviCallback callback, 
                                    void *serviceData );

void rviServiceDestroy ( TRviService *service );

TRviRemote *rviRemoteCreate ( BIO *sbio, const int fd );

void rviRemoteDestroy ( TRviRemote *remote );

TRviRights *rviRightsCreate (   const char *rightToReceive, 
                                    const char *rightToInvoke, 
                                    long validity );

void rviRightsDestroy ( TRviRights *rights );

void rviRightsListDestroy ( TRviList *list );

void rviCredentialListDestroy ( TRviList *list );

char *rviFqsnGet( TRviHandle handle, const char *serviceName );

/* Comparison functions for constructing btrees and retrieving values */
int rviCompareFd ( void *a, void *b );

int rviCompareRegistrant ( void *a, void *b );

int rviCompareName ( void *a, void *b );

int rviComparePattern ( const char *pattern, const char *fqsn );

/* Utility functions related to OpenSSL library */
int sslVerifyCallback ( int ok, X509_STORE_CTX *store );

SSL_CTX *rviSetupClientCtx ( TRviHandle handle );

/* Additional utility functions */

int rviReadJsonConfig ( TRviHandle handle, const char * filename );

int rviReadJsonChunk( json_t **json, char *src, TRviRemote *remote);

json_t *rviGetJsonGrant ( jwt_t *jwt, const char *grant );

char *rviGetPubkeyFile( char *filename );

int rviValidateCredential( TRviHandle handle, const char *cred, X509 *cert );

int rviGetRightsFromCredential( TRviHandle handle, const char *cred, 
                           TRviList *rights );

int rviRightToReceiveError( TRviList *rlist, const char *serviceName );

int rviRightToInvokeError( TRviList *rlist, const char *serviceName );

int rviRemoveService(TRviHandle handle, const char *serviceName);

int rviReadAu( TRviHandle handle, json_t *msg, TRviRemote *remote );

int rviWriteAu( TRviHandle handle, TRviRemote *remote );

int rviReadSa( TRviHandle handle, json_t *msg, TRviRemote *remote );

int rviAllServiceAnnounce( TRviHandle handle, TRviRemote *remote );

int rviServiceAnnounce( TRviHandle handle, TRviService *service, int available );

int rviReadRcv( TRviHandle handle, json_t *msg, TRviRemote *remote );

/****************************************************************************/

/* 
 * This function compares 2 pointers to TRviRemote structures on the basis of
 * the remote's file descriptor. It is used for building the index for remote
 * connections. 
 */
int rviCompareFd ( void *a, void *b )
{
    TRviRemote *remoteA = a;
    TRviRemote *remoteB = b;

    return ( remoteA->fd - remoteB->fd );
}

/* 
 * This function compares 2 pointers to TRviService structures on the basis
 * of the registrant (i.e., file descriptor). For services registered by the
 * same remote RVI node, the service name is used to guarantee a unique
 * position in the b-tree. 
 */
int rviCompareRegistrant ( void *a, void *b )
{
    TRviService *serviceA = a;
    TRviService *serviceB = b;

    int result;
    if ((( result = ( serviceA->registrant - serviceB->registrant)) == 0 ) &&
            serviceA->name && serviceB->name ) {
        result = strcmp ( serviceA->name, serviceB->name );
    }

    return result;
}

/* 
 * This function will compare 2 pointers to TRviService structures on the
 * basis of the unique fully-qualified service name. 
 */
int rviCompareName ( void *a, void *b )
{
    TRviService *serviceA = a;
    TRviService *serviceB = b;

    return strcmp ( serviceA->name, serviceB->name );
}

/*
 * This function compares an RVI pattern to a fully-qualified service name. If
 * the service name matches the pattern, it returns RVI_OK or an error
 * otherwise.
 */
int rviComparePattern ( const char *pattern, const char *fqsn )
{
    /* Check input */
    if( !pattern || !fqsn ) { return EINVAL; }
    /* While there are bytes to compare */
    while( *pattern != '\0' && *fqsn != '\0' ) {
        /* If there's a topic wildcard... */
        if( *pattern == '+' ) {
            /* Advance topic in pattern */
            while( *pattern++ != '/' && *pattern != '\0' );
            /* Advance topic in fqsn */
            while( *fqsn++ != '/' && *fqsn != '\0' );
        }
        /* If the bytes don't match, return error */
        if( *pattern++ != *fqsn++ ) { return -1; }
    }
    /* If the pattern still has characters, the fqsn doesn't match */
    if( *pattern != '\0' ) { return -1; }

    /* Otherwise, the fqsn matches the pattern */
    return RVI_OK;
}

/* 
 * This function initializes a new service struct and sets the name,
 * registrant, and callback to the specified values. 
 *
 * If service name is null or registrant is negative, this returns NULL and
 * performs no operations. 
 */

TRviService *rviServiceCreate ( const char *name, const int registrant, 
                                    const TRviCallback callback, 
                                    void *serviceData )
{
    /* If name is NULL or registrant is negative, there's an error */
    if ( !name || (registrant < 0) ) { return NULL; }

    /* Zero-initialize the struct */
    TRviService *service = malloc( sizeof ( TRviService ) );
    if( !service ) { return NULL; }
    memset(service, 0, sizeof ( TRviService ) );

    /* Set the service name */
    service->name = strdup ( name );

    /* Set the service registrant */
{'fraction_non_alphanumeric': 0.11806696504447341, 'fraction_numerical': 0.00747832983966914, 'mean_word_length': 2.8382257012394, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5540496', 'n_tokens_mistral': 5408, 'n_tokens_neox': 5115, 'n_words': 1862}