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 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