1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 2014-2020 The ProFTPD Project team
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  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, the ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* Signal handling. */
26 
27 #include "conf.h"
28 #include "privs.h"
29 
30 #ifdef HAVE_EXECINFO_H
31 # include <execinfo.h>
32 #endif
33 
34 #ifdef HAVE_UCONTEXT_H
35 # include <ucontext.h>
36 #endif
37 
38 /* From src/main.c */
39 extern unsigned char is_master;
40 extern pid_t mpid;
41 extern int nodaemon;
42 
43 int have_dead_child = FALSE;
44 volatile unsigned int recvd_signal_flags = 0;
45 
46 static const char *trace_channel = "signal";
47 
48 static RETSIGTYPE sig_terminate(int);
49 static void install_stacktrace_handler(void);
50 
51 /* Used to capture an "unknown" signal value that causes termination. */
52 static int term_signo = 0;
53 
finish_terminate(int signo)54 static void finish_terminate(int signo) {
55   int reason_code = PR_SESS_DISCONNECT_SIGNAL;
56 
57   if (is_master &&
58       mpid == getpid()) {
59     PRIVS_ROOT
60 
61     /* Do not need the pidfile any longer. */
62     if (ServerType == SERVER_STANDALONE &&
63         !nodaemon) {
64       pr_pidfile_remove();
65     }
66 
67     /* Run any exit handlers registered in the master process here, so that
68      * they may have the benefit of root privs.  More than likely these
69      * exit handlers were registered by modules' module initialization
70      * functions, which also occur under root priv conditions.
71      *
72      * If an exit handler is registered after the fork(), it won't be run here;
73      * that registration occurs in a different process space.
74      */
75     pr_event_generate("core.exit", NULL);
76     pr_event_generate("core.shutdown", NULL);
77 
78     /* Remove the registered exit handlers now, so that the ensuing
79      * pr_session_end() call (outside the root privs condition) does not call
80      * the exit handlers for the master process again.
81      */
82     pr_event_unregister(NULL, "core.exit", NULL);
83     pr_event_unregister(NULL, "core.shutdown", NULL);
84 
85     PRIVS_RELINQUISH
86 
87     if (ServerType == SERVER_STANDALONE) {
88       pr_log_pri(PR_LOG_NOTICE, "ProFTPD " PROFTPD_VERSION_TEXT
89         " standalone mode SHUTDOWN");
90 
91       /* Clean up the scoreboard */
92       PRIVS_ROOT
93       pr_delete_scoreboard();
94       PRIVS_RELINQUISH
95     }
96   }
97 
98   if (signo == SIGSEGV) {
99     reason_code = PR_SESS_DISCONNECT_SEGFAULT;
100   }
101 
102   pr_session_disconnect(NULL, reason_code, "Killed by signal");
103 }
104 
handle_abort(void)105 static void handle_abort(void) {
106   pr_log_pri(PR_LOG_NOTICE, "ProFTPD received SIGABRT signal, no core dump");
107   finish_terminate(SIGABRT);
108 }
109 
handle_chld(void)110 static void handle_chld(void) {
111   sigset_t sig_set;
112   pid_t pid;
113 
114   sigemptyset(&sig_set);
115   sigaddset(&sig_set, SIGTERM);
116   sigaddset(&sig_set, SIGCHLD);
117 
118   pr_alarms_block();
119 
120   /* Block SIGTERM in here, so we don't create havoc with the child list
121    * while modifying it.
122    */
123   if (sigprocmask(SIG_BLOCK, &sig_set, NULL) < 0) {
124     pr_log_pri(PR_LOG_NOTICE,
125       "unable to block signal set: %s", strerror(errno));
126   }
127 
128   while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
129     if (child_remove(pid) == 0) {
130       have_dead_child = TRUE;
131     }
132   }
133 
134   if (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
135     pr_log_pri(PR_LOG_NOTICE,
136       "unable to unblock signal set: %s", strerror(errno));
137   }
138 
139   pr_alarms_unblock();
140 }
141 
handle_evnt(void)142 static void handle_evnt(void) {
143   pr_event_generate("core.signal.USR2", NULL);
144 }
145 
handle_terminate_with_kids(void)146 static void handle_terminate_with_kids(void) {
147   /* Do not log if we are a child that has been terminated. */
148   if (is_master == TRUE) {
149 
150     /* Send a SIGTERM to all our children */
151     if (child_count()) {
152       PRIVS_ROOT
153       child_signal(SIGTERM);
154       PRIVS_RELINQUISH
155     }
156 
157     pr_log_pri(PR_LOG_NOTICE, "ProFTPD killed (signal %d)", term_signo);
158   }
159 
160   finish_terminate(term_signo);
161 }
162 
handle_terminate_without_kids(void)163 static void handle_terminate_without_kids(void) {
164   pr_log_pri(PR_LOG_WARNING, "ProFTPD terminating (signal %d)", term_signo);
165   finish_terminate(term_signo);
166 }
167 
handle_stacktrace_signal(int signo,siginfo_t * info,void * ptr)168 static void handle_stacktrace_signal(int signo, siginfo_t *info, void *ptr) {
169 #ifdef HAVE_BACKTRACE
170   register int i;
171 # if defined(HAVE_UCONTEXT_H)
172   ucontext_t *uc = NULL;
173 # endif /* !HAVE_UCONTEXT_H */
174   void *trace[PR_TUNABLE_CALLER_DEPTH];
175   char **strings = NULL;
176   int tracesz;
177 #endif /* HAVE_BACKTRACE */
178 
179   /* Call the "normal" signal handler. */
180   table_handling_signal(TRUE);
181 
182   pr_log_pri(PR_LOG_ERR, "-----BEGIN STACK TRACE-----");
183 
184 #ifdef HAVE_BACKTRACE
185   tracesz = backtrace(trace, PR_TUNABLE_CALLER_DEPTH);
186   if (tracesz < 0) {
187     pr_log_pri(PR_LOG_ERR, "backtrace(3) error: %s", strerror(errno));
188   }
189 
190 # if defined(HAVE_UCONTEXT_H)
191   /* Overwrite sigaction with caller's address */
192   uc = (ucontext_t *) ptr;
193 #  if defined(REG_EIP)
194   trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];
195 #  elif defined(REG_RIP)
196   trace[1] = (void *) uc->uc_mcontext.gregs[REG_RIP];
197 #  endif
198 # endif /* !HAVE_UCONTEXT_H */
199 
200 # ifdef HAVE_BACKTRACE_SYMBOLS
201   strings = backtrace_symbols(trace, tracesz);
202   if (strings == NULL) {
203     pr_log_pri(PR_LOG_ERR, "backtrace_symbols(3) error: %s", strerror(errno));
204   }
205 # endif /* HAVE_BACKTRACE_SYMBOLS */
206 
207   if (strings != NULL) {
208     /* Skip first stack frame; it just points here. */
209     for (i = 1; i < tracesz; ++i) {
210       pr_log_pri(PR_LOG_ERR, "[%u] %s", i-1, strings[i]);
211     }
212   }
213 #else
214   pr_log_pri(PR_LOG_ERR, " backtrace(3) unavailable");
215 #endif /* HAVE_BACKTRACE */
216   pr_log_pri(PR_LOG_ERR, "-----END STACK TRACE-----");
217 
218   sig_terminate(signo);
219   finish_terminate(signo);
220 }
221 
handle_xcpu(void)222 static void handle_xcpu(void) {
223   pr_log_pri(PR_LOG_NOTICE, "ProFTPD CPU limit exceeded (signal %d)", SIGXCPU);
224   finish_terminate(SIGXCPU);
225 }
226 
227 #ifdef SIGXFSZ
handle_xfsz(void)228 static void handle_xfsz(void) {
229   pr_log_pri(PR_LOG_NOTICE, "ProFTPD File size limit exceeded (signal %d)",
230     SIGXFSZ);
231   finish_terminate(SIGXFSZ);
232 }
233 #endif /* SIGXFSZ */
234 
sig_child(int signo)235 static RETSIGTYPE sig_child(int signo) {
236   recvd_signal_flags |= RECEIVED_SIG_CHLD;
237 
238   /* We make an exception here to the synchronous processing that is done
239    * for other signals; SIGCHLD is handled asynchronously.  This is made
240    * necessary by two things.
241    *
242    * First, we need to support non-POSIX systems.  Under POSIX, once a
243    * signal handler has been configured for a given signal, that becomes
244    * that signal's disposition, until explicitly changed later.  Non-POSIX
245    * systems, on the other hand, will restore the default disposition of
246    * a signal after a custom signal handler has been configured.  Thus,
247    * to properly support non-POSIX systems, a call to signal(2) is necessary
248    * as one of the last steps in our signal handlers.
249    *
250    * Second, SVR4 systems differ specifically in their semantics of signal(2)
251    * and SIGCHLD.  These systems will check for any unhandled SIGCHLD
252    * signals, waiting to be reaped via wait(2) or waitpid(2), whenever
253    * the disposition of SIGCHLD is changed.  This means that if our process
254    * handles SIGCHLD, but does not call wait(2) or waitpid(2), and then
255    * calls signal(2), another SIGCHLD is generated; this loop repeats,
256    * until the process runs out of stack space and terminates.
257    *
258    * Thus, in order to cover this interaction, we'll need to call handle_chld()
259    * here, asynchronously.  handle_chld() does the work of reaping dead
260    * child processes, and does not seem to call any non-reentrant functions,
261    * so it should be safe.
262    */
263 
264   handle_chld();
265 
266   if (signal(SIGCHLD, sig_child) == SIG_ERR) {
267     pr_log_pri(PR_LOG_NOTICE,
268       "unable to install SIGCHLD (signal %d) handler: %s", SIGCHLD,
269       strerror(errno));
270   }
271 }
272 
273 #ifdef PR_DEVEL_COREDUMP
prepare_core(void)274 static char *prepare_core(void) {
275   static char dir[256];
276 
277   memset(dir, '\0', sizeof(dir));
278   pr_snprintf(dir, sizeof(dir)-1, "%s/proftpd-core-%lu", PR_CORE_DIR,
279     (unsigned long) getpid());
280 
281   if (mkdir(dir, 0700) < 0) {
282     pr_log_pri(PR_LOG_WARNING, "unable to create directory '%s' for "
283       "coredump: %s", dir, strerror(errno));
284 
285   } else {
286     chdir(dir);
287   }
288 
289   return dir;
290 }
291 #endif /* PR_DEVEL_COREDUMP */
292 
sig_abort(int signo)293 static RETSIGTYPE sig_abort(int signo) {
294   recvd_signal_flags |= RECEIVED_SIG_ABORT;
295 
296   if (signal(SIGABRT, SIG_DFL) == SIG_ERR) {
297     pr_log_pri(PR_LOG_NOTICE,
298       "unable to install SIGABRT (signal %d) handler: %s", SIGABRT,
299       strerror(errno));
300   }
301 
302 #ifdef PR_DEVEL_COREDUMP
303   pr_log_pri(PR_LOG_NOTICE, "ProFTPD received SIGABRT signal, generating core "
304     "file in %s", prepare_core());
305   pr_session_end(PR_SESS_END_FL_NOEXIT);
306   abort();
307 #endif /* PR_DEVEL_COREDUMP */
308 }
309 
sig_terminate(int signo)310 static RETSIGTYPE sig_terminate(int signo) {
311   const char *signame = "(unsupported)";
312   int log_signal = TRUE, log_stacktrace = TRUE;
313 
314   /* Capture the signal number for later display purposes. */
315   term_signo = signo;
316 
317   /* Some terminating signals get more special treatment than others. */
318 
319   switch (signo) {
320     case SIGSEGV:
321       recvd_signal_flags |= RECEIVED_SIG_SEGV;
322       signame = "SIGSEGV";
323       break;
324 
325     case SIGXCPU:
326       recvd_signal_flags |= RECEIVED_SIG_XCPU;
327       signame = "SIGXCPU";
328       break;
329 
330 #ifdef SIGXFSZ
331     case SIGXFSZ:
332       recvd_signal_flags |= RECEIVED_SIG_XFSZ;
333       signame = "SIGXFSZ";
334       break;
335 #endif /* SIGXFSZ */
336 
337     case SIGTERM:
338       /* Since SIGTERM is more common, we do not want to log as much for it. */
339       log_signal = log_stacktrace = FALSE;
340       recvd_signal_flags |= RECEIVED_SIG_TERMINATE;
341       signame = "SIGTERM";
342       break;
343 
344 #ifdef SIGBUS
345     case SIGBUS:
346       recvd_signal_flags |= RECEIVED_SIG_TERMINATE;
347       signame = "SIGBUS";
348       break;
349 #endif /* SIGBUS */
350 
351     case SIGILL:
352       recvd_signal_flags |= RECEIVED_SIG_TERMINATE;
353       signame = "SIGILL";
354       break;
355 
356     case SIGINT:
357       recvd_signal_flags |= RECEIVED_SIG_TERMINATE;
358       signame = "SIGINT";
359       break;
360 
361     default:
362       /* Note that we do NOT want to automatically set the
363        * RECEIVED_SIG_TERMINATE here by as a fallback for unspecified signals;
364        * that flag causes the daemon to terminate all of its child processes.
365        * And not every signal should have that effect; it's on a case-by-case
366        * basis.
367        */
368       break;
369   }
370 
371   if (log_signal == TRUE) {
372     /* This is probably not the safest thing to be doing, but since the
373      * process is terminating anyway, why not?  It helps when knowing/logging
374      * that a segfault (or other unusual event) happened.
375      */
376     pr_trace_msg(trace_channel, 9, "handling %s (signal %d)", signame, signo);
377     pr_log_pri(PR_LOG_NOTICE, "ProFTPD terminating (signal %d)", signo);
378 
379     if (!is_master) {
380       pr_log_pri(PR_LOG_INFO, "%s session closed.",
381         pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT));
382     }
383   }
384 
385   if (log_stacktrace == TRUE) {
386     install_stacktrace_handler();
387   }
388 
389   /* Ignore future occurrences of this signal; we'll be terminating anyway. */
390   if (signal(signo, SIG_IGN) == SIG_ERR) {
391     pr_log_pri(PR_LOG_NOTICE,
392       "unable to install handler for signal %d: %s", signo, strerror(errno));
393   }
394 }
395 
install_stacktrace_handler(void)396 static void install_stacktrace_handler(void) {
397   struct sigaction action;
398 
399   memset(&action, 0, sizeof(action));
400   action.sa_sigaction = handle_stacktrace_signal;
401   action.sa_flags = SA_SIGINFO;
402 
403   if (sigaction(SIGSEGV, &action, NULL) < 0) {
404     pr_log_pri(PR_LOG_NOTICE,
405       "unable to install SIGSEGV stacktrace signal handler: %s",
406       strerror(errno));
407   }
408 #ifdef SIGBUS
409   if (sigaction(SIGBUS, &action, NULL) < 0) {
410     pr_log_pri(PR_LOG_NOTICE,
411       "unable to install SIGBUS stacktrace signal handler: %s",
412       strerror(errno));
413   }
414 #endif /* SIGBUS */
415   if (sigaction(SIGXCPU, &action, NULL) < 0) {
416     pr_log_pri(PR_LOG_NOTICE,
417       "unable to install SIGXCPU stacktrace signal handler: %s",
418       strerror(errno));
419   }
420 }
421 
422 /* This function is to handle the dispatching of actions based on
423  * signals received by the signal handlers, to avoid signal handler-based
424  * race conditions.
425  */
pr_signals_handle(void)426 void pr_signals_handle(void) {
427   table_handling_signal(TRUE);
428 
429   if (errno == EINTR &&
430       PR_TUNABLE_EINTR_RETRY_INTERVAL > 0) {
431     struct timeval tv;
432     unsigned long interval_usecs = PR_TUNABLE_EINTR_RETRY_INTERVAL * 1000000;
433 
434     tv.tv_sec = (interval_usecs / 1000000);
435     tv.tv_usec = (interval_usecs - (tv.tv_sec * 1000000));
436 
437     pr_trace_msg(trace_channel, 18, "interrupted system call, "
438       "delaying for %lu %s, %lu %s",
439       (unsigned long) tv.tv_sec, tv.tv_sec != 1 ? "secs" : "sec",
440       (unsigned long) tv.tv_usec, tv.tv_usec != 1 ? "microsecs" : "microsec");
441 
442     pr_timer_usleep(interval_usecs);
443 
444     /* Clear the EINTR errno, now that we've dealt with it. */
445     errno = 0;
446   }
447 
448   while (recvd_signal_flags) {
449     if (recvd_signal_flags & RECEIVED_SIG_ALRM) {
450       recvd_signal_flags &= ~RECEIVED_SIG_ALRM;
451       pr_trace_msg(trace_channel, 9, "handling SIGALRM (signal %d)", SIGALRM);
452       handle_alarm();
453     }
454 
455     if (recvd_signal_flags & RECEIVED_SIG_CHLD) {
456       recvd_signal_flags &= ~RECEIVED_SIG_CHLD;
457       pr_trace_msg(trace_channel, 9, "handling SIGCHLD (signal %d)", SIGCHLD);
458       handle_chld();
459     }
460 
461     if (recvd_signal_flags & RECEIVED_SIG_EVENT) {
462       recvd_signal_flags &= ~RECEIVED_SIG_EVENT;
463 
464       /* The "event" signal is SIGUSR2 in proftpd. */
465       pr_trace_msg(trace_channel, 9, "handling SIGUSR2 (signal %d)", SIGUSR2);
466       handle_evnt();
467     }
468 
469     if (recvd_signal_flags & RECEIVED_SIG_SEGV) {
470       recvd_signal_flags &= ~RECEIVED_SIG_SEGV;
471       pr_trace_msg(trace_channel, 9, "handling SIGSEGV (signal %d)", SIGSEGV);
472       handle_terminate_without_kids();
473     }
474 
475     if (recvd_signal_flags & RECEIVED_SIG_TERMINATE) {
476       recvd_signal_flags &= ~RECEIVED_SIG_TERMINATE;
477       pr_trace_msg(trace_channel, 9, "handling signal %d", term_signo);
478       handle_terminate_with_kids();
479     }
480 
481     if (recvd_signal_flags & RECEIVED_SIG_XCPU) {
482       recvd_signal_flags &= ~RECEIVED_SIG_XCPU;
483       pr_trace_msg(trace_channel, 9, "handling SIGXCPU (signal %d)", SIGXCPU);
484       handle_xcpu();
485     }
486 
487 #ifdef SIGXFSZ
488     if (recvd_signal_flags & RECEIVED_SIG_XFSZ) {
489       recvd_signal_flags &= ~RECEIVED_SIG_XFSZ;
490       pr_trace_msg(trace_channel, 9, "handling SIGXFSZ (signal %d)", SIGXFSZ);
491       handle_xfsz();
492     }
493 #endif /* SIGXFSZ */
494 
495     if (recvd_signal_flags & RECEIVED_SIG_ABORT) {
496       recvd_signal_flags &= ~RECEIVED_SIG_ABORT;
497       pr_trace_msg(trace_channel, 9, "handling SIGABRT (signal %d)", SIGABRT);
498       handle_abort();
499     }
500 
501     if (recvd_signal_flags & RECEIVED_SIG_RESTART) {
502       recvd_signal_flags &= ~RECEIVED_SIG_RESTART;
503       pr_trace_msg(trace_channel, 9, "handling SIGHUP (signal %d)", SIGHUP);
504 
505       /* NOTE: should this be done here, rather than using a schedule? */
506       schedule(restart_daemon, 0, NULL, NULL, NULL, NULL);
507     }
508 
509     if (recvd_signal_flags & RECEIVED_SIG_EXIT) {
510       recvd_signal_flags &= ~RECEIVED_SIG_EXIT;
511       pr_trace_msg(trace_channel, 9, "handling SIGUSR1 (signal %d)", SIGUSR1);
512       pr_log_pri(PR_LOG_NOTICE, "%s", "Parent process requested shutdown");
513       pr_session_disconnect(NULL, PR_SESS_DISCONNECT_SERVER_SHUTDOWN, NULL);
514     }
515 
516     if (recvd_signal_flags & RECEIVED_SIG_SHUTDOWN) {
517       recvd_signal_flags &= ~RECEIVED_SIG_SHUTDOWN;
518       pr_trace_msg(trace_channel, 9, "handling SIGUSR1 (signal %d)", SIGUSR1);
519 
520       /* NOTE: should this be done here, rather than using a schedule? */
521       schedule(shutdown_end_session, 0, NULL, NULL, NULL, NULL);
522     }
523   }
524 
525   table_handling_signal(FALSE);
526 }
527 
528 /* sig_restart occurs in the master daemon when manually "kill -HUP"
529  * in order to re-read configuration files, and is sent to all
530  * children by the master.
531  */
sig_restart(int signo)532 static RETSIGTYPE sig_restart(int signo) {
533   recvd_signal_flags |= RECEIVED_SIG_RESTART;
534 
535   if (signal(SIGHUP, sig_restart) == SIG_ERR) {
536     pr_log_pri(PR_LOG_NOTICE,
537       "unable to install SIGHUP (signal %d) handler: %s", SIGHUP,
538       strerror(errno));
539   }
540 }
541 
542 /* pr_signals_handle_disconnect is called in children when the parent daemon
543  * detects that shutmsg has been created and that client sessions should be
544  * destroyed.  If a file transfer is underway, the process simply dies,
545  * otherwise a function is scheduled to attempt to display the shutdown reason.
546  */
pr_signals_handle_disconnect(int signo)547 RETSIGTYPE pr_signals_handle_disconnect(int signo) {
548 
549   /* If this is an anonymous session, or a transfer is in progress,
550    * perform the exit a little later...
551    */
552   if ((session.sf_flags & SF_ANON) ||
553       (session.sf_flags & SF_XFER)) {
554     recvd_signal_flags |= RECEIVED_SIG_EXIT;
555 
556   } else {
557     recvd_signal_flags |= RECEIVED_SIG_SHUTDOWN;
558   }
559 
560   if (signal(SIGUSR1, SIG_IGN) == SIG_ERR) {
561     pr_log_pri(PR_LOG_NOTICE,
562       "unable to install SIGUSR1 (signal %d) handler: %s", SIGUSR1,
563       strerror(errno));
564   }
565 }
566 
567 /* "Events", in this case, are SIGUSR2 signals. */
pr_signals_handle_event(int signo)568 RETSIGTYPE pr_signals_handle_event(int signo) {
569   recvd_signal_flags |= RECEIVED_SIG_EVENT;
570 
571   if (signal(SIGUSR2, pr_signals_handle_event) == SIG_ERR) {
572     pr_log_pri(PR_LOG_NOTICE,
573       "unable to install SIGUSR2 (signal %d) handler: %s", SIGUSR2,
574       strerror(errno));
575   }
576 }
577 
init_signals(void)578 int init_signals(void) {
579   sigset_t sig_set;
580 
581   /* Should the master server (only applicable in standalone mode)
582    * kill off children if we receive a signal that causes termination?
583    * Hmmmm... maybe this needs to be rethought, but I've done it in
584    * such a way as to only kill off our children if we receive a SIGTERM,
585    * meaning that the admin wants us dead (and probably our kids too).
586    */
587 
588   /* The sub-pool for the child list is created the first time we fork
589    * off a child.  To conserve memory, the pool and list is destroyed
590    * when our last child dies (to prevent the list from eating more and
591    * more memory on long uptimes).
592    */
593 
594   sigemptyset(&sig_set);
595 
596   sigaddset(&sig_set, SIGCHLD);
597   sigaddset(&sig_set, SIGINT);
598   sigaddset(&sig_set, SIGQUIT);
599   sigaddset(&sig_set, SIGILL);
600   sigaddset(&sig_set, SIGABRT);
601   sigaddset(&sig_set, SIGFPE);
602   sigaddset(&sig_set, SIGSEGV);
603   sigaddset(&sig_set, SIGALRM);
604   sigaddset(&sig_set, SIGTERM);
605   sigaddset(&sig_set, SIGHUP);
606   sigaddset(&sig_set, SIGUSR2);
607 #ifdef SIGSTKFLT
608   sigaddset(&sig_set, SIGSTKFLT);
609 #endif /* SIGSTKFLT */
610 #ifdef SIGIO
611   sigaddset(&sig_set, SIGIO);
612 #endif /* SIGIO */
613 #ifdef SIGBUS
614   sigaddset(&sig_set, SIGBUS);
615 #endif /* SIGBUS */
616 
617   if (signal(SIGCHLD, sig_child) == SIG_ERR) {
618     pr_log_pri(PR_LOG_NOTICE,
619       "unable to install SIGCHLD (signal %d) handler: %s", SIGCHLD,
620       strerror(errno));
621   }
622 
623   if (signal(SIGHUP, sig_restart) == SIG_ERR) {
624     pr_log_pri(PR_LOG_NOTICE,
625       "unable to install SIGHUP (signal %d) handler: %s", SIGHUP,
626       strerror(errno));
627   }
628 
629   if (signal(SIGINT, sig_terminate) == SIG_ERR) {
630     pr_log_pri(PR_LOG_NOTICE,
631       "unable to install SIGINT (signal %d) handler: %s", SIGINT,
632       strerror(errno));
633   }
634 
635   if (signal(SIGQUIT, sig_terminate) == SIG_ERR) {
636     pr_log_pri(PR_LOG_NOTICE,
637       "unable to install SIGQUIT (signal %d) handler: %s", SIGQUIT,
638       strerror(errno));
639   }
640 
641   if (signal(SIGILL, sig_terminate) == SIG_ERR) {
642     pr_log_pri(PR_LOG_NOTICE,
643       "unable to install SIGILL (signal %d) handler: %s", SIGILL,
644       strerror(errno));
645   }
646 
647   if (signal(SIGFPE, sig_terminate) == SIG_ERR) {
648     pr_log_pri(PR_LOG_NOTICE,
649       "unable to install SIGFPE (signal %d) handler: %s", SIGFPE,
650       strerror(errno));
651   }
652 
653 #ifdef SIGXFSZ
654   if (signal(SIGXFSZ, sig_terminate) == SIG_ERR) {
655     pr_log_pri(PR_LOG_NOTICE,
656       "unable to install SIGXFSZ (signal %d) handler: %s", SIGXFSZ,
657       strerror(errno));
658   }
659 #endif /* SIGXFSZ */
660 
661   if (signal(SIGABRT, sig_abort) == SIG_ERR) {
662     pr_log_pri(PR_LOG_NOTICE,
663       "unable to install SIGABRT (signal %d) handler: %s", SIGABRT,
664       strerror(errno));
665   }
666 
667   /* Installs stacktrace handlers for SIGSEGV, SIGXCPU, and SIGBUS. */
668   install_stacktrace_handler();
669 
670   /* Ignore SIGALRM; this will be changed when a timer is registered. But
671    * this will prevent SIGALRMs from killing us if we don't currently have
672    * any timers registered.
673     */
674   if (signal(SIGALRM, SIG_IGN) == SIG_ERR) {
675     pr_log_pri(PR_LOG_NOTICE,
676       "unable to install SIGALRM (signal %d) handler: %s", SIGALRM,
677       strerror(errno));
678   }
679 
680   if (signal(SIGTERM, sig_terminate) == SIG_ERR) {
681     pr_log_pri(PR_LOG_NOTICE,
682       "unable to install SIGTERM (signal %d) handler: %s", SIGTERM,
683       strerror(errno));
684   }
685 
686   if (signal(SIGURG, SIG_IGN) == SIG_ERR) {
687     pr_log_pri(PR_LOG_NOTICE,
688       "unable to install SIGURG (signal %d) handler: %s", SIGURG,
689       strerror(errno));
690   }
691 
692 #ifdef SIGSTKFLT
693   if (signal(SIGSTKFLT, sig_terminate) == SIG_ERR) {
694     pr_log_pri(PR_LOG_NOTICE,
695       "unable to install SIGSTKFLT (signal %d) handler: %s", SIGSTKFLT,
696       strerror(errno));
697   }
698 #endif /* SIGSTKFLT */
699 
700 #ifdef SIGIO
701   if (signal(SIGIO, SIG_IGN) == SIG_ERR) {
702     pr_log_pri(PR_LOG_NOTICE,
703       "unable to install SIGIO (signal %d) handler: %s", SIGIO,
704       strerror(errno));
705   }
706 #endif /* SIGIO */
707 
708   if (signal(SIGUSR2, pr_signals_handle_event) == SIG_ERR) {
709     pr_log_pri(PR_LOG_NOTICE,
710       "unable to install SIGUSR2 (signal %d) handler: %s", SIGUSR2,
711       strerror(errno));
712   }
713 
714   /* In case our parent left signals blocked (as happens under some
715    * poor inetd implementations)
716    */
717   if (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
718     pr_log_pri(PR_LOG_NOTICE,
719       "unable to block signal set: %s", strerror(errno));
720   }
721 
722   return 0;
723 }
724