/*
* Copyright 2011--2014 Red Hat Inc., Durham, North Carolina.
* All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
* Tomas Heinrich <theinric@redhat.com>
*/
#include <config.h>
#include <libxml/tree.h>
#include "oval_definitions_impl.h"
#include "oval_agent_api_impl.h"
#include "oval_system_characteristics_impl.h"
#include "adt/oval_collection_impl.h"
#include "oval_parser_impl.h"
#include "common/util.h"
#include "common/debug_priv.h"
#include "common/elements.h"
typedef struct oval_record_field {
oval_record_field_type_t record_field_type;
char *name;
char *value;
oval_datatype_t datatype;
int mask;
} oval_record_field_t;
typedef struct oval_record_field_STATE {
oval_record_field_type_t record_field_type;
char *name;
char *value;
oval_datatype_t datatype;
int mask;
oval_operation_t operation;
struct oval_variable *variable;
oval_check_t var_check;
oval_check_t ent_check;
} oval_record_field_STATE_t;
typedef struct oval_record_field_ITEM {
oval_record_field_type_t record_field_type;
char *name;
char *value;
oval_datatype_t datatype;
int mask;
oval_syschar_status_t status;
} oval_record_field_ITEM_t;
bool oval_record_field_iterator_has_more(struct oval_record_field_iterator *itr)
{
return oval_collection_iterator_has_more((struct oval_iterator *) itr);
}
struct oval_record_field *oval_record_field_iterator_next(struct oval_record_field_iterator *itr)
{
return (struct oval_record_field *)
oval_collection_iterator_next((struct oval_iterator *) itr);
}
void oval_record_field_iterator_free(struct oval_record_field_iterator *itr)
{
oval_collection_iterator_free((struct oval_iterator *) itr);
}
struct oval_record_field *oval_record_field_new(oval_record_field_type_t type)
{
struct oval_record_field *rf;
switch (type) {
case OVAL_RECORD_FIELD_STATE:
{
struct oval_record_field_STATE *rfs;
rfs = malloc(sizeof(*rfs));
if (rfs == NULL)
return NULL;
rfs->operation = OVAL_OPERATION_UNKNOWN;
rfs->variable = NULL;
rfs->var_check = OVAL_CHECK_UNKNOWN;
rfs->ent_check = OVAL_CHECK_UNKNOWN;
rf = (struct oval_record_field *) rfs;
break;
}
case OVAL_RECORD_FIELD_ITEM:
{
struct oval_record_field_ITEM *rfi;
rfi = malloc(sizeof(*rfi));
if (rfi == NULL)
return NULL;
rfi->status = SYSCHAR_STATUS_UNKNOWN;
rf = (struct oval_record_field *) rfi;
break;
}
default:
dE("Unsupported record field type: %d.", type);
return NULL;
}
rf->record_field_type = type;
rf->name = NULL;
rf->value = NULL;
rf->datatype = OVAL_DATATYPE_UNKNOWN;
rf->mask = 0;
return rf;
}
struct oval_record_field *oval_record_field_clone(struct oval_record_field *old_rf)
{
struct oval_record_field *new_rf;
switch (old_rf->record_field_type) {
case OVAL_RECORD_FIELD_STATE:
{
struct oval_record_field_STATE *new_rfs, *old_rfs;
new_rfs = malloc(sizeof(*new_rfs));
if (new_rfs == NULL)
return NULL;
old_rfs = (struct oval_record_field_STATE *) old_rf;
new_rfs->operation = old_rfs->operation;
new_rfs->variable = old_rfs->variable;
new_rfs->var_check = old_rfs->var_check;
new_rfs->ent_check = old_rfs->ent_check;
new_rf = (struct oval_record_field *) new_rfs;
break;
}
case OVAL_RECORD_FIELD_ITEM:
{
struct oval_record_field_ITEM *new_rfi, *old_rfi;
new_rfi = malloc(sizeof(*new_rfi));
if (new_rfi == NULL)
return NULL;
old_rfi = (struct oval_record_field_ITEM *) old_rf;
new_rfi->status = old_rfi->status;
new_rf = (struct oval_record_field *) new_rfi;
break;
}
default:
dE("Unsupported record field type: %d.", old_rf->record_field_type);
return NULL;
}
new_rf->record_field_type = old_rf->record_field_type;
new_rf->name = oscap_strdup(old_rf->name);
new_rf->value = oscap_strdup(old_rf->value);
new_rf->datatype = old_rf->datatype;
new_rf->mask = old_rf->mask;
return new_rf;
}
void oval_record_field_free(struct oval_record_field *rf)
{
if (rf == NULL)
return;
if (rf->name != NULL)
free(rf->name);
if (rf->value != NULL)
free(rf->value);
rf->name = rf->value = NULL;
free(rf);
}
void oval_record_field_set_name(struct oval_record_field *rf, char *name)
{
rf->name = oscap_strdup(name);
}
void oval_record_field_set_value(struct oval_record_field *rf, char *value)
{
rf->value = oscap_strdup(value);
}
void oval_record_field_set_datatype(struct oval_record_field *rf, oval_datatype_t dt)
{
rf->datatype = dt;
}
void oval_record_field_set_mask(struct oval_record_field *rf, int mask)
{
rf->mask = mask;
}
void oval_record_field_set_operation(struct oval_record_field *rf, oval_operation_t operation)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) {
dE("Wrong record field type (set operation): %d.", rf->record_field_type);
return;
}
((struct oval_record_field_STATE *) rf)->operation = operation;
}
void oval_record_field_set_variable(struct oval_record_field *rf, struct oval_variable *var)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) {
dE("Wrong record field type (set variable): %d.", rf->record_field_type);
return;
}
((struct oval_record_field_STATE *) rf)->variable = var;
}
void oval_record_field_set_var_check(struct oval_record_field *rf, oval_check_t var_check)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) {
dE("Wrong record field type (set var_check): %d.", rf->record_field_type);
return;
}
((struct oval_record_field_STATE *) rf)->var_check = var_check;
}
void oval_record_field_set_ent_check(struct oval_record_field *rf, oval_check_t ent_check)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) {
dE("Wrong record field type (set ent_check): %d.", rf->record_field_type);
return;
}
((struct oval_record_field_STATE *) rf)->ent_check = ent_check;
}
void oval_record_field_set_status(struct oval_record_field *rf, oval_syschar_status_t status)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_ITEM) {
dE("Wrong record field type (set status): %d.", rf->record_field_type);
return;
}
((struct oval_record_field_ITEM *) rf)->status = status;
}
oval_record_field_type_t oval_record_field_get_type(struct oval_record_field *rf)
{
return rf->record_field_type;
}
char *oval_record_field_get_name(struct oval_record_field *rf)
{
return rf->name;
}
char *oval_record_field_get_value(struct oval_record_field *rf)
{
return rf->value;
}
oval_datatype_t oval_record_field_get_datatype(struct oval_record_field *rf)
{
return rf->datatype;
}
int oval_record_field_get_mask(struct oval_record_field *rf)
{
return rf->mask;
}
oval_operation_t oval_record_field_get_operation(struct oval_record_field *rf)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) {
dE("Wrong record field type (get operation): %d.", rf->record_field_type);
return OVAL_OPERATION_UNKNOWN;
}
return ((struct oval_record_field_STATE *) rf)->operation;
}
struct oval_variable *oval_record_field_get_variable(struct oval_record_field *rf)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) {
dE("Wrong record field type (get variable): %d.", rf->record_field_type);
return NULL;
}
return ((struct oval_record_field_STATE *) rf)->variable;
}
oval_check_t oval_record_field_get_var_check(struct oval_record_field *rf)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) {
dE("Wrong record field type (get var_check): %d.", rf->record_field_type);
return OVAL_CHECK_UNKNOWN;
}
return ((struct oval_record_field_STATE *) rf)->var_check;
}
oval_check_t oval_record_field_get_ent_check(struct oval_record_field *rf)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) {
dE("Wrong record field type (get ent_check): %d.", rf->record_field_type);
return OVAL_CHECK_UNKNOWN;
}
return ((struct oval_record_field_STATE *) rf)->ent_check;
}
oval_syschar_status_t oval_record_field_get_status(struct oval_record_field *rf)
{
if (rf->record_field_type != OVAL_RECORD_FIELD_ITEM) {
dE("Wrong record field type (get status): %d.", rf->record_field_type);
return SYSCHAR_STATUS_UNKNOWN;
}
return ((struct oval_record_field_ITEM *) rf)->status;
}
static void _oval_record_field_value_consumer(char *value, void *rf)
{
oval_record_field_set_value(rf, value);
}
int oval_record_field_parse_tag(xmlTextReaderPtr reader, struct oval_parser_context *context,
oscap_consumer_func consumer, void *user,
oval_record_field_type_t record_field_type)
{
int ret = 0, mask;
char *name;
oval_datatype_t datatype;
struct oval_record_field *rf;
rf = oval_record_field_new(record_field_type);
if (rf == NULL)
return -1;
name = (char *) xmlTextReaderGetAttribute(reader, BAD_CAST "name");
datatype = oval_datatype_parse(reader, "datatype", OVAL_DATATYPE_STRING);
mask = oval_parser_boolean_attribute(reader, "mask", 0);
oval_record_field_set_name(rf, name);
xmlFree(name);
oval_record_field_set_datatype(rf, datatype);
oval_record_field_set_mask(rf, mask);
switch (record_field_type) {
case OVAL_RECORD_FIELD_STATE:
{
oval_operation_t opr;
oval_check_t var_check;
oval_check_t ent_check;
char *var_ref;
opr = oval_operation_parse(reader, "operation", OVAL_OPERATION_EQUALS);
oval_record_field_set_operation(rf, opr);
var_check = oval_check_parse(reader, "var_check", OVAL_CHECK_ALL);
oval_record_field_set_var_check(rf, var_check);
ent_check = oval_check_parse(reader, "entity_check", OVAL_CHECK_ALL);
oval_record_field_set_ent_check(rf, ent_check);
var_ref = (char *) xmlTextReaderGetAttribute(reader, BAD_CAST "var_ref");
if (var_ref == NULL) {
ret = oscap_parser_text_value(reader, &_oval_record_field_value_consumer, rf);
} else {
struct oval_definition_model *model;
struct oval_variable *var;
model = context->definition_model;
var = oval_definition_model_get_new_variable(model, var_ref, OVAL_VARIABLE_UNKNOWN);
oval_record_field_set_variable(rf, var);
xmlFree(var_ref);
}
break;
}
case OVAL_RECORD_FIELD_ITEM:
{
oval_syschar_status_t status;
status = oval_syschar_status_parse(reader, "status", SYSCHAR_STATUS_EXISTS);
oval_record_field_set_status(rf, status);
ret = oscap_parser_text_value(reader, &_oval_record_field_value_consumer, rf);
break;
}
default:
dE("Impossible happened.");
}
(*consumer) (rf, user);
return ret;
}
xmlNode *oval_record_field_to_dom(struct oval_record_field *rf, bool parent_mask, xmlDoc *doc, xmlNode *parent, xmlNs *namespace)
{
char *name, *value;
bool rf_mask, masked;
xmlNode *node, *root_node;
oval_datatype_t datatype;
if (rf->record_field_type != OVAL_RECORD_FIELD_STATE
&& rf->record_field_type != OVAL_RECORD_FIELD_ITEM) {
dE("Unsupported record field type: %d.", rf->record_field_type);
return NULL;
}
root_node = xmlDocGetRootElement(doc);
name = oval_record_field_get_name(rf);
rf_mask = oval_record_field_get_mask(rf);
if (!xmlStrcmp(root_node->name, BAD_CAST OVAL_ROOT_ELM_RESULTS)
&& (rf_mask || parent_mask)) {
value = NULL;
masked = true;
} else {
value = oval_record_field_get_value(rf);
masked = false;
}
node = xmlNewTextChild(parent, namespace, BAD_CAST "field", BAD_CAST value);
xmlNewProp(node, BAD_CAST "name", BAD_CAST name);
datatype = oval_record_field_get_datatype(rf);
if (datatype != OVAL_DATATYPE_STRING)
xmlNewProp(node, BAD_CAST "datatype", BAD_CAST oval_datatype_get_text(datatype));
if (rf_mask)
xmlNewProp(node, BAD_CAST "mask", BAD_CAST "true");
switch (rf->record_field_type) {
case OVAL_RECORD_FIELD_STATE:
{
struct oval_variable *var;
oval_check_t var_check;
oval_check_t ent_check;
if (!masked) {
oval_operation_t opr;
opr = oval_record_field_get_operation(rf);
if (opr != OVAL_OPERATION_EQUALS)
xmlNewProp(node, BAD_CAST "operation", BAD_CAST oval_operation_get_text(opr));
}
var = oval_record_field_get_variable(rf);
if (var != NULL)
xmlNewProp(node, BAD_CAST "var_ref", BAD_CAST oval_variable_get_id(var));
var_check = oval_record_field_get_var_check(rf);
if (var_check != OVAL_CHECK_ALL)
xmlNewProp(node, BAD_CAST "var_check", BAD_CAST oval_check_get_text(var_check));
ent_check = oval_record_field_get_ent_check(rf);
if (ent_check != OVAL_CHECK_ALL)
xmlNewProp(node, BAD_CAST "entity_check", BAD_CAST oval_check_get_text(ent_check));
break;
}
case OVAL_RECORD_FIELD_ITEM:
{
oval_syschar_status_t status;
status = oval_record_field_get_status(rf);
if (status != SYSCHAR_STATUS_EXISTS)
xmlNewProp(node, BAD_CAST "status", BAD_CAST oval_syschar_status_get_text(status));
break;
}
default:
dE("Impossible happened.");
}
return node;
}