ADAPT / src / loaders.c
loaders.c
Raw
#include "loaders.h"
#include "attack_repertoire.h"
#include "arc_system.h"
#include "arc_utils.h"

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tokenize.h"

struct tool_plugin *extract_toolset(struct arc_model *toolset_arch, size_t *num_tools)
{

    //Noone can touch the model while we load tools.
    pthread_mutex_lock(&toolset_arch->sys_lock);
    //This is a bit slow but it should hopefully only happen a few times, at most.
    struct tool_plugin *toolset = malloc(sizeof(struct tool_plugin)*toolset_arch->sys->num_components);
    
    size_t num_loaded = 0;
    for(size_t i=0;i<toolset_arch->sys->num_components;i++)
    {
	struct arc_component *c = toolset_arch->sys->components[i];
	struct arc_property *p = comp_find_property(c,"PluginPath");
	if(p && p->type == P_STRING)
	{
	    load_tool_plugin(&toolset[i],p->v_str);
	    num_loaded++;
	}

	if(toolset[i].num_caps > 1)
	{
	    printf("[Init] Loaded %s with %zu capabilities\n",toolset[i].name,toolset[i].num_caps);
	}
	else
	{
	    printf("[Init] Loaded %s with %zu capability\n",toolset[i].name,toolset[i].num_caps);
	}
    }
    
    *num_tools = num_loaded;
    pthread_mutex_unlock(&toolset_arch->sys_lock);
    
    
    return toolset;
    
}


struct tool_capability *find_capability(struct tool_plugin *toolset, size_t num_tools, char *capability)
{
    for(size_t i=0;i<num_tools;i++)
    {
	for(size_t j=0;j<toolset[i].num_caps;j++)
	{
	    if(strcmp(toolset[i].caps[j].name,capability) == 0)
	    {
		return &toolset[i].caps[j];
	    }
	}
    }
    fprintf(stderr, "[Warn] Could not find tool to provide %s\n", capability);
    return NULL;
}

struct attack_step *extract_attack_steps(struct arc_model *attacks_arch, size_t *num_steps,
					 struct tool_plugin *toolset, size_t num_tools)
{
    pthread_mutex_lock(&attacks_arch->sys_lock);
    struct arc_component *c_attack_steps = sys_find_component(attacks_arch->sys,"AttackSteps");

    if(!c_attack_steps)
    {
	fprintf(stderr, "[Err] Could not find the AttackSteps component panic exiting\n");
    }
    
	
    //This is a bit slow but it should hopefully only happen a few times, at most.
    struct attack_step *attack_steps = malloc(sizeof(struct attack_step)*c_attack_steps->num_interfaces);

    for(size_t i = 0; i < c_attack_steps->num_interfaces; i++)
    {

	struct arc_interface *as_if = c_attack_steps->interfaces[i];

	char *a_s_name = as_if->if_name;
	struct arc_property *p_MATTACK = iface_find_property(as_if,"MitreAttck");
	if(!p_MATTACK)
	{
	    fprintf(stderr,"[Warn] Could not find the MitreAttck property for attack step:%s\n",a_s_name);
	    exit(-1);
	}
	struct tool_capability *cap = find_capability(toolset,num_tools, a_s_name);
	if(cap)
	{
	    cap_execute run = cap->run;
	    cap_guard guard = cap->guard;
	    attack_step_init(&attack_steps[i],a_s_name,p_MATTACK->v_str,run,guard);    
	}
	else
	{
	    fprintf(stderr, "[Warn] Could not find attack step capability for %s\n",a_s_name);
	    attack_step_init(&attack_steps[i],a_s_name,p_MATTACK->v_str,NULL,NULL);    
	}
	
    }
    *num_steps = c_attack_steps->num_interfaces;
    pthread_mutex_unlock(&attacks_arch->sys_lock);

    return attack_steps;
}


static void parse_add_attack_steps(struct attack_pattern *a_p, char *a_s_str)
{

    struct tokenizer a_s_tok;
    tokenizer_init(&a_s_tok, a_s_str, "[ , ]");
    char *token = next_token(&a_s_tok);
    while(token)
    {

	attack_pattern_add_step(a_p,token);
	token = next_token(&a_s_tok);
    }
    tokenizer_cleanup(&a_s_tok);
}

