libarchive: do not extract unsafe symlinks unless $EXTRACT_UNSAFE_SYMLINKS=1
[oweals/busybox.git] / archival / libarchive / unsafe_symlink_target.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4  */
5 #include "libbb.h"
6 #include "bb_archive.h"
7
8 int FAST_FUNC unsafe_symlink_target(const char *target)
9 {
10         const char *dot;
11
12         if (target[0] == '/') {
13                 const char *var;
14  unsafe:
15                 var = getenv("EXTRACT_UNSAFE_SYMLINKS");
16                 if (var) {
17                         if (LONE_CHAR(var, '1'))
18                                 return 0; /* pretend it's safe */
19                         return 1; /* "UNSAFE!" */
20                 }
21                 bb_error_msg("skipping unsafe symlink to '%s' in archive,"
22                         " set %s=1 to extract",
23                         target,
24                         "EXTRACT_UNSAFE_SYMLINKS"
25                 );
26                 /* Prevent further messages */
27                 setenv("EXTRACT_UNSAFE_SYMLINKS", "0", 0);
28                 return 1; /* "UNSAFE!" */
29         }
30
31         dot = target;
32         for (;;) {
33                 dot = strchr(dot, '.');
34                 if (!dot)
35                         return 0; /* safe target */
36
37                 /* Is it a path component starting with ".."? */
38                 if ((dot[1] == '.')
39                  && (dot == target || dot[-1] == '/')
40                     /* Is it exactly ".."? */
41                  && (dot[2] == '/' || dot[2] == '\0')
42                 ) {
43                         goto unsafe;
44                 }
45                 /* NB: it can even be trailing ".", should only add 1 */
46                 dot += 1;
47         }
48 }