Relevant BUGIDs:

Purpose of commit: new feature

Commit summary:
---------------
        * modules/pam_limits/Makefile.am: Define limits.d dir and install it.
        * modules/pam_limits/pam_limits.8.xml: Describe limits.d parsing.
        * modules/pam_limits/pam_limits.c (pam_limit_s): Make conf_file ptr.
        (pam_parse): conf_file is now ptr.
        (pam_sm_open_session): Add parsing files from limits.d subdir using
        glob, change pl to pointer.
This commit is contained in:
Tomas Mraz 2007-03-29 20:33:07 +00:00
parent e2546c9b58
commit f6b973b922
5 changed files with 81 additions and 20 deletions

View File

@ -9,6 +9,13 @@
* modules/pam_unix/pam_unix_passwd.c (check_old_password,
save_old_password): Likewise.
* modules/pam_limits/Makefile.am: Define limits.d dir and install it.
* modules/pam_limits/pam_limits.8.xml: Describe limits.d parsing.
* modules/pam_limits/pam_limits.c (pam_limit_s): Make conf_file ptr.
(pam_parse): conf_file is now ptr.
(pam_sm_open_session): Add parsing files from limits.d subdir using
glob, change pl to pointer.
2007-03-12 Thorsten Kukuk <kukuk@thkukuk.de>
* po/ar.po: New translation.

6
NEWS
View File

@ -3,9 +3,9 @@ Linux-PAM NEWS -- history of user-visible changes.
Release X.XX.X.X
* Add translations for ar, ca, da, ru, sv and zu
* Update hungarian translation
* Add translations for ar, ca, da, ru, sv and zu.
* Update hungarian translation.
* Add support for limits.d directory to pam_limits.
Release 0.99.7.1

View File

@ -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)

View File

@ -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>

View File

@ -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) {