1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <security/pam_ext.h>
4 #include <security/pam_modules.h>
8 #include "bus-common-errors.h"
9 #include "errno-util.h"
11 #include "home-util.h"
12 #include "memory-util.h"
14 #include "parse-util.h"
16 #include "user-record-util.h"
17 #include "user-record.h"
18 #include "user-util.h"
20 /* Used for the "systemd-user-record-is-homed" PAM data field, to indicate whether we know whether this user
21 * record is managed by homed or by something else. */
22 #define USER_RECORD_IS_HOMED INT_TO_PTR(1)
23 #define USER_RECORD_IS_OTHER INT_TO_PTR(2)
25 static int parse_argv(
27 int argc
, const char **argv
,
34 assert(argc
== 0 || argv
);
36 for (i
= 0; i
< argc
; i
++) {
39 if ((v
= startswith(argv
[i
], "suspend="))) {
44 pam_syslog(handle
, LOG_WARNING
, "Failed to parse suspend= argument, ignoring: %s", v
);
45 else if (please_suspend
)
48 } else if ((v
= startswith(argv
[i
], "debug="))) {
53 pam_syslog(handle
, LOG_WARNING
, "Failed to parse debug= argument, ignoring: %s", v
);
58 pam_syslog(handle
, LOG_WARNING
, "Unknown parameter '%s', ignoring", argv
[i
]);
64 static int acquire_user_record(
66 UserRecord
**ret_record
) {
68 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
69 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
70 _cleanup_(user_record_unrefp
) UserRecord
*ur
= NULL
;
71 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
72 const char *username
= NULL
, *json
= NULL
;
78 r
= pam_get_user(handle
, &username
, NULL
);
79 if (r
!= PAM_SUCCESS
) {
80 pam_syslog(handle
, LOG_ERR
, "Failed to get user name: %s", pam_strerror(handle
, r
));
84 if (isempty(username
)) {
85 pam_syslog(handle
, LOG_ERR
, "User name not set.");
86 return PAM_SERVICE_ERR
;
89 /* Let's bypass all IPC complexity for the two user names we know for sure we don't manage, and for
90 * user names we don't consider valid. */
91 if (STR_IN_SET(username
, "root", NOBODY_USER_NAME
) || !valid_user_group_name(username
, 0))
92 return PAM_USER_UNKNOWN
;
94 /* Let's check if a previous run determined that this user is not managed by homed. If so, let's exit early */
95 r
= pam_get_data(handle
, "systemd-user-record-is-homed", &b
);
96 if (!IN_SET(r
, PAM_SUCCESS
, PAM_NO_MODULE_DATA
)) {
98 pam_syslog(handle
, LOG_ERR
, "Failed to get PAM user-record-is-homed flag: %s", pam_strerror(handle
, r
));
100 } else if (b
== NULL
)
101 /* Nothing cached yet, need to acquire fresh */
103 else if (b
!= USER_RECORD_IS_HOMED
)
104 /* Definitely not a homed record */
105 return PAM_USER_UNKNOWN
;
107 /* It's a homed record, let's use the cache, so that we can share it between the session and
108 * the authentication hooks */
109 r
= pam_get_data(handle
, "systemd-user-record", (const void**) &json
);
110 if (!IN_SET(r
, PAM_SUCCESS
, PAM_NO_MODULE_DATA
)) {
111 pam_syslog(handle
, LOG_ERR
, "Failed to get PAM user record data: %s", pam_strerror(handle
, r
));
117 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
118 _cleanup_free_
char *json_copy
= NULL
;
120 r
= pam_acquire_bus_connection(handle
, &bus
);
121 if (r
!= PAM_SUCCESS
)
124 r
= sd_bus_call_method(
126 "org.freedesktop.home1",
127 "/org/freedesktop/home1",
128 "org.freedesktop.home1.Manager",
129 "GetUserRecordByName",
135 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_SERVICE_UNKNOWN
) ||
136 sd_bus_error_has_name(&error
, SD_BUS_ERROR_NAME_HAS_NO_OWNER
)) {
137 pam_syslog(handle
, LOG_DEBUG
, "systemd-homed is not available: %s", bus_error_message(&error
, r
));
141 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_HOME
)) {
142 pam_syslog(handle
, LOG_DEBUG
, "Not a user managed by systemd-homed: %s", bus_error_message(&error
, r
));
146 pam_syslog(handle
, LOG_ERR
, "Failed to query user record: %s", bus_error_message(&error
, r
));
147 return PAM_SERVICE_ERR
;
150 r
= sd_bus_message_read(reply
, "sbo", &json
, NULL
, NULL
);
152 return pam_bus_log_parse_error(handle
, r
);
154 json_copy
= strdup(json
);
156 return pam_log_oom(handle
);
158 r
= pam_set_data(handle
, "systemd-user-record", json_copy
, pam_cleanup_free
);
159 if (r
!= PAM_SUCCESS
) {
160 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM user record data: %s", pam_strerror(handle
, r
));
166 r
= pam_set_data(handle
, "systemd-user-record-is-homed", USER_RECORD_IS_HOMED
, NULL
);
167 if (r
!= PAM_SUCCESS
) {
168 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM user record is homed flag: %s", pam_strerror(handle
, r
));
173 r
= json_parse(json
, JSON_PARSE_SENSITIVE
, &v
, NULL
, NULL
);
175 pam_syslog(handle
, LOG_ERR
, "Failed to parse JSON user record: %s", strerror_safe(r
));
176 return PAM_SERVICE_ERR
;
179 ur
= user_record_new();
181 return pam_log_oom(handle
);
183 r
= user_record_load(ur
, v
, USER_RECORD_LOAD_REFUSE_SECRET
);
185 pam_syslog(handle
, LOG_ERR
, "Failed to load user record: %s", strerror_safe(r
));
186 return PAM_SERVICE_ERR
;
189 if (!streq_ptr(username
, ur
->user_name
)) {
190 pam_syslog(handle
, LOG_ERR
, "Acquired user record does not match user name.");
191 return PAM_SERVICE_ERR
;
195 *ret_record
= TAKE_PTR(ur
);
200 /* Cache this, so that we don't check again */
201 r
= pam_set_data(handle
, "systemd-user-record-is-homed", USER_RECORD_IS_OTHER
, NULL
);
202 if (r
!= PAM_SUCCESS
)
203 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM user-record-is-homed flag, ignoring: %s", pam_strerror(handle
, r
));
205 return PAM_USER_UNKNOWN
;
208 static int release_user_record(pam_handle_t
*handle
) {
211 r
= pam_set_data(handle
, "systemd-user-record", NULL
, NULL
);
212 if (r
!= PAM_SUCCESS
)
213 pam_syslog(handle
, LOG_ERR
, "Failed to release PAM user record data: %s", pam_strerror(handle
, r
));
215 k
= pam_set_data(handle
, "systemd-user-record-is-homed", NULL
, NULL
);
216 if (k
!= PAM_SUCCESS
)
217 pam_syslog(handle
, LOG_ERR
, "Failed to release PAM user-record-is-homed flag: %s", pam_strerror(handle
, k
));
219 return IN_SET(r
, PAM_SUCCESS
, PAM_NO_MODULE_DATA
) ? k
: r
;
222 static void cleanup_home_fd(pam_handle_t
*handle
, void *data
, int error_status
) {
223 safe_close(PTR_TO_FD(data
));
226 static int handle_generic_user_record_error(
227 pam_handle_t
*handle
,
228 const char *user_name
,
231 const sd_bus_error
*error
) {
239 /* Logs about all errors, except for PAM_CONV_ERR, i.e. when requesting more info failed. */
241 if (sd_bus_error_has_name(error
, BUS_ERROR_HOME_ABSENT
)) {
242 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Home of user %s is currently absent, please plug in the necessary storage device or backing file system.", user_name
);
243 pam_syslog(handle
, LOG_ERR
, "Failed to acquire home for user %s: %s", user_name
, bus_error_message(error
, ret
));
244 return PAM_PERM_DENIED
;
246 } else if (sd_bus_error_has_name(error
, BUS_ERROR_AUTHENTICATION_LIMIT_HIT
)) {
247 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Too frequent unsuccessful login attempts for user %s, try again later.", user_name
);
248 pam_syslog(handle
, LOG_ERR
, "Failed to acquire home for user %s: %s", user_name
, bus_error_message(error
, ret
));
251 } else if (sd_bus_error_has_name(error
, BUS_ERROR_BAD_PASSWORD
)) {
252 _cleanup_(erase_and_freep
) char *newp
= NULL
;
254 /* This didn't work? Ask for an (additional?) password */
256 if (strv_isempty(secret
->password
))
257 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Password: ");
259 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Password incorrect or not sufficient for authentication of user %s, please try again: ", user_name
);
260 if (r
!= PAM_SUCCESS
)
261 return PAM_CONV_ERR
; /* no logging here */
264 pam_syslog(handle
, LOG_DEBUG
, "Password request aborted.");
265 return PAM_AUTHTOK_ERR
;
268 r
= user_record_set_password(secret
, STRV_MAKE(newp
), true);
270 pam_syslog(handle
, LOG_ERR
, "Failed to store password: %s", strerror_safe(r
));
271 return PAM_SERVICE_ERR
;
274 } else if (sd_bus_error_has_name(error
, BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN
)) {
275 _cleanup_(erase_and_freep
) char *newp
= NULL
;
277 if (strv_isempty(secret
->password
))
278 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Security token of user %s not inserted, please enter password: ", user_name
);
280 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Password incorrect or not sufficient, and configured security token of user %s not inserted, please enter password: ", user_name
);
281 if (r
!= PAM_SUCCESS
)
282 return PAM_CONV_ERR
; /* no logging here */
285 pam_syslog(handle
, LOG_DEBUG
, "Password request aborted.");
286 return PAM_AUTHTOK_ERR
;
289 r
= user_record_set_password(secret
, STRV_MAKE(newp
), true);
291 pam_syslog(handle
, LOG_ERR
, "Failed to store password: %s", strerror_safe(r
));
292 return PAM_SERVICE_ERR
;
295 } else if (sd_bus_error_has_name(error
, BUS_ERROR_TOKEN_PIN_NEEDED
)) {
296 _cleanup_(erase_and_freep
) char *newp
= NULL
;
298 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Please enter security token PIN: ");
299 if (r
!= PAM_SUCCESS
)
300 return PAM_CONV_ERR
; /* no logging here */
303 pam_syslog(handle
, LOG_DEBUG
, "PIN request aborted.");
304 return PAM_AUTHTOK_ERR
;
307 r
= user_record_set_pkcs11_pin(secret
, STRV_MAKE(newp
), false);
309 pam_syslog(handle
, LOG_ERR
, "Failed to store PIN: %s", strerror_safe(r
));
310 return PAM_SERVICE_ERR
;
313 } else if (sd_bus_error_has_name(error
, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED
)) {
315 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Please authenticate physically on security token of user %s.", user_name
);
317 r
= user_record_set_pkcs11_protected_authentication_path_permitted(secret
, true);
319 pam_syslog(handle
, LOG_ERR
, "Failed to set PKCS#11 protected authentication path permitted flag: %s", strerror_safe(r
));
320 return PAM_SERVICE_ERR
;
323 } else if (sd_bus_error_has_name(error
, BUS_ERROR_TOKEN_BAD_PIN
)) {
324 _cleanup_(erase_and_freep
) char *newp
= NULL
;
326 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Security token PIN incorrect, please enter PIN for security token of user %s again: ", user_name
);
327 if (r
!= PAM_SUCCESS
)
328 return PAM_CONV_ERR
; /* no logging here */
331 pam_syslog(handle
, LOG_DEBUG
, "PIN request aborted.");
332 return PAM_AUTHTOK_ERR
;
335 r
= user_record_set_pkcs11_pin(secret
, STRV_MAKE(newp
), false);
337 pam_syslog(handle
, LOG_ERR
, "Failed to store PIN: %s", strerror_safe(r
));
338 return PAM_SERVICE_ERR
;
341 } else if (sd_bus_error_has_name(error
, BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT
)) {
342 _cleanup_(erase_and_freep
) char *newp
= NULL
;
344 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Security token PIN incorrect (only a few tries left!), please enter PIN for security token of user %s again: ", user_name
);
345 if (r
!= PAM_SUCCESS
)
346 return PAM_CONV_ERR
; /* no logging here */
349 pam_syslog(handle
, LOG_DEBUG
, "PIN request aborted.");
350 return PAM_AUTHTOK_ERR
;
353 r
= user_record_set_pkcs11_pin(secret
, STRV_MAKE(newp
), false);
355 pam_syslog(handle
, LOG_ERR
, "Failed to store PIN: %s", strerror_safe(r
));
356 return PAM_SERVICE_ERR
;
359 } else if (sd_bus_error_has_name(error
, BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT
)) {
360 _cleanup_(erase_and_freep
) char *newp
= NULL
;
362 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Security token PIN incorrect (only one try left!), please enter PIN for security token of user %s again: ", user_name
);
363 if (r
!= PAM_SUCCESS
)
364 return PAM_CONV_ERR
; /* no logging here */
367 pam_syslog(handle
, LOG_DEBUG
, "PIN request aborted.");
368 return PAM_AUTHTOK_ERR
;
371 r
= user_record_set_pkcs11_pin(secret
, STRV_MAKE(newp
), false);
373 pam_syslog(handle
, LOG_ERR
, "Failed to store PIN: %s", strerror_safe(r
));
374 return PAM_SERVICE_ERR
;
378 pam_syslog(handle
, LOG_ERR
, "Failed to acquire home for user %s: %s", user_name
, bus_error_message(error
, ret
));
379 return PAM_SERVICE_ERR
;
385 static int acquire_home(
386 pam_handle_t
*handle
,
387 bool please_authenticate
,
391 _cleanup_(user_record_unrefp
) UserRecord
*ur
= NULL
, *secret
= NULL
;
392 bool do_auth
= please_authenticate
, home_not_active
= false, home_locked
= false;
393 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
394 _cleanup_close_
int acquired_fd
= -1;
395 const void *home_fd_ptr
= NULL
;
396 unsigned n_attempts
= 0;
401 /* This acquires a reference to a home directory in one of two ways: if please_authenticate is true,
402 * then we'll call AcquireHome() after asking the user for a password. Otherwise it tries to call
403 * RefHome() and if that fails queries the user for a password and uses AcquireHome().
405 * The idea is that the PAM authentication hook sets please_authenticate and thus always
406 * authenticates, while the other PAM hooks unset it so that they can a ref of their own without
407 * authentication if possible, but with authentication if necessary. */
409 /* If we already have acquired the fd, let's shortcut this */
410 r
= pam_get_data(handle
, "systemd-home-fd", &home_fd_ptr
);
411 if (r
== PAM_SUCCESS
&& PTR_TO_INT(home_fd_ptr
) >= 0)
414 r
= pam_acquire_bus_connection(handle
, &bus
);
415 if (r
!= PAM_SUCCESS
)
418 r
= acquire_user_record(handle
, &ur
);
419 if (r
!= PAM_SUCCESS
)
422 /* Implement our own retry loop here instead of relying on the PAM client's one. That's because it
423 * might happen that the the record we stored on the host does not match the encryption password of
424 * the LUKS image in case the image was used in a different system where the password was
425 * changed. In that case it will happen that the LUKS password and the host password are
426 * different, and we handle that by collecting and passing multiple passwords in that case. Hence we
427 * treat bad passwords as a request to collect one more password and pass the new all all previously
428 * used passwords again. */
431 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
432 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
434 if (do_auth
&& !secret
) {
435 const char *cached_password
= NULL
;
437 secret
= user_record_new();
439 return pam_log_oom(handle
);
441 /* If there's already a cached password, use it. But if not let's authenticate
442 * without anything, maybe some other authentication mechanism systemd-homed
443 * implements (such as PKCS#11) allows us to authenticate without anything else. */
444 r
= pam_get_item(handle
, PAM_AUTHTOK
, (const void**) &cached_password
);
445 if (!IN_SET(r
, PAM_BAD_ITEM
, PAM_SUCCESS
)) {
446 pam_syslog(handle
, LOG_ERR
, "Failed to get cached password: %s", pam_strerror(handle
, r
));
450 if (!isempty(cached_password
)) {
451 r
= user_record_set_password(secret
, STRV_MAKE(cached_password
), true);
453 pam_syslog(handle
, LOG_ERR
, "Failed to store password: %s", strerror_safe(r
));
454 return PAM_SERVICE_ERR
;
459 r
= sd_bus_message_new_method_call(
462 "org.freedesktop.home1",
463 "/org/freedesktop/home1",
464 "org.freedesktop.home1.Manager",
465 do_auth
? "AcquireHome" : "RefHome");
467 return pam_bus_log_create_error(handle
, r
);
469 r
= sd_bus_message_append(m
, "s", ur
->user_name
);
471 return pam_bus_log_create_error(handle
, r
);
474 r
= bus_message_append_secret(m
, secret
);
476 return pam_bus_log_create_error(handle
, r
);
479 r
= sd_bus_message_append(m
, "b", please_suspend
);
481 return pam_bus_log_create_error(handle
, r
);
483 r
= sd_bus_call(bus
, m
, HOME_SLOW_BUS_CALL_TIMEOUT_USEC
, &error
, &reply
);
486 if (sd_bus_error_has_name(&error
, BUS_ERROR_HOME_NOT_ACTIVE
))
487 /* Only on RefHome(): We can't access the home directory currently, unless
488 * it's unlocked with a password. Hence, let's try this again, this time with
490 home_not_active
= true;
491 else if (sd_bus_error_has_name(&error
, BUS_ERROR_HOME_LOCKED
))
492 home_locked
= true; /* Similar */
494 r
= handle_generic_user_record_error(handle
, ur
->user_name
, secret
, r
, &error
);
495 if (r
== PAM_CONV_ERR
) {
496 /* Password/PIN prompts will fail in certain environments, for example when
497 * we are called from OpenSSH's account or session hooks, or in systemd's
498 * per-service PAM logic. In that case, print a friendly message and accept
502 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Home of user %s is currently not active, please log in locally first.", ur
->user_name
);
504 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Home of user %s is currently locked, please unlock locally first.", ur
->user_name
);
506 pam_syslog(handle
, please_authenticate
? LOG_ERR
: LOG_DEBUG
, "Failed to prompt for password/prompt.");
508 return home_not_active
|| home_locked
? PAM_PERM_DENIED
: PAM_CONV_ERR
;
510 if (r
!= PAM_SUCCESS
)
517 r
= sd_bus_message_read(reply
, "h", &fd
);
519 return pam_bus_log_parse_error(handle
, r
);
521 acquired_fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
522 if (acquired_fd
< 0) {
523 pam_syslog(handle
, LOG_ERR
, "Failed to duplicate acquired fd: %s", bus_error_message(&error
, r
));
524 return PAM_SERVICE_ERR
;
530 if (++n_attempts
>= 5) {
531 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Too many unsuccessful login attempts for user %s, refusing.", ur
->user_name
);
532 pam_syslog(handle
, LOG_ERR
, "Failed to acquire home for user %s: %s", ur
->user_name
, bus_error_message(&error
, r
));
536 /* Try again, this time with authentication if we didn't do that before. */
540 r
= pam_set_data(handle
, "systemd-home-fd", FD_TO_PTR(acquired_fd
), cleanup_home_fd
);
542 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM bus data: %s", pam_strerror(handle
, r
));
545 TAKE_FD(acquired_fd
);
548 /* We likely just activated the home directory, let's flush out the user record, since a
549 * newer embedded user record might have been acquired from the activation. */
551 r
= release_user_record(handle
);
552 if (!IN_SET(r
, PAM_SUCCESS
, PAM_NO_MODULE_DATA
))
556 pam_syslog(handle
, LOG_NOTICE
, "Home for user %s successfully acquired.", ur
->user_name
);
561 static int release_home_fd(pam_handle_t
*handle
) {
562 const void *home_fd_ptr
= NULL
;
565 r
= pam_get_data(handle
, "systemd-home-fd", &home_fd_ptr
);
566 if (r
== PAM_NO_MODULE_DATA
|| PTR_TO_FD(home_fd_ptr
) < 0)
567 return PAM_NO_MODULE_DATA
;
569 r
= pam_set_data(handle
, "systemd-home-fd", NULL
, NULL
);
570 if (r
!= PAM_SUCCESS
)
571 pam_syslog(handle
, LOG_ERR
, "Failed to release PAM home reference fd: %s", pam_strerror(handle
, r
));
576 _public_ PAM_EXTERN
int pam_sm_authenticate(
577 pam_handle_t
*handle
,
579 int argc
, const char **argv
) {
581 bool debug
= false, suspend_please
= false;
583 if (parse_argv(handle
,
590 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed authenticating");
592 return acquire_home(handle
, /* please_authenticate= */ true, suspend_please
, debug
);
595 _public_ PAM_EXTERN
int pam_sm_setcred(pam_handle_t
*pamh
, int flags
, int argc
, const char **argv
) {
599 _public_ PAM_EXTERN
int pam_sm_open_session(
600 pam_handle_t
*handle
,
602 int argc
, const char **argv
) {
604 bool debug
= false, suspend_please
= false;
607 if (parse_argv(handle
,
611 return PAM_SESSION_ERR
;
614 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed session start");
616 r
= acquire_home(handle
, /* please_authenticate = */ false, suspend_please
, debug
);
617 if (r
== PAM_USER_UNKNOWN
) /* Not managed by us? Don't complain. */
619 if (r
!= PAM_SUCCESS
)
622 r
= pam_putenv(handle
, "SYSTEMD_HOME=1");
623 if (r
!= PAM_SUCCESS
) {
624 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM environment variable $SYSTEMD_HOME: %s", pam_strerror(handle
, r
));
628 /* Let's release the D-Bus connection, after all the session might live quite a long time, and we are
629 * not going to process the bus connection in that time, so let's better close before the daemon
630 * kicks us off because we are not processing anything. */
631 (void) pam_release_bus_connection(handle
);
635 _public_ PAM_EXTERN
int pam_sm_close_session(
636 pam_handle_t
*handle
,
638 int argc
, const char **argv
) {
640 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
641 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
642 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
643 const char *username
= NULL
;
647 if (parse_argv(handle
,
651 return PAM_SESSION_ERR
;
654 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed session end");
656 /* Let's explicitly drop the reference to the homed session, so that the subsequent ReleaseHome()
657 * call will be able to do its thing. */
658 r
= release_home_fd(handle
);
659 if (r
== PAM_NO_MODULE_DATA
) /* Nothing to do, we never acquired an fd */
661 if (r
!= PAM_SUCCESS
)
664 r
= pam_get_user(handle
, &username
, NULL
);
665 if (r
!= PAM_SUCCESS
) {
666 pam_syslog(handle
, LOG_ERR
, "Failed to get user name: %s", pam_strerror(handle
, r
));
670 r
= pam_acquire_bus_connection(handle
, &bus
);
671 if (r
!= PAM_SUCCESS
)
674 r
= sd_bus_message_new_method_call(
677 "org.freedesktop.home1",
678 "/org/freedesktop/home1",
679 "org.freedesktop.home1.Manager",
682 return pam_bus_log_create_error(handle
, r
);
684 r
= sd_bus_message_append(m
, "s", username
);
686 return pam_bus_log_create_error(handle
, r
);
688 r
= sd_bus_call(bus
, m
, HOME_SLOW_BUS_CALL_TIMEOUT_USEC
, &error
, NULL
);
690 if (sd_bus_error_has_name(&error
, BUS_ERROR_HOME_BUSY
))
691 pam_syslog(handle
, LOG_NOTICE
, "Not deactivating home directory of %s, as it is still used.", username
);
693 pam_syslog(handle
, LOG_ERR
, "Failed to release user home: %s", bus_error_message(&error
, r
));
694 return PAM_SESSION_ERR
;
701 _public_ PAM_EXTERN
int pam_sm_acct_mgmt(
702 pam_handle_t
*handle
,
707 _cleanup_(user_record_unrefp
) UserRecord
*ur
= NULL
;
708 bool debug
= false, please_suspend
= false;
712 if (parse_argv(handle
,
719 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed account management");
721 r
= acquire_home(handle
, /* please_authenticate = */ false, please_suspend
, debug
);
722 if (r
== PAM_USER_UNKNOWN
)
723 return PAM_SUCCESS
; /* we don't have anything to say about users we don't manage */
724 if (r
!= PAM_SUCCESS
)
727 r
= acquire_user_record(handle
, &ur
);
728 if (r
!= PAM_SUCCESS
)
731 r
= user_record_test_blocked(ur
);
735 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record is newer than current system time, prohibiting access.");
736 return PAM_ACCT_EXPIRED
;
739 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record is blocked, prohibiting access.");
740 return PAM_ACCT_EXPIRED
;
743 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record is not valid yet, prohibiting access.");
744 return PAM_ACCT_EXPIRED
;
747 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record is not valid anymore, prohibiting access.");
748 return PAM_ACCT_EXPIRED
;
752 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record not valid, prohibiting access.");
753 return PAM_ACCT_EXPIRED
;
759 t
= user_record_ratelimit_next_try(ur
);
760 if (t
!= USEC_INFINITY
) {
761 usec_t n
= now(CLOCK_REALTIME
);
764 char buf
[FORMAT_TIMESPAN_MAX
];
765 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Too many logins, try again in %s.",
766 format_timespan(buf
, sizeof(buf
), t
- n
, USEC_PER_SEC
));
772 r
= user_record_test_password_change_required(ur
);
776 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password change required.");
777 return PAM_NEW_AUTHTOK_REQD
;
780 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password expired, change requird.");
781 return PAM_NEW_AUTHTOK_REQD
;
784 /* Strictly speaking this is only about password expiration, and we might want to allow
785 * authentication via PKCS#11 or so, but let's ignore this fine distinction for now. */
786 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password is expired, but can't change, refusing login.");
787 return PAM_AUTHTOK_EXPIRED
;
790 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password will expire soon, please change.");
794 /* All good, just means the password if we wanted to change we couldn't, but we don't need to */
799 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record not valid, prohibiting access.");
800 return PAM_AUTHTOK_EXPIRED
;
809 _public_ PAM_EXTERN
int pam_sm_chauthtok(
810 pam_handle_t
*handle
,
815 _cleanup_(user_record_unrefp
) UserRecord
*ur
= NULL
, *old_secret
= NULL
, *new_secret
= NULL
;
816 const char *old_password
= NULL
, *new_password
= NULL
;
817 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
818 unsigned n_attempts
= 0;
822 if (parse_argv(handle
,
829 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed account management");
831 r
= pam_acquire_bus_connection(handle
, &bus
);
832 if (r
!= PAM_SUCCESS
)
835 r
= acquire_user_record(handle
, &ur
);
836 if (r
!= PAM_SUCCESS
)
839 /* Start with cached credentials */
840 r
= pam_get_item(handle
, PAM_OLDAUTHTOK
, (const void**) &old_password
);
841 if (!IN_SET(r
, PAM_BAD_ITEM
, PAM_SUCCESS
)) {
842 pam_syslog(handle
, LOG_ERR
, "Failed to get old password: %s", pam_strerror(handle
, r
));
845 r
= pam_get_item(handle
, PAM_AUTHTOK
, (const void**) &new_password
);
846 if (!IN_SET(r
, PAM_BAD_ITEM
, PAM_SUCCESS
)) {
847 pam_syslog(handle
, LOG_ERR
, "Failed to get cached password: %s", pam_strerror(handle
, r
));
851 if (isempty(new_password
)) {
852 /* No, it's not cached, then let's ask for the password and its verification, and cache
855 r
= pam_get_authtok_noverify(handle
, &new_password
, "New password: ");
856 if (r
!= PAM_SUCCESS
) {
857 pam_syslog(handle
, LOG_ERR
, "Failed to get new password: %s", pam_strerror(handle
, r
));
860 if (isempty(new_password
)) {
861 pam_syslog(handle
, LOG_DEBUG
, "Password request aborted.");
862 return PAM_AUTHTOK_ERR
;
865 r
= pam_get_authtok_verify(handle
, &new_password
, "new password: "); /* Lower case, since PAM prefixes 'Repeat' */
866 if (r
!= PAM_SUCCESS
) {
867 pam_syslog(handle
, LOG_ERR
, "Failed to get password again: %s", pam_strerror(handle
, r
));
871 // FIXME: pam_pwquality will ask for the password a third time. It really shouldn't do
872 // that, and instead assume the password was already verified once when it is found to be
873 // cached already. needs to be fixed in pam_pwquality
876 /* Now everything is cached and checked, let's exit from the preliminary check */
877 if (FLAGS_SET(flags
, PAM_PRELIM_CHECK
))
880 old_secret
= user_record_new();
882 return pam_log_oom(handle
);
884 if (!isempty(old_password
)) {
885 r
= user_record_set_password(old_secret
, STRV_MAKE(old_password
), true);
887 pam_syslog(handle
, LOG_ERR
, "Failed to store old password: %s", strerror_safe(r
));
888 return PAM_SERVICE_ERR
;
892 new_secret
= user_record_new();
894 return pam_log_oom(handle
);
896 r
= user_record_set_password(new_secret
, STRV_MAKE(new_password
), true);
898 pam_syslog(handle
, LOG_ERR
, "Failed to store new password: %s", strerror_safe(r
));
899 return PAM_SERVICE_ERR
;
903 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
904 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
906 r
= sd_bus_message_new_method_call(
909 "org.freedesktop.home1",
910 "/org/freedesktop/home1",
911 "org.freedesktop.home1.Manager",
912 "ChangePasswordHome");
914 return pam_bus_log_create_error(handle
, r
);
916 r
= sd_bus_message_append(m
, "s", ur
->user_name
);
918 return pam_bus_log_create_error(handle
, r
);
920 r
= bus_message_append_secret(m
, new_secret
);
922 return pam_bus_log_create_error(handle
, r
);
924 r
= bus_message_append_secret(m
, old_secret
);
926 return pam_bus_log_create_error(handle
, r
);
928 r
= sd_bus_call(bus
, m
, HOME_SLOW_BUS_CALL_TIMEOUT_USEC
, &error
, NULL
);
930 r
= handle_generic_user_record_error(handle
, ur
->user_name
, old_secret
, r
, &error
);
931 if (r
== PAM_CONV_ERR
) {
932 pam_syslog(handle
, LOG_ERR
, "Failed to prompt for password/prompt.");
935 if (r
!= PAM_SUCCESS
)
938 pam_syslog(handle
, LOG_NOTICE
, "Successfully changed password for user %s.", ur
->user_name
);
942 if (++n_attempts
>= 5)
948 pam_syslog(handle
, LOG_NOTICE
, "Failed to change password for user %s: %m", ur
->user_name
);