#include #include #include #include #include #include #include #include #include #include #include #include #include "prototypes.h" uid_t euid, uid; gid_t egid, gid; char *username, *rootpath, assgnpath[MAXPATHLEN]; int logfile = -1; main(int argc, char *args[]) { int i; struct passwd *pw; euid = geteuid(); uid = getuid(); egid = getegid(); gid = getgid(); seteuid(uid); setegid(egid); pw = getpwuid(uid); username = strdup(pw->pw_name); pw = getpwuid(euid); rootpath = strdup(pw->pw_dir); if(argc < 3) { fprintf(stderr, "usage: handin [ ...]\n"); exit(-1); } open_log(); if(!check_user()) { fprintf(stderr, "%s: You are not authorized for this program.\n", args[0]); log("Not authorized\n"); exit(-1); } log("Assignment: %s\n", args[1]); switch(check_assgn(args[1])) { case 0: fprintf(stderr, "Assignment %s unknown.\n", args[1]); log("Assignment %s unknown\n", args[1]); exit(-1); break; case 1: strcat(strcpy(assgnpath, rootpath), "/handin/assign"); if(!checkdir(assgnpath)) { seteuid(euid);setegid(egid); mkdir(assgnpath, S_IRUSR | S_IWUSR | S_IXUSR); seteuid(uid);setegid(gid); } strcat(strcat(assgnpath, "/"), args[1]); if(!checkdir(assgnpath)) { seteuid(euid);setegid(egid); mkdir(assgnpath, S_IRUSR | S_IWUSR | S_IXUSR); seteuid(uid);setegid(gid); } strcat(strcat(assgnpath, "/"), username); if(!checkdir(assgnpath)) { seteuid(euid);setegid(egid); mkdir(assgnpath, S_IRUSR | S_IWUSR | S_IXUSR); seteuid(uid);setegid(gid); } strcat(assgnpath, "/"); break; case 2: fprintf(stdout, "Turning in assignment late.\n", args[1]); log("Assignment is late\n"); strcat(strcpy(assgnpath, rootpath), "/handin/assign"); if(!checkdir(assgnpath)) { seteuid(euid);setegid(egid); mkdir(assgnpath, S_IRUSR | S_IWUSR | S_IXUSR); seteuid(uid);setegid(gid); } strcat(strcat(strcat(assgnpath, "/"), args[1]), ".late"); if(!checkdir(assgnpath)) { seteuid(euid);setegid(egid); mkdir(assgnpath, S_IRUSR | S_IWUSR | S_IXUSR); seteuid(uid);setegid(gid); } strcat(strcat(assgnpath, "/"), username); if(!checkdir(assgnpath)) { seteuid(euid);setegid(egid); mkdir(assgnpath, S_IRUSR | S_IWUSR | S_IXUSR); seteuid(uid);setegid(gid); } strcat(assgnpath, "/"); break; case 3: fprintf(stderr, "Past late-turnin date.\n"); log("Past late-turnin date\n"); exit(-1); break; } for(i = 2 ; i < argc; i++) do_item(args[i]); } char *stripnl(char *s) { int i; if(s[i=strlen(s)-1]=='\n') s[i]='\0'; return s; } void open_log() { int ret; char sbuf[MAXPATHLEN]; struct stat st; strcpy(sbuf, rootpath); strcat(sbuf, "/handin/log/handin.log"); seteuid(euid);setegid(egid); logfile = open(sbuf, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); seteuid(uid);setegid(gid); if(logfile < 0) { strcpy(sbuf, rootpath); strcat(sbuf, "/handin/log"); seteuid(euid);setegid(egid); ret = stat(sbuf, &st); seteuid(uid);setegid(gid); if(ret < 0) { seteuid(euid);setegid(egid); ret = mkdir(sbuf, S_IRUSR | S_IWUSR | S_IXUSR); seteuid(uid);setegid(gid); if(ret != 0) { fprintf(stderr, "Error opening log file.\n"); exit(-1); } else { strcpy(sbuf, rootpath); strcat(sbuf, "/handin/log/handin.log"); seteuid(euid);setegid(egid); logfile = open(sbuf, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); seteuid(uid);setegid(gid); if(logfile < 0) { fprintf(stderr, "Error opening log file.\n"); exit(-1); } } } } } void log(const char *fmt, ...) { va_list args; time_t now = time(0); char *nowstr = ctime(&now), sbuf[1025]; nowstr[19] = '\0'; va_start(args, fmt); sprintf(sbuf, "%s (%s): ", nowstr + 4, username); vsprintf(sbuf+20+strlen(username), fmt, args); va_end(args); if(write(logfile, sbuf, strlen(sbuf)) == -1) { fprintf(stderr, "Error opening log file.\n"); exit(-1); } } int checkdir(char *dir) { struct stat st; if(stat(dir, &st) == -1) return 0; return S_ISDIR(st.st_mode); } int check_user() { char sbuf[MAXPATHLEN]; FILE *userfile; strcat(strcpy(sbuf, rootpath), "/handin/conf/user.conf"); seteuid(euid);setegid(egid); userfile = fopen(sbuf, "r"); seteuid(uid);setegid(gid); if(!userfile) { fprintf(stderr, "HandIn not configured. Aborting.\n"); log("HandIn not configured. Aborting.\n"); exit(-1); } while(fgets(sbuf, MAXPATHLEN, userfile)) if(!strcmp(username, stripnl(sbuf))) return 1; fclose(userfile); return 0; } int check_assgn(char *assgn) { FILE *assgnfile; char sbuf[MAXPATHLEN], *linep[3], *datep[3]; time_t now = time(0), then; strcat(strcpy(sbuf, rootpath), "/handin/conf/handin.conf"); seteuid(euid);setegid(egid); assgnfile = fopen(sbuf, "r"); seteuid(uid);setegid(gid); if(!assgnfile) { log("No assignment configuration file.\n"); return 0; } while(fgets(sbuf, MAXPATHLEN, assgnfile)) { if(sbuf[1]=='#') continue; parse_fields(linep, sbuf, " \t", 3); if(strcmp(linep[0], assgn)) { free(linep[0]);free(linep[1]);free(linep[2]); continue; } parse_fields(datep, linep[1], "/", 3); then = fromdate(atoi(datep[0]),atoi(datep[1]),atoi(datep[2])); free(datep[0]);free(datep[1]);free(datep[2]); if(now < then) { free(linep[0]);free(linep[1]);free(linep[2]); return 1; } parse_fields(datep, linep[2], "/", 3); then = fromdate(atoi(datep[0]),atoi(datep[1]),atoi(datep[2])); free(datep[0]);free(datep[1]);free(datep[2]); free(linep[0]);free(linep[1]);free(linep[2]); if(now < then) { return 2; } else return 3; } return 0; } int do_item(char *item) { int ret; char sbuf[MAXPATHLEN], *i; struct stat st; if(item[ret=strlen(item)-1] == '/') item[ret] = '\0'; if(i = strrchr(item, '/')) strcat(strcpy(sbuf, assgnpath), i+1); else strcat(strcpy(sbuf, assgnpath), item); if(stat(item, &st) == -1) { printf("%s not found.\n", item); log("File \"%s\" not found\n", item); return -1; } else if(st.st_uid != uid) { printf("You do not own %s!\n", item); log("File \"%s\" not owned by user.\n", item); return -1; } else if(S_ISDIR(st.st_mode)) return do_dir(item, sbuf); seteuid(euid);setegid(egid); ret = stat(sbuf, &st); seteuid(uid);setegid(gid); if(ret == 0) { printf("\"%s\" already turned in. Overwrite? [Y/N] ", item); if(get_choice() != 'y') { log("Not overwriting %s\n", sbuf); return -1; } else log("Overwriting existing %s\n", item); } stat(item, &st); log("Copying %s to %s\n", item, sbuf); if(file_copy(item, sbuf, st)) printf("%s copied.\n", item); else { printf("%s, copy failed.\n", item); log("Copy failed!\n"); } } int do_dir(char *source, char *dest) { char sbuf[MAXPATHLEN]; DIR *d; int ret; struct dirent *de; if(!(d = opendir(source))) { printf("Failed to open directory %s.\n", source); log("Failed to open directory %s", source); return -3; } seteuid(euid);setegid(egid); ret = checkdir(dest); seteuid(uid);setegid(gid); if(!ret) { seteuid(euid);setegid(egid); ret = mkdir(dest, S_IRUSR | S_IWUSR | S_IXUSR); seteuid(uid);setegid(gid); if(ret) { printf("failed to make directory.\n"); log("Failed to make directory \"%s\"\n", dest); return -3; } else log("Created directory %s\n", dest); } printf("Entering %s...\n", source); while(de = readdir(d)) if(strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) do_item(strcat(strcat(strcpy(sbuf, source), "/"), de->d_name)); closedir(d); } int file_copy(char *source, char *dest, struct stat st) { int s, d, n; char buffer[1024]; if((s = open(source, O_RDONLY)) < 0) return 0; seteuid(euid);setegid(egid); d = open(dest, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode & (S_IRUSR | S_IWUSR | S_IXUSR)); seteuid(uid);setegid(gid); if(d < 0) return 0; while( (n = read(s, buffer, 1024)) > 0) if(write(d, buffer, n) != n) { close(s); close(d); return 0; } close(s); close(d); if(n < 0) return 0; return 1; } int get_choice() { char c=0; while(c != 'y' && c != 'n') { fflush(stdin); scanf("%c", &c); c = tolower(c); } return c; } long fromdate(long month, long day, long year) { long monthlens[] = { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; long zone = 6; struct timezone tz; gettimeofday(NULL, &tz); zone = tz.tz_minuteswest / 60; year = (year < 100) ? ( (year < 38) ? 2000+year : 1900+year ) : year; day = monthlens[month-1] + day + year * 366; return (((day - (day + 1038) / 1464 - (day + 672) / 1464 - (day + 306) / 1464 - (day + 109740) / 146400 - (day + 73140) / 146400 - (day + 36540) / 146400 - 719528) * 24 + 23 + zone) * 60 + 59) * 60 + 59; } int parse_fields(char **fields, char *input, char *delim, int max_fields) { int count = 0; char *s; if(max_fields < 1 || !(s=strtok(input, delim))) return 0; fields[count++] = strdup(s); while((count < max_fields) && (s=strtok(NULL, delim))) fields[count++] = strdup(s); return count; }