]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-user-dbus.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / login / logind-user-dbus.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3f49d45a
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
3f49d45a
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
3f49d45a 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <errno.h>
a185c5aa 22#include <string.h>
3f49d45a 23
b5efdb8a 24#include "alloc-util.h"
cc377381 25#include "bus-util.h"
f97b34a6 26#include "format-util.h"
b1d4f8e1
LP
27#include "logind-user.h"
28#include "logind.h"
6eb7c172 29#include "signal-util.h"
b1d4f8e1
LP
30#include "strv.h"
31#include "user-util.h"
3f49d45a 32
cc377381
LP
33static int property_get_display(
34 sd_bus *bus,
35 const char *path,
36 const char *interface,
37 const char *property,
38 sd_bus_message *reply,
ebcf1f97
LP
39 void *userdata,
40 sd_bus_error *error) {
3f49d45a 41
cc377381
LP
42 _cleanup_free_ char *p = NULL;
43 User *u = userdata;
3f49d45a 44
cc377381
LP
45 assert(bus);
46 assert(reply);
47 assert(u);
3f49d45a 48
cc377381
LP
49 p = u->display ? session_bus_path(u->display) : strdup("/");
50 if (!p)
3f49d45a
LP
51 return -ENOMEM;
52
cc377381 53 return sd_bus_message_append(reply, "(so)", u->display ? u->display->id : "", p);
3f49d45a
LP
54}
55
cc377381
LP
56static int property_get_state(
57 sd_bus *bus,
58 const char *path,
59 const char *interface,
60 const char *property,
61 sd_bus_message *reply,
ebcf1f97
LP
62 void *userdata,
63 sd_bus_error *error) {
3f49d45a 64
cc377381 65 User *u = userdata;
3f49d45a 66
cc377381
LP
67 assert(bus);
68 assert(reply);
69 assert(u);
3f49d45a 70
cc377381 71 return sd_bus_message_append(reply, "s", user_state_to_string(user_get_state(u)));
3f49d45a
LP
72}
73
cc377381
LP
74static int property_get_sessions(
75 sd_bus *bus,
76 const char *path,
77 const char *interface,
78 const char *property,
79 sd_bus_message *reply,
ebcf1f97
LP
80 void *userdata,
81 sd_bus_error *error) {
cc377381
LP
82
83 User *u = userdata;
3f49d45a 84 Session *session;
cc377381 85 int r;
3f49d45a 86
cc377381
LP
87 assert(bus);
88 assert(reply);
3f49d45a
LP
89 assert(u);
90
cc377381
LP
91 r = sd_bus_message_open_container(reply, 'a', "(so)");
92 if (r < 0)
93 return r;
3f49d45a
LP
94
95 LIST_FOREACH(sessions_by_user, session, u->sessions) {
cc377381 96 _cleanup_free_ char *p = NULL;
3f49d45a
LP
97
98 p = session_bus_path(session);
99 if (!p)
100 return -ENOMEM;
101
cc377381
LP
102 r = sd_bus_message_append(reply, "(so)", session->id, p);
103 if (r < 0)
104 return r;
3f49d45a 105
3f49d45a
LP
106 }
107
0f826101 108 return sd_bus_message_close_container(reply);
3f49d45a
LP
109}
110
cc377381
LP
111static int property_get_idle_hint(
112 sd_bus *bus,
113 const char *path,
114 const char *interface,
115 const char *property,
116 sd_bus_message *reply,
ebcf1f97
LP
117 void *userdata,
118 sd_bus_error *error) {
a185c5aa 119
cc377381 120 User *u = userdata;
77527da0 121
cc377381
LP
122 assert(bus);
123 assert(reply);
124 assert(u);
a185c5aa 125
cc377381 126 return sd_bus_message_append(reply, "b", user_get_idle_hint(u, NULL) > 0);
a185c5aa
LP
127}
128
cc377381
LP
129static int property_get_idle_since_hint(
130 sd_bus *bus,
131 const char *path,
132 const char *interface,
133 const char *property,
134 sd_bus_message *reply,
ebcf1f97
LP
135 void *userdata,
136 sd_bus_error *error) {
cc377381
LP
137
138 User *u = userdata;
5cb14b37 139 dual_timestamp t = DUAL_TIMESTAMP_NULL;
a185c5aa
LP
140 uint64_t k;
141
cc377381
LP
142 assert(bus);
143 assert(reply);
a185c5aa
LP
144 assert(u);
145
146 user_get_idle_hint(u, &t);
147 k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
148
cc377381 149 return sd_bus_message_append(reply, "t", k);
a185c5aa
LP
150}
151
3a9f7a30
LP
152static int property_get_linger(
153 sd_bus *bus,
154 const char *path,
155 const char *interface,
156 const char *property,
157 sd_bus_message *reply,
ebcf1f97
LP
158 void *userdata,
159 sd_bus_error *error) {
3a9f7a30
LP
160
161 User *u = userdata;
162 int r;
163
164 assert(bus);
165 assert(reply);
166 assert(u);
167
168 r = user_check_linger_file(u);
169
170 return sd_bus_message_append(reply, "b", r > 0);
171}
172
19070062 173int bus_user_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 174 User *u = userdata;
3f49d45a
LP
175 int r;
176
cc377381
LP
177 assert(message);
178 assert(u);
3f49d45a 179
c529695e
LP
180 r = bus_verify_polkit_async(
181 message,
182 CAP_KILL,
183 "org.freedesktop.login1.manage",
403ed0e5 184 NULL,
c529695e
LP
185 false,
186 u->uid,
187 &u->manager->polkit_registry,
188 error);
189 if (r < 0)
190 return r;
191 if (r == 0)
192 return 1; /* Will call us back */
193
9bb69af4 194 r = user_stop(u, true);
3f49d45a 195 if (r < 0)
ebcf1f97 196 return r;
3f49d45a 197
df2d202e 198 return sd_bus_reply_method_return(message, NULL);
3f49d45a
LP
199}
200
19070062 201int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
202 User *u = userdata;
203 int32_t signo;
a185c5aa
LP
204 int r;
205
3f49d45a 206 assert(message);
cc377381 207 assert(u);
3f49d45a 208
c529695e
LP
209 r = bus_verify_polkit_async(
210 message,
211 CAP_KILL,
212 "org.freedesktop.login1.manage",
403ed0e5 213 NULL,
c529695e
LP
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
6eb7c172 227 if (!SIGNAL_VALID(signo))
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 248 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
91ab7b01 249 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
cc377381
LP
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
LP
273 if (streq(path, "/org/freedesktop/login1/user/self")) {
274 sd_bus_message *message;
3f49d45a 275
19befb2d 276 message = sd_bus_get_current_message(bus);
927b1649
LP
277 if (!message)
278 return 0;
279
e4d2984b 280 r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user);
927b1649 281 if (r < 0)
5b12334d 282 return r;
927b1649 283 } else {
927b1649 284 const char *p;
3f49d45a 285
927b1649
LP
286 p = startswith(path, "/org/freedesktop/login1/user/_");
287 if (!p)
288 return 0;
289
309a29df 290 r = parse_uid(p, &uid);
927b1649 291 }
309a29df
LP
292 if (r < 0)
293 return 0;
294
8cb4ab00 295 user = hashmap_get(m->users, UID_TO_PTR(uid));
309a29df
LP
296 if (!user)
297 return 0;
3f49d45a 298
cc377381
LP
299 *found = user;
300 return 1;
3f49d45a
LP
301}
302
3f49d45a
LP
303char *user_bus_path(User *u) {
304 char *s;
305
306 assert(u);
307
de0671ee 308 if (asprintf(&s, "/org/freedesktop/login1/user/_"UID_FMT, u->uid) < 0)
3f49d45a
LP
309 return NULL;
310
311 return s;
312}
da119395 313
f00c3121 314int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
cc377381 315 _cleanup_strv_free_ char **l = NULL;
ca56b0a6 316 sd_bus_message *message;
cc377381
LP
317 Manager *m = userdata;
318 User *user;
319 Iterator i;
320 int r;
da119395 321
cc377381
LP
322 assert(bus);
323 assert(path);
324 assert(nodes);
da119395 325
cc377381
LP
326 HASHMAP_FOREACH(user, m->users, i) {
327 char *p;
da119395 328
cc377381
LP
329 p = user_bus_path(user);
330 if (!p)
331 return -ENOMEM;
da119395 332
6e18964d
ZJS
333 r = strv_consume(&l, p);
334 if (r < 0)
cc377381 335 return r;
cc377381 336 }
da119395 337
ca56b0a6
DH
338 message = sd_bus_get_current_message(bus);
339 if (message) {
4afd3348 340 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
ca56b0a6
DH
341 uid_t uid;
342
343 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
344 if (r >= 0) {
345 r = sd_bus_creds_get_owner_uid(creds, &uid);
346 if (r >= 0) {
347 user = hashmap_get(m->users, UID_TO_PTR(uid));
348 if (user) {
349 r = strv_extend(&l, "/org/freedesktop/login1/user/self");
350 if (r < 0)
351 return r;
352 }
353 }
354 }
355 }
b298e984 356
cc377381
LP
357 *nodes = l;
358 l = NULL;
da119395 359
cc377381
LP
360 return 1;
361}
362
363int user_send_signal(User *u, bool new_user) {
364 _cleanup_free_ char *p = NULL;
da119395 365
cc377381
LP
366 assert(u);
367
368 p = user_bus_path(u);
369 if (!p)
4654e558 370 return -ENOMEM;
da119395 371
cc377381
LP
372 return sd_bus_emit_signal(
373 u->manager->bus,
374 "/org/freedesktop/login1",
375 "org.freedesktop.login1.Manager",
376 new_user ? "UserNew" : "UserRemoved",
377 "uo", (uint32_t) u->uid, p);
da119395 378}
9418f147 379
cc377381 380int user_send_changed(User *u, const char *properties, ...) {
ce0fc5f5 381 _cleanup_free_ char *p = NULL;
cc377381 382 char **l;
9418f147
LP
383
384 assert(u);
385
ed18b08b
LP
386 if (!u->started)
387 return 0;
388
9418f147
LP
389 p = user_bus_path(u);
390 if (!p)
391 return -ENOMEM;
392
cc377381 393 l = strv_from_stdarg_alloca(properties);
9418f147 394
cc377381 395 return sd_bus_emit_properties_changed_strv(u->manager->bus, p, "org.freedesktop.login1.User", l);
9418f147 396}