add swifi to the build/install.
[minix.git] / test / test46.c
blob7d0d0ac169fa56354416ffe34a482766c9f56166
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 _PROTOTYPE( void api_test, (void) );
21 _PROTOTYPE( void e, (int error_no) );
22 _PROTOTYPE( void group_test, (void) );
23 _PROTOTYPE( void limit_test, (void) );
24 _PROTOTYPE( void group_test_1, (void) );
25 _PROTOTYPE( void group_test_2, (void) );
26 _PROTOTYPE( void group_test_3, (void) );
27 _PROTOTYPE( void group_test_4, (void) );
28 _PROTOTYPE( void group_test_5, (void) );
29 _PROTOTYPE( int dotest, (void (*testfunc)(void)) );
31 int subtest = -1, errorct = 0;
32 #define ERROR_MAX 5
33 #define IMAGINARY_GID 100
34 #define IMAGINARY_GID_STR "100"
35 #define IMAGINARY_UID 101
36 #define IMAGINARY_UID_STR "101"
37 #define SET_CREDENTIALS do { \
38 setgid((IMAGINARY_GID) + 1 ); \
39 setuid(IMAGINARY_UID); \
40 } while(0)
42 int main(int argc, char *argv[])
44 int superuser;
45 printf("Test 46 ");
46 fflush(stdout);
48 superuser = (geteuid() == 0);
50 if(!superuser) {
51 if(!(setuid(0) || seteuid(0))) {
52 printf("Test 46 has to be run as root; test aborted\n");
53 exit(1);
57 limit_test(); /* Perform some tests on POSIX limits */
58 api_test(); /* Perform some very basic API tests */
59 group_test(); /* Perform some tests that mimic actual use */
61 if(errorct > 0) {
62 printf("%d error(s)\n", errorct);
63 return(errorct);
66 printf("ok\n");
67 return(0);
70 void limit_test() {
71 /* According to POSIX 2008 a process can have up to NGROUPS_MAX simultaneous
72 * supplementary group IDs. The minimum acceptable value is _POSIX_NGROUPS_MAX.
73 * In turn, _POSIX_NGROUPS_MAX is defined as 8. */
75 subtest = 1;
76 if (_POSIX_NGROUPS_MAX < 8) e(1);
77 if (NGROUPS_MAX < _POSIX_NGROUPS_MAX) e(2);
80 void api_test() {
81 /* int getgroups( int gidsetsize, gid_t grouplist[]);
82 * int setgroups( int size_t size, const gid_t grouplist[]);
84 /* The getgroups() function shall fill in the array grouplist with the current
85 * supplementary group IDs of the calling process. It is implementation-
86 * defined whether getgroups() also returns the effective group ID in the
87 * grouplist array.
88 * The gidsetsize argument specifies the number of elements in the array
89 * grouplist. The actual number of group IDs stored in the array shall be
90 * returned. The values of array entries with indices greater than or equal to
91 * the value returned are undefined.
92 * If gidsetsize is 0, getgroups shall return the number of group IDs that it
93 * would otherwise return without modifying the array pointed to by grouplist.
95 * setgroups() sets the supplementary group IDs for the calling process. The
96 * size argument specifies the number of supplementary group IDs in the buffer
97 * pointed to by grouplist. setgroups() is a privileged operation.
100 /* Minix does not return the effective group ID with the supplementary groups.
101 * Use getegid() to get that value. In order to call setgroups, a process
102 * must have super user privileges.
105 int r, i, nogroups;
106 gid_t *grouplist, *grouplist2;
107 long ngroups_max;
109 subtest = 2;
111 /* Ask the system how many groups we're allowed to set */
112 ngroups_max = sysconf(_SC_NGROUPS_MAX);
113 grouplist = malloc(ngroups_max *sizeof(gid_t));
114 grouplist2 = malloc(ngroups_max *sizeof(gid_t));
116 /* Let's invent some imaginary groups */
117 #define START_GID 20001
118 for (i = START_GID; i < START_GID + ngroups_max; i++)
119 grouplist[i - START_GID] = i;
121 /* Normal usage */
122 if (setgroups(ngroups_max, grouplist) != 0) e(1);
124 /* Try one less than max supported groups */
125 if (setgroups(ngroups_max - 1, grouplist) != 0) e(2);
127 /* Try just one group */
128 if (setgroups(1, grouplist) != 0) e(3);
130 /* Unset all supplementary groups */
131 if (setgroups(0, grouplist) != 0) e(4);
133 /* Should not be allowed to use a negative set size */
134 if (setgroups(-1, grouplist) == 0) e(5);
135 else if(errno != EINVAL) e(6); /* error must be EINVAL */
137 /* Should not be allowed to set more groups than supported by the system */
138 if (setgroups(ngroups_max + 1, grouplist) == 0) e(7);
139 else if(errno != EINVAL) e(8); /* error must be EINVAL */
141 /* Should not be allowed to provide an invalid grouplist address */
142 if (setgroups(ngroups_max, NULL) == 0) e(9);
143 else if(errno != EFAULT) e(10); /* error must be EFAULT */
145 /* The last time we called setgroups with proper parameters, we effectively
146 * cleared the list. Verify that with getgroups(). */
147 if (getgroups(ngroups_max, grouplist2) != 0) e(11);
149 /* Repopulate grouplist with values and read them back */
150 if (setgroups(ngroups_max, grouplist) != 0) e(12);
151 if (getgroups(0, grouplist2) != ngroups_max) e(13);
152 if (getgroups(ngroups_max, grouplist2) != ngroups_max) e(14);
153 for (i = 0; i < ngroups_max; i++) {
154 if(grouplist[i] != grouplist2[i]) {
155 e(15);
156 break; /* One error message should be enough here */
160 /* Should not be able to read less groups than are actually stored. */
161 if (getgroups(ngroups_max - 1, grouplist2) != -1) e(16);
163 /* Repopulate grouplist with only half the groups and read them back */
164 memset(grouplist2, 0, ngroups_max * sizeof(gid_t)); /* Clear array */
165 #define HALF_LIST_SIZE ngroups_max / 2
166 if (setgroups(HALF_LIST_SIZE, grouplist) != 0) e(17);
167 if (getgroups(0, grouplist2) != HALF_LIST_SIZE) e(18);
168 if (getgroups(HALF_LIST_SIZE, grouplist2) != HALF_LIST_SIZE) e(19);
169 for (i = 0; i < HALF_LIST_SIZE; i++) {
170 if(grouplist[i] != grouplist2[i]) {
171 e(20);
172 break; /* Also here one message ought to be enough */
176 /* Try to read more groups than we have set */
177 memset(grouplist2, 0, ngroups_max * sizeof(gid_t)); /* Clear array */
178 if (getgroups(ngroups_max, grouplist2) != HALF_LIST_SIZE) e(21);
179 for (i = 0; i < HALF_LIST_SIZE; i++) {
180 /* Anything above indices 'HALF_LIST_SIZE' is undefined */
181 if(grouplist[i] != grouplist2[i]) {
182 e(22);
183 break;
187 free(grouplist);
188 free(grouplist2);
191 void group_test() {
192 /* To test supplemental group support we're going to create a temporary
193 * directory that can only be accessed (x bit) by members of our imaginary
194 * group, read from (r bit) and written to (w bit).
195 * Then we're going to create a file in that directory that's only readable and
196 * writable by the owner, also readable, writable, and both (in that order) by
197 * the imaginary group, and readable, writable, and both by everyone else (2).
200 int r, i, round, test_result;
201 gid_t *grouplist;
202 long ngroups_max;
203 #define ROUNDS 8
205 subtest = 3;
207 ngroups_max = sysconf(_SC_NGROUPS_MAX);
208 grouplist = malloc(ngroups_max *sizeof(gid_t));
210 /* Let's invent imaginary groups and user id */
211 grouplist = malloc(ngroups_max * sizeof(gid_t));
213 /* Now loop a few tests while using different group set sizes */
214 for(round = 0; round < ROUNDS; round++) {
215 grouplist[round] = IMAGINARY_GID;
216 for(i = 0; i < ngroups_max; i++) {
217 if(i == round) continue;
218 grouplist[i] = IMAGINARY_GID + i + ngroups_max;
220 setgroups(round+1, grouplist);
222 system("rm -r DIR_046 > /dev/null 2>&1");
223 system("mkdir DIR_046");
224 system("chmod u=rwx,g=,o= DIR_046"); /* Only access for superuser */
225 system("chgrp "IMAGINARY_GID_STR" DIR_046"); /* Make imaginary group
226 * owner */
228 /* Test group access on directories */
229 if(dotest(group_test_1) != 0) e(1);
230 system("chmod g+r DIR_046"); /* Allow group read access */
231 if(dotest(group_test_1) == 0) e(2);
233 system("chmod g= DIR_046");
234 if(dotest(group_test_2) != 0) e(3);
235 system("chmod g+x DIR_046"); /* Allow 'search' (i.e., inode data)
236 * access */
237 if(dotest(group_test_2) == 0) e(4);
239 if(dotest(group_test_3) != 0) e(5);
240 system("chmod g+w DIR_046"); /* Allow group write access */
241 if(dotest(group_test_3) == 0) e(6);
243 system("chmod g-wx DIR_046"); /* Remove write and 'search' permission */
244 if(dotest(group_test_4) != 0) e(7);
245 system("chmod g+w DIR_046"); /* Add write permission */
246 if(dotest(group_test_4) != 0) e(8);
247 system("chmod g+x DIR_046"); /* Add 'search' permission */
248 if(dotest(group_test_4) == 0) e(9);
250 /* Subdirectories */
251 system("mkdir -p DIR_046/sub");
252 system("chmod u=rwx,g=,o= DIR_046");
253 system("chmod u=rwx,g=,o= DIR_046/sub");
254 system("chgrp "IMAGINARY_GID_STR" DIR_046/sub");
256 if(dotest(group_test_1) != 0) e(10);
257 if(dotest(group_test_5) != 0) e(11);
259 system("chmod g+r DIR_046");
260 if(dotest(group_test_1) == 0) e(12);
261 if(dotest(group_test_5) != 0) e(13);
263 system("chmod g= DIR_046");
264 if(dotest(group_test_5) != 0) e(14);
265 system("chmod g+r DIR_046/sub");
266 if(dotest(group_test_5) != 0) e(15); /* We need search permission for
267 * sub directory DIR_046 to be
268 * able to read the contents of
269 * DIR_046/sub */
270 system("chmod g+x DIR_046");
271 if(dotest(group_test_1) != 0) e(16);
272 if(dotest(group_test_5) == 0) e(17);
273 system("chmod g+r DIR_046");
274 if(dotest(group_test_5) == 0) e(18);
276 system("rm -r DIR_046");
277 free(grouplist);
280 int dotest( void (*func)(void) ) {
281 int test_result;
283 if(fork() == 0) (*func)();
284 else wait(&test_result);
286 return(test_result);
289 void group_test_1() {
290 /* Test x bit for group access. Exit value is 1 when we were able to read from
291 * the directory and 0 otherwise. */
292 DIR *dirp = NULL;
294 SET_CREDENTIALS;
296 dirp = opendir("DIR_046");
297 exit(dirp != NULL); /* If not NULL, we were able to access it */
300 void group_test_2() {
301 /* Test x bit for group access. Exit value is 1 when we were able to access
302 * inode data of the directory and 0 otherwise. */
303 struct stat buf;
304 int res;
306 SET_CREDENTIALS;
308 res = stat("DIR_046/.", &buf);
309 exit(res == 0);
312 void group_test_3() {
313 /* Test wx bits for group access. Exit value is 1 when we were able to write to
314 * the directory and 0 otherwise. */
315 int fd;
317 SET_CREDENTIALS;
319 fd = open("DIR_046/writetest", O_WRONLY|O_CREAT);
321 exit(fd != -1);
324 void group_test_4() {
325 /* Test w bit for group access. Exit value is 1 when we were able to rename a
326 * the directory and 0 otherwise. */
327 int res;
329 SET_CREDENTIALS;
331 res = rename("DIR_046/writetest", "DIR_046/renametest");
333 exit(res == 0);
336 void group_test_5() {
337 /* Test x bit for group access. Exit value is 1 when we were able to read from
338 * the directory and 0 otherwise. */
339 DIR *dirp = NULL;
341 SET_CREDENTIALS;
343 dirp = opendir("DIR_046/sub");
344 exit(dirp != NULL); /* If not NULL, we were able to access it */
347 void e(int error_no) {
348 printf("Subtest %d, error %d\n", subtest, error_no);
350 if (errorct++ > ERROR_MAX) {
351 printf("Too many errors, test aborted\n");
352 exit(1);