* NEWS, libmisc/limits.c: Fix parsing of limits.
* NEWS, libmisc/limits.c, man/limits.5.xml: Add support for infinite limits. * NEWS, libmisc/limits.c, man/limits.5.xml: Add support for @group syntax.
This commit is contained in:
parent
6b14a0d08c
commit
52c2bb51fb
@ -1,3 +1,11 @@
|
||||
2010-03-18 Thomas Orgis <thomas@orgis.org>
|
||||
|
||||
* NEWS, libmisc/limits.c: Fix parsing of limits.
|
||||
* NEWS, libmisc/limits.c, man/limits.5.xml: Add support for
|
||||
infinite limits.
|
||||
* NEWS, libmisc/limits.c, man/limits.5.xml: Add support for @group
|
||||
syntax.
|
||||
|
||||
2010-03-18 Nicolas François <nicolas.francois@centraliens.net>
|
||||
|
||||
* lib/tcbfuncs.h: Re-indent.
|
||||
|
4
NEWS
4
NEWS
@ -13,6 +13,10 @@ shadow-4.1.4.2 -> shadow-4.1.4.3 UNRELEASED
|
||||
specified.
|
||||
- groupmod
|
||||
* Fixed groupmod when configured with --enable-account-tools-setuid.
|
||||
-login
|
||||
* Fixed limits support (non PAM enabled versions only)
|
||||
* Added support for infinite limits and group based limits (non PAM
|
||||
enabled versions only)
|
||||
- su
|
||||
* Document the su exit values.
|
||||
* When su receives a signal, wait for the child to terminate (after
|
||||
|
113
libmisc/limits.c
113
libmisc/limits.c
@ -33,6 +33,7 @@
|
||||
/*
|
||||
* Separated from setup.c. --marekm
|
||||
* Resource limits thanks to Cristian Gafton.
|
||||
* Enhancements of resource limit code by Thomas Orgis <thomas@orgis.org> ("thor").
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@ -44,6 +45,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <pwd.h>
|
||||
@ -69,17 +71,37 @@ setrlimit_value (unsigned int resource, const char *value,
|
||||
unsigned int multiplier)
|
||||
{
|
||||
struct rlimit rlim;
|
||||
long limit;
|
||||
rlim_t limit;
|
||||
|
||||
if (getlong (value, &limit) == 0) {
|
||||
return 0;
|
||||
/* The "-" is special, not belonging to a strange negative limit.
|
||||
It is infinity, in a controlled way. --thor */
|
||||
if(value[0] == '-') {
|
||||
limit = RLIM_INFINITY;
|
||||
}
|
||||
limit *= multiplier;
|
||||
if (limit != (rlim_t) limit) {
|
||||
return 0;
|
||||
else {
|
||||
/* We cannot use getlong here because it fails when there
|
||||
is more to the value than just this number!
|
||||
Also, we are limited to base 10 here (hex numbers will not
|
||||
work with the limit string parser as is anyway) --thor */
|
||||
char *endptr;
|
||||
long longlimit = strtol(value, &endptr, 10);
|
||||
if ((0 == longlimit) && (value == endptr)) {
|
||||
/* No argument at all. No-op.
|
||||
We could instead throw an error, though. --thor */
|
||||
return 0;
|
||||
}
|
||||
longlimit *= multiplier;
|
||||
limit = (rlim_t)longlimit;
|
||||
if(longlimit != limit)
|
||||
{
|
||||
/* Again, silent error handling... I left it that way.
|
||||
Wouldn't screaming make more sense? --thor */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rlim.rlim_cur = (rlim_t) limit;
|
||||
rlim.rlim_max = (rlim_t) limit;
|
||||
|
||||
rlim.rlim_cur = limit;
|
||||
rlim.rlim_max = limit;
|
||||
if (setrlimit (resource, &rlim) != 0) {
|
||||
return LOGIN_ERROR_RLIMIT;
|
||||
}
|
||||
@ -199,6 +221,9 @@ static int check_logins (const char *name, const char *maxlogins)
|
||||
* [Ii]: i = RLIMIT_NICE max nice value (0..39 translates to 20..-19)
|
||||
* [Oo]: o = RLIMIT_RTPRIO max real time priority (linux/sched.h 0..MAX_RT_PRIO)
|
||||
*
|
||||
* Remember to extend the "no-limits" string below when adding a new limit...
|
||||
* --thor
|
||||
*
|
||||
* Return value:
|
||||
* 0 = okay, of course
|
||||
* LOGIN_ERROR_RLIMIT = error setting some RLIMIT
|
||||
@ -214,6 +239,19 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
bool reported = false;
|
||||
|
||||
pp = buf;
|
||||
/* Skip leading whitespace. --thor */
|
||||
while(*pp == ' ' || *pp == '\t') ++pp;
|
||||
|
||||
/* The special limit string "-" results in no limit for all known limits.
|
||||
We achieve that by parsing a full limit string, parts of it being ignored
|
||||
if a limit type is not known to the system.
|
||||
Though, there will be complaining for unknown limit types. --thor */
|
||||
if(strcmp(pp, "-") == 0) {
|
||||
/* Remember to extend this, too, when adding new limits!
|
||||
Oh... but "unlimited" does not make sense for umask, or does it?
|
||||
--thor */
|
||||
pp = "A- C- D- F- M- N- R- S- T- P- I- O-";
|
||||
}
|
||||
|
||||
while ('\0' != *pp) {
|
||||
switch (*pp++) {
|
||||
@ -316,6 +354,10 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
break;
|
||||
default:
|
||||
/* Only report invalid strings once */
|
||||
/* Note: A string can be invalid just because a specific (theoretically
|
||||
valid) setting is not supported by this build.
|
||||
It is just a warning in syslog anyway. The line is still processed
|
||||
--thor */
|
||||
if (!reported) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Invalid limit string: '%s'",
|
||||
@ -324,13 +366,51 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
retval |= LOGIN_ERROR_RLIMIT;
|
||||
}
|
||||
}
|
||||
/* After parsing one limit setting (or just complaining about it),
|
||||
one still needs to skip its argument to prevent a bogus warning on
|
||||
trying to parse that as limit specification.
|
||||
So, let's skip all digits, "-" and our limited set of whitespace.
|
||||
--thor */
|
||||
while(isdigit(*pp) || *pp == '-' || *pp == ' ' || *pp == '\t') {
|
||||
++pp;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Check if user uname is in the group gname.
|
||||
* Can I be sure that gr_mem contains no UID as string?
|
||||
* Returns true when user is in the group, false when not.
|
||||
* Any error is treated as false. --thor
|
||||
*/
|
||||
static bool user_in_group (const char *uname, const char *gname)
|
||||
{
|
||||
struct group *groupdata;
|
||||
char **member;
|
||||
if(uname == NULL || gname == NULL){
|
||||
return false;
|
||||
}
|
||||
/* We are not claiming to be re-entrant!
|
||||
* In case of paranoia or a multithreaded login program,
|
||||
* one needs to add some mess for getgrnam_r. */
|
||||
groupdata = getgrnam(gname);
|
||||
if(groupdata == NULL) {
|
||||
SYSLOG ((LOG_WARN, "Nonexisting group `%s' in limits file.", gname));
|
||||
return false;
|
||||
}
|
||||
/* Now look for our user in the list of members. */
|
||||
member = groupdata->gr_mem;
|
||||
while(*member != NULL) {
|
||||
if(strcmp(*member, uname) == 0) {
|
||||
return true;
|
||||
}
|
||||
++member;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int setup_user_limits (const char *uname)
|
||||
{
|
||||
/* TODO: allow and use @group syntax --cristiang */
|
||||
FILE *fil;
|
||||
char buf[1024];
|
||||
char name[1024];
|
||||
@ -352,7 +432,7 @@ static int setup_user_limits (const char *uname)
|
||||
}
|
||||
/* The limits file have the following format:
|
||||
* - '#' (comment) chars only as first chars on a line;
|
||||
* - username must start on first column
|
||||
* - username must start on first column (or *, or @group --thor)
|
||||
* A better (smarter) checking should be done --cristiang */
|
||||
while (fgets (buf, 1024, fil) != NULL) {
|
||||
if (('#' == buf[0]) || ('\n' == buf[0])) {
|
||||
@ -367,6 +447,13 @@ static int setup_user_limits (const char *uname)
|
||||
* Imposing a limit should be done with care, so a wrong
|
||||
* entry means no care anyway :-). A '-' as a limits
|
||||
* strings means no limits --cristiang */
|
||||
/* In addition to the handling of * as name which was alrady present,
|
||||
I added handling of the @group syntax.
|
||||
To clarify: The first entry with matching user name rules,
|
||||
everything after it is ignored. If there is no user entry,
|
||||
the last encountered entry for a matching group rules.
|
||||
If there is no matching group entry, the default limits rule.
|
||||
--thor. */
|
||||
if (sscanf (buf, "%s%[ACDFMNRSTULPIOacdfmnrstulpio0-9 \t-]",
|
||||
name, tempbuf) == 2) {
|
||||
if (strcmp (name, uname) == 0) {
|
||||
@ -374,6 +461,12 @@ static int setup_user_limits (const char *uname)
|
||||
break;
|
||||
} else if (strcmp (name, "*") == 0) {
|
||||
strcpy (deflimits, tempbuf);
|
||||
} else if (name[0] == '@') {
|
||||
/* If the user is in the group, the group limits apply unless
|
||||
later a line for the specific user is found. --thor */
|
||||
if(user_in_group(uname, name+1)) {
|
||||
strcpy (limits, tempbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,12 @@
|
||||
<emphasis remap='I'>user LIMITS_STRING</emphasis>
|
||||
</para>
|
||||
|
||||
<para>or in the form:</para>
|
||||
|
||||
<para>
|
||||
<emphasis remap='I'>@group LIMITS_STRING</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <emphasis>LIMITS_STRING</emphasis> is a string of a concatenated
|
||||
list of resource limits. Each limit consists of a letter identifier
|
||||
@ -124,11 +130,23 @@
|
||||
as the default entry.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The limits specified in the form "<replaceable>@group</replaceable>"
|
||||
apply to the members of the specified
|
||||
<replaceable>group</replaceable>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To completely disable limits for a user, a single dash
|
||||
"<emphasis>-</emphasis>" will do.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To disable a limit for a user, a single dash
|
||||
"<replaceable>-</replaceable>" can be used instead of the numerical
|
||||
value for this limit.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Also, please note that all limit settings are set PER LOGIN. They are
|
||||
not global, nor are they permanent. Perhaps global limits will come,
|
||||
|
Loading…
Reference in New Issue
Block a user