1 /* test35: utime() Author: Jan-Mark Wams (jms@cs.vu.nl) */ 2 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <sys/wait.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 #include <string.h> 9 #include <fcntl.h> 10 #include <limits.h> 11 #include <utime.h> 12 #include <errno.h> 13 #include <time.h> 14 #include <ctype.h> 15 #include <stdio.h> 16 17 int max_error = 1; 18 #include "common.h" 19 20 #define ITERATIONS 10 21 #define N 100 22 23 24 #define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd) 25 #define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir) 26 #define Stat(a,b) if (stat(a,b) != 0) printf("Can't stat %s\n", a) 27 #define Mkfifo(f) if (mkfifo(f,0777)!=0) printf("Can't make fifo %s\n", f) 28 #define Mkdir(f) if (mkdir(f,0777)!=0) printf("Can't make dir %s\n", f) 29 #define Creat(f) if (close(creat(f,0777))!=0) printf("Can't creat %s\n",f) 30 #define Time(t) if (time(t) == (time_t)-1) printf("Time error\n") 31 #define Chown(f,u,g) if (chown(f,u,g) != 0) printf("Can't chown %s\n", f) 32 #define Chmod(f,m) if (chmod(f,m) != 0) printf("Can't chmod %s\n", f) 33 34 #define PASSWD_FILE "/etc/passwd" 35 36 int I_can_chown; 37 int superuser; 38 char *MaxName; /* Name of maximum length */ 39 char MaxPath[PATH_MAX]; /* Same for path */ 40 char *NameTooLong; /* Name of maximum +1 length */ 41 char PathTooLong[PATH_MAX + 1]; /* Same for path, both too long */ 42 43 void test35a(void); 44 void test35b(void); 45 void test35c(void); 46 void makelongnames(void); 47 void getids(uid_t * uid, gid_t * gid); 48 49 int main(int argc, char *argv[]) 50 { 51 int i, m = 0xFFFF; 52 53 sync(); 54 if (argc == 2) m = atoi(argv[1]); 55 start(35); 56 makelongnames(); 57 superuser = (geteuid() == 0); 58 59 #ifdef _POSIX_CHOWN_RESTRICTED 60 # if _POSIX_CHOWN_RESTRICTED - 0 != -1 61 I_can_chown = superuser; 62 # else 63 I_can_chown = 1; 64 # endif 65 #else 66 # include "error, this case requires dynamic checks and is not handled" 67 #endif 68 69 for (i = 0; i < ITERATIONS; i++) { 70 if (m & 0001) test35a(); 71 if (m & 0002) test35b(); 72 if (m & 0004) test35c(); 73 } 74 quit(); 75 return 1; 76 } 77 78 void test35a() 79 { /* Test normal operation. */ 80 struct stat st; 81 struct utimbuf ub; 82 time_t time1, time2; 83 int cnt; 84 85 subtest = 1; 86 87 /* Creat scratch file. */ 88 Creat("foo"); 89 90 /* Set file times back two seconds. */ 91 Stat("foo", &st); 92 ub.actime = st.st_atime - 2; 93 ub.modtime = st.st_mtime - 2; 94 Time(&time1); 95 utime("foo", &ub); 96 Time(&time2); 97 Stat("foo", &st); 98 if (ub.actime != st.st_atime) e(1); 99 if (ub.modtime != st.st_mtime) e(2); 100 101 /* The status changed time sould be changed. */ 102 #ifndef V1_FILESYSTEM 103 if (st.st_ctime < time1) e(3); 104 #endif 105 if (st.st_ctime > time2) e(4); 106 107 /* Add twenty seconds. */ 108 Stat("foo", &st); 109 ub.actime = st.st_atime + 20; 110 ub.modtime = st.st_mtime + 20; 111 Time(&time1); 112 utime("foo", &ub); 113 Time(&time2); 114 Stat("foo", &st); 115 if (ub.actime != st.st_atime) e(5); 116 if (ub.modtime != st.st_mtime) e(6); 117 if (st.st_ctime < time1) e(7); 118 #ifndef V1_FILESYSTEM 119 if (st.st_ctime > time2) e(8); 120 #endif 121 122 /* Try 100 times to do utime in less than one second. */ 123 cnt = 0; 124 do { 125 Time(&time1); 126 utime("foo", (struct utimbuf *) NULL); 127 Time(&time2); 128 } while (time1 != time2 && cnt++ < 100); 129 if (time1 == time2) { 130 Stat("foo", &st); 131 Time(&time2); 132 if (st.st_atime != time1) e(9); 133 if (st.st_mtime != time1) e(10); 134 } else { 135 Stat("foo", &st); 136 if (st.st_atime > time2) e(11); 137 if (st.st_mtime > time2) e(12); 138 Time(&time2); 139 if (st.st_atime < time1) e(13); 140 if (st.st_mtime < time1) e(14); 141 } 142 if (st.st_ctime < time1) e(15); 143 if (st.st_ctime > time2) e(16); 144 145 System("rm -rf ../DIR_35/*"); 146 } 147 148 void test35b() 149 { 150 subtest = 2; 151 152 /* MaxPath and MaxName checkup. */ 153 Creat(MaxName); 154 MaxPath[strlen(MaxPath) - 2] = '/'; 155 MaxPath[strlen(MaxPath) - 1] = 'a'; /* make ././.../a */ 156 Creat(MaxPath); 157 if (utime(MaxName, NULL) != 0) e(1); 158 if (utime(MaxPath, NULL) != 0) e(2); 159 160 /* The owner doesn't need write permisson to set times. */ 161 Creat("foo"); 162 if (chmod("foo", 0) != 0) e(3); 163 if (utime("foo", NULL) != 0) e(4); 164 if (chmod("foo", 0777) != 0) e(5); 165 if (utime("foo", NULL) != 0) e(6); 166 167 System("rm -rf ../DIR_35/*"); 168 } 169 170 void test35c() 171 { 172 gid_t gid, gid2; 173 uid_t uid, uid2; 174 struct utimbuf ub; 175 int fd, does_truncate, stat_loc; 176 177 subtest = 3; 178 179 /* Access problems. */ 180 Mkdir("bar"); 181 Creat("bar/tryme"); 182 if (superuser) { 183 Chmod("bar", 0000); /* No search permisson at all. */ 184 if (utime("bar/tryme", NULL) != 0) e(1); 185 } 186 if (!superuser) { 187 Chmod("bar", 0677); /* No search permisson. */ 188 if (utime("bar/tryme", NULL) != -1) e(2); 189 if (errno != EACCES) e(3); 190 } 191 Chmod("bar", 0777); 192 193 if (I_can_chown) { 194 switch (fork()) { 195 case -1: printf("Can't fork\n"); break; 196 case 0: 197 alarm(20); 198 199 /* Get two differend non root uids. */ 200 if (superuser) { 201 getids(&uid, &gid); 202 if (uid == 0) getids(&uid, &gid); 203 if (uid == 0) e(4); 204 } 205 if (!superuser) { 206 uid = geteuid(); 207 gid = getegid(); 208 } 209 getids(&uid2, &gid); 210 if (uid == uid2) getids(&uid2, &gid2); 211 if (uid == uid2) e(5); 212 213 /* Creat a number of files for root, user and user2. */ 214 Creat("rootfile"); /* Owned by root. */ 215 Chmod("rootfile", 0600); 216 Chown("rootfile", 0, 0); 217 Creat("user2file"); /* Owned by user 2, writeable. */ 218 Chmod("user2file", 0020); 219 Chown("user2file", uid2, gid); 220 Creat("user2private"); /* Owned by user 2, privately. */ 221 Chmod("user2private", 0600); 222 Chown("user2private", uid2, gid); 223 224 if (superuser) { 225 setgid(gid); 226 setuid(uid); 227 } 228 229 /* We now are user ``uid'' from group ``gid''. */ 230 ub.actime = (time_t) 12345L; 231 ub.modtime = (time_t) 12345L; 232 233 if (utime("rootfile", NULL) != -1) e(6); 234 if (errno != EACCES) e(7); 235 if (utime("rootfile", &ub) != -1) e(8); 236 if (errno != EPERM) e(9); 237 238 if (utime("user2file", NULL) != 0) e(10); 239 if (utime("user2file", &ub) != -1) e(11); 240 if (errno != EPERM) e(12); 241 242 if (utime("user2private", NULL) != -1) e(13); 243 if (errno != EACCES) e(14); 244 if (utime("user2private", &ub) != -1) e(15); 245 if (errno != EPERM) e(16); 246 247 exit(errct ? 1 : 0); 248 default: 249 wait(&stat_loc); 250 if (stat_loc != 0) e(17); /* Alarm? */ 251 } 252 } 253 254 /* Test names that are too long. */ 255 does_truncate = does_fs_truncate(); 256 fd = creat(NameTooLong, 0777); 257 if (does_truncate) { 258 if (utime(NameTooLong, NULL) != 0) e(18); 259 } else { 260 if (utime(NameTooLong, NULL) != -1) e(19); 261 if (errno != ENAMETOOLONG) e(20); 262 } 263 (void) close(fd); 264 265 /* Make PathTooLong contain ././.../a */ 266 PathTooLong[strlen(PathTooLong) - 2] = '/'; 267 PathTooLong[strlen(PathTooLong) - 1] = 'a'; 268 Creat("a"); 269 if (utime(PathTooLong, NULL) != -1) e(21); 270 if (errno != ENAMETOOLONG) e(22); 271 272 /* Non existing file name. */ 273 if (utime("nonexist", NULL) != -1) e(23); 274 if (errno != ENOENT) e(24); 275 276 /* Empty file name. */ 277 if (utime("", NULL) != -1) e(25); 278 if (errno != ENOENT) e(26); 279 280 System("rm -rf ../DIR_35/*"); 281 } 282 283 void makelongnames() 284 { 285 register int i; 286 int max_name_length; 287 288 max_name_length = name_max("."); /* Aka NAME_MAX, but not every FS supports 289 * the same length, hence runtime check */ 290 MaxName = malloc(max_name_length + 1); 291 NameTooLong = malloc(max_name_length + 1 + 1); /* Name of maximum +1 length */ 292 memset(MaxName, 'a', max_name_length); 293 MaxName[max_name_length] = '\0'; 294 295 for (i = 0; i < PATH_MAX - 1; i++) { /* idem path */ 296 MaxPath[i++] = '.'; 297 MaxPath[i] = '/'; 298 } 299 MaxPath[PATH_MAX - 1] = '\0'; 300 301 strcpy(NameTooLong, MaxName); /* copy them Max to ToLong */ 302 strcpy(PathTooLong, MaxPath); 303 304 NameTooLong[max_name_length] = 'a'; 305 NameTooLong[max_name_length+1] = '\0';/* extend ToLongName by one too many */ 306 PathTooLong[PATH_MAX - 1] = '/'; 307 PathTooLong[PATH_MAX] = '\0'; /* inc ToLongPath by one */ 308 } 309 310 /* Getids returns a valid uid and gid. Is used PASSWD FILE. 311 ** It assumes the following format for a passwd file line: 312 ** <user_name>:<passwd>:<uid>:<gid>:<other_stuff> 313 ** If no uids and gids can be found, it will only return 0 ids. 314 */ 315 void getids(r_uid, r_gid) 316 uid_t *r_uid; 317 gid_t *r_gid; 318 { 319 char line[N]; 320 unsigned char *p; 321 uid_t uid; 322 gid_t gid; 323 FILE *fp; 324 int i; 325 326 static uid_t a_uid[N]; /* Array for uids. */ 327 static gid_t a_gid[N]; /* Array for gids. */ 328 static int nuid = 0, ngid = 0;/* The number of user & group ids. */ 329 static int cuid = 0, cgid = 0;/* The current id index. */ 330 331 /* If we don't have any uids go read some from the passwd file. */ 332 if (nuid == 0) { 333 a_uid[nuid++] = 0; /* Root uid and gid. */ 334 a_gid[ngid++] = 0; 335 if ((fp = fopen(PASSWD_FILE, "r")) == NULL) { 336 printf("Can't open "); 337 perror(PASSWD_FILE); 338 } 339 while (fp != NULL && fgets(line, sizeof(line), fp) != NULL) { 340 p = strchr(line, ':'); 341 if (p != NULL) p = strchr(p + 1, ':'); 342 if (p != NULL) { 343 p++; 344 uid = 0; 345 while (isdigit(*p)) { 346 uid *= 10; 347 uid += (uid_t) (*p - '0'); 348 p++; 349 } 350 if (*p != ':') continue; 351 p++; 352 gid = 0; 353 while (isdigit(*p)) { 354 gid *= 10; 355 gid += (gid_t) (*p - '0'); 356 p++; 357 } 358 if (*p != ':') continue; 359 if (nuid < N) { 360 for (i = 0; i < nuid; i++) 361 if (a_uid[i] == uid) break; 362 if (i == nuid) a_uid[nuid++] = uid; 363 } 364 if (ngid < N) { 365 for (i = 0; i < ngid; i++) 366 if (a_gid[i] == gid) break; 367 if (i == ngid) a_gid[ngid++] = gid; 368 } 369 if (nuid >= N && ngid >= N) break; 370 } 371 } 372 if (fp != NULL) fclose(fp); 373 } 374 375 /* We now have uids and gids in a_uid and a_gid. */ 376 if (cuid >= nuid) cuid = 0; 377 if (cgid >= ngid) cgid = 0; 378 *r_uid = a_uid[cuid++]; 379 *r_gid = a_gid[cgid++]; 380 } 381