]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-user-dbus.c
machinectl: issue all bus commands while allowing interactive auth
[thirdparty/systemd.git] / src / login / logind-user-dbus.c
CommitLineData
3f49d45a
LP
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
5430f7f2
LP
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
3f49d45a
LP
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
5430f7f2 16 Lesser General Public License for more details.
3f49d45a 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
a185c5aa 23#include <string.h>
3f49d45a 24
cc377381
LP
25#include "strv.h"
26#include "bus-util.h"
3f49d45a
LP
27#include "logind.h"
28#include "logind-user.h"
3f49d45a 29
cc377381
LP
30static int property_get_display(
31 sd_bus *bus,
32 const char *path,
33 const char *interface,
34 const char *property,
35 sd_bus_message *reply,
ebcf1f97
LP
36 void *userdata,
37 sd_bus_error *error) {
3f49d45a 38
cc377381
LP
39 _cleanup_free_ char *p = NULL;
40 User *u = userdata;
3f49d45a 41
cc377381
LP
42 assert(bus);
43 assert(reply);
44 assert(u);
3f49d45a 45
cc377381
LP
46 p = u->display ? session_bus_path(u->display) : strdup("/");
47 if (!p)
3f49d45a
LP
48 return -ENOMEM;
49
cc377381 50 return sd_bus_message_append(reply, "(so)", u->display ? u->display->id : "", p);
3f49d45a
LP
51}
52
cc377381
LP
53static int property_get_state(
54 sd_bus *bus,
55 const char *path,
56 const char *interface,
57 const char *property,
58 sd_bus_message *reply,
ebcf1f97
LP
59 void *userdata,
60 sd_bus_error *error) {
3f49d45a 61
cc377381 62 User *u = userdata;
3f49d45a 63
cc377381
LP
64 assert(bus);
65 assert(reply);
66 assert(u);
3f49d45a 67
cc377381 68 return sd_bus_message_append(reply, "s", user_state_to_string(user_get_state(u)));
3f49d45a
LP
69}
70
cc377381
LP
71static int property_get_sessions(
72 sd_bus *bus,
73 const char *path,
74 const char *interface,
75 const char *property,
76 sd_bus_message *reply,
ebcf1f97
LP
77 void *userdata,
78 sd_bus_error *error) {
cc377381
LP
79
80 User *u = userdata;
3f49d45a 81 Session *session;
cc377381 82 int r;
3f49d45a 83
cc377381
LP
84 assert(bus);
85 assert(reply);
3f49d45a
LP
86 assert(u);
87
cc377381
LP
88 r = sd_bus_message_open_container(reply, 'a', "(so)");
89 if (r < 0)
90 return r;
3f49d45a
LP
91
92 LIST_FOREACH(sessions_by_user, session, u->sessions) {
cc377381 93 _cleanup_free_ char *p = NULL;
3f49d45a
LP
94
95 p = session_bus_path(session);
96 if (!p)
97 return -ENOMEM;
98
cc377381
LP
99 r = sd_bus_message_append(reply, "(so)", session->id, p);
100 if (r < 0)
101 return r;
3f49d45a 102
3f49d45a
LP
103 }
104
cc377381
LP
105 r = sd_bus_message_close_container(reply);
106 if (r < 0)
107 return r;
3f49d45a 108
cc377381 109 return 1;
3f49d45a
LP
110}
111
cc377381
LP
112static int property_get_idle_hint(
113 sd_bus *bus,
114 const char *path,
115 const char *interface,
116 const char *property,
117 sd_bus_message *reply,
ebcf1f97
LP
118 void *userdata,
119 sd_bus_error *error) {
a185c5aa 120
cc377381 121 User *u = userdata;
77527da0 122
cc377381
LP
123 assert(bus);
124 assert(reply);
125 assert(u);
a185c5aa 126
cc377381 127 return sd_bus_message_append(reply, "b", user_get_idle_hint(u, NULL) > 0);
a185c5aa
LP
128}
129
cc377381
LP
130static int property_get_idle_since_hint(
131 sd_bus *bus,
132 const char *path,
133 const char *interface,
134 const char *property,
135 sd_bus_message *reply,
ebcf1f97
LP
136 void *userdata,
137 sd_bus_error *error) {
cc377381
LP
138
139 User *u = userdata;
a185c5aa
LP
140 dual_timestamp t;
141 uint64_t k;
142
cc377381
LP
143 assert(bus);
144 assert(reply);
a185c5aa
LP
145 assert(u);
146
147 user_get_idle_hint(u, &t);
148 k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
149
cc377381 150 return sd_bus_message_append(reply, "t", k);
a185c5aa
LP
151}
152
3a9f7a30
LP
153static int property_get_linger(
154 sd_bus *bus,
155 const char *path,
156 const char *interface,
157 const char *property,
158 sd_bus_message *reply,
ebcf1f97
LP
159 void *userdata,
160 sd_bus_error *error) {
3a9f7a30
LP
161
162 User *u = userdata;
163 int r;
164
165 assert(bus);
166 assert(reply);
167 assert(u);
168
169 r = user_check_linger_file(u);
170
171 return sd_bus_message_append(reply, "b", r > 0);
172}
173
ebcf1f97 174static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 175 User *u = userdata;
3f49d45a
LP
176 int r;
177
cc377381
LP
178 assert(bus);
179 assert(message);
180 assert(u);
3f49d45a 181
9bb69af4 182 r = user_stop(u, true);
3f49d45a 183 if (r < 0)
ebcf1f97 184 return r;
3f49d45a 185
df2d202e 186 return sd_bus_reply_method_return(message, NULL);
3f49d45a
LP
187}
188
ebcf1f97 189static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
190 User *u = userdata;
191 int32_t signo;
a185c5aa
LP
192 int r;
193
cc377381 194 assert(bus);
3f49d45a 195 assert(message);
cc377381 196 assert(u);
3f49d45a 197
cc377381
LP
198 r = sd_bus_message_read(message, "i", &signo);
199 if (r < 0)
ebcf1f97 200 return r;
a185c5aa 201
cc377381 202 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 203 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
a185c5aa 204
cc377381
LP
205 r = user_kill(u, signo);
206 if (r < 0)
ebcf1f97 207 return r;
a185c5aa 208
df2d202e 209 return sd_bus_reply_method_return(message, NULL);
3f49d45a
LP
210}
211
cc377381
LP
212const sd_bus_vtable user_vtable[] = {
213 SD_BUS_VTABLE_START(0),
214
556089dc
LP
215 SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(User, uid), SD_BUS_VTABLE_PROPERTY_CONST),
216 SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(User, gid), SD_BUS_VTABLE_PROPERTY_CONST),
217 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(User, name), SD_BUS_VTABLE_PROPERTY_CONST),
218 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(User, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
219 SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), SD_BUS_VTABLE_PROPERTY_CONST),
220 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), SD_BUS_VTABLE_PROPERTY_CONST),
221 SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
952d3260 222 SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
cc377381
LP
223 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
224 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
225 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
226 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
227 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
3a9f7a30 228 SD_BUS_PROPERTY("Linger", "b", property_get_linger, 0, 0),
cc377381 229
adacb957
LP
230 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
231 SD_BUS_METHOD("Kill", "i", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
cc377381
LP
232
233 SD_BUS_VTABLE_END
234};
3f49d45a 235
f00c3121 236int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
3f49d45a 237 Manager *m = userdata;
309a29df 238 uid_t uid;
cc377381 239 User *user;
3f49d45a
LP
240 int r;
241
cc377381
LP
242 assert(bus);
243 assert(path);
244 assert(interface);
245 assert(found);
246 assert(m);
3f49d45a 247
927b1649 248 if (streq(path, "/org/freedesktop/login1/user/self")) {
5b12334d 249 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
927b1649 250 sd_bus_message *message;
3f49d45a 251
19befb2d 252 message = sd_bus_get_current_message(bus);
927b1649
LP
253 if (!message)
254 return 0;
255
309a29df 256 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
927b1649 257 if (r < 0)
5b12334d
LP
258 return r;
259
309a29df 260 r = sd_bus_creds_get_owner_uid(creds, &uid);
927b1649 261 } else {
927b1649 262 const char *p;
3f49d45a 263
927b1649
LP
264 p = startswith(path, "/org/freedesktop/login1/user/_");
265 if (!p)
266 return 0;
267
309a29df 268 r = parse_uid(p, &uid);
927b1649 269 }
309a29df
LP
270 if (r < 0)
271 return 0;
272
8cb4ab00 273 user = hashmap_get(m->users, UID_TO_PTR(uid));
309a29df
LP
274 if (!user)
275 return 0;
3f49d45a 276
cc377381
LP
277 *found = user;
278 return 1;
3f49d45a
LP
279}
280
3f49d45a
LP
281char *user_bus_path(User *u) {
282 char *s;
283
284 assert(u);
285
de0671ee 286 if (asprintf(&s, "/org/freedesktop/login1/user/_"UID_FMT, u->uid) < 0)
3f49d45a
LP
287 return NULL;
288
289 return s;
290}
da119395 291
f00c3121 292int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
cc377381 293 _cleanup_strv_free_ char **l = NULL;
ca56b0a6 294 sd_bus_message *message;
cc377381
LP
295 Manager *m = userdata;
296 User *user;
297 Iterator i;
298 int r;
da119395 299
cc377381
LP
300 assert(bus);
301 assert(path);
302 assert(nodes);
da119395 303
cc377381
LP
304 HASHMAP_FOREACH(user, m->users, i) {
305 char *p;
da119395 306
cc377381
LP
307 p = user_bus_path(user);
308 if (!p)
309 return -ENOMEM;
da119395 310
6e18964d
ZJS
311 r = strv_consume(&l, p);
312 if (r < 0)
cc377381 313 return r;
cc377381 314 }
da119395 315
ca56b0a6
DH
316 message = sd_bus_get_current_message(bus);
317 if (message) {
318 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
319 uid_t uid;
320
321 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
322 if (r >= 0) {
323 r = sd_bus_creds_get_owner_uid(creds, &uid);
324 if (r >= 0) {
325 user = hashmap_get(m->users, UID_TO_PTR(uid));
326 if (user) {
327 r = strv_extend(&l, "/org/freedesktop/login1/user/self");
328 if (r < 0)
329 return r;
330 }
331 }
332 }
333 }
b298e984 334
cc377381
LP
335 *nodes = l;
336 l = NULL;
da119395 337
cc377381
LP
338 return 1;
339}
340
341int user_send_signal(User *u, bool new_user) {
342 _cleanup_free_ char *p = NULL;
da119395 343
cc377381
LP
344 assert(u);
345
346 p = user_bus_path(u);
347 if (!p)
4654e558 348 return -ENOMEM;
da119395 349
cc377381
LP
350 return sd_bus_emit_signal(
351 u->manager->bus,
352 "/org/freedesktop/login1",
353 "org.freedesktop.login1.Manager",
354 new_user ? "UserNew" : "UserRemoved",
355 "uo", (uint32_t) u->uid, p);
da119395 356}
9418f147 357
cc377381 358int user_send_changed(User *u, const char *properties, ...) {
ce0fc5f5 359 _cleanup_free_ char *p = NULL;
cc377381 360 char **l;
9418f147
LP
361
362 assert(u);
363
ed18b08b
LP
364 if (!u->started)
365 return 0;
366
9418f147
LP
367 p = user_bus_path(u);
368 if (!p)
369 return -ENOMEM;
370
cc377381 371 l = strv_from_stdarg_alloca(properties);
9418f147 372
cc377381 373 return sd_bus_emit_properties_changed_strv(u->manager->bus, p, "org.freedesktop.login1.User", l);
9418f147 374}