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