Open SCAP Library

systemdshared.h

00001 
00007 /*
00008  * Copyright 2014 Red Hat Inc., Durham, North Carolina.
00009  * All Rights Reserved.
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Lesser General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2.1 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with this library; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  * Authors:
00026  *
00027  */
00028 
00029 #pragma once
00030 
00031 #ifndef OPENSCAP_OVAL_PROBES_SYSTEMDSHARED_H_
00032 #define OPENSCAP_OVAL_PROBES_SYSTEMDSHARED_H_
00033 
00034 #ifdef HAVE_CONFIG_H
00035 #include <config.h>
00036 #endif
00037 
00038 #include <dbus/dbus.h>
00039 #include "common/debug_priv.h"
00040 
00041 // Old versions of libdbus API don't have DBusBasicValue and DBus8ByteStruct
00042 // as a public typedefs.
00043 // These two typedefs were copied from libdbus 1.8 branch, see
00044 // http://cgit.freedesktop.org/dbus/dbus/tree/dbus/dbus-types.h?h=dbus-1.8#n137
00045 typedef struct
00046 {
00047         dbus_uint32_t first32;
00048         dbus_uint32_t second32;
00049 } _DBus8ByteStruct;
00050 
00051 typedef union
00052 {
00053         unsigned char bytes[8]; 
00054         dbus_int16_t  i16;   
00055         dbus_uint16_t u16;   
00056         dbus_int32_t  i32;   
00057         dbus_uint32_t u32;   
00058         dbus_bool_t   bool_val; 
00059 #ifdef DBUS_HAVE_INT64
00060         dbus_int64_t  i64;   
00061         dbus_uint64_t u64;   
00062 #endif
00063         _DBus8ByteStruct eight; 
00064         double dbl;          
00065         unsigned char byt;   
00066         char *str;           
00067         int fd;              
00068 } _DBusBasicValue;
00069 
00070 static char *get_path_by_unit(DBusConnection *conn, const char *unit)
00071 {
00072         DBusMessage *msg = NULL;
00073         DBusPendingCall *pending = NULL;
00074         _DBusBasicValue path;
00075         char *ret = NULL;
00076 
00077         msg = dbus_message_new_method_call(
00078                 "org.freedesktop.systemd1",
00079                 "/org/freedesktop/systemd1",
00080                 "org.freedesktop.systemd1.Manager",
00081                 // LoadUnit is similar to GetUnit except it will load the unit file
00082                 // if it hasn't been loaded yet.
00083                 "LoadUnit"
00084         );
00085         if (msg == NULL) {
00086                 dI("Failed to create dbus_message via dbus_message_new_method_call!");
00087                 goto cleanup;
00088         }
00089 
00090         DBusMessageIter args;
00091 
00092         dbus_message_iter_init_append(msg, &args);
00093         if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &unit)) {
00094                 dI("Failed to append unit '%s' string parameter to dbus message!", unit);
00095                 goto cleanup;
00096         }
00097 
00098         if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
00099                 dI("Failed to send message via dbus!");
00100                 goto cleanup;
00101         }
00102         if (pending == NULL) {
00103                 dI("Invalid dbus pending call!");
00104                 goto cleanup;
00105         }
00106 
00107         dbus_connection_flush(conn);
00108         dbus_message_unref(msg); msg = NULL;
00109 
00110         dbus_pending_call_block(pending);
00111         msg = dbus_pending_call_steal_reply(pending);
00112         if (msg == NULL) {
00113                 dI("Failed to steal dbus pending call reply.");
00114                 goto cleanup;
00115         }
00116         dbus_pending_call_unref(pending); pending = NULL;
00117 
00118         if (!dbus_message_iter_init(msg, &args)) {
00119                 dI("Failed to initialize iterator over received dbus message.");
00120                 goto cleanup;
00121         }
00122 
00123         if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) {
00124                 dI("Expected string argument in reply. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&args)));
00125                 goto cleanup;
00126         }
00127 
00128         dbus_message_iter_get_basic(&args, &path);
00129         ret = oscap_strdup(path.str);
00130         dbus_message_unref(msg); msg = NULL;
00131 
00132 cleanup:
00133         if (pending != NULL)
00134                 dbus_pending_call_unref(pending);
00135 
00136         if (msg != NULL)
00137                 dbus_message_unref(msg);
00138 
00139         return ret;
00140 }
00141 
00142 static int get_all_systemd_units(DBusConnection* conn, int(*callback)(const char *, void *), void *cbarg)
00143 {
00144         DBusMessage *msg = NULL;
00145         DBusPendingCall *pending = NULL;
00146         char ret = 1;
00147 
00148         msg = dbus_message_new_method_call(
00149                 "org.freedesktop.systemd1",
00150                 "/org/freedesktop/systemd1",
00151                 "org.freedesktop.systemd1.Manager",
00152                 "ListUnits"
00153         );
00154         if (msg == NULL) {
00155                 dI("Failed to create dbus_message via dbus_message_new_method_call!");
00156                 goto cleanup;
00157         }
00158 
00159         DBusMessageIter args, unit_iter;
00160 
00161         // the args should be empty for this call
00162         dbus_message_iter_init_append(msg, &args);
00163 
00164         if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
00165                 dI("Failed to send message via dbus!");
00166                 goto cleanup;
00167         }
00168         if (pending == NULL) {
00169                 dI("Invalid dbus pending call!");
00170                 goto cleanup;
00171         }
00172 
00173         dbus_connection_flush(conn);
00174         dbus_message_unref(msg); msg = NULL;
00175 
00176         dbus_pending_call_block(pending);
00177         msg = dbus_pending_call_steal_reply(pending);
00178         if (msg == NULL) {
00179                 dI("Failed to steal dbus pending call reply.");
00180                 goto cleanup;
00181         }
00182         dbus_pending_call_unref(pending); pending = NULL;
00183 
00184         if (!dbus_message_iter_init(msg, &args)) {
00185                 dI("Failed to initialize iterator over received dbus message.");
00186                 goto cleanup;
00187         }
00188 
00189         if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) {
00190                 dI("Expected array of structs in reply. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&args)));
00191                 goto cleanup;
00192         }
00193 
00194         dbus_message_iter_recurse(&args, &unit_iter);
00195         do {
00196                 if (dbus_message_iter_get_arg_type(&unit_iter) != DBUS_TYPE_STRUCT) {
00197                         dI("Expected unit struct as elements in returned array. Instead received: %s.", dbus_message_type_to_string(dbus_message_iter_get_arg_type(&unit_iter)));
00198                         goto cleanup;
00199                 }
00200 
00201                 DBusMessageIter unit_name;
00202                 dbus_message_iter_recurse(&unit_iter, &unit_name);
00203 
00204                 if (dbus_message_iter_get_arg_type(&unit_name) != DBUS_TYPE_STRING) {
00205                         dI("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)));
00206                         goto cleanup;
00207                 }
00208 
00209                 _DBusBasicValue value;
00210                 dbus_message_iter_get_basic(&unit_name, &value);
00211                 char *unit_name_s = oscap_strdup(value.str);
00212                 int cbret = callback(unit_name_s, cbarg);
00213                 free(unit_name_s);
00214                 if (cbret != 0) {
00215                         goto cleanup;
00216                 }
00217         }
00218         while (dbus_message_iter_next(&unit_iter));
00219 
00220         dbus_message_unref(msg); msg = NULL;
00221 
00222         ret = 0;
00223 
00224 cleanup:
00225         if (pending != NULL)
00226                 dbus_pending_call_unref(pending);
00227 
00228         if (msg != NULL)
00229                 dbus_message_unref(msg);
00230 
00231         return ret;
00232 }
00233 
00234 static char *dbus_value_to_string(DBusMessageIter *iter)
00235 {
00236         const int arg_type = dbus_message_iter_get_arg_type(iter);
00237         if (dbus_type_is_basic(arg_type)) {
00238                 _DBusBasicValue value;
00239                 dbus_message_iter_get_basic(iter, &value);
00240 
00241                 switch (arg_type)
00242                 {
00243                         case DBUS_TYPE_BYTE:
00244                                 return oscap_sprintf("%c", value.byt);
00245 
00246                         case DBUS_TYPE_BOOLEAN:
00247                                 return oscap_strdup(value.bool_val ? "true" : "false");
00248 
00249                         case DBUS_TYPE_INT16:
00250                                 return oscap_sprintf("%i", value.i16);
00251 
00252                         case DBUS_TYPE_UINT16:
00253                                 return oscap_sprintf("%u", value.u16);
00254 
00255                         case DBUS_TYPE_INT32:
00256                                 return oscap_sprintf("%i", value.i32);
00257 
00258                         case DBUS_TYPE_UINT32:
00259                                 return oscap_sprintf("%u", value.u32);
00260 
00261 #ifdef DBUS_HAVE_INT64
00262                         case DBUS_TYPE_INT64:
00263                                 return oscap_sprintf("%lli", value.i32);
00264 
00265                         case DBUS_TYPE_UINT64:
00266                                 return oscap_sprintf("%llu", value.u32);
00267 #endif
00268 
00269                         case DBUS_TYPE_DOUBLE:
00270                                 return oscap_sprintf("%g", value.dbl);
00271 
00272                         case DBUS_TYPE_STRING:
00273                         case DBUS_TYPE_OBJECT_PATH:
00274                         case DBUS_TYPE_SIGNATURE:
00275                                 return oscap_strdup(value.str);
00276 
00277                         // non-basic types
00278                         //case DBUS_TYPE_ARRAY:
00279                         //case DBUS_TYPE_STRUCT:
00280                         //case DBUS_TYPE_DICT_ENTRY:
00281                         //case DBUS_TYPE_VARIANT:
00282 
00283                         //case DBUS_TYPE_UNIX_FD:
00284                         //      return oscap_sprintf("%i", value.fd);
00285 
00286                         default:
00287                                 dI("Encountered unknown dbus basic type!");
00288                                 return oscap_strdup("error, unknown basic type!");
00289                 }
00290         }
00291         else if (arg_type == DBUS_TYPE_ARRAY) {
00292                 DBusMessageIter array;
00293                 dbus_message_iter_recurse(iter, &array);
00294 
00295                 char *ret = NULL;
00296                 do {
00297                         char *element = dbus_value_to_string(&array);
00298 
00299                         if (element == NULL)
00300                                 continue;
00301 
00302                         char *old_ret = ret;
00303                         if (old_ret == NULL)
00304                                 ret = oscap_sprintf("%s", element);
00305                         else
00306                                 ret = oscap_sprintf("%s, %s", old_ret, element);
00307 
00308                         free(old_ret);
00309                         free(element);
00310                 }
00311                 while (dbus_message_iter_next(&array));
00312 
00313                 return ret;
00314         }/*
00315         else if (arg_type == DBUS_TYPE_VARIANT) {
00316                 DBusMessageIter inner;
00317                 dbus_message_iter_recurse(iter, &inner);
00318                 return dbus_value_to_string(&inner);
00319         }*/
00320 
00321         return NULL;
00322 }
00323 
00324 static DBusConnection *connect_dbus()
00325 {
00326         DBusConnection *conn = NULL;
00327 
00328         DBusError err;
00329         dbus_error_init(&err);
00330 
00331         conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
00332         if (dbus_error_is_set(&err)) {
00333                 dI("Failed to get DBUS_BUS_SYSTEM connection - %s", err.message);
00334                 goto cleanup;
00335         }
00336         if (conn == NULL) {
00337                 dI("DBusConnection == NULL!");
00338                 goto cleanup;
00339         }
00340 
00341         dbus_bus_register(conn, &err);
00342         if (dbus_error_is_set(&err)) {
00343                 dI("Failed to register on dbus - %s", err.message);
00344                 goto cleanup;
00345         }
00346 
00347 cleanup:
00348         dbus_error_free(&err);
00349 
00350         return conn;
00351 }
00352 
00353 static void disconnect_dbus(DBusConnection *conn)
00354 {
00355         // NOOP
00356 
00357         // Connections retrieved via dbus_bus_get shall not be destroyed,
00358         // these connections are shared.
00359 }
00360 
00361 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines