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 
50 static char fpath[1024];
51 static 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  */
58 static u_long
59 getflags(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 
69 int
70 priv_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 
79 int
80 priv_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 
90 int
91 priv_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 
101 void
102 priv_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 
125 void
126 priv_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 
149 void
150 priv_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 
173 void
174 priv_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 
197 void
198 priv_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 
221 void
222 priv_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 
245 void
246 priv_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