diff --git a/ChangeLog b/ChangeLog index dcecd4a6..43203efe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,9 @@ group IDs. * NEWS, src/grpck.c, src/pwck.c: Issue a warning if an ID is set to -1. + * NEWS, src/newusers.c, src/usermod.c, src/useradd.c, + src/groupmod.c, src/groupadd.c: Make sure no user or group are + created with an ID set to -1. 2009-03-07 Nicolas François diff --git a/src/groupadd.c b/src/groupadd.c index 45f5d5b3..b00e3cdc 100644 --- a/src/groupadd.c +++ b/src/groupadd.c @@ -2,7 +2,7 @@ * Copyright (c) 1991 - 1993, Julianne Frances Haugh * Copyright (c) 1996 - 2000, Marek Michałkiewicz * Copyright (c) 2000 - 2006, Tomasz Kłoczko - * Copyright (c) 2007 - 2008, Nicolas François + * Copyright (c) 2007 - 2009, Nicolas François * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -98,7 +98,6 @@ static void grp_update (void); static void check_new_name (void); static void close_files (void); static void open_files (void); -static gid_t get_gid (const char *gidstr); static void process_flags (int argc, char **argv); static void check_flags (void); static void check_perms (void); @@ -362,23 +361,6 @@ static void open_files (void) #endif /* SHADOWGRP */ } -/* - * get_id - validate and get group ID - */ -static gid_t get_gid (const char *gidstr) -{ - long val; - char *errptr; - - val = strtol (gidstr, &errptr, 10); - if (('\0' != *errptr) || (errno == ERANGE) || (val < 0)) { - fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), - Prog, gidstr); - exit (E_BAD_ARG); - } - return (gid_t) val; -} - /* * process_flags - parse the command line options * @@ -419,7 +401,13 @@ static void process_flags (int argc, char **argv) break; case 'g': gflg = true; - group_id = get_gid (optarg); + if ( (get_gid (optarg, &group_id) == 0) + || (group_id == (gid_t)-1)) { + fprintf (stderr, + _("%s: invalid group ID '%s'\n"), + Prog, optarg); + exit (E_BAD_ARG); + } break; case 'h': usage (); diff --git a/src/groupmod.c b/src/groupmod.c index 90e7ab0a..8a0b2c88 100644 --- a/src/groupmod.c +++ b/src/groupmod.c @@ -2,7 +2,7 @@ * Copyright (c) 1991 - 1994, Julianne Frances Haugh * Copyright (c) 1996 - 2000, Marek Michałkiewicz * Copyright (c) 2000 - 2006, Tomasz Kłoczko - * Copyright (c) 2007 - 2008, Nicolas François + * Copyright (c) 2007 - 2009, Nicolas François * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -104,7 +104,6 @@ static void lock_files (void); static void prepare_failure_reports (void); static void open_files (void); static void close_files (void); -static gid_t get_gid (const char *gidstr); static void update_primary_groups (gid_t ogid, gid_t ngid); /* @@ -324,24 +323,6 @@ static void check_new_name (void) exit (E_BAD_ARG); } -/* - * get_id - validate and get group ID - */ -static gid_t get_gid (const char *gidstr) -{ - long val; - char *errptr; - - val = strtol (gidstr, &errptr, 10); /* FIXME: Should be strtoul ? */ - if (('\0' != *errptr) || (ERANGE == errno) || (val < 0)) { - fprintf (stderr, - _("%s: invalid numeric argument '%s'\n"), - Prog, gidstr); - exit (E_BAD_ARG); - } - return (gid_t) val; -} - /* * process_flags - perform command line argument setting * @@ -367,7 +348,13 @@ static void process_flags (int argc, char **argv) switch (c) { case 'g': gflg = true; - group_newid = get_gid (optarg); + if ( (get_gid (optarg, &group_newid) == 0) + || (group_newid == (gid_t)-1)) { + fprintf (stderr, + _("%s: invalid group ID '%s'\n"), + Prog, optarg); + exit (E_BAD_ARG); + } break; case 'n': nflg = true; diff --git a/src/newusers.c b/src/newusers.c index 209a4b4e..c2d32a3e 100644 --- a/src/newusers.c +++ b/src/newusers.c @@ -2,7 +2,7 @@ * Copyright (c) 1990 - 1993, Julianne Frances Haugh * Copyright (c) 1996 - 2000, Marek Michałkiewicz * Copyright (c) 2000 - 2006, Tomasz Kłoczko - * Copyright (c) 2007 - 2008, Nicolas François + * Copyright (c) 2007 - 2009, Nicolas François * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -89,7 +89,7 @@ static bool spw_locked = false; static void usage (void); static void fail_exit (int); static int add_group (const char *, const char *, gid_t *, gid_t); -static int get_uid (const char *, uid_t *); +static int get_user_id (const char *, uid_t *); static int add_user (const char *, uid_t, gid_t); static void update_passwd (struct passwd *, const char *); static int add_passwd (struct passwd *, const char *); @@ -193,25 +193,32 @@ static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid) * The GID is a number, which means either this is a brand * new group, or an existing group. */ - char *endptr; - unsigned long int i = strtoul (gid, &endptr, 10); - if ((*endptr != '\0') || (ERANGE == errno)) { + + if (get_gid (gid, &grent.gr_gid) == 0) { fprintf (stderr, - _("%s: group ID '%s' is not valid\n"), + _("%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) i) != NULL) - || (gr_locate_gid ((gid_t) i) != NULL)) { + 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) i; + *ngid = (gid_t) grent.gr_gid; return 0; } - grent.gr_gid = (gid_t) i; + + /* 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. @@ -282,22 +289,19 @@ static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid) return 0; } -static int get_uid (const char *uid, uid_t *nuid) { +static int get_user_id (const char *uid, uid_t *nuid) { /* * The first guess for the UID is either the numerical UID that the * caller provided, or the next available UID. */ if (isdigit (uid[0])) { - char *endptr; - unsigned long int i = strtoul (uid, &endptr, 10); - if (('\0' != *endptr) || (ERANGE == errno)) { + if ((get_uid (uid, nuid) == 0) || (*nuid == (uid_t)-1)) { fprintf (stderr, - _("%s: user ID '%s' is not valid\n"), + _("%s: invalid user ID '%s'\n"), Prog, uid); return -1; } - *nuid = (uid_t) i; } else { if ('\0' != uid[0]) { const struct passwd *pwd; @@ -824,7 +828,7 @@ int main (int argc, char **argv) } if ( (NULL == pw) - && (get_uid (fields[2], &uid) != 0)) { + && (get_user_id (fields[2], &uid) != 0)) { fprintf (stderr, _("%s: line %d: can't create user\n"), Prog, line); diff --git a/src/useradd.c b/src/useradd.c index a8a7b32e..9753e357 100644 --- a/src/useradd.c +++ b/src/useradd.c @@ -2,7 +2,7 @@ * Copyright (c) 1991 - 1994, Julianne Frances Haugh * Copyright (c) 1996 - 2000, Marek Michałkiewicz * Copyright (c) 2000 - 2006, Tomasz Kłoczko - * Copyright (c) 2007 - 2008, Nicolas François + * Copyright (c) 2007 - 2009, Nicolas François * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -171,7 +171,6 @@ static bool home_added = false; static void fail_exit (int); static struct group *getgr_nam_gid (const char *); static long get_number (const char *); -static uid_t get_uid (const char *); static void get_defaults (void); static void show_defaults (void); static int set_defaults (void); @@ -268,11 +267,15 @@ static void fail_exit (int code) static struct group *getgr_nam_gid (const char *grname) { - long gid; - char *errptr; + long long int gid; + char *endptr; - gid = strtol (grname, &errptr, 10); - if (*grname != '\0' && *errptr == '\0' && errno != ERANGE && gid >= 0) { + errno = 0; + gid = strtoll (grname, &errptr, 10); + if ( ('\0' != *grname) + && ('\0' == *endptr) + && (ERANGE != errno) + && (gid == (gid_t)gid)) { return xgetgrgid ((gid_t) gid); } return xgetgrnam (grname); @@ -284,29 +287,15 @@ static long get_number (const char *numstr) char *errptr; val = strtol (numstr, &errptr, 10); - if (('\0' != *errptr) || (ERANGE == errno)) { - fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, - numstr); + if (('\0' == *numstr) || ('\0' != *errptr) || (ERANGE == errno)) { + fprintf (stderr, + _("%s: invalid numeric argument '%s'\n"), + Prog, numstr); exit (E_BAD_ARG); } return val; } -static uid_t get_uid (const char *uidstr) -{ - long val; - char *errptr; - - val = strtol (uidstr, &errptr, 10); - if (('\0' != *errptr) || (ERANGE == errno) || (val < 0)) { - fprintf (stderr, - _("%s: invalid numeric argument '%s'\n"), Prog, - uidstr); - exit (E_BAD_ARG); - } - return (uid_t) val; -} - #define MATCH(x,y) (strncmp((x),(y),strlen(y)) == 0) /* @@ -352,27 +341,14 @@ static void get_defaults (void) * Primary GROUP identifier */ if (MATCH (buf, DGROUP)) { - unsigned int val = (unsigned int) strtoul (cp, &ep, 10); - const struct group *grp; - - if (*cp != '\0' && *ep == '\0') { /* valid number */ - def_group = val; - /* local, no need for xgetgrgid */ - grp = getgrgid (def_group); - if (NULL != grp) { - def_gname = xstrdup (grp->gr_name); - } else { - fprintf (stderr, - _("%s: GID '%s' does not exist\n"), - Prog, cp); - } - /* local, no need for xgetgrnam */ - } else if ((grp = getgrnam (cp)) != NULL) { - def_group = grp->gr_gid; - def_gname = xstrdup (cp); - } else { + const struct group *grp = getgr_nam_gid (cp); + if (NULL == grp) { fprintf (stderr, - _("%s: group '%s' does not exist\n"), Prog, cp); + _("%s: group '%s' does not exist\n"), + Prog, cp); + } else { + def_group = grp->gr_gid; + def_gname = xstrdup (grp->gr_name); } } @@ -396,7 +372,10 @@ static void get_defaults (void) else if (MATCH (buf, INACT)) { long val = strtol (cp, &ep, 10); - if (('\0' != *cp) || (ERANGE == errno)) { + if ( ('\0' != *cp) + && ('\0' == *ep) + && (ERANGE != errno) + && (val >= 0)) { def_inactive = val; } else { def_inactive = -1; @@ -1173,7 +1152,13 @@ static void process_flags (int argc, char **argv) sflg = true; break; case 'u': - user_id = get_uid (optarg); + if ( (get_uid (optarg, &user_id) == 0) + || (user_id == (gid_t)-1)) { + fprintf (stderr, + _("%s: invalid user ID '%s'\n"), + Prog, optarg); + exit (E_BAD_ARG); + } uflg = true; break; case 'U': diff --git a/src/usermod.c b/src/usermod.c index d5bb3ba4..76c3b4f6 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -2,7 +2,7 @@ * Copyright (c) 1991 - 1994, Julianne Frances Haugh * Copyright (c) 1996 - 2000, Marek Michałkiewicz * Copyright (c) 2000 - 2006, Tomasz Kłoczko - * Copyright (c) 2007 - 2008, Nicolas François + * Copyright (c) 2007 - 2009, Nicolas François * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -154,7 +154,6 @@ static void update_gshadow (void); static void grp_update (void); static long get_number (const char *); -static uid_t get_id (const char *); static void process_flags (int, char **); static void close_files (void); static void open_files (void); @@ -193,11 +192,15 @@ static void date_to_str (char *buf, size_t maxsize, */ static struct group *getgr_nam_gid (const char *grname) { - long val; - char *errptr; + long long int val; + char *endptr; - val = strtol (grname, &errptr, 10); - if (*grname != '\0' && *errptr == '\0' && errno != ERANGE && val >= 0) { + errno = 0; + val = strtoll (grname, &errptr, 10); + if ( ('\0' != *grname) + && ('\0' == *endptr) + && (ERANGE != errno) + && (val == (gid_t)val)) { return xgetgrgid ((gid_t) val); } return xgetgrnam (grname); @@ -795,20 +798,6 @@ static long get_number (const char *numstr) return val; } -static uid_t get_id (const char *uidstr) -{ - long val; - char *errptr; - - val = strtol (uidstr, &errptr, 10); - if (('\0' != *errptr) || (ERANGE == errno) || (val < 0)) { - fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, - uidstr); - exit (E_BAD_ARG); - } - return (uid_t) val; -} - /* * process_flags - perform command line argument setting * @@ -1003,7 +992,13 @@ static void process_flags (int argc, char **argv) sflg = true; break; case 'u': - user_newid = get_id (optarg); + if ( (get_uid (optarg, &user_newid) ==0) + || (user_newid == (uid_t)-1)) { + fprintf (stderr, + _("%s: invalid user ID '%s'\n"), + Prog, optarg); + exit (E_BAD_ARG); + } uflg = true; break; case 'U':