make vfs & filesystems use failable copying
[minix3.git] / test / test46.c
blob93b80512d541fe4f56d011a0c3b23e7073183926
1 /* Test46.c
3 * Test getgroups(...) and setgroups system calls
5 * Please note that getgroups is POSIX defined, but setgroups is not. Errors
6 * related to setgroups are thus not POSIX conformance issues.
7 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <limits.h>
14 #include <dirent.h>
15 #include <sys/types.h>
16 #include <sys/wait.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
20 void api_test(void);
21 void e(int error_no);
22 void group_test(void);
23 void limit_test(void);
24 void group_test_1(void);
25 void group_test_2(void);
26 void group_test_3(void);
27 void group_test_4(void);
28 void group_test_5(void);
29 int dotest(void (*testfunc)(void));
31 int max_error = 5;
32 #include "common.h"
34 #define IMAGINARY_GID 100
35 #define IMAGINARY_GID_STR "100"
36 #define IMAGINARY_UID 101
37 #define IMAGINARY_UID_STR "101"
38 #define SET_CREDENTIALS do { \
39 setgid((IMAGINARY_GID) + 1 ); \
40 setuid(IMAGINARY_UID); \
41 } while(0)
43 int subtest = -1, errorct = 0;
45 int main(int argc, char *argv[])
47 int superuser;
48 start(46);
50 superuser = (geteuid() == 0);
52 if(!superuser) {
53 if(!(setuid(0) || seteuid(0))) {
54 printf("Test 46 has to be run as root; test aborted\n");
55 exit(1);
59 limit_test(); /* Perform some tests on POSIX limits */
60 api_test(); /* Perform some very basic API tests */
61 group_test(); /* Perform some tests that mimic actual use */
63 quit();
65 return(-1); /* Unreachable */
68 void limit_test() {
69 /* According to POSIX 2008 a process can have up to NGROUPS_MAX simultaneous
70 * supplementary group IDs. The minimum acceptable value is _POSIX_NGROUPS_MAX.
71 * In turn, _POSIX_NGROUPS_MAX is defined as 8. */
73 subtest = 1;
74 if (_POSIX_NGROUPS_MAX < 8) e(1);
75 if (NGROUPS_MAX < _POSIX_NGROUPS_MAX) e(2);
78 void api_test() {
79 /* int getgroups( int gidsetsize, gid_t grouplist[]);
80 * int setgroups( int size_t size, const gid_t grouplist[]);
82 /* The getgroups() function shall fill in the array grouplist with the current
83 * supplementary group IDs of the calling process. It is implementation-
84 * defined whether getgroups() also returns the effective group ID in the
85 * grouplist array.
86 * The gidsetsize argument specifies the number of elements in the array
87 * grouplist. The actual number of group IDs stored in the array shall be
88 * returned. The values of array entries with indices greater than or equal to
89 * the value returned are undefined.
90 * If gidsetsize is 0, getgroups shall return the number of group IDs that it
91 * would otherwise return without modifying the array pointed to by grouplist.
93 * setgroups() sets the supplementary group IDs for the calling process. The
94 * size argument specifies the number of supplementary group IDs in the buffer
95 * pointed to by grouplist. setgroups() is a privileged operation.
98 /* Minix does not return the effective group ID with the supplementary groups.
99 * Use getegid() to get that value. In order to call setgroups, a process
100 * must have super user privileges.
103 int i;
104 gid_t *grouplist, *grouplist2;
105 long ngroups_max;
107 subtest = 2;
109 /* Ask the system how many groups we're allowed to set */
110 ngroups_max = sysconf(_SC_NGROUPS_MAX);
111 grouplist = malloc(ngroups_max *sizeof(gid_t));
112 grouplist2 = malloc(ngroups_max *sizeof(gid_t));
114 /* Let's invent some imaginary groups */
115 #define START_GID 20001
116 for (i = 0; i < ngroups_max; i++)
117 grouplist[i] = i + START_GID;
119 /* Normal usage */
120 if (setgroups(ngroups_max, grouplist) != 0) e(1);
122 /* Try one less than max supported groups */
123 if (setgroups(ngroups_max - 1, grouplist) != 0) e(2);
125 /* Try just one group */
126 if (setgroups(1, grouplist) != 0) e(3);
128 /* Unset all supplementary groups */
129 if (setgroups(0, grouplist) != 0) e(4);
131 /* Should not be allowed to use a negative set size */
132 if (setgroups(-1, grouplist) == 0) e(5);
133 else if(errno != EINVAL) e(6); /* error must be EINVAL */
135 /* Should not be allowed to set more groups than supported by the system */
136 if (setgroups(ngroups_max + 1, grouplist) == 0) e(7);
137 else if(errno != EINVAL) e(8); /* error must be EINVAL */
139 /* Should not be allowed to provide an invalid grouplist address */
140 if (setgroups(ngroups_max, NULL) == 0) e(9);
141 else if(errno != EFAULT) e(10); /* error must be EFAULT */
143 /* The last time we called setgroups with proper parameters, we effectively
144 * cleared the list. Verify that with getgroups(). */
145 if (getgroups(ngroups_max, grouplist2) != 0) e(11);
147 /* Repopulate grouplist with values and read them back */
148 if (setgroups(ngroups_max, grouplist) != 0) e(12);
149 if (getgroups(0, grouplist2) != ngroups_max) e(13);
150 if (getgroups(ngroups_max, grouplist2) != ngroups_max) e(14);
151 for (i = 0; i < ngroups_max; i++) {
152 if(grouplist[i] != grouplist2[i]) {
153 e(15);
154 break; /* One error message should be enough here */
158 /* Should not be able to read less groups than are actually stored. */
159 if (getgroups(ngroups_max - 1, grouplist2) != -1) e(16);
161 /* Repopulate grouplist with only half the groups and read them back */
162 memset(grouplist2, 0, ngroups_max * sizeof(gid_t)); /* Clear array */
163 #define HALF_LIST_SIZE ngroups_max / 2
164 if (setgroups(HALF_LIST_SIZE, grouplist) != 0) e(17);
165 if (getgroups(0, grouplist2) != HALF_LIST_SIZE) e(18);
166 if (getgroups(HALF_LIST_SIZE, grouplist2) != HALF_LIST_SIZE) e(19);
167 for (i = 0; i < HALF_LIST_SIZE; i++) {
168 if(grouplist[i] != grouplist2[i]) {
169 e(20);
170 break; /* Also here one message ought to be enough */
174 /* Try to read more groups than we have set */
175 memset(grouplist2, 0, ngroups_max * sizeof(gid_t)); /* Clear array */
176 if (getgroups(ngroups_max, grouplist2) != HALF_LIST_SIZE) e(21);
177 for (i = 0; i < HALF_LIST_SIZE; i++) {
178 /* Anything above indices 'HALF_LIST_SIZE' is undefined */
179 if(grouplist[i] != grouplist2[i]) {
180 e(22);
181 break;
185 /* Try to set too high a group ID */
186 grouplist2[0] = GID_MAX + 1; /* Out of range */
187 if (setgroups(1, grouplist2) == 0) e(23);
188 if (errno != EINVAL) e(24);
190 free(grouplist);
191 free(grouplist2);
194 void group_test() {
195 /* To test supplemental group support we're going to create a temporary
196 * directory that can only be accessed (x bit) by members of our imaginary
197 * group, read from (r bit) and written to (w bit).
198 * Then we're going to create a file in that directory that's only readable and
199 * writable by the owner, also readable, writable, and both (in that order) by
200 * the imaginary group, and readable, writable, and both by everyone else (2).
203 int i, round;
204 gid_t *grouplist;
205 long ngroups_max;
206 #define ROUNDS 8
208 subtest = 3;
210 ngroups_max = sysconf(_SC_NGROUPS_MAX);
211 grouplist = malloc(ngroups_max *sizeof(gid_t));
213 /* Let's invent imaginary groups and user id */
214 grouplist = malloc(ngroups_max * sizeof(gid_t));
216 /* Now loop a few tests while using different group set sizes */
217 for(round = 0; round < ROUNDS; round++) {
218 grouplist[round] = IMAGINARY_GID;
219 for(i = 0; i < ngroups_max; i++) {
220 if(i == round) continue;
221 grouplist[i] = IMAGINARY_GID + i + ngroups_max;
223 setgroups(round+1, grouplist);
225 system("rm -rf DIR_046 > /dev/null 2>&1");
226 system("mkdir DIR_046");
227 system("chmod u=rwx,g=,o= DIR_046"); /* Only access for superuser */
228 system("chgrp "IMAGINARY_GID_STR" DIR_046"); /* Make imaginary group
229 * owner */
231 /* Test group access on directories */
232 if(dotest(group_test_1) != 0) e(1);
233 system("chmod g+r DIR_046"); /* Allow group read access */
234 if(dotest(group_test_1) == 0) e(2);
236 system("chmod g= DIR_046");
237 if(dotest(group_test_2) != 0) e(3);
238 system("chmod g+x DIR_046"); /* Allow 'search' (i.e., inode data)
239 * access */
240 if(dotest(group_test_2) == 0) e(4);
242 if(dotest(group_test_3) != 0) e(5);
243 system("chmod g+w DIR_046"); /* Allow group write access */
244 if(dotest(group_test_3) == 0) e(6);
246 system("chmod g-wx DIR_046"); /* Remove write and 'search' permission */
247 if(dotest(group_test_4) != 0) e(7);
248 system("chmod g+w DIR_046"); /* Add write permission */
249 if(dotest(group_test_4) != 0) e(8);
250 system("chmod g+x DIR_046"); /* Add 'search' permission */
251 if(dotest(group_test_4) == 0) e(9);
253 /* Subdirectories */
254 system("mkdir -p DIR_046/sub");
255 system("chmod u=rwx,g=,o= DIR_046");
256 system("chmod u=rwx,g=,o= DIR_046/sub");
257 system("chgrp "IMAGINARY_GID_STR" DIR_046/sub");
259 if(dotest(group_test_1) != 0) e(10);
260 if(dotest(group_test_5) != 0) e(11);
262 system("chmod g+r DIR_046");
263 if(dotest(group_test_1) == 0) e(12);
264 if(dotest(group_test_5) != 0) e(13);
266 system("chmod g= DIR_046");
267 if(dotest(group_test_5) != 0) e(14);
268 system("chmod g+r DIR_046/sub");
269 if(dotest(group_test_5) != 0) e(15); /* We need search permission for
270 * sub directory DIR_046 to be
271 * able to read the contents of
272 * DIR_046/sub */
273 system("chmod g+x DIR_046");
274 if(dotest(group_test_1) != 0) e(16);
275 if(dotest(group_test_5) == 0) e(17);
276 system("chmod g+r DIR_046");
277 if(dotest(group_test_5) == 0) e(18);
279 system("rm -rf DIR_046");
280 free(grouplist);
283 int dotest( void (*func)(void) ) {
284 int test_result;
286 if(fork() == 0) (*func)();
287 else wait(&test_result);
289 return(test_result);
292 void group_test_1() {
293 /* Test x bit for group access. Exit value is 1 when we were able to read from
294 * the directory and 0 otherwise. */
295 DIR *dirp = NULL;
297 SET_CREDENTIALS;
299 dirp = opendir("DIR_046");
300 exit(dirp != NULL); /* If not NULL, we were able to access it */
303 void group_test_2() {
304 /* Test x bit for group access. Exit value is 1 when we were able to access
305 * inode data of the directory and 0 otherwise. */
306 struct stat buf;
307 int res;
309 SET_CREDENTIALS;
311 res = stat("DIR_046/.", &buf);
312 exit(res == 0);
315 void group_test_3() {
316 /* Test wx bits for group access. Exit value is 1 when we were able to write to
317 * the directory and 0 otherwise. */
318 int fd;
320 SET_CREDENTIALS;
322 fd = open("DIR_046/writetest", O_WRONLY|O_CREAT);
324 exit(fd != -1);
327 void group_test_4() {
328 /* Test w bit for group access. Exit value is 1 when we were able to rename a
329 * the directory and 0 otherwise. */
330 int res;
332 SET_CREDENTIALS;
334 res = rename("DIR_046/writetest", "DIR_046/renametest");
336 exit(res == 0);
339 void group_test_5() {
340 /* Test x bit for group access. Exit value is 1 when we were able to read from
341 * the directory and 0 otherwise. */
342 DIR *dirp = NULL;
344 SET_CREDENTIALS;
346 dirp = opendir("DIR_046/sub");
347 exit(dirp != NULL); /* If not NULL, we were able to access it */