diff --git a/index.c b/index.c index 90c0089..98b02dc 100755 --- a/index.c +++ b/index.c @@ -12,6 +12,7 @@ #define MAX_ENTRIES 1000 #define TEMPLATE_PATH "/home/romkazvo/www/cgi-bin/template.html" #define OUTPUT_BUFFER_SIZE 65536 +#define PASSWD_FILE "/home/romkazvo/www/cgi-bin/.htpasswd" typedef struct { char name[256]; @@ -20,6 +21,7 @@ typedef struct { char icon[8]; char encoded_path[1024]; char file_url[1024]; + int is_protected; } entry_t; // Быстрый буферизированный вывод @@ -58,6 +60,53 @@ void buffer_free(buffer_t *buf) { free(buf->data); } +// Функция проверки пароля для папки +int check_folder_password(const char *folder_name, const char *password) { + FILE *f = fopen(PASSWD_FILE, "r"); + if (!f) return 1; // Если нет файла с паролями - доступ разрешен + + char line[512]; + while (fgets(line, sizeof(line), f)) { + // Убираем перевод строки + line[strcspn(line, "\r\n")] = 0; + + char *colon = strchr(line, ':'); + if (!colon) continue; + + *colon = '\0'; + char *folder = line; + char *pass = colon + 1; + + if (strcmp(folder, folder_name) == 0) { + fclose(f); + return strcmp(pass, password) == 0; + } + } + fclose(f); + return 1; // Папка не найдена в списке - доступ разрешен +} + +// Проверяет, защищена ли папка паролем +int is_folder_protected(const char *folder_name) { + FILE *f = fopen(PASSWD_FILE, "r"); + if (!f) return 0; + + char line[512]; + while (fgets(line, sizeof(line), f)) { + line[strcspn(line, "\r\n")] = 0; + char *colon = strchr(line, ':'); + if (!colon) continue; + + *colon = '\0'; + if (strcmp(line, folder_name) == 0) { + fclose(f); + return 1; + } + } + fclose(f); + return 0; +} + const char* get_file_icon(const char* filename) { const char *ext = strrchr(filename, '.'); if (!ext) return "📄"; @@ -90,21 +139,18 @@ const char* get_file_icon(const char* filename) { return "📄"; } -// Проверяет, можно ли открыть файл в браузере int is_previewable(const char* filename) { const char *ext = strrchr(filename, '.'); if (!ext) return 0; ext++; - // Изображения if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "jpeg") == 0 || strcasecmp(ext, "png") == 0 || strcasecmp(ext, "gif") == 0 || strcasecmp(ext, "webp") == 0 || strcasecmp(ext, "bmp") == 0 || strcasecmp(ext, "svg") == 0 || strcasecmp(ext, "ico") == 0) return 1; - // Текстовые файлы if (strcasecmp(ext, "txt") == 0 || strcasecmp(ext, "md") == 0 || strcasecmp(ext, "html") == 0 || strcasecmp(ext, "htm") == 0 || strcasecmp(ext, "css") == 0 || strcasecmp(ext, "js") == 0 || @@ -112,17 +158,14 @@ int is_previewable(const char* filename) { strcasecmp(ext, "csv") == 0) return 1; - // PDF if (strcasecmp(ext, "pdf") == 0) return 1; - // Аудио if (strcasecmp(ext, "mp3") == 0 || strcasecmp(ext, "wav") == 0 || strcasecmp(ext, "ogg") == 0 || strcasecmp(ext, "flac") == 0 || strcasecmp(ext, "m4a") == 0 || strcasecmp(ext, "aac") == 0) return 1; - // Видео if (strcasecmp(ext, "mp4") == 0 || strcasecmp(ext, "webm") == 0 || strcasecmp(ext, "ogv") == 0 || strcasecmp(ext, "mov") == 0 || strcasecmp(ext, "avi") == 0 || strcasecmp(ext, "mkv") == 0) @@ -254,6 +297,37 @@ void print_breadcrumb(buffer_t *buf, const char *display_path) { buffer_append(buf, "\n\n"); } +void print_password_form(buffer_t *buf, const char *folder_name) { + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "
🔒
\n"); + buffer_append(buf, "