struct attack_pattern *extract_attack_patterns(struct arc_model *attacks_arch, size_t *num_patterns)
{
    pthread_mutex_lock(&attacks_arch->sys_lock);
    struct arc_component *c_attack_patterns = sys_find_component(attacks_arch->sys,"AttackPatterns");

    if(!c_attack_patterns)
    {
	fprintf(stderr, "[Err] Could not find the AttackSteps component panic exiting\n");
    }
    
	
    //This is a bit slow but it should hopefully only happen a few times, at most.
    struct attack_pattern *attack_patterns = malloc(sizeof(struct attack_pattern)*c_attack_patterns->num_interfaces);

    for(size_t i = 0; i < c_attack_patterns->num_interfaces; i++)
    {

	struct arc_interface *ap_if = c_attack_patterns->interfaces[i];

	char *a_p_name = ap_if->if_name;
	
	struct arc_property *p_attack_vector = iface_find_property(ap_if, "AttackVector");
	if(!p_attack_vector)
	{
	    fprintf(stderr,"[Err] Could not find the AttackVector property for attack pattern:%s\n",a_p_name);
	    exit(-1);
	}

	struct arc_property *p_attack_complexity = iface_find_property(ap_if, "AttackComplexity");
	if(!p_attack_complexity)
	{
	    fprintf(stderr,"[Err] Could not find the AttackComplexity property for attack pattern:%s\n",a_p_name);
	    exit(-1);
	}

	struct arc_property *p_required_privileges = iface_find_property(ap_if, "RequiredPrivileges");
	if(!p_required_privileges)
	{
	    fprintf(stderr,"[Err] Could not find the RequiredPrivileges property for attack pattern:%s\n",a_p_name);
	    exit(-1);
	}

	struct arc_property *p_user_interaction = iface_find_property(ap_if, "UserInteraction");
	if(!p_user_interaction)
	{
	    fprintf(stderr,"[Err] Could not find the UserInteraction property for attack pattern:%s\n",a_p_name);
	    exit(-1);
	}

	struct arc_property *p_running_time = iface_find_property(ap_if, "RunningTime");
	if(!p_running_time)
	{
	    fprintf(stderr,"[Err] Could not find the RunningTime property for attack pattern:%s\n",a_p_name);
	    exit(-1);
	}

	struct arc_property *p_attack_steps = iface_find_property(ap_if, "Steps");
	if(!p_attack_steps)
	{
	    fprintf(stderr,"[Err] Could not find the Steps property for attack pattern:%s\n",a_p_name);
	    exit(-1);
	}
	

	
	enum ATTACK_VECTOR a_v = str_to_attack_vector(p_attack_vector->v_str);
	enum ATTACK_COMPLEXITY a_c = str_to_attack_complexity(p_attack_complexity->v_str);
	enum PRIVILEGES_REQUIRED p_r = str_to_privileges_required(p_required_privileges->v_str);
	enum USER_INTERACTION u_i = str_to_user_interaction(p_user_interaction->v_str);
	enum RUNNING_TIME r_t = str_to_running_time(p_running_time->v_str);

	if(a_v == AV_Size || a_c == AC_Size || p_r == PR_Size || u_i == UI_Size || r_t == RT_Size)
	{
	    fprintf(stderr, "[Err] One of the utility metrics for the attack pattern %s is invalid, panic exiting\n",a_p_name);
	    exit(-1);
	}

       

	attack_pattern_init(&attack_patterns[i],a_p_name,a_v,a_c,p_r,u_i,r_t);
	parse_add_attack_steps(&attack_patterns[i], p_attack_steps->v_str);

	

    }
    *num_patterns = c_attack_patterns->num_interfaces;
    pthread_mutex_unlock(&attacks_arch->sys_lock);

    return attack_patterns;
}

void load_attack_repertoire(struct attack_repertoire *a_r, struct arc_model *attacks_m,
			    struct tool_plugin *toolset, size_t num_tools)
{
    size_t num_attack_steps = 0;
    struct attack_step *attack_steps = extract_attack_steps(attacks_m,&num_attack_steps,toolset,num_tools);

    //This is a bit slow and wastes a bit of memory, redesign if this becomes a bottleneck;
    for(size_t i=0;i<num_attack_steps;i++)
    {
	attack_repertoire_add_step(a_r, &attack_steps[i]);
    }
    free(attack_steps);

