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; }
static void find_new_gid (void) { const struct group *grp; gid_t gid_min, gid_max; gid_min = getdef_unum ("GID_MIN", 100); gid_max = getdef_unum ("GID_MAX", 60000); /* * Start with some GID value if the user didn't provide us with * one already. */ if (!gflg) group_id = gid_min; /* * Search the entire group file, either looking for this GID (if the * user specified one with -g) or looking for the largest unused * value. */ #ifdef NO_GETGRENT gr_rewind (); while ((grp = gr_next ())) { #else setgrent (); while ((grp = getgrent ())) { #endif if (strcmp (group_name, grp->gr_name) == 0) { if (fflg) { fail_exit (E_SUCCESS); } fprintf (stderr, _("%s: name %s is not unique\n"), Prog, group_name); fail_exit (E_NAME_IN_USE); } if (gflg && group_id == grp->gr_gid) { if (fflg) { /* turn off -g and search again */ gflg = 0; #ifdef NO_GETGRENT gr_rewind (); #else setgrent (); #endif continue; } fprintf (stderr, _("%s: gid %u is not unique\n"), Prog, (unsigned int) group_id); fail_exit (E_GID_IN_USE); } if (!gflg && grp->gr_gid >= group_id) { if (grp->gr_gid > gid_max) continue; group_id = grp->gr_gid + 1; } } if (!gflg && group_id == gid_max + 1) { for (group_id = gid_min; group_id < gid_max; group_id++) { #ifdef NO_GETGRENT gr_rewind (); while ((grp = gr_next ()) && grp->gr_gid != group_id); if (!grp) break; #else if (!getgrgid (group_id)) break; #endif } if (group_id == gid_max) { fprintf (stderr, _("%s: can't get unique gid\n"), Prog); fail_exit (E_GID_IN_USE); } } } /* * check_new_name - check the new name for validity * * check_new_name() insures that the new name doesn't contain any * illegal characters. */ static void check_new_name (void) { if (check_group_name (group_name)) return; /* * All invalid group names land here. */ fprintf (stderr, _("%s: %s is a not a valid group name\n"), Prog, group_name); exit (E_BAD_ARG); } /* * process_flags - perform command line argument setting * * process_flags() interprets the command line arguments and sets the * values that the user will be created with accordingly. The values * are checked for sanity. */ static void process_flags (int argc, char **argv) { char *cp; int arg; while ((arg = getopt (argc, argv, "og:O:f")) != EOF) { switch (arg) { case 'g': gflg++; if (!isdigit (optarg[0])) usage (); group_id = strtoul (optarg, &cp, 10); if (*cp != '\0') { fprintf (stderr, _("%s: invalid group %s\n"), Prog, optarg); fail_exit (E_BAD_ARG); } break; case 'o': oflg++; break; case 'O': /* * override login.defs defaults (-O name=value) * example: -O GID_MIN=100 -O GID_MAX=499 * note: -O GID_MIN=10,GID_MAX=499 doesn't work yet */ cp = strchr (optarg, '='); if (!cp) { fprintf (stderr, _("%s: -O requires NAME=VALUE\n"), Prog); exit (E_BAD_ARG); } /* terminate name, point to value */ *cp++ = '\0'; if (putdef_str (optarg, cp) < 0) exit (E_BAD_ARG); break; case 'f': /* * "force" - do nothing, just exit(0), if the * specified group already exists. With -g, if * specified gid already exists, choose another * (unique) gid (turn off -g). Based on the RedHat's * patch from shadow-utils-970616-9. */ fflg++; break; default: usage (); } } if (oflg && !gflg) usage (); if (optind != argc - 1) usage (); group_name = argv[argc - 1]; check_new_name (); }
static void update_groups(void) { const struct group *grp; struct group *ngrp; #ifdef SHADOWGRP 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 ();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 (!ngrp) { exit(13); /* XXX */ } ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); if (!gr_update(ngrp)) fprintf(stderr, _("%s: error updating group entry\n"), Prog); /* * Update the DBM group file with the new entry as well. */ #ifdef NDBM if (!gr_dbm_update(ngrp)) fprintf(stderr, _("%s: cannot update dbm group entry\n"), Prog); #endif /* NDBM */ SYSLOG((LOG_INFO, "delete `%s' from group `%s'\n", user_name, ngrp->gr_name)); } #ifdef NDBM endgrent (); #endif /* NDBM */ #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 ();sgrp;sgrp = sgr_next ()) { int 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 (!nsgrp) { 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)) fprintf(stderr, _("%s: error updating group entry\n"), Prog); #ifdef NDBM /* * Update the DBM group file with the new entry as well. */ if (!sg_dbm_update(nsgrp)) fprintf(stderr, _("%s: cannot update dbm group entry\n"), Prog); #endif /* NDBM */ SYSLOG((LOG_INFO, "delete `%s' from shadow group `%s'\n", user_name, nsgrp->sg_name)); } #ifdef NDBM endsgent (); #endif /* NDBM */ #endif /* SHADOWGRP */ }
/* * 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; #ifdef SHADOWGRP 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 /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n", user_name, ngrp->gr_name)); } if (getdef_bool ("USERGROUPS_ENAB")) { remove_usergroup (); } #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 /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n", user_name, nsgrp->sg_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 */ }