chiark / gitweb /
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[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 = TAKE_PTR(l);
670
671         return 1;
672 }
673
674 int session_send_signal(Session *s, bool new_session) {
675         _cleanup_free_ char *p = NULL;
676
677         assert(s);
678
679         p = session_bus_path(s);
680         if (!p)
681                 return -ENOMEM;
682
683         return sd_bus_emit_signal(
684                         s->manager->bus,
685                         "/org/freedesktop/login1",
686                         "org.freedesktop.login1.Manager",
687                         new_session ? "SessionNew" : "SessionRemoved",
688                         "so", s->id, p);
689 }
690
691 int session_send_changed(Session *s, const char *properties, ...) {
692         _cleanup_free_ char *p = NULL;
693         char **l;
694
695         assert(s);
696
697         if (!s->started)
698                 return 0;
699
700         p = session_bus_path(s);
701         if (!p)
702                 return -ENOMEM;
703
704         l = strv_from_stdarg_alloca(properties);
705
706         return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
707 }
708
709 int session_send_lock(Session *s, bool lock) {
710         _cleanup_free_ char *p = NULL;
711
712         assert(s);
713
714         p = session_bus_path(s);
715         if (!p)
716                 return -ENOMEM;
717
718         return sd_bus_emit_signal(
719                         s->manager->bus,
720                         p,
721                         "org.freedesktop.login1.Session",
722                         lock ? "Lock" : "Unlock",
723                         NULL);
724 }
725
726 int session_send_lock_all(Manager *m, bool lock) {
727         Session *session;
728         Iterator i;
729         int r = 0;
730
731         assert(m);
732
733         HASHMAP_FOREACH(session, m->sessions, i) {
734                 int k;
735
736                 k = session_send_lock(session, lock);
737                 if (k < 0)
738                         r = k;
739         }
740
741         return r;
742 }
743
744 int session_send_create_reply(Session *s, sd_bus_error *error) {
745         _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
746         _cleanup_close_ int fifo_fd = -1;
747         _cleanup_free_ char *p = NULL;
748
749         assert(s);
750
751         /* This is called after the session scope and the user service
752          * were successfully created, and finishes where
753          * bus_manager_create_session() left off. */
754
755         if (!s->create_message)
756                 return 0;
757
758 #if 0 /// elogind does not support scope and service jobs
759         if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job))
760                 return 0;
761 #endif // 0
762
763         c = s->create_message;
764         s->create_message = NULL;
765
766         if (error)
767                 return sd_bus_reply_method_error(c, error);
768
769         fifo_fd = session_create_fifo(s);
770         if (fifo_fd < 0)
771                 return fifo_fd;
772
773         /* Update the session state file before we notify the client
774          * about the result. */
775         session_save(s);
776
777 #if 1 /// Additionally elogind saves the user state file
778         user_save(s->user);
779 #endif // 1
780         p = session_bus_path(s);
781         if (!p)
782                 return -ENOMEM;
783
784         log_debug("Sending reply about created session: "
785                   "id=%s object_path=%s uid=%u runtime_path=%s "
786                   "session_fd=%d seat=%s vtnr=%u",
787                   s->id,
788                   p,
789                   (uint32_t) s->user->uid,
790                   s->user->runtime_path,
791                   fifo_fd,
792                   s->seat ? s->seat->id : "",
793                   (uint32_t) s->vtnr);
794
795         return sd_bus_reply_method_return(
796                         c, "soshusub",
797                         s->id,
798                         p,
799                         s->user->runtime_path,
800                         fifo_fd,
801                         (uint32_t) s->user->uid,
802                         s->seat ? s->seat->id : "",
803                         (uint32_t) s->vtnr,
804                         false);
805 }