]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/regression/security/access/testaccess.c
stress2: Added a few regression tests
[FreeBSD/FreeBSD.git] / tools / regression / security / access / testaccess.c
1 /*-
2  * Copyright (c) 2001 Networks Associates Technology, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Written at NAI Labs at Network Associates by Robert Watson for the
27  * TrustedBSD Project.
28  *
29  * Work sponsored by Defense Advanced Research Projects Agency under the
30  * CHATS research program, CBOSS project.
31  */
32
33 #include <sys/types.h>
34
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40
41 /*
42  * Regression test to check some basic cases and see if access() and
43  * eaccess() are using the correct portions of the process credential.
44  * This test relies on running with privilege, and on UFS filesystem
45  * semantics.  Running the test in other environments may result
46  * in incorrect failure identification.
47  *
48  * Note that this may also break if filesystem access control is
49  * broken, or if the ability to check and set credentials is broken.
50  *
51  * Note that this test uses two hard-coded non-root UIDs; on multi-user
52  * systems, these UIDs may be in use by an untrusted user, in which
53  * case those users could interfere with the test.
54  */
55
56 #define ROOT_UID        (uid_t)0
57 #define WHEEL_GID       (gid_t)0
58 #define TEST_UID_ONE    (uid_t)500
59 #define TEST_GID_ONE    (gid_t)500
60 #define TEST_UID_TWO    (uid_t)501
61 #define TEST_GID_TWO    (gid_t)501
62
63 struct file_description {
64         char    *fd_name;
65         uid_t    fd_owner;
66         gid_t    fd_group;
67         mode_t   fd_mode;
68 };
69
70 static struct file_description fd_list[] = {
71 {"test1", ROOT_UID, WHEEL_GID, 0400},
72 {"test2", TEST_UID_ONE, WHEEL_GID,0400},
73 {"test3", TEST_UID_TWO, WHEEL_GID, 0400},
74 {"test4", ROOT_UID, WHEEL_GID, 0040},
75 {"test5", ROOT_UID, TEST_GID_ONE, 0040},
76 {"test6", ROOT_UID, TEST_GID_TWO, 0040}};
77
78 static int fd_list_count = sizeof(fd_list) /
79     sizeof(struct file_description);
80
81 int
82 setup(void)
83 {
84         int i, error;
85
86         for (i = 0; i < fd_list_count; i++) {
87                 error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode);
88                 if (error == -1) {
89                         perror("open");
90                         return (error);
91                 }
92                 close(error);
93                 error = chown(fd_list[i].fd_name, fd_list[i].fd_owner,
94                     fd_list[i].fd_group);
95                 if (error) {
96                         perror("chown");
97                         return (error);
98                 }
99         }
100         return (0);
101 }
102
103 int
104 restoreprivilege(void)
105 {
106         int error;
107
108         error = setreuid(ROOT_UID, ROOT_UID);
109         if (error)
110                 return (error);
111
112         error = setregid(WHEEL_GID, WHEEL_GID);
113         if (error)
114                 return (error);
115
116         return (0);
117 }
118
119 int
120 reportprivilege(char *message)
121 {
122         uid_t euid, ruid, suid;
123         gid_t egid, rgid, sgid;
124         int error;
125
126         error = getresuid(&ruid, &euid, &suid);
127         if (error) {
128                 perror("getresuid");
129                 return (error);
130         }
131
132         error = getresgid(&rgid, &egid, &sgid);
133         if (error) {
134                 perror("getresgid");
135                 return (error);
136         }
137
138         if (message)
139                 printf("%s: ", message);
140         printf("ruid: %d, euid: %d, suid: %d,     ", ruid, euid, suid);
141         printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid);
142
143         return (0);
144 }
145
146 int
147 cleanup(void)
148 {
149         int i, error;
150
151         error = restoreprivilege();
152         if (error) {
153                 perror("restoreprivilege");
154                 return (error);
155         }
156
157         for (i = 0; i < fd_list_count; i++) {
158                 error = unlink(fd_list[i].fd_name);
159                 if (error)
160                         return (error);
161         }
162
163         return (0);
164 }
165
166 int
167 main(int argc, char *argv[])
168 {
169         int error, errorseen;
170
171         if (geteuid() != 0) {
172                 fprintf(stderr, "testaccess must run as root.\n");
173                 exit (EXIT_FAILURE);
174         }
175
176         error = setup();
177         if (error) {
178                 cleanup();
179                 exit (EXIT_FAILURE);
180         }
181
182         /* Make sure saved uid is set appropriately. */
183         error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID);
184         if (error) {
185                 perror("setresuid");
186                 cleanup();
187         }
188
189         /* Clear out additional groups. */
190         error = setgroups(0, NULL);
191         if (error) {
192                 perror("setgroups");
193                 cleanup();
194         }
195
196         /* Make sure saved gid is set appropriately. */
197         error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID);
198         if (error) {
199                 perror("setresgid");
200                 cleanup();
201         }
202
203         /*
204          * UID-only tests.
205          */
206
207         /* Check that saved uid is not used */
208         error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
209         if (error) {
210                 perror("setresuid.1");
211                 cleanup();
212                 exit (EXIT_FAILURE);
213         }
214
215         errorseen = 0;
216
217         error = access("test1", R_OK);
218         if (!error) {
219                 fprintf(stderr, "saved uid used instead of real uid\n");
220                 errorseen++;
221         }
222
223 #ifdef EACCESS_AVAILABLE
224         error = eaccess("test1", R_OK);
225         if (!error) {
226                 fprintf(stderr, "saved uid used instead of effective uid\n");
227                 errorseen++;
228         }
229 #endif
230
231         error = restoreprivilege();
232         if (error) {
233                 perror("restoreprivilege");
234                 cleanup();
235                 exit (EXIT_FAILURE);
236         }
237
238         error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID);
239         if (error) {
240                 perror("setresid.2");
241                 cleanup();
242                 exit (EXIT_FAILURE);
243         }
244
245         /* Check that the real uid is used, not the effective uid */
246         error = access("test2", R_OK);
247         if (error) {
248                 fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
249                 errorseen++;
250         }
251
252 #ifdef EACCESS_AVAILABLE
253         /* Check that the effective uid is used, not the real uid */
254         error = eaccess("test3", R_OK);
255         if (error) {
256                 fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
257                 errorseen++;
258         }
259 #endif
260
261         /* Check that the real uid is used, not the effective uid */
262         error = access("test3", R_OK);
263         if (!error) {
264                 fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
265                 errorseen++;
266         }
267
268 #ifdef EACCESS_AVAILABLE
269         /* Check that the effective uid is used, not the real uid */
270         error = eaccess("test2", R_OK);
271         if (!error) {
272                 fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
273                 errorseen++;
274         }
275 #endif
276
277         error = restoreprivilege();
278         if (error) {
279                 perror("restoreprivilege");
280                 cleanup();
281                 exit (EXIT_FAILURE);
282         }
283
284         error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID);
285         if (error) {
286                 perror("setresgid.1");
287                 cleanup();
288                 exit (EXIT_FAILURE);
289         }
290
291         /* Set non-root effective uid to avoid excess privilege. */
292         error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
293         if (error) {
294                 perror("setresuid.3");
295                 cleanup();
296                 exit (EXIT_FAILURE);
297         }
298
299         /* Check that the saved gid is not used */
300         error = access("test4", R_OK);
301         if (!error) {
302                 fprintf(stderr, "saved gid used instead of real gid\n");
303         }
304
305 #ifdef EACCESS_AVAILABLE
306         error = eaccess("test4", R_OK);
307         if (!error) {
308                 fprintf(stderr, "saved gid used instead of effective gid\n");
309                 errorseen++;
310         }
311 #endif
312
313         /* Check that the real gid is used, not the effective gid */
314         error = access("test5", R_OK);
315         if (error) {
316                 fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
317                 errorseen++;
318         }
319
320 #ifdef EACCESS_AVAILABLE
321         /* Check that the effective gid is used, not the real gid */
322         error = eaccess("test6", R_OK);
323         if (error) {
324                 fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
325                 errorseen++;
326         }
327 #endif
328
329         /* Check that the real gid is used, not the effective gid */
330         error = access("test6", R_OK);
331         if (!error) {
332                 fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
333                 errorseen++;
334         }
335
336 #ifdef EACCESS_AVAILABLE
337         /* Check that the effective gid is used, not the real gid */
338         error = eaccess("test5", R_OK);
339         if (!error) {
340                 fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
341                 errorseen++;
342         }
343 #endif
344
345         fprintf(stderr, "%d errors seen.\n", errorseen);
346
347         /*
348          * All tests done, restore and clean up
349          */
350
351         error = cleanup();
352         if (error) {
353                 perror("cleanup");
354                 exit (EXIT_FAILURE);
355         }
356
357         exit (EXIT_SUCCESS);
358 }