]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session-dbus.c
logind: introduce session-devices
[thirdparty/systemd.git] / src / login / logind-session-dbus.c
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 Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24
25 #include "logind.h"
26 #include "logind-session.h"
27 #include "logind-session-device.h"
28 #include "dbus-common.h"
29 #include "util.h"
30
31 #define BUS_SESSION_INTERFACE \
32 " <interface name=\"org.freedesktop.login1.Session\">\n" \
33 " <method name=\"Terminate\"/>\n" \
34 " <method name=\"Activate\"/>\n" \
35 " <method name=\"Lock\"/>\n" \
36 " <method name=\"Unlock\"/>\n" \
37 " <method name=\"SetIdleHint\">\n" \
38 " <arg name=\"b\" type=\"b\"/>\n" \
39 " </method>\n" \
40 " <method name=\"Kill\">\n" \
41 " <arg name=\"who\" type=\"s\"/>\n" \
42 " <arg name=\"signal\" type=\"s\"/>\n" \
43 " </method>\n" \
44 " <method name=\"TakeControl\"/>\n" \
45 " <arg name=\"force\" type=\"b\"/>\n" \
46 " </method>\n" \
47 " <method name=\"ReleaseControl\"/>\n" \
48 " <method name=\"TakeDevice\">\n" \
49 " <arg name=\"major\" type=\"u\" direction=\"in\"/>\n" \
50 " <arg name=\"minor\" type=\"u\" direction=\"in\"/>\n" \
51 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
52 " <arg name=\"paused\" type=\"b\" direction=\"out\"/>\n" \
53 " </method>\n" \
54 " <method name=\"ReleaseDevice\">\n" \
55 " <arg name=\"major\" type=\"u\"/>\n" \
56 " <arg name=\"minor\" type=\"u\"/>\n" \
57 " </method>\n" \
58 " <method name=\"PauseDeviceComplete\">\n" \
59 " <arg name=\"major\" type=\"u\"/>\n" \
60 " <arg name=\"minor\" type=\"u\"/>\n" \
61 " </method>\n" \
62 " <signal name=\"PauseDevice\">\n" \
63 " <arg name=\"major\" type=\"u\"/>\n" \
64 " <arg name=\"minor\" type=\"u\"/>\n" \
65 " <arg name=\"type\" type=\"s\"/>\n" \
66 " </signal>\n" \
67 " <signal name=\"ResumeDevice\">\n" \
68 " <arg name=\"major\" type=\"u\"/>\n" \
69 " <arg name=\"minor\" type=\"u\"/>\n" \
70 " <arg name=\"fd\" type=\"h\"/>\n" \
71 " </signal>\n" \
72 " <signal name=\"Lock\"/>\n" \
73 " <signal name=\"Unlock\"/>\n" \
74 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
75 " <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
76 " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
77 " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
78 " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
79 " <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n" \
80 " <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n" \
81 " <property name=\"TTY\" type=\"s\" access=\"read\"/>\n" \
82 " <property name=\"Display\" type=\"s\" access=\"read\"/>\n" \
83 " <property name=\"Remote\" type=\"b\" access=\"read\"/>\n" \
84 " <property name=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
85 " <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
86 " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
87 " <property name=\"Scope\" type=\"s\" access=\"read\"/>\n" \
88 " <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
89 " <property name=\"Audit\" type=\"u\" access=\"read\"/>\n" \
90 " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
91 " <property name=\"Class\" type=\"s\" access=\"read\"/>\n" \
92 " <property name=\"Active\" type=\"b\" access=\"read\"/>\n" \
93 " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
94 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
95 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
96 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
97 " </interface>\n"
98
99 #define INTROSPECTION \
100 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
101 "<node>\n" \
102 BUS_SESSION_INTERFACE \
103 BUS_PROPERTIES_INTERFACE \
104 BUS_PEER_INTERFACE \
105 BUS_INTROSPECTABLE_INTERFACE \
106 "</node>\n"
107
108 #define INTERFACES_LIST \
109 BUS_GENERIC_INTERFACES_LIST \
110 "org.freedesktop.login1.Session\0"
111
112 static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
113 DBusMessageIter sub;
114 Session *s = data;
115 const char *id, *path;
116 char *p = NULL;
117
118 assert(i);
119 assert(property);
120 assert(s);
121
122 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
123 return -ENOMEM;
124
125 if (s->seat) {
126 id = s->seat->id;
127 path = p = seat_bus_path(s->seat);
128
129 if (!p)
130 return -ENOMEM;
131 } else {
132 id = "";
133 path = "/";
134 }
135
136 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
137 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path))
138 return -ENOMEM;
139
140 if (!dbus_message_iter_close_container(i, &sub))
141 return -ENOMEM;
142
143 return 0;
144 }
145
146 static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
147 DBusMessageIter sub;
148 User *u = data;
149 _cleanup_free_ char *p = NULL;
150
151 assert(i);
152 assert(property);
153 assert(u);
154
155 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
156 return -ENOMEM;
157
158 p = user_bus_path(u);
159 if (!p)
160 return -ENOMEM;
161
162 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->uid) ||
163 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p))
164 return -ENOMEM;
165
166 if (!dbus_message_iter_close_container(i, &sub))
167 return -ENOMEM;
168
169 return 0;
170 }
171
172 static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
173 Session *s = data;
174 dbus_bool_t b;
175
176 assert(i);
177 assert(property);
178 assert(s);
179
180 b = session_is_active(s);
181 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
182 return -ENOMEM;
183
184 return 0;
185 }
186
187 static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
188 Session *s = data;
189 int b;
190
191 assert(i);
192 assert(property);
193 assert(s);
194
195 b = session_get_idle_hint(s, NULL) > 0;
196 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
197 return -ENOMEM;
198
199 return 0;
200 }
201
202 static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
203 Session *s = data;
204 dual_timestamp t;
205 uint64_t u;
206 int r;
207
208 assert(i);
209 assert(property);
210 assert(s);
211
212 r = session_get_idle_hint(s, &t);
213 if (r < 0)
214 return r;
215
216 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
217
218 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
219 return -ENOMEM;
220
221 return 0;
222 }
223
224 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
225 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
226
227 static int bus_session_append_state(DBusMessageIter *i, const char *property, void *data) {
228 Session *s = data;
229 const char *state;
230
231 assert(i);
232 assert(property);
233 assert(s);
234
235 state = session_state_to_string(session_get_state(s));
236
237 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
238 return -ENOMEM;
239
240 return 0;
241 }
242
243 static int get_session_for_path(Manager *m, const char *path, Session **_s) {
244 _cleanup_free_ char *id = NULL;
245 Session *s;
246
247 assert(m);
248 assert(path);
249 assert(_s);
250
251 if (!startswith(path, "/org/freedesktop/login1/session/"))
252 return -EINVAL;
253
254 id = bus_path_unescape(path + 32);
255 if (!id)
256 return -ENOMEM;
257
258 s = hashmap_get(m->sessions, id);
259 if (!s)
260 return -ENOENT;
261
262 *_s = s;
263 return 0;
264 }
265
266 static const BusProperty bus_login_session_properties[] = {
267 { "Id", bus_property_append_string, "s", offsetof(Session, id), true },
268 { "Timestamp", bus_property_append_usec, "t", offsetof(Session, timestamp.realtime) },
269 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Session, timestamp.monotonic) },
270 { "VTNr", bus_property_append_uint32, "u", offsetof(Session, vtnr) },
271 { "Seat", bus_session_append_seat, "(so)", 0 },
272 { "TTY", bus_property_append_string, "s", offsetof(Session, tty), true },
273 { "Display", bus_property_append_string, "s", offsetof(Session, display), true },
274 { "Remote", bus_property_append_bool, "b", offsetof(Session, remote) },
275 { "RemoteUser", bus_property_append_string, "s", offsetof(Session, remote_user), true },
276 { "RemoteHost", bus_property_append_string, "s", offsetof(Session, remote_host), true },
277 { "Service", bus_property_append_string, "s", offsetof(Session, service), true },
278 { "Scope", bus_property_append_string, "s", offsetof(Session, scope), true },
279 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
280 { "Audit", bus_property_append_uint32, "u", offsetof(Session, audit_id) },
281 { "Type", bus_session_append_type, "s", offsetof(Session, type) },
282 { "Class", bus_session_append_class, "s", offsetof(Session, class) },
283 { "Active", bus_session_append_active, "b", 0 },
284 { "State", bus_session_append_state, "s", 0 },
285 { "IdleHint", bus_session_append_idle_hint, "b", 0 },
286 { "IdleSinceHint", bus_session_append_idle_hint_since, "t", 0 },
287 { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
288 { NULL, }
289 };
290
291 static const BusProperty bus_login_session_user_properties[] = {
292 { "User", bus_session_append_user, "(uo)", 0 },
293 { "Name", bus_property_append_string, "s", offsetof(User, name), true },
294 { NULL, }
295 };
296
297 static DBusHandlerResult session_message_dispatch(
298 Session *s,
299 DBusConnection *connection,
300 DBusMessage *message) {
301
302 DBusError error;
303 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
304 int r;
305
306 assert(s);
307 assert(connection);
308 assert(message);
309
310 dbus_error_init(&error);
311
312 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
313
314 r = session_stop(s);
315 if (r < 0)
316 return bus_send_error_reply(connection, message, NULL, r);
317
318 reply = dbus_message_new_method_return(message);
319 if (!reply)
320 goto oom;
321
322 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
323
324 r = session_activate(s);
325 if (r < 0)
326 return bus_send_error_reply(connection, message, NULL, r);
327
328 reply = dbus_message_new_method_return(message);
329 if (!reply)
330 goto oom;
331
332 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
333 dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
334
335 if (session_send_lock(s, streq(dbus_message_get_member(message), "Lock")) < 0)
336 goto oom;
337
338 reply = dbus_message_new_method_return(message);
339 if (!reply)
340 goto oom;
341
342 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
343 dbus_bool_t b;
344 unsigned long ul;
345
346 if (!dbus_message_get_args(
347 message,
348 &error,
349 DBUS_TYPE_BOOLEAN, &b,
350 DBUS_TYPE_INVALID))
351 return bus_send_error_reply(connection, message, &error, -EINVAL);
352
353 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
354 if (ul == (unsigned long) -1)
355 return bus_send_error_reply(connection, message, &error, -EIO);
356
357 if (ul != 0 && ul != s->user->uid)
358 return bus_send_error_reply(connection, message, NULL, -EPERM);
359
360 session_set_idle_hint(s, b);
361
362 reply = dbus_message_new_method_return(message);
363 if (!reply)
364 goto oom;
365
366 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
367 const char *swho;
368 int32_t signo;
369 KillWho who;
370
371 if (!dbus_message_get_args(
372 message,
373 &error,
374 DBUS_TYPE_STRING, &swho,
375 DBUS_TYPE_INT32, &signo,
376 DBUS_TYPE_INVALID))
377 return bus_send_error_reply(connection, message, &error, -EINVAL);
378
379 if (isempty(swho))
380 who = KILL_ALL;
381 else {
382 who = kill_who_from_string(swho);
383 if (who < 0)
384 return bus_send_error_reply(connection, message, &error, -EINVAL);
385 }
386
387 if (signo <= 0 || signo >= _NSIG)
388 return bus_send_error_reply(connection, message, &error, -EINVAL);
389
390 r = session_kill(s, who, signo);
391 if (r < 0)
392 return bus_send_error_reply(connection, message, NULL, r);
393
394 reply = dbus_message_new_method_return(message);
395 if (!reply)
396 goto oom;
397
398 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "TakeControl")) {
399 dbus_bool_t force;
400 unsigned long ul;
401
402 if (!dbus_message_get_args(
403 message,
404 &error,
405 DBUS_TYPE_BOOLEAN, &force,
406 DBUS_TYPE_INVALID))
407 return bus_send_error_reply(connection, message, &error, -EINVAL);
408
409 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
410 if (ul == (unsigned long) -1)
411 return bus_send_error_reply(connection, message, &error, -EIO);
412
413 if (ul != 0 && (force || ul != s->user->uid))
414 return bus_send_error_reply(connection, message, NULL, -EPERM);
415
416 r = session_set_controller(s, bus_message_get_sender_with_fallback(message), force);
417 if (r < 0)
418 return bus_send_error_reply(connection, message, NULL, r);
419
420 reply = dbus_message_new_method_return(message);
421 if (!reply)
422 goto oom;
423
424 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "ReleaseControl")) {
425 const char *sender = bus_message_get_sender_with_fallback(message);
426
427 if (!session_is_controller(s, sender))
428 return bus_send_error_reply(connection, message, NULL, -EPERM);
429
430 session_drop_controller(s);
431
432 reply = dbus_message_new_method_return(message);
433 if (!reply)
434 goto oom;
435
436 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "TakeDevice")) {
437 SessionDevice *sd;
438 bool b;
439 dbus_bool_t paused;
440 uint32_t major, minor;
441 dev_t dev;
442
443 if (!session_is_controller(s, bus_message_get_sender_with_fallback(message)))
444 return bus_send_error_reply(connection, message, NULL, -EPERM);
445
446 if (!dbus_message_get_args(
447 message,
448 &error,
449 DBUS_TYPE_UINT32, &major,
450 DBUS_TYPE_UINT32, &minor,
451 DBUS_TYPE_INVALID))
452 return bus_send_error_reply(connection, message, &error, -EINVAL);
453
454 dev = makedev(major, minor);
455 assert_cc(sizeof(unsigned long) >= sizeof(dev_t));
456
457 sd = hashmap_get(s->devices, ULONG_TO_PTR((unsigned long)dev));
458 if (sd) {
459 /* We don't allow retrieving a device multiple times.
460 * The related ReleaseDevice call is not ref-counted.
461 * The caller should use dup() if it requires more than
462 * one fd (it would be functionally equivalent). */
463 return bus_send_error_reply(connection, message, &error, -EBUSY);
464 }
465
466 r = session_device_new(s, dev, &sd);
467 if (r < 0)
468 return bus_send_error_reply(connection, message, NULL, r);
469
470 reply = dbus_message_new_method_return(message);
471 if (!reply) {
472 session_device_free(sd);
473 goto oom;
474 }
475
476 paused = !sd->active;
477 b = dbus_message_append_args(
478 reply,
479 DBUS_TYPE_UNIX_FD, &sd->fd,
480 DBUS_TYPE_BOOLEAN, &paused,
481 DBUS_TYPE_INVALID);
482 if (!b) {
483 session_device_free(sd);
484 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
485 }
486
487 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "ReleaseDevice")) {
488 SessionDevice *sd;
489 uint32_t major, minor;
490
491 if (!session_is_controller(s, bus_message_get_sender_with_fallback(message)))
492 return bus_send_error_reply(connection, message, NULL, -EPERM);
493
494 if (!dbus_message_get_args(
495 message,
496 &error,
497 DBUS_TYPE_UINT32, &major,
498 DBUS_TYPE_UINT32, &minor,
499 DBUS_TYPE_INVALID))
500 return bus_send_error_reply(connection, message, &error, -EINVAL);
501
502 sd = hashmap_get(s->devices, ULONG_TO_PTR((unsigned long)makedev(major, minor)));
503 if (!sd)
504 return bus_send_error_reply(connection, message, NULL, -ENODEV);
505
506 session_device_free(sd);
507
508 reply = dbus_message_new_method_return(message);
509 if (!reply)
510 goto oom;
511
512 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "PauseDeviceComplete")) {
513 SessionDevice *sd;
514 uint32_t major, minor;
515
516 if (!session_is_controller(s, bus_message_get_sender_with_fallback(message)))
517 return bus_send_error_reply(connection, message, NULL, -EPERM);
518
519 if (!dbus_message_get_args(
520 message,
521 &error,
522 DBUS_TYPE_UINT32, &major,
523 DBUS_TYPE_UINT32, &minor,
524 DBUS_TYPE_INVALID))
525 return bus_send_error_reply(connection, message, &error, -EINVAL);
526
527 sd = hashmap_get(s->devices, ULONG_TO_PTR((unsigned long)makedev(major, minor)));
528 if (!sd)
529 return bus_send_error_reply(connection, message, NULL, -ENODEV);
530
531 session_device_complete_pause(sd);
532
533 reply = dbus_message_new_method_return(message);
534 if (!reply)
535 goto oom;
536
537 } else {
538 const BusBoundProperties bps[] = {
539 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
540 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
541 { NULL, }
542 };
543 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
544 }
545
546 if (reply) {
547 if (!bus_maybe_send_reply(connection, message, reply))
548 goto oom;
549 }
550
551 return DBUS_HANDLER_RESULT_HANDLED;
552
553 oom:
554 dbus_error_free(&error);
555
556 return DBUS_HANDLER_RESULT_NEED_MEMORY;
557 }
558
559 static DBusHandlerResult session_message_handler(
560 DBusConnection *connection,
561 DBusMessage *message,
562 void *userdata) {
563
564 Manager *m = userdata;
565 Session *s;
566 int r;
567
568 r = get_session_for_path(m, dbus_message_get_path(message), &s);
569 if (r < 0) {
570
571 if (r == -ENOMEM)
572 return DBUS_HANDLER_RESULT_NEED_MEMORY;
573
574 if (r == -ENOENT) {
575 DBusError e;
576
577 dbus_error_init(&e);
578 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
579 return bus_send_error_reply(connection, message, &e, r);
580 }
581
582 return bus_send_error_reply(connection, message, NULL, r);
583 }
584
585 return session_message_dispatch(s, connection, message);
586 }
587
588 const DBusObjectPathVTable bus_session_vtable = {
589 .message_function = session_message_handler
590 };
591
592 char *session_bus_path(Session *s) {
593 _cleanup_free_ char *t = NULL;
594
595 assert(s);
596
597 t = bus_path_escape(s->id);
598 if (!t)
599 return NULL;
600
601 return strappend("/org/freedesktop/login1/session/", t);
602 }
603
604 int session_send_signal(Session *s, bool new_session) {
605 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
606 _cleanup_free_ char *p = NULL;
607
608 assert(s);
609
610 m = dbus_message_new_signal("/org/freedesktop/login1",
611 "org.freedesktop.login1.Manager",
612 new_session ? "SessionNew" : "SessionRemoved");
613
614 if (!m)
615 return -ENOMEM;
616
617 p = session_bus_path(s);
618 if (!p)
619 return -ENOMEM;
620
621 if (!dbus_message_append_args(
622 m,
623 DBUS_TYPE_STRING, &s->id,
624 DBUS_TYPE_OBJECT_PATH, &p,
625 DBUS_TYPE_INVALID))
626 return -ENOMEM;
627
628 if (!dbus_connection_send(s->manager->bus, m, NULL))
629 return -ENOMEM;
630
631 return 0;
632 }
633
634 int session_send_changed(Session *s, const char *properties) {
635 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
636 _cleanup_free_ char *p = NULL;
637
638 assert(s);
639
640 if (!s->started)
641 return 0;
642
643 p = session_bus_path(s);
644 if (!p)
645 return -ENOMEM;
646
647 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
648 if (!m)
649 return -ENOMEM;
650
651 if (!dbus_connection_send(s->manager->bus, m, NULL))
652 return -ENOMEM;
653
654 return 0;
655 }
656
657 int session_send_lock(Session *s, bool lock) {
658 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
659 bool b;
660 _cleanup_free_ char *p = NULL;
661
662 assert(s);
663
664 p = session_bus_path(s);
665 if (!p)
666 return -ENOMEM;
667
668 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
669
670 if (!m)
671 return -ENOMEM;
672
673 b = dbus_connection_send(s->manager->bus, m, NULL);
674 if (!b)
675 return -ENOMEM;
676
677 return 0;
678 }
679
680 int session_send_lock_all(Manager *m, bool lock) {
681 Session *session;
682 Iterator i;
683 int r = 0;
684
685 assert(m);
686
687 HASHMAP_FOREACH(session, m->sessions, i) {
688 int k;
689
690 k = session_send_lock(session, lock);
691 if (k < 0)
692 r = k;
693 }
694
695 return r;
696 }
697
698 int session_send_create_reply(Session *s, DBusError *error) {
699 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
700
701 assert(s);
702
703 if (!s->create_message)
704 return 0;
705
706 /* This is called after the session scope was successfully
707 * created, and finishes where bus_manager_create_session()
708 * left off. */
709
710 if (error) {
711 DBusError buffer;
712
713 dbus_error_init(&buffer);
714
715 if (!dbus_error_is_set(error)) {
716 dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
717 error = &buffer;
718 }
719
720 reply = dbus_message_new_error(s->create_message, error->name, error->message);
721 dbus_error_free(&buffer);
722
723 if (!reply)
724 return log_oom();
725 } else {
726 _cleanup_close_ int fifo_fd = -1;
727 _cleanup_free_ char *path = NULL;
728 const char *cseat;
729 uint32_t vtnr;
730 dbus_bool_t exists;
731
732 fifo_fd = session_create_fifo(s);
733 if (fifo_fd < 0) {
734 log_error("Failed to create fifo: %s", strerror(-fifo_fd));
735 return fifo_fd;
736 }
737
738 path = session_bus_path(s);
739 if (!path)
740 return log_oom();
741
742 reply = dbus_message_new_method_return(s->create_message);
743 if (!reply)
744 return log_oom();
745
746 cseat = s->seat ? s->seat->id : "";
747 vtnr = s->vtnr;
748 exists = false;
749
750 if (!dbus_message_append_args(
751 reply,
752 DBUS_TYPE_STRING, &s->id,
753 DBUS_TYPE_OBJECT_PATH, &path,
754 DBUS_TYPE_STRING, &s->user->runtime_path,
755 DBUS_TYPE_UNIX_FD, &fifo_fd,
756 DBUS_TYPE_STRING, &cseat,
757 DBUS_TYPE_UINT32, &vtnr,
758 DBUS_TYPE_BOOLEAN, &exists,
759 DBUS_TYPE_INVALID))
760 return log_oom();
761 }
762
763 /* Update the state file before we notify the client about the
764 * result */
765 session_save(s);
766
767 if (!dbus_connection_send(s->manager->bus, reply, NULL))
768 return log_oom();
769
770 dbus_message_unref(s->create_message);
771 s->create_message = NULL;
772
773 return 0;
774 }