]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session-dbus.c
logind: fix build for ARM with sizeof(dev_t) > sizeof(void*)
[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 sd = hashmap_get(s->devices, &dev);
456 if (sd) {
457 /* We don't allow retrieving a device multiple times.
458 * The related ReleaseDevice call is not ref-counted.
459 * The caller should use dup() if it requires more than
460 * one fd (it would be functionally equivalent). */
461 return bus_send_error_reply(connection, message, &error, -EBUSY);
462 }
463
464 r = session_device_new(s, dev, &sd);
465 if (r < 0)
466 return bus_send_error_reply(connection, message, NULL, r);
467
468 reply = dbus_message_new_method_return(message);
469 if (!reply) {
470 session_device_free(sd);
471 goto oom;
472 }
473
474 paused = !sd->active;
475 b = dbus_message_append_args(
476 reply,
477 DBUS_TYPE_UNIX_FD, &sd->fd,
478 DBUS_TYPE_BOOLEAN, &paused,
479 DBUS_TYPE_INVALID);
480 if (!b) {
481 session_device_free(sd);
482 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
483 }
484
485 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "ReleaseDevice")) {
486 SessionDevice *sd;
487 uint32_t major, minor;
488 dev_t dev;
489
490 if (!session_is_controller(s, bus_message_get_sender_with_fallback(message)))
491 return bus_send_error_reply(connection, message, NULL, -EPERM);
492
493 if (!dbus_message_get_args(
494 message,
495 &error,
496 DBUS_TYPE_UINT32, &major,
497 DBUS_TYPE_UINT32, &minor,
498 DBUS_TYPE_INVALID))
499 return bus_send_error_reply(connection, message, &error, -EINVAL);
500
501 dev = makedev(major, minor);
502 sd = hashmap_get(s->devices, &dev);
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 dev_t dev;
516
517 if (!session_is_controller(s, bus_message_get_sender_with_fallback(message)))
518 return bus_send_error_reply(connection, message, NULL, -EPERM);
519
520 if (!dbus_message_get_args(
521 message,
522 &error,
523 DBUS_TYPE_UINT32, &major,
524 DBUS_TYPE_UINT32, &minor,
525 DBUS_TYPE_INVALID))
526 return bus_send_error_reply(connection, message, &error, -EINVAL);
527
528 dev = makedev(major, minor);
529 sd = hashmap_get(s->devices, &dev);
530 if (!sd)
531 return bus_send_error_reply(connection, message, NULL, -ENODEV);
532
533 session_device_complete_pause(sd);
534
535 reply = dbus_message_new_method_return(message);
536 if (!reply)
537 goto oom;
538
539 } else {
540 const BusBoundProperties bps[] = {
541 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
542 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
543 { NULL, }
544 };
545 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
546 }
547
548 if (reply) {
549 if (!bus_maybe_send_reply(connection, message, reply))
550 goto oom;
551 }
552
553 return DBUS_HANDLER_RESULT_HANDLED;
554
555 oom:
556 dbus_error_free(&error);
557
558 return DBUS_HANDLER_RESULT_NEED_MEMORY;
559 }
560
561 static DBusHandlerResult session_message_handler(
562 DBusConnection *connection,
563 DBusMessage *message,
564 void *userdata) {
565
566 Manager *m = userdata;
567 Session *s;
568 int r;
569
570 r = get_session_for_path(m, dbus_message_get_path(message), &s);
571 if (r < 0) {
572
573 if (r == -ENOMEM)
574 return DBUS_HANDLER_RESULT_NEED_MEMORY;
575
576 if (r == -ENOENT) {
577 DBusError e;
578
579 dbus_error_init(&e);
580 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
581 return bus_send_error_reply(connection, message, &e, r);
582 }
583
584 return bus_send_error_reply(connection, message, NULL, r);
585 }
586
587 return session_message_dispatch(s, connection, message);
588 }
589
590 const DBusObjectPathVTable bus_session_vtable = {
591 .message_function = session_message_handler
592 };
593
594 char *session_bus_path(Session *s) {
595 _cleanup_free_ char *t = NULL;
596
597 assert(s);
598
599 t = bus_path_escape(s->id);
600 if (!t)
601 return NULL;
602
603 return strappend("/org/freedesktop/login1/session/", t);
604 }
605
606 int session_send_signal(Session *s, bool new_session) {
607 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
608 _cleanup_free_ char *p = NULL;
609
610 assert(s);
611
612 m = dbus_message_new_signal("/org/freedesktop/login1",
613 "org.freedesktop.login1.Manager",
614 new_session ? "SessionNew" : "SessionRemoved");
615
616 if (!m)
617 return -ENOMEM;
618
619 p = session_bus_path(s);
620 if (!p)
621 return -ENOMEM;
622
623 if (!dbus_message_append_args(
624 m,
625 DBUS_TYPE_STRING, &s->id,
626 DBUS_TYPE_OBJECT_PATH, &p,
627 DBUS_TYPE_INVALID))
628 return -ENOMEM;
629
630 if (!dbus_connection_send(s->manager->bus, m, NULL))
631 return -ENOMEM;
632
633 return 0;
634 }
635
636 int session_send_changed(Session *s, const char *properties) {
637 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
638 _cleanup_free_ char *p = NULL;
639
640 assert(s);
641
642 if (!s->started)
643 return 0;
644
645 p = session_bus_path(s);
646 if (!p)
647 return -ENOMEM;
648
649 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
650 if (!m)
651 return -ENOMEM;
652
653 if (!dbus_connection_send(s->manager->bus, m, NULL))
654 return -ENOMEM;
655
656 return 0;
657 }
658
659 int session_send_lock(Session *s, bool lock) {
660 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
661 bool b;
662 _cleanup_free_ char *p = NULL;
663
664 assert(s);
665
666 p = session_bus_path(s);
667 if (!p)
668 return -ENOMEM;
669
670 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
671
672 if (!m)
673 return -ENOMEM;
674
675 b = dbus_connection_send(s->manager->bus, m, NULL);
676 if (!b)
677 return -ENOMEM;
678
679 return 0;
680 }
681
682 int session_send_lock_all(Manager *m, bool lock) {
683 Session *session;
684 Iterator i;
685 int r = 0;
686
687 assert(m);
688
689 HASHMAP_FOREACH(session, m->sessions, i) {
690 int k;
691
692 k = session_send_lock(session, lock);
693 if (k < 0)
694 r = k;
695 }
696
697 return r;
698 }
699
700 int session_send_create_reply(Session *s, DBusError *error) {
701 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
702
703 assert(s);
704
705 if (!s->create_message)
706 return 0;
707
708 /* This is called after the session scope was successfully
709 * created, and finishes where bus_manager_create_session()
710 * left off. */
711
712 if (error) {
713 DBusError buffer;
714
715 dbus_error_init(&buffer);
716
717 if (!dbus_error_is_set(error)) {
718 dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
719 error = &buffer;
720 }
721
722 reply = dbus_message_new_error(s->create_message, error->name, error->message);
723 dbus_error_free(&buffer);
724
725 if (!reply)
726 return log_oom();
727 } else {
728 _cleanup_close_ int fifo_fd = -1;
729 _cleanup_free_ char *path = NULL;
730 const char *cseat;
731 uint32_t vtnr;
732 dbus_bool_t exists;
733
734 fifo_fd = session_create_fifo(s);
735 if (fifo_fd < 0) {
736 log_error("Failed to create fifo: %s", strerror(-fifo_fd));
737 return fifo_fd;
738 }
739
740 path = session_bus_path(s);
741 if (!path)
742 return log_oom();
743
744 reply = dbus_message_new_method_return(s->create_message);
745 if (!reply)
746 return log_oom();
747
748 cseat = s->seat ? s->seat->id : "";
749 vtnr = s->vtnr;
750 exists = false;
751
752 if (!dbus_message_append_args(
753 reply,
754 DBUS_TYPE_STRING, &s->id,
755 DBUS_TYPE_OBJECT_PATH, &path,
756 DBUS_TYPE_STRING, &s->user->runtime_path,
757 DBUS_TYPE_UNIX_FD, &fifo_fd,
758 DBUS_TYPE_STRING, &cseat,
759 DBUS_TYPE_UINT32, &vtnr,
760 DBUS_TYPE_BOOLEAN, &exists,
761 DBUS_TYPE_INVALID))
762 return log_oom();
763 }
764
765 /* Update the state file before we notify the client about the
766 * result */
767 session_save(s);
768
769 if (!dbus_connection_send(s->manager->bus, reply, NULL))
770 return log_oom();
771
772 dbus_message_unref(s->create_message);
773 s->create_message = NULL;
774
775 return 0;
776 }