1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <stdlib.h>
21: #include <string.h>
22: #include <unistd.h>
23: #include <limits.h>
24: #include <sys/param.h>
25: #include <sys/stat.h>
26: #include <errno.h>
27: #include <stddef.h>
28: #include <stdint.h>
29:
30: #include <ldconfig.h>
31:
32: #ifndef PATH_MAX
33: #define PATH_MAX 1024
34: #endif
35:
36:
37:
38:
39:
40:
41:
42: char *
43: chroot_canon (const char *chroot, const char *name)
44: {
45: char *rpath;
46: char *dest;
47: char *extra_buf = NULL;
48: char *rpath_root;
49: const char *start;
50: const char *end;
51: const char *rpath_limit;
52: int num_links = 0;
53: size_t chroot_len = strlen (chroot);
54:
55: if (chroot_len < 1)
56: {
57: __set_errno (EINVAL);
58: return NULL;
59: }
60:
61: rpath = malloc (chroot_len + PATH_MAX);
62: if (rpath == NULL)
63: return NULL;
64:
65: rpath_limit = rpath + chroot_len + PATH_MAX;
66:
67: rpath_root = (char *) mempcpy (rpath, chroot, chroot_len) - 1;
68: if (*rpath_root != '/')
69: *++rpath_root = '/';
70: dest = rpath_root + 1;
71:
72: for (start = end = name; *start; start = end)
73: {
74: struct stat64 st;
75: int n;
76:
77:
78: while (*start == '/')
79: ++start;
80:
81:
82: for (end = start; *end && *end != '/'; ++end)
83: ;
84:
85: if (end - start == 0)
86: break;
87: else if (end - start == 1 && start[0] == '.')
88: ;
89: else if (end - start == 2 && start[0] == '.' && start[1] == '.')
90: {
91:
92: if (dest > rpath_root + 1)
93: while ((--dest)[-1] != '/');
94: }
95: else
96: {
97: size_t new_size;
98:
99: if (dest[-1] != '/')
100: *dest++ = '/';
101:
102: if (dest + (end - start) >= rpath_limit)
103: {
104: ptrdiff_t dest_offset = dest - rpath;
105: char *new_rpath;
106:
107: new_size = rpath_limit - rpath;
108: if (end - start + 1 > PATH_MAX)
109: new_size += end - start + 1;
110: else
111: new_size += PATH_MAX;
112: new_rpath = (char *) realloc (rpath, new_size);
113: if (new_rpath == NULL)
114: goto error;
115: rpath = new_rpath;
116: rpath_limit = rpath + new_size;
117:
118: dest = rpath + dest_offset;
119: }
120:
121: dest = mempcpy (dest, start, end - start);
122: *dest = '\0';
123:
124: if (lstat64 (rpath, &st) < 0)
125: {
126: if (*end == '\0')
127: goto done;
128: goto error;
129: }
130:
131: if (S_ISLNK (st.st_mode))
132: {
133: char *buf = alloca (PATH_MAX);
134: size_t len;
135:
136: if (++num_links > MAXSYMLINKS)
137: {
138: __set_errno (ELOOP);
139: goto error;
140: }
141:
142: n = readlink (rpath, buf, PATH_MAX);
143: if (n < 0)
144: {
145: if (*end == '\0')
146: goto done;
147: goto error;
148: }
149: buf[n] = '\0';
150:
151: if (!extra_buf)
152: extra_buf = alloca (PATH_MAX);
153:
154: len = strlen (end);
155: if ((long int) (n + len) >= PATH_MAX)
156: {
157: __set_errno (ENAMETOOLONG);
158: goto error;
159: }
160:
161:
162: memmove (&extra_buf[n], end, len + 1);
163: name = end = memcpy (extra_buf, buf, n);
164:
165: if (buf[0] == '/')
166: dest = rpath_root + 1;
167: else
168:
169: if (dest > rpath_root + 1)
170: while ((--dest)[-1] != '/');
171: }
172: }
173: }
174: done:
175: if (dest > rpath_root + 1 && dest[-1] == '/')
176: --dest;
177: *dest = '\0';
178:
179: return rpath;
180:
181: error:
182: free (rpath);
183: return NULL;
184: }