2 * Copyright (c) 2006 nCircle Network Security, Inc.
5 * This software was developed by Robert N. M. Watson for the TrustedBSD
6 * Project under contract to nCircle Network Security, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
21 * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * Check that privilege is required for a variety of administrative
34 * activities on a file owned by another user. Admin privileges are required
35 * for the following services:
38 * - Set utimes to non-NULL.
40 * - Set file ownership.
41 * - Remove a file from a sticky directory. (XXXRW: Not tested here.)
42 * - Set the ACL on a file. (XXXRW: Not tested here.)
43 * - Delete the ACL on a file. (XXXRW: Not tested here.)
46 #include <sys/types.h>
58 getflags(char *fpathp)
62 if (stat(fpathp, &sb) < 0)
63 err(-1, "stat(%s)", fpathp);
69 priv_vfs_admin_chflags(void)
76 * Test that setting file flags works as and not as the file owner
77 * when running with privilege, but only as the file owner when
78 * running without privilege.
80 setup_file(fpath, UID_ROOT, GID_WHEEL, 0600);
81 flags = getflags(fpath);
83 if (chflags(fpath, flags) < 0) {
84 warn("chflags(%s, UF_NODUMP) owner as root", fpath);
89 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
90 flags = getflags(fpath);
92 if (chflags(fpath, flags) < 0) {
93 warn("chflags(%s, UF_NODUMP) !owner as root", fpath);
98 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
99 flags = getflags(fpath);
102 if (chflags(fpath, flags) < 0) {
103 warn("chflags(%s, UF_NODUMP) owner as !root", fpath);
109 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
110 flags = getflags(fpath);
113 error = chflags(fpath, flags);
115 warnx("chflags(%s, UF_NODUMP) succeeded !owner as !root",
119 if (errno != EPERM) {
120 warn("chflags(%s, UF_NODUMP) wrong errno %d !owner a !root",
128 (void)seteuid(UID_ROOT);
133 priv_vfs_admin_utimes(void)
135 struct timeval tv[2];
140 * Actual values don't matter here.
148 * When using a non-NULL argument to utimes(), must either hold
149 * privilege or be the file owner. Check all four possible
150 * combinations of privilege, ownership.
152 setup_file(fpath, UID_ROOT, GID_WHEEL, 0600);
153 if (utimes(fpath, tv) < 0) {
154 warn("utimes(%s, !NULL) owner as root", fpath);
159 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
160 if (utimes(fpath, tv) < 0) {
161 warn("utimes(%s, !NULL) !owner as root", fpath);
166 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
168 if (utimes(fpath, tv) < 0) {
169 warn("utimes(%s, !NULL) owner as !root", fpath);
175 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
177 error = utimes(fpath, tv);
179 warnx("utimes(%s, !NULL) succeeded !owner as !root",
183 if (errno != EPERM) {
184 warn("utimes(%s, !NULL) wrong errno %d !owner a !root",
192 (void)seteuid(UID_ROOT);
197 priv_vfs_admin_chmod(void)
203 * Test that setting file permissions works either as file owner or
204 * not when running with privilege, but only as file owner when
205 * running without privilege.
207 setup_file(fpath, UID_ROOT, GID_WHEEL, 0600);
208 if (chmod(fpath, 0640) < 0) {
209 warn("chmod(%s, 0640) owner as root", fpath);
214 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
215 if (chmod(fpath, 0640) < 0) {
216 warn("chmod(%s, 0640) !owner as root", fpath);
221 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
223 if (chmod(fpath, 0640) < 0) {
224 warn("chmod(%s, 0640) owner as !root", fpath);
230 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
232 error = chmod(fpath, 0640);
234 warnx("chmod(%s, 0640) succeeded !owner as !root",
238 if (errno != EPERM) {
239 warn("chmod(%s, 0640) wrong errno %d !owner a !root",
247 (void)seteuid(UID_ROOT);
251 static const gid_t gidset[] = { GID_WHEEL, GID_OWNER, GID_OTHER};
254 priv_vfs_admin_chown(void)
260 * Test that the group of the file can only be changed with privilege
261 * or as the owner. These test is run last as it frobs the group
262 * context. We change the file group from one group we're in to
263 * another we're in to avoid any other access control checks failing.
265 if (setgroups(3, gidset) < 0)
266 err(-1, "priv_vfs_admin_chown:setgroups(3, {%d, %d, %d})",
267 GID_WHEEL, GID_OWNER, GID_OTHER);
270 * Test that setting file permissions works either as file owner or
271 * not when running with privilege, but only as file owner when
272 * running without privilege.
274 setup_file(fpath, UID_ROOT, GID_WHEEL, 0600);
275 if (chown(fpath, -1, GID_OWNER) < 0) {
276 warn("chown(%s, %d) owner as root", fpath, GID_OWNER);
281 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
282 if (chown(fpath, -1, GID_OWNER) < 0) {
283 warn("chown(%s, %d) !owner as root", fpath, GID_OWNER);
288 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
290 if (chown(fpath, -1, GID_OWNER) < 0) {
291 warn("chown(%s, %d) owner as !root", fpath, GID_OWNER);
297 setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
299 error = chown(fpath, -1, GID_OWNER);
301 warnx("chown(%s, %d) succeeded !owner as !root",
305 if (errno != EPERM) {
306 warn("chown(%s, %d) wrong errno %d !owner a !root",
307 fpath, GID_OWNER, errno);
314 (void)seteuid(UID_ROOT);
324 priv_vfs_admin_chflags();
325 priv_vfs_admin_utimes();
326 priv_vfs_admin_chmod();
327 priv_vfs_admin_chown(); /* Run this last. */