|
25 | 25 | #include "fd-util.h" |
26 | 26 | #include "fileio.h" |
27 | 27 | #include "format-util.h" |
| 28 | +#include "fs-util.h" |
28 | 29 | #include "hostname-util.h" |
| 30 | +#include "locale-util.h" |
29 | 31 | #include "login-util.h" |
30 | 32 | #include "macro.h" |
31 | 33 | #include "pam-util.h" |
32 | 34 | #include "parse-util.h" |
33 | 35 | #include "path-util.h" |
34 | 36 | #include "process-util.h" |
| 37 | +#include "rlimit-util.h" |
35 | 38 | #include "socket-util.h" |
36 | 39 | #include "stdio-util.h" |
37 | 40 | #include "strv.h" |
@@ -473,6 +476,138 @@ static bool validate_runtime_directory(pam_handle_t *handle, const char *path, u |
473 | 476 | return false; |
474 | 477 | } |
475 | 478 |
|
| 479 | +static int pam_putenv_and_log(pam_handle_t *handle, const char *e, bool debug) { |
| 480 | + int r; |
| 481 | + |
| 482 | + assert(handle); |
| 483 | + assert(e); |
| 484 | + |
| 485 | + r = pam_putenv(handle, e); |
| 486 | + if (r != PAM_SUCCESS) { |
| 487 | + pam_syslog(handle, LOG_ERR, "Failed to set PAM environment variable %s: %s", e, pam_strerror(handle, r)); |
| 488 | + return r; |
| 489 | + } |
| 490 | + |
| 491 | + if (debug) |
| 492 | + pam_syslog(handle, LOG_DEBUG, "PAM environment variable %s set based on user record.", e); |
| 493 | + |
| 494 | + return PAM_SUCCESS; |
| 495 | +} |
| 496 | + |
| 497 | +static int apply_user_record_settings(pam_handle_t *handle, UserRecord *ur, bool debug) { |
| 498 | + char **i; |
| 499 | + int r; |
| 500 | + |
| 501 | + assert(handle); |
| 502 | + assert(ur); |
| 503 | + |
| 504 | + if (ur->umask != MODE_INVALID) { |
| 505 | + umask(ur->umask); |
| 506 | + |
| 507 | + if (debug) |
| 508 | + pam_syslog(handle, LOG_DEBUG, "Set user umask to %04o based on user record.", ur->umask); |
| 509 | + } |
| 510 | + |
| 511 | + STRV_FOREACH(i, ur->environment) { |
| 512 | + _cleanup_free_ char *n = NULL; |
| 513 | + const char *e; |
| 514 | + |
| 515 | + assert_se(e = strchr(*i, '=')); /* environment was already validated while parsing JSON record, this thus must hold */ |
| 516 | + |
| 517 | + n = strndup(*i, e - *i); |
| 518 | + if (!n) |
| 519 | + return pam_log_oom(handle); |
| 520 | + |
| 521 | + if (pam_getenv(handle, n)) { |
| 522 | + if (debug) |
| 523 | + pam_syslog(handle, LOG_DEBUG, "PAM environment variable $%s already set, not changing based on record.", *i); |
| 524 | + continue; |
| 525 | + } |
| 526 | + |
| 527 | + r = pam_putenv_and_log(handle, *i, debug); |
| 528 | + if (r != PAM_SUCCESS) |
| 529 | + return r; |
| 530 | + } |
| 531 | + |
| 532 | + if (ur->email_address) { |
| 533 | + if (pam_getenv(handle, "EMAIL")) { |
| 534 | + if (debug) |
| 535 | + pam_syslog(handle, LOG_DEBUG, "PAM environment variable $EMAIL already set, not changing based on user record."); |
| 536 | + } else { |
| 537 | + _cleanup_free_ char *joined = NULL; |
| 538 | + |
| 539 | + joined = strjoin("EMAIL=", ur->email_address); |
| 540 | + if (!joined) |
| 541 | + return pam_log_oom(handle); |
| 542 | + |
| 543 | + r = pam_putenv_and_log(handle, joined, debug); |
| 544 | + if (r != PAM_SUCCESS) |
| 545 | + return r; |
| 546 | + } |
| 547 | + } |
| 548 | + |
| 549 | + if (ur->time_zone) { |
| 550 | + if (pam_getenv(handle, "TZ")) { |
| 551 | + if (debug) |
| 552 | + pam_syslog(handle, LOG_DEBUG, "PAM environment variable $TZ already set, not changing based on user record."); |
| 553 | + } else if (!timezone_is_valid(ur->time_zone, LOG_DEBUG)) { |
| 554 | + if (debug) |
| 555 | + pam_syslog(handle, LOG_DEBUG, "Time zone specified in user record is not valid locally, not setting $TZ."); |
| 556 | + } else { |
| 557 | + _cleanup_free_ char *joined = NULL; |
| 558 | + |
| 559 | + joined = strjoin("TZ=:", ur->time_zone); |
| 560 | + if (!joined) |
| 561 | + return pam_log_oom(handle); |
| 562 | + |
| 563 | + r = pam_putenv_and_log(handle, joined, debug); |
| 564 | + if (r != PAM_SUCCESS) |
| 565 | + return r; |
| 566 | + } |
| 567 | + } |
| 568 | + |
| 569 | + if (ur->preferred_language) { |
| 570 | + if (pam_getenv(handle, "LANG")) { |
| 571 | + if (debug) |
| 572 | + pam_syslog(handle, LOG_DEBUG, "PAM environment variable $LANG already set, not changing based on user record."); |
| 573 | + } else if (!locale_is_valid(ur->preferred_language)) { |
| 574 | + if (debug) |
| 575 | + pam_syslog(handle, LOG_DEBUG, "Preferred language specified in user record is not valid locally, not setting $LANG."); |
| 576 | + } else { |
| 577 | + _cleanup_free_ char *joined = NULL; |
| 578 | + |
| 579 | + joined = strjoin("LANG=", ur->preferred_language); |
| 580 | + if (!joined) |
| 581 | + return pam_log_oom(handle); |
| 582 | + |
| 583 | + r = pam_putenv_and_log(handle, joined, debug); |
| 584 | + if (r != PAM_SUCCESS) |
| 585 | + return r; |
| 586 | + } |
| 587 | + } |
| 588 | + |
| 589 | + if (nice_is_valid(ur->nice_level)) { |
| 590 | + if (nice(ur->nice_level) < 0) |
| 591 | + pam_syslog(handle, LOG_ERR, "Failed to set nice level to %i, ignoring: %s", ur->nice_level, strerror_safe(errno)); |
| 592 | + else if (debug) |
| 593 | + pam_syslog(handle, LOG_DEBUG, "Nice level set, based on user record."); |
| 594 | + } |
| 595 | + |
| 596 | + for (int rl = 0; rl < _RLIMIT_MAX; rl++) { |
| 597 | + |
| 598 | + if (!ur->rlimits[rl]) |
| 599 | + continue; |
| 600 | + |
| 601 | + r = setrlimit_closest(rl, ur->rlimits[rl]); |
| 602 | + if (r < 0) |
| 603 | + pam_syslog(handle, LOG_ERR, "Failed to set resource limit %s, ignoring: %s", rlimit_to_string(rl), strerror_safe(r)); |
| 604 | + else if (debug) |
| 605 | + pam_syslog(handle, LOG_DEBUG, "Resource limit %s set, based on user record.", rlimit_to_string(rl)); |
| 606 | + } |
| 607 | + |
| 608 | + return PAM_SUCCESS; |
| 609 | +} |
| 610 | + |
476 | 611 | _public_ PAM_EXTERN int pam_sm_open_session( |
477 | 612 | pam_handle_t *handle, |
478 | 613 | int flags, |
@@ -540,6 +675,10 @@ _public_ PAM_EXTERN int pam_sm_open_session( |
540 | 675 | if (r != PAM_SUCCESS) |
541 | 676 | return r; |
542 | 677 |
|
| 678 | + r = apply_user_record_settings(handle, ur, debug); |
| 679 | + if (r != PAM_SUCCESS) |
| 680 | + return r; |
| 681 | + |
543 | 682 | return PAM_SUCCESS; |
544 | 683 | } |
545 | 684 |
|
@@ -797,9 +936,13 @@ _public_ PAM_EXTERN int pam_sm_open_session( |
797 | 936 | } |
798 | 937 | } |
799 | 938 |
|
| 939 | + r = apply_user_record_settings(handle, ur, debug); |
| 940 | + if (r != PAM_SUCCESS) |
| 941 | + return r; |
| 942 | + |
800 | 943 | /* Let's release the D-Bus connection, after all the session might live quite a long time, and we are |
801 | | - * not going to process the bus connection in that time, so let's better close before the daemon |
802 | | - * kicks us off because we are not processing anything. */ |
| 944 | + * not going to use the bus connection in that time, so let's better close before the daemon kicks us |
| 945 | + * off because we are not processing anything. */ |
803 | 946 | (void) pam_release_bus_connection(handle); |
804 | 947 | return PAM_SUCCESS; |
805 | 948 | } |
|
0 commit comments