diff --git a/ChangeLog b/ChangeLog index af004395..4e9943ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-11-16 Nicolas François + + * lib/commonio.c (next_entry_by_name): New function. + * NEWS, lib/commonio.c (commonio_update): When an entry is updated, make + sure that there are no other entry with the same name. This fixes + an infinite loop in userdel and usermod when an (erroneous) group + file contains two entries with the same name. + (https://bugzilla.redhat.com/show_bug.cgi?id=240915) + 2007-11-16 Nicolas François * libmisc/salt.c: Make sure the salt string is terminated at the diff --git a/NEWS b/NEWS index 5d0fa96b..b5778f26 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,10 @@ shadow-4.0.18.1 -> shadow-4.0.18.2 UNRELEASED (i.e. lookup in the local database for an user with an @). Thanks to Mike Frysinger for the patch. - Add support for uClibc with no l64a(). +- userdel/usermod: Fix infinite loop caused by erroneous group file + containing two entries with the same name. (The fix strategy differs + from + (https://bugzilla.redhat.com/show_bug.cgi?id=240915) shadow-4.0.18.1 -> shadow-4.0.18.2 28-10-2007 diff --git a/lib/commonio.c b/lib/commonio.c index b0989f94..036d232d 100644 --- a/lib/commonio.c +++ b/lib/commonio.c @@ -35,6 +35,9 @@ static int name_is_nis (const char *); static int write_all (const struct commonio_db *); static struct commonio_entry *find_entry_by_name (struct commonio_db *, const char *); +static struct commonio_entry *next_entry_by_name (struct commonio_db *, + struct commonio_entry *pos, + const char *); static int lock_count = 0; static int nscd_need_reload = 0; @@ -761,14 +764,17 @@ int commonio_close (struct commonio_db *db) return errors == 0; } - -static struct commonio_entry *find_entry_by_name (struct commonio_db *db, - const char *name) +static struct commonio_entry *next_entry_by_name (struct commonio_db *db, + struct commonio_entry *pos, + const char *name) { struct commonio_entry *p; void *ep; - for (p = db->head; p; p = p->next) { + if (NULL == pos) + return NULL; + + for (p = pos; p; p = p->next) { ep = p->eptr; if (ep && strcmp (db->ops->getname (ep), name) == 0) break; @@ -776,6 +782,12 @@ static struct commonio_entry *find_entry_by_name (struct commonio_db *db, return p; } +static struct commonio_entry *find_entry_by_name (struct commonio_db *db, + const char *name) +{ + return next_entry_by_name(db, db->head, name); +} + int commonio_update (struct commonio_db *db, const void *eptr) { @@ -792,6 +804,11 @@ int commonio_update (struct commonio_db *db, const void *eptr) } p = find_entry_by_name (db, db->ops->getname (eptr)); if (p) { + if (next_entry_by_name (db, p->next, db->ops->getname (eptr))) + { + fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename); + return 0; + } db->ops->free (p->eptr); p->eptr = nentry; p->changed = 1;