chiark / gitweb /
core: rework policykit hookup
[elogind.git] / src / core / dbus-scope.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "selinux-access.h"
23 #include "unit.h"
24 #include "scope.h"
25 #include "dbus.h"
26 #include "bus-util.h"
27 #include "bus-internal.h"
28 #include "bus-common-errors.h"
29 #include "dbus-unit.h"
30 #include "dbus-cgroup.h"
31 #include "dbus-kill.h"
32 #include "dbus-scope.h"
33
34 static int bus_scope_abandon(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
35         Scope *s = userdata;
36         int r;
37
38         assert(bus);
39         assert(message);
40         assert(s);
41
42         r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
43         if (r < 0)
44                 return r;
45
46         r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
47         if (r < 0)
48                 return r;
49         if (r == 0)
50                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
51
52         r = scope_abandon(s);
53         if (r == -ESTALE)
54                 return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
55         if (r < 0)
56                 return r;
57
58         return sd_bus_reply_method_return(message, NULL);
59 }
60
61 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
62
63 const sd_bus_vtable bus_scope_vtable[] = {
64         SD_BUS_VTABLE_START(0),
65         SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_CONST),
66         SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
67         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
68         SD_BUS_SIGNAL("RequestStop", NULL, 0),
69         SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
70         SD_BUS_VTABLE_END
71 };
72
73 static int bus_scope_set_transient_property(
74                 Scope *s,
75                 const char *name,
76                 sd_bus_message *message,
77                 UnitSetPropertiesMode mode,
78                 sd_bus_error *error) {
79
80         int r;
81
82         assert(s);
83         assert(name);
84         assert(message);
85
86         if (streq(name, "PIDs")) {
87                 unsigned n = 0;
88                 uint32_t pid;
89
90                 r = sd_bus_message_enter_container(message, 'a', "u");
91                 if (r < 0)
92                         return r;
93
94                 while ((r = sd_bus_message_read(message, "u", &pid)) > 0) {
95
96                         if (pid <= 1)
97                                 return -EINVAL;
98
99                         if (mode != UNIT_CHECK) {
100                                 r = unit_watch_pid(UNIT(s), pid);
101                                 if (r < 0 && r != -EEXIST)
102                                         return r;
103                         }
104
105                         n++;
106                 }
107                 if (r < 0)
108                         return r;
109
110                 r = sd_bus_message_exit_container(message);
111                 if (r < 0)
112                         return r;
113
114                 if (n <= 0)
115                         return -EINVAL;
116
117                 return 1;
118
119         } else if (streq(name, "Controller")) {
120                 const char *controller;
121                 char *c;
122
123                 r = sd_bus_message_read(message, "s", &controller);
124                 if (r < 0)
125                         return r;
126
127                 if (!isempty(controller) && !service_name_is_valid(controller))
128                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
129
130                 if (mode != UNIT_CHECK) {
131                         if (isempty(controller))
132                                 c = NULL;
133                         else {
134                                 c = strdup(controller);
135                                 if (!c)
136                                         return -ENOMEM;
137                         }
138
139                         free(s->controller);
140                         s->controller = c;
141                 }
142
143                 return 1;
144
145         } else if (streq(name, "TimeoutStopUSec")) {
146
147                 if (mode != UNIT_CHECK) {
148                         r = sd_bus_message_read(message, "t", &s->timeout_stop_usec);
149                         if (r < 0)
150                                 return r;
151
152                         unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec="USEC_FMT"us\n", s->timeout_stop_usec);
153                 } else {
154                         r = sd_bus_message_skip(message, "t");
155                         if (r < 0)
156                                 return r;
157                 }
158
159                 return 1;
160         }
161
162         return 0;
163 }
164
165 int bus_scope_set_property(
166                 Unit *u,
167                 const char *name,
168                 sd_bus_message *message,
169                 UnitSetPropertiesMode mode,
170                 sd_bus_error *error) {
171
172         Scope *s = SCOPE(u);
173         int r;
174
175         assert(s);
176         assert(name);
177         assert(message);
178
179         r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
180         if (r != 0)
181                 return r;
182
183         if (u->load_state == UNIT_STUB) {
184                 /* While we are created we still accept PIDs */
185
186                 r = bus_scope_set_transient_property(s, name, message, mode, error);
187                 if (r != 0)
188                         return r;
189
190                 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
191                 if (r != 0)
192                         return r;
193         }
194
195         return 0;
196 }
197
198 int bus_scope_commit_properties(Unit *u) {
199         assert(u);
200
201         unit_update_cgroup_members_masks(u);
202         unit_realize_cgroup(u);
203
204         return 0;
205 }
206
207 int bus_scope_send_request_stop(Scope *s) {
208         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
209         _cleanup_free_ char *p = NULL;
210         int r;
211
212         assert(s);
213
214         if (!s->controller)
215                 return 0;
216
217         p = unit_dbus_path(UNIT(s));
218         if (!p)
219                 return -ENOMEM;
220
221         r = sd_bus_message_new_signal(
222                         UNIT(s)->manager->api_bus,
223                         &m,
224                         p,
225                         "org.freedesktop.systemd1.Scope",
226                         "RequestStop");
227         if (r < 0)
228                 return r;
229
230         return sd_bus_send_to(UNIT(s)->manager->api_bus, m, /* s->controller */ NULL, NULL);
231 }