summaryrefslogtreecommitdiffstats
path: root/contrib/libpam/modules/pam_limits/pam_limits.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libpam/modules/pam_limits/pam_limits.c')
-rw-r--r--contrib/libpam/modules/pam_limits/pam_limits.c246
1 files changed, 150 insertions, 96 deletions
diff --git a/contrib/libpam/modules/pam_limits/pam_limits.c b/contrib/libpam/modules/pam_limits/pam_limits.c
index 179c430..7a5ec47 100644
--- a/contrib/libpam/modules/pam_limits/pam_limits.c
+++ b/contrib/libpam/modules/pam_limits/pam_limits.c
@@ -1,6 +1,8 @@
/*
* pam_limits - impose resource limits when opening a user session
*
+ * 1.6 - modified for PLD (added process priority settings)
+ * by Marcin Korzonek <mkorz@shadow.eu.org
* 1.5 - Elliot Lee's "max system logins patch"
* 1.4 - addressed bug in configuration file parser
* 1.3 - modified the configuration file format
@@ -15,9 +17,10 @@
#error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!!
#endif
+#include <security/_pam_aconf.h>
+
#include <stdio.h>
#include <unistd.h>
-#define __USE_POSIX2
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
@@ -26,11 +29,15 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
+
#include <utmp.h>
#ifndef UT_USER /* some systems have ut_name instead of ut_user */
#define UT_USER ut_user
#endif
+#include <grp.h>
+#include <pwd.h>
+
/* Module defines */
#define LINE_LENGTH 1024
@@ -39,23 +46,28 @@
#define LIMITS_DEF_DEFAULT 2 /* limit was set by an default entry */
#define LIMITS_DEF_NONE 3 /* this limit was not set yet */
-/* internal data */
-static char conf_file[BUFSIZ];
-
struct user_limits_struct {
int src_soft;
int src_hard;
struct rlimit limit;
};
-static struct user_limits_struct limits[RLIM_NLIMITS];
-static int login_limit; /* the max logins limit */
-static int login_limit_def; /* which entry set the login limit */
-static int flag_numsyslogins; /* whether to limit logins only for a
- specific user or to count all logins */
+/* internal data */
+struct pam_limit_s {
+ int login_limit; /* the max logins limit */
+ int login_limit_def; /* which entry set the login limit */
+ int flag_numsyslogins; /* whether to limit logins only for a
+ 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];
+};
#define LIMIT_LOGIN RLIM_NLIMITS+1
#define LIMIT_NUMSYSLOGINS RLIM_NLIMITS+2
+
+#define LIMIT_PRI RLIM_NLIMITS+3
+
#define LIMIT_SOFT 1
#define LIMIT_HARD 2
@@ -63,7 +75,6 @@ static int flag_numsyslogins; /* whether to limit logins only for a
#include <security/pam_modules.h>
#include <security/_pam_macros.h>
-#include <pwdb/pwdb_map.h>
/* logging */
static void _pam_log(int err, const char *format, ...)
@@ -80,8 +91,9 @@ static void _pam_log(int err, const char *format, ...)
/* argument parsing */
#define PAM_DEBUG_ARG 0x0001
+#define PAM_DO_SETREUID 0x0002
-static int _pam_parse(int argc, const char **argv)
+static int _pam_parse(int argc, const char **argv, struct pam_limit_s *pl)
{
int ctrl=0;
@@ -93,7 +105,9 @@ static int _pam_parse(int argc, const char **argv)
if (!strcmp(*argv,"debug"))
ctrl |= PAM_DEBUG_ARG;
else if (!strncmp(*argv,"conf=",5))
- strcpy(conf_file,*argv+5);
+ strcpy(pl->conf_file,*argv+5);
+ else if (!strncmp(*argv,"change_uid",10))
+ ctrl |= PAM_DO_SETREUID;
else {
_pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
}
@@ -104,15 +118,18 @@ static int _pam_parse(int argc, const char **argv)
/* limits stuff */
-#ifndef LIMITS_FILE
-#define LIMITS_FILE "/etc/security/limits.conf"
+#ifdef DEFAULT_CONF_FILE
+# define LIMITS_FILE DEFAULT_CONF_FILE
+#else
+# define LIMITS_FILE "/etc/security/limits.conf"
#endif
#define LIMIT_ERR 1 /* error setting a limit */
#define LOGIN_ERR 2 /* too many logins err */
/* Counts the number of user logins and check against the limit*/
-static int check_logins(const char *name, int limit, int ctrl)
+static int check_logins(const char *name, int limit, int ctrl,
+ struct pam_limit_s *pl)
{
struct utmp *ut;
unsigned int count;
@@ -137,7 +154,7 @@ static int check_logins(const char *name, int limit, int ctrl)
#endif
if (ut->UT_USER[0] == '\0')
continue;
- if (!flag_numsyslogins
+ if (!pl->flag_numsyslogins
&& strncmp(name, ut->UT_USER, sizeof(ut->UT_USER)) != 0)
continue;
if (++count >= limit)
@@ -212,65 +229,61 @@ static int is_on_group(const char *user_name, const char *group_name)
return 0;
}
-static int init_limits(void)
+static int init_limits(struct pam_limit_s *pl)
{
+ int i;
int retval = PAM_SUCCESS;
D(("called."));
- retval |= getrlimit(RLIMIT_CPU, &limits[RLIMIT_CPU].limit);
- limits[RLIMIT_CPU].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_CPU].src_hard = LIMITS_DEF_NONE;
+ for(i = 0; i < RLIM_NLIMITS; i++)
+ retval |= getrlimit(i, &pl->limits[i].limit);
+
+ pl->limits[RLIMIT_CPU].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_CPU].src_hard = LIMITS_DEF_NONE;
+
+ pl->limits[RLIMIT_FSIZE].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_FSIZE].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_FSIZE, &limits[RLIMIT_FSIZE].limit);
- limits[RLIMIT_FSIZE].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_FSIZE].src_hard = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_DATA].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_DATA].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_DATA, &limits[RLIMIT_DATA].limit);
- limits[RLIMIT_DATA].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_DATA].src_hard = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_STACK].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_STACK].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_STACK, &limits[RLIMIT_STACK].limit);
- limits[RLIMIT_STACK].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_STACK].src_hard = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_CORE].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_CORE].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_CORE, &limits[RLIMIT_CORE].limit);
- limits[RLIMIT_CORE].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_CORE].src_hard = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_RSS].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_RSS].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_RSS, &limits[RLIMIT_RSS].limit);
- limits[RLIMIT_RSS].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_RSS].src_hard = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_NPROC].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_NPROC].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_NPROC, &limits[RLIMIT_NPROC].limit);
- limits[RLIMIT_NPROC].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_NPROC].src_hard = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_NOFILE].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_NOFILE].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_NOFILE, &limits[RLIMIT_NOFILE].limit);
- limits[RLIMIT_NOFILE].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_NOFILE].src_hard = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_MEMLOCK].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_MEMLOCK].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_MEMLOCK, &limits[RLIMIT_MEMLOCK].limit);
- limits[RLIMIT_MEMLOCK].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_MEMLOCK].src_hard = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_AS].src_soft = LIMITS_DEF_NONE;
+ pl->limits[RLIMIT_AS].src_hard = LIMITS_DEF_NONE;
- retval |= getrlimit(RLIMIT_AS, &limits[RLIMIT_AS].limit);
- limits[RLIMIT_AS].src_soft = LIMITS_DEF_NONE;
- limits[RLIMIT_AS].src_hard = LIMITS_DEF_NONE;
+ pl->priority = 0;
+ pl->login_limit = -2;
+ pl->login_limit_def = LIMITS_DEF_NONE;
- login_limit = -2;
- login_limit_def = LIMITS_DEF_NONE;
return retval;
}
static void process_limit(int source, const char *lim_type,
const char *lim_item, const char *lim_value,
- int ctrl)
+ int ctrl, struct pam_limit_s *pl)
{
int limit_item;
int limit_type = 0;
long limit_value;
- char **endptr = (char **) &lim_value;
+ const char **endptr = &lim_value;
const char *value_orig = lim_value;
if (ctrl & PAM_DEBUG_ARG)
@@ -299,10 +312,12 @@ static void process_limit(int source, const char *lim_type,
limit_item = RLIMIT_AS;
else if (strcmp(lim_item, "maxlogins") == 0) {
limit_item = LIMIT_LOGIN;
- flag_numsyslogins = 0;
+ pl->flag_numsyslogins = 0;
} else if (strcmp(lim_item, "maxsyslogins") == 0) {
limit_item = LIMIT_NUMSYSLOGINS;
- flag_numsyslogins = 1;
+ pl->flag_numsyslogins = 1;
+ } else if (strcmp(lim_item, "priority") == 0) {
+ limit_item = LIMIT_PRI;
} else {
_pam_log(LOG_DEBUG,"unknown limit item '%s'", lim_item);
return;
@@ -349,38 +364,47 @@ static void process_limit(int source, const char *lim_type,
break;
}
- if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS) {
- if (limit_type & LIMIT_SOFT)
- if (limits[limit_item].src_soft < source)
+ if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS
+ && limit_item != LIMIT_PRI
+ ) {
+ if (limit_type & LIMIT_SOFT) {
+ if (pl->limits[limit_item].src_soft < source) {
return;
- else {
- limits[limit_item].limit.rlim_cur = limit_value;
- limits[limit_item].src_soft = source;
+ } else {
+ pl->limits[limit_item].limit.rlim_cur = limit_value;
+ pl->limits[limit_item].src_soft = source;
}
- if (limit_type & LIMIT_HARD)
- if (limits[limit_item].src_hard < source)
+ }
+ if (limit_type & LIMIT_HARD) {
+ if (pl->limits[limit_item].src_hard < source) {
return;
- else {
- limits[limit_item].limit.rlim_max = limit_value;
- limits[limit_item].src_hard = source;
+ } else {
+ pl->limits[limit_item].limit.rlim_max = limit_value;
+ pl->limits[limit_item].src_hard = source;
}
- } else
- if (login_limit_def < source)
- return;
- else {
- login_limit = limit_value;
- login_limit_def = source;
- }
-
- return;
+ }
+ } else
+ if (limit_item == LIMIT_PRI) {
+ /* additional check */
+ pl->priority = ((limit_value>0)?limit_value:0);
+ } else {
+ if (pl->login_limit_def < source) {
+ return;
+ } else {
+ pl->login_limit = limit_value;
+ pl->login_limit_def = source;
+ }
+ }
+ return;
}
-static int parse_config_file(const char *uname, int ctrl)
+static int parse_config_file(const char *uname, int ctrl,
+ struct pam_limit_s *pl)
{
FILE *fil;
char buf[LINE_LENGTH];
-#define CONF_FILE (conf_file[0])?conf_file:LIMITS_FILE
+#define CONF_FILE (pl->conf_file[0])?pl->conf_file:LIMITS_FILE
/* check for the LIMITS_FILE */
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_DEBUG,"reading settings from '%s'", CONF_FILE);
@@ -428,6 +452,9 @@ static int parse_config_file(const char *uname, int ctrl)
memset(value, 0, sizeof(value));
i = sscanf(buf,"%s%s%s%s", domain, ltype, item, value);
+ D(("scanned line[%d]: domain[%s], ltype[%s], item[%s], value[%s]",
+ i, domain, ltype, item, value));
+
for(j=0; j < strlen(domain); j++)
domain[j]=tolower(domain[j]);
for(j=0; j < strlen(ltype); j++)
@@ -439,36 +466,56 @@ static int parse_config_file(const char *uname, int ctrl)
if (i == 4) { /* a complete line */
if (strcmp(uname, domain) == 0) /* this user have a limit */
- process_limit(LIMITS_DEF_USER, ltype, item, value, ctrl);
+ process_limit(LIMITS_DEF_USER, ltype, item, value, ctrl, pl);
else if (domain[0]=='@') {
if (is_on_group(uname, domain+1))
- process_limit(LIMITS_DEF_GROUP, ltype, item, value, ctrl);
+ process_limit(LIMITS_DEF_GROUP, ltype, item, value, ctrl,
+ pl);
} else if (strcmp(domain, "*") == 0)
- process_limit(LIMITS_DEF_DEFAULT, ltype, item, value, ctrl);
- } else
- _pam_log(LOG_DEBUG,"invalid line '%s'", buf);
+ process_limit(LIMITS_DEF_DEFAULT, ltype, item, value, ctrl,
+ pl);
+ } else if (i == 2 && ltype[0] == '-') { /* Probably a no-limit line */
+ if (strcmp(uname, domain) == 0) {
+ _pam_log(LOG_DEBUG, "no limits for '%s'", uname);
+ fclose(fil);
+ return PAM_IGNORE;
+ } else if (domain[0] == '@' && is_on_group(uname, domain+1)) {
+ _pam_log(LOG_DEBUG, "no limits for '%s' in group '%s'",
+ uname, domain+1);
+ fclose(fil);
+ return PAM_IGNORE;
+ }
+ } else {
+ _pam_log(LOG_DEBUG,"invalid line '%s' - skipped", buf);
+ }
}
fclose(fil);
return PAM_SUCCESS;
}
-static int setup_limits(const char * uname, int ctrl)
+static int setup_limits(const char * uname, int ctrl, struct pam_limit_s *pl)
{
int i;
int retval = PAM_SUCCESS;
for (i=0; i<RLIM_NLIMITS; i++) {
- if (limits[i].limit.rlim_cur > limits[i].limit.rlim_max)
- limits[i].limit.rlim_cur = limits[i].limit.rlim_max;
- retval |= setrlimit(i, &limits[i].limit);
+ if (pl->limits[i].limit.rlim_cur > pl->limits[i].limit.rlim_max)
+ pl->limits[i].limit.rlim_cur = pl->limits[i].limit.rlim_max;
+ retval |= setrlimit(i, &pl->limits[i].limit);
}
if (retval != PAM_SUCCESS)
retval = LIMIT_ERR;
- if (login_limit > 0) {
- if (check_logins(uname, login_limit, ctrl) == LOGIN_ERR)
+
+ retval=setpriority(PRIO_PROCESS, 0, pl->priority);
+
+ if (retval != PAM_SUCCESS)
+ retval = LIMIT_ERR;
+
+ if (pl->login_limit > 0) {
+ if (check_logins(uname, pl->login_limit, ctrl, pl) == LOGIN_ERR)
retval |= LOGIN_ERR;
- } else if (login_limit == 0)
+ } else if (pl->login_limit == 0)
retval |= LOGIN_ERR;
return retval;
}
@@ -481,12 +528,13 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
char *user_name;
struct passwd *pwd;
int ctrl;
-
+ struct pam_limit_s pl;
+
D(("called."));
- memset(conf_file, 0, sizeof(conf_file));
-
- ctrl = _pam_parse(argc, argv);
+ memset(&pl, 0, sizeof(pl));
+
+ ctrl = _pam_parse(argc, argv, &pl);
retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
if ( user_name == NULL || retval != PAM_SUCCESS ) {
_pam_log(LOG_CRIT, "open_session - error recovering username");
@@ -511,19 +559,25 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
return PAM_SUCCESS;
}
- retval = init_limits();
+ retval = init_limits(&pl);
if (retval != PAM_SUCCESS) {
- _pam_log(LOG_WARNING, "can not initialize");
+ _pam_log(LOG_WARNING, "cannot initialize");
return PAM_IGNORE;
}
- retval = parse_config_file(pwd->pw_name,ctrl);
+ retval = parse_config_file(pwd->pw_name, ctrl, &pl);
+ if (retval == PAM_IGNORE) {
+ D(("the configuration file has an applicable '<domain> -' entry"));
+ return PAM_SUCCESS;
+ }
if (retval != PAM_SUCCESS) {
_pam_log(LOG_WARNING, "error parsing the configuration file");
return PAM_IGNORE;
}
-
- retval = setup_limits(pwd->pw_name, ctrl);
+
+ if (ctrl & PAM_DO_SETREUID)
+ setreuid(pwd->pw_uid, -1);
+ retval = setup_limits(pwd->pw_name, ctrl, &pl);
if (retval & LOGIN_ERR) {
printf("\nToo many logins for '%s'\n",pwd->pw_name);
sleep(2);
OpenPOWER on IntegriCloud