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