    size_t num_attack_patterns = 0;
    struct attack_pattern *attack_patterns = extract_attack_patterns(attacks_m,&num_attack_patterns);
    //The same holds for patterns
    for(size_t i = 0 ; i < num_attack_patterns ; i++)
    {
	attack_repertoire_add_pattern(a_r, &attack_patterns[i]);
	//attack_pattern_print(&attack_patterns[i]);
    }
    //Note this doesn't free the a_steps contents, ownership is passed to the repository for that.
    free(attack_patterns);
}

struct scan *extract_scans(struct arc_model *scans_arc, size_t *num_scans,
			   struct tool_plugin *toolset, size_t num_tools)
{
    pthread_mutex_lock(&scans_arc->sys_lock);
    struct arc_component *c_scans = sys_find_component(scans_arc->sys,"Scans");

    if(!c_scans)
    {
	fprintf(stderr, "[Err] Could not find the Scans component panic exiting\n");
    }
    
	
    //This is a bit slow but it should hopefully only happen a few times, at most.
    struct scan *scans = malloc(sizeof(struct scan)*c_scans->num_interfaces);

    for(size_t i = 0; i < c_scans->num_interfaces; i++)
    {

	struct arc_interface *s_if = c_scans->interfaces[i];

	char *s_name = s_if->if_name;
	struct arc_property *p_MATTACK = iface_find_property(s_if,"MitreAttck");
	if(!p_MATTACK)
	{
	    fprintf(stderr,"[Err] Could not find the MitreAttck property for scan:%s\n",s_name);
	    exit(-1);
	}

	struct arc_property *p_range = iface_find_property(s_if,"ScanRange");
	if(!p_range)
	{
	    fprintf(stderr,"[Err] Could not find the ScanRange property for scan:%s\n",s_name);
	    exit(-1);
	}
	struct arc_property *p_targets = iface_find_property(s_if,"ScanTargets");
	if(!p_targets)
	{
	    fprintf(stderr,"[Err] Could not find the ScanTargets property for scan:%s\n",s_name);
	    exit(-1);
	}
	struct arc_property *p_duration = iface_find_property(s_if,"ScanDuration");
	if(!p_duration)
	{
	    fprintf(stderr,"[Err] Could not find the ScanDuration property for scan:%s\n",s_name);
	    exit(-1);
	}
	struct arc_property *p_complexity = iface_find_property(s_if,"ScanComplexity");
	if(!p_complexity)
	{
	    fprintf(stderr,"[Err] Could not find the ScanComplexity property for scan:%s\n",s_name);
	    exit(-1);
	}

	enum SCAN_RANGE s_r = str_to_scan_range(p_range->v_str);
	enum SCAN_TARGETS s_t = str_to_scan_targets(p_targets->v_str);
	enum SCAN_DURATION s_d = str_to_scan_duration(p_duration->v_str);
	enum SCAN_COMPLEXITY s_c = str_to_scan_complexity(p_complexity->v_str);
	

	
	struct tool_capability *cap = find_capability(toolset, num_tools,s_name);
	if(cap)
	{
	    cap_execute run = cap->run;
	    cap_guard guard = cap->guard;
	    scan_init(&scans[i],s_name,p_MATTACK->v_str,run, guard,s_r,s_t,s_d,s_c);
	}
	else
	{
	    fprintf(stderr,"[Warn] Could not find scan capability %s\n",s_name);
	    scan_init(&scans[i],s_name,p_MATTACK->v_str,NULL,NULL,s_r,s_t,s_d,s_c);
	}
    }
    *num_scans = c_scans->num_interfaces;
    pthread_mutex_unlock(&scans_arc->sys_lock);

    return scans;
}

void load_scan_repertoire(struct scan_repertoire *s_r, struct arc_model *scans_m,
			  struct tool_plugin *toolset, size_t num_tools)
{

    size_t num_scans = 0;
    struct scan *scans = extract_scans(scans_m,&num_scans,toolset, num_tools);

    //This is a bit slow and wastes a bit of memory, redesign if this becomes a bottleneck;
    for(size_t i=0;i<num_scans;i++)
    {
	scan_repertoire_add_scan(s_r, &scans[i]);
    }
    free(scans);
    
}