]> granicus.if.org Git - shadow/commitdiff
* lib/commonio.c: Avoid PATH_MAX. On glibc, we can use realpath
authornekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Sun, 10 May 2009 13:49:03 +0000 (13:49 +0000)
committernekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Sun, 10 May 2009 13:49:03 +0000 (13:49 +0000)
with a NULL argument.
* src/useradd.c: Replace PATH_MAX by a fixed constant. The buffer
was not meant as a storage for a path.
* src/useradd.c, src/newusers.c, src/chpasswd.c: Better detection
of fgets errors. Lines shall end with a \n, unless we reached the
end of file.
* libmisc/copydir.c: Avoid PATH_MAX. Support file paths with any
length. Added readlink_malloc().

ChangeLog
lib/commonio.c
libmisc/copydir.c
src/chpasswd.c
src/newusers.c
src/useradd.c

index afae0aac53e5ceea16db419e7ee3f1ab36124ff4..4d06858889852c60c7d5169abebf3b9cb719f298 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2009-05-10  Nicolas François  <nicolas.francois@centraliens.net>
+
+       * lib/commonio.c: Avoid PATH_MAX. On glibc, we can use realpath
+       with a NULL argument.
+       * src/useradd.c: Replace PATH_MAX by a fixed constant. The buffer
+       was not meant as a storage for a path.
+       * src/useradd.c, src/newusers.c, src/chpasswd.c: Better detection
+       of fgets errors. Lines shall end with a \n, unless we reached the
+       end of file.
+       * libmisc/copydir.c: Avoid PATH_MAX. Support file paths with any
+       length. Added readlink_malloc().
+
 2009-05-09  Nicolas François  <nicolas.francois@centraliens.net>
 
        * src/pwck.c: Warn if an user has an entry in passwd and shadow,
