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