X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fdbus-unit.c;h=83ee018ff3dd445484e68f2a7b2bb2f1e3b5614a;hp=fdfa5ee200c642a961e958cce86f8389528a15f0;hb=ffc227c9568eb0a12dc750761d1e5d68ea125aad;hpb=c53158818d8cdaf46b3f1b5299b9bda118a1043f diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index fdfa5ee20..83ee018ff 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -26,6 +26,7 @@ #include "dbus-unit.h" #include "bus-errors.h" #include "dbus-common.h" +#include "selinux-access.h" const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE; @@ -405,12 +406,11 @@ static int bus_unit_append_load_error(DBusMessageIter *i, const char *property, } static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *connection, DBusMessage *message) { - DBusMessage *reply = NULL; - Manager *m = u->manager; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusError error; JobType job_type = _JOB_TYPE_INVALID; - char *path = NULL; bool reload_if_possible = false; + int r; dbus_error_init(&error); @@ -434,7 +434,6 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn const char *swho; int32_t signo; KillWho who; - int r; if (!dbus_message_get_args( message, @@ -455,6 +454,8 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn if (signo <= 0 || signo >= _NSIG) return bus_send_error_reply(connection, message, &error, -EINVAL); + SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); + r = unit_kill(u, who, signo, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -465,9 +466,12 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetFailed")) { + SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload"); + unit_reset_failed(u); - if (!(reply = dbus_message_new_method_return(message))) + reply = dbus_message_new_method_return(message); + if (!reply) goto oom; } else if (UNIT_VTABLE(u)->bus_message_handler) @@ -478,16 +482,6 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn if (job_type != _JOB_TYPE_INVALID) { const char *smode; JobMode mode; - Job *j; - int r; - - if ((job_type == JOB_START && u->refuse_manual_start) || - (job_type == JOB_STOP && u->refuse_manual_stop) || - ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) && - (u->refuse_manual_start || u->refuse_manual_stop))) { - dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only."); - return bus_send_error_reply(connection, message, &error, -EPERM); - } if (!dbus_message_get_args( message, @@ -496,53 +490,23 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn DBUS_TYPE_INVALID)) return bus_send_error_reply(connection, message, &error, -EINVAL); - if (reload_if_possible && unit_can_reload(u)) { - if (job_type == JOB_RESTART) - job_type = JOB_RELOAD_OR_START; - else if (job_type == JOB_TRY_RESTART) - job_type = JOB_RELOAD; - } - - if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) { + mode = job_mode_from_string(smode); + if (mode < 0) { dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); return bus_send_error_reply(connection, message, &error, -EINVAL); } - if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(path = job_dbus_path(j))) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; + return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible); } - if (reply) { + if (reply) if (!dbus_connection_send(connection, reply, NULL)) goto oom; - dbus_message_unref(reply); - } - - free(path); - return DBUS_HANDLER_RESULT_HANDLED; oom: - free(path); - - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); - return DBUS_HANDLER_RESULT_NEED_MEMORY; } @@ -550,7 +514,7 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB Manager *m = data; Unit *u; int r; - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusError error; assert(connection); @@ -562,6 +526,8 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/unit")) { /* Be nice to gdbus and return introspection data for our mid-level paths */ + SELINUX_ACCESS_CHECK(connection, message, "status"); + if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { char *introspection = NULL; FILE *f; @@ -569,7 +535,8 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB const char *k; size_t size; - if (!(reply = dbus_message_new_method_return(message))) + reply = dbus_message_new_method_return(message); + if (!reply) goto oom; /* We roll our own introspection code here, instead of @@ -577,7 +544,8 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB * need to generate our introspection string * dynamically. */ - if (!(f = open_memstream(&introspection, &size))) + f = open_memstream(&introspection, &size); + if (!f) goto oom; fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE @@ -592,7 +560,8 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB if (k != u->id) continue; - if (!(p = bus_path_escape(k))) { + p = bus_path_escape(k); + if (!p) { fclose(f); free(introspection); goto oom; @@ -625,8 +594,6 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB if (!dbus_connection_send(connection, reply, NULL)) goto oom; - dbus_message_unref(reply); - return DBUS_HANDLER_RESULT_HANDLED; } @@ -634,19 +601,14 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB } r = manager_load_unit_from_dbus_path(m, dbus_message_get_path(message), &error, &u); - if (r < 0) { - if (r == -ENOMEM) - goto oom; - + if (r == -ENOMEM) + goto oom; + if (r < 0) return bus_send_error_reply(connection, message, &error, r); - } return bus_unit_message_dispatch(u, connection, message); oom: - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -776,6 +738,87 @@ oom: log_error("Failed to allocate unit remove signal."); } +DBusHandlerResult bus_unit_queue_job( + DBusConnection *connection, + DBusMessage *message, + Unit *u, + JobType type, + JobMode mode, + bool reload_if_possible) { + + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + _cleanup_free_ char *path = NULL; + Job *j; + JobBusClient *cl; + DBusError error; + int r; + + assert(connection); + assert(message); + assert(u); + assert(type >= 0 && type < _JOB_TYPE_MAX); + assert(mode >= 0 && mode < _JOB_MODE_MAX); + + dbus_error_init(&error); + + if (reload_if_possible && unit_can_reload(u)) { + if (type == JOB_RESTART) + type = JOB_RELOAD_OR_START; + else if (type == JOB_TRY_RESTART) + type = JOB_RELOAD; + } + + SELINUX_UNIT_ACCESS_CHECK(u, connection, message, + (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" : + type == JOB_STOP ? "stop" : "reload"); + + if (type == JOB_STOP && u->load_state == UNIT_ERROR && unit_active_state(u) == UNIT_INACTIVE) { + dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); + return bus_send_error_reply(connection, message, &error, -EPERM); + } + + if ((type == JOB_START && u->refuse_manual_start) || + (type == JOB_STOP && u->refuse_manual_stop) || + ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) { + dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id); + return bus_send_error_reply(connection, message, &error, -EPERM); + } + + r = manager_add_job(u->manager, type, u, mode, true, &error, &j); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + cl = job_bus_client_new(connection, bus_message_get_sender_with_fallback(message)); + if (!cl) + goto oom; + + LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + + path = job_dbus_path(j); + if (!path) + goto oom; + + if (!dbus_message_append_args( + reply, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) + goto oom; + + if (!dbus_connection_send(connection, reply, NULL)) + goto oom; + + return DBUS_HANDLER_RESULT_HANDLED; + +oom: + dbus_error_free(&error); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; +} + const BusProperty bus_unit_properties[] = { { "Id", bus_property_append_string, "s", offsetof(Unit, id), true }, { "Names", bus_unit_append_names, "as", 0 },