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