--- lbbs/src/net_server.c 2025/12/01 14:01:36 1.99 +++ lbbs/src/net_server.c 2025/12/25 05:20:09 1.113 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -114,6 +115,11 @@ static int auth_password(ssh_session ses else { ret = check_user(user, password); + if (ret == 2) // Enforce update user agreement + { + BBS_update_eula = 1; + ret = 0; + } } if (ret == 0) @@ -147,7 +153,7 @@ static int pty_request(ssh_session sessi rc = openpty(&cdata->pty_master, &cdata->pty_slave, NULL, NULL, cdata->winsize); if (rc != 0) { - log_error("Failed to open pty\n"); + log_error("Failed to open pty"); return SSH_ERROR; } @@ -181,7 +187,7 @@ static int exec_pty(const char *mode, co if (command != NULL) { - log_error("Forbid exec /bin/sh %s %s)\n", mode, command); + log_error("Forbid exec /bin/sh %s %s)", mode, command); } return SSH_OK; @@ -193,7 +199,7 @@ static int exec_nopty(const char *comman if (command != NULL) { - log_error("Forbid exec /bin/sh -c %s)\n", command); + log_error("Forbid exec /bin/sh -c %s)", command); } return SSH_OK; @@ -243,7 +249,7 @@ static int subsystem_request(ssh_session (void)session; (void)channel; - log_error("subsystem_request(subsystem=%s)\n", subsystem); + log_error("subsystem_request(subsystem=%s)", subsystem); /* subsystem requests behave similarly to exec requests. */ if (strcmp(subsystem, "sftp") == 0) @@ -317,12 +323,12 @@ static int fork_server(void) if (pid > 0) // Parent process { SYS_child_process_count++; - log_common("Child process (%d) start\n", pid); + log_common("Child process (%d) start", pid); return pid; } else if (pid < 0) // Error { - log_error("fork() error (%d)\n", errno); + log_error("fork() error (%d)", errno); return -1; } @@ -330,7 +336,7 @@ static int fork_server(void) #ifdef HAVE_SYS_EPOLL_H if (close(epollfd_server) < 0) { - log_error("close(epollfd_server) error (%d)\n"); + log_error("close(epollfd_server) error (%d)"); } #endif @@ -338,7 +344,7 @@ static int fork_server(void) { if (close(socket_server[i]) == -1) { - log_error("Close server socket failed\n"); + log_error("Close server socket failed"); } } @@ -351,7 +357,7 @@ static int fork_server(void) { if (ssh_bind_accept_fd(sshbind, SSH_session, socket_client) != SSH_OK) { - log_error("ssh_bind_accept_fd() error: %s\n", ssh_get_error(SSH_session)); + log_error("ssh_bind_accept_fd() error: %s", ssh_get_error(SSH_session)); goto cleanup; } @@ -360,7 +366,7 @@ static int fork_server(void) ssh_timeout = 60; // second if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0) { - log_error("Error setting SSH options: %s\n", ssh_get_error(SSH_session)); + log_error("Error setting SSH options: %s", ssh_get_error(SSH_session)); goto cleanup; } @@ -373,7 +379,7 @@ static int fork_server(void) if (ssh_handle_key_exchange(SSH_session)) { - log_error("ssh_handle_key_exchange() error: %s\n", ssh_get_error(SSH_session)); + log_error("ssh_handle_key_exchange() error: %s", ssh_get_error(SSH_session)); goto cleanup; } @@ -385,16 +391,14 @@ static int fork_server(void) ret = ssh_event_dopoll(event, 100); // 0.1 second if (ret == SSH_ERROR) { -#ifdef _DEBUG - log_error("ssh_event_dopoll() error: %s\n", ssh_get_error(SSH_session)); -#endif + log_debug("ssh_event_dopoll() error: %s", ssh_get_error(SSH_session)); goto cleanup; } } if (cb_data.error) { - log_error("SSH auth error, tried %d times\n", cb_data.tries); + log_error("SSH auth error, tried %d times", cb_data.tries); goto cleanup; } @@ -419,7 +423,7 @@ static int fork_server(void) ssh_timeout = 0; if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0) { - log_error("Error setting SSH options: %s\n", ssh_get_error(SSH_session)); + log_error("Error setting SSH options: %s", ssh_get_error(SSH_session)); goto cleanup; } @@ -429,20 +433,20 @@ static int fork_server(void) // Redirect Input if (dup2(socket_client, STDIN_FILENO) == -1) { - log_error("Redirect stdin to client socket failed\n"); + log_error("Redirect stdin to client socket failed"); goto cleanup; } // Redirect Output if (dup2(socket_client, STDOUT_FILENO) == -1) { - log_error("Redirect stdout to client socket failed\n"); + log_error("Redirect stdout to client socket failed"); goto cleanup; } if (io_init() < 0) { - log_error("io_init() error\n"); + log_error("io_init() error"); goto cleanup; } @@ -451,7 +455,7 @@ static int fork_server(void) // BWF compile if (bwf_compile() < 0) { - log_error("bwf_compile() error\n"); + log_error("bwf_compile() error"); goto cleanup; } @@ -485,7 +489,7 @@ cleanup: } else if (close(socket_client) == -1) { - log_error("Close client socket failed\n"); + log_error("Close client socket failed"); } ssh_free(SSH_session); @@ -499,7 +503,7 @@ cleanup: close(STDIN_FILENO); close(STDOUT_FILENO); - log_common("Process exit normally\n"); + log_common("Process exit normally"); log_end(); _exit(0); @@ -509,10 +513,12 @@ cleanup: int net_server(const char *hostaddr, in_port_t port[]) { + struct stat file_stat; unsigned int addrlen; int ret; int flags_server[2]; struct sockaddr_in sin; + char local_addr[INET_ADDRSTRLEN]; #ifdef HAVE_SYS_EPOLL_H struct epoll_event ev, events[MAX_EVENTS]; @@ -523,7 +529,6 @@ int net_server(const char *hostaddr, in_ int nfds; int notify_child_exit = 0; time_t tm_notify_child_exit = time(NULL); - int i, j; pid_t pid; int ssh_key_valid = 0; int ssh_log_level = SSH_LOG_NOLOG; @@ -538,7 +543,7 @@ int net_server(const char *hostaddr, in_ if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_RSA_KEY_FILE) < 0) { - log_error("Error loading SSH RSA key: %s\n", SSH_HOST_RSA_KEY_FILE); + log_error("Error loading SSH RSA key: %s", SSH_HOST_RSA_KEY_FILE); } else { @@ -546,7 +551,7 @@ int net_server(const char *hostaddr, in_ } if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_ED25519_KEY_FILE) < 0) { - log_error("Error loading SSH ED25519 key: %s\n", SSH_HOST_ED25519_KEY_FILE); + log_error("Error loading SSH ED25519 key: %s", SSH_HOST_ED25519_KEY_FILE); } else { @@ -554,7 +559,7 @@ int net_server(const char *hostaddr, in_ } if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_ECDSA_KEY_FILE) < 0) { - log_error("Error loading SSH ECDSA key: %s\n", SSH_HOST_ECDSA_KEY_FILE); + log_error("Error loading SSH ECDSA key: %s", SSH_HOST_ECDSA_KEY_FILE); } else { @@ -563,17 +568,17 @@ int net_server(const char *hostaddr, in_ if (!ssh_key_valid) { - log_error("Error: no valid SSH host key\n"); + log_error("Error: no valid SSH host key"); ssh_bind_free(sshbind); return -1; } if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, hostaddr) < 0 || ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &port) < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "+ssh-rsa") < 0 || + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "+ssh-ed25519,ecdsa-sha2-nistp256,ssh-rsa") < 0 || ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level) < 0) { - log_error("Error setting SSH bind options: %s\n", ssh_get_error(sshbind)); + log_error("Error setting SSH bind options: %s", ssh_get_error(sshbind)); ssh_bind_free(sshbind); return -1; } @@ -582,19 +587,19 @@ int net_server(const char *hostaddr, in_ epollfd_server = epoll_create1(0); if (epollfd_server == -1) { - log_error("epoll_create1() error (%d)\n", errno); + log_error("epoll_create1() error (%d)", errno); return -1; } #endif // Server socket - for (i = 0; i < 2; i++) + for (int i = 0; i < 2; i++) { socket_server[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (socket_server[i] < 0) { - log_error("Create socket_server error (%d)\n", errno); + log_error("Create socket_server error (%d)", errno); return -1; } @@ -602,43 +607,49 @@ int net_server(const char *hostaddr, in_ sin.sin_addr.s_addr = (hostaddr[0] != '\0' ? inet_addr(hostaddr) : INADDR_ANY); sin.sin_port = htons(port[i]); + if (inet_ntop(AF_INET, &(sin.sin_addr), local_addr, sizeof(local_addr)) == NULL) + { + log_error("inet_ntop() error (%d)", errno); + return -1; + } + // Reuse address and port flags_server[i] = 1; if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEADDR, &flags_server[i], sizeof(flags_server[i])) < 0) { - log_error("setsockopt SO_REUSEADDR error (%d)\n", errno); + log_error("setsockopt SO_REUSEADDR error (%d)", errno); } #if defined(SO_REUSEPORT) if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEPORT, &flags_server[i], sizeof(flags_server[i])) < 0) { - log_error("setsockopt SO_REUSEPORT error (%d)\n", errno); + log_error("setsockopt SO_REUSEPORT error (%d)", errno); } #endif if (bind(socket_server[i], (struct sockaddr *)&sin, sizeof(sin)) < 0) { - log_error("Bind address %s:%u error (%d)\n", - inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), errno); + log_error("Bind address %s:%u error (%d)", + local_addr, port[i], errno); return -1; } if (listen(socket_server[i], 10) < 0) { - log_error("Telnet socket listen error (%d)\n", errno); + log_error("Telnet socket listen error (%d)", errno); return -1; } - log_common("Listening at %s:%u\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + log_common("Listening at %s:%u", local_addr, port[i]); #ifdef HAVE_SYS_EPOLL_H ev.events = EPOLLIN; ev.data.fd = socket_server[i]; if (epoll_ctl(epollfd_server, EPOLL_CTL_ADD, socket_server[i], &ev) == -1) { - log_error("epoll_ctl(socket_server[%d]) error (%d)\n", i, errno); + log_error("epoll_ctl(socket_server[%d]) error (%d)", i, errno); if (close(epollfd_server) < 0) { - log_error("close(epoll) error (%d)\n"); + log_error("close(epoll) error (%d)"); } return -1; } @@ -653,13 +664,13 @@ int net_server(const char *hostaddr, in_ hash_dict_pid_sockaddr = hash_dict_create(MAX_CLIENT_LIMIT); if (hash_dict_pid_sockaddr == NULL) { - log_error("hash_dict_create(hash_dict_pid_sockaddr) error\n"); + log_error("hash_dict_create(hash_dict_pid_sockaddr) error"); return -1; } hash_dict_sockaddr_count = hash_dict_create(MAX_CLIENT_LIMIT); if (hash_dict_sockaddr_count == NULL) { - log_error("hash_dict_create(hash_dict_sockaddr_count) error\n"); + log_error("hash_dict_create(hash_dict_sockaddr_count) error"); return -1; } @@ -693,37 +704,37 @@ int net_server(const char *hostaddr, in_ if (WIFEXITED(ret)) { - log_common("Child process (%d) exited, status=%d\n", pid, WEXITSTATUS(ret)); + log_common("Child process (%d) exited, status=%d", pid, WEXITSTATUS(ret)); } else if (WIFSIGNALED(ret)) { - log_common("Child process (%d) is killed, status=%d\n", pid, WTERMSIG(ret)); + log_common("Child process (%d) is killed, status=%d", pid, WTERMSIG(ret)); } else { - log_common("Child process (%d) exited abnormally, status=%d\n", pid, ret); + log_common("Child process (%d) exited abnormally, status=%d", pid, ret); } if (pid != section_list_loader_pid) { - j = 0; - ret = hash_dict_get(hash_dict_pid_sockaddr, (uint64_t)pid, (int64_t *)&j); + int64_t j = 0; + ret = hash_dict_get(hash_dict_pid_sockaddr, (uint64_t)pid, &j); if (ret < 0) { - log_error("hash_dict_get(hash_dict_pid_sockaddr, %d) error\n", pid); + log_error("hash_dict_get(hash_dict_pid_sockaddr, %d) error", pid); } else { - ret = hash_dict_inc(hash_dict_sockaddr_count, (uint64_t)j, -1); - if (ret < 0) + ret = hash_dict_inc(hash_dict_sockaddr_count, (in_addr_t)j, -1); + if (ret <= 0) { - log_error("hash_dict_inc(hash_dict_sockaddr_count, %d, -1) error\n", j); + log_error("hash_dict_inc(hash_dict_sockaddr_count, %lu, -1) error: %d", (in_addr_t)j, ret); } ret = hash_dict_del(hash_dict_pid_sockaddr, (uint64_t)pid); if (ret < 0) { - log_error("hash_dict_del(hash_dict_pid_sockaddr, %d) error\n", pid); + log_error("hash_dict_del(hash_dict_pid_sockaddr, %lu) error", (uint64_t)pid); } } } @@ -734,7 +745,7 @@ int net_server(const char *hostaddr, in_ } else if (pid < 0) { - log_error("Error in waitpid(): %d\n", errno); + log_error("Error in waitpid(): %d", errno); break; } } @@ -745,12 +756,12 @@ int net_server(const char *hostaddr, in_ { #ifdef HAVE_SYSTEMD_SD_DAEMON_H sd_notifyf(0, "STATUS=Notify %d child process to exit", SYS_child_process_count); - log_common("Notify %d child process to exit\n", SYS_child_process_count); + log_common("Notify %d child process to exit", SYS_child_process_count); #endif if (kill(0, SIGTERM) < 0) { - log_error("Send SIGTERM signal failed (%d)\n", errno); + log_error("Send SIGTERM signal failed (%d)", errno); } notify_child_exit = 1; @@ -764,7 +775,7 @@ int net_server(const char *hostaddr, in_ if (kill(0, SIGKILL) < 0) { - log_error("Send SIGKILL signal failed (%d)\n", errno); + log_error("Send SIGKILL signal failed (%d)", errno); } notify_child_exit = 2; @@ -772,7 +783,7 @@ int net_server(const char *hostaddr, in_ } else if (notify_child_exit == 2 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_KILL_TIMEOUT) { - log_error("Main process prepare to exit without waiting for %d child process any longer\n", SYS_child_process_count); + log_error("Main process prepare to exit without waiting for %d child process any longer", SYS_child_process_count); SYS_child_process_count = 0; } } @@ -785,62 +796,75 @@ int net_server(const char *hostaddr, in_ sd_notify(0, "RELOADING=1"); #endif + log_common("Reload configuration"); + // Restart log if (log_restart() < 0) { - log_error("Restart logging failed\n"); + log_error("Restart logging failed"); } // Reload configuration if (load_conf(CONF_BBSD) < 0) { - log_error("Reload conf failed\n"); + log_error("Reload conf failed"); } // Reload BWF config if (bwf_load(CONF_BWF) < 0) { - log_error("Reload BWF conf failed\n"); + log_error("Reload BWF conf failed"); + } + + // Get EULA modification tm + if (stat(DATA_EULA, &file_stat) == -1) + { + log_error("stat(%s) error", DATA_EULA, errno); + } + else + { + BBS_eula_tm = file_stat.st_mtim.tv_sec; } if (detach_menu_shm(&bbs_menu) < 0) { - log_error("detach_menu_shm(bbs_menu) error\n"); + log_error("detach_menu_shm(bbs_menu) error"); } if (load_menu(&bbs_menu, CONF_MENU) < 0) { - log_error("load_menu(bbs_menu) error\n"); + log_error("load_menu(bbs_menu) error"); unload_menu(&bbs_menu); } if (detach_menu_shm(&top10_menu) < 0) { - log_error("detach_menu_shm(top10_menu) error\n"); + log_error("detach_menu_shm(top10_menu) error"); } if (load_menu(&top10_menu, CONF_TOP10_MENU) < 0) { - log_error("load_menu(top10_menu) error\n"); + log_error("load_menu(top10_menu) error"); unload_menu(&top10_menu); } + top10_menu.allow_exit = 1; for (int i = 0; i < data_files_load_startup_count; i++) { if (load_file(data_files_load_startup[i]) < 0) { - log_error("load_file(%s) error\n", data_files_load_startup[i]); + log_error("load_file(%s) error", data_files_load_startup[i]); } } // Load section config and gen_ex if (load_section_config_from_db(1) < 0) { - log_error("load_section_config_from_db(1) error\n"); + log_error("load_section_config_from_db(1) error"); } // Notify child processes to reload configuration if (kill(0, SIGUSR1) < 0) { - log_error("Send SIGUSR1 signal failed (%d)\n", errno); + log_error("Send SIGUSR1 signal failed (%d)", errno); } #ifdef HAVE_SYSTEMD_SD_DAEMON_H @@ -864,9 +888,9 @@ int net_server(const char *hostaddr, in_ if (errno != EINTR) { #ifdef HAVE_SYS_EPOLL_H - log_error("epoll_wait() error (%d)\n", errno); + log_error("epoll_wait() error (%d)", errno); #else - log_error("poll() error (%d)\n", errno); + log_error("poll() error (%d)", errno); #endif break; } @@ -909,61 +933,83 @@ int net_server(const char *hostaddr, in_ } else { - log_error("accept(socket_server) error (%d)\n", errno); + log_error("accept(socket_server) error (%d)", errno); break; } } - strncpy(hostaddr_client, inet_ntoa(sin.sin_addr), sizeof(hostaddr_client) - 1); - hostaddr_client[sizeof(hostaddr_client) - 1] = '\0'; - + if (inet_ntop(AF_INET, &(sin.sin_addr), hostaddr_client, sizeof(hostaddr_client)) == NULL) + { + log_error("inet_ntop() error (%d)", errno); + close(socket_client); + break; + } port_client = ntohs(sin.sin_port); - log_common("Accept %s connection from %s:%d\n", (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client); - if (SYS_child_process_count - 1 < BBS_max_client) { - j = 0; - ret = hash_dict_get(hash_dict_sockaddr_count, (uint64_t)sin.sin_addr.s_addr, (int64_t *)&j); + int64_t j = 0; + ret = hash_dict_get(hash_dict_sockaddr_count, sin.sin_addr.s_addr, &j); if (ret < 0) { - log_error("hash_dict_get(hash_dict_sockaddr_count, %s) error\n", hostaddr_client); + log_error("hash_dict_get(hash_dict_sockaddr_count, %s) error", hostaddr_client); } if (j < BBS_max_client_per_ip) { if ((pid = fork_server()) < 0) { - log_error("fork_server() error\n"); + log_error("fork_server() error"); } else if (pid > 0) { ret = hash_dict_set(hash_dict_pid_sockaddr, (uint64_t)pid, sin.sin_addr.s_addr); if (ret < 0) { - log_error("hash_dict_set(hash_dict_pid_sockaddr, %d, %s) error\n", pid, hostaddr_client); + log_error("hash_dict_set(hash_dict_pid_sockaddr, %lu, %s) error", (uint64_t)pid, hostaddr_client); } - ret = hash_dict_inc(hash_dict_sockaddr_count, (uint64_t)sin.sin_addr.s_addr, 1); - if (ret < 0) + if (j == 0) { - log_error("hash_dict_inc(hash_dict_sockaddr_count, %s, %d) error\n", hostaddr_client, 1); + // First connection from this IP + log_common("Accept %s connection from %s:%d", + (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client); + + ret = hash_dict_set(hash_dict_sockaddr_count, (uint64_t)sin.sin_addr.s_addr, 1); + if (ret < 0) + { + log_error("hash_dict_set(hash_dict_sockaddr_count, %s, 1) error", hostaddr_client); + } + } + else + { + // Increase connection count from this IP + log_common("Accept %s connection from %s:%d, already have %d connections", + (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client, j); + + ret = hash_dict_inc(hash_dict_sockaddr_count, (uint64_t)sin.sin_addr.s_addr, 1); + if (ret <= 0) + { + log_error("hash_dict_inc(hash_dict_sockaddr_count, %s, 1) error: %d", hostaddr_client, ret); + } } } } else { - log_error("Rejected client connection from %s over limit per IP (%d)\n", hostaddr_client, BBS_max_client_per_ip); + log_error("Rejected %s connection from %s:%d over limit per IP (%d >= %d)", + (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client, j, BBS_max_client_per_ip); } } else { - log_error("Rejected client connection over limit (%d)\n", SYS_child_process_count - 1); + log_error("Rejected %s connection from %s:%d over limit (%d >= %d)", + (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client, SYS_child_process_count - 1, BBS_max_client); } if (close(socket_client) == -1) { - log_error("close(socket_lient) error (%d)\n", errno); + log_error("close(socket_lient) error (%d)", errno); } } } @@ -973,15 +1019,15 @@ int net_server(const char *hostaddr, in_ #ifdef HAVE_SYS_EPOLL_H if (close(epollfd_server) < 0) { - log_error("close(epollfd_server) error (%d)\n"); + log_error("close(epollfd_server) error (%d)"); } #endif - for (i = 0; i < 2; i++) + for (int i = 0; i < 2; i++) { if (close(socket_server[i]) == -1) { - log_error("Close server socket failed\n"); + log_error("Close server socket failed"); } }