X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fgrpck.c;h=ca4d72e18d9c7d56a1b34106888f3bd562b7967f;hb=4e75bb57bb1b8d1f29c376354d43183c9fbc2884;hp=30e2f189e7d771887c5985a576272a7c7e4a4dc2;hpb=f6e79f59be5ac6fb448784c43d7b33d816b2bb71;p=shadow diff --git a/src/grpck.c b/src/grpck.c index 30e2f189..ca4d72e1 100644 --- a/src/grpck.c +++ b/src/grpck.c @@ -1,5 +1,9 @@ /* - * Copyright 1992 - 1994, Julianne Frances Haugh + * Copyright (c) 1992 - 1994, Julianne Frances Haugh + * Copyright (c) 1996 - 2000, Marek Michałkiewicz + * Copyright (c) 2001 , Michał Moskal + * Copyright (c) 2001 - 2006, Tomasz Kłoczko + * Copyright (c) 2007 - 2009, Nicolas François * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -10,21 +14,21 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Julianne F. Haugh nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * 3. The name of the copyright holders or contributors may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include @@ -41,19 +45,15 @@ #include "groupio.h" #include "nscd.h" #include "prototypes.h" -extern void __gr_del_entry (const struct commonio_entry *); -extern struct commonio_entry *__gr_get_head (void); #ifdef SHADOWGRP #include "sgroupio.h" -extern void __sgr_del_entry (const struct commonio_entry *); -extern struct commonio_entry *__sgr_get_head (void); #endif /* * Exit codes */ - +/*@-exitarg@*/ #define E_OKAY 0 #define E_USAGE 1 #define E_BAD_ENTRY 2 @@ -64,41 +64,73 @@ extern struct commonio_entry *__sgr_get_head (void); /* * Global variables */ -static char *Prog; +char *Prog; + static const char *grp_file = GROUP_FILE; -static int use_system_grp_file = 1; +static bool use_system_grp_file = true; #ifdef SHADOWGRP static const char *sgr_file = SGROUP_FILE; -static int use_system_sgr_file = 1; -static int is_shadow = 0; +static bool use_system_sgr_file = true; +static bool is_shadow = false; +static bool sgr_locked = false; #endif +static bool gr_locked = false; /* Options */ -static int read_only = 0; -static int sort_mode = 0; +static bool read_only = false; +static bool sort_mode = false; /* local function prototypes */ +static void fail_exit (int status); static void usage (void); static void delete_member (char **, const char *); static void process_flags (int argc, char **argv); static void open_files (void); -static void close_files (int changed); +static void close_files (bool changed); static int check_members (const char *groupname, char **members, const char *fmt_info, const char *fmt_prompt, const char *fmt_syslog, int *errors); +static void check_grp_file (int *errors, bool *changed); +#ifdef SHADOWGRP static void compare_members_lists (const char *groupname, char **members, char **other_members, const char *file, const char *other_file); -static void check_grp_file (int *errors, int *changed); -#ifdef SHADOWGRP -static void check_sgr_file (int *errors, int *changed); +static void check_sgr_file (int *errors, bool *changed); +#endif + +/* + * fail_exit - exit with an error code after unlocking files + */ +static void fail_exit (int status) +{ + if (gr_locked) { + 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 */ + } + } + +#ifdef SHADOWGRP + if (sgr_locked) { + 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 */ + } + } #endif + closelog (); + + exit (status); +} + /* * usage - print syntax message and exit */ @@ -114,6 +146,8 @@ static void usage (void) /* * delete_member - delete an entry in a list of members + * + * It only deletes the first entry with the given name. */ static void delete_member (char **list, const char *member) { @@ -150,10 +184,10 @@ static void process_flags (int argc, char **argv) /* quiet - ignored for now */ break; case 'r': - read_only = 1; + read_only = true; break; case 's': - sort_mode = 1; + sort_mode = true; break; default: usage (); @@ -183,15 +217,15 @@ static void process_flags (int argc, char **argv) */ if (optind != argc) { grp_file = argv[optind]; - gr_name (grp_file); - use_system_grp_file = 0; + gr_setdbname (grp_file); + use_system_grp_file = false; } #ifdef SHADOWGRP if ((optind + 2) == argc) { sgr_file = argv[optind + 1]; - sgr_name (sgr_file); - is_shadow = 1; - use_system_sgr_file = 0; + sgr_setdbname (sgr_file); + is_shadow = true; + use_system_sgr_file = false; } else if (optind == argc) { is_shadow = sgr_file_present (); } @@ -211,23 +245,21 @@ static void open_files (void) */ if (!read_only) { if (gr_lock () == 0) { - fprintf (stderr, _("%s: cannot lock file %s\n"), + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), Prog, grp_file); - if (use_system_grp_file) { - SYSLOG ((LOG_WARN, "cannot lock %s", grp_file)); - } - closelog (); - exit (E_CANT_LOCK); + fail_exit (E_CANT_LOCK); } + gr_locked = true; #ifdef SHADOWGRP - if (is_shadow && (sgr_lock () == 0)) { - fprintf (stderr, _("%s: cannot lock file %s\n"), - Prog, sgr_file); - if (use_system_sgr_file) { - SYSLOG ((LOG_WARN, "cannot lock %s", sgr_file)); + if (is_shadow) { + if (sgr_lock () == 0) { + fprintf (stderr, + _("%s: cannot lock %s; try again later.\n"), + Prog, sgr_file); + fail_exit (E_CANT_LOCK); } - closelog (); - exit (E_CANT_LOCK); + sgr_locked = true; } #endif } @@ -237,23 +269,21 @@ static void open_files (void) * O_RDWR otherwise. */ if (gr_open (read_only ? O_RDONLY : O_RDWR) == 0) { - fprintf (stderr, _("%s: cannot open file %s\n"), Prog, + fprintf (stderr, _("%s: cannot open %s\n"), Prog, grp_file); if (use_system_grp_file) { SYSLOG ((LOG_WARN, "cannot open %s", grp_file)); } - closelog (); - exit (E_CANT_OPEN); + fail_exit (E_CANT_OPEN); } #ifdef SHADOWGRP if (is_shadow && (sgr_open (read_only ? O_RDONLY : O_RDWR) == 0)) { - fprintf (stderr, _("%s: cannot open file %s\n"), Prog, + fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_file); if (use_system_sgr_file) { SYSLOG ((LOG_WARN, "cannot open %s", sgr_file)); } - closelog (); - exit (E_CANT_OPEN); + fail_exit (E_CANT_OPEN); } #endif } @@ -265,7 +295,7 @@ static void open_files (void) * changes are committed in the databases. The databases are * unlocked anyway. */ -static void close_files (int changed) +static void close_files (bool changed) { /* * All done. If there were no change we can just abandon any @@ -273,15 +303,15 @@ static void close_files (int changed) */ if (changed) { if (gr_close () == 0) { - fprintf (stderr, _("%s: cannot update file %s\n"), + fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, grp_file); - exit (E_CANT_UPDATE); + fail_exit (E_CANT_UPDATE); } #ifdef SHADOWGRP if (is_shadow && (sgr_close () == 0)) { - fprintf (stderr, _("%s: cannot update file %s\n"), + fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sgr_file); - exit (E_CANT_UPDATE); + fail_exit (E_CANT_UPDATE); } #endif } @@ -290,11 +320,23 @@ static void close_files (int changed) * Don't be anti-social - unlock the files when you're done. */ #ifdef SHADOWGRP - if (is_shadow) { - sgr_unlock (); + if (sgr_locked) { + 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 */ + } + sgr_locked = false; } #endif - (void) gr_unlock (); + if (gr_locked) { + 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 */ + } + gr_locked = false; + } } /* @@ -329,9 +371,9 @@ static int check_members (const char *groupname, /* * Make sure each member exists */ - for (i = 0; members[i]; i++) { + for (i = 0; NULL != members[i]; i++) { /* local, no need for xgetpwnam */ - if (getpwnam (members[i])) { + if (getpwnam (members[i]) != NULL) { continue; } /* @@ -349,11 +391,15 @@ static int check_members (const char *groupname, SYSLOG ((LOG_INFO, fmt_syslog, members[i], groupname)); members_changed = 1; delete_member (members, members[i]); + + /* Rewind in case of removal */ + i--; } return members_changed; } +#ifdef SHADOWGRP /* * compare_members_lists - make sure the list of members is contained in * another list. @@ -372,8 +418,8 @@ static void compare_members_lists (const char *groupname, { char **pmem, **other_pmem; - for (pmem = members; *pmem; pmem++) { - for (other_pmem = other_members; *other_pmem; other_pmem++) { + for (pmem = members; NULL != *pmem; pmem++) { + for (other_pmem = other_members; NULL != *other_pmem; other_pmem++) { if (strcmp (*pmem, *other_pmem) == 0) { break; } @@ -385,11 +431,12 @@ static void compare_members_lists (const char *groupname, } } } +#endif /* SHADOWGRP */ /* * check_grp_file - check the content of the group file */ -static void check_grp_file (int *errors, int *changed) +static void check_grp_file (int *errors, bool *changed) { struct commonio_entry *gre, *tgre; struct group *grp; @@ -400,7 +447,7 @@ static void check_grp_file (int *errors, int *changed) /* * Loop through the entire group file. */ - for (gre = __gr_get_head (); gre; gre = gre->next) { + for (gre = __gr_get_head (); NULL != gre; gre = gre->next) { /* * Skip all NIS entries. */ @@ -414,13 +461,13 @@ static void check_grp_file (int *errors, int *changed) * have no (struct group) entry because they couldn't be * parsed properly. */ - if (!gre->eptr) { + if (NULL == gre->eptr) { /* * Tell the user this entire line is bogus and ask * them to delete it. */ - printf (_("invalid group file entry\n")); + (void) puts (_("invalid group file entry")); printf (_("delete line '%s'? "), gre->line); *errors += 1; @@ -438,9 +485,9 @@ static void check_grp_file (int *errors, int *changed) * to try out the next list element. */ delete_gr: - SYSLOG ((LOG_INFO, "delete group line `%s'", + SYSLOG ((LOG_INFO, "delete group line '%s'", gre->line)); - *changed = 1; + *changed = true; __gr_del_entry (gre); continue; @@ -454,7 +501,7 @@ static void check_grp_file (int *errors, int *changed) /* * Make sure this entry has a unique name. */ - for (tgre = __gr_get_head (); tgre; tgre = tgre->next) { + for (tgre = __gr_get_head (); NULL != tgre; tgre = tgre->next) { const struct group *ent = tgre->eptr; @@ -468,7 +515,7 @@ static void check_grp_file (int *errors, int *changed) /* * Don't check invalid entries. */ - if (!ent) { + if (NULL == ent) { continue; } @@ -480,7 +527,7 @@ static void check_grp_file (int *errors, int *changed) * Tell the user this entry is a duplicate of * another and ask them to delete it. */ - printf (_("duplicate group entry\n")); + (void) puts (_("duplicate group entry")); printf (_("delete line '%s'? "), gre->line); *errors += 1; @@ -495,28 +542,37 @@ static void check_grp_file (int *errors, int *changed) /* * Check for invalid group names. --marekm */ - if (!check_group_name (grp->gr_name)) { + 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 (grp->gr_mem[0] && !grp->gr_mem[1] - && *(grp->gr_mem[0]) == '\0') { - grp->gr_mem[0] = (char *) 0; + 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'", + "delete member '%s' from group '%s'", errors) == 1) { - *changed = 1; - gre->changed = 1; + *changed = true; + gre->changed = true; __gr_set_changed (); } @@ -528,10 +584,9 @@ static void check_grp_file (int *errors, int *changed) if (is_shadow) { sgr = (struct sgrp *) sgr_locate (grp->gr_name); if (sgr == NULL) { - printf (_ - ("no matching group file entry in %s\n"), + printf (_("no matching group file entry in %s\n"), sgr_file); - printf (_("add group '%s' in %s ?"), + printf (_("add group '%s' in %s? "), grp->gr_name, sgr_file); *errors += 1; if (yes_or_no (read_only)) { @@ -544,26 +599,24 @@ static void check_grp_file (int *errors, int *changed) sg.sg_adm = ∅ sg.sg_mem = grp->gr_mem; SYSLOG ((LOG_INFO, - "add group `%s' to `%s'", + "add group '%s' to '%s'", grp->gr_name, sgr_file)); - *changed = 1; + *changed = true; - if (!sgr_update (&sg)) { + if (sgr_update (&sg) == 0) { fprintf (stderr, - _ - ("%s: can't update shadow entry for %s\n"), - Prog, sg.sg_name); - exit (E_CANT_UPDATE); + _("%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)) { + if (gr_update (&gr) == 0) { fprintf (stderr, - _ - ("%s: can't update entry for group %s\n"), - Prog, gr.gr_name); - exit (E_CANT_UPDATE); + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, gr_dbname (), gr.gr_name); + fail_exit (E_CANT_UPDATE); } } } else { @@ -585,7 +638,7 @@ static void check_grp_file (int *errors, int *changed) /* * check_sgr_file - check the content of the shadowed group file (gshadow) */ -static void check_sgr_file (int *errors, int *changed) +static void check_sgr_file (int *errors, bool *changed) { struct group *grp; struct commonio_entry *sge, *tsge; @@ -594,20 +647,20 @@ static void check_sgr_file (int *errors, int *changed) /* * Loop through the entire shadow group file. */ - for (sge = __sgr_get_head (); sge; sge = sge->next) { + for (sge = __sgr_get_head (); NULL != sge; sge = sge->next) { /* * Start with the entries that are completely corrupt. They * have no (struct sgrp) entry because they couldn't be * parsed properly. */ - if (!sge->eptr) { + if (NULL == sge->eptr) { /* * Tell the user this entire line is bogus and ask * them to delete it. */ - printf (_("invalid shadow group file entry\n")); + (void) puts (_("invalid shadow group file entry")); printf (_("delete line '%s'? "), sge->line); *errors += 1; @@ -625,9 +678,9 @@ static void check_sgr_file (int *errors, int *changed) * of the loop to try out the next list element. */ delete_sg: - SYSLOG ((LOG_INFO, "delete shadow line `%s'", + SYSLOG ((LOG_INFO, "delete shadow line '%s'", sge->line)); - *changed = 1; + *changed = true; __sgr_del_entry (sge); continue; @@ -641,7 +694,7 @@ static void check_sgr_file (int *errors, int *changed) /* * Make sure this entry has a unique name. */ - for (tsge = __sgr_get_head (); tsge; tsge = tsge->next) { + for (tsge = __sgr_get_head (); NULL != tsge; tsge = tsge->next) { const struct sgrp *ent = tsge->eptr; @@ -655,7 +708,7 @@ static void check_sgr_file (int *errors, int *changed) /* * Don't check invalid entries. */ - if (!ent) { + if (NULL == ent) { continue; } @@ -667,7 +720,7 @@ static void check_sgr_file (int *errors, int *changed) * Tell the user this entry is a duplicate of * another and ask them to delete it. */ - printf (_("duplicate shadow group entry\n")); + (void) puts (_("duplicate shadow group entry")); printf (_("delete line '%s'? "), sge->line); *errors += 1; @@ -707,10 +760,10 @@ static void check_sgr_file (int *errors, int *changed) if (check_members (sgr->sg_name, sgr->sg_adm, _("shadow group %s: no administrative user %s\n"), _("delete administrative member '%s'? "), - "delete admin `%s' from shadow group `%s'", + "delete admin '%s' from shadow group '%s'", errors) == 1) { - *changed = 1; - sge->changed = 1; + *changed = true; + sge->changed = true; __sgr_set_changed (); } @@ -720,10 +773,10 @@ static void check_sgr_file (int *errors, int *changed) if (check_members (sgr->sg_name, sgr->sg_mem, _("shadow group %s: no user %s\n"), _("delete member '%s'? "), - "delete member `%s' from shadow group `%s'", + "delete member '%s' from shadow group '%s'", errors) == 1) { - *changed = 1; - sge->changed = 1; + *changed = true; + sge->changed = true; __sgr_set_changed (); } } @@ -736,16 +789,16 @@ static void check_sgr_file (int *errors, int *changed) int main (int argc, char **argv) { int errors = 0; - int changed = 0; + bool changed = false; /* * Get my name so that I can use it to report errors. */ Prog = Basename (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + (void) setlocale (LC_ALL, ""); + (void) bindtextdomain (PACKAGE, LOCALEDIR); + (void) textdomain (PACKAGE); OPENLOG ("grpck"); @@ -760,7 +813,7 @@ int main (int argc, char **argv) if (is_shadow) { sgr_sort (); } - changed = 1; + changed = true; #endif } else { check_grp_file (&errors, &changed); @@ -779,12 +832,14 @@ int main (int argc, char **argv) /* * Tell the user what we did and exit. */ - if (errors) { - printf (changed ? - _("%s: the files have been updated\n") : - _("%s: no changes\n"), Prog); + if (0 != errors) { + if (changed) { + printf (_("%s: the files have been updated\n"), Prog); + } else { + printf (_("%s: no changes\n"), Prog); + } } - exit (errors ? E_BAD_ENTRY : E_OKAY); + return ((0 != errors) ? E_BAD_ENTRY : E_OKAY); }