index c2394310927dd4ea8914aeadf590bfe71b25cbff..6bad6622a6c4491b9a2a47890ebc94850c1ad6b2 100644 (file)
@@ -83,21 +83,36 @@ static bool nscd_need_reload = false;
  */
 int lrename (const char *old, const char *new)
 {
-
-       char resolved_path[PATH_MAX];
        int res;
+       char *r = NULL;
 
 #if defined(S_ISLNK)
+#ifndef __GLIBC__
+       char resolved_path[PATH_MAX];
+#endif                         /* !__GLIBC__ */
        struct stat sb;
        if (lstat (new, &sb) == 0 && S_ISLNK (sb.st_mode)) {
-               if (realpath (new, resolved_path) == NULL) {
+#ifdef __GLIBC__ /* now a POSIX.1-2008 feature */
+               r = realpath (new, NULL);
+#else                          /* !__GLIBC__ */
+               r = realpath (new, resolved_path);
+#endif                         /* !__GLIBC__ */
+               if (NULL == r) {
                        perror ("realpath in lrename()");
                } else {
-                       new = resolved_path;
+                       new = r;
                }
        }
-#endif
+#endif                         /* S_ISLNK */
+
        res = rename (old, new);
+
+#ifdef __GLIBC__
+       if (NULL != r) {
+               free (r);
+       }
+#endif                         /* __GLIBC__ */
+
        return res;
 }
 
index df8ae74ec6f68c2372a2d8782c99cf4484470f38..c061e057c39e48334ffffd99653f7cd479a305b6 100644 (file)
@@ -199,8 +199,6 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
 int copy_tree (const char *src_root, const char *dst_root,
                long int uid, long int gid)
 {
-       char src_name[PATH_MAX];
-       char dst_name[PATH_MAX];
        int err = 0;
        bool set_orig = false;
        struct DIRECT *ent;
@@ -240,27 +238,36 @@ int copy_tree (const char *src_root, const char *dst_root,
                 */
                if ((strcmp (ent->d_name, ".") != 0) &&
                    (strcmp (ent->d_name, "..") != 0)) {
-                       /*
-                        * Make sure the resulting source and destination
-                        * filenames will fit in their buffers.
-                        */
-                       if (   (strlen (src_root) + strlen (ent->d_name) + 2 >
-                               sizeof src_name)
-                           || (strlen (dst_root) + strlen (ent->d_name) + 2 >
-                               sizeof dst_name)) {
+                       char *src_name;
+                       char *dst_name;
+                       size_t src_len = strlen (ent->d_name) + 2;
+                       size_t dst_len = strlen (ent->d_name) + 2;
+                       src_len += strlen (src_root);
+                       dst_len += strlen (dst_root);
+
+                       src_name = (char *) malloc (src_len);
+                       dst_name = (char *) malloc (dst_len);
+
+                       if ((NULL == src_name) || (NULL == dst_name)) {
                                err = -1;
                        } else {
                                /*
                                 * Build the filename for both the source and
                                 * the destination files.
                                 */
-                               snprintf (src_name, sizeof src_name, "%s/%s",
+                               snprintf (src_name, src_len, "%s/%s",
                                          src_root, ent->d_name);
-                               snprintf (dst_name, sizeof dst_name, "%s/%s",
+                               snprintf (dst_name, dst_len, "%s/%s",
                                          dst_root, ent->d_name);
 
                                err = copy_entry (src_name, dst_name, uid, gid);
                        }
+                       if (NULL != src_name) {
+                               free (src_name);
+                       }
+                       if (NULL != dst_name) {
+                               free (dst_name);
+                       }
                }
        }
        (void) closedir (dir);
@@ -415,6 +422,41 @@ static int copy_dir (const char *src, const char *dst,
 }
 
 #ifdef S_IFLNK
+/*
+ * readlink_malloc - wrapper for readlink
+ *
+ * return NULL on error.
+ * The return string shall be freed by the caller.
+ */
+char *readlink_malloc (const char *filename)
+{
+       size_t size = 1024;
+
+       while (1) {
+               ssize_t nchars;
+               char *buffer = (char *) malloc (size);
+               if (NULL == buffer) {
+                       return NULL;
+               }
+
+               nchars = readlink (filename, buffer, size);
+
+               if (nchars < 0) {
+                       return NULL;
+               }
+
+               if ( (size_t) nchars < size) { /* The buffer was large enough */
+                       /* readlink does not nul-terminate */
+                       buffer[nchars] = '\0';
+                       return buffer;
+               }
+
+               /* Try again with a bigger buffer */
+               free (buffer);
+               size *= 2;
+       }
+}
+
 /*
  * copy_symlink - copy a symlink
  *
@@ -429,10 +471,7 @@ static int copy_symlink (const char *src, const char *dst,
                          const struct stat *statp, const struct timeval mt[],
                          long int uid, long int gid)
 {
-       char oldlink[PATH_MAX];
-       char dummy[PATH_MAX];
-       int len;
-       int err = 0;
+       char *oldlink;
 
        /* copy_tree () must be the entry point */
        assert (NULL != src_orig);
@@ -446,17 +485,25 @@ static int copy_symlink (const char *src, const char *dst,
         * destination directory name.
         */
 
-       len = readlink (src, oldlink, sizeof (oldlink) - 1);
-       if (len < 0) {
+       oldlink = readlink_malloc (src);
+       if (NULL == oldlink) {
                return -1;
        }
-       oldlink[len] = '\0';    /* readlink() does not NUL-terminate */
+
+       /* If src was a link to an entry of the src_orig directory itself,
+        * create a link to the corresponding entry in the dst_orig
+        * directory.
+        */
        if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
-               snprintf (dummy, sizeof dummy, "%s%s",
+               size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
+               char *dummy = (char *) malloc (len);
+               snprintf (dummy, len, "%s%s",
                          dst_orig,
                          oldlink + strlen (src_orig));
-               strcpy (oldlink, dummy);
+               free (oldlink);
+               oldlink = dummy;
        }
+
 #ifdef WITH_SELINUX
        selinux_file_context (dst);
 #endif
@@ -464,8 +511,10 @@ static int copy_symlink (const char *src, const char *dst,
            || (lchown (dst,
                        (uid == -1) ? statp->st_uid : (uid_t) uid,
                        (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
+               free (oldlink);
                return -1;
        }
+       free (oldlink);
 
 #ifdef HAVE_LUTIMES
        /* 2007-10-18: We don't care about
@@ -476,7 +525,7 @@ static int copy_symlink (const char *src, const char *dst,
        lutimes (dst, mt);
 #endif
 
-       return err;
+       return 0;
 }
 #endif
 
@@ -618,7 +667,7 @@ static int copy_file (const char *src, const char *dst,
 
 int remove_tree (const char *root)
 {
-       char new_name[PATH_MAX];
+       char *new_name = NULL;
        int err = 0;
        struct DIRECT *ent;
        struct stat sb;
@@ -645,6 +694,7 @@ int remove_tree (const char *root)
        }
 
        while ((ent = readdir (dir))) {
+               size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
 
                /*
                 * Skip the "." and ".." entries
@@ -659,12 +709,15 @@ int remove_tree (const char *root)
                 * Make the filename for the current entry.
                 */
 
-               if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
+               if (NULL != new_name) {
+                       free (new_name);
+               }
+               new_name = (char *) malloc (new_len);
+               if (NULL == new_name) {
                        err = -1;
                        break;
                }
-               snprintf (new_name, sizeof new_name, "%s/%s", root,
-                         ent->d_name);
+               snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
                if (LSTAT (new_name, &sb) == -1) {
                        continue;
                }
@@ -687,6 +740,9 @@ int remove_tree (const char *root)
                        }
                }
        }
+       if (NULL != new_name) {
+               free (new_name);
+       }
        (void) closedir (dir);
 
        if (0 == err) {
index 0c896ee7f88f42f2c741fb75cab68b448580f272..e4334ae7db7c7887e5d48275c389cd3e1ad8d8a5 100644 (file)
@@ -434,11 +434,13 @@ int main (int argc, char **argv)
                if (NULL != cp) {
                        *cp = '\0';
                } else {
-                       fprintf (stderr,
-                                _("%s: line %d: line too long\n"),
-                                Prog, line);
-                       errors++;
-                       continue;
+                       if (feof (stdin) == 0) {
+                               fprintf (stderr,
+                                        _("%s: line %d: line too long\n"),
+                                        Prog, line);
+                               errors++;
+                               continue;
+                       }
                }
 
                /*
index cedb8e42bfb154534dc28942a9983c4d5e02c524..9da38de0011a961c59ae61aa5024de4016d70435 100644 (file)
@@ -863,10 +863,13 @@ int main (int argc, char **argv)
                if (NULL != cp) {
                        *cp = '\0';
                } else {
-                       fprintf (stderr, _("%s: line %d: line too long\n"),
-                                Prog, line);
-                       errors++;
-                       continue;
+                       if (feof (stdin) == 0) {
+                               fprintf (stderr,
+                                        _("%s: line %d: line too long\n"),
+                                        Prog, line);
+                               errors++;
+                               continue;
+                       }
                }
 
                /*
index 04dc5477724a4165e3c9c75f74e39dc1de236ade..9bc81b38511a8822dc321ae7417329614a3cd790 100644 (file)
@@ -421,7 +421,7 @@ static int set_defaults (void)
 {
        FILE *ifp;
        FILE *ofp;
-       char buf[PATH_MAX];
+       char buf[1024];
        static char new_file[] = NEW_USER_FILE;
        char *cp;
        int ofd;
@@ -468,6 +468,16 @@ static int set_defaults (void)
                cp = strrchr (buf, '\n');
                if (NULL != cp) {
                        *cp = '\0';
+               } else {
+                       /* A line which does not end with \n is only valid
+                        * at the end of the file.
+                        */
+                       if (feof (ifp) == 0) {
+                               fprintf (stderr,
+                                        _("%s: line too long in %s: %s..."),
+                                        Prog, def_file, buf);
+                               return -1;
+                       }
                }
 
                if (!out_group && MATCH (buf, DGROUP)) {