]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/logind-dbus.c
update todo
[thirdparty/systemd.git] / src / logind-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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
a185c5aa
LP
22#include <errno.h>
23#include <string.h>
98a28fef 24#include <unistd.h>
7f7bb946 25#include <pwd.h>
a185c5aa 26
3f49d45a
LP
27#include "logind.h"
28#include "dbus-common.h"
98a28fef 29#include "strv.h"
7f7bb946 30#include "polkit.h"
3f49d45a
LP
31
32#define BUS_MANAGER_INTERFACE \
33 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
bef422ae 34 " <method name=\"GetSession\">\n" \
3f49d45a 35 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 36 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a
LP
37 " </method>\n" \
38 " <method name=\"GetUser\">\n" \
bef422ae 39 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
40 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
41 " </method>\n" \
bef422ae 42 " <method name=\"GetSeat\">\n" \
3f49d45a 43 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 44 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 45 " </method>\n" \
bef422ae 46 " <method name=\"ListSessions\">\n" \
e1c9c2d5 47 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
3f49d45a
LP
48 " </method>\n" \
49 " <method name=\"ListUsers\">\n" \
50 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
51 " </method>\n" \
bef422ae
LP
52 " <method name=\"ListSeats\">\n" \
53 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
3f49d45a
LP
54 " </method>\n" \
55 " <method name=\"CreateSession\">\n" \
56 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
57 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
4d6d6518 58 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a
LP
59 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
60 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
4d6d6518 61 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
62 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
63 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
65 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
68 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
98a28fef 69 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
3f49d45a
LP
70 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
71 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
98a28fef 72 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a
LP
73 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
74 " </method>\n" \
a185c5aa
LP
75 " <method name=\"ActivateSession\">\n" \
76 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
77 " </method>\n" \
3f49d45a
LP
78 " <method name=\"TerminateSession\">\n" \
79 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
80 " </method>\n" \
81 " <method name=\"TerminateUser\">\n" \
bef422ae 82 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
83 " </method>\n" \
84 " <method name=\"TerminateSeat\">\n" \
85 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
86 " </method>\n" \
7f7bb946
LP
87 " <method name=\"SetUserLinger\">\n" \
88 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
89 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
90 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
91 " </method>\n" \
47a26690
LP
92 " <method name=\"AttachDevice\">\n" \
93 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
94 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
96 " </method>\n" \
b668e064
LP
97 " <method name=\"FlushDevices\">\n" \
98 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
99 " </method>\n" \
3f49d45a
LP
100 " <signal name=\"SessionNew\">\n" \
101 " <arg name=\"id\" type=\"s\"/>\n" \
102 " <arg name=\"path\" type=\"o\"/>\n" \
103 " </signal>\n" \
104 " <signal name=\"SessionRemoved\">\n" \
105 " <arg name=\"id\" type=\"s\"/>\n" \
106 " <arg name=\"path\" type=\"o\"/>\n" \
107 " </signal>\n" \
108 " <signal name=\"UserNew\">\n" \
109 " <arg name=\"uid\" type=\"u\"/>\n" \
110 " <arg name=\"path\" type=\"o\"/>\n" \
111 " </signal>\n" \
112 " <signal name=\"UserRemoved\">\n" \
113 " <arg name=\"uid\" type=\"u\"/>\n" \
114 " <arg name=\"path\" type=\"o\"/>\n" \
115 " </signal>\n" \
116 " <signal name=\"SeatNew\">\n" \
117 " <arg name=\"id\" type=\"s\"/>\n" \
118 " <arg name=\"path\" type=\"o\"/>\n" \
119 " </signal>\n" \
120 " <signal name=\"SeatRemoved\">\n" \
121 " <arg name=\"id\" type=\"s\"/>\n" \
122 " <arg name=\"path\" type=\"o\"/>\n" \
123 " </signal>\n" \
124 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
125 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
126 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
127 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
128 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
129 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
130 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
a185c5aa
LP
131 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
132 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
133 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
3f49d45a
LP
134 " </interface>\n"
135
136#define INTROSPECTION_BEGIN \
137 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
138 "<node>\n" \
139 BUS_MANAGER_INTERFACE \
140 BUS_PROPERTIES_INTERFACE \
141 BUS_PEER_INTERFACE \
142 BUS_INTROSPECTABLE_INTERFACE
143
144#define INTROSPECTION_END \
145 "</node>\n"
146
147#define INTERFACES_LIST \
148 BUS_GENERIC_INTERFACES_LIST \
149 "org.freedesktop.login1.Manager\0"
150
a185c5aa
LP
151static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
152 Manager *m = data;
77527da0 153 dbus_bool_t b;
a185c5aa
LP
154
155 assert(i);
156 assert(property);
157 assert(m);
158
77527da0 159 b = manager_get_idle_hint(m, NULL) > 0;
a185c5aa
LP
160 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
161 return -ENOMEM;
162
163 return 0;
164}
165
166static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
167 Manager *m = data;
168 dual_timestamp t;
169 uint64_t u;
170
171 assert(i);
172 assert(property);
173 assert(m);
174
175 manager_get_idle_hint(m, &t);
176 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
177
178 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
179 return -ENOMEM;
180
181 return 0;
182}
183
98a28fef
LP
184static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
185 Session *session = NULL;
186 User *user = NULL;
187 const char *type, *seat, *tty, *display, *remote_user, *remote_host, *service;
188 uint32_t uid, leader, audit_id = 0;
189 dbus_bool_t remote, kill_processes;
190 char **controllers = NULL, **reset_controllers = NULL;
191 SessionType t;
192 Seat *s;
193 DBusMessageIter iter;
194 int r;
07714753 195 char *id = NULL, *p;
4d6d6518 196 uint32_t vtnr = 0;
932e3ee7 197 int fifo_fd = -1;
98a28fef
LP
198 DBusMessage *reply = NULL;
199 bool b;
200
201 assert(m);
202 assert(message);
203 assert(_reply);
204
205 if (!dbus_message_iter_init(message, &iter) ||
206 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
207 return -EINVAL;
208
209 dbus_message_iter_get_basic(&iter, &uid);
210
211 if (!dbus_message_iter_next(&iter) ||
212 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
213 return -EINVAL;
214
215 dbus_message_iter_get_basic(&iter, &leader);
216
217 if (leader <= 0 ||
218 !dbus_message_iter_next(&iter) ||
219 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
220 return -EINVAL;
221
222 dbus_message_iter_get_basic(&iter, &service);
223
224 if (!dbus_message_iter_next(&iter) ||
225 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
226 return -EINVAL;
227
228 dbus_message_iter_get_basic(&iter, &type);
229 t = session_type_from_string(type);
230
231 if (t < 0 ||
232 !dbus_message_iter_next(&iter) ||
233 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
234 return -EINVAL;
235
236 dbus_message_iter_get_basic(&iter, &seat);
237
238 if (isempty(seat))
239 s = NULL;
240 else {
241 s = hashmap_get(m->seats, seat);
242 if (!s)
243 return -ENOENT;
244 }
245
4d6d6518
LP
246 if (!dbus_message_iter_next(&iter) ||
247 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
248 return -EINVAL;
249
250 dbus_message_iter_get_basic(&iter, &vtnr);
251
98a28fef
LP
252 if (!dbus_message_iter_next(&iter) ||
253 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
254 return -EINVAL;
255
256 dbus_message_iter_get_basic(&iter, &tty);
257
258 if (tty_is_vc(tty)) {
4d6d6518 259 int v;
98a28fef
LP
260
261 if (!s)
262 s = m->vtconsole;
263 else if (s != m->vtconsole)
264 return -EINVAL;
265
4d6d6518
LP
266 v = vtnr_from_tty(tty);
267
268 if (v <= 0)
269 return v < 0 ? v : -EINVAL;
98a28fef
LP
270
271 if (vtnr <= 0)
4d6d6518
LP
272 vtnr = (uint32_t) v;
273 else if (vtnr != (uint32_t) v)
274 return -EINVAL;
98a28fef 275
bf100920 276 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
98a28fef
LP
277 return -EINVAL;
278
4d6d6518
LP
279 if (s) {
280 if (seat_is_vtconsole(s)) {
281 if (vtnr <= 0 || vtnr > 63)
282 return -EINVAL;
283 } else {
284 if (vtnr > 0)
285 return -EINVAL;
286 }
287 }
288
98a28fef
LP
289 if (!dbus_message_iter_next(&iter) ||
290 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
291 return -EINVAL;
292
293 dbus_message_iter_get_basic(&iter, &display);
294
295 if (!dbus_message_iter_next(&iter) ||
296 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
297 return -EINVAL;
298
299 dbus_message_iter_get_basic(&iter, &remote);
300
301 if (!dbus_message_iter_next(&iter) ||
302 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
303 return -EINVAL;
304
305 dbus_message_iter_get_basic(&iter, &remote_user);
306
307 if (!dbus_message_iter_next(&iter) ||
308 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
309 return -EINVAL;
310
311 dbus_message_iter_get_basic(&iter, &remote_host);
312
313 if (!dbus_message_iter_next(&iter) ||
314 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
315 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
316 return -EINVAL;
317
318 r = bus_parse_strv_iter(&iter, &controllers);
319 if (r < 0)
320 return -EINVAL;
321
25d93491
LP
322 if (strv_contains(controllers, "systemd") ||
323 !dbus_message_iter_next(&iter) ||
98a28fef
LP
324 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
325 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
326 r = -EINVAL;
327 goto fail;
328 }
329
330 r = bus_parse_strv_iter(&iter, &reset_controllers);
331 if (r < 0)
332 goto fail;
333
25d93491
LP
334 if (strv_contains(reset_controllers, "systemd") ||
335 !dbus_message_iter_next(&iter) ||
98a28fef
LP
336 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
337 r = -EINVAL;
338 goto fail;
339 }
340
341 dbus_message_iter_get_basic(&iter, &kill_processes);
342
343 r = manager_add_user_by_uid(m, uid, &user);
344 if (r < 0)
345 goto fail;
346
347 audit_session_from_pid(leader, &audit_id);
348
07714753 349 if (audit_id > 0) {
98a28fef 350 asprintf(&id, "%lu", (unsigned long) audit_id);
98a28fef 351
07714753
LP
352 if (!id) {
353 r = -ENOMEM;
354 goto fail;
355 }
98a28fef 356
21c390cc
LP
357 session = hashmap_get(m->sessions, id);
358
359 if (session) {
360
932e3ee7
LP
361 fifo_fd = session_create_fifo(session);
362 if (fifo_fd < 0) {
363 r = fifo_fd;
364 goto fail;
365 }
366
21c390cc
LP
367 /* Session already exists, client is probably
368 * something like "su" which changes uid but
369 * is still the same audit session */
370
371 reply = dbus_message_new_method_return(message);
372 if (!reply) {
373 r = -ENOMEM;
374 goto fail;
375 }
376
21c390cc
LP
377 p = session_bus_path(session);
378 if (!p) {
379 r = -ENOMEM;
380 goto fail;
381 }
382
383 b = dbus_message_append_args(
384 reply,
385 DBUS_TYPE_STRING, &session->id,
386 DBUS_TYPE_OBJECT_PATH, &p,
387 DBUS_TYPE_STRING, &session->user->runtime_path,
932e3ee7 388 DBUS_TYPE_UNIX_FD, &fifo_fd,
21c390cc
LP
389 DBUS_TYPE_INVALID);
390 free(p);
391
392 if (!b) {
393 r = -ENOMEM;
394 goto fail;
395 }
396
932e3ee7 397 close_nointr_nofail(fifo_fd);
21c390cc
LP
398 *_reply = reply;
399
400 return 0;
07714753
LP
401 }
402
403 } else {
404 do {
405 free(id);
406 asprintf(&id, "c%lu", ++m->session_counter);
407
408 if (!id) {
409 r = -ENOMEM;
410 goto fail;
411 }
412
413 } while (hashmap_get(m->sessions, id));
98a28fef
LP
414 }
415
416 r = manager_add_session(m, user, id, &session);
417 free(id);
418 if (r < 0)
419 goto fail;
420
421 session->leader = leader;
422 session->audit_id = audit_id;
423 session->type = t;
424 session->remote = remote;
425 session->controllers = controllers;
426 session->reset_controllers = reset_controllers;
427 session->kill_processes = kill_processes;
428 session->vtnr = vtnr;
429
430 controllers = reset_controllers = NULL;
431
432 if (!isempty(tty)) {
433 session->tty = strdup(tty);
434 if (!session->tty) {
435 r = -ENOMEM;
436 goto fail;
437 }
438 }
439
440 if (!isempty(display)) {
441 session->display = strdup(display);
442 if (!session->display) {
443 r = -ENOMEM;
444 goto fail;
445 }
446 }
447
448 if (!isempty(remote_user)) {
449 session->remote_user = strdup(remote_user);
450 if (!session->remote_user) {
451 r = -ENOMEM;
452 goto fail;
453 }
454 }
455
456 if (!isempty(remote_host)) {
457 session->remote_host = strdup(remote_host);
458 if (!session->remote_host) {
459 r = -ENOMEM;
460 goto fail;
461 }
462 }
463
464 if (!isempty(service)) {
465 session->service = strdup(service);
466 if (!session->service) {
467 r = -ENOMEM;
468 goto fail;
469 }
470 }
471
932e3ee7
LP
472 fifo_fd = session_create_fifo(session);
473 if (fifo_fd < 0) {
474 r = fifo_fd;
98a28fef
LP
475 goto fail;
476 }
477
98a28fef
LP
478 if (s) {
479 r = seat_attach_session(s, session);
480 if (r < 0)
481 goto fail;
482 }
483
484 r = session_start(session);
485 if (r < 0)
486 goto fail;
487
488 reply = dbus_message_new_method_return(message);
489 if (!reply) {
490 r = -ENOMEM;
491 goto fail;
492 }
493
494 p = session_bus_path(session);
495 if (!p) {
496 r = -ENOMEM;
497 goto fail;
498 }
499
500 b = dbus_message_append_args(
501 reply,
502 DBUS_TYPE_STRING, &session->id,
503 DBUS_TYPE_OBJECT_PATH, &p,
504 DBUS_TYPE_STRING, &session->user->runtime_path,
932e3ee7 505 DBUS_TYPE_UNIX_FD, &fifo_fd,
98a28fef
LP
506 DBUS_TYPE_INVALID);
507 free(p);
508
509 if (!b) {
510 r = -ENOMEM;
511 goto fail;
512 }
513
932e3ee7 514 close_nointr_nofail(fifo_fd);
98a28fef
LP
515 *_reply = reply;
516
517 return 0;
518
519fail:
520 strv_free(controllers);
521 strv_free(reset_controllers);
522
523 if (session)
524 session_add_to_gc_queue(session);
525
526 if (user)
527 user_add_to_gc_queue(user);
528
932e3ee7
LP
529 if (fifo_fd >= 0)
530 close_nointr_nofail(fifo_fd);
98a28fef
LP
531
532 if (reply)
533 dbus_message_unref(reply);
534
535 return r;
536}
537
47a26690
LP
538static bool device_has_tag(struct udev_device *d, const char *tag) {
539 struct udev_list_entry *first, *item;
540
541 assert(d);
542 assert(tag);
543
88bb8d21
LP
544 udev_device_get_is_initialized(d);
545
47a26690
LP
546 first = udev_device_get_tags_list_entry(d);
547 udev_list_entry_foreach(item, first)
548 if (streq(udev_list_entry_get_name(item), tag))
549 return true;
550
551 return false;
552}
553
b668e064
LP
554static int trigger_device(Manager *m, const char *prefix) {
555 struct udev_enumerate *e;
556 struct udev_list_entry *first, *item;
557 int r;
558
559 assert(m);
560
561 e = udev_enumerate_new(m->udev);
562 if (!e) {
563 r = -ENOMEM;
564 goto finish;
565 }
566
567 if (udev_enumerate_scan_devices(e) < 0) {
568 r = -EIO;
569 goto finish;
570 }
571
572 first = udev_enumerate_get_list_entry(e);
573 udev_list_entry_foreach(item, first) {
574 char *t;
575 const char *p;
576
577 p = udev_list_entry_get_name(item);
578
579 if (prefix && !path_startswith(p, prefix))
580 continue;
581
582 t = strappend(p, "/uevent");
583 if (!t) {
584 r = -ENOMEM;
585 goto finish;
586 }
587
588 write_one_line_file(t, "change");
589 free(t);
590 }
591
592 r = 0;
593
594finish:
595 if (e)
596 udev_enumerate_unref(e);
597
598 return r;
599}
600
47a26690
LP
601static int attach_device(Manager *m, const char *seat, const char *sysfs) {
602 struct udev_device *d;
603 char *rule = NULL, *file = NULL;
c28fa3d3 604 const char *id_for_seat;
47a26690
LP
605 int r;
606
607 assert(m);
608 assert(seat);
609 assert(sysfs);
610
611 d = udev_device_new_from_syspath(m->udev, sysfs);
612 if (!d)
613 return -ENODEV;
614
615 if (!device_has_tag(d, "seat")) {
616 r = -ENODEV;
617 goto finish;
618 }
619
c28fa3d3
LP
620 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
621 if (!id_for_seat) {
47a26690
LP
622 r = -ENODEV;
623 goto finish;
624 }
625
c28fa3d3 626 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
47a26690
LP
627 r = -ENOMEM;
628 goto finish;
629 }
630
c28fa3d3 631 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
47a26690
LP
632 r = -ENOMEM;
633 goto finish;
634 }
635
c28fa3d3 636 mkdir_p("/etc/udev/rules.d", 0755);
47a26690 637 r = write_one_line_file(file, rule);
a0a0c7f1
LP
638 if (r < 0)
639 goto finish;
640
b668e064 641 r = trigger_device(m, sysfs);
47a26690
LP
642
643finish:
644 free(rule);
645 free(file);
646
647 if (d)
648 udev_device_unref(d);
649
650 return r;
651}
652
b668e064
LP
653static int flush_devices(Manager *m) {
654 DIR *d;
655
656 assert(m);
657
658 d = opendir("/etc/udev/rules.d");
659 if (!d) {
660 if (errno != ENOENT)
661 log_warning("Failed to open /etc/udev/rules.d: %m");
662 } else {
663 struct dirent *de;
664
665 while ((de = readdir(d))) {
666
667 if (!dirent_is_file(de))
668 continue;
669
670 if (!startswith(de->d_name, "72-seat-"))
671 continue;
672
673 if (!endswith(de->d_name, ".rules"))
674 continue;
675
676 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
677 log_warning("Failed to unlink %s: %m", de->d_name);
678 }
679
680 closedir(d);
681 }
682
683 return trigger_device(m, NULL);
684}
685
3f49d45a
LP
686static DBusHandlerResult manager_message_handler(
687 DBusConnection *connection,
688 DBusMessage *message,
689 void *userdata) {
690
691 Manager *m = userdata;
692
693 const BusProperty properties[] = {
a185c5aa
LP
694 { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path },
695 { "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers },
193197e8 696 { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers },
a185c5aa
LP
697 { "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts },
698 { "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users },
699 { "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users },
700 { "org.freedesktop.login1.Manager", "KillUserProcesses", bus_property_append_bool, "b", &m->kill_user_processes },
701 { "org.freedesktop.login1.Manager", "IdleHint", bus_manager_append_idle_hint, "b", m },
702 { "org.freedesktop.login1.Manager", "IdleSinceHint", bus_manager_append_idle_hint_since, "t", m },
703 { "org.freedesktop.login1.Manager", "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", m },
3f49d45a
LP
704 { NULL, NULL, NULL, NULL, NULL }
705 };
706
707 DBusError error;
708 DBusMessage *reply = NULL;
bef422ae 709 int r;
3f49d45a
LP
710
711 assert(connection);
712 assert(message);
713 assert(m);
714
715 dbus_error_init(&error);
716
bef422ae
LP
717 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
718 const char *name;
719 char *p;
720 Session *session;
721 bool b;
722
723 if (!dbus_message_get_args(
724 message,
725 &error,
726 DBUS_TYPE_STRING, &name,
727 DBUS_TYPE_INVALID))
728 return bus_send_error_reply(connection, message, &error, -EINVAL);
729
730 session = hashmap_get(m->sessions, name);
731 if (!session)
732 return bus_send_error_reply(connection, message, &error, -ENOENT);
733
734 reply = dbus_message_new_method_return(message);
735 if (!reply)
736 goto oom;
737
738 p = session_bus_path(session);
739 if (!p)
740 goto oom;
741
742 b = dbus_message_append_args(
743 reply,
744 DBUS_TYPE_OBJECT_PATH, &p,
745 DBUS_TYPE_INVALID);
746 free(p);
747
748 if (!b)
749 goto oom;
750
751 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
752 uint32_t uid;
753 char *p;
754 User *user;
755 bool b;
756
757 if (!dbus_message_get_args(
758 message,
759 &error,
760 DBUS_TYPE_UINT32, &uid,
761 DBUS_TYPE_INVALID))
762 return bus_send_error_reply(connection, message, &error, -EINVAL);
763
764 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
765 if (!user)
766 return bus_send_error_reply(connection, message, &error, -ENOENT);
767
768 reply = dbus_message_new_method_return(message);
769 if (!reply)
770 goto oom;
771
772 p = user_bus_path(user);
773 if (!p)
774 goto oom;
775
776 b = dbus_message_append_args(
777 reply,
778 DBUS_TYPE_OBJECT_PATH, &p,
779 DBUS_TYPE_INVALID);
780 free(p);
781
782 if (!b)
783 goto oom;
784
785 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
786 const char *name;
787 char *p;
788 Seat *seat;
789 bool b;
790
791 if (!dbus_message_get_args(
792 message,
793 &error,
794 DBUS_TYPE_STRING, &name,
795 DBUS_TYPE_INVALID))
796 return bus_send_error_reply(connection, message, &error, -EINVAL);
797
798 seat = hashmap_get(m->seats, name);
799 if (!seat)
800 return bus_send_error_reply(connection, message, &error, -ENOENT);
801
802 reply = dbus_message_new_method_return(message);
803 if (!reply)
804 goto oom;
805
806 p = seat_bus_path(seat);
807 if (!p)
808 goto oom;
809
810 b = dbus_message_append_args(
811 reply,
812 DBUS_TYPE_OBJECT_PATH, &p,
813 DBUS_TYPE_INVALID);
814 free(p);
815
816 if (!b)
817 goto oom;
818
e1c9c2d5
LP
819 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
820 char *p;
821 Session *session;
822 Iterator i;
823 DBusMessageIter iter, sub;
824 const char *empty = "";
825
826 reply = dbus_message_new_method_return(message);
827 if (!reply)
828 goto oom;
829
830 dbus_message_iter_init_append(reply, &iter);
831
dec15e92 832 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
e1c9c2d5
LP
833 goto oom;
834
835 HASHMAP_FOREACH(session, m->sessions, i) {
836 DBusMessageIter sub2;
837 uint32_t uid;
838
839 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
840 goto oom;
841
842 uid = session->user->uid;
843
844 p = session_bus_path(session);
845 if (!p)
846 goto oom;
847
848 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
849 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
850 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
851 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
852 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
853 free(p);
854 goto oom;
855 }
856
857 free(p);
858
859 if (!dbus_message_iter_close_container(&sub, &sub2))
860 goto oom;
861 }
862
863 if (!dbus_message_iter_close_container(&iter, &sub))
864 goto oom;
865
866 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
867 char *p;
868 User *user;
869 Iterator i;
870 DBusMessageIter iter, sub;
871
872 reply = dbus_message_new_method_return(message);
873 if (!reply)
874 goto oom;
875
876 dbus_message_iter_init_append(reply, &iter);
877
dec15e92 878 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
e1c9c2d5
LP
879 goto oom;
880
881 HASHMAP_FOREACH(user, m->users, i) {
882 DBusMessageIter sub2;
883 uint32_t uid;
884
885 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
886 goto oom;
887
888 uid = user->uid;
889
890 p = user_bus_path(user);
891 if (!p)
892 goto oom;
893
894 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
895 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
896 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
897 free(p);
898 goto oom;
899 }
900
901 free(p);
902
903 if (!dbus_message_iter_close_container(&sub, &sub2))
904 goto oom;
905 }
906
907 if (!dbus_message_iter_close_container(&iter, &sub))
908 goto oom;
909
910 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
911 char *p;
912 Seat *seat;
913 Iterator i;
914 DBusMessageIter iter, sub;
915
916 reply = dbus_message_new_method_return(message);
917 if (!reply)
918 goto oom;
919
920 dbus_message_iter_init_append(reply, &iter);
921
dec15e92 922 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
e1c9c2d5
LP
923 goto oom;
924
925 HASHMAP_FOREACH(seat, m->seats, i) {
926 DBusMessageIter sub2;
927
928 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
929 goto oom;
930
931 p = seat_bus_path(seat);
932 if (!p)
933 goto oom;
934
935 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
936 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
937 free(p);
938 goto oom;
939 }
940
941 free(p);
942
943 if (!dbus_message_iter_close_container(&sub, &sub2))
944 goto oom;
945 }
946
947 if (!dbus_message_iter_close_container(&iter, &sub))
948 goto oom;
949
98a28fef
LP
950 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
951
952 r = bus_manager_create_session(m, message, &reply);
953 if (r == -ENOMEM)
954 goto oom;
955
956 if (r < 0)
957 return bus_send_error_reply(connection, message, &error, r);
958
bef422ae
LP
959 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
960 const char *name;
961 Session *session;
962
963 if (!dbus_message_get_args(
964 message,
965 &error,
966 DBUS_TYPE_STRING, &name,
967 DBUS_TYPE_INVALID))
968 return bus_send_error_reply(connection, message, &error, -EINVAL);
969
970 session = hashmap_get(m->sessions, name);
971 if (!session)
972 return bus_send_error_reply(connection, message, &error, -ENOENT);
973
974 r = session_activate(session);
975 if (r < 0)
976 return bus_send_error_reply(connection, message, NULL, r);
977
978 reply = dbus_message_new_method_return(message);
979 if (!reply)
980 goto oom;
981
982 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
983 const char *name;
984 Session *session;
985
986 if (!dbus_message_get_args(
987 message,
988 &error,
989 DBUS_TYPE_STRING, &name,
990 DBUS_TYPE_INVALID))
991 return bus_send_error_reply(connection, message, &error, -EINVAL);
992
993 session = hashmap_get(m->sessions, name);
994 if (!session)
995 return bus_send_error_reply(connection, message, &error, -ENOENT);
996
997 r = session_stop(session);
998 if (r < 0)
999 return bus_send_error_reply(connection, message, NULL, r);
1000
1001 reply = dbus_message_new_method_return(message);
1002 if (!reply)
1003 goto oom;
1004
1005 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1006 uint32_t uid;
1007 User *user;
1008
1009 if (!dbus_message_get_args(
1010 message,
1011 &error,
1012 DBUS_TYPE_UINT32, &uid,
1013 DBUS_TYPE_INVALID))
1014 return bus_send_error_reply(connection, message, &error, -EINVAL);
1015
1016 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1017 if (!user)
1018 return bus_send_error_reply(connection, message, &error, -ENOENT);
1019
1020 r = user_stop(user);
1021 if (r < 0)
1022 return bus_send_error_reply(connection, message, NULL, r);
1023
1024 reply = dbus_message_new_method_return(message);
1025 if (!reply)
1026 goto oom;
1027
1028 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1029 const char *name;
1030 Seat *seat;
1031
1032 if (!dbus_message_get_args(
1033 message,
1034 &error,
1035 DBUS_TYPE_STRING, &name,
1036 DBUS_TYPE_INVALID))
1037 return bus_send_error_reply(connection, message, &error, -EINVAL);
1038
1039 seat = hashmap_get(m->seats, name);
1040 if (!seat)
1041 return bus_send_error_reply(connection, message, &error, -ENOENT);
1042
1043 r = seat_stop_sessions(seat);
1044 if (r < 0)
1045 return bus_send_error_reply(connection, message, NULL, r);
1046
1047 reply = dbus_message_new_method_return(message);
1048 if (!reply)
1049 goto oom;
1050
7f7bb946
LP
1051 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1052 uint32_t uid;
1053 struct passwd *pw;
1054 dbus_bool_t b, interactive;
1055 char *path;
1056
1057 if (!dbus_message_get_args(
1058 message,
1059 &error,
1060 DBUS_TYPE_UINT32, &uid,
1061 DBUS_TYPE_BOOLEAN, &b,
1062 DBUS_TYPE_BOOLEAN, &interactive,
1063 DBUS_TYPE_INVALID))
1064 return bus_send_error_reply(connection, message, &error, -EINVAL);
1065
1066 errno = 0;
1067 pw = getpwuid(uid);
1068 if (!pw)
1069 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1070
1071 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, &error);
1072 if (r < 0)
1073 return bus_send_error_reply(connection, message, &error, r);
1074
1075 r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
1076 if (r < 0)
1077 return bus_send_error_reply(connection, message, &error, r);
1078
1079 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1080 if (!path)
1081 goto oom;
1082
1083 if (b) {
38f3fc7d
LP
1084 User *u;
1085
7f7bb946
LP
1086 r = touch(path);
1087 free(path);
1088
1089 if (r < 0)
1090 return bus_send_error_reply(connection, message, &error, r);
38f3fc7d
LP
1091
1092 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1093 user_start(u);
1094
7f7bb946 1095 } else {
38f3fc7d
LP
1096 User *u;
1097
7f7bb946
LP
1098 r = unlink(path);
1099 free(path);
1100
1101 if (r < 0 && errno != ENOENT)
1102 return bus_send_error_reply(connection, message, &error, -errno);
38f3fc7d
LP
1103
1104 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1105 if (u)
1106 user_add_to_gc_queue(u);
7f7bb946
LP
1107 }
1108
1109 reply = dbus_message_new_method_return(message);
1110 if (!reply)
1111 goto oom;
1112
47a26690
LP
1113 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1114 const char *sysfs, *seat;
1115 dbus_bool_t interactive;
1116
1117 if (!dbus_message_get_args(
1118 message,
1119 &error,
1120 DBUS_TYPE_STRING, &seat,
1121 DBUS_TYPE_STRING, &sysfs,
1122 DBUS_TYPE_BOOLEAN, &interactive,
1123 DBUS_TYPE_INVALID))
1124 return bus_send_error_reply(connection, message, &error, -EINVAL);
1125
1126 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1127 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1128
1129 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, &error);
1130 if (r < 0)
1131 return bus_send_error_reply(connection, message, &error, r);
1132
1133 r = attach_device(m, seat, sysfs);
1134 if (r < 0)
1135 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1136
1137 reply = dbus_message_new_method_return(message);
1138 if (!reply)
1139 goto oom;
7f7bb946 1140
b668e064
LP
1141
1142 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1143 dbus_bool_t interactive;
1144
1145 if (!dbus_message_get_args(
1146 message,
1147 &error,
1148 DBUS_TYPE_BOOLEAN, &interactive,
1149 DBUS_TYPE_INVALID))
1150 return bus_send_error_reply(connection, message, &error, -EINVAL);
1151
1152 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, &error);
1153 if (r < 0)
1154 return bus_send_error_reply(connection, message, &error, r);
1155
1156 r = flush_devices(m);
1157 if (r < 0)
1158 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1159
1160 reply = dbus_message_new_method_return(message);
1161 if (!reply)
1162 goto oom;
1163
bef422ae 1164 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3f49d45a
LP
1165 char *introspection = NULL;
1166 FILE *f;
1167 Iterator i;
1168 Session *session;
1169 Seat *seat;
1170 User *user;
1171 size_t size;
1172 char *p;
1173
1174 if (!(reply = dbus_message_new_method_return(message)))
1175 goto oom;
1176
1177 /* We roll our own introspection code here, instead of
1178 * relying on bus_default_message_handler() because we
1179 * need to generate our introspection string
1180 * dynamically. */
1181
1182 if (!(f = open_memstream(&introspection, &size)))
1183 goto oom;
1184
1185 fputs(INTROSPECTION_BEGIN, f);
1186
1187 HASHMAP_FOREACH(seat, m->seats, i) {
1188 p = bus_path_escape(seat->id);
1189
1190 if (p) {
1191 fprintf(f, "<node name=\"seat/%s\"/>", p);
1192 free(p);
1193 }
1194 }
1195
1196 HASHMAP_FOREACH(user, m->users, i)
1197 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
1198
1199 HASHMAP_FOREACH(session, m->sessions, i) {
1200 p = bus_path_escape(session->id);
1201
1202 if (p) {
1203 fprintf(f, "<node name=\"session/%s\"/>", p);
1204 free(p);
1205 }
1206 }
1207
1208 fputs(INTROSPECTION_END, f);
1209
1210 if (ferror(f)) {
1211 fclose(f);
1212 free(introspection);
1213 goto oom;
1214 }
1215
1216 fclose(f);
1217
1218 if (!introspection)
1219 goto oom;
1220
1221 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1222 free(introspection);
1223 goto oom;
1224 }
1225
1226 free(introspection);
1227 } else
1228 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, properties);
1229
1230 if (reply) {
1231 if (!dbus_connection_send(connection, reply, NULL))
1232 goto oom;
1233
1234 dbus_message_unref(reply);
1235 }
1236
1237 return DBUS_HANDLER_RESULT_HANDLED;
1238
1239oom:
1240 if (reply)
1241 dbus_message_unref(reply);
1242
1243 dbus_error_free(&error);
1244
1245 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1246}
1247
1248const DBusObjectPathVTable bus_manager_vtable = {
1249 .message_function = manager_message_handler
1250};
9418f147 1251
1713813d
LP
1252DBusHandlerResult bus_message_filter(
1253 DBusConnection *connection,
1254 DBusMessage *message,
1255 void *userdata) {
1256
1257 Manager *m = userdata;
1258 DBusError error;
1259
1260 assert(m);
1261 assert(connection);
1262 assert(message);
1263
1264 dbus_error_init(&error);
1265
1266 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
1267 const char *cgroup;
1268
1269 if (!dbus_message_get_args(message, &error,
1270 DBUS_TYPE_STRING, &cgroup,
1271 DBUS_TYPE_INVALID))
1272 log_error("Failed to parse Released message: %s", bus_error_message(&error));
1273 else
1274 manager_cgroup_notify_empty(m, cgroup);
1275 }
1276
1277 dbus_error_free(&error);
1278
1279 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1280}
1281
9418f147
LP
1282int manager_send_changed(Manager *manager, const char *properties) {
1283 DBusMessage *m;
1284 int r = -ENOMEM;
1285
1286 assert(manager);
1287
1288 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
1289 if (!m)
1290 goto finish;
1291
1292 if (!dbus_connection_send(manager->bus, m, NULL))
1293 goto finish;
1294
1295 r = 0;
1296
1297finish:
1298 if (m)
1299 dbus_message_unref(m);
1300
1301 return r;
1302}