summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/canonicalize.h1
-rw-r--r--lib/canonicalize.c42
2 files changed, 43 insertions, 0 deletions
diff --git a/include/canonicalize.h b/include/canonicalize.h
index f26df18c2..c14973802 100644
--- a/include/canonicalize.h
+++ b/include/canonicalize.h
@@ -4,6 +4,7 @@
#include "c.h" /* for PATH_MAX */
extern char *canonicalize_path(const char *path);
+extern char *canonicalize_path_restricted(const char *path);
extern char *canonicalize_dm_name(const char *ptname);
#endif /* CANONICALIZE_H */
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index ab32c1043..1e8aff4f2 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -188,6 +188,48 @@ canonicalize_path(const char *path)
return strdup(canonical);
}
+char *
+canonicalize_path_restricted(const char *path)
+{
+ char canonical[PATH_MAX+2];
+ char *p = NULL;
+ int errsv;
+ uid_t euid;
+ gid_t egid;
+
+ if (path == NULL)
+ return NULL;
+
+ euid = geteuid();
+ egid = getegid();
+
+ /* drop permissions */
+ if (setegid(getgid()) < 0 || seteuid(getuid()) < 0)
+ return NULL;
+
+ errsv = errno = 0;
+
+ if (myrealpath(path, canonical, PATH_MAX+1)) {
+ 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);
+ } else
+ errsv = errno;
+
+ /* restore */
+ if (setegid(egid) < 0 || seteuid(euid) < 0) {
+ free(p);
+ return NULL;
+ }
+
+ errno = errsv;
+ return p;
+}
+
#ifdef TEST_PROGRAM_CANONICALIZE
int main(int argc, char **argv)