--- lbbs/src/net_server.c 2025/12/17 03:44:29 1.106 +++ lbbs/src/net_server.c 2026/01/07 14:37:55 1.116 @@ -3,7 +3,7 @@ * net_server * - network server with SSH support * - * Copyright (C) 2004-2025 Leaflet + * Copyright (C) 2004-2026 Leaflet */ #ifdef HAVE_CONFIG_H @@ -56,6 +56,7 @@ enum _net_server_constant_t { + SOCKET_LISTEN_BACKLOG = 20, WAIT_CHILD_PROCESS_EXIT_TIMEOUT = 5, // second WAIT_CHILD_PROCESS_KILL_TIMEOUT = 1, // second @@ -124,6 +125,7 @@ static int auth_password(ssh_session ses if (ret == 0) { + log_common("User [%s] authenticated successfully", user); return SSH_AUTH_SUCCESS; } @@ -132,6 +134,8 @@ static int auth_password(ssh_session ses sdata->error = 1; } + log_common("User [%s] authentication failed (%d/%d)", user, + sdata->tries, BBS_login_retry_times); return SSH_AUTH_DENIED; } @@ -153,7 +157,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; } @@ -187,7 +191,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; @@ -199,7 +203,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; @@ -249,7 +253,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) @@ -323,12 +327,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; } @@ -336,7 +340,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 @@ -344,7 +348,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"); } } @@ -357,7 +361,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; } @@ -366,7 +370,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; } @@ -379,7 +383,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; } @@ -391,16 +395,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; } @@ -425,7 +427,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; } @@ -435,20 +437,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; } @@ -457,7 +459,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; } @@ -491,7 +493,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); @@ -505,7 +507,7 @@ cleanup: close(STDIN_FILENO); close(STDOUT_FILENO); - log_common("Process exit normally\n"); + log_common("Process exit normally"); log_end(); _exit(0); @@ -520,6 +522,7 @@ int net_server(const char *hostaddr, in_ 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]; @@ -530,7 +533,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; @@ -545,7 +547,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 { @@ -553,7 +555,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 { @@ -561,7 +563,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 { @@ -570,17 +572,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; } @@ -589,19 +591,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; } @@ -609,43 +611,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) + if (listen(socket_server[i], SOCKET_LISTEN_BACKLOG) < 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; } @@ -660,13 +668,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; } @@ -700,37 +708,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); + 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: %d\n", j, ret); + 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); } } } @@ -741,7 +749,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; } } @@ -752,12 +760,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; @@ -771,7 +779,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; @@ -779,7 +787,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; } } @@ -792,28 +800,30 @@ 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\n", DATA_EULA, errno); + log_error("stat(%s) error", DATA_EULA, errno); } else { @@ -822,21 +832,21 @@ int net_server(const char *hostaddr, in_ 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; @@ -845,20 +855,20 @@ int net_server(const char *hostaddr, in_ { 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 @@ -882,9 +892,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; } @@ -927,80 +937,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); 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); } if (j == 0) { // First connection from this IP - log_common("Accept %s connection from %s:%d\n", + 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\n", hostaddr_client); + 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\n", + 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\n", hostaddr_client, ret); + log_error("hash_dict_inc(hash_dict_sockaddr_count, %s, 1) error: %d", hostaddr_client, ret); } } } } else { - log_error("Rejected %s connection from %s:%d over limit per IP (%d >= %d)\n", + 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 %s connection from %s:%d over limit (%d >= %d)\n", + 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); } } } @@ -1010,15 +1023,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"); } }