/[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.113 - (hide 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 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.81 #ifdef HAVE_CONFIG_H
10     #include "config.h"
11     #endif
12    
13 sysadm 1.62 #include "bbs.h"
14     #include "bbs_main.h"
15 sysadm 1.80 #include "bwf.h"
16 sysadm 1.1 #include "common.h"
17 sysadm 1.62 #include "database.h"
18     #include "file_loader.h"
19 sysadm 1.82 #include "hash_dict.h"
20 sysadm 1.7 #include "io.h"
21 sysadm 1.44 #include "init.h"
22 sysadm 1.62 #include "log.h"
23     #include "login.h"
24 sysadm 1.19 #include "menu.h"
25 sysadm 1.62 #include "net_server.h"
26 sysadm 1.67 #include "section_list.h"
27 sysadm 1.42 #include "section_list_loader.h"
28 sysadm 1.20 #include <errno.h>
29     #include <fcntl.h>
30 sysadm 1.74 #include <pty.h>
31 sysadm 1.19 #include <signal.h>
32 sysadm 1.20 #include <stdlib.h>
33 sysadm 1.62 #include <string.h>
34 sysadm 1.19 #include <unistd.h>
35 sysadm 1.74 #include <utmp.h>
36 sysadm 1.9 #include <arpa/inet.h>
37 sysadm 1.62 #include <libssh/callbacks.h>
38 sysadm 1.55 #include <libssh/libssh.h>
39     #include <libssh/server.h>
40 sysadm 1.62 #include <netinet/in.h>
41 sysadm 1.89 #include <sys/ioctl.h>
42 sysadm 1.62 #include <sys/socket.h>
43 sysadm 1.100 #include <sys/stat.h>
44 sysadm 1.61 #include <sys/types.h>
45     #include <sys/wait.h>
46 sysadm 1.86
47 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
48     #include <sys/epoll.h>
49     #else
50     #include <poll.h>
51     #endif
52    
53 sysadm 1.86 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
54 sysadm 1.61 #include <systemd/sd-daemon.h>
55 sysadm 1.86 #endif
56 sysadm 1.3
57 sysadm 1.79 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 sysadm 1.70
65 sysadm 1.74 /* A userdata struct for session. */
66     struct session_data_struct
67 sysadm 1.55 {
68     int tries;
69     int error;
70     };
71    
72 sysadm 1.74 /* 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 sysadm 1.87 static int socket_server[2];
92     static int socket_client;
93 sysadm 1.88
94     #ifdef HAVE_SYS_EPOLL_H
95 sysadm 1.87 static int epollfd_server = -1;
96 sysadm 1.88 #endif
97    
98 sysadm 1.87 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 sysadm 1.55 static int auth_password(ssh_session session, const char *user,
106     const char *password, void *userdata)
107     {
108 sysadm 1.74 struct session_data_struct *sdata = (struct session_data_struct *)userdata;
109 sysadm 1.55 int ret;
110    
111     if (strcmp(user, "guest") == 0)
112     {
113 sysadm 1.57 ret = load_guest_info();
114 sysadm 1.55 }
115     else
116     {
117 sysadm 1.57 ret = check_user(user, password);
118 sysadm 1.101 if (ret == 2) // Enforce update user agreement
119     {
120     BBS_update_eula = 1;
121     ret = 0;
122     }
123 sysadm 1.55 }
124    
125     if (ret == 0)
126     {
127     return SSH_AUTH_SUCCESS;
128     }
129    
130 sysadm 1.74 if ((++(sdata->tries)) >= BBS_login_retry_times)
131 sysadm 1.55 {
132 sysadm 1.74 sdata->error = 1;
133 sysadm 1.55 }
134    
135     return SSH_AUTH_DENIED;
136     }
137    
138     static int pty_request(ssh_session session, ssh_channel channel, const char *term,
139 sysadm 1.74 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 sysadm 1.112 log_error("Failed to open pty");
157 sysadm 1.74 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 sysadm 1.112 log_error("Forbid exec /bin/sh %s %s)", mode, command);
191 sysadm 1.74 }
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 sysadm 1.112 log_error("Forbid exec /bin/sh -c %s)", command);
203 sysadm 1.74 }
204    
205     return SSH_OK;
206     }
207    
208     static int exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata)
209 sysadm 1.55 {
210 sysadm 1.74 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 sysadm 1.55 }
226    
227     static int shell_request(ssh_session session, ssh_channel channel, void *userdata)
228     {
229 sysadm 1.74 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 sysadm 1.55 }
246    
247 sysadm 1.74 static int subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata)
248     {
249     (void)session;
250     (void)channel;
251    
252 sysadm 1.112 log_error("subsystem_request(subsystem=%s)", subsystem);
253 sysadm 1.74
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 sysadm 1.55
262 sysadm 1.74 static ssh_channel channel_open(ssh_session session, void *userdata)
263 sysadm 1.55 {
264 sysadm 1.74 (void)userdata;
265    
266 sysadm 1.55 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 sysadm 1.56 static int fork_server(void)
277 sysadm 1.55 {
278     ssh_event event;
279 sysadm 1.71 long int ssh_timeout = 0;
280 sysadm 1.55 int pid;
281     int i;
282     int ret;
283    
284 sysadm 1.74 /* 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 sysadm 1.55 .tries = 0,
304     .error = 0,
305     };
306    
307 sysadm 1.74 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 sysadm 1.55 .userdata = &cb_data,
317     .auth_password_function = auth_password,
318 sysadm 1.74 .channel_open_request_session_function = channel_open,
319 sysadm 1.55 };
320    
321     pid = fork();
322    
323     if (pid > 0) // Parent process
324     {
325     SYS_child_process_count++;
326 sysadm 1.112 log_common("Child process (%d) start", pid);
327 sysadm 1.55 return pid;
328     }
329     else if (pid < 0) // Error
330     {
331 sysadm 1.112 log_error("fork() error (%d)", errno);
332 sysadm 1.55 return -1;
333     }
334    
335     // Child process
336 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
337 sysadm 1.87 if (close(epollfd_server) < 0)
338     {
339 sysadm 1.112 log_error("close(epollfd_server) error (%d)");
340 sysadm 1.87 }
341 sysadm 1.88 #endif
342 sysadm 1.55
343 sysadm 1.87 for (i = 0; i < 2; i++)
344 sysadm 1.55 {
345 sysadm 1.87 if (close(socket_server[i]) == -1)
346     {
347 sysadm 1.112 log_error("Close server socket failed");
348 sysadm 1.87 }
349 sysadm 1.55 }
350    
351 sysadm 1.87 hash_dict_destroy(hash_dict_pid_sockaddr);
352     hash_dict_destroy(hash_dict_sockaddr_count);
353    
354 sysadm 1.55 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 sysadm 1.112 log_error("ssh_bind_accept_fd() error: %s", ssh_get_error(SSH_session));
361 sysadm 1.55 goto cleanup;
362     }
363    
364     ssh_bind_free(sshbind);
365    
366 sysadm 1.71 ssh_timeout = 60; // second
367     if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
368     {
369 sysadm 1.112 log_error("Error setting SSH options: %s", ssh_get_error(SSH_session));
370 sysadm 1.71 goto cleanup;
371     }
372    
373 sysadm 1.75 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 sysadm 1.55 if (ssh_handle_key_exchange(SSH_session))
381     {
382 sysadm 1.112 log_error("ssh_handle_key_exchange() error: %s", ssh_get_error(SSH_session));
383 sysadm 1.55 goto cleanup;
384     }
385    
386     event = ssh_event_new();
387     ssh_event_add_session(event, SSH_session);
388    
389 sysadm 1.58 for (i = 0; i < SSH_AUTH_MAX_DURATION && !SYS_server_exit && !cb_data.error && SSH_channel == NULL; i += 100)
390 sysadm 1.55 {
391 sysadm 1.58 ret = ssh_event_dopoll(event, 100); // 0.1 second
392 sysadm 1.55 if (ret == SSH_ERROR)
393     {
394 sysadm 1.112 log_debug("ssh_event_dopoll() error: %s", ssh_get_error(SSH_session));
395 sysadm 1.55 goto cleanup;
396     }
397     }
398    
399     if (cb_data.error)
400     {
401 sysadm 1.112 log_error("SSH auth error, tried %d times", cb_data.tries);
402 sysadm 1.55 goto cleanup;
403     }
404 sysadm 1.71
405 sysadm 1.74 ssh_set_channel_callbacks(SSH_channel, &channel_cb);
406    
407 sysadm 1.75 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 sysadm 1.71 ssh_timeout = 0;
424     if (ssh_options_set(SSH_session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0)
425     {
426 sysadm 1.112 log_error("Error setting SSH options: %s", ssh_get_error(SSH_session));
427 sysadm 1.71 goto cleanup;
428     }
429 sysadm 1.98
430     ssh_set_blocking(SSH_session, 0);
431 sysadm 1.55 }
432    
433     // Redirect Input
434     if (dup2(socket_client, STDIN_FILENO) == -1)
435     {
436 sysadm 1.112 log_error("Redirect stdin to client socket failed");
437 sysadm 1.55 goto cleanup;
438     }
439    
440     // Redirect Output
441     if (dup2(socket_client, STDOUT_FILENO) == -1)
442     {
443 sysadm 1.112 log_error("Redirect stdout to client socket failed");
444 sysadm 1.55 goto cleanup;
445     }
446    
447 sysadm 1.87 if (io_init() < 0)
448     {
449 sysadm 1.112 log_error("io_init() error");
450 sysadm 1.87 goto cleanup;
451     }
452    
453 sysadm 1.55 SYS_child_process_count = 0;
454    
455 sysadm 1.96 // BWF compile
456     if (bwf_compile() < 0)
457 sysadm 1.95 {
458 sysadm 1.112 log_error("bwf_compile() error");
459 sysadm 1.95 goto cleanup;
460     }
461    
462 sysadm 1.55 bbs_main();
463    
464     cleanup:
465     // Child process exit
466     SYS_server_exit = 1;
467    
468     if (SSH_v2)
469     {
470 sysadm 1.87 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 sysadm 1.74
487 sysadm 1.55 ssh_channel_free(SSH_channel);
488     ssh_disconnect(SSH_session);
489     }
490     else if (close(socket_client) == -1)
491     {
492 sysadm 1.112 log_error("Close client socket failed");
493 sysadm 1.55 }
494    
495     ssh_free(SSH_session);
496     ssh_finalize();
497    
498 sysadm 1.96 // BWF cleanup
499     bwf_cleanup();
500 sysadm 1.95
501 sysadm 1.55 // Close Input and Output for client
502 sysadm 1.87 io_cleanup();
503 sysadm 1.55 close(STDIN_FILENO);
504     close(STDOUT_FILENO);
505    
506 sysadm 1.112 log_common("Process exit normally");
507 sysadm 1.55 log_end();
508    
509     _exit(0);
510    
511     return 0;
512     }
513    
514 sysadm 1.52 int net_server(const char *hostaddr, in_port_t port[])
515 sysadm 1.1 {
516 sysadm 1.100 struct stat file_stat;
517 sysadm 1.52 unsigned int addrlen;
518 sysadm 1.19 int ret;
519 sysadm 1.87 int flags_server[2];
520 sysadm 1.13 struct sockaddr_in sin;
521 sysadm 1.113 char local_addr[INET_ADDRSTRLEN];
522 sysadm 1.88
523     #ifdef HAVE_SYS_EPOLL_H
524 sysadm 1.25 struct epoll_event ev, events[MAX_EVENTS];
525 sysadm 1.88 #else
526     struct pollfd pfds[2];
527     #endif
528    
529 sysadm 1.87 int nfds;
530 sysadm 1.70 int notify_child_exit = 0;
531     time_t tm_notify_child_exit = time(NULL);
532 sysadm 1.44 pid_t pid;
533 sysadm 1.97 int ssh_key_valid = 0;
534 sysadm 1.51 int ssh_log_level = SSH_LOG_NOLOG;
535 sysadm 1.88
536 sysadm 1.86 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
537     int sd_notify_stopping = 0;
538     #endif
539 sysadm 1.10
540 sysadm 1.51 ssh_init();
541    
542     sshbind = ssh_bind_new();
543    
544 sysadm 1.97 if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_RSA_KEY_FILE) < 0)
545     {
546 sysadm 1.112 log_error("Error loading SSH RSA key: %s", SSH_HOST_RSA_KEY_FILE);
547 sysadm 1.97 }
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 sysadm 1.112 log_error("Error loading SSH ED25519 key: %s", SSH_HOST_ED25519_KEY_FILE);
555 sysadm 1.99 }
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 sysadm 1.112 log_error("Error loading SSH ECDSA key: %s", SSH_HOST_ECDSA_KEY_FILE);
563 sysadm 1.97 }
564     else
565     {
566     ssh_key_valid = 1;
567     }
568    
569     if (!ssh_key_valid)
570     {
571 sysadm 1.112 log_error("Error: no valid SSH host key");
572 sysadm 1.97 ssh_bind_free(sshbind);
573     return -1;
574     }
575    
576 sysadm 1.51 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 sysadm 1.110 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "+ssh-ed25519,ecdsa-sha2-nistp256,ssh-rsa") < 0 ||
579 sysadm 1.51 ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level) < 0)
580     {
581 sysadm 1.112 log_error("Error setting SSH bind options: %s", ssh_get_error(sshbind));
582 sysadm 1.51 ssh_bind_free(sshbind);
583     return -1;
584     }
585 sysadm 1.10
586 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
587 sysadm 1.87 epollfd_server = epoll_create1(0);
588     if (epollfd_server == -1)
589 sysadm 1.13 {
590 sysadm 1.112 log_error("epoll_create1() error (%d)", errno);
591 sysadm 1.27 return -1;
592 sysadm 1.13 }
593 sysadm 1.88 #endif
594 sysadm 1.10
595 sysadm 1.52 // Server socket
596 sysadm 1.108 for (int i = 0; i < 2; i++)
597 sysadm 1.23 {
598 sysadm 1.52 socket_server[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
599 sysadm 1.23
600 sysadm 1.52 if (socket_server[i] < 0)
601     {
602 sysadm 1.112 log_error("Create socket_server error (%d)", errno);
603 sysadm 1.52 return -1;
604     }
605 sysadm 1.10
606 sysadm 1.52 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 sysadm 1.113 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 sysadm 1.52 // Reuse address and port
617 sysadm 1.87 flags_server[i] = 1;
618     if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEADDR, &flags_server[i], sizeof(flags_server[i])) < 0)
619 sysadm 1.52 {
620 sysadm 1.112 log_error("setsockopt SO_REUSEADDR error (%d)", errno);
621 sysadm 1.52 }
622 sysadm 1.90 #if defined(SO_REUSEPORT)
623 sysadm 1.87 if (setsockopt(socket_server[i], SOL_SOCKET, SO_REUSEPORT, &flags_server[i], sizeof(flags_server[i])) < 0)
624 sysadm 1.52 {
625 sysadm 1.112 log_error("setsockopt SO_REUSEPORT error (%d)", errno);
626 sysadm 1.52 }
627 sysadm 1.90 #endif
628 sysadm 1.1
629 sysadm 1.52 if (bind(socket_server[i], (struct sockaddr *)&sin, sizeof(sin)) < 0)
630     {
631 sysadm 1.112 log_error("Bind address %s:%u error (%d)",
632 sysadm 1.113 local_addr, port[i], errno);
633 sysadm 1.52 return -1;
634     }
635 sysadm 1.16
636 sysadm 1.52 if (listen(socket_server[i], 10) < 0)
637     {
638 sysadm 1.112 log_error("Telnet socket listen error (%d)", errno);
639 sysadm 1.52 return -1;
640     }
641 sysadm 1.13
642 sysadm 1.113 log_common("Listening at %s:%u", local_addr, port[i]);
643 sysadm 1.25
644 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
645 sysadm 1.52 ev.events = EPOLLIN;
646     ev.data.fd = socket_server[i];
647 sysadm 1.87 if (epoll_ctl(epollfd_server, EPOLL_CTL_ADD, socket_server[i], &ev) == -1)
648 sysadm 1.30 {
649 sysadm 1.112 log_error("epoll_ctl(socket_server[%d]) error (%d)", i, errno);
650 sysadm 1.87 if (close(epollfd_server) < 0)
651 sysadm 1.52 {
652 sysadm 1.112 log_error("close(epoll) error (%d)");
653 sysadm 1.52 }
654     return -1;
655 sysadm 1.30 }
656 sysadm 1.88 #endif
657 sysadm 1.52
658 sysadm 1.87 flags_server[i] = fcntl(socket_server[i], F_GETFL, 0);
659     fcntl(socket_server[i], F_SETFL, flags_server[i] | O_NONBLOCK);
660 sysadm 1.25 }
661    
662 sysadm 1.98 ssh_bind_set_blocking(sshbind, 0);
663    
664 sysadm 1.82 hash_dict_pid_sockaddr = hash_dict_create(MAX_CLIENT_LIMIT);
665     if (hash_dict_pid_sockaddr == NULL)
666     {
667 sysadm 1.112 log_error("hash_dict_create(hash_dict_pid_sockaddr) error");
668 sysadm 1.82 return -1;
669     }
670     hash_dict_sockaddr_count = hash_dict_create(MAX_CLIENT_LIMIT);
671     if (hash_dict_sockaddr_count == NULL)
672     {
673 sysadm 1.112 log_error("hash_dict_create(hash_dict_sockaddr_count) error");
674 sysadm 1.82 return -1;
675     }
676    
677 sysadm 1.31 // Startup complete
678 sysadm 1.86 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
679 sysadm 1.31 sd_notifyf(0, "READY=1\n"
680 sysadm 1.52 "STATUS=Listening at %s:%d (Telnet) and %s:%d (SSH2)\n"
681 sysadm 1.31 "MAINPID=%d",
682 sysadm 1.52 hostaddr, port[0], hostaddr, port[1], getpid());
683 sysadm 1.86 #endif
684 sysadm 1.31
685 sysadm 1.19 while (!SYS_server_exit || SYS_child_process_count > 0)
686 sysadm 1.13 {
687 sysadm 1.86 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
688 sysadm 1.31 if (SYS_server_exit && !sd_notify_stopping)
689     {
690     sd_notify(0, "STOPPING=1");
691     sd_notify_stopping = 1;
692     }
693 sysadm 1.86 #endif
694 sysadm 1.37
695 sysadm 1.22 while ((SYS_child_exit || SYS_server_exit) && SYS_child_process_count > 0)
696 sysadm 1.19 {
697 sysadm 1.30 SYS_child_exit = 0;
698    
699 sysadm 1.92 pid = waitpid(-1, &ret, WNOHANG);
700 sysadm 1.89 if (pid > 0)
701 sysadm 1.19 {
702 sysadm 1.30 SYS_child_exit = 1; // Retry waitid
703 sysadm 1.92 SYS_child_process_count--;
704 sysadm 1.30
705 sysadm 1.92 if (WIFEXITED(ret))
706     {
707 sysadm 1.112 log_common("Child process (%d) exited, status=%d", pid, WEXITSTATUS(ret));
708 sysadm 1.92 }
709     else if (WIFSIGNALED(ret))
710     {
711 sysadm 1.112 log_common("Child process (%d) is killed, status=%d", pid, WTERMSIG(ret));
712 sysadm 1.92 }
713     else
714     {
715 sysadm 1.112 log_common("Child process (%d) exited abnormally, status=%d", pid, ret);
716 sysadm 1.92 }
717 sysadm 1.44
718 sysadm 1.89 if (pid != section_list_loader_pid)
719 sysadm 1.44 {
720 sysadm 1.108 int64_t j = 0;
721     ret = hash_dict_get(hash_dict_pid_sockaddr, (uint64_t)pid, &j);
722 sysadm 1.82 if (ret < 0)
723     {
724 sysadm 1.112 log_error("hash_dict_get(hash_dict_pid_sockaddr, %d) error", pid);
725 sysadm 1.82 }
726     else
727 sysadm 1.44 {
728 sysadm 1.107 ret = hash_dict_inc(hash_dict_sockaddr_count, (in_addr_t)j, -1);
729 sysadm 1.106 if (ret <= 0)
730 sysadm 1.82 {
731 sysadm 1.112 log_error("hash_dict_inc(hash_dict_sockaddr_count, %lu, -1) error: %d", (in_addr_t)j, ret);
732 sysadm 1.82 }
733    
734 sysadm 1.89 ret = hash_dict_del(hash_dict_pid_sockaddr, (uint64_t)pid);
735 sysadm 1.82 if (ret < 0)
736 sysadm 1.45 {
737 sysadm 1.112 log_error("hash_dict_del(hash_dict_pid_sockaddr, %lu) error", (uint64_t)pid);
738 sysadm 1.45 }
739     }
740 sysadm 1.44 }
741 sysadm 1.19 }
742 sysadm 1.89 else if (pid == 0)
743 sysadm 1.19 {
744     break;
745     }
746 sysadm 1.89 else if (pid < 0)
747 sysadm 1.19 {
748 sysadm 1.112 log_error("Error in waitpid(): %d", errno);
749 sysadm 1.19 break;
750     }
751     }
752    
753 sysadm 1.22 if (SYS_server_exit && !SYS_child_exit && SYS_child_process_count > 0)
754 sysadm 1.21 {
755 sysadm 1.70 if (notify_child_exit == 0)
756 sysadm 1.21 {
757 sysadm 1.86 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
758 sysadm 1.70 sd_notifyf(0, "STATUS=Notify %d child process to exit", SYS_child_process_count);
759 sysadm 1.112 log_common("Notify %d child process to exit", SYS_child_process_count);
760 sysadm 1.86 #endif
761 sysadm 1.70
762 sysadm 1.93 if (kill(0, SIGTERM) < 0)
763 sysadm 1.70 {
764 sysadm 1.112 log_error("Send SIGTERM signal failed (%d)", errno);
765 sysadm 1.70 }
766    
767     notify_child_exit = 1;
768     tm_notify_child_exit = time(NULL);
769 sysadm 1.21 }
770 sysadm 1.70 else if (notify_child_exit == 1 && time(NULL) - tm_notify_child_exit >= WAIT_CHILD_PROCESS_EXIT_TIMEOUT)
771     {
772 sysadm 1.86 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
773 sysadm 1.70 sd_notifyf(0, "STATUS=Kill %d child process", SYS_child_process_count);
774 sysadm 1.86 #endif
775 sysadm 1.31
776 sysadm 1.93 if (kill(0, SIGKILL) < 0)
777 sysadm 1.70 {
778 sysadm 1.112 log_error("Send SIGKILL signal failed (%d)", errno);
779 sysadm 1.70 }
780 sysadm 1.69
781 sysadm 1.70 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 sysadm 1.112 log_error("Main process prepare to exit without waiting for %d child process any longer", SYS_child_process_count);
787 sysadm 1.70 SYS_child_process_count = 0;
788     }
789 sysadm 1.21 }
790    
791 sysadm 1.44 if (SYS_conf_reload && !SYS_server_exit)
792 sysadm 1.19 {
793 sysadm 1.44 SYS_conf_reload = 0;
794 sysadm 1.86
795     #ifdef HAVE_SYSTEMD_SD_DAEMON_H
796 sysadm 1.37 sd_notify(0, "RELOADING=1");
797 sysadm 1.86 #endif
798 sysadm 1.30
799 sysadm 1.112 log_common("Reload configuration");
800 sysadm 1.113
801 sysadm 1.84 // Restart log
802     if (log_restart() < 0)
803     {
804 sysadm 1.112 log_error("Restart logging failed");
805 sysadm 1.84 }
806    
807 sysadm 1.44 // Reload configuration
808     if (load_conf(CONF_BBSD) < 0)
809     {
810 sysadm 1.112 log_error("Reload conf failed");
811 sysadm 1.44 }
812    
813 sysadm 1.80 // Reload BWF config
814     if (bwf_load(CONF_BWF) < 0)
815     {
816 sysadm 1.112 log_error("Reload BWF conf failed");
817 sysadm 1.80 }
818    
819 sysadm 1.100 // Get EULA modification tm
820     if (stat(DATA_EULA, &file_stat) == -1)
821     {
822 sysadm 1.112 log_error("stat(%s) error", DATA_EULA, errno);
823 sysadm 1.100 }
824     else
825     {
826     BBS_eula_tm = file_stat.st_mtim.tv_sec;
827     }
828    
829 sysadm 1.94 if (detach_menu_shm(&bbs_menu) < 0)
830 sysadm 1.34 {
831 sysadm 1.112 log_error("detach_menu_shm(bbs_menu) error");
832 sysadm 1.19 }
833 sysadm 1.94 if (load_menu(&bbs_menu, CONF_MENU) < 0)
834 sysadm 1.19 {
835 sysadm 1.112 log_error("load_menu(bbs_menu) error");
836 sysadm 1.68 unload_menu(&bbs_menu);
837 sysadm 1.72 }
838    
839 sysadm 1.94 if (detach_menu_shm(&top10_menu) < 0)
840 sysadm 1.72 {
841 sysadm 1.112 log_error("detach_menu_shm(top10_menu) error");
842 sysadm 1.72 }
843 sysadm 1.94 if (load_menu(&top10_menu, CONF_TOP10_MENU) < 0)
844 sysadm 1.72 {
845 sysadm 1.112 log_error("load_menu(top10_menu) error");
846 sysadm 1.72 unload_menu(&top10_menu);
847 sysadm 1.19 }
848 sysadm 1.102 top10_menu.allow_exit = 1;
849 sysadm 1.37
850 sysadm 1.35 for (int i = 0; i < data_files_load_startup_count; i++)
851     {
852 sysadm 1.39 if (load_file(data_files_load_startup[i]) < 0)
853 sysadm 1.35 {
854 sysadm 1.112 log_error("load_file(%s) error", data_files_load_startup[i]);
855 sysadm 1.35 }
856     }
857    
858 sysadm 1.68 // Load section config and gen_ex
859     if (load_section_config_from_db(1) < 0)
860     {
861 sysadm 1.112 log_error("load_section_config_from_db(1) error");
862 sysadm 1.68 }
863    
864 sysadm 1.84 // Notify child processes to reload configuration
865 sysadm 1.93 if (kill(0, SIGUSR1) < 0)
866 sysadm 1.84 {
867 sysadm 1.112 log_error("Send SIGUSR1 signal failed (%d)", errno);
868 sysadm 1.84 }
869    
870 sysadm 1.86 #ifdef HAVE_SYSTEMD_SD_DAEMON_H
871 sysadm 1.68 sd_notify(0, "READY=1");
872 sysadm 1.86 #endif
873 sysadm 1.42 }
874    
875 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
876 sysadm 1.87 nfds = epoll_wait(epollfd_server, events, MAX_EVENTS, 100); // 0.1 second
877 sysadm 1.88 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 sysadm 1.19 {
888     if (errno != EINTR)
889     {
890 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
891 sysadm 1.112 log_error("epoll_wait() error (%d)", errno);
892 sysadm 1.88 #else
893 sysadm 1.112 log_error("poll() error (%d)", errno);
894 sysadm 1.88 #endif
895 sysadm 1.25 break;
896 sysadm 1.19 }
897     continue;
898     }
899 sysadm 1.13
900 sysadm 1.19 // Stop accept new connection on exit
901     if (SYS_server_exit)
902 sysadm 1.13 {
903     continue;
904     }
905    
906 sysadm 1.25 for (int i = 0; i < nfds; i++)
907 sysadm 1.13 {
908 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
909 sysadm 1.52 if (events[i].data.fd == socket_server[0] || events[i].data.fd == socket_server[1])
910 sysadm 1.88 #else
911     if ((pfds[i].fd == socket_server[0] || pfds[i].fd == socket_server[1]) && (pfds[i].revents & POLLIN))
912     #endif
913 sysadm 1.13 {
914 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
915 sysadm 1.53 SSH_v2 = (events[i].data.fd == socket_server[1] ? 1 : 0);
916 sysadm 1.88 #else
917     SSH_v2 = (pfds[i].fd == socket_server[1] ? 1 : 0);
918     #endif
919 sysadm 1.52
920 sysadm 1.29 while (!SYS_server_exit) // Accept all incoming connections until error
921 sysadm 1.13 {
922 sysadm 1.52 addrlen = sizeof(sin);
923 sysadm 1.91 socket_client = accept(socket_server[SSH_v2], (struct sockaddr *)&sin, (socklen_t *)&addrlen);
924 sysadm 1.25 if (socket_client < 0)
925     {
926 sysadm 1.28 if (errno == EAGAIN || errno == EWOULDBLOCK)
927     {
928     break;
929     }
930     else if (errno == EINTR)
931     {
932     continue;
933     }
934     else
935 sysadm 1.25 {
936 sysadm 1.112 log_error("accept(socket_server) error (%d)", errno);
937 sysadm 1.28 break;
938 sysadm 1.25 }
939     }
940    
941 sysadm 1.113 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 sysadm 1.25 port_client = ntohs(sin.sin_port);
948    
949 sysadm 1.43 if (SYS_child_process_count - 1 < BBS_max_client)
950 sysadm 1.25 {
951 sysadm 1.108 int64_t j = 0;
952     ret = hash_dict_get(hash_dict_sockaddr_count, sin.sin_addr.s_addr, &j);
953 sysadm 1.82 if (ret < 0)
954 sysadm 1.44 {
955 sysadm 1.112 log_error("hash_dict_get(hash_dict_sockaddr_count, %s) error", hostaddr_client);
956 sysadm 1.44 }
957    
958     if (j < BBS_max_client_per_ip)
959 sysadm 1.43 {
960 sysadm 1.52 if ((pid = fork_server()) < 0)
961 sysadm 1.44 {
962 sysadm 1.112 log_error("fork_server() error");
963 sysadm 1.44 }
964     else if (pid > 0)
965     {
966 sysadm 1.82 ret = hash_dict_set(hash_dict_pid_sockaddr, (uint64_t)pid, sin.sin_addr.s_addr);
967     if (ret < 0)
968 sysadm 1.44 {
969 sysadm 1.112 log_error("hash_dict_set(hash_dict_pid_sockaddr, %lu, %s) error", (uint64_t)pid, hostaddr_client);
970 sysadm 1.44 }
971    
972 sysadm 1.106 if (j == 0)
973     {
974     // First connection from this IP
975 sysadm 1.112 log_common("Accept %s connection from %s:%d",
976 sysadm 1.106 (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 sysadm 1.112 log_error("hash_dict_set(hash_dict_sockaddr_count, %s, 1) error", hostaddr_client);
982 sysadm 1.106 }
983     }
984     else
985 sysadm 1.44 {
986 sysadm 1.106 // Increase connection count from this IP
987 sysadm 1.112 log_common("Accept %s connection from %s:%d, already have %d connections",
988 sysadm 1.106 (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 sysadm 1.112 log_error("hash_dict_inc(hash_dict_sockaddr_count, %s, 1) error: %d", hostaddr_client, ret);
994 sysadm 1.106 }
995 sysadm 1.44 }
996     }
997 sysadm 1.43 }
998 sysadm 1.82 else
999     {
1000 sysadm 1.112 log_error("Rejected %s connection from %s:%d over limit per IP (%d >= %d)",
1001 sysadm 1.105 (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client, j, BBS_max_client_per_ip);
1002 sysadm 1.82 }
1003 sysadm 1.43 }
1004     else
1005     {
1006 sysadm 1.112 log_error("Rejected %s connection from %s:%d over limit (%d >= %d)",
1007 sysadm 1.105 (SSH_v2 ? "SSH" : "telnet"), hostaddr_client, port_client, SYS_child_process_count - 1, BBS_max_client);
1008 sysadm 1.25 }
1009    
1010     if (close(socket_client) == -1)
1011     {
1012 sysadm 1.112 log_error("close(socket_lient) error (%d)", errno);
1013 sysadm 1.25 }
1014 sysadm 1.13 }
1015     }
1016     }
1017 sysadm 1.25 }
1018 sysadm 1.13
1019 sysadm 1.88 #ifdef HAVE_SYS_EPOLL_H
1020 sysadm 1.87 if (close(epollfd_server) < 0)
1021 sysadm 1.30 {
1022 sysadm 1.112 log_error("close(epollfd_server) error (%d)");
1023 sysadm 1.30 }
1024 sysadm 1.88 #endif
1025 sysadm 1.30
1026 sysadm 1.108 for (int i = 0; i < 2; i++)
1027 sysadm 1.52 {
1028     if (close(socket_server[i]) == -1)
1029     {
1030 sysadm 1.112 log_error("Close server socket failed");
1031 sysadm 1.52 }
1032 sysadm 1.13 }
1033 sysadm 1.7
1034 sysadm 1.82 hash_dict_destroy(hash_dict_pid_sockaddr);
1035     hash_dict_destroy(hash_dict_sockaddr_count);
1036    
1037 sysadm 1.51 ssh_bind_free(sshbind);
1038     ssh_finalize();
1039    
1040 sysadm 1.13 return 0;
1041 sysadm 1.1 }

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