mirror of
https://github.com/NationalSecurityAgency/maat.git
synced 2026-11-13 00:11:29 -10:00
386 lines
9.8 KiB
C
386 lines
9.8 KiB
C
/*
|
|
* Copyright 2023 United States Government
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
/*! \file graph-fs.c: Implementation of the graph api as a set of
|
|
* files and directories.
|
|
*/
|
|
|
|
#include "graph-fs-private.h"
|
|
#include <errno.h>
|
|
|
|
/* end helper functions, begin api functions */
|
|
|
|
|
|
measurement_graph *create_measurement_graph(char *template)
|
|
{
|
|
measurement_graph *g = calloc(1, sizeof(measurement_graph));
|
|
char tmppath[PATH_MAX+1];
|
|
|
|
if(g == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
if(template != NULL) {
|
|
size_t tmpllen = strlen(template);
|
|
if(tmpllen > PATH_MAX) {
|
|
dlog(1, "Error creating measurement graph: template is too long");
|
|
free(g);
|
|
return NULL;
|
|
}
|
|
memcpy(g->path, template, tmpllen+1);
|
|
} else {
|
|
memcpy(g->path, PATH_TEMPLATE, strlen(PATH_TEMPLATE)+1);
|
|
}
|
|
|
|
/* mkdtemp modifies its argument in place. */
|
|
if(mkdtemp(g->path) == NULL) {
|
|
dlog(1, "Error creating graph backing store: %s\n",
|
|
strerror(errno) ?: "unknown error");
|
|
goto error;
|
|
}
|
|
chmod(g->path, S_IRWXU | S_IRWXG);
|
|
dlog(4, "Graph backing path at: %s\n", g->path);
|
|
|
|
|
|
if((construct_path(tmppath, PATH_MAX+1, g->path,
|
|
EDGES_SUBDIR, NULL) < 0)) {
|
|
dlog(1, "Error creating edge backing store: failed to sprintf\n");
|
|
goto error;
|
|
}
|
|
if(mkdir(tmppath, S_IRWXU | S_IRWXG) != 0) {
|
|
dlog(1, "Error creating edge backing store: %s\n",
|
|
strerror(errno) ?: "unknown error");
|
|
goto error;
|
|
}
|
|
|
|
if((construct_path(tmppath, PATH_MAX+1, g->path,
|
|
NODES_SUBDIR, NULL) < 0)) {
|
|
dlog(1, "error creating node backing store: failed to sprintf\n");
|
|
goto error;
|
|
}
|
|
if(mkdir(tmppath, S_IRWXU | S_IRWXG) != 0) {
|
|
dlog(1, "Error creating node backing store: %s\n",
|
|
strerror(errno) ?: "unknown error");
|
|
goto error;
|
|
}
|
|
|
|
if(construct_path(tmppath, PATH_MAX+1, g->path,
|
|
NODES_BY_ID_SUBDIR, NULL) < 0) {
|
|
dlog(1, "Error create node by_id path: pathname too long\n");
|
|
goto error;
|
|
}
|
|
if(mkdir(tmppath, S_IRWXU | S_IRWXG) != 0) {
|
|
dlog(1, "Error creating node by_id path: %s\n",
|
|
strerror(errno) ?: "unknown error");
|
|
goto error;
|
|
}
|
|
|
|
if(construct_path(tmppath, PATH_MAX+1, g->path,
|
|
NEXT_NODE_ID_FILE, NULL)< 0) {
|
|
dlog(1, "Error creating next_node_id file: pathname too long\n");
|
|
goto error;
|
|
}
|
|
if(buffer_to_file_perm(tmppath, (unsigned char*)"0", 1, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 1) {
|
|
dlog(1, "Error writing initial next_node_id file.\n");
|
|
goto error;
|
|
}
|
|
|
|
if(construct_path(tmppath, PATH_MAX+1, g->path,
|
|
NEXT_EDGE_ID_FILE, NULL)< 0) {
|
|
dlog(1, "Error creating next_edge_id file: pathname too long\n");
|
|
goto error;
|
|
}
|
|
if(buffer_to_file_perm(tmppath, (unsigned char*)"0", 1, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 1) {
|
|
dlog(1, "Error writing initial next_edge_id file.\n");
|
|
goto error;
|
|
}
|
|
|
|
|
|
|
|
return g;
|
|
|
|
error:
|
|
if(g->path[0] != '\0') {
|
|
rmrf(g->path);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void destroy_measurement_graph(measurement_graph *g)
|
|
{
|
|
if(g != NULL) {
|
|
rmrf(g->path);
|
|
}
|
|
free(g);
|
|
}
|
|
|
|
int merge_graphs(measurement_graph __attribute__((unused)) *in1,
|
|
measurement_graph __attribute__((unused)) *in2,
|
|
measurement_graph __attribute__((unused)) **out)
|
|
{
|
|
return -ENOTTY;
|
|
}
|
|
|
|
int merge_graphs_xml(size_t __attribute__((unused)) g1_size,
|
|
char __attribute__((unused)) *g1,
|
|
size_t __attribute__((unused)) g2_size,
|
|
char __attribute__((unused)) *g2,
|
|
unsigned char __attribute__((unused)) **out,
|
|
size_t __attribute__((unused)) *size)
|
|
{
|
|
return -ENOTTY;
|
|
}
|
|
|
|
measurement_graph *measurement_graph_copy_graph(measurement_graph __attribute__((unused)) *in)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
char *measurement_graph_get_path(measurement_graph *g)
|
|
{
|
|
return strdup(measurement_graph_path(g));
|
|
}
|
|
|
|
int map_measurement_graph(char *path, measurement_graph **out)
|
|
{
|
|
measurement_graph *tmp = malloc(sizeof(measurement_graph));
|
|
size_t len = strlen(path);
|
|
if(tmp == NULL) {
|
|
dlog(0, "Failed to allocate memory for measurement graph\n");
|
|
goto error;
|
|
}
|
|
if(len > PATH_MAX) {
|
|
dlog(0, "Error: Invalid path argument \"%s\" (too long)\n", path);
|
|
goto error;
|
|
} else {
|
|
memcpy(tmp->path, path, len+1);
|
|
}
|
|
*out = tmp;
|
|
return 0;
|
|
|
|
error:
|
|
free(tmp);
|
|
return -1;
|
|
}
|
|
|
|
void unmap_measurement_graph(measurement_graph *g)
|
|
{
|
|
free(g);
|
|
}
|
|
|
|
edge_id_t next_edge_id(measurement_graph *g)
|
|
{
|
|
char path[PATH_MAX+1];
|
|
char *buf;
|
|
edge_id_t id;
|
|
edge_id_str outbuf;
|
|
if(construct_path(path, PATH_MAX+1, g->path,
|
|
NEXT_EDGE_ID_FILE, NULL)< 0) {
|
|
return INVALID_NODE_ID;
|
|
}
|
|
|
|
buf = file_to_string(path);
|
|
if(buf == NULL) {
|
|
return INVALID_NODE_ID;
|
|
}
|
|
|
|
id = edge_id_of_str(buf);
|
|
free(buf);
|
|
|
|
if(id == INVALID_NODE_ID) {
|
|
return INVALID_NODE_ID;
|
|
}
|
|
|
|
str_of_edge_id(id+1, outbuf);
|
|
buffer_to_file_perm(path, (unsigned char*)outbuf, strlen(outbuf),
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
return id;
|
|
}
|
|
|
|
node_id_t next_node_id(measurement_graph *g)
|
|
{
|
|
char path[PATH_MAX+1];
|
|
char *buf;
|
|
node_id_t id;
|
|
node_id_str outbuf;
|
|
if(construct_path(path, PATH_MAX+1, g->path,
|
|
NEXT_NODE_ID_FILE, NULL)< 0) {
|
|
return INVALID_NODE_ID;
|
|
}
|
|
|
|
buf = file_to_string(path);
|
|
if(buf == NULL) {
|
|
return INVALID_NODE_ID;
|
|
}
|
|
|
|
id = node_id_of_str(buf);
|
|
free(buf);
|
|
|
|
if(id == INVALID_NODE_ID) {
|
|
return INVALID_NODE_ID;
|
|
}
|
|
|
|
str_of_node_id(id+1, outbuf);
|
|
buffer_to_file_perm(path, (unsigned char*)outbuf, strlen(outbuf),
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
return id;
|
|
}
|
|
|
|
node_id_t max_node_id(measurement_graph *g)
|
|
{
|
|
char path[PATH_MAX+1];
|
|
char *buf;
|
|
node_id_t id;
|
|
if(construct_path(path, PATH_MAX+1, g->path,
|
|
NEXT_NODE_ID_FILE, NULL)< 0) {
|
|
return INVALID_NODE_ID;
|
|
}
|
|
|
|
buf = file_to_string(path);
|
|
if(buf == NULL) {
|
|
return INVALID_NODE_ID;
|
|
}
|
|
|
|
id = node_id_of_str(buf);
|
|
free(buf);
|
|
|
|
return id;
|
|
}
|
|
|
|
int consume_from_pipe(int pfd, aggregator *aggregators, int nr_aggregators, GList **unconsumed)
|
|
{
|
|
char *line = NULL;
|
|
size_t len;
|
|
|
|
FILE *in = fdopen(pfd, "r");
|
|
if(!in) {
|
|
return -errno;
|
|
}
|
|
|
|
while(getline(&line, &len, in) != -1) {
|
|
int consumed = 0;
|
|
//Take off the newline
|
|
char *newline = strchr(line, '\n');
|
|
if(newline != NULL) {
|
|
*newline = '\0';
|
|
}
|
|
|
|
for(int i = 0; i < nr_aggregators; i++) {
|
|
aggregation_result r;
|
|
/* Need to give each its own copy of the line in case others edit */
|
|
char *tmp = strdup(line);
|
|
if(tmp == NULL) {
|
|
dlog(2, "Warning: strdup error on line\n");
|
|
continue;
|
|
}
|
|
|
|
r = aggregators[i].fn(tmp, aggregators[i].out);
|
|
free(tmp);
|
|
if(r == AGGREGATOR_CONSUMED) {
|
|
consumed = 1;
|
|
break;
|
|
}
|
|
if(r == AGGREGATOR_ERROR) {
|
|
dlog(2, "Warning: Aggregator error on line: %s\n", line);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if((consumed == 0) && (unconsumed != NULL)) {
|
|
*unconsumed = g_list_append(*unconsumed, strdup(line));
|
|
}
|
|
}
|
|
|
|
free(line);
|
|
fclose(in);
|
|
return 0;
|
|
}
|
|
|
|
static aggregation_result consume_simple_id(char *line, char *identifier, GList **out)
|
|
{
|
|
char *token = NULL;
|
|
char *idstr = NULL;
|
|
|
|
token = strtok(line, " ");
|
|
if(token == NULL || strcmp(token, identifier) != 0) {
|
|
return AGGREGATOR_PASS;
|
|
}
|
|
|
|
token = strtok(NULL, " ");
|
|
if(token == NULL || strlen(token) > 16) {
|
|
return AGGREGATOR_ERROR;
|
|
}
|
|
|
|
idstr = strdup(token);
|
|
if(idstr == NULL) {
|
|
return AGGREGATOR_ERROR;
|
|
}
|
|
|
|
*out = g_list_append(*out, idstr);
|
|
dlog(5, "Consumed %s id %s\n", identifier, idstr);
|
|
|
|
return AGGREGATOR_CONSUMED;
|
|
}
|
|
|
|
aggregation_result consume_nodes(char *line, GList **out)
|
|
{
|
|
return consume_simple_id(line, "NODE", out);
|
|
}
|
|
|
|
aggregation_result consume_edges(char *line, GList **out)
|
|
{
|
|
return consume_simple_id(line, "EDGE", out);
|
|
}
|
|
|
|
int retrieve_nodes(int pfd, GList **nodes)
|
|
{
|
|
GList *tmp = NULL;
|
|
aggregator aggregators[] = {{&consume_nodes, &tmp}};
|
|
int rc = consume_from_pipe(pfd, aggregators, 1, NULL);
|
|
if (rc == 0) {
|
|
*nodes = tmp;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int retrieve_edges(int pfd, GList **edges)
|
|
{
|
|
GList * tmp = NULL;
|
|
aggregator aggregators[] = {{&consume_edges, &tmp}};
|
|
int rc = consume_from_pipe(pfd, aggregators, 1, NULL);
|
|
if(rc == 0) {
|
|
*edges = tmp;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int retrieve_edges_and_nodes(int pfd, GList **edges, GList **nodes)
|
|
{
|
|
GList *tmp_nodes = NULL;
|
|
GList *tmp_edges = NULL;
|
|
aggregator aggregators[] = {{&consume_nodes, &tmp_nodes}, {&consume_edges, &tmp_edges}};
|
|
int rc = consume_from_pipe(pfd, aggregators, 2, NULL);
|
|
if(rc == 0) {
|
|
*edges = tmp_edges;
|
|
*nodes = tmp_nodes;
|
|
}
|
|
|
|
return rc;
|
|
}
|