/[LeafOK_CVS]/lbbs/src/net_server.c
ViewVC logotype

Contents of /lbbs/src/net_server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.113 - (show annotations)
Thu Dec 25 05:20:09 2025 UTC (2 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.112: +16 -6 lines
Content type: text/x-csrc
Replace dprecated inet_ntoa() with inet_ntop()

1 /* SPDX-License-Identifier: GPL-3.0-or-later */
2 /*
3 * net_server
4 * - network server with SSH support
5 *
6 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "bbs.h"
14 #include "bbs_main.h"
15 #include "bwf.h"
16 #include "common.h"
17 #include "database.h"
18 #include "file_loader.h"
19 #include "hash_dict.h"
20 #include "io.h"
21 #include "init.h"
22 #include "log.h"
23 #include "login.h"
24 #include "menu.h"
25 #include "net_server.h"
26 #include "section_list.h"
27 #include "section_list_loader.h"
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <pty.h>
31 #include <signal.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <utmp.h>
36 #include <arpa/inet.h>
37 #include <libssh/callbacks.h>
38 #include <libssh/libssh.h>
39 #include <libssh/server.h>
40 #include <netinet/in.h>
41 #include <sys/ioctl.h>
42 #include <sys/socket.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46
47 #ifdef HAVE_SYS_EPOLL_H
48 #include <sys/epoll.h>
49 #else
50 #include <poll.h>
51 #endif
52
53 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
54 #include <systemd/sd-daemon.h>
55 #endif
56
57 enum _net_server_constant_t
58 {
59 WAIT_CHILD_PROCESS_EXIT_TIMEOUT = 5, // second
60 WAIT_CHILD_PROCESS_KILL_TIMEOUT = 1, // second
61
62 SSH_AUTH_MAX_DURATION = 60 * 1000, // milliseconds
63 };
64
65 /* A userdata struct for session. */
66 struct session_data_struct
67 {
68 int tries;
69 int error;
70 };
71
72 /* A userdata struct for channel. */
73 struct channel_data_struct
74 {
75 /* pid of the child process the channel will spawn. */
76 pid_t pid;
77 /* For PTY allocation */
78 socket_t pty_master;
79 socket_t pty_slave;
80 /* For communication with the child process. */
81 socket_t child_stdin;
82 socket_t child_stdout;
83 /* Only used for subsystem and exec requests. */
84 socket_t child_stderr;
85 /* Event which is used to poll the above descriptors. */
86 ssh_event event;
87 /* Terminal size struct. */
88 struct winsize *winsize;
89 };
90
91 static int socket_server[2];
92 static int socket_client;
93
94 #ifdef HAVE_SYS_EPOLL_H
95 static int epollfd_server = -1;
96 #endif
97
98 static ssh_bind sshbind;
99
100 static HASH_DICT *hash_dict_pid_sockaddr = NULL;
101 static HASH_DICT *hash_dict_sockaddr_count = NULL;
102
103 static const char SFTP_SERVER_PATH[] = "/usr/lib/sftp-server";
104
105 static int auth_password(ssh_session session, const char *user,
106 const char *password, void *userdata)
107 {
108 struct session_data_struct *sdata = (struct session_data_struct *)userdata;
109 int ret;
110
111 if (strcmp(user, "guest") == 0)
112 {
113 ret = load_guest_info();
114 }
115 else
116 {
117 ret = check_user(user, password);
118 if (ret == 2) // Enforce update user agreement
119 {
120 BBS_update_eula = 1;
121 ret = 0;
122 }
123 }
124
125 if (ret == 0)
126 {
127 return SSH_AUTH_SUCCESS;
128 }
129
130 if ((++(sdata->tries)) >= BBS_login_retry_times)
131 {
132 sdata->error = 1;
133 }
134
135 return SSH_AUTH_DENIED;
136 }
137
138 static int pty_request(ssh_session session, ssh_channel channel, const char *term,
139 int cols, int rows, int px, int py, void *userdata)
140 {
141 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
142 int rc;
143
144 (void)session;
145 (void)channel;
146 (void)term;
147
148 cdata->winsize->ws_row = (unsigned short int)rows;
149 cdata->winsize->ws_col = (unsigned short int)cols;
150 cdata->winsize->ws_xpixel = (unsigned short int)px;
151 cdata->winsize->ws_ypixel = (unsigned short int)py;
152
153 rc = openpty(&cdata->pty_master, &cdata->pty_slave, NULL, NULL, cdata->winsize);
154 if (rc != 0)
155 {
156 log_error("Failed to open pty");
157 return SSH_ERROR;
158 }
159
160 return SSH_OK;
161 }
162
163 static int pty_resize(ssh_session session, ssh_channel channel, int cols, int rows,
164 int py, int px, void *userdata)
165 {
166 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
167
168 (void)session;
169 (void)channel;
170
171 cdata->winsize->ws_row = (unsigned short int)rows;
172 cdata->winsize->ws_col = (unsigned short int)cols;
173 cdata->winsize->ws_xpixel = (unsigned short int)px;
174 cdata->winsize->ws_ypixel = (unsigned short int)py;
175
176 if (cdata->pty_master != -1)
177 {
178 return ioctl(cdata->pty_master, TIOCSWINSZ, cdata->winsize);
179 }
180
181 return SSH_ERROR;
182 }
183
184 static int exec_pty(const char *mode, const char *command, struct channel_data_struct *cdata)
185 {
186 (void)cdata;
187
188 if (command != NULL)
189 {
190 log_error("Forbid exec /bin/sh %s %s)", mode, command);
191 }
192
193 return SSH_OK;
194 }
195
196 static int exec_nopty(const char *command, struct channel_data_struct *cdata)
197 {
198 (void)cdata;
199
200 if (command != NULL)
201 {
202 log_error("Forbid exec /bin/sh -c %s)", command);
203 }
204
205 return SSH_OK;
206 }
207
208 static int exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata)
209 {
210 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
211
212 (void)session;
213 (void)channel;
214
215 if (cdata->pid > 0)
216 {
217 return SSH_ERROR;
218 }
219
220 if (cdata->pty_master != -1 && cdata->pty_slave != -1)
221 {
222 return exec_pty("-c", command, cdata);
223 }
224 return exec_nopty(command, cdata);
225 }
226
227 static int shell_request(ssh_session session, ssh_channel channel, void *userdata)
228 {
229 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
230
231 (void)session;
232 (void)channel;
233
234 if (cdata->pid > 0)
235 {
236 return SSH_ERROR;
237 }
238
239 if (cdata->pty_master != -1 && cdata->pty_slave != -1)
240 {
241 return exec_pty("-l", NULL, cdata);
242 }
243 /* Client requested a shell without a pty, let's pretend we allow that */
244 return SSH_OK;
245 }
246
247 static int subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata)
248 {
249 (void)session;
250 (void)channel;
251
252 log_error("subsystem_request(subsystem=%s)", subsystem);
253
254 /* subsystem requests behave similarly to exec requests. */
255 if (strcmp(subsystem, "sftp") == 0)
256 {
257 return exec_request(session, channel, SFTP_SERVER_PATH, userdata);
258 }
259 return SSH_ERROR;
260 }
261
262 static ssh_channel channel_open(ssh_session session, void *userdata)
263 {
264 (void)userdata;
265
266 if (SSH_channel != NULL)
267 {
268 return NULL;
269 }
270
271 SSH_channel = ssh_channel_new(session);
272
273 return SSH_channel;
274 }
275
276 static int fork_server(void)
277 {
278 ssh_event event;
279 long int ssh_timeout = 0;
280 int pid;
281 int i;
282 int ret;
283
284 /* Structure for storing the pty size. */
285 struct winsize wsize = {
286 .ws_row = 0,
287 .ws_col = 0,
288 .ws_xpixel = 0,
289 .ws_ypixel = 0};
290
291 /* Our struct holding information about the channel. */
292 struct channel_data_struct cdata = {
293 .pid = 0,
294 .pty_master = -1,
295 .pty_slave = -1,
296 .child_stdin = -1,
297 .child_stdout = -1,
298 .child_stderr = -1,
299 .event = NULL,
300 .winsize = &wsize};
301
302 struct session_data_struct cb_data = {
303 .tries = 0,
304 .error = 0,
305 };
306
307 struct ssh_channel_callbacks_struct channel_cb = {
308 .userdata = &cdata,
309 .channel_pty_request_function = pty_request,
310 .channel_pty_window_change_function = pty_resize,
311 .channel_shell_request_function = shell_request,
312 .channel_exec_request_function = exec_request,
313 .channel_subsystem_request_function = subsystem_request};
314
315 struct ssh_server_callbacks_struct server_cb = {
316 .userdata = &cb_data,
317 .auth_password_function = auth_password,
318 .channel_open_request_session_function = channel_open,
319 };
320
321 pid = fork();
322
323 if (pid > 0) // Parent process
324 {
325 SYS_child_process_count++;
326 log_common("Child process (%d) start", pid);
327 return pid;
328 }
329 else if (pid < 0) // Error
330 {
331 log_error("fork() error (%d)", errno);
332 return -1;
333 }
334
335 // Child process
336 #ifdef HAVE_SYS_EPOLL_H
337 if (close(epollfd_server) < 0)
338 {
339 log_error("close(epollfd_server) error (%d)");
340 }
341 #endif
342
343 for (i = 0; i < 2; i++)
344 {
345 if (close(socket_server[i]) == -1)
346 {
347 log_error("Close server socket failed");
348 }
349 }
350
351 hash_dict_destroy(hash_dict_pid_sockaddr);
352 hash_dict_destroy(hash_dict_sockaddr_count);
353
354 SSH_session = ssh_new();
355
356 if (SSH_v2)
357 {
358 if (ssh_bind_accept_fd(sshbind, SSH_session, socket_client) != SSH_OK)
359 {
360 log_error("ssh_bind_accept_fd() error: %s", ssh_get_error(SSH_session));
361 goto cleanup;
362 }
363
364 ssh_bind_free(sshbind);
365
366 ssh_timeout = 60; // second
367 if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
368 {
369 log_error("Error setting SSH options: %s", ssh_get_error(SSH_session));
370 goto cleanup;
371 }
372
373 ssh_set_auth_methods(SSH_session, SSH_AUTH_METHOD_PASSWORD);
374
375 ssh_callbacks_init(&server_cb);
376 ssh_callbacks_init(&channel_cb);
377
378 ssh_set_server_callbacks(SSH_session, &server_cb);
379
380 if (ssh_handle_key_exchange(SSH_session))
381 {
382 log_error("ssh_handle_key_exchange() error: %s", ssh_get_error(SSH_session));
383 goto cleanup;
384 }
385
386 event = ssh_event_new();
387 ssh_event_add_session(event, SSH_session);
388
389 for (i = 0; i < SSH_AUTH_MAX_DURATION && !SYS_server_exit && !cb_data.error && SSH_channel == NULL; i += 100)
390 {
391 ret = ssh_event_dopoll(event, 100); // 0.1 second
392 if (ret == SSH_ERROR)
393 {
394 log_debug("ssh_event_dopoll() error: %s", ssh_get_error(SSH_session));
395 goto cleanup;
396 }
397 }
398
399 if (cb_data.error)
400 {
401 log_error("SSH auth error, tried %d times", cb_data.tries);
402 goto cleanup;
403 }
404
405 ssh_set_channel_callbacks(SSH_channel, &channel_cb);
406
407 do
408 {
409 ret = ssh_event_dopoll(event, 100); // 0.1 second
410 if (ret == SSH_ERROR)
411 {
412 ssh_channel_close(SSH_channel);
413 }
414
415 if (ret == SSH_AGAIN) // loop until SSH connection is fully established
416 {
417 /* Executed only once, once the child process starts. */
418 cdata.event = event;
419 break;
420 }
421 } while (ssh_channel_is_open(SSH_channel));
422
423 ssh_timeout = 0;
424 if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
425 {
426 log_error("Error setting SSH options: %s", ssh_get_error(SSH_session));
427 goto cleanup;
428 }
429
430 ssh_set_blocking(SSH_session, 0);
431 }
432
433 // Redirect Input
434 if (dup2(socket_client, STDIN_FILENO) == -1)
435 {
436 log_error("Redirect stdin to client socket failed");
437 goto cleanup;
438 }
439
440 // Redirect Output
441 if (dup2(socket_client, STDOUT_FILENO) == -1)
442 {
443 log_error("Redirect stdout to client socket failed");
444 goto cleanup;
445 }
446
447 if (io_init() < 0)
448 {
449 log_error("io_init() error");
450 goto cleanup;
451 }
452
453 SYS_child_process_count = 0;
454
455 // BWF compile
456 if (bwf_compile() < 0)
457 {
458 log_error("bwf_compile() error");
459 goto cleanup;
460 }
461
462 bbs_main();
463
464 cleanup:
465 // Child process exit
466 SYS_server_exit = 1;
467
468 if (SSH_v2)
469 {
470 if (cdata.pty_master != -1)
471 {
472 close(cdata.pty_master);
473 }
474 if (cdata.child_stdin != -1)
475 {
476 close(cdata.child_stdin);
477 }
478 if (cdata.child_stdout != -1)
479 {
480 close(cdata.child_stdout);
481 }
482 if (cdata.child_stderr != -1)
483 {
484 close(cdata.child_stderr);
485 }
486
487 ssh_channel_free(SSH_channel);
488 ssh_disconnect(SSH_session);
489 }
490 else if (close(socket_client) == -1)
491 {
492 log_error("Close client socket failed");
493 }
494
495 ssh_free(SSH_session);
496 ssh_finalize();
497
498 // BWF cleanup
499 bwf_cleanup();
500
501 // Close Input and Output for client
502 io_cleanup();
503 close(STDIN_FILENO);
504 close(STDOUT_FILENO);
505
506 log_common("Process exit normally");
507 log_end();
508
509 _exit(0);
510
511 return 0;
512 }
513
514 int net_server(const char *hostaddr, in_port_t port[])
515 {
516 struct stat file_stat;
517 unsigned int addrlen;
518 int ret;
519 int flags_server[2];
520 struct sockaddr_in sin;
521 char local_addr[INET_ADDRSTRLEN];
522
523 #ifdef HAVE_SYS_EPOLL_H
524 struct epoll_event ev, events[MAX_EVENTS];
525 #else
526 struct pollfd pfds[2];
527 #endif
528
529 int nfds;
530 int notify_child_exit = 0;
531 time_t tm_notify_child_exit = time(NULL);
532 pid_t pid;
533 int ssh_key_valid = 0;
534 int ssh_log_level = SSH_LOG_NOLOG;
535
536 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
537 int sd_notify_stopping = 0;
538 #endif
539
540 ssh_init();
541
542 sshbind = ssh_bind_new();
543
544 if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_RSA_KEY_FILE) < 0)
545 {
546 log_error("Error loading SSH RSA key: %s", SSH_HOST_RSA_KEY_FILE);
547 }
548 else
549 {
550 ssh_key_valid = 1;
551 }
552 if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_ED25519_KEY_FILE) < 0)
553 {
554 log_error("Error loading SSH ED25519 key: %s", SSH_HOST_ED25519_KEY_FILE);
555 }
556 else
557 {
558 ssh_key_valid = 1;
559 }
560 if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_ECDSA_KEY_FILE) < 0)
561 {
562 log_error("Error loading SSH ECDSA key: %s", SSH_HOST_ECDSA_KEY_FILE);
563 }
564 else
565 {
566 ssh_key_valid = 1;
567 }
568
569 if (!ssh_key_valid)
570 {
571 log_error("Error: no valid SSH host key");
572 ssh_bind_free(sshbind);
573 return -1;
574 }
575
576 if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, hostaddr) < 0 ||
577 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &port) < 0 ||
578 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "+ssh-ed25519,ecdsa-sha2-nistp256,ssh-rsa") < 0 ||
579 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level) < 0)
580 {
581 log_error("Error setting SSH bind options: %s", ssh_get_error(sshbind));
582 ssh_bind_free(sshbind);
583 return -1;
584 }
585
586 #ifdef HAVE_SYS_EPOLL_H
587 epollfd_server = epoll_create1(0);
588 if (epollfd_server == -1)
589 {
590 log_error("epoll_create1() error (%d)", errno);
591 return -1;
592 }
593 #endif
594
595 // Server socket
596 for (int i = 0; i < 2; i++)
597 {
598 socket_server[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
599
600 if (socket_server[i] < 0)
601 {
602 log_error("Create socket_server error (%d)", errno);
603 return -1;
604 }
605
606 sin.sin_family = AF_INET;
607 sin.sin_addr.s_addr = (hostaddr[0] != '\0' ? inet_addr(hostaddr) : INADDR_ANY);
608 sin.sin_port = htons(port[i]);
609
610 if (inet_ntop(AF_INET, &(sin.sin_addr), local_addr, sizeof(local_addr)) == NULL)
611 {
612 log_error("inet_ntop() error (%d)", errno);
613 return -1;
614 }
615
616 // Reuse address and port
617 flags_server[i] = 1;
618 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEADDR, &flags_server[i], sizeof(flags_server[i])) < 0)
619 {
620 log_error("setsockopt SO_REUSEADDR error (%d)", errno);
621 }
622 #if defined(SO_REUSEPORT)
623 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEPORT, &flags_server[i], sizeof(flags_server[i])) < 0)
624 {
625 log_error("setsockopt SO_REUSEPORT error (%d)", errno);
626 }
627 #endif
628
629 if (bind(socket_server[i], (struct sockaddr *)&sin, sizeof(sin)) < 0)
630 {
631 log_error("Bind address %s:%u error (%d)",
632 local_addr, port[i], errno);
633 return -1;
634 }
635
636 if (listen(socket_server[i], 10) < 0)
637 {
638 log_error("Telnet socket listen error (%d)", errno);
639 return -1;
640 }
641
642 log_common("Listening at %s:%u", local_addr, port[i]);
643
644 #ifdef HAVE_SYS_EPOLL_H
645 ev.events = EPOLLIN;
646 ev.data.fd = socket_server[i];
647 if (epoll_ctl(epollfd_server, EPOLL_CTL_ADD, socket_server[i], &ev) == -1)
648 {
649 log_error("epoll_ctl(socket_server[%d]) error (%d)", i, errno);
650 if (close(epollfd_server) < 0)
651 {
652 log_error("close(epoll) error (%d)");
653 }
654 return -1;
655 }
656 #endif
657
658 flags_server[i] = fcntl(socket_server[i], F_GETFL, 0);
659 fcntl(socket_server[i], F_SETFL, flags_server[i] | O_NONBLOCK);
660 }
661
662 ssh_bind_set_blocking(sshbind, 0);
663
664 hash_dict_pid_sockaddr = hash_dict_create(MAX_CLIENT_LIMIT);
665 if (hash_dict_pid_sockaddr == NULL)
666 {
667 log_error("hash_dict_create(hash_dict_pid_sockaddr) error");
668 return -1;
669 }
670 hash_dict_sockaddr_count = hash_dict_create(MAX_CLIENT_LIMIT);
671 if (hash_dict_sockaddr_count == NULL)
672 {
673 log_error("hash_dict_create(hash_dict_sockaddr_count) error");
674 return -1;
675 }
676
677 // Startup complete
678 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
679 sd_notifyf(0, "READY=1\n"
680 "STATUS=Listening at %s:%d (Telnet) and %s:%d (SSH2)\n"
681 "MAINPID=%d",
682 hostaddr, port[0], hostaddr, port[1], getpid());
683 #endif
684
685 while (!SYS_server_exit || SYS_child_process_count > 0)
686 {
687 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
688 if (SYS_server_exit && !sd_notify_stopping)
689 {
690 sd_notify(0, "STOPPING=1");
691 sd_notify_stopping = 1;
692 }
693 #endif
694
695 while ((SYS_child_exit || SYS_server_exit) && SYS_child_process_count > 0)
696 {
697 SYS_child_exit = 0;
698
699 pid = waitpid(-1, &ret, WNOHANG);
700 if (pid > 0)
701 {
702 SYS_child_exit = 1; // Retry waitid
703 SYS_child_process_count--;
704
705 if (WIFEXITED(ret))
706 {
707 log_common("Child process (%d) exited, status=%d", pid, WEXITSTATUS(ret));
708 }
709 else if (WIFSIGNALED(ret))
710 {
711 log_common("Child process (%d) is killed, status=%d", pid, WTERMSIG(ret));
712 }
713 else
714 {
715 log_common("Child process (%d) exited abnormally, status=%d", pid, ret);
716 }
717
718 if (pid != section_list_loader_pid)
719 {
720 int64_t j = 0;
721 ret = hash_dict_get(hash_dict_pid_sockaddr, (uint64_t)pid, &j);
722 if (ret < 0)
723 {
724 log_error("hash_dict_get(hash_dict_pid_sockaddr, %d) error", pid);
725 }
726 else
727 {
728 ret = hash_dict_inc(hash_dict_sockaddr_count, (in_addr_t)j, -1);
729 if (ret <= 0)
730 {
731 log_error("hash_dict_inc(hash_dict_sockaddr_count, %lu, -1) error: %d", (in_addr_t)j, ret);
732 }
733
734 ret = hash_dict_del(hash_dict_pid_sockaddr, (uint64_t)pid);
735 if (ret < 0)
736 {
737 log_error("hash_dict_del(hash_dict_pid_sockaddr, %lu) error", (uint64_t)pid);
738 }
739 }
740 }
741 }
742 else if (pid == 0)
743 {
744 break;
745 }
746 else if (pid < 0)
747 {
748 log_error("Error in waitpid(): %d", errno);
749 break;
750 }
751 }
752
753 if (SYS_server_exit && !SYS_child_exit && SYS_child_process_count > 0)
754 {
755 if (notify_child_exit == 0)
756 {
757 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
758 sd_notifyf(0, "STATUS=Notify %d child process to exit", SYS_child_process_count);
759 log_common("Notify %d child process to exit", SYS_child_process_count);
760 #endif
761
762 if (kill(0, SIGTERM) < 0)
763 {
764 log_error("Send SIGTERM signal failed (%d)", errno);
765 }
766
767 notify_child_exit = 1;
768 tm_notify_child_exit = time(NULL);
769 }
770 else if (notify_child_exit == 1 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_EXIT_TIMEOUT)
771 {
772 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
773 sd_notifyf(0, "STATUS=Kill %d child process", SYS_child_process_count);
774 #endif
775
776 if (kill(0, SIGKILL) < 0)
777 {
778 log_error("Send SIGKILL signal failed (%d)", errno);
779 }
780
781 notify_child_exit = 2;
782 tm_notify_child_exit = time(NULL);
783 }
784 else if (notify_child_exit == 2 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_KILL_TIMEOUT)
785 {
786 log_error("Main process prepare to exit without waiting for %d child process any longer", SYS_child_process_count);
787 SYS_child_process_count = 0;
788 }
789 }
790
791 if (SYS_conf_reload && !SYS_server_exit)
792 {
793 SYS_conf_reload = 0;
794
795 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
796 sd_notify(0, "RELOADING=1");
797 #endif
798
799 log_common("Reload configuration");
800
801 // Restart log
802 if (log_restart() < 0)
803 {
804 log_error("Restart logging failed");
805 }
806
807 // Reload configuration
808 if (load_conf(CONF_BBSD) < 0)
809 {
810 log_error("Reload conf failed");
811 }
812
813 // Reload BWF config
814 if (bwf_load(CONF_BWF) < 0)
815 {
816 log_error("Reload BWF conf failed");
817 }
818
819 // Get EULA modification tm
820 if (stat(DATA_EULA, &file_stat) == -1)
821 {
822 log_error("stat(%s) error", DATA_EULA, errno);
823 }
824 else
825 {
826 BBS_eula_tm = file_stat.st_mtim.tv_sec;
827 }
828
829 if (detach_menu_shm(&bbs_menu) < 0)
830 {
831 log_error("detach_menu_shm(bbs_menu) error");
832 }
833 if (load_menu(&bbs_menu, CONF_MENU) < 0)
834 {
835 log_error("load_menu(bbs_menu) error");
836 unload_menu(&bbs_menu);
837 }
838
839 if (detach_menu_shm(&top10_menu) < 0)
840 {
841 log_error("detach_menu_shm(top10_menu) error");
842 }
843 if (load_menu(&top10_menu, CONF_TOP10_MENU) < 0)
844 {
845 log_error("load_menu(top10_menu) error");
846 unload_menu(&top10_menu);
847 }
848 top10_menu.allow_exit = 1;
849
850 for (int i = 0; i < data_files_load_startup_count; i++)
851 {
852 if (load_file(data_files_load_startup[i]) < 0)
853 {
854 log_error("load_file(%s) error", data_files_load_startup[i]);
855 }
856 }
857
858 // Load section config and gen_ex
859 if (load_section_config_from_db(1) < 0)
860 {
861 log_error("load_section_config_from_db(1) error");
862 }
863
864 // Notify child processes to reload configuration
865 if (kill(0, SIGUSR1) < 0)
866 {
867 log_error("Send SIGUSR1 signal failed (%d)", errno);
868 }
869
870 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
871 sd_notify(0, "READY=1");
872 #endif
873 }
874
875 #ifdef HAVE_SYS_EPOLL_H
876 nfds = epoll_wait(epollfd_server, events, MAX_EVENTS, 100); // 0.1 second
877 ret = nfds;
878 #else
879 pfds[0].fd = socket_server[0];
880 pfds[0].events = POLLIN;
881 pfds[1].fd = socket_server[1];
882 pfds[1].events = POLLIN;
883 nfds = 2;
884 ret = poll(pfds, (nfds_t)nfds, 100); // 0.1 second
885 #endif
886 if (ret < 0)
887 {
888 if (errno != EINTR)
889 {
890 #ifdef HAVE_SYS_EPOLL_H
891 log_error("epoll_wait() error (%d)", errno);
892 #else
893 log_error("poll() error (%d)", errno);
894 #endif
895 break;
896 }
897 continue;
898 }
899
900 // Stop accept new connection on exit
901 if (SYS_server_exit)
902 {
903 continue;
904 }
905
906 for (int i = 0; i < nfds; i++)
907 {
908 #ifdef HAVE_SYS_EPOLL_H
909 if (events[i].data.fd == socket_server[0] || events[i].data.fd == socket_server[1])
910 #else
911 if ((pfds[i].fd == socket_server[0] || pfds[i].fd == socket_server[1]) && (pfds[i].revents & POLLIN))
912 #endif
913 {
914 #ifdef HAVE_SYS_EPOLL_H
915 SSH_v2 = (events[i].data.fd == socket_server[1] ? 1 : 0);
916 #else
917 SSH_v2 = (pfds[i].fd == socket_server[1] ? 1 : 0);
918 #endif
919
920 while (!SYS_server_exit) // Accept all incoming connections until error
921 {
922 addrlen = sizeof(sin);
923 socket_client = accept(socket_server[SSH_v2], (struct sockaddr *)&sin, (socklen_t *)&addrlen);
924 if (socket_client < 0)
925 {
926 if (errno == EAGAIN || errno == EWOULDBLOCK)
927 {
928 break;
929 }
930 else if (errno == EINTR)
931 {
932 continue;
933 }
934 else
935 {
936 log_error("accept(socket_server) error (%d)", errno);
937 break;
938 }
939 }
940
941 if (inet_ntop(AF_INET, &(sin.sin_addr), hostaddr_client, sizeof(hostaddr_client)) == NULL)
942 {
943 log_error("inet_ntop() error (%d)", errno);
944 close(socket_client);
945 break;
946 }
947 port_client = ntohs(sin.sin_port);
948
949 if (SYS_child_process_count - 1 < BBS_max_client)
950 {
951 int64_t j = 0;
952 ret = hash_dict_get(hash_dict_sockaddr_count, sin.sin_addr.s_addr, &j);
953 if (ret < 0)
954 {
955 log_error("hash_dict_get(hash_dict_sockaddr_count, %s) error", hostaddr_client);
956 }
957
958 if (j < BBS_max_client_per_ip)
959 {
960 if ((pid = fork_server()) < 0)
961 {
962 log_error("fork_server() error");
963 }
964 else if (pid > 0)
965 {
966 ret = hash_dict_set(hash_dict_pid_sockaddr, (uint64_t)pid, sin.sin_addr.s_addr);
967 if (ret < 0)
968 {
969 log_error("hash_dict_set(hash_dict_pid_sockaddr, %lu, %s) error", (uint64_t)pid, hostaddr_client);
970 }
971
972 if (j == 0)
973 {
974 // First connection from this IP
975 log_common("Accept %s connection from %s:%d",
976 (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client);
977
978 ret = hash_dict_set(hash_dict_sockaddr_count, (uint64_t)sin.sin_addr.s_addr, 1);
979 if (ret < 0)
980 {
981 log_error("hash_dict_set(hash_dict_sockaddr_count, %s, 1) error", hostaddr_client);
982 }
983 }
984 else
985 {
986 // Increase connection count from this IP
987 log_common("Accept %s connection from %s:%d, already have %d connections",
988 (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client, j);
989
990 ret = hash_dict_inc(hash_dict_sockaddr_count, (uint64_t)sin.sin_addr.s_addr, 1);
991 if (ret <= 0)
992 {
993 log_error("hash_dict_inc(hash_dict_sockaddr_count, %s, 1) error: %d", hostaddr_client, ret);
994 }
995 }
996 }
997 }
998 else
999 {
1000 log_error("Rejected %s connection from %s:%d over limit per IP (%d >= %d)",
1001 (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client, j, BBS_max_client_per_ip);
1002 }
1003 }
1004 else
1005 {
1006 log_error("Rejected %s connection from %s:%d over limit (%d >= %d)",
1007 (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client, SYS_child_process_count - 1, BBS_max_client);
1008 }
1009
1010 if (close(socket_client) == -1)
1011 {
1012 log_error("close(socket_lient) error (%d)", errno);
1013 }
1014 }
1015 }
1016 }
1017 }
1018
1019 #ifdef HAVE_SYS_EPOLL_H
1020 if (close(epollfd_server) < 0)
1021 {
1022 log_error("close(epollfd_server) error (%d)");
1023 }
1024 #endif
1025
1026 for (int i = 0; i < 2; i++)
1027 {
1028 if (close(socket_server[i]) == -1)
1029 {
1030 log_error("Close server socket failed");
1031 }
1032 }
1033
1034 hash_dict_destroy(hash_dict_pid_sockaddr);
1035 hash_dict_destroy(hash_dict_sockaddr_count);
1036
1037 ssh_bind_free(sshbind);
1038 ssh_finalize();
1039
1040 return 0;
1041 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1