~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to .pc/debian-changes/src/login/pam-module.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Michael Biebl, Michael Stapelberg, Daniel Schaal, Ondrej Balaz
  • Date: 2013-09-12 00:13:11 UTC
  • mfrom: (1.1.11) (9.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: package-import@ubuntu.com-20130912001311-dz35it34wr2lbday
Tags: 204-3
[ Michael Biebl ]
* Upload to unstable.
* Use /bin/bash in debug-shell.service as Debian doesn't have /sbin/sushell.
* Only import net.ifaces cmdline property for network devices.
* Generate strict dependencies between the binary packages using a
  shlibs.local file and add an explicit versioned dependency on
  libsystemd-login0 to systemd to ensure packages are upgraded in sync.
  Closes: #719444
* Drop obsolete Replaces: libudev0 from udev package.
* Use correct paths for various binaries, like /sbin/quotaon, which are
  installed in / and not /usr in Debian.  Closes: #721347
* Don't install kernel-install(8) man page since we don't install the
  corresponding binary either.  Closes: #722180
* Cherry-pick upstream fixes to make switching runlevels and starting
  reboot via ctrl-alt-del more robust.
* Cherry-pick upstream fix to properly apply ACLs to Journal files.

[ Michael Stapelberg ]
* Make systemctl enable|disable call update-rc.d for SysV init scripts.
  Closes: #709780
* Don't mount /tmp as tmpfs by default and make it possible to enable this
  feature via "systemctl enable tmp.mount".

[ Daniel Schaal ]
* Add bug-script to systemd and udev.  Closes: #711245

[ Ondrej Balaz ]
* Recognize discard option in /etc/crypttab.

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 2010 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 <fcntl.h>
 
24
#include <sys/file.h>
 
25
#include <pwd.h>
 
26
#include <endian.h>
 
27
#include <sys/capability.h>
 
28
 
 
29
#include <security/pam_modules.h>
 
30
#include <security/_pam_macros.h>
 
31
#include <security/pam_modutil.h>
 
32
#include <security/pam_ext.h>
 
33
#include <security/pam_misc.h>
 
34
 
 
35
#include "util.h"
 
36
#include "audit.h"
 
37
#include "macro.h"
 
38
#include "strv.h"
 
39
#include "dbus-common.h"
 
40
#include "def.h"
 
41
#include "socket-util.h"
 
42
#include "fileio.h"
 
43
 
 
44
static int parse_argv(pam_handle_t *handle,
 
45
                      int argc, const char **argv,
 
46
                      char ***controllers,
 
47
                      char ***reset_controllers,
 
48
                      bool *kill_processes,
 
49
                      char ***kill_only_users,
 
50
                      char ***kill_exclude_users,
 
51
                      const char **class,
 
52
                      bool *debug) {
 
53
 
 
54
        unsigned i;
 
55
 
 
56
        assert(argc >= 0);
 
57
        assert(argc == 0 || argv);
 
58
 
 
59
        for (i = 0; i < (unsigned) argc; i++) {
 
60
                int k;
 
61
 
 
62
                if (startswith(argv[i], "kill-session-processes=")) {
 
63
                        if ((k = parse_boolean(argv[i] + 23)) < 0) {
 
64
                                pam_syslog(handle, LOG_ERR, "Failed to parse kill-session-processes= argument.");
 
65
                                return k;
 
66
                        }
 
67
 
 
68
                        if (kill_processes)
 
69
                                *kill_processes = k;
 
70
 
 
71
                } else if (startswith(argv[i], "kill-session=")) {
 
72
                        /* As compatibility for old versions */
 
73
 
 
74
                        if ((k = parse_boolean(argv[i] + 13)) < 0) {
 
75
                                pam_syslog(handle, LOG_ERR, "Failed to parse kill-session= argument.");
 
76
                                return k;
 
77
                        }
 
78
 
 
79
                        if (kill_processes)
 
80
                                *kill_processes = k;
 
81
 
 
82
                } else if (startswith(argv[i], "controllers=")) {
 
83
 
 
84
                        if (controllers) {
 
85
                                char **l;
 
86
 
 
87
                                if (!(l = strv_split(argv[i] + 12, ","))) {
 
88
                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
 
89
                                        return -ENOMEM;
 
90
                                }
 
91
 
 
92
                                strv_free(*controllers);
 
93
                                *controllers = l;
 
94
                        }
 
95
 
 
96
                } else if (startswith(argv[i], "reset-controllers=")) {
 
97
 
 
98
                        if (reset_controllers) {
 
99
                                char **l;
 
100
 
 
101
                                if (!(l = strv_split(argv[i] + 18, ","))) {
 
102
                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
 
103
                                        return -ENOMEM;
 
104
                                }
 
105
 
 
106
                                strv_free(*reset_controllers);
 
107
                                *reset_controllers = l;
 
108
                        }
 
109
 
 
110
                } else if (startswith(argv[i], "kill-only-users=")) {
 
111
 
 
112
                        if (kill_only_users) {
 
113
                                char **l;
 
114
 
 
115
                                if (!(l = strv_split(argv[i] + 16, ","))) {
 
116
                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
 
117
                                        return -ENOMEM;
 
118
                                }
 
119
 
 
120
                                strv_free(*kill_only_users);
 
121
                                *kill_only_users = l;
 
122
                        }
 
123
 
 
124
                } else if (startswith(argv[i], "kill-exclude-users=")) {
 
125
 
 
126
                        if (kill_exclude_users) {
 
127
                                char **l;
 
128
 
 
129
                                if (!(l = strv_split(argv[i] + 19, ","))) {
 
130
                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
 
131
                                        return -ENOMEM;
 
132
                                }
 
133
 
 
134
                                strv_free(*kill_exclude_users);
 
135
                                *kill_exclude_users = l;
 
136
                        }
 
137
 
 
138
                } else if (startswith(argv[i], "class=")) {
 
139
 
 
140
                        if (class)
 
141
                                *class = argv[i] + 6;
 
142
 
 
143
                } else if (startswith(argv[i], "debug=")) {
 
144
                        if ((k = parse_boolean(argv[i] + 6)) < 0) {
 
145
                                pam_syslog(handle, LOG_ERR, "Failed to parse debug= argument.");
 
146
                                return k;
 
147
                        }
 
148
 
 
149
                        if (debug)
 
150
                                *debug = k;
 
151
 
 
152
                } else if (startswith(argv[i], "create-session=") ||
 
153
                           startswith(argv[i], "kill-user=")) {
 
154
 
 
155
                        pam_syslog(handle, LOG_WARNING, "Option %s not supported anymore, ignoring.", argv[i]);
 
156
 
 
157
                } else {
 
158
                        pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]);
 
159
                        return -EINVAL;
 
160
                }
 
161
        }
 
