diff --git a/include/net/ssh.h b/include/net/ssh.h new file mode 100644 index 0000000..c934b94 --- /dev/null +++ b/include/net/ssh.h @@ -0,0 +1,50 @@ +#ifndef _NET_SSH_H +#define _NET_SSH_H + +#include +#include +#include + +#define SSH_DEFAULT_PORT 22 +#define SSH_MAX_SESSIONS 8 +#define SSH_BANNER "SSH-2.0-SUB_OS_SSH_1.0 (Titan-Enterprise)\r\n" +#define SSH_BUFFER_SIZE 2048 + +typedef enum { + SSH_STATE_DISCONNECTED = 0, + SSH_STATE_BANNER_SENT, + SSH_STATE_KEX_INIT, + SSH_STATE_AUTH_REQUEST, + SSH_STATE_AUTHENTICATED, + SSH_STATE_CHANNEL_OPEN, + SSH_STATE_SHELL_ACTIVE +} ssh_state_t; + +typedef struct ssh_session { + uint32_t session_id; + char username[32]; + uint32_t client_ip; + uint16_t client_port; + ssh_state_t state; + bool authenticated; + uint64_t connect_time; + uint64_t bytes_rx; + uint64_t bytes_tx; + bool in_use; +} ssh_session_t; + +void sshd_init(void); +int sshd_start(uint16_t port); +int sshd_stop(void); +bool sshd_is_running(void); +uint16_t sshd_get_port(void); +uint32_t sshd_get_sessions_count(void); +const ssh_session_t* sshd_get_session(size_t index); + +// SSH Remote Execution & Handshake Processor +int sshd_process_packet(const char* in_data, size_t in_len, char* out_resp, size_t max_resp_len); + +// SSH Client Command Runner (e.g. ssh user@host "command") +int ssh_client_execute(const char* username, const char* password, const char* host, uint16_t port, const char* command, char* out_buf, size_t max_len); + +#endif // _NET_SSH_H diff --git a/init/service.c b/init/service.c index 26cbaf3..e1070e8 100644 --- a/init/service.c +++ b/init/service.c @@ -13,10 +13,10 @@ void service_manager_init(void) { memset(services_table, 0, sizeof(services_table)); registered_count = 0; - // Register essential server services service_register("syslogd.service", "System Logging Daemon", default_dummy_start, default_dummy_stop, true); service_register("networking.service", "IPv4 Network Interface Manager", default_dummy_start, default_dummy_stop, true); service_register("httpd.service", "Embedded Micro HTTP Web Server", default_dummy_start, default_dummy_stop, true); + service_register("sshd.service", "OpenSSH Remote Secure Shell Server", default_dummy_start, default_dummy_stop, true); service_register("crond.service", "Periodic Command Scheduler Daemon", default_dummy_start, default_dummy_stop, true); service_register("firewall.service", "NetFilter Stateful Packet Inspection", default_dummy_start, default_dummy_stop, true); @@ -27,7 +27,7 @@ void service_manager_init(void) { } } - printk(KERN_INFO "SYSTEMD: Service Unit Manager initialized (5 services online)\n"); + printk(KERN_INFO "SYSTEMD: Service Unit Manager initialized (6 services online)\n"); } int service_register(const char* name, const char* desc, service_func_t start_fn, service_func_t stop_fn, bool enable_at_boot) { diff --git a/kernel/main.c b/kernel/main.c index 03dd2fc..5ad7bb7 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -130,10 +130,11 @@ void kernel_main(void* memory_map, uint64_t memory_map_count) { usb_init(); printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET); - // 7. Network Subsystem, NetFilter & Web Server - printk(KERN_INFO "[9/18] Initializing Network Stack, NetFilter & Micro HTTPD... "); + // 7. Network Subsystem, NetFilter, HTTPD & SSH Server + printk(KERN_INFO "[9/18] Initializing Network Stack, NetFilter, HTTPD & SSHD... "); filter_init(); httpd_init(); + sshd_init(); if (e1000_init()) { net_init(); socket_subsystem_init(); diff --git a/net/ssh.c b/net/ssh.c new file mode 100644 index 0000000..096827b --- /dev/null +++ b/net/ssh.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool sshd_running = false; +static uint16_t sshd_listen_port = SSH_DEFAULT_PORT; +static ssh_session_t ssh_sessions[SSH_MAX_SESSIONS]; +static uint32_t next_session_id = 1001; + +void sshd_init(void) { + sshd_running = false; + sshd_listen_port = SSH_DEFAULT_PORT; + memset(ssh_sessions, 0, sizeof(ssh_sessions)); + printk(KERN_INFO "SSHD: Secure Shell Protocol 2.0 Daemon Subsystem initialized\n"); +} + +int sshd_start(uint16_t port) { + sshd_listen_port = port > 0 ? port : SSH_DEFAULT_PORT; + sshd_running = true; + + // Create default listening session slot + ssh_sessions[0].session_id = next_session_id++; + ssh_sessions[0].in_use = true; + ssh_sessions[0].state = SSH_STATE_SHELL_ACTIVE; + ssh_sessions[0].authenticated = true; + strcpy(ssh_sessions[0].username, "root"); + ssh_sessions[0].client_ip = 0x0A000202; // 10.0.2.2 (QEMU Host Gateway) + ssh_sessions[0].client_port = 52341; + ssh_sessions[0].connect_time = pit_get_ticks() / 100; + + printk(KERN_INFO "SSHD: Server listening on 0.0.0.0:%u (SSH-2.0-OpenSSH/SUB-OS)\n", sshd_listen_port); + return 0; +} + +int sshd_stop(void) { + sshd_running = false; + memset(ssh_sessions, 0, sizeof(ssh_sessions)); + printk(KERN_INFO "SSHD: Server stopped\n"); + return 0; +} + +bool sshd_is_running(void) { + return sshd_running; +} + +uint16_t sshd_get_port(void) { + return sshd_listen_port; +} + +uint32_t sshd_get_sessions_count(void) { + uint32_t count = 0; + for (size_t i = 0; i < SSH_MAX_SESSIONS; i++) { + if (ssh_sessions[i].in_use) count++; + } + return count; +} + +const ssh_session_t* sshd_get_session(size_t index) { + if (index >= SSH_MAX_SESSIONS || !ssh_sessions[index].in_use) return NULL; + return &ssh_sessions[index]; +} + +int sshd_process_packet(const char* in_data, size_t in_len, char* out_resp, size_t max_resp_len) { + if (!in_data || !out_resp || max_resp_len == 0) return -1; + (void)in_len; + + // Echo banner exchange / auth check + if (strncmp(in_data, "SSH-", 4) == 0) { + snprintf(out_resp, max_resp_len, "%s", SSH_BANNER); + return (int)strlen(out_resp); + } + + snprintf(out_resp, max_resp_len, "SUB-OS Remote Terminal Ready\n"); + return (int)strlen(out_resp); +} + +int ssh_client_execute(const char* username, const char* password, const char* host, uint16_t port, const char* command, char* out_buf, size_t max_len) { + if (!username || !host || !out_buf || max_len == 0) return -1; + + if (!sshd_running) { + snprintf(out_buf, max_len, "ssh: connect to host %s port %u: Connection refused\n", host, port ? port : 22); + return -1; + } + + // Verify credentials + const char* pass_to_check = password ? password : username; + if (!auth_verify_password(username, pass_to_check)) { + snprintf(out_buf, max_len, "Permission denied (publickey,password) for user '%s'.\n", username); + return -1; + } + + // Record session + for (size_t i = 1; i < SSH_MAX_SESSIONS; i++) { + if (!ssh_sessions[i].in_use) { + ssh_sessions[i].session_id = next_session_id++; + ssh_sessions[i].in_use = true; + strncpy(ssh_sessions[i].username, username, sizeof(ssh_sessions[i].username) - 1); + ssh_sessions[i].state = SSH_STATE_SHELL_ACTIVE; + ssh_sessions[i].authenticated = true; + ssh_sessions[i].client_ip = 0x7F000001; // 127.0.0.1 + ssh_sessions[i].client_port = 49152 + (uint16_t)i; + ssh_sessions[i].connect_time = pit_get_ticks() / 100; + break; + } + } + + if (!command || command[0] == '\0') { + snprintf(out_buf, max_len, + "Authenticated to %s ([%s]:%u) with password.\n" + "Welcome to SUB-OS Enterprise Remote Shell v0.2.0 (x86_64).\n" + "Last login: Sun Aug 16 2026 from %s\n", + host, host, port ? port : 22, host); + return 0; + } + + // Remote Command Execution + snprintf(out_buf, max_len, + "[%s@%s ~]$ %s\n", username, host, command); + + return 0; +} diff --git a/userland/lazybox/lazybox.c b/userland/lazybox/lazybox.c index 970ce2d..f18c934 100644 --- a/userland/lazybox/lazybox.c +++ b/userland/lazybox/lazybox.c @@ -1032,6 +1032,72 @@ static int applet_httpd(int argc, char** argv) { return 0; } +#include + +static int applet_sshd(int argc, char** argv) { + if (argc >= 2) { + if (strcmp(argv[1], "start") == 0) { + uint16_t port = (argc >= 3) ? (uint16_t)atoi(argv[2]) : 22; + sshd_start(port); + return 0; + } else if (strcmp(argv[1], "stop") == 0) { + sshd_stop(); + return 0; + } + } + + printk(ANSI_BRIGHT_CYAN "=== OpenSSH Remote Secure Shell Server (SSHD) ===\n" ANSI_RESET); + printk("Status: %s\n", sshd_is_running() ? ANSI_BRIGHT_GREEN "RUNNING" ANSI_RESET : ANSI_YELLOW "STOPPED" ANSI_RESET); + printk("Port: %u (SSH-2.0)\n", sshd_get_port()); + printk("Active Sessions: %u\n", sshd_get_sessions_count()); + printk("Usage: sshd [start [port] | stop | status]\n"); + return 0; +} + +static int applet_ssh(int argc, char** argv) { + if (argc < 2) { + printk(KERN_INFO "Usage: ssh [user@]hostname [command]\n"); + return 1; + } + + char username[32] = "root"; + char host[64] = "localhost"; + uint16_t port = 22; + + const char* target = argv[1]; + const char* at = strchr(target, '@'); + if (at) { + size_t ulen = at - target; + if (ulen < sizeof(username)) { + memcpy(username, target, ulen); + username[ulen] = '\0'; + } + strncpy(host, at + 1, sizeof(host) - 1); + } else { + strncpy(host, target, sizeof(host) - 1); + } + + char cmd_buf[128] = ""; + if (argc >= 3) { + for (int i = 2; i < argc; i++) { + strcat(cmd_buf, argv[i]); + if (i + 1 < argc) strcat(cmd_buf, " "); + } + } + + char out_resp[1024]; + if (ssh_client_execute(username, username, host, port, cmd_buf, out_resp, sizeof(out_resp)) == 0) { + printk("%s", out_resp); + if (cmd_buf[0] != '\0') { + // Execute the requested command + return lazybox_run_applet(argv[2], argc - 2, &argv[2]); + } + return 0; + } + printk(KERN_ERR "%s", out_resp); + return 1; +} + static int applet_curl(int argc, char** argv) { if (argc < 2) { printk(KERN_INFO "Usage: curl \n"); @@ -1254,6 +1320,8 @@ static const lazybox_applet_t applets[] = { // Server & Web {"httpd", applet_httpd, "httpd [start|stop|status]", "Embedded micro HTTP server", "Server"}, + {"sshd", applet_sshd, "sshd [start|stop|status]", "OpenSSH server daemon", "Server"}, + {"ssh", applet_ssh, "ssh [user@]host [cmd]", "Secure shell remote client", "Server"}, {"curl", applet_curl, "curl ", "HTTP transfer utility", "Server"}, {"wget", applet_wget, "wget ", "Download files via HTTP", "Server"}, {"systemctl", applet_systemctl, "systemctl [cmd] [unit]", "Manage system service daemons","Server"},