]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/canonical: use realpath() from libc
authorKarel Zak <kzak@redhat.com>
Mon, 1 Jul 2013 14:13:46 +0000 (16:13 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 1 Jul 2013 14:13:46 +0000 (16:13 +0200)
.. after many many years it seems that we can follow libc code rather
than duplicate realpath(3) implementation.

Signed-off-by: Karel Zak <kzak@redhat.com>
lib/canonicalize.c

index 548e29b75e30f10f76196d8f0edc1e7f7bea3ffc..cac60d7a4b6d457b56e5c46a6ee280e09f11702f 100644 (file)
@@ -1,24 +1,10 @@
 /*
  * canonicalize.c -- canonicalize pathname by removing symlinks
- * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library Public License for more details.
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
  *
- */
-
-/*
- * This routine is part of libc.  We include it nevertheless,
- * since the libc version has some security flaws.
- *
- * TODO: use canonicalize_file_name() when exist in glibc
+ * Copyright (C) 2009-2013 Karel Zak <kzak@redhat.com>
  */
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include "canonicalize.h"
 
-#ifndef MAXSYMLINKS
-# define MAXSYMLINKS 256
-#endif
-
-static char *
-myrealpath(const char *path, char *resolved_path, int maxreslth) {
-       int readlinks = 0;
-       char *npath;
-       char link_path[PATH_MAX+1];
-       int n;
-       char *buf = NULL;
-
-       npath = resolved_path;
-
-       /* If it's a relative pathname use getcwd for starters. */
-       if (*path != '/') {
-               if (!getcwd(npath, maxreslth-2))
-                       return NULL;
-               npath += strlen(npath);
-               if (npath[-1] != '/')
-                       *npath++ = '/';
-       } else {
-               *npath++ = '/';
-               path++;
-       }
-
-       /* Expand each slash-separated pathname component. */
-       while (*path != '\0') {
-               /* Ignore stray "/" */
-               if (*path == '/') {
-                       path++;
-                       continue;
-               }
-               if (*path == '.' && (path[1] == '\0' || path[1] == '/')) {
-                       /* Ignore "." */
-                       path++;
-                       continue;
-               }
-               if (*path == '.' && path[1] == '.' &&
-                   (path[2] == '\0' || path[2] == '/')) {
-                       /* Backup for ".." */
-                       path += 2;
-                       while (npath > resolved_path+1 &&
-                              (--npath)[-1] != '/')
-                               ;
-                       continue;
-               }
-               /* Safely copy the next pathname component. */
-               while (*path != '\0' && *path != '/') {
-                       if (npath-resolved_path > maxreslth-2) {
-                               errno = ENAMETOOLONG;
-                               goto err;
-                       }
-                       *npath++ = *path++;
-               }
-
-               /* Protect against infinite loops. */
-               if (readlinks++ > MAXSYMLINKS) {
-                       errno = ELOOP;
-                       goto err;
-               }
-
-               /* See if last pathname component is a symlink. */
-               *npath = '\0';
-               n = readlink(resolved_path, link_path, PATH_MAX);
-               if (n < 0) {
-                       /* EINVAL means the file exists but isn't a symlink. */
-                       if (errno != EINVAL)
-                               goto err;
-               } else {
-                       int m;
-                       char *newbuf;
-
-                       /* Note: readlink doesn't add the null byte. */
-                       link_path[n] = '\0';
-                       if (*link_path == '/')
-                               /* Start over for an absolute symlink. */
-                               npath = resolved_path;
-                       else
-                               /* Otherwise back up over this component. */
-                               while (*(--npath) != '/')
-                                       ;
-
-                       /* Insert symlink contents into path. */
-                       m = strlen(path);
-                       newbuf = malloc(m + n + 1);
-                       if (!newbuf)
-                               goto err;
-                       memcpy(newbuf, link_path, n);
-                       memcpy(newbuf + n, path, m + 1);
-                       free(buf);
-                       path = buf = newbuf;
-               }
-               *npath++ = '/';
-       }
-       /* Delete trailing slash but don't whomp a lone slash. */
-       if (npath != resolved_path+1 && npath[-1] == '/')
-               npath--;
-       /* Make sure it's null terminated. */
-       *npath = '\0';
-
-       free(buf);
-       return resolved_path;
-
- err:
-       free(buf);
-       return NULL;
-}
-
 /*
  * Converts private "dm-N" names to "/dev/mapper/<name>"
  *
  * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
  * provides the real DM device names in /sys/block/<ptname>/dm/name
  */
-char *
-canonicalize_dm_name(const char *ptname)
+char *canonicalize_dm_name(const char *ptname)
 {
        FILE    *f;
        size_t  sz;
@@ -170,34 +48,32 @@ canonicalize_dm_name(const char *ptname)
        return res;
 }
 
-char *
-canonicalize_path(const char *path)
+char *canonicalize_path(const char *path)
 {
-       char canonical[PATH_MAX+2];
-       char *p;
+       char *canonical, *p;
 
        if (!path || !*path)
                return NULL;
 
-       if (!myrealpath(path, canonical, PATH_MAX+1))
+       canonical = realpath(path, NULL);
+       if (!canonical)
                return strdup(path);
 
-
        p = strrchr(canonical, '/');
        if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
-               p = canonicalize_dm_name(p+1);
-               if (p)
-                       return p;
+               char *dm = canonicalize_dm_name(p + 1);
+               if (dm) {
+                       free(canonical);
+                       return dm;
+               }
        }
 
-       return strdup(canonical);
+       return canonical;
 }
 
-char *
-canonicalize_path_restricted(const char *path)
+char *canonicalize_path_restricted(const char *path)
 {
-       char canonical[PATH_MAX+2];
-       char *p = NULL;
+       char *canonical, *p = NULL;
        int errsv;
        uid_t euid;
        gid_t egid;
@@ -214,25 +90,27 @@ canonicalize_path_restricted(const char *path)
 
        errsv = errno = 0;
 
-       if (myrealpath(path, canonical, PATH_MAX+1)) {
+       canonical = realpath(path, NULL);
+       if (canonical) {
                p = strrchr(canonical, '/');
-               if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4)))
-                       p = canonicalize_dm_name(p+1);
-               else
-                       p = NULL;
-               if (!p)
-                       p = strdup(canonical);
+               if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
+                       char *dm = canonicalize_dm_name(p + 1);
+                       if (dm) {
+                               free(canonical);
+                               canonical = dm;
+                       }
+               }
        } else
                errsv = errno;
 
        /* restore */
        if (setegid(egid) < 0 || seteuid(euid) < 0) {
-               free(p);
+               free(canonical);
                return NULL;
        }
 
        errno = errsv;
-       return p;
+       return canonical;
 }