]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/sighandlers.c
Clarify that "CAFile" is not set by default
[ngircd-alex.git] / src / ngircd / sighandlers.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2024 Alexander Barton (alex@barton.de) and Contributors.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * Please read the file COPYING, README and AUTHORS for more information.
10  */
11
12 #include "portab.h"
13
14 /**
15  * @file
16  * Signal Handlers: Actions to be performed when the program
17  * receives a signal.
18  */
19
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <time.h>
28
29 #ifdef HAVE_SYS_UN_H
30 # include <sys/socket.h>
31 # include <sys/un.h>
32 #endif
33
34 #include "conn.h"
35 #include "channel.h"
36 #include "conf.h"
37 #include "io.h"
38 #include "log.h"
39 #include "ngircd.h"
40
41 #include "sighandlers.h"
42
43 static int signalpipe[2];
44
45 static const int signals_catch[] = {
46        SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2
47 };
48
49
50 static void
51 Dump_State(void)
52 {
53         LogDebug("--- Internal server state: %s ---",
54             Client_ID(Client_ThisServer()));
55 #ifdef HAVE_LONG_LONG
56         LogDebug("time()=%llu", (unsigned long long)time(NULL));
57 #else
58         LogDebug("time()=%lu", (unsigned long)time(NULL));
59 #endif
60         Conf_DebugDump();
61         Conn_DebugDump();
62         Client_DebugDump();
63         LogDebug("--- End of state dump ---");
64 } /* Dump_State */
65
66
67 static void
68 Signal_Block(int sig)
69 {
70 #ifdef HAVE_SIGPROCMASK
71         sigset_t set;
72
73         sigemptyset(&set);
74         sigaddset(&set, sig);
75
76         sigprocmask(SIG_BLOCK, &set, NULL);
77 #else
78         sigblock(sig);
79 #endif
80 }
81
82 static void
83 Signal_Unblock(int sig)
84 {
85 #ifdef HAVE_SIGPROCMASK
86         sigset_t set;
87
88         sigemptyset(&set);
89         sigaddset(&set, sig);
90
91         sigprocmask(SIG_UNBLOCK, &set, NULL);
92 #else
93         int old = sigblock(0) & ~sig;
94         sigsetmask(old);
95 #endif
96 }
97
98 /**
99  * Reload the server configuration file.
100  */
101 static void
102 Rehash(void)
103 {
104         char old_name[CLIENT_ID_LEN];
105         unsigned old_nicklen;
106
107         Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
108         Signal_NotifySvcMgr("RELOADING=1\n");
109
110         /* Remember old server name and nickname length */
111         strlcpy( old_name, Conf_ServerName, sizeof old_name );
112         old_nicklen = Conf_MaxNickLength;
113
114         /* Re-read configuration ... */
115         if (!Conf_Rehash()) {
116                 Signal_NotifySvcMgr("READY=1\n");
117                 return;
118         }
119
120         /* Close down all listening sockets */
121         Conn_ExitListeners( );
122
123         /* Recover old server name and nickname length: these values can't
124          * be changed during run-time */
125         if (strcmp(old_name, Conf_ServerName) != 0 ) {
126                 strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
127                 Log(LOG_ERR,
128                     "Can't change server name (\"Name\") on runtime! Ignored new name.");
129         }
130         if (old_nicklen != Conf_MaxNickLength) {
131                 Conf_MaxNickLength = old_nicklen;
132                 Log(LOG_ERR,
133                     "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
134         }
135
136         /* Create new pre-defined channels */
137         Channel_InitPredefined( );
138
139         if (!ConnSSL_InitLibrary())
140                 Log(LOG_WARNING,
141                     "Re-Initializing of SSL failed!");
142
143         /* Start listening on sockets */
144         Conn_InitListeners( );
145
146         /* Sync configuration with established connections */
147         Conn_SyncServerStruct( );
148
149         Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
150         Signal_NotifySvcMgr("READY=1\n");
151 } /* Rehash */
152
153 /**
154  * Signal handler of ngIRCd.
155  * This function is called whenever ngIRCd catches a signal sent by the
156  * user and/or the system to it. For example SIGTERM and SIGHUP.
157  *
158  * It blocks the signal and queues it for later execution by Signal_Handler_BH.
159  * @param Signal Number of the signal to handle.
160  */
161 static void
162 Signal_Handler(int Signal)
163 {
164         if (Signal != SIGCHLD) {
165 #ifdef HAVE_STRSIGNAL
166                 Log(LOG_INFO, "Got signal \"%s\" ...", strsignal(Signal));
167 #else
168                 Log(LOG_INFO, "Got signal %d ...", Signal);
169 #endif
170         }
171
172         switch (Signal) {
173         case SIGTERM:
174         case SIGINT:
175         case SIGQUIT:
176                 /* shut down sever */
177                 NGIRCd_SignalQuit = true;
178                 return;
179         case SIGCHLD:
180                 /* child-process exited, avoid zombies */
181                 while (waitpid( -1, NULL, WNOHANG) > 0)
182                         ;
183                 return;
184         case SIGUSR1:
185                 if (! NGIRCd_Debug) {
186                         Log(LOG_INFO|LOG_snotice,
187                             "Got SIGUSR1, debug mode activated.");
188 #ifdef SNIFFER
189                         strcpy(NGIRCd_DebugLevel, "2");
190                         NGIRCd_Debug = true;
191                         NGIRCd_Sniffer = true;
192 #else
193                         strcpy(NGIRCd_DebugLevel, "1");
194                         NGIRCd_Debug = true;
195 #endif /* SNIFFER */
196                 } else {
197                         Log(LOG_INFO|LOG_snotice,
198                             "Got SIGUSR1, debug mode deactivated.");
199                         strcpy(NGIRCd_DebugLevel, "");
200                         NGIRCd_Debug = false;
201 #ifdef SNIFFER
202                         NGIRCd_Sniffer = false;
203 #endif /* SNIFFER */
204                 }
205                 return;
206         }
207
208         /*
209          * other signal: queue for later execution.
210          * This has the advantage that we are not restricted
211          * to functions that can be called safely from signal handlers.
212          */
213         if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
214                 Signal_Block(Signal);
215 } /* Signal_Handler */
216
217 /**
218  * Signal processing handler of ngIRCd.
219  * This function is called from the main conn event loop in (io_dispatch)
220  * whenever ngIRCd has queued a signal.
221  *
222  * This function runs in normal context, not from the real signal handler,
223  * thus its not necessary to only use functions that are signal safe.
224  * @param Signal Number of the signal that was queued.
225  */
226 static void
227 Signal_Handler_BH(int Signal)
228 {
229         switch (Signal) {
230         case SIGHUP:
231                 /* re-read configuration */
232                 Rehash();
233                 break;
234         case SIGUSR2:
235                 if (NGIRCd_Debug) {
236                         Log(LOG_INFO|LOG_snotice,
237                             "Got SIGUSR2, dumping internal state ...");
238                         Dump_State();
239                 }
240                 break;
241         default:
242                 LogDebug("Got signal %d! Ignored.", Signal);
243         }
244         Signal_Unblock(Signal);
245 }
246
247 static void
248 Signal_Callback(int fd, short UNUSED what)
249 {
250         int sig, ret;
251         (void) what;
252
253         do {
254                 ret = (int)read(fd, &sig, sizeof(sig));
255                 if (ret == sizeof(int))
256                         Signal_Handler_BH(sig);
257         } while (ret == sizeof(int));
258
259         if (ret == -1) {
260                 if (errno == EAGAIN || errno == EINTR)
261                         return;
262
263                 Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!",
264                     strerror(errno));
265                 exit(1);
266         }
267
268         Log(LOG_EMERG, "EOF on signal pipe!? - Exiting!");
269         exit(1);
270 }
271
272 /**
273  * Initialize the signal handlers, catch
274  * those signals we are interested in and sets SIGPIPE to be ignored.
275  * @return true if initialization was successful.
276  */
277 bool
278 Signals_Init(void)
279 {
280         size_t i;
281 #ifdef HAVE_SIGACTION
282         struct sigaction saction;
283 #endif
284         if (signalpipe[0] > 0 || signalpipe[1] > 0)
285                 return true;
286
287         if (pipe(signalpipe))
288                 return false;
289
290         if (!io_setnonblock(signalpipe[0]) ||
291             !io_setnonblock(signalpipe[1]))
292                 return false;
293         if (!io_setcloexec(signalpipe[0]) ||
294             !io_setcloexec(signalpipe[1]))
295                 return false;
296 #ifdef HAVE_SIGACTION
297         memset( &saction, 0, sizeof( saction ));
298         saction.sa_handler = Signal_Handler;
299 #ifdef SA_RESTART
300         saction.sa_flags |= SA_RESTART;
301 #endif
302 #ifdef SA_NOCLDWAIT
303         saction.sa_flags |= SA_NOCLDWAIT;
304 #endif
305
306         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
307                 sigaction(signals_catch[i], &saction, NULL);
308
309         /* we handle write errors properly; ignore SIGPIPE */
310         saction.sa_handler = SIG_IGN;
311         sigaction(SIGPIPE, &saction, NULL);
312 #else
313         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
314                 signal(signals_catch[i], Signal_Handler);
315
316         signal(SIGPIPE, SIG_IGN);
317 #endif
318         return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
319 } /* Signals_Init */
320
321 /**
322  * Restores signals to their default behavior.
323  *
324  * This should be called after a fork() in the new
325  * child prodcess, especially when we are about to call
326  * 3rd party code (e.g. PAM).
327  */
328 void
329 Signals_Exit(void)
330 {
331         size_t i;
332 #ifdef HAVE_SIGACTION
333         struct sigaction saction;
334
335         memset(&saction, 0, sizeof(saction));
336         saction.sa_handler = SIG_DFL;
337
338         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
339                 sigaction(signals_catch[i], &saction, NULL);
340         sigaction(SIGPIPE, &saction, NULL);
341 #else
342         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
343                 signal(signals_catch[i], SIG_DFL);
344         signal(SIGPIPE, SIG_DFL);
345 #endif
346         close(signalpipe[1]);
347         close(signalpipe[0]);
348         signalpipe[0] = signalpipe[1] = 0;
349 }
350
351 /**
352  * Check if the service manager of the system can be notified.
353  *
354  * @returns true if notifying the service manager is theoretically possible.
355  */
356 GLOBAL bool
357 Signal_NotifySvcMgr_Possible(void)
358 {
359 #if !defined(HAVE_SYS_UN_H) || !defined(SOCK_CLOEXEC)
360         return false;
361 #else
362         return getenv("NOTIFY_SOCKET") != NULL;
363 #endif
364 }
365
366 /**
367  * Notify the service manager using the "sd_notify" protocol.
368  *
369  * This function is based on the example notify() function shown in the
370  * sd_notify(3) manual page, with one significant difference: we keep the file
371  * descriptor open to reduce overhead when called multiple times.
372  *
373  * @param message: The message to pass to the service manager including "\n".
374  */
375 GLOBAL void
376 #if !defined(HAVE_SYS_UN_H) || !defined(SOCK_CLOEXEC)
377 Signal_NotifySvcMgr(UNUSED const char *message)
378 {
379         return;
380 #else
381 Signal_NotifySvcMgr(const char *message)
382 {
383         struct sockaddr_un socket_addr;
384         const char *socket_path;
385         size_t path_length, message_length;
386         static int fd = NONE;
387
388         assert(message != NULL);
389         assert(message[0] != '\0');
390
391         if (fd == NONE) {
392                 /* No socket to the service manager open: Check if a path name
393                  * is given in the environment and try to open it! */
394                 socket_path = getenv("NOTIFY_SOCKET");
395                 if (!socket_path)
396                         return; /* No socket specified, nothing to do. */
397
398                 /* Only AF_UNIX is supported, with path or abstract sockets */
399                 if (socket_path[0] != '/' && socket_path[0] != '@') {
400                         Log(LOG_CRIT,
401                         "Failed to notify service manager: Unsupported socket path!");
402                         return;
403                 }
404
405                 path_length = strlen(socket_path);
406
407                 /* Ensure there is room for NUL byte */
408                 if (path_length >= sizeof(socket_addr.sun_path)) {
409                         Log(LOG_CRIT,
410                         "Failed to notify service manager: Socket path too long!");
411                         return;
412                 }
413
414                 memset(&socket_addr, 0, sizeof(struct sockaddr_un));
415                 socket_addr.sun_family = AF_UNIX;
416                 memcpy(socket_addr.sun_path, socket_path, path_length);
417
418                 /* Support for abstract socket */
419                 if (socket_addr.sun_path[0] == '@')
420                         socket_addr.sun_path[0] = 0;
421
422                 fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
423                 if (fd < 0) {
424                         Log(LOG_CRIT,
425                             "Failed to notify service manager: %s [socket()]",
426                             strerror(errno));
427                         return;
428                 }
429
430                 if (connect(fd, (struct sockaddr *)&socket_addr,
431                             sizeof(struct sockaddr_un)) != 0) {
432                         Log(LOG_CRIT,
433                             "Failed to notify service manager: %s [connect()]",
434                             strerror(errno));
435                         close(fd);
436                         fd = NONE;
437                         return;
438                 }
439         }
440
441         message_length = strlen(message);
442         ssize_t written = write(fd, message, message_length);
443         if (written != (ssize_t)message_length) {
444                 Log(LOG_CRIT,
445                         "Failed to notify service manager: %s [write()]",
446                         strerror(errno));
447                 close(fd);
448                 fd = NONE;
449         }
450 #endif
451 }