chiark / gitweb /
bus: add new sd_bus_creds object to encapsulate process credentials
[elogind.git] / src / machine / machine-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 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 <errno.h>
23 #include <string.h>
24
25 #include "bus-util.h"
26 #include "strv.h"
27 #include "machine.h"
28
29 static int property_get_id(
30                 sd_bus *bus,
31                 const char *path,
32                 const char *interface,
33                 const char *property,
34                 sd_bus_message *reply,
35                 void *userdata,
36                 sd_bus_error *error) {
37
38         Machine *m = userdata;
39         int r;
40
41         assert(bus);
42         assert(reply);
43         assert(m);
44
45         r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
46         if (r < 0)
47                 return r;
48
49         return 1;
50 }
51
52 static int property_get_state(
53                 sd_bus *bus,
54                 const char *path,
55                 const char *interface,
56                 const char *property,
57                 sd_bus_message *reply,
58                 void *userdata,
59                 sd_bus_error *error) {
60
61         Machine *m = userdata;
62         const char *state;
63         int r;
64
65         assert(bus);
66         assert(reply);
67         assert(m);
68
69         state = machine_state_to_string(machine_get_state(m));
70
71         r = sd_bus_message_append_basic(reply, 's', state);
72         if (r < 0)
73                 return r;
74
75         return 1;
76 }
77
78 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
79
80 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
81         Machine *m = userdata;
82         int r;
83
84         assert(bus);
85         assert(message);
86         assert(m);
87
88         r = machine_stop(m);
89         if (r < 0)
90                 return r;
91
92         return sd_bus_reply_method_return(message, NULL);
93 }
94
95 static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
96         Machine *m = userdata;
97         const char *swho;
98         int32_t signo;
99         KillWho who;
100         int r;
101
102         assert(bus);
103         assert(message);
104         assert(m);
105
106         r = sd_bus_message_read(message, "si", &swho, &signo);
107         if (r < 0)
108                 return r;
109
110         if (isempty(swho))
111                 who = KILL_ALL;
112         else {
113                 who = kill_who_from_string(swho);
114                 if (who < 0)
115                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
116         }
117
118         if (signo <= 0 || signo >= _NSIG)
119                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
120
121         r = machine_kill(m, who, signo);
122         if (r < 0)
123                 return r;
124
125         return sd_bus_reply_method_return(message, NULL);
126 }
127
128 const sd_bus_vtable machine_vtable[] = {
129         SD_BUS_VTABLE_START(0),
130         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), 0),
131         SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, 0),
132         SD_BUS_PROPERTY("Timestamp", "t", NULL, offsetof(Machine, timestamp.realtime), 0),
133         SD_BUS_PROPERTY("TimestampMonotonic", "t", NULL, offsetof(Machine, timestamp.monotonic), 0),
134         SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), 0),
135         SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, scope), 0),
136         SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), 0),
137         SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), 0),
138         SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
139         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), 0),
140         SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, 0),
141         SD_BUS_METHOD("Kill", "si", NULL, method_kill, 0),
142         SD_BUS_VTABLE_END
143 };
144
145 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
146         Manager *m = userdata;
147         Machine *machine;
148         int r;
149
150         assert(bus);
151         assert(path);
152         assert(interface);
153         assert(found);
154         assert(m);
155
156         if (streq(path, "/org/freedesktop/machine1/machine/self")) {
157                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
158                 sd_bus_message *message;
159                 pid_t pid;
160
161                 message = sd_bus_get_current(bus);
162                 if (!message)
163                         return 0;
164
165                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
166                 if (r < 0)
167                         return r;
168
169                 r = sd_bus_creds_get_pid(creds, &pid);
170                 if (r < 0)
171                         return r;
172
173                 r = manager_get_machine_by_pid(m, pid, &machine);
174                 if (r <= 0)
175                         return 0;
176         } else {
177                 _cleanup_free_ char *e = NULL;
178                 const char *p;
179
180                 p = startswith(path, "/org/freedesktop/machine1/machine/");
181                 if (!p)
182                         return 0;
183
184                 e = sd_bus_label_unescape(p);
185                 if (!e)
186                         return -ENOMEM;
187
188                 machine = hashmap_get(m->machines, e);
189                 if (!machine)
190                         return 0;
191         }
192
193         *found = machine;
194         return 1;
195 }
196
197 char *machine_bus_path(Machine *m) {
198         _cleanup_free_ char *e = NULL;
199
200         assert(m);
201
202         e = sd_bus_label_escape(m->name);
203         if (!e)
204                 return NULL;
205
206         return strappend("/org/freedesktop/machine1/machine/", e);
207 }
208
209 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
210         _cleanup_strv_free_ char **l = NULL;
211         Machine *machine = NULL;
212         Manager *m = userdata;
213         Iterator i;
214         int r;
215
216         assert(bus);
217         assert(path);
218         assert(nodes);
219
220         HASHMAP_FOREACH(machine, m->machines, i) {
221                 char *p;
222
223                 p = machine_bus_path(machine);
224                 if (!p)
225                         return -ENOMEM;
226
227                 r = strv_push(&l, p);
228                 if (r < 0) {
229                         free(p);
230                         return r;
231                 }
232         }
233
234         *nodes = l;
235         l = NULL;
236
237         return 1;
238 }
239
240 int machine_send_signal(Machine *m, bool new_machine) {
241         _cleanup_free_ char *p = NULL;
242
243         assert(m);
244
245         p = machine_bus_path(m);
246         if (!p)
247                 return -ENOMEM;
248
249         return sd_bus_emit_signal(
250                         m->manager->bus,
251                         "/org/freedesktop/machine1",
252                         "org.freedesktop.machine1.Manager",
253                         new_machine ? "MachineNew" : "MachineRemoved",
254                         "so", m->name, p);
255 }
256
257 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
258         _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
259         _cleanup_free_ char *p = NULL;
260
261         assert(m);
262
263         if (!m->create_message)
264                 return 0;
265
266         c = m->create_message;
267         m->create_message = NULL;
268
269         if (error)
270                 return sd_bus_reply_method_error(c, error);
271
272         /* Update the machine state file before we notify the client
273          * about the result. */
274         machine_save(m);
275
276         p = machine_bus_path(m);
277         if (!p)
278                 return -ENOMEM;
279
280         return sd_bus_reply_method_return(c, "o", p);
281 }