]> granicus.if.org Git - shadow/commitdiff
* NEWS: newusers will behave more like useradd.
authornekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Sun, 3 Feb 2008 17:45:58 +0000 (17:45 +0000)
committernekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Sun, 3 Feb 2008 17:45:58 +0000 (17:45 +0000)
* src/newusers.c: The user's ID must be found before the group ID
to mimic useradd's behavior choices of UID and GID.
* src/newusers.c: Reuse the generic find_new_uid() and
find_new_gid() functions. This permits to respect the
UID_MIN/UID_MAX and GID_MIN/GID_MAX variables, should
* src/newusers.c: Check if the user or group exist using the
external databases (with the libc getpwnam/getgrnam functions).
Refuse to update an user which exist in an external database but
does not exist in the local database.
* src/newusers.c: Check the usernames and groupnames with
check_user_name() and check_group_name()
* src/newusers.c: Use isdigit() for readability.
* src/newusers.c: Check if numerical IDs are valid (no remaining
chars).

* NEWS, src/newusers.c: Fix the support for the NONE crypt method.

* src/newusers.c: Fix shadow group support (the list of admins was
not defined; it is now set to an empty list).

ChangeLog
NEWS
src/newusers.c

index a6d24c272ffd66136c30def9ad58a13771c2bee6..d99a732a61488cd6b5e75ecacbb5b549ee235071 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2008-02-03  Nicolas François  <nicolas.francois@centraliens.net>
+
+       * NEWS: newusers will behave more like useradd.
+       * src/newusers.c: The user's ID must be found before the group ID
+       to mimic useradd's behavior choices of UID and GID.
+       * src/newusers.c: Reuse the generic find_new_uid() and
+       find_new_gid() functions. This permits to respect the
+       UID_MIN/UID_MAX and GID_MIN/GID_MAX variables, should 
+       * src/newusers.c: Check if the user or group exist using the
+       external databases (with the libc getpwnam/getgrnam functions).
+       Refuse to update an user which exist in an external database but
+       does not exist in the local database.
+       * src/newusers.c: Check the usernames and groupnames with
+       check_user_name() and check_group_name()
+       * src/newusers.c: Use isdigit() for readability.
+       * src/newusers.c: Check if numerical IDs are valid (no remaining
+       chars).
+
+2008-02-03  Nicolas François  <nicolas.francois@centraliens.net>
+
+       * NEWS, src/newusers.c: Fix the support for the NONE crypt method.
+
+2008-02-03  Nicolas François  <nicolas.francois@centraliens.net>
+
+       * src/newusers.c: Fix shadow group support (the list of admins was
+       not defined; it is now set to an empty list).
+
 2008-02-03  Nicolas François  <nicolas.francois@centraliens.net>
 
        * NEWS, libmisc/salt.c: Do not seed the random number generator
diff --git a/NEWS b/NEWS
index 73b9d87c5be35b7736f28078601e2ba709dc5086..93887c13ce978447f117a42d39b67d64ccbc7322 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,9 @@ shadow-4.1.0 -> shadow-4.1.1                                          UNRELEASED
     because the membership is already set by their primary group.
   * Added support for gshadow.
   * Avoid using the same salt for different passwords.
+  * Fix support for the NONE crypt method.
+  * newusers will behave more like useradd regarding the choice of UID or
+    GID or regarding the validity of user and group names.
 - passwd
   * Make sure that no more than one username argument was provided.
 - pwck
index 615e2ff27bac5aa658d344d2454597f179aebcdd..07de99c5abe33ad0dabeeeaf288c6cd48c183872 100644 (file)
@@ -44,6 +44,7 @@
 #include <grp.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <ctype.h>
 #ifdef USE_PAM
 #include "pam_defs.h"
 #endif                         /* USE_PAM */
@@ -55,6 +56,7 @@
 #include "pwio.h"
 #include "sgroupio.h"
 #include "shadowio.h"
+#include "chkname.h"
 /*
  * Global variables
  */