162
 
 
163
        return 0;
 
164
}
 
165
 
 
166
static int get_user_data(
 
167
                pam_handle_t *handle,
 
168
                const char **ret_username,
 
169
                struct passwd **ret_pw) {
 
170
 
 
171
        const char *username = NULL;
 
172
        struct passwd *pw = NULL;
 
173
        uid_t uid;
 
174
        int r;
 
175
 
 
176
        assert(handle);
 
177
        assert(ret_username);
 
178
        assert(ret_pw);
 
179
 
 
180
        r = audit_loginuid_from_pid(0, &uid);
 
181
        if (r >= 0)
 
182
                pw = pam_modutil_getpwuid(handle, uid);
 
183
        else {
 
184
                r = pam_get_user(handle, &username, NULL);
 
185
                if (r != PAM_SUCCESS) {
 
186
                        pam_syslog(handle, LOG_ERR, "Failed to get user name.");
 
187
                        return r;
 
188
                }
 
189
 
 
190
                if (isempty(username)) {
 
191
                        pam_syslog(handle, LOG_ERR, "User name not valid.");
 
192
                        return PAM_AUTH_ERR;
 
193
                }
 
194
 
 
195
                pw = pam_modutil_getpwnam(handle, username);
 
196
        }
 
197
 
 
198
        if (!pw) {
 
199
                pam_syslog(handle, LOG_ERR, "Failed to get user data.");
 
200
                return PAM_USER_UNKNOWN;
 
201
        }
 
202
 
 
203
        *ret_pw = pw;
 
204
        *ret_username = username ? username : pw->pw_name;
 
205
 
 
206
        return PAM_SUCCESS;
 
207
}
 
