1/*-
2 * Copyright (c) 2006 nCircle Network Security, Inc.
3 * Copyright (c) 2007 Robert N. 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 * Test privileges associated with setting file flags on files; whether or
35 * not it requires privilege depends on the flag, and some flags cannot be
36 * set in jail at all.
37 */
38
39#include <sys/types.h>
40#include <sys/stat.h>
41
42#include <err.h>
43#include <errno.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47
48#include "main.h"
49
50static char fpath[1024];
51static int fpath_initialized;
52
53/*
54 * For chflags, we consider three dimmensions: process owner, file owner, and
55 * flag type.  The calling framework handles variations in process owner; the
56 * rest are handled via multiple tests.  One cleanup function is used.
57 */
58static u_long
59getflags(char *fpathp)
60{
61	struct stat sb;
62
63	if (stat(fpathp, &sb) < 0)
64		err(-1, "stat(%s)", fpathp);
65
66	return (sb.st_flags);
67}
68
69int
70priv_vfs_chflags_froot_setup(int asroot, int injail, struct test *test)
71{
72
73	setup_file("priv_vfs_chflags_froot_setup: fpath", fpath, UID_ROOT,
74	    GID_WHEEL, 0600);
75	fpath_initialized = 1;
76	return (0);
77}
78
79int
80priv_vfs_chflags_fowner_setup(int asroot, int injail,
81    struct test *test)
82{
83
84	setup_file("priv_vfs_chflags_fowner_setup: fpath", fpath, UID_OWNER,
85	    GID_OWNER, 0600);
86	fpath_initialized = 1;
87	return (0);
88}
89
90int
91priv_vfs_chflags_fother_setup(int asroot, int injail,
92    struct test *test)
93{
94
95	setup_file("priv_vfs_chflags_fowner_setup: fpath", fpath, UID_OTHER,
96	    GID_OTHER, 0600);
97	fpath_initialized = 1;
98	return (0);
99}
100
101void
102priv_vfs_chflags_froot_uflags(int asroot, int injail,
103    struct test *test)
104{
105	u_long flags;
106	int error;
107
108	flags = getflags(fpath);
109	flags |= UF_NODUMP;
110	error = chflags(fpath, flags);
111	if (asroot && injail)
112		expect("priv_vfs_chflags_froot_uflags(asroot, injail)",
113		    error, 0, 0);
114	if (asroot && !injail)
115		expect("priv_vfs_chflags_froot_uflags(asroot, !injail)",
116		    error, 0, 0);
117	if (!asroot && injail)
118		expect("priv_vfs_chflags_froot_uflags(!asroot, injail)",
119		    error, -1, EPERM);
120	if (!asroot && !injail)
121		expect("priv_vfs_chflags_froot_uflags(!asroot, !injail)",
122		    error, -1, EPERM);
123}
124
125void
126priv_vfs_chflags_fowner_uflags(int asroot, int injail,
127    struct test *test)
128{
129	u_long flags;
130	int error;
131
132	flags = getflags(fpath);
133	flags |= UF_NODUMP;
134	error = chflags(fpath, flags);
135	if (asroot && injail)
136		expect("priv_vfs_chflags_fowner_uflags(asroot, injail)",
137		    error, 0, 0);
138	if (asroot && !injail)
139		expect("priv_vfs_chflags_fowner_uflags(asroot, !injail)",
140		    error, 0, 0);
141	if (!asroot && injail)
142		expect("priv_vfs_chflags_fowner_uflags(!asroot, injail)",
143		    error, 0, 0);
144	if (!asroot && !injail)
145		expect("priv_vfs_chflags_fowner_uflags(!asroot, !injail)",
146		    error, 0, 0);
147}
148
149void
150priv_vfs_chflags_fother_uflags(int asroot, int injail,
151    struct test *test)
152{
153	u_long flags;
154	int error;
155
156	flags = getflags(fpath);
157	flags |= UF_NODUMP;
158	error = chflags(fpath, flags);
159	if (asroot && injail)
160		expect("priv_vfs_chflags_fother_uflags(asroot, injail)",
161		    error, 0, 0);
162	if (asroot && !injail)
163		expect("priv_vfs_chflags_fother_uflags(asroot, !injail)",
164		    error, 0, 0);
165	if (!asroot && injail)
166		expect("priv_vfs_chflags_fother_uflags(!asroot, injail)",
167		    error, -1, EPERM);
168	if (!asroot && !injail)
169		expect("priv_vfs_chflags_fother_uflags(!asroot, !injail)",
170		    error, -1, EPERM);
171}
172
173void
174priv_vfs_chflags_froot_sflags(int asroot, int injail,
175    struct test *test)
176{
177	u_long flags;
178	int error;
179
180	flags = getflags(fpath);
181	flags |= SF_ARCHIVED;
182	error = chflags(fpath, flags);
183	if (asroot && injail)
184		expect("priv_vfs_chflags_froot_sflags(asroot, injail)",
185		    error, -1, EPERM);
186	if (asroot && !injail)
187		expect("priv_vfs_chflags_froot_sflags(asroot, !injail)",
188		    error, 0, 0);
189	if (!asroot && injail)
190		expect("priv_vfs_chflags_froot_sflags(!asroot, injail)",
191		    error, -1, EPERM);
192	if (!asroot && !injail)
193		expect("priv_vfs_chflags_froot_sflags(!asroot, !injail)",
194		    error, -1, EPERM);
195}
196
197void
198priv_vfs_chflags_fowner_sflags(int asroot, int injail,
199    struct test *test)
200{
201	u_long flags;
202	int error;
203
204	flags = getflags(fpath);
205	flags |= SF_ARCHIVED;
206	error = chflags(fpath, flags);
207	if (asroot && injail)
208		expect("priv_vfs_chflags_fowner_sflags(asroot, injail)",
209		    error, -1, EPERM);
210	if (asroot && !injail)
211		expect("priv_vfs_chflags_fowner_sflags(asroot, !injail)",
212		    error, 0, 0);
213	if (!asroot && injail)
214		expect("priv_vfs_chflags_fowner_sflags(!asroot, injail)",
215		    error, -1, EPERM);
216	if (!asroot && !injail)
217		expect("priv_vfs_chflags_fowner_sflags(!asroot, !injail)",
218		    error, -1, EPERM);
219}
220
221void
222priv_vfs_chflags_fother_sflags(int asroot, int injail,
223    struct test *test)
224{
225	u_long flags;
226	int error;
227
228	flags = getflags(fpath);
229	flags |= SF_ARCHIVED;
230	error = chflags(fpath, flags);
231	if (asroot && injail)
232		expect("priv_vfs_chflags_fother_sflags(asroot, injail)",
233		    error, -1, EPERM);
234	if (asroot && !injail)
235		expect("priv_vfs_chflags_fother_sflags(asroot, !injail)",
236		    error, 0, 0);
237	if (!asroot && injail)
238		expect("priv_vfs_chflags_fother_sflags(!asroot, injail)",
239		    error, -1, EPERM);
240	if (!asroot && !injail)
241		expect("priv_vfs_chflags_fother_sflags(!asroot, !injail)",
242		    error, -1, EPERM);
243}
244
245void
246priv_vfs_chflags_cleanup(int asroot, int injail, struct test *test)
247{
248
249	if (fpath_initialized) {
250		(void)chflags(fpath, 0);
251		(void)unlink(fpath);
252		fpath_initialized = 0;
253	}
254}
255