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  dD("LoadUnit: %s", unit);
89 
90  if (msg == NULL) {
91  dD("Failed to create dbus_message via dbus_message_new_method_call!");
92  goto cleanup;
93  }
94 
95  DBusMessageIter args;
96 
97  dbus_message_iter_init_append(msg, &args);
98  if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &unit)) {
99  dD("Failed to append unit '%s' string parameter to dbus message!", unit);
100  goto cleanup;
101  }
102 
103  if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
104  dD("Failed to send message via dbus!");
105  goto cleanup;
106  }
107  if (pending == NULL) {
108  dD("Invalid dbus pending call!");
109  goto cleanup;
110  }
111 
112  dbus_connection_flush(conn);
113  dbus_message_unref(msg); msg = NULL;
114 
115  dbus_pending_call_block(pending);
116  msg = dbus_pending_call_steal_reply(pending);
117  if (msg == NULL) {
118  dD("Failed to steal dbus pending call reply.");
119  goto cleanup;
120  }
121  dbus_pending_call_unref(pending); pending = NULL;
122 
123  if (!dbus_message_iter_init(msg, &args)) {
124  dD("Failed to initialize iterator over received dbus message.");
125  goto cleanup;
126  }
127 
128  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) {
129  dD("Expected object path argument in reply. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&args)));
130  goto cleanup;
131  }
132 
133  dbus_message_iter_get_basic(&args, &path);
134  ret = oscap_strdup(path.str);
135  dbus_message_unref(msg); msg = NULL;
136 
137 cleanup:
138  if (pending != NULL)
139  dbus_pending_call_unref(pending);
140 
141  if (msg != NULL)
142  dbus_message_unref(msg);
143 
144  return ret;
145 }
146 
147 static int get_all_systemd_units(DBusConnection* conn, int(*callback)(const char *, void *), void *cbarg)
148 {
149  DBusMessage *msg = NULL;
150  DBusPendingCall *pending = NULL;
151  char ret = 1;
152 
153  msg = dbus_message_new_method_call(
154  "org.freedesktop.systemd1",
155  "/org/freedesktop/systemd1",
156  "org.freedesktop.systemd1.Manager",
157  "ListUnitFiles"
158  );
159  if (msg == NULL) {
160  dD("Failed to create dbus_message via dbus_message_new_method_call!");
161  goto cleanup;
162  }
163 
164  DBusMessageIter args, unit_iter;
165 
166  // the args should be empty for this call
167  dbus_message_iter_init_append(msg, &args);
168 
169  if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
170  dD("Failed to send message via dbus!");
171  goto cleanup;
172  }
173  if (pending == NULL) {
174  dD("Invalid dbus pending call!");
175  goto cleanup;
176  }
177 
178  dbus_connection_flush(conn);
179  dbus_message_unref(msg); msg = NULL;
180 
181  dbus_pending_call_block(pending);
182  msg = dbus_pending_call_steal_reply(pending);
183  if (msg == NULL) {
184  dD("Failed to steal dbus pending call reply.");
185  goto cleanup;
186  }
187  dbus_pending_call_unref(pending); pending = NULL;
188 
189  if (!dbus_message_iter_init(msg, &args)) {
190  dD("Failed to initialize iterator over received dbus message.");
191  goto cleanup;
192  }
193 
194  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) {
195  dD("Expected array of structs in reply. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&args)));
196  goto cleanup;
197  }
198 
199  dbus_message_iter_recurse(&args, &unit_iter);
200  do {
201  if (dbus_message_iter_get_arg_type(&unit_iter) != DBUS_TYPE_STRUCT) {
202  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)));
203  goto cleanup;
204  }
205 
206  DBusMessageIter unit_full_path_and_name;
207  dbus_message_iter_recurse(&unit_iter, &unit_full_path_and_name);
208 
209  if (dbus_message_iter_get_arg_type(&unit_full_path_and_name) != DBUS_TYPE_STRING) {
210  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_full_path_and_name)));
211  goto cleanup;
212  }
213 
214  _DBusBasicValue value;
215  dbus_message_iter_get_basic(&unit_full_path_and_name, &value);
216  char *unit_name_s = oscap_strdup(basename(value.str));
217  oscap_strrm(unit_name_s, "@");
218  int cbret = callback(unit_name_s, cbarg);
219  free(unit_name_s);
220  if (cbret != 0) {
221  goto cleanup;
222  }
223  }
224  while (dbus_message_iter_next(&unit_iter));
225 
226  dbus_message_unref(msg); msg = NULL;
227 
228  ret = 0;
229 
230 cleanup:
231  if (pending != NULL)
232  dbus_pending_call_unref(pending);
233 
234  if (msg != NULL)
235  dbus_message_unref(msg);
236 
237  return ret;
238 }
239 
240 static char *dbus_value_to_string(DBusMessageIter *iter)
241 {
242  const int arg_type = dbus_message_iter_get_arg_type(iter);
243  if (dbus_type_is_basic(arg_type)) {
244  _DBusBasicValue value;
245  dbus_message_iter_get_basic(iter, &value);
246 
247  switch (arg_type)
248  {
249  case DBUS_TYPE_BYTE:
250  return oscap_sprintf("%c", value.byt);
251 
252  case DBUS_TYPE_BOOLEAN:
253  return oscap_strdup(value.bool_val ? "true" : "false");
254 
255  case DBUS_TYPE_INT16:
256  return oscap_sprintf("%i", value.i16);
257 
258  case DBUS_TYPE_UINT16:
259  return oscap_sprintf("%u", value.u16);
260 
261  case DBUS_TYPE_INT32:
262  return oscap_sprintf("%i", value.i32);
263 
264  case DBUS_TYPE_UINT32:
265  return oscap_sprintf("%u", value.u32);
266 
267 #ifdef DBUS_HAVE_INT64
268  case DBUS_TYPE_INT64:
269  return oscap_sprintf("%li", value.i64);
270 
271  case DBUS_TYPE_UINT64:
272  return oscap_sprintf("%lu", value.u64);
273 #endif
274 
275  case DBUS_TYPE_DOUBLE:
276  return oscap_sprintf("%g", value.dbl);
277 
278  case DBUS_TYPE_STRING:
279  case DBUS_TYPE_OBJECT_PATH:
280  case DBUS_TYPE_SIGNATURE:
281  return oscap_strdup(value.str);
282 
283  // non-basic types
284  //case DBUS_TYPE_ARRAY:
285  //case DBUS_TYPE_STRUCT:
286  //case DBUS_TYPE_DICT_ENTRY:
287  //case DBUS_TYPE_VARIANT:
288 
289  //case DBUS_TYPE_UNIX_FD:
290  // return oscap_sprintf("%i", value.fd);
291 
292  default:
293  dD("Encountered unknown dbus basic type!");
294  return oscap_strdup("error, unknown basic type!");
295  }
296  }
297  else if (arg_type == DBUS_TYPE_ARRAY) {
298  DBusMessageIter array;
299  dbus_message_iter_recurse(iter, &array);
300 
301  char *ret = NULL;
302  do {
303  char *element = dbus_value_to_string(&array);
304 
305  if (element == NULL)
306  continue;
307 
308  char *old_ret = ret;
309  if (old_ret == NULL)
310  ret = oscap_sprintf("%s", element);
311  else
312  ret = oscap_sprintf("%s, %s", old_ret, element);
313 
314  free(old_ret);
315  free(element);
316  }
317  while (dbus_message_iter_next(&array));
318 
319  return ret;
320  }/*
321  else if (arg_type == DBUS_TYPE_VARIANT) {
322  DBusMessageIter inner;
323  dbus_message_iter_recurse(iter, &inner);
324  return dbus_value_to_string(&inner);
325  }*/
326 
327  return NULL;
328 }
329 
330 static DBusConnection *connect_dbus()
331 {
332  DBusConnection *conn = NULL;
333 
334  DBusError err;
335  dbus_error_init(&err);
336 
337  const char *prefix = getenv("OSCAP_PROBE_ROOT");
338  if (prefix != NULL) {
339  char dbus_address[PATH_MAX] = {0};
340  snprintf(dbus_address, PATH_MAX, "unix:path=%s/run/dbus/system_bus_socket", prefix);
341  setenv("DBUS_SYSTEM_BUS_ADDRESS", dbus_address, 0);
342  /* We won't overwrite DBUS_SYSTEM_BUS_ADDRESS so that
343  * user could have a way to define some non-standard system bus socket location */
344  }
345 
346  conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
347  if (dbus_error_is_set(&err)) {
348  dD("Failed to get DBUS_BUS_SYSTEM connection - %s", err.message);
349  goto cleanup;
350  }
351  if (conn == NULL) {
352  dD("DBusConnection == NULL!");
353  goto cleanup;
354  }
355 
356  dbus_bus_register(conn, &err);
357  if (dbus_error_is_set(&err)) {
358  dD("Failed to register on dbus - %s", err.message);
359  goto cleanup;
360  }
361 
362 cleanup:
363  dbus_error_free(&err);
364 
365  return conn;
366 }
367 
368 static void disconnect_dbus(DBusConnection *conn)
369 {
370  // NOOP
371 
372  // Connections retrieved via dbus_bus_get shall not be destroyed,
373  // these connections are shared.
374 }
375 
376 #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