@@ -76,8 +78,9 @@ static pam_handle_t *pamh = NULL;
 
 /* local function prototypes */
 static void usage (void);
-static int add_group (const char *, const char *, gid_t *);
-static int add_user (const char *, const char *, uid_t *, gid_t);
+static int add_group (const char *, const char *, gid_t *, gid_t);
+static int get_uid (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 *);
 static void process_flags (int argc, char **argv);
@@ -111,13 +114,11 @@ static void usage (void)
 /*
  * 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)
+static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid)
 {
-       const struct passwd *pwd;
        const struct group *grp;
        struct group grent;
        char *members[1];
-       int i;
 #ifdef SHADOWGRP
        const struct sgrp *sg;
 #endif
@@ -126,7 +127,10 @@ static int add_group (const char *name, const char *gid, gid_t * ngid)
         * Start by seeing if the named group already exists. This will be
         * very easy to deal with if it does.
         */
-       grp = gr_locate (gid);
+       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;
@@ -134,72 +138,56 @@ static int add_group (const char *name, const char *gid, gid_t * ngid)
                return 0;
        }
 
-       /*
-        * The group did not exist, so I try to figure out what the GID is
-        * going to be. The gid parameter is probably "", meaning I figure
-        * out the GID from the password file. I want the UID and GID to
-        * match, unless the GID is already used.
-        */
-       if (gid[0] == '\0') {
-               i = 100;
-               for (pw_rewind (); (pwd = pw_next ());) {
-                       if (pwd->pw_uid >= (unsigned int)i) {
-                               i = pwd->pw_uid + 1;
-                       }
-               }
-               for (gr_rewind (); (grp = gr_next ());) {
-                       if (grp->gr_gid == (unsigned int)i) {
-                               i = -1;
-                               break;
-                       }
-               }
-       } else if ((gid[0] >= '0') && (gid[0] <= '9')) {
+       if (isdigit (gid[0])) {
                /*
                 * The GID is a number, which means either this is a brand
                 * new group, or an existing group.
                 */
-               i = atoi (gid);
-               for (gr_rewind (); (grp = gr_next ());) {
-                       if (grp->gr_gid == (unsigned int)i) {
-                               /* The user will use this ID for her
-                                * primary group */
-                               *ngid = grp->gr_gid;
-                               /* Don't check gshadow */
-                               return 0;
-                       }
+               char *endptr;
+               long int i = strtoul (gid, &endptr, 10);
+               if ((*endptr != '\0') && (errno != ERANGE)) {
+                       fprintf (stderr,
+                                _("%s: group ID `%s' is not valid\n"),
+                                Prog, gid);
+                       return -1;
+               }
+               if (   (getgrgid (i) != NULL)
+                   || (gr_locate_gid (i) != NULL)) {
+                       /* The user will use this ID for her
+                        * primary group */
+                       *ngid = i;
+                       return 0;
                }
+               grent.gr_gid = i;
        } else {
-               /*
-                * The last alternative is that the GID is a name which is
-                * not already the name of an existing group, and I need to
-                * figure out what group ID that group name is going to
-                * have.
+               /* 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.
                 */
-               i = -1;
-       }
-
-       /*
-        * If I don't have a group ID by now, I'll go get the next one.
-        */
-       if (i == -1) {
-               for (i = 100, gr_rewind (); (grp = gr_next ());) {
-                       if (grp->gr_gid >= (unsigned int)i) {
-                               i = grp->gr_gid + 1;
-                       }
+               if (find_new_gid(0, &grent.gr_gid, &uid) < 0) {
+                       return -1;
                }
        }
 
        /*
         * Now I have all of the fields required to create the new group.
         */
-       if (('\0' != gid[0]) && ((gid[0] <= '0') || (gid[0] >= '9'))) {
+       if (('\0' != gid[0]) && (!isdigit (gid[0]))) {
                grent.gr_name = xstrdup (gid);
        } else {
                grent.gr_name = xstrdup (name);
        }
 
+       /* Check if this is a valid group name */
+       if (check_group_name (grent.gr_name) == 0) {
+               fprintf (stderr,
+                        _("%s: invalid group name `%s'\n"),
+                        Prog, grent.gr_name);
+               free (grent.gr_name);
+               return -1;
+       }
+
        grent.gr_passwd = "x";  /* XXX warning: const */
-       grent.gr_gid = i;
        members[0] = NULL;
        grent.gr_mem = members;
 
@@ -207,12 +195,12 @@ static int add_group (const char *name, const char *gid, gid_t * ngid)
 
 #ifdef SHADOWGRP
        if (is_shadow_grp) {
-               sg = sgr_locate (grp->gr_name);
+               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, grp->gr_name);
+                                Prog, grent.gr_name);
                        return -1;
                }
        }
@@ -225,9 +213,11 @@ static int add_group (const char *name, const char *gid, gid_t * ngid)
 #ifdef SHADOWGRP
        if (is_shadow_grp) {
                struct sgrp sgrent;
+               char *admins[1];
                sgrent.sg_name = grent.gr_name;
                sgrent.sg_passwd = "*"; /* XXX warning: const */
-               sgrent.sg_adm = NULL;
+               admins[0] = NULL;
+               sgrent.sg_adm = admins;
                sgrent.sg_mem = members;
 
                if (sgr_update (&sgrent) == 0) {
@@ -242,54 +232,77 @@ static int add_group (const char *name, const char *gid, gid_t * ngid)
        return 0;
 }
 
-/*
- * add_user - create a new user ID
- */
-static int add_user (const char *name, const char *uid, uid_t * nuid, gid_t gid)
-{
+static int get_uid (const char *uid, uid_t *nuid) {
        const struct passwd *pwd = NULL;
-       struct passwd pwent;
-       uid_t i;
 
        /*
         * The first guess for the UID is either the numerical UID that the
         * caller provided, or the next available UID.
         */
-       if ((uid[0] >= '0') && (uid[0] <= '9')) {
-               i = atoi (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"),
+                                Prog, uid);
+                       return -1;
+               }
+               *nuid = i;
        } else {
                if ('\0' != uid[0]) {
-                       pwd = pw_locate (uid);
-               }
+                       /* local, no need for xgetpwnam */
+                       pwd = getpwnam (uid);
+                       if (NULL == pwd) {
+                               pwd = pw_locate (uid);
+                       }
 
-               if (NULL != pwd) {
-                       i = pwd->pw_uid;
+                       if (NULL != pwd) {
+                               *nuid = pwd->pw_uid;
+                       } else {
+                               fprintf (stderr,
+                                        _("%s: user `%s' does not exist\n"),
+                                        Prog, uid);
+                               return -1;
+                       }
                } else {
-                       /* Start with gid, either the specified GID, or an ID
-                        * greater than all the group and user IDs */
-                       i = gid;
-                       for (pw_rewind (); (pwd = pw_next ());) {
-                               if (pwd->pw_uid >= i) {
-                                       i = pwd->pw_uid + 1;
-                               }
+                       if (find_new_uid (0, nuid, NULL) < 0) {
+                               return -1;
                        }
                }
        }
 
+       return 0;
+}
+
+/*
+ * add_user - create a new user ID
+ */
+static int add_user (const char *name, uid_t uid, gid_t gid)
+{
+       struct passwd pwent;
+
+       /* Check if this is a valid user name */
+       if (check_user_name (name) == 0) {
+               fprintf (stderr,
+                        _("%s: invalid user name `%s'\n"),
+                        Prog, name);
+               return -1;
+       }
+
        /*
         * I don't want to fill in the entire password structure members
         * JUST YET, since there is still more data to be added. So, I fill
         * in the parts that I have.
         */
        pwent.pw_name = xstrdup (name);
+       pwent.pw_uid = uid;
        pwent.pw_passwd = "x";  /* XXX warning: const */
-       pwent.pw_uid = i;
        pwent.pw_gid = gid;
        pwent.pw_gecos = "";    /* XXX warning: const */
        pwent.pw_dir = "";      /* XXX warning: const */
        pwent.pw_shell = "";    /* XXX warning: const */
 
-       *nuid = i;
        return !pw_update (&pwent);
 }
 
@@ -342,9 +355,14 @@ static int add_passwd (struct passwd *pwd, const char *password)
        sp = spw_locate (pwd->pw_name);
        if (NULL != sp) {
                spent = *sp;
-               spent.sp_pwdp = pw_encrypt (password,
-                                           crypt_make_salt (crypt_method,
-                                                            crypt_arg));
+               if (   (crypt_method != NULL)
+                   && (0 == strcmp(crypt_method, "NONE"))) {
+                       spent.sp_pwdp = (char *)password;
+               } else {
+                       const char *salt = crypt_make_salt (crypt_method,
+                                                           crypt_arg);
+                       spent.sp_pwdp = pw_encrypt (password, salt);
+               }
                return !spw_update (&spent);
        }
 
@@ -364,8 +382,12 @@ static int add_passwd (struct passwd *pwd, const char *password)
         * shadow password file entry.
         */
        spent.sp_namp = pwd->pw_name;
-       spent.sp_pwdp = pw_encrypt (password,
-                                   crypt_make_salt (crypt_method, crypt_arg));
+       if ((crypt_method != NULL) && (0 == strcmp(crypt_method, "NONE"))) {
+               pwd->pw_passwd = (char *)password;
+       } else {
+               const char *salt = crypt_make_salt (crypt_method, crypt_arg);
+               spent.sp_pwdp = pw_encrypt (password, salt);
+       }
        spent.sp_lstchg = time ((time_t *) 0) / SCALE;
        spent.sp_min = getdef_num ("PASS_MIN_DAYS", 0);
        /* 10000 is infinity this week */
@@ -684,8 +706,28 @@ int main (int argc, char **argv)
                }
 
                /*
-                * Now the fields are processed one by one. The first field
-                * to be processed is the group name. A new group will be
+                * First check if we have to create of update an user
+                */
+               pw = pw_locate (fields[0]);
+               /* local, no need for xgetpwnam */
+               if (   (NULL == pw)
+                   && (getpwnam (fields[0]) != NULL)) {
+                       fprintf (stderr, _("%s: cannot update the entry of user %s (not in the passwd database)\n"), Prog, fields[0]);
+                       errors++;
+                       continue;
+               }
+
+               if (   (NULL == pw)
+                   && (get_uid (fields[2], &uid) != 0)) {
+                       fprintf (stderr,
+                                _("%s: line %d: can't create user\n"),
+                                Prog, line);
+                       errors++;
+                       continue;
+               }
+
+               /*
+                * Processed is the group name. A new group will be
                 * created if the group name is non-numeric and does not
                 * already exist. If the group name is a number (which is not
                 * an existing GID), a group with the same name as the user
@@ -696,11 +738,10 @@ int main (int argc, char **argv)
                 * new group, if that group ID exists, a whole new group ID
                 * will be made up.
                 */
-               pw = pw_locate (fields[0]);
                if (   (NULL == pw)
-                   && (add_group (fields[0], fields[3], &gid) != 0)) {
+                   && (add_group (fields[0], fields[3], &gid, uid) != 0)) {
                        fprintf (stderr,
-                                _("%s: line %d: can't create GID\n"),
+                                _("%s: line %d: can't create group\n"),
                                 Prog, line);
                        errors++;
                        continue;
@@ -714,9 +755,9 @@ int main (int argc, char **argv)
                 * will at least be a (struct passwd) for the user.
                 */
                if (   (NULL == pw)
-                   && (add_user (fields[0], fields[2], &uid, gid) != 0)) {
+                   && (add_user (fields[0], uid, gid) != 0)) {
                        fprintf (stderr,
-                                _("%s: line %d: can't create UID\n"),
+                                _("%s: line %d: can't create user\n"),
                                 Prog, line);
                        errors++;
                        continue;