208
 
 
209
static bool check_user_lists(
 
210
                pam_handle_t *handle,
 
211
                uid_t uid,
 
212
                char **kill_only_users,
 
213
                char **kill_exclude_users) {
 
214
 
 
215
        const char *name = NULL;
 
216
        char **l;
 
217
 
 
218
        assert(handle);
 
219
 
 
220
        if (uid == 0)
 
221
                name = "root"; /* Avoid obvious NSS requests, to suppress network traffic */
 
222
        else {
 
223
                struct passwd *pw;
 
224
 
 
225
                pw = pam_modutil_getpwuid(handle, uid);
 
226
                if (pw)
 
227
                        name = pw->pw_name;
 
228
        }
 
229
 
 
230
        STRV_FOREACH(l, kill_exclude_users) {
 
231
                uid_t u;
 
232
 
 
233
                if (parse_uid(*l, &u) >= 0)
 
234
                        if (u == uid)
 
235
                                return false;
 
236
 
 
237
                if (name && streq(name, *l))
 
238
                        return false;
 
239
        }
 
240
 
 
241
        if (strv_isempty(kill_only_users))
 
242
                return true;
 
243
 
 
244
        STRV_FOREACH(l, kill_only_users) {
 
245
                uid_t u;
 
246
 
 
247
                if (parse_uid(*l, &u) >= 0)
 
248
                        if (u == uid)
 
249
                                return true;
 
250
 
 
251
                if (name && streq(name, *l))
 
252
                        return true;
 
253
        }
 
254
 
 
255
        return false;
 
256
}
 
257
 
 
258
static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) {
 
259
        _cleanup_free_ char *p = NULL;
 
260
        int r;
 
261
        _cleanup_close_ int fd = -1;
 
262
        union sockaddr_union sa = {
 
263
                .un.sun_family = AF_UNIX,
 
264
        };
 
265
        struct ucred ucred;
 
266
        socklen_t l;
 
267
        _cleanup_free_ char *tty = NULL;
 
268
        int v;
 
269
 
 
270
        assert(display);
 
271
        assert(vtnr);
 
272
 
 
273
        /* We deduce the X11 socket from the display name, then use
 
274
         * SO_PEERCRED to determine the X11 server process, ask for
 
275
         * the controlling tty of that and if it's a VC then we know
 
276
         * the seat and the virtual terminal. Sounds ugly, is only
 
277
         * semi-ugly. */
 
278
 
 
279
        r = socket_from_display(display, &p);
 
280
        if (r < 0)
 
281
                return r;
 
282
        strncpy(sa.un.sun_path, p, sizeof(sa.un.sun_path)-1);
 
283
 
 
284
        fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
 
285
        if (fd < 0)
 
286
                return -errno;
 
287
 
 
288
        if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
 
289
                return -errno;
 
290
 
 
291
        l = sizeof(ucred);
 
292
        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
 
293
        if (r < 0)
 
294
                return -errno;
 
295
 
 
296
        r = get_ctty(ucred.pid, NULL, &tty);
 
297
        if (r < 0)
 
298
                return r;
 
299
 
 
300
        v = vtnr_from_tty(tty);
 
301
        if (v < 0)
 
302
                return v;
 
303
        else if (v == 0)
 
304
                return -ENOENT;
 
305
 
 
306
        if (seat)
 
307
                *seat = "seat0";
 
308
        *vtnr = (uint32_t) v;
 
309
 
 
310
        return 0;
 
311
}
 
