[Pkg-shadow-commits] r1442 - in upstream/trunk: . lib man

nekral-guest at alioth.debian.org nekral-guest at alioth.debian.org
Fri Nov 23 00:07:59 UTC 2007


Author: nekral-guest
Date: 2007-11-23 00:07:59 +0000 (Fri, 23 Nov 2007)
New Revision: 1442

Modified:
   upstream/trunk/ChangeLog
   upstream/trunk/NEWS
   upstream/trunk/lib/commonio.c
   upstream/trunk/lib/commonio.h
   upstream/trunk/lib/getdef.c
   upstream/trunk/lib/groupio.c
   upstream/trunk/lib/pwio.c
   upstream/trunk/lib/sgroupio.c
   upstream/trunk/lib/shadowio.c
   upstream/trunk/man/login.defs.5.xml
Log:
* NEWS, lib/getdef.c, man/login.defs.5.xml: New login.defs
  variable: MAX_MEMBERS_PER_GROUP. Used for the split groups support.
* lib/commonio.c, lib/commonio.h: Add an open_hook and close_hook
  operation. They are called after the database is actually opened
  and parse, or before it is closed.
* lib/groupio.c: Add an open_hook to merge split groups, and an
  close group to split groups if MAX_MEMBERS_PER_GROUP is set.
  This fixes gpasswd and chgpasswd when split groups are used.
* lib/sgroupio.c, lib/shadowio.c, lib/pwio.c: No open or close
  hooks for these databases. (unsure about what should be the gshadow
  behavior for split groups)


Modified: upstream/trunk/ChangeLog
===================================================================
--- upstream/trunk/ChangeLog	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/ChangeLog	2007-11-23 00:07:59 UTC (rev 1442)
@@ -1,5 +1,19 @@
 2007-11-22  Nicolas François  <nicolas.francois at centraliens.net>
 
+	* NEWS, lib/getdef.c, man/login.defs.5.xml: New login.defs
+	variable: MAX_MEMBERS_PER_GROUP. Used for the split groups support.
+	* lib/commonio.c, lib/commonio.h: Add an open_hook and close_hook
+	operation. They are called after the database is actually opened
+	and parse, or before it is closed.
+	* lib/groupio.c: Add an open_hook to merge split groups, and an
+	close group to split groups if MAX_MEMBERS_PER_GROUP is set.
+	This fixes gpasswd and chgpasswd when split groups are used.
+	* lib/sgroupio.c, lib/shadowio.c, lib/pwio.c: No open or close
+	hooks for these databases. (unsure about what should be the gshadow
+	behavior for split groups)
+
+2007-11-22  Nicolas François  <nicolas.francois at centraliens.net>
+
 	* NEWS, src/gpasswd.c: Read the group and shadow groups using
 	gr_locate and sgr_locate. gpasswd write in the file database. Thus
 	it should read information from the file database, not using

Modified: upstream/trunk/NEWS
===================================================================
--- upstream/trunk/NEWS	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/NEWS	2007-11-23 00:07:59 UTC (rev 1442)
@@ -46,6 +46,10 @@
 - gpasswd: Only read information from the local file group database. It
   writes the changes in /etc/group and/or /etc/gshadow, but used to read
   information from getgrnam (hence possibly from another group database).
+- New login.defs variable: MAX_MEMBERS_PER_GROUP. It should provide a
+  better support for split groups. Be careful when using this variable:
+  not all tools support well split groups (in or out of the shadow
+  tool suite). It fixes gpasswd and chgpasswd when split groups are used.
 
 *** documentation:
 - Generate the translated manpages from PO at build time.

Modified: upstream/trunk/lib/commonio.c
===================================================================
--- upstream/trunk/lib/commonio.c	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/lib/commonio.c	2007-11-23 00:07:59 UTC (rev 1442)
@@ -520,6 +520,9 @@
 	if (ferror (db->fp))
 		goto cleanup_errno;
 
+	if (db->ops->open_hook && !db->ops->open_hook ())
+		goto cleanup_errno;
+
 	db->isopen = 1;
 	return 1;
 
@@ -669,6 +672,9 @@
 		goto success;
 	}
 
