4e4196cb74
Security: FreeBSD-SA-06:13.sendmail
341 lines
7.0 KiB
C
341 lines
7.0 KiB
C
/*
|
|
* Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
|
|
* All rights reserved.
|
|
*
|
|
* By using this file, you agree to the terms and conditions set
|
|
* forth in the LICENSE file which can be found at the top level of
|
|
* the sendmail distribution.
|
|
*/
|
|
|
|
#include <sm/gen.h>
|
|
SM_RCSID("@(#)$Id: signal.c,v 1.17 2005/06/14 23:07:20 ca Exp $")
|
|
|
|
#if SM_CONF_SETITIMER
|
|
# include <sm/time.h>
|
|
#endif /* SM_CONF_SETITIMER */
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <sm/clock.h>
|
|
#include <sm/signal.h>
|
|
#include <signal.h>
|
|
#include <sm/string.h>
|
|
|
|
unsigned int volatile InCriticalSection; /* >0 if inside critical section */
|
|
int volatile PendingSignal; /* pending signal to resend */
|
|
|
|
/*
|
|
** SM_SIGNAL -- set a signal handler
|
|
**
|
|
** This is essentially old BSD "signal(3)".
|
|
**
|
|
** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
|
|
** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
|
|
** DOING.
|
|
*/
|
|
|
|
sigfunc_t
|
|
sm_signal(sig, handler)
|
|
int sig;
|
|
sigfunc_t handler;
|
|
{
|
|
# if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
|
|
struct sigaction n, o;
|
|
# endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */
|
|
|
|
/*
|
|
** First, try for modern signal calls
|
|
** and restartable syscalls
|
|
*/
|
|
|
|
# ifdef SA_RESTART
|
|
(void) memset(&n, '\0', sizeof n);
|
|
# if USE_SA_SIGACTION
|
|
n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
|
|
n.sa_flags = SA_RESTART|SA_SIGINFO;
|
|
# else /* USE_SA_SIGACTION */
|
|
n.sa_handler = handler;
|
|
n.sa_flags = SA_RESTART;
|
|
# endif /* USE_SA_SIGACTION */
|
|
if (sigaction(sig, &n, &o) < 0)
|
|
return SIG_ERR;
|
|
return o.sa_handler;
|
|
# else /* SA_RESTART */
|
|
|
|
/*
|
|
** Else check for SYS5SIGNALS or
|
|
** BSD4_3 signals
|
|
*/
|
|
|
|
# if defined(SYS5SIGNALS) || defined(BSD4_3)
|
|
# ifdef BSD4_3
|
|
return signal(sig, handler);
|
|
# else /* BSD4_3 */
|
|
return sigset(sig, handler);
|
|
# endif /* BSD4_3 */
|
|
# else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
|
|
|
|
/*
|
|
** Finally, if nothing else is available,
|
|
** go for a default
|
|
*/
|
|
|
|
(void) memset(&n, '\0', sizeof n);
|
|
n.sa_handler = handler;
|
|
if (sigaction(sig, &n, &o) < 0)
|
|
return SIG_ERR;
|
|
return o.sa_handler;
|
|
# endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
|
|
# endif /* SA_RESTART */
|
|
}
|
|
/*
|
|
** SM_BLOCKSIGNAL -- hold a signal to prevent delivery
|
|
**
|
|
** Parameters:
|
|
** sig -- the signal to block.
|
|
**
|
|
** Returns:
|
|
** 1 signal was previously blocked
|
|
** 0 signal was not previously blocked
|
|
** -1 on failure.
|
|
*/
|
|
|
|
int
|
|
sm_blocksignal(sig)
|
|
int sig;
|
|
{
|
|
# ifdef BSD4_3
|
|
# ifndef sigmask
|
|
# define sigmask(s) (1 << ((s) - 1))
|
|
# endif /* ! sigmask */
|
|
return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
|
|
# else /* BSD4_3 */
|
|
# ifdef ALTOS_SYSTEM_V
|
|
sigfunc_t handler;
|
|
|
|
handler = sigset(sig, SIG_HOLD);
|
|
if (handler == SIG_ERR)
|
|
return -1;
|
|
else
|
|
return handler == SIG_HOLD;
|
|
# else /* ALTOS_SYSTEM_V */
|
|
sigset_t sset, oset;
|
|
|
|
(void) sigemptyset(&sset);
|
|
(void) sigaddset(&sset, sig);
|
|
if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
|
|
return -1;
|
|
else
|
|
return sigismember(&oset, sig);
|
|
# endif /* ALTOS_SYSTEM_V */
|
|
# endif /* BSD4_3 */
|
|
}
|
|
/*
|
|
** SM_RELEASESIGNAL -- release a held signal
|
|
**
|
|
** Parameters:
|
|
** sig -- the signal to release.
|
|
**
|
|
** Returns:
|
|
** 1 signal was previously blocked
|
|
** 0 signal was not previously blocked
|
|
** -1 on failure.
|
|
*/
|
|
|
|
int
|
|
sm_releasesignal(sig)
|
|
int sig;
|
|
{
|
|
# ifdef BSD4_3
|
|
return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
|
|
# else /* BSD4_3 */
|
|
# ifdef ALTOS_SYSTEM_V
|
|
sigfunc_t handler;
|
|
|
|
handler = sigset(sig, SIG_HOLD);
|
|
if (sigrelse(sig) < 0)
|
|
return -1;
|
|
else
|
|
return handler == SIG_HOLD;
|
|
# else /* ALTOS_SYSTEM_V */
|
|
sigset_t sset, oset;
|
|
|
|
(void) sigemptyset(&sset);
|
|
(void) sigaddset(&sset, sig);
|
|
if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
|
|
return -1;
|
|
else
|
|
return sigismember(&oset, sig);
|
|
# endif /* ALTOS_SYSTEM_V */
|
|
# endif /* BSD4_3 */
|
|
}
|
|
/*
|
|
** PEND_SIGNAL -- Add a signal to the pending signal list
|
|
**
|
|
** Parameters:
|
|
** sig -- signal to add
|
|
**
|
|
** Returns:
|
|
** none.
|
|
**
|
|
** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
|
|
** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
|
|
** DOING.
|
|
*/
|
|
|
|
void
|
|
pend_signal(sig)
|
|
int sig;
|
|
{
|
|
int sigbit;
|
|
int save_errno = errno;
|
|
#if SM_CONF_SETITIMER
|
|
struct itimerval clr;
|
|
#endif /* SM_CONF_SETITIMER */
|
|
|
|
/*
|
|
** Don't want to interrupt something critical, hence delay
|
|
** the alarm for one second. Hopefully, by then we
|
|
** will be out of the critical section. If not, then
|
|
** we will just delay again. The events to be run will
|
|
** still all be run, maybe just a little bit late.
|
|
*/
|
|
|
|
switch (sig)
|
|
{
|
|
case SIGHUP:
|
|
sigbit = PEND_SIGHUP;
|
|
break;
|
|
|
|
case SIGINT:
|
|
sigbit = PEND_SIGINT;
|
|
break;
|
|
|
|
case SIGTERM:
|
|
sigbit = PEND_SIGTERM;
|
|
break;
|
|
|
|
case SIGUSR1:
|
|
sigbit = PEND_SIGUSR1;
|
|
break;
|
|
|
|
case SIGALRM:
|
|
/* don't have to pend these */
|
|
sigbit = 0;
|
|
break;
|
|
|
|
default:
|
|
/* If we get here, we are in trouble */
|
|
abort();
|
|
|
|
/* NOTREACHED */
|
|
/* shut up stupid compiler warning on HP-UX 11 */
|
|
sigbit = 0;
|
|
break;
|
|
}
|
|
|
|
if (sigbit != 0)
|
|
PendingSignal |= sigbit;
|
|
(void) sm_signal(SIGALRM, sm_tick);
|
|
#if SM_CONF_SETITIMER
|
|
clr.it_interval.tv_sec = 0;
|
|
clr.it_interval.tv_usec = 0;
|
|
clr.it_value.tv_sec = 1;
|
|
clr.it_value.tv_usec = 0;
|
|
(void) setitimer(ITIMER_REAL, &clr, NULL);
|
|
#else /* SM_CONF_SETITIMER */
|
|
(void) alarm(1);
|
|
#endif /* SM_CONF_SETITIMER */
|
|
errno = save_errno;
|
|
}
|
|
/*
|
|
** SM_ALLSIGNALS -- act on all signals
|
|
**
|
|
** Parameters:
|
|
** block -- whether to block or release all signals.
|
|
**
|
|
** Returns:
|
|
** none.
|
|
*/
|
|
|
|
void
|
|
sm_allsignals(block)
|
|
bool block;
|
|
{
|
|
# ifdef BSD4_3
|
|
# ifndef sigmask
|
|
# define sigmask(s) (1 << ((s) - 1))
|
|
# endif /* ! sigmask */
|
|
if (block)
|
|
{
|
|
int mask = 0;
|
|
|
|
mask |= sigmask(SIGALRM);
|
|
mask |= sigmask(SIGCHLD);
|
|
mask |= sigmask(SIGHUP);
|
|
mask |= sigmask(SIGINT);
|
|
mask |= sigmask(SIGTERM);
|
|
mask |= sigmask(SIGUSR1);
|
|
|
|
(void) sigblock(mask);
|
|
}
|
|
else
|
|
sigsetmask(0);
|
|
# else /* BSD4_3 */
|
|
# ifdef ALTOS_SYSTEM_V
|
|
if (block)
|
|
{
|
|
(void) sigset(SIGALRM, SIG_HOLD);
|
|
(void) sigset(SIGCHLD, SIG_HOLD);
|
|
(void) sigset(SIGHUP, SIG_HOLD);
|
|
(void) sigset(SIGINT, SIG_HOLD);
|
|
(void) sigset(SIGTERM, SIG_HOLD);
|
|
(void) sigset(SIGUSR1, SIG_HOLD);
|
|
}
|
|
else
|
|
{
|
|
(void) sigset(SIGALRM, SIG_DFL);
|
|
(void) sigset(SIGCHLD, SIG_DFL);
|
|
(void) sigset(SIGHUP, SIG_DFL);
|
|
(void) sigset(SIGINT, SIG_DFL);
|
|
(void) sigset(SIGTERM, SIG_DFL);
|
|
(void) sigset(SIGUSR1, SIG_DFL);
|
|
}
|
|
# else /* ALTOS_SYSTEM_V */
|
|
sigset_t sset;
|
|
|
|
(void) sigemptyset(&sset);
|
|
(void) sigaddset(&sset, SIGALRM);
|
|
(void) sigaddset(&sset, SIGCHLD);
|
|
(void) sigaddset(&sset, SIGHUP);
|
|
(void) sigaddset(&sset, SIGINT);
|
|
(void) sigaddset(&sset, SIGTERM);
|
|
(void) sigaddset(&sset, SIGUSR1);
|
|
(void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
|
|
# endif /* ALTOS_SYSTEM_V */
|
|
# endif /* BSD4_3 */
|
|
}
|
|
/*
|
|
** SM_SIGNAL_NOOP -- A signal no-op function
|
|
**
|
|
** Parameters:
|
|
** sig -- signal received
|
|
**
|
|
** Returns:
|
|
** SIGFUNC_RETURN
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
SIGFUNC_DECL
|
|
sm_signal_noop(sig)
|
|
int sig;
|
|
{
|
|
int save_errno = errno;
|
|
|
|
FIX_SYSV_SIGNAL(sig, sm_signal_noop);
|
|
errno = save_errno;
|
|
return SIGFUNC_RETURN;
|
|
}
|
|
|