~ubuntu-branches/debian/jessie/systemd/jessie

« back to all changes in this revision

Viewing changes to src/login/logind-dbus.c

  • Committer: Package Import Robot
  • Author(s): Tollef Fog Heen, Tollef Fog Heen, Michael Biebl
  • Date: 2012-04-03 19:59:17 UTC
  • mfrom: (1.1.10) (6.1.3 experimental)
  • Revision ID: package-import@ubuntu.com-20120403195917-l532urrbg4pkreas
Tags: 44-1
[ Tollef Fog Heen ]
* New upstream version.
  - Backport 3492207: journal: PAGE_SIZE is not known on ppc and other
    archs
  - Backport 5a2a2a1: journal: react with immediate rotation to a couple
    of more errors
  - Backport 693ce21: util: never follow symlinks in rm_rf_children()
    Fixes CVE-2012-1174, closes: #664364
* Drop output message from init-functions hook, it's pointless.
* Only rmdir /lib/init/rw if it exists.
* Explicitly order debian-fixup before sysinit.target to prevent a
  possible race condition with the creation of sockets.  Thanks to
  Michael Biebl for debugging this.
* Always restart the initctl socket on upgrades, to mask sysvinit
  removing it.

[ Michael Biebl ]
* Remove workaround for non-interactive sessions from pam config again.
* Create compat /dev/initctl symlink in case we are upgrading from a system
  running a newer version of sysvinit (using /run/initctl) and sysvinit is
  replaced with systemd-sysv during the upgrade. Closes: #663219
* Install new man pages.
* Build-Depend on valac (>= 0.12) instead of valac-0.12. Closes: #663323

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 General Public License as published by
 
10
  the Free Software Foundation; either version 2 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
  General Public License for more details.
 
17
 
 
18
  You should have received a copy of the GNU 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
#include <unistd.h>
 
25
#include <pwd.h>
 
26
 
 
27
#include "logind.h"
 
28
#include "dbus-common.h"
 
29
#include "strv.h"
 
30
#include "polkit.h"
 
31
#include "special.h"
 
32
 
 
33
#define BUS_MANAGER_INTERFACE                                           \
 
34
        " <interface name=\"org.freedesktop.login1.Manager\">\n"        \
 
35
        "  <method name=\"GetSession\">\n"                              \
 
36
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
37
        "   <arg name=\"session\" type=\"o\" direction=\"out\"/>\n"     \
 
38
        "  </method>\n"                                                 \
 
39
        "  <method name=\"GetSessionByPID\">\n"                         \
 
40
        "   <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n"          \
 
41
        "   <arg name=\"session\" type=\"o\" direction=\"out\"/>\n"     \
 
42
        "  </method>\n"                                                 \
 
43
        "  <method name=\"GetUser\">\n"                                 \
 
44
        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
 
45
        "   <arg name=\"user\" type=\"o\" direction=\"out\"/>\n"        \
 
46
        "  </method>\n"                                                 \
 
47
        "  <method name=\"GetSeat\">\n"                                 \
 
48
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
49
        "   <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n"        \
 
50
        "  </method>\n"                                                 \
 
51
        "  <method name=\"ListSessions\">\n"                            \
 
52
        "   <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
 
53
        "  </method>\n"                                                 \
 
54
        "  <method name=\"ListUsers\">\n"                               \
 
55
        "   <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n"  \
 
56
        "  </method>\n"                                                 \
 
57
        "  <method name=\"ListSeats\">\n"                               \
 
58
        "   <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n"   \
 
59
        "  </method>\n"                                                 \
 
60
        "  <method name=\"CreateSession\">\n"                           \
 
61
        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
 
62
        "   <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n"       \
 
63
        "   <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n"       \
 
64
        "   <arg name=\"type\" type=\"s\" direction=\"in\"/>\n"         \
 
65
        "   <arg name=\"class\" type=\"s\" direction=\"in\"/>\n"        \
 
66
        "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n"         \
 
67
        "   <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n"         \
 
68
        "   <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n"          \
 
69
        "   <arg name=\"display\" type=\"s\" direction=\"in\"/>\n"      \
 
70
        "   <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n"       \
 
71
        "   <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n"  \
 
72
        "   <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n"  \
 
73
        "   <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
 
74
        "   <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
 
75
        "   <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
 
76
        "   <arg name=\"id\" type=\"s\" direction=\"out\"/>\n"          \
 
77
        "   <arg name=\"path\" type=\"o\" direction=\"out\"/>\n"        \
 
78
        "   <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
 
79
        "   <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n"          \
 
80
        "   <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n"        \
 
81
        "   <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n"        \
 
82
        "  </method>\n"                                                 \
 
83
        "  <method name=\"ActivateSession\">\n"                         \
 
84
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
85
        "  </method>\n"                                                 \
 
86
        "  <method name=\"ActivateSessionOnSeat\">\n"                   \
 
87
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
88
        "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n"         \
 
89
        "  </method>\n"                                                 \
 
90
        "  <method name=\"LockSession\">\n"                             \
 
91
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
92
        "  </method>\n"                                                 \
 
93
        "  <method name=\"UnlockSession\">\n"                           \
 
94
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
95
        "  </method>\n"                                                 \
 
96
        "  <method name=\"KillSession\">\n"                             \
 
97
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
98
        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
 
99
        "   <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n"       \
 
100
        "  </method>\n"                                                 \
 
101
        "  <method name=\"KillUser\">\n"                                \
 
102
        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
 
103
        "   <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n"       \
 
104
        "  </method>\n"                                                 \
 
105
        "  <method name=\"TerminateSession\">\n"                        \
 
106
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
107
        "  </method>\n"                                                 \
 
108
        "  <method name=\"TerminateUser\">\n"                           \
 
109
        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
 
110
        "  </method>\n"                                                 \
 
111
        "  <method name=\"TerminateSeat\">\n"                           \
 
112
        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
 
113
        "  </method>\n"                                                 \
 
114
        "  <method name=\"SetUserLinger\">\n"                           \
 
115
        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
 
116
        "   <arg name=\"b\" type=\"b\" direction=\"in\"/>\n"            \
 
117
        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
 
118
        "  </method>\n"                                                 \
 
119
        "  <method name=\"AttachDevice\">\n"                            \
 
120
        "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n"         \
 
121
        "   <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n"        \
 
122
        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
 
123
        "  </method>\n"                                                 \
 
124
        "  <method name=\"FlushDevices\">\n"                            \
 
125
        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
 
126
        "  </method>\n"                                                 \
 
127
        "  <method name=\"PowerOff\">\n"                                \
 
128
        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
 
129
        "  </method>\n"                                                 \
 
130
        "  <method name=\"Reboot\">\n"                                  \
 
131
        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
 
132
        "  </method>\n"                                                 \
 
133
        "  <method name=\"CanPowerOff\">\n"                             \
 
134
        "   <arg name=\"result\" type=\"s\" direction=\"out\"/>\n"      \
 
135
        "  </method>\n"                                                 \
 
136
        "  <method name=\"CanReboot\">\n"                               \
 
137
        "   <arg name=\"result\" type=\"s\" direction=\"out\"/>\n"      \
 
138
        "  </method>\n"                                                 \
 
139
        "  <signal name=\"SessionNew\">\n"                              \
 
140
        "   <arg name=\"id\" type=\"s\"/>\n"                            \
 
141
        "   <arg name=\"path\" type=\"o\"/>\n"                          \
 
142
        "  </signal>\n"                                                 \
 
143
        "  <signal name=\"SessionRemoved\">\n"                          \
 
144
        "   <arg name=\"id\" type=\"s\"/>\n"                            \
 
