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