chiark / gitweb /
Prep v236 : Add missing SPDX-License-Identifier (5/9) src/login
[elogind.git] / src / login / logind-session-dbus.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2011 Lennart Poettering
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <string.h>
23
24 #include "alloc-util.h"
25 #include "bus-common-errors.h"
26 #include "bus-label.h"
27 #include "bus-util.h"
28 #include "fd-util.h"
29 #include "logind-session-device.h"
30 #include "logind-session.h"
31 #include "logind.h"
32 #include "signal-util.h"
33 #include "strv.h"
34 #include "util.h"
35
36 static int property_get_user(
37                 sd_bus *bus,
38                 const char *path,
39                 const char *interface,
40                 const char *property,
41                 sd_bus_message *reply,
42                 void *userdata,
43                 sd_bus_error *error) {
44
45         _cleanup_free_ char *p = NULL;
46         Session *s = userdata;
47
48         assert(bus);
49         assert(reply);
50         assert(s);
51
52         p = user_bus_path(s->user);
53         if (!p)
54                 return -ENOMEM;
55
56         return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->uid, p);
57 }
58
59 static int property_get_name(
60                 sd_bus *bus,
61                 const char *path,
62                 const char *interface,
63                 const char *property,
64                 sd_bus_message *reply,
65                 void *userdata,
66                 sd_bus_error *error) {
67
68         Session *s = userdata;
69
70         assert(bus);
71         assert(reply);
72         assert(s);
73
74         return sd_bus_message_append(reply, "s", s->user->name);
75 }
76
77 static int property_get_seat(
78                 sd_bus *bus,
79                 const char *path,
80                 const char *interface,
81                 const char *property,
82                 sd_bus_message *reply,
83                 void *userdata,
84                 sd_bus_error *error) {
85
86         _cleanup_free_ char *p = NULL;
87         Session *s = userdata;
88
89         assert(bus);
90         assert(reply);
91         assert(s);
92
93         p = s->seat ? seat_bus_path(s->seat) : strdup("/");
94         if (!p)
95                 return -ENOMEM;
96
97         return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
98 }
99
100 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
101 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
102
103 static int property_get_active(
104                 sd_bus *bus,
105                 const char *path,
106                 const char *interface,
107                 const char *property,
108                 sd_bus_message *reply,
109                 void *userdata,
110                 sd_bus_error *error) {
111
112         Session *s = userdata;
113
114         assert(bus);
115         assert(reply);
116         assert(s);
117
118         return sd_bus_message_append(reply, "b", session_is_active(s));
119 }
120
121 static int property_get_state(
122                 sd_bus *bus,
123                 const char *path,
124                 const char *interface,
125                 const char *property,
126                 sd_bus_message *reply,
127                 void *userdata,
128                 sd_bus_error *error) {
129
130         Session *s = userdata;
131
132         assert(bus);
133         assert(reply);
134         assert(s);
135
136         return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s)));
137 }
138
139 static int property_get_idle_hint(
140                 sd_bus *bus,
141                 const char *path,
142                 const char *interface,
143                 const char *property,
144                 sd_bus_message *reply,
145                 void *userdata,
146                 sd_bus_error *error) {
147
148         Session *s = userdata;
149
150         assert(bus);
151         assert(reply);
152         assert(s);
153
154         return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
155 }
156
157 static int property_get_idle_since_hint(
158                 sd_bus *bus,
159                 const char *path,
160                 const char *interface,
161                 const char *property,
162                 sd_bus_message *reply,
163                 void *userdata,
164                 sd_bus_error *error) {
165
166         Session *s = userdata;
167         dual_timestamp t = DUAL_TIMESTAMP_NULL;
168         uint64_t u;
169         int r;
170
171         assert(bus);
172         assert(reply);
173         assert(s);
174
175         r = session_get_idle_hint(s, &t);
176         if (r < 0)
177                 return r;
178
179         u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
180
181         return sd_bus_message_append(reply, "t", u);
182 }
183
184 static int property_get_locked_hint(
185                 sd_bus *bus,
186                 const char *path,
187                 const char *interface,
188                 const char *property,
189                 sd_bus_message *reply,
190                 void *userdata,
191                 sd_bus_error *error) {
192
193         Session *s = userdata;
194
195         assert(bus);
196         assert(reply);
197         assert(s);
198
199         return sd_bus_message_append(reply, "b", session_get_locked_hint(s) > 0);
200 }
201
202 int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
203         Session *s = userdata;
204         int r;
205
206         assert(message);
207         assert(s);
208
209         r = bus_verify_polkit_async(
210                         message,
211                         CAP_KILL,
212                         "org.freedesktop.login1.manage",
213                         NULL,
214                         false,
215                         s->user->uid,
216                         &s->manager->polkit_registry,
217                         error);
218         if (r < 0)
219                 return r;
220         if (r == 0)
221                 return 1; /* Will call us back */
222
223         r = session_stop(s, true);
224         if (r < 0)
225                 return r;
226
227         return sd_bus_reply_method_return(message, NULL);
228 }
229
230 int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
231         Session *s = userdata;
232         int r;
233
234         assert(message);
235         assert(s);
236
237         r = session_activate(s);
238         if (r < 0)
239                 return r;
240
241         return sd_bus_reply_method_return(message, NULL);
242 }
243
244 int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error) {
245         Session *s = userdata;
246         int r;
247
248         assert(message);
249         assert(s);
250
251         r = bus_verify_polkit_async(
252                         message,
253                         CAP_SYS_ADMIN,
254                         "org.freedesktop.login1.lock-sessions",
255                         NULL,
256                         false,
257                         s->user->uid,
258                         &s->manager->polkit_registry,
259                         error);
260         if (r < 0)
261                 return r;
262         if (r == 0)
263                 return 1; /* Will call us back */
264
265         r = session_send_lock(s, strstr(sd_bus_message_get_member(message), "Lock"));
266         if (r < 0)
267                 return r;
268
269         return sd_bus_reply_method_return(message, NULL);
270 }
271
272 static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
273         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
274         Session *s = userdata;
275         uid_t uid;
276         int r, b;
277
278         assert(message);
279         assert(s);
280
281         r = sd_bus_message_read(message, "b", &b);
282         if (r < 0)
283                 return r;
284
285         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
286         if (r < 0)
287                 return r;
288
289         r = sd_bus_creds_get_euid(creds, &uid);
290         if (r < 0)
291                 return r;
292
293         if (uid != 0 && uid != s->user->uid)
294                 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
295
296         session_set_idle_hint(s, b);
297
298         return sd_bus_reply_method_return(message, NULL);
299 }
300
301 static int method_set_locked_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
302         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
303         Session *s = userdata;
304         uid_t uid;
305         int r, b;
306
307         assert(message);
308         assert(s);
309
310         r = sd_bus_message_read(message, "b", &b);
311         if (r < 0)
312                 return r;
313
314         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
315         if (r < 0)
316                 return r;
317
318         r = sd_bus_creds_get_euid(creds, &uid);
319         if (r < 0)
320                 return r;
321
322         if (uid != 0 && uid != s->user->uid)
323                 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint");
324
325         session_set_locked_hint(s, b);
326
327         return sd_bus_reply_method_return(message, NULL);
328 }
329
330 int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
331         Session *s = userdata;
332         const char *swho;
333         int32_t signo;
334         KillWho who;
335         int r;
336
337         assert(message);
338         assert(s);
339
340         r = sd_bus_message_read(message, "si", &swho, &signo);
341         if (r < 0)
342                 return r;
343
344         if (isempty(swho))
345                 who = KILL_ALL;
346         else {
347                 who = kill_who_from_string(swho);
348                 if (who < 0)
349                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
350         }
351
352         if (!SIGNAL_VALID(signo))
353                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
354
355         r = bus_verify_polkit_async(
356                         message,
357                         CAP_KILL,
358                         "org.freedesktop.login1.manage",
359                         NULL,
360                         false,
361                         s->user->uid,
362                         &s->manager->polkit_registry,
363                         error);
364         if (r < 0)
365                 return r;
366         if (r == 0)
367                 return 1; /* Will call us back */
368
369         r = session_kill(s, who, signo);
370         if (r < 0)
371                 return r;
372
373         return sd_bus_reply_method_return(message, NULL);
374 }
375
376 static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
377         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
378         Session *s = userdata;
379         int r, force;
380         uid_t uid;
381
382         assert(message);
383         assert(s);
384
385         r = sd_bus_message_read(message, "b", &force);
386         if (r < 0)
387                 return r;
388
389         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
390         if (r < 0)
391                 return r;
392
393         r = sd_bus_creds_get_euid(creds, &uid);
394         if (r < 0)
395                 return r;
396
397         if (uid != 0 && (force || uid != s->user->uid))
398                 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
399
400         r = session_set_controller(s, sd_bus_message_get_sender(message), force, true);
401         if (r < 0)
402                 return r;
403
404         return sd_bus_reply_method_return(message, NULL);
405 }
406
407 static int method_release_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
408         Session *s = userdata;
409
410         assert(message);
411         assert(s);
412
413         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
414                 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
415
416         session_drop_controller(s);
417
418         return sd_bus_reply_method_return(message, NULL);
419 }
420
421 static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
422         Session *s = userdata;
423         uint32_t major, minor;
424         SessionDevice *sd;
425         dev_t dev;
426         int r;
427
428         assert(message);
429         assert(s);
430
431         r = sd_bus_message_read(message, "uu", &major, &minor);
432         if (r < 0)
433                 return r;
434
435         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
436                 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
437
438         dev = makedev(major, minor);
439         sd = hashmap_get(s->devices, &dev);
440         if (sd)
441                 /* We don't allow retrieving a device multiple times.
442                  * The related ReleaseDevice call is not ref-counted.
443                  * The caller should use dup() if it requires more
444                  * than one fd (it would be functionally
445                  * equivalent). */
446                 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
447
448         r = session_device_new(s, dev, true, &sd);
449         if (r < 0)
450                 return r;
451
452         r = session_device_save(sd);
453         if (r < 0)
454                 goto error;
455
456         r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
457         if (r < 0)
458                 goto error;
459
460         session_save(s);
461         return 1;
462
463 error:
464         session_device_free(sd);
465         return r;
466 }
467
468 static int method_release_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
469         Session *s = userdata;
470         uint32_t major, minor;
471         SessionDevice *sd;
472         dev_t dev;
473         int r;
474
475         assert(message);
476         assert(s);
477
478         r = sd_bus_message_read(message, "uu", &major, &minor);
479         if (r < 0)
480                 return r;
481
482         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
483                 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
484
485         dev = makedev(major, minor);
486         sd = hashmap_get(s->devices, &dev);
487         if (!sd)
488                 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
489
490         session_device_free(sd);
491         session_save(s);
492
493         return sd_bus_reply_method_return(message, NULL);
494 }
495
496 static int method_pause_device_complete(sd_bus_message *message, void *userdata, sd_bus_error *error) {
497         Session *s = userdata;
498         uint32_t major, minor;
499         SessionDevice *sd;
500         dev_t dev;
501         int r;
502
503         assert(message);
504         assert(s);
505
506         r = sd_bus_message_read(message, "uu", &major, &minor);
507         if (r < 0)
508                 return r;
509
510         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
511                 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
512
513         dev = makedev(major, minor);
514         sd = hashmap_get(s->devices, &dev);
515         if (!sd)
516                 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
517
518         session_device_complete_pause(sd);
519
520         return sd_bus_reply_method_return(message, NULL);
521 }
522
523 const sd_bus_vtable session_vtable[] = {
524         SD_BUS_VTABLE_START(0),
525
526         SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
527         SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
528         SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
529         BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
530         SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
531         SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
532         SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
533         SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
534         SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
535         SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
536         SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
537         SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
538         SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
539         SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
540         SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
541         SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
542         SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
543         SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
544         SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
545         SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
546         SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
547         SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
548         SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
549         SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
550
551         SD_BUS_METHOD("Terminate", NULL, NULL, bus_session_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
552         SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
553         SD_BUS_METHOD("Lock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
554         SD_BUS_METHOD("Unlock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
555         SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
556         SD_BUS_METHOD("SetLockedHint", "b", NULL, method_set_locked_hint, SD_BUS_VTABLE_UNPRIVILEGED),
557         SD_BUS_METHOD("Kill", "si", NULL, bus_session_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
558         SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
559         SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
560         SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
561         SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED),
562         SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED),
563
564         SD_BUS_SIGNAL("PauseDevice", "uus", 0),
565         SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
566         SD_BUS_SIGNAL("Lock", NULL, 0),
567         SD_BUS_SIGNAL("Unlock", NULL, 0),
568
569         SD_BUS_VTABLE_END
570 };
571
572 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
573         Manager *m = userdata;
574         Session *session;
575         int r;
576
577         assert(bus);
578         assert(path);
579         assert(interface);
580         assert(found);
581         assert(m);
582
583         if (streq(path, "/org/freedesktop/login1/session/self")) {
584                 sd_bus_message *message;
585
586                 message = sd_bus_get_current_message(bus);
587                 if (!message)
588                         return 0;
589
590                 r = manager_get_session_from_creds(m, message, NULL, error, &session);
591                 if (r < 0)
592                         return r;
593         } else {
594                 _cleanup_free_ char *e = NULL;
595                 const char *p;
596
597                 p = startswith(path, "/org/freedesktop/login1/session/");
598                 if (!p)
599                         return 0;
600
601                 e = bus_label_unescape(p);
602                 if (!e)
603                         return -ENOMEM;
604
605                 session = hashmap_get(m->sessions, e);
606                 if (!session)
607                         return 0;
608         }
609
610         *found = session;
611         return 1;
612 }
613
614 char *session_bus_path(Session *s) {
615         _cleanup_free_ char *t = NULL;
616
617         assert(s);
618
619         t = bus_label_escape(s->id);
620         if (!t)
621                 return NULL;
622
623         return strappend("/org/freedesktop/login1/session/", t);
624 }
625
626 int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
627         _cleanup_strv_free_ char **l = NULL;
628         sd_bus_message *message;
629         Manager *m = userdata;
630         Session *session;
631         Iterator i;
632         int r;
633
634         assert(bus);
635         assert(path);
636         assert(nodes);
637
638         HASHMAP_FOREACH(session, m->sessions, i) {
639                 char *p;
640
641                 p = session_bus_path(session);
642                 if (!p)
643                         return -ENOMEM;
644
645                 r = strv_consume(&l, p);
646                 if (r < 0)
647                         return r;
648         }
649
650         message = sd_bus_get_current_message(bus);
651         if (message) {
652                 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
653                 const char *name;
654
655                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
656                 if (r >= 0) {
657                         r = sd_bus_creds_get_session(creds, &name);
658                         if (r >= 0) {
659                                 session = hashmap_get(m->sessions, name);
660                                 if (session) {
661                                         r = strv_extend(&l, "/org/freedesktop/login1/session/self");
662                                         if (r < 0)
663                                                 return r;
664                                 }
665                         }
666                 }
667         }
668
669         *nodes = l;
670         l = NULL;
671
672         return 1;
673 }
674
675 int session_send_signal(Session *s, bool new_session) {
676         _cleanup_free_ char *p = NULL;
677
678         assert(s);
679
680         p = session_bus_path(s);
681         if (!p)
682                 return -ENOMEM;
683
684         return sd_bus_emit_signal(
685                         s->manager->bus,
686                         "/org/freedesktop/login1",
687                         "org.freedesktop.login1.Manager",
688                         new_session ? "SessionNew" : "SessionRemoved",
689                         "so", s->id, p);
690 }
691
692 int session_send_changed(Session *s, const char *properties, ...) {
693         _cleanup_free_ char *p = NULL;
694         char **l;
695
696         assert(s);
697
698         if (!s->started)
699                 return 0;
700
701         p = session_bus_path(s);
702         if (!p)
703                 return -ENOMEM;
704
705         l = strv_from_stdarg_alloca(properties);
706
707         return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
708 }
709
710 int session_send_lock(Session *s, bool lock) {
711         _cleanup_free_ char *p = NULL;
712
713         assert(s);
714
715         p = session_bus_path(s);
716         if (!p)
717                 return -ENOMEM;
718
719         return sd_bus_emit_signal(
720                         s->manager->bus,
721                         p,
722                         "org.freedesktop.login1.Session",
723                         lock ? "Lock" : "Unlock",
724                         NULL);
725 }
726
727 int session_send_lock_all(Manager *m, bool lock) {
728         Session *session;
729         Iterator i;
730         int r = 0;
731
732         assert(m);
733
734         HASHMAP_FOREACH(session, m->sessions, i) {
735                 int k;
736
737                 k = session_send_lock(session, lock);
738                 if (k < 0)
739                         r = k;
740         }
741
742         return r;
743 }
744
745 int session_send_create_reply(Session *s, sd_bus_error *error) {
746         _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
747         _cleanup_close_ int fifo_fd = -1;
748         _cleanup_free_ char *p = NULL;
749
750         assert(s);
751
752         /* This is called after the session scope and the user service
753          * were successfully created, and finishes where
754          * bus_manager_create_session() left off. */
755
756         if (!s->create_message)
757                 return 0;
758
759 #if 0 /// elogind does not support scope and service jobs
760         if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job))
761                 return 0;
762 #endif // 0
763
764         c = s->create_message;
765         s->create_message = NULL;
766
767         if (error)
768                 return sd_bus_reply_method_error(c, error);
769
770         fifo_fd = session_create_fifo(s);
771         if (fifo_fd < 0)
772                 return fifo_fd;
773
774         /* Update the session state file before we notify the client
775          * about the result. */
776         session_save(s);
777
778 #if 1 /// Additionally elogind saves the user state file
779         user_save(s->user);
780 #endif // 1
781         p = session_bus_path(s);
782         if (!p)
783                 return -ENOMEM;
784
785         log_debug("Sending reply about created session: "
786                   "id=%s object_path=%s uid=%u runtime_path=%s "
787                   "session_fd=%d seat=%s vtnr=%u",
788                   s->id,
789                   p,
790                   (uint32_t) s->user->uid,
791                   s->user->runtime_path,
792                   fifo_fd,
793                   s->seat ? s->seat->id : "",
794                   (uint32_t) s->vtnr);
795
796         return sd_bus_reply_method_return(
797                         c, "soshusub",
798                         s->id,
799                         p,
800                         s->user->runtime_path,
801                         fifo_fd,
802                         (uint32_t) s->user->uid,
803                         s->seat ? s->seat->id : "",
804                         (uint32_t) s->vtnr,
805                         false);
806 }