312
 
 
313
_public_ PAM_EXTERN int pam_sm_open_session(
 
314
                pam_handle_t *handle,
 
315
                int flags,
 
316
                int argc, const char **argv) {
 
317
 
 
318
        struct passwd *pw;
 
319
        bool kill_processes = false, debug = false;
 
320
        const char *username, *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type = NULL, *class = NULL, *class_pam = NULL, *cvtnr = NULL;
 
321
        char **controllers = NULL, **reset_controllers = NULL, **kill_only_users = NULL, **kill_exclude_users = NULL;
 
322
        DBusError error;
 
323
        uint32_t uid, pid;
 
324
        DBusMessageIter iter;
 
325
        dbus_bool_t kp;
 
326
        int session_fd = -1;
 
327
        DBusConnection *bus = NULL;
 
328
        DBusMessage *m = NULL, *reply = NULL;
 
329
        dbus_bool_t remote, existing;
 
330
        int r;
 
331
        uint32_t vtnr = 0;
 
332
 
 
333
        assert(handle);
 
334
 
 
335
        dbus_error_init(&error);
 
336
 
 
337
        /* pam_syslog(handle, LOG_INFO, "pam-systemd initializing"); */
 
338
 
 
339
        /* Make this a NOP on non-logind systems */
 
340
        if (!logind_running())
 
341
                return PAM_SUCCESS;
 
342
 
 
343
        if (parse_argv(handle,
 
344
                       argc, argv,
 
345
                       &controllers, &reset_controllers,
 
346
                       &kill_processes, &kill_only_users, &kill_exclude_users,
 
347
                       &class_pam, &debug) < 0) {
 
348
                r = PAM_SESSION_ERR;
 
349
                goto finish;
 
350
        }
 
351
 
 
352
        r = get_user_data(handle, &username, &pw);
 
353
        if (r != PAM_SUCCESS)
 
354
                goto finish;
 
355
 
 
356
        /* Make sure we don't enter a loop by talking to
 
357
         * systemd-logind when it is actually waiting for the
 
358
         * background to finish start-up. If the service is
 
359
         * "systemd-shared" we simply set XDG_RUNTIME_DIR and
 
360
         * leave. */
 
361
 
 
362
        pam_get_item(handle, PAM_SERVICE, (const void**) &service);
 
363
        if (streq_ptr(service, "systemd-shared")) {
 
364
                char *p, *rt = NULL;
 
365
 
 
366
                if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) pw->pw_uid) < 0) {
 
367
                        r = PAM_BUF_ERR;
 
368
                        goto finish;
 
369
                }
 
370
 
 
371
                r = parse_env_file(p, NEWLINE,
 
372
                                   "RUNTIME", &rt,
 
373
                                   NULL);
 
374
                free(p);
 
375
 
 
376
                if (r < 0 && r != -ENOENT) {
 
377
                        r = PAM_SESSION_ERR;
 
378
                        free(rt);
 
379
                        goto finish;
 
380
                }
 
381
 
 
382
                if (rt)  {
 
383
                        r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0);
 
384
                        free(rt);
 
385
 
 
386
                        if (r != PAM_SUCCESS) {
 
387
                                pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
 
388
                                goto finish;
 
389
                        }
 
390
                }
 
391
 
 
392
                r = PAM_SUCCESS;
 
393
                goto finish;
 
394
        }
 
395
 
 
396
        if (kill_processes)
 
397
                kill_processes = check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users);
 
398
 
 
399
        dbus_connection_set_change_sigpipe(FALSE);
 
400
 
 
401
        bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
 
402
        if (!bus) {
 
403
                pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", bus_error_message(&error));
 
404
                r = PAM_SESSION_ERR;
 
405
                goto finish;
 
406
        }
 
407
 
 
408
        m = dbus_message_new_method_call(
 
409
                        "org.freedesktop.login1",
 
410
                        "/org/freedesktop/login1",
 
411
                        "org.freedesktop.login1.Manager",
 
412
                        "CreateSession");
 
413
        if (!m) {
 
414
                pam_syslog(handle, LOG_ERR, "Could not allocate create session message.");
 
415
                r = PAM_BUF_ERR;
 
416
                goto finish;
 
417
        }
 
418
 
 
419
        uid = pw->pw_uid;
 
420
        pid = getpid();
 
421
 
 
422
        pam_get_item(handle, PAM_XDISPLAY, (const void**) &display);
 
423
        pam_get_item(handle, PAM_TTY, (const void**) &tty);
 
424
        pam_get_item(handle, PAM_RUSER, (const void**) &remote_user);
 
