# Author: Vlad Glagolev <stealth@sourcemage.org>
#
# Changes in this patch:
# * groups and comments support
# * bugfix for not found user or empty file
# * bugfix for unlimited values
# * bugfix for tab separators

--- src/ulimits.c.orig	2013-01-28 14:39:13.000000000 +0400
+++ src/ulimits.c	2014-10-02 21:39:49.318495483 +0400
@@ -29,6 +29,7 @@
 
 #include <unistd.h>
 #include <pwd.h>
+#include <grp.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/resource.h>
@@ -95,6 +96,47 @@
 #define PLIMIT_PRIORITY RLIMIT_NLIMITS + 3
 
 /**
+ * Check if user is in the group
+ *
+ * @param uname A pointer to a username
+ * @param gname A pointer to a groupname
+ * @return 0 if a user belongs to group, -1 otherwise
+ */
+static int user_in_group(const *uname, const char *gname)
+{
+	struct group *groupdata;
+	char *const *list;
+
+	if (uname == NULL || gname == NULL) {
+		return -1;
+	}
+
+	if (*gname == '@') {
+		gname++;
+	} else {
+		return -1;
+	}
+
+	groupdata = getgrnam(gname);
+
+	if (groupdata == NULL) {
+		return -1;
+	}
+
+	list = groupdata->gr_mem;
+
+	while (*list != NULL) {
+		if (strcmp(*list, uname) == 0) {
+			return 0;
+		}
+
+		list++;
+	}
+
+	return -1;
+}
+
+/**
  * Parses a single limit specification.
  * This function parses a single limit specification (that is, a single
  * letter followed by a numerical value) and fills the provided
@@ -109,7 +151,7 @@
 parse_limit_value(char **s, struct rlimit_setting *rlimit)
 {
     char *c, *p;
-    int value;
+    int value, inf;
 
     if ( s == NULL || *s == NULL || rlimit == NULL ) {
         errno = EINVAL;
@@ -123,7 +165,16 @@
 
     /* Get the numerical value for the limit. */
     errno = 0;
-    value = strtol(c + 1, &p, 10);
+
+    /* A single dash means no limits. */
+    if (*(c+1) == '-') {
+        p = c+2;
+        inf = 1;
+    } else {
+        value = strtol(c + 1, &p, 10);
+        inf = 0;
+    }
+
     if ( errno || p == c + 1 )
         return -1;
 
@@ -132,7 +183,7 @@
 #define ULIMIT(symbol, letter, unused1, factor, unused2)    \
     case letter:                                            \
         rlimit->resource = symbol;                          \
-        rlimit->limit = value * factor;                     \
+        rlimit->limit = inf == 1 ? RLIM_INFINITY : value * factor; \
         break;
 #include "ulimits.h"
 #undef ULIMIT
@@ -174,15 +225,6 @@
     while ( *s == ' ' || *s == '\t' )
         s += 1;
 
-    /* A single dash means no limits. */
-    if ( *s == '-' && *(s + 1) == '\0' ) {
-        for ( ; n < RLIMIT_NLIMITS && n < len - 1 ; n++ ) {
-            rlimits[n].resource = n;
-            rlimits[n].limit = RLIM_INFINITY;
-        }
-        s += 1;
-    }
-
     while ( *s != '\0' && n < len - 1 ) {
         if ( parse_limit_value(&s, &(rlimits[n])) < 0 )
             return -1;
@@ -280,9 +322,11 @@
     while ( ! found && ! feof(f) ) {
         c = fgetc(f);
 
-        if ( isgraph(c) && n < len - 1 )
+        if (c == '#')
+            discard_line(f);
+        else if ( isgraph(c) && n < len - 1 )
             buffer[n++] = (char)c;
-        else if ( c == ' ' && n > 0 )
+        else if ( (c == ' ' || c == '\t') && n > 0 )
             found = 1;
         else {
             n = 0;
@@ -357,18 +401,21 @@
 
         if ( strcmp(nbuf, "*") == 0 )
             default_found = get_line(f, lbuf, sizeof(lbuf)) != -1;
-        else if ( strcmp(nbuf, user) == 0 )
+        else if ( strcmp(nbuf, user) == 0 || user_in_group(user, nbuf) == 0 )
             user_found = get_line(f, lbuf, sizeof(lbuf)) != -1;
         else
             discard_line(f);
     }
     fclose(f);
 
-    if ( user_found || default_found )
+    if ( user_found || default_found ) {
         if ( (n = parse_limit_string(lbuf, rlimits, len)) == -1 )
             errno = EBADMSG;
 
-    return n;
+        return n;
+    }
+
+    return -1;
 }
 
 static int
