164562Sgshapiro/*
2261194Sgshapiro *  Copyright (c) 1999-2004, 2006 Proofpoint, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
464562Sgshapiro *
564562Sgshapiro * By using this file, you agree to the terms and conditions set
664562Sgshapiro * forth in the LICENSE file which can be found at the top level of
764562Sgshapiro * the sendmail distribution.
864562Sgshapiro *
964562Sgshapiro */
1064562Sgshapiro
1190792Sgshapiro#include <sm/gen.h>
12266527SgshapiroSM_RCSID("@(#)$Id: signal.c,v 8.45 2013-11-22 20:51:36 ca Exp $")
1364562Sgshapiro
1464562Sgshapiro#include "libmilter.h"
1564562Sgshapiro
1664562Sgshapiro/*
1766494Sgshapiro**  thread to handle signals
1864562Sgshapiro*/
1964562Sgshapiro
2064562Sgshapirostatic smutex_t M_Mutex;
2164562Sgshapiro
2264562Sgshapirostatic int MilterStop = MILTER_CONT;
2364562Sgshapiro
24141858Sgshapirostatic void	*mi_signal_thread __P((void *));
25141858Sgshapirostatic int	 mi_spawn_signal_thread __P((char *));
26141858Sgshapiro
2790792Sgshapiro/*
2864562Sgshapiro**  MI_STOP -- return value of MilterStop
2964562Sgshapiro**
3064562Sgshapiro**	Parameters:
3164562Sgshapiro**		none.
3264562Sgshapiro**
3364562Sgshapiro**	Returns:
3464562Sgshapiro**		value of MilterStop
3564562Sgshapiro*/
3664562Sgshapiro
3764562Sgshapiroint
3864562Sgshapiromi_stop()
3964562Sgshapiro{
4064562Sgshapiro	return MilterStop;
4164562Sgshapiro}
4290792Sgshapiro/*
4364562Sgshapiro**  MI_STOP_MILTERS -- set value of MilterStop
4464562Sgshapiro**
4564562Sgshapiro**	Parameters:
4664562Sgshapiro**		v -- new value for MilterStop.
4764562Sgshapiro**
4864562Sgshapiro**	Returns:
4964562Sgshapiro**		none.
5064562Sgshapiro*/
5164562Sgshapiro
5264562Sgshapirovoid
5364562Sgshapiromi_stop_milters(v)
5464562Sgshapiro	int v;
5564562Sgshapiro{
5664562Sgshapiro	(void) smutex_lock(&M_Mutex);
5764562Sgshapiro	if (MilterStop < v)
5864562Sgshapiro		MilterStop = v;
5966494Sgshapiro
6066494Sgshapiro	/* close listen socket */
6166494Sgshapiro	mi_closener();
6264562Sgshapiro	(void) smutex_unlock(&M_Mutex);
6364562Sgshapiro}
6490792Sgshapiro/*
6564562Sgshapiro**  MI_CLEAN_SIGNALS -- clean up signal handler thread
6664562Sgshapiro**
6764562Sgshapiro**	Parameters:
6864562Sgshapiro**		none.
6964562Sgshapiro**
7064562Sgshapiro**	Returns:
7164562Sgshapiro**		none.
7264562Sgshapiro*/
7364562Sgshapiro
7464562Sgshapirovoid
7564562Sgshapiromi_clean_signals()
7664562Sgshapiro{
7764562Sgshapiro	(void) smutex_destroy(&M_Mutex);
7864562Sgshapiro}
7990792Sgshapiro/*
8064562Sgshapiro**  MI_SIGNAL_THREAD -- thread to deal with signals
8164562Sgshapiro**
8264562Sgshapiro**	Parameters:
8364562Sgshapiro**		name -- name of milter
8464562Sgshapiro**
8564562Sgshapiro**	Returns:
8664562Sgshapiro**		NULL
8764562Sgshapiro*/
8864562Sgshapiro
8964562Sgshapirostatic void *
9064562Sgshapiromi_signal_thread(name)
9164562Sgshapiro	void *name;
9264562Sgshapiro{
93157001Sgshapiro	int sig, errs, sigerr;
9464562Sgshapiro	sigset_t set;
9564562Sgshapiro
96120256Sgshapiro	(void) sigemptyset(&set);
97120256Sgshapiro	(void) sigaddset(&set, SIGHUP);
98120256Sgshapiro	(void) sigaddset(&set, SIGTERM);
9964562Sgshapiro
10064562Sgshapiro	/* Handle Ctrl-C gracefully for debugging */
101120256Sgshapiro	(void) sigaddset(&set, SIGINT);
10264562Sgshapiro	errs = 0;
10364562Sgshapiro
104120256Sgshapiro	for (;;)
10564562Sgshapiro	{
106157001Sgshapiro		sigerr = sig = 0;
107285229Sgshapiro#if SIGWAIT_TAKES_1_ARG
10864562Sgshapiro		if ((sig = sigwait(&set)) < 0)
109285229Sgshapiro#else
110157001Sgshapiro		if ((sigerr = sigwait(&set, &sig)) != 0)
111285229Sgshapiro#endif
11264562Sgshapiro		{
113157001Sgshapiro			/* some OS return -1 and set errno: copy it */
114157001Sgshapiro			if (sigerr <= 0)
115157001Sgshapiro				sigerr = errno;
116157001Sgshapiro
117110560Sgshapiro			/* this can happen on OSF/1 (at least) */
118157001Sgshapiro			if (sigerr == EINTR)
119110560Sgshapiro				continue;
12064562Sgshapiro			smi_log(SMI_LOG_ERR,
12190792Sgshapiro				"%s: sigwait returned error: %d",
122157001Sgshapiro				(char *)name, sigerr);
12364562Sgshapiro			if (++errs > MAX_FAILS_T)
12464562Sgshapiro			{
12564562Sgshapiro				mi_stop_milters(MILTER_ABRT);
12664562Sgshapiro				return NULL;
12764562Sgshapiro			}
12864562Sgshapiro			continue;
12964562Sgshapiro		}
13064562Sgshapiro		errs = 0;
13164562Sgshapiro
13264562Sgshapiro		switch (sig)
13364562Sgshapiro		{
13464562Sgshapiro		  case SIGHUP:
13564562Sgshapiro		  case SIGTERM:
13664562Sgshapiro			mi_stop_milters(MILTER_STOP);
13764562Sgshapiro			return NULL;
13864562Sgshapiro		  case SIGINT:
13964562Sgshapiro			mi_stop_milters(MILTER_ABRT);
14064562Sgshapiro			return NULL;
14164562Sgshapiro		  default:
14264562Sgshapiro			smi_log(SMI_LOG_ERR,
14364562Sgshapiro				"%s: sigwait returned unmasked signal: %d",
14464562Sgshapiro				(char *)name, sig);
14564562Sgshapiro			break;
14664562Sgshapiro		}
14764562Sgshapiro	}
148120256Sgshapiro	/* NOTREACHED */
14964562Sgshapiro}
15090792Sgshapiro/*
15164562Sgshapiro**  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
15264562Sgshapiro**
15364562Sgshapiro**	Parameters:
15464562Sgshapiro**		name -- name of milter
15564562Sgshapiro**
15664562Sgshapiro**	Returns:
15764562Sgshapiro**		MI_SUCCESS/MI_FAILURE
15864562Sgshapiro*/
15964562Sgshapiro
16064562Sgshapirostatic int
16164562Sgshapiromi_spawn_signal_thread(name)
16264562Sgshapiro	char *name;
16364562Sgshapiro{
16464562Sgshapiro	sthread_t tid;
16590792Sgshapiro	int r;
16664562Sgshapiro	sigset_t set;
16764562Sgshapiro
16864562Sgshapiro	/* Mask HUP and KILL signals */
169120256Sgshapiro	(void) sigemptyset(&set);
170120256Sgshapiro	(void) sigaddset(&set, SIGHUP);
171120256Sgshapiro	(void) sigaddset(&set, SIGTERM);
172120256Sgshapiro	(void) sigaddset(&set, SIGINT);
17364562Sgshapiro
17464562Sgshapiro	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
17564562Sgshapiro	{
17664562Sgshapiro		smi_log(SMI_LOG_ERR,
17764562Sgshapiro			"%s: Couldn't mask HUP and KILL signals", name);
17864562Sgshapiro		return MI_FAILURE;
17964562Sgshapiro	}
18090792Sgshapiro	r = thread_create(&tid, mi_signal_thread, (void *)name);
18190792Sgshapiro	if (r != 0)
18264562Sgshapiro	{
18364562Sgshapiro		smi_log(SMI_LOG_ERR,
18490792Sgshapiro			"%s: Couldn't start signal thread: %d",
18590792Sgshapiro			name, r);
18664562Sgshapiro		return MI_FAILURE;
18764562Sgshapiro	}
18864562Sgshapiro	return MI_SUCCESS;
18964562Sgshapiro}
19090792Sgshapiro/*
19164562Sgshapiro**  MI_CONTROL_STARTUP -- startup for thread to handle signals
19264562Sgshapiro**
19364562Sgshapiro**	Parameters:
19464562Sgshapiro**		name -- name of milter
19564562Sgshapiro**
19664562Sgshapiro**	Returns:
19764562Sgshapiro**		MI_SUCCESS/MI_FAILURE
19864562Sgshapiro*/
19964562Sgshapiro
20064562Sgshapiroint
20164562Sgshapiromi_control_startup(name)
20264562Sgshapiro	char *name;
20364562Sgshapiro{
20464562Sgshapiro
20564562Sgshapiro	if (!smutex_init(&M_Mutex))
20664562Sgshapiro	{
20764562Sgshapiro		smi_log(SMI_LOG_ERR,
20864562Sgshapiro			"%s: Couldn't initialize control pipe mutex", name);
20964562Sgshapiro		return MI_FAILURE;
21064562Sgshapiro	}
21164562Sgshapiro
21264562Sgshapiro	/*
21364562Sgshapiro	**  spawn_signal_thread must happen before other threads are spawned
21464562Sgshapiro	**  off so that it can mask the right signals and other threads
21564562Sgshapiro	**  will inherit that mask.
21664562Sgshapiro	*/
21764562Sgshapiro	if (mi_spawn_signal_thread(name) == MI_FAILURE)
21864562Sgshapiro	{
21964562Sgshapiro		smi_log(SMI_LOG_ERR,
22064562Sgshapiro			"%s: Couldn't spawn signal thread", name);
22164562Sgshapiro		(void) smutex_destroy(&M_Mutex);
22264562Sgshapiro		return MI_FAILURE;
22364562Sgshapiro	}
22464562Sgshapiro	return MI_SUCCESS;
22564562Sgshapiro}
226