pam_group: group-based access

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello all,

I've been looking for a way to dynamically add groups to users
belonging to a certain user-group.

For example, I would like to dynamically add to the group 'plugdev',
all users belonging to the 'Domain Users' group.

From a quick look at the pam_group module I see that it supports
netgroups but not regular user groups (the kind you get from
/etc/groups).

To this end, I'm attaching a short patch that enables group-based access
in pam_group. Since the '@' sign is reserved for specifying netgroups,
I'm using the '%' sign to specify user-groups in the config file, like this:

xsh; tty* ; %users ; Al0000-2400 ; disk

Also, some tweaking has been done on the code that parses the config
file. To be able to specify user-groups containing spaces, but still
retain backwards compatibility with space-delimited lists, I've
introduced the escaped space '\ ' sequence, which is used like this:

gdm ; * ; %Domain\ Users ; Al0000-2400 ; plugdev

Documentation files, along with the sample config file have been updated to reflect these changes.

A few words regarding the implementation:

To be able to retain '\ ' as a space ' ' I'm scanning the input
data for consecutive spaces, comma's etc. just once. In the CVS
version of the code the whole buffer was (redundantly) scanned
multiple times, each time new data was read from the config file
(see modules/pam_group/pam_group.c:128).

The patch also includes a few indentation fixes and a new
macro ( IS_TOKEN(c) ) for simplifying the task of parsing
the tokens of logical expressions.

I'm not sure if this was needed, but I've added a short
entry in the ChangeLog file with an overview of the changes
made.

So, have a look at the patch and let me know what you think :-)

Best Regards,

Dimitris Glynos
diff -urN Linux-PAM/ChangeLog Linux-PAMb/ChangeLog
--- Linux-PAM/ChangeLog	2009-11-19 12:43:23.000000000 +0200
+++ Linux-PAMb/ChangeLog	2009-12-07 20:50:32.000000000 +0200
@@ -1,3 +1,14 @@
+2009-12-07  Dimitris Glynos <dimitris@xxxxxxxxxxxxxxx>
+	* modules/pam_group/pam_group.c: 
+		- Support the dynamic "subscription" to groups for members of 
+		  regular user groups (i.e. not just netgroups).
+		- Support (escaped) space characters in group names.
+		- Perform buffer contraction, comment deletion and
+		  multiple space substitution, in one pass, on the
+		  config file data
+		- Use the macro IS_TOKEN(c) for detecting characters of 
+		  a token belonging to a logical expression.
+
 2009-11-19  Tomas Mraz  <t8m@xxxxxxxxxx>
 
 	* modules/pam_sepermit/pam_sepermit.c(sepermit_match): Return
diff -urN Linux-PAM/modules/pam_group/group.conf Linux-PAMb/modules/pam_group/group.conf
--- Linux-PAM/modules/pam_group/group.conf	2007-09-01 05:10:32.000000000 +0300
+++ Linux-PAMb/modules/pam_group/group.conf	2009-12-07 20:53:31.000000000 +0200
@@ -95,5 +95,12 @@
 #xsh; tty* ;*;Al0900-1800;floppy
 
 #
+# and another example: any member of the group 'Domain Users' running 
+# 'xsh' on tty*, is granted access (at any time) to the group 'plugdev'
+#
+
+#xsh; tty* ; %Domain\ Users ; Al0000-2400 ; plugdev
+
+#
 # End of group.conf file
 #
diff -urN Linux-PAM/modules/pam_group/group.conf.5.xml Linux-PAMb/modules/pam_group/group.conf.5.xml
--- Linux-PAM/modules/pam_group/group.conf.5.xml	2006-06-22 22:44:30.000000000 +0300
+++ Linux-PAMb/modules/pam_group/group.conf.5.xml	2009-12-07 20:53:31.000000000 +0200
@@ -28,7 +28,9 @@
       For this module to function correctly there must be a correctly
       formatted <filename>/etc/security/group.conf</filename> file present.
       White spaces are ignored and lines maybe extended with '\' (escaped
-      newlines). Text following a '#' is ignored to the end of the line.
+      newlines). Space characters that are part of group names may be
+      specified using the escaped form '\ '. Text following a '#' is ignored
+      to the end of the line.
    </para>
 
     <para>
@@ -52,13 +54,14 @@
 
     <para>
       The third field, the <replaceable>users</replaceable>
-      field, is a logic list of users or a netgroup of users to whom this
-      rule applies.
+      field, is a logic list of users, or a group of users, or a netgroup of 
+      users to whom this rule applies. Group names are preceded by a '%' 
+      symbol, while netgroup names are preceded by a '@' symbol.
     </para>
 
     <para>
       For these items the simple wildcard '*' may be used only once.
-      With netgroups no wildcards or logic operators are allowed.
+      With groups or netgroups no wildcards or logic operators are allowed.
     </para>
 
     <para>
@@ -109,7 +112,14 @@
     </para>
     <programlisting>
 xsh; tty* ;sword;!Wk0900-1800;games, sound
-xsh; tty* ;*;Al0900-1800;floppy
+xsh; tty* ;*;Al0900-1800;floppy</programlisting>
+
+    <para>
+      Any member of the group 'Domain Users' running 'xsh' on tty*, 
+      is granted access (at any time) to the group 'plugdev'
+    </para>
+    <programlisting>
+xsh; tty* ; %Domain\ Users ; Al0000-2400 ; plugdev
     </programlisting>
   </refsect1>
 
