#include #include #include #include #include /* for umask() */ #include #include /* for file locking */ #include /* for unlink() */ #include "../global.h" #include "../custom.h" #include "shared_util.h" #include "shared_authenticate.h" /* for sub_dir_name() */ #include "shared_cookie.h" #include "shared_lock.h" #include "shared_cs_util.h" #define CHAR_SET "" void send_content_type () { static int content_type_sent = 0; if (!content_type_sent) { printf ("Content-type: text/html%s%s\n\n", strlen (CHAR_SET) ? "; " : "", CHAR_SET); /* LANG_CHARSET is #defined in lang.h */ content_type_sent = 1; } } void read_configuration_file (const char *fname, CONFIG_STRUCT * config) { #define MAX_MSG 100 FILE *fp; int fd; char fullpath[MAX_PATH + 1]; int is_template; /* if the first letter of the course fname starts with a 'T', ** then this is a course template and the config file will be ** located in the TEMPLATE_PATH directory instead of the ** COURSE_PATH directory */ is_template = (*fname == 'T'); snprintf (fullpath, MAX_PATH + 1, "%s%s/%s", is_template ? TEMPLATE_PATH : COURSE_PATH, fname, CONFIG_FNAME); fp = fopen (fullpath, "r"); if (!fp) { cs_critical_error (ERR_ERROR_OPENING_CONFIG_FILE, fullpath); /* shared_cs_util.c */ } /* the config file can be changed by a teacher or administrator ** so we use advisory file locking */ fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ if (fread (config, sizeof (CONFIG_STRUCT), 1, fp) != 1) cs_critical_error (ERR_ERROR_READING_CONFIG_FILE, fullpath); /* shared_cs_util.c */ release_lock(fd); /* shared_lock.c */ fclose (fp); /* whether the course is a template or not is NOT stored in the file.. ** instead it is set here based on the course name */ config->template = is_template; /* the course_path data item used to be saved in the file since the ** addition of the course templates idea, it is more convenient to set ** it here */ snprintf (config->course_path, MAX_PATH + 1, "%s%s/", is_template ? TEMPLATE_PATH : COURSE_PATH, fname); #undef MAX_MSG } /** this version of read_configuration_file() *** returns 1 on success, else 0 **/ int read_configuration_file_ok (const char *fname, CONFIG_STRUCT * config) { FILE *fp; int fd; char fullpath[MAX_PATH + 1]; int is_template; /* if the first letter of the course fname starts with a 'T', ** then this is a course template and the config file will be ** located in the TEMPLATE_PATH directory instead of the ** COURSE_PATH directory */ is_template = (*fname == 'T'); snprintf (fullpath, MAX_PATH + 1, "%s%s/%s", is_template ? TEMPLATE_PATH : COURSE_PATH, fname, CONFIG_FNAME); fp = fopen (fullpath, "r"); if (!fp) return 0; /* the config file can be changed by a teacher or administrator ** so we use advisory file locking */ fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ if (fread (config, sizeof (CONFIG_STRUCT), 1, fp) != 1) { release_lock(fd); fclose(fp); return 0; } release_lock(fd); /* shared_lock.c */ fclose (fp); /* whether the course is a template or not is NOT stored in the file.. ** instead it is set here based on the course name */ config->template = is_template; /* the course_path data item used to be saved in the file since the ** addition of the course templates idea, it is more convenient to set ** it here */ snprintf (config->course_path, MAX_PATH + 1, "%s%s/", is_template ? TEMPLATE_PATH : COURSE_PATH, fname); return 1; /* success */ } /*void set_umask () { umask (0006); all files to have rw-rw---- access } */ void check_key_for_cookie(const char *orig_key_fname, char *new_key_fname) { if(!strcmp(orig_key_fname, USE_COOKIE)) { if(!parse_cookie(new_key_fname)) /* shared_cookie.c */ cs_critical_error (ERR_SORRY_YOUVE_BEEN_LOGGED_OUT, ""); } else strncpy(new_key_fname, orig_key_fname, MAX_KEY + 1); } void get_ip_address(char *this_ip) { char *ip_ptr; ip_ptr = getenv("REMOTE_ADDR"); if(!ip_ptr) *this_ip = '\0'; else { strncpy(this_ip, ip_ptr, MAX_IP + 1); *(this_ip + MAX_IP) = '\0'; } } void secure_server_check() { int server_port; if(USE_HTTPS) { server_port = atoi(getenv("SERVER_PORT")); if(server_port != HTTPS_PORT) cs_critical_error(ERR_THIS_IS_A_SECURE_SERVER, ""); } } /* converts first occurrence of a slash / to a ** dot - returns results in new ** assumes length of orig < MAX_PATH */ void course_slash_to_dot(const char *orig, char *new) { char *ptr; strncpy(new, orig, MAX_PATH + 1); ptr = strchr(new, '/'); if(ptr) *ptr = '.'; } void get_symlink_fname ( const char *course, char *symlink_fname, const SESSION *user) { char modified_course[MAX_PATH + 1]; course_slash_to_dot(course, modified_course); /* shared_util.c */ snprintf (symlink_fname, MAX_FILENAME + 1, "%s_%s_%ld_%d", user->username, modified_course, (long)time(NULL), getpid()); } void validate_server_key (const char *key_fname, SESSION *user) { #define MAX_MSG 200 FILE *fp; time_t now; char msg[MAX_MSG]; char keypath[MAX_PATH + 1]; char key_filename[MAX_KEY + 1]; char this_ip[MAX_IP + 1]; secure_server_check(); check_key_for_cookie(key_fname, key_filename); snprintf (keypath, MAX_PATH + 1, "../%s/keys/%s", USERS_DIR, key_filename); fp = fopen (keypath, "r+"); if (!fp) cs_timeout_error(ERR_SORRY_YOUVE_BEEN_LOGGED_OUT, ""); if (fread (user, sizeof (SESSION), 1, fp) != 1) { cs_timeout_error (ERR_ERROR_READING_KEY_FILE, key_filename); } if(IP_CHECK_ENABLED) /* see custom.h - compare ip address stored in key to this_ip */ { get_ip_address(this_ip); if(strcmp(user->ip_address, this_ip)) cs_timeout_error(ERR_REQUEST_DENIED, ""); } if (user->expires) { now = time (NULL); if (user->expires < now) { snprintf (msg, MAX_MSG, "%d", (MAX_KEY_EXPIRE) / 60); cs_timeout_error (ERR_YOUR_SESSION_HAS_TIMED_OUT, msg); } user->expires = now + MAX_KEY_EXPIRE; if (fseek(fp,0,SEEK_SET)) cs_timeout_error (ERR_CANT_CREATE_NEW_KEY, ""); if (fwrite (user, sizeof (SESSION), 1, fp) != 1) cs_timeout_error (ERR_ERROR_WRITING_KEY, ""); fclose (fp); } #undef MAX_MSG } void validate_key (const char *key_fname, SESSION * user, CONFIG_STRUCT *conf) { #define MAX_MSG 256 FILE *fp; time_t now; char msg[MAX_MSG]; char keypath[MAX_PATH + 1]; char *ptr2; char key_filename[MAX_KEY + 1]; char this_ip[MAX_IP + 1]; char course_name[MAX_PATH + 1]; if(conf->standalone) { secure_server_check(); check_key_for_cookie(key_fname, key_filename); snprintf (keypath, MAX_PATH + 1, "%skeys/%s", conf->course_path, key_filename); fp = fopen (keypath, "r+"); if (!fp) cs_timeout_error (ERR_SORRY_YOUVE_BEEN_LOGGED_OUT, ""); if (fread (user, sizeof (SESSION), 1, fp) != 1) { cs_timeout_error (ERR_ERROR_READING_KEY_FILE, key_filename); } if(IP_CHECK_ENABLED) /*see custom.h */ { get_ip_address(this_ip); if(strcmp(user->ip_address, this_ip)) cs_timeout_error(ERR_REQUEST_DENIED, ""); } if (user->expires) { now = time (NULL); if (user->expires < now) { snprintf (msg, MAX_MSG, "%d", conf->key_expire / 60); cs_timeout_error (ERR_YOUR_SESSION_HAS_TIMED_OUT, msg); } user->expires = now + conf->key_expire; if(fseek(fp,0,SEEK_SET)) cs_timeout_error (ERR_CANT_CREATE_NEW_KEY, ""); if (fwrite (user, sizeof (SESSION), 1, fp) != 1) cs_timeout_error (ERR_ERROR_WRITING_KEY, ""); fclose (fp); } } else /* course is a centralized login course */ { validate_server_key (key_fname, user); if(user->group != ADMIN) { strncpy(course_name, conf->course_path, MAX_PATH + 1); /* extract course name from course_path */ ptr2 = strrchr(course_name,'/'); if(!ptr2 || (ptr2 == course_name)) cs_timeout_error(ERR_NO_SLASH_IN_COURSE_PATH, ""); *ptr2 = '\0'; ptr2 = strrchr(course_name, '/'); if(!ptr2 || (ptr2== course_name)) cs_timeout_error(ERR_NO_SLASH_IN_COURSE_PATH, ""); *ptr2 = '.'; ptr2 = strrchr(course_name, '/'); if(!ptr2 || (ptr2== course_name)) cs_timeout_error(ERR_NO_SLASH_IN_COURSE_PATH, ""); /* sub_dir_name() is in shared_authenticate.c */ snprintf(keypath, MAX_PATH + 1, "../%s/%c/%s/%s%s", USERS_DIR, sub_dir_name(user->username), user->username, ptr2 + 1,KEY_FILE_EXTENSION); fp = fopen(keypath, "r"); if(!fp) cs_timeout_error (ERR_SORRY_YOUVE_BEEN_LOGGED_OUT, ""); if(fread(user,sizeof(SESSION), 1, fp) != 1) cs_timeout_error (ERR_SORRY_YOUVE_BEEN_LOGGED_OUT, ""); fclose(fp); } } #undef MAX_MSG } void crash (const char *msg1, const char *msg2) { puts (msg1); puts (msg2); exit (1); } /* this is only for WNEC */ /* WNEC's faculty id is 4 digits */ int is_wnec_faculty(const char *id) { #ifdef WNEC_FACULTY_ID int count = 0; int i, len; if(WNEC_FACULTY_ID) { len = strlen(id); for(i = 0; i < len; i++) { if(isdigit(id[i])) count++; } if(count == 4) return 1; return 0; } #endif return 1; }