Папка защищена паролем

\n"); + buffer_append(buf, "

Введите пароль для доступа к папке "); + buffer_append(buf, folder_name); + buffer_append(buf, "

\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, " \n"); + buffer_append(buf, " \n"); + buffer_append(buf, " \n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "

"); + + // Проверяем, была ли ошибка ввода пароля + char *query_string = getenv("QUERY_STRING"); + if (query_string && strstr(query_string, "error=1")) { + buffer_append(buf, "❌ Неверный пароль! Попробуйте снова."); + } + + buffer_append(buf, "

\n"); + buffer_append(buf, " ← Вернуться на главную\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); +} + void print_content(buffer_t *buf, const char *base_path, const char *display_path) { DIR *dir; struct dirent *entry; @@ -265,6 +339,46 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat int dir_count = 0, file_count = 0; long long total_size = 0; + // Проверяем, не защищена ли текущая папка паролем + char folder_name[256] = ""; + if (display_path && display_path[0]) { + char *last_slash = strrchr(display_path, '/'); + if (last_slash) { + strcpy(folder_name, last_slash + 1); + } else { + strcpy(folder_name, display_path); + } + + // Проверяем пароль + char *query_string = getenv("QUERY_STRING"); + char *password = NULL; + if (query_string) { + char *pass_start = strstr(query_string, "password="); + if (pass_start) { + pass_start += 9; + char *pass_end = strchr(pass_start, '&'); + int pass_len = pass_end ? pass_end - pass_start : strlen(pass_start); + if (pass_len > 0 && pass_len < 256) { + char pass_buf[256]; + strncpy(pass_buf, pass_start, pass_len); + pass_buf[pass_len] = '\0'; + // URL декодируем пароль + char decoded_pass[256]; + url_decode_enhanced(pass_buf, decoded_pass, sizeof(decoded_pass)); + password = decoded_pass; + } + } + } + + if (is_folder_protected(folder_name)) { + if (!password || !check_folder_password(folder_name, password)) { + // Показываем форму ввода пароля + print_password_form(buf, folder_name); + return; + } + } + } + dir = opendir(base_path); if (!dir) { char alt_path[1024]; @@ -298,6 +412,14 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat continue; if (strcmp(entry->d_name, "cgi-bin") == 0) continue; + // Скрываем файл с паролями (на всякий случай, если кто-то сможет получить доступ) + if (strcmp(entry->d_name, ".htpasswd") == 0) + continue; + if (strcmp(entry->d_name, ".htaccess") == 0) + continue; + // Скрываем все файлы, начинающиеся с точки + if (entry->d_name[0] == '.') + continue; snprintf(full_path, sizeof(full_path), "%s/%s", base_path, entry->d_name); @@ -308,9 +430,16 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat if (S_ISDIR(file_stat.st_mode)) { entries[entry_count].is_dir = 1; entries[entry_count].size = 0; - strcpy(entries[entry_count].icon, "📁"); - // Предварительно кодируем путь для папок + // Проверяем, защищена ли папка + if (is_folder_protected(entry->d_name)) { + strcpy(entries[entry_count].icon, "🔒"); + entries[entry_count].is_protected = 1; + } else { + strcpy(entries[entry_count].icon, "📁"); + entries[entry_count].is_protected = 0; + } + char new_path[2048]; snprintf(new_path, sizeof(new_path), "%s%s%s", display_path, display_path[0] ? "/" : "", entries[entry_count].name); @@ -321,8 +450,8 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat entries[entry_count].is_dir = 0; entries[entry_count].size = file_stat.st_size; strcpy(entries[entry_count].icon, get_file_icon(entry->d_name)); + entries[entry_count].is_protected = 0; - // Предварительно формируем URL для файлов snprintf(entries[entry_count].file_url, sizeof(entries[0].file_url), "%s%s%s", display_path, display_path[0] ? "/" : "", entries[entry_count].name); @@ -349,7 +478,7 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat buffer_append(buf, "