425
        pam_get_item(handle, PAM_RHOST, (const void**) &remote_host);
 
426
 
 
427
        seat = pam_getenv(handle, "XDG_SEAT");
 
428
        if (isempty(seat))
 
429
                seat = getenv("XDG_SEAT");
 
430
 
 
431
        cvtnr = pam_getenv(handle, "XDG_VTNR");
 
432
        if (isempty(cvtnr))
 
433
                cvtnr = getenv("XDG_VTNR");
 
434
 
 
435
        service = strempty(service);
 
436
        tty = strempty(tty);
 
437
        display = strempty(display);
 
438
        remote_user = strempty(remote_user);
 
439
        remote_host = strempty(remote_host);
 
440
        seat = strempty(seat);
 
441
 
 
442
        if (strchr(tty, ':')) {
 
443
                /* A tty with a colon is usually an X11 display,
 
444
                 * placed there to show up in utmp. We rearrange
 
445
                 * things and don't pretend that an X display was a
 
446
                 * tty. */
 
447
 
 
448
                if (isempty(display))
 
449
                        display = tty;
 
450
                tty = "";
 
451
        } else if (streq(tty, "cron")) {
 
452
                /* cron has been setting PAM_TTY to "cron" for a very
 
453
                 * long time and it probably shouldn't stop doing that
 
454
                 * for compatibility reasons. */
 
455
                tty = "";
 
456
                type = "unspecified";
 
457
        } else if (streq(tty, "ssh")) {
 
458
                /* ssh has been setting PAM_TTY to "ssh" for a very
 
459
                 * long time and probably shouldn't stop doing that
 
460
                 * for compatibility reasons. */
 
461
                tty = "";
 
462
                type ="tty";
 
463
        }
 
464
 
 
465
        /* If this fails vtnr will be 0, that's intended */
 
466
        if (!isempty(cvtnr))
 
467
                safe_atou32(cvtnr, &vtnr);
 
468
 
 
469
        if (!isempty(display) && vtnr <= 0) {
 
470
                if (isempty(seat))
 
471
                        get_seat_from_display(display, &seat, &vtnr);
 
472
                else if (streq(seat, "seat0"))
 
473
                        get_seat_from_display(display, NULL, &vtnr);
 
474
        }
 
475
 
 
476
        if (!type)
 
477
                type = !isempty(display) ? "x11" :
 
478
                        !isempty(tty) ? "tty" : "unspecified";
 
479
 
 
480
        class = pam_getenv(handle, "XDG_SESSION_CLASS");
 
481
        if (isempty(class))
 
482
                class = getenv("XDG_SESSION_CLASS");
 
483
        if (isempty(class))
 
484
                class = class_pam;
 
485
        if (isempty(class))
 
486
                class = streq(type, "unspecified") ? "background" : "user";
 
487
 
 
488
        remote = !isempty(remote_host) &&
 
489
                !streq(remote_host, "localhost") &&
 
490
                !streq(remote_host, "localhost.localdomain");
 
491
 
 
492
        if (!dbus_message_append_args(m,
 
493
                                      DBUS_TYPE_UINT32, &uid,
 
494
                                      DBUS_TYPE_UINT32, &pid,
 
495
                                      DBUS_TYPE_STRING, &service,
 
496
                                      DBUS_TYPE_STRING, &type,
 
497
                                      DBUS_TYPE_STRING, &class,
 
498
                                      DBUS_TYPE_STRING, &seat,
 
499
                                      DBUS_TYPE_UINT32, &vtnr,
 
500
                                      DBUS_TYPE_STRING, &tty,
 
501
                                      DBUS_TYPE_STRING, &display,
 
502
                                      DBUS_TYPE_BOOLEAN, &remote,
 
503
                                      DBUS_TYPE_STRING, &remote_user,
 
504
                                      DBUS_TYPE_STRING, &remote_host,
 
505
                                      DBUS_TYPE_INVALID)) {
 
506
                pam_syslog(handle, LOG_ERR, "Could not attach parameters to message.");
 
507
                r = PAM_BUF_ERR;
 
508
                goto finish;
 
509
        }
 
510
 
 
511
        dbus_message_iter_init_append(m, &iter);
 
