/[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.115 - (hide annotations)
Sat Jan 3 10:27:14 2026 UTC (2 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.114: +1 -1 lines
Content type: text/x-csrc
Update copyright info

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

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