xref: /freebsd/contrib/libarchive/libarchive/test/test_write_disk_secure.c (revision 185becb1e1bd2657c156f78aeb52edac05ba5fb5)
1 /*-
2  * Copyright (c) 2003-2007 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "test.h"
26 
27 #define UMASK 022
28 
29 #ifndef S_IFLNK
30 #define	S_IFLNK     0120000
31 #endif
32 
33 /*
34  * Exercise security checks that should prevent certain
35  * writes.
36  */
37 
DEFINE_TEST(test_write_disk_secure)38 DEFINE_TEST(test_write_disk_secure)
39 {
40 	struct archive *a;
41 	struct archive_entry *ae;
42 #if defined(HAVE_LCHMOD) && defined(HAVE_SYMLINK) && \
43     defined(S_IRUSR) && defined(S_IWUSR) && defined(S_IXUSR)
44 	int working_lchmod;
45 #endif
46 
47 	if (!canSymlink()) {
48 		skipping("Can't test symlinks on this filesystem");
49 		return;
50 	}
51 
52 	/* Start with a known umask. */
53 	assertUmask(UMASK);
54 
55 	/* Create an archive_write_disk object. */
56 	assert((a = archive_write_disk_new()) != NULL);
57 
58 	/* Write a regular dir to it. */
59 	assert((ae = archive_entry_new()) != NULL);
60 	archive_entry_copy_pathname(ae, "dir");
61 	archive_entry_set_mode(ae, S_IFDIR | 0777);
62 	assert(0 == archive_write_header(a, ae));
63 	archive_entry_free(ae);
64 	assert(0 == archive_write_finish_entry(a));
65 
66 	/* Write a symlink to the dir above. */
67 	assert((ae = archive_entry_new()) != NULL);
68 	archive_entry_copy_pathname(ae, "link_to_dir");
69 	archive_entry_set_mode(ae, S_IFLNK | 0777);
70 	archive_entry_set_symlink(ae, "dir");
71 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
72 	archive_write_disk_set_options(a, 0);
73 	assert(0 == archive_write_header(a, ae));
74 	assert(0 == archive_write_finish_entry(a));
75 
76 	/*
77 	 * Without security checks, we should be able to
78 	 * extract a file through the link.
79 	 */
80 	assert(archive_entry_clear(ae) != NULL);
81 	archive_entry_copy_pathname(ae, "link_to_dir/filea");
82 	archive_entry_set_mode(ae, S_IFREG | 0777);
83 	assert(0 == archive_write_header(a, ae));
84 	assert(0 == archive_write_finish_entry(a));
85 
86 	/* But with security checks enabled, this should fail. */
87 	assert(archive_entry_clear(ae) != NULL);
88 	archive_entry_copy_pathname(ae, "link_to_dir/fileb");
89 	archive_entry_set_mode(ae, S_IFREG | 0777);
90 	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
91 	failure("Extracting a file through a symlink should fail here.");
92 	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
93 	archive_entry_free(ae);
94 	assert(0 == archive_write_finish_entry(a));
95 
96 	/* These tests hardcode the location of /tmp. skip them on Windows for now. */
97 #if !defined(_WIN32) || defined(__CYGWIN__)
98 	/* Write an absolute symlink to /tmp. */
99 	assert((ae = archive_entry_new()) != NULL);
100 	archive_entry_copy_pathname(ae, "/tmp/libarchive_test-test_write_disk_secure-absolute_symlink");
101 	archive_entry_set_mode(ae, S_IFLNK | 0777);
102 	archive_entry_set_symlink(ae, "/tmp");
103 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
104 	archive_write_disk_set_options(a, 0);
105 	assert(0 == archive_write_header(a, ae));
106 	assert(0 == archive_write_finish_entry(a));
107 
108 	/* With security checks enabled, this should fail. */
109 	assert(archive_entry_clear(ae) != NULL);
110 	archive_entry_copy_pathname(ae, "/tmp/libarchive_test-test_write_disk_secure-absolute_symlink/libarchive_test-test_write_disk_secure-absolute_symlink_path.tmp");
111 	archive_entry_set_mode(ae, S_IFREG | 0777);
112 	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
113 	failure("Extracting a file through an absolute symlink should fail here.");
114 	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
115 	archive_entry_free(ae);
116 	assertFileNotExists("/tmp/libarchive_test-test_write_disk_secure-absolute_symlink/libarchive_test-test_write_disk_secure-absolute_symlink_path.tmp");
117 	assert(0 == unlink("/tmp/libarchive_test-test_write_disk_secure-absolute_symlink"));
118 	unlink("/tmp/libarchive_test-test_write_disk_secure-absolute_symlink_path.tmp");
119 #endif
120 
121 	/* Create another link. */
122 	assert((ae = archive_entry_new()) != NULL);
123 	archive_entry_copy_pathname(ae, "link_to_dir2");
124 	archive_entry_set_mode(ae, S_IFLNK | 0777);
125 	archive_entry_set_symlink(ae, "dir");
126 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
127 	archive_write_disk_set_options(a, 0);
128 	assert(0 == archive_write_header(a, ae));
129 	assert(0 == archive_write_finish_entry(a));
130 
131 	/*
132 	 * With symlink check and unlink option, it should remove
133 	 * the link and create the dir.
134 	 */
135 	assert(archive_entry_clear(ae) != NULL);
136 	archive_entry_copy_pathname(ae, "link_to_dir2/filec");
137 	archive_entry_set_mode(ae, S_IFREG | 0777);
138 	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_UNLINK);
139 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
140 	archive_entry_free(ae);
141 	assert(0 == archive_write_finish_entry(a));
142 
143 	/* Create a nested symlink. */
144 	assert((ae = archive_entry_new()) != NULL);
145 	archive_entry_copy_pathname(ae, "dir/nested_link_to_dir");
146 	archive_entry_set_mode(ae, S_IFLNK | 0777);
147 	archive_entry_set_symlink(ae, "../dir");
148 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
149 	archive_write_disk_set_options(a, 0);
150 	assert(0 == archive_write_header(a, ae));
151 	assert(0 == archive_write_finish_entry(a));
152 
153 	/* But with security checks enabled, this should fail. */
154 	assert(archive_entry_clear(ae) != NULL);
155 	archive_entry_copy_pathname(ae, "dir/nested_link_to_dir/filed");
156 	archive_entry_set_mode(ae, S_IFREG | 0777);
157 	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
158 	failure("Extracting a file through a symlink should fail here.");
159 	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
160 	archive_entry_free(ae);
161 	assert(0 == archive_write_finish_entry(a));
162 
163 	/*
164 	 * Without security checks, extracting a dir over a link to a
165 	 * dir should follow the link.
166 	 */
167 	/* Create a symlink to a dir. */
168 	assert((ae = archive_entry_new()) != NULL);
169 	archive_entry_copy_pathname(ae, "link_to_dir3");
170 	archive_entry_set_mode(ae, S_IFLNK | 0777);
171 	archive_entry_set_symlink(ae, "dir");
172 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
173 	archive_write_disk_set_options(a, 0);
174 	assert(0 == archive_write_header(a, ae));
175 	assert(0 == archive_write_finish_entry(a));
176 	/* Extract a dir whose name matches the symlink. */
177 	assert(archive_entry_clear(ae) != NULL);
178 	archive_entry_copy_pathname(ae, "link_to_dir3");
179 	archive_entry_set_mode(ae, S_IFDIR | 0777);
180 	assert(0 == archive_write_header(a, ae));
181 	assert(0 == archive_write_finish_entry(a));
182 	/* Verify link was followed. */
183 	assertIsSymlink("link_to_dir3", "dir", 1);
184 	archive_entry_free(ae);
185 
186 	/*
187 	 * As above, but a broken link, so the link should get replaced.
188 	 */
189 	/* Create a symlink to a dir. */
190 	assert((ae = archive_entry_new()) != NULL);
191 	archive_entry_copy_pathname(ae, "link_to_dir4");
192 	archive_entry_set_mode(ae, S_IFLNK | 0777);
193 	archive_entry_set_symlink(ae, "nonexistent_dir");
194 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
195 	archive_write_disk_set_options(a, 0);
196 	assert(0 == archive_write_header(a, ae));
197 	assert(0 == archive_write_finish_entry(a));
198 	/* Extract a dir whose name matches the symlink. */
199 	assert(archive_entry_clear(ae) != NULL);
200 	archive_entry_copy_pathname(ae, "link_to_dir4");
201 	archive_entry_set_mode(ae, S_IFDIR | 0777);
202 	assert(0 == archive_write_header(a, ae));
203 	assert(0 == archive_write_finish_entry(a));
204 	/* Verify link was replaced. */
205 	assertIsDir("link_to_dir4", -1);
206 	archive_entry_free(ae);
207 
208 	/*
209 	 * As above, but a link to a non-dir, so the link should get replaced.
210 	 */
211 	/* Create a regular file and a symlink to it */
212 	assert((ae = archive_entry_new()) != NULL);
213 	archive_entry_copy_pathname(ae, "non_dir");
214 	archive_entry_set_mode(ae, S_IFREG | 0777);
215 	archive_write_disk_set_options(a, 0);
216 	assert(0 == archive_write_header(a, ae));
217 	assert(0 == archive_write_finish_entry(a));
218 	/* Create symlink to the file. */
219 	archive_entry_copy_pathname(ae, "link_to_dir5");
220 	archive_entry_set_mode(ae, S_IFLNK | 0777);
221 	archive_entry_set_symlink(ae, "non_dir");
222 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_FILE);
223 	archive_write_disk_set_options(a, 0);
224 	assert(0 == archive_write_header(a, ae));
225 	assert(0 == archive_write_finish_entry(a));
226 	/* Extract a dir whose name matches the symlink. */
227 	assert(archive_entry_clear(ae) != NULL);
228 	archive_entry_copy_pathname(ae, "link_to_dir5");
229 	archive_entry_set_mode(ae, S_IFDIR | 0777);
230 	assert(0 == archive_write_header(a, ae));
231 	assert(0 == archive_write_finish_entry(a));
232 	/* Verify link was replaced. */
233 	assertIsDir("link_to_dir5", -1);
234 	archive_entry_free(ae);
235 
236 	/* These tests hardcode the location of /tmp. skip them on Windows for now. */
237 #if !defined(_WIN32) || defined(__CYGWIN__)
238 	/*
239 	 * Without security checks, we should be able to
240 	 * extract an absolute path.
241 	 */
242 	assert((ae = archive_entry_new()) != NULL);
243 	archive_entry_copy_pathname(ae, "/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp");
244 	archive_entry_set_mode(ae, S_IFREG | 0777);
245 	assert(0 == archive_write_header(a, ae));
246 	assert(0 == archive_write_finish_entry(a));
247 	assertFileExists("/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp");
248 	assert(0 == unlink("/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp"));
249 
250 	/* But with security checks enabled, this should fail. */
251 	assert(archive_entry_clear(ae) != NULL);
252 	archive_entry_copy_pathname(ae, "/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp");
253 	archive_entry_set_mode(ae, S_IFREG | 0777);
254 	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS);
255 	failure("Extracting an absolute path should fail here.");
256 	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
257 	archive_entry_free(ae);
258 	assert(0 == archive_write_finish_entry(a));
259 	assertFileNotExists("/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp");
260 #endif
261 
262 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
263 
264 	/* Test the entries on disk. */
265 	assertIsDir("dir", 0755);
266 	assertIsSymlink("link_to_dir", "dir", 1);
267 
268 #if defined(HAVE_SYMLINK) && defined(HAVE_LCHMOD) && \
269     defined(S_IRUSR) && defined(S_IWUSR) && defined(S_IXUSR)
270 	/* Verify if we are able to lchmod() */
271 	if (symlink("dir", "testlink_to_dir") == 0) {
272 		if (lchmod("testlink_to_dir",
273 		    S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
274 			switch (errno) {
275 				case ENOTSUP:
276 				case ENOSYS:
277 #if ENOTSUP != EOPNOTSUPP
278 				case EOPNOTSUPP:
279 #endif
280 					working_lchmod = 0;
281 					break;
282 				default:
283 					working_lchmod = 1;
284 			}
285 		} else
286 			working_lchmod = 1;
287 	} else
288 		working_lchmod = 0;
289 
290 	if (working_lchmod) {
291 		struct stat st;
292 		assert(0 == lstat("link_to_dir", &st));
293 		failure("link_to_dir: st.st_mode=%o", st.st_mode);
294 		assert((st.st_mode & 07777) == 0755);
295 	}
296 #endif
297 
298 	assertIsReg("dir/filea", 0755);
299 	assertFileNotExists("dir/fileb");
300 	assertIsDir("link_to_dir2", 0755);
301 	assertIsReg("link_to_dir2/filec", 0755);
302 	assertFileNotExists("dir/filed");
303 }
304 
305 /*
306  * This is a simplified variant of the above test which never turns off secure
307  * symlinks. It is designed to test quirks in the Windows implementation of
308  * archive_write_disk; however, its behavior under test should not be exclusive
309  * to Windows.
310  */
DEFINE_TEST(test_write_disk_secure_symlinks_only)311 DEFINE_TEST(test_write_disk_secure_symlinks_only)
312 {
313 	struct archive *a;
314 	struct archive_entry *ae;
315 	const int default_options = ARCHIVE_EXTRACT_SECURE_SYMLINKS;
316 
317 	if (!canSymlink()) {
318 		skipping("Can't test symlinks on this filesystem");
319 		return;
320 	}
321 
322 	/* Start with a known umask. */
323 	assertUmask(UMASK);
324 
325 	/* Create an archive_write_disk object. */
326 	assert((a = archive_write_disk_new()) != NULL);
327 	archive_write_disk_set_options(a, default_options);
328 
329 	/* Write a regular dir to it. */
330 	assert((ae = archive_entry_new()) != NULL);
331 	archive_entry_copy_pathname(ae, "dir");
332 	archive_entry_set_mode(ae, S_IFDIR | 0777);
333 	assert(0 == archive_write_header(a, ae));
334 	archive_entry_free(ae);
335 	assert(0 == archive_write_finish_entry(a));
336 	assertIsDir("dir", -1);
337 
338 	/* Write a symlink to the dir above. */
339 	assert((ae = archive_entry_new()) != NULL);
340 	archive_entry_copy_pathname(ae, "link_to_dir");
341 	archive_entry_set_mode(ae, S_IFLNK | 0777);
342 	archive_entry_set_symlink(ae, "dir");
343 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
344 	assert(0 == archive_write_header(a, ae));
345 	assert(0 == archive_write_finish_entry(a));
346 	assertIsSymlink("link_to_dir", "dir", 1);
347 
348 	/* With security checks enabled, this should fail. */
349 	assert(archive_entry_clear(ae) != NULL);
350 	archive_entry_copy_pathname(ae, "link_to_dir/fileb");
351 	archive_entry_set_mode(ae, S_IFREG | 0777);
352 	failure("Extracting a file through a symlink should fail here.");
353 	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
354 	archive_entry_free(ae);
355 	assert(0 == archive_write_finish_entry(a));
356 	assertFileNotExists("dir/fileb");
357 
358 	/* Create another link. */
359 	assert((ae = archive_entry_new()) != NULL);
360 	archive_entry_copy_pathname(ae, "link_to_dir2");
361 	archive_entry_set_mode(ae, S_IFLNK | 0777);
362 	archive_entry_set_symlink(ae, "dir");
363 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
364 	assert(0 == archive_write_header(a, ae));
365 	assert(0 == archive_write_finish_entry(a));
366 	assertIsSymlink("link_to_dir2", "dir", 1);
367 
368 	/*
369 	 * With symlink check and unlink option, it should remove
370 	 * the link and create the dir.
371 	 */
372 	assert(archive_entry_clear(ae) != NULL);
373 	archive_entry_copy_pathname(ae, "link_to_dir2/filec");
374 	archive_entry_set_mode(ae, S_IFREG | 0777);
375 	archive_write_disk_set_options(a, default_options | ARCHIVE_EXTRACT_UNLINK);
376 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
377 	archive_entry_free(ae);
378 	assert(0 == archive_write_finish_entry(a));
379 	assertIsDir("link_to_dir2", -1);
380 	assertIsReg("link_to_dir2/filec", -1);
381 
382 	/*
383 	 * Restore the prior security mode.
384 	 */
385 	archive_write_disk_set_options(a, default_options);
386 
387 	/* Create a nested symlink. */
388 	assert((ae = archive_entry_new()) != NULL);
389 	archive_entry_copy_pathname(ae, "dir/nested_link_to_dir");
390 	archive_entry_set_mode(ae, S_IFLNK | 0777);
391 	archive_entry_set_symlink(ae, "../dir");
392 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
393 	assert(0 == archive_write_header(a, ae));
394 	assert(0 == archive_write_finish_entry(a));
395 	assertIsSymlink("dir/nested_link_to_dir", "../dir", -1);
396 
397 	/* With security checks enabled, this should fail. */
398 	assert(archive_entry_clear(ae) != NULL);
399 	archive_entry_copy_pathname(ae, "dir/nested_link_to_dir/filed");
400 	archive_entry_set_mode(ae, S_IFREG | 0777);
401 	failure("Extracting a file through a symlink should fail here.");
402 	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
403 	archive_entry_free(ae);
404 	assert(0 == archive_write_finish_entry(a));
405 	assertFileNotExists("dir/filed");
406 
407 	/* Create a symlink to a dir. */
408 	assert((ae = archive_entry_new()) != NULL);
409 	archive_entry_copy_pathname(ae, "link_to_dir3");
410 	archive_entry_set_mode(ae, S_IFLNK | 0777);
411 	archive_entry_set_symlink(ae, "dir");
412 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
413 	assert(0 == archive_write_header(a, ae));
414 	assert(0 == archive_write_finish_entry(a));
415 	assertIsSymlink("link_to_dir3", "dir", 1);
416 	/* Extract a dir whose name matches the symlink. */
417 	assert(archive_entry_clear(ae) != NULL);
418 	archive_entry_copy_pathname(ae, "link_to_dir3");
419 	archive_entry_set_mode(ae, S_IFDIR | 0777);
420 	assert(0 == archive_write_header(a, ae));
421 	assert(0 == archive_write_finish_entry(a));
422 	archive_entry_free(ae);
423 	assertIsDir("link_to_dir3", -1);
424 
425 	/*
426 	 * As above, but a broken link, so the link should get replaced.
427 	 */
428 
429 	/* Create a symlink to a dir. */
430 	assert((ae = archive_entry_new()) != NULL);
431 	archive_entry_copy_pathname(ae, "link_to_dir4");
432 	archive_entry_set_mode(ae, S_IFLNK | 0777);
433 	archive_entry_set_symlink(ae, "nonexistent_dir");
434 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
435 	assert(0 == archive_write_header(a, ae));
436 	assert(0 == archive_write_finish_entry(a));
437 	assertIsSymlink("link_to_dir4", "nonexistent_dir", 1);
438 	/* Extract a dir whose name matches the symlink. */
439 	assert(archive_entry_clear(ae) != NULL);
440 	archive_entry_copy_pathname(ae, "link_to_dir4");
441 	archive_entry_set_mode(ae, S_IFDIR | 0777);
442 	assert(0 == archive_write_header(a, ae));
443 	assert(0 == archive_write_finish_entry(a));
444 	archive_entry_free(ae);
445 	assertIsDir("link_to_dir4", -1);
446 
447 	/*
448 	 * As above, but a link to a non-dir, so the link should get replaced.
449 	 * (file is named "link_to_dir" because we are transforming a link into a dir,)
450 	 */
451 	/* Create a regular file and a symlink to it */
452 	assert((ae = archive_entry_new()) != NULL);
453 	archive_entry_copy_pathname(ae, "non_dir");
454 	archive_entry_set_mode(ae, S_IFREG | 0777);
455 	assert(0 == archive_write_header(a, ae));
456 	assert(0 == archive_write_finish_entry(a));
457 	assertIsReg("non_dir", -1);
458 	/* Create symlink to the file. */
459 	archive_entry_copy_pathname(ae, "link_to_dir5");
460 	archive_entry_set_mode(ae, S_IFLNK | 0777);
461 	archive_entry_set_symlink(ae, "non_dir");
462 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_FILE);
463 	assert(0 == archive_write_header(a, ae));
464 	assert(0 == archive_write_finish_entry(a));
465 	assertIsSymlink("link_to_dir5", "non_dir", 0);
466 	/* Extract a dir whose name matches the symlink. */
467 	assert(archive_entry_clear(ae) != NULL);
468 	archive_entry_copy_pathname(ae, "link_to_dir5");
469 	archive_entry_set_mode(ae, S_IFDIR | 0777);
470 	assert(0 == archive_write_header(a, ae));
471 	assert(0 == archive_write_finish_entry(a));
472 	archive_entry_free(ae);
473 	assertIsDir("link_to_dir5", -1);
474 
475 	/*
476 	 * Create a link to a (technically safe) directory, then replace it, then write through it.
477 	 * Exercises the safety cache to ensure that it does not treat new entries as safe.
478 	 */
479 	assert((ae = archive_entry_new()) != NULL);
480 	archive_entry_copy_pathname(ae, "link_to_dir6");
481 	archive_entry_set_mode(ae, S_IFLNK | 0777);
482 	archive_entry_set_symlink(ae, "dir");
483 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
484 	assert(0 == archive_write_header(a, ae));
485 	assert(0 == archive_write_finish_entry(a));
486 	assertIsSymlink("link_to_dir6", "dir", 1);
487 	/* Replace it. */
488 	assert(archive_entry_clear(ae) != NULL);
489 	archive_entry_copy_pathname(ae, "link_to_dir6");
490 	archive_entry_set_mode(ae, S_IFLNK | 0777);
491 	archive_entry_set_symlink(ae, "dir");
492 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
493 	assert(0 == archive_write_header(a, ae));
494 	assert(0 == archive_write_finish_entry(a));
495 	assertIsSymlink("link_to_dir6", "dir", 1);
496 	/* Extract through it. */
497 	assert(archive_entry_clear(ae) != NULL);
498 	archive_entry_copy_pathname(ae, "link_to_dir6/filee");
499 	archive_entry_set_mode(ae, S_IFREG | 0777);
500 	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
501 	archive_entry_free(ae);
502 	assertFileNotExists("dir/filee");
503 
504 	/*
505 	 * Create an empty directory, then replace it, then write through it.
506 	 * Exercises the safety cache to ensure that it does not treat new entries as safe.
507 	 */
508 	assert((ae = archive_entry_new()) != NULL);
509 	archive_entry_copy_pathname(ae, "link_to_dir7");
510 	archive_entry_set_mode(ae, S_IFDIR | 0777);
511 	assert(0 == archive_write_header(a, ae));
512 	assert(0 == archive_write_finish_entry(a));
513 	assertIsDir("link_to_dir7", -1);
514 	/* Replace it. */
515 	assert(archive_entry_clear(ae) != NULL);
516 	archive_entry_copy_pathname(ae, "link_to_dir7");
517 	archive_entry_set_mode(ae, S_IFLNK | 0777);
518 	archive_entry_set_symlink(ae, "dir");
519 	archive_entry_set_symlink_type(ae, AE_SYMLINK_TYPE_DIRECTORY);
520 	assert(0 == archive_write_header(a, ae));
521 	assert(0 == archive_write_finish_entry(a));
522 	assertIsSymlink("link_to_dir7", "dir", 1);
523 	/* Extract through it. */
524 	assert(archive_entry_clear(ae) != NULL);
525 	archive_entry_copy_pathname(ae, "link_to_dir7/filef");
526 	archive_entry_set_mode(ae, S_IFREG | 0777);
527 	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
528 	archive_entry_free(ae);
529 	assertFileNotExists("dir/filef");
530 
531 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
532 }
533