]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/regression/security/access/testaccess.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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  * $FreeBSD$
33  */
34
35 #include <sys/types.h>
36
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42
43 /*
44  * Regression test to check some basic cases and see if access() and
45  * eaccess() are using the correct portions of the process credential.
46  * This test relies on running with privilege, and on UFS filesystem
47  * semantics.  Running the test in other environments may result
48  * in incorrect failure identification.
49  *
50  * Note that this may also break if filesystem access control is
51  * broken, or if the ability to check and set credentials is broken.
52  *
53  * Note that this test uses two hard-coded non-root UIDs; on multi-user
54  * systems, these UIDs may be in use by an untrusted user, in which
55  * case those users could interfere with the test.
56  */
57
58 #define ROOT_UID        (uid_t)0
59 #define WHEEL_GID       (gid_t)0
60 #define TEST_UID_ONE    (uid_t)500
61 #define TEST_GID_ONE    (gid_t)500
62 #define TEST_UID_TWO    (uid_t)501
63 #define TEST_GID_TWO    (gid_t)501
64
65 struct file_description {
66         char    *fd_name;
67         uid_t    fd_owner;
68         gid_t    fd_group;
69         mode_t   fd_mode;
70 };
71
72 static struct file_description fd_list[] = {
73 {"test1", ROOT_UID, WHEEL_GID, 0400},
74 {"test2", TEST_UID_ONE, WHEEL_GID,0400},
75 {"test3", TEST_UID_TWO, WHEEL_GID, 0400},
76 {"test4", ROOT_UID, WHEEL_GID, 0040},
77 {"test5", ROOT_UID, TEST_GID_ONE, 0040},
78 {"test6", ROOT_UID, TEST_GID_TWO, 0040}};
79
80 static int fd_list_count = sizeof(fd_list) /
81     sizeof(struct file_description);
82
83 int
84 setup(void)
85 {
86         int i, error;
87
88         for (i = 0; i < fd_list_count; i++) {
89                 error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode);
90                 if (error == -1) {
91                         perror("open");
92                         return (error);
93                 }
94                 close(error);
95                 error = chown(fd_list[i].fd_name, fd_list[i].fd_owner,
96                     fd_list[i].fd_group);
97                 if (error) {
98                         perror("chown");
99                         return (error);
100                 }
101         }
102         return (0);
103 }
104
105 int
106 restoreprivilege(void)
107 {
108         int error;
109
110         error = setreuid(ROOT_UID, ROOT_UID);
111         if (error)
112                 return (error);
113
114         error = setregid(WHEEL_GID, WHEEL_GID);
115         if (error)
116                 return (error);
117
118         return (0);
119 }
120
121 int
122 reportprivilege(char *message)
123 {
124         uid_t euid, ruid, suid;
125         gid_t egid, rgid, sgid;
126         int error;
127
128         error = getresuid(&ruid, &euid, &suid);
129         if (error) {
130                 perror("getresuid");
131                 return (error);
132         }
133
134         error = getresgid(&rgid, &egid, &sgid);
135         if (error) {
136                 perror("getresgid");
137                 return (error);
138         }
139
140         if (message)
141                 printf("%s: ", message);
142         printf("ruid: %d, euid: %d, suid: %d,     ", ruid, euid, suid);
143         printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid);
144
145         return (0);
146 }
147
148 int
149 cleanup(void)
150 {
151         int i, error;
152
153         error = restoreprivilege();
154         if (error) {
155                 perror("restoreprivilege");
156                 return (error);
157         }
158
159         for (i = 0; i < fd_list_count; i++) {
160                 error = unlink(fd_list[i].fd_name);
161                 if (error)
162                         return (error);
163         }
164
165         return (0);
166 }
167
168 int
169 main(int argc, char *argv[])
170 {
171         int error, errorseen;
172
173         if (geteuid() != 0) {
174                 fprintf(stderr, "testaccess must run as root.\n");
175                 exit (EXIT_FAILURE);
176         }
177
178         error = setup();
179         if (error) {
180                 cleanup();
181                 exit (EXIT_FAILURE);
182         }
183
184         /* Make sure saved uid is set appropriately. */
185         error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID);
186         if (error) {
187                 perror("setresuid");
188                 cleanup();
189         }
190
191         /* Clear out additional groups. */
192         error = setgroups(0, NULL);
193         if (error) {
194                 perror("setgroups");
195                 cleanup();
196         }
197
198         /* Make sure saved gid is set appropriately. */
199         error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID);
200         if (error) {
201                 perror("setresgid");
202                 cleanup();
203         }
204
205         /*
206          * UID-only tests.
207          */
208
209         /* Check that saved uid is not used */
210         error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
211         if (error) {
212                 perror("setresuid.1");
213                 cleanup();
214                 exit (EXIT_FAILURE);
215         }
216
217         errorseen = 0;
218
219         error = access("test1", R_OK);
220         if (!error) {
221                 fprintf(stderr, "saved uid used instead of real uid\n");
222                 errorseen++;
223         }
224
225 #ifdef EACCESS_AVAILABLE
226         error = eaccess("test1", R_OK);
227         if (!error) {
228                 fprintf(stderr, "saved uid used instead of effective uid\n");
229                 errorseen++;
230         }
231 #endif
232
233         error = restoreprivilege();
234         if (error) {
235                 perror("restoreprivilege");
236                 cleanup();
237                 exit (EXIT_FAILURE);
238         }
239
240         error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID);
241         if (error) {
242                 perror("setresid.2");
243                 cleanup();
244                 exit (EXIT_FAILURE);
245         }
246
247         /* Check that the real uid is used, not the effective uid */
248         error = access("test2", R_OK);
249         if (error) {
250                 fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
251                 errorseen++;
252         }
253
254 #ifdef EACCESS_AVAILABLE
255         /* Check that the effective uid is used, not the real uid */
256         error = eaccess("test3", R_OK);
257         if (error) {
258                 fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
259                 errorseen++;
260         }
261 #endif
262
263         /* Check that the real uid is used, not the effective uid */
264         error = access("test3", R_OK);
265         if (!error) {
266                 fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
267                 errorseen++;
268         }
269
270 #ifdef EACCESS_AVAILABLE
271         /* Check that the effective uid is used, not the real uid */
272         error = eaccess("test2", R_OK);
273         if (!error) {
274                 fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
275                 errorseen++;
276         }
277 #endif
278
279         error = restoreprivilege();
280         if (error) {
281                 perror("restoreprivilege");
282                 cleanup();
283                 exit (EXIT_FAILURE);
284         }
285
286         error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID);
287         if (error) {
288                 perror("setresgid.1");
289                 cleanup();
290                 exit (EXIT_FAILURE);
291         }
292
293         /* Set non-root effective uid to avoid excess privilege. */
294         error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
295         if (error) {
296                 perror("setresuid.3");
297                 cleanup();
298                 exit (EXIT_FAILURE);
299         }
300
301         /* Check that the saved gid is not used */
302         error = access("test4", R_OK);
303         if (!error) {
304                 fprintf(stderr, "saved gid used instead of real gid\n");
305         }
306
307 #ifdef EACCESS_AVAILABLE
308         error = eaccess("test4", R_OK);
309         if (!error) {
310                 fprintf(stderr, "saved gid used instead of effective gid\n");
311                 errorseen++;
312         }
313 #endif
314
315         /* Check that the real gid is used, not the effective gid */
316         error = access("test5", R_OK);
317         if (error) {
318                 fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
319                 errorseen++;
320         }
321
322 #ifdef EACCESS_AVAILABLE
323         /* Check that the effective gid is used, not the real gid */
324         error = eaccess("test6", R_OK);
325         if (error) {
326                 fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
327                 errorseen++;
328         }
329 #endif
330
331         /* Check that the real gid is used, not the effective gid */
332         error = access("test6", R_OK);
333         if (!error) {
334                 fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
335                 errorseen++;
336         }
337
338 #ifdef EACCESS_AVAILABLE
339         /* Check that the effective gid is used, not the real gid */
340         error = eaccess("test5", R_OK);
341         if (!error) {
342                 fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
343                 errorseen++;
344         }
345 #endif
346
347         fprintf(stderr, "%d errors seen.\n", errorseen);
348
349         /*
350          * All tests done, restore and clean up
351          */
352
353         error = cleanup();
354         if (error) {
355                 perror("cleanup");
356                 exit (EXIT_FAILURE);
357         }
358
359         exit (EXIT_SUCCESS);
360 }