Open SCAP Library
systemdshared.h
1 
7 /*
8  * Copyright 2014 Red Hat Inc., Durham, North Carolina.
9  * All Rights Reserved.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24  *
25  * Authors:
26  *
27  */
28 
29 #pragma once
30 
31 #ifndef OPENSCAP_OVAL_PROBES_SYSTEMDSHARED_H_
32 #define OPENSCAP_OVAL_PROBES_SYSTEMDSHARED_H_
33 
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 
38 #include <limits.h>
39 #include <stdio.h>
40 #include <dbus/dbus.h>
41 #include "common/debug_priv.h"
42 #include "oscap_helpers.h"
43 
44 // Old versions of libdbus API don't have DBusBasicValue and DBus8ByteStruct
45 // as a public typedefs.
46 // These two typedefs were copied from libdbus 1.8 branch, see
47 // http://cgit.freedesktop.org/dbus/dbus/tree/dbus/dbus-types.h?h=dbus-1.8#n137
48 typedef struct
49 {
50  dbus_uint32_t first32;
51  dbus_uint32_t second32;
53 
54 typedef union
55 {
56  unsigned char bytes[8];
57  dbus_int16_t i16;
58  dbus_uint16_t u16;
59  dbus_int32_t i32;
60  dbus_uint32_t u32;
61  dbus_bool_t bool_val;
62 #ifdef DBUS_HAVE_INT64
63  dbus_int64_t i64;
64  dbus_uint64_t u64;
65 #endif
67  double dbl;
68  unsigned char byt;
69  char *str;
70  int fd;
72 
73 static char *get_path_by_unit(DBusConnection *conn, const char *unit)
74 {
75  DBusMessage *msg = NULL;
76  DBusPendingCall *pending = NULL;
77  _DBusBasicValue path;
78  char *ret = NULL;
79 
80  msg = dbus_message_new_method_call(
81  "org.freedesktop.systemd1",
82  "/org/freedesktop/systemd1",
83  "org.freedesktop.systemd1.Manager",
84  // LoadUnit is similar to GetUnit except it will load the unit file
85  // if it hasn't been loaded yet.
86  "LoadUnit"
87  );
88  if (msg == NULL) {
89  dD("Failed to create dbus_message via dbus_message_new_method_call!");
90  goto cleanup;
91  }
92 
93  DBusMessageIter args;
94 
95  dbus_message_iter_init_append(msg, &args);
96  if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &unit)) {
97  dD("Failed to append unit '%s' string parameter to dbus message!", unit);
98  goto cleanup;
99  }
100 
101  if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
102  dD("Failed to send message via dbus!");
103  goto cleanup;
104  }
105  if (pending == NULL) {
106  dD("Invalid dbus pending call!");
107  goto cleanup;
108  }
109 
110  dbus_connection_flush(conn);
111  dbus_message_unref(msg); msg = NULL;
112 
113  dbus_pending_call_block(pending);
114  msg = dbus_pending_call_steal_reply(pending);
115  if (msg == NULL) {
116  dD("Failed to steal dbus pending call reply.");
117  goto cleanup;
118  }
119  dbus_pending_call_unref(pending); pending = NULL;
120 
121  if (!dbus_message_iter_init(msg, &args)) {
122  dD("Failed to initialize iterator over received dbus message.");
123  goto cleanup;
124  }
125 
126  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) {
127  dD("Expected string argument in reply. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&args)));
128  goto cleanup;
129  }
130 
131  dbus_message_iter_get_basic(&args, &path);
132  ret = oscap_strdup(path.str);
133  dbus_message_unref(msg); msg = NULL;
134 
135 cleanup:
136  if (pending != NULL)
137  dbus_pending_call_unref(pending);
138 
139  if (msg != NULL)
140  dbus_message_unref(msg);
141 
142  return ret;
143 }
144 
145 static int get_all_systemd_units(DBusConnection* conn, int(*callback)(const char *, void *), void *cbarg)
146 {
147  DBusMessage *msg = NULL;
148  DBusPendingCall *pending = NULL;
149  char ret = 1;
150 
151  msg = dbus_message_new_method_call(
152  "org.freedesktop.systemd1",
153  "/org/freedesktop/systemd1",
154  "org.freedesktop.systemd1.Manager",
155  "ListUnits"
156  );
157  if (msg == NULL) {
158  dD("Failed to create dbus_message via dbus_message_new_method_call!");
159  goto cleanup;
160  }
161 
162  DBusMessageIter args, unit_iter;
163 
164  // the args should be empty for this call
165  dbus_message_iter_init_append(msg, &args);
166 
167  if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
168  dD("Failed to send message via dbus!");
169  goto cleanup;
170  }
171  if (pending == NULL) {
172  dD("Invalid dbus pending call!");
173  goto cleanup;
174  }
175 
176  dbus_connection_flush(conn);
177  dbus_message_unref(msg); msg = NULL;
178 
179  dbus_pending_call_block(pending);
180  msg = dbus_pending_call_steal_reply(pending);
181  if (msg == NULL) {
182  dD("Failed to steal dbus pending call reply.");
183  goto cleanup;
184  }
185  dbus_pending_call_unref(pending); pending = NULL;
186 
187  if (!dbus_message_iter_init(msg, &args)) {
188  dD("Failed to initialize iterator over received dbus message.");
189  goto cleanup;
190  }
191 
192  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) {
193  dD("Expected array of structs in reply. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&args)));
194  goto cleanup;
195  }
196 
197  dbus_message_iter_recurse(&args, &unit_iter);
198  do {
199  if (dbus_message_iter_get_arg_type(&unit_iter) != DBUS_TYPE_STRUCT) {
200  dD("Expected unit struct as elements in returned array. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&unit_iter)));
201  goto cleanup;
202  }
203 
204  DBusMessageIter unit_name;
205  dbus_message_iter_recurse(&unit_iter, &unit_name);
206 
207  if (dbus_message_iter_get_arg_type(&unit_name) != DBUS_TYPE_STRING) {
208  dD("Expected string as the first element in the unit struct. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&unit_name)));
209  goto cleanup;
210  }
211 
212  _DBusBasicValue value;
213  dbus_message_iter_get_basic(&unit_name, &value);
214  char *unit_name_s = oscap_strdup(value.str);
215  int cbret = callback(unit_name_s, cbarg);
216  free(unit_name_s);
217  if (cbret != 0) {
218  goto cleanup;
219  }
220  }
221  while (dbus_message_iter_next(&unit_iter));
222 
223  dbus_message_unref(msg); msg = NULL;
224 
225  ret = 0;
226 
227 cleanup:
228  if (pending != NULL)
229  dbus_pending_call_unref(pending);
230 
231  if (msg != NULL)
232  dbus_message_unref(msg);
233 
234  return ret;
235 }
236 
237 static char *dbus_value_to_string(DBusMessageIter *iter)
238 {
239  const int arg_type = dbus_message_iter_get_arg_type(iter);
240  if (dbus_type_is_basic(arg_type)) {
241  _DBusBasicValue value;
242  dbus_message_iter_get_basic(iter, &value);
243 
244  switch (arg_type)
245  {
246  case DBUS_TYPE_BYTE:
247  return oscap_sprintf("%c", value.byt);
248 
249  case DBUS_TYPE_BOOLEAN:
250  return oscap_strdup(value.bool_val ? "true" : "false");
251 
252  case DBUS_TYPE_INT16:
253  return oscap_sprintf("%i", value.i16);
254 
255  case DBUS_TYPE_UINT16:
256  return oscap_sprintf("%u", value.u16);
257 
258  case DBUS_TYPE_INT32:
259  return oscap_sprintf("%i", value.i32);
260 
261  case DBUS_TYPE_UINT32:
262  return oscap_sprintf("%u", value.u32);
263 
264 #ifdef DBUS_HAVE_INT64
265  case DBUS_TYPE_INT64:
266  return oscap_sprintf("%li", value.i64);
267 
268  case DBUS_TYPE_UINT64:
269  return oscap_sprintf("%lu", value.u64);
270 #endif
271 
272  case DBUS_TYPE_DOUBLE:
273  return oscap_sprintf("%g", value.dbl);
274 
275  case DBUS_TYPE_STRING:
276  case DBUS_TYPE_OBJECT_PATH:
277  case DBUS_TYPE_SIGNATURE:
278  return oscap_strdup(value.str);
279 
280  // non-basic types
281  //case DBUS_TYPE_ARRAY:
282  //case DBUS_TYPE_STRUCT:
283  //case DBUS_TYPE_DICT_ENTRY:
284  //case DBUS_TYPE_VARIANT:
285 
286  //case DBUS_TYPE_UNIX_FD:
287  // return oscap_sprintf("%i", value.fd);
288 
289  default:
290  dD("Encountered unknown dbus basic type!");
291  return oscap_strdup("error, unknown basic type!");
292  }
293  }
294  else if (arg_type == DBUS_TYPE_ARRAY) {
295  DBusMessageIter array;
296  dbus_message_iter_recurse(iter, &array);
297 
298  char *ret = NULL;
299  do {
300  char *element = dbus_value_to_string(&array);
301 
302  if (element == NULL)
303  continue;
304 
305  char *old_ret = ret;
306  if (old_ret == NULL)
307  ret = oscap_sprintf("%s", element);
308  else
309  ret = oscap_sprintf("%s, %s", old_ret, element);
310 
311  free(old_ret);
312  free(element);
313  }
314  while (dbus_message_iter_next(&array));
315 
316  return ret;
317  }/*
318  else if (arg_type == DBUS_TYPE_VARIANT) {
319  DBusMessageIter inner;
320  dbus_message_iter_recurse(iter, &inner);
321  return dbus_value_to_string(&inner);
322  }*/
323 
324  return NULL;
325 }
326 
327 static DBusConnection *connect_dbus()
328 {
329  DBusConnection *conn = NULL;
330 
331  DBusError err;
332  dbus_error_init(&err);
333 
334  const char *prefix = getenv("OSCAP_PROBE_ROOT");
335  if (prefix != NULL) {
336  char dbus_address[PATH_MAX] = {0};
337  snprintf(dbus_address, PATH_MAX, "unix:path=%s/run/dbus/system_bus_socket", prefix);
338  setenv("DBUS_SYSTEM_BUS_ADDRESS", dbus_address, 0);
339  /* We won't overwrite DBUS_SYSTEM_BUS_ADDRESS so that
340  * user could have a way to define some non-standard system bus socket location */
341  }
342 
343  conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
344  if (dbus_error_is_set(&err)) {
345  dD("Failed to get DBUS_BUS_SYSTEM connection - %s", err.message);
346  goto cleanup;
347  }
348  if (conn == NULL) {
349  dD("DBusConnection == NULL!");
350  goto cleanup;
351  }
352 
353  dbus_bus_register(conn, &err);
354  if (dbus_error_is_set(&err)) {
355  dD("Failed to register on dbus - %s", err.message);
356  goto cleanup;
357  }
358 
359 cleanup:
360  dbus_error_free(&err);
361 
362  return conn;
363 }
364 
365 static void disconnect_dbus(DBusConnection *conn)
366 {
367  // NOOP
368 
369  // Connections retrieved via dbus_bus_get shall not be destroyed,
370  // these connections are shared.
371 }
372 
373 #endif
oscap debug helpers private header
Definition: systemdshared.h:49
Definition: systemdshared.h:55
dbus_uint16_t u16
as int16
Definition: systemdshared.h:58
dbus_int16_t i16
as int16
Definition: systemdshared.h:57
double dbl
as double
Definition: systemdshared.h:67
_DBus8ByteStruct eight
as 8-byte struct
Definition: systemdshared.h:66
char * str
as char* (string, object path or signature)
Definition: systemdshared.h:69
int fd
as Unix file descriptor
Definition: systemdshared.h:70
dbus_uint32_t u32
as int32
Definition: systemdshared.h:60
dbus_bool_t bool_val
as boolean
Definition: systemdshared.h:61
unsigned char byt
as byte
Definition: systemdshared.h:68
dbus_int32_t i32
as int32
Definition: systemdshared.h:59