]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/pam-module.c
scope: fix state string table
[thirdparty/systemd.git] / src / login / pam-module.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8c6db833
LP
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
5430f7f2
LP
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
8c6db833
LP
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
5430f7f2 16 Lesser General Public License for more details.
8c6db833 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
8c6db833
LP
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>
a838e6a1 26#include <endian.h>
ac123445 27#include <sys/capability.h>
8c6db833
LP
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
8c6db833 35#include "util.h"
d7832d2c 36#include "audit.h"
8c6db833 37#include "macro.h"
74fe1fe3 38#include "strv.h"
98a28fef
LP
39#include "dbus-common.h"
40#include "def.h"
4d6d6518 41#include "socket-util.h"
a5c32cff 42#include "fileio.h"
8c6db833
LP
43
44static int parse_argv(pam_handle_t *handle,
45 int argc, const char **argv,
b20c6be6 46 char ***controllers,
e9fbc77c 47 char ***reset_controllers,
98a28fef 48 bool *kill_processes,
e9fbc77c 49 char ***kill_only_users,
0e318cad 50 char ***kill_exclude_users,
485507b8 51 const char **class,
0e318cad 52 bool *debug) {
8c6db833
LP
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
c36eecdf
LP
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.");
8c6db833
LP
65 return k;
66 }
67
98a28fef
LP
68 if (kill_processes)
69 *kill_processes = k;
74fe1fe3 70
8c6db833 71 } else if (startswith(argv[i], "kill-session=")) {
98a28fef
LP
72 /* As compatibility for old versions */
73
8c6db833
LP
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
98a28fef
LP
79 if (kill_processes)
80 *kill_processes = k;
74fe1fe3
LP
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
b20c6be6
LP
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
e9fbc77c
LP
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
485507b8
MM
138 } else if (startswith(argv[i], "class=")) {
139
140 if (class)
141 *class = argv[i] + 6;
142
0e318cad
MS
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
98a28fef
LP
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
8c6db833
LP
157 } else {
158 pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]);
159 return -EINVAL;
160 }
161 }
162
8c6db833
LP
163 return 0;
164}
165
8c6db833
LP
166static int get_user_data(
167 pam_handle_t *handle,
168 const char **ret_username,
169 struct passwd **ret_pw) {
170
d90b9d27
LP
171 const char *username = NULL;
172 struct passwd *pw = NULL;
87d2c1ff 173 uid_t uid;
8c6db833
LP
174 int r;
175
176 assert(handle);
177 assert(ret_username);
178 assert(ret_pw);
179
87d2c1ff
LP
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) {
d90b9d27
LP
186 pam_syslog(handle, LOG_ERR, "Failed to get user name.");
187 return r;
188 }
189
87d2c1ff 190 if (isempty(username)) {
d90b9d27
LP
191 pam_syslog(handle, LOG_ERR, "User name not valid.");
192 return PAM_AUTH_ERR;
193 }
194
195 pw = pam_modutil_getpwnam(handle, username);
8c6db833
LP
196 }
197
d90b9d27 198 if (!pw) {
8c6db833
LP
199 pam_syslog(handle, LOG_ERR, "Failed to get user data.");
200 return PAM_USER_UNKNOWN;
201 }
202
203 *ret_pw = pw;
d90b9d27 204 *ret_username = username ? username : pw->pw_name;
8c6db833
LP
205
206 return PAM_SUCCESS;
207}
208
e9fbc77c
LP
209static 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
98a28fef
LP
225 pw = pam_modutil_getpwuid(handle, uid);
226 if (pw)
e9fbc77c
LP
227 name = pw->pw_name;
228 }
229
230 STRV_FOREACH(l, kill_exclude_users) {
ddd88763 231 uid_t u;
e9fbc77c 232
ddd88763
LP
233 if (parse_uid(*l, &u) >= 0)
234 if (u == uid)
e9fbc77c
LP
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) {
ddd88763 245 uid_t u;
e9fbc77c 246
ddd88763
LP
247 if (parse_uid(*l, &u) >= 0)
248 if (u == uid)
e9fbc77c
LP
249 return true;
250
251 if (name && streq(name, *l))
252 return true;
253 }
254
255 return false;
256}
257
4d6d6518 258static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) {
7fd1b19b 259 _cleanup_free_ char *p = NULL;
4d6d6518 260 int r;
7fd1b19b 261 _cleanup_close_ int fd = -1;
b92bea5d
ZJS
262 union sockaddr_union sa = {
263 .un.sun_family = AF_UNIX,
264 };
4d6d6518
LP
265 struct ucred ucred;
266 socklen_t l;
7fd1b19b 267 _cleanup_free_ char *tty = NULL;
4d6d6518
LP
268 int v;
269
270 assert(display);
4d6d6518
LP
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;
b92bea5d 282 strncpy(sa.un.sun_path, p, sizeof(sa.un.sun_path)-1);
4d6d6518
LP
283
284 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
b92bea5d 285 if (fd < 0)
4d6d6518 286 return -errno;
4d6d6518 287
b92bea5d 288 if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
4d6d6518 289 return -errno;
4d6d6518
LP
290
291 l = sizeof(ucred);
292 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
4d6d6518
LP
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);
4d6d6518
LP
301 if (v < 0)
302 return v;
303 else if (v == 0)
304 return -ENOENT;
305
fc7985ed
LP
306 if (seat)
307 *seat = "seat0";
4d6d6518
LP
308 *vtnr = (uint32_t) v;
309
310 return 0;
311}
312
98a28fef 313_public_ PAM_EXTERN int pam_sm_open_session(
8c6db833
LP
314 pam_handle_t *handle,
315 int flags,
316 int argc, const char **argv) {
317
8c6db833 318 struct passwd *pw;
98a28fef 319 bool kill_processes = false, debug = false;
485507b8 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;
98a28fef 321 char **controllers = NULL, **reset_controllers = NULL, **kill_only_users = NULL, **kill_exclude_users = NULL;
98a28fef
LP
322 DBusError error;
323 uint32_t uid, pid;
324 DBusMessageIter iter;
325 dbus_bool_t kp;
98a28fef
LP
326 int session_fd = -1;
327 DBusConnection *bus = NULL;
328 DBusMessage *m = NULL, *reply = NULL;
77085881 329 dbus_bool_t remote, existing;
ed18b08b 330 int r;
4d6d6518 331 uint32_t vtnr = 0;
8c6db833
LP
332
333 assert(handle);
334
98a28fef
LP
335 dbus_error_init(&error);
336
ed18b08b 337 /* pam_syslog(handle, LOG_INFO, "pam-systemd initializing"); */
98a28fef 338
79d860fe
MP
339 /* Make this a NOP on non-logind systems */
340 if (!logind_running())
8c6db833
LP
341 return PAM_SUCCESS;
342
e9fbc77c
LP
343 if (parse_argv(handle,
344 argc, argv,
98a28fef
LP
345 &controllers, &reset_controllers,
346 &kill_processes, &kill_only_users, &kill_exclude_users,
485507b8 347 &class_pam, &debug) < 0) {
ed18b08b
LP
348 r = PAM_SESSION_ERR;
349 goto finish;
350 }
74fe1fe3 351
98a28fef
LP
352 r = get_user_data(handle, &username, &pw);
353 if (r != PAM_SUCCESS)
8c6db833
LP
354 goto finish;
355
30b2c336
LP
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
98a28fef
LP
396 if (kill_processes)
397 kill_processes = check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users);
1f73f0f1 398
ed18b08b
LP
399 dbus_connection_set_change_sigpipe(FALSE);
400
98a28fef
LP
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;
8c6db833
LP
405 goto finish;
406 }
407
98a28fef
LP
408 m = dbus_message_new_method_call(
409 "org.freedesktop.login1",
410 "/org/freedesktop/login1",
411 "org.freedesktop.login1.Manager",
412 "CreateSession");
98a28fef
LP
413 if (!m) {
414 pam_syslog(handle, LOG_ERR, "Could not allocate create session message.");
8c6db833
LP
415 r = PAM_BUF_ERR;
416 goto finish;
417 }
418
98a28fef
LP
419 uid = pw->pw_uid;
420 pid = getpid();
421
98a28fef
LP
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);
a8573ccc 426
bbc73283 427 seat = pam_getenv(handle, "XDG_SEAT");
a8573ccc
LP
428 if (isempty(seat))
429 seat = getenv("XDG_SEAT");
430
bbc73283 431 cvtnr = pam_getenv(handle, "XDG_VTNR");
a8573ccc
LP
432 if (isempty(cvtnr))
433 cvtnr = getenv("XDG_VTNR");
98a28fef 434
ed18b08b
LP
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);
98a28fef 441
ee8545b0 442 if (strchr(tty, ':')) {
e2acb67b
LP
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. */
ee8545b0
LP
447
448 if (isempty(display))
449 display = tty;
cd58752a 450 tty = "";
1a4459d6 451 } else if (streq(tty, "cron")) {
0ad1271f
LP
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. */
1a4459d6 455 tty = "";
0ad1271f
LP
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";
ee8545b0
LP
463 }
464
8e7705e5 465 /* If this fails vtnr will be 0, that's intended */
4d6d6518
LP
466 if (!isempty(cvtnr))
467 safe_atou32(cvtnr, &vtnr);
468
fc7985ed
LP
469 if (!isempty(display) && vtnr <= 0) {
470 if (isempty(seat))
6ef25fb6 471 get_seat_from_display(display, &seat, &vtnr);
fc7985ed 472 else if (streq(seat, "seat0"))
6ef25fb6 473 get_seat_from_display(display, NULL, &vtnr);
fc7985ed 474 }
4d6d6518 475
0ad1271f
LP
476 if (!type)
477 type = !isempty(display) ? "x11" :
478 !isempty(tty) ? "tty" : "unspecified";
98a28fef 479
55efac6c 480 class = pam_getenv(handle, "XDG_SESSION_CLASS");
a8573ccc
LP
481 if (isempty(class))
482 class = getenv("XDG_SESSION_CLASS");
485507b8
MM
483 if (isempty(class))
484 class = class_pam;
55efac6c 485 if (isempty(class))
e2acb67b 486 class = streq(type, "unspecified") ? "background" : "user";
55efac6c
LP
487
488 remote = !isempty(remote_host) &&
489 !streq(remote_host, "localhost") &&
490 !streq(remote_host, "localhost.localdomain");
98a28fef
LP
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,
55efac6c 497 DBUS_TYPE_STRING, &class,
98a28fef 498 DBUS_TYPE_STRING, &seat,
4d6d6518 499 DBUS_TYPE_UINT32, &vtnr,
98a28fef
LP
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 }
8c6db833 510
98a28fef 511 dbus_message_iter_init_append(m, &iter);
8c6db833 512
98a28fef
LP
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 }
672c48cc 519
98a28fef
LP
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 }
672c48cc 526
98a28fef
LP
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 }
8c6db833 533
ce959314
MS
534 if (debug)
535 pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: "
f904bdf2
CG
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);
ce959314 538
98a28fef
LP
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 }
74fe1fe3 545
98a28fef
LP
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,
bbc73283
LP
551 DBUS_TYPE_STRING, &seat,
552 DBUS_TYPE_UINT32, &vtnr,
77085881 553 DBUS_TYPE_BOOLEAN, &existing,
98a28fef
LP
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 }
74fe1fe3 559
ce959314
MS
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
98a28fef
LP
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;
8c6db833
LP
569 }
570
98a28fef
LP
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 }
8c6db833 576
bbc73283
LP
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
77085881
LP
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
21c390cc
LP
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 }
98a28fef 609 }
8c6db833 610
98a28fef 611 session_fd = -1;
8c6db833 612
98a28fef 613 r = PAM_SUCCESS;
8c6db833 614
98a28fef
LP
615finish:
616 strv_free(controllers);
617 strv_free(reset_controllers);
618 strv_free(kill_only_users);
619 strv_free(kill_exclude_users);
8c6db833 620
98a28fef 621 dbus_error_free(&error);
35d2e7ec 622
98a28fef
LP
623 if (bus) {
624 dbus_connection_close(bus);
625 dbus_connection_unref(bus);
8c6db833
LP
626 }
627
98a28fef
LP
628 if (m)
629 dbus_message_unref(m);
8c6db833 630
ed18b08b
LP
631 if (reply)
632 dbus_message_unref(reply);
633
98a28fef
LP
634 if (session_fd >= 0)
635 close_nointr_nofail(session_fd);
672c48cc 636
98a28fef
LP
637 return r;
638}
8c6db833 639
98a28fef
LP
640_public_ PAM_EXTERN int pam_sm_close_session(
641 pam_handle_t *handle,
642 int flags,
643 int argc, const char **argv) {
8c6db833 644
77085881 645 const void *p = NULL, *existing = NULL;
75c8e3cf
LP
646 const char *id;
647 DBusConnection *bus = NULL;
648 DBusMessage *m = NULL, *reply = NULL;
649 DBusError error;
650 int r;
8c6db833 651
75c8e3cf
LP
652 assert(handle);
653
654 dbus_error_init(&error);
655
77085881
LP
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
75c8e3cf 660 id = pam_getenv(handle, "XDG_SESSION_ID");
77085881 661 if (id && !existing) {
75c8e3cf
LP
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 }
74fe1fe3 693
75c8e3cf
LP
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
704finish:
705 pam_get_data(handle, "systemd.session-fd", &p);
98a28fef
LP
706 if (p)
707 close_nointr(PTR_TO_INT(p) - 1);
1f73f0f1 708
75c8e3cf
LP
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;
8c6db833 723}