Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial fix for systemdunitproperty probe #1533

Closed
wants to merge 9 commits into from
Closed
40 changes: 24 additions & 16 deletions src/OVAL/probes/unix/linux/systemdshared.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@ static int get_all_systemd_units(DBusConnection* conn, int(*callback)(const char

static char *dbus_value_to_string(DBusMessageIter *iter)
{
/* Unfortunately we don't know anything about semantics of data that we
* recieved from DBus. We can only use conversion that fits in most generic
* cases. This is a difference from behavior of systemctl show command.
* Systemd knows semantics of DBus data and in some situation it uses a
* different conversion, for example converts integer values to date and
* time.
*/
const int arg_type = dbus_message_iter_get_arg_type(iter);
if (dbus_type_is_basic(arg_type)) {
_DBusBasicValue value;
Expand All @@ -244,10 +251,10 @@ static char *dbus_value_to_string(DBusMessageIter *iter)
switch (arg_type)
{
case DBUS_TYPE_BYTE:
return oscap_sprintf("%c", value.byt);
return oscap_sprintf("0x%x", value.byt);

case DBUS_TYPE_BOOLEAN:
return oscap_strdup(value.bool_val ? "true" : "false");
return oscap_strdup(value.bool_val ? "yes" : "no");

case DBUS_TYPE_INT16:
return oscap_sprintf("%i", value.i16);
Expand Down Expand Up @@ -277,12 +284,6 @@ static char *dbus_value_to_string(DBusMessageIter *iter)
case DBUS_TYPE_SIGNATURE:
return oscap_strdup(value.str);

// non-basic types
//case DBUS_TYPE_ARRAY:
//case DBUS_TYPE_STRUCT:
//case DBUS_TYPE_DICT_ENTRY:
//case DBUS_TYPE_VARIANT:

//case DBUS_TYPE_UNIX_FD:
// return oscap_sprintf("%i", value.fd);

Expand All @@ -291,7 +292,19 @@ static char *dbus_value_to_string(DBusMessageIter *iter)
return oscap_strdup("error, unknown basic type!");
}
}
else if (arg_type == DBUS_TYPE_ARRAY) {
else if (arg_type == DBUS_TYPE_ARRAY || arg_type == DBUS_TYPE_STRUCT ||
arg_type == DBUS_TYPE_VARIANT || arg_type == DBUS_TYPE_DICT_ENTRY) {
/* OVAL specification for systemdunitproperty_item says: "The value
* of the property associated with a systemd unit. Exactly one value
* shall be used for all property types except dbus arrays - each
* array element shall be represented by one value."
* The properties that are dbus arrays are handled by the caller
* (get_all_properties_by_unit_path_using_interface). Therefore this
* code handles only dbus arrays that are part of a different top
* level dbus type. Also it handles other dbus container types which
* are not mentioned in the OVAL specification. We assume that these
* types should be serialized into a single value.
*/
DBusMessageIter array;
dbus_message_iter_recurse(iter, &array);

Expand All @@ -306,20 +319,15 @@ static char *dbus_value_to_string(DBusMessageIter *iter)
if (old_ret == NULL)
ret = oscap_sprintf("%s", element);
else
ret = oscap_sprintf("%s, %s", old_ret, element);
ret = oscap_sprintf("%s ; %s", old_ret, element);

free(old_ret);
free(element);
}
while (dbus_message_iter_next(&array));

return ret;
}/*
else if (arg_type == DBUS_TYPE_VARIANT) {
DBusMessageIter inner;
dbus_message_iter_recurse(iter, &inner);
return dbus_value_to_string(&inner);
}*/
}

return NULL;
}
Expand Down
84 changes: 66 additions & 18 deletions src/OVAL/probes/unix/linux/systemdunitproperty_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,19 @@
#include "systemdshared.h"
#include "systemdunitproperty_probe.h"

static int get_all_properties_by_unit_path(DBusConnection *conn, const char *unit_path, int(*callback)(const char *name, const char *value, void *arg), void *cbarg)
struct unit_callback_vars {
DBusConnection *dbus_conn;
probe_ctx *ctx;
SEXP_t *unit_entity;
SEXP_t *property_entity;
SEXP_t *se_unit;
SEXP_t *se_property;
SEXP_t *item;
};

static int collect_property(const char *property, const char *value, struct unit_callback_vars *vars);

static int get_all_properties_by_unit_path_using_interface(DBusConnection *conn, const char *unit_path, const char *interface, void *vars)
{
int ret = 1;
DBusMessage *msg = NULL;
Expand All @@ -57,7 +69,6 @@ static int get_all_properties_by_unit_path(DBusConnection *conn, const char *uni

DBusMessageIter args, property_iter;

const char *interface = "org.freedesktop.systemd1.Unit";

dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &interface)) {
Expand Down Expand Up @@ -135,7 +146,7 @@ static int get_all_properties_by_unit_path(DBusConnection *conn, const char *uni
if (element == NULL)
continue;

const int elementcbret = callback(property_name, element, cbarg);
const int elementcbret = collect_property(property_name, element, vars);
if (elementcbret > cbret)
cbret = elementcbret;

Expand All @@ -145,7 +156,7 @@ static int get_all_properties_by_unit_path(DBusConnection *conn, const char *uni
}
else {
char *property_value = dbus_value_to_string(&value_variant);
cbret = callback(property_name, property_value, cbarg);
cbret = collect_property(property_name, property_value, vars);
free(property_value);
}

Expand All @@ -169,20 +180,58 @@ static int get_all_properties_by_unit_path(DBusConnection *conn, const char *uni
return ret;
}

struct unit_callback_vars {
DBusConnection *dbus_conn;
probe_ctx *ctx;
SEXP_t *unit_entity;
SEXP_t *property_entity;
SEXP_t *se_unit;
SEXP_t *se_property;
SEXP_t *item;
};

static int property_callback(const char *property, const char *value, void *cbarg)
static int get_all_properties_by_unit_path(DBusConnection *conn, const char *unit, const char *unit_path, void *vars)
{
struct unit_callback_vars *vars = (struct unit_callback_vars *)cbarg;
const char *interface = "org.freedesktop.systemd1.Unit";
int ret = get_all_properties_by_unit_path_using_interface(conn, unit_path, interface, vars);
if (ret != 0) {
return ret;
}

/* All Unit objects implement the generic org.freedesktop.systemd1.Unit
* interface. But, depending on the unit type they also implement one
* unit-type-specific interface.
* https://www.freedesktop.org/wiki/Software/systemd/dbus/
*/
char *sep = strrchr(unit, '.');
if (sep == NULL) {
return ret;
}
char *unit_type = sep + 1;
if (!strcmp(unit_type, "service")) {
interface = "org.freedesktop.systemd1.Service";
} else if (!strcmp(unit_type, "socket")) {
interface = "org.freedesktop.systemd1.Socket";
} else if (!strcmp(unit_type, "target")) {
/* Target units have neither type-specific methods nor properties. */
return ret;
} else if (!strcmp(unit_type, "device")) {
interface = "org.freedesktop.systemd1.Device";
} else if (!strcmp(unit_type, "mount")) {
interface = "org.freedesktop.systemd1.Mount";
} else if (!strcmp(unit_type, "automount")) {
interface = "org.freedesktop.systemd1.Automount";
} else if (!strcmp(unit_type, "snapshot")) {
interface = "org.freedesktop.systemd1.Snapshot";
} else if (!strcmp(unit_type, "timer")) {
interface = "org.freedesktop.systemd1.Timer";
} else if (!strcmp(unit_type, "swap")) {
interface = "org.freedesktop.systemd1.Swap";
} else if (!strcmp(unit_type, "path")) {
interface = "org.freedesktop.systemd1.Path";
} else if (!strcmp(unit_type, "slice")) {
interface = "org.freedesktop.systemd1.Slice";
} else if (!strcmp(unit_type, "scope")) {
interface = "org.freedesktop.systemd1.Scope";
} else {
return ret;
}
ret = get_all_properties_by_unit_path_using_interface(conn, unit_path, interface, vars);
return ret;
}

static int collect_property(const char *property, const char *value, struct unit_callback_vars *vars)
{
if (vars->se_property != NULL) {
//
// Compare the previously matched entity to the current one
Expand Down Expand Up @@ -240,8 +289,7 @@ static int unit_callback(const char *unit, void *cbarg)
return 1;
}

get_all_properties_by_unit_path(vars->dbus_conn, unit_path,
property_callback, vars);
get_all_properties_by_unit_path(vars->dbus_conn, unit, unit_path, vars);

if (vars->item != NULL) {
probe_item_collect(vars->ctx, vars->item);
Expand Down