512
 
 
513
        r = bus_append_strv_iter(&iter, controllers);
 
514
        if (r < 0) {
 
515
                pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
 
516
                r = PAM_BUF_ERR;
 
517
                goto finish;
 
518
        }
 
519
 
 
520
        r = bus_append_strv_iter(&iter, reset_controllers);
 
521
        if (r < 0) {
 
522
                pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
 
523
                r = PAM_BUF_ERR;
 
524
                goto finish;
 
525
        }
 
526
 
 
527
        kp = kill_processes;
 
528
        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &kp)) {
 
529
                pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
 
530
                r = PAM_BUF_ERR;
 
531
                goto finish;
 
532
        }
 
533
 
 
534
        if (debug)
 
535
                pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: "
 
536
                           "uid=%u pid=%u service=%s type=%s class=%s seat=%s vtnr=%u tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
 
537
                           uid, pid, service, type, class, seat, vtnr, tty, display, yes_no(remote), remote_user, remote_host);
 
538
 
 
539
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
 
540
        if (!reply) {
 
541
                pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error));
 
542
                r = PAM_SESSION_ERR;
 
543
                goto finish;
 
544
        }
 
545
 
 
546
        if (!dbus_message_get_args(reply, &error,
 
547
                                   DBUS_TYPE_STRING, &id,
 
548
                                   DBUS_TYPE_OBJECT_PATH, &object_path,
 
549
                                   DBUS_TYPE_STRING, &runtime_path,
 
550
                                   DBUS_TYPE_UNIX_FD, &session_fd,
 
551
                                   DBUS_TYPE_STRING, &seat,
 
552
                                   DBUS_TYPE_UINT32, &vtnr,
 
553
                                   DBUS_TYPE_BOOLEAN, &existing,
 
554
                                   DBUS_TYPE_INVALID)) {
 
555
                pam_syslog(handle, LOG_ERR, "Failed to parse message: %s", bus_error_message(&error));
 
556
                r = PAM_SESSION_ERR;
 
557
                goto finish;
 
558
        }
 
559
 
 
560
        if (debug)
 
561
                pam_syslog(handle, LOG_DEBUG, "Reply from logind: "
 
562
                           "id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u",
 
563
                           id, object_path, runtime_path, session_fd, seat, vtnr);
 
564
 
 
565
        r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0);
 
566
        if (r != PAM_SUCCESS) {
 
567
                pam_syslog(handle, LOG_ERR, "Failed to set session id.");
 
568
                goto finish;
 
569
        }
 
570
 
 
571
        r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", runtime_path, 0);
 
572
        if (r != PAM_SUCCESS) {
 
573
                pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
 
574
                goto finish;
 
575
        }
 
576
 
 
577
        if (!isempty(seat)) {
 
578
                r = pam_misc_setenv(handle, "XDG_SEAT", seat, 0);
 
579
                if (r != PAM_SUCCESS) {
 
580
                        pam_syslog(handle, LOG_ERR, "Failed to set seat.");
 
581
                        goto finish;
 
582
                }
 
583
        }
 
584
 
 
585
        if (vtnr > 0) {
 
586
                char buf[11];
 
587
                snprintf(buf, sizeof(buf), "%u", vtnr);
 
588
                char_array_0(buf);
 
589
 
 
590
                r = pam_misc_setenv(handle, "XDG_VTNR", buf, 0);
 
591
                if (r != PAM_SUCCESS) {
 
592
                        pam_syslog(handle, LOG_ERR, "Failed to set virtual terminal number.");
 
593
                        goto finish;
 
594
                }
 
595
        }
 
596
 
 
597
        r = pam_set_data(handle, "systemd.existing", INT_TO_PTR(!!existing), NULL);
 
598
        if (r != PAM_SUCCESS) {
 
599
                pam_syslog(handle, LOG_ERR, "Failed to install existing flag.");
 
600
                return r;
 
601
        }
 
602
 
 
603
        if (session_fd >= 0) {
 
604
                r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL);
 
605
                if (r != PAM_SUCCESS) {
 
606
                        pam_syslog(handle, LOG_ERR, "Failed to install session fd.");
 
607
                        return r;
 
608
                }
 