145
        "   <arg name=\"path\" type=\"o\"/>\n"                          \
 
146
        "  </signal>\n"                                                 \
 
147
        "  <signal name=\"UserNew\">\n"                                 \
 
148
        "   <arg name=\"uid\" type=\"u\"/>\n"                           \
 
149
        "   <arg name=\"path\" type=\"o\"/>\n"                          \
 
150
        "  </signal>\n"                                                 \
 
151
        "  <signal name=\"UserRemoved\">\n"                             \
 
152
        "   <arg name=\"uid\" type=\"u\"/>\n"                           \
 
153
        "   <arg name=\"path\" type=\"o\"/>\n"                          \
 
154
        "  </signal>\n"                                                 \
 
155
        "  <signal name=\"SeatNew\">\n"                                 \
 
156
        "   <arg name=\"id\" type=\"s\"/>\n"                            \
 
157
        "   <arg name=\"path\" type=\"o\"/>\n"                          \
 
158
        "  </signal>\n"                                                 \
 
159
        "  <signal name=\"SeatRemoved\">\n"                             \
 
160
        "   <arg name=\"id\" type=\"s\"/>\n"                            \
 
161
        "   <arg name=\"path\" type=\"o\"/>\n"                          \
 
162
        "  </signal>\n"                                                 \
 
163
        "  <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
 
164
        "  <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
 
165
        "  <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
 
166
        "  <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
 
167
        "  <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
 
168
        "  <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
 
169
        "  <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
 
170
        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
 
171
        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
 
172
        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
 
173
        " </interface>\n"
 
174
 
 
175
#define INTROSPECTION_BEGIN                                             \
 
176
        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
 
177
        "<node>\n"                                                      \
 
178
        BUS_MANAGER_INTERFACE                                           \
 
179
        BUS_PROPERTIES_INTERFACE                                        \
 
180
        BUS_PEER_INTERFACE                                              \
 
181
        BUS_INTROSPECTABLE_INTERFACE
 
182
 
 
183
#define INTROSPECTION_END                                               \
 
184
        "</node>\n"
 
185
 
 
186
#define INTERFACES_LIST                              \
 
187
        BUS_GENERIC_INTERFACES_LIST                  \
 
188
        "org.freedesktop.login1.Manager\0"
 
189
 
 
190
static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
 
191
        Manager *m = data;
 
192
        dbus_bool_t b;
 
193
 
 
194
        assert(i);
 
195
        assert(property);
 
196
        assert(m);
 
197
 
 
198
        b = manager_get_idle_hint(m, NULL) > 0;
 
199
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
 
200
                return -ENOMEM;
 
201
 
 
202
        return 0;
 
203
}
 
204
 
 
205
static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
 
206
        Manager *m = data;
 
207
        dual_timestamp t;
 
208
        uint64_t u;
 
209
 
 
210
        assert(i);
 
211
        assert(property);
 
212
        assert(m);
 
213
 
 
214
        manager_get_idle_hint(m, &t);
 
215
        u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
 
216
 
 
217
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
 
218
                return -ENOMEM;
 
219
 
 
220
        return 0;
 
221
}
 
222
 
 
223
static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
 
224
        Session *session = NULL;
 
225
        User *user = NULL;
 
226
        const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
 
227
        uint32_t uid, leader, audit_id = 0;
 
228
        dbus_bool_t remote, kill_processes;
 
229
        char **controllers = NULL, **reset_controllers = NULL;
 
230
        SessionType t;
 
231
        SessionClass c;
 
232
        Seat *s;
 
233
        DBusMessageIter iter;
 
234
        int r;
 
235
        char *id = NULL, *p;
 
236
        uint32_t vtnr = 0;
 
237
        int fifo_fd = -1;
 
238
        DBusMessage *reply = NULL;
 
239
        bool b;
 
240
 
 
241
        assert(m);
 
242
        assert(message);
 
243
        assert(_reply);
 
