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

« back to all changes in this revision

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