/* * grp_update - update group file entries * * grp_update() writes the new records to the group files. */ static void grp_update (void) { /* * To add the group, we need to update /etc/group. * Make sure failures will be reported. */ add_cleanup (cleanup_report_del_group_group, group_name); #ifdef SHADOWGRP if (is_shadow_grp) { /* We also need to update /etc/gshadow */ add_cleanup (cleanup_report_del_group_gshadow, group_name); } #endif /* * Delete the group entry. */ if (gr_remove (group_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, group_name, gr_dbname ()); exit (E_GRP_UPDATE); } #ifdef SHADOWGRP /* * Delete the shadow group entries as well. */ if (is_shadow_grp && (sgr_locate (group_name) != NULL)) { if (sgr_remove (group_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, group_name, sgr_dbname ()); exit (E_GRP_UPDATE); } } #endif /* SHADOWGRP */ }
int main (int argc, char **argv) { const struct group *gr; struct group grent; const struct sgrp *sg; Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); OPENLOG ("grpunconv"); process_flags (argc, argv); if (sgr_file_present () == 0) { exit (0); /* no /etc/gshadow, nothing to do */ } if (gr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, gr_dbname ()); fail_exit (5); } gr_locked = true; if (gr_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); fail_exit (1); } if (sgr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sgr_dbname ()); fail_exit (5); } sgr_locked = true; if (sgr_open (O_RDONLY) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ()); fail_exit (1); } /* * Update group passwords if non-shadow password is "x". */ (void) gr_rewind (); while ((gr = gr_next ()) != NULL) { sg = sgr_locate (gr->gr_name); if ( (NULL != sg) && (strcmp (gr->gr_passwd, SHADOW_PASSWD_STRING) == 0)) { /* add password to /etc/group */ grent = *gr; grent.gr_passwd = sg->sg_passwd; if (gr_update (&grent) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, gr_dbname (), grent.gr_name); fail_exit (3); } } } (void) sgr_close (); /* was only open O_RDONLY */ if (gr_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); fail_exit (3); } if (unlink (SGROUP_FILE) != 0) { fprintf (stderr, _("%s: cannot delete %s\n"), Prog, SGROUP_FILE); SYSLOG ((LOG_ERR, "cannot delete %s", SGROUP_FILE)); fail_exit (3); } if (gr_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); /* continue */ } if (sgr_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); /* continue */ } nscd_flush_cache ("group"); return 0; }
int main (int argc, char **argv) { char buf[BUFSIZ]; char *name; char *newpwd; char *cp; #ifdef SHADOWGRP const struct sgrp *sg; struct sgrp newsg; #endif const struct group *gr; struct group newgr; int errors = 0; int line = 0; Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); process_flags (argc, argv); OPENLOG ("chgpasswd"); check_perms (); #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif open_files (); /* * Read each line, separating the group name from the password. The * group entry for each group will be looked up in the appropriate * file (gshadow or group) and the password changed. */ while (fgets (buf, (int) sizeof buf, stdin) != (char *) 0) { line++; cp = strrchr (buf, '\n'); if (NULL != cp) { *cp = '\0'; } else { fprintf (stderr, _("%s: line %d: line too long\n"), Prog, line); errors++; continue; } /* * The group's name is the first field. It is separated from * the password with a ":" character which is replaced with a * NUL to give the new password. The new password will then * be encrypted in the normal fashion with a new salt * generated, unless the '-e' is given, in which case it is * assumed to already be encrypted. */ name = buf; cp = strchr (name, ':'); if (NULL != cp) { *cp = '\0'; cp++; } else { fprintf (stderr, _("%s: line %d: missing new password\n"), Prog, line); errors++; continue; } newpwd = cp; if ( (!eflg) && ( (NULL == crypt_method) || (0 != strcmp (crypt_method, "NONE")))) { void *arg = NULL; const char *salt; if (md5flg) { crypt_method = "MD5"; } #ifdef USE_SHA_CRYPT if (sflg) { arg = &sha_rounds; } #endif salt = crypt_make_salt (crypt_method, arg); cp = pw_encrypt (newpwd, salt); if (NULL == cp) { fprintf (stderr, _("%s: failed to crypt password with salt '%s': %s\n"), Prog, salt, strerror (errno)); fail_exit (1); } } /* * Get the group file entry for this group. The group must * already exist. */ gr = gr_locate (name); if (NULL == gr) { fprintf (stderr, _("%s: line %d: group '%s' does not exist\n"), Prog, line, name); errors++; continue; } #ifdef SHADOWGRP if (is_shadow_grp) { /* The gshadow entry should be updated if the * group entry has a password set to 'x'. * But on the other hand, if there is already both * a group and a gshadow password, it's preferable * to update both. */ sg = sgr_locate (name); if ( (NULL == sg) && (strcmp (gr->gr_passwd, SHADOW_PASSWD_STRING) == 0)) { static char *empty = NULL; /* If the password is set to 'x' in * group, but there are no entries in * gshadow, create one. */ newsg.sg_name = name; /* newsg.sg_passwd = NULL; will be set later */ newsg.sg_adm = ∅ newsg.sg_mem = dup_list (gr->gr_mem); sg = &newsg; } } else { sg = NULL; } #endif /* * The freshly encrypted new password is merged into the * group's entry. */ #ifdef SHADOWGRP if (NULL != sg) { newsg = *sg; newsg.sg_passwd = cp; } if ( (NULL == sg) || (strcmp (gr->gr_passwd, SHADOW_PASSWD_STRING) != 0)) #endif { newgr = *gr; newgr.gr_passwd = cp; } /* * The updated group file entry is then put back and will * be written to the group file later, after all the * other entries have been updated as well. */ #ifdef SHADOWGRP if (NULL != sg) { if (sgr_update (&newsg) == 0) { fprintf (stderr, _("%s: line %d: failed to prepare the new %s entry '%s'\n"), Prog, line, sgr_dbname (), newsg.sg_name); errors++; continue; } } if ( (NULL == sg) || (strcmp (gr->gr_passwd, SHADOW_PASSWD_STRING) != 0)) #endif { if (gr_update (&newgr) == 0) { fprintf (stderr, _("%s: line %d: failed to prepare the new %s entry '%s'\n"), Prog, line, gr_dbname (), newgr.gr_name); errors++; continue; } } } /* * Any detected errors will cause the entire set of changes to be * aborted. Unlocking the group file will cause all of the * changes to be ignored. Otherwise the file is closed, causing the * changes to be written out all at once, and then unlocked * afterwards. */ if (0 != errors) { fprintf (stderr, _("%s: error detected, changes ignored\n"), Prog); fail_exit (1); } close_files (); nscd_flush_cache ("group"); return (0); }
static void get_group (struct group *gr) #endif { struct group const*tmpgr = NULL; #ifdef SHADOWGRP struct sgrp const*tmpsg = NULL; #endif if (gr_open (O_RDONLY) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ())); exit (E_NOPERM); } tmpgr = gr_locate (group); if (NULL == tmpgr) { fprintf (stderr, _("%s: group '%s' does not exist in %s\n"), Prog, group, gr_dbname ()); exit (E_BAD_ARG); } *gr = *tmpgr; gr->gr_name = xstrdup (tmpgr->gr_name); gr->gr_passwd = xstrdup (tmpgr->gr_passwd); gr->gr_mem = dup_list (tmpgr->gr_mem); if (gr_close () == 0) { fprintf (stderr, _("%s: failure while closing read-only %s\n"), Prog, gr_dbname ()); SYSLOG ((LOG_ERR, "failure while closing read-only %s", gr_dbname ())); exit (E_NOPERM); } #ifdef SHADOWGRP if (is_shadowgrp) { if (sgr_open (O_RDONLY) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ()); SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ())); exit (E_NOPERM); } tmpsg = sgr_locate (group); if (NULL != tmpsg) { *sg = *tmpsg; sg->sg_name = xstrdup (tmpsg->sg_name); sg->sg_passwd = xstrdup (tmpsg->sg_passwd); sg->sg_mem = dup_list (tmpsg->sg_mem); sg->sg_adm = dup_list (tmpsg->sg_adm); } else { sg->sg_name = xstrdup (group); sg->sg_passwd = gr->gr_passwd; gr->gr_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */ sg->sg_mem = dup_list (gr->gr_mem); sg->sg_adm = (char **) xmalloc (sizeof (char *) * 2); #ifdef FIRST_MEMBER_IS_ADMIN if (sg->sg_mem[0]) { sg->sg_adm[0] = xstrdup (sg->sg_mem[0]); sg->sg_adm[1] = NULL; } else #endif { sg->sg_adm[0] = NULL; } } if (sgr_close () == 0) { fprintf (stderr, _("%s: failure while closing read-only %s\n"), Prog, sgr_dbname ()); SYSLOG ((LOG_ERR, "failure while closing read-only %s", sgr_dbname ())); exit (E_NOPERM); } } #endif /* SHADOWGRP */ }
/* * add_group - create a new group or add a user to an existing group */ static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid) { const struct group *grp; struct group grent; char *members[1]; #ifdef SHADOWGRP const struct sgrp *sg; #endif /* * Start by seeing if the named group already exists. This will be * very easy to deal with if it does. */ grp = getgrnam (gid); if (NULL == grp) { grp = gr_locate (gid); } if (NULL != grp) { /* The user will use this ID for her primary group */ *ngid = grp->gr_gid; /* Don't check gshadow */ return 0; } if (isdigit (gid[0])) { /* * The GID is a number, which means either this is a brand * new group, or an existing group. */ if (get_gid (gid, &grent.gr_gid) == 0) { fprintf (stderr, _("%s: invalid group ID '%s'\n"), Prog, gid); return -1; } /* Look in both the system database (getgrgid) and in the * internal database (gr_locate_gid), which may contain * uncommitted changes */ if ( (getgrgid ((gid_t) grent.gr_gid) != NULL) || (gr_locate_gid ((gid_t) grent.gr_gid) != NULL)) { /* The user will use this ID for her * primary group */ *ngid = (gid_t) grent.gr_gid; return 0; } /* Do not create groups with GID == (gid_t)-1 */ if (grent.gr_gid == (gid_t)-1) { fprintf (stderr, _("%s: invalid group ID '%s'\n"), Prog, gid); return -1; } } else { /* The gid parameter can be "" or a name which is not * already the name of an existing group. * In both cases, figure out what group ID can be used. */ if (find_new_gid(rflg, &grent.gr_gid, &uid) < 0) { return -1; } } /* * Now I have all of the fields required to create the new group. */ if (('\0' != gid[0]) && (!isdigit (gid[0]))) { grent.gr_name = xstrdup (gid); } else { grent.gr_name = xstrdup (name); /* FIXME: check if the group exists */ } /* Check if this is a valid group name */ if (!is_valid_group_name (grent.gr_name)) { fprintf (stderr, _("%s: invalid group name '%s'\n"), Prog, grent.gr_name); if (grent.gr_name) free (grent.gr_name); return -1; } grent.gr_passwd = "*"; /* XXX warning: const */ members[0] = NULL; grent.gr_mem = members; *ngid = grent.gr_gid; #ifdef SHADOWGRP if (is_shadow_grp) { sg = sgr_locate (grent.gr_name); if (NULL != sg) { fprintf (stderr, _("%s: group '%s' is a shadow group, but does not exist in /etc/group\n"), Prog, grent.gr_name); return -1; } } #endif #ifdef SHADOWGRP if (is_shadow_grp) { struct sgrp sgrent; char *admins[1]; sgrent.sg_name = grent.gr_name; sgrent.sg_passwd = "*"; /* XXX warning: const */ grent.gr_passwd = "x"; /* XXX warning: const */ admins[0] = NULL; sgrent.sg_adm = admins; sgrent.sg_mem = members; if (sgr_update (&sgrent) == 0) { return -1; } } #endif if (gr_update (&grent) == 0) { return -1; } return 0; }
/* * check_grp_file - check the content of the group file */ static void check_grp_file (int *errors, bool *changed) { struct commonio_entry *gre, *tgre; struct group *grp; #ifdef SHADOWGRP struct sgrp *sgr; #endif /* * Loop through the entire group file. */ for (gre = __gr_get_head (); NULL != gre; gre = gre->next) { /* * Skip all NIS entries. */ if ((gre->line[0] == '+') || (gre->line[0] == '-')) { continue; } /* * Start with the entries that are completely corrupt. They * have no (struct group) entry because they couldn't be * parsed properly. */ if (NULL == gre->eptr) { /* * Tell the user this entire line is bogus and ask * them to delete it. */ (void) puts (_("invalid group file entry")); printf (_("delete line '%s'? "), gre->line); *errors += 1; /* * prompt the user to delete the entry or not */ if (!yes_or_no (read_only)) { continue; } /* * All group file deletions wind up here. This code * removes the current entry from the linked list. * When done, it skips back to the top of the loop * to try out the next list element. */ delete_gr: SYSLOG ((LOG_INFO, "delete group line '%s'", gre->line)); *changed = true; __gr_del_entry (gre); continue; } /* * Group structure is good, start using it. */ grp = gre->eptr; /* * Make sure this entry has a unique name. */ for (tgre = __gr_get_head (); NULL != tgre; tgre = tgre->next) { const struct group *ent = tgre->eptr; /* * Don't check this entry */ if (tgre == gre) { continue; } /* * Don't check invalid entries. */ if (NULL == ent) { continue; } if (strcmp (grp->gr_name, ent->gr_name) != 0) { continue; } /* * Tell the user this entry is a duplicate of * another and ask them to delete it. */ (void) puts (_("duplicate group entry")); printf (_("delete line '%s'? "), gre->line); *errors += 1; /* * prompt the user to delete the entry or not */ if (yes_or_no (read_only)) { goto delete_gr; } } /* * Check for invalid group names. --marekm */ if (!is_valid_group_name (grp->gr_name)) { *errors += 1; printf (_("invalid group name '%s'\n"), grp->gr_name); } /* * Check for invalid group ID. */ if (grp->gr_gid == (gid_t)-1) { printf (_("invalid group ID '%lu'\n"), (long unsigned int)grp->gr_gid); *errors += 1; } /* * Workaround for a NYS libc 5.3.12 bug on RedHat 4.2 - * groups with no members are returned as groups with one * member "", causing grpck to fail. --marekm */ if ( (NULL != grp->gr_mem[0]) && (NULL == grp->gr_mem[1]) && ('\0' == grp->gr_mem[0][0])) { grp->gr_mem[0] = NULL; } if (check_members (grp->gr_name, grp->gr_mem, _("group %s: no user %s\n"), _("delete member '%s'? "), "delete member '%s' from group '%s'", errors) == 1) { *changed = true; gre->changed = true; __gr_set_changed (); } #ifdef SHADOWGRP /* * Make sure this entry exists in the /etc/gshadow file. */ if (is_shadow) { sgr = (struct sgrp *) sgr_locate (grp->gr_name); if (sgr == NULL) { printf (_("no matching group file entry in %s\n"), sgr_file); printf (_("add group '%s' in %s? "), grp->gr_name, sgr_file); *errors += 1; if (yes_or_no (read_only)) { struct sgrp sg; struct group gr; static char *empty = NULL; sg.sg_name = grp->gr_name; sg.sg_passwd = grp->gr_passwd; sg.sg_adm = ∅ sg.sg_mem = grp->gr_mem; SYSLOG ((LOG_INFO, "add group '%s' to '%s'", grp->gr_name, sgr_file)); *changed = true; if (sgr_update (&sg) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, sgr_dbname (), sg.sg_name); fail_exit (E_CANT_UPDATE); } /* remove password from /etc/group */ gr = *grp; gr.gr_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */ if (gr_update (&gr) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, gr_dbname (), gr.gr_name); fail_exit (E_CANT_UPDATE); } } } else { /** * Verify that all the members defined in /etc/group are also * present in /etc/gshadow. */ compare_members_lists (grp->gr_name, grp->gr_mem, sgr->sg_mem, grp_file, sgr_file); /* The group entry has a gshadow counterpart. * Make sure no passwords are in group. */ if (strcmp (grp->gr_passwd, SHADOW_PASSWD_STRING) != 0) { printf (_("group %s has an entry in %s, but its password field in %s is not set to 'x'\n"), grp->gr_name, sgr_file, grp_file); *errors += 1; } } } #endif } }
/* * grp_update - update group file entries * * grp_update() updates the new records in the memory databases. */ static void grp_update (void) { struct group grp; const struct group *ogrp; #ifdef SHADOWGRP struct sgrp sgrp; const struct sgrp *osgrp = NULL; #endif /* SHADOWGRP */ /* * Get the current settings for this group. */ ogrp = gr_locate (group_name); if (!ogrp) { fprintf (stderr, _("%s: group '%s' does not exist in %s\n"), Prog, group_name, gr_dbname ()); exit (E_GRP_UPDATE); } grp = *ogrp; new_grent (&grp); #ifdef SHADOWGRP if ( is_shadow_grp && (pflg || nflg)) { osgrp = sgr_locate (group_name); if (NULL != osgrp) { sgrp = *osgrp; new_sgent (&sgrp); if (pflg) { grp.gr_passwd = SHADOW_PASSWD_STRING; } } } #endif /* SHADOWGRP */ if (gflg) { update_primary_groups (ogrp->gr_gid, group_newid); } /* * Write out the new group file entry. */ if (gr_update (&grp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, gr_dbname (), grp.gr_name); exit (E_GRP_UPDATE); } if (nflg && (gr_remove (group_name) == 0)) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, grp.gr_name, gr_dbname ()); exit (E_GRP_UPDATE); } #ifdef SHADOWGRP /* * Make sure there was a shadow entry to begin with. */ if ( (NULL != osgrp) && (pflg || nflg)) { /* * Write out the new shadow group entries as well. */ if (sgr_update (&sgrp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, sgr_dbname (), sgrp.sg_name); exit (E_GRP_UPDATE); } if (nflg && (sgr_remove (group_name) == 0)) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, group_name, sgr_dbname ()); exit (E_GRP_UPDATE); } } #endif /* SHADOWGRP */ }
/* * grp_update - update group file entries * * grp_update() updates the new records in the memory databases. */ static void grp_update (void) { struct group grp; const struct group *ogrp; #ifdef SHADOWGRP struct sgrp sgrp; const struct sgrp *osgrp = NULL; #endif /* SHADOWGRP */ /* * Get the current settings for this group. */ ogrp = gr_locate (group_name); if (NULL == ogrp) { fprintf (stderr, _("%s: group '%s' does not exist in %s\n"), Prog, group_name, gr_dbname ()); exit (E_GRP_UPDATE); } grp = *ogrp; new_grent (&grp); #ifdef SHADOWGRP if ( is_shadow_grp && (pflg || nflg)) { osgrp = sgr_locate (group_name); if (NULL != osgrp) { sgrp = *osgrp; new_sgent (&sgrp); } else if ( pflg && (strcmp (grp.gr_passwd, SHADOW_PASSWD_STRING) == 0)) { static char *empty = NULL; /* If there is a gshadow file with no entries for * the group, but the group file indicates a * shadowed password, we force the creation of a * gshadow entry when a new password is requested. */ memset (&sgrp, 0, sizeof sgrp); sgrp.sg_name = xstrdup (grp.gr_name); sgrp.sg_passwd = xstrdup (grp.gr_passwd); sgrp.sg_adm = ∅ sgrp.sg_mem = dup_list (grp.gr_mem); new_sgent (&sgrp); osgrp = &sgrp; /* entry needs to be committed */ } } #endif /* SHADOWGRP */ if (gflg) { update_primary_groups (ogrp->gr_gid, group_newid); } /* * Write out the new group file entry. */ if (gr_update (&grp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, gr_dbname (), grp.gr_name); exit (E_GRP_UPDATE); } if (nflg && (gr_remove (group_name) == 0)) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, grp.gr_name, gr_dbname ()); exit (E_GRP_UPDATE); } #ifdef SHADOWGRP /* * Make sure there was a shadow entry to begin with. */ if (NULL != osgrp) { /* * Write out the new shadow group entries as well. */ if (sgr_update (&sgrp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, sgr_dbname (), sgrp.sg_name); exit (E_GRP_UPDATE); } if (nflg && (sgr_remove (group_name) == 0)) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, group_name, sgr_dbname ()); exit (E_GRP_UPDATE); } } #endif /* SHADOWGRP */ }
/* * remove_usergroup - delete the user's group if it is a usergroup * * An usergroup is removed if * + it has the same name as the user * + it is the primary group of the user * + it has no other members * + it is not the primary group of any other user */ static void remove_usergroup (void) { const struct group *grp; const struct passwd *pwd = NULL; grp = gr_locate (user_name); if (NULL == grp) { /* This user has no usergroup. */ return; } if (grp->gr_gid != user_gid) { fprintf (stderr, _("%s: group %s not removed because it is not the primary group of user %s.\n"), Prog, grp->gr_name, user_name); return; } if (NULL != grp->gr_mem[0]) { /* The usergroup has other members. */ fprintf (stderr, _("%s: group %s not removed because it has other members.\n"), Prog, grp->gr_name); return; } if (!fflg) { /* * Scan the passwd file to check if this group is still * used as a primary group. */ setpwent (); while ((pwd = getpwent ()) != NULL) { if (strcmp (pwd->pw_name, user_name) == 0) { continue; } if (pwd->pw_gid == grp->gr_gid) { fprintf (stderr, _("%s: group %s is the primary group of another user and is not removed.\n"), Prog, grp->gr_name); break; } } endpwent (); } if (NULL == pwd) { /* * We can remove this group, it is not the primary * group of any remaining user. */ if (gr_remove (user_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, gr_dbname ()); fail_exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, "deleting group", user_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "removed group '%s' owned by '%s'\n", user_name, user_name)); #ifdef SHADOWGRP if (sgr_locate (user_name) != NULL) { if (sgr_remove (user_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, sgr_dbname ()); fail_exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, "deleting shadow group", user_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "removed shadow group '%s' owned by '%s'\n", user_name, user_name)); } #endif /* SHADOWGRP */ } }
int main (int argc, char **argv) { const struct group *gr; struct group grent; const struct sgrp *sg; struct sgrp sgent; Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); OPENLOG ("grpconv"); process_flags (argc, argv); if (gr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, gr_dbname ()); fail_exit (5); } gr_locked = true; if (gr_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); fail_exit (1); } if (sgr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sgr_dbname ()); fail_exit (5); } sgr_locked = true; if (sgr_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ()); fail_exit (1); } /* * Remove /etc/gshadow entries for groups not in /etc/group. */ (void) sgr_rewind (); while ((sg = sgr_next ()) != NULL) { if (gr_locate (sg->sg_name) != NULL) { continue; } if (sgr_remove (sg->sg_name) == 0) { /* * This shouldn't happen (the entry exists) but... */ fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, sg->sg_name, sgr_dbname ()); fail_exit (3); } } /* * Update shadow group passwords if non-shadow password is not "x". * Add any missing shadow group entries. */ (void) gr_rewind (); while ((gr = gr_next ()) != NULL) { sg = sgr_locate (gr->gr_name); if (NULL != sg) { /* update existing shadow group entry */ sgent = *sg; if (strcmp (gr->gr_passwd, SHADOW_PASSWD_STRING) != 0) sgent.sg_passwd = gr->gr_passwd; } else { static char *empty = 0; /* add new shadow group entry */ memset (&sgent, 0, sizeof sgent); sgent.sg_name = gr->gr_name; sgent.sg_passwd = gr->gr_passwd; sgent.sg_adm = ∅ } /* * XXX - sg_mem is redundant, it is currently always a copy * of gr_mem. Very few programs actually use sg_mem, and all * of them are in the shadow suite. Maybe this field could * be used for something else? Any suggestions? */ sgent.sg_mem = gr->gr_mem; if (sgr_update (&sgent) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, sgr_dbname (), sgent.sg_name); fail_exit (3); } /* remove password from /etc/group */ grent = *gr; grent.gr_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */ if (gr_update (&grent) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, gr_dbname (), grent.gr_name); fail_exit (3); } } if (sgr_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sgr_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ())); fail_exit (3); } if (gr_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); fail_exit (3); } if (sgr_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); /* continue */ } if (gr_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); /* continue */ } nscd_flush_cache ("group"); return 0; }
/* * update_groups - delete user from secondary group set * * update_groups() takes the user name that was given and searches * the group files for membership in any group. * * we also check to see if they have any groups they own (the same * name is their user name) and delete them too (only if USERGROUPS_ENAB * is enabled). */ static void update_groups (void) { const struct group *grp; struct group *ngrp; struct passwd *pwd; #ifdef SHADOWGRP bool deleted_user_group = false; const struct sgrp *sgrp; struct sgrp *nsgrp; #endif /* SHADOWGRP */ /* * Scan through the entire group file looking for the groups that * the user is a member of. */ for (gr_rewind (), grp = gr_next (); NULL != grp; grp = gr_next ()) { /* * See if the user specified this group as one of their * concurrent groups. */ if (!is_on_list (grp->gr_mem, user_name)) { continue; } /* * Delete the username from the list of group members and * update the group entry to reflect the change. */ ngrp = __gr_dup (grp); if (NULL == ngrp) { fprintf (stderr, _("%s: Out of memory. Cannot update %s.\n"), Prog, gr_dbname ()); exit (13); /* XXX */ } ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); if (gr_update (ngrp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, gr_dbname (), ngrp->gr_name); exit (E_GRP_UPDATE); } /* * Update the DBM group file with the new entry as well. */ #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user from group", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n", user_name, ngrp->gr_name)); } /* * we've removed their name from all the groups above, so * now if they have a group with the same name as their * user name, with no members, we delete it. * FIXME: below, the check for grp->gr_mem[0] is not sufficient. * We should retrieve the group with gr_locate and check * that gr_mem is empty. */ grp = xgetgrnam (user_name); if ( (NULL != grp) && getdef_bool ("USERGROUPS_ENAB") && ( (NULL == grp->gr_mem[0]) || ( (NULL == grp->gr_mem[1]) && (strcmp (grp->gr_mem[0], user_name) == 0)))) { pwd = NULL; if (!fflg) { /* * Scan the passwd file to check if this group is still * used as a primary group. */ setpwent (); while ((pwd = getpwent ()) != NULL) { if (strcmp (pwd->pw_name, user_name) == 0) { continue; } if (pwd->pw_gid == grp->gr_gid) { fprintf (stderr, _("%s: group %s is the primary group of another user and is not removed.\n"), Prog, grp->gr_name); break; } } endpwent (); } if (NULL == pwd) { /* * We can remove this group, it is not the primary * group of any remaining user. */ if (gr_remove (grp->gr_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, grp->gr_name, gr_dbname ()); fail_exit (E_GRP_UPDATE); } #ifdef SHADOWGRP deleted_user_group = true; #endif #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, "deleting group", grp->gr_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "removed group '%s' owned by '%s'\n", grp->gr_name, user_name)); } } #ifdef SHADOWGRP if (!is_shadow_grp) { return; } /* * Scan through the entire shadow group file looking for the groups * that the user is a member of. Both the administrative list and * the ordinary membership list is checked. */ for (sgr_rewind (), sgrp = sgr_next (); NULL != sgrp; sgrp = sgr_next ()) { bool was_member, was_admin; /* * See if the user specified this group as one of their * concurrent groups. */ was_member = is_on_list (sgrp->sg_mem, user_name); was_admin = is_on_list (sgrp->sg_adm, user_name); if (!was_member && !was_admin) { continue; } nsgrp = __sgr_dup (sgrp); if (NULL == nsgrp) { fprintf (stderr, _("%s: Out of memory. Cannot update %s.\n"), Prog, sgr_dbname ()); exit (13); /* XXX */ } if (was_member) { nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name); } if (was_admin) { nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name); } if (sgr_update (nsgrp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, sgr_dbname (), nsgrp->sg_name); exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user from shadow group", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n", user_name, nsgrp->sg_name)); } if ( deleted_user_group && (sgr_locate (user_name) != NULL)) { if (sgr_remove (user_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, sgr_dbname ()); fail_exit (E_GRP_UPDATE); } } #endif /* SHADOWGRP */ }