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