244
 
 
245
        if (!dbus_message_iter_init(message, &iter) ||
 
246
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
 
247
                return -EINVAL;
 
248
 
 
249
        dbus_message_iter_get_basic(&iter, &uid);
 
250
 
 
251
        if (!dbus_message_iter_next(&iter) ||
 
252
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
 
253
                return -EINVAL;
 
254
 
 
255
        dbus_message_iter_get_basic(&iter, &leader);
 
256
 
 
257
        if (leader <= 0 ||
 
258
            !dbus_message_iter_next(&iter) ||
 
259
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
260
                return -EINVAL;
 
261
 
 
262
        dbus_message_iter_get_basic(&iter, &service);
 
263
 
 
264
        if (!dbus_message_iter_next(&iter) ||
 
265
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
266
                return -EINVAL;
 
267
 
 
268
        dbus_message_iter_get_basic(&iter, &type);
 
269
        t = session_type_from_string(type);
 
270
 
 
271
        if (t < 0 ||
 
272
            !dbus_message_iter_next(&iter) ||
 
273
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
274
                return -EINVAL;
 
275
 
 
276
        dbus_message_iter_get_basic(&iter, &class);
 
277
        if (isempty(class))
 
278
                c = SESSION_USER;
 
279
        else
 
280
                c = session_class_from_string(class);
 
281
 
 
282
        if (c < 0 ||
 
283
            !dbus_message_iter_next(&iter) ||
 
284
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
285
                return -EINVAL;
 
286
 
 
287
        dbus_message_iter_get_basic(&iter, &seat);
 
288
 
 
289
        if (isempty(seat))
 
290
                s = NULL;
 
291
        else {
 
292
                s = hashmap_get(m->seats, seat);
 
293
                if (!s)
 
294
                        return -ENOENT;
 
295
        }
 
296
 
 
297
        if (!dbus_message_iter_next(&iter) ||
 
298
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
 
299
                return -EINVAL;
 
300
 
 
301
        dbus_message_iter_get_basic(&iter, &vtnr);
 
302
 
 
303
        if (!dbus_message_iter_next(&iter) ||
 
304
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
305
                return -EINVAL;
 
306
 
 
307
        dbus_message_iter_get_basic(&iter, &tty);
 
308
 
 
309
        if (tty_is_vc(tty)) {
 
310
                int v;
 
311
 
 
312
                if (!s)
 
313
                        s = m->vtconsole;
 
314
                else if (s != m->vtconsole)
 
315
                        return -EINVAL;
 
316
 
 
317
                v = vtnr_from_tty(tty);
 
318
 
 
319
                if (v <= 0)
 
320
                        return v < 0 ? v : -EINVAL;
 
321
 
 
322
                if (vtnr <= 0)
 
323
                        vtnr = (uint32_t) v;
 
324
                else if (vtnr != (uint32_t) v)
 
325
                        return -EINVAL;
 
326
 
 
327
        } else if (!isempty(tty) && s && seat_is_vtconsole(s))
 
328
                return -EINVAL;
 
329
 
 
330
        if (s) {
 
331
                if (seat_can_multi_session(s)) {
 
332
                        if (vtnr <= 0 || vtnr > 63)
 
333
                                return -EINVAL;
 
334
                } else {
 
335
                        if (vtnr > 0)
 
336
                                return -EINVAL;
 
337
                }
 
338
        }
 
339
 
 
340
        if (!dbus_message_iter_next(&iter) ||
 
341
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
342
                return -EINVAL;
 
343
 
 
344
        dbus_message_iter_get_basic(&iter, &display);
 
345
 
 
346
        if (!dbus_message_iter_next(&iter) ||
 
347
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
 
348
                return -EINVAL;
 
349
 
 
350
        dbus_message_iter_get_basic(&iter, &remote);
 
351
 
 
352
        if (!dbus_message_iter_next(&iter) ||
 
353
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
354
                return -EINVAL;
 
355
 
 
356
        dbus_message_iter_get_basic(&iter, &remote_user);
 
357
 
 
358
        if (!dbus_message_iter_next(&iter) ||
 
359
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
360
                return -EINVAL;
 
361
 
 
362
        dbus_message_iter_get_basic(&iter, &remote_host);
 
363
 
 
364
        if (!dbus_message_iter_next(&iter) ||
 
365
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
366
            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
 
367
                return -EINVAL;
 
368
 
 
369
        r = bus_parse_strv_iter(&iter, &controllers);
 
370
        if (r < 0)
 
371
                return -EINVAL;
 
372
 
 
373
        if (strv_contains(controllers, "systemd") ||
 
374
            !dbus_message_iter_next(&iter) ||
 
375
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
376
            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
 
377
                r = -EINVAL;
 
378
                goto fail;
 
379
        }
 
380
 
 
381
        r = bus_parse_strv_iter(&iter, &reset_controllers);
 
382
        if (r < 0)
 
383
                goto fail;
 
384
 
 
385
        if (strv_contains(reset_controllers, "systemd") ||
 
386
            !dbus_message_iter_next(&iter) ||
 
387
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
 
388
                r = -EINVAL;
 
389
                goto fail;
 
390
        }
 
391
 
 
392
        dbus_message_iter_get_basic(&iter, &kill_processes);
 
393
 
 
394
        r = manager_add_user_by_uid(m, uid, &user);
 
395
        if (r < 0)
 
396
                goto fail;
 
397
 
 
398
        audit_session_from_pid(leader, &audit_id);
 
399
 
 
400
        if (audit_id > 0) {
 
401
                asprintf(&id, "%lu", (unsigned long) audit_id);
 
402
 
 
403
                if (!id) {
 
404
                        r = -ENOMEM;
 
405
                        goto fail;
 
406
                }
 
407
 
 
408
                session = hashmap_get(m->sessions, id);
 
409
 
 
410
                if (session) {
 
411
                        free(id);
 
412
 
 
413
                        fifo_fd = session_create_fifo(session);
 
414
                        if (fifo_fd < 0) {
 
415
                                r = fifo_fd;
 
416
                                goto fail;
 
417
                        }
 
418
 
 
419
                        /* Session already exists, client is probably
 
420
                         * something like "su" which changes uid but
 
421
                         * is still the same audit session */
 
422
 
 
423
                        reply = dbus_message_new_method_return(message);
 
424
                        if (!reply) {
 
425
                                r = -ENOMEM;
 
426
                                goto fail;
 
427
                        }
 
428
 
 
429
                        p = session_bus_path(session);
 
430
                        if (!p) {
 
431
                                r = -ENOMEM;
 
432
                                goto fail;
 
433
                        }
 
434
 
 
435
                        seat = session->seat ? session->seat->id : "";
 
436
                        vtnr = session->vtnr;
 
437
                        b = dbus_message_append_args(
 
438
                                        reply,
 
439
                                        DBUS_TYPE_STRING, &session->id,
 
440
                                        DBUS_TYPE_OBJECT_PATH, &p,
 
441
                                        DBUS_TYPE_STRING, &session->user->runtime_path,
 
442
                                        DBUS_TYPE_UNIX_FD, &fifo_fd,
 
443
                                        DBUS_TYPE_STRING, &seat,
 
444
                                        DBUS_TYPE_UINT32, &vtnr,
 
445
                                        DBUS_TYPE_INVALID);
 
446
                        free(p);
 
447
 
 
448
                        if (!b) {
 
449
                                r = -ENOMEM;
 
450
                                goto fail;
 
451
                        }
 
452
 
 
453
                        close_nointr_nofail(fifo_fd);
 
454
                        *_reply = reply;
 
455
 
 
456
                        strv_free(controllers);
 
457
                        strv_free(reset_controllers);
 
458
 
 
459
                        return 0;
 
460
                }
 
461
 
 
462
        } else {
 
463
                do {
 
464
                        free(id);
 
465
                        asprintf(&id, "c%lu", ++m->session_counter);
 
466
 
 
467
                        if (!id) {
 
468
                                r = -ENOMEM;
 
469
                                goto fail;
 
470
                        }
 
471
 
 
472
                } while (hashmap_get(m->sessions, id));
 
473
        }
 
474
 
 
475
        r = manager_add_session(m, user, id, &session);
 
476
        free(id);
 
477
        if (r < 0)
 
478
                goto fail;
 
479
 
 
480
        session->leader = leader;
 
481
        session->audit_id = audit_id;
 
482
        session->type = t;
 
483
        session->class = c;
 
484
        session->remote = remote;
 
485
        session->controllers = controllers;
 
486
        session->reset_controllers = reset_controllers;
 
487
        session->kill_processes = kill_processes;
 
488
        session->vtnr = vtnr;
 
489
 
 
490
        controllers = reset_controllers = NULL;
 
491
 
 
492
        if (!isempty(tty)) {
 
493
                session->tty = strdup(tty);
 
494
                if (!session->tty) {
 
495
                        r = -ENOMEM;
 
496
                        goto fail;
 
497
                }
 
498
        }
 
499
 
 
500
        if (!isempty(display)) {
 
501
                session->display = strdup(display);
 
502
                if (!session->display) {
 
503
                        r = -ENOMEM;
 
504
                        goto fail;
 
505
                }
 
506
        }
 
507
 
 
508
        if (!isempty(remote_user)) {
 
509
                session->remote_user = strdup(remote_user);
 
510
                if (!session->remote_user) {
 
511
                        r = -ENOMEM;
 
512
                        goto fail;
 
513
                }
 
514
        }
 
515
 
 
516
        if (!isempty(remote_host)) {
 
517
                session->remote_host = strdup(remote_host);
 
518
                if (!session->remote_host) {
 
519
                        r = -ENOMEM;
 
520
                        goto fail;
 
521
                }
 
522
        }
 
523
 
 
524
        if (!isempty(service)) {
 
525
                session->service = strdup(service);
 
526
                if (!session->service) {
 
527
                        r = -ENOMEM;
 
528
                        goto fail;
 
529
                }
 
530
        }
 
531
 
 
532
        fifo_fd = session_create_fifo(session);
 
533
        if (fifo_fd < 0) {
 
534
                r = fifo_fd;
 
535
                goto fail;
 
536
        }
 
537
 
 
538
        if (s) {
 
539
                r = seat_attach_session(s, session);
 
540
                if (r < 0)
 
541
                        goto fail;
 
542
        }
 
543
 
 
544
        r = session_start(session);
 
545
        if (r < 0)
 
546
                goto fail;
 
547
 
 
548
        reply = dbus_message_new_method_return(message);
 
549
        if (!reply) {
 
550
                r = -ENOMEM;
 
551
                goto fail;
 
552
        }
 
553
 
 
554
        p = session_bus_path(session);
 
555
        if (!p) {
 
556
                r = -ENOMEM;
 
557
                goto fail;
 
558
        }
 
559
 
 
560
        seat = s ? s->id : "";
 
561
        b = dbus_message_append_args(
 
562
                        reply,
 
563
                        DBUS_TYPE_STRING, &session->id,
 
564
                        DBUS_TYPE_OBJECT_PATH, &p,
 
565
                        DBUS_TYPE_STRING, &session->user->runtime_path,
 
566
                        DBUS_TYPE_UNIX_FD, &fifo_fd,
 
567
                        DBUS_TYPE_STRING, &seat,
 
568
                        DBUS_TYPE_UINT32, &vtnr,
 
569
                        DBUS_TYPE_INVALID);
 
570
        free(p);
 
571
 
 
572
        if (!b) {
 
573
                r = -ENOMEM;
 
574
                goto fail;
 
575
        }
 
576
 
 
577
        close_nointr_nofail(fifo_fd);
 
578
        *_reply = reply;
 
579
 
 
580
        return 0;
 
581
 
 
582
fail:
 
583
        strv_free(controllers);
 
584
        strv_free(reset_controllers);
 
585
 
 
586
        if (session)
 
587
                session_add_to_gc_queue(session);
 
588
 
 
589
        if (user)
 
590
                user_add_to_gc_queue(user);
 
591
 
 
592
        if (fifo_fd >= 0)
 
593
                close_nointr_nofail(fifo_fd);
 
594
 
 
595
        if (reply)
 
596
                dbus_message_unref(reply);
 
597
 
 
598
        return r;
 
599
}
 
600
 
 
601
static int trigger_device(Manager *m, struct udev_device *d) {
 
602
        struct udev_enumerate *e;
 
603
        struct udev_list_entry *first, *item;
 
604
        int r;
 
605
 
 
606
        assert(m);
 
607
 
 
608
        e = udev_enumerate_new(m->udev);
 
609
        if (!e) {
 
610
                r = -ENOMEM;
 
611
                goto finish;
 
612
        }
 
613
 
 
614
        if (d) {
 
615
                if (udev_enumerate_add_match_parent(e, d) < 0) {
 
616
                        r = -EIO;
 
617
                        goto finish;
 
618
                }
 
619
        }
 
620
 
 
621
        if (udev_enumerate_scan_devices(e) < 0) {
 
622
                r = -EIO;
 
623
                goto finish;
 
624
        }
 
625
 
 
626
        first = udev_enumerate_get_list_entry(e);
 
627
        udev_list_entry_foreach(item, first) {
 
628
                char *t;
 
629
                const char *p;
 
630
 
 
631
                p = udev_list_entry_get_name(item);
 
632
 
 
633
                t = strappend(p, "/uevent");
 
634
                if (!t) {
 
635
                        r = -ENOMEM;
 
636
                        goto finish;
 
637
                }
 
638
 
 
639
                write_one_line_file(t, "change");
 
640
                free(t);
 
641
        }
 
642
 
 
643
        r = 0;
 
644
 
 
645
finish:
 
646
        if (e)
 
647
                udev_enumerate_unref(e);
 
648
 
 
649
        return r;
 
650
}
 
651
 
 
652
static int attach_device(Manager *m, const char *seat, const char *sysfs) {
 
653
        struct udev_device *d;
 
654
        char *rule = NULL, *file = NULL;
 
655
        const char *id_for_seat;
 
656
        int r;
 
657
 
 
658
        assert(m);
 
659
        assert(seat);
 
660
        assert(sysfs);
 
661
 
 
662
        d = udev_device_new_from_syspath(m->udev, sysfs);
 
663
        if (!d)
 
664
                return -ENODEV;
 
665
 
 
666
        if (!udev_device_has_tag(d, "seat")) {
 
667
                r = -ENODEV;
 
668
                goto finish;
 
669
        }
 
670
 
 
671
        id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
 
672
        if (!id_for_seat) {
 
673
                r = -ENODEV;
 
674
                goto finish;
 
675
        }
 
676
 
 
677
        if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
 
678
                r = -ENOMEM;
 
679
                goto finish;
 
680
        }
 
681
 
 
682
        if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
 
683
                r = -ENOMEM;
 
684
                goto finish;
 
685
        }
 
686
 
 
687
        mkdir_p("/etc/udev/rules.d", 0755);
 
688
        r = write_one_line_file_atomic(file, rule);
 
689
        if (r < 0)
 
690
                goto finish;
 
691
 
 
692
        r = trigger_device(m, d);
 
693
 
 
694
finish:
 
695
        free(rule);
 
696
        free(file);
 
697
 
 
698
        if (d)
 
699
                udev_device_unref(d);
 
700
 
 
701
        return r;
 
702
}
 
703
 
 
704
static int flush_devices(Manager *m) {
 
705
        DIR *d;
 
706
 
 
707
        assert(m);
 
708
 
 
709
        d = opendir("/etc/udev/rules.d");
 
710
        if (!d) {
 
711
                if (errno != ENOENT)
 
712
                        log_warning("Failed to open /etc/udev/rules.d: %m");
 
713
        } else {
 
714
                struct dirent *de;
 
715
 
 
716
                while ((de = readdir(d))) {
 
717
 
 
718
                        if (!dirent_is_file(de))
 
719
                                continue;
 
720
 
 
721
                        if (!startswith(de->d_name, "72-seat-"))
 
722
                                continue;
 
723
 
 
724
                        if (!endswith(de->d_name, ".rules"))
 
725
                                continue;
 
726
 
 
727
                        if (unlinkat(dirfd(d), de->d_name, 0) < 0)
 
728
                                log_warning("Failed to unlink %s: %m", de->d_name);
 
729
                }
 
730
 
 
731
                closedir(d);
 
732
        }
 
733
 
 
734
        return trigger_device(m, NULL);
 
735
}
 
736
 
 
737
static int have_multiple_sessions(
 
738
                DBusConnection *connection,
 
739
                Manager *m,
 
740
                DBusMessage *message,
 
741
                DBusError *error) {
 
742
 
 
743
        Session *s;
 
744
 
 
745
        assert(m);
 
746
 
 
747
        if (hashmap_size(m->sessions) > 1)
 
748
                return true;
 
749
 
 
750
        /* Hmm, there's only one session, but let's make sure it
 
751
         * actually belongs to the user who is asking. If not, better
 
752
         * be safe than sorry. */
 
753
 
 
754
        s = hashmap_first(m->sessions);
 
755
        if (s) {
 
756
                unsigned long ul;
 
757
 
 
758
                ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
 
759
                if (ul == (unsigned long) -1)
 
760
                        return -EIO;
 
761
 
 
762
                return s->user->uid != ul;
 
763
        }
 
764
 
 
765
        return false;
 
766
}
 
767
 
 
768
static const BusProperty bus_login_manager_properties[] = {
 
769
        { "ControlGroupHierarchy",  bus_property_append_string,         "s",  offsetof(Manager, cgroup_path),        true },
 
770
        { "Controllers",            bus_property_append_strv,           "as", offsetof(Manager, controllers),        true },
 
771
        { "ResetControllers",       bus_property_append_strv,           "as", offsetof(Manager, reset_controllers),  true },
 
772
        { "NAutoVTs",               bus_property_append_unsigned,       "u",  offsetof(Manager, n_autovts)           },
 
773
        { "KillOnlyUsers",          bus_property_append_strv,           "as", offsetof(Manager, kill_only_users),    true },
 
774
        { "KillExcludeUsers",       bus_property_append_strv,           "as", offsetof(Manager, kill_exclude_users), true },
 
775
        { "KillUserProcesses",      bus_property_append_bool,           "b",  offsetof(Manager, kill_user_processes) },
 
776
        { "IdleHint",               bus_manager_append_idle_hint,       "b",  0 },
 
777
        { "IdleSinceHint",          bus_manager_append_idle_hint_since, "t",  0 },
 
778
        { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t",  0 },
 
779
        { NULL, }
 
780
};
 
781
 
 
782
static DBusHandlerResult manager_message_handler(
 
783
                DBusConnection *connection,
 
784
                DBusMessage *message,
 
785
                void *userdata) {
 
786
 
 
787
        Manager *m = userdata;
 
788
 
 
789
        DBusError error;
 
790
        DBusMessage *reply = NULL;
 
791
        int r;
 
792
 
 
793
        assert(connection);
 
794
        assert(message);
 
795
        assert(m);
 
796
 
 
797
        dbus_error_init(&error);
 
798
 
 
799
        if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
 
800
                const char *name;
 
801
                char *p;
 
802
                Session *session;
 
803
                bool b;
 
804
 
 
805
                if (!dbus_message_get_args(
 
806
                                    message,
 
807
                                    &error,
 
808
                                    DBUS_TYPE_STRING, &name,
 
809
                                    DBUS_TYPE_INVALID))
 
810
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
811
 
 
812
                session = hashmap_get(m->sessions, name);
 
813
                if (!session)
 
814
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
815
 
 
816
                reply = dbus_message_new_method_return(message);
 
817
                if (!reply)
 
818
                        goto oom;
 
819
 
 
820
                p = session_bus_path(session);
 
821
                if (!p)
 
822
                        goto oom;
 
823
 
 
824
                b = dbus_message_append_args(
 
825
                                reply,
 
826
                                DBUS_TYPE_OBJECT_PATH, &p,
 
827
                                DBUS_TYPE_INVALID);
 
828
                free(p);
 
829
 
 
830
                if (!b)
 
831
                        goto oom;
 
832
 
 
833
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
 
834
                uint32_t pid;
 
835
                char *p;
 
836
                Session *session;
 
837
                bool b;
 
838
 
 
839
                if (!dbus_message_get_args(
 
840
                                    message,
 
841
                                    &error,
 
842
                                    DBUS_TYPE_UINT32, &pid,
 
843
                                    DBUS_TYPE_INVALID))
 
844
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
845
 
 
846
                r = manager_get_session_by_pid(m, pid, &session);
 
847
                if (r <= 0)
 
848
                        return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
 
849
 
 
850
                reply = dbus_message_new_method_return(message);
 
851
                if (!reply)
 
852
                        goto oom;
 
853
 
 
854
                p = session_bus_path(session);
 
855
                if (!p)
 
856
                        goto oom;
 
857
 
 
858
                b = dbus_message_append_args(
 
859
                                reply,
 
860
                                DBUS_TYPE_OBJECT_PATH, &p,
 
861
                                DBUS_TYPE_INVALID);
 
862
                free(p);
 
863
 
 
864
                if (!b)
 
865
                        goto oom;
 
866
 
 
867
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
 
868
                uint32_t uid;
 
869
                char *p;
 
870
                User *user;
 
871
                bool b;
 
872
 
 
873
                if (!dbus_message_get_args(
 
874
                                    message,
 
875
                                    &error,
 
876
                                    DBUS_TYPE_UINT32, &uid,
 
877
                                    DBUS_TYPE_INVALID))
 
878
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
879
 
 
880
                user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
 
881
                if (!user)
 
882
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
883
 
 
884
                reply = dbus_message_new_method_return(message);
 
885
                if (!reply)
 
886
                        goto oom;
 
887
 
 
888
                p = user_bus_path(user);
 
889
                if (!p)
 
890
                        goto oom;
 
891
 
 
892
                b = dbus_message_append_args(
 
893
                                reply,
 
894
                                DBUS_TYPE_OBJECT_PATH, &p,
 
895
                                DBUS_TYPE_INVALID);
 
896
                free(p);
 
897
 
 
898
                if (!b)
 
899
                        goto oom;
 
900
 
 
901
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
 
902
                const char *name;
 
903
                char *p;
 
904
                Seat *seat;
 
905
                bool b;
 
906
 
 
907
                if (!dbus_message_get_args(
 
908
                                    message,
 
909
                                    &error,
 
910
                                    DBUS_TYPE_STRING, &name,
 
911
                                    DBUS_TYPE_INVALID))
 
912
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
913
 
 
914
                seat = hashmap_get(m->seats, name);
 
915
                if (!seat)
 
916
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
917
 
 
918
                reply = dbus_message_new_method_return(message);
 
919
                if (!reply)
 
920
                        goto oom;
 
921
 
 
922
                p = seat_bus_path(seat);
 
923
                if (!p)
 
924
                        goto oom;
 
925
 
 
926
                b = dbus_message_append_args(
 
927
                                reply,
 
928
                                DBUS_TYPE_OBJECT_PATH, &p,
 
929
                                DBUS_TYPE_INVALID);
 
930
                free(p);
 
931
 
 
932
                if (!b)
 
933
                        goto oom;
 
934
 
 
935
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
 
936
                char *p;
 
937
                Session *session;
 
938
                Iterator i;
 
939
                DBusMessageIter iter, sub;
 
940
                const char *empty = "";
 
941
 
 
942
                reply = dbus_message_new_method_return(message);
 
943
                if (!reply)
 
944
                        goto oom;
 
945
 
 
946
                dbus_message_iter_init_append(reply, &iter);
 
947
 
 
948
                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
 
949
                        goto oom;
 
950
 
 
951
                HASHMAP_FOREACH(session, m->sessions, i) {
 
952
                        DBusMessageIter sub2;
 
953
                        uint32_t uid;
 
954
 
 
955
                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
 
956
                                goto oom;
 
957
 
 
958
                        uid = session->user->uid;
 
959
 
 
960
                        p = session_bus_path(session);
 
961
                        if (!p)
 
962
                                goto oom;
 
963
 
 
964
                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
 
965
                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
 
966
                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
 
967
                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
 
968
                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
 
969
                                free(p);
 
970
                                goto oom;
 
971
                        }
 
972
 
 
973
                        free(p);
 
974
 
 
975
                        if (!dbus_message_iter_close_container(&sub, &sub2))
 
976
                                goto oom;
 
977
                }
 
978
 
 
979
                if (!dbus_message_iter_close_container(&iter, &sub))
 
980
                        goto oom;
 
981
 
 
982
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
 
983
                char *p;
 
984
                User *user;
 
985
                Iterator i;
 
986
                DBusMessageIter iter, sub;
 
987
 
 
988
                reply = dbus_message_new_method_return(message);
 
989
                if (!reply)
 
990
                        goto oom;
 
991
 
 
992
                dbus_message_iter_init_append(reply, &iter);
 
993
 
 
994
                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
 
995
                        goto oom;
 
996
 
 
997
                HASHMAP_FOREACH(user, m->users, i) {
 
998
                        DBusMessageIter sub2;
 
999
                        uint32_t uid;
 
1000
 
 
1001
                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
 
1002
                                goto oom;
 
1003
 
 
1004
                        uid = user->uid;
 
1005
 
 
1006
                        p = user_bus_path(user);
 
1007
                        if (!p)
 
1008
                                goto oom;
 
1009
 
 
1010
                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
 
1011
                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
 
1012
                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
 
1013
                                free(p);
 
1014
                                goto oom;
 
1015
                        }
 
1016
 
 
1017
                        free(p);
 
1018
 
 
1019
                        if (!dbus_message_iter_close_container(&sub, &sub2))
 
1020
                                goto oom;
 
1021
                }
 
1022
 
 
1023
                if (!dbus_message_iter_close_container(&iter, &sub))
 
1024
                        goto oom;
 
1025
 
 
1026
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
 
1027
                char *p;
 
1028
                Seat *seat;
 
1029
                Iterator i;
 
1030
                DBusMessageIter iter, sub;
 
1031
 
 
1032
                reply = dbus_message_new_method_return(message);
 
1033
                if (!reply)
 
1034
                        goto oom;
 
1035
 
 
1036
                dbus_message_iter_init_append(reply, &iter);
 
1037
 
 
1038
                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
 
1039
                        goto oom;
 
1040
 
 
1041
                HASHMAP_FOREACH(seat, m->seats, i) {
 
1042
                        DBusMessageIter sub2;
 
1043
 
 
1044
                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
 
1045
                                goto oom;
 
1046
 
 
1047
                        p = seat_bus_path(seat);
 
1048
                        if (!p)
 
1049
                                goto oom;
 
1050
 
 
1051
                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
 
1052
                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
 
1053
                                free(p);
 
1054
                                goto oom;
 
1055
                        }
 
1056
 
 
1057
                        free(p);
 
1058
 
 
1059
                        if (!dbus_message_iter_close_container(&sub, &sub2))
 
1060
                                goto oom;
 
1061
                }
 
1062
 
 
1063
                if (!dbus_message_iter_close_container(&iter, &sub))
 
1064
                        goto oom;
 
1065
 
 
1066
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
 
1067
 
 
1068
                r = bus_manager_create_session(m, message, &reply);
 
1069
 
 
1070
                /* Don't delay the work on OOM here, since it might be
 
1071
                 * triggered by a low RLIMIT_NOFILE here (since we
 
1072
                 * send a dupped fd to the client), and we'd rather
 
1073
                 * see this fail quickly then be retried later */
 
1074
 
 
1075
                if (r < 0)
 
1076
                        return bus_send_error_reply(connection, message, &error, r);
 
1077
 
 
1078
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
 
1079
                const char *name;
 
1080
                Session *session;
 
1081
 
 
1082
                if (!dbus_message_get_args(
 
1083
                                    message,
 
1084
                                    &error,
 
1085
                                    DBUS_TYPE_STRING, &name,
 
1086
                                    DBUS_TYPE_INVALID))
 
1087
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1088
 
 
1089
                session = hashmap_get(m->sessions, name);
 
1090
                if (!session)
 
1091
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1092
 
 
1093
                r = session_activate(session);
 
1094
                if (r < 0)
 
1095
                        return bus_send_error_reply(connection, message, NULL, r);
 
1096
 
 
1097
                reply = dbus_message_new_method_return(message);
 
1098
                if (!reply)
 
1099
                        goto oom;
 
1100
 
 
1101
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
 
1102
                const char *session_name, *seat_name;
 
1103
                Session *session;
 
1104
                Seat *seat;
 
1105
 
 
1106
                /* Same as ActivateSession() but refuses to work if
 
1107
                 * the seat doesn't match */
 
1108
 
 
1109
                if (!dbus_message_get_args(
 
1110
                                    message,
 
1111
                                    &error,
 
1112
                                    DBUS_TYPE_STRING, &session_name,
 
1113
                                    DBUS_TYPE_STRING, &seat_name,
 
1114
                                    DBUS_TYPE_INVALID))
 
1115
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1116
 
 
1117
                session = hashmap_get(m->sessions, session_name);
 
1118
                if (!session)
 
1119
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1120
 
 
1121
                seat = hashmap_get(m->seats, seat_name);
 
1122
                if (!seat)
 
1123
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1124
 
 
1125
                if (session->seat != seat)
 
1126
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1127
 
 
1128
                r = session_activate(session);
 
1129
                if (r < 0)
 
1130
                        return bus_send_error_reply(connection, message, NULL, r);
 
1131
 
 
1132
                reply = dbus_message_new_method_return(message);
 
1133
                if (!reply)
 
1134
                        goto oom;
 
1135
 
 
1136
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
 
1137
                   dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
 
1138
                const char *name;
 
1139
                Session *session;
 
1140
 
 
1141
                if (!dbus_message_get_args(
 
1142
                                    message,
 
1143
                                    &error,
 
1144
                                    DBUS_TYPE_STRING, &name,
 
1145
                                    DBUS_TYPE_INVALID))
 
1146
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1147
 
 
1148
                session = hashmap_get(m->sessions, name);
 
1149
                if (!session)
 
1150
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1151
 
 
1152
                if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
 
1153
                        goto oom;
 
1154
 
 
1155
                reply = dbus_message_new_method_return(message);
 
1156
                if (!reply)
 
1157
                        goto oom;
 
1158
 
 
1159
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
 
1160
                const char *swho;
 
1161
                int32_t signo;
 
1162
                KillWho who;
 
1163
                const char *name;
 
1164
                Session *session;
 
1165
 
 
1166
                if (!dbus_message_get_args(
 
1167
                                    message,
 
1168
                                    &error,
 
1169
                                    DBUS_TYPE_STRING, &name,
 
1170
                                    DBUS_TYPE_STRING, &swho,
 
1171
                                    DBUS_TYPE_INT32, &signo,
 
1172
                                    DBUS_TYPE_INVALID))
 
1173
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1174
 
 
1175
                if (isempty(swho))
 
1176
                        who = KILL_ALL;
 
1177
                else {
 
1178
                        who = kill_who_from_string(swho);
 
1179
                        if (who < 0)
 
1180
                                return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1181
                }
 
1182
 
 
1183
                if (signo <= 0 || signo >= _NSIG)
 
1184
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1185
 
 
1186
                session = hashmap_get(m->sessions, name);
 
1187
                if (!session)
 
1188
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1189
 
 
1190
                r = session_kill(session, who, signo);
 
1191
                if (r < 0)
 
1192
                        return bus_send_error_reply(connection, message, NULL, r);
 
1193
 
 
1194
                reply = dbus_message_new_method_return(message);
 
1195
                if (!reply)
 
1196
                        goto oom;
 
1197
 
 
1198
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
 
1199
                uint32_t uid;
 
1200
                User *user;
 
1201
                int32_t signo;
 
1202
 
 
1203
                if (!dbus_message_get_args(
 
1204
                                    message,
 
1205
                                    &error,
 
1206
                                    DBUS_TYPE_UINT32, &uid,
 
1207
                                    DBUS_TYPE_INT32, &signo,
 
1208
                                    DBUS_TYPE_INVALID))
 
1209
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1210
 
 
1211
                if (signo <= 0 || signo >= _NSIG)
 
1212
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1213
 
 
1214
                user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
 
1215
                if (!user)
 
1216
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1217
 
 
1218
                r = user_kill(user, signo);
 
1219
                if (r < 0)
 
1220
                        return bus_send_error_reply(connection, message, NULL, r);
 
1221
 
 
1222
                reply = dbus_message_new_method_return(message);
 
1223
                if (!reply)
 
1224
                        goto oom;
 
1225
 
 
1226
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
 
1227
                const char *name;
 
1228
                Session *session;
 
1229
 
 
1230
                if (!dbus_message_get_args(
 
1231
                                    message,
 
1232
                                    &error,
 
1233
                                    DBUS_TYPE_STRING, &name,
 
1234
                                    DBUS_TYPE_INVALID))
 
1235
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1236
 
 
1237
                session = hashmap_get(m->sessions, name);
 
1238
                if (!session)
 
1239
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1240
 
 
1241
                r = session_stop(session);
 
1242
                if (r < 0)
 
1243
                        return bus_send_error_reply(connection, message, NULL, r);
 
1244
 
 
1245
                reply = dbus_message_new_method_return(message);
 
1246
                if (!reply)
 
1247
                        goto oom;
 
1248
 
 
1249
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
 
1250
                uint32_t uid;
 
1251
                User *user;
 
1252
 
 
1253
                if (!dbus_message_get_args(
 
1254
                                    message,
 
1255
                                    &error,
 
1256
                                    DBUS_TYPE_UINT32, &uid,
 
1257
                                    DBUS_TYPE_INVALID))
 
1258
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1259
 
 
1260
                user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
 
1261
                if (!user)
 
1262
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1263
 
 
1264
                r = user_stop(user);
 
1265
                if (r < 0)
 
1266
                        return bus_send_error_reply(connection, message, NULL, r);
 
1267
 
 
1268
                reply = dbus_message_new_method_return(message);
 
1269
                if (!reply)
 
1270
                        goto oom;
 
1271
 
 
1272
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
 
1273
                const char *name;
 
1274
                Seat *seat;
 
1275
 
 
1276
                if (!dbus_message_get_args(
 
1277
                                    message,
 
1278
                                    &error,
 
1279
                                    DBUS_TYPE_STRING, &name,
 
1280
                                    DBUS_TYPE_INVALID))
 
1281
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1282
 
 
1283
                seat = hashmap_get(m->seats, name);
 
1284
                if (!seat)
 
1285
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
 
1286
 
 
1287
                r = seat_stop_sessions(seat);
 
1288
                if (r < 0)
 
1289
                        return bus_send_error_reply(connection, message, NULL, r);
 
1290
 
 
1291
                reply = dbus_message_new_method_return(message);
 
1292
                if (!reply)
 
1293
                        goto oom;
 
1294
 
 
1295
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
 
1296
                uint32_t uid;
 
1297
                struct passwd *pw;
 
1298
                dbus_bool_t b, interactive;
 
1299
                char *path;
 
1300
 
 
1301
                if (!dbus_message_get_args(
 
1302
                                    message,
 
1303
                                    &error,
 
1304
                                    DBUS_TYPE_UINT32, &uid,
 
1305
                                    DBUS_TYPE_BOOLEAN, &b,
 
1306
                                    DBUS_TYPE_BOOLEAN, &interactive,
 
1307
                                    DBUS_TYPE_INVALID))
 
1308
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1309
 
 
1310
                errno = 0;
 
1311
                pw = getpwuid(uid);
 
1312
                if (!pw)
 
1313
                        return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
 
1314
 
 
1315
                r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
 
1316
                if (r < 0)
 
1317
                        return bus_send_error_reply(connection, message, &error, r);
 
1318
 
 
1319
                mkdir_p("/var/lib/systemd", 0755);
 
1320
 
 
1321
                r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
 
1322
                if (r < 0)
 
1323
                        return bus_send_error_reply(connection, message, &error, r);
 
1324
 
 
1325
                path = strappend("/var/lib/systemd/linger/", pw->pw_name);
 
1326
                if (!path)
 
1327
                        goto oom;
 
1328
 
 
1329
                if (b) {
 
1330
                        User *u;
 
1331
 
 
1332
                        r = touch(path);
 
1333
                        free(path);
 
1334
 
 
1335
                        if (r < 0)
 
1336
                                return bus_send_error_reply(connection, message, &error, r);
 
1337
 
 
1338
                        if (manager_add_user_by_uid(m, uid, &u) >= 0)
 
1339
                                user_start(u);
 
1340
 
 
1341
                } else {
 
1342
                        User *u;
 
1343
 
 
1344
                        r = unlink(path);
 
1345
                        free(path);
 
1346
 
 
1347
                        if (r < 0 && errno != ENOENT)
 
1348
                                return bus_send_error_reply(connection, message, &error, -errno);
 
1349
 
 
1350
                        u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
 
1351
                        if (u)
 
1352
                                user_add_to_gc_queue(u);
 
1353
                }
 
1354
 
 
1355
                reply = dbus_message_new_method_return(message);
 
1356
                if (!reply)
 
1357
                        goto oom;
 
1358
 
 
1359
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
 
1360
                const char *sysfs, *seat;
 
1361
                dbus_bool_t interactive;
 
1362
 
 
1363
                if (!dbus_message_get_args(
 
1364
                                    message,
 
1365
                                    &error,
 
1366
                                    DBUS_TYPE_STRING, &seat,
 
1367
                                    DBUS_TYPE_STRING, &sysfs,
 
1368
                                    DBUS_TYPE_BOOLEAN, &interactive,
 
1369
                                    DBUS_TYPE_INVALID))
 
1370
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1371
 
 
1372
                if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
 
1373
                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
 
1374
 
 
1375
                r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
 
1376
                if (r < 0)
 
1377
                        return bus_send_error_reply(connection, message, &error, r);
 
1378
 
 
1379
                r = attach_device(m, seat, sysfs);
 
1380
                if (r < 0)
 
1381
                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
 
1382
 
 
1383
                reply = dbus_message_new_method_return(message);
 
1384
                if (!reply)
 
1385
                        goto oom;
 
1386
 
 
1387
 
 
1388
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
 
1389
                dbus_bool_t interactive;
 
1390
 
 
1391
                if (!dbus_message_get_args(
 
1392
                                    message,
 
1393
                                    &error,
 
1394
                                    DBUS_TYPE_BOOLEAN, &interactive,
 
1395
                                    DBUS_TYPE_INVALID))
 
1396
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1397
 
 
1398
                r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
 
1399
                if (r < 0)
 
1400
                        return bus_send_error_reply(connection, message, &error, r);
 
1401
 
 
1402
                r = flush_devices(m);
 
1403
                if (r < 0)
 
1404
                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
 
1405
 
 
1406
                reply = dbus_message_new_method_return(message);
 
1407
                if (!reply)
 
1408
                        goto oom;
 
1409
 
 
1410
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") ||
 
1411
                   dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
 
1412
                dbus_bool_t interactive;
 
1413
                bool multiple_sessions;
 
1414
                DBusMessage *forward, *freply;
 
1415
                const char *name;
 
1416
                const char *mode = "replace";
 
1417
                const char *action;
 
1418
 
 
1419
                if (!dbus_message_get_args(
 
1420
                                    message,
 
1421
                                    &error,
 
1422
                                    DBUS_TYPE_BOOLEAN, &interactive,
 
1423
                                    DBUS_TYPE_INVALID))
 
1424
                        return bus_send_error_reply(connection, message, &error, -EINVAL);
 
1425
 
 
1426
                r = have_multiple_sessions(connection, m, message, &error);
 
1427
                if (r < 0)
 
1428
                        return bus_send_error_reply(connection, message, &error, r);
 
1429
 
 
1430
                multiple_sessions = r > 0;
 
1431
 
 
1432
                if (streq(dbus_message_get_member(message), "PowerOff")) {
 
1433
                        if (multiple_sessions)
 
1434
                                action = "org.freedesktop.login1.power-off-multiple-sessions";
 
1435
                        else
 
1436
                                action = "org.freedesktop.login1.power-off";
 
1437
 
 
1438
                        name = SPECIAL_POWEROFF_TARGET;
 
1439
                } else {
 
1440
                        if (multiple_sessions)
 
1441
                                action = "org.freedesktop.login1.reboot-multiple-sessions";
 
1442
                        else
 
1443
                                action = "org.freedesktop.login1.reboot";
 
1444
 
 
1445
                        name = SPECIAL_REBOOT_TARGET;
 
1446
                }
 
1447
 
 
1448
                r = verify_polkit(connection, message, action, interactive, NULL, &error);
 
1449
                if (r < 0)
 
1450
                        return bus_send_error_reply(connection, message, &error, r);
 
1451
 
 
1452
                forward = dbus_message_new_method_call(
 
1453
                              "org.freedesktop.systemd1",
 
1454
                              "/org/freedesktop/systemd1",
 
1455
                              "org.freedesktop.systemd1.Manager",
 
1456
                              "StartUnit");
 
1457
                if (!forward)
 
1458
                        return bus_send_error_reply(connection, message, NULL, -ENOMEM);
 
1459
 
 
1460
                if (!dbus_message_append_args(forward,
 
1461
                                              DBUS_TYPE_STRING, &name,
 
1462
                                              DBUS_TYPE_STRING, &mode,
 
1463
                                              DBUS_TYPE_INVALID)) {
 
1464
                        dbus_message_unref(forward);
 
1465
                        return bus_send_error_reply(connection, message, NULL, -ENOMEM);
 
1466
                }
 
1467
 
 
1468
                freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error);
 
1469
                dbus_message_unref(forward);
 
1470
 
 
1471
                if (!freply)
 
1472
                        return bus_send_error_reply(connection, message, &error, -EIO);
 
1473
 
 
1474
                dbus_message_unref(freply);
 
1475
 
 
1476
                reply = dbus_message_new_method_return(message);
 
1477
                if (!reply)
 
1478
                        goto oom;
 
1479
 
 
1480
        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff") ||
 
1481
                   dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
 
1482
 
 
1483
                bool multiple_sessions, challenge, b;
 
1484
                const char *t, *action;
 
1485
 
 
1486
                r = have_multiple_sessions(connection, m, message, &error);
 
1487
                if (r < 0)
 
1488
                        return bus_send_error_reply(connection, message, &error, r);
 
1489
 
 
1490
                multiple_sessions = r > 0;
 
1491
 
 
1492
                if (streq(dbus_message_get_member(message), "CanPowerOff")) {
 
1493
                        if (multiple_sessions)
 
1494
                                action = "org.freedesktop.login1.power-off-multiple-sessions";
 
1495
                        else
 
1496
                                action = "org.freedesktop.login1.power-off";
 
1497
 
 
1498
                } else {
 
1499
                        if (multiple_sessions)
 
1500
                                action = "org.freedesktop.login1.reboot-multiple-sessions";
 
1501
                        else
 
1502
                                action = "org.freedesktop.login1.reboot";
 
1503
                }
 
1504
 
 
1505
                r = verify_polkit(connection, message, action, false, &challenge, &error);
 
1506
                if (r < 0)
 
1507
                        return bus_send_error_reply(connection, message, &error, r);
 
1508
 
 
1509
                reply = dbus_message_new_method_return(message);
 
1510
                if (!reply)
 
1511
                        goto oom;
 
1512
 
 
1513
                t =     r > 0 ?     "yes" :
 
1514
                        challenge ? "challenge" :
 
1515
                                    "no";
 
1516
 
 
1517
                b = dbus_message_append_args(
 
1518
                                reply,
 
1519
                                DBUS_TYPE_STRING, &t,
 
1520
                                DBUS_TYPE_INVALID);
 
1521
                if (!b)
 
1522
                        goto oom;
 
1523
 
 
1524
        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
 
1525
                char *introspection = NULL;
 
1526
                FILE *f;
 
1527
                Iterator i;
 
1528
                Session *session;
 
1529
                Seat *seat;
 
1530
                User *user;
 
1531
                size_t size;
 
1532
                char *p;
 
1533
 
 
1534
                if (!(reply = dbus_message_new_method_return(message)))
 
1535
                        goto oom;
 
1536
 
 
1537
                /* We roll our own introspection code here, instead of
 
1538
                 * relying on bus_default_message_handler() because we
 
1539
                 * need to generate our introspection string
 
1540
                 * dynamically. */
 
1541
 
 
1542
                if (!(f = open_memstream(&introspection, &size)))
 
1543
                        goto oom;
 
1544
 
 
1545
                fputs(INTROSPECTION_BEGIN, f);
 
1546
 
 
1547
                HASHMAP_FOREACH(seat, m->seats, i) {
 
1548
                        p = bus_path_escape(seat->id);
 
1549
 
 
1550
                        if (p) {
 
1551
                                fprintf(f, "<node name=\"seat/%s\"/>", p);
 
1552
                                free(p);
 
1553
                        }
 
1554
                }
 
1555
 
 
1556
                HASHMAP_FOREACH(user, m->users, i)
 
1557
                        fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
 
1558
 
 
1559
                HASHMAP_FOREACH(session, m->sessions, i) {
 
1560
                        p = bus_path_escape(session->id);
 
1561
 
 
1562
                        if (p) {
 
1563
                                fprintf(f, "<node name=\"session/%s\"/>", p);
 
1564
                                free(p);
 
1565
                        }
 
1566
                }
 
1567
 
 
1568
                fputs(INTROSPECTION_END, f);
 
1569
 
 
1570
                if (ferror(f)) {
 
1571
                        fclose(f);
 
1572
                        free(introspection);
 
1573
                        goto oom;
 
1574
                }
 
1575
 
 
1576
                fclose(f);
 
1577
 
 
1578
                if (!introspection)
 
1579
                        goto oom;
 
1580
 
 
1581
                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
 
1582
                        free(introspection);
 
1583
                        goto oom;
 
1584
                }
 
1585
 
 
1586
                free(introspection);
 
1587
        } else {
 
1588
                const BusBoundProperties bps[] = {
 
1589
                        { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
 
1590
                        { NULL, }
 
1591
                };
 
1592
                return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
 
1593
        }
 
1594
 
 
1595
        if (reply) {
 
1596
                if (!dbus_connection_send(connection, reply, NULL))
 
1597
                        goto oom;
 
1598
 
 
1599
                dbus_message_unref(reply);
 
1600
        }
 
1601
 
 
1602
        return DBUS_HANDLER_RESULT_HANDLED;
 
1603
 
 
1604
oom:
 
1605
        if (reply)
 
1606
                dbus_message_unref(reply);
 
1607
 
 
1608
        dbus_error_free(&error);
 
1609
 
 
1610
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
1611
}
 
1612
 
 
1613
const DBusObjectPathVTable bus_manager_vtable = {
 
1614
        .message_function = manager_message_handler
 
1615
};
 
1616
 
 
1617
DBusHandlerResult bus_message_filter(
 
1618
                DBusConnection *connection,
 
1619
                DBusMessage *message,
 
1620
                void *userdata) {
 
1621
 
 
1622
        Manager *m = userdata;
 
1623
        DBusError error;
 
1624
 
 
1625
        assert(m);
 
1626
        assert(connection);
 
1627
        assert(message);
 
1628
 
 
1629
        dbus_error_init(&error);
 
1630
 
 
1631
        if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
 
1632
                const char *cgroup;
 
1633
 
 
1634
                if (!dbus_message_get_args(message, &error,
 
1635
                                           DBUS_TYPE_STRING, &cgroup,
 
1636
                                           DBUS_TYPE_INVALID))
 
1637
                        log_error("Failed to parse Released message: %s", bus_error_message(&error));
 
1638
                else
 
1639
                        manager_cgroup_notify_empty(m, cgroup);
 
1640
        }
 
1641
 
 
1642
        dbus_error_free(&error);
 
1643
 
 
1644
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
1645
}
 
1646
 
 
1647
int manager_send_changed(Manager *manager, const char *properties) {
 
1648
        DBusMessage *m;
 
1649
        int r = -ENOMEM;
 
1650
 
 
1651
        assert(manager);
 
1652
 
 
1653
        m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
 
1654
        if (!m)
 
1655
                goto finish;
 
1656
 
 
1657
        if (!dbus_connection_send(manager->bus, m, NULL))
 
1658
                goto finish;
 
1659
 
 
1660
        r = 0;
 
1661
 
 
1662
finish:
 
1663
        if (m)
 
1664
                dbus_message_unref(m);
 
1665
 
 
1666
        return r;
 
1667
}