diff -urN Linux-PAM/modules/pam_group/pam_group.c Linux-PAMb/modules/pam_group/pam_group.c
--- Linux-PAM/modules/pam_group/pam_group.c	2008-12-01 13:26:59.000000000 +0200
+++ Linux-PAMb/modules/pam_group/pam_group.c	2009-12-07 20:53:31.000000000 +0200
@@ -24,6 +24,10 @@
 
 #define PAM_GROUP_BUFLEN        1000
 #define FIELD_SEPARATOR         ';'   /* this is new as of .02 */
+#define IS_TOKEN(c)  ( isalpha(c) || (c) == '*' || isdigit(c) \
+                                  || (c) == '_' || (c) == '-' \
+                                  || (c) == '.' || (c) == '/' \
+                                  || (c) == ':' || (c) == ' ' )
 
 #ifndef TRUE
 # define TRUE 1
@@ -105,7 +109,7 @@
     (*buf)[*to] = '\0';
 
     while (fd >= 0 && *to < PAM_GROUP_BUFLEN) {
-	int i;
+	int i, last_read_pos;
 
 	/* now try to fill the remainder of the buffer */
 
@@ -117,15 +121,18 @@
 	} else if (!i) {
 	    close(fd);
 	    fd = -1;          /* end of file reached */
-	} else
+	    last_read_pos = *to;
+	} else {
+	    last_read_pos = *to;
 	    *to += i;
+	}
 
 	/*
 	 * contract the buffer. Delete any comments, and replace all
 	 * multiple spaces with single commas
 	 */
 
-	i = 0;
+	i = last_read_pos;
 #ifdef DEBUG_DUMP
 	D(("buffer=<%s>",*buf));
 #endif
@@ -162,8 +169,12 @@
 		if ((*buf)[i+1] == '\n') {
 		    shift_bytes(i + *buf, 2, *to - (i+2));
 		    *to -= 2;
+		} else if ((*buf)[i+1] == ' ') {
+		    shift_bytes(i + *buf, 1, *to - (i+1));
+		    *to -= 1;
+		    ++i;
 		} else {
-		    ++i;   /* we don't escape non-newline characters */
+		    ++i; /* we escape only space and newline characters */
 		}
 		break;
 	    case '!':
@@ -198,8 +209,8 @@
 		return fd;
 	    case FIELD_SEPARATOR:    /* end of the field */
 		(*buf)[i] = '\0';
-	    *from = ++i;
-	    return fd;
+		*from = ++i;
+		return fd;
 	    }
 	}
 	*from = i;
@@ -242,8 +253,7 @@
 	       break;
 
 	  default:
-	       if (isalpha(c) || c == '*' || isdigit(c) || c == '_'
-		    || c == '-' || c == '.' || c == '/' || c == ':') {
+	       if (IS_TOKEN(c)) {
 		    token = 1;
 	       } else if (token) {
 		    --to;
@@ -276,8 +286,7 @@
 	  if (next == VAL) {
 	       if (c == '!')
 		    not = !not;
-	       else if (isalpha(c) || c == '*' || isdigit(c) || c == '_'
-                    || c == '-' || c == '.' || c == '/' || c == ':') {
+	       else if (IS_TOKEN(c)) {
 		    right = not ^ agrees(pamh, me, x+at, l, rule);
 		    if (oper == AND)
 			 left &= right;
@@ -506,8 +515,7 @@
                break;
 
           default:
-               if (isalpha(c) || isdigit(c) || c == '_' || c == '*'
-                    || c == '-') {
+               if (IS_TOKEN(c)) {
                     token = 1;
                } else if (token) {
                     --to;
@@ -578,6 +586,28 @@
      return len;
 }
 
+static int 
+grp_exists(pam_handle_t *pamh, const char *grpnam, gid_t *grps, int no_grps)
+{
+	struct group *grp;
+	gid_t grp_id;
+	int i;
+
+	if (!(grp = pam_modutil_getgrnam(pamh, grpnam))) {
+		D(("unknown group name: %s\n", grpnam));
+		return 0;
+	}
+
+	grp_id = grp->gr_gid;
+
+	for (i=0; i<no_grps; i++) {
+		if (grps[i] == grp_id) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
 
 static int check_account(pam_handle_t *pamh, const char *service,
 			 const char *tty, const char *user)
@@ -657,9 +687,15 @@
 		       "%s: no user entry #%d", PAM_GROUP_CONF, count);
 	    continue;
 	}
+
 	/* If buffer starts with @, we are using netgroups */
 	if (buffer[0] == '@')
 	  good &= innetgr (&buffer[1], NULL, user, NULL);
+
+	/* if buffer starts with %, we are using user groups */
+	else if (buffer[0] == '%')
+	  good &= grp_exists(pamh, &buffer[1], grps, no_grps);
+
 	else
 	  good &= logic_field(pamh,user, buffer, count, is_same);
 	D(("with user: %s", good ? "passes":"fails" ));
_______________________________________________
Pam-list mailing list
Pam-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/pam-list

[Index of Archives]     [Fedora Users]     [Kernel]     [Red Hat Install]     [Linux for the blind]     [Gimp]

  Powered by Linux