summaryrefslogtreecommitdiff
path: root/modules/pam_limits
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_limits')
-rw-r--r--modules/pam_limits/Makefile.am4
-rw-r--r--modules/pam_limits/pam_limits.8.xml10
-rw-r--r--modules/pam_limits/pam_limits.c74
3 files changed, 71 insertions, 17 deletions
diff --git a/modules/pam_limits/Makefile.am b/modules/pam_limits/Makefile.am
index be2852a9..60256a7c 100644
--- a/modules/pam_limits/Makefile.am
+++ b/modules/pam_limits/Makefile.am
@@ -13,8 +13,10 @@ TESTS = tst-pam_limits
securelibdir = $(SECUREDIR)
secureconfdir = $(SCONFIGDIR)
+limits_conf_dir = $(SCONFIGDIR)/limits.d
AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
+ -DLIMITS_FILE_DIR=\"$(limits_conf_dir)/*.conf\" \
-DLIMITS_FILE=\"$(SCONFIGDIR)/limits.conf\"
AM_LDFLAGS = -no-undefined -avoid-version -module \
-L$(top_builddir)/libpam -lpam
@@ -32,3 +34,5 @@ README: pam_limits.8.xml limits.conf.5.xml
-include $(top_srcdir)/Make.xml.rules
endif
+install-data-local:
+ mkdir -p $(DESTDIR)$(limits_conf_dir)
diff --git a/modules/pam_limits/pam_limits.8.xml b/modules/pam_limits/pam_limits.8.xml
index 78060a20..9f13bb68 100644
--- a/modules/pam_limits/pam_limits.8.xml
+++ b/modules/pam_limits/pam_limits.8.xml
@@ -47,7 +47,15 @@
</para>
<para>
By default limits are taken from the <filename>/etc/security/limits.conf</filename>
- config file.
+ config file. Then individual files from the <filename>/etc/security/limits.d/</filename>
+ directory are read. The files are parsed one after another in the order of "C" locale.
+ The effect of the individual files is the same as if all the files were
+ concatenated together in the order of parsing.
+ If a config file is explicitely specified with a module option then the
+ files in the above directory are not parsed.
+ </para>
+ <para>
+ The module must not be called by a multithreaded application.
</para>
</refsect1>
diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c
index 20aa794a..f9a91164 100644
--- a/modules/pam_limits/pam_limits.c
+++ b/modules/pam_limits/pam_limits.c
@@ -31,7 +31,7 @@
#include <sys/stat.h>
#include <sys/resource.h>
#include <limits.h>
-
+#include <glob.h>
#include <utmp.h>
#ifndef UT_USER /* some systems have ut_name instead of ut_user */
#define UT_USER ut_user
@@ -75,7 +75,7 @@ struct pam_limit_s {
specific user or to count all logins */
int priority; /* the priority to run user process with */
struct user_limits_struct limits[RLIM_NLIMITS];
- char conf_file[BUFSIZ];
+ const char *conf_file;
int utmp_after_pam_call;
char login_group[LINE_LENGTH];
};
@@ -101,6 +101,11 @@ struct pam_limit_s {
#define PAM_DO_SETREUID 0x0002
#define PAM_UTMP_EARLY 0x0004
+/* Limits from globbed files. */
+#define LIMITS_CONF_GLOB LIMITS_FILE_DIR
+
+#define CONF_FILE (pl->conf_file != NULL)?pl->conf_file:LIMITS_FILE
+
static int
_pam_parse (const pam_handle_t *pamh, int argc, const char **argv,
struct pam_limit_s *pl)
@@ -115,7 +120,7 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv,
if (!strcmp(*argv,"debug")) {
ctrl |= PAM_DEBUG_ARG;
} else if (!strncmp(*argv,"conf=",5)) {
- strncpy(pl->conf_file,*argv+5,sizeof(pl->conf_file)-1);
+ pl->conf_file = *argv+5;
} else if (!strncmp(*argv,"change_uid",10)) {
ctrl |= PAM_DO_SETREUID;
} else if (!strcmp(*argv,"utmp_early")) {
@@ -124,7 +129,6 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv,
pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
}
}
- pl->conf_file[sizeof(pl->conf_file) - 1] = '\0';
return ctrl;
}
@@ -434,7 +438,6 @@ static int parse_config_file(pam_handle_t *pamh, const char *uname, int ctrl,
FILE *fil;
char buf[LINE_LENGTH];
-#define CONF_FILE (pl->conf_file[0])?pl->conf_file:LIMITS_FILE
/* check for the LIMITS_FILE */
if (ctrl & PAM_DEBUG_ARG)
pam_syslog(pamh, LOG_DEBUG, "reading settings from '%s'", CONF_FILE);
@@ -444,7 +447,6 @@ static int parse_config_file(pam_handle_t *pamh, const char *uname, int ctrl,
"cannot read settings from %s: %m", CONF_FILE);
return PAM_SERVICE_ERR;
}
-#undef CONF_FILE
/* init things */
memset(buf, 0, sizeof(buf));
@@ -599,16 +601,22 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED,
int argc, const char **argv)
{
int retval;
+ int i;
+ int glob_rc;
char *user_name;
struct passwd *pwd;
int ctrl;
- struct pam_limit_s pl;
+ struct pam_limit_s plstruct;
+ struct pam_limit_s *pl = &plstruct;
+ glob_t globbuf;
+ const char *oldlocale;
D(("called."));
- memset(&pl, 0, sizeof(pl));
+ memset(pl, 0, sizeof(*pl));
+ memset(&globbuf, 0, sizeof(globbuf));
- ctrl = _pam_parse(pamh, argc, argv, &pl);
+ ctrl = _pam_parse(pamh, argc, argv, pl);
retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
if ( user_name == NULL || retval != PAM_SUCCESS ) {
pam_syslog(pamh, LOG_CRIT, "open_session - error recovering username");
@@ -623,26 +631,60 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED,
return PAM_USER_UNKNOWN;
}
- retval = init_limits(&pl);
+ retval = init_limits(pl);
if (retval != PAM_SUCCESS) {
pam_syslog(pamh, LOG_WARNING, "cannot initialize");
return PAM_ABORT;
}
- retval = parse_config_file(pamh, pwd->pw_name, ctrl, &pl);
+ retval = parse_config_file(pamh, pwd->pw_name, ctrl, pl);
if (retval == PAM_IGNORE) {
- D(("the configuration file has an applicable '<domain> -' entry"));
+ D(("the configuration file ('%s') has an applicable '<domain> -' entry", CONF_FILE));
return PAM_SUCCESS;
}
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_WARNING, "error parsing the configuration file");
- return retval;
+ if (retval != PAM_SUCCESS || pl->conf_file != NULL)
+ /* skip reading limits.d if config file explicitely specified */
+ goto out;
+
+ /* Read subsequent *.conf files, if they exist. */
+
+ /* set the LC_COLLATE so the sorting order doesn't depend
+ on system locale */
+
+ oldlocale = setlocale(LC_COLLATE, "C");
+ glob_rc = glob(LIMITS_CONF_GLOB, GLOB_ERR, NULL, &globbuf);
+
+ if (oldlocale != NULL)
+ setlocale (LC_COLLATE, oldlocale);
+
+ if (!glob_rc) {
+ /* Parse the *.conf files. */
+ for (i = 0; globbuf.gl_pathv[i] != NULL; i++) {
+ pl->conf_file = globbuf.gl_pathv[i];
+ retval = parse_config_file(pamh, pwd->pw_name, ctrl, pl);
+ if (retval == PAM_IGNORE) {
+ D(("the configuration file ('%s') has an applicable '<domain> -' entry", pl->conf_file));
+ globfree(&globbuf);
+ return PAM_SUCCESS;
+ }
+ if (retval != PAM_SUCCESS)
+ goto out;
+ }
+ }
+
+out:
+ globfree(&globbuf);
+ if (retval != PAM_SUCCESS)
+ {
+ pam_syslog(pamh, LOG_WARNING, "error parsing the configuration file: '%s' ",CONF_FILE);
+ return retval;
}
if (ctrl & PAM_DO_SETREUID) {
setreuid(pwd->pw_uid, -1);
}
- retval = setup_limits(pamh, pwd->pw_name, pwd->pw_uid, ctrl, &pl);
+
+ retval = setup_limits(pamh, pwd->pw_name, pwd->pw_uid, ctrl, pl);
if (retval & LOGIN_ERR)
pam_error(pamh, _("Too many logins for '%s'."), pwd->pw_name);
if (retval != LIMITED_OK) {