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