xref: /freebsd/contrib/sendmail/src/sched.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
1*d39bd2c1SGregory Neil Shapiro /*
2*d39bd2c1SGregory Neil Shapiro  * Copyright (c) 2021 Proofpoint, Inc. and its suppliers.
3*d39bd2c1SGregory Neil Shapiro  *	All rights reserved.
4*d39bd2c1SGregory Neil Shapiro  *
5*d39bd2c1SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
6*d39bd2c1SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
7*d39bd2c1SGregory Neil Shapiro  * the sendmail distribution.
8*d39bd2c1SGregory Neil Shapiro  *
9*d39bd2c1SGregory Neil Shapiro  */
10*d39bd2c1SGregory Neil Shapiro 
11*d39bd2c1SGregory Neil Shapiro #include <sendmail.h>
12*d39bd2c1SGregory Neil Shapiro 
13*d39bd2c1SGregory Neil Shapiro #if _FFR_DMTRIGGER
14*d39bd2c1SGregory Neil Shapiro #include <sm/sendmail.h>
15*d39bd2c1SGregory Neil Shapiro #include <sm/notify.h>
16*d39bd2c1SGregory Neil Shapiro 
17*d39bd2c1SGregory Neil Shapiro static ENVELOPE	QmEnvelope;
18*d39bd2c1SGregory Neil Shapiro 
19*d39bd2c1SGregory Neil Shapiro /*
20*d39bd2c1SGregory Neil Shapiro **  Macro for fork():
21*d39bd2c1SGregory Neil Shapiro **  FORK_P1(): parent
22*d39bd2c1SGregory Neil Shapiro **  FORK_C1(): child
23*d39bd2c1SGregory Neil Shapiro **  Note: these are not "universal", e.g.,
24*d39bd2c1SGregory Neil Shapiro **  proc_list_add() might be used in parent or child.
25*d39bd2c1SGregory Neil Shapiro **  maybe check pname != NULL to invoke proc_list_add()?
26*d39bd2c1SGregory Neil Shapiro */
27*d39bd2c1SGregory Neil Shapiro 
28*d39bd2c1SGregory Neil Shapiro #define FORK_P1(emsg, pname, ptype)	\
29*d39bd2c1SGregory Neil Shapiro 	do {	\
30*d39bd2c1SGregory Neil Shapiro 		(void) sm_blocksignal(SIGCHLD);	\
31*d39bd2c1SGregory Neil Shapiro 		(void) sm_signal(SIGCHLD, reapchild);	\
32*d39bd2c1SGregory Neil Shapiro 		\
33*d39bd2c1SGregory Neil Shapiro 		pid = dofork();	\
34*d39bd2c1SGregory Neil Shapiro 		if (pid == -1)	\
35*d39bd2c1SGregory Neil Shapiro 		{	\
36*d39bd2c1SGregory Neil Shapiro 			const char *msg = emsg;	\
37*d39bd2c1SGregory Neil Shapiro 			const char *err = sm_errstring(errno);	\
38*d39bd2c1SGregory Neil Shapiro 		\
39*d39bd2c1SGregory Neil Shapiro 			if (LogLevel > 8)	\
40*d39bd2c1SGregory Neil Shapiro 				sm_syslog(LOG_INFO, NOQID, "%s: %s",	\
41*d39bd2c1SGregory Neil Shapiro 					  msg, err);	\
42*d39bd2c1SGregory Neil Shapiro 			(void) sm_releasesignal(SIGCHLD);	\
43*d39bd2c1SGregory Neil Shapiro 			return false;	\
44*d39bd2c1SGregory Neil Shapiro 		}	\
45*d39bd2c1SGregory Neil Shapiro 		if (pid != 0)	\
46*d39bd2c1SGregory Neil Shapiro 		{	\
47*d39bd2c1SGregory Neil Shapiro 			proc_list_add(pid, pname, ptype, 0, -1, NULL); \
48*d39bd2c1SGregory Neil Shapiro 			/* parent -- pick up intermediate zombie */	\
49*d39bd2c1SGregory Neil Shapiro 			(void) sm_releasesignal(SIGCHLD);	\
50*d39bd2c1SGregory Neil Shapiro 			return true;	\
51*d39bd2c1SGregory Neil Shapiro 		}	\
52*d39bd2c1SGregory Neil Shapiro 	} while (0)
53*d39bd2c1SGregory Neil Shapiro 
54*d39bd2c1SGregory Neil Shapiro #define FORK_C1()	\
55*d39bd2c1SGregory Neil Shapiro 	do {	\
56*d39bd2c1SGregory Neil Shapiro 		/* child -- clean up signals */	\
57*d39bd2c1SGregory Neil Shapiro 		\
58*d39bd2c1SGregory Neil Shapiro 		/* Reset global flags */	\
59*d39bd2c1SGregory Neil Shapiro 		RestartRequest = NULL;	\
60*d39bd2c1SGregory Neil Shapiro 		RestartWorkGroup = false;	\
61*d39bd2c1SGregory Neil Shapiro 		ShutdownRequest = NULL;	\
62*d39bd2c1SGregory Neil Shapiro 		PendingSignal = 0;	\
63*d39bd2c1SGregory Neil Shapiro 		CurrentPid = getpid();	\
64*d39bd2c1SGregory Neil Shapiro 		close_sendmail_pid();	\
65*d39bd2c1SGregory Neil Shapiro 		\
66*d39bd2c1SGregory Neil Shapiro 		/*	\
67*d39bd2c1SGregory Neil Shapiro 		**  Initialize exception stack and default exception	\
68*d39bd2c1SGregory Neil Shapiro 		**  handler for child process.	\
69*d39bd2c1SGregory Neil Shapiro 		*/	\
70*d39bd2c1SGregory Neil Shapiro 		\
71*d39bd2c1SGregory Neil Shapiro 		sm_exc_newthread(fatal_error);	\
72*d39bd2c1SGregory Neil Shapiro 		clrcontrol();	\
73*d39bd2c1SGregory Neil Shapiro 		proc_list_clear();	\
74*d39bd2c1SGregory Neil Shapiro 		\
75*d39bd2c1SGregory Neil Shapiro 		(void) sm_releasesignal(SIGCHLD);	\
76*d39bd2c1SGregory Neil Shapiro 		(void) sm_signal(SIGCHLD, SIG_DFL);	\
77*d39bd2c1SGregory Neil Shapiro 		(void) sm_signal(SIGHUP, SIG_DFL);	\
78*d39bd2c1SGregory Neil Shapiro 		(void) sm_signal(SIGTERM, intsig);	\
79*d39bd2c1SGregory Neil Shapiro 		\
80*d39bd2c1SGregory Neil Shapiro 		/* drop privileges */	\
81*d39bd2c1SGregory Neil Shapiro 		if (geteuid() == (uid_t) 0)	\
82*d39bd2c1SGregory Neil Shapiro 			(void) drop_privileges(false);	\
83*d39bd2c1SGregory Neil Shapiro 		disconnect(1, NULL);	\
84*d39bd2c1SGregory Neil Shapiro 		QuickAbort = false;	\
85*d39bd2c1SGregory Neil Shapiro 		\
86*d39bd2c1SGregory Neil Shapiro 	} while (0)
87*d39bd2c1SGregory Neil Shapiro 
88*d39bd2c1SGregory Neil Shapiro /*
89*d39bd2c1SGregory Neil Shapiro **  QM -- queue "manager"
90*d39bd2c1SGregory Neil Shapiro **
91*d39bd2c1SGregory Neil Shapiro **	Parameters:
92*d39bd2c1SGregory Neil Shapiro **		none.
93*d39bd2c1SGregory Neil Shapiro **
94*d39bd2c1SGregory Neil Shapiro **	Returns:
95*d39bd2c1SGregory Neil Shapiro **		false on error
96*d39bd2c1SGregory Neil Shapiro **
97*d39bd2c1SGregory Neil Shapiro **	Side Effects:
98*d39bd2c1SGregory Neil Shapiro **		fork()s and runs as process to deliver queue entries
99*d39bd2c1SGregory Neil Shapiro */
100*d39bd2c1SGregory Neil Shapiro 
101*d39bd2c1SGregory Neil Shapiro bool
qm()102*d39bd2c1SGregory Neil Shapiro qm()
103*d39bd2c1SGregory Neil Shapiro {
104*d39bd2c1SGregory Neil Shapiro 	int r;
105*d39bd2c1SGregory Neil Shapiro 	pid_t pid;
106*d39bd2c1SGregory Neil Shapiro 	long tmo;
107*d39bd2c1SGregory Neil Shapiro 
108*d39bd2c1SGregory Neil Shapiro 	sm_syslog(LOG_DEBUG, NOQID, "queue manager: start");
109*d39bd2c1SGregory Neil Shapiro 
110*d39bd2c1SGregory Neil Shapiro 	FORK_P1("Queue manager -- fork() failed", "QM", PROC_QM);
111*d39bd2c1SGregory Neil Shapiro 	FORK_C1();
112*d39bd2c1SGregory Neil Shapiro 
113*d39bd2c1SGregory Neil Shapiro 	r = sm_notify_start(true, 0);
114*d39bd2c1SGregory Neil Shapiro 	if (r != 0)
115*d39bd2c1SGregory Neil Shapiro 		syserr("sm_notify_start() failed=%d", r);
116*d39bd2c1SGregory Neil Shapiro 
117*d39bd2c1SGregory Neil Shapiro 	/*
118*d39bd2c1SGregory Neil Shapiro 	**  Initially wait indefinitely, then only wait
119*d39bd2c1SGregory Neil Shapiro 	**  until something needs to get done (not yet implemented).
120*d39bd2c1SGregory Neil Shapiro 	*/
121*d39bd2c1SGregory Neil Shapiro 
122*d39bd2c1SGregory Neil Shapiro 	tmo = -1;
123*d39bd2c1SGregory Neil Shapiro 	while (true)
124*d39bd2c1SGregory Neil Shapiro 	{
125*d39bd2c1SGregory Neil Shapiro 		char buf[64];
126*d39bd2c1SGregory Neil Shapiro 		ENVELOPE *e;
127*d39bd2c1SGregory Neil Shapiro 		SM_RPOOL_T *rpool;
128*d39bd2c1SGregory Neil Shapiro 
129*d39bd2c1SGregory Neil Shapiro /*
130*d39bd2c1SGregory Neil Shapiro **  TODO: This should try to receive multiple ids:
131*d39bd2c1SGregory Neil Shapiro **  after it got one, check for more with a very short timeout
132*d39bd2c1SGregory Neil Shapiro **  and collect them in a list.
133*d39bd2c1SGregory Neil Shapiro **  but them some other code should be used to run all of them.
134*d39bd2c1SGregory Neil Shapiro */
135*d39bd2c1SGregory Neil Shapiro 
136*d39bd2c1SGregory Neil Shapiro 		sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=start");
137*d39bd2c1SGregory Neil Shapiro 		r = sm_notify_rcv(buf, sizeof(buf), tmo);
138*d39bd2c1SGregory Neil Shapiro 		if (-ETIMEDOUT == r)
139*d39bd2c1SGregory Neil Shapiro 		{
140*d39bd2c1SGregory Neil Shapiro 			sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=timed_out");
141*d39bd2c1SGregory Neil Shapiro 			continue;
142*d39bd2c1SGregory Neil Shapiro 		}
143*d39bd2c1SGregory Neil Shapiro 		if (r < 0)
144*d39bd2c1SGregory Neil Shapiro 		{
145*d39bd2c1SGregory Neil Shapiro 			sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=%d", r);
146*d39bd2c1SGregory Neil Shapiro 			goto end;
147*d39bd2c1SGregory Neil Shapiro 		}
148*d39bd2c1SGregory Neil Shapiro 		if (r > 0 && r < sizeof(buf))
149*d39bd2c1SGregory Neil Shapiro 			buf[r] = '\0';
150*d39bd2c1SGregory Neil Shapiro 		buf[sizeof(buf) - 1] = '\0';
151*d39bd2c1SGregory Neil Shapiro 		sm_syslog(LOG_DEBUG, NOQID, "queue manager: got=%s", buf);
152*d39bd2c1SGregory Neil Shapiro 		CurEnv = &QmEnvelope;
153*d39bd2c1SGregory Neil Shapiro 		rpool = sm_rpool_new_x(NULL);
154*d39bd2c1SGregory Neil Shapiro 		e = newenvelope(&QmEnvelope, CurEnv, rpool);
155*d39bd2c1SGregory Neil Shapiro 		e->e_flags = BlankEnvelope.e_flags;
156*d39bd2c1SGregory Neil Shapiro 		e->e_parent = NULL;
157*d39bd2c1SGregory Neil Shapiro 		r = sm_io_sscanf(buf, "N:%d:%d:%s", &e->e_qgrp, &e->e_qdir, e->e_id);
158*d39bd2c1SGregory Neil Shapiro 		if (r != 3)
159*d39bd2c1SGregory Neil Shapiro 		{
160*d39bd2c1SGregory Neil Shapiro 			sm_syslog(LOG_DEBUG, NOQID, "queue manager: buf=%s, scan=%d", buf, r);
161*d39bd2c1SGregory Neil Shapiro 			goto end;
162*d39bd2c1SGregory Neil Shapiro 		}
163*d39bd2c1SGregory Neil Shapiro 		dowork(e->e_qgrp, e->e_qdir, e->e_id, true, false, e);
164*d39bd2c1SGregory Neil Shapiro 	}
165*d39bd2c1SGregory Neil Shapiro 
166*d39bd2c1SGregory Neil Shapiro   end:
167*d39bd2c1SGregory Neil Shapiro 	sm_syslog(LOG_DEBUG, NOQID, "queue manager: stop");
168*d39bd2c1SGregory Neil Shapiro 	finis(false, false, EX_OK);
169*d39bd2c1SGregory Neil Shapiro 	/* NOTREACHED */
170*d39bd2c1SGregory Neil Shapiro 	return false;
171*d39bd2c1SGregory Neil Shapiro }
172*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_DMTRIGGER */
173