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

Annotation of /lbbs/src/net_server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.80 - (hide annotations)
Fri Nov 7 04:58:09 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.79: +7 -0 lines
Content type: text/x-csrc
Load / Reload BWF config file on startup / reload

1 sysadm 1.77 /* SPDX-License-Identifier: GPL-3.0-or-later */
2     /*
3     * net_server
4     * - network server with SSH support
5     *
6 sysadm 1.78 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 sysadm 1.77 */
8 sysadm 1.1
9 sysadm 1.62 #include "bbs.h"
10     #include "bbs_main.h"
11 sysadm 1.80 #include "bwf.h"
12 sysadm 1.1 #include "common.h"
13 sysadm 1.62 #include "database.h"
14     #include "file_loader.h"
15 sysadm 1.7 #include "io.h"
16 sysadm 1.44 #include "init.h"
17 sysadm 1.62 #include "log.h"
18     #include "login.h"
19 sysadm 1.19 #include "menu.h"
20 sysadm 1.62 #include "net_server.h"
21 sysadm 1.67 #include "section_list.h"
22 sysadm 1.42 #include "section_list_loader.h"
23 sysadm 1.20 #include <errno.h>
24     #include <fcntl.h>
25 sysadm 1.74 #include <pty.h>
26 sysadm 1.19 #include <signal.h>
27 sysadm 1.20 #include <stdlib.h>
28 sysadm 1.62 #include <string.h>
29 sysadm 1.19 #include <unistd.h>
30 sysadm 1.74 #include <utmp.h>
31 sysadm 1.9 #include <arpa/inet.h>
32 sysadm 1.62 #include <libssh/callbacks.h>
33 sysadm 1.55 #include <libssh/libssh.h>
34     #include <libssh/server.h>
35 sysadm 1.62 #include <netinet/in.h>
36 sysadm 1.61 #include <sys/epoll.h>
37 sysadm 1.62 #include <sys/socket.h>
38 sysadm 1.61 #include <sys/syscall.h>
39     #include <sys/types.h>
40     #include <sys/wait.h>
41     #include <systemd/sd-daemon.h>
42 sysadm 1.3
43 sysadm 1.79 enum _net_server_constant_t
44     {
45     WAIT_CHILD_PROCESS_EXIT_TIMEOUT = 5, // second
46     WAIT_CHILD_PROCESS_KILL_TIMEOUT = 1, // second
47    
48     SSH_AUTH_MAX_DURATION = 60 * 1000, // milliseconds
49     };
50 sysadm 1.70
51 sysadm 1.44 struct process_sockaddr_t
52     {
53     pid_t pid;
54     in_addr_t s_addr;
55     };
56     typedef struct process_sockaddr_t PROCESS_SOCKADDR;
57    
58 sysadm 1.48 static PROCESS_SOCKADDR process_sockaddr_pool[MAX_CLIENT_LIMIT];
59 sysadm 1.44
60 sysadm 1.79 static const char SFTP_SERVER_PATH[] = "/usr/lib/sftp-server";
61 sysadm 1.74
62     /* A userdata struct for session. */
63     struct session_data_struct
64 sysadm 1.55 {
65     int tries;
66     int error;
67     };
68    
69 sysadm 1.74 /* A userdata struct for channel. */
70     struct channel_data_struct
71     {
72     /* pid of the child process the channel will spawn. */
73     pid_t pid;
74     /* For PTY allocation */
75     socket_t pty_master;
76     socket_t pty_slave;
77     /* For communication with the child process. */
78     socket_t child_stdin;
79     socket_t child_stdout;
80     /* Only used for subsystem and exec requests. */
81     socket_t child_stderr;
82     /* Event which is used to poll the above descriptors. */
83     ssh_event event;
84     /* Terminal size struct. */
85     struct winsize *winsize;
86     };
87    
88 sysadm 1.55 static int auth_password(ssh_session session, const char *user,
89     const char *password, void *userdata)
90     {
91 sysadm 1.74 struct session_data_struct *sdata = (struct session_data_struct *)userdata;
92 sysadm 1.55 int ret;
93    
94     if (strcmp(user, "guest") == 0)
95     {
96 sysadm 1.57 ret = load_guest_info();
97 sysadm 1.55 }
98     else
99     {
100 sysadm 1.57 ret = check_user(user, password);
101 sysadm 1.55 }
102    
103     if (ret == 0)
104     {
105     return SSH_AUTH_SUCCESS;
106     }
107    
108 sysadm 1.74 if ((++(sdata->tries)) >= BBS_login_retry_times)
109 sysadm 1.55 {
110 sysadm 1.74 sdata->error = 1;
111 sysadm 1.55 }
112    
113     return SSH_AUTH_DENIED;
114     }
115    
116     static int pty_request(ssh_session session, ssh_channel channel, const char *term,
117 sysadm 1.74 int cols, int rows, int px, int py, void *userdata)
118     {
119     struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
120     int rc;
121    
122     (void)session;
123     (void)channel;
124     (void)term;
125    
126     cdata->winsize->ws_row = (unsigned short int)rows;
127     cdata->winsize->ws_col = (unsigned short int)cols;
128     cdata->winsize->ws_xpixel = (unsigned short int)px;
129     cdata->winsize->ws_ypixel = (unsigned short int)py;
130    
131     rc = openpty(&cdata->pty_master, &cdata->pty_slave, NULL, NULL, cdata->winsize);
132     if (rc != 0)
133     {
134     log_error("Failed to open pty\n");
135     return SSH_ERROR;
136     }
137    
138     return SSH_OK;
139     }
140    
141     static int pty_resize(ssh_session session, ssh_channel channel, int cols, int rows,
142     int py, int px, void *userdata)
143     {
144     struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
145    
146     (void)session;
147     (void)channel;
148    
149     cdata->winsize->ws_row = (unsigned short int)rows;
150     cdata->winsize->ws_col = (unsigned short int)cols;
151     cdata->winsize->ws_xpixel = (unsigned short int)px;
152     cdata->winsize->ws_ypixel = (unsigned short int)py;
153    
154     if (cdata->pty_master != -1)
155     {
156     return ioctl(cdata->pty_master, TIOCSWINSZ, cdata->winsize);
157     }
158    
159     return SSH_ERROR;
160     }
161    
162     static int exec_pty(const char *mode, const char *command, struct channel_data_struct *cdata)
163     {
164     (void)cdata;
165    
166     if (command != NULL)
167     {
168     log_error("Forbid exec /bin/sh %s %s)\n", mode, command);
169     }
170    
171     return SSH_OK;
172     }
173    
174     static int exec_nopty(const char *command, struct channel_data_struct *cdata)
175     {
176     (void)cdata;
177    
178     if (command != NULL)
179     {
180     log_error("Forbid exec /bin/sh -c %s)\n", command);
181     }
182    
183     return SSH_OK;
184     }
185    
186     static int exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata)
187 sysadm 1.55 {
188 sysadm 1.74 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
189    
190     (void)session;
191     (void)channel;
192    
193     if (cdata->pid > 0)
194     {
195     return SSH_ERROR;
196     }
197    
198     if (cdata->pty_master != -1 && cdata->pty_slave != -1)
199     {
200     return exec_pty("-c", command, cdata);
201     }
202     return exec_nopty(command, cdata);
203 sysadm 1.55 }
204    
205     static int shell_request(ssh_session session, ssh_channel channel, void *userdata)
206     {
207 sysadm 1.74 struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
208    
209     (void)session;
210     (void)channel;
211    
212     if (cdata->pid > 0)
213     {
214     return SSH_ERROR;
215     }
216    
217     if (cdata->pty_master != -1 && cdata->pty_slave != -1)
218     {
219     return exec_pty("-l", NULL, cdata);
220     }
221     /* Client requested a shell without a pty, let's pretend we allow that */
222     return SSH_OK;
223 sysadm 1.55 }
224    
225 sysadm 1.74 static int subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata)
226     {
227     (void)session;
228     (void)channel;
229    
230     log_error("subsystem_request(subsystem=%s)\n", subsystem);
231    
232     /* subsystem requests behave similarly to exec requests. */
233     if (strcmp(subsystem, "sftp") == 0)
234     {
235     return exec_request(session, channel, SFTP_SERVER_PATH, userdata);
236     }
237     return SSH_ERROR;
238     }
239 sysadm 1.55
240 sysadm 1.74 static ssh_channel channel_open(ssh_session session, void *userdata)
241 sysadm 1.55 {
242 sysadm 1.74 (void)userdata;
243    
244 sysadm 1.55 if (SSH_channel != NULL)
245     {
246     return NULL;
247     }
248    
249     SSH_channel = ssh_channel_new(session);
250    
251     return SSH_channel;
252     }
253    
254 sysadm 1.56 static int fork_server(void)
255 sysadm 1.55 {
256     ssh_event event;
257 sysadm 1.71 long int ssh_timeout = 0;
258 sysadm 1.55 int pid;
259     int i;
260     int ret;
261    
262 sysadm 1.74 /* Structure for storing the pty size. */
263     struct winsize wsize = {
264     .ws_row = 0,
265     .ws_col = 0,
266     .ws_xpixel = 0,
267     .ws_ypixel = 0};
268    
269     /* Our struct holding information about the channel. */
270     struct channel_data_struct cdata = {
271     .pid = 0,
272     .pty_master = -1,
273     .pty_slave = -1,
274     .child_stdin = -1,
275     .child_stdout = -1,
276     .child_stderr = -1,
277     .event = NULL,
278     .winsize = &wsize};
279    
280     struct session_data_struct cb_data = {
281 sysadm 1.55 .tries = 0,
282     .error = 0,
283     };
284    
285 sysadm 1.74 struct ssh_channel_callbacks_struct channel_cb = {
286     .userdata = &cdata,
287     .channel_pty_request_function = pty_request,
288     .channel_pty_window_change_function = pty_resize,
289     .channel_shell_request_function = shell_request,
290     .channel_exec_request_function = exec_request,
291     .channel_subsystem_request_function = subsystem_request};
292    
293     struct ssh_server_callbacks_struct server_cb = {
294 sysadm 1.55 .userdata = &cb_data,
295     .auth_password_function = auth_password,
296 sysadm 1.74 .channel_open_request_session_function = channel_open,
297 sysadm 1.55 };
298    
299     pid = fork();
300    
301     if (pid > 0) // Parent process
302     {
303     SYS_child_process_count++;
304     log_common("Child process (%d) start\n", pid);
305     return pid;
306     }
307     else if (pid < 0) // Error
308     {
309     log_error("fork() error (%d)\n", errno);
310     return -1;
311     }
312    
313     // Child process
314    
315     if (close(socket_server[0]) == -1 || close(socket_server[1]) == -1)
316     {
317     log_error("Close server socket failed\n");
318     }
319    
320     SSH_session = ssh_new();
321    
322     if (SSH_v2)
323     {
324     if (ssh_bind_accept_fd(sshbind, SSH_session, socket_client) != SSH_OK)
325     {
326     log_error("ssh_bind_accept_fd() error: %s\n", ssh_get_error(SSH_session));
327     goto cleanup;
328     }
329    
330     ssh_bind_free(sshbind);
331    
332 sysadm 1.71 ssh_timeout = 60; // second
333     if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
334     {
335     log_error("Error setting SSH options: %s\n", ssh_get_error(SSH_session));
336     goto cleanup;
337     }
338    
339 sysadm 1.75 ssh_set_auth_methods(SSH_session, SSH_AUTH_METHOD_PASSWORD);
340    
341     ssh_callbacks_init(&server_cb);
342     ssh_callbacks_init(&channel_cb);
343    
344     ssh_set_server_callbacks(SSH_session, &server_cb);
345    
346 sysadm 1.55 if (ssh_handle_key_exchange(SSH_session))
347     {
348     log_error("ssh_handle_key_exchange() error: %s\n", ssh_get_error(SSH_session));
349     goto cleanup;
350     }
351    
352     event = ssh_event_new();
353     ssh_event_add_session(event, SSH_session);
354    
355 sysadm 1.58 for (i = 0; i < SSH_AUTH_MAX_DURATION && !SYS_server_exit && !cb_data.error && SSH_channel == NULL; i += 100)
356 sysadm 1.55 {
357 sysadm 1.58 ret = ssh_event_dopoll(event, 100); // 0.1 second
358 sysadm 1.55 if (ret == SSH_ERROR)
359     {
360 sysadm 1.73 #ifdef _DEBUG
361 sysadm 1.55 log_error("ssh_event_dopoll() error: %s\n", ssh_get_error(SSH_session));
362 sysadm 1.73 #endif
363 sysadm 1.55 goto cleanup;
364     }
365     }
366    
367     if (cb_data.error)
368     {
369     log_error("SSH auth error, tried %d times\n", cb_data.tries);
370     goto cleanup;
371     }
372 sysadm 1.71
373 sysadm 1.74 ssh_set_channel_callbacks(SSH_channel, &channel_cb);
374    
375 sysadm 1.75 do
376     {
377     ret = ssh_event_dopoll(event, 100); // 0.1 second
378     if (ret == SSH_ERROR)
379     {
380     ssh_channel_close(SSH_channel);
381     }
382    
383     if (ret == SSH_AGAIN) // loop until SSH connection is fully established
384     {
385     /* Executed only once, once the child process starts. */
386     cdata.event = event;
387     break;
388     }
389     } while (ssh_channel_is_open(SSH_channel));
390    
391 sysadm 1.71 ssh_timeout = 0;
392     if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
393     {
394     log_error("Error setting SSH options: %s\n", ssh_get_error(SSH_session));
395     goto cleanup;
396     }
397 sysadm 1.55 }
398    
399     // Redirect Input
400     close(STDIN_FILENO);
401     if (dup2(socket_client, STDIN_FILENO) == -1)
402     {
403     log_error("Redirect stdin to client socket failed\n");
404     goto cleanup;
405     }
406    
407     // Redirect Output
408     close(STDOUT_FILENO);
409     if (dup2(socket_client, STDOUT_FILENO) == -1)
410     {
411     log_error("Redirect stdout to client socket failed\n");
412     goto cleanup;
413     }
414    
415     SYS_child_process_count = 0;
416    
417     bbs_main();
418    
419     cleanup:
420     // Child process exit
421     SYS_server_exit = 1;
422    
423     if (SSH_v2)
424     {
425 sysadm 1.74 close(cdata.pty_master);
426     close(cdata.child_stdin);
427     close(cdata.child_stdout);
428     close(cdata.child_stderr);
429    
430 sysadm 1.55 ssh_channel_free(SSH_channel);
431     ssh_disconnect(SSH_session);
432     }
433     else if (close(socket_client) == -1)
434     {
435     log_error("Close client socket failed\n");
436     }
437    
438     ssh_free(SSH_session);
439     ssh_finalize();
440    
441     // Close Input and Output for client
442     close(STDIN_FILENO);
443     close(STDOUT_FILENO);
444    
445     log_common("Process exit normally\n");
446     log_end();
447    
448     _exit(0);
449    
450     return 0;
451     }
452    
453 sysadm 1.52 int net_server(const char *hostaddr, in_port_t port[])
454 sysadm 1.1 {
455 sysadm 1.52 unsigned int addrlen;
456 sysadm 1.19 int ret;
457 sysadm 1.52 int flags[2];
458 sysadm 1.13 struct sockaddr_in sin;
459 sysadm 1.25 struct epoll_event ev, events[MAX_EVENTS];
460     int nfds, epollfd;
461 sysadm 1.19 siginfo_t siginfo;
462 sysadm 1.70 int notify_child_exit = 0;
463     time_t tm_notify_child_exit = time(NULL);
464 sysadm 1.31 int sd_notify_stopping = 0;
465 sysadm 1.66 MENU_SET bbs_menu_new;
466 sysadm 1.72 MENU_SET top10_menu_new;
467 sysadm 1.44 int i, j;
468     pid_t pid;
469 sysadm 1.51 int ssh_log_level = SSH_LOG_NOLOG;
470 sysadm 1.10
471 sysadm 1.51 ssh_init();
472    
473     sshbind = ssh_bind_new();
474    
475     if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, hostaddr) < 0 ||
476     ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &port) < 0 ||
477     ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_KEYFILE) < 0 ||
478 sysadm 1.63 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "ssh-rsa,rsa-sha2-512,rsa-sha2-256") < 0 ||
479 sysadm 1.51 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level) < 0)
480     {
481     log_error("Error setting SSH bind options: %s\n", ssh_get_error(sshbind));
482     ssh_bind_free(sshbind);
483     return -1;
484     }
485 sysadm 1.10
486 sysadm 1.52 epollfd = epoll_create1(0);
487     if (epollfd < 0)
488 sysadm 1.13 {
489 sysadm 1.52 log_error("epoll_create1() error (%d)\n", errno);
490 sysadm 1.27 return -1;
491 sysadm 1.13 }
492 sysadm 1.10
493 sysadm 1.52 // Server socket
494     for (i = 0; i < 2; i++)
495 sysadm 1.23 {
496 sysadm 1.52 socket_server[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
497 sysadm 1.23
498 sysadm 1.52 if (socket_server[i] < 0)
499     {
500     log_error("Create socket_server error (%d)\n", errno);
501     return -1;
502     }
503 sysadm 1.10
504 sysadm 1.52 sin.sin_family = AF_INET;
505     sin.sin_addr.s_addr = (hostaddr[0] != '\0' ? inet_addr(hostaddr) : INADDR_ANY);
506     sin.sin_port = htons(port[i]);
507    
508     // Reuse address and port
509     flags[i] = 1;
510     if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEADDR, &flags[i], sizeof(flags[i])) < 0)
511     {
512     log_error("setsockopt SO_REUSEADDR error (%d)\n", errno);
513     }
514     if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEPORT, &flags[i], sizeof(flags[i])) < 0)
515     {
516     log_error("setsockopt SO_REUSEPORT error (%d)\n", errno);
517     }
518 sysadm 1.1
519 sysadm 1.52 if (bind(socket_server[i], (struct sockaddr *)&sin, sizeof(sin)) < 0)
520     {
521     log_error("Bind address %s:%u error (%d)\n",
522     inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), errno);
523     return -1;
524     }
525 sysadm 1.16
526 sysadm 1.52 if (listen(socket_server[i], 10) < 0)
527     {
528     log_error("Telnet socket listen error (%d)\n", errno);
529     return -1;
530     }
531 sysadm 1.13
532 sysadm 1.52 log_common("Listening at %s:%u\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
533 sysadm 1.25
534 sysadm 1.52 ev.events = EPOLLIN;
535     ev.data.fd = socket_server[i];
536     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, socket_server[i], &ev) == -1)
537 sysadm 1.30 {
538 sysadm 1.52 log_error("epoll_ctl(socket_server[%d]) error (%d)\n", i, errno);
539     if (close(epollfd) < 0)
540     {
541     log_error("close(epoll) error (%d)\n");
542     }
543     return -1;
544 sysadm 1.30 }
545 sysadm 1.52
546     flags[i] = fcntl(socket_server[i], F_GETFL, 0);
547     fcntl(socket_server[i], F_SETFL, flags[i] | O_NONBLOCK);
548 sysadm 1.25 }
549    
550 sysadm 1.31 // Startup complete
551     sd_notifyf(0, "READY=1\n"
552 sysadm 1.52 "STATUS=Listening at %s:%d (Telnet) and %s:%d (SSH2)\n"
553 sysadm 1.31 "MAINPID=%d",
554 sysadm 1.52 hostaddr, port[0], hostaddr, port[1], getpid());
555 sysadm 1.31
556 sysadm 1.19 while (!SYS_server_exit || SYS_child_process_count > 0)
557 sysadm 1.13 {
558 sysadm 1.31 if (SYS_server_exit && !sd_notify_stopping)
559     {
560     sd_notify(0, "STOPPING=1");
561     sd_notify_stopping = 1;
562     }
563 sysadm 1.37
564 sysadm 1.22 while ((SYS_child_exit || SYS_server_exit) && SYS_child_process_count > 0)
565 sysadm 1.19 {
566 sysadm 1.30 SYS_child_exit = 0;
567    
568 sysadm 1.19 siginfo.si_pid = 0;
569     ret = waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG);
570     if (ret == 0 && siginfo.si_pid > 0)
571     {
572 sysadm 1.30 SYS_child_exit = 1; // Retry waitid
573    
574 sysadm 1.19 SYS_child_process_count--;
575 sysadm 1.49 log_common("Child process (%d) exited\n", siginfo.si_pid);
576 sysadm 1.44
577 sysadm 1.45 if (siginfo.si_pid != section_list_loader_pid)
578 sysadm 1.44 {
579 sysadm 1.45 i = 0;
580     for (; i < BBS_max_client; i++)
581 sysadm 1.44 {
582 sysadm 1.45 if (process_sockaddr_pool[i].pid == siginfo.si_pid)
583     {
584     process_sockaddr_pool[i].pid = 0;
585     break;
586     }
587     }
588     if (i >= BBS_max_client)
589     {
590     log_error("Child process (%d) not found in process sockaddr pool\n", siginfo.si_pid);
591 sysadm 1.44 }
592     }
593 sysadm 1.19 }
594     else if (ret == 0)
595     {
596     break;
597     }
598     else if (ret < 0)
599     {
600     log_error("Error in waitid: %d\n", errno);
601     break;
602     }
603     }
604    
605 sysadm 1.22 if (SYS_server_exit && !SYS_child_exit && SYS_child_process_count > 0)
606 sysadm 1.21 {
607 sysadm 1.70 if (notify_child_exit == 0)
608 sysadm 1.21 {
609 sysadm 1.70 sd_notifyf(0, "STATUS=Notify %d child process to exit", SYS_child_process_count);
610     log_common("Notify %d child process to exit\n", SYS_child_process_count);
611    
612     if (kill(0, SIGTERM) < 0)
613     {
614     log_error("Send SIGTERM signal failed (%d)\n", errno);
615     }
616    
617     notify_child_exit = 1;
618     tm_notify_child_exit = time(NULL);
619 sysadm 1.21 }
620 sysadm 1.70 else if (notify_child_exit == 1 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_EXIT_TIMEOUT)
621     {
622     sd_notifyf(0, "STATUS=Kill %d child process", SYS_child_process_count);
623 sysadm 1.31
624 sysadm 1.70 for (i = 0; i < BBS_max_client; i++)
625     {
626     if (process_sockaddr_pool[i].pid != 0)
627     {
628     log_error("Kill child process (pid=%d)\n", process_sockaddr_pool[i].pid);
629     if (kill(process_sockaddr_pool[i].pid, SIGKILL) < 0)
630     {
631     log_error("Send SIGKILL signal failed (%d)\n", errno);
632     }
633     }
634     }
635 sysadm 1.69
636 sysadm 1.70 notify_child_exit = 2;
637     tm_notify_child_exit = time(NULL);
638     }
639     else if (notify_child_exit == 2 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_KILL_TIMEOUT)
640     {
641     log_error("Main process prepare to exit without waiting for %d child process any longer\n", SYS_child_process_count);
642     SYS_child_process_count = 0;
643     }
644 sysadm 1.21 }
645    
646 sysadm 1.44 if (SYS_conf_reload && !SYS_server_exit)
647 sysadm 1.19 {
648 sysadm 1.44 SYS_conf_reload = 0;
649 sysadm 1.37 sd_notify(0, "RELOADING=1");
650 sysadm 1.30
651 sysadm 1.44 // Reload configuration
652     if (load_conf(CONF_BBSD) < 0)
653     {
654     log_error("Reload conf failed\n");
655     }
656    
657 sysadm 1.80 // Reload BWF config
658     if (bwf_load(CONF_BWF) < 0)
659     {
660     log_error("Reload BWF conf failed\n");
661     }
662    
663 sysadm 1.68 if (load_menu(&bbs_menu_new, CONF_MENU) < 0)
664 sysadm 1.34 {
665 sysadm 1.68 unload_menu(&bbs_menu_new);
666 sysadm 1.72 log_error("Reload bbs menu failed\n");
667 sysadm 1.19 }
668     else
669     {
670 sysadm 1.68 unload_menu(&bbs_menu);
671     memcpy(&bbs_menu, &bbs_menu_new, sizeof(bbs_menu_new));
672 sysadm 1.72 log_common("Reload bbs menu successfully\n");
673     }
674    
675     if (load_menu(&top10_menu_new, CONF_TOP10_MENU) < 0)
676     {
677     unload_menu(&top10_menu_new);
678     log_error("Reload top10 menu failed\n");
679     }
680     else
681     {
682     unload_menu(&top10_menu);
683     top10_menu_new.allow_exit = 1;
684     memcpy(&top10_menu, &top10_menu_new, sizeof(top10_menu_new));
685     log_common("Reload top10 menu successfully\n");
686 sysadm 1.19 }
687 sysadm 1.37
688 sysadm 1.35 for (int i = 0; i < data_files_load_startup_count; i++)
689     {
690 sysadm 1.39 if (load_file(data_files_load_startup[i]) < 0)
691 sysadm 1.35 {
692 sysadm 1.76 log_error("load_file(%s) error\n", data_files_load_startup[i]);
693 sysadm 1.35 }
694     }
695 sysadm 1.49 log_common("Reload data files successfully\n");
696 sysadm 1.35
697 sysadm 1.68 // Load section config and gen_ex
698     if (load_section_config_from_db(1) < 0)
699     {
700     log_error("load_section_config_from_db(1) error\n");
701     }
702     else
703 sysadm 1.42 {
704 sysadm 1.68 log_common("Reload section config and gen_ex successfully\n");
705 sysadm 1.42 }
706 sysadm 1.68
707     sd_notify(0, "READY=1");
708 sysadm 1.42 }
709    
710 sysadm 1.25 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
711 sysadm 1.22
712 sysadm 1.25 if (nfds < 0)
713 sysadm 1.19 {
714     if (errno != EINTR)
715     {
716 sysadm 1.25 log_error("epoll_wait() error (%d)\n", errno);
717     break;
718 sysadm 1.19 }
719     continue;
720     }
721 sysadm 1.13
722 sysadm 1.19 // Stop accept new connection on exit
723     if (SYS_server_exit)
724 sysadm 1.13 {
725     continue;
726     }
727    
728 sysadm 1.25 for (int i = 0; i < nfds; i++)
729 sysadm 1.13 {
730 sysadm 1.52 if (events[i].data.fd == socket_server[0] || events[i].data.fd == socket_server[1])
731 sysadm 1.13 {
732 sysadm 1.53 SSH_v2 = (events[i].data.fd == socket_server[1] ? 1 : 0);
733 sysadm 1.52
734 sysadm 1.29 while (!SYS_server_exit) // Accept all incoming connections until error
735 sysadm 1.13 {
736 sysadm 1.52 addrlen = sizeof(sin);
737 sysadm 1.53 socket_client = accept(socket_server[SSH_v2], (struct sockaddr *)&sin, &addrlen);
738 sysadm 1.25 if (socket_client < 0)
739     {
740 sysadm 1.28 if (errno == EAGAIN || errno == EWOULDBLOCK)
741     {
742     break;
743     }
744     else if (errno == EINTR)
745     {
746     continue;
747     }
748     else
749 sysadm 1.25 {
750     log_error("accept(socket_server) error (%d)\n", errno);
751 sysadm 1.28 break;
752 sysadm 1.25 }
753     }
754    
755     strncpy(hostaddr_client, inet_ntoa(sin.sin_addr), sizeof(hostaddr_client) - 1);
756     hostaddr_client[sizeof(hostaddr_client) - 1] = '\0';
757    
758     port_client = ntohs(sin.sin_port);
759    
760 sysadm 1.64 log_common("Accept %s connection from %s:%d\n", (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client);
761 sysadm 1.25
762 sysadm 1.43 if (SYS_child_process_count - 1 < BBS_max_client)
763 sysadm 1.25 {
764 sysadm 1.44 j = 0;
765     for (i = 0; i < BBS_max_client; i++)
766     {
767     if (process_sockaddr_pool[i].pid != 0 && process_sockaddr_pool[i].s_addr == sin.sin_addr.s_addr)
768     {
769     j++;
770     if (j >= BBS_max_client_per_ip)
771     {
772 sysadm 1.50 log_common("Too many client connections (%d) from %s\n", j, hostaddr_client);
773 sysadm 1.44 break;
774     }
775     }
776     }
777    
778     if (j < BBS_max_client_per_ip)
779 sysadm 1.43 {
780 sysadm 1.52 if ((pid = fork_server()) < 0)
781 sysadm 1.44 {
782     log_error("fork_server() error\n");
783     }
784     else if (pid > 0)
785     {
786     i = 0;
787     for (; i < BBS_max_client; i++)
788     {
789     if (process_sockaddr_pool[i].pid == 0)
790     {
791     break;
792     }
793     }
794    
795     if (i >= BBS_max_client)
796     {
797     log_error("Process sockaddr pool depleted\n");
798     }
799     else
800     {
801     process_sockaddr_pool[i].pid = pid;
802     process_sockaddr_pool[i].s_addr = sin.sin_addr.s_addr;
803     }
804     }
805 sysadm 1.43 }
806     }
807     else
808     {
809     log_error("Rejected client connection over limit (%d)\n", SYS_child_process_count - 1);
810 sysadm 1.25 }
811    
812     if (close(socket_client) == -1)
813     {
814     log_error("close(socket_lient) error (%d)\n", errno);
815     }
816 sysadm 1.13 }
817     }
818     }
819 sysadm 1.25 }
820 sysadm 1.13
821 sysadm 1.30 if (close(epollfd) < 0)
822     {
823     log_error("close(epoll) error (%d)\n");
824     }
825    
826 sysadm 1.52 for (i = 0; i < 2; i++)
827     {
828     fcntl(socket_server[i], F_SETFL, flags[i]);
829 sysadm 1.13
830 sysadm 1.52 if (close(socket_server[i]) == -1)
831     {
832     log_error("Close server socket failed\n");
833     }
834 sysadm 1.13 }
835 sysadm 1.7
836 sysadm 1.51 ssh_bind_free(sshbind);
837     ssh_finalize();
838    
839 sysadm 1.13 return 0;
840 sysadm 1.1 }

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