1228753Smm/*-
2228753Smm * Copyright (c) 2003-2007 Tim Kientzle
3228753Smm * All rights reserved.
4228753Smm *
5228753Smm * Redistribution and use in source and binary forms, with or without
6228753Smm * modification, are permitted provided that the following conditions
7228753Smm * are met:
8228753Smm * 1. Redistributions of source code must retain the above copyright
9228753Smm *    notice, this list of conditions and the following disclaimer.
10228753Smm * 2. Redistributions in binary form must reproduce the above copyright
11228753Smm *    notice, this list of conditions and the following disclaimer in the
12228753Smm *    documentation and/or other materials provided with the distribution.
13228753Smm *
14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24228753Smm */
25228753Smm#include "test.h"
26228763Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/test/test_write_disk_perms.c 328828 2018-02-03 02:17:25Z mm $");
27228753Smm
28232153Smm#if !defined(_WIN32) || defined(__CYGWIN__)
29228753Smm
30228753Smm#define UMASK 022
31228753Smm
32228753Smmstatic long _default_gid = -1;
33228753Smmstatic long _invalid_gid = -1;
34228753Smmstatic long _alt_gid = -1;
35228753Smm
36228753Smm/*
37228753Smm * To fully test SGID restores, we need three distinct GIDs to work
38228753Smm * with:
39228753Smm *    * the GID that files are created with by default (for the
40228753Smm *      current user in the current directory)
41228753Smm *    * An "alt gid" that this user can create files with
42228753Smm *    * An "invalid gid" that this user is not permitted to create
43228753Smm *      files with.
44228753Smm * The second fails if this user doesn't belong to at least two groups;
45228753Smm * the third fails if the current user is root.
46228753Smm */
47228753Smmstatic void
48228753Smmsearchgid(void)
49228753Smm{
50228753Smm	static int   _searched = 0;
51228753Smm	uid_t uid = getuid();
52228753Smm	gid_t gid = 0;
53228753Smm	unsigned int n;
54228753Smm	struct stat st;
55228753Smm	int fd;
56228753Smm
57228753Smm	/* If we've already looked this up, we're done. */
58228753Smm	if (_searched)
59228753Smm		return;
60228753Smm	_searched = 1;
61228753Smm
62228753Smm	/* Create a file on disk in the current default dir. */
63228753Smm	fd = open("test_gid", O_CREAT | O_BINARY, 0664);
64228753Smm	failure("Couldn't create a file for gid testing.");
65228753Smm	assert(fd > 0);
66228753Smm
67228753Smm	/* See what GID it ended up with.  This is our "valid" GID. */
68228753Smm	assert(fstat(fd, &st) == 0);
69228753Smm	_default_gid = st.st_gid;
70228753Smm
71228753Smm	/* Find a GID for which fchown() fails.  This is our "invalid" GID. */
72228753Smm	_invalid_gid = -1;
73228753Smm	/* This loop stops when we wrap the gid or examine 10,000 gids. */
74228753Smm	for (gid = 1, n = 1; gid == n && n < 10000 ; n++, gid++) {
75228753Smm		if (fchown(fd, uid, gid) != 0) {
76228753Smm			_invalid_gid = gid;
77228753Smm			break;
78228753Smm		}
79228753Smm	}
80228753Smm
81228753Smm	/*
82228753Smm	 * Find a GID for which fchown() succeeds, but which isn't the
83228753Smm	 * default.  This is the "alternate" gid.
84228753Smm	 */
85228753Smm	_alt_gid = -1;
86228753Smm	for (gid = 0, n = 0; gid == n && n < 10000 ; n++, gid++) {
87228753Smm		/* _alt_gid must be different than _default_gid */
88228753Smm		if (gid == (gid_t)_default_gid)
89228753Smm			continue;
90228753Smm		if (fchown(fd, uid, gid) == 0) {
91228753Smm			_alt_gid = gid;
92228753Smm			break;
93228753Smm		}
94228753Smm	}
95228753Smm	close(fd);
96228753Smm}
97228753Smm
98228753Smmstatic int
99228753Smmaltgid(void)
100228753Smm{
101228753Smm	searchgid();
102228753Smm	return (_alt_gid);
103228753Smm}
104228753Smm
105228753Smmstatic int
106228753Smminvalidgid(void)
107228753Smm{
108228753Smm	searchgid();
109228753Smm	return (_invalid_gid);
110228753Smm}
111228753Smm
112228753Smmstatic int
113228753Smmdefaultgid(void)
114228753Smm{
115228753Smm	searchgid();
116228753Smm	return (_default_gid);
117228753Smm}
118228753Smm#endif
119228753Smm
120228753Smm/*
121228753Smm * Exercise permission and ownership restores.
122228753Smm * In particular, try to exercise a bunch of border cases related
123228753Smm * to files/dirs that already exist, SUID/SGID bits, etc.
124228753Smm */
125228753Smm
126228753SmmDEFINE_TEST(test_write_disk_perms)
127228753Smm{
128232153Smm#if defined(_WIN32) && !defined(__CYGWIN__)
129228753Smm	skipping("archive_write_disk interface");
130228753Smm#else
131228753Smm	struct archive *a;
132228753Smm	struct archive_entry *ae;
133228753Smm	struct stat st;
134328828Smm	uid_t original_uid;
135328828Smm	uid_t try_to_change_uid;
136228753Smm
137228753Smm	assertUmask(UMASK);
138228753Smm
139228753Smm	/*
140228753Smm	 * Set ownership of the current directory to the group of this
141228753Smm	 * process.  Otherwise, the SGID tests below fail if the
142228753Smm	 * /tmp directory is owned by a group to which we don't belong
143228753Smm	 * and we're on a system where group ownership is inherited.
144228753Smm	 * (Because we're not allowed to SGID files with defaultgid().)
145228753Smm	 */
146228753Smm	assertEqualInt(0, chown(".", getuid(), getgid()));
147228753Smm
148228753Smm	/* Create an archive_write_disk object. */
149228753Smm	assert((a = archive_write_disk_new()) != NULL);
150228753Smm
151228753Smm	/* Write a regular file to it. */
152228753Smm	assert((ae = archive_entry_new()) != NULL);
153228753Smm	archive_entry_copy_pathname(ae, "file_0755");
154228753Smm	archive_entry_set_mode(ae, S_IFREG | 0777);
155302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
156302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
157228753Smm	archive_entry_free(ae);
158228753Smm
159228753Smm	/* Write a regular file, then write over it. */
160228753Smm	/* For files, the perms should get updated. */
161228753Smm	assert((ae = archive_entry_new()) != NULL);
162228753Smm	archive_entry_copy_pathname(ae, "file_overwrite_0144");
163228753Smm	archive_entry_set_mode(ae, S_IFREG | 0777);
164302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
165228753Smm	archive_entry_free(ae);
166302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
167228753Smm	/* Check that file was created with different perms. */
168302001Smm	assertEqualInt(0, stat("file_overwrite_0144", &st));
169228753Smm	failure("file_overwrite_0144: st.st_mode=%o", st.st_mode);
170228753Smm	assert((st.st_mode & 07777) != 0144);
171228753Smm	/* Overwrite, this should change the perms. */
172228753Smm	assert((ae = archive_entry_new()) != NULL);
173228753Smm	archive_entry_copy_pathname(ae, "file_overwrite_0144");
174228753Smm	archive_entry_set_mode(ae, S_IFREG | 0144);
175302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
176228753Smm	archive_entry_free(ae);
177302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
178228753Smm
179228753Smm	/* Write a regular dir. */
180228753Smm	assert((ae = archive_entry_new()) != NULL);
181228753Smm	archive_entry_copy_pathname(ae, "dir_0514");
182228753Smm	archive_entry_set_mode(ae, S_IFDIR | 0514);
183302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
184228753Smm	archive_entry_free(ae);
185302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
186228753Smm
187228753Smm	/* Overwrite an existing dir. */
188228753Smm	/* For dir, the first perms should get left. */
189228753Smm	assertMakeDir("dir_overwrite_0744", 0744);
190228753Smm	/* Check original perms. */
191302001Smm	assertEqualInt(0, stat("dir_overwrite_0744", &st));
192228753Smm	failure("dir_overwrite_0744: st.st_mode=%o", st.st_mode);
193302001Smm	assertEqualInt(st.st_mode & 0777, 0744);
194228753Smm	/* Overwrite shouldn't edit perms. */
195228753Smm	assert((ae = archive_entry_new()) != NULL);
196228753Smm	archive_entry_copy_pathname(ae, "dir_overwrite_0744");
197228753Smm	archive_entry_set_mode(ae, S_IFDIR | 0777);
198302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
199228753Smm	archive_entry_free(ae);
200302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
201228753Smm	/* Make sure they're unchanged. */
202302001Smm	assertEqualInt(0, stat("dir_overwrite_0744", &st));
203228753Smm	failure("dir_overwrite_0744: st.st_mode=%o", st.st_mode);
204302001Smm	assertEqualInt(st.st_mode & 0777, 0744);
205228753Smm
206328828Smm	/* For dir, the owner should get left when not overwritting. */
207328828Smm	assertMakeDir("dir_owner", 0744);
208328828Smm
209328828Smm	if (getuid() == 0) {
210328828Smm		original_uid = getuid() + 1;
211328828Smm		try_to_change_uid = getuid();
212328828Smm		assertEqualInt(0, chown("dir_owner", original_uid, getgid()));
213328828Smm	} else {
214328828Smm		original_uid = getuid();
215328828Smm		try_to_change_uid = getuid() + 1;
216328828Smm	}
217328828Smm
218328828Smm	/* Check original owner. */
219328828Smm	assertEqualInt(0, stat("dir_owner", &st));
220328828Smm	failure("dir_owner: st.st_uid=%d", st.st_uid);
221328828Smm	assertEqualInt(st.st_uid, original_uid);
222328828Smm	/* Shouldn't try to edit the owner when no overwrite option is set. */
223328828Smm	assert((ae = archive_entry_new()) != NULL);
224328828Smm	archive_entry_copy_pathname(ae, "dir_owner");
225328828Smm	archive_entry_set_mode(ae, S_IFDIR | 0744);
226328828Smm	archive_entry_set_uid(ae, try_to_change_uid);
227328828Smm	archive_write_disk_set_options(a,
228328828Smm	    ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_NO_OVERWRITE);
229328828Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
230328828Smm	archive_entry_free(ae);
231328828Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
232328828Smm	/* Make sure they're unchanged. */
233328828Smm	assertEqualInt(0, stat("dir_owner", &st));
234328828Smm	failure("dir_owner: st.st_uid=%d", st.st_uid);
235328828Smm	assertEqualInt(st.st_uid, original_uid);
236328828Smm
237228753Smm	/* Write a regular file with SUID bit, but don't use _EXTRACT_PERM. */
238228753Smm	assert((ae = archive_entry_new()) != NULL);
239228753Smm	archive_entry_copy_pathname(ae, "file_no_suid");
240228753Smm	archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0777);
241228753Smm	archive_write_disk_set_options(a, 0);
242302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
243302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
244228753Smm
245228753Smm	/* Write a regular file with ARCHIVE_EXTRACT_PERM. */
246228753Smm	assert(archive_entry_clear(ae) != NULL);
247228753Smm	archive_entry_copy_pathname(ae, "file_0777");
248228753Smm	archive_entry_set_mode(ae, S_IFREG | 0777);
249228753Smm	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
250302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
251302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
252228753Smm
253228753Smm	/* Write a regular file with ARCHIVE_EXTRACT_PERM & SUID bit */
254228753Smm	assert(archive_entry_clear(ae) != NULL);
255228753Smm	archive_entry_copy_pathname(ae, "file_4742");
256228753Smm	archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0742);
257228753Smm	archive_entry_set_uid(ae, getuid());
258228753Smm	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
259302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
260302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
261228753Smm
262228753Smm	/*
263228753Smm	 * Write a regular file with ARCHIVE_EXTRACT_PERM & SUID bit,
264228753Smm	 * but wrong uid.  POSIX says you shouldn't restore SUID bit
265228753Smm	 * unless the UID could be restored.
266228753Smm	 */
267228753Smm	assert(archive_entry_clear(ae) != NULL);
268228753Smm	archive_entry_copy_pathname(ae, "file_bad_suid");
269228753Smm	archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0742);
270228753Smm	archive_entry_set_uid(ae, getuid() + 1);
271228753Smm	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
272228753Smm	assertA(0 == archive_write_header(a, ae));
273228753Smm	/*
274228753Smm	 * Because we didn't ask for owner, the failure to
275228753Smm	 * restore SUID shouldn't return a failure.
276228753Smm	 * We check below to make sure SUID really wasn't set.
277228753Smm	 * See more detailed comments below.
278228753Smm	 */
279228753Smm	failure("Opportunistic SUID failure shouldn't return error.");
280228753Smm	assertEqualInt(0, archive_write_finish_entry(a));
281228753Smm
282228753Smm        if (getuid() != 0) {
283228753Smm		assert(archive_entry_clear(ae) != NULL);
284228753Smm		archive_entry_copy_pathname(ae, "file_bad_suid2");
285228753Smm		archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0742);
286228753Smm		archive_entry_set_uid(ae, getuid() + 1);
287228753Smm		archive_write_disk_set_options(a,
288228753Smm		    ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_OWNER);
289228753Smm		assertA(0 == archive_write_header(a, ae));
290228753Smm		/* Owner change should fail here. */
291228753Smm		failure("Non-opportunistic SUID failure should return error.");
292228753Smm		assertEqualInt(ARCHIVE_WARN, archive_write_finish_entry(a));
293228753Smm	}
294228753Smm
295228753Smm	/* Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit */
296228753Smm	assert(archive_entry_clear(ae) != NULL);
297228753Smm	archive_entry_copy_pathname(ae, "file_perm_sgid");
298228753Smm	archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
299228753Smm	archive_entry_set_gid(ae, defaultgid());
300228753Smm	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
301302001Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
302228753Smm	failure("Setting SGID bit should succeed here.");
303228753Smm	assertEqualIntA(a, 0, archive_write_finish_entry(a));
304228753Smm
305228753Smm	if (altgid() == -1) {
306228753Smm		/*
307228753Smm		 * Current user must belong to at least two groups or
308228753Smm		 * else we can't test setting the GID to another group.
309228753Smm		 */
310228753Smm		skipping("Current user can't test gid restore: must belong to more than one group.");
311228753Smm	} else {
312228753Smm		/*
313228753Smm		 * Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit
314228753Smm		 * but without ARCHIVE_EXTRACT_OWNER.
315228753Smm		 */
316228753Smm		/*
317228753Smm		 * This is a weird case: The user has asked for permissions to
318228753Smm		 * be restored but not asked for ownership to be restored.  As
319228753Smm		 * a result, the default file creation will create a file with
320228753Smm		 * the wrong group.  There are several possible behaviors for
321228753Smm		 * libarchive in this scenario:
322228753Smm		 *  = Set the SGID bit.  It is wrong and a security hole to
323228753Smm		 *    set SGID with the wrong group.  Even POSIX thinks so.
324228753Smm		 *  = Implicitly set the group.  I don't like this.
325228753Smm		 *  = drop the SGID bit and warn (the old libarchive behavior)
326228753Smm		 *  = drop the SGID bit and don't warn (the current libarchive
327228753Smm		 *    behavior).
328228753Smm		 * The current behavior sees SGID/SUID restore when you
329228753Smm		 * don't ask for owner restore as an "opportunistic"
330228753Smm		 * action.  That is, libarchive should do it if it can,
331228753Smm		 * but if it can't, it's not an error.
332228753Smm		 */
333228753Smm		assert(archive_entry_clear(ae) != NULL);
334228753Smm		archive_entry_copy_pathname(ae, "file_alt_sgid");
335228753Smm		archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
336228753Smm		archive_entry_set_uid(ae, getuid());
337228753Smm		archive_entry_set_gid(ae, altgid());
338228753Smm		archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
339302001Smm		assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
340228753Smm		failure("Setting SGID bit should fail because of group mismatch but the failure should be silent because we didn't ask for the group to be set.");
341228753Smm		assertEqualIntA(a, 0, archive_write_finish_entry(a));
342228753Smm
343228753Smm		/*
344228753Smm		 * As above, but add _EXTRACT_OWNER to verify that it
345228753Smm		 * does succeed.
346228753Smm		 */
347228753Smm		assert(archive_entry_clear(ae) != NULL);
348228753Smm		archive_entry_copy_pathname(ae, "file_alt_sgid_owner");
349228753Smm		archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
350228753Smm		archive_entry_set_uid(ae, getuid());
351228753Smm		archive_entry_set_gid(ae, altgid());
352228753Smm		archive_write_disk_set_options(a,
353228753Smm		    ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_OWNER);
354302001Smm		assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
355228753Smm		failure("Setting SGID bit should succeed here.");
356228753Smm		assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
357228753Smm	}
358228753Smm
359228753Smm	/*
360228753Smm	 * Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit,
361228753Smm	 * but wrong GID.  POSIX says you shouldn't restore SGID bit
362228753Smm	 * unless the GID could be restored.
363228753Smm	 */
364228753Smm	if (invalidgid() == -1) {
365228753Smm		/* This test always fails for root. */
366228753Smm		printf("Running as root: Can't test SGID failures.\n");
367228753Smm	} else {
368228753Smm		assert(archive_entry_clear(ae) != NULL);
369228753Smm		archive_entry_copy_pathname(ae, "file_bad_sgid");
370228753Smm		archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
371228753Smm		archive_entry_set_gid(ae, invalidgid());
372228753Smm		archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
373228753Smm		assertA(0 == archive_write_header(a, ae));
374228753Smm		failure("This SGID restore should fail without an error.");
375228753Smm		assertEqualIntA(a, 0, archive_write_finish_entry(a));
376228753Smm
377228753Smm		assert(archive_entry_clear(ae) != NULL);
378228753Smm		archive_entry_copy_pathname(ae, "file_bad_sgid2");
379228753Smm		archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
380228753Smm		archive_entry_set_gid(ae, invalidgid());
381228753Smm		archive_write_disk_set_options(a,
382228753Smm		    ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_OWNER);
383228753Smm		assertA(0 == archive_write_header(a, ae));
384228753Smm		failure("This SGID restore should fail with an error.");
385228753Smm		assertEqualIntA(a, ARCHIVE_WARN, archive_write_finish_entry(a));
386228753Smm	}
387228753Smm
388228753Smm	/* Set ownership should fail if we're not root. */
389228753Smm	if (getuid() == 0) {
390228753Smm		printf("Running as root: Can't test setuid failures.\n");
391228753Smm	} else {
392228753Smm		assert(archive_entry_clear(ae) != NULL);
393228753Smm		archive_entry_copy_pathname(ae, "file_bad_owner");
394228753Smm		archive_entry_set_mode(ae, S_IFREG | 0744);
395228753Smm		archive_entry_set_uid(ae, getuid() + 1);
396228753Smm		archive_write_disk_set_options(a, ARCHIVE_EXTRACT_OWNER);
397228753Smm		assertA(0 == archive_write_header(a, ae));
398228753Smm		assertEqualIntA(a,ARCHIVE_WARN,archive_write_finish_entry(a));
399228753Smm	}
400228753Smm
401232153Smm	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
402228753Smm	archive_entry_free(ae);
403228753Smm
404228753Smm	/* Test the entries on disk. */
405302001Smm	assertEqualInt(0, stat("file_0755", &st));
406228753Smm	failure("file_0755: st.st_mode=%o", st.st_mode);
407302001Smm	assertEqualInt(st.st_mode & 07777, 0755);
408228753Smm
409302001Smm	assertEqualInt(0, stat("file_overwrite_0144", &st));
410228753Smm	failure("file_overwrite_0144: st.st_mode=%o", st.st_mode);
411302001Smm	assertEqualInt(st.st_mode & 07777, 0144);
412228753Smm
413302001Smm	assertEqualInt(0, stat("dir_0514", &st));
414228753Smm	failure("dir_0514: st.st_mode=%o", st.st_mode);
415302001Smm	assertEqualInt(st.st_mode & 07777, 0514);
416228753Smm
417302001Smm	assertEqualInt(0, stat("dir_overwrite_0744", &st));
418228753Smm	failure("dir_overwrite_0744: st.st_mode=%o", st.st_mode);
419302001Smm	assertEqualInt(st.st_mode & 0777, 0744);
420228753Smm
421302001Smm	assertEqualInt(0, stat("file_no_suid", &st));
422228753Smm	failure("file_0755: st.st_mode=%o", st.st_mode);
423302001Smm	assertEqualInt(st.st_mode & 07777, 0755);
424228753Smm
425302001Smm	assertEqualInt(0, stat("file_0777", &st));
426228753Smm	failure("file_0777: st.st_mode=%o", st.st_mode);
427302001Smm	assertEqualInt(st.st_mode & 07777, 0777);
428228753Smm
429228753Smm	/* SUID bit should get set here. */
430302001Smm	assertEqualInt(0, stat("file_4742", &st));
431228753Smm	failure("file_4742: st.st_mode=%o", st.st_mode);
432302001Smm	assertEqualInt(st.st_mode & 07777, S_ISUID | 0742);
433228753Smm
434228753Smm	/* SUID bit should NOT have been set here. */
435302001Smm	assertEqualInt(0, stat("file_bad_suid", &st));
436228753Smm	failure("file_bad_suid: st.st_mode=%o", st.st_mode);
437302001Smm	assertEqualInt(st.st_mode & 07777, 0742);
438228753Smm
439228753Smm	/* Some things don't fail if you're root, so suppress this. */
440228753Smm	if (getuid() != 0) {
441228753Smm		/* SUID bit should NOT have been set here. */
442302001Smm		assertEqualInt(0, stat("file_bad_suid2", &st));
443228753Smm		failure("file_bad_suid2: st.st_mode=%o", st.st_mode);
444302001Smm		assertEqualInt(st.st_mode & 07777, 0742);
445228753Smm	}
446228753Smm
447228753Smm	/* SGID should be set here. */
448302001Smm	assertEqualInt(0, stat("file_perm_sgid", &st));
449228753Smm	failure("file_perm_sgid: st.st_mode=%o", st.st_mode);
450302001Smm	assertEqualInt(st.st_mode & 07777, S_ISGID | 0742);
451228753Smm
452228753Smm	if (altgid() != -1) {
453228753Smm		/* SGID should not be set here. */
454302001Smm		assertEqualInt(0, stat("file_alt_sgid", &st));
455228753Smm		failure("file_alt_sgid: st.st_mode=%o", st.st_mode);
456302001Smm		assertEqualInt(st.st_mode & 07777, 0742);
457228753Smm
458228753Smm		/* SGID should be set here. */
459302001Smm		assertEqualInt(0, stat("file_alt_sgid_owner", &st));
460228753Smm		failure("file_alt_sgid: st.st_mode=%o", st.st_mode);
461302001Smm		assertEqualInt(st.st_mode & 07777, S_ISGID | 0742);
462228753Smm	}
463228753Smm
464228753Smm	if (invalidgid() != -1) {
465228753Smm		/* SGID should NOT be set here. */
466302001Smm		assertEqualInt(0, stat("file_bad_sgid", &st));
467228753Smm		failure("file_bad_sgid: st.st_mode=%o", st.st_mode);
468302001Smm		assertEqualInt(st.st_mode & 07777, 0742);
469228753Smm		/* SGID should NOT be set here. */
470302001Smm		assertEqualInt(0, stat("file_bad_sgid2", &st));
471228753Smm		failure("file_bad_sgid2: st.st_mode=%o", st.st_mode);
472302001Smm		assertEqualInt(st.st_mode & 07777, 0742);
473228753Smm	}
474228753Smm
475228753Smm	if (getuid() != 0) {
476302001Smm		assertEqualInt(0, stat("file_bad_owner", &st));
477228753Smm		failure("file_bad_owner: st.st_mode=%o", st.st_mode);
478302001Smm		assertEqualInt(st.st_mode & 07777, 0744);
479228753Smm		failure("file_bad_owner: st.st_uid=%d getuid()=%d",
480228753Smm		    st.st_uid, getuid());
481228753Smm		/* The entry had getuid()+1, but because we're
482228753Smm		 * not root, we should not have been able to set that. */
483302001Smm		assertEqualInt(st.st_uid, getuid());
484228753Smm	}
485228753Smm#endif
486228753Smm}
487