* NEWS, src/groupmod.c: Make sure the passwd, group, and gshadow

files are unlocked on exit. Unlock locked files in fail_exit().
  Prefer fail_exit() over exit().
* NEWS, src/groupmod.c: When the GID of a group is changed, update
  also the GID of the passwd entries of the users whose primary
  group is the group being modified.
This commit is contained in:
nekral-guest 2008-03-08 23:01:49 +00:00
parent b1a0769d3d
commit a8a614c515
3 changed files with 128 additions and 27 deletions

View File

@ -1,3 +1,12 @@
2008-03-08 Nicolas François <nicolas.francois@centraliens.net>
* NEWS, src/groupmod.c: Make sure the passwd, group, and gshadow
files are unlocked on exit. Unlock locked files in fail_exit().
Prefer fail_exit() over exit().
* NEWS, src/groupmod.c: When the GID of a group is changed, update
also the GID of the passwd entries of the users whose primary
group is the group being modified.
2008-03-08 Nicolas François <nicolas.francois@centraliens.net> 2008-03-08 Nicolas François <nicolas.francois@centraliens.net>
* lib/commonio.c (commonio_remove): Fail when the name to be * lib/commonio.c (commonio_remove): Fail when the name to be

3
NEWS
View File

@ -42,6 +42,9 @@ shadow-4.1.0 -> shadow-4.1.1 UNRELEASED
* Fix buffer overflow when adding an user to a group. Thanks to Peter Vrabec. * Fix buffer overflow when adding an user to a group. Thanks to Peter Vrabec.
- groupmod - groupmod
* New option -p/--password to specify an encrypted password. * New option -p/--password to specify an encrypted password.
* Make sure the group and gshadow files are unlocked on exit.
* When the GID of a group is changed, update also the GID of the passwd
entries of the users whose primary group is the group being modified.
- grpck - grpck
* Fix logging of changes to syslog when a group file is provided, * Fix logging of changes to syslog when a group file is provided,
without a gshadow file. without a gshadow file.

View File

