diff --git a/ChangeLog b/ChangeLog index 1d5fe2ce..a1cdcd26 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-09-07 Nicolas François + + From RedHat's patch shadow-4.1.2-sysAccountDownhill.patch + Thanks to Peter Vrabec. + * NEWS, libmisc/find_new_gid.c, libmisc/find_new_uid.c: Build an + index of used IDs to avoid a database request for each id in the + allowed range (when the highest allowed ID is already used). + This speedups the addition of users or groups when the highest + allowed ID is already used. The additional memory usage of the + tools should be acceptable when UID_MAX/SYS_UID_MAX are set to a + reasonable number. + 2008-09-07 Nicolas François * configure.in: Fix the dependency of ACCT_TOOLS_SETUID on diff --git a/NEWS b/NEWS index 205dc2e9..31ef88c7 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,10 @@ shadow-4.1.2.1 -> shadow-4.1.3 UNRELEASED groupadd, groupdel, groupmod, newusers, useradd, userdel, and usermod. This authentication is not necessary when these tools are not installed setuid root. +- addition of users or groups + * Speed improvement in case UID_MAX/SYS_UID_MAX/GID_MAX/SYS_GID_MAX is + used for an user/group. This should be noticeable in case of LDAP + configured systems. This should impact useradd, groupadd, and newusers - gpasswd * Added support for long options --add (-a), --delete (-d), @@ -19,6 +23,7 @@ shadow-4.1.2.1 -> shadow-4.1.3 UNRELEASED --members (-M). - groupadd * audit logging improvements. + * Speedup (see "addition of users or groups" above). - groupdel * audit logging improvements. - groupmems @@ -35,12 +40,14 @@ shadow-4.1.2.1 -> shadow-4.1.3 UNRELEASED --list (-l), --group (-g). - newusers * Implement the -r, --system option. + * Speedup (see "addition of users or groups" above). - passwd * For compatibility with other passwd version, the --lock an --unlock options do not lock or unlock the user account anymore. They only lock or unlock the user's password. - useradd * audit logging improvements. + * Speedup (see "addition of users or groups" above). - userdel * audit logging improvements. - usermod diff --git a/libmisc/find_new_gid.c b/libmisc/find_new_gid.c index 7225ce30..85e00d3e 100644 --- a/libmisc/find_new_gid.c +++ b/libmisc/find_new_gid.c @@ -51,6 +51,7 @@ int find_new_gid (bool sys_group, gid_t *gid, gid_t const *preferred_gid) { const struct group *grp; gid_t gid_min, gid_max, group_id; + char *used_gids; assert (gid != NULL); @@ -62,6 +63,8 @@ int find_new_gid (bool sys_group, gid_t *gid, gid_t const *preferred_gid) gid_max = getdef_ulong ("GID_MIN", 1000L) - 1; gid_max = getdef_ulong ("SYS_GID_MAX", (unsigned long) gid_max); } + used_gids = alloca (sizeof (char) * gid_max +1); + memset (used_gids, 0, sizeof (char) * gid_max + 1); if ( (NULL != preferred_gid) && (*preferred_gid >= gid_min) @@ -81,8 +84,8 @@ int find_new_gid (bool sys_group, gid_t *gid, gid_t const *preferred_gid) * Search the entire group file, * looking for the largest unused value. * - * We check the list of users according to NSS (setpwent/getpwent), - * but we also check the local database (pw_rewind/pw_next) in case + * We check the list of groups according to NSS (setgrent/getgrent), + * but we also check the local database (gr_rewind/gr_next) in case * some groups were created but the changes were not committed yet. */ setgrent (); @@ -92,20 +95,21 @@ int find_new_gid (bool sys_group, gid_t *gid, gid_t const *preferred_gid) if ((grp->gr_gid >= group_id) && (grp->gr_gid <= gid_max)) { group_id = grp->gr_gid + 1; } + /* create index of used GIDs */ + if (grp->gr_gid <= gid_max) { + used_gids[grp->gr_gid] = 1; + } } endgrent (); /* * If a group with GID equal to GID_MAX exists, the above algorithm * will give us GID_MAX+1 even if not unique. Search for the first - * free GID starting with GID_MIN (it's O(n*n) but can be avoided - * by not having users with GID equal to GID_MAX). --marekm + * free GID starting with GID_MIN. */ if (group_id == gid_max + 1) { for (group_id = gid_min; group_id < gid_max; group_id++) { - /* local, no need for xgetgrgid */ - if ( (getgrgid (group_id) == NULL) - && (gr_locate_gid (group_id) == NULL)) { + if (0 == used_gids[grp->gr_gid]) { break; } } diff --git a/libmisc/find_new_uid.c b/libmisc/find_new_uid.c index cdf12521..f4efb9f8 100644 --- a/libmisc/find_new_uid.c +++ b/libmisc/find_new_uid.c @@ -51,6 +51,7 @@ int find_new_uid (bool sys_user, uid_t *uid, uid_t const *preferred_uid) { const struct passwd *pwd; uid_t uid_min, uid_max, user_id; + char *used_uids; assert (uid != NULL); @@ -62,6 +63,8 @@ int find_new_uid (bool sys_user, uid_t *uid, uid_t const *preferred_uid) uid_max = getdef_ulong ("UID_MIN", 1000L) - 1; uid_max = getdef_ulong ("SYS_UID_MAX", (unsigned long) uid_max); } + used_uids = alloca (sizeof (char) * uid_max +1); + memset (used_uids, 0, sizeof (char) * uid_max + 1); if ( (NULL != preferred_uid) && (*preferred_uid >= uid_min) @@ -93,20 +96,21 @@ int find_new_uid (bool sys_user, uid_t *uid, uid_t const *preferred_uid) if ((pwd->pw_uid >= user_id) && (pwd->pw_uid <= uid_max)) { user_id = pwd->pw_uid + 1; } + /* create index of used UIDs */ + if (pwd->pw_uid <= uid_max) { + used_uids[pwd->pw_uid] = 1; + } } endpwent (); /* * If a user with UID equal to UID_MAX exists, the above algorithm * will give us UID_MAX+1 even if not unique. Search for the first - * free UID starting with UID_MIN (it's O(n*n) but can be avoided - * by not having users with UID equal to UID_MAX). --marekm + * free UID starting with UID_MIN. */ if (user_id == uid_max + 1) { for (user_id = uid_min; user_id < uid_max; user_id++) { - /* local, no need for xgetpwuid */ - if ( (getpwuid (user_id) == NULL) - && (pw_locate_uid (user_id) == NULL)) { + if (0 == used_uids[pwd->pw_uid]) { break; } }