#include #include #include #include #include #include #include #include #include "global.h" #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_strtrm.h" #include "manhat-lib/shared_super_util.h" #include "manhat-lib/shared_authenticate.h" #include "manhat-lib/shared_server_string.h" #include "manhat-lib/shared_person_list.h" #include "manhat-lib/shared_roster_xml_parser.h" #include "manhat-lib/shared_user_index.h" #include "manhat-lib/shared_central_user.h" #include "manhat-lib/shared_encrypt.h" #include "manhat-lib/shared_update_user_info.h" #include "manhat-lib/shared_cs_util.h" #include "manhat-lib/shared_super_menu.h" #define MAX_ROSTER_LINE 200 /* max len of a line in the uploaded roster.txt file */ static void read_parameters (char *subdir, char *key, COURSE_TYPE *course_type) { char tmp[21]; char new_subdir[MAX_COURSE_SUBDIR +1]; int i; cs_get_required_parameter ("id", key, MAX_KEY ); cs_get_required_parameter ("subdir", subdir, MAX_COURSE_SUBDIR ); cs_get_required_parameter ("type", tmp, 20); *course_type = CENTRAL; /* to prevent uninitialized variable compiler warnings */ i = atoi(tmp); switch(i) { case 0: *course_type = CENTRAL; break; case 1: *course_type = STANDALONE; break; case 2: *course_type = TEMPLATE; break; default: cs_critical_error (ERR_INVALID_COURSE_TYPE, "Course type"); break; } if( !strcmp(subdir, "__new__") && *course_type != TEMPLATE) { cs_get_required_parameter("new_subdir", new_subdir, MAX_COURSE_SUBDIR ); strncpy(subdir, new_subdir, MAX_COURSE_SUBDIR +1); } } static void write_cgi_file (FILE *infp, const char *filepath) { #define CHUNKSIZE 2048 FILE *outfp; int bytes_read; int bytes_left; char buffer[CHUNKSIZE]; struct stat file_stat; if(fstat(fileno(infp), &file_stat)) cs_critical_error(ERR_NO_FILE, ""); if(file_stat.st_size ==0) cs_critical_error(ERR_NO_FILE, ""); outfp = fopen (filepath, "w"); if (!outfp) cs_critical_error (ERR_FOPEN_WRITE_FAILED, filepath); bytes_left = file_stat.st_size; bytes_read = CHUNKSIZE; while (bytes_left) { if (bytes_left < CHUNKSIZE) bytes_read = bytes_left; if (fread (buffer, bytes_read, 1, infp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); bytes_left -= bytes_read; if (fwrite (buffer, bytes_read, 1, outfp) != 1) cs_critical_error(ERR_FWRITE_FAILED, filepath); } fclose (outfp); #undef CHUNKSIZE } void get_tmp_name(char *filepath) { int fd; snprintf (filepath, MAX_PATH + 1, "%sCGI_DATA_XXXXXX", TMP_PATH); fd = mkstemp (filepath); if(fd == -1) cs_critical_error(ERR_MKSTEMP_FAILED, ""); close(fd); change_mkstemp_permission(filepath); /*shared_file_util.c */ } /* writes the uploaded file to ROSTER_FNAME in course_dir ** exits if the uploaded file is missing or empty */ static void write_roster_file (FILE *fp, char *filepath) { char file[MAX_PATH +1]; get_tmp_name(filepath); snprintf(file, MAX_PATH +1, "%s.tar", filepath); write_cgi_file (fp, file); } void make_work_space(const char *prefix) { char command[MAX_PATH+1]; unlink(prefix); if(mkdir(prefix,0770)) cs_critical_error(ERR_MKDIR_FAILED, ""); snprintf(command, MAX_PATH+1, "mv %s.tar %s", prefix, prefix); if(system(command) == -1) cs_critical_error(ERR_CANT_CREATE_WORK_SPACE, ""); snprintf(command, MAX_PATH +1, "cd %s ; tar -xzf *.tar ; cd ../../sbin", prefix); if(system(command) == -1) cs_critical_error(ERR_CANT_CREATE_WORK_SPACE, ""); } int get_course_name(char *course_name, const char *prefix) { DIR *dir_p, *test; struct dirent *dir_entry_p; char path[MAX_PATH +1]; dir_p = opendir(prefix); if(!dir_p) cs_critical_error(ERR_CANT_FIND_WORK_SPACE, prefix); while(NULL != (dir_entry_p = readdir(dir_p))) { if(*(dir_entry_p->d_name) != '.' && !(strstr(dir_entry_p->d_name, ".tar"))) { snprintf(path, MAX_PATH +1, "%s/%s", prefix, dir_entry_p->d_name); test = opendir(path); if(test) { strncpy(course_name, dir_entry_p->d_name, MAX_COURSE_ID +1); closedir(test); return 1; } } } closedir(dir_p); course_name[0] = '\0'; return 0; } void get_conf(const char *prefix, const char *course_name, CONFIG_STRUCT *conf) { FILE *fp; char conf_file[MAX_PATH +1]; snprintf(conf_file, MAX_PATH +1, "%s/%s/%s", prefix, course_name, CONFIG_FNAME); fp = fopen(conf_file, "r"); if(!fp) cs_critical_error(ERR_CANT_FIND_CONF , ""); if(fread(conf, sizeof(CONFIG_STRUCT), 1, fp) != 1) cs_critical_error(ERR_FOPEN_READ_FAILED, ""); fclose(fp); } P_NODE * build_person_list(const char *prefix, const char *course_name) { char passwd_fname[MAX_PATH + 1]; FILE *fp; int fd; char line[200]; P_NODE *person, *pptr = 0; P_NODE *pers_head = 0; snprintf (passwd_fname, MAX_PATH + 1, "%s/%s/%s", prefix, course_name, PASSWORD_FNAME); fp = fopen (passwd_fname, "r"); if (!fp) cs_critical_error (ERR_PASSWD_OPEN_FAILED, passwd_fname); fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ while (fgets (line, 200, fp)) { if (*line == '?') /* password lines starting with a '?' are ignored */ continue; person = (P_NODE *) malloc (sizeof (P_NODE)); if (!person) cs_critical_error (ERR_MALLOC_FAILED, "build password"); get_passwd_line_data(line, &(person->data)); /* now add it to the linked list */ person->data.team = 'A'; /* reassign team value to distinguish value 'O' from 'N' */ person->next = 0; if (!pers_head) pers_head = person; else pptr->next = person; pptr = person; } release_lock(fd); /* shared_lock.c */ fclose (fp); pers_head = sort_person_list (pers_head); return pers_head; } /* void do_untar(const char *prefix) { pid_t pid, status; if ((pid = fork ()) < 0) critical_error (L47E_CANT_START_NEW_PROCESS, ""); if(pid == 0) { execl(prefix, "tar", "-xzf", "*.tar", (char*)0); exit(88); } while (wait (&status) != pid); }*/ XML_COURSE_INFO * build_course_info(const char *prefix, const char *subdir) { XML_COURSE_INFO *course_data; CONFIG_STRUCT conf; course_data = (XML_COURSE_INFO*) malloc(sizeof(XML_COURSE_INFO)); if(!get_course_name(course_data->dir_id, prefix) ) cs_critical_error(ERR_FOPEN_READ_FAILED, ""); get_conf(prefix, course_data->dir_id, &conf); strncpy(course_data->subdir, subdir, MAX_COURSE_SUBDIR +1); strncpy(course_data->course_code, conf.course_no, MAX_COURSE_NO +1); strncpy(course_data->title, conf.title, MAX_COURSE_TITLE +1); strncpy(course_data->semester, conf.semester, MAX_SEMESTER +1); course_data->user_head = build_person_list(prefix, course_data->dir_id); return course_data; } int find_user_in_index(INDEX_USER_LIST *index_list, P_NODE *user_data) { INDEX_USER *ptr; for(ptr = index_list->head; ptr; ptr = ptr->next) { if(strcmp(ptr->id, user_data->data.id) ==0) { if(strcmp(ptr->username, user_data->data.username) != 0 ) { strncpy(user_data->data.alias, "1" , MAX_NAME +1); return 2; } else return 1; } } return 0; } int find_teacher_in_course( P_NODE *head, INDEX_USER_LIST *index_list) { P_NODE *teacher; int find =-1; for(teacher = head; teacher; teacher= teacher->next) { if(teacher->data.group == FACULTY) { find = find_user_in_index(index_list, teacher); if(find != 2) return 1; } } return find; } int find_invalid_user(P_NODE * invalid_head, const char *username) { P_NODE *ptr; for( ptr = invalid_head; ptr; ptr = ptr->next) { if(strcmp(ptr->data.username, username) ==0) return 1; } return 0; } void update_course_path(XML_COURSE_INFO *course_data, COURSE_TYPE course_type, const char *prefix, INDEX_USER_LIST *index_list) { char path[MAX_PATH+1]; struct stat buff; char command[MAX_PATH +1]; char subdir_path[MAX_PATH +1]; if(course_type == TEMPLATE) snprintf(subdir_path, MAX_PATH +1, "%s%s", TEMPLATE_PATH, course_data->subdir); else snprintf(subdir_path, MAX_PATH +1, "%s%s", COURSE_PATH, course_data->subdir); snprintf(path, MAX_PATH +1, "%s/%s", subdir_path, course_data->dir_id); if(!stat(path, &buff)) cs_critical_error(ERR_COURSE_EXIST_ERROR_MSG, path); if(find_teacher_in_course(course_data->user_head, index_list) != 1) cs_critical_error(ERR_NO_VALID_TEACHER, "can't find teacher"); mkdir(subdir_path, 0770); snprintf(command, MAX_PATH +1, "mv %s/%s %s", prefix, course_data->dir_id, path); system(command); snprintf(command, MAX_PATH +1, "rm -rf %s", prefix); system(command); } P_NODE * find_teacher(P_NODE *head) { P_NODE *ptr; for(ptr = head; ptr; ptr = ptr->next) { if(ptr->data.group == FACULTY) return ptr; } return 0; } void update_course_info(XML_COURSE_INFO *course_data, COURSE_TYPE course_type) { P_NODE *ptr; char subdir[MAX_COURSE_SUBDIR +1]; if(course_type == TEMPLATE) { ptr = find_teacher(course_data->user_head); if(ptr) { snprintf(subdir, MAX_COURSE_SUBDIR +1, "T%s", ptr->data.username); strncpy(course_data->subdir, subdir, MAX_COURSE_SUBDIR +1); } else cs_critical_error(ERR_NO_VALID_TEACHER, ""); } } P_NODE * update_userinfo(XML_COURSE_INFO *course_data, COURSE_TYPE course_type, int *count,INDEX_USER_LIST *index_list) { P_NODE *ptr; P_NODE *invalid_head =0, *current = 0, *invalid_ptr; char *space; char tempname[MAX_NAME +1]; char course[MAX_PATH +1]; int ok = -1, central =0, central_course =0; snprintf(course, MAX_PATH +1, "%s/%s", course_data->subdir, course_data->dir_id); if(course_type != STANDALONE) { for(ptr = course_data->user_head; ptr; ptr = ptr->next) { ok = find_user_in_index(index_list, ptr); if(ok ==0) /* user is not in current server adding user to central database */ { index_list = add_to_index_list(index_list, ptr->data.username, ptr->data.id, ptr->data.realname); strncpy(tempname, ptr->data.realname, MAX_NAME +1); space = strchr(tempname, ' '); if(space) *space = '\0'; derive_password (ptr->data.username, tempname,ptr->data.lastname,ptr->data.id, ptr->data.password, MAX_PASSWORD +1); /* shared_authenticate.c */ if(!create_central_letter_dir (sub_dir_name(ptr->data.username))) strncpy(ptr->data.alias,"1", MAX_NAME +1); else strncpy(ptr->data.alias,"0", MAX_NAME +1); if(!create_central_user_dir(ptr->data.username)) strncpy(ptr->data.alias,"1", MAX_NAME +1); else strncpy(ptr->data.alias,"0", MAX_NAME +1); if(!write_central_id_file (ptr->data.realname,ptr->data.username, ptr->data.id)) strncpy(ptr->data.alias,"1", MAX_NAME +1); else strncpy(ptr->data.alias,"0", MAX_NAME +1); if(!write_central_password_file (ptr->data.username, ptr->data.password)) strncpy(ptr->data.alias,"1", MAX_NAME +1); else { strncpy(ptr->data.alias,"0", MAX_NAME +1); central =1; } } /* update central course list */ if((ok ==0 && central ==1) || ok ==1) { if(!add_course(ptr->data.username, course)) strncpy(ptr->data.alias,"1", MAX_NAME +1); else { strncpy(ptr->data.alias,"0", MAX_NAME +1); central_course =1; } } /* add user to central database failed or user's username has a conflict with existing user's username */ if((central==0 && ok ==0 && central_course ==0) || ok == 2 || (ok ==1 && central_course ==0)) { invalid_ptr = (P_NODE *)malloc(sizeof(P_NODE)); strncpy(invalid_ptr->data.username, ptr->data.username, MAX_USERNAME +1); strncpy(invalid_ptr->data.id, ptr->data.id, MAX_ID +1); strncpy(invalid_ptr->data.realname, ptr->data.realname, MAX_NAME +1); strncpy(invalid_ptr->data.lastname, ptr->data.lastname, MAX_NAME +1); strncpy(invalid_ptr->data.alias, ptr->data.alias, MAX_NAME +1); invalid_ptr->data.group = ptr->data.group; invalid_ptr->next =0; (*count)++; if(!invalid_head) invalid_head = invalid_ptr; else current->next = invalid_ptr; current = invalid_ptr; } if(ok == 0 && central ==1 && central_course ==1) { ptr->data.team = 'N'; central = 0; central_course = 0; } else if(ok == 1 && central_course == 1) { ptr->data.team = 'O'; central_course = 0; } } } return invalid_head; } void print_import_course_info(XML_COURSE_INFO *course_data, COURSE_TYPE course_type, int invalid_count, P_NODE *invalid_head) { #define MAX_TMP_NAME 30 P_NODE *ptr; int total =0, i =0; int flag =0; char name[MAX_TMP_NAME +1], prefix[6]; if(course_type == STANDALONE) { strncpy(prefix, "std", 6); cs_set_int_value("std_total", 1); } else { strncpy(prefix, "ctr", 6); cs_set_int_value("ctr_total", 1); } snprintf(name, MAX_TMP_NAME, "%s.0.course_subdir", prefix); cs_set_value(name, course_data->subdir); snprintf(name, MAX_TMP_NAME, "%s.0.course_dir", prefix); cs_set_value(name, course_data->dir_id); snprintf(name, MAX_TMP_NAME, "%s.0.course_no", prefix); cs_set_value(name, course_data->course_code); snprintf(name, MAX_TMP_NAME, "%s.0.course_title", prefix); cs_set_value(name, course_data->title); snprintf(name, MAX_TMP_NAME, "%s.0.course_semester", prefix); cs_set_value(name, course_data->semester); snprintf(name, MAX_TMP_NAME, "%s.0.type", prefix); cs_set_int_value(name, course_type); for(ptr= course_data->user_head; ptr; ptr = ptr->next) { flag = 0; snprintf(name, MAX_TMP_NAME, "%s.0.user.%d.add_state", prefix, i); if(find_invalid_user(invalid_head, ptr->data.username)) { cs_set_int_value(name, 1); flag =1; } else cs_set_int_value(name, 0); snprintf(name, MAX_TMP_NAME, "%s.0.users.%d.group", prefix, i); cs_set_int_value(name, ptr->data.group ); snprintf(name, MAX_TMP_NAME, "%s.0.users.%d.first", prefix, i); cs_set_value(name, ptr->data.realname); snprintf(name, MAX_TMP_NAME, "%s.0.users.%d.id", prefix, i); cs_set_value(name, ptr->data.id); snprintf(name, MAX_TMP_NAME, "%s.0.users.%d.username", prefix, i); cs_set_value(name, ptr->data.username); snprintf(name, MAX_TMP_NAME, "%s.0.users.%d.is_new", prefix, i); if(course_type == STANDALONE) cs_set_int_value(name, 3 ); else if(ptr->data.team == 'N') cs_set_int_value(name, 0 ); else if(flag == 1) cs_set_int_value(name, 2 ); else cs_set_int_value(name, 1 ); snprintf(name, MAX_TMP_NAME, "%s.0.users.%d.central_state", prefix, i); cs_set_int_value(name, atoi(ptr->data.alias) ); total++; i++; } cs_set_int_value("suc_total", total - invalid_count); cs_set_int_value("inv_total", invalid_count); #undef MAX_TMP_NAME } void update_password(P_NODE *invalid_head, XML_COURSE_INFO *course_data) { char path[MAX_PATH +1]; CONFIG_STRUCT conf; P_NODE *ptr; if(invalid_head) { snprintf(path, MAX_PATH +1, "%s/%s", course_data->subdir, course_data->dir_id); read_configuration_file (path, &conf); for(ptr = invalid_head; ptr; ptr = ptr->next) mark_passwd_file (ptr->data.username, &conf); } } void do_action(XML_COURSE_INFO *course_data, const char *prefix, COURSE_TYPE course_type) { P_NODE *invalid_head; int invalid_count =0; INDEX_USER_LIST *index_list =0; index_list = (INDEX_USER_LIST *)malloc(sizeof(INDEX_USER_LIST)); index_list->current =0; index_list->head =0; index_list = build_index_user_list(index_list); update_course_info(course_data, course_type); update_course_path(course_data, course_type, prefix, index_list); invalid_head = update_userinfo(course_data, course_type, &invalid_count, index_list); update_password(invalid_head, course_data); reindex_users("../users"); print_import_course_info(course_data, course_type, invalid_count, invalid_head); free_option_person_list (invalid_head); free_index_user_list(index_list); } int main() { char subdir[MAX_COURSE_SUBDIR + 1]; char temp_course[MAX_COURSE_SUBDIR + 1]; char key[MAX_KEY + 1]; COURSE_TYPE course_type; SESSION user; char prefix_rosterfile[MAX_PATH +1]; XML_COURSE_INFO *course_data; FILE *fp; struct stat file_stat; cs_cgi_init(); read_parameters (subdir, key, &course_type); validate_super_key(key, &user); /* shared_super_util.c */ set_admin_page(&user, key, 0, "super_new_course_form"); /* shared_super_menu.c */ fp = cgi_filehandle (global_cgi, "roster"); if(!fp) cs_critical_error(ERR_UPLOAD_FILE, ""); /** shared_cs_util.h */ if(fstat(fileno(fp), &file_stat)) cs_critical_error(ERR_NO_FILE, ""); if(file_stat.st_size ==0) cs_critical_error(ERR_NO_FILE, ""); if(course_type == TEMPLATE) { if(*subdir != 'T') { snprintf(temp_course, MAX_COURSE_SUBDIR+1, "%s%s", "T", subdir); strncpy(subdir, temp_course, MAX_COURSE_SUBDIR +1); } } write_roster_file(fp, prefix_rosterfile); make_work_space(prefix_rosterfile); course_data = build_course_info(prefix_rosterfile, subdir); do_action(course_data, prefix_rosterfile, course_type); free_option_person_list (course_data->user_head); free(course_data); cs_cgi_display("super_upload_tar", 1); cs_cgi_destroy(); return 0; }