609
        }
 
610
 
 
611
        session_fd = -1;
 
612
 
 
613
        r = PAM_SUCCESS;
 
614
 
 
615
finish:
 
616
        strv_free(controllers);
 
617
        strv_free(reset_controllers);
 
618
        strv_free(kill_only_users);
 
619
        strv_free(kill_exclude_users);
 
620
 
 
621
        dbus_error_free(&error);
 
622
 
 
623
        if (bus) {
 
624
                dbus_connection_close(bus);
 
625
                dbus_connection_unref(bus);
 
626
        }
 
627
 
 
628
        if (m)
 
629
                dbus_message_unref(m);
 
630
 
 
631
        if (reply)
 
632
                dbus_message_unref(reply);
 
633
 
 
634
        if (session_fd >= 0)
 
635
                close_nointr_nofail(session_fd);
 
636
 
 
637
        return r;
 
638
}
 
639
 
 
640
_public_ PAM_EXTERN int pam_sm_close_session(
 
641
                pam_handle_t *handle,
 
642
                int flags,
 
643
                int argc, const char **argv) {
 
644
 
 
645
        const void *p = NULL, *existing = NULL;
 
646
        const char *id;
 
647
        DBusConnection *bus = NULL;
 
648
        DBusMessage *m = NULL, *reply = NULL;
 
649
        DBusError error;
 
650
        int r;
 
651
 
 
652
        assert(handle);
 
653
 
 
654
        dbus_error_init(&error);
 
655
 
 
656
        /* Only release session if it wasn't pre-existing when we
 
657
         * tried to create it */
 
658
        pam_get_data(handle, "systemd.existing", &existing);
 
659
 
 
660
        id = pam_getenv(handle, "XDG_SESSION_ID");
 
661
        if (id && !existing) {
 
662
 
 
663
                /* Before we go and close the FIFO we need to tell
 
664
                 * logind that this is a clean session shutdown, so
 
665
                 * that it doesn't just go and slaughter us
 
666
                 * immediately after closing the fd */
 
667
 
 
668
                bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
 
669
                if (!bus) {
 
670
                        pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", bus_error_message(&error));
 
671
                        r = PAM_SESSION_ERR;
 
672
                        goto finish;
 
673
                }
 
674
 
 
675
                m = dbus_message_new_method_call(
 
676
                                "org.freedesktop.login1",
 
677
                                "/org/freedesktop/login1",
 
678
                                "org.freedesktop.login1.Manager",
 
679
                                "ReleaseSession");
 
680
                if (!m) {
 
681
                        pam_syslog(handle, LOG_ERR, "Could not allocate release session message.");
 
682
                        r = PAM_BUF_ERR;
 
683
                        goto finish;
 
684
                }
 
685
 
 
686
                if (!dbus_message_append_args(m,
 
687
                                              DBUS_TYPE_STRING, &id,
 
688
                                              DBUS_TYPE_INVALID)) {
 
689
                        pam_syslog(handle, LOG_ERR, "Could not attach parameters to message.");
 
690
                        r = PAM_BUF_ERR;
 
691
                        goto finish;
 
692
                }
 
693
 
 
694
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
 
695
                if (!reply) {
 
696
                        pam_syslog(handle, LOG_ERR, "Failed to release session: %s", bus_error_message(&error));
 
697
                        r = PAM_SESSION_ERR;
 
698
                        goto finish;
 
699
                }
 
700
        }
 
701
 
 
702
        r = PAM_SUCCESS;
 
703
 
 
704
finish:
 
705
        pam_get_data(handle, "systemd.session-fd", &p);
 
706
        if (p)
 
707
                close_nointr(PTR_TO_INT(p) - 1);
 
708
 
 
709
        dbus_error_free(&error);
 
710
 
 
711
        if (bus) {
 
712
                dbus_connection_close(bus);
 
713
                dbus_connection_unref(bus);
 
714
        }
 
715
 
 
716
        if (m)
 
717
                dbus_message_unref(m);
 
718
 
 
719
        if (reply)
 
720
                dbus_message_unref(reply);
 
721
 
 
722
        return r;
 
723
}