1 /* test34: chmod() chown() Author: Jan-Mark Wams (jms@cs.vu.nl) */
3 /* There is a problem getting valid uids and gids, so we use the passwd
4 ** file (ie. /etc/passwd). I don't like this, but I see no other way.
5 ** The read-only-device-error (EROFS) is not checked!
6 ** Supplementary group IDs are ignored.
26 #define ALL_RWXB (S_IRWXU | S_IRWXG | S_IRWXO)
27 #define ALL_SETB (S_ISUID | S_ISGID)
28 #define ALL_BITS (ALL_RWXB | ALL_SETB)
30 #define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
31 #define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
32 #define Stat(a,b) if (stat(a,b) != 0) printf("Can't stat %s\n", a)
33 #define Mkfifo(f) if (mkfifo(f,0777)!=0) printf("Can't make fifo %s\n", f)
34 #define Mkdir(f) if (mkdir(f,0777)!=0) printf("Can't make dir %s\n", f)
35 #define Creat(f) if (close(creat(f,0777))!=0) printf("Can't creat %s\n",f)
37 /* This program uses /etc/passwd and assumes things about it's contents. */
38 #define PASSWD_FILE "/etc/passwd"
44 char MaxName
[NAME_MAX
+ 1]; /* Name of maximum length */
45 char MaxPath
[PATH_MAX
]; /* Same for path */
46 char NameTooLong
[NAME_MAX
+ 2]; /* Name of maximum +1 length */
47 char PathTooLong
[PATH_MAX
+ 1]; /* Same for path, both too long */
49 _PROTOTYPE(void main
, (int argc
, char *argv
[]));
50 _PROTOTYPE(void test34a
, (void));
51 _PROTOTYPE(void test34b
, (void));
52 _PROTOTYPE(void test34c
, (void));
53 _PROTOTYPE(mode_t mode
, (char *file_name
));
54 _PROTOTYPE(void makelongnames
, (void));
55 _PROTOTYPE(void e
, (int number
));
56 _PROTOTYPE(void quit
, (void));
57 _PROTOTYPE(void getids
, (uid_t
* uid
, gid_t
* gid
));
66 if (argc
== 2) m
= atoi(argv
[1]);
69 (void) system("chmod 777 DIR_34/* > /dev/null 2> /dev/null");
70 System("rm -rf DIR_34; mkdir DIR_34");
71 if (chdir("DIR_34") != 0) {
72 fprintf(stderr
, "Can't go to DIR_34\n");
73 system("rm -rf DIR_34");
77 superuser
= (geteuid() == (uid_t
) 0);
79 #ifdef _POSIX_CHOWN_RESTRICTED
80 I_can_chown
= superuser
;
87 for (i
= 1; i
< ITERATIONS
; i
++) {
88 if (m
& 0001) test34a();
89 if (m
& 0002) test34b();
90 if (m
& 0004) test34c();
96 { /* Test normal operation. */
107 /* Make scratch file. */
110 for (mod
= 0; mod
<= ALL_BITS
; mod
++) {
111 if ((mod
& ALL_BITS
) != mod
) /* If not a valid mod next. */
114 if (time(&time1
) == (time_t) - 1) e(1);
115 if (chmod("foo", mod
) != 0) e(2);
117 if (time(&time2
) == (time_t) - 1) e(3);
119 if ((st2
.st_mode
& ALL_BITS
) != mod
) e(4);
121 if ((st2
.st_mode
& ALL_RWXB
) != (mod
& ALL_RWXB
)) e(5);
123 /* Test the C time feald. */
124 if (st1
.st_ctime
> st2
.st_ctime
) e(6);
125 if (st1
.st_ctime
> time1
) e(7);
126 if (st1
.st_ctime
> time2
) e(8);
127 #ifndef V1_FILESYSTEM
128 if (st2
.st_ctime
< time1
) e(9);
130 if (st2
.st_ctime
> time2
) e(10);
131 if (st1
.st_atime
!= st2
.st_atime
) e(11);
132 if (st1
.st_mtime
!= st2
.st_mtime
) e(12);
133 } /* End for loop. */
135 /* Check if chown(file, geteuid(), getegid()) works. */
136 for (cnt
= 0; cnt
< 20; cnt
++) {
137 /* Set all rights on foo, including the set .id bits. */
138 if (chmod("foo", ALL_BITS
) != 0) e(13);
140 if (time(&time1
) == (time_t) -1) e(14);
142 if (chown("foo", geteuid(), getegid()) != 0) e(15);
144 if (time(&time2
) == (time_t) -1) e(16);
146 /* Check ``chown()'' killed the set .id bits. */
148 if ((st1
.st_mode
& ALL_RWXB
) != ALL_RWXB
) e(17);
149 if ((st2
.st_mode
& ALL_BITS
) != ALL_RWXB
) e(18);
152 if ((st1
.st_mode
& ALL_BITS
) != ALL_BITS
) e(19);
153 if ((st1
.st_mode
& ALL_RWXB
) != ALL_RWXB
) e(20);
156 /* Check the timing. */
157 if (st1
.st_ctime
> st2
.st_ctime
) e(21);
158 if (st1
.st_ctime
> time1
) e(22);
159 if (st1
.st_ctime
> time2
) e(23);
160 #ifndef V1_FILESYSTEM
161 if (st2
.st_ctime
< time1
) e(24);
163 if (st2
.st_ctime
> time2
) e(25);
164 if (st1
.st_atime
!= st2
.st_atime
) e(26);
165 if (st1
.st_mtime
!= st2
.st_mtime
) e(27);
166 } /* End for loop. */
168 /* Make scratch file. */
169 if (chmod("foo", ALL_RWXB
) != 0) e(28);
172 /* Do a 20 tests on a gid and uid. */
173 for (cnt
= 0; cnt
< 20; cnt
++) {
174 /* Get a uid and a gid, test chown. */
177 if (time(&time1
) == (time_t) -1) e(29);
178 if (chown("foo", (uid_t
) 0, (gid_t
) 0) != 0) e(30);
180 if (time(&time2
) == (time_t) -1) e(31);
182 /* Test the C time field. */
183 if (st1
.st_ctime
> st2
.st_ctime
) e(32);
184 if (st1
.st_ctime
> time1
) e(33);
185 if (st1
.st_ctime
> time2
) e(34);
186 if (st2
.st_ctime
< time1
) e(35);
187 if (st2
.st_ctime
> time2
) e(36);
188 if (st1
.st_atime
!= st2
.st_atime
) e(37);
189 if (st1
.st_mtime
!= st2
.st_mtime
) e(38);
191 /* Do aditional tests. */
192 if (chown("foo", (uid_t
) 0, gid
) != 0) e(39);
193 if (chown("foo", uid
, (gid_t
) 0) != 0) e(40);
194 if (chown("foo", uid
, gid
) != 0) e(41);
198 /* Check if a non-superuser can change a files gid to gid2 *
199 * if gid2 is the current process gid. */
200 for (cnt
= 0; cnt
< 5; cnt
++) {
203 printf("Can't fork\n");
213 getids(&uid2
, &gid2
);
214 if (gid
== gid2
) e(43);
216 /* Creat boo and bar for user uid of group gid. */
218 if (chown("boo", uid
, gid
) != 0) e(44);
219 if (chmod("boo", ALL_BITS
) != 0) e(45);
221 if (chown("bar", uid
, gid
) != 0) e(46);
222 if (chmod("bar", ALL_BITS
) != 0) e(47);
224 /* We now become user uid of group gid2. */
229 if (time(&time1
) == (time_t) -1) e(48);
230 if (chown("bar", uid
, gid2
) != 0) e(49);
232 if (time(&time2
) == (time_t) -1) e(50);
234 /* Check if the SET_BITS are cleared. */
235 if ((st1
.st_mode
& ALL_BITS
) != ALL_BITS
) e(51);
236 if ((st2
.st_mode
& ALL_BITS
) != ALL_RWXB
) e(52);
238 /* Check the st_times. */
239 if (st1
.st_ctime
> st2
.st_ctime
) e(53);
240 if (st1
.st_ctime
> time1
) e(54);
241 if (st1
.st_ctime
> time2
) e(55);
242 if (st2
.st_ctime
< time1
) e(56);
243 if (st2
.st_ctime
> time2
) e(57);
244 if (st1
.st_atime
!= st2
.st_atime
) e(58);
245 if (st1
.st_mtime
!= st2
.st_mtime
) e(59);
248 if (chmod("boo", ALL_BITS
) != 0) e(60);
251 /* Check if the set gid bit is cleared. */
252 if ((st1
.st_mode
& ALL_RWXB
) != ALL_RWXB
) e(61);
253 if ((st2
.st_mode
& S_ISGID
) != 0) e(62);
255 if (chown("boo", uid
, gid2
) != 0) e(63);
258 /* Check if the set uid bit is cleared. */
259 if ((st1
.st_mode
& S_ISUID
) != 0) e(64);
264 if (stat_loc
!= 0) e(65); /* Alarm? */
266 } /* end for loop. */
267 } /* end if (superuser). */
268 if (chmod("foo", ALL_BITS
) != 0) e(66);
270 if (chown("foo", geteuid(), getegid()) != 0) e(67);
272 if ((st1
.st_mode
& ALL_BITS
) != ALL_BITS
) e(68); /* See intro! */
274 if ((st2
.st_mode
& ALL_RWXB
) != ALL_RWXB
) e(69);
276 if ((st2
.st_mode
& ALL_BITS
) != ALL_RWXB
) e(70);
278 (void) system("chmod 777 ../DIR_34/* > /dev/null 2> /dev/null");
279 System("rm -rf ../DIR_34/*");
286 struct stat st1
, st2
;
290 /* Test chmod() and chown() on non regular files and on MaxName and
291 * MaxPath. * Funny, but dirs should also have S_IS.ID bits.
296 MaxPath
[strlen(MaxPath
) - 2] = '/';
297 MaxPath
[strlen(MaxPath
) - 1] = 'a'; /* make ././.../a */
300 for (mod
= 1; mod
<= ALL_BITS
; mod
<<= 1) {
301 if ((mod
& ALL_BITS
) != mod
) continue; /* bad mod */
303 if (time(&time1
) == (time_t) -1) e(1);
304 if (chmod("dir", mod
) != 0) e(2);
306 if (time(&time2
) == (time_t) -1) e(3);
308 if ((st2
.st_mode
& ALL_BITS
) != mod
) e(4);
310 if ((st2
.st_mode
& ALL_RWXB
) != (mod
& ALL_RWXB
)) e(5);
312 /* Test the C time field. */
313 if (st1
.st_ctime
> st2
.st_ctime
) e(6);
314 if (st1
.st_ctime
> time1
) e(7);
315 if (st1
.st_ctime
> time2
) e(8);
316 #ifndef V1_FILESYSTEM
317 if (st2
.st_ctime
< time1
) e(9);
319 if (st2
.st_ctime
> time2
) e(10);
320 if (st1
.st_atime
!= st2
.st_atime
) e(11);
321 if (st1
.st_mtime
!= st2
.st_mtime
) e(12);
324 if (time(&time1
) == (time_t) -1) e(13);
325 if (chmod("fifo", mod
) != 0) e(14);
327 if (time(&time2
) == (time_t) -1) e(15);
329 if ((st2
.st_mode
& ALL_BITS
) != mod
) e(16);
331 if ((st2
.st_mode
& ALL_RWXB
) != (mod
& ALL_RWXB
)) e(17);
333 /* Test the C time field. */
334 if (st1
.st_ctime
> st2
.st_ctime
) e(18);
335 if (st1
.st_ctime
> time1
) e(19);
336 if (st1
.st_ctime
> time2
) e(20);
337 #ifndef V1_FILESYSTEM
338 if (st2
.st_ctime
< time1
) e(21);
340 if (st2
.st_ctime
> time2
) e(22);
341 if (st1
.st_atime
!= st2
.st_atime
) e(23);
342 if (st1
.st_mtime
!= st2
.st_mtime
) e(24);
345 if (time(&time1
) == (time_t) -1) e(25);
346 if (chmod(MaxName
, mod
) != 0) e(26);
348 if (time(&time2
) == (time_t) -1) e(27);
350 if ((st2
.st_mode
& ALL_BITS
) != mod
) e(28);
352 if ((st2
.st_mode
& ALL_RWXB
) != (mod
& ALL_RWXB
)) e(29);
354 /* Test the C time field. */
355 if (st1
.st_ctime
> st2
.st_ctime
) e(30);
356 if (st1
.st_ctime
> time1
) e(31);
357 if (st1
.st_ctime
> time2
) e(32);
358 #ifndef V1_FILESYSTEM
359 if (st2
.st_ctime
< time1
) e(33);
361 if (st2
.st_ctime
> time2
) e(34);
362 if (st1
.st_atime
!= st2
.st_atime
) e(35);
363 if (st1
.st_mtime
!= st2
.st_mtime
) e(36);
366 if (time(&time1
) == (time_t) -1) e(37);
367 if (chmod(MaxPath
, mod
) != 0) e(38);
369 if (time(&time2
) == (time_t) -1) e(39);
371 if ((st2
.st_mode
& ALL_BITS
) != mod
) e(40);
373 if ((st2
.st_mode
& ALL_RWXB
) != (mod
& ALL_RWXB
)) e(41);
375 /* Test the C time field. */
376 if (st1
.st_ctime
> st2
.st_ctime
) e(42);
377 if (st1
.st_ctime
> time1
) e(43);
378 if (st1
.st_ctime
> time2
) e(44);
379 #ifndef V1_FILESYSTEM
380 if (st2
.st_ctime
< time1
) e(45);
382 if (st2
.st_ctime
> time2
) e(46);
383 if (st1
.st_atime
!= st2
.st_atime
) e(47);
384 if (st1
.st_mtime
!= st2
.st_mtime
) e(48);
387 if (chmod("dir", 0777) != 0) e(49);
388 if (chmod("fifo", 0777) != 0) e(50);
389 if (chmod(MaxName
, 0777) != 0) e(51);
390 if (chmod(MaxPath
, 0777) != 0) e(52);
392 (void) system("chmod 777 ../DIR_34/* > /dev/null 2> /dev/null");
393 System("rm -rf ../DIR_34/*");
408 /* Disalow search permission and see if chmod() and chown() return
411 if (chmod("dir", ALL_BITS
& ~S_IXUSR
) != 0) e(1);
413 if (chmod("dir/try_me", 0) != -1) e(2);
414 if (errno
!= EACCES
) e(3);
416 if (chown("dir/try_me", geteuid(), getegid()) != -1) e(4);
417 if (errno
!= EACCES
) e(5);
423 if (chmod("fifo/try_me", 0) != -1) e(6);
424 if (errno
!= ENOTDIR
) e(7);
425 if (chown("fifo/try_me", geteuid(), getegid()) != -1) e(8);
426 if (errno
!= ENOTDIR
) e(9);
429 if (chmod("file/try_me", 0) != -1) e(10);
430 if (errno
!= ENOTDIR
) e(11);
431 if (chown("file/try_me", geteuid(), getegid()) != -1) e(12);
432 if (errno
!= ENOTDIR
) e(13);
434 /* Check empty path. */
435 if (chmod("", 0) != -1) e(14);
436 if (errno
!= ENOENT
) e(15);
437 if (chown("", geteuid(), getegid()) != -1) e(16);
438 if (errno
!= ENOENT
) e(17);
440 /* Check non existing file name. */
441 if (chmod("non_exist", 0) != -1) e(18);
442 if (errno
!= ENOENT
) e(19);
443 if (chown("non_exist", geteuid(), getegid()) != -1) e(20);
444 if (errno
!= ENOENT
) e(21);
446 /* Check what we get if we do not have permisson. */
449 if (st
.st_uid
== geteuid()) e(22);
451 /* First I had 0, I changed it to st.st_mode 8-). */
452 if (chmod("/", st
.st_mode
) != -1) e(23);
453 if (errno
!= EPERM
) e(24);
457 if (st
.st_uid
== geteuid()) e(25);
458 if (chown("/", geteuid(), getegid()) != -1) e(26);
459 if (errno
!= EPERM
) e(27);
462 /* If we are superuser, we can test all id combinations. */
465 case -1: printf("Can't fork\n"); break;
474 getids(&uid2
, &gid2
);
475 if (gid
== gid2
) e(29);
476 if (uid
== uid2
) e(30);
478 /* Creat boo, owned by root. */
480 if (chmod("boo", ALL_BITS
) != 0) e(31);
482 /* Creat boo for user uid2 of group gid2. */
484 if (chown("bar", uid2
, gid2
) != 0) e(32);
485 if (chmod("bar", ALL_BITS
) != 0) e(33);
487 /* Creat my_gid for user uid2 of group gid. */
489 if (chown("my_gid", uid2
, gid
) != 0) e(34);
490 if (chmod("my_gid", ALL_BITS
) != 0) e(35);
492 /* Creat my_uid for user uid of uid gid. */
494 if (chown("my_uid", uid
, gid
) != 0) e(36);
495 if (chmod("my_uid", ALL_BITS
) != 0) e(37);
497 /* We now become user uid of uid gid. */
501 if (chown("boo", uid
, gid
) != -1) e(38);
502 if (errno
!= EPERM
) e(39);
503 if (chown("bar", uid
, gid
) != -1) e(40);
504 if (errno
!= EPERM
) e(41);
505 if (chown("my_gid", uid
, gid
) != -1) e(42);
506 if (errno
!= EPERM
) e(43);
507 if (chown("my_uid", uid
, gid2
) != -1) e(44);
509 /* The EPERM is not strict POSIX. */
510 if (errno
!= EPERM
) e(45);
512 if (chmod("boo", 0) != -1) e(46);
513 if (errno
!= EPERM
) e(47);
514 if (chmod("bar", 0) != -1) e(48);
515 if (errno
!= EPERM
) e(49);
516 if (chmod("my_gid", 0) != -1) e(50);
517 if (errno
!= EPERM
) e(51);
522 if (stat_loc
!= 0) e(52); /* Alarm? */
526 /* Check too long path ed. */
528 if (chmod(NameTooLong
, 0777) != 0) e(57);
529 if (chown(NameTooLong
, geteuid(), getegid()) != 0) e(58);
531 /* Make PathTooLong contain ././.../a */
532 PathTooLong
[strlen(PathTooLong
) - 2] = '/';
533 PathTooLong
[strlen(PathTooLong
) - 1] = 'a';
535 if (chmod(PathTooLong
, 0777) != -1) e(59);
536 if (errno
!= ENAMETOOLONG
) e(60);
537 if (chown(PathTooLong
, geteuid(), getegid()) != -1) e(61);
538 if (errno
!= ENAMETOOLONG
) e(62);
540 (void) system("chmod 777 ../DIR_34/* > /dev/null 2> /dev/null");
541 System("rm -rf ../DIR_34/*");
548 memset(MaxName
, 'a', NAME_MAX
);
549 MaxName
[NAME_MAX
] = '\0';
550 for (i
= 0; i
< PATH_MAX
- 1; i
++) { /* idem path */
554 MaxPath
[PATH_MAX
- 1] = '\0';
556 strcpy(NameTooLong
, MaxName
); /* copy them Max to TooLong */
557 strcpy(PathTooLong
, MaxPath
);
559 NameTooLong
[NAME_MAX
] = 'a';
560 NameTooLong
[NAME_MAX
+ 1] = '\0'; /* extend NameTooLong by one too many*/
561 PathTooLong
[PATH_MAX
- 1] = '/';
562 PathTooLong
[PATH_MAX
] = '\0'; /* inc PathTooLong by one */
568 int err_num
= errno
; /* Save in case printf clobbers it. */
570 printf("Subtest %d, error %d errno=%d: ", subtest
, n
, errno
);
573 if (errct
++ > MAX_ERROR
) {
574 printf("Too many errors; test aborted\n");
576 system("rm -rf DIR*");
577 system("rm -rf DIR_34");
586 (void) system("chmod 777 DIR_34/* > /dev/null 2> /dev/null");
587 System("rm -rf DIR_34");
593 printf("%d errors\n", errct
);
598 /* Getids returns a valid uid and gid. Is used PASSWD FILE.
599 * It assumes the following format for a passwd file line:
600 * <user_name>:<passwd>:<uid>:<gid>:<other_stuff>
601 * If no uids and gids can be found, it will only return 0 ids.
603 void getids(r_uid
, r_gid
)
614 static uid_t a_uid
[N
]; /* Array for uids. */
615 static gid_t a_gid
[N
]; /* Array for gids. */
616 static int nuid
= 0, ngid
= 0;/* The number of user & group ids. */
617 static int cuid
= 0, cgid
= 0;/* The current id index. */
619 /* If we don't have any uids go read some from the passwd file. */
621 a_uid
[nuid
++] = 0; /* Root uid and gid. */
623 if ((fp
= fopen(PASSWD_FILE
, "r")) == NULL
) {
624 printf("Can't open ");
627 while (fp
!= NULL
&& fgets(line
, sizeof(line
), fp
) != NULL
) {
628 p
= strchr(line
, ':');
629 if (p
!= NULL
) p
= strchr(p
+ 1, ':');
633 while (isdigit(*p
)) {
635 uid
+= (uid_t
) (*p
- '0');
638 if (*p
!= ':') continue;
641 while (isdigit(*p
)) {
643 gid
+= (gid_t
) (*p
- '0');
646 if (*p
!= ':') continue;
648 for (i
= 0; i
< nuid
; i
++)
649 if (a_uid
[i
] == uid
) break;
650 if (i
== nuid
) a_uid
[nuid
++] = uid
;
653 for (i
= 0; i
< ngid
; i
++)
654 if (a_gid
[i
] == gid
) break;
655 if (i
== ngid
) a_gid
[ngid
++] = gid
;
657 if (nuid
>= N
&& ngid
>= N
) break;
660 if (fp
!= NULL
) fclose(fp
);
663 /* We now have uids and gids in a_uid and a_gid. */
664 if (cuid
>= nuid
) cuid
= 0;
665 if (cgid
>= ngid
) cgid
= 0;
666 *r_uid
= a_uid
[cuid
++];
667 *r_gid
= a_gid
[cgid
++];