+	if (db->ops->close_hook && !db->ops->close_hook ())
+		goto fail;
+
 	memzero (&sb, sizeof sb);
 	if (db->fp) {
 		if (fstat (fileno (db->fp), &sb)) {

Modified: upstream/trunk/lib/commonio.h
===================================================================
--- upstream/trunk/lib/commonio.h	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/lib/commonio.h	2007-11-23 00:07:59 UTC (rev 1442)
@@ -52,6 +52,15 @@
 	 */
 	char *(*fgets) (char *, int, FILE *);
 	int (*fputs) (const char *, FILE *);
+
+	/*
+	 * open_hook and close_hook.
+	 * If non NULL, these functions will be called after the database
+	 * is open or before it is closed.
+	 * They return 0 on failure and 1 on success.
+	 */
+	int (*open_hook) (void);
+	int (*close_hook) (void);
 };
 
 /*

Modified: upstream/trunk/lib/getdef.c
===================================================================
--- upstream/trunk/lib/getdef.c	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/lib/getdef.c	2007-11-23 00:07:59 UTC (rev 1442)
@@ -68,6 +68,7 @@
 	{"LOG_UNKFAIL_ENAB", NULL},
 	{"MAIL_DIR", NULL},
 	{"MAIL_FILE", NULL},
+	{"MAX_MEMBERS_PER_GROUP", NULL},
 	{"MD5_CRYPT_ENAB", NULL},
 	{"PASS_MAX_DAYS", NULL},
 	{"PASS_MIN_DAYS", NULL},

Modified: upstream/trunk/lib/groupio.c
===================================================================
--- upstream/trunk/lib/groupio.c	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/lib/groupio.c	2007-11-23 00:07:59 UTC (rev 1442)
@@ -10,6 +10,11 @@
 extern int putgrent (const struct group *, FILE *);
 extern struct group *sgetgrent (const char *);
 
+static struct commonio_entry *merge_group_entries (struct commonio_entry *,
+                                                   struct commonio_entry *);
+static int split_groups (unsigned int);
+static int group_open_hook (void);
+
 static void *group_dup (const void *ent)
 {
 	const struct group *gr = ent;
@@ -49,6 +54,16 @@
 	return (putgrent (gr, file) == -1) ? -1 : 0;
 }
 
+static int group_close_hook (void)
+{
+	unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
+
+	if (0 == max_members)
+		return 1;
+
+	return split_groups (max_members);
+}
+
 static struct commonio_ops group_ops = {
 	group_dup,
 	group_free,
@@ -56,7 +71,9 @@
 	group_parse,
 	group_put,
 	fgetsx,
-	fputsx
+	fputsx,
+	group_open_hook,
+	group_close_hook
 };
 
 static struct commonio_db group_db = {
@@ -170,3 +187,171 @@
 {
 	return commonio_sort (&group_db, gr_cmp);
 }
+
+static int group_open_hook (void)
+{
+	unsigned int max_members = getdef_unum("MAX_MEMBERS_PER_GROUP", 0);
+	struct commonio_entry *gr1, *gr2;
+
+	if (0 == max_members)
+		return 1;
+
+	for (gr1 = group_db.head; gr1; gr1 = gr1->next) {
+		for (gr2 = gr1->next; gr2; gr2 = gr2->next) {
+			struct group *g1 = (struct group *)gr1->eptr;
+			struct group *g2 = (struct group *)gr2->eptr;
+			if (NULL != g1 &&
+			    NULL != g2 &&
+			    0 == strcmp (g1->gr_name, g2->gr_name) &&
+			    0 == strcmp (g1->gr_passwd, g2->gr_passwd) &&
+			    g1->gr_gid == g2->gr_gid) {
+				/* Both group entries refer to the same
+				 * group. It is a split group. Merge the
+				 * members. */
+				gr1 = merge_group_entries (gr1, gr2);
+				if (NULL == gr1)
+					return 0;
+				/* Unlink gr2 */
+				if (NULL != gr2->next)
+					gr2->next->prev = gr2->prev;
+				gr2->prev->next = gr2->next;
+			}
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * Merge the list of members of the two group entries.
+ *
+ * The commonio_entry arguments shall be group entries.
+ *
+ * You should not merge the members of two groups if they don't have the
+ * same name, password and gid.
+ *
+ * It merge the members of the second entry in the first one, and return
+ * the modified first entry on success, or NUll on failure (with errno
+ * set).
+ */
+static struct commonio_entry *merge_group_entries (struct commonio_entry *gr1,
+                                                   struct commonio_entry *gr2)
+{
+	struct group *gptr1;
+	struct group *gptr2;
+	char *member;
+	char **new_members;
+	int members = 0;
+	char *new_line;
+	int new_line_len, i;
+	if (NULL == gr2 || NULL == gr1) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	gptr1 = (struct group *)gr1->eptr;
+	gptr2 = (struct group *)gr2->eptr;
+	if (NULL == gptr2 || NULL == gptr1) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/* Concatenate the 2 lines */
+	new_line_len = strlen (gr1->line) + strlen (gr2->line) +1;
+	new_line = (char *)malloc ((new_line_len + 1) * sizeof(char*));
+	if (NULL == new_line) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	snprintf(new_line, new_line_len, "%s\n%s", gr1->line, gr2->line);
+	new_line[new_line_len] = '\0';
+
+	/* Concatenate the 2 list of members */
+	for (i=0; NULL != gptr1->gr_mem[i]; i++);
+	members += i;
+	for (i=0; NULL != gptr2->gr_mem[i]; i++) {
+		char **pmember = gptr1->gr_mem;
+		while (NULL != *pmember) {
+			if (0 == strcmp(*pmember, gptr2->gr_mem[i]))
+				break;
+			pmember++;
+		}
+		if (NULL == *pmember)
+			members++;
+	}
+	new_members = (char **)malloc ( (members+1) * sizeof(char*) );
+	if (NULL == new_members) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	for (i=0; NULL != gptr1->gr_mem[i]; i++)
+		new_members[i] = gptr1->gr_mem[i];
+	members = i;
+	for (i=0; NULL != gptr2->gr_mem[i]; i++) {
+		char **pmember = new_members;
+		while (NULL != *pmember) {
+			if (0 == strcmp(*pmember, gptr2->gr_mem[i]))
+				break;
+			pmember++;
+		}
+		if (NULL == *pmember) {
+			new_members[members++] = gptr2->gr_mem[i];
+			new_members[members] = NULL;
+		}
+	}
+
+	gr1->line = new_line;
+	gptr1->gr_mem = new_members;
+
+	return gr1;
+}
+
+/*
+ * Scan the group database and split the groups which have more members
+ * than specified, if this is the result from a current change.
+ *
+ * Return 0 on failure (errno set) and 1 on success.
+ */
+static int split_groups (unsigned int max_members)
+{
+	struct commonio_entry *gr;
+
+	for (gr = group_db.head; gr; gr = gr->next) {
+		struct group *gptr = (struct group *)gr->eptr;
+		struct commonio_entry *new;
+		struct group *new_gptr;
+		unsigned int members = 0;
+
+		/* Check if this group must be split */
+		if (!gr->changed)
+			continue;
+		if (NULL == gptr)
+			continue;
+		for (members = 0; NULL != gptr->gr_mem[members]; members++);
+		if (members <= max_members)
+			continue;
+
+		new = (struct commonio_entry *) malloc (sizeof *new);
+		new->eptr = group_dup(gr->eptr);
+		if (NULL == new->eptr) {
+			errno = ENOMEM;
+			return 0;
+		}
+		new_gptr = (struct group *)new->eptr;
+		new->line = NULL;
+		new->changed = 1;
+
+		/* Enforce the maximum number of members on gptr */
+		gptr->gr_mem[max_members] = NULL;
+		/* The number of members in new_gptr will be check later */
+		new_gptr->gr_mem = &new_gptr->gr_mem[max_members];
+
+		/* insert the new entry in the list */
+		new->prev = gr;
+		new->next = gr->next;
+		gr->next = new;
+	}
+
+	return 1;
+}
+

Modified: upstream/trunk/lib/pwio.c
===================================================================
--- upstream/trunk/lib/pwio.c	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/lib/pwio.c	2007-11-23 00:07:59 UTC (rev 1442)
@@ -57,7 +57,9 @@
 	passwd_parse,
 	passwd_put,
 	fgets,
-	fputs
+	fputs,
+	NULL,			/* open_hook */
+	NULL			/* close_hook */
 };
 
 static struct commonio_db passwd_db = {

Modified: upstream/trunk/lib/sgroupio.c
===================================================================
--- upstream/trunk/lib/sgroupio.c	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/lib/sgroupio.c	2007-11-23 00:07:59 UTC (rev 1442)
@@ -100,7 +100,9 @@
 	gshadow_parse,
 	gshadow_put,
 	fgetsx,
-	fputsx
+	fputsx,
+	NULL,			/* open_hook */
+	NULL			/* close_hook */
 };
 
 static struct commonio_db gshadow_db = {

Modified: upstream/trunk/lib/shadowio.c
===================================================================
--- upstream/trunk/lib/shadowio.c	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/lib/shadowio.c	2007-11-23 00:07:59 UTC (rev 1442)
@@ -54,7 +54,9 @@
 	shadow_parse,
 	shadow_put,
 	fgets,
-	fputs
+	fputs,
+	NULL,			/* open_hook */
+	NULL			/* close_hook */
 };
 
 static struct commonio_db shadow_db = {

Modified: upstream/trunk/man/login.defs.5.xml
===================================================================
--- upstream/trunk/man/login.defs.5.xml	2007-11-22 21:55:12 UTC (rev 1441)
+++ upstream/trunk/man/login.defs.5.xml	2007-11-23 00:07:59 UTC (rev 1442)
@@ -122,6 +122,36 @@
 	</listitem>
       </varlistentry>
       <varlistentry>
+	<term>MAX_MEMBERS_PER_GROUP (number)</term>
+	<listitem>
+	  <para>
+	    Maximum members per group entry. When the maximum is reached,
+	    a new group entry (line) is started is
+	    <filename>/etc/group</filename> (with the same name, same
+	    password, and same GID).
+	  </para>
+	  <para>
+	    The default value is 0, meaning that there are no limits in
+	    the number of members in a group.
+	  </para>
+	  <!-- Note: on HP, split groups have the same ID, but different
+	             names. -->
+	  <para>
+	    This feature (split group) permits to limit the length of
+	    lines in the group file. This is useful to make sure that
+	    lines for NIS groups are not larger than 1024 characters.
+	  </para>
+	  <para>
+	    If you need to enforce such limit, you can use 25.
+	  </para>
+	  <para>
+	    Note: split groups may not be supported by all tools (even in
+	    the Shadow toolsuite. Yous hould not use this variable unless
+	    you really need it.
+	  </para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
 	<term>MD5_CRYPT_ENAB (boolean)</term>
 	<listitem>
 	  <para>




More information about the Pkg-shadow-commits mailing list