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"
10 #include "errno-util.h"
12 #include "home-util.h"
13 #include "memory-util.h"
15 #include "parse-util.h"
17 #include "user-record-util.h"
18 #include "user-record.h"
19 #include "user-util.h"
21 /* Used for the "systemd-user-record-is-homed" PAM data field, to indicate whether we know whether this user
22 * record is managed by homed or by something else. */
23 #define USER_RECORD_IS_HOMED INT_TO_PTR(1)
24 #define USER_RECORD_IS_OTHER INT_TO_PTR(2)
26 static int parse_argv(
28 int argc
, const char **argv
,
35 assert(argc
== 0 || argv
);
37 for (i
= 0; i
< argc
; i
++) {
40 if ((v
= startswith(argv
[i
], "suspend="))) {
45 pam_syslog(handle
, LOG_WARNING
, "Failed to parse suspend= argument, ignoring: %s", v
);
46 else if (please_suspend
)
49 } else if (streq(argv
[i
], "debug")) {
53 } else if ((v
= startswith(argv
[i
], "debug="))) {
57 pam_syslog(handle
, LOG_WARNING
, "Failed to parse debug= argument, ignoring: %s", v
);
62 pam_syslog(handle
, LOG_WARNING
, "Unknown parameter '%s', ignoring", argv
[i
]);
68 static int acquire_user_record(
70 UserRecord
**ret_record
) {
72 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
73 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
74 _cleanup_(user_record_unrefp
) UserRecord
*ur
= NULL
;
75 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
76 const char *username
= NULL
, *json
= NULL
;
82 r
= pam_get_user(handle
, &username
, NULL
);
83 if (r
!= PAM_SUCCESS
) {
84 pam_syslog(handle
, LOG_ERR
, "Failed to get user name: %s", pam_strerror(handle
, r
));
88 if (isempty(username
)) {
89 pam_syslog(handle
, LOG_ERR
, "User name not set.");
90 return PAM_SERVICE_ERR
;
93 /* Let's bypass all IPC complexity for the two user names we know for sure we don't manage, and for
94 * user names we don't consider valid. */
95 if (STR_IN_SET(username
, "root", NOBODY_USER_NAME
) || !valid_user_group_name(username
, 0))
96 return PAM_USER_UNKNOWN
;
98 /* Let's check if a previous run determined that this user is not managed by homed. If so, let's exit early */
99 r
= pam_get_data(handle
, "systemd-user-record-is-homed", &b
);
100 if (!IN_SET(r
, PAM_SUCCESS
, PAM_NO_MODULE_DATA
)) {
102 pam_syslog(handle
, LOG_ERR
, "Failed to get PAM user-record-is-homed flag: %s", pam_strerror(handle
, r
));
104 } else if (b
== NULL
)
105 /* Nothing cached yet, need to acquire fresh */
107 else if (b
!= USER_RECORD_IS_HOMED
)
108 /* Definitely not a homed record */
109 return PAM_USER_UNKNOWN
;
111 /* It's a homed record, let's use the cache, so that we can share it between the session and
112 * the authentication hooks */
113 r
= pam_get_data(handle
, "systemd-user-record", (const void**) &json
);
114 if (!IN_SET(r
, PAM_SUCCESS
, PAM_NO_MODULE_DATA
)) {
115 pam_syslog(handle
, LOG_ERR
, "Failed to get PAM user record data: %s", pam_strerror(handle
, r
));
121 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
122 _cleanup_free_
char *json_copy
= NULL
;
124 r
= pam_acquire_bus_connection(handle
, &bus
);
125 if (r
!= PAM_SUCCESS
)
128 r
= bus_call_method(bus
, bus_home_mgr
, "GetUserRecordByName", &error
, &reply
, "s", username
);
130 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_SERVICE_UNKNOWN
) ||
131 sd_bus_error_has_name(&error
, SD_BUS_ERROR_NAME_HAS_NO_OWNER
)) {
132 pam_syslog(handle
, LOG_DEBUG
, "systemd-homed is not available: %s", bus_error_message(&error
, r
));
136 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_HOME
)) {
137 pam_syslog(handle
, LOG_DEBUG
, "Not a user managed by systemd-homed: %s", bus_error_message(&error
, r
));
141 pam_syslog(handle
, LOG_ERR
, "Failed to query user record: %s", bus_error_message(&error
, r
));
142 return PAM_SERVICE_ERR
;
145 r
= sd_bus_message_read(reply
, "sbo", &json
, NULL
, NULL
);
147 return pam_bus_log_parse_error(handle
, r
);
149 json_copy
= strdup(json
);
151 return pam_log_oom(handle
);
153 r
= pam_set_data(handle
, "systemd-user-record", json_copy
, pam_cleanup_free
);
154 if (r
!= PAM_SUCCESS
) {
155 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM user record data: %s", pam_strerror(handle
, r
));
161 r
= pam_set_data(handle
, "systemd-user-record-is-homed", USER_RECORD_IS_HOMED
, NULL
);
162 if (r
!= PAM_SUCCESS
) {
163 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM user record is homed flag: %s", pam_strerror(handle
, r
));
168 r
= json_parse(json
, JSON_PARSE_SENSITIVE
, &v
, NULL
, NULL
);
170 pam_syslog(handle
, LOG_ERR
, "Failed to parse JSON user record: %s", strerror_safe(r
));
171 return PAM_SERVICE_ERR
;
174 ur
= user_record_new();
176 return pam_log_oom(handle
);
178 r
= user_record_load(ur
, v
, USER_RECORD_LOAD_REFUSE_SECRET
);
180 pam_syslog(handle
, LOG_ERR
, "Failed to load user record: %s", strerror_safe(r
));
181 return PAM_SERVICE_ERR
;
184 if (!streq_ptr(username
, ur
->user_name
)) {
185 pam_syslog(handle
, LOG_ERR
, "Acquired user record does not match user name.");
186 return PAM_SERVICE_ERR
;
190 *ret_record
= TAKE_PTR(ur
);
195 /* Cache this, so that we don't check again */
196 r
= pam_set_data(handle
, "systemd-user-record-is-homed", USER_RECORD_IS_OTHER
, NULL
);
197 if (r
!= PAM_SUCCESS
)
198 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM user-record-is-homed flag, ignoring: %s", pam_strerror(handle
, r
));
200 return PAM_USER_UNKNOWN
;
203 static int release_user_record(pam_handle_t
*handle
) {
206 r
= pam_set_data(handle
, "systemd-user-record", NULL
, NULL
);
207 if (r
!= PAM_SUCCESS
)
208 pam_syslog(handle
, LOG_ERR
, "Failed to release PAM user record data: %s", pam_strerror(handle
, r
));
210 k
= pam_set_data(handle
, "systemd-user-record-is-homed", NULL
, NULL
);
211 if (k
!= PAM_SUCCESS
)
212 pam_syslog(handle
, LOG_ERR
, "Failed to release PAM user-record-is-homed flag: %s", pam_strerror(handle
, k
));
214 return IN_SET(r
, PAM_SUCCESS
, PAM_NO_MODULE_DATA
) ? k
: r
;
217 static void cleanup_home_fd(pam_handle_t
*handle
, void *data
, int error_status
) {
218 safe_close(PTR_TO_FD(data
));
221 static int handle_generic_user_record_error(
222 pam_handle_t
*handle
,
223 const char *user_name
,
226 const sd_bus_error
*error
) {
234 /* Logs about all errors, except for PAM_CONV_ERR, i.e. when requesting more info failed. */
236 if (sd_bus_error_has_name(error
, BUS_ERROR_HOME_ABSENT
)) {
237 (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
);
238 pam_syslog(handle
, LOG_ERR
, "Failed to acquire home for user %s: %s", user_name
, bus_error_message(error
, ret
));
239 return PAM_PERM_DENIED
;
241 } else if (sd_bus_error_has_name(error
, BUS_ERROR_AUTHENTICATION_LIMIT_HIT
)) {
242 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Too frequent unsuccessful login attempts for user %s, try again later.", user_name
);
243 pam_syslog(handle
, LOG_ERR
, "Failed to acquire home for user %s: %s", user_name
, bus_error_message(error
, ret
));
246 } else if (sd_bus_error_has_name(error
, BUS_ERROR_BAD_PASSWORD
)) {
247 _cleanup_(erase_and_freep
) char *newp
= NULL
;
249 /* This didn't work? Ask for an (additional?) password */
251 if (strv_isempty(secret
->password
))
252 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Password: ");
254 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password incorrect or not sufficient for authentication of user %s.", user_name
);
255 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Sorry, try again: ");
257 if (r
!= PAM_SUCCESS
)
258 return PAM_CONV_ERR
; /* no logging here */
261 pam_syslog(handle
, LOG_DEBUG
, "Password request aborted.");
262 return PAM_AUTHTOK_ERR
;
265 r
= user_record_set_password(secret
, STRV_MAKE(newp
), true);
267 pam_syslog(handle
, LOG_ERR
, "Failed to store password: %s", strerror_safe(r
));
268 return PAM_SERVICE_ERR
;
271 } else if (sd_bus_error_has_name(error
, BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN
)) {
272 _cleanup_(erase_and_freep
) char *newp
= NULL
;
274 if (strv_isempty(secret
->password
)) {
275 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Security token of user %s not inserted.", user_name
);
276 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Try again with password: ");
278 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password incorrect or not sufficient, and configured security token of user %s not inserted.", user_name
);
279 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Try again with password: ");
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
, "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 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Security token PIN incorrect for user %s.", user_name
);
327 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Sorry, retry security token PIN: ");
328 if (r
!= PAM_SUCCESS
)
329 return PAM_CONV_ERR
; /* no logging here */
332 pam_syslog(handle
, LOG_DEBUG
, "PIN request aborted.");
333 return PAM_AUTHTOK_ERR
;
336 r
= user_record_set_pkcs11_pin(secret
, STRV_MAKE(newp
), false);
338 pam_syslog(handle
, LOG_ERR
, "Failed to store PIN: %s", strerror_safe(r
));
339 return PAM_SERVICE_ERR
;
342 } else if (sd_bus_error_has_name(error
, BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT
)) {
343 _cleanup_(erase_and_freep
) char *newp
= NULL
;
345 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Security token PIN of user %s incorrect (only a few tries left!)", user_name
);
346 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Sorry, retry security token PIN: ");
347 if (r
!= PAM_SUCCESS
)
348 return PAM_CONV_ERR
; /* no logging here */
351 pam_syslog(handle
, LOG_DEBUG
, "PIN request aborted.");
352 return PAM_AUTHTOK_ERR
;
355 r
= user_record_set_pkcs11_pin(secret
, STRV_MAKE(newp
), false);
357 pam_syslog(handle
, LOG_ERR
, "Failed to store PIN: %s", strerror_safe(r
));
358 return PAM_SERVICE_ERR
;
361 } else if (sd_bus_error_has_name(error
, BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT
)) {
362 _cleanup_(erase_and_freep
) char *newp
= NULL
;
364 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Security token PIN of user %s incorrect (only one try left!)", user_name
);
365 r
= pam_prompt(handle
, PAM_PROMPT_ECHO_OFF
, &newp
, "Sorry, retry security token PIN: ");
366 if (r
!= PAM_SUCCESS
)
367 return PAM_CONV_ERR
; /* no logging here */
370 pam_syslog(handle
, LOG_DEBUG
, "PIN request aborted.");
371 return PAM_AUTHTOK_ERR
;
374 r
= user_record_set_pkcs11_pin(secret
, STRV_MAKE(newp
), false);
376 pam_syslog(handle
, LOG_ERR
, "Failed to store PIN: %s", strerror_safe(r
));
377 return PAM_SERVICE_ERR
;
381 pam_syslog(handle
, LOG_ERR
, "Failed to acquire home for user %s: %s", user_name
, bus_error_message(error
, ret
));
382 return PAM_SERVICE_ERR
;
388 static int acquire_home(
389 pam_handle_t
*handle
,
390 bool please_authenticate
,
394 _cleanup_(user_record_unrefp
) UserRecord
*ur
= NULL
, *secret
= NULL
;
395 bool do_auth
= please_authenticate
, home_not_active
= false, home_locked
= false;
396 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
397 _cleanup_close_
int acquired_fd
= -1;
398 const void *home_fd_ptr
= NULL
;
399 unsigned n_attempts
= 0;
404 /* This acquires a reference to a home directory in one of two ways: if please_authenticate is true,
405 * then we'll call AcquireHome() after asking the user for a password. Otherwise it tries to call
406 * RefHome() and if that fails queries the user for a password and uses AcquireHome().
408 * The idea is that the PAM authentication hook sets please_authenticate and thus always
409 * authenticates, while the other PAM hooks unset it so that they can a ref of their own without
410 * authentication if possible, but with authentication if necessary. */
412 /* If we already have acquired the fd, let's shortcut this */
413 r
= pam_get_data(handle
, "systemd-home-fd", &home_fd_ptr
);
414 if (r
== PAM_SUCCESS
&& PTR_TO_INT(home_fd_ptr
) >= 0)
417 r
= pam_acquire_bus_connection(handle
, &bus
);
418 if (r
!= PAM_SUCCESS
)
421 r
= acquire_user_record(handle
, &ur
);
422 if (r
!= PAM_SUCCESS
)
425 /* Implement our own retry loop here instead of relying on the PAM client's one. That's because it
426 * might happen that the the record we stored on the host does not match the encryption password of
427 * the LUKS image in case the image was used in a different system where the password was
428 * changed. In that case it will happen that the LUKS password and the host password are
429 * different, and we handle that by collecting and passing multiple passwords in that case. Hence we
430 * treat bad passwords as a request to collect one more password and pass the new all all previously
431 * used passwords again. */
434 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
435 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
437 if (do_auth
&& !secret
) {
438 const char *cached_password
= NULL
;
440 secret
= user_record_new();
442 return pam_log_oom(handle
);
444 /* If there's already a cached password, use it. But if not let's authenticate
445 * without anything, maybe some other authentication mechanism systemd-homed
446 * implements (such as PKCS#11) allows us to authenticate without anything else. */
447 r
= pam_get_item(handle
, PAM_AUTHTOK
, (const void**) &cached_password
);
448 if (!IN_SET(r
, PAM_BAD_ITEM
, PAM_SUCCESS
)) {
449 pam_syslog(handle
, LOG_ERR
, "Failed to get cached password: %s", pam_strerror(handle
, r
));
453 if (!isempty(cached_password
)) {
454 r
= user_record_set_password(secret
, STRV_MAKE(cached_password
), true);
456 pam_syslog(handle
, LOG_ERR
, "Failed to store password: %s", strerror_safe(r
));
457 return PAM_SERVICE_ERR
;
462 r
= bus_message_new_method_call(bus
, &m
, bus_home_mgr
, do_auth
? "AcquireHome" : "RefHome");
464 return pam_bus_log_create_error(handle
, r
);
466 r
= sd_bus_message_append(m
, "s", ur
->user_name
);
468 return pam_bus_log_create_error(handle
, r
);
471 r
= bus_message_append_secret(m
, secret
);
473 return pam_bus_log_create_error(handle
, r
);
476 r
= sd_bus_message_append(m
, "b", please_suspend
);
478 return pam_bus_log_create_error(handle
, r
);
480 r
= sd_bus_call(bus
, m
, HOME_SLOW_BUS_CALL_TIMEOUT_USEC
, &error
, &reply
);
483 if (sd_bus_error_has_name(&error
, BUS_ERROR_HOME_NOT_ACTIVE
))
484 /* Only on RefHome(): We can't access the home directory currently, unless
485 * it's unlocked with a password. Hence, let's try this again, this time with
487 home_not_active
= true;
488 else if (sd_bus_error_has_name(&error
, BUS_ERROR_HOME_LOCKED
))
489 home_locked
= true; /* Similar */
491 r
= handle_generic_user_record_error(handle
, ur
->user_name
, secret
, r
, &error
);
492 if (r
== PAM_CONV_ERR
) {
493 /* Password/PIN prompts will fail in certain environments, for example when
494 * we are called from OpenSSH's account or session hooks, or in systemd's
495 * per-service PAM logic. In that case, print a friendly message and accept
499 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Home of user %s is currently not active, please log in locally first.", ur
->user_name
);
501 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Home of user %s is currently locked, please unlock locally first.", ur
->user_name
);
503 pam_syslog(handle
, please_authenticate
? LOG_ERR
: LOG_DEBUG
, "Failed to prompt for password/prompt.");
505 return home_not_active
|| home_locked
? PAM_PERM_DENIED
: PAM_CONV_ERR
;
507 if (r
!= PAM_SUCCESS
)
514 r
= sd_bus_message_read(reply
, "h", &fd
);
516 return pam_bus_log_parse_error(handle
, r
);
518 acquired_fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
519 if (acquired_fd
< 0) {
520 pam_syslog(handle
, LOG_ERR
, "Failed to duplicate acquired fd: %s", bus_error_message(&error
, r
));
521 return PAM_SERVICE_ERR
;
527 if (++n_attempts
>= 5) {
528 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Too many unsuccessful login attempts for user %s, refusing.", ur
->user_name
);
529 pam_syslog(handle
, LOG_ERR
, "Failed to acquire home for user %s: %s", ur
->user_name
, bus_error_message(&error
, r
));
533 /* Try again, this time with authentication if we didn't do that before. */
537 r
= pam_set_data(handle
, "systemd-home-fd", FD_TO_PTR(acquired_fd
), cleanup_home_fd
);
539 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM bus data: %s", pam_strerror(handle
, r
));
542 TAKE_FD(acquired_fd
);
545 /* We likely just activated the home directory, let's flush out the user record, since a
546 * newer embedded user record might have been acquired from the activation. */
548 r
= release_user_record(handle
);
549 if (!IN_SET(r
, PAM_SUCCESS
, PAM_NO_MODULE_DATA
))
553 pam_syslog(handle
, LOG_NOTICE
, "Home for user %s successfully acquired.", ur
->user_name
);
558 static int release_home_fd(pam_handle_t
*handle
) {
559 const void *home_fd_ptr
= NULL
;
562 r
= pam_get_data(handle
, "systemd-home-fd", &home_fd_ptr
);
563 if (r
== PAM_NO_MODULE_DATA
|| PTR_TO_FD(home_fd_ptr
) < 0)
564 return PAM_NO_MODULE_DATA
;
566 r
= pam_set_data(handle
, "systemd-home-fd", NULL
, NULL
);
567 if (r
!= PAM_SUCCESS
)
568 pam_syslog(handle
, LOG_ERR
, "Failed to release PAM home reference fd: %s", pam_strerror(handle
, r
));
573 _public_ PAM_EXTERN
int pam_sm_authenticate(
574 pam_handle_t
*handle
,
576 int argc
, const char **argv
) {
578 bool debug
= false, suspend_please
= false;
580 if (parse_argv(handle
,
587 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed authenticating");
589 return acquire_home(handle
, /* please_authenticate= */ true, suspend_please
, debug
);
592 _public_ PAM_EXTERN
int pam_sm_setcred(pam_handle_t
*pamh
, int flags
, int argc
, const char **argv
) {
596 _public_ PAM_EXTERN
int pam_sm_open_session(
597 pam_handle_t
*handle
,
599 int argc
, const char **argv
) {
601 bool debug
= false, suspend_please
= false;
604 if (parse_argv(handle
,
608 return PAM_SESSION_ERR
;
611 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed session start");
613 r
= acquire_home(handle
, /* please_authenticate = */ false, suspend_please
, debug
);
614 if (r
== PAM_USER_UNKNOWN
) /* Not managed by us? Don't complain. */
616 if (r
!= PAM_SUCCESS
)
619 r
= pam_putenv(handle
, "SYSTEMD_HOME=1");
620 if (r
!= PAM_SUCCESS
) {
621 pam_syslog(handle
, LOG_ERR
, "Failed to set PAM environment variable $SYSTEMD_HOME: %s", pam_strerror(handle
, r
));
625 /* Let's release the D-Bus connection, after all the session might live quite a long time, and we are
626 * not going to process the bus connection in that time, so let's better close before the daemon
627 * kicks us off because we are not processing anything. */
628 (void) pam_release_bus_connection(handle
);
632 _public_ PAM_EXTERN
int pam_sm_close_session(
633 pam_handle_t
*handle
,
635 int argc
, const char **argv
) {
637 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
638 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
639 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
640 const char *username
= NULL
;
644 if (parse_argv(handle
,
648 return PAM_SESSION_ERR
;
651 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed session end");
653 /* Let's explicitly drop the reference to the homed session, so that the subsequent ReleaseHome()
654 * call will be able to do its thing. */
655 r
= release_home_fd(handle
);
656 if (r
== PAM_NO_MODULE_DATA
) /* Nothing to do, we never acquired an fd */
658 if (r
!= PAM_SUCCESS
)
661 r
= pam_get_user(handle
, &username
, NULL
);
662 if (r
!= PAM_SUCCESS
) {
663 pam_syslog(handle
, LOG_ERR
, "Failed to get user name: %s", pam_strerror(handle
, r
));
667 r
= pam_acquire_bus_connection(handle
, &bus
);
668 if (r
!= PAM_SUCCESS
)
671 r
= bus_message_new_method_call(bus
, &m
, bus_home_mgr
, "ReleaseHome");
673 return pam_bus_log_create_error(handle
, r
);
675 r
= sd_bus_message_append(m
, "s", username
);
677 return pam_bus_log_create_error(handle
, r
);
679 r
= sd_bus_call(bus
, m
, HOME_SLOW_BUS_CALL_TIMEOUT_USEC
, &error
, NULL
);
681 if (sd_bus_error_has_name(&error
, BUS_ERROR_HOME_BUSY
))
682 pam_syslog(handle
, LOG_NOTICE
, "Not deactivating home directory of %s, as it is still used.", username
);
684 pam_syslog(handle
, LOG_ERR
, "Failed to release user home: %s", bus_error_message(&error
, r
));
685 return PAM_SESSION_ERR
;
692 _public_ PAM_EXTERN
int pam_sm_acct_mgmt(
693 pam_handle_t
*handle
,
698 _cleanup_(user_record_unrefp
) UserRecord
*ur
= NULL
;
699 bool debug
= false, please_suspend
= false;
703 if (parse_argv(handle
,
710 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed account management");
712 r
= acquire_home(handle
, /* please_authenticate = */ false, please_suspend
, debug
);
713 if (r
== PAM_USER_UNKNOWN
)
714 return PAM_SUCCESS
; /* we don't have anything to say about users we don't manage */
715 if (r
!= PAM_SUCCESS
)
718 r
= acquire_user_record(handle
, &ur
);
719 if (r
!= PAM_SUCCESS
)
722 r
= user_record_test_blocked(ur
);
726 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record is newer than current system time, prohibiting access.");
727 return PAM_ACCT_EXPIRED
;
730 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record is blocked, prohibiting access.");
731 return PAM_ACCT_EXPIRED
;
734 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record is not valid yet, prohibiting access.");
735 return PAM_ACCT_EXPIRED
;
738 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record is not valid anymore, prohibiting access.");
739 return PAM_ACCT_EXPIRED
;
743 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record not valid, prohibiting access.");
744 return PAM_ACCT_EXPIRED
;
750 t
= user_record_ratelimit_next_try(ur
);
751 if (t
!= USEC_INFINITY
) {
752 usec_t n
= now(CLOCK_REALTIME
);
755 char buf
[FORMAT_TIMESPAN_MAX
];
756 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Too many logins, try again in %s.",
757 format_timespan(buf
, sizeof(buf
), t
- n
, USEC_PER_SEC
));
763 r
= user_record_test_password_change_required(ur
);
767 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password change required.");
768 return PAM_NEW_AUTHTOK_REQD
;
771 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password expired, change requird.");
772 return PAM_NEW_AUTHTOK_REQD
;
775 /* Strictly speaking this is only about password expiration, and we might want to allow
776 * authentication via PKCS#11 or so, but let's ignore this fine distinction for now. */
777 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password is expired, but can't change, refusing login.");
778 return PAM_AUTHTOK_EXPIRED
;
781 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "Password will expire soon, please change.");
785 /* All good, just means the password if we wanted to change we couldn't, but we don't need to */
790 (void) pam_prompt(handle
, PAM_ERROR_MSG
, NULL
, "User record not valid, prohibiting access.");
791 return PAM_AUTHTOK_EXPIRED
;
800 _public_ PAM_EXTERN
int pam_sm_chauthtok(
801 pam_handle_t
*handle
,
806 _cleanup_(user_record_unrefp
) UserRecord
*ur
= NULL
, *old_secret
= NULL
, *new_secret
= NULL
;
807 const char *old_password
= NULL
, *new_password
= NULL
;
808 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
809 unsigned n_attempts
= 0;
813 if (parse_argv(handle
,
820 pam_syslog(handle
, LOG_DEBUG
, "pam-systemd-homed account management");
822 r
= pam_acquire_bus_connection(handle
, &bus
);
823 if (r
!= PAM_SUCCESS
)
826 r
= acquire_user_record(handle
, &ur
);
827 if (r
!= PAM_SUCCESS
)
830 /* Start with cached credentials */
831 r
= pam_get_item(handle
, PAM_OLDAUTHTOK
, (const void**) &old_password
);
832 if (!IN_SET(r
, PAM_BAD_ITEM
, PAM_SUCCESS
)) {
833 pam_syslog(handle
, LOG_ERR
, "Failed to get old password: %s", pam_strerror(handle
, r
));
836 r
= pam_get_item(handle
, PAM_AUTHTOK
, (const void**) &new_password
);
837 if (!IN_SET(r
, PAM_BAD_ITEM
, PAM_SUCCESS
)) {
838 pam_syslog(handle
, LOG_ERR
, "Failed to get cached password: %s", pam_strerror(handle
, r
));
842 if (isempty(new_password
)) {
843 /* No, it's not cached, then let's ask for the password and its verification, and cache
846 r
= pam_get_authtok_noverify(handle
, &new_password
, "New password: ");
847 if (r
!= PAM_SUCCESS
) {
848 pam_syslog(handle
, LOG_ERR
, "Failed to get new password: %s", pam_strerror(handle
, r
));
851 if (isempty(new_password
)) {
852 pam_syslog(handle
, LOG_DEBUG
, "Password request aborted.");
853 return PAM_AUTHTOK_ERR
;
856 r
= pam_get_authtok_verify(handle
, &new_password
, "new password: "); /* Lower case, since PAM prefixes 'Repeat' */
857 if (r
!= PAM_SUCCESS
) {
858 pam_syslog(handle
, LOG_ERR
, "Failed to get password again: %s", pam_strerror(handle
, r
));
862 // FIXME: pam_pwquality will ask for the password a third time. It really shouldn't do
863 // that, and instead assume the password was already verified once when it is found to be
864 // cached already. needs to be fixed in pam_pwquality
867 /* Now everything is cached and checked, let's exit from the preliminary check */
868 if (FLAGS_SET(flags
, PAM_PRELIM_CHECK
))
871 old_secret
= user_record_new();
873 return pam_log_oom(handle
);
875 if (!isempty(old_password
)) {
876 r
= user_record_set_password(old_secret
, STRV_MAKE(old_password
), true);
878 pam_syslog(handle
, LOG_ERR
, "Failed to store old password: %s", strerror_safe(r
));
879 return PAM_SERVICE_ERR
;
883 new_secret
= user_record_new();
885 return pam_log_oom(handle
);
887 r
= user_record_set_password(new_secret
, STRV_MAKE(new_password
), true);
889 pam_syslog(handle
, LOG_ERR
, "Failed to store new password: %s", strerror_safe(r
));
890 return PAM_SERVICE_ERR
;
894 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
895 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
897 r
= bus_message_new_method_call(bus
, &m
, bus_home_mgr
, "ChangePasswordHome");
899 return pam_bus_log_create_error(handle
, r
);
901 r
= sd_bus_message_append(m
, "s", ur
->user_name
);
903 return pam_bus_log_create_error(handle
, r
);
905 r
= bus_message_append_secret(m
, new_secret
);
907 return pam_bus_log_create_error(handle
, r
);
909 r
= bus_message_append_secret(m
, old_secret
);
911 return pam_bus_log_create_error(handle
, r
);
913 r
= sd_bus_call(bus
, m
, HOME_SLOW_BUS_CALL_TIMEOUT_USEC
, &error
, NULL
);
915 r
= handle_generic_user_record_error(handle
, ur
->user_name
, old_secret
, r
, &error
);
916 if (r
== PAM_CONV_ERR
) {
917 pam_syslog(handle
, LOG_ERR
, "Failed to prompt for password/prompt.");
920 if (r
!= PAM_SUCCESS
)
923 pam_syslog(handle
, LOG_NOTICE
, "Successfully changed password for user %s.", ur
->user_name
);
927 if (++n_attempts
>= 5)
933 pam_syslog(handle
, LOG_NOTICE
, "Failed to change password for user %s: %m", ur
->user_name
);