]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/sighandlers.c
Correctly use cloaked IRC masks on "INVITE nickname"
[ngircd-alex.git] / src / ngircd / sighandlers.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2013 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
28 #include "imp.h"
29 #include "conn.h"
30 #include "conf-ssl.h"
31 #include "channel.h"
32 #include "conf.h"
33 #include "io.h"
34 #include "log.h"
35 #include "ngircd.h"
36 #include "sighandlers.h"
37
38 static int signalpipe[2];
39
40 static const int signals_catch[] = {
41        SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2
42 };
43
44 #ifdef DEBUG
45
46 static void
47 Dump_State(void)
48 {
49         Log(LOG_DEBUG, "--- Internal server state: %s ---",
50             Client_ID(Client_ThisServer()));
51         Log(LOG_DEBUG, "time()=%ld", time(NULL));
52         Conf_DebugDump();
53         Conn_DebugDump();
54         Client_DebugDump();
55         Log(LOG_DEBUG, "--- End of state dump ---");
56 } /* Dump_State */
57
58 #endif
59
60 static void
61 Signal_Block(int sig)
62 {
63 #ifdef HAVE_SIGPROCMASK
64         sigset_t set;
65
66         sigemptyset(&set);
67         sigaddset(&set, sig);
68
69         sigprocmask(SIG_BLOCK, &set, NULL);
70 #else
71         sigblock(sig);
72 #endif
73 }
74
75 static void
76 Signal_Unblock(int sig)
77 {
78 #ifdef HAVE_SIGPROCMASK
79         sigset_t set;
80
81         sigemptyset(&set);
82         sigaddset(&set, sig);
83
84         sigprocmask(SIG_UNBLOCK, &set, NULL);
85 #else
86         int old = sigblock(0) & ~sig;
87         sigsetmask(old);
88 #endif
89 }
90
91 /**
92  * Reload the server configuration file.
93  */
94 static void
95 Rehash(void)
96 {
97         char old_name[CLIENT_ID_LEN];
98         unsigned old_nicklen;
99
100         Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
101
102         /* Remember old server name and nickname length */
103         strlcpy( old_name, Conf_ServerName, sizeof old_name );
104         old_nicklen = Conf_MaxNickLength;
105
106         /* Re-read configuration ... */
107         if (!Conf_Rehash( ))
108                 return;
109
110         /* Close down all listening sockets */
111         Conn_ExitListeners( );
112
113         /* Recover old server name and nickname length: these values can't
114          * be changed during run-time */
115         if (strcmp(old_name, Conf_ServerName) != 0 ) {
116                 strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
117                 Log(LOG_ERR,
118                     "Can't change \"ServerName\" on runtime! Ignored new name.");
119         }
120         if (old_nicklen != Conf_MaxNickLength) {
121                 Conf_MaxNickLength = old_nicklen;
122                 Log(LOG_ERR,
123                     "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
124         }
125
126         /* Create new pre-defined channels */
127         Channel_InitPredefined( );
128
129         if (!ConnSSL_InitLibrary())
130                 Log(LOG_WARNING,
131                     "Re-Initializing of SSL failed, using old keys!");
132
133         /* Start listening on sockets */
134         Conn_InitListeners( );
135
136         /* Sync configuration with established connections */
137         Conn_SyncServerStruct( );
138
139         Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
140 } /* Rehash */
141
142 /**
143  * Signal handler of ngIRCd.
144  * This function is called whenever ngIRCd catches a signal sent by the
145  * user and/or the system to it. For example SIGTERM and SIGHUP.
146  *
147  * It blocks the signal and queues it for later execution by Signal_Handler_BH.
148  * @param Signal Number of the signal to handle.
149  */
150 static void
151 Signal_Handler(int Signal)
152 {
153         switch (Signal) {
154         case SIGTERM:
155         case SIGINT:
156         case SIGQUIT:
157                 /* shut down sever */
158                 NGIRCd_SignalQuit = true;
159                 return;
160         case SIGCHLD:
161                 /* child-process exited, avoid zombies */
162                 while (waitpid( -1, NULL, WNOHANG) > 0)
163                         ;
164                 return;
165 #ifdef DEBUG
166         case SIGUSR1:
167                 if (! NGIRCd_Debug) {
168                         Log(LOG_INFO|LOG_snotice,
169                             "Got SIGUSR1, debug mode activated.");
170 #ifdef SNIFFER
171                         strcpy(NGIRCd_DebugLevel, "2");
172                         NGIRCd_Debug = true;
173                         NGIRCd_Sniffer = true;
174 #else
175                         strcpy(NGIRCd_DebugLevel, "1");
176                         NGIRCd_Debug = true;
177 #endif /* SNIFFER */
178                 } else {
179                         Log(LOG_INFO|LOG_snotice,
180                             "Got SIGUSR1, debug mode deactivated.");
181                         strcpy(NGIRCd_DebugLevel, "");
182                         NGIRCd_Debug = false;
183 #ifdef SNIFFER
184                         NGIRCd_Sniffer = false;
185 #endif /* SNIFFER */
186                 }
187                 return;
188 #endif
189         }
190
191         /*
192          * other signal: queue for later execution.
193          * This has the advantage that we are not restricted
194          * to functions that can be called safely from signal handlers.
195          */
196         if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
197                 Signal_Block(Signal);
198 } /* Signal_Handler */
199
200 /**
201  * Signal processing handler of ngIRCd.
202  * This function is called from the main conn event loop in (io_dispatch)
203  * whenever ngIRCd has queued a signal.
204  *
205  * This function runs in normal context, not from the real signal handler,
206  * thus its not necessary to only use functions that are signal safe.
207  * @param Signal Number of the signal that was queued.
208  */
209 static void
210 Signal_Handler_BH(int Signal)
211 {
212         switch (Signal) {
213         case SIGHUP:
214                 /* re-read configuration */
215                 Rehash();
216                 break;
217 #ifdef DEBUG
218         case SIGUSR2:
219                 if (NGIRCd_Debug) {
220                         Log(LOG_INFO|LOG_snotice,
221                             "Got SIGUSR2, dumping internal state ...");
222                         Dump_State();
223                 }
224                 break;
225         default:
226                 Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
227 #endif
228         }
229         Signal_Unblock(Signal);
230 }
231
232 static void
233 Signal_Callback(int fd, short UNUSED what)
234 {
235         int sig, ret;
236         (void) what;
237
238         do {
239                 ret = (int)read(fd, &sig, sizeof(sig));
240                 if (ret == sizeof(int))
241                         Signal_Handler_BH(sig);
242         } while (ret == sizeof(int));
243
244         if (ret == -1) {
245                 if (errno == EAGAIN || errno == EINTR)
246                         return;
247
248                 Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!",
249                     strerror(errno));
250                 exit(1);
251         }
252
253         Log(LOG_EMERG, "EOF on signal pipe!? - Exiting!");
254         exit(1);
255 }
256
257 /**
258  * Initialize the signal handlers, catch
259  * those signals we are interested in and sets SIGPIPE to be ignored.
260  * @return true if initialization was successful.
261  */
262 bool
263 Signals_Init(void)
264 {
265         size_t i;
266 #ifdef HAVE_SIGACTION
267         struct sigaction saction;
268 #endif
269         if (signalpipe[0] > 0 || signalpipe[1] > 0)
270                 return true;
271
272         if (pipe(signalpipe))
273                 return false;
274
275         if (!io_setnonblock(signalpipe[0]) ||
276             !io_setnonblock(signalpipe[1]))
277                 return false;
278         if (!io_setcloexec(signalpipe[0]) ||
279             !io_setcloexec(signalpipe[1]))
280                 return false;
281 #ifdef HAVE_SIGACTION
282         memset( &saction, 0, sizeof( saction ));
283         saction.sa_handler = Signal_Handler;
284 #ifdef SA_RESTART
285         saction.sa_flags |= SA_RESTART;
286 #endif
287 #ifdef SA_NOCLDWAIT
288         saction.sa_flags |= SA_NOCLDWAIT;
289 #endif
290
291         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
292                 sigaction(signals_catch[i], &saction, NULL);
293
294         /* we handle write errors properly; ignore SIGPIPE */
295         saction.sa_handler = SIG_IGN;
296         sigaction(SIGPIPE, &saction, NULL);
297 #else
298         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
299                 signal(signals_catch[i], Signal_Handler);
300
301         signal(SIGPIPE, SIG_IGN);
302 #endif
303         return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
304 } /* Signals_Init */
305
306 /**
307  * Restores signals to their default behavior.
308  *
309  * This should be called after a fork() in the new
310  * child prodcess, especially when we are about to call
311  * 3rd party code (e.g. PAM).
312  */
313 void
314 Signals_Exit(void)
315 {
316         size_t i;
317 #ifdef HAVE_SIGACTION
318         struct sigaction saction;
319
320         memset(&saction, 0, sizeof(saction));
321         saction.sa_handler = SIG_DFL;
322
323         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
324                 sigaction(signals_catch[i], &saction, NULL);
325         sigaction(SIGPIPE, &saction, NULL);
326 #else
327         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
328                 signal(signals_catch[i], SIG_DFL);
329         signal(SIGPIPE, SIG_DFL);
330 #endif
331         close(signalpipe[1]);
332         close(signalpipe[0]);
333         signalpipe[0] = signalpipe[1] = 0;
334 }
335
336 /* -eof- */