diff options
-rw-r--r-- | modules/pam_limits/Makefile.am | 4 | ||||
-rw-r--r-- | modules/pam_limits/pam_limits.c | 81 |
2 files changed, 80 insertions, 5 deletions
diff --git a/modules/pam_limits/Makefile.am b/modules/pam_limits/Makefile.am index ab3cf33e..3f64d79b 100644 --- a/modules/pam_limits/Makefile.am +++ b/modules/pam_limits/Makefile.am @@ -24,7 +24,7 @@ limits_conf_dir = $(SCONFIGDIR)/limits.d AM_CFLAGS = -I$(top_srcdir)/libpam/include \ -DLIMITS_FILE_DIR=\"$(limits_conf_dir)\" \ - $(WARN_CFLAGS) + $(LOGIND_CFLAGS) $(WARN_CFLAGS) AM_LDFLAGS = -no-undefined -avoid-version -module if HAVE_VERSIONING AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map @@ -32,7 +32,7 @@ endif securelib_LTLIBRARIES = pam_limits.la pam_limits_la_LIBADD = $(top_builddir)/libpam_internal/libpam_internal.la \ - $(top_builddir)/libpam/libpam.la + $(top_builddir)/libpam/libpam.la $(SYSTEMD_LIBS) dist_secureconf_DATA = limits.conf diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c index 75c584fc..1e4dfa3d 100644 --- a/modules/pam_limits/pam_limits.c +++ b/modules/pam_limits/pam_limits.c @@ -36,7 +36,12 @@ #include <sys/resource.h> #include <limits.h> #include <glob.h> +#ifdef USE_LOGIND +#include <systemd/sd-login.h> +#else #include <utmp.h> +#endif + #ifndef UT_USER /* some systems have ut_name instead of ut_user */ #define UT_USER ut_user #endif @@ -240,7 +245,6 @@ static int check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl, struct pam_limit_s *pl) { - struct utmp *ut; int count; if (ctrl & PAM_DEBUG_ARG) { @@ -255,8 +259,6 @@ check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl, return LOGIN_ERR; } - setutent(); - /* Because there is no definition about when an application actually adds a utmp entry, some applications bizarrely do the utmp call before the have PAM authenticate them to the system: @@ -273,6 +275,78 @@ check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl, count = 1; } +#ifdef USE_LOGIND + char **sessions_list; + int sessions = sd_get_sessions(&sessions_list); + + /* maxlogins needs to be 2 with systemd-logind because + of the systemd --user process started with first login by + pam_systemd. + Which is also calling pam_limits, but in this very first special + case the session does already exist and is counted twice. + With start of the second session, session manager is already running + and no longer counted. */ + if (limit == 1) { + pam_syslog(pamh, LOG_WARNING, "Maxlogin limit needs to be 2 or higher with systemd-logind"); + return LIMIT_ERR; + } + + if (sessions < 0) { + pam_syslog(pamh, LOG_ERR, "logind error getting session list: %s", + strerror(-sessions)); + return LIMIT_ERR; + } else if (sessions > 0 && sessions_list != NULL && !pl->flag_numsyslogins) { + int i; + + for (i = 0; i < sessions; i++) { + char *user = NULL; + char *class = NULL; + + if (sd_session_get_class(sessions_list[i], &class) < 0 || class == NULL) + continue; + + if (strncmp(class, "user", 4) != 0) { /* user, user-early, user-incomplete */ + free (class); + continue; + } + free (class); + + if (sd_session_get_username(sessions_list[i], &user) < 0 || user == NULL) { + pam_syslog(pamh, LOG_ERR, "logind error getting username: %s", + strerror(-sessions)); + return LIMIT_ERR; + } + + if (((pl->login_limit_def == LIMITS_DEF_USER) + || (pl->login_limit_def == LIMITS_DEF_GROUP) + || (pl->login_limit_def == LIMITS_DEF_DEFAULT)) + && strcmp(name, user) != 0) { + free(user); + continue; + } + if ((pl->login_limit_def == LIMITS_DEF_ALLGROUP) + && pl->login_group != NULL + && !pam_modutil_user_in_group_nam_nam(pamh, user, pl->login_group)) { + free(user); + continue; + } + free(user); + + if (++count > limit) { + break; + } + } + for (i = 0; i < sessions; i++) + free(sessions_list[i]); + free(sessions_list); + } else { + count = sessions; + } +#else + struct utmp *ut; + + setutent(); + while((ut = getutent())) { #ifdef USER_PROCESS if (ut->ut_type != USER_PROCESS) { @@ -311,6 +385,7 @@ check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl, } } endutent(); +#endif if (count > limit) { if (name) { pam_syslog(pamh, LOG_NOTICE, |