1/*-
2 * Copyright (c) 2006 nCircle Network Security, Inc.
3 * Copyright (c) 2007 Robert M. M. Watson
4 * All rights reserved.
5 *
6 * This software was developed by Robert N. M. Watson for the TrustedBSD
7 * Project under contract to nCircle Network Security, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
22 * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $FreeBSD$
31 */
32
33/*
34 * Confirm that privilege is required in the cases using chown():
35 *
36 * - If the process euid does not match the file uid.
37 *
38 * - If the target uid is different than the current uid.
39 *
40 * - If the target gid changes and we the process is not a member of the new
41 *   group.
42 */
43
44#include <sys/types.h>
45#include <sys/stat.h>
46
47#include <err.h>
48#include <errno.h>
49#include <stdio.h>
50#include <unistd.h>
51
52#include "main.h"
53
54static char fpath[1024];
55static int fpath_initialized;
56
57/*
58 * Check that changing the uid of a file requires privilege.
59 */
60int
61priv_vfs_chown_uid_setup(int asroot, int injail, struct test *test)
62{
63
64	setup_file("priv_vfs_chown_uid: fpath", fpath, UID_ROOT, GID_WHEEL,
65	    0600);
66	fpath_initialized = 1;
67	return (0);
68}
69
70void
71priv_vfs_chown_uid(int asroot, int injail, struct test *test)
72{
73	int error;
74
75	error = chown(fpath, UID_OWNER, -1);
76	if (asroot && injail)
77		expect("priv_vfs_chown_uid(root, jail)", error, 0, 0);
78	if (asroot && !injail)
79		expect("priv_vfs_chown_uid(root, !jail)", error, 0, 0);
80	if (!asroot && injail)
81		expect("priv_vfs_chown_uid(!root, jail)", error, -1, EPERM);
82	if (!asroot && !injail)
83		expect("priv_vfs_chown_uid(!root, !jail)", error, -1, EPERM);
84}
85
86/*
87 * Check that changing the gid of a file owned by the user is allowed without
88 * privilege as long as the gid matches the process.
89 */
90int
91priv_vfs_chown_mygid_setup(int asroot, int injail, struct test *test)
92{
93
94	/*
95	 * Create a file with a matching uid to the test process, but not a
96	 * matching gid.
97	 */
98	setup_file("priv_vfs_chown_mygid: fpath", fpath, asroot ? UID_ROOT :
99	    UID_OWNER, GID_OTHER, 0600);
100	fpath_initialized = 1;
101	return (0);
102}
103
104void
105priv_vfs_chown_mygid(int asroot, int injail, struct test *test)
106{
107	int error;
108
109	error = chown(fpath, -1, asroot ? GID_WHEEL : GID_OWNER);
110	if (asroot && injail)
111		expect("priv_vfs_chown_mygid(root, jail)", error, 0, 0);
112	if (asroot && !injail)
113		expect("priv_vfs_chown_mygid(root, !jail)", error, 0, 0);
114	if (!asroot && injail)
115		expect("priv_vfs_chown_mygid(!root, !jail)", error, 0, 0);
116	if (!asroot && !injail)
117		expect("priv_vfs_chown_mygid(!root, !jail)", error, 0, 0);
118}
119
120/*
121 * Check that changing the gid of a file owned by the user is not allowed
122 * without privilege if the gid doesn't match the process.
123 */
124int
125priv_vfs_chown_othergid_setup(int asroot, int injail, struct test *test)
126{
127
128	/*
129	 * Create a file with a matching uid to the test process with a
130	 * matching gid.
131	 */
132	setup_file("priv_vfs_chown_othergid: fpath", fpath, asroot ? UID_ROOT
133	    : UID_OWNER, asroot ? GID_WHEEL : GID_OWNER, 0600);
134	fpath_initialized = 1;
135	return (0);
136}
137
138void
139priv_vfs_chown_othergid(int asroot, int injail, struct test *test)
140{
141	int error;
142
143	error = chown(fpath, -1, GID_OTHER);
144	if (asroot && injail)
145		expect("priv_vfs_chown_othergid(root, jail)", error, 0, 0);
146	if (asroot && !injail)
147		expect("priv_vfs_chown_othergid(root, !jail)", error, 0, 0);
148	if (!asroot && injail)
149		expect("priv_vfs_chown_othergid(!root, !jail)", error, -1,
150		    EPERM);
151	if (!asroot && !injail)
152		expect("priv_vfs_chown_othergid(!root, !jail)", error, -1,
153		    EPERM);
154}
155
156void
157priv_vfs_chown_cleanup(int asroot, int injail, struct test *test)
158{
159
160	if (fpath_initialized) {
161		(void)unlink(fpath);
162		fpath_initialized = 0;
163	}
164}
165