xref: /freebsd-src/contrib/sendmail/libmilter/signal.c (revision b5ff185e19f6013ca565b2a15bc2d6abce933f46)
106f25ae9SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro  *  Copyright (c) 1999-2004, 2006 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
406f25ae9SGregory Neil Shapiro  *
506f25ae9SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
606f25ae9SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
706f25ae9SGregory Neil Shapiro  * the sendmail distribution.
806f25ae9SGregory Neil Shapiro  *
906f25ae9SGregory Neil Shapiro  */
1006f25ae9SGregory Neil Shapiro 
1140266059SGregory Neil Shapiro #include <sm/gen.h>
124313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: signal.c,v 8.45 2013-11-22 20:51:36 ca Exp $")
1306f25ae9SGregory Neil Shapiro 
1406f25ae9SGregory Neil Shapiro #include "libmilter.h"
1506f25ae9SGregory Neil Shapiro 
1606f25ae9SGregory Neil Shapiro /*
1706f25ae9SGregory Neil Shapiro **  thread to handle signals
1806f25ae9SGregory Neil Shapiro */
1906f25ae9SGregory Neil Shapiro 
2006f25ae9SGregory Neil Shapiro static smutex_t M_Mutex;
2106f25ae9SGregory Neil Shapiro 
2206f25ae9SGregory Neil Shapiro static int MilterStop = MILTER_CONT;
2306f25ae9SGregory Neil Shapiro 
24b6bacd31SGregory Neil Shapiro static void	*mi_signal_thread __P((void *));
25b6bacd31SGregory Neil Shapiro static int	 mi_spawn_signal_thread __P((char *));
26b6bacd31SGregory Neil Shapiro 
2740266059SGregory Neil Shapiro /*
2806f25ae9SGregory Neil Shapiro **  MI_STOP -- return value of MilterStop
2906f25ae9SGregory Neil Shapiro **
3006f25ae9SGregory Neil Shapiro **	Parameters:
3106f25ae9SGregory Neil Shapiro **		none.
3206f25ae9SGregory Neil Shapiro **
3306f25ae9SGregory Neil Shapiro **	Returns:
3406f25ae9SGregory Neil Shapiro **		value of MilterStop
3506f25ae9SGregory Neil Shapiro */
3606f25ae9SGregory Neil Shapiro 
3706f25ae9SGregory Neil Shapiro int
mi_stop()3806f25ae9SGregory Neil Shapiro mi_stop()
3906f25ae9SGregory Neil Shapiro {
4006f25ae9SGregory Neil Shapiro 	return MilterStop;
4106f25ae9SGregory Neil Shapiro }
4240266059SGregory Neil Shapiro /*
4306f25ae9SGregory Neil Shapiro **  MI_STOP_MILTERS -- set value of MilterStop
4406f25ae9SGregory Neil Shapiro **
4506f25ae9SGregory Neil Shapiro **	Parameters:
4606f25ae9SGregory Neil Shapiro **		v -- new value for MilterStop.
4706f25ae9SGregory Neil Shapiro **
4806f25ae9SGregory Neil Shapiro **	Returns:
4906f25ae9SGregory Neil Shapiro **		none.
5006f25ae9SGregory Neil Shapiro */
5106f25ae9SGregory Neil Shapiro 
5206f25ae9SGregory Neil Shapiro void
mi_stop_milters(v)5306f25ae9SGregory Neil Shapiro mi_stop_milters(v)
5406f25ae9SGregory Neil Shapiro 	int v;
5506f25ae9SGregory Neil Shapiro {
5606f25ae9SGregory Neil Shapiro 	(void) smutex_lock(&M_Mutex);
5706f25ae9SGregory Neil Shapiro 	if (MilterStop < v)
5806f25ae9SGregory Neil Shapiro 		MilterStop = v;
5942e5d165SGregory Neil Shapiro 
6042e5d165SGregory Neil Shapiro 	/* close listen socket */
6142e5d165SGregory Neil Shapiro 	mi_closener();
6206f25ae9SGregory Neil Shapiro 	(void) smutex_unlock(&M_Mutex);
6306f25ae9SGregory Neil Shapiro }
6440266059SGregory Neil Shapiro /*
6506f25ae9SGregory Neil Shapiro **  MI_CLEAN_SIGNALS -- clean up signal handler thread
6606f25ae9SGregory Neil Shapiro **
6706f25ae9SGregory Neil Shapiro **	Parameters:
6806f25ae9SGregory Neil Shapiro **		none.
6906f25ae9SGregory Neil Shapiro **
7006f25ae9SGregory Neil Shapiro **	Returns:
7106f25ae9SGregory Neil Shapiro **		none.
7206f25ae9SGregory Neil Shapiro */
7306f25ae9SGregory Neil Shapiro 
7406f25ae9SGregory Neil Shapiro void
mi_clean_signals()7506f25ae9SGregory Neil Shapiro mi_clean_signals()
7606f25ae9SGregory Neil Shapiro {
7706f25ae9SGregory Neil Shapiro 	(void) smutex_destroy(&M_Mutex);
7806f25ae9SGregory Neil Shapiro }
7940266059SGregory Neil Shapiro /*
8006f25ae9SGregory Neil Shapiro **  MI_SIGNAL_THREAD -- thread to deal with signals
8106f25ae9SGregory Neil Shapiro **
8206f25ae9SGregory Neil Shapiro **	Parameters:
8306f25ae9SGregory Neil Shapiro **		name -- name of milter
8406f25ae9SGregory Neil Shapiro **
8506f25ae9SGregory Neil Shapiro **	Returns:
8606f25ae9SGregory Neil Shapiro **		NULL
8706f25ae9SGregory Neil Shapiro */
8806f25ae9SGregory Neil Shapiro 
8906f25ae9SGregory Neil Shapiro static void *
mi_signal_thread(name)9006f25ae9SGregory Neil Shapiro mi_signal_thread(name)
9106f25ae9SGregory Neil Shapiro 	void *name;
9206f25ae9SGregory Neil Shapiro {
934e4196cbSGregory Neil Shapiro 	int sig, errs, sigerr;
9406f25ae9SGregory Neil Shapiro 	sigset_t set;
9506f25ae9SGregory Neil Shapiro 
96a7ec597cSGregory Neil Shapiro 	(void) sigemptyset(&set);
97a7ec597cSGregory Neil Shapiro 	(void) sigaddset(&set, SIGHUP);
98a7ec597cSGregory Neil Shapiro 	(void) sigaddset(&set, SIGTERM);
9906f25ae9SGregory Neil Shapiro 
10006f25ae9SGregory Neil Shapiro 	/* Handle Ctrl-C gracefully for debugging */
101a7ec597cSGregory Neil Shapiro 	(void) sigaddset(&set, SIGINT);
10206f25ae9SGregory Neil Shapiro 	errs = 0;
10306f25ae9SGregory Neil Shapiro 
104a7ec597cSGregory Neil Shapiro 	for (;;)
10506f25ae9SGregory Neil Shapiro 	{
1064e4196cbSGregory Neil Shapiro 		sigerr = sig = 0;
107*da7d7b9cSGregory Neil Shapiro #if SIGWAIT_TAKES_1_ARG
10806f25ae9SGregory Neil Shapiro 		if ((sig = sigwait(&set)) < 0)
109*da7d7b9cSGregory Neil Shapiro #else
1104e4196cbSGregory Neil Shapiro 		if ((sigerr = sigwait(&set, &sig)) != 0)
111*da7d7b9cSGregory Neil Shapiro #endif
11206f25ae9SGregory Neil Shapiro 		{
1134e4196cbSGregory Neil Shapiro 			/* some OS return -1 and set errno: copy it */
1144e4196cbSGregory Neil Shapiro 			if (sigerr <= 0)
1154e4196cbSGregory Neil Shapiro 				sigerr = errno;
1164e4196cbSGregory Neil Shapiro 
11713bd1963SGregory Neil Shapiro 			/* this can happen on OSF/1 (at least) */
1184e4196cbSGregory Neil Shapiro 			if (sigerr == EINTR)
11913bd1963SGregory Neil Shapiro 				continue;
12006f25ae9SGregory Neil Shapiro 			smi_log(SMI_LOG_ERR,
12140266059SGregory Neil Shapiro 				"%s: sigwait returned error: %d",
1224e4196cbSGregory Neil Shapiro 				(char *)name, sigerr);
12306f25ae9SGregory Neil Shapiro 			if (++errs > MAX_FAILS_T)
12406f25ae9SGregory Neil Shapiro 			{
12506f25ae9SGregory Neil Shapiro 				mi_stop_milters(MILTER_ABRT);
12606f25ae9SGregory Neil Shapiro 				return NULL;
12706f25ae9SGregory Neil Shapiro 			}
12806f25ae9SGregory Neil Shapiro 			continue;
12906f25ae9SGregory Neil Shapiro 		}
13006f25ae9SGregory Neil Shapiro 		errs = 0;
13106f25ae9SGregory Neil Shapiro 
13206f25ae9SGregory Neil Shapiro 		switch (sig)
13306f25ae9SGregory Neil Shapiro 		{
13406f25ae9SGregory Neil Shapiro 		  case SIGHUP:
13506f25ae9SGregory Neil Shapiro 		  case SIGTERM:
13606f25ae9SGregory Neil Shapiro 			mi_stop_milters(MILTER_STOP);
13706f25ae9SGregory Neil Shapiro 			return NULL;
13806f25ae9SGregory Neil Shapiro 		  case SIGINT:
13906f25ae9SGregory Neil Shapiro 			mi_stop_milters(MILTER_ABRT);
14006f25ae9SGregory Neil Shapiro 			return NULL;
14106f25ae9SGregory Neil Shapiro 		  default:
14206f25ae9SGregory Neil Shapiro 			smi_log(SMI_LOG_ERR,
14306f25ae9SGregory Neil Shapiro 				"%s: sigwait returned unmasked signal: %d",
14406f25ae9SGregory Neil Shapiro 				(char *)name, sig);
14506f25ae9SGregory Neil Shapiro 			break;
14606f25ae9SGregory Neil Shapiro 		}
14706f25ae9SGregory Neil Shapiro 	}
148a7ec597cSGregory Neil Shapiro 	/* NOTREACHED */
14906f25ae9SGregory Neil Shapiro }
15040266059SGregory Neil Shapiro /*
15106f25ae9SGregory Neil Shapiro **  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
15206f25ae9SGregory Neil Shapiro **
15306f25ae9SGregory Neil Shapiro **	Parameters:
15406f25ae9SGregory Neil Shapiro **		name -- name of milter
15506f25ae9SGregory Neil Shapiro **
15606f25ae9SGregory Neil Shapiro **	Returns:
15706f25ae9SGregory Neil Shapiro **		MI_SUCCESS/MI_FAILURE
15806f25ae9SGregory Neil Shapiro */
15906f25ae9SGregory Neil Shapiro 
16006f25ae9SGregory Neil Shapiro static int
mi_spawn_signal_thread(name)16106f25ae9SGregory Neil Shapiro mi_spawn_signal_thread(name)
16206f25ae9SGregory Neil Shapiro 	char *name;
16306f25ae9SGregory Neil Shapiro {
16406f25ae9SGregory Neil Shapiro 	sthread_t tid;
16540266059SGregory Neil Shapiro 	int r;
16606f25ae9SGregory Neil Shapiro 	sigset_t set;
16706f25ae9SGregory Neil Shapiro 
16806f25ae9SGregory Neil Shapiro 	/* Mask HUP and KILL signals */
169a7ec597cSGregory Neil Shapiro 	(void) sigemptyset(&set);
170a7ec597cSGregory Neil Shapiro 	(void) sigaddset(&set, SIGHUP);
171a7ec597cSGregory Neil Shapiro 	(void) sigaddset(&set, SIGTERM);
172a7ec597cSGregory Neil Shapiro 	(void) sigaddset(&set, SIGINT);
17306f25ae9SGregory Neil Shapiro 
17406f25ae9SGregory Neil Shapiro 	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
17506f25ae9SGregory Neil Shapiro 	{
17606f25ae9SGregory Neil Shapiro 		smi_log(SMI_LOG_ERR,
17706f25ae9SGregory Neil Shapiro 			"%s: Couldn't mask HUP and KILL signals", name);
17806f25ae9SGregory Neil Shapiro 		return MI_FAILURE;
17906f25ae9SGregory Neil Shapiro 	}
18040266059SGregory Neil Shapiro 	r = thread_create(&tid, mi_signal_thread, (void *)name);
18140266059SGregory Neil Shapiro 	if (r != 0)
18206f25ae9SGregory Neil Shapiro 	{
18306f25ae9SGregory Neil Shapiro 		smi_log(SMI_LOG_ERR,
18440266059SGregory Neil Shapiro 			"%s: Couldn't start signal thread: %d",
18540266059SGregory Neil Shapiro 			name, r);
18606f25ae9SGregory Neil Shapiro 		return MI_FAILURE;
18706f25ae9SGregory Neil Shapiro 	}
18806f25ae9SGregory Neil Shapiro 	return MI_SUCCESS;
18906f25ae9SGregory Neil Shapiro }
19040266059SGregory Neil Shapiro /*
19106f25ae9SGregory Neil Shapiro **  MI_CONTROL_STARTUP -- startup for thread to handle signals
19206f25ae9SGregory Neil Shapiro **
19306f25ae9SGregory Neil Shapiro **	Parameters:
19406f25ae9SGregory Neil Shapiro **		name -- name of milter
19506f25ae9SGregory Neil Shapiro **
19606f25ae9SGregory Neil Shapiro **	Returns:
19706f25ae9SGregory Neil Shapiro **		MI_SUCCESS/MI_FAILURE
19806f25ae9SGregory Neil Shapiro */
19906f25ae9SGregory Neil Shapiro 
20006f25ae9SGregory Neil Shapiro int
mi_control_startup(name)20106f25ae9SGregory Neil Shapiro mi_control_startup(name)
20206f25ae9SGregory Neil Shapiro 	char *name;
20306f25ae9SGregory Neil Shapiro {
20406f25ae9SGregory Neil Shapiro 
20506f25ae9SGregory Neil Shapiro 	if (!smutex_init(&M_Mutex))
20606f25ae9SGregory Neil Shapiro 	{
20706f25ae9SGregory Neil Shapiro 		smi_log(SMI_LOG_ERR,
20806f25ae9SGregory Neil Shapiro 			"%s: Couldn't initialize control pipe mutex", name);
20906f25ae9SGregory Neil Shapiro 		return MI_FAILURE;
21006f25ae9SGregory Neil Shapiro 	}
21106f25ae9SGregory Neil Shapiro 
21206f25ae9SGregory Neil Shapiro 	/*
21306f25ae9SGregory Neil Shapiro 	**  spawn_signal_thread must happen before other threads are spawned
21406f25ae9SGregory Neil Shapiro 	**  off so that it can mask the right signals and other threads
21506f25ae9SGregory Neil Shapiro 	**  will inherit that mask.
21606f25ae9SGregory Neil Shapiro 	*/
21706f25ae9SGregory Neil Shapiro 	if (mi_spawn_signal_thread(name) == MI_FAILURE)
21806f25ae9SGregory Neil Shapiro 	{
21906f25ae9SGregory Neil Shapiro 		smi_log(SMI_LOG_ERR,
22006f25ae9SGregory Neil Shapiro 			"%s: Couldn't spawn signal thread", name);
22106f25ae9SGregory Neil Shapiro 		(void) smutex_destroy(&M_Mutex);
22206f25ae9SGregory Neil Shapiro 		return MI_FAILURE;
22306f25ae9SGregory Neil Shapiro 	}
22406f25ae9SGregory Neil Shapiro 	return MI_SUCCESS;
22506f25ae9SGregory Neil Shapiro }
226