@ -44,6 +44,7 @@
#include "chkname.h" #include "chkname.h"
#include "defines.h" #include "defines.h"
#include "groupio.h" #include "groupio.h"
#include "pwio.h"
#include "nscd.h" #include "nscd.h"
#include "prototypes.h" #include "prototypes.h"
#ifdef SHADOWGRP #ifdef SHADOWGRP
@ -64,7 +65,10 @@
*/ */
#ifdef SHADOWGRP #ifdef SHADOWGRP
static int is_shadow_grp; static int is_shadow_grp;
static int gshadow_locked = 0;
#endif #endif
static int group_locked = 0;
static int passwd_locked = 0;
static char *group_name; static char *group_name;
static char *group_newname; static char *group_newname;
static char *group_passwd; static char *group_passwd;
@ -81,6 +85,7 @@ static int
/* local function prototypes */ /* local function prototypes */
static void usage (void); static void usage (void);
static void fail_exit (int);
static void new_grent (struct group *); static void new_grent (struct group *);
#ifdef SHADOWGRP #ifdef SHADOWGRP
@ -93,6 +98,7 @@ static void process_flags (int, char **);
static void close_files (void); static void close_files (void);
static void open_files (void); static void open_files (void);
static gid_t get_gid (const char *gidstr); static gid_t get_gid (const char *gidstr);
static void update_primary_groups (gid_t ogid, gid_t ngid);
/* /*
* usage - display usage message and exit * usage - display usage message and exit
@ -112,6 +118,20 @@ static void usage (void)
exit (E_USAGE); exit (E_USAGE);
} }
static void fail_exit (int status)
{
if (group_locked) {
gr_unlock ();
}
if (gshadow_locked) {
sgr_unlock ();
}
if (passwd_locked) {
pw_unlock();
}
exit (status);
}
/* /*
* new_grent - updates the values in a group file entry * new_grent - updates the values in a group file entry
* *
@ -174,7 +194,7 @@ static void grp_update (void)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modifying group", audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modifying group",
group_name, -1, 0); group_name, -1, 0);
#endif #endif
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
grp = *ogrp; grp = *ogrp;
new_grent (&grp); new_grent (&grp);
@ -187,6 +207,10 @@ static void grp_update (void)
} }
#endif /* SHADOWGRP */ #endif /* SHADOWGRP */
if (gflg) {
update_primary_groups (ogrp->gr_gid, group_newid);
}
/* /*
* Write out the new group file entry. * Write out the new group file entry.
*/ */
@ -196,7 +220,7 @@ static void grp_update (void)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding group", audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding group",
group_name, -1, 0); group_name, -1, 0);
#endif #endif
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
if (nflg && !gr_remove (group_name)) { if (nflg && !gr_remove (group_name)) {
fprintf (stderr, _("%s: error removing group entry\n"), Prog); fprintf (stderr, _("%s: error removing group entry\n"), Prog);
@ -204,7 +228,7 @@ static void grp_update (void)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "deleting group", audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "deleting group",
group_name, -1, 0); group_name, -1, 0);
#endif #endif
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
#ifdef SHADOWGRP #ifdef SHADOWGRP
@ -225,7 +249,7 @@ static void grp_update (void)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding group", audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding group",
group_name, -1, 0); group_name, -1, 0);
#endif #endif
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
if (is_shadow_grp && nflg && !sgr_remove (group_name)) { if (is_shadow_grp && nflg && !sgr_remove (group_name)) {
fprintf (stderr, _("%s: error removing group entry\n"), Prog); fprintf (stderr, _("%s: error removing group entry\n"), Prog);
@ -233,7 +257,7 @@ static void grp_update (void)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "deleting group", audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "deleting group",
group_name, -1, 0); group_name, -1, 0);
#endif #endif
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
out: out:
#endif /* SHADOWGRP */ #endif /* SHADOWGRP */
@ -246,9 +270,10 @@ static void grp_update (void)
SYSLOG ((LOG_INFO, "change group `%s' to `%s'", SYSLOG ((LOG_INFO, "change group `%s' to `%s'",
group_name, group_newname)); group_name, group_newname));
if (gflg) if (gflg) {
SYSLOG ((LOG_INFO, "change GID for `%s' to %u", SYSLOG ((LOG_INFO, "change GID for `%s' to %u",
nflg ? group_newname : group_name, group_newid)); nflg ? group_newname : group_name, group_newid));
}
} }
/* /*
@ -279,7 +304,7 @@ static void check_new_gid (void)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modify gid", NULL, audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modify gid", NULL,
group_newid, 0); group_newid, 0);
#endif #endif
exit (E_GID_IN_USE); fail_exit (E_GID_IN_USE);
} }
/* /*
@ -312,7 +337,7 @@ static void check_new_name (void)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"modifying group", group_name, -1, 0); "modifying group", group_name, -1, 0);
#endif #endif
exit (E_NAME_IN_USE); fail_exit (E_NAME_IN_USE);
} }
return; return;
} }
@ -327,7 +352,7 @@ static void check_new_name (void)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modifying group", group_name, audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modifying group", group_name,
-1, 0); -1, 0);
#endif #endif
exit (E_BAD_ARG); fail_exit (E_BAD_ARG);
} }
/* /*
@ -342,7 +367,7 @@ static gid_t get_gid (const char *gidstr)
if (*errptr || errno == ERANGE || val < 0) { if (*errptr || errno == ERANGE || val < 0) {
fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog,
gidstr); gidstr);
exit (E_BAD_ARG); fail_exit (E_BAD_ARG);
} }
return val; return val;
} }
@ -417,18 +442,30 @@ static void close_files (void)
{ {
if (!gr_close ()) { if (!gr_close ()) {
fprintf (stderr, _("%s: cannot rewrite group file\n"), Prog); fprintf (stderr, _("%s: cannot rewrite group file\n"), Prog);
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
gr_unlock (); gr_unlock ();
group_locked--;
#ifdef SHADOWGRP #ifdef SHADOWGRP
if (is_shadow_grp && !sgr_close ()) { if (is_shadow_grp && !sgr_close ()) {
fprintf (stderr, fprintf (stderr,
_("%s: cannot rewrite shadow group file\n"), Prog); _("%s: cannot rewrite shadow group file\n"), Prog);
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
if (is_shadow_grp) if (is_shadow_grp) {
sgr_unlock (); sgr_unlock ();
gshadow_locked--;
}
#endif /* SHADOWGRP */ #endif /* SHADOWGRP */
if (gflg) {
if (!pw_close ()) {
fprintf (stderr,
_("%s: cannot rewrite passwd file\n"), Prog);
fail_exit (E_GRP_UPDATE);
}
pw_unlock();
passwd_locked--;
}
} }
/* /*
@ -440,24 +477,74 @@ static void open_files (void)
{ {
if (!gr_lock ()) { if (!gr_lock ()) {
fprintf (stderr, _("%s: unable to lock group file\n"), Prog); fprintf (stderr, _("%s: unable to lock group file\n"), Prog);
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
group_locked++;
if (!gr_open (O_RDWR)) { if (!gr_open (O_RDWR)) {
fprintf (stderr, _("%s: unable to open group file\n"), Prog); fprintf (stderr, _("%s: unable to open group file\n"), Prog);
exit (E_GRP_UPDATE); fail_exit (E_GRP_UPDATE);
} }
#ifdef SHADOWGRP #ifdef SHADOWGRP
if (is_shadow_grp && !sgr_lock ()) { if (is_shadow_grp) {
fprintf (stderr, if (!sgr_lock ()) {
_("%s: unable to lock shadow group file\n"), Prog); fprintf (stderr,
exit (E_GRP_UPDATE); _("%s: unable to lock shadow group file\n"),
} Prog);
if (is_shadow_grp && !sgr_open (O_RDWR)) { fail_exit (E_GRP_UPDATE);
fprintf (stderr, }
_("%s: unable to open shadow group file\n"), Prog); gshadow_locked++;
exit (E_GRP_UPDATE); if (!sgr_open (O_RDWR)) {
fprintf (stderr,
_("%s: unable to open shadow group file\n"),
Prog);
fail_exit (E_GRP_UPDATE);
}
} }
#endif /* SHADOWGRP */ #endif /* SHADOWGRP */
if (gflg) {
if (!pw_lock ()) {
fprintf (stderr,
_("%s: unable to lock password file\n"),
Prog);
fail_exit (E_GRP_UPDATE);
}
passwd_locked++;
if (!pw_open (O_RDWR)) {
fprintf (stderr,
_("%s: unable to open password file\n"),
Prog);
fail_exit (E_GRP_UPDATE);
}
}
}
void update_primary_groups (gid_t ogid, gid_t ngid)
{
struct passwd *pwd;
setpwent ();
while ((pwd = getpwent ()) != NULL) {
if (pwd->pw_gid == ogid) {
const struct passwd *lpwd;
struct passwd npwd;
lpwd = pw_locate (pwd->pw_name);
if (NULL == lpwd) {
fprintf (stderr,
_("%s: cannot change the primary group of user '%s' from %u to %u, since it is not in the passwd file.\n"),
Prog, pwd->pw_name, ogid, ngid);
fail_exit (E_GRP_UPDATE);
} else {
npwd = *lpwd;
npwd.pw_gid = ngid;
if (!pw_update (&npwd)) {
fprintf (stderr,
_("%s: cannot change the primary group of user '%s' from %u to %u.\n"),
Prog, pwd->pw_name, ogid, ngid);
fail_exit (E_GRP_UPDATE);
}
}
}
}
} }
/* /*
@ -528,7 +615,7 @@ int main (int argc, char **argv)
if (retval != PAM_SUCCESS) { if (retval != PAM_SUCCESS) {
fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
exit (1); fail_exit (1);
} }
#endif /* USE_PAM */ #endif /* USE_PAM */
@ -548,7 +635,7 @@ int main (int argc, char **argv)
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"modifying group", group_name, -1, 0); "modifying group", group_name, -1, 0);
#endif #endif
exit (E_NOTFOUND); fail_exit (E_NOTFOUND);
} else } else
group_id = grp->gr_gid; group_id = grp->gr_gid;
} }
@ -581,7 +668,7 @@ int main (int argc, char **argv)
fprintf (stderr, _("%s: %s is the NIS master\n"), fprintf (stderr, _("%s: %s is the NIS master\n"),
Prog, nis_master); Prog, nis_master);
} }
exit (E_NOTFOUND); fail_exit (E_NOTFOUND);
} }
#endif #endif
@ -598,6 +685,7 @@ int main (int argc, char **argv)
open_files (); open_files ();
grp_update (); grp_update ();
close_files (); close_files ();
nscd_flush_cache ("group"); nscd_flush_cache ("group");
@ -609,3 +697,4 @@ int main (int argc, char **argv)
exit (E_SUCCESS); exit (E_SUCCESS);
/* NOT REACHED */ /* NOT REACHED */
} }