diff -up /dev/null shadow-4.1.2/lib/get_gid.c --- /dev/null 2009-03-16 11:03:38.574001227 +0100 +++ shadow-4.1.2/lib/get_gid.c 2009-03-23 18:45:59.000000000 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009 , Nicolas François + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. 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 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 + +#ident "$Id$" + +#include "prototypes.h" +#include "defines.h" + +int get_gid (const char *gidstr, gid_t *gid) +{ + long long int val; + char *endptr; + + errno = 0; + val = strtoll (gidstr, &endptr, 10); + if ( ('\0' == gidstr) + || ('\0' != *endptr) + || (ERANGE == errno) + || (val != (gid_t)val)) { + return 0; + } + + *gid = (gid_t)val; + return 1; +} + diff -up /dev/null shadow-4.1.2/lib/get_uid.c --- /dev/null 2009-03-16 11:03:38.574001227 +0100 +++ shadow-4.1.2/lib/get_uid.c 2009-03-23 18:45:59.000000000 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009 , Nicolas François + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. 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 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 + +#ident "$Id$" + +#include "prototypes.h" +#include "defines.h" + +int get_uid (const char *uidstr, uid_t *uid) +{ + long long int val; + char *endptr; + + errno = 0; + val = strtoll (uidstr, &endptr, 10); + if ( ('\0' == uidstr) + || ('\0' != *endptr) + || (ERANGE == errno) + || (val != (uid_t)val)) { + return 0; + } + + *uid = (uid_t)val; + return 1; +} + + diff -up shadow-4.1.2/lib/Makefile.am.uid shadow-4.1.2/lib/Makefile.am --- shadow-4.1.2/lib/Makefile.am.uid 2008-01-06 14:57:28.000000000 +0100 +++ shadow-4.1.2/lib/Makefile.am 2009-03-23 18:45:59.000000000 +0100 @@ -17,6 +17,8 @@ libshadow_la_SOURCES = \ fputsx.c \ getdef.c \ getdef.h \ + get_gid.c \ + get_uid.c \ groupio.c \ groupmem.c \ groupio.h \ diff -up shadow-4.1.2/lib/prototypes.h.uid shadow-4.1.2/lib/prototypes.h --- shadow-4.1.2/lib/prototypes.h.uid 2009-03-23 18:45:59.000000000 +0100 +++ shadow-4.1.2/lib/prototypes.h 2009-03-23 18:45:59.000000000 +0100 @@ -110,6 +110,12 @@ extern int find_new_gid (int sys_group, /* getlong.c */ extern int getlong(const char *numstr, long int *result); +/* get_gid.c */ +extern int get_gid (const char *gidstr, gid_t *gid); + +/* get_uid.c */ +extern int get_uid (const char *uidstr, uid_t *uid); + /* fputsx.c */ extern char *fgetsx (char *, int, FILE *); extern int fputsx (const char *, FILE *); diff -up shadow-4.1.2/src/groupadd.c.uid shadow-4.1.2/src/groupadd.c --- shadow-4.1.2/src/groupadd.c.uid 2009-03-23 18:45:59.000000000 +0100 +++ shadow-4.1.2/src/groupadd.c 2009-03-23 18:45:59.000000000 +0100 @@ -98,7 +98,6 @@ static void check_new_name (void); static void close_files (void); static void open_files (void); static void fail_exit (int code); -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); @@ -326,22 +325,6 @@ static void fail_exit (int code) exit (code); } -/* - * 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 val; -} /* * process_flags - parse the command line options @@ -383,7 +366,13 @@ static void process_flags (int argc, cha break; case 'g': gflg++; - 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 -up shadow-4.1.2/src/groupmod.c.uid shadow-4.1.2/src/groupmod.c --- shadow-4.1.2/src/groupmod.c.uid 2008-04-27 02:40:13.000000000 +0200 +++ shadow-4.1.2/src/groupmod.c 2009-03-23 18:45:59.000000000 +0100 @@ -100,7 +100,6 @@ static void check_new_name (void); static void process_flags (int, char **); static void close_files (void); static void open_files (void); -static gid_t get_gid (const char *gidstr); static void update_primary_groups (gid_t ogid, gid_t ngid); /* @@ -361,23 +360,6 @@ static void check_new_name (void) } /* - * 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 (*errptr || errno == ERANGE || val < 0) { - fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, - gidstr); - fail_exit (E_BAD_ARG); - } - return val; -} - -/* * process_flags - perform command line argument setting * * process_flags() interprets the command line arguments and sets the @@ -404,7 +386,13 @@ static void process_flags (int argc, cha switch (c) { case 'g': gflg++; - 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); + } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modifying group", diff -up shadow-4.1.2/src/newusers.c.uid shadow-4.1.2/src/newusers.c --- shadow-4.1.2/src/newusers.c.uid 2008-04-27 02:40:13.000000000 +0200 +++ shadow-4.1.2/src/newusers.c 2009-03-23 18:45:59.000000000 +0100 @@ -90,7 +90,7 @@ static pam_handle_t *pamh = NULL; 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 *); @@ -178,22 +178,26 @@ static int add_group (const char *name, * The GID is a number, which means either this is a brand * new group, or an existing group. */ - char *endptr; - long int i = strtoul (gid, &endptr, 10); - if ((*endptr != '\0') && (errno != ERANGE)) { + 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; } - if ( (getgrgid (i) != NULL) - || (gr_locate_gid (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 = i; + *ngid = (gid_t) grent.gr_gid; return 0; } - grent.gr_gid = 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. @@ -267,7 +271,7 @@ static int add_group (const char *name, return 0; } -static int get_uid (const char *uid, uid_t *nuid) { +static int get_user_id (const char *uid, uid_t *nuid) { const struct passwd *pwd = NULL; /* @@ -275,15 +279,11 @@ static int get_uid (const char *uid, uid * caller provided, or the next available UID. */ if (isdigit (uid[0])) { - char *endptr; - long int i = strtoul (uid, &endptr, 10); - if ((*endptr != '\0') && (errno != ERANGE)) { - fprintf (stderr, - _("%s: user ID `%s' is not valid\n"), + if ((get_uid (uid, nuid) == 0) || (*nuid == (uid_t)-1)) { + fprintf (stderr, _("%s: invalid user ID '%s'\n"), Prog, uid); return -1; } - *nuid = i; } else { if ('\0' != uid[0]) { /* local, no need for xgetpwnam */ @@ -740,7 +740,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 -up shadow-4.1.2/src/useradd.c.uid shadow-4.1.2/src/useradd.c --- shadow-4.1.2/src/useradd.c.uid 2009-03-23 18:45:59.000000000 +0100 +++ shadow-4.1.2/src/useradd.c 2009-03-23 18:45:59.000000000 +0100 @@ -170,7 +170,6 @@ static int home_added; 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); @@ -225,39 +224,30 @@ static void fail_exit (int code) static struct group *getgr_nam_gid (const char *grname) { - long gid; - char *errptr; - - gid = strtol (grname, &errptr, 10); - if (*grname != '\0' && *errptr == '\0' && errno != ERANGE && gid >= 0) + long long int gid; + char *endptr; + + errno = 0; + gid = strtoll (grname, &endptr, 10); + if ( ('\0' != *grname) + && ('\0' == *endptr) + && (ERANGE != errno) + && (gid == (gid_t)gid)) { return xgetgrgid (gid); + } return xgetgrnam (grname); } static long get_number (const char *numstr) { long val; - char *errptr; + char *endptr; - val = strtol (numstr, &errptr, 10); - if (*errptr || errno == ERANGE) { - 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 (*errptr || errno == ERANGE || val < 0) { - fprintf (stderr, - _("%s: invalid numeric argument '%s'\n"), Prog, - uidstr); + errno = 0; + val = strtol (numstr, &endptr, 10); + if (('\0' == *numstr) || ('\0' != *endptr) || (ERANGE == errno)) { + fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), + Prog, numstr); exit (E_BAD_ARG); } return val; @@ -302,26 +292,13 @@ 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 */ - if ((grp = getgrgid (def_group))) { - def_gname = xstrdup (grp->gr_name); - } else { - fprintf (stderr, - _("%s: unknown GID %s\n"), - Prog, cp); - } - /* local, no need for xgetgrnam */ - } else if ((grp = getgrnam (cp))) { - def_group = grp->gr_gid; - def_gname = xstrdup (cp); + const struct group *grp = getgr_nam_gid (cp); + if (NULL == grp) { + fprintf (stderr, _("%s: unknown GID %s\n"), + Prog, cp); } else { - fprintf (stderr, - _("%s: unknown group %s\n"), Prog, cp); + def_group = grp->gr_gid; + def_gname = xstrdup (grp->gr_name); } } @@ -343,12 +320,17 @@ static void get_defaults (void) * Default Password Inactive value */ else if (MATCH (buf, INACT)) { + errno = 0; long val = strtol (cp, &ep, 10); - if (*cp || errno == ERANGE) + if ( ('\0' != *cp) + && ('\0' == *ep) + && (ERANGE != errno) + && (val >= 0)) { def_inactive = val; - else + } else { def_inactive = -1; + } } /* @@ -1080,7 +1062,13 @@ static void process_flags (int argc, cha sflg++; 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++; break; case 'U': diff -up shadow-4.1.2/src/usermod.c.uid shadow-4.1.2/src/usermod.c --- shadow-4.1.2/src/usermod.c.uid 2009-03-23 18:45:59.000000000 +0100 +++ shadow-4.1.2/src/usermod.c 2009-03-23 18:48:36.000000000 +0100 @@ -155,7 +155,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,12 +192,17 @@ static void date_to_str (char *buf, size */ static struct group *getgr_nam_gid (const char *grname) { - long val; - char *errptr; - - val = strtol (grname, &errptr, 10); - if (*grname != '\0' && *errptr == '\0' && errno != ERANGE && val >= 0) + long long int val; + char *endptr; + + errno = 0; + val = strtoll (grname, &endptr, 10); + if ( ('\0' != *grname) + && ('\0' == *endptr) + && (ERANGE != errno) + && (val == (gid_t)val)) { return xgetgrgid (val); + } return xgetgrnam (grname); } @@ -752,20 +756,6 @@ static long get_number (const char *nums return val; } -static uid_t get_id (const char *uidstr) -{ - long val; - char *errptr; - - val = strtol (uidstr, &errptr, 10); - if (*errptr || errno == ERANGE || val < 0) { - fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, - uidstr); - exit (E_BAD_ARG); - } - return val; -} - /* * process_flags - perform command line argument setting * @@ -963,7 +953,13 @@ static void process_flags (int argc, cha sflg++; 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++; break; case 'U':