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