Commit | Line | Data |
---|---|---|
059ec3d9 PH |
1 | /************************************************* |
2 | * Exim - an Internet mail transport agent * | |
3 | *************************************************/ | |
4 | ||
f9ba5e22 | 5 | /* Copyright (c) University of Cambridge 1995 - 2018 */ |
1e1ddfac | 6 | /* Copyright (c) The Exim Maintainers 2020 */ |
059ec3d9 PH |
7 | /* See the file NOTICE for conditions of use and distribution. */ |
8 | ||
9 | ||
10 | /* The main function: entry point, initialization, and high-level control. | |
11 | Also a few functions that don't naturally fit elsewhere. */ | |
12 | ||
13 | ||
14 | #include "exim.h" | |
15 | ||
98913c8e | 16 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
01f3091a JH |
17 | # include <gnu/libc-version.h> |
18 | #endif | |
19 | ||
f797c123 JH |
20 | #ifdef USE_GNUTLS |
21 | # include <gnutls/gnutls.h> | |
22 | # if GNUTLS_VERSION_NUMBER < 0x030103 && !defined(DISABLE_OCSP) | |
23 | # define DISABLE_OCSP | |
24 | # endif | |
25 | #endif | |
26 | ||
12815ef0 JH |
27 | #ifndef _TIME_H |
28 | # include <time.h> | |
29 | #endif | |
30 | ||
6545de78 PP |
31 | extern void init_lookup_list(void); |
32 | ||
059ec3d9 PH |
33 | |
34 | ||
35 | /************************************************* | |
36 | * Function interface to store functions * | |
37 | *************************************************/ | |
38 | ||
39 | /* We need some real functions to pass to the PCRE regular expression library | |
40 | for store allocation via Exim's store manager. The normal calls are actually | |
41 | macros that pass over location information to make tracing easier. These | |
42 | functions just interface to the standard macro calls. A good compiler will | |
43 | optimize out the tail recursion and so not make them too expensive. There | |
44 | are two sets of functions; one for use when we want to retain the compiled | |
45 | regular expression for a long time; the other for short-term use. */ | |
46 | ||
47 | static void * | |
48 | function_store_get(size_t size) | |
49 | { | |
f3ebb786 JH |
50 | /* For now, regard all RE results as potentially tainted. We might need |
51 | more intelligence on this point. */ | |
52 | return store_get((int)size, TRUE); | |
059ec3d9 PH |
53 | } |
54 | ||
55 | static void | |
56 | function_dummy_free(void *block) { block = block; } | |
57 | ||
58 | static void * | |
59 | function_store_malloc(size_t size) | |
60 | { | |
61 | return store_malloc((int)size); | |
62 | } | |
63 | ||
64 | static void | |
65 | function_store_free(void *block) | |
66 | { | |
67 | store_free(block); | |
68 | } | |
69 | ||
70 | ||
71 | ||
72 | ||
98a90c36 PP |
73 | /************************************************* |
74 | * Enums for cmdline interface * | |
75 | *************************************************/ | |
76 | ||
77 | enum commandline_info { CMDINFO_NONE=0, | |
36a3ae5f | 78 | CMDINFO_HELP, CMDINFO_SIEVE, CMDINFO_DSCP }; |
98a90c36 PP |
79 | |
80 | ||
81 | ||
82 | ||
059ec3d9 PH |
83 | /************************************************* |
84 | * Compile regular expression and panic on fail * | |
85 | *************************************************/ | |
86 | ||
87 | /* This function is called when failure to compile a regular expression leads | |
88 | to a panic exit. In other cases, pcre_compile() is called directly. In many | |
89 | cases where this function is used, the results of the compilation are to be | |
90 | placed in long-lived store, so we temporarily reset the store management | |
91 | functions that PCRE uses if the use_malloc flag is set. | |
92 | ||
93 | Argument: | |
94 | pattern the pattern to compile | |
95 | caseless TRUE if caseless matching is required | |
96 | use_malloc TRUE if compile into malloc store | |
97 | ||
98 | Returns: pointer to the compiled pattern | |
99 | */ | |
100 | ||
101 | const pcre * | |
476be7e2 | 102 | regex_must_compile(const uschar *pattern, BOOL caseless, BOOL use_malloc) |
059ec3d9 PH |
103 | { |
104 | int offset; | |
105 | int options = PCRE_COPT; | |
106 | const pcre *yield; | |
107 | const uschar *error; | |
108 | if (use_malloc) | |
109 | { | |
110 | pcre_malloc = function_store_malloc; | |
111 | pcre_free = function_store_free; | |
112 | } | |
113 | if (caseless) options |= PCRE_CASELESS; | |
3d2e82c5 | 114 | yield = pcre_compile(CCS pattern, options, CCSS &error, &offset, NULL); |
059ec3d9 PH |
115 | pcre_malloc = function_store_get; |
116 | pcre_free = function_dummy_free; | |
117 | if (yield == NULL) | |
118 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "regular expression error: " | |
119 | "%s at offset %d while compiling %s", error, offset, pattern); | |
120 | return yield; | |
121 | } | |
122 | ||
123 | ||
124 | ||
125 | ||
126 | /************************************************* | |
127 | * Execute regular expression and set strings * | |
128 | *************************************************/ | |
129 | ||
130 | /* This function runs a regular expression match, and sets up the pointers to | |
131 | the matched substrings. | |
132 | ||
133 | Arguments: | |
134 | re the compiled expression | |
135 | subject the subject string | |
136 | options additional PCRE options | |
137 | setup if < 0 do full setup | |
138 | if >= 0 setup from setup+1 onwards, | |
139 | excluding the full matched string | |
140 | ||
141 | Returns: TRUE or FALSE | |
142 | */ | |
143 | ||
144 | BOOL | |
1dc92d5a | 145 | regex_match_and_setup(const pcre *re, const uschar *subject, int options, int setup) |
059ec3d9 PH |
146 | { |
147 | int ovector[3*(EXPAND_MAXN+1)]; | |
1dc92d5a JH |
148 | uschar * s = string_copy(subject); /* de-constifying */ |
149 | int n = pcre_exec(re, NULL, CS s, Ustrlen(s), 0, | |
ee8b8090 | 150 | PCRE_EOPT | options, ovector, nelem(ovector)); |
059ec3d9 PH |
151 | BOOL yield = n >= 0; |
152 | if (n == 0) n = EXPAND_MAXN + 1; | |
153 | if (yield) | |
154 | { | |
ee8b8090 | 155 | expand_nmax = setup < 0 ? 0 : setup + 1; |
d7978c0f | 156 | for (int nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2) |
059ec3d9 | 157 | { |
1dc92d5a | 158 | expand_nstring[expand_nmax] = s + ovector[nn]; |
059ec3d9 PH |
159 | expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn]; |
160 | } | |
161 | expand_nmax--; | |
162 | } | |
163 | return yield; | |
164 | } | |
165 | ||
166 | ||
167 | ||
168 | ||
921b12ca TF |
169 | /************************************************* |
170 | * Set up processing details * | |
171 | *************************************************/ | |
172 | ||
173 | /* Save a text string for dumping when SIGUSR1 is received. | |
174 | Do checks for overruns. | |
175 | ||
176 | Arguments: format and arguments, as for printf() | |
177 | Returns: nothing | |
178 | */ | |
179 | ||
180 | void | |
181 | set_process_info(const char *format, ...) | |
182 | { | |
d12746bc JH |
183 | gstring gs = { .size = PROCESS_INFO_SIZE - 2, .ptr = 0, .s = process_info }; |
184 | gstring * g; | |
185 | int len; | |
921b12ca | 186 | va_list ap; |
d12746bc JH |
187 | |
188 | g = string_fmt_append(&gs, "%5d ", (int)getpid()); | |
189 | len = g->ptr; | |
921b12ca | 190 | va_start(ap, format); |
f3ebb786 | 191 | if (!string_vformat(g, 0, format, ap)) |
d12746bc JH |
192 | { |
193 | gs.ptr = len; | |
194 | g = string_cat(&gs, US"**** string overflowed buffer ****"); | |
195 | } | |
196 | g = string_catn(g, US"\n", 1); | |
197 | string_from_gstring(g); | |
198 | process_info_len = g->ptr; | |
921b12ca TF |
199 | DEBUG(D_process_info) debug_printf("set_process_info: %s", process_info); |
200 | va_end(ap); | |
201 | } | |
202 | ||
830832c9 HSHR |
203 | /*********************************************** |
204 | * Handler for SIGTERM * | |
205 | ***********************************************/ | |
921b12ca | 206 | |
830832c9 HSHR |
207 | static void |
208 | term_handler(int sig) | |
209 | { | |
01446a56 | 210 | exit(1); |
830832c9 | 211 | } |
921b12ca TF |
212 | |
213 | ||
059ec3d9 PH |
214 | /************************************************* |
215 | * Handler for SIGUSR1 * | |
216 | *************************************************/ | |
217 | ||
218 | /* SIGUSR1 causes any exim process to write to the process log details of | |
219 | what it is currently doing. It will only be used if the OS is capable of | |
220 | setting up a handler that causes automatic restarting of any system call | |
221 | that is in progress at the time. | |
222 | ||
921b12ca TF |
223 | This function takes care to be signal-safe. |
224 | ||
059ec3d9 PH |
225 | Argument: the signal number (SIGUSR1) |
226 | Returns: nothing | |
227 | */ | |
228 | ||
229 | static void | |
230 | usr1_handler(int sig) | |
231 | { | |
921b12ca TF |
232 | int fd; |
233 | ||
234 | os_restarting_signal(sig, usr1_handler); | |
235 | ||
cab0c277 | 236 | if ((fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE)) < 0) |
921b12ca TF |
237 | { |
238 | /* If we are already running as the Exim user, try to create it in the | |
239 | current process (assuming spool_directory exists). Otherwise, if we are | |
240 | root, do the creation in an exim:exim subprocess. */ | |
241 | ||
242 | int euid = geteuid(); | |
243 | if (euid == exim_uid) | |
244 | fd = Uopen(process_log_path, O_CREAT|O_APPEND|O_WRONLY, LOG_MODE); | |
245 | else if (euid == root_uid) | |
246 | fd = log_create_as_exim(process_log_path); | |
247 | } | |
248 | ||
249 | /* If we are neither exim nor root, or if we failed to create the log file, | |
250 | give up. There is not much useful we can do with errors, since we don't want | |
251 | to disrupt whatever is going on outside the signal handler. */ | |
252 | ||
253 | if (fd < 0) return; | |
254 | ||
2f21487f | 255 | (void)write(fd, process_info, process_info_len); |
921b12ca | 256 | (void)close(fd); |
059ec3d9 PH |
257 | } |
258 | ||
259 | ||
260 | ||
261 | /************************************************* | |
262 | * Timeout handler * | |
263 | *************************************************/ | |
264 | ||
265 | /* This handler is enabled most of the time that Exim is running. The handler | |
266 | doesn't actually get used unless alarm() has been called to set a timer, to | |
267 | place a time limit on a system call of some kind. When the handler is run, it | |
268 | re-enables itself. | |
269 | ||
270 | There are some other SIGALRM handlers that are used in special cases when more | |
271 | than just a flag setting is required; for example, when reading a message's | |
272 | input. These are normally set up in the code module that uses them, and the | |
273 | SIGALRM handler is reset to this one afterwards. | |
274 | ||
275 | Argument: the signal value (SIGALRM) | |
276 | Returns: nothing | |
277 | */ | |
278 | ||
279 | void | |
280 | sigalrm_handler(int sig) | |
281 | { | |
282 | sig = sig; /* Keep picky compilers happy */ | |
283 | sigalrm_seen = TRUE; | |
284 | os_non_restarting_signal(SIGALRM, sigalrm_handler); | |
285 | } | |
286 | ||
287 | ||
288 | ||
289 | /************************************************* | |
290 | * Sleep for a fractional time interval * | |
291 | *************************************************/ | |
292 | ||
293 | /* This function is called by millisleep() and exim_wait_tick() to wait for a | |
294 | period of time that may include a fraction of a second. The coding is somewhat | |
eb2c0248 PH |
295 | tedious. We do not expect setitimer() ever to fail, but if it does, the process |
296 | will wait for ever, so we panic in this instance. (There was a case of this | |
297 | when a bug in a function that calls milliwait() caused it to pass invalid data. | |
7086e875 | 298 | That's when I added the check. :-) |
059ec3d9 | 299 | |
6906c131 | 300 | We assume it to be not worth sleeping for under 50us; this value will |
0f8ba377 JH |
301 | require revisiting as hardware advances. This avoids the issue of |
302 | a zero-valued timer setting meaning "never fire". | |
303 | ||
059ec3d9 PH |
304 | Argument: an itimerval structure containing the interval |
305 | Returns: nothing | |
306 | */ | |
307 | ||
308 | static void | |
309 | milliwait(struct itimerval *itval) | |
310 | { | |
311 | sigset_t sigmask; | |
312 | sigset_t old_sigmask; | |
c85879f8 | 313 | int save_errno = errno; |
0f8ba377 | 314 | |
6906c131 | 315 | if (itval->it_value.tv_usec < 50 && itval->it_value.tv_sec == 0) |
0f8ba377 | 316 | return; |
059ec3d9 PH |
317 | (void)sigemptyset(&sigmask); /* Empty mask */ |
318 | (void)sigaddset(&sigmask, SIGALRM); /* Add SIGALRM */ | |
319 | (void)sigprocmask(SIG_BLOCK, &sigmask, &old_sigmask); /* Block SIGALRM */ | |
7086e875 | 320 | if (setitimer(ITIMER_REAL, itval, NULL) < 0) /* Start timer */ |
eb2c0248 PH |
321 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, |
322 | "setitimer() failed: %s", strerror(errno)); | |
059ec3d9 PH |
323 | (void)sigfillset(&sigmask); /* All signals */ |
324 | (void)sigdelset(&sigmask, SIGALRM); /* Remove SIGALRM */ | |
325 | (void)sigsuspend(&sigmask); /* Until SIGALRM */ | |
326 | (void)sigprocmask(SIG_SETMASK, &old_sigmask, NULL); /* Restore mask */ | |
c85879f8 JH |
327 | errno = save_errno; |
328 | sigalrm_seen = FALSE; | |
059ec3d9 PH |
329 | } |
330 | ||
331 | ||
332 | ||
333 | ||
334 | /************************************************* | |
335 | * Millisecond sleep function * | |
336 | *************************************************/ | |
337 | ||
338 | /* The basic sleep() function has a granularity of 1 second, which is too rough | |
339 | in some cases - for example, when using an increasing delay to slow down | |
340 | spammers. | |
341 | ||
342 | Argument: number of millseconds | |
343 | Returns: nothing | |
344 | */ | |
345 | ||
346 | void | |
347 | millisleep(int msec) | |
348 | { | |
96c81511 JH |
349 | struct itimerval itval = {.it_interval = {.tv_sec = 0, .tv_usec = 0}, |
350 | .it_value = {.tv_sec = msec/1000, | |
351 | .tv_usec = (msec % 1000) * 1000}}; | |
059ec3d9 PH |
352 | milliwait(&itval); |
353 | } | |
354 | ||
355 | ||
356 | ||
357 | /************************************************* | |
358 | * Compare microsecond times * | |
359 | *************************************************/ | |
360 | ||
361 | /* | |
362 | Arguments: | |
363 | tv1 the first time | |
364 | tv2 the second time | |
365 | ||
366 | Returns: -1, 0, or +1 | |
367 | */ | |
368 | ||
32dfdf8b | 369 | static int |
059ec3d9 PH |
370 | exim_tvcmp(struct timeval *t1, struct timeval *t2) |
371 | { | |
372 | if (t1->tv_sec > t2->tv_sec) return +1; | |
373 | if (t1->tv_sec < t2->tv_sec) return -1; | |
374 | if (t1->tv_usec > t2->tv_usec) return +1; | |
375 | if (t1->tv_usec < t2->tv_usec) return -1; | |
376 | return 0; | |
377 | } | |
378 | ||
379 | ||
380 | ||
381 | ||
382 | /************************************************* | |
383 | * Clock tick wait function * | |
384 | *************************************************/ | |
385 | ||
6906c131 JH |
386 | #ifdef _POSIX_MONOTONIC_CLOCK |
387 | /* Amount CLOCK_MONOTONIC is behind realtime, at startup. */ | |
388 | static struct timespec offset_ts; | |
389 | ||
390 | static void | |
391 | exim_clock_init(void) | |
392 | { | |
393 | struct timeval tv; | |
394 | if (clock_gettime(CLOCK_MONOTONIC, &offset_ts) != 0) return; | |
395 | (void)gettimeofday(&tv, NULL); | |
396 | offset_ts.tv_sec = tv.tv_sec - offset_ts.tv_sec; | |
397 | offset_ts.tv_nsec = tv.tv_usec * 1000 - offset_ts.tv_nsec; | |
398 | if (offset_ts.tv_nsec >= 0) return; | |
399 | offset_ts.tv_sec--; | |
400 | offset_ts.tv_nsec += 1000*1000*1000; | |
401 | } | |
402 | #endif | |
403 | ||
404 | ||
059ec3d9 PH |
405 | /* Exim uses a time + a pid to generate a unique identifier in two places: its |
406 | message IDs, and in file names for maildir deliveries. Because some OS now | |
407 | re-use pids within the same second, sub-second times are now being used. | |
4c04137d | 408 | However, for absolute certainty, we must ensure the clock has ticked before |
059ec3d9 PH |
409 | allowing the relevant process to complete. At the time of implementation of |
410 | this code (February 2003), the speed of processors is such that the clock will | |
411 | invariably have ticked already by the time a process has done its job. This | |
412 | function prepares for the time when things are faster - and it also copes with | |
413 | clocks that go backwards. | |
414 | ||
415 | Arguments: | |
6906c131 | 416 | tgt_tv A timeval which was used to create uniqueness; its usec field |
059ec3d9 PH |
417 | has been rounded down to the value of the resolution. |
418 | We want to be sure the current time is greater than this. | |
419 | resolution The resolution that was used to divide the microseconds | |
420 | (1 for maildir, larger for message ids) | |
421 | ||
422 | Returns: nothing | |
423 | */ | |
424 | ||
425 | void | |
6906c131 | 426 | exim_wait_tick(struct timeval * tgt_tv, int resolution) |
059ec3d9 PH |
427 | { |
428 | struct timeval now_tv; | |
429 | long int now_true_usec; | |
430 | ||
6906c131 JH |
431 | #ifdef _POSIX_MONOTONIC_CLOCK |
432 | struct timespec now_ts; | |
433 | ||
434 | if (clock_gettime(CLOCK_MONOTONIC, &now_ts) == 0) | |
435 | { | |
436 | now_ts.tv_sec += offset_ts.tv_sec; | |
437 | if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000) | |
438 | { | |
439 | now_ts.tv_sec++; | |
440 | now_ts.tv_nsec -= 1000*1000*1000; | |
441 | } | |
442 | now_tv.tv_sec = now_ts.tv_sec; | |
443 | now_true_usec = (now_ts.tv_nsec / (resolution * 1000)) * resolution; | |
444 | now_tv.tv_usec = now_true_usec; | |
445 | } | |
446 | else | |
447 | #endif | |
448 | { | |
449 | (void)gettimeofday(&now_tv, NULL); | |
450 | now_true_usec = now_tv.tv_usec; | |
451 | now_tv.tv_usec = (now_true_usec/resolution) * resolution; | |
452 | } | |
059ec3d9 | 453 | |
6906c131 | 454 | while (exim_tvcmp(&now_tv, tgt_tv) <= 0) |
059ec3d9 PH |
455 | { |
456 | struct itimerval itval; | |
457 | itval.it_interval.tv_sec = 0; | |
458 | itval.it_interval.tv_usec = 0; | |
6906c131 JH |
459 | itval.it_value.tv_sec = tgt_tv->tv_sec - now_tv.tv_sec; |
460 | itval.it_value.tv_usec = tgt_tv->tv_usec + resolution - now_true_usec; | |
059ec3d9 PH |
461 | |
462 | /* We know that, overall, "now" is less than or equal to "then". Therefore, a | |
463 | negative value for the microseconds is possible only in the case when "now" | |
6906c131 | 464 | is more than a second less than "tgt". That means that itval.it_value.tv_sec |
059ec3d9 PH |
465 | is greater than zero. The following correction is therefore safe. */ |
466 | ||
467 | if (itval.it_value.tv_usec < 0) | |
468 | { | |
469 | itval.it_value.tv_usec += 1000000; | |
470 | itval.it_value.tv_sec -= 1; | |
471 | } | |
472 | ||
473 | DEBUG(D_transport|D_receive) | |
474 | { | |
8768d548 | 475 | if (!f.running_in_test_harness) |
059ec3d9 | 476 | { |
d0291a0a | 477 | debug_printf("tick check: " TIME_T_FMT ".%06lu " TIME_T_FMT ".%06lu\n", |
6906c131 | 478 | tgt_tv->tv_sec, (long) tgt_tv->tv_usec, |
7437665e | 479 | now_tv.tv_sec, (long) now_tv.tv_usec); |
6906c131 | 480 | debug_printf("waiting " TIME_T_FMT ".%06lu sec\n", |
d0291a0a | 481 | itval.it_value.tv_sec, (long) itval.it_value.tv_usec); |
059ec3d9 PH |
482 | } |
483 | } | |
484 | ||
485 | milliwait(&itval); | |
fce5c23c ST |
486 | |
487 | /* Be prapared to go around if the kernel does not implement subtick | |
488 | granularity (GNU Hurd) */ | |
489 | ||
490 | (void)gettimeofday(&now_tv, NULL); | |
491 | now_true_usec = now_tv.tv_usec; | |
492 | now_tv.tv_usec = (now_true_usec/resolution) * resolution; | |
059ec3d9 PH |
493 | } |
494 | } | |
495 | ||
496 | ||
497 | ||
498 | ||
2632889e PH |
499 | /************************************************* |
500 | * Call fopen() with umask 777 and adjust mode * | |
501 | *************************************************/ | |
502 | ||
503 | /* Exim runs with umask(0) so that files created with open() have the mode that | |
504 | is specified in the open() call. However, there are some files, typically in | |
505 | the spool directory, that are created with fopen(). They end up world-writeable | |
506 | if no precautions are taken. Although the spool directory is not accessible to | |
507 | the world, this is an untidiness. So this is a wrapper function for fopen() | |
508 | that sorts out the mode of the created file. | |
509 | ||
510 | Arguments: | |
511 | filename the file name | |
512 | options the fopen() options | |
513 | mode the required mode | |
514 | ||
515 | Returns: the fopened FILE or NULL | |
516 | */ | |
517 | ||
518 | FILE * | |
1ba28e2b | 519 | modefopen(const uschar *filename, const char *options, mode_t mode) |
2632889e | 520 | { |
67d175de PH |
521 | mode_t saved_umask = umask(0777); |
522 | FILE *f = Ufopen(filename, options); | |
523 | (void)umask(saved_umask); | |
2632889e PH |
524 | if (f != NULL) (void)fchmod(fileno(f), mode); |
525 | return f; | |
526 | } | |
527 | ||
528 | ||
059ec3d9 PH |
529 | /************************************************* |
530 | * Ensure stdin, stdout, and stderr exist * | |
531 | *************************************************/ | |
532 | ||
533 | /* Some operating systems grumble if an exec() happens without a standard | |
534 | input, output, and error (fds 0, 1, 2) being defined. The worry is that some | |
535 | file will be opened and will use these fd values, and then some other bit of | |
536 | code will assume, for example, that it can write error messages to stderr. | |
537 | This function ensures that fds 0, 1, and 2 are open if they do not already | |
538 | exist, by connecting them to /dev/null. | |
539 | ||
540 | This function is also used to ensure that std{in,out,err} exist at all times, | |
541 | so that if any library that Exim calls tries to use them, it doesn't crash. | |
542 | ||
543 | Arguments: None | |
544 | Returns: Nothing | |
545 | */ | |
546 | ||
547 | void | |
548 | exim_nullstd(void) | |
549 | { | |
059ec3d9 PH |
550 | int devnull = -1; |
551 | struct stat statbuf; | |
d7978c0f | 552 | for (int i = 0; i <= 2; i++) |
059ec3d9 PH |
553 | { |
554 | if (fstat(i, &statbuf) < 0 && errno == EBADF) | |
555 | { | |
556 | if (devnull < 0) devnull = open("/dev/null", O_RDWR); | |
557 | if (devnull < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", | |
f3ebb786 | 558 | string_open_failed(errno, "/dev/null", NULL)); |
1fe64dcc | 559 | if (devnull != i) (void)dup2(devnull, i); |
059ec3d9 PH |
560 | } |
561 | } | |
1fe64dcc | 562 | if (devnull > 2) (void)close(devnull); |
059ec3d9 PH |
563 | } |
564 | ||
565 | ||
566 | ||
567 | ||
568 | /************************************************* | |
569 | * Close unwanted file descriptors for delivery * | |
570 | *************************************************/ | |
571 | ||
572 | /* This function is called from a new process that has been forked to deliver | |
573 | an incoming message, either directly, or using exec. | |
574 | ||
575 | We want any smtp input streams to be closed in this new process. However, it | |
576 | has been observed that using fclose() here causes trouble. When reading in -bS | |
577 | input, duplicate copies of messages have been seen. The files will be sharing a | |
578 | file pointer with the parent process, and it seems that fclose() (at least on | |
579 | some systems - I saw this on Solaris 2.5.1) messes with that file pointer, at | |
580 | least sometimes. Hence we go for closing the underlying file descriptors. | |
581 | ||
582 | If TLS is active, we want to shut down the TLS library, but without molesting | |
583 | the parent's SSL connection. | |
584 | ||
585 | For delivery of a non-SMTP message, we want to close stdin and stdout (and | |
586 | stderr unless debugging) because the calling process might have set them up as | |
587 | pipes and be waiting for them to close before it waits for the submission | |
588 | process to terminate. If they aren't closed, they hold up the calling process | |
589 | until the initial delivery process finishes, which is not what we want. | |
590 | ||
591 | Exception: We do want it for synchronous delivery! | |
592 | ||
593 | And notwithstanding all the above, if D_resolver is set, implying resolver | |
594 | debugging, leave stdout open, because that's where the resolver writes its | |
595 | debugging output. | |
596 | ||
597 | When we close stderr (which implies we've also closed stdout), we also get rid | |
598 | of any controlling terminal. | |
599 | ||
600 | Arguments: None | |
601 | Returns: Nothing | |
602 | */ | |
603 | ||
604 | static void | |
605 | close_unwanted(void) | |
606 | { | |
607 | if (smtp_input) | |
608 | { | |
01603eec | 609 | #ifndef DISABLE_TLS |
74f1a423 JH |
610 | tls_close(NULL, TLS_NO_SHUTDOWN); /* Shut down the TLS library */ |
611 | #endif | |
1fe64dcc PH |
612 | (void)close(fileno(smtp_in)); |
613 | (void)close(fileno(smtp_out)); | |
059ec3d9 PH |
614 | smtp_in = NULL; |
615 | } | |
616 | else | |
617 | { | |
1fe64dcc PH |
618 | (void)close(0); /* stdin */ |
619 | if ((debug_selector & D_resolver) == 0) (void)close(1); /* stdout */ | |
620 | if (debug_selector == 0) /* stderr */ | |
059ec3d9 | 621 | { |
8768d548 | 622 | if (!f.synchronous_delivery) |
059ec3d9 | 623 | { |
1fe64dcc | 624 | (void)close(2); |
059ec3d9 PH |
625 | log_stderr = NULL; |
626 | } | |
627 | (void)setsid(); | |
628 | } | |
629 | } | |
630 | } | |
631 | ||
632 | ||
633 | ||
634 | ||
635 | /************************************************* | |
636 | * Set uid and gid * | |
637 | *************************************************/ | |
638 | ||
639 | /* This function sets a new uid and gid permanently, optionally calling | |
640 | initgroups() to set auxiliary groups. There are some special cases when running | |
641 | Exim in unprivileged modes. In these situations the effective uid will not be | |
642 | root; if we already have the right effective uid/gid, and don't need to | |
643 | initialize any groups, leave things as they are. | |
644 | ||
645 | Arguments: | |
646 | uid the uid | |
647 | gid the gid | |
648 | igflag TRUE if initgroups() wanted | |
649 | msg text to use in debugging output and failure log | |
650 | ||
651 | Returns: nothing; bombs out on failure | |
652 | */ | |
653 | ||
654 | void | |
655 | exim_setugid(uid_t uid, gid_t gid, BOOL igflag, uschar *msg) | |
656 | { | |
657 | uid_t euid = geteuid(); | |
658 | gid_t egid = getegid(); | |
659 | ||
660 | if (euid == root_uid || euid != uid || egid != gid || igflag) | |
661 | { | |
662 | /* At least one OS returns +1 for initgroups failure, so just check for | |
663 | non-zero. */ | |
664 | ||
665 | if (igflag) | |
666 | { | |
667 | struct passwd *pw = getpwuid(uid); | |
9af3c549 JH |
668 | if (!pw) |
669 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "cannot run initgroups(): " | |
670 | "no passwd entry for uid=%ld", (long int)uid); | |
671 | ||
672 | if (initgroups(pw->pw_name, gid) != 0) | |
673 | log_write(0,LOG_MAIN|LOG_PANIC_DIE,"initgroups failed for uid=%ld: %s", | |
674 | (long int)uid, strerror(errno)); | |
059ec3d9 PH |
675 | } |
676 | ||
677 | if (setgid(gid) < 0 || setuid(uid) < 0) | |
059ec3d9 PH |
678 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "unable to set gid=%ld or uid=%ld " |
679 | "(euid=%ld): %s", (long int)gid, (long int)uid, (long int)euid, msg); | |
059ec3d9 PH |
680 | } |
681 | ||
682 | /* Debugging output included uid/gid and all groups */ | |
683 | ||
684 | DEBUG(D_uid) | |
685 | { | |
cd59ab18 | 686 | int group_count, save_errno; |
157d73b5 | 687 | gid_t group_list[EXIM_GROUPLIST_SIZE]; |
059ec3d9 PH |
688 | debug_printf("changed uid/gid: %s\n uid=%ld gid=%ld pid=%ld\n", msg, |
689 | (long int)geteuid(), (long int)getegid(), (long int)getpid()); | |
157d73b5 | 690 | group_count = getgroups(nelem(group_list), group_list); |
cd59ab18 | 691 | save_errno = errno; |
059ec3d9 PH |
692 | debug_printf(" auxiliary group list:"); |
693 | if (group_count > 0) | |
d7978c0f | 694 | for (int i = 0; i < group_count; i++) debug_printf(" %d", (int)group_list[i]); |
cd59ab18 PP |
695 | else if (group_count < 0) |
696 | debug_printf(" <error: %s>", strerror(save_errno)); | |
059ec3d9 PH |
697 | else debug_printf(" <none>"); |
698 | debug_printf("\n"); | |
699 | } | |
700 | } | |
701 | ||
702 | ||
703 | ||
704 | ||
705 | /************************************************* | |
706 | * Exit point * | |
707 | *************************************************/ | |
708 | ||
709 | /* Exim exits via this function so that it always clears up any open | |
710 | databases. | |
711 | ||
712 | Arguments: | |
713 | rc return code | |
714 | ||
715 | Returns: does not return | |
716 | */ | |
717 | ||
718 | void | |
81022793 | 719 | exim_exit(int rc) |
059ec3d9 PH |
720 | { |
721 | search_tidyup(); | |
f3ebb786 | 722 | store_exit(); |
059ec3d9 | 723 | DEBUG(D_any) |
81022793 JH |
724 | debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d (%s) terminating with rc=%d " |
725 | ">>>>>>>>>>>>>>>>\n", | |
726 | (int)getpid(), process_purpose, rc); | |
059ec3d9 PH |
727 | exit(rc); |
728 | } | |
729 | ||
730 | ||
f3ebb786 | 731 | void |
81022793 | 732 | exim_underbar_exit(int rc) |
f3ebb786 JH |
733 | { |
734 | store_exit(); | |
afd5e75f | 735 | DEBUG(D_any) |
81022793 JH |
736 | debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d (%s) terminating with rc=%d " |
737 | ">>>>>>>>>>>>>>>>\n", | |
738 | (int)getpid(), process_purpose, rc); | |
f3ebb786 JH |
739 | _exit(rc); |
740 | } | |
741 | ||
742 | ||
059ec3d9 | 743 | |
9af3c549 JH |
744 | /* Print error string, then die */ |
745 | static void | |
746 | exim_fail(const char * fmt, ...) | |
747 | { | |
748 | va_list ap; | |
749 | va_start(ap, fmt); | |
750 | vfprintf(stderr, fmt, ap); | |
751 | exit(EXIT_FAILURE); | |
752 | } | |
753 | ||
b66fecb4 HSHR |
754 | /* exim_chown_failure() called from exim_chown()/exim_fchown() on failure |
755 | of chown()/fchown(). See src/functions.h for more explanation */ | |
756 | int | |
757 | exim_chown_failure(int fd, const uschar *name, uid_t owner, gid_t group) | |
758 | { | |
ecf14f2a | 759 | int saved_errno = errno; /* from the preceeding chown call */ |
b66fecb4 HSHR |
760 | #if 1 |
761 | log_write(0, LOG_MAIN|LOG_PANIC, | |
762 | __FILE__ ":%d: chown(%s, %d:%d) failed (%s)." | |
763 | " Please contact the authors and refer to https://bugs.exim.org/show_bug.cgi?id=2391", | |
764 | __LINE__, name?name:US"<unknown>", owner, group, strerror(errno)); | |
765 | #else | |
766 | /* I leave this here, commented, in case the "bug"(?) comes up again. | |
767 | It is not an Exim bug, but we can provide a workaround. | |
768 | See Bug 2391 | |
769 | HS 2019-04-18 */ | |
770 | ||
b66fecb4 HSHR |
771 | struct stat buf; |
772 | ||
773 | if (0 == (fd < 0 ? stat(name, &buf) : fstat(fd, &buf))) | |
774 | { | |
775 | if (buf.st_uid == owner && buf.st_gid == group) return 0; | |
776 | log_write(0, LOG_MAIN|LOG_PANIC, "Wrong ownership on %s", name); | |
777 | } | |
778 | else log_write(0, LOG_MAIN|LOG_PANIC, "Stat failed on %s: %s", name, strerror(errno)); | |
779 | ||
ecf14f2a | 780 | #endif |
b66fecb4 HSHR |
781 | errno = saved_errno; |
782 | return -1; | |
b66fecb4 | 783 | } |
9af3c549 | 784 | |
059ec3d9 PH |
785 | |
786 | /************************************************* | |
787 | * Extract port from host address * | |
788 | *************************************************/ | |
789 | ||
790 | /* Called to extract the port from the values given to -oMa and -oMi. | |
b90c388a PH |
791 | It also checks the syntax of the address, and terminates it before the |
792 | port data when a port is extracted. | |
059ec3d9 PH |
793 | |
794 | Argument: | |
795 | address the address, with possible port on the end | |
796 | ||
797 | Returns: the port, or zero if there isn't one | |
798 | bombs out on a syntax error | |
799 | */ | |
800 | ||
801 | static int | |
802 | check_port(uschar *address) | |
803 | { | |
7cd1141b | 804 | int port = host_address_extract_port(address); |
8e669ac1 | 805 | if (string_is_ip_address(address, NULL) == 0) |
9af3c549 | 806 | exim_fail("exim abandoned: \"%s\" is not an IP address\n", address); |
059ec3d9 PH |
807 | return port; |
808 | } | |
809 | ||
810 | ||
811 | ||
812 | /************************************************* | |
813 | * Test/verify an address * | |
814 | *************************************************/ | |
815 | ||
816 | /* This function is called by the -bv and -bt code. It extracts a working | |
817 | address from a full RFC 822 address. This isn't really necessary per se, but it | |
818 | has the effect of collapsing source routes. | |
819 | ||
820 | Arguments: | |
821 | s the address string | |
822 | flags flag bits for verify_address() | |
823 | exit_value to be set for failures | |
824 | ||
a5a28604 | 825 | Returns: nothing |
059ec3d9 PH |
826 | */ |
827 | ||
828 | static void | |
829 | test_address(uschar *s, int flags, int *exit_value) | |
830 | { | |
831 | int start, end, domain; | |
832 | uschar *parse_error = NULL; | |
833 | uschar *address = parse_extract_address(s, &parse_error, &start, &end, &domain, | |
834 | FALSE); | |
5fcc791a | 835 | if (!address) |
059ec3d9 PH |
836 | { |
837 | fprintf(stdout, "syntax error: %s\n", parse_error); | |
838 | *exit_value = 2; | |
839 | } | |
840 | else | |
841 | { | |
842 | int rc = verify_address(deliver_make_addr(address,TRUE), stdout, flags, -1, | |
4deaf07d | 843 | -1, -1, NULL, NULL, NULL); |
059ec3d9 PH |
844 | if (rc == FAIL) *exit_value = 2; |
845 | else if (rc == DEFER && *exit_value == 0) *exit_value = 1; | |
846 | } | |
847 | } | |
848 | ||
849 | ||
850 | ||
059ec3d9 PH |
851 | /************************************************* |
852 | * Show supported features * | |
853 | *************************************************/ | |
854 | ||
059ec3d9 | 855 | static void |
96508de1 | 856 | show_db_version(FILE * f) |
059ec3d9 PH |
857 | { |
858 | #ifdef DB_VERSION_STRING | |
96508de1 JH |
859 | DEBUG(D_any) |
860 | { | |
861 | fprintf(f, "Library version: BDB: Compile: %s\n", DB_VERSION_STRING); | |
862 | fprintf(f, " Runtime: %s\n", | |
863 | db_version(NULL, NULL, NULL)); | |
864 | } | |
865 | else | |
866 | fprintf(f, "Berkeley DB: %s\n", DB_VERSION_STRING); | |
867 | ||
059ec3d9 PH |
868 | #elif defined(BTREEVERSION) && defined(HASHVERSION) |
869 | #ifdef USE_DB | |
870 | fprintf(f, "Probably Berkeley DB version 1.8x (native mode)\n"); | |
871 | #else | |
872 | fprintf(f, "Probably Berkeley DB version 1.8x (compatibility mode)\n"); | |
873 | #endif | |
96508de1 | 874 | |
059ec3d9 PH |
875 | #elif defined(_DBM_RDONLY) || defined(dbm_dirfno) |
876 | fprintf(f, "Probably ndbm\n"); | |
877 | #elif defined(USE_TDB) | |
878 | fprintf(f, "Using tdb\n"); | |
879 | #else | |
880 | #ifdef USE_GDBM | |
881 | fprintf(f, "Probably GDBM (native mode)\n"); | |
882 | #else | |
883 | fprintf(f, "Probably GDBM (compatibility mode)\n"); | |
884 | #endif | |
885 | #endif | |
96508de1 JH |
886 | } |
887 | ||
888 | ||
889 | /* This function is called for -bV/--version and for -d to output the optional | |
890 | features of the current Exim binary. | |
891 | ||
892 | Arguments: a FILE for printing | |
893 | Returns: nothing | |
894 | */ | |
895 | ||
896 | static void | |
8768d548 | 897 | show_whats_supported(FILE * fp) |
96508de1 | 898 | { |
ab1604ea JH |
899 | rmark reset_point = store_mark(); |
900 | gstring * g; | |
8768d548 | 901 | DEBUG(D_any) {} else show_db_version(fp); |
059ec3d9 | 902 | |
ab1604ea | 903 | g = string_cat(NULL, US"Support for:"); |
9cec981f | 904 | #ifdef SUPPORT_CRYPTEQ |
ab1604ea | 905 | g = string_cat(g, US" crypteq"); |
9cec981f | 906 | #endif |
059ec3d9 | 907 | #if HAVE_ICONV |
ab1604ea | 908 | g = string_cat(g, US" iconv()"); |
059ec3d9 PH |
909 | #endif |
910 | #if HAVE_IPV6 | |
ab1604ea | 911 | g = string_cat(g, US" IPv6"); |
059ec3d9 | 912 | #endif |
79378e0f | 913 | #ifdef HAVE_SETCLASSRESOURCES |
ab1604ea | 914 | g = string_cat(g, US" use_setclassresources"); |
929ba01c | 915 | #endif |
059ec3d9 | 916 | #ifdef SUPPORT_PAM |
ab1604ea | 917 | g = string_cat(g, US" PAM"); |
059ec3d9 PH |
918 | #endif |
919 | #ifdef EXIM_PERL | |
ab1604ea | 920 | g = string_cat(g, US" Perl"); |
059ec3d9 | 921 | #endif |
1a46a8c5 | 922 | #ifdef EXPAND_DLFUNC |
ab1604ea | 923 | g = string_cat(g, US" Expand_dlfunc"); |
1a46a8c5 | 924 | #endif |
059ec3d9 | 925 | #ifdef USE_TCP_WRAPPERS |
ab1604ea | 926 | g = string_cat(g, US" TCPwrappers"); |
059ec3d9 | 927 | #endif |
de517fd3 | 928 | #ifdef USE_GNUTLS |
ab1604ea | 929 | g = string_cat(g, US" GnuTLS"); |
de517fd3 JH |
930 | #endif |
931 | #ifdef USE_OPENSSL | |
ab1604ea | 932 | g = string_cat(g, US" OpenSSL"); |
059ec3d9 | 933 | #endif |
b2f5a032 | 934 | #ifdef SUPPORT_TRANSLATE_IP_ADDRESS |
ab1604ea | 935 | g = string_cat(g, US" translate_ip_address"); |
b2f5a032 | 936 | #endif |
f174f16e | 937 | #ifdef SUPPORT_MOVE_FROZEN_MESSAGES |
ab1604ea | 938 | g = string_cat(g, US" move_frozen_messages"); |
f174f16e | 939 | #endif |
8523533c | 940 | #ifdef WITH_CONTENT_SCAN |
ab1604ea | 941 | g = string_cat(g, US" Content_Scanning"); |
8523533c | 942 | #endif |
c0635b6d | 943 | #ifdef SUPPORT_DANE |
ab1604ea | 944 | g = string_cat(g, US" DANE"); |
c0635b6d | 945 | #endif |
74f150bf | 946 | #ifndef DISABLE_DKIM |
ab1604ea | 947 | g = string_cat(g, US" DKIM"); |
74f150bf | 948 | #endif |
ef1bbb27 | 949 | #ifndef DISABLE_DNSSEC |
ab1604ea | 950 | g = string_cat(g, US" DNSSEC"); |
ef1bbb27 | 951 | #endif |
0cbf2b82 | 952 | #ifndef DISABLE_EVENT |
ab1604ea | 953 | g = string_cat(g, US" Event"); |
0cbf2b82 | 954 | #endif |
8c5d388a | 955 | #ifdef SUPPORT_I18N |
ab1604ea | 956 | g = string_cat(g, US" I18N"); |
8c5d388a | 957 | #endif |
74f150bf | 958 | #ifndef DISABLE_OCSP |
ab1604ea | 959 | g = string_cat(g, US" OCSP"); |
74f150bf | 960 | #endif |
81344b40 | 961 | #ifndef DISABLE_PIPE_CONNECT |
ab1604ea | 962 | g = string_cat(g, US" PIPE_CONNECT"); |
4e48d56c | 963 | #endif |
4d832da1 | 964 | #ifndef DISABLE_PRDR |
ab1604ea | 965 | g = string_cat(g, US" PRDR"); |
4d832da1 | 966 | #endif |
cee5f132 | 967 | #ifdef SUPPORT_PROXY |
ab1604ea | 968 | g = string_cat(g, US" PROXY"); |
cee5f132 | 969 | #endif |
f0989ec0 | 970 | #ifdef SUPPORT_SOCKS |
ab1604ea | 971 | g = string_cat(g, US" SOCKS"); |
f2de3a33 | 972 | #endif |
7952eef9 | 973 | #ifdef SUPPORT_SPF |
ab1604ea | 974 | g = string_cat(g, US" SPF"); |
7952eef9 | 975 | #endif |
1a2e76e1 | 976 | #ifdef SUPPORT_DMARC |
ab1604ea | 977 | g = string_cat(g, US" DMARC"); |
1a2e76e1 | 978 | #endif |
1a2dfad5 | 979 | #ifdef TCP_FASTOPEN |
d85cdeb5 | 980 | tcp_init(); |
ab1604ea | 981 | if (f.tcp_fastopen_ok) g = string_cat(g, US" TCP_Fast_Open"); |
1a2dfad5 | 982 | #endif |
617d3932 | 983 | #ifdef EXPERIMENTAL_ARC |
ab1604ea | 984 | g = string_cat(g, US" Experimental_ARC"); |
617d3932 | 985 | #endif |
8523533c | 986 | #ifdef EXPERIMENTAL_BRIGHTMAIL |
ab1604ea | 987 | g = string_cat(g, US" Experimental_Brightmail"); |
8523533c | 988 | #endif |
6a8f9482 | 989 | #ifdef EXPERIMENTAL_DCC |
ab1604ea | 990 | g = string_cat(g, US" Experimental_DCC"); |
6a8f9482 | 991 | #endif |
895fbaf2 | 992 | #ifdef EXPERIMENTAL_DSN_INFO |
ab1604ea | 993 | g = string_cat(g, US" Experimental_DSN_info"); |
895fbaf2 | 994 | #endif |
ff966302 | 995 | #ifdef EXPERIMENTAL_LMDB |
ab1604ea | 996 | g = string_cat(g, US" Experimental_LMDB"); |
ff966302 JH |
997 | #endif |
998 | #ifdef EXPERIMENTAL_QUEUE_RAMP | |
ab1604ea | 999 | g = string_cat(g, US" Experimental_Queue_Ramp"); |
ff966302 JH |
1000 | #endif |
1001 | #ifdef EXPERIMENTAL_QUEUEFILE | |
ab1604ea | 1002 | g = string_cat(g, US" Experimental_QUEUEFILE"); |
ff966302 JH |
1003 | #endif |
1004 | #if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE) | |
ab1604ea | 1005 | g = string_cat(g, US" Experimental_SRS"); |
ff966302 | 1006 | #endif |
b10c87b3 | 1007 | #ifdef EXPERIMENTAL_TLS_RESUME |
ab1604ea | 1008 | g = string_cat(g, US" Experimental_TLS_resume"); |
b10c87b3 | 1009 | #endif |
ab1604ea | 1010 | g = string_cat(g, US"\n"); |
059ec3d9 | 1011 | |
ab1604ea | 1012 | g = string_cat(g, US"Lookups (built-in):"); |
e6d225ae | 1013 | #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2 |
ab1604ea | 1014 | g = string_cat(g, US" lsearch wildlsearch nwildlsearch iplsearch"); |
059ec3d9 | 1015 | #endif |
e6d225ae | 1016 | #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2 |
ab1604ea | 1017 | g = string_cat(g, US" cdb"); |
059ec3d9 | 1018 | #endif |
e6d225ae | 1019 | #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2 |
ab1604ea | 1020 | g = string_cat(g, US" dbm dbmjz dbmnz"); |
059ec3d9 | 1021 | #endif |
e6d225ae | 1022 | #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2 |
ab1604ea | 1023 | g = string_cat(g, US" dnsdb"); |
059ec3d9 | 1024 | #endif |
e6d225ae | 1025 | #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2 |
ab1604ea | 1026 | g = string_cat(g, US" dsearch"); |
059ec3d9 | 1027 | #endif |
e6d225ae | 1028 | #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2 |
ab1604ea | 1029 | g = string_cat(g, US" ibase"); |
059ec3d9 | 1030 | #endif |
ffc92d69 | 1031 | #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2 |
ab1604ea | 1032 | g = string_cat(g, US" json"); |
ffc92d69 | 1033 | #endif |
e6d225ae | 1034 | #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 |
ab1604ea | 1035 | g = string_cat(g, US" ldap ldapdn ldapm"); |
059ec3d9 | 1036 | #endif |
5bde3efa | 1037 | #ifdef EXPERIMENTAL_LMDB |
ab1604ea | 1038 | g = string_cat(g, US" lmdb"); |
5bde3efa | 1039 | #endif |
e6d225ae | 1040 | #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2 |
ab1604ea | 1041 | g = string_cat(g, US" mysql"); |
059ec3d9 | 1042 | #endif |
e6d225ae | 1043 | #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2 |
ab1604ea | 1044 | g = string_cat(g, US" nis nis0"); |
059ec3d9 | 1045 | #endif |
e6d225ae | 1046 | #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2 |
ab1604ea | 1047 | g = string_cat(g, US" nisplus"); |
059ec3d9 | 1048 | #endif |
e6d225ae | 1049 | #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2 |
ab1604ea | 1050 | g = string_cat(g, US" oracle"); |
059ec3d9 | 1051 | #endif |
e6d225ae | 1052 | #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2 |
ab1604ea | 1053 | g = string_cat(g, US" passwd"); |
059ec3d9 | 1054 | #endif |
e6d225ae | 1055 | #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2 |
ab1604ea | 1056 | g = string_cat(g, US" pgsql"); |
059ec3d9 | 1057 | #endif |
de78e2d5 | 1058 | #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2 |
ab1604ea | 1059 | g = string_cat(g, US" redis"); |
de78e2d5 | 1060 | #endif |
e6d225ae | 1061 | #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2 |
ab1604ea | 1062 | g = string_cat(g, US" sqlite"); |
13b685f9 | 1063 | #endif |
e6d225ae | 1064 | #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2 |
ab1604ea | 1065 | g = string_cat(g, US" testdb"); |
059ec3d9 | 1066 | #endif |
e6d225ae | 1067 | #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2 |
ab1604ea | 1068 | g = string_cat(g, US" whoson"); |
059ec3d9 | 1069 | #endif |
ab1604ea | 1070 | g = string_cat(g, US"\n"); |
059ec3d9 | 1071 | |
ab1604ea JH |
1072 | g = auth_show_supported(g); |
1073 | g = route_show_supported(g); | |
1074 | g = transport_show_supported(g); | |
059ec3d9 | 1075 | |
c11d665d | 1076 | #ifdef WITH_CONTENT_SCAN |
ab1604ea | 1077 | g = malware_show_supported(g); |
c11d665d JH |
1078 | #endif |
1079 | ||
059ec3d9 PH |
1080 | if (fixed_never_users[0] > 0) |
1081 | { | |
1082 | int i; | |
ab1604ea | 1083 | g = string_cat(g, US"Fixed never_users: "); |
059ec3d9 | 1084 | for (i = 1; i <= (int)fixed_never_users[0] - 1; i++) |
ab1604ea JH |
1085 | string_fmt_append(g, "%u:", (unsigned)fixed_never_users[i]); |
1086 | g = string_fmt_append(g, "%u\n", (unsigned)fixed_never_users[i]); | |
059ec3d9 | 1087 | } |
21c28500 | 1088 | |
ab1604ea JH |
1089 | g = string_fmt_append(g, "Configure owner: %d:%d\n", config_uid, config_gid); |
1090 | fputs(CS string_from_gstring(g), fp); | |
19bfe9e7 | 1091 | |
8768d548 | 1092 | fprintf(fp, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t)); |
36f12725 | 1093 | |
6545de78 PP |
1094 | /* Everything else is details which are only worth reporting when debugging. |
1095 | Perhaps the tls_version_report should move into this too. */ | |
1096 | DEBUG(D_any) do { | |
1097 | ||
b3c261f7 PP |
1098 | /* clang defines __GNUC__ (at least, for me) so test for it first */ |
1099 | #if defined(__clang__) | |
8768d548 | 1100 | fprintf(fp, "Compiler: CLang [%s]\n", __clang_version__); |
b3c261f7 | 1101 | #elif defined(__GNUC__) |
8768d548 | 1102 | fprintf(fp, "Compiler: GCC [%s]\n", |
b3c261f7 PP |
1103 | # ifdef __VERSION__ |
1104 | __VERSION__ | |
1105 | # else | |
1106 | "? unknown version ?" | |
1107 | # endif | |
1108 | ); | |
1109 | #else | |
8768d548 | 1110 | fprintf(fp, "Compiler: <unknown>\n"); |
b3c261f7 PP |
1111 | #endif |
1112 | ||
98913c8e | 1113 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
8768d548 | 1114 | fprintf(fp, "Library version: Glibc: Compile: %d.%d\n", |
01f3091a JH |
1115 | __GLIBC__, __GLIBC_MINOR__); |
1116 | if (__GLIBC_PREREQ(2, 1)) | |
8768d548 | 1117 | fprintf(fp, " Runtime: %s\n", |
01f3091a JH |
1118 | gnu_get_libc_version()); |
1119 | #endif | |
1120 | ||
8768d548 | 1121 | show_db_version(fp); |
96508de1 | 1122 | |
01603eec | 1123 | #ifndef DISABLE_TLS |
8768d548 | 1124 | tls_version_report(fp); |
754a0503 | 1125 | #endif |
8c5d388a | 1126 | #ifdef SUPPORT_I18N |
8768d548 | 1127 | utf8_version_report(fp); |
b04be5e7 | 1128 | #endif |
85e453f6 JH |
1129 | #ifdef SUPPORT_SPF |
1130 | spf_lib_version_report(fp); | |
1131 | #endif | |
754a0503 | 1132 | |
d7978c0f | 1133 | for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi) |
fc362fc5 | 1134 | if (authi->version_report) |
8768d548 | 1135 | (*authi->version_report)(fp); |
6545de78 | 1136 | |
decd95cb | 1137 | /* PCRE_PRERELEASE is either defined and empty or a bare sequence of |
6475bd82 PP |
1138 | characters; unless it's an ancient version of PCRE in which case it |
1139 | is not defined. */ | |
1140 | #ifndef PCRE_PRERELEASE | |
01f3091a | 1141 | # define PCRE_PRERELEASE |
6475bd82 PP |
1142 | #endif |
1143 | #define QUOTE(X) #X | |
1144 | #define EXPAND_AND_QUOTE(X) QUOTE(X) | |
8768d548 | 1145 | fprintf(fp, "Library version: PCRE: Compile: %d.%d%s\n" |
6545de78 PP |
1146 | " Runtime: %s\n", |
1147 | PCRE_MAJOR, PCRE_MINOR, | |
6475bd82 | 1148 | EXPAND_AND_QUOTE(PCRE_PRERELEASE) "", |
6545de78 | 1149 | pcre_version()); |
6475bd82 PP |
1150 | #undef QUOTE |
1151 | #undef EXPAND_AND_QUOTE | |
6545de78 PP |
1152 | |
1153 | init_lookup_list(); | |
d7978c0f | 1154 | for (int i = 0; i < lookup_list_count; i++) |
6545de78 | 1155 | if (lookup_list[i]->version_report) |
8768d548 | 1156 | lookup_list[i]->version_report(fp); |
6545de78 | 1157 | |
b70d2586 | 1158 | #ifdef WHITELIST_D_MACROS |
8768d548 | 1159 | fprintf(fp, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS); |
b70d2586 | 1160 | #else |
8768d548 | 1161 | fprintf(fp, "WHITELIST_D_MACROS unset\n"); |
b70d2586 PP |
1162 | #endif |
1163 | #ifdef TRUSTED_CONFIG_LIST | |
8768d548 | 1164 | fprintf(fp, "TRUSTED_CONFIG_LIST: \"%s\"\n", TRUSTED_CONFIG_LIST); |
b70d2586 | 1165 | #else |
8768d548 | 1166 | fprintf(fp, "TRUSTED_CONFIG_LIST unset\n"); |
b70d2586 PP |
1167 | #endif |
1168 | ||
6545de78 | 1169 | } while (0); |
ab1604ea | 1170 | store_reset(reset_point); |
059ec3d9 PH |
1171 | } |
1172 | ||
1173 | ||
98a90c36 PP |
1174 | /************************************************* |
1175 | * Show auxiliary information about Exim * | |
1176 | *************************************************/ | |
1177 | ||
1178 | static void | |
1179 | show_exim_information(enum commandline_info request, FILE *stream) | |
1180 | { | |
98a90c36 PP |
1181 | switch(request) |
1182 | { | |
1183 | case CMDINFO_NONE: | |
1184 | fprintf(stream, "Oops, something went wrong.\n"); | |
1185 | return; | |
1186 | case CMDINFO_HELP: | |
1187 | fprintf(stream, | |
1188 | "The -bI: flag takes a string indicating which information to provide.\n" | |
1189 | "If the string is not recognised, you'll get this help (on stderr).\n" | |
1190 | "\n" | |
1191 | " exim -bI:help this information\n" | |
030caf2a JS |
1192 | " exim -bI:dscp list of known dscp value keywords\n" |
1193 | " exim -bI:sieve list of supported sieve extensions\n" | |
98a90c36 PP |
1194 | ); |
1195 | return; | |
1196 | case CMDINFO_SIEVE: | |
d7978c0f | 1197 | for (const uschar ** pp = exim_sieve_extension_list; *pp; ++pp) |
98a90c36 PP |
1198 | fprintf(stream, "%s\n", *pp); |
1199 | return; | |
36a3ae5f PP |
1200 | case CMDINFO_DSCP: |
1201 | dscp_list_to_stream(stream); | |
1202 | return; | |
98a90c36 PP |
1203 | } |
1204 | } | |
059ec3d9 PH |
1205 | |
1206 | ||
1207 | /************************************************* | |
1208 | * Quote a local part * | |
1209 | *************************************************/ | |
1210 | ||
1211 | /* This function is used when a sender address or a From: or Sender: header | |
1212 | line is being created from the caller's login, or from an authenticated_id. It | |
1213 | applies appropriate quoting rules for a local part. | |
1214 | ||
1215 | Argument: the local part | |
1216 | Returns: the local part, quoted if necessary | |
1217 | */ | |
1218 | ||
1219 | uschar * | |
1220 | local_part_quote(uschar *lpart) | |
1221 | { | |
1222 | BOOL needs_quote = FALSE; | |
acec9514 | 1223 | gstring * g; |
059ec3d9 | 1224 | |
d7978c0f | 1225 | for (uschar * t = lpart; !needs_quote && *t != 0; t++) |
059ec3d9 PH |
1226 | { |
1227 | needs_quote = !isalnum(*t) && strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL && | |
1228 | (*t != '.' || t == lpart || t[1] == 0); | |
1229 | } | |
1230 | ||
1231 | if (!needs_quote) return lpart; | |
1232 | ||
acec9514 | 1233 | g = string_catn(NULL, US"\"", 1); |
059ec3d9 PH |
1234 | |
1235 | for (;;) | |
1236 | { | |
1237 | uschar *nq = US Ustrpbrk(lpart, "\\\""); | |
1238 | if (nq == NULL) | |
1239 | { | |
acec9514 | 1240 | g = string_cat(g, lpart); |
059ec3d9 PH |
1241 | break; |
1242 | } | |
acec9514 JH |
1243 | g = string_catn(g, lpart, nq - lpart); |
1244 | g = string_catn(g, US"\\", 1); | |
1245 | g = string_catn(g, nq, 1); | |
059ec3d9 PH |
1246 | lpart = nq + 1; |
1247 | } | |
1248 | ||
acec9514 JH |
1249 | g = string_catn(g, US"\"", 1); |
1250 | return string_from_gstring(g); | |
059ec3d9 PH |
1251 | } |
1252 | ||
1253 | ||
1254 | ||
1255 | #ifdef USE_READLINE | |
1256 | /************************************************* | |
1257 | * Load readline() functions * | |
1258 | *************************************************/ | |
1259 | ||
1260 | /* This function is called from testing executions that read data from stdin, | |
1261 | but only when running as the calling user. Currently, only -be does this. The | |
1262 | function loads the readline() function library and passes back the functions. | |
1263 | On some systems, it needs the curses library, so load that too, but try without | |
1264 | it if loading fails. All this functionality has to be requested at build time. | |
1265 | ||
1266 | Arguments: | |
1267 | fn_readline_ptr pointer to where to put the readline pointer | |
1268 | fn_addhist_ptr pointer to where to put the addhistory function | |
1269 | ||
1270 | Returns: the dlopen handle or NULL on failure | |
1271 | */ | |
1272 | ||
1273 | static void * | |
1ba28e2b PP |
1274 | set_readline(char * (**fn_readline_ptr)(const char *), |
1275 | void (**fn_addhist_ptr)(const char *)) | |
059ec3d9 PH |
1276 | { |
1277 | void *dlhandle; | |
e12f8c32 | 1278 | void *dlhandle_curses = dlopen("libcurses." DYNLIB_FN_EXT, RTLD_GLOBAL|RTLD_LAZY); |
059ec3d9 | 1279 | |
e12f8c32 | 1280 | dlhandle = dlopen("libreadline." DYNLIB_FN_EXT, RTLD_GLOBAL|RTLD_NOW); |
b1c673dd | 1281 | if (dlhandle_curses) dlclose(dlhandle_curses); |
059ec3d9 | 1282 | |
b1c673dd | 1283 | if (dlhandle) |
059ec3d9 | 1284 | { |
1ba28e2b PP |
1285 | /* Checked manual pages; at least in GNU Readline 6.1, the prototypes are: |
1286 | * char * readline (const char *prompt); | |
1287 | * void add_history (const char *string); | |
1288 | */ | |
1289 | *fn_readline_ptr = (char *(*)(const char*))dlsym(dlhandle, "readline"); | |
1290 | *fn_addhist_ptr = (void(*)(const char*))dlsym(dlhandle, "add_history"); | |
059ec3d9 PH |
1291 | } |
1292 | else | |
059ec3d9 | 1293 | DEBUG(D_any) debug_printf("failed to load readline: %s\n", dlerror()); |
059ec3d9 PH |
1294 | |
1295 | return dlhandle; | |
1296 | } | |
1297 | #endif | |
1298 | ||
1299 | ||
1300 | ||
1301 | /************************************************* | |
1302 | * Get a line from stdin for testing things * | |
1303 | *************************************************/ | |
1304 | ||
1305 | /* This function is called when running tests that can take a number of lines | |
1306 | of input (for example, -be and -bt). It handles continuations and trailing | |
1307 | spaces. And prompting and a blank line output on eof. If readline() is in use, | |
1308 | the arguments are non-NULL and provide the relevant functions. | |
1309 | ||
1310 | Arguments: | |
1311 | fn_readline readline function or NULL | |
1312 | fn_addhist addhist function or NULL | |
1313 | ||
1314 | Returns: pointer to dynamic memory, or NULL at end of file | |
1315 | */ | |
1316 | ||
1317 | static uschar * | |
1ba28e2b | 1318 | get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *)) |
059ec3d9 | 1319 | { |
acec9514 | 1320 | gstring * g = NULL; |
059ec3d9 | 1321 | |
acec9514 | 1322 | if (!fn_readline) { printf("> "); fflush(stdout); } |
059ec3d9 | 1323 | |
d7978c0f | 1324 | for (int i = 0;; i++) |
059ec3d9 PH |
1325 | { |
1326 | uschar buffer[1024]; | |
1327 | uschar *p, *ss; | |
1328 | ||
1329 | #ifdef USE_READLINE | |
1330 | char *readline_line = NULL; | |
f3ebb786 | 1331 | if (fn_readline) |
059ec3d9 | 1332 | { |
f3ebb786 JH |
1333 | if (!(readline_line = fn_readline((i > 0)? "":"> "))) break; |
1334 | if (*readline_line != 0 && fn_addhist) fn_addhist(readline_line); | |
059ec3d9 PH |
1335 | p = US readline_line; |
1336 | } | |
1337 | else | |
1338 | #endif | |
1339 | ||
1340 | /* readline() not in use */ | |
1341 | ||
1342 | { | |
1343 | if (Ufgets(buffer, sizeof(buffer), stdin) == NULL) break; | |
1344 | p = buffer; | |
1345 | } | |
1346 | ||
1347 | /* Handle the line */ | |
1348 | ||
1349 | ss = p + (int)Ustrlen(p); | |
1350 | while (ss > p && isspace(ss[-1])) ss--; | |
1351 | ||
1352 | if (i > 0) | |
059ec3d9 | 1353 | while (p < ss && isspace(*p)) p++; /* leading space after cont */ |
059ec3d9 | 1354 | |
acec9514 | 1355 | g = string_catn(g, p, ss - p); |
059ec3d9 PH |
1356 | |
1357 | #ifdef USE_READLINE | |
acec9514 | 1358 | if (fn_readline) free(readline_line); |
059ec3d9 PH |
1359 | #endif |
1360 | ||
acec9514 JH |
1361 | /* g can only be NULL if ss==p */ |
1362 | if (ss == p || g->s[g->ptr-1] != '\\') | |
059ec3d9 | 1363 | break; |
acec9514 JH |
1364 | |
1365 | --g->ptr; | |
1366 | (void) string_from_gstring(g); | |
059ec3d9 PH |
1367 | } |
1368 | ||
acec9514 JH |
1369 | if (!g) printf("\n"); |
1370 | return string_from_gstring(g); | |
059ec3d9 PH |
1371 | } |
1372 | ||
1373 | ||
1374 | ||
81ea09ca NM |
1375 | /************************************************* |
1376 | * Output usage information for the program * | |
1377 | *************************************************/ | |
1378 | ||
1379 | /* This function is called when there are no recipients | |
1380 | or a specific --help argument was added. | |
1381 | ||
1382 | Arguments: | |
1383 | progname information on what name we were called by | |
1384 | ||
1385 | Returns: DOES NOT RETURN | |
1386 | */ | |
1387 | ||
1388 | static void | |
1389 | exim_usage(uschar *progname) | |
1390 | { | |
1391 | ||
4c04137d | 1392 | /* Handle specific program invocation variants */ |
81ea09ca | 1393 | if (Ustrcmp(progname, US"-mailq") == 0) |
9af3c549 | 1394 | exim_fail( |
e765a0f1 | 1395 | "mailq - list the contents of the mail queue\n\n" |
81ea09ca | 1396 | "For a list of options, see the Exim documentation.\n"); |
81ea09ca NM |
1397 | |
1398 | /* Generic usage - we output this whatever happens */ | |
9af3c549 | 1399 | exim_fail( |
81ea09ca NM |
1400 | "Exim is a Mail Transfer Agent. It is normally called by Mail User Agents,\n" |
1401 | "not directly from a shell command line. Options and/or arguments control\n" | |
1402 | "what it does when called. For a list of options, see the Exim documentation.\n"); | |
81ea09ca NM |
1403 | } |
1404 | ||
1405 | ||
1406 | ||
a7cbbf50 PP |
1407 | /************************************************* |
1408 | * Validate that the macros given are okay * | |
1409 | *************************************************/ | |
1410 | ||
1411 | /* Typically, Exim will drop privileges if macros are supplied. In some | |
1412 | cases, we want to not do so. | |
1413 | ||
a4034eb8 | 1414 | Arguments: opt_D_used - true if the commandline had a "-D" option |
a7cbbf50 PP |
1415 | Returns: true if trusted, false otherwise |
1416 | */ | |
1417 | ||
1418 | static BOOL | |
a4034eb8 | 1419 | macros_trusted(BOOL opt_D_used) |
a7cbbf50 PP |
1420 | { |
1421 | #ifdef WHITELIST_D_MACROS | |
d7978c0f | 1422 | uschar *whitelisted, *end, *p, **whites; |
a7cbbf50 PP |
1423 | int white_count, i, n; |
1424 | size_t len; | |
1425 | BOOL prev_char_item, found; | |
1426 | #endif | |
1427 | ||
a4034eb8 | 1428 | if (!opt_D_used) |
a7cbbf50 PP |
1429 | return TRUE; |
1430 | #ifndef WHITELIST_D_MACROS | |
1431 | return FALSE; | |
1432 | #else | |
1433 | ||
66581d1e PP |
1434 | /* We only trust -D overrides for some invoking users: |
1435 | root, the exim run-time user, the optional config owner user. | |
1436 | I don't know why config-owner would be needed, but since they can own the | |
1437 | config files anyway, there's no security risk to letting them override -D. */ | |
1438 | if ( ! ((real_uid == root_uid) | |
1439 | || (real_uid == exim_uid) | |
1440 | #ifdef CONFIGURE_OWNER | |
1441 | || (real_uid == config_uid) | |
1442 | #endif | |
1443 | )) | |
1444 | { | |
1445 | debug_printf("macros_trusted rejecting macros for uid %d\n", (int) real_uid); | |
1446 | return FALSE; | |
1447 | } | |
1448 | ||
a7cbbf50 | 1449 | /* Get a list of macros which are whitelisted */ |
f3ebb786 | 1450 | whitelisted = string_copy_perm(US WHITELIST_D_MACROS, FALSE); |
a7cbbf50 PP |
1451 | prev_char_item = FALSE; |
1452 | white_count = 0; | |
1453 | for (p = whitelisted; *p != '\0'; ++p) | |
1454 | { | |
1455 | if (*p == ':' || isspace(*p)) | |
1456 | { | |
1457 | *p = '\0'; | |
1458 | if (prev_char_item) | |
1459 | ++white_count; | |
1460 | prev_char_item = FALSE; | |
1461 | continue; | |
1462 | } | |
1463 | if (!prev_char_item) | |
1464 | prev_char_item = TRUE; | |
1465 | } | |
1466 | end = p; | |
1467 | if (prev_char_item) | |
1468 | ++white_count; | |
1469 | if (!white_count) | |
1470 | return FALSE; | |
1471 | whites = store_malloc(sizeof(uschar *) * (white_count+1)); | |
1472 | for (p = whitelisted, i = 0; (p != end) && (i < white_count); ++p) | |
1473 | { | |
1474 | if (*p != '\0') | |
1475 | { | |
1476 | whites[i++] = p; | |
1477 | if (i == white_count) | |
1478 | break; | |
1479 | while (*p != '\0' && p < end) | |
1480 | ++p; | |
1481 | } | |
1482 | } | |
1483 | whites[i] = NULL; | |
1484 | ||
1a7c9a48 JH |
1485 | /* The list of commandline macros should be very short. |
1486 | Accept the N*M complexity. */ | |
d7978c0f | 1487 | for (macro_item * m = macros_user; m; m = m->next) if (m->command_line) |
1a7c9a48 JH |
1488 | { |
1489 | found = FALSE; | |
d7978c0f | 1490 | for (uschar ** w = whites; *w; ++w) |
1a7c9a48 JH |
1491 | if (Ustrcmp(*w, m->name) == 0) |
1492 | { | |
1493 | found = TRUE; | |
1494 | break; | |
1495 | } | |
1496 | if (!found) | |
1497 | return FALSE; | |
1498 | if (!m->replacement) | |
1499 | continue; | |
1500 | if ((len = m->replen) == 0) | |
1501 | continue; | |
1502 | n = pcre_exec(regex_whitelisted_macro, NULL, CS m->replacement, len, | |
1503 | 0, PCRE_EOPT, NULL, 0); | |
1504 | if (n < 0) | |
1505 | { | |
1506 | if (n != PCRE_ERROR_NOMATCH) | |
1507 | debug_printf("macros_trusted checking %s returned %d\n", m->name, n); | |
1508 | return FALSE; | |
1509 | } | |
1510 | } | |
43236f35 | 1511 | DEBUG(D_any) debug_printf("macros_trusted overridden to true by whitelisting\n"); |
a7cbbf50 PP |
1512 | return TRUE; |
1513 | #endif | |
1514 | } | |
1515 | ||
1516 | ||
9650d98a JH |
1517 | /************************************************* |
1518 | * Expansion testing * | |
1519 | *************************************************/ | |
1520 | ||
1521 | /* Expand and print one item, doing macro-processing. | |
1522 | ||
1523 | Arguments: | |
1524 | item line for expansion | |
1525 | */ | |
1526 | ||
1527 | static void | |
1528 | expansion_test_line(uschar * line) | |
1529 | { | |
1530 | int len; | |
1531 | BOOL dummy_macexp; | |
1532 | ||
1533 | Ustrncpy(big_buffer, line, big_buffer_size); | |
1534 | big_buffer[big_buffer_size-1] = '\0'; | |
1535 | len = Ustrlen(big_buffer); | |
1536 | ||
1537 | (void) macros_expand(0, &len, &dummy_macexp); | |
1538 | ||
1539 | if (isupper(big_buffer[0])) | |
1540 | { | |
1541 | if (macro_read_assignment(big_buffer)) | |
1a7c9a48 | 1542 | printf("Defined macro '%s'\n", mlast->name); |
9650d98a JH |
1543 | } |
1544 | else | |
1545 | if ((line = expand_string(big_buffer))) printf("%s\n", CS line); | |
1546 | else printf("Failed: %s\n", expand_string_message); | |
1547 | } | |
1548 | ||
1549 | ||
9af3c549 | 1550 | |
059ec3d9 PH |
1551 | /************************************************* |
1552 | * Entry point and high-level code * | |
1553 | *************************************************/ | |
1554 | ||
1555 | /* Entry point for the Exim mailer. Analyse the arguments and arrange to take | |
1556 | the appropriate action. All the necessary functions are present in the one | |
1557 | binary. I originally thought one should split it up, but it turns out that so | |
1558 | much of the apparatus is needed in each chunk that one might as well just have | |
1559 | it all available all the time, which then makes the coding easier as well. | |
1560 | ||
1561 | Arguments: | |
1562 | argc count of entries in argv | |
1563 | argv argument strings, with argv[0] being the program name | |
1564 | ||
1565 | Returns: EXIT_SUCCESS if terminated successfully | |
1566 | EXIT_FAILURE otherwise, except when a message has been sent | |
1567 | to the sender, and -oee was given | |
1568 | */ | |
1569 | ||
1570 | int | |
1571 | main(int argc, char **cargv) | |
1572 | { | |
1573 | uschar **argv = USS cargv; | |
1574 | int arg_receive_timeout = -1; | |
1575 | int arg_smtp_receive_timeout = -1; | |
1576 | int arg_error_handling = error_handling; | |
f05da2e8 PH |
1577 | int filter_sfd = -1; |
1578 | int filter_ufd = -1; | |
059ec3d9 | 1579 | int group_count; |
1670ef10 | 1580 | int i, rv; |
059ec3d9 PH |
1581 | int list_queue_option = 0; |
1582 | int msg_action = 0; | |
1583 | int msg_action_arg = -1; | |
1584 | int namelen = (argv[0] == NULL)? 0 : Ustrlen(argv[0]); | |
1585 | int queue_only_reason = 0; | |
1586 | #ifdef EXIM_PERL | |
1587 | int perl_start_option = 0; | |
1588 | #endif | |
1589 | int recipients_arg = argc; | |
1590 | int sender_address_domain = 0; | |
1591 | int test_retry_arg = -1; | |
1592 | int test_rewrite_arg = -1; | |
3b7ac02c | 1593 | gid_t original_egid; |
059ec3d9 PH |
1594 | BOOL arg_queue_only = FALSE; |
1595 | BOOL bi_option = FALSE; | |
1596 | BOOL checking = FALSE; | |
1597 | BOOL count_queue = FALSE; | |
1598 | BOOL expansion_test = FALSE; | |
1599 | BOOL extract_recipients = FALSE; | |
f4ee74ac | 1600 | BOOL flag_G = FALSE; |
12f69989 | 1601 | BOOL flag_n = FALSE; |
059ec3d9 PH |
1602 | BOOL forced_delivery = FALSE; |
1603 | BOOL f_end_dot = FALSE; | |
1604 | BOOL deliver_give_up = FALSE; | |
1605 | BOOL list_queue = FALSE; | |
1606 | BOOL list_options = FALSE; | |
bf3c2c6b | 1607 | BOOL list_config = FALSE; |
059ec3d9 PH |
1608 | BOOL local_queue_only; |
1609 | BOOL more = TRUE; | |
1610 | BOOL one_msg_action = FALSE; | |
4ab69ec7 | 1611 | BOOL opt_D_used = FALSE; |
059ec3d9 PH |
1612 | BOOL queue_only_set = FALSE; |
1613 | BOOL receiving_message = TRUE; | |
33d73e3b | 1614 | BOOL sender_ident_set = FALSE; |
8669f003 | 1615 | BOOL session_local_queue_only; |
059ec3d9 PH |
1616 | BOOL unprivileged; |
1617 | BOOL removed_privilege = FALSE; | |
81ea09ca | 1618 | BOOL usage_wanted = FALSE; |
059ec3d9 PH |
1619 | BOOL verify_address_mode = FALSE; |
1620 | BOOL verify_as_sender = FALSE; | |
1621 | BOOL version_printed = FALSE; | |
1622 | uschar *alias_arg = NULL; | |
1623 | uschar *called_as = US""; | |
a3fb9793 | 1624 | uschar *cmdline_syslog_name = NULL; |
059ec3d9 PH |
1625 | uschar *start_queue_run_id = NULL; |
1626 | uschar *stop_queue_run_id = NULL; | |
328895cc | 1627 | uschar *expansion_test_message = NULL; |
059ec3d9 PH |
1628 | uschar *ftest_domain = NULL; |
1629 | uschar *ftest_localpart = NULL; | |
1630 | uschar *ftest_prefix = NULL; | |
1631 | uschar *ftest_suffix = NULL; | |
0ad2e0fc | 1632 | uschar *log_oneline = NULL; |
8544e77a | 1633 | uschar *malware_test_file = NULL; |
059ec3d9 PH |
1634 | uschar *real_sender_address; |
1635 | uschar *originator_home = US"/"; | |
a3fb9793 | 1636 | size_t sz; |
059ec3d9 PH |
1637 | |
1638 | struct passwd *pw; | |
1639 | struct stat statbuf; | |
1640 | pid_t passed_qr_pid = (pid_t)0; | |
1641 | int passed_qr_pipe = -1; | |
157d73b5 | 1642 | gid_t group_list[EXIM_GROUPLIST_SIZE]; |
059ec3d9 | 1643 | |
98a90c36 PP |
1644 | /* For the -bI: flag */ |
1645 | enum commandline_info info_flag = CMDINFO_NONE; | |
1646 | BOOL info_stdout = FALSE; | |
1647 | ||
059ec3d9 PH |
1648 | /* Possible options for -R and -S */ |
1649 | ||
1650 | static uschar *rsopts[] = { US"f", US"ff", US"r", US"rf", US"rff" }; | |
1651 | ||
1652 | /* Need to define this in case we need to change the environment in order | |
1653 | to get rid of a bogus time zone. We have to make it char rather than uschar | |
1654 | because some OS define it in /usr/include/unistd.h. */ | |
1655 | ||
1656 | extern char **environ; | |
1657 | ||
9f01e50d JH |
1658 | #ifdef MEASURE_TIMING |
1659 | (void)gettimeofday(×tamp_startup, NULL); | |
1660 | #endif | |
1661 | ||
35edf2ff | 1662 | /* If the Exim user and/or group and/or the configuration file owner/group were |
059ec3d9 PH |
1663 | defined by ref:name at build time, we must now find the actual uid/gid values. |
1664 | This is a feature to make the lives of binary distributors easier. */ | |
1665 | ||
1666 | #ifdef EXIM_USERNAME | |
1667 | if (route_finduser(US EXIM_USERNAME, &pw, &exim_uid)) | |
1668 | { | |
10385c15 | 1669 | if (exim_uid == 0) |
9af3c549 JH |
1670 | exim_fail("exim: refusing to run with uid 0 for \"%s\"\n", EXIM_USERNAME); |
1671 | ||
084c1d8c PP |
1672 | /* If ref:name uses a number as the name, route_finduser() returns |
1673 | TRUE with exim_uid set and pw coerced to NULL. */ | |
1674 | if (pw) | |
1675 | exim_gid = pw->pw_gid; | |
1676 | #ifndef EXIM_GROUPNAME | |
1677 | else | |
9af3c549 | 1678 | exim_fail( |
084c1d8c PP |
1679 | "exim: ref:name should specify a usercode, not a group.\n" |
1680 | "exim: can't let you get away with it unless you also specify a group.\n"); | |
084c1d8c | 1681 | #endif |
059ec3d9 PH |
1682 | } |
1683 | else | |
9af3c549 | 1684 | exim_fail("exim: failed to find uid for user name \"%s\"\n", EXIM_USERNAME); |
059ec3d9 PH |
1685 | #endif |
1686 | ||
1687 | #ifdef EXIM_GROUPNAME | |
1688 | if (!route_findgroup(US EXIM_GROUPNAME, &exim_gid)) | |
9af3c549 | 1689 | exim_fail("exim: failed to find gid for group name \"%s\"\n", EXIM_GROUPNAME); |
059ec3d9 PH |
1690 | #endif |
1691 | ||
1692 | #ifdef CONFIGURE_OWNERNAME | |
1693 | if (!route_finduser(US CONFIGURE_OWNERNAME, NULL, &config_uid)) | |
9af3c549 | 1694 | exim_fail("exim: failed to find uid for user name \"%s\"\n", |
059ec3d9 | 1695 | CONFIGURE_OWNERNAME); |
059ec3d9 PH |
1696 | #endif |
1697 | ||
79d4bc3d PP |
1698 | /* We default the system_filter_user to be the Exim run-time user, as a |
1699 | sane non-root value. */ | |
1700 | system_filter_uid = exim_uid; | |
1701 | ||
35edf2ff PH |
1702 | #ifdef CONFIGURE_GROUPNAME |
1703 | if (!route_findgroup(US CONFIGURE_GROUPNAME, &config_gid)) | |
9af3c549 | 1704 | exim_fail("exim: failed to find gid for group name \"%s\"\n", |
35edf2ff | 1705 | CONFIGURE_GROUPNAME); |
35edf2ff PH |
1706 | #endif |
1707 | ||
92e6a3d9 JH |
1708 | /* In the Cygwin environment, some initialization used to need doing. |
1709 | It was fudged in by means of this macro; now no longer but we'll leave | |
1710 | it in case of others. */ | |
059ec3d9 PH |
1711 | |
1712 | #ifdef OS_INIT | |
1713 | OS_INIT | |
1714 | #endif | |
1715 | ||
1716 | /* Check a field which is patched when we are running Exim within its | |
1717 | testing harness; do a fast initial check, and then the whole thing. */ | |
1718 | ||
8768d548 | 1719 | f.running_in_test_harness = |
059ec3d9 | 1720 | *running_status == '<' && Ustrcmp(running_status, "<<<testing>>>") == 0; |
8768d548 | 1721 | if (f.running_in_test_harness) |
65a32f85 | 1722 | debug_store = TRUE; |
059ec3d9 PH |
1723 | |
1724 | /* The C standard says that the equivalent of setlocale(LC_ALL, "C") is obeyed | |
1725 | at the start of a program; however, it seems that some environments do not | |
1726 | follow this. A "strange" locale can affect the formatting of timestamps, so we | |
1727 | make quite sure. */ | |
1728 | ||
1729 | setlocale(LC_ALL, "C"); | |
1730 | ||
6906c131 JH |
1731 | /* Get the offset between CLOCK_MONOTONIC and wallclock */ |
1732 | ||
1733 | #ifdef _POSIX_MONOTONIC_CLOCK | |
1734 | exim_clock_init(); | |
1735 | #endif | |
1736 | ||
059ec3d9 PH |
1737 | /* Set up the default handler for timing using alarm(). */ |
1738 | ||
1739 | os_non_restarting_signal(SIGALRM, sigalrm_handler); | |
1740 | ||
1741 | /* Ensure we have a buffer for constructing log entries. Use malloc directly, | |
1742 | because store_malloc writes a log entry on failure. */ | |
1743 | ||
40c90bca | 1744 | if (!(log_buffer = US malloc(LOG_BUFFER_SIZE))) |
9af3c549 | 1745 | exim_fail("exim: failed to get store for log buffer\n"); |
059ec3d9 | 1746 | |
6c6d6e48 TF |
1747 | /* Initialize the default log options. */ |
1748 | ||
1749 | bits_set(log_selector, log_selector_size, log_default); | |
1750 | ||
059ec3d9 PH |
1751 | /* Set log_stderr to stderr, provided that stderr exists. This gets reset to |
1752 | NULL when the daemon is run and the file is closed. We have to use this | |
1753 | indirection, because some systems don't allow writing to the variable "stderr". | |
1754 | */ | |
1755 | ||
1756 | if (fstat(fileno(stderr), &statbuf) >= 0) log_stderr = stderr; | |
1757 | ||
1758 | /* Arrange for the PCRE regex library to use our store functions. Note that | |
1759 | the normal calls are actually macros that add additional arguments for | |
1760 | debugging purposes so we have to assign specially constructed functions here. | |
1761 | The default is to use store in the stacking pool, but this is overridden in the | |
1762 | regex_must_compile() function. */ | |
1763 | ||
1764 | pcre_malloc = function_store_get; | |
1765 | pcre_free = function_dummy_free; | |
1766 | ||
1767 | /* Ensure there is a big buffer for temporary use in several places. It is put | |
1768 | in malloc store so that it can be freed for enlargement if necessary. */ | |
1769 | ||
1770 | big_buffer = store_malloc(big_buffer_size); | |
1771 | ||
1772 | /* Set up the handler for the data request signal, and set the initial | |
1773 | descriptive text. */ | |
1774 | ||
f3ebb786 | 1775 | process_info = store_get(PROCESS_INFO_SIZE, TRUE); /* tainted */ |
059ec3d9 PH |
1776 | set_process_info("initializing"); |
1777 | os_restarting_signal(SIGUSR1, usr1_handler); | |
1778 | ||
830832c9 HSHR |
1779 | /* If running in a dockerized environment, the TERM signal is only |
1780 | delegated to the PID 1 if we request it by setting an signal handler */ | |
1781 | if (getpid() == 1) signal(SIGTERM, term_handler); | |
1782 | ||
059ec3d9 PH |
1783 | /* SIGHUP is used to get the daemon to reconfigure. It gets set as appropriate |
1784 | in the daemon code. For the rest of Exim's uses, we ignore it. */ | |
1785 | ||
1786 | signal(SIGHUP, SIG_IGN); | |
1787 | ||
1788 | /* We don't want to die on pipe errors as the code is written to handle | |
1789 | the write error instead. */ | |
1790 | ||
1791 | signal(SIGPIPE, SIG_IGN); | |
1792 | ||
1793 | /* Under some circumstance on some OS, Exim can get called with SIGCHLD | |
1794 | set to SIG_IGN. This causes subprocesses that complete before the parent | |
1795 | process waits for them not to hang around, so when Exim calls wait(), nothing | |
1796 | is there. The wait() code has been made robust against this, but let's ensure | |
1797 | that SIGCHLD is set to SIG_DFL, because it's tidier to wait and get a process | |
1798 | ending status. We use sigaction rather than plain signal() on those OS where | |
1799 | SA_NOCLDWAIT exists, because we want to be sure it is turned off. (There was a | |
1800 | problem on AIX with this.) */ | |
1801 | ||
1802 | #ifdef SA_NOCLDWAIT | |
1803 | { | |
1804 | struct sigaction act; | |
1805 | act.sa_handler = SIG_DFL; | |
1806 | sigemptyset(&(act.sa_mask)); | |
1807 | act.sa_flags = 0; | |
1808 | sigaction(SIGCHLD, &act, NULL); | |
1809 | } | |
1810 | #else | |
1811 | signal(SIGCHLD, SIG_DFL); | |
1812 | #endif | |
1813 | ||
1814 | /* Save the arguments for use if we re-exec exim as a daemon after receiving | |
1815 | SIGHUP. */ | |
1816 | ||
1817 | sighup_argv = argv; | |
1818 | ||
1819 | /* Set up the version number. Set up the leading 'E' for the external form of | |
1820 | message ids, set the pointer to the internal form, and initialize it to | |
1821 | indicate no message being processed. */ | |
1822 | ||
1823 | version_init(); | |
1824 | message_id_option[0] = '-'; | |
1825 | message_id_external = message_id_option + 1; | |
1826 | message_id_external[0] = 'E'; | |
1827 | message_id = message_id_external + 1; | |
1828 | message_id[0] = 0; | |
1829 | ||
67d175de | 1830 | /* Set the umask to zero so that any files Exim creates using open() are |
2632889e PH |
1831 | created with the modes that it specifies. NOTE: Files created with fopen() have |
1832 | a problem, which was not recognized till rather late (February 2006). With this | |
1833 | umask, such files will be world writeable. (They are all content scanning files | |
1834 | in the spool directory, which isn't world-accessible, so this is not a | |
1835 | disaster, but it's untidy.) I don't want to change this overall setting, | |
1836 | however, because it will interact badly with the open() calls. Instead, there's | |
1837 | now a function called modefopen() that fiddles with the umask while calling | |
1838 | fopen(). */ | |
059ec3d9 | 1839 | |
67d175de | 1840 | (void)umask(0); |
059ec3d9 PH |
1841 | |
1842 | /* Precompile the regular expression for matching a message id. Keep this in | |
1843 | step with the code that generates ids in the accept.c module. We need to do | |
1844 | this here, because the -M options check their arguments for syntactic validity | |
1845 | using mac_ismsgid, which uses this. */ | |
1846 | ||
1847 | regex_ismsgid = | |
1848 | regex_must_compile(US"^(?:[^\\W_]{6}-){2}[^\\W_]{2}$", FALSE, TRUE); | |
1849 | ||
a5bd321b | 1850 | /* Precompile the regular expression that is used for matching an SMTP error |
d6a96edc PH |
1851 | code, possibly extended, at the start of an error message. Note that the |
1852 | terminating whitespace character is included. */ | |
a5bd321b PH |
1853 | |
1854 | regex_smtp_code = | |
1855 | regex_must_compile(US"^\\d\\d\\d\\s(?:\\d\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\s)?", | |
1856 | FALSE, TRUE); | |
1857 | ||
a7cbbf50 PP |
1858 | #ifdef WHITELIST_D_MACROS |
1859 | /* Precompile the regular expression used to filter the content of macros | |
1860 | given to -D for permissibility. */ | |
1861 | ||
1862 | regex_whitelisted_macro = | |
1863 | regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE); | |
1864 | #endif | |
1865 | ||
f38917cc JH |
1866 | for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; |
1867 | ||
059ec3d9 PH |
1868 | /* If the program is called as "mailq" treat it as equivalent to "exim -bp"; |
1869 | this seems to be a generally accepted convention, since one finds symbolic | |
1870 | links called "mailq" in standard OS configurations. */ | |
1871 | ||
1872 | if ((namelen == 5 && Ustrcmp(argv[0], "mailq") == 0) || | |
1873 | (namelen > 5 && Ustrncmp(argv[0] + namelen - 6, "/mailq", 6) == 0)) | |
1874 | { | |
1875 | list_queue = TRUE; | |
1876 | receiving_message = FALSE; | |
1877 | called_as = US"-mailq"; | |
1878 | } | |
1879 | ||
1880 | /* If the program is called as "rmail" treat it as equivalent to | |
1881 | "exim -i -oee", thus allowing UUCP messages to be input using non-SMTP mode, | |
1882 | i.e. preventing a single dot on a line from terminating the message, and | |
1883 | returning with zero return code, even in cases of error (provided an error | |
1884 | message has been sent). */ | |
1885 | ||
1886 | if ((namelen == 5 && Ustrcmp(argv[0], "rmail") == 0) || | |
1887 | (namelen > 5 && Ustrncmp(argv[0] + namelen - 6, "/rmail", 6) == 0)) | |
1888 | { | |
8768d548 | 1889 | f.dot_ends = FALSE; |
059ec3d9 PH |
1890 | called_as = US"-rmail"; |
1891 | errors_sender_rc = EXIT_SUCCESS; | |
1892 | } | |
1893 | ||
1894 | /* If the program is called as "rsmtp" treat it as equivalent to "exim -bS"; | |
1895 | this is a smail convention. */ | |
1896 | ||
1897 | if ((namelen == 5 && Ustrcmp(argv[0], "rsmtp") == 0) || | |
1898 | (namelen > 5 && Ustrncmp(argv[0] + namelen - 6, "/rsmtp", 6) == 0)) | |
1899 | { | |
1900 | smtp_input = smtp_batched_input = TRUE; | |
1901 | called_as = US"-rsmtp"; | |
1902 | } | |
1903 | ||
1904 | /* If the program is called as "runq" treat it as equivalent to "exim -q"; | |
1905 | this is a smail convention. */ | |
1906 | ||
1907 | if ((namelen == 4 && Ustrcmp(argv[0], "runq") == 0) || | |
1908 | (namelen > 4 && Ustrncmp(argv[0] + namelen - 5, "/runq", 5) == 0)) | |
1909 | { | |
1910 | queue_interval = 0; | |
1911 | receiving_message = FALSE; | |
1912 | called_as = US"-runq"; | |
1913 | } | |
1914 | ||
1915 | /* If the program is called as "newaliases" treat it as equivalent to | |
1916 | "exim -bi"; this is a sendmail convention. */ | |
1917 | ||
1918 | if ((namelen == 10 && Ustrcmp(argv[0], "newaliases") == 0) || | |
1919 | (namelen > 10 && Ustrncmp(argv[0] + namelen - 11, "/newaliases", 11) == 0)) | |
1920 | { | |
1921 | bi_option = TRUE; | |
1922 | receiving_message = FALSE; | |
1923 | called_as = US"-newaliases"; | |
1924 | } | |
1925 | ||
1926 | /* Save the original effective uid for a couple of uses later. It should | |
1927 | normally be root, but in some esoteric environments it may not be. */ | |
1928 | ||
1929 | original_euid = geteuid(); | |
3b7ac02c | 1930 | original_egid = getegid(); |
059ec3d9 PH |
1931 | |
1932 | /* Get the real uid and gid. If the caller is root, force the effective uid/gid | |
1933 | to be the same as the real ones. This makes a difference only if Exim is setuid | |
1934 | (or setgid) to something other than root, which could be the case in some | |
1935 | special configurations. */ | |
1936 | ||
1937 | real_uid = getuid(); | |
1938 | real_gid = getgid(); | |
1939 | ||
1940 | if (real_uid == root_uid) | |
1941 | { | |
9af3c549 JH |
1942 | if ((rv = setgid(real_gid))) |
1943 | exim_fail("exim: setgid(%ld) failed: %s\n", | |
1670ef10 | 1944 | (long int)real_gid, strerror(errno)); |
9af3c549 JH |
1945 | if ((rv = setuid(real_uid))) |
1946 | exim_fail("exim: setuid(%ld) failed: %s\n", | |
1670ef10 | 1947 | (long int)real_uid, strerror(errno)); |
059ec3d9 PH |
1948 | } |
1949 | ||
1950 | /* If neither the original real uid nor the original euid was root, Exim is | |
1951 | running in an unprivileged state. */ | |
1952 | ||
1953 | unprivileged = (real_uid != root_uid && original_euid != root_uid); | |
1954 | ||
137ae145 JH |
1955 | /* For most of the args-parsing we need to use permanent pool memory */ |
1956 | { | |
1957 | int old_pool = store_pool; | |
1958 | store_pool = POOL_PERM; | |
1959 | ||
059ec3d9 PH |
1960 | /* Scan the program's arguments. Some can be dealt with right away; others are |
1961 | simply recorded for checking and handling afterwards. Do a high-level switch | |
1962 | on the second character (the one after '-'), to save some effort. */ | |
1963 | ||
137ae145 | 1964 | for (i = 1; i < argc; i++) |
059ec3d9 PH |
1965 | { |
1966 | BOOL badarg = FALSE; | |
a76d120a JH |
1967 | uschar * arg = argv[i]; |
1968 | uschar * argrest; | |
059ec3d9 PH |
1969 | int switchchar; |
1970 | ||
1971 | /* An argument not starting with '-' is the start of a recipients list; | |
1972 | break out of the options-scanning loop. */ | |
1973 | ||
1974 | if (arg[0] != '-') | |
1975 | { | |
1976 | recipients_arg = i; | |
1977 | break; | |
1978 | } | |
1979 | ||
4c04137d | 1980 | /* An option consisting of -- terminates the options */ |
059ec3d9 PH |
1981 | |
1982 | if (Ustrcmp(arg, "--") == 0) | |
1983 | { | |
1984 | recipients_arg = i + 1; | |
1985 | break; | |
1986 | } | |
1987 | ||
1988 | /* Handle flagged options */ | |
1989 | ||
1990 | switchchar = arg[1]; | |
1991 | argrest = arg+2; | |
1992 | ||
1993 | /* Make all -ex options synonymous with -oex arguments, since that | |
1994 | is assumed by various callers. Also make -qR options synonymous with -R | |
1995 | options, as that seems to be required as well. Allow for -qqR too, and | |
1996 | the same for -S options. */ | |
1997 | ||
1998 | if (Ustrncmp(arg+1, "oe", 2) == 0 || | |
1999 | Ustrncmp(arg+1, "qR", 2) == 0 || | |
2000 | Ustrncmp(arg+1, "qS", 2) == 0) | |
2001 | { | |
2002 | switchchar = arg[2]; | |
2003 | argrest++; | |
2004 | } | |
2005 | else if (Ustrncmp(arg+1, "qqR", 3) == 0 || Ustrncmp(arg+1, "qqS", 3) == 0) | |
2006 | { | |
2007 | switchchar = arg[3]; | |
2008 | argrest += 2; | |
8768d548 | 2009 | f.queue_2stage = TRUE; |
059ec3d9 PH |
2010 | } |
2011 | ||
2012 | /* Make -r synonymous with -f, since it is a documented alias */ | |
2013 | ||
2014 | else if (arg[1] == 'r') switchchar = 'f'; | |
2015 | ||
2016 | /* Make -ov synonymous with -v */ | |
2017 | ||
2018 | else if (Ustrcmp(arg, "-ov") == 0) | |
2019 | { | |
2020 | switchchar = 'v'; | |
2021 | argrest++; | |
2022 | } | |
2023 | ||
4b2241d2 PP |
2024 | /* deal with --option_aliases */ |
2025 | else if (switchchar == '-') | |
2026 | { | |
2027 | if (Ustrcmp(argrest, "help") == 0) | |
2028 | { | |
2029 | usage_wanted = TRUE; | |
2030 | break; | |
2031 | } | |
2032 | else if (Ustrcmp(argrest, "version") == 0) | |
2033 | { | |
2034 | switchchar = 'b'; | |
73a46702 | 2035 | argrest = US"V"; |
4b2241d2 PP |
2036 | } |
2037 | } | |
2038 | ||
059ec3d9 PH |
2039 | /* High-level switch on active initial letter */ |
2040 | ||
2041 | switch(switchchar) | |
2042 | { | |
a3fb9793 PP |
2043 | |
2044 | /* sendmail uses -Ac and -Am to control which .cf file is used; | |
2045 | we ignore them. */ | |
2046 | case 'A': | |
a76d120a | 2047 | if (!*argrest) { badarg = TRUE; break; } |
a3fb9793 PP |
2048 | else |
2049 | { | |
2050 | BOOL ignore = FALSE; | |
2051 | switch (*argrest) | |
2052 | { | |
2053 | case 'c': | |
2054 | case 'm': | |
2055 | if (*(argrest + 1) == '\0') | |
2056 | ignore = TRUE; | |
2057 | break; | |
2058 | } | |
bdcc6f2b | 2059 | if (!ignore) badarg = TRUE; |
a3fb9793 PP |
2060 | } |
2061 | break; | |
2062 | ||
059ec3d9 PH |
2063 | /* -Btype is a sendmail option for 7bit/8bit setting. Exim is 8-bit clean |
2064 | so has no need of it. */ | |
2065 | ||
2066 | case 'B': | |
bdcc6f2b | 2067 | if (!*argrest) i++; /* Skip over the type */ |
059ec3d9 PH |
2068 | break; |
2069 | ||
2070 | ||
2071 | case 'b': | |
059ec3d9 | 2072 | { |
bdcc6f2b JH |
2073 | receiving_message = FALSE; /* Reset TRUE for -bm, -bS, -bs below */ |
2074 | ||
2075 | switch (*argrest++) | |
2076 | { | |
2077 | /* -bd: Run in daemon mode, awaiting SMTP connections. | |
2078 | -bdf: Ditto, but in the foreground. | |
2079 | */ | |
2080 | case 'd': | |
2081 | f.daemon_listen = TRUE; | |
2082 | if (*argrest == 'f') f.background_daemon = FALSE; | |
2083 | else if (*argrest) badarg = TRUE; | |
2084 | break; | |
2085 | ||
2086 | /* -be: Run in expansion test mode | |
2087 | -bem: Ditto, but read a message from a file first | |
2088 | */ | |
2089 | case 'e': | |
2090 | expansion_test = checking = TRUE; | |
2091 | if (*argrest == 'm') | |
2092 | { | |
2093 | if (++i >= argc) { badarg = TRUE; break; } | |
2094 | expansion_test_message = argv[i]; | |
2095 | argrest++; | |
2096 | } | |
2097 | if (*argrest) badarg = TRUE; | |
2098 | break; | |
2099 | ||
2100 | /* -bF: Run system filter test */ | |
2101 | case 'F': | |
2102 | filter_test |= checking = FTEST_SYSTEM; | |
a76d120a JH |
2103 | if (*argrest) badarg = TRUE; |
2104 | else if (++i < argc) filter_test_sfile = argv[i]; | |
2105 | else exim_fail("exim: file name expected after %s\n", argv[i-1]); | |
bdcc6f2b JH |
2106 | break; |
2107 | ||
2108 | /* -bf: Run user filter test | |
2109 | -bfd: Set domain for filter testing | |
2110 | -bfl: Set local part for filter testing | |
2111 | -bfp: Set prefix for filter testing | |
2112 | -bfs: Set suffix for filter testing | |
2113 | */ | |
2114 | case 'f': | |
2115 | if (!*argrest) | |
2116 | { | |
2117 | filter_test |= checking = FTEST_USER; | |
2118 | if (++i < argc) filter_test_ufile = argv[i]; | |
2119 | else exim_fail("exim: file name expected after %s\n", argv[i-1]); | |
2120 | } | |
2121 | else | |
2122 | { | |
2123 | if (++i >= argc) | |
2124 | exim_fail("exim: string expected after %s\n", arg); | |
2125 | if (Ustrcmp(argrest, "d") == 0) ftest_domain = argv[i]; | |
2126 | else if (Ustrcmp(argrest, "l") == 0) ftest_localpart = argv[i]; | |
2127 | else if (Ustrcmp(argrest, "p") == 0) ftest_prefix = argv[i]; | |
2128 | else if (Ustrcmp(argrest, "s") == 0) ftest_suffix = argv[i]; | |
2129 | else badarg = TRUE; | |
2130 | } | |
2131 | break; | |
2132 | ||
2133 | /* -bh: Host checking - an IP address must follow. */ | |
2134 | case 'h': | |
2135 | if (!*argrest || Ustrcmp(argrest, "c") == 0) | |
2136 | { | |
2137 | if (++i >= argc) { badarg = TRUE; break; } | |
a76d120a | 2138 | sender_host_address = string_copy_taint(argv[i], TRUE); |
bdcc6f2b JH |
2139 | host_checking = checking = f.log_testing_mode = TRUE; |
2140 | f.host_checking_callout = *argrest == 'c'; | |
2141 | message_logs = FALSE; | |
2142 | } | |
2143 | else badarg = TRUE; | |
2144 | break; | |
2145 | ||
2146 | /* -bi: This option is used by sendmail to initialize *the* alias file, | |
2147 | though it has the -oA option to specify a different file. Exim has no | |
2148 | concept of *the* alias file, but since Sun's YP make script calls | |
2149 | sendmail this way, some support must be provided. */ | |
2150 | case 'i': | |
2151 | if (!*++argrest) bi_option = TRUE; | |
2152 | else badarg = TRUE; | |
2153 | break; | |
2154 | ||
2155 | /* -bI: provide information, of the type to follow after a colon. | |
2156 | This is an Exim flag. */ | |
2157 | case 'I': | |
2158 | if (Ustrlen(argrest) >= 1 && *argrest == ':') | |
2159 | { | |
2160 | uschar *p = argrest+1; | |
2161 | info_flag = CMDINFO_HELP; | |
2162 | if (Ustrlen(p)) | |
2163 | if (strcmpic(p, CUS"sieve") == 0) | |
2164 | { | |
2165 | info_flag = CMDINFO_SIEVE; | |
2166 | info_stdout = TRUE; | |
2167 | } | |
2168 | else if (strcmpic(p, CUS"dscp") == 0) | |
2169 | { | |
2170 | info_flag = CMDINFO_DSCP; | |
2171 | info_stdout = TRUE; | |
2172 | } | |
2173 | else if (strcmpic(p, CUS"help") == 0) | |
2174 | info_stdout = TRUE; | |
2175 | } | |
2176 | else badarg = TRUE; | |
2177 | break; | |
2178 | ||
2179 | /* -bm: Accept and deliver message - the default option. Reinstate | |
2180 | receiving_message, which got turned off for all -b options. | |
2181 | -bmalware: test the filename given for malware */ | |
2182 | case 'm': | |
2183 | if (!*argrest) receiving_message = TRUE; | |
2184 | else if (Ustrcmp(argrest, "alware") == 0) | |
2185 | { | |
2186 | if (++i >= argc) { badarg = TRUE; break; } | |
2187 | checking = TRUE; | |
2188 | malware_test_file = argv[i]; | |
2189 | } | |
2190 | else badarg = TRUE; | |
2191 | break; | |
2192 | ||
2193 | /* -bnq: For locally originating messages, do not qualify unqualified | |
2194 | addresses. In the envelope, this causes errors; in header lines they | |
2195 | just get left. */ | |
2196 | case 'n': | |
2197 | if (Ustrcmp(argrest, "q") == 0) | |
2198 | { | |
2199 | f.allow_unqualified_sender = FALSE; | |
2200 | f.allow_unqualified_recipient = FALSE; | |
2201 | } | |
2202 | else badarg = TRUE; | |
2203 | break; | |
2204 | ||
2205 | /* -bpxx: List the contents of the mail queue, in various forms. If | |
2206 | the option is -bpc, just a queue count is needed. Otherwise, if the | |
2207 | first letter after p is r, then order is random. */ | |
2208 | case 'p': | |
2209 | if (*argrest == 'c') | |
2210 | { | |
2211 | count_queue = TRUE; | |
2212 | if (*++argrest) badarg = TRUE; | |
2213 | break; | |
2214 | } | |
2215 | ||
2216 | if (*argrest == 'r') | |
2217 | { | |
2218 | list_queue_option = 8; | |
2219 | argrest++; | |
2220 | } | |
2221 | else list_queue_option = 0; | |
2222 | ||
2223 | list_queue = TRUE; | |
2224 | ||
2225 | /* -bp: List the contents of the mail queue, top-level only */ | |
2226 | ||
2227 | if (!*argrest) {} | |
2228 | ||
2229 | /* -bpu: List the contents of the mail queue, top-level undelivered */ | |
2230 | ||
2231 | else if (Ustrcmp(argrest, "u") == 0) list_queue_option += 1; | |
2232 | ||
2233 | /* -bpa: List the contents of the mail queue, including all delivered */ | |
2234 | ||
2235 | else if (Ustrcmp(argrest, "a") == 0) list_queue_option += 2; | |
2236 | ||
2237 | /* Unknown after -bp[r] */ | |
2238 | ||
2239 | else badarg = TRUE; | |
2240 | break; | |
2241 | ||
2242 | ||
2243 | /* -bP: List the configuration variables given as the address list. | |
2244 | Force -v, so configuration errors get displayed. */ | |
2245 | case 'P': | |
2246 | ||
2247 | /* -bP config: we need to setup here, because later, | |
2248 | * when list_options is checked, the config is read already */ | |
2249 | if (*argrest) | |
2250 | badarg = TRUE; | |
2251 | else if (argv[i+1] && Ustrcmp(argv[i+1], "config") == 0) | |
2252 | { | |
2253 | list_config = TRUE; | |
2254 | readconf_save_config(version_string); | |
2255 | } | |
2256 | else | |
2257 | { | |
2258 | list_options = TRUE; | |
2259 | debug_selector |= D_v; | |
2260 | debug_file = stderr; | |
2261 | } | |
2262 | break; | |
2263 | ||
2264 | /* -brt: Test retry configuration lookup */ | |
2265 | case 'r': | |
2266 | if (Ustrcmp(argrest, "t") == 0) | |
2267 | { | |
2268 | checking = TRUE; | |
2269 | test_retry_arg = i + 1; | |
2270 | goto END_ARG; | |
2271 | } | |
2272 | ||
2273 | /* -brw: Test rewrite configuration */ | |
2274 | ||
2275 | else if (Ustrcmp(argrest, "w") == 0) | |
2276 | { | |
2277 | checking = TRUE; | |
2278 | test_rewrite_arg = i + 1; | |
2279 | goto END_ARG; | |
2280 | } | |
2281 | else badarg = TRUE; | |
2282 | break; | |
2283 | ||
2284 | /* -bS: Read SMTP commands on standard input, but produce no replies - | |
2285 | all errors are reported by sending messages. */ | |
2286 | case 'S': | |
2287 | if (!*argrest) | |
2288 | smtp_input = smtp_batched_input = receiving_message = TRUE; | |
2289 | else badarg = TRUE; | |
2290 | break; | |
2291 | ||
2292 | /* -bs: Read SMTP commands on standard input and produce SMTP replies | |
2293 | on standard output. */ | |
2294 | case 's': | |
2295 | if (!*argrest) smtp_input = receiving_message = TRUE; | |
2296 | else badarg = TRUE; | |
2297 | break; | |
2298 | ||
2299 | /* -bt: address testing mode */ | |
2300 | case 't': | |
2301 | if (!*argrest) | |
2302 | f.address_test_mode = checking = f.log_testing_mode = TRUE; | |
2303 | else badarg = TRUE; | |
2304 | break; | |
2305 | ||
2306 | /* -bv: verify addresses */ | |
2307 | case 'v': | |
2308 | if (!*argrest) | |
2309 | verify_address_mode = checking = f.log_testing_mode = TRUE; | |
2310 | ||
2311 | /* -bvs: verify sender addresses */ | |
2312 | ||
2313 | else if (Ustrcmp(argrest, "s") == 0) | |
2314 | { | |
2315 | verify_address_mode = checking = f.log_testing_mode = TRUE; | |
2316 | verify_as_sender = TRUE; | |
2317 | } | |
2318 | else badarg = TRUE; | |
2319 | break; | |
2320 | ||
2321 | /* -bV: Print version string and support details */ | |
2322 | case 'V': | |
2323 | if (!*argrest) | |
2324 | { | |
2325 | printf("Exim version %s #%s built %s\n", version_string, | |
2326 | version_cnumber, version_date); | |
2327 | printf("%s\n", CS version_copyright); | |
2328 | version_printed = TRUE; | |
2329 | show_whats_supported(stdout); | |
2330 | f.log_testing_mode = TRUE; | |
2331 | } | |
2332 | else badarg = TRUE; | |
2333 | break; | |
2334 | ||
2335 | /* -bw: inetd wait mode, accept a listening socket as stdin */ | |
2336 | case 'w': | |
2337 | f.inetd_wait_mode = TRUE; | |
2338 | f.background_daemon = FALSE; | |
2339 | f.daemon_listen = TRUE; | |
2340 | if (*argrest) | |
2341 | if ((inetd_wait_timeout = readconf_readtime(argrest, 0, FALSE)) <= 0) | |
2342 | exim_fail("exim: bad time value %s: abandoned\n", argv[i]); | |
2343 | break; | |
2344 | ||
2345 | default: | |
2346 | badarg = TRUE; | |
2347 | break; | |
2348 | } | |
2349 | break; | |
9ee44efb PP |
2350 | } |
2351 | ||
059ec3d9 PH |
2352 | |
2353 | /* -C: change configuration file list; ignore if it isn't really | |
2354 | a change! Enforce a prefix check if required. */ | |
2355 | ||
2356 | case 'C': | |
a76d120a JH |
2357 | if (!*argrest) |
2358 | if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; } | |
059ec3d9 PH |
2359 | if (Ustrcmp(config_main_filelist, argrest) != 0) |
2360 | { | |
2361 | #ifdef ALT_CONFIG_PREFIX | |
2362 | int sep = 0; | |
2363 | int len = Ustrlen(ALT_CONFIG_PREFIX); | |
863bd541 | 2364 | const uschar *list = argrest; |
059ec3d9 PH |
2365 | uschar *filename; |
2366 | while((filename = string_nextinlist(&list, &sep, big_buffer, | |
a76d120a JH |
2367 | big_buffer_size))) |
2368 | if ( ( Ustrlen(filename) < len | |
2369 | || Ustrncmp(filename, ALT_CONFIG_PREFIX, len) != 0 | |
2370 | || Ustrstr(filename, "/../") != NULL | |
2371 | ) | |
2372 | && (Ustrcmp(filename, "/dev/null") != 0 || real_uid != root_uid) | |
2373 | ) | |
9af3c549 | 2374 | exim_fail("-C Permission denied\n"); |
059ec3d9 | 2375 | #endif |
261dc43e DW |
2376 | if (real_uid != root_uid) |
2377 | { | |
90b6341f | 2378 | #ifdef TRUSTED_CONFIG_LIST |
261dc43e | 2379 | |
90b6341f DW |
2380 | if (real_uid != exim_uid |
2381 | #ifdef CONFIGURE_OWNER | |
2382 | && real_uid != config_uid | |
2383 | #endif | |
2384 | ) | |
8768d548 | 2385 | f.trusted_config = FALSE; |
261dc43e DW |
2386 | else |
2387 | { | |
90b6341f | 2388 | FILE *trust_list = Ufopen(TRUSTED_CONFIG_LIST, "rb"); |
261dc43e DW |
2389 | if (trust_list) |
2390 | { | |
2391 | struct stat statbuf; | |
2392 | ||
2393 | if (fstat(fileno(trust_list), &statbuf) != 0 || | |
2394 | (statbuf.st_uid != root_uid /* owner not root */ | |
2395 | #ifdef CONFIGURE_OWNER | |
2396 | && statbuf.st_uid != config_uid /* owner not the special one */ | |
2397 | #endif | |
2398 | ) || /* or */ | |
2399 | (statbuf.st_gid != root_gid /* group not root */ | |
2400 | #ifdef CONFIGURE_GROUP | |
2401 | && statbuf.st_gid != config_gid /* group not the special one */ | |
2402 | #endif | |
2403 | && (statbuf.st_mode & 020) != 0 /* group writeable */ | |
2404 | ) || /* or */ | |
2405 | (statbuf.st_mode & 2) != 0) /* world writeable */ | |
2406 | { | |
8768d548 | 2407 | f.trusted_config = FALSE; |
261dc43e DW |
2408 | fclose(trust_list); |
2409 | } | |
2410 | else | |
2411 | { | |
2412 | /* Well, the trust list at least is up to scratch... */ | |
137ae145 | 2413 | rmark reset_point; |
90b6341f DW |
2414 | uschar *trusted_configs[32]; |
2415 | int nr_configs = 0; | |
261dc43e | 2416 | int i = 0; |
137ae145 JH |
2417 | int old_pool = store_pool; |
2418 | store_pool = POOL_MAIN; | |
261dc43e | 2419 | |
137ae145 | 2420 | reset_point = store_mark(); |
261dc43e DW |
2421 | while (Ufgets(big_buffer, big_buffer_size, trust_list)) |
2422 | { | |
2423 | uschar *start = big_buffer, *nl; | |
2424 | while (*start && isspace(*start)) | |
2425 | start++; | |
1e83d68b | 2426 | if (*start != '/') |
261dc43e DW |
2427 | continue; |
2428 | nl = Ustrchr(start, '\n'); | |
2429 | if (nl) | |
2430 | *nl = 0; | |
90b6341f | 2431 | trusted_configs[nr_configs++] = string_copy(start); |
a76d120a | 2432 | if (nr_configs == nelem(trusted_configs)) |
261dc43e DW |
2433 | break; |
2434 | } | |
2435 | fclose(trust_list); | |
2436 | ||
90b6341f | 2437 | if (nr_configs) |
261dc43e DW |
2438 | { |
2439 | int sep = 0; | |
55414b25 | 2440 | const uschar *list = argrest; |
261dc43e | 2441 | uschar *filename; |
8768d548 | 2442 | while (f.trusted_config && (filename = string_nextinlist(&list, |
a76d120a | 2443 | &sep, big_buffer, big_buffer_size))) |
261dc43e | 2444 | { |
90b6341f | 2445 | for (i=0; i < nr_configs; i++) |
90b6341f | 2446 | if (Ustrcmp(filename, trusted_configs[i]) == 0) |
261dc43e | 2447 | break; |
90b6341f | 2448 | if (i == nr_configs) |
261dc43e | 2449 | { |
8768d548 | 2450 | f.trusted_config = FALSE; |
261dc43e DW |
2451 | break; |
2452 | } | |
2453 | } | |
2454 | } | |
f3ebb786 | 2455 | else /* No valid prefixes found in trust_list file. */ |
8768d548 | 2456 | f.trusted_config = FALSE; |
f3ebb786 | 2457 | store_reset(reset_point); |
137ae145 | 2458 | store_pool = old_pool; |
261dc43e DW |
2459 | } |
2460 | } | |
f3ebb786 | 2461 | else /* Could not open trust_list file. */ |
8768d548 | 2462 | f.trusted_config = FALSE; |
261dc43e DW |
2463 | } |
2464 | #else | |
2465 | /* Not root; don't trust config */ | |
8768d548 | 2466 | f.trusted_config = FALSE; |
261dc43e DW |
2467 | #endif |
2468 | } | |
059ec3d9 PH |
2469 | |
2470 | config_main_filelist = argrest; | |
8768d548 | 2471 | f.config_changed = TRUE; |
059ec3d9 PH |
2472 | } |
2473 | break; | |
2474 | ||
2475 | ||
2476 | /* -D: set up a macro definition */ | |
2477 | ||
2478 | case 'D': | |
9af3c549 JH |
2479 | #ifdef DISABLE_D_OPTION |
2480 | exim_fail("exim: -D is not available in this Exim binary\n"); | |
2481 | #else | |
059ec3d9 PH |
2482 | { |
2483 | int ptr = 0; | |
059ec3d9 PH |
2484 | macro_item *m; |
2485 | uschar name[24]; | |
2486 | uschar *s = argrest; | |
2487 | ||
4ab69ec7 | 2488 | opt_D_used = TRUE; |
059ec3d9 PH |
2489 | while (isspace(*s)) s++; |
2490 | ||
2491 | if (*s < 'A' || *s > 'Z') | |
9af3c549 | 2492 | exim_fail("exim: macro name set by -D must start with " |
059ec3d9 | 2493 | "an upper case letter\n"); |
059ec3d9 PH |
2494 | |
2495 | while (isalnum(*s) || *s == '_') | |
2496 | { | |
2497 | if (ptr < sizeof(name)-1) name[ptr++] = *s; | |
2498 | s++; | |
2499 | } | |
2500 | name[ptr] = 0; | |
2501 | if (ptr == 0) { badarg = TRUE; break; } | |
2502 | while (isspace(*s)) s++; | |
2503 | if (*s != 0) | |
2504 | { | |
2505 | if (*s++ != '=') { badarg = TRUE; break; } | |
2506 | while (isspace(*s)) s++; | |
2507 | } | |
2508 | ||
85e03244 | 2509 | for (m = macros_user; m; m = m->next) |
1a7c9a48 | 2510 | if (Ustrcmp(m->name, name) == 0) |
9af3c549 | 2511 | exim_fail("exim: duplicated -D in command line\n"); |
059ec3d9 | 2512 | |
85e03244 | 2513 | m = macro_create(name, s, TRUE); |
059ec3d9 PH |
2514 | |
2515 | if (clmacro_count >= MAX_CLMACROS) | |
9af3c549 | 2516 | exim_fail("exim: too many -D options on command line\n"); |
f3ebb786 JH |
2517 | clmacros[clmacro_count++] = |
2518 | string_sprintf("-D%s=%s", m->name, m->replacement); | |
059ec3d9 PH |
2519 | } |
2520 | #endif | |
2521 | break; | |
2522 | ||
2523 | /* -d: Set debug level (see also -v below) or set the drop_cr option. | |
8e669ac1 | 2524 | The latter is now a no-op, retained for compatibility only. If -dd is used, |
3d235903 | 2525 | debugging subprocesses of the daemon is disabled. */ |
059ec3d9 PH |
2526 | |
2527 | case 'd': | |
2528 | if (Ustrcmp(argrest, "ropcr") == 0) | |
2529 | { | |
2530 | /* drop_cr = TRUE; */ | |
2531 | } | |
2532 | ||
2533 | /* Use an intermediate variable so that we don't set debugging while | |
2534 | decoding the debugging bits. */ | |
2535 | ||
2536 | else | |
2537 | { | |
2538 | unsigned int selector = D_default; | |
2539 | debug_selector = 0; | |
2540 | debug_file = NULL; | |
3d235903 PH |
2541 | if (*argrest == 'd') |
2542 | { | |
8768d548 | 2543 | f.debug_daemon = TRUE; |
3d235903 PH |
2544 | argrest++; |
2545 | } | |
a76d120a | 2546 | if (*argrest) |
6c6d6e48 TF |
2547 | decode_bits(&selector, 1, debug_notall, argrest, |
2548 | debug_options, debug_options_count, US"debug", 0); | |
059ec3d9 PH |
2549 | debug_selector = selector; |
2550 | } | |
2551 | break; | |
2552 | ||
2553 | ||
2554 | /* -E: This is a local error message. This option is not intended for | |
2555 | external use at all, but is not restricted to trusted callers because it | |
2556 | does no harm (just suppresses certain error messages) and if Exim is run | |
2557 | not setuid root it won't always be trusted when it generates error | |
2558 | messages using this option. If there is a message id following -E, point | |
2559 | message_reference at it, for logging. */ | |
2560 | ||
2561 | case 'E': | |
8768d548 | 2562 | f.local_error_message = TRUE; |
059ec3d9 PH |
2563 | if (mac_ismsgid(argrest)) message_reference = argrest; |
2564 | break; | |
2565 | ||
2566 | ||
2567 | /* -ex: The vacation program calls sendmail with the undocumented "-eq" | |
2568 | option, so it looks as if historically the -oex options are also callable | |
2569 | without the leading -o. So we have to accept them. Before the switch, | |
2570 | anything starting -oe has been converted to -e. Exim does not support all | |
2571 | of the sendmail error options. */ | |
2572 | ||
2573 | case 'e': | |
2574 | if (Ustrcmp(argrest, "e") == 0) | |
2575 | { | |
2576 | arg_error_handling = ERRORS_SENDER; | |
2577 | errors_sender_rc = EXIT_SUCCESS; | |
2578 | } | |
2579 | else if (Ustrcmp(argrest, "m") == 0) arg_error_handling = ERRORS_SENDER; | |
2580 | else if (Ustrcmp(argrest, "p") == 0) arg_error_handling = ERRORS_STDERR; | |
2581 | else if (Ustrcmp(argrest, "q") == 0) arg_error_handling = ERRORS_STDERR; | |
2582 | else if (Ustrcmp(argrest, "w") == 0) arg_error_handling = ERRORS_SENDER; | |
2583 | else badarg = TRUE; | |
2584 | break; | |
2585 | ||
2586 | ||
2587 | /* -F: Set sender's full name, used instead of the gecos entry from | |
2588 | the password file. Since users can usually alter their gecos entries, | |
2589 | there's no security involved in using this instead. The data can follow | |
2590 | the -F or be in the next argument. */ | |
2591 | ||
2592 | case 'F': | |
a76d120a JH |
2593 | if (!*argrest) |
2594 | if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; } | |
2595 | originator_name = string_copy_taint(argrest, TRUE); | |
8768d548 | 2596 | f.sender_name_forced = TRUE; |
059ec3d9 PH |
2597 | break; |
2598 | ||
2599 | ||
2600 | /* -f: Set sender's address - this value is only actually used if Exim is | |
2601 | run by a trusted user, or if untrusted_set_sender is set and matches the | |
2602 | address, except that the null address can always be set by any user. The | |
2603 | test for this happens later, when the value given here is ignored when not | |
2604 | permitted. For an untrusted user, the actual sender is still put in Sender: | |
2605 | if it doesn't match the From: header (unless no_local_from_check is set). | |
2606 | The data can follow the -f or be in the next argument. The -r switch is an | |
2607 | obsolete form of -f but since there appear to be programs out there that | |
2608 | use anything that sendmail has ever supported, better accept it - the | |
2609 | synonymizing is done before the switch above. | |
2610 | ||
2611 | At this stage, we must allow domain literal addresses, because we don't | |
2612 | know what the setting of allow_domain_literals is yet. Ditto for trailing | |
2613 | dots and strip_trailing_dot. */ | |
2614 | ||
2615 | case 'f': | |
2616 | { | |
250b6871 | 2617 | int dummy_start, dummy_end; |
059ec3d9 | 2618 | uschar *errmess; |
a76d120a JH |
2619 | if (!*argrest) |
2620 | if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; } | |
2621 | if (!*argrest) | |
f3ebb786 | 2622 | *(sender_address = store_get(1, FALSE)) = '\0'; /* Ensure writeable memory */ |
059ec3d9 PH |
2623 | else |
2624 | { | |
a76d120a | 2625 | uschar * temp = argrest + Ustrlen(argrest) - 1; |
059ec3d9 PH |
2626 | while (temp >= argrest && isspace(*temp)) temp--; |
2627 | if (temp >= argrest && *temp == '.') f_end_dot = TRUE; | |
2628 | allow_domain_literals = TRUE; | |
2629 | strip_trailing_dot = TRUE; | |
8c5d388a | 2630 | #ifdef SUPPORT_I18N |
250b6871 JH |
2631 | allow_utf8_domains = TRUE; |
2632 | #endif | |
5fcc791a JH |
2633 | if (!(sender_address = parse_extract_address(argrest, &errmess, |
2634 | &dummy_start, &dummy_end, &sender_address_domain, TRUE))) | |
2635 | exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess); | |
2636 | ||
f3ebb786 | 2637 | sender_address = string_copy_taint(sender_address, TRUE); |
8c5d388a | 2638 | #ifdef SUPPORT_I18N |
250b6871 JH |
2639 | message_smtputf8 = string_is_utf8(sender_address); |
2640 | allow_utf8_domains = FALSE; | |
2641 | #endif | |
059ec3d9 PH |
2642 | allow_domain_literals = FALSE; |
2643 | strip_trailing_dot = FALSE; | |
059ec3d9 | 2644 | } |
8768d548 | 2645 | f.sender_address_forced = TRUE; |
059ec3d9 PH |
2646 | } |
2647 | break; | |
2648 | ||
a3fb9793 | 2649 | /* -G: sendmail invocation to specify that it's a gateway submission and |
f4ee74ac PP |
2650 | sendmail may complain about problems instead of fixing them. |
2651 | We make it equivalent to an ACL "control = suppress_local_fixups" and do | |
2652 | not at this time complain about problems. */ | |
059ec3d9 PH |
2653 | |
2654 | case 'G': | |
f4ee74ac | 2655 | flag_G = TRUE; |
059ec3d9 PH |
2656 | break; |
2657 | ||
2658 | /* -h: Set the hop count for an incoming message. Exim does not currently | |
2659 | support this; it always computes it by counting the Received: headers. | |
2660 | To put it in will require a change to the spool header file format. */ | |
2661 | ||
2662 | case 'h': | |
a76d120a JH |
2663 | if (!*argrest) |
2664 | if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; } | |
059ec3d9 PH |
2665 | if (!isdigit(*argrest)) badarg = TRUE; |
2666 | break; | |
2667 | ||
2668 | ||
2669 | /* -i: Set flag so dot doesn't end non-SMTP input (same as -oi, seems | |
2670 | not to be documented for sendmail but mailx (at least) uses it) */ | |
2671 | ||
2672 | case 'i': | |
a76d120a | 2673 | if (!*argrest) f.dot_ends = FALSE; else badarg = TRUE; |
059ec3d9 PH |
2674 | break; |
2675 | ||
2676 | ||
a3fb9793 PP |
2677 | /* -L: set the identifier used for syslog; equivalent to setting |
2678 | syslog_processname in the config file, but needs to be an admin option. */ | |
2679 | ||
2680 | case 'L': | |
a76d120a JH |
2681 | if (!*argrest) |
2682 | if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; } | |
9af3c549 JH |
2683 | if ((sz = Ustrlen(argrest)) > 32) |
2684 | exim_fail("exim: the -L syslog name is too long: \"%s\"\n", argrest); | |
a3fb9793 | 2685 | if (sz < 1) |
9af3c549 | 2686 | exim_fail("exim: the -L syslog name is too short\n"); |
a76d120a | 2687 | cmdline_syslog_name = string_copy_taint(argrest, TRUE); |
a3fb9793 PP |
2688 | break; |
2689 | ||
059ec3d9 PH |
2690 | case 'M': |
2691 | receiving_message = FALSE; | |
2692 | ||
2693 | /* -MC: continue delivery of another message via an existing open | |
2694 | file descriptor. This option is used for an internal call by the | |
2695 | smtp transport when there is a pending message waiting to go to an | |
2696 | address to which it has got a connection. Five subsequent arguments are | |
2697 | required: transport name, host name, IP address, sequence number, and | |
2698 | message_id. Transports may decline to create new processes if the sequence | |
2699 | number gets too big. The channel is stdin. This (-MC) must be the last | |
2700 | argument. There's a subsequent check that the real-uid is privileged. | |
2701 | ||
2702 | If we are running in the test harness. delay for a bit, to let the process | |
2703 | that set this one up complete. This makes for repeatability of the logging, | |
2704 | etc. output. */ | |
2705 | ||
2706 | if (Ustrcmp(argrest, "C") == 0) | |
2707 | { | |
41c7c167 PH |
2708 | union sockaddr_46 interface_sock; |
2709 | EXIM_SOCKLEN_T size = sizeof(interface_sock); | |
2710 | ||
059ec3d9 | 2711 | if (argc != i + 6) |
9af3c549 | 2712 | exim_fail("exim: too many or too few arguments after -MC\n"); |
059ec3d9 PH |
2713 | |
2714 | if (msg_action_arg >= 0) | |
9af3c549 | 2715 | exim_fail("exim: incompatible arguments\n"); |
059ec3d9 | 2716 | |
a76d120a JH |
2717 | continue_transport = string_copy_taint(argv[++i], TRUE); |
2718 | continue_hostname = string_copy_taint(argv[++i], TRUE); | |
2719 | continue_host_address = string_copy_taint(argv[++i], TRUE); | |
059ec3d9 PH |
2720 | continue_sequence = Uatoi(argv[++i]); |
2721 | msg_action = MSG_DELIVER; | |
2722 | msg_action_arg = ++i; | |
2723 | forced_delivery = TRUE; | |
2724 | queue_run_pid = passed_qr_pid; | |
2725 | queue_run_pipe = passed_qr_pipe; | |
2726 | ||
2727 | if (!mac_ismsgid(argv[i])) | |
9af3c549 | 2728 | exim_fail("exim: malformed message id %s after -MC option\n", |
059ec3d9 | 2729 | argv[i]); |
059ec3d9 | 2730 | |
875512a3 JH |
2731 | /* Set up $sending_ip_address and $sending_port, unless proxied */ |
2732 | ||
5013d912 | 2733 | if (!continue_proxy_cipher) |
875512a3 JH |
2734 | if (getsockname(fileno(stdin), (struct sockaddr *)(&interface_sock), |
2735 | &size) == 0) | |
2736 | sending_ip_address = host_ntoa(-1, &interface_sock, NULL, | |
2737 | &sending_port); | |
2738 | else | |
9af3c549 | 2739 | exim_fail("exim: getsockname() failed after -MC option: %s\n", |
875512a3 | 2740 | strerror(errno)); |
41c7c167 | 2741 | |
9f01e50d | 2742 | testharness_pause_ms(500); |
059ec3d9 PH |
2743 | break; |
2744 | } | |
2745 | ||
2d14f397 JH |
2746 | else if (*argrest == 'C' && argrest[1] && !argrest[2]) |
2747 | { | |
875512a3 | 2748 | switch(argrest[1]) |
2d14f397 | 2749 | { |
059ec3d9 PH |
2750 | /* -MCA: set the smtp_authenticated flag; this is useful only when it |
2751 | precedes -MC (see above). The flag indicates that the host to which | |
2752 | Exim is connected has accepted an AUTH sequence. */ | |
2753 | ||
8768d548 | 2754 | case 'A': f.smtp_authenticated = TRUE; break; |
059ec3d9 | 2755 | |
6c1c3d1d WB |
2756 | /* -MCD: set the smtp_use_dsn flag; this indicates that the host |
2757 | that exim is connected to supports the esmtp extension DSN */ | |
28b3821f | 2758 | |
14de8063 | 2759 | case 'D': smtp_peer_options |= OPTION_DSN; break; |
6c1c3d1d | 2760 | |
32393657 JH |
2761 | /* -MCd: for debug, set a process-purpose string */ |
2762 | ||
4b01271f JH |
2763 | case 'd': if (++i < argc) |
2764 | process_purpose = string_copy_taint(argv[i], TRUE); | |
32393657 JH |
2765 | else badarg = TRUE; |
2766 | break; | |
2767 | ||
e37f8a84 | 2768 | /* -MCG: set the queue name, to a non-default value */ |
28b3821f | 2769 | |
a76d120a | 2770 | case 'G': if (++i < argc) queue_name = string_copy_taint(argv[i], TRUE); |
2d14f397 JH |
2771 | else badarg = TRUE; |
2772 | break; | |
2773 | ||
2774 | /* -MCK: the peer offered CHUNKING. Must precede -MC */ | |
2775 | ||
14de8063 | 2776 | case 'K': smtp_peer_options |= OPTION_CHUNKING; break; |
28b3821f | 2777 | |
059ec3d9 PH |
2778 | /* -MCP: set the smtp_use_pipelining flag; this is useful only when |
2779 | it preceded -MC (see above) */ | |
2780 | ||
14de8063 | 2781 | case 'P': smtp_peer_options |= OPTION_PIPE; break; |
059ec3d9 PH |
2782 | |
2783 | /* -MCQ: pass on the pid of the queue-running process that started | |
2784 | this chain of deliveries and the fd of its synchronizing pipe; this | |
2785 | is useful only when it precedes -MC (see above) */ | |
2786 | ||
2d14f397 JH |
2787 | case 'Q': if (++i < argc) passed_qr_pid = (pid_t)(Uatol(argv[i])); |
2788 | else badarg = TRUE; | |
2789 | if (++i < argc) passed_qr_pipe = (int)(Uatol(argv[i])); | |
2790 | else badarg = TRUE; | |
2791 | break; | |
059ec3d9 PH |
2792 | |
2793 | /* -MCS: set the smtp_use_size flag; this is useful only when it | |
2794 | precedes -MC (see above) */ | |
2795 | ||
14de8063 | 2796 | case 'S': smtp_peer_options |= OPTION_SIZE; break; |
059ec3d9 | 2797 | |
01603eec | 2798 | #ifndef DISABLE_TLS |
875512a3 | 2799 | /* -MCt: similar to -MCT below but the connection is still open |
aded2255 | 2800 | via a proxy process which handles the TLS context and coding. |
5013d912 JH |
2801 | Require three arguments for the proxied local address and port, |
2802 | and the TLS cipher. */ | |
875512a3 | 2803 | |
a76d120a JH |
2804 | case 't': if (++i < argc) |
2805 | sending_ip_address = string_copy_taint(argv[i], TRUE); | |
875512a3 | 2806 | else badarg = TRUE; |
a76d120a JH |
2807 | if (++i < argc) |
2808 | sending_port = (int)(Uatol(argv[i])); | |
875512a3 | 2809 | else badarg = TRUE; |
a76d120a JH |
2810 | if (++i < argc) |
2811 | continue_proxy_cipher = string_copy_taint(argv[i], TRUE); | |
5013d912 | 2812 | else badarg = TRUE; |
875512a3 JH |
2813 | /*FALLTHROUGH*/ |
2814 | ||
059ec3d9 PH |
2815 | /* -MCT: set the tls_offered flag; this is useful only when it |
2816 | precedes -MC (see above). The flag indicates that the host to which | |
2817 | Exim is connected has offered TLS support. */ | |
2818 | ||
14de8063 | 2819 | case 'T': smtp_peer_options |= OPTION_TLS; break; |
2d14f397 JH |
2820 | #endif |
2821 | ||
2822 | default: badarg = TRUE; break; | |
2823 | } | |
8ac90765 JH |
2824 | break; |
2825 | } | |
2826 | ||
059ec3d9 PH |
2827 | /* -M[x]: various operations on the following list of message ids: |
2828 | -M deliver the messages, ignoring next retry times and thawing | |
2829 | -Mc deliver the messages, checking next retry times, no thawing | |
2830 | -Mf freeze the messages | |
2831 | -Mg give up on the messages | |
2832 | -Mt thaw the messages | |
2833 | -Mrm remove the messages | |
2834 | In the above cases, this must be the last option. There are also the | |
2835 | following options which are followed by a single message id, and which | |
2836 | act on that message. Some of them use the "recipient" addresses as well. | |
2837 | -Mar add recipient(s) | |
2838 | -Mmad mark all recipients delivered | |
2839 | -Mmd mark recipients(s) delivered | |
2840 | -Mes edit sender | |
0ef732d9 | 2841 | -Mset load a message for use with -be |
059ec3d9 | 2842 | -Mvb show body |
a96603a0 | 2843 | -Mvc show copy (of whole message, in RFC 2822 format) |
059ec3d9 PH |
2844 | -Mvh show header |
2845 | -Mvl show log | |
2846 | */ | |
2847 | ||
a76d120a | 2848 | else if (!*argrest) |
059ec3d9 PH |
2849 | { |
2850 | msg_action = MSG_DELIVER; | |
8768d548 | 2851 | forced_delivery = f.deliver_force_thaw = TRUE; |
059ec3d9 PH |
2852 | } |
2853 | else if (Ustrcmp(argrest, "ar") == 0) | |
2854 | { | |
2855 | msg_action = MSG_ADD_RECIPIENT; | |
2856 | one_msg_action = TRUE; | |
2857 | } | |
2858 | else if (Ustrcmp(argrest, "c") == 0) msg_action = MSG_DELIVER; | |
2859 | else if (Ustrcmp(argrest, "es") == 0) | |
2860 | { | |
2861 | msg_action = MSG_EDIT_SENDER; | |
2862 | one_msg_action = TRUE; | |
2863 | } | |
2864 | else if (Ustrcmp(argrest, "f") == 0) msg_action = MSG_FREEZE; | |
2865 | else if (Ustrcmp(argrest, "g") == 0) | |
2866 | { | |
2867 | msg_action = MSG_DELIVER; | |
2868 | deliver_give_up = TRUE; | |
2869 | } | |
fc7bae7f JH |
2870 | else if (Ustrcmp(argrest, "G") == 0) |
2871 | { | |
2872 | msg_action = MSG_SETQUEUE; | |
a76d120a | 2873 | queue_name_dest = string_copy_taint(argv[++i], TRUE); |
fc7bae7f | 2874 | } |
059ec3d9 PH |
2875 | else if (Ustrcmp(argrest, "mad") == 0) |
2876 | { | |
2877 | msg_action = MSG_MARK_ALL_DELIVERED; | |
2878 | } | |
2879 | else if (Ustrcmp(argrest, "md") == 0) | |
2880 | { | |
2881 | msg_action = MSG_MARK_DELIVERED; | |
2882 | one_msg_action = TRUE; | |
2883 | } | |
2884 | else if (Ustrcmp(argrest, "rm") == 0) msg_action = MSG_REMOVE; | |
0ef732d9 PH |
2885 | else if (Ustrcmp(argrest, "set") == 0) |
2886 | { | |
2887 | msg_action = MSG_LOAD; | |
2888 | one_msg_action = TRUE; | |
2889 | } | |
059ec3d9 PH |
2890 | else if (Ustrcmp(argrest, "t") == 0) msg_action = MSG_THAW; |
2891 | else if (Ustrcmp(argrest, "vb") == 0) | |
2892 | { | |
2893 | msg_action = MSG_SHOW_BODY; | |
2894 | one_msg_action = TRUE; | |
2895 | } | |
a96603a0 PH |
2896 | else if (Ustrcmp(argrest, "vc") == 0) |
2897 | { | |
2898 | msg_action = MSG_SHOW_COPY; | |
2899 | one_msg_action = TRUE; | |
2900 | } | |
059ec3d9 PH |
2901 | else if (Ustrcmp(argrest, "vh") == 0) |
2902 | { | |
2903 | msg_action = MSG_SHOW_HEADER; | |
2904 | one_msg_action = TRUE; | |
2905 | } | |
2906 | else if (Ustrcmp(argrest, "vl") == 0) | |
2907 | { | |
2908 | msg_action = MSG_SHOW_LOG; | |
2909 | one_msg_action = TRUE; | |
2910 | } | |
2911 | else { badarg = TRUE; break; } | |
2912 | ||
2913 | /* All the -Mxx options require at least one message id. */ | |
2914 | ||
2915 | msg_action_arg = i + 1; | |
2916 | if (msg_action_arg >= argc) | |
9af3c549 | 2917 | exim_fail("exim: no message ids given after %s option\n", arg); |
059ec3d9 PH |
2918 | |
2919 | /* Some require only message ids to follow */ | |
2920 | ||
2921 | if (!one_msg_action) | |
2922 | { | |
d7978c0f | 2923 | for (int j = msg_action_arg; j < argc; j++) if (!mac_ismsgid(argv[j])) |
9af3c549 | 2924 | exim_fail("exim: malformed message id %s after %s option\n", |
059ec3d9 | 2925 | argv[j], arg); |
059ec3d9 PH |
2926 | goto END_ARG; /* Remaining args are ids */ |
2927 | } | |
2928 | ||
2929 | /* Others require only one message id, possibly followed by addresses, | |
2930 | which will be handled as normal arguments. */ | |
2931 | ||
2932 | else | |
2933 | { | |
2934 | if (!mac_ismsgid(argv[msg_action_arg])) | |
9af3c549 | 2935 | exim_fail("exim: malformed message id %s after %s option\n", |
059ec3d9 | 2936 | argv[msg_action_arg], arg); |
059ec3d9 PH |
2937 | i++; |
2938 | } | |
2939 | break; | |
2940 | ||
2941 | ||
2942 | /* Some programs seem to call the -om option without the leading o; | |
2943 | for sendmail it askes for "me too". Exim always does this. */ | |
2944 | ||
2945 | case 'm': | |
a76d120a | 2946 | if (*argrest) badarg = TRUE; |
059ec3d9 PH |
2947 | break; |
2948 | ||
2949 | ||
2950 | /* -N: don't do delivery - a debugging option that stops transports doing | |
2951 | their thing. It implies debugging at the D_v level. */ | |
2952 | ||
2953 | case 'N': | |
a76d120a | 2954 | if (!*argrest) |
059ec3d9 | 2955 | { |
8768d548 | 2956 | f.dont_deliver = TRUE; |
059ec3d9 PH |
2957 | debug_selector |= D_v; |
2958 | debug_file = stderr; | |
2959 | } | |
2960 | else badarg = TRUE; | |
2961 | break; | |
2962 | ||
2963 | ||
12f69989 PP |
2964 | /* -n: This means "don't alias" in sendmail, apparently. |
2965 | For normal invocations, it has no effect. | |
2966 | It may affect some other options. */ | |
059ec3d9 PH |
2967 | |
2968 | case 'n': | |
12f69989 | 2969 | flag_n = TRUE; |
059ec3d9 PH |
2970 | break; |
2971 | ||
2972 | /* -O: Just ignore it. In sendmail, apparently -O option=value means set | |
2973 | option to the specified value. This form uses long names. We need to handle | |
2974 | -O option=value and -Ooption=value. */ | |
2975 | ||
2976 | case 'O': | |
a76d120a | 2977 | if (!*argrest) |
059ec3d9 | 2978 | if (++i >= argc) |
9af3c549 | 2979 | exim_fail("exim: string expected after -O\n"); |
059ec3d9 PH |
2980 | break; |
2981 | ||
2982 | case 'o': | |
777cc748 | 2983 | switch (*argrest++) |
059ec3d9 | 2984 | { |
777cc748 JH |
2985 | /* -oA: Set an argument for the bi command (sendmail's "alternate alias |
2986 | file" option). */ | |
2987 | case 'A': | |
2988 | if (!*(alias_arg = argrest)) | |
2989 | if (i+1 < argc) alias_arg = argv[++i]; | |
2990 | else exim_fail("exim: string expected after -oA\n"); | |
2991 | break; | |
2992 | ||
2993 | /* -oB: Set a connection message max value for remote deliveries */ | |
2994 | case 'B': | |
2995 | { | |
2996 | uschar * p = argrest; | |
2997 | if (!*p) | |
2998 | if (i+1 < argc && isdigit((argv[i+1][0]))) | |
2999 | p = argv[++i]; | |
3000 | else | |
3001 | { | |
3002 | connection_max_messages = 1; | |
3003 | p = NULL; | |
3004 | } | |
059ec3d9 | 3005 | |
777cc748 JH |
3006 | if (p) |
3007 | { | |
3008 | if (!isdigit(*p)) | |
3009 | exim_fail("exim: number expected after -oB\n"); | |
3010 | connection_max_messages = Uatoi(p); | |
3011 | } | |
3012 | } | |
3013 | break; | |
3014 | ||
3015 | /* -odb: background delivery */ | |
3016 | ||
3017 | case 'd': | |
3018 | if (Ustrcmp(argrest, "b") == 0) | |
3019 | { | |
3020 | f.synchronous_delivery = FALSE; | |
3021 | arg_queue_only = FALSE; | |
3022 | queue_only_set = TRUE; | |
3023 | } | |
3024 | ||
ff966302 JH |
3025 | /* -odd: testsuite-only: add no inter-process delays */ |
3026 | ||
3027 | else if (Ustrcmp(argrest, "d") == 0) | |
3028 | f.testsuite_delays = FALSE; | |
3029 | ||
777cc748 JH |
3030 | /* -odf: foreground delivery (smail-compatible option); same effect as |
3031 | -odi: interactive (synchronous) delivery (sendmail-compatible option) | |
3032 | */ | |
3033 | ||
3034 | else if (Ustrcmp(argrest, "f") == 0 || Ustrcmp(argrest, "i") == 0) | |
3035 | { | |
3036 | f.synchronous_delivery = TRUE; | |
3037 | arg_queue_only = FALSE; | |
3038 | queue_only_set = TRUE; | |
3039 | } | |
3040 | ||
3041 | /* -odq: queue only */ | |
3042 | ||
3043 | else if (Ustrcmp(argrest, "q") == 0) | |
3044 | { | |
3045 | f.synchronous_delivery = FALSE; | |
3046 | arg_queue_only = TRUE; | |
3047 | queue_only_set = TRUE; | |
3048 | } | |
3049 | ||
3050 | /* -odqs: queue SMTP only - do local deliveries and remote routing, | |
3051 | but no remote delivery */ | |
3052 | ||
3053 | else if (Ustrcmp(argrest, "qs") == 0) | |
3054 | { | |
3055 | f.queue_smtp = TRUE; | |
3056 | arg_queue_only = FALSE; | |
3057 | queue_only_set = TRUE; | |
3058 | } | |
3059 | else badarg = TRUE; | |
3060 | break; | |
3061 | ||
3062 | /* -oex: Sendmail error flags. As these are also accepted without the | |
3063 | leading -o prefix, for compatibility with vacation and other callers, | |
3064 | they are handled with -e above. */ | |
3065 | ||
3066 | /* -oi: Set flag so dot doesn't end non-SMTP input (same as -i) | |
3067 | -oitrue: Another sendmail syntax for the same */ | |
3068 | ||
3069 | case 'i': | |
3070 | if (!*argrest || Ustrcmp(argrest, "true") == 0) | |
3071 | f.dot_ends = FALSE; | |
3072 | else badarg = TRUE; | |
3073 | break; | |
059ec3d9 PH |
3074 | |
3075 | /* -oM*: Set various characteristics for an incoming message; actually | |
3076 | acted on for trusted callers only. */ | |
3077 | ||
777cc748 JH |
3078 | case 'M': |
3079 | { | |
3080 | if (i+1 >= argc) | |
3081 | exim_fail("exim: data expected after -oM%s\n", argrest); | |
059ec3d9 | 3082 | |
777cc748 | 3083 | /* -oMa: Set sender host address */ |
059ec3d9 | 3084 | |
a76d120a JH |
3085 | if (Ustrcmp(argrest, "a") == 0) |
3086 | sender_host_address = string_copy_taint(argv[++i], TRUE); | |
059ec3d9 | 3087 | |
777cc748 | 3088 | /* -oMaa: Set authenticator name */ |
059ec3d9 | 3089 | |
777cc748 | 3090 | else if (Ustrcmp(argrest, "aa") == 0) |
a76d120a | 3091 | sender_host_authenticated = string_copy_taint(argv[++i], TRUE); |
059ec3d9 | 3092 | |
777cc748 | 3093 | /* -oMas: setting authenticated sender */ |
059ec3d9 | 3094 | |
777cc748 JH |
3095 | else if (Ustrcmp(argrest, "as") == 0) |
3096 | authenticated_sender = string_copy_taint(argv[++i], TRUE); | |
059ec3d9 | 3097 | |
777cc748 | 3098 | /* -oMai: setting authenticated id */ |
059ec3d9 | 3099 | |
777cc748 JH |
3100 | else if (Ustrcmp(argrest, "ai") == 0) |
3101 | authenticated_id = string_copy_taint(argv[++i], TRUE); | |
059ec3d9 | 3102 | |
777cc748 | 3103 | /* -oMi: Set incoming interface address */ |
d2af03f4 | 3104 | |
a76d120a JH |
3105 | else if (Ustrcmp(argrest, "i") == 0) |
3106 | interface_address = string_copy_taint(argv[++i], TRUE); | |
d2af03f4 | 3107 | |
777cc748 | 3108 | /* -oMm: Message reference */ |
059ec3d9 | 3109 | |
777cc748 JH |
3110 | else if (Ustrcmp(argrest, "m") == 0) |
3111 | { | |
3112 | if (!mac_ismsgid(argv[i+1])) | |
3113 | exim_fail("-oMm must be a valid message ID\n"); | |
3114 | if (!f.trusted_config) | |
3115 | exim_fail("-oMm must be called by a trusted user/config\n"); | |
3116 | message_reference = argv[++i]; | |
3117 | } | |
059ec3d9 | 3118 | |
777cc748 | 3119 | /* -oMr: Received protocol */ |
059ec3d9 | 3120 | |
777cc748 | 3121 | else if (Ustrcmp(argrest, "r") == 0) |
059ec3d9 | 3122 | |
777cc748 JH |
3123 | if (received_protocol) |
3124 | exim_fail("received_protocol is set already\n"); | |
3125 | else | |
a76d120a | 3126 | received_protocol = string_copy_taint(argv[++i], TRUE); |
059ec3d9 | 3127 | |
777cc748 | 3128 | /* -oMs: Set sender host name */ |
059ec3d9 | 3129 | |
777cc748 JH |
3130 | else if (Ustrcmp(argrest, "s") == 0) |
3131 | sender_host_name = string_copy_taint(argv[++i], TRUE); | |
059ec3d9 | 3132 | |
777cc748 | 3133 | /* -oMt: Set sender ident */ |
059ec3d9 | 3134 | |
777cc748 JH |
3135 | else if (Ustrcmp(argrest, "t") == 0) |
3136 | { | |
3137 | sender_ident_set = TRUE; | |
a76d120a | 3138 | sender_ident = string_copy_taint(argv[++i], TRUE); |
777cc748 | 3139 | } |
059ec3d9 | 3140 | |
777cc748 | 3141 | /* Else a bad argument */ |
059ec3d9 | 3142 | |
777cc748 JH |
3143 | else |
3144 | badarg = TRUE; | |
3145 | } | |
3146 | break; | |
3147 | ||
3148 | /* -om: Me-too flag for aliases. Exim always does this. Some programs | |
3149 | seem to call this as -m (undocumented), so that is also accepted (see | |
3150 | above). */ | |
3151 | /* -oo: An ancient flag for old-style addresses which still seems to | |
3152 | crop up in some calls (see in SCO). */ | |
3153 | ||
3154 | case 'm': | |
3155 | case 'o': | |
305e4fae | 3156 | if (*argrest) badarg = TRUE; |
777cc748 JH |
3157 | break; |
3158 | ||
3159 | /* -oP <name>: set pid file path for daemon | |
3160 | -oPX: delete pid file of daemon */ | |
3161 | ||
3162 | case 'P': | |
3163 | if (!*argrest) override_pid_file_path = argv[++i]; | |
3164 | else if (Ustrcmp(argrest, "X") == 0) delete_pid_file(); | |
3165 | else badarg = TRUE; | |
3166 | break; | |
3167 | ||
3168 | ||
3169 | /* -or <n>: set timeout for non-SMTP acceptance | |
3170 | -os <n>: set timeout for SMTP acceptance */ | |
3171 | ||
3172 | case 'r': | |
3173 | case 's': | |
305e4fae HSHR |
3174 | { |
3175 | int * tp = argrest[-1] == 'r' | |
3176 | ? &arg_receive_timeout : &arg_smtp_receive_timeout; | |
3177 | if (*argrest) | |
3178 | *tp = readconf_readtime(argrest, 0, FALSE); | |
3179 | else if (i+1 < argc) | |
3180 | *tp = readconf_readtime(argv[++i], 0, FALSE); | |
3181 | ||
3182 | if (*tp < 0) | |
3183 | exim_fail("exim: bad time value %s: abandoned\n", argv[i]); | |
3184 | } | |
777cc748 | 3185 | break; |
059ec3d9 | 3186 | |
777cc748 | 3187 | /* -oX <list>: Override local_interfaces and/or default daemon ports */ |
059ec3d9 | 3188 | |
777cc748 | 3189 | case 'X': |
305e4fae | 3190 | if (*argrest) badarg = TRUE; |
a76d120a | 3191 | else override_local_interfaces = string_copy_taint(argv[++i], TRUE); |
777cc748 | 3192 | break; |
01446a56 | 3193 | |
777cc748 | 3194 | /* Unknown -o argument */ |
059ec3d9 | 3195 | |
777cc748 JH |
3196 | default: |
3197 | badarg = TRUE; | |
059ec3d9 | 3198 | } |
059ec3d9 PH |
3199 | break; |
3200 | ||
3201 | ||
3202 | /* -ps: force Perl startup; -pd force delayed Perl startup */ | |
3203 | ||
3204 | case 'p': | |
3205 | #ifdef EXIM_PERL | |
3206 | if (*argrest == 's' && argrest[1] == 0) | |
3207 | { | |
3208 | perl_start_option = 1; | |
3209 | break; | |
3210 | } | |
3211 | if (*argrest == 'd' && argrest[1] == 0) | |
3212 | { | |
3213 | perl_start_option = -1; | |
3214 | break; | |
3215 | } | |
3216 | #endif | |
3217 | ||
3218 | /* -panythingelse is taken as the Sendmail-compatible argument -prval:sval, | |
3219 | which sets the host protocol and host name */ | |
3220 | ||
a76d120a JH |
3221 | if (!*argrest) |
3222 | if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; } | |
059ec3d9 | 3223 | |
a76d120a | 3224 | if (*argrest) |
059ec3d9 | 3225 | { |
137ae145 | 3226 | uschar * hn = Ustrchr(argrest, ':'); |
65e061b7 HSHR |
3227 | |
3228 | if (received_protocol) | |
9af3c549 | 3229 | exim_fail("received_protocol is set already\n"); |
65e061b7 | 3230 | |
a76d120a JH |
3231 | if (!hn) |
3232 | received_protocol = string_copy_taint(argrest, TRUE); | |
059ec3d9 PH |
3233 | else |
3234 | { | |
a76d120a | 3235 | received_protocol = string_copyn_taint(argrest, hn - argrest, TRUE); |
a76d120a | 3236 | sender_host_name = string_copy_taint(hn + 1, TRUE); |
059ec3d9 PH |
3237 | } |
3238 | } | |
3239 | break; | |
3240 | ||
3241 | ||
3242 | case 'q': | |
3243 | receiving_message = FALSE; | |
3cc66b45 | 3244 | if (queue_interval >= 0) |
9af3c549 | 3245 | exim_fail("exim: -q specified more than once\n"); |
059ec3d9 PH |
3246 | |
3247 | /* -qq...: Do queue runs in a 2-stage manner */ | |
3248 | ||
3249 | if (*argrest == 'q') | |
3250 | { | |
8768d548 | 3251 | f.queue_2stage = TRUE; |
059ec3d9 PH |
3252 | argrest++; |
3253 | } | |
3254 | ||
3255 | /* -qi...: Do only first (initial) deliveries */ | |
3256 | ||
3257 | if (*argrest == 'i') | |
3258 | { | |
8768d548 | 3259 | f.queue_run_first_delivery = TRUE; |
059ec3d9 PH |
3260 | argrest++; |
3261 | } | |
3262 | ||
3263 | /* -qf...: Run the queue, forcing deliveries | |
3264 | -qff..: Ditto, forcing thawing as well */ | |
3265 | ||
3266 | if (*argrest == 'f') | |
3267 | { | |
8768d548 | 3268 | f.queue_run_force = TRUE; |
55e70e76 | 3269 | if (*++argrest == 'f') |
059ec3d9 | 3270 | { |
8768d548 | 3271 | f.deliver_force_thaw = TRUE; |
059ec3d9 PH |
3272 | argrest++; |
3273 | } | |
3274 | } | |
3275 | ||
3276 | /* -q[f][f]l...: Run the queue only on local deliveries */ | |
3277 | ||
3278 | if (*argrest == 'l') | |
3279 | { | |
8768d548 | 3280 | f.queue_run_local = TRUE; |
059ec3d9 PH |
3281 | argrest++; |
3282 | } | |
3283 | ||
55e70e76 | 3284 | /* -q[f][f][l][G<name>]... Work on the named queue */ |
28b3821f JH |
3285 | |
3286 | if (*argrest == 'G') | |
3287 | { | |
fa665e0b JH |
3288 | int i; |
3289 | for (argrest++, i = 0; argrest[i] && argrest[i] != '/'; ) i++; | |
3290 | queue_name = string_copyn(argrest, i); | |
3291 | argrest += i; | |
3292 | if (*argrest == '/') argrest++; | |
28b3821f JH |
3293 | } |
3294 | ||
3295 | /* -q[f][f][l][G<name>]: Run the queue, optionally forced, optionally local | |
3296 | only, optionally named, optionally starting from a given message id. */ | |
059ec3d9 | 3297 | |
e5903596 | 3298 | if (!(list_queue || count_queue)) |
a76d120a | 3299 | if ( !*argrest |
e5903596 JH |
3300 | && (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1]))) |
3301 | { | |
3302 | queue_interval = 0; | |
3303 | if (i+1 < argc && mac_ismsgid(argv[i+1])) | |
a76d120a | 3304 | start_queue_run_id = string_copy_taint(argv[++i], TRUE); |
e5903596 | 3305 | if (i+1 < argc && mac_ismsgid(argv[i+1])) |
a76d120a | 3306 | stop_queue_run_id = string_copy_taint(argv[++i], TRUE); |
e5903596 | 3307 | } |
059ec3d9 | 3308 | |
fa665e0b JH |
3309 | /* -q[f][f][l][G<name>/]<n>: Run the queue at regular intervals, optionally |
3310 | forced, optionally local only, optionally named. */ | |
059ec3d9 | 3311 | |
e5903596 JH |
3312 | else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i], |
3313 | 0, FALSE)) <= 0) | |
3314 | exim_fail("exim: bad time value %s: abandoned\n", argv[i]); | |
059ec3d9 PH |
3315 | break; |
3316 | ||
3317 | ||
3318 | case 'R': /* Synonymous with -qR... */ | |
3319 | receiving_message = FALSE; | |
3320 | ||
3321 | /* -Rf: As -R (below) but force all deliveries, | |
3322 | -Rff: Ditto, but also thaw all frozen messages, | |
3323 | -Rr: String is regex | |
3324 | -Rrf: Regex and force | |
3325 | -Rrff: Regex and force and thaw | |
3326 | ||
3327 | in all cases provided there are no further characters in this | |
3328 | argument. */ | |
3329 | ||
a76d120a | 3330 | if (*argrest) |
d7978c0f | 3331 | for (int i = 0; i < nelem(rsopts); i++) |
059ec3d9 PH |
3332 | if (Ustrcmp(argrest, rsopts[i]) == 0) |
3333 | { | |
8768d548 JH |
3334 | if (i != 2) f.queue_run_force = TRUE; |
3335 | if (i >= 2) f.deliver_selectstring_regex = TRUE; | |
3336 | if (i == 1 || i == 4) f.deliver_force_thaw = TRUE; | |
059ec3d9 PH |
3337 | argrest += Ustrlen(rsopts[i]); |
3338 | } | |
059ec3d9 PH |
3339 | |
3340 | /* -R: Set string to match in addresses for forced queue run to | |
3341 | pick out particular messages. */ | |
3342 | ||
55e70e76 | 3343 | if (*argrest) |
a76d120a | 3344 | deliver_selectstring = string_copy_taint(argrest, TRUE); |
55e70e76 | 3345 | else if (i+1 < argc) |
a76d120a | 3346 | deliver_selectstring = string_copy_taint(argv[++i], TRUE); |
55e70e76 | 3347 | else |
9af3c549 | 3348 | exim_fail("exim: string expected after -R\n"); |
059ec3d9 PH |
3349 | break; |
3350 | ||
3351 | ||
3352 | /* -r: an obsolete synonym for -f (see above) */ | |
3353 | ||
3354 | ||
3355 | /* -S: Like -R but works on sender. */ | |
3356 | ||
3357 | case 'S': /* Synonymous with -qS... */ | |
3358 | receiving_message = FALSE; | |
3359 | ||
3360 | /* -Sf: As -S (below) but force all deliveries, | |
3361 | -Sff: Ditto, but also thaw all frozen messages, | |
3362 | -Sr: String is regex | |
3363 | -Srf: Regex and force | |
3364 | -Srff: Regex and force and thaw | |
3365 | ||
3366 | in all cases provided there are no further characters in this | |
3367 | argument. */ | |
3368 | ||
55e70e76 | 3369 | if (*argrest) |
d7978c0f | 3370 | for (int i = 0; i < nelem(rsopts); i++) |
059ec3d9 PH |
3371 | if (Ustrcmp(argrest, rsopts[i]) == 0) |
3372 | { | |
8768d548 JH |
3373 | if (i != 2) f.queue_run_force = TRUE; |
3374 | if (i >= 2) f.deliver_selectstring_sender_regex = TRUE; | |
3375 | if (i == 1 || i == 4) f.deliver_force_thaw = TRUE; | |
059ec3d9 PH |
3376 | argrest += Ustrlen(rsopts[i]); |
3377 | } | |
059ec3d9 PH |
3378 | |
3379 | /* -S: Set string to match in addresses for forced queue run to | |
3380 | pick out particular messages. */ | |
3381 | ||
55e70e76 | 3382 | if (*argrest) |
a76d120a | 3383 | deliver_selectstring_sender = string_copy_taint(argrest, TRUE); |
55e70e76 | 3384 | else if (i+1 < argc) |
a76d120a | 3385 | deliver_selectstring_sender = string_copy_taint(argv[++i], TRUE); |
55e70e76 | 3386 | else |
9af3c549 | 3387 | exim_fail("exim: string expected after -S\n"); |
059ec3d9 PH |
3388 | break; |
3389 | ||
3390 | /* -Tqt is an option that is exclusively for use by the testing suite. | |
3391 | It is not recognized in other circumstances. It allows for the setting up | |
3392 | of explicit "queue times" so that various warning/retry things can be | |
3393 | tested. Otherwise variability of clock ticks etc. cause problems. */ | |
3394 | ||
3395 | case 'T': | |
8768d548 | 3396 | if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0) |
a76d120a | 3397 | fudged_queue_times = string_copy_taint(argv[++i], TRUE); |
059ec3d9 PH |
3398 | else badarg = TRUE; |
3399 | break; | |
3400 | ||
3401 | ||
3402 | /* -t: Set flag to extract recipients from body of message. */ | |
3403 | ||
3404 | case 't': | |
a76d120a | 3405 | if (!*argrest) extract_recipients = TRUE; |
059ec3d9 PH |
3406 | |
3407 | /* -ti: Set flag to extract recipients from body of message, and also | |
3408 | specify that dot does not end the message. */ | |
3409 | ||
3410 | else if (Ustrcmp(argrest, "i") == 0) | |
3411 | { | |
3412 | extract_recipients = TRUE; | |
8768d548 | 3413 | f.dot_ends = FALSE; |
059ec3d9 PH |
3414 | } |
3415 | ||
3416 | /* -tls-on-connect: don't wait for STARTTLS (for old clients) */ | |
3417 | ||
01603eec | 3418 | #ifndef DISABLE_TLS |
817d9f57 | 3419 | else if (Ustrcmp(argrest, "ls-on-connect") == 0) tls_in.on_connect = TRUE; |
059ec3d9 PH |
3420 | #endif |
3421 | ||
3422 | else badarg = TRUE; | |
3423 | break; | |
3424 | ||
3425 | ||
3426 | /* -U: This means "initial user submission" in sendmail, apparently. The | |
3427 | doc claims that in future sendmail may refuse syntactically invalid | |
3428 | messages instead of fixing them. For the moment, we just ignore it. */ | |
3429 | ||
3430 | case 'U': | |
3431 | break; | |
3432 | ||
3433 | ||
3434 | /* -v: verify things - this is a very low-level debugging */ | |
3435 | ||
3436 | case 'v': | |
a76d120a | 3437 | if (!*argrest) |
059ec3d9 PH |
3438 | { |
3439 | debug_selector |= D_v; | |
3440 | debug_file = stderr; | |
3441 | } | |
3442 | else badarg = TRUE; | |
3443 | break; | |
3444 | ||
3445 | ||
3446 | /* -x: AIX uses this to indicate some fancy 8-bit character stuff: | |
3447 | ||
3448 | The -x flag tells the sendmail command that mail from a local | |
3449 | mail program has National Language Support (NLS) extended characters | |
3450 | in the body of the mail item. The sendmail command can send mail with | |
3451 | extended NLS characters across networks that normally corrupts these | |
3452 | 8-bit characters. | |
3453 | ||
3454 | As Exim is 8-bit clean, it just ignores this flag. */ | |
3455 | ||
3456 | case 'x': | |
a76d120a | 3457 | if (*argrest) badarg = TRUE; |
059ec3d9 PH |
3458 | break; |
3459 | ||
a3fb9793 PP |
3460 | /* -X: in sendmail: takes one parameter, logfile, and sends debugging |
3461 | logs to that file. We swallow the parameter and otherwise ignore it. */ | |
3462 | ||
3463 | case 'X': | |
a76d120a | 3464 | if (!*argrest) |
a3fb9793 | 3465 | if (++i >= argc) |
9af3c549 | 3466 | exim_fail("exim: string expected after -X\n"); |
0ad2e0fc JH |
3467 | break; |
3468 | ||
3469 | case 'z': | |
a76d120a | 3470 | if (!*argrest) |
9af3c549 | 3471 | if (++i < argc) |
a76d120a | 3472 | log_oneline = string_copy_taint(argv[i], TRUE); |
9af3c549 JH |
3473 | else |
3474 | exim_fail("exim: file name expected after %s\n", argv[i-1]); | |
a3fb9793 PP |
3475 | break; |
3476 | ||
059ec3d9 PH |
3477 | /* All other initial characters are errors */ |
3478 | ||
3479 | default: | |
3480 | badarg = TRUE; | |
3481 | break; | |
3482 | } /* End of high-level switch statement */ | |
3483 | ||
3484 | /* Failed to recognize the option, or syntax error */ | |
3485 | ||
3486 | if (badarg) | |
9af3c549 | 3487 | exim_fail("exim abandoned: unknown, malformed, or incomplete " |
059ec3d9 | 3488 | "option %s\n", arg); |
059ec3d9 PH |
3489 | } |
3490 | ||
3491 | ||
3cc66b45 PH |
3492 | /* If -R or -S have been specified without -q, assume a single queue run. */ |
3493 | ||
137ae145 JH |
3494 | if ( (deliver_selectstring || deliver_selectstring_sender) |
3495 | && queue_interval < 0) | |
3496 | queue_interval = 0; | |
3cc66b45 PH |
3497 | |
3498 | ||
059ec3d9 | 3499 | END_ARG: |
137ae145 JH |
3500 | store_pool = old_pool; |
3501 | } | |
3502 | ||
81ea09ca NM |
3503 | /* If usage_wanted is set we call the usage function - which never returns */ |
3504 | if (usage_wanted) exim_usage(called_as); | |
3505 | ||
3506 | /* Arguments have been processed. Check for incompatibilities. */ | |
059ec3d9 PH |
3507 | if (( |
3508 | (smtp_input || extract_recipients || recipients_arg < argc) && | |
8768d548 | 3509 | (f.daemon_listen || queue_interval >= 0 || bi_option || |
059ec3d9 | 3510 | test_retry_arg >= 0 || test_rewrite_arg >= 0 || |
f05da2e8 | 3511 | filter_test != FTEST_NONE || (msg_action_arg > 0 && !one_msg_action)) |
059ec3d9 PH |
3512 | ) || |
3513 | ( | |
3514 | msg_action_arg > 0 && | |
8768d548 | 3515 | (f.daemon_listen || queue_interval > 0 || list_options || |
0ef732d9 PH |
3516 | (checking && msg_action != MSG_LOAD) || |
3517 | bi_option || test_retry_arg >= 0 || test_rewrite_arg >= 0) | |
059ec3d9 PH |
3518 | ) || |
3519 | ( | |
8768d548 | 3520 | (f.daemon_listen || queue_interval > 0) && |
059ec3d9 | 3521 | (sender_address != NULL || list_options || list_queue || checking || |
0ef732d9 | 3522 | bi_option) |
059ec3d9 PH |
3523 | ) || |
3524 | ( | |
8768d548 | 3525 | f.daemon_listen && queue_interval == 0 |
059ec3d9 PH |
3526 | ) || |
3527 | ( | |
8768d548 | 3528 | f.inetd_wait_mode && queue_interval >= 0 |
9ee44efb PP |
3529 | ) || |
3530 | ( | |
059ec3d9 PH |
3531 | list_options && |
3532 | (checking || smtp_input || extract_recipients || | |
f05da2e8 | 3533 | filter_test != FTEST_NONE || bi_option) |
059ec3d9 PH |
3534 | ) || |
3535 | ( | |
3536 | verify_address_mode && | |
8768d548 | 3537 | (f.address_test_mode || smtp_input || extract_recipients || |
f05da2e8 | 3538 | filter_test != FTEST_NONE || bi_option) |
059ec3d9 PH |
3539 | ) || |
3540 | ( | |
8768d548 | 3541 | f.address_test_mode && (smtp_input || extract_recipients || |
f05da2e8 | 3542 | filter_test != FTEST_NONE || bi_option) |
059ec3d9 PH |
3543 | ) || |
3544 | ( | |
f05da2e8 | 3545 | smtp_input && (sender_address != NULL || filter_test != FTEST_NONE || |
059ec3d9 PH |
3546 | extract_recipients) |
3547 | ) || | |
3548 | ( | |
3549 | deliver_selectstring != NULL && queue_interval < 0 | |
328895cc PH |
3550 | ) || |
3551 | ( | |
3552 | msg_action == MSG_LOAD && | |
3553 | (!expansion_test || expansion_test_message != NULL) | |
059ec3d9 PH |
3554 | ) |
3555 | ) | |
9af3c549 | 3556 | exim_fail("exim: incompatible command-line options or arguments\n"); |
059ec3d9 PH |
3557 | |
3558 | /* If debugging is set up, set the file and the file descriptor to pass on to | |
3559 | child processes. It should, of course, be 2 for stderr. Also, force the daemon | |
3560 | to run in the foreground. */ | |
3561 | ||
3562 | if (debug_selector != 0) | |
3563 | { | |
3564 | debug_file = stderr; | |
3565 | debug_fd = fileno(debug_file); | |
8768d548 | 3566 | f.background_daemon = FALSE; |
9f01e50d | 3567 | testharness_pause_ms(100); /* lets caller finish */ |
059ec3d9 PH |
3568 | if (debug_selector != D_v) /* -v only doesn't show this */ |
3569 | { | |
3570 | debug_printf("Exim version %s uid=%ld gid=%ld pid=%d D=%x\n", | |
3571 | version_string, (long int)real_uid, (long int)real_gid, (int)getpid(), | |
3572 | debug_selector); | |
6545de78 PP |
3573 | if (!version_printed) |
3574 | show_whats_supported(stderr); | |
059ec3d9 PH |
3575 | } |
3576 | } | |
3577 | ||
3578 | /* When started with root privilege, ensure that the limits on the number of | |
3579 | open files and the number of processes (where that is accessible) are | |
3580 | sufficiently large, or are unset, in case Exim has been called from an | |
3581 | environment where the limits are screwed down. Not all OS have the ability to | |
3582 | change some of these limits. */ | |
3583 | ||
3584 | if (unprivileged) | |
3585 | { | |
3586 | DEBUG(D_any) debug_print_ids(US"Exim has no root privilege:"); | |
3587 | } | |
3588 | else | |
3589 | { | |
3590 | struct rlimit rlp; | |
3591 | ||
3592 | #ifdef RLIMIT_NOFILE | |
3593 | if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) | |
3594 | { | |
3595 | log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NOFILE) failed: %s", | |
3596 | strerror(errno)); | |
3597 | rlp.rlim_cur = rlp.rlim_max = 0; | |
3598 | } | |
eb2c0248 PH |
3599 | |
3600 | /* I originally chose 1000 as a nice big number that was unlikely to | |
a494b1e1 PH |
3601 | be exceeded. It turns out that some older OS have a fixed upper limit of |
3602 | 256. */ | |
eb2c0248 | 3603 | |
059ec3d9 PH |
3604 | if (rlp.rlim_cur < 1000) |
3605 | { | |
3606 | rlp.rlim_cur = rlp.rlim_max = 1000; | |
3607 | if (setrlimit(RLIMIT_NOFILE, &rlp) < 0) | |
eb2c0248 | 3608 | { |
a494b1e1 PH |
3609 | rlp.rlim_cur = rlp.rlim_max = 256; |
3610 | if (setrlimit(RLIMIT_NOFILE, &rlp) < 0) | |
3611 | log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NOFILE) failed: %s", | |
3612 | strerror(errno)); | |
eb2c0248 | 3613 | } |
059ec3d9 PH |
3614 | } |
3615 | #endif | |
3616 | ||
3617 | #ifdef RLIMIT_NPROC | |
3618 | if (getrlimit(RLIMIT_NPROC, &rlp) < 0) | |
3619 | { | |
3620 | log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NPROC) failed: %s", | |
3621 | strerror(errno)); | |
3622 | rlp.rlim_cur = rlp.rlim_max = 0; | |
3623 | } | |
3624 | ||
3625 | #ifdef RLIM_INFINITY | |
3626 | if (rlp.rlim_cur != RLIM_INFINITY && rlp.rlim_cur < 1000) | |
3627 | { | |
3628 | rlp.rlim_cur = rlp.rlim_max = RLIM_INFINITY; | |
3629 | #else | |
3630 | if (rlp.rlim_cur < 1000) | |
3631 | { | |
3632 | rlp.rlim_cur = rlp.rlim_max = 1000; | |
3633 | #endif | |
3634 | if (setrlimit(RLIMIT_NPROC, &rlp) < 0) | |
3635 | log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NPROC) failed: %s", | |
3636 | strerror(errno)); | |
3637 | } | |
3638 | #endif | |
3639 | } | |
3640 | ||
3641 | /* Exim is normally entered as root (but some special configurations are | |
3642 | possible that don't do this). However, it always spins off sub-processes that | |
3643 | set their uid and gid as required for local delivery. We don't want to pass on | |
3644 | any extra groups that root may belong to, so we want to get rid of them all at | |
3645 | this point. | |
3646 | ||
3647 | We need to obey setgroups() at this stage, before possibly giving up root | |
3648 | privilege for a changed configuration file, but later on we might need to | |
3649 | check on the additional groups for the admin user privilege - can't do that | |
3650 | till after reading the config, which might specify the exim gid. Therefore, | |
3651 | save the group list here first. */ | |
3652 | ||
157d73b5 | 3653 | if ((group_count = getgroups(nelem(group_list), group_list)) < 0) |
9af3c549 | 3654 | exim_fail("exim: getgroups() failed: %s\n", strerror(errno)); |
059ec3d9 PH |
3655 | |
3656 | /* There is a fundamental difference in some BSD systems in the matter of | |
3657 | groups. FreeBSD and BSDI are known to be different; NetBSD and OpenBSD are | |
3658 | known not to be different. On the "different" systems there is a single group | |
3659 | list, and the first entry in it is the current group. On all other versions of | |
3660 | Unix there is a supplementary group list, which is in *addition* to the current | |
3661 | group. Consequently, to get rid of all extraneous groups on a "standard" system | |
3662 | you pass over 0 groups to setgroups(), while on a "different" system you pass | |
3663 | over a single group - the current group, which is always the first group in the | |
3664 | list. Calling setgroups() with zero groups on a "different" system results in | |
3665 | an error return. The following code should cope with both types of system. | |
3666 | ||
3b7ac02c JH |
3667 | Unfortunately, recent MacOS, which should be a FreeBSD, "helpfully" succeeds |
3668 | the "setgroups() with zero groups" - and changes the egid. | |
3669 | Thanks to that we had to stash the original_egid above, for use below | |
3670 | in the call to exim_setugid(). | |
3671 | ||
059ec3d9 | 3672 | However, if this process isn't running as root, setgroups() can't be used |
ccbb15c9 ST |
3673 | since you have to be root to run it, even if throwing away groups. |
3674 | Except, sigh, for Hurd - where you can. | |
3675 | Not being root here happens only in some unusual configurations. */ | |
059ec3d9 | 3676 | |
ccbb15c9 | 3677 | if ( !unprivileged |
25ef0f44 | 3678 | #ifndef OS_SETGROUPS_ZERO_DROPS_ALL |
ccbb15c9 | 3679 | && setgroups(0, NULL) != 0 |
25ef0f44 | 3680 | #endif |
ccbb15c9 | 3681 | && setgroups(1, group_list) != 0) |
9af3c549 | 3682 | exim_fail("exim: setgroups() failed: %s\n", strerror(errno)); |
059ec3d9 PH |
3683 | |
3684 | /* If the configuration file name has been altered by an argument on the | |
3685 | command line (either a new file name or a macro definition) and the caller is | |
cd25e41d DW |
3686 | not root, or if this is a filter testing run, remove any setuid privilege the |
3687 | program has and run as the underlying user. | |
059ec3d9 | 3688 | |
cd25e41d DW |
3689 | The exim user is locked out of this, which severely restricts the use of -C |
3690 | for some purposes. | |
059ec3d9 PH |
3691 | |
3692 | Otherwise, set the real ids to the effective values (should be root unless run | |
3693 | from inetd, which it can either be root or the exim uid, if one is configured). | |
3694 | ||
3695 | There is a private mechanism for bypassing some of this, in order to make it | |
3696 | possible to test lots of configurations automatically, without having either to | |
3697 | recompile each time, or to patch in an actual configuration file name and other | |
3698 | values (such as the path name). If running in the test harness, pretend that | |
3699 | configuration file changes and macro definitions haven't happened. */ | |
3700 | ||
3701 | if (( /* EITHER */ | |
8768d548 | 3702 | (!f.trusted_config || /* Config changed, or */ |
a4034eb8 | 3703 | !macros_trusted(opt_D_used)) && /* impermissible macros and */ |
059ec3d9 | 3704 | real_uid != root_uid && /* Not root, and */ |
8768d548 | 3705 | !f.running_in_test_harness /* Not fudged */ |
059ec3d9 PH |
3706 | ) || /* OR */ |
3707 | expansion_test /* expansion testing */ | |
3708 | || /* OR */ | |
f05da2e8 | 3709 | filter_test != FTEST_NONE) /* Filter testing */ |
059ec3d9 PH |
3710 | { |
3711 | setgroups(group_count, group_list); | |
3712 | exim_setugid(real_uid, real_gid, FALSE, | |
3713 | US"-C, -D, -be or -bf forces real uid"); | |
3714 | removed_privilege = TRUE; | |
3715 | ||
3716 | /* In the normal case when Exim is called like this, stderr is available | |
3717 | and should be used for any logging information because attempts to write | |
3718 | to the log will usually fail. To arrange this, we unset really_exim. However, | |
3719 | if no stderr is available there is no point - we might as well have a go | |
b7487bce | 3720 | at the log (if it fails, syslog will be written). |
059ec3d9 | 3721 | |
b7487bce PP |
3722 | Note that if the invoker is Exim, the logs remain available. Messing with |
3723 | this causes unlogged successful deliveries. */ | |
3724 | ||
9af3c549 | 3725 | if (log_stderr && real_uid != exim_uid) |
8768d548 | 3726 | f.really_exim = FALSE; |
059ec3d9 PH |
3727 | } |
3728 | ||
3729 | /* Privilege is to be retained for the moment. It may be dropped later, | |
3730 | depending on the job that this Exim process has been asked to do. For now, set | |
3731 | the real uid to the effective so that subsequent re-execs of Exim are done by a | |
3732 | privileged user. */ | |
3733 | ||
9af3c549 | 3734 | else |
3b7ac02c | 3735 | exim_setugid(geteuid(), original_egid, FALSE, US"forcing real = effective"); |
059ec3d9 | 3736 | |
f05da2e8 | 3737 | /* If testing a filter, open the file(s) now, before wasting time doing other |
059ec3d9 PH |
3738 | setups and reading the message. */ |
3739 | ||
9af3c549 JH |
3740 | if (filter_test & FTEST_SYSTEM) |
3741 | if ((filter_sfd = Uopen(filter_test_sfile, O_RDONLY, 0)) < 0) | |
3742 | exim_fail("exim: failed to open %s: %s\n", filter_test_sfile, | |
f05da2e8 | 3743 | strerror(errno)); |
f05da2e8 | 3744 | |
9af3c549 JH |
3745 | if (filter_test & FTEST_USER) |
3746 | if ((filter_ufd = Uopen(filter_test_ufile, O_RDONLY, 0)) < 0) | |
3747 | exim_fail("exim: failed to open %s: %s\n", filter_test_ufile, | |
059ec3d9 | 3748 | strerror(errno)); |
059ec3d9 | 3749 | |
8829633f PP |
3750 | /* Initialise lookup_list |
3751 | If debugging, already called above via version reporting. | |
3752 | In either case, we initialise the list of available lookups while running | |
3753 | as root. All dynamically modules are loaded from a directory which is | |
3754 | hard-coded into the binary and is code which, if not a module, would be | |
3755 | part of Exim already. Ability to modify the content of the directory | |
3756 | is equivalent to the ability to modify a setuid binary! | |
3757 | ||
3758 | This needs to happen before we read the main configuration. */ | |
3759 | init_lookup_list(); | |
3760 | ||
8c5d388a | 3761 | #ifdef SUPPORT_I18N |
8768d548 | 3762 | if (f.running_in_test_harness) smtputf8_advertise_hosts = NULL; |
9d4319df JH |
3763 | #endif |
3764 | ||
059ec3d9 PH |
3765 | /* Read the main runtime configuration data; this gives up if there |
3766 | is a failure. It leaves the configuration file open so that the subsequent | |
3de973a2 | 3767 | configuration data for delivery can be read if needed. |
059ec3d9 | 3768 | |
aded2255 | 3769 | NOTE: immediately after opening the configuration file we change the working |
3de973a2 HSHR |
3770 | directory to "/"! Later we change to $spool_directory. We do it there, because |
3771 | during readconf_main() some expansion takes place already. */ | |
bc3c7bb7 | 3772 | |
cd328be9 JH |
3773 | /* Store the initial cwd before we change directories. Can be NULL if the |
3774 | dir has already been unlinked. */ | |
3775 | initial_cwd = os_getcwd(NULL, 0); | |
3615fa9a | 3776 | |
34e86e20 HSHR |
3777 | /* checking: |
3778 | -be[m] expansion test - | |
3779 | -b[fF] filter test new | |
3780 | -bh[c] host test - | |
3781 | -bmalware malware_test_file new | |
3782 | -brt retry test new | |
3783 | -brw rewrite test new | |
3784 | -bt address test - | |
3785 | -bv[s] address verify - | |
3786 | list_options: | |
3787 | -bP <option> (except -bP config, which sets list_config) | |
3788 | ||
3789 | If any of these options is set, we suppress warnings about configuration | |
3790 | issues (currently about tls_advertise_hosts and keep_environment not being | |
3791 | defined) */ | |
3792 | ||
9f01e50d JH |
3793 | { |
3794 | #ifdef MEASURE_TIMING | |
3795 | struct timeval t0, diff; | |
3796 | (void)gettimeofday(&t0, NULL); | |
3797 | #endif | |
3798 | ||
3799 | readconf_main(checking || list_options); | |
3800 | ||
3801 | #ifdef MEASURE_TIMING | |
3802 | report_time_since(&t0, US"readconf_main (delta)"); | |
3803 | #endif | |
3804 | } | |
059ec3d9 | 3805 | |
32b8ce41 | 3806 | |
3de973a2 HSHR |
3807 | /* Now in directory "/" */ |
3808 | ||
bc3c7bb7 HSHR |
3809 | if (cleanup_environment() == FALSE) |
3810 | log_write(0, LOG_PANIC_DIE, "Can't cleanup environment"); | |
3811 | ||
3812 | ||
a3fb9793 PP |
3813 | /* If an action on specific messages is requested, or if a daemon or queue |
3814 | runner is being started, we need to know if Exim was called by an admin user. | |
3815 | This is the case if the real user is root or exim, or if the real group is | |
3816 | exim, or if one of the supplementary groups is exim or a group listed in | |
3817 | admin_groups. We don't fail all message actions immediately if not admin_user, | |
3818 | since some actions can be performed by non-admin users. Instead, set admin_user | |
3819 | for later interrogation. */ | |
3820 | ||
3821 | if (real_uid == root_uid || real_uid == exim_uid || real_gid == exim_gid) | |
8768d548 | 3822 | f.admin_user = TRUE; |
a3fb9793 | 3823 | else |
d7978c0f | 3824 | for (int i = 0; i < group_count && !f.admin_user; i++) |
32b8ce41 | 3825 | if (group_list[i] == exim_gid) |
8768d548 | 3826 | f.admin_user = TRUE; |
32b8ce41 | 3827 | else if (admin_groups) |
d7978c0f | 3828 | for (int j = 1; j <= (int)admin_groups[0] && !f.admin_user; j++) |
a3fb9793 | 3829 | if (admin_groups[j] == group_list[i]) |
8768d548 | 3830 | f.admin_user = TRUE; |
a3fb9793 PP |
3831 | |
3832 | /* Another group of privileged users are the trusted users. These are root, | |
3833 | exim, and any caller matching trusted_users or trusted_groups. Trusted callers | |
3834 | are permitted to specify sender_addresses with -f on the command line, and | |
3835 | other message parameters as well. */ | |
3836 | ||
3837 | if (real_uid == root_uid || real_uid == exim_uid) | |
8768d548 | 3838 | f.trusted_caller = TRUE; |
a3fb9793 PP |
3839 | else |
3840 | { | |
32b8ce41 | 3841 | if (trusted_users) |
d7978c0f | 3842 | for (int i = 1; i <= (int)trusted_users[0] && !f.trusted_caller; i++) |
a3fb9793 | 3843 | if (trusted_users[i] == real_uid) |
8768d548 | 3844 | f.trusted_caller = TRUE; |
a3fb9793 | 3845 | |
32b8ce41 | 3846 | if (trusted_groups) |
d7978c0f | 3847 | for (int i = 1; i <= (int)trusted_groups[0] && !f.trusted_caller; i++) |
a3fb9793 | 3848 | if (trusted_groups[i] == real_gid) |
8768d548 | 3849 | f.trusted_caller = TRUE; |
d7978c0f | 3850 | else for (int j = 0; j < group_count && !f.trusted_caller; j++) |
a3fb9793 | 3851 | if (trusted_groups[i] == group_list[j]) |
8768d548 | 3852 | f.trusted_caller = TRUE; |
a3fb9793 PP |
3853 | } |
3854 | ||
f33875c3 | 3855 | /* At this point, we know if the user is privileged and some command-line |
b4a1e238 | 3856 | options become possibly impermissible, depending upon the configuration file. */ |
f33875c3 | 3857 | |
9af3c549 JH |
3858 | if (checking && commandline_checks_require_admin && !f.admin_user) |
3859 | exim_fail("exim: those command-line flags are set to require admin\n"); | |
f33875c3 | 3860 | |
059ec3d9 PH |
3861 | /* Handle the decoding of logging options. */ |
3862 | ||
6c6d6e48 | 3863 | decode_bits(log_selector, log_selector_size, log_notall, |
ed7f7860 | 3864 | log_selector_string, log_options, log_options_count, US"log", 0); |
059ec3d9 PH |
3865 | |
3866 | DEBUG(D_any) | |
3867 | { | |
3868 | debug_printf("configuration file is %s\n", config_main_filename); | |
6c6d6e48 | 3869 | debug_printf("log selectors ="); |
d7978c0f | 3870 | for (int i = 0; i < log_selector_size; i++) |
6c6d6e48 TF |
3871 | debug_printf(" %08x", log_selector[i]); |
3872 | debug_printf("\n"); | |
059ec3d9 PH |
3873 | } |
3874 | ||
3875 | /* If domain literals are not allowed, check the sender address that was | |
3876 | supplied with -f. Ditto for a stripped trailing dot. */ | |
3877 | ||
9af3c549 | 3878 | if (sender_address) |
059ec3d9 PH |
3879 | { |
3880 | if (sender_address[sender_address_domain] == '[' && !allow_domain_literals) | |
9af3c549 | 3881 | exim_fail("exim: bad -f address \"%s\": domain literals not " |
059ec3d9 | 3882 | "allowed\n", sender_address); |
059ec3d9 | 3883 | if (f_end_dot && !strip_trailing_dot) |
9af3c549 | 3884 | exim_fail("exim: bad -f address \"%s.\": domain is malformed " |
059ec3d9 | 3885 | "(trailing dot not allowed)\n", sender_address); |
059ec3d9 PH |
3886 | } |
3887 | ||
a3fb9793 PP |
3888 | /* See if an admin user overrode our logging. */ |
3889 | ||
9af3c549 | 3890 | if (cmdline_syslog_name) |
8768d548 | 3891 | if (f.admin_user) |
a3fb9793 PP |
3892 | { |
3893 | syslog_processname = cmdline_syslog_name; | |
3894 | log_file_path = string_copy(CUS"syslog"); | |
3895 | } | |
3896 | else | |
a3fb9793 | 3897 | /* not a panic, non-privileged users should not be able to spam paniclog */ |
9af3c549 | 3898 | exim_fail( |
a3fb9793 | 3899 | "exim: you lack sufficient privilege to specify syslog process name\n"); |
a3fb9793 | 3900 | |
059ec3d9 PH |
3901 | /* Paranoia check of maximum lengths of certain strings. There is a check |
3902 | on the length of the log file path in log.c, which will come into effect | |
3903 | if there are any calls to write the log earlier than this. However, if we | |
3904 | get this far but the string is very long, it is better to stop now than to | |
3905 | carry on and (e.g.) receive a message and then have to collapse. The call to | |
3906 | log_write() from here will cause the ultimate panic collapse if the complete | |
3907 | file name exceeds the buffer length. */ | |
3908 | ||
3909 | if (Ustrlen(log_file_path) > 200) | |
3910 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, | |
3911 | "log_file_path is longer than 200 chars: aborting"); | |
3912 | ||
3913 | if (Ustrlen(pid_file_path) > 200) | |
3914 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, | |
3915 | "pid_file_path is longer than 200 chars: aborting"); | |
3916 | ||
3917 | if (Ustrlen(spool_directory) > 200) | |
3918 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, | |
3919 | "spool_directory is longer than 200 chars: aborting"); | |
3920 | ||
3921 | /* Length check on the process name given to syslog for its TAG field, | |
3922 | which is only permitted to be 32 characters or less. See RFC 3164. */ | |
3923 | ||
3924 | if (Ustrlen(syslog_processname) > 32) | |
3925 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, | |
3926 | "syslog_processname is longer than 32 chars: aborting"); | |
3927 | ||
0ad2e0fc | 3928 | if (log_oneline) |
8768d548 | 3929 | if (f.admin_user) |
0ad2e0fc JH |
3930 | { |
3931 | log_write(0, LOG_MAIN, "%s", log_oneline); | |
3932 | return EXIT_SUCCESS; | |
3933 | } | |
3934 | else | |
3935 | return EXIT_FAILURE; | |
0ad2e0fc | 3936 | |
059ec3d9 PH |
3937 | /* In some operating systems, the environment variable TMPDIR controls where |
3938 | temporary files are created; Exim doesn't use these (apart from when delivering | |
3939 | to MBX mailboxes), but called libraries such as DBM libraries may require them. | |
3940 | If TMPDIR is found in the environment, reset it to the value defined in the | |
8f3bfb82 HSHR |
3941 | EXIM_TMPDIR macro, if this macro is defined. For backward compatibility this |
3942 | macro may be called TMPDIR in old "Local/Makefile"s. It's converted to | |
3943 | EXIM_TMPDIR by the build scripts. | |
3944 | */ | |
059ec3d9 | 3945 | |
75286da3 | 3946 | #ifdef EXIM_TMPDIR |
d7978c0f | 3947 | if (environ) for (uschar ** p = USS environ; *p; p++) |
40c90bca | 3948 | if (Ustrncmp(*p, "TMPDIR=", 7) == 0 && Ustrcmp(*p+7, EXIM_TMPDIR) != 0) |
059ec3d9 | 3949 | { |
40c90bca | 3950 | uschar * newp = store_malloc(Ustrlen(EXIM_TMPDIR) + 8); |
75286da3 | 3951 | sprintf(CS newp, "TMPDIR=%s", EXIM_TMPDIR); |
059ec3d9 | 3952 | *p = newp; |
75286da3 | 3953 | DEBUG(D_any) debug_printf("reset TMPDIR=%s in environment\n", EXIM_TMPDIR); |
059ec3d9 | 3954 | } |
059ec3d9 PH |
3955 | #endif |
3956 | ||
3957 | /* Timezone handling. If timezone_string is "utc", set a flag to cause all | |
3958 | timestamps to be in UTC (gmtime() is used instead of localtime()). Otherwise, | |
3959 | we may need to get rid of a bogus timezone setting. This can arise when Exim is | |
3960 | called by a user who has set the TZ variable. This then affects the timestamps | |
3961 | in log files and in Received: headers, and any created Date: header lines. The | |
3962 | required timezone is settable in the configuration file, so nothing can be done | |
3963 | about this earlier - but hopefully nothing will normally be logged earlier than | |
3964 | this. We have to make a new environment if TZ is wrong, but don't bother if | |
3965 | timestamps_utc is set, because then all times are in UTC anyway. */ | |
3966 | ||
40c90bca | 3967 | if (timezone_string && strcmpic(timezone_string, US"UTC") == 0) |
8768d548 | 3968 | f.timestamps_utc = TRUE; |
059ec3d9 PH |
3969 | else |
3970 | { | |
3971 | uschar *envtz = US getenv("TZ"); | |
4dc2379a JH |
3972 | if (envtz |
3973 | ? !timezone_string || Ustrcmp(timezone_string, envtz) != 0 | |
3974 | : timezone_string != NULL | |
3975 | ) | |
059ec3d9 PH |
3976 | { |
3977 | uschar **p = USS environ; | |
3978 | uschar **new; | |
3979 | uschar **newp; | |
3980 | int count = 0; | |
40c90bca JH |
3981 | if (environ) while (*p++) count++; |
3982 | if (!envtz) count++; | |
3983 | newp = new = store_malloc(sizeof(uschar *) * (count + 1)); | |
3984 | if (environ) for (p = USS environ; *p; p++) | |
3985 | if (Ustrncmp(*p, "TZ=", 3) != 0) *newp++ = *p; | |
3986 | if (timezone_string) | |
3987 | { | |
3988 | *newp = store_malloc(Ustrlen(timezone_string) + 4); | |
059ec3d9 PH |
3989 | sprintf(CS *newp++, "TZ=%s", timezone_string); |
3990 | } | |
3991 | *newp = NULL; | |
3992 | environ = CSS new; | |
3993 | tzset(); | |
3994 | DEBUG(D_any) debug_printf("Reset TZ to %s: time is %s\n", timezone_string, | |
3995 | tod_stamp(tod_log)); | |
3996 | } | |
3997 | } | |
3998 | ||
3999 | /* Handle the case when we have removed the setuid privilege because of -C or | |
cd25e41d | 4000 | -D. This means that the caller of Exim was not root. |
059ec3d9 | 4001 | |
cd25e41d DW |
4002 | There is a problem if we were running as the Exim user. The sysadmin may |
4003 | expect this case to retain privilege because "the binary was called by the | |
4004 | Exim user", but it hasn't, because either the -D option set macros, or the | |
261dc43e | 4005 | -C option set a non-trusted configuration file. There are two possibilities: |
059ec3d9 PH |
4006 | |
4007 | (1) If deliver_drop_privilege is set, Exim is not going to re-exec in order | |
4008 | to do message deliveries. Thus, the fact that it is running as a | |
4009 | non-privileged user is plausible, and might be wanted in some special | |
4010 | configurations. However, really_exim will have been set false when | |
4011 | privilege was dropped, to stop Exim trying to write to its normal log | |
4012 | files. Therefore, re-enable normal log processing, assuming the sysadmin | |
4013 | has set up the log directory correctly. | |
4014 | ||
4015 | (2) If deliver_drop_privilege is not set, the configuration won't work as | |
4016 | apparently intended, and so we log a panic message. In order to retain | |
261dc43e DW |
4017 | root for -C or -D, the caller must either be root or be invoking a |
4018 | trusted configuration file (when deliver_drop_privilege is false). */ | |
059ec3d9 | 4019 | |
4ab69ec7 | 4020 | if ( removed_privilege |
8768d548 | 4021 | && (!f.trusted_config || opt_D_used) |
4ab69ec7 | 4022 | && real_uid == exim_uid) |
059ec3d9 | 4023 | if (deliver_drop_privilege) |
8768d548 | 4024 | f.really_exim = TRUE; /* let logging work normally */ |
059ec3d9 PH |
4025 | else |
4026 | log_write(0, LOG_MAIN|LOG_PANIC, | |
cd25e41d | 4027 | "exim user lost privilege for using %s option", |
8768d548 | 4028 | f.trusted_config? "-D" : "-C"); |
059ec3d9 PH |
4029 | |
4030 | /* Start up Perl interpreter if Perl support is configured and there is a | |
4031 | perl_startup option, and the configuration or the command line specifies | |
4032 | initializing starting. Note that the global variables are actually called | |
4033 | opt_perl_xxx to avoid clashing with perl's namespace (perl_*). */ | |
4034 | ||
4035 | #ifdef EXIM_PERL | |
4036 | if (perl_start_option != 0) | |
4037 | opt_perl_at_start = (perl_start_option > 0); | |
4038 | if (opt_perl_at_start && opt_perl_startup != NULL) | |
4039 | { | |
4040 | uschar *errstr; | |
4041 | DEBUG(D_any) debug_printf("Starting Perl interpreter\n"); | |
9af3c549 JH |
4042 | if ((errstr = init_perl(opt_perl_startup))) |
4043 | exim_fail("exim: error in perl_startup code: %s\n", errstr); | |
059ec3d9 PH |
4044 | opt_perl_started = TRUE; |
4045 | } | |
4046 | #endif /* EXIM_PERL */ | |
4047 | ||
4048 | /* Log the arguments of the call if the configuration file said so. This is | |
4049 | a debugging feature for finding out what arguments certain MUAs actually use. | |
4050 | Don't attempt it if logging is disabled, or if listing variables or if | |
4051 | verifying/testing addresses or expansions. */ | |
4052 | ||
675ae646 | 4053 | if ( (debug_selector & D_any || LOGGING(arguments)) |
8768d548 | 4054 | && f.really_exim && !list_options && !checking) |
059ec3d9 | 4055 | { |
059ec3d9 | 4056 | uschar *p = big_buffer; |
f3ebb786 | 4057 | Ustrcpy(p, US"cwd= (failed)"); |
3615fa9a | 4058 | |
675ae646 JH |
4059 | if (!initial_cwd) |
4060 | p += 13; | |
4061 | else | |
4062 | { | |
4063 | Ustrncpy(p + 4, initial_cwd, big_buffer_size-5); | |
4064 | p += 4 + Ustrlen(initial_cwd); | |
4065 | /* in case p is near the end and we don't provide enough space for | |
4066 | * string_format to be willing to write. */ | |
4067 | *p = '\0'; | |
4068 | } | |
3615fa9a | 4069 | |
059ec3d9 PH |
4070 | (void)string_format(p, big_buffer_size - (p - big_buffer), " %d args:", argc); |
4071 | while (*p) p++; | |
d7978c0f | 4072 | for (int i = 0; i < argc; i++) |
059ec3d9 PH |
4073 | { |
4074 | int len = Ustrlen(argv[i]); | |
55414b25 | 4075 | const uschar *printing; |
059ec3d9 PH |
4076 | uschar *quote; |
4077 | if (p + len + 8 >= big_buffer + big_buffer_size) | |
4078 | { | |
f3ebb786 | 4079 | Ustrcpy(p, US" ..."); |
059ec3d9 | 4080 | log_write(0, LOG_MAIN, "%s", big_buffer); |
f3ebb786 | 4081 | Ustrcpy(big_buffer, US"..."); |
059ec3d9 PH |
4082 | p = big_buffer + 3; |
4083 | } | |
4084 | printing = string_printing(argv[i]); | |
a76d120a JH |
4085 | if (!*printing) quote = US"\""; |
4086 | else | |
059ec3d9 | 4087 | { |
55414b25 | 4088 | const uschar *pp = printing; |
059ec3d9 | 4089 | quote = US""; |
a76d120a | 4090 | while (*pp) if (isspace(*pp++)) { quote = US"\""; break; } |
059ec3d9 | 4091 | } |
5976eb99 | 4092 | p += sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size - |
059ec3d9 | 4093 | (p - big_buffer) - 4), printing, quote); |
059ec3d9 | 4094 | } |
31619da6 | 4095 | |
6c6d6e48 | 4096 | if (LOGGING(arguments)) |
31619da6 PH |
4097 | log_write(0, LOG_MAIN, "%s", big_buffer); |
4098 | else | |
4099 | debug_printf("%s\n", big_buffer); | |
059ec3d9 PH |
4100 | } |
4101 | ||
4102 | /* Set the working directory to be the top-level spool directory. We don't rely | |
4103 | on this in the code, which always uses fully qualified names, but it's useful | |
4104 | for core dumps etc. Don't complain if it fails - the spool directory might not | |
4105 | be generally accessible and calls with the -C option (and others) have lost | |
ba18e66a PH |
4106 | privilege by now. Before the chdir, we try to ensure that the directory exists. |
4107 | */ | |
059ec3d9 PH |
4108 | |
4109 | if (Uchdir(spool_directory) != 0) | |
4110 | { | |
1ac6b2e7 | 4111 | int dummy; |
ba18e66a | 4112 | (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE); |
1ac6b2e7 | 4113 | dummy = /* quieten compiler */ Uchdir(spool_directory); |
cab0c277 | 4114 | dummy = dummy; /* yet more compiler quietening, sigh */ |
059ec3d9 PH |
4115 | } |
4116 | ||
4117 | /* Handle calls with the -bi option. This is a sendmail option to rebuild *the* | |
4118 | alias file. Exim doesn't have such a concept, but this call is screwed into | |
4119 | Sun's YP makefiles. Handle this by calling a configured script, as the real | |
4120 | user who called Exim. The -oA option can be used to pass an argument to the | |
4121 | script. */ | |
4122 | ||
4123 | if (bi_option) | |
4124 | { | |
1fe64dcc | 4125 | (void)fclose(config_file); |
a76d120a | 4126 | if (bi_command) |
059ec3d9 PH |
4127 | { |
4128 | int i = 0; | |
4129 | uschar *argv[3]; | |
4130 | argv[i++] = bi_command; | |
a76d120a | 4131 | if (alias_arg) argv[i++] = alias_arg; |
059ec3d9 PH |
4132 | argv[i++] = NULL; |
4133 | ||
4134 | setgroups(group_count, group_list); | |
4135 | exim_setugid(real_uid, real_gid, FALSE, US"running bi_command"); | |
4136 | ||
4137 | DEBUG(D_exec) debug_printf("exec %.256s %.256s\n", argv[0], | |
a76d120a | 4138 | argv[1] ? argv[1] : US""); |
059ec3d9 PH |
4139 | |
4140 | execv(CS argv[0], (char *const *)argv); | |
9af3c549 | 4141 | exim_fail("exim: exec failed: %s\n", strerror(errno)); |
059ec3d9 PH |
4142 | } |
4143 | else | |
4144 | { | |
4145 | DEBUG(D_any) debug_printf("-bi used but bi_command not set; exiting\n"); | |
4146 | exit(EXIT_SUCCESS); | |
4147 | } | |
4148 | } | |
4149 | ||
a3fb9793 PP |
4150 | /* We moved the admin/trusted check to be immediately after reading the |
4151 | configuration file. We leave these prints here to ensure that syslog setup, | |
4152 | logfile setup, and so on has already happened. */ | |
059ec3d9 | 4153 | |
8768d548 JH |
4154 | if (f.trusted_caller) DEBUG(D_any) debug_printf("trusted user\n"); |
4155 | if (f.admin_user) DEBUG(D_any) debug_printf("admin user\n"); | |
059ec3d9 PH |
4156 | |
4157 | /* Only an admin user may start the daemon or force a queue run in the default | |
4158 | configuration, but the queue run restriction can be relaxed. Only an admin | |
4159 | user may request that a message be returned to its sender forthwith. Only an | |
4160 | admin user may specify a debug level greater than D_v (because it might show | |
4161 | passwords, etc. in lookup queries). Only an admin user may request a queue | |
8544e77a PP |
4162 | count. Only an admin user can use the test interface to scan for email |
4163 | (because Exim will be in the spool dir and able to look at mails). */ | |
059ec3d9 | 4164 | |
8768d548 | 4165 | if (!f.admin_user) |
059ec3d9 PH |
4166 | { |
4167 | BOOL debugset = (debug_selector & ~D_v) != 0; | |
fc7bae7f JH |
4168 | if ( deliver_give_up || f.daemon_listen || malware_test_file |
4169 | || count_queue && queue_list_requires_admin | |
4170 | || list_queue && queue_list_requires_admin | |
4171 | || queue_interval >= 0 && prod_requires_admin | |
4172 | || queue_name_dest && prod_requires_admin | |
4173 | || debugset && !f.running_in_test_harness | |
4174 | ) | |
9af3c549 | 4175 | exim_fail("exim:%s permission denied\n", debugset? " debugging" : ""); |
059ec3d9 PH |
4176 | } |
4177 | ||
4178 | /* If the real user is not root or the exim uid, the argument for passing | |
4179 | in an open TCP/IP connection for another message is not permitted, nor is | |
4180 | running with the -N option for any delivery action, unless this call to exim is | |
4181 | one that supplied an input message, or we are using a patched exim for | |
4182 | regression testing. */ | |
4183 | ||
4184 | if (real_uid != root_uid && real_uid != exim_uid && | |
4185 | (continue_hostname != NULL || | |
8768d548 JH |
4186 | (f.dont_deliver && |
4187 | (queue_interval >= 0 || f.daemon_listen || msg_action_arg > 0) | |
4188 | )) && !f.running_in_test_harness) | |
9af3c549 | 4189 | exim_fail("exim: Permission denied\n"); |
059ec3d9 PH |
4190 | |
4191 | /* If the caller is not trusted, certain arguments are ignored when running for | |
f05da2e8 PH |
4192 | real, but are permitted when checking things (-be, -bv, -bt, -bh, -bf, -bF). |
4193 | Note that authority for performing certain actions on messages is tested in the | |
059ec3d9 PH |
4194 | queue_action() function. */ |
4195 | ||
8768d548 | 4196 | if (!f.trusted_caller && !checking) |
059ec3d9 PH |
4197 | { |
4198 | sender_host_name = sender_host_address = interface_address = | |
4199 | sender_ident = received_protocol = NULL; | |
4200 | sender_host_port = interface_port = 0; | |
4201 | sender_host_authenticated = authenticated_sender = authenticated_id = NULL; | |
4202 | } | |
4203 | ||
4204 | /* If a sender host address is set, extract the optional port number off the | |
4205 | end of it and check its syntax. Do the same thing for the interface address. | |
4206 | Exim exits if the syntax is bad. */ | |
4207 | ||
4208 | else | |
4209 | { | |
4210 | if (sender_host_address != NULL) | |
4211 | sender_host_port = check_port(sender_host_address); | |
4212 | if (interface_address != NULL) | |
4213 | interface_port = check_port(interface_address); | |
4214 | } | |
4215 | ||
f4ee74ac PP |
4216 | /* If the caller is trusted, then they can use -G to suppress_local_fixups. */ |
4217 | if (flag_G) | |
4218 | { | |
8768d548 | 4219 | if (f.trusted_caller) |
f4ee74ac | 4220 | { |
8768d548 | 4221 | f.suppress_local_fixups = f.suppress_local_fixups_default = TRUE; |
f4ee74ac PP |
4222 | DEBUG(D_acl) debug_printf("suppress_local_fixups forced on by -G\n"); |
4223 | } | |
4224 | else | |
9af3c549 | 4225 | exim_fail("exim: permission denied (-G requires a trusted user)\n"); |
f4ee74ac PP |
4226 | } |
4227 | ||
059ec3d9 PH |
4228 | /* If an SMTP message is being received check to see if the standard input is a |
4229 | TCP/IP socket. If it is, we assume that Exim was called from inetd if the | |
4230 | caller is root or the Exim user, or if the port is a privileged one. Otherwise, | |
4231 | barf. */ | |
4232 | ||
4233 | if (smtp_input) | |
4234 | { | |
4235 | union sockaddr_46 inetd_sock; | |
36a3b041 | 4236 | EXIM_SOCKLEN_T size = sizeof(inetd_sock); |
059ec3d9 PH |
4237 | if (getpeername(0, (struct sockaddr *)(&inetd_sock), &size) == 0) |
4238 | { | |
4239 | int family = ((struct sockaddr *)(&inetd_sock))->sa_family; | |
4240 | if (family == AF_INET || family == AF_INET6) | |
4241 | { | |
4242 | union sockaddr_46 interface_sock; | |
4243 | size = sizeof(interface_sock); | |
4244 | ||
4245 | if (getsockname(0, (struct sockaddr *)(&interface_sock), &size) == 0) | |
4246 | interface_address = host_ntoa(-1, &interface_sock, NULL, | |
4247 | &interface_port); | |
4248 | ||
817d9f57 | 4249 | if (host_is_tls_on_connect_port(interface_port)) tls_in.on_connect = TRUE; |
059ec3d9 PH |
4250 | |
4251 | if (real_uid == root_uid || real_uid == exim_uid || interface_port < 1024) | |
4252 | { | |
8768d548 | 4253 | f.is_inetd = TRUE; |
059ec3d9 PH |
4254 | sender_host_address = host_ntoa(-1, (struct sockaddr *)(&inetd_sock), |
4255 | NULL, &sender_host_port); | |
4256 | if (mua_wrapper) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Input from " | |
4257 | "inetd is not supported when mua_wrapper is set"); | |
4258 | } | |
4259 | else | |
9af3c549 | 4260 | exim_fail( |
059ec3d9 | 4261 | "exim: Permission denied (unprivileged user, unprivileged port)\n"); |
059ec3d9 PH |
4262 | } |
4263 | } | |
4264 | } | |
4265 | ||
4266 | /* If the load average is going to be needed while receiving a message, get it | |
4267 | now for those OS that require the first call to os_getloadavg() to be done as | |
4268 | root. There will be further calls later for each message received. */ | |
4269 | ||
4270 | #ifdef LOAD_AVG_NEEDS_ROOT | |
fc7bae7f JH |
4271 | if ( receiving_message |
4272 | && (queue_only_load >= 0 || (f.is_inetd && smtp_load_reserve >= 0))) | |
8669f003 | 4273 | load_average = OS_GETLOADAVG(); |
059ec3d9 PH |
4274 | #endif |
4275 | ||
4276 | /* The queue_only configuration option can be overridden by -odx on the command | |
4277 | line, except that if queue_only_override is false, queue_only cannot be unset | |
4278 | from the command line. */ | |
4279 | ||
4280 | if (queue_only_set && (queue_only_override || arg_queue_only)) | |
4281 | queue_only = arg_queue_only; | |
4282 | ||
4283 | /* The receive_timeout and smtp_receive_timeout options can be overridden by | |
4284 | -or and -os. */ | |
4285 | ||
4286 | if (arg_receive_timeout >= 0) receive_timeout = arg_receive_timeout; | |
4287 | if (arg_smtp_receive_timeout >= 0) | |
4288 | smtp_receive_timeout = arg_smtp_receive_timeout; | |
4289 | ||
4290 | /* If Exim was started with root privilege, unless we have already removed the | |
4291 | root privilege above as a result of -C, -D, -be, -bf or -bF, remove it now | |
4292 | except when starting the daemon or doing some kind of delivery or address | |
4293 | testing (-bt). These are the only cases when root need to be retained. We run | |
4294 | as exim for -bv and -bh. However, if deliver_drop_privilege is set, root is | |
805e5aab TF |
4295 | retained only for starting the daemon. We always do the initgroups() in this |
4296 | situation (controlled by the TRUE below), in order to be as close as possible | |
4297 | to the state Exim usually runs in. */ | |
059ec3d9 PH |
4298 | |
4299 | if (!unprivileged && /* originally had root AND */ | |
4300 | !removed_privilege && /* still got root AND */ | |
8768d548 | 4301 | !f.daemon_listen && /* not starting the daemon */ |
059ec3d9 PH |
4302 | queue_interval <= 0 && /* (either kind of daemon) */ |
4303 | ( /* AND EITHER */ | |
4304 | deliver_drop_privilege || /* requested unprivileged */ | |
4305 | ( /* OR */ | |
4306 | queue_interval < 0 && /* not running the queue */ | |
4307 | (msg_action_arg < 0 || /* and */ | |
4308 | msg_action != MSG_DELIVER) && /* not delivering and */ | |
8768d548 | 4309 | (!checking || !f.address_test_mode) /* not address checking */ |
57cc2785 | 4310 | ) ) ) |
805e5aab | 4311 | exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed"); |
059ec3d9 PH |
4312 | |
4313 | /* When we are retaining a privileged uid, we still change to the exim gid. */ | |
4314 | ||
1670ef10 PP |
4315 | else |
4316 | { | |
4317 | int rv; | |
4b424e0d | 4318 | DEBUG(D_any) debug_printf("dropping to exim gid; retaining priv uid\n"); |
1670ef10 PP |
4319 | rv = setgid(exim_gid); |
4320 | /* Impact of failure is that some stuff might end up with an incorrect group. | |
4321 | We track this for failures from root, since any attempt to change privilege | |
4322 | by root should succeed and failures should be examined. For non-root, | |
4323 | there's no security risk. For me, it's { exim -bV } on a just-built binary, | |
4324 | no need to complain then. */ | |
4325 | if (rv == -1) | |
33191679 | 4326 | if (!(unprivileged || removed_privilege)) |
9af3c549 | 4327 | exim_fail("exim: changing group failed: %s\n", strerror(errno)); |
1670ef10 | 4328 | else |
59620376 JH |
4329 | DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n", |
4330 | (long int)exim_gid, strerror(errno)); | |
1670ef10 | 4331 | } |
059ec3d9 | 4332 | |
8544e77a PP |
4333 | /* Handle a request to scan a file for malware */ |
4334 | if (malware_test_file) | |
4335 | { | |
dbc4b90d | 4336 | #ifdef WITH_CONTENT_SCAN |
8544e77a PP |
4337 | int result; |
4338 | set_process_info("scanning file for malware"); | |
4339 | result = malware_in_file(malware_test_file); | |
4340 | if (result == FAIL) | |
4341 | { | |
4342 | printf("No malware found.\n"); | |
4343 | exit(EXIT_SUCCESS); | |
4344 | } | |
4345 | if (result != OK) | |
4346 | { | |
4347 | printf("Malware lookup returned non-okay/fail: %d\n", result); | |
4348 | exit(EXIT_FAILURE); | |
4349 | } | |
4350 | if (malware_name) | |
4351 | printf("Malware found: %s\n", malware_name); | |
4352 | else | |
4353 | printf("Malware scan detected malware of unknown name.\n"); | |
dbc4b90d PP |
4354 | #else |
4355 | printf("Malware scanning not enabled at compile time.\n"); | |
4356 | #endif | |
8544e77a PP |
4357 | exit(EXIT_FAILURE); |
4358 | } | |
4359 | ||
059ec3d9 PH |
4360 | /* Handle a request to list the delivery queue */ |
4361 | ||
4362 | if (list_queue) | |
4363 | { | |
4364 | set_process_info("listing the queue"); | |
4365 | queue_list(list_queue_option, argv + recipients_arg, argc - recipients_arg); | |
4366 | exit(EXIT_SUCCESS); | |
4367 | } | |
4368 | ||
4369 | /* Handle a request to count the delivery queue */ | |
4370 | ||
4371 | if (count_queue) | |
4372 | { | |
4373 | set_process_info("counting the queue"); | |
04403ab0 | 4374 | fprintf(stdout, "%u\n", queue_count()); |
059ec3d9 PH |
4375 | exit(EXIT_SUCCESS); |
4376 | } | |
4377 | ||
0ef732d9 PH |
4378 | /* Handle actions on specific messages, except for the force delivery and |
4379 | message load actions, which are done below. Some actions take a whole list of | |
4380 | message ids, which are known to continue up to the end of the arguments. Others | |
4381 | take a single message id and then operate on the recipients list. */ | |
059ec3d9 | 4382 | |
0ef732d9 | 4383 | if (msg_action_arg > 0 && msg_action != MSG_DELIVER && msg_action != MSG_LOAD) |
059ec3d9 PH |
4384 | { |
4385 | int yield = EXIT_SUCCESS; | |
4386 | set_process_info("acting on specified messages"); | |
4387 | ||
7ea1237c MK |
4388 | /* ACL definitions may be needed when removing a message (-Mrm) because |
4389 | event_action gets expanded */ | |
4390 | ||
4391 | if (msg_action == MSG_REMOVE) | |
4392 | readconf_rest(); | |
4393 | ||
059ec3d9 PH |
4394 | if (!one_msg_action) |
4395 | { | |
4396 | for (i = msg_action_arg; i < argc; i++) | |
4397 | if (!queue_action(argv[i], msg_action, NULL, 0, 0)) | |
4398 | yield = EXIT_FAILURE; | |
11ce40d8 JH |
4399 | switch (msg_action) |
4400 | { | |
aefbeb18 | 4401 | case MSG_REMOVE: case MSG_FREEZE: case MSG_THAW: break; |
11ce40d8 JH |
4402 | default: printf("\n"); break; |
4403 | } | |
059ec3d9 PH |
4404 | } |
4405 | ||
4406 | else if (!queue_action(argv[msg_action_arg], msg_action, argv, argc, | |
4407 | recipients_arg)) yield = EXIT_FAILURE; | |
4408 | exit(yield); | |
4409 | } | |
4410 | ||
cb46fd2b | 4411 | /* We used to set up here to skip reading the ACL section, on |
8768d548 | 4412 | (msg_action_arg > 0 || (queue_interval == 0 && !f.daemon_listen) |
cb46fd2b JH |
4413 | Now, since the intro of the ${acl } expansion, ACL definitions may be |
4414 | needed in transports so we lost the optimisation. */ | |
059ec3d9 | 4415 | |
9f01e50d JH |
4416 | { |
4417 | #ifdef MEASURE_TIMING | |
4418 | struct timeval t0, diff; | |
4419 | (void)gettimeofday(&t0, NULL); | |
4420 | #endif | |
4421 | ||
4422 | readconf_rest(); | |
4423 | ||
4424 | #ifdef MEASURE_TIMING | |
4425 | report_time_since(&t0, US"readconf_rest (delta)"); | |
4426 | #endif | |
4427 | } | |
059ec3d9 | 4428 | |
059ec3d9 PH |
4429 | /* Handle the -brt option. This is for checking out retry configurations. |
4430 | The next three arguments are a domain name or a complete address, and | |
4431 | optionally two error numbers. All it does is to call the function that | |
4432 | scans the retry configuration data. */ | |
4433 | ||
4434 | if (test_retry_arg >= 0) | |
4435 | { | |
4436 | retry_config *yield; | |
4437 | int basic_errno = 0; | |
4438 | int more_errno = 0; | |
4439 | uschar *s1, *s2; | |
4440 | ||
4441 | if (test_retry_arg >= argc) | |
4442 | { | |
4443 | printf("-brt needs a domain or address argument\n"); | |
81022793 | 4444 | exim_exit(EXIT_FAILURE); |
059ec3d9 PH |
4445 | } |
4446 | s1 = argv[test_retry_arg++]; | |
4447 | s2 = NULL; | |
4448 | ||
4449 | /* If the first argument contains no @ and no . it might be a local user | |
4450 | or it might be a single-component name. Treat as a domain. */ | |
4451 | ||
4452 | if (Ustrchr(s1, '@') == NULL && Ustrchr(s1, '.') == NULL) | |
4453 | { | |
4454 | printf("Warning: \"%s\" contains no '@' and no '.' characters. It is " | |
4455 | "being \ntreated as a one-component domain, not as a local part.\n\n", | |
4456 | s1); | |
4457 | } | |
4458 | ||
4459 | /* There may be an optional second domain arg. */ | |
4460 | ||
4461 | if (test_retry_arg < argc && Ustrchr(argv[test_retry_arg], '.') != NULL) | |
4462 | s2 = argv[test_retry_arg++]; | |
4463 | ||
4464 | /* The final arg is an error name */ | |
4465 | ||
4466 | if (test_retry_arg < argc) | |
4467 | { | |
4468 | uschar *ss = argv[test_retry_arg]; | |
4469 | uschar *error = | |
4470 | readconf_retry_error(ss, ss + Ustrlen(ss), &basic_errno, &more_errno); | |
4471 | if (error != NULL) | |
4472 | { | |
4473 | printf("%s\n", CS error); | |
4474 | return EXIT_FAILURE; | |
4475 | } | |
4476 | ||
e97957bc PH |
4477 | /* For the {MAIL,RCPT,DATA}_4xx errors, a value of 255 means "any", and a |
4478 | code > 100 as an error is for matching codes to the decade. Turn them into | |
4479 | a real error code, off the decade. */ | |
059ec3d9 | 4480 | |
e97957bc PH |
4481 | if (basic_errno == ERRNO_MAIL4XX || |
4482 | basic_errno == ERRNO_RCPT4XX || | |
4483 | basic_errno == ERRNO_DATA4XX) | |
059ec3d9 PH |
4484 | { |
4485 | int code = (more_errno >> 8) & 255; | |
4486 | if (code == 255) | |
4487 | more_errno = (more_errno & 0xffff00ff) | (21 << 8); | |
4488 | else if (code > 100) | |
4489 | more_errno = (more_errno & 0xffff00ff) | ((code - 96) << 8); | |
4490 | } | |
4491 | } | |
4492 | ||
32dfdf8b JH |
4493 | if (!(yield = retry_find_config(s1, s2, basic_errno, more_errno))) |
4494 | printf("No retry information found\n"); | |
4495 | else | |
059ec3d9 | 4496 | { |
059ec3d9 PH |
4497 | more_errno = yield->more_errno; |
4498 | printf("Retry rule: %s ", yield->pattern); | |
4499 | ||
4500 | if (yield->basic_errno == ERRNO_EXIMQUOTA) | |
4501 | { | |
4502 | printf("quota%s%s ", | |
4503 | (more_errno > 0)? "_" : "", | |
4504 | (more_errno > 0)? readconf_printtime(more_errno) : US""); | |
4505 | } | |
4506 | else if (yield->basic_errno == ECONNREFUSED) | |
4507 | { | |
4508 | printf("refused%s%s ", | |
4509 | (more_errno > 0)? "_" : "", | |
4510 | (more_errno == 'M')? "MX" : | |
4511 | (more_errno == 'A')? "A" : ""); | |
4512 | } | |
4513 | else if (yield->basic_errno == ETIMEDOUT) | |
4514 | { | |
4515 | printf("timeout"); | |
4516 | if ((more_errno & RTEF_CTOUT) != 0) printf("_connect"); | |
4517 | more_errno &= 255; | |
4518 | if (more_errno != 0) printf("_%s", | |
4519 | (more_errno == 'M')? "MX" : "A"); | |
4520 | printf(" "); | |
4521 | } | |
4522 | else if (yield->basic_errno == ERRNO_AUTHFAIL) | |
4523 | printf("auth_failed "); | |
4524 | else printf("* "); | |
4525 | ||
d7978c0f | 4526 | for (retry_rule * r = yield->rules; r; r = r->next) |
059ec3d9 PH |
4527 | { |
4528 | printf("%c,%s", r->rule, readconf_printtime(r->timeout)); /* Do not */ | |
4529 | printf(",%s", readconf_printtime(r->p1)); /* amalgamate */ | |
4530 | if (r->rule == 'G') | |
4531 | { | |
4532 | int x = r->p2; | |
4533 | int f = x % 1000; | |
4534 | int d = 100; | |
4535 | printf(",%d.", x/1000); | |
4536 | do | |
4537 | { | |
4538 | printf("%d", f/d); | |
4539 | f %= d; | |
4540 | d /= 10; | |
4541 | } | |
4542 | while (f != 0); | |
4543 | } | |
4544 | printf("; "); | |
4545 | } | |
4546 | ||
4547 | printf("\n"); | |
4548 | } | |
81022793 | 4549 | exim_exit(EXIT_SUCCESS); |
059ec3d9 PH |
4550 | } |
4551 | ||
4552 | /* Handle a request to list one or more configuration options */ | |
12f69989 | 4553 | /* If -n was set, we suppress some information */ |
059ec3d9 PH |
4554 | |
4555 | if (list_options) | |
4556 | { | |
2be324ee | 4557 | BOOL fail = FALSE; |
059ec3d9 | 4558 | set_process_info("listing variables"); |
2be324ee JH |
4559 | if (recipients_arg >= argc) |
4560 | fail = !readconf_print(US"all", NULL, flag_n); | |
4561 | else for (i = recipients_arg; i < argc; i++) | |
4562 | { | |
4563 | if (i < argc - 1 && | |
4564 | (Ustrcmp(argv[i], "router") == 0 || | |
4565 | Ustrcmp(argv[i], "transport") == 0 || | |
4566 | Ustrcmp(argv[i], "authenticator") == 0 || | |
4567 | Ustrcmp(argv[i], "macro") == 0 || | |
4568 | Ustrcmp(argv[i], "environment") == 0)) | |
059ec3d9 | 4569 | { |
2be324ee JH |
4570 | fail |= !readconf_print(argv[i+1], argv[i], flag_n); |
4571 | i++; | |
059ec3d9 | 4572 | } |
2be324ee JH |
4573 | else |
4574 | fail = !readconf_print(argv[i], NULL, flag_n); | |
4575 | } | |
81022793 | 4576 | exim_exit(fail ? EXIT_FAILURE : EXIT_SUCCESS); |
059ec3d9 PH |
4577 | } |
4578 | ||
bf3c2c6b HSHR |
4579 | if (list_config) |
4580 | { | |
4581 | set_process_info("listing config"); | |
2be324ee | 4582 | exim_exit(readconf_print(US"config", NULL, flag_n) |
81022793 | 4583 | ? EXIT_SUCCESS : EXIT_FAILURE); |
bf3c2c6b HSHR |
4584 | } |
4585 | ||
059ec3d9 | 4586 | |
d85cdeb5 | 4587 | /* Initialise subsystems as required. */ |
2592e6c0 | 4588 | |
d85cdeb5 | 4589 | tcp_init(); |
2592e6c0 | 4590 | |
059ec3d9 | 4591 | /* Handle a request to deliver one or more messages that are already on the |
0ef732d9 PH |
4592 | queue. Values of msg_action other than MSG_DELIVER and MSG_LOAD are dealt with |
4593 | above. MSG_LOAD is handled with -be (which is the only time it applies) below. | |
4594 | ||
4595 | Delivery of specific messages is typically used for a small number when | |
4596 | prodding by hand (when the option forced_delivery will be set) or when | |
4597 | re-execing to regain root privilege. Each message delivery must happen in a | |
4598 | separate process, so we fork a process for each one, and run them sequentially | |
4599 | so that debugging output doesn't get intertwined, and to avoid spawning too | |
4600 | many processes if a long list is given. However, don't fork for the last one; | |
4601 | this saves a process in the common case when Exim is called to deliver just one | |
4602 | message. */ | |
4603 | ||
4604 | if (msg_action_arg > 0 && msg_action != MSG_LOAD) | |
059ec3d9 | 4605 | { |
8768d548 | 4606 | if (prod_requires_admin && !f.admin_user) |
059ec3d9 PH |
4607 | { |
4608 | fprintf(stderr, "exim: Permission denied\n"); | |
81022793 | 4609 | exim_exit(EXIT_FAILURE); |
059ec3d9 PH |
4610 | } |
4611 | set_process_info("delivering specified messages"); | |
8768d548 | 4612 | if (deliver_give_up) forced_delivery = f.deliver_force_thaw = TRUE; |
059ec3d9 PH |
4613 | for (i = msg_action_arg; i < argc; i++) |
4614 | { | |
4615 | int status; | |
4616 | pid_t pid; | |
a76d120a JH |
4617 | /*XXX This use of argv[i] for msg_id should really be tainted, but doing |
4618 | that runs into a later copy into the untainted global message_id[] */ | |
059ec3d9 PH |
4619 | if (i == argc - 1) |
4620 | (void)deliver_message(argv[i], forced_delivery, deliver_give_up); | |
8e9fdd63 | 4621 | else if ((pid = exim_fork(US"cmdline-delivery")) == 0) |
059ec3d9 PH |
4622 | { |
4623 | (void)deliver_message(argv[i], forced_delivery, deliver_give_up); | |
81022793 | 4624 | exim_underbar_exit(EXIT_SUCCESS); |
059ec3d9 PH |
4625 | } |
4626 | else if (pid < 0) | |
4627 | { | |
4628 | fprintf(stderr, "failed to fork delivery process for %s: %s\n", argv[i], | |
4629 | strerror(errno)); | |
81022793 | 4630 | exim_exit(EXIT_FAILURE); |
059ec3d9 PH |
4631 | } |
4632 | else wait(&status); | |
4633 | } | |
81022793 | 4634 | exim_exit(EXIT_SUCCESS); |
059ec3d9 PH |
4635 | } |
4636 | ||
4637 | ||
4638 | /* If only a single queue run is requested, without SMTP listening, we can just | |
4639 | turn into a queue runner, with an optional starting message id. */ | |
4640 | ||
8768d548 | 4641 | if (queue_interval == 0 && !f.daemon_listen) |
059ec3d9 PH |
4642 | { |
4643 | DEBUG(D_queue_run) debug_printf("Single queue run%s%s%s%s\n", | |
46473d31 JH |
4644 | start_queue_run_id ? US" starting at " : US"", |
4645 | start_queue_run_id ? start_queue_run_id: US"", | |
4646 | stop_queue_run_id ? US" stopping at " : US"", | |
4647 | stop_queue_run_id ? stop_queue_run_id : US""); | |
6073ad45 | 4648 | if (*queue_name) |
4d146046 | 4649 | set_process_info("running the '%s' queue (single queue run)", queue_name); |
6073ad45 JH |
4650 | else |
4651 | set_process_info("running the queue (single queue run)"); | |
059ec3d9 | 4652 | queue_run(start_queue_run_id, stop_queue_run_id, FALSE); |
81022793 | 4653 | exim_exit(EXIT_SUCCESS); |
059ec3d9 PH |
4654 | } |
4655 | ||
4656 | ||
4657 | /* Find the login name of the real user running this process. This is always | |
4658 | needed when receiving a message, because it is written into the spool file. It | |
4659 | may also be used to construct a from: or a sender: header, and in this case we | |
4660 | need the user's full name as well, so save a copy of it, checked for RFC822 | |
4661 | syntax and munged if necessary, if it hasn't previously been set by the -F | |
4662 | argument. We may try to get the passwd entry more than once, in case NIS or | |
4663 | other delays are in evidence. Save the home directory for use in filter testing | |
4664 | (only). */ | |
4665 | ||
4666 | for (i = 0;;) | |
4667 | { | |
4668 | if ((pw = getpwuid(real_uid)) != NULL) | |
4669 | { | |
4670 | originator_login = string_copy(US pw->pw_name); | |
4671 | originator_home = string_copy(US pw->pw_dir); | |
4672 | ||
4673 | /* If user name has not been set by -F, set it from the passwd entry | |
4674 | unless -f has been used to set the sender address by a trusted user. */ | |
4675 | ||
bb07bcd3 | 4676 | if (!originator_name) |
059ec3d9 | 4677 | { |
8768d548 | 4678 | if (!sender_address || (!f.trusted_caller && filter_test == FTEST_NONE)) |
059ec3d9 PH |
4679 | { |
4680 | uschar *name = US pw->pw_gecos; | |
4681 | uschar *amp = Ustrchr(name, '&'); | |
4682 | uschar buffer[256]; | |
4683 | ||
4684 | /* Most Unix specify that a '&' character in the gecos field is | |
4685 | replaced by a copy of the login name, and some even specify that | |
4686 | the first character should be upper cased, so that's what we do. */ | |
4687 | ||
bb07bcd3 | 4688 | if (amp) |
059ec3d9 PH |
4689 | { |
4690 | int loffset; | |
4691 | string_format(buffer, sizeof(buffer), "%.*s%n%s%s", | |
bb07bcd3 | 4692 | (int)(amp - name), name, &loffset, originator_login, amp + 1); |
059ec3d9 PH |
4693 | buffer[loffset] = toupper(buffer[loffset]); |
4694 | name = buffer; | |
4695 | } | |
4696 | ||
4697 | /* If a pattern for matching the gecos field was supplied, apply | |
4698 | it and then expand the name string. */ | |
4699 | ||
bb07bcd3 | 4700 | if (gecos_pattern && gecos_name) |
059ec3d9 PH |
4701 | { |
4702 | const pcre *re; | |
4703 | re = regex_must_compile(gecos_pattern, FALSE, TRUE); /* Use malloc */ | |
4704 | ||
4705 | if (regex_match_and_setup(re, name, 0, -1)) | |
4706 | { | |
4707 | uschar *new_name = expand_string(gecos_name); | |
4708 | expand_nmax = -1; | |
bb07bcd3 | 4709 | if (new_name) |
059ec3d9 PH |
4710 | { |
4711 | DEBUG(D_receive) debug_printf("user name \"%s\" extracted from " | |
4712 | "gecos field \"%s\"\n", new_name, name); | |
4713 | name = new_name; | |
4714 | } | |
4715 | else DEBUG(D_receive) debug_printf("failed to expand gecos_name string " | |
4716 | "\"%s\": %s\n", gecos_name, expand_string_message); | |
4717 | } | |
4718 | else DEBUG(D_receive) debug_printf("gecos_pattern \"%s\" did not match " | |
4719 | "gecos field \"%s\"\n", gecos_pattern, name); | |
4720 | store_free((void *)re); | |
4721 | } | |
4722 | originator_name = string_copy(name); | |
4723 | } | |
4724 | ||
4725 | /* A trusted caller has used -f but not -F */ | |
4726 | ||
4727 | else originator_name = US""; | |
4728 | } | |
4729 | ||
4730 | /* Break the retry loop */ | |
4731 | ||
4732 | break; | |
4733 | } | |
4734 | ||
4735 | if (++i > finduser_retries) break; | |
4736 | sleep(1); | |
4737 | } | |
4738 | ||
4739 | /* If we cannot get a user login, log the incident and give up, unless the | |
4740 | configuration specifies something to use. When running in the test harness, | |
8800895a | 4741 | any setting of unknown_login overrides the actual name. */ |
059ec3d9 | 4742 | |
8768d548 | 4743 | if (originator_login == NULL || f.running_in_test_harness) |
059ec3d9 PH |
4744 | { |
4745 | if (unknown_login != NULL) | |
4746 | { | |
4747 | originator_login = expand_string(unknown_login); | |
4748 | if (originator_name == NULL && unknown_username != NULL) | |
4749 | originator_name = expand_string(unknown_username); | |
4750 | if (originator_name == NULL) originator_name = US""; | |
4751 | } | |
4752 | if (originator_login == NULL) | |
4753 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to get user name for uid %d", | |
4754 | (int)real_uid); | |
4755 | } | |
4756 | ||
4757 | /* Ensure that the user name is in a suitable form for use as a "phrase" in an | |
4758 | RFC822 address.*/ | |
4759 | ||
4760 | originator_name = string_copy(parse_fix_phrase(originator_name, | |
4761 | Ustrlen(originator_name), big_buffer, big_buffer_size)); | |
4762 | ||
4763 | /* If a message is created by this call of Exim, the uid/gid of its originator | |
4764 | are those of the caller. These values are overridden if an existing message is | |
4765 | read in from the spool. */ | |
4766 | ||
4767 | originator_uid = real_uid; | |
4768 | originator_gid = real_gid; | |
4769 | ||
4770 | DEBUG(D_receive) debug_printf("originator: uid=%d gid=%d login=%s name=%s\n", | |
4771 | (int)originator_uid, (int)originator_gid, originator_login, originator_name); | |
4772 | ||
4773 | /* Run in daemon and/or queue-running mode. The function daemon_go() never | |
4774 | returns. We leave this till here so that the originator_ fields are available | |
47c7a64a PH |
4775 | for incoming messages via the daemon. The daemon cannot be run in mua_wrapper |
4776 | mode. */ | |
059ec3d9 | 4777 | |
8768d548 | 4778 | if (f.daemon_listen || f.inetd_wait_mode || queue_interval > 0) |
059ec3d9 | 4779 | { |
47c7a64a PH |
4780 | if (mua_wrapper) |
4781 | { | |
4782 | fprintf(stderr, "Daemon cannot be run when mua_wrapper is set\n"); | |
4783 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Daemon cannot be run when " | |
4784 | "mua_wrapper is set"); | |
4785 | } | |
d85cdeb5 | 4786 | |
0d75f945 | 4787 | # ifndef DISABLE_TLS |
d85cdeb5 JH |
4788 | /* This also checks that the library linkage is working and we can call |
4789 | routines in it, so call even if tls_require_ciphers is unset */ | |
4790 | { | |
0d75f945 | 4791 | # ifdef MEASURE_TIMING |
d85cdeb5 JH |
4792 | struct timeval t0, diff; |
4793 | (void)gettimeofday(&t0, NULL); | |
0d75f945 | 4794 | # endif |
d85cdeb5 JH |
4795 | if (!tls_dropprivs_validate_require_cipher(FALSE)) |
4796 | exit(1); | |
0d75f945 | 4797 | # ifdef MEASURE_TIMING |
d85cdeb5 | 4798 | report_time_since(&t0, US"validate_ciphers (delta)"); |
0d75f945 | 4799 | # endif |
d85cdeb5 | 4800 | } |
0d75f945 | 4801 | #endif |
d85cdeb5 | 4802 | |
059ec3d9 PH |
4803 | daemon_go(); |
4804 | } | |
4805 | ||
4806 | /* If the sender ident has not been set (by a trusted caller) set it to | |
4807 | the caller. This will get overwritten below for an inetd call. If a trusted | |
4808 | caller has set it empty, unset it. */ | |
4809 | ||
f3ebb786 JH |
4810 | if (!sender_ident) sender_ident = originator_login; |
4811 | else if (!*sender_ident) sender_ident = NULL; | |
059ec3d9 PH |
4812 | |
4813 | /* Handle the -brw option, which is for checking out rewriting rules. Cause log | |
4814 | writes (on errors) to go to stderr instead. Can't do this earlier, as want the | |
4815 | originator_* variables set. */ | |
4816 | ||
4817 | if (test_rewrite_arg >= 0) | |
4818 | { | |
8768d548 | 4819 | f.really_exim = FALSE; |
059ec3d9 PH |
4820 | if (test_rewrite_arg >= argc) |
4821 | { | |
4822 | printf("-brw needs an address argument\n"); | |
81022793 | 4823 | exim_exit(EXIT_FAILURE); |
059ec3d9 PH |
4824 | } |
4825 | rewrite_test(argv[test_rewrite_arg]); | |
81022793 | 4826 | exim_exit(EXIT_SUCCESS); |
059ec3d9 PH |
4827 | } |
4828 | ||
4829 | /* A locally-supplied message is considered to be coming from a local user | |
4830 | unless a trusted caller supplies a sender address with -f, or is passing in the | |
4831 | message via SMTP (inetd invocation or otherwise). */ | |
4832 | ||
f3ebb786 JH |
4833 | if ( !sender_address && !smtp_input |
4834 | || !f.trusted_caller && filter_test == FTEST_NONE) | |
059ec3d9 | 4835 | { |
8768d548 | 4836 | f.sender_local = TRUE; |
059ec3d9 PH |
4837 | |
4838 | /* A trusted caller can supply authenticated_sender and authenticated_id | |
33d73e3b PH |
4839 | via -oMas and -oMai and if so, they will already be set. Otherwise, force |
4840 | defaults except when host checking. */ | |
059ec3d9 | 4841 | |
f3ebb786 | 4842 | if (!authenticated_sender && !host_checking) |
059ec3d9 PH |
4843 | authenticated_sender = string_sprintf("%s@%s", originator_login, |
4844 | qualify_domain_sender); | |
f3ebb786 | 4845 | if (!authenticated_id && !host_checking) |
33d73e3b | 4846 | authenticated_id = originator_login; |
059ec3d9 PH |
4847 | } |
4848 | ||
4849 | /* Trusted callers are always permitted to specify the sender address. | |
4850 | Untrusted callers may specify it if it matches untrusted_set_sender, or if what | |
4851 | is specified is the empty address. However, if a trusted caller does not | |
4852 | specify a sender address for SMTP input, we leave sender_address unset. This | |
4853 | causes the MAIL commands to be honoured. */ | |
4854 | ||
f3ebb786 JH |
4855 | if ( !smtp_input && !sender_address |
4856 | || !receive_check_set_sender(sender_address)) | |
059ec3d9 PH |
4857 | { |
4858 | /* Either the caller is not permitted to set a general sender, or this is | |
4859 | non-SMTP input and the trusted caller has not set a sender. If there is no | |
4860 | sender, or if a sender other than <> is set, override with the originator's | |
4861 | login (which will get qualified below), except when checking things. */ | |
4862 | ||
4863 | if (sender_address == NULL /* No sender_address set */ | |
4864 | || /* OR */ | |
4865 | (sender_address[0] != 0 && /* Non-empty sender address, AND */ | |
34e86e20 | 4866 | !checking)) /* Not running tests, including filter tests */ |
059ec3d9 PH |
4867 | { |
4868 | sender_address = originator_login; | |
8768d548 | 4869 | f.sender_address_forced = FALSE; |
059ec3d9 PH |
4870 | sender_address_domain = 0; |
4871 | } | |
4872 | } | |
4873 | ||
4874 | /* Remember whether an untrusted caller set the sender address */ | |
4875 | ||
8768d548 | 4876 | f.sender_set_untrusted = sender_address != originator_login && !f.trusted_caller; |
059ec3d9 PH |
4877 | |
4878 | /* Ensure that the sender address is fully qualified unless it is the empty | |
4879 | address, which indicates an error message, or doesn't exist (root caller, smtp | |
4880 | interface, no -f argument). */ | |
4881 | ||
f3ebb786 | 4882 | if (sender_address && *sender_address && sender_address_domain == 0) |
059ec3d9 PH |
4883 | sender_address = string_sprintf("%s@%s", local_part_quote(sender_address), |
4884 | qualify_domain_sender); | |
4885 | ||
4886 | DEBUG(D_receive) debug_printf("sender address = %s\n", sender_address); | |
4887 | ||
4888 | /* Handle a request to verify a list of addresses, or test them for delivery. | |
4889 | This must follow the setting of the sender address, since routers can be | |
4890 | predicated upon the sender. If no arguments are given, read addresses from | |
4891 | stdin. Set debug_level to at least D_v to get full output for address testing. | |
4892 | */ | |
4893 | ||
8768d548 | 4894 | if (verify_address_mode || f.address_test_mode) |
059ec3d9 PH |
4895 | { |
4896 | int exit_value = 0; | |
4897 | int flags = vopt_qualify; | |
4898 | ||
4899 | if (verify_address_mode) | |
4900 | { | |
4901 | if (!verify_as_sender) flags |= vopt_is_recipient; | |
4902 | DEBUG(D_verify) debug_print_ids(US"Verifying:"); | |
4903 | } | |
4904 | ||
4905 | else | |
4906 | { | |
4907 | flags |= vopt_is_recipient; | |
4908 | debug_selector |= D_v; | |
4909 | debug_file = stderr; | |
4910 | debug_fd = fileno(debug_file); | |
4911 | DEBUG(D_verify) debug_print_ids(US"Address testing:"); | |
4912 | } | |
4913 | ||
4914 | if (recipients_arg < argc) | |
4915 | { | |
4916 | while (recipients_arg < argc) | |
4917 | { | |
f0fe22cb JH |
4918 | /* Supplied addresses are tainted since they come from a user */ |
4919 | uschar * s = string_copy_taint(argv[recipients_arg++], TRUE); | |
4920 | while (*s) | |
059ec3d9 PH |
4921 | { |
4922 | BOOL finished = FALSE; | |
4923 | uschar *ss = parse_find_address_end(s, FALSE); | |
4924 | if (*ss == ',') *ss = 0; else finished = TRUE; | |
4925 | test_address(s, flags, &exit_value); | |
4926 | s = ss; | |
4927 | if (!finished) | |
f0fe22cb | 4928 | while (*++s == ',' || isspace(*s)) ; |
059ec3d9 PH |
4929 | } |
4930 | } | |
4931 | } | |
4932 | ||
4933 | else for (;;) | |
4934 | { | |
f0fe22cb JH |
4935 | uschar * s = get_stdinput(NULL, NULL); |
4936 | if (!s) break; | |
4937 | test_address(string_copy_taint(s, TRUE), flags, &exit_value); | |
059ec3d9 PH |
4938 | } |
4939 | ||
4940 | route_tidyup(); | |
81022793 | 4941 | exim_exit(exit_value); |
059ec3d9 PH |
4942 | } |
4943 | ||
0ef732d9 PH |
4944 | /* Handle expansion checking. Either expand items on the command line, or read |
4945 | from stdin if there aren't any. If -Mset was specified, load the message so | |
328895cc PH |
4946 | that its variables can be used, but restrict this facility to admin users. |
4947 | Otherwise, if -bem was used, read a message from stdin. */ | |
059ec3d9 PH |
4948 | |
4949 | if (expansion_test) | |
4950 | { | |
03f68c52 | 4951 | dns_init(FALSE, FALSE, FALSE); |
0ef732d9 PH |
4952 | if (msg_action_arg > 0 && msg_action == MSG_LOAD) |
4953 | { | |
4954 | uschar spoolname[256]; /* Not big_buffer; used in spool_read_header() */ | |
8768d548 | 4955 | if (!f.admin_user) |
9af3c549 | 4956 | exim_fail("exim: permission denied\n"); |
0ef732d9 PH |
4957 | message_id = argv[msg_action_arg]; |
4958 | (void)string_format(spoolname, sizeof(spoolname), "%s-H", message_id); | |
789f8a4f | 4959 | if ((deliver_datafile = spool_open_datafile(message_id)) < 0) |
0ef732d9 PH |
4960 | printf ("Failed to load message datafile %s\n", message_id); |
4961 | if (spool_read_header(spoolname, TRUE, FALSE) != spool_read_OK) | |
4962 | printf ("Failed to load message %s\n", message_id); | |
4963 | } | |
4964 | ||
328895cc PH |
4965 | /* Read a test message from a file. We fudge it up to be on stdin, saving |
4966 | stdin itself for later reading of expansion strings. */ | |
4967 | ||
9650d98a | 4968 | else if (expansion_test_message) |
328895cc PH |
4969 | { |
4970 | int save_stdin = dup(0); | |
4971 | int fd = Uopen(expansion_test_message, O_RDONLY, 0); | |
4972 | if (fd < 0) | |
9af3c549 | 4973 | exim_fail("exim: failed to open %s: %s\n", expansion_test_message, |
328895cc | 4974 | strerror(errno)); |
328895cc PH |
4975 | (void) dup2(fd, 0); |
4976 | filter_test = FTEST_USER; /* Fudge to make it look like filter test */ | |
4977 | message_ended = END_NOTENDED; | |
4978 | read_message_body(receive_msg(extract_recipients)); | |
2d2b05f4 | 4979 | message_linecount += body_linecount; |
328895cc PH |
4980 | (void)dup2(save_stdin, 0); |
4981 | (void)close(save_stdin); | |
935ff400 | 4982 | clearerr(stdin); /* Required by Darwin */ |
328895cc PH |
4983 | } |
4984 | ||
9650d98a JH |
4985 | /* Only admin users may see config-file macros this way */ |
4986 | ||
8768d548 | 4987 | if (!f.admin_user) macros_user = macros = mlast = NULL; |
9650d98a | 4988 | |
328895cc PH |
4989 | /* Allow $recipients for this testing */ |
4990 | ||
8768d548 | 4991 | f.enable_dollar_recipients = TRUE; |
328895cc | 4992 | |
0ef732d9 PH |
4993 | /* Expand command line items */ |
4994 | ||
059ec3d9 | 4995 | if (recipients_arg < argc) |
059ec3d9 | 4996 | while (recipients_arg < argc) |
9650d98a | 4997 | expansion_test_line(argv[recipients_arg++]); |
059ec3d9 PH |
4998 | |
4999 | /* Read stdin */ | |
5000 | ||
5001 | else | |
5002 | { | |
1ba28e2b PP |
5003 | char *(*fn_readline)(const char *) = NULL; |
5004 | void (*fn_addhist)(const char *) = NULL; | |
9650d98a | 5005 | uschar * s; |
059ec3d9 | 5006 | |
9650d98a | 5007 | #ifdef USE_READLINE |
059ec3d9 | 5008 | void *dlhandle = set_readline(&fn_readline, &fn_addhist); |
9650d98a | 5009 | #endif |
059ec3d9 | 5010 | |
9650d98a JH |
5011 | while (s = get_stdinput(fn_readline, fn_addhist)) |
5012 | expansion_test_line(s); | |
059ec3d9 | 5013 | |
9650d98a JH |
5014 | #ifdef USE_READLINE |
5015 | if (dlhandle) dlclose(dlhandle); | |
5016 | #endif | |
059ec3d9 PH |
5017 | } |
5018 | ||
0ef732d9 PH |
5019 | /* The data file will be open after -Mset */ |
5020 | ||
5021 | if (deliver_datafile >= 0) | |
5022 | { | |
5023 | (void)close(deliver_datafile); | |
5024 | deliver_datafile = -1; | |
5025 | } | |
5026 | ||
81022793 | 5027 | exim_exit(EXIT_SUCCESS); |
059ec3d9 PH |
5028 | } |
5029 | ||
5030 | ||
5031 | /* The active host name is normally the primary host name, but it can be varied | |
5032 | for hosts that want to play several parts at once. We need to ensure that it is | |
5033 | set for host checking, and for receiving messages. */ | |
5034 | ||
5035 | smtp_active_hostname = primary_hostname; | |
5036 | if (raw_active_hostname != NULL) | |
5037 | { | |
5038 | uschar *nah = expand_string(raw_active_hostname); | |
5039 | if (nah == NULL) | |
5040 | { | |
8768d548 | 5041 | if (!f.expand_string_forcedfail) |
059ec3d9 PH |
5042 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand \"%s\" " |
5043 | "(smtp_active_hostname): %s", raw_active_hostname, | |
5044 | expand_string_message); | |
5045 | } | |
5046 | else if (nah[0] != 0) smtp_active_hostname = nah; | |
5047 | } | |
5048 | ||
5049 | /* Handle host checking: this facility mocks up an incoming SMTP call from a | |
33d73e3b PH |
5050 | given IP address so that the blocking and relay configuration can be tested. |
5051 | Unless a sender_ident was set by -oMt, we discard it (the default is the | |
5052 | caller's login name). An RFC 1413 call is made only if we are running in the | |
5053 | test harness and an incoming interface and both ports are specified, because | |
5054 | there is no TCP/IP call to find the ident for. */ | |
059ec3d9 PH |
5055 | |
5056 | if (host_checking) | |
5057 | { | |
8e669ac1 | 5058 | int x[4]; |
6f0c9a4f | 5059 | int size; |
8e669ac1 | 5060 | |
33d73e3b PH |
5061 | if (!sender_ident_set) |
5062 | { | |
5063 | sender_ident = NULL; | |
3af06092 JH |
5064 | if (f.running_in_test_harness && sender_host_port |
5065 | && interface_address && interface_port) | |
5066 | verify_get_ident(1223); /* note hardwired port number */ | |
33d73e3b | 5067 | } |
8e669ac1 | 5068 | |
4c04137d | 5069 | /* In case the given address is a non-canonical IPv6 address, canonicalize |
6f0c9a4f | 5070 | it. The code works for both IPv4 and IPv6, as it happens. */ |
8e669ac1 | 5071 | |
6f0c9a4f | 5072 | size = host_aton(sender_host_address, x); |
f3ebb786 | 5073 | sender_host_address = store_get(48, FALSE); /* large enough for full IPv6 */ |
6f0c9a4f PH |
5074 | (void)host_nmtoa(size, x, -1, sender_host_address, ':'); |
5075 | ||
5076 | /* Now set up for testing */ | |
059ec3d9 PH |
5077 | |
5078 | host_build_sender_fullhost(); | |
5079 | smtp_input = TRUE; | |
5080 | smtp_in = stdin; | |
5081 | smtp_out = stdout; | |
8768d548 JH |
5082 | f.sender_local = FALSE; |
5083 | f.sender_host_notsocket = TRUE; | |
059ec3d9 PH |
5084 | debug_file = stderr; |
5085 | debug_fd = fileno(debug_file); | |
5086 | fprintf(stdout, "\n**** SMTP testing session as if from host %s\n" | |
5087 | "**** but without any ident (RFC 1413) callback.\n" | |
5088 | "**** This is not for real!\n\n", | |
5089 | sender_host_address); | |
5090 | ||
ce325893 | 5091 | memset(sender_host_cache, 0, sizeof(sender_host_cache)); |
059ec3d9 | 5092 | if (verify_check_host(&hosts_connection_nolog) == OK) |
6c6d6e48 | 5093 | BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection); |
059ec3d9 PH |
5094 | log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info()); |
5095 | ||
24796b8d PH |
5096 | /* NOTE: We do *not* call smtp_log_no_mail() if smtp_start_session() fails, |
5097 | because a log line has already been written for all its failure exists | |
5098 | (usually "connection refused: <reason>") and writing another one is | |
5099 | unnecessary clutter. */ | |
5100 | ||
059ec3d9 PH |
5101 | if (smtp_start_session()) |
5102 | { | |
137ae145 | 5103 | rmark reset_point; |
f3ebb786 | 5104 | for (; (reset_point = store_mark()); store_reset(reset_point)) |
059ec3d9 | 5105 | { |
059ec3d9 PH |
5106 | if (smtp_setup_msg() <= 0) break; |
5107 | if (!receive_msg(FALSE)) break; | |
90341c71 JH |
5108 | |
5109 | return_path = sender_address = NULL; | |
5110 | dnslist_domain = dnslist_matched = NULL; | |
5111 | #ifndef DISABLE_DKIM | |
5112 | dkim_cur_signer = NULL; | |
5113 | #endif | |
5114 | acl_var_m = NULL; | |
5115 | deliver_localpart_orig = NULL; | |
5116 | deliver_domain_orig = NULL; | |
5117 | callout_address = sending_ip_address = NULL; | |
5118 | sender_rate = sender_rate_limit = sender_rate_period = NULL; | |
059ec3d9 | 5119 | } |
24796b8d | 5120 | smtp_log_no_mail(); |
059ec3d9 | 5121 | } |
81022793 | 5122 | exim_exit(EXIT_SUCCESS); |
059ec3d9 PH |
5123 | } |
5124 | ||
5125 | ||
5126 | /* Arrange for message reception if recipients or SMTP were specified; | |
5127 | otherwise complain unless a version print (-bV) happened or this is a filter | |
98a90c36 PP |
5128 | verification test or info dump. |
5129 | In the former case, show the configuration file name. */ | |
059ec3d9 PH |
5130 | |
5131 | if (recipients_arg >= argc && !extract_recipients && !smtp_input) | |
5132 | { | |
5133 | if (version_printed) | |
5134 | { | |
36f7a17f HSHR |
5135 | if (Ustrchr(config_main_filelist, ':')) |
5136 | printf("Configuration file search path is %s\n", config_main_filelist); | |
059ec3d9 PH |
5137 | printf("Configuration file is %s\n", config_main_filename); |
5138 | return EXIT_SUCCESS; | |
5139 | } | |
81ea09ca | 5140 | |
98a90c36 PP |
5141 | if (info_flag != CMDINFO_NONE) |
5142 | { | |
5143 | show_exim_information(info_flag, info_stdout ? stdout : stderr); | |
5144 | return info_stdout ? EXIT_SUCCESS : EXIT_FAILURE; | |
5145 | } | |
5146 | ||
f05da2e8 | 5147 | if (filter_test == FTEST_NONE) |
81ea09ca | 5148 | exim_usage(called_as); |
059ec3d9 PH |
5149 | } |
5150 | ||
5151 | ||
5152 | /* If mua_wrapper is set, Exim is being used to turn an MUA that submits on the | |
5153 | standard input into an MUA that submits to a smarthost over TCP/IP. We know | |
5154 | that we are not called from inetd, because that is rejected above. The | |
5155 | following configuration settings are forced here: | |
5156 | ||
5157 | (1) Synchronous delivery (-odi) | |
5158 | (2) Errors to stderr (-oep == -oeq) | |
5159 | (3) No parallel remote delivery | |
5160 | (4) Unprivileged delivery | |
5161 | ||
5162 | We don't force overall queueing options because there are several of them; | |
5163 | instead, queueing is avoided below when mua_wrapper is set. However, we do need | |
5164 | to override any SMTP queueing. */ | |
5165 | ||
5166 | if (mua_wrapper) | |
5167 | { | |
8768d548 | 5168 | f.synchronous_delivery = TRUE; |
059ec3d9 PH |
5169 | arg_error_handling = ERRORS_STDERR; |
5170 | remote_max_parallel = 1; | |
5171 | deliver_drop_privilege = TRUE; | |
8768d548 | 5172 | f.queue_smtp = FALSE; |
059ec3d9 | 5173 | queue_smtp_domains = NULL; |
8c5d388a | 5174 | #ifdef SUPPORT_I18N |
0ec7e948 JH |
5175 | message_utf8_downconvert = -1; /* convert-if-needed */ |
5176 | #endif | |
059ec3d9 PH |
5177 | } |
5178 | ||
5179 | ||
5180 | /* Prepare to accept one or more new messages on the standard input. When a | |
5181 | message has been read, its id is returned in message_id[]. If doing immediate | |
5182 | delivery, we fork a delivery process for each received message, except for the | |
5183 | last one, where we can save a process switch. | |
5184 | ||
5185 | It is only in non-smtp mode that error_handling is allowed to be changed from | |
5186 | its default of ERRORS_SENDER by argument. (Idle thought: are any of the | |
5187 | sendmail error modes other than -oem ever actually used? Later: yes.) */ | |
5188 | ||
5189 | if (!smtp_input) error_handling = arg_error_handling; | |
5190 | ||
5191 | /* If this is an inetd call, ensure that stderr is closed to prevent panic | |
5192 | logging being sent down the socket and make an identd call to get the | |
5193 | sender_ident. */ | |
5194 | ||
8768d548 | 5195 | else if (f.is_inetd) |
059ec3d9 | 5196 | { |
1fe64dcc | 5197 | (void)fclose(stderr); |
059ec3d9 PH |
5198 | exim_nullstd(); /* Re-open to /dev/null */ |
5199 | verify_get_ident(IDENT_PORT); | |
5200 | host_build_sender_fullhost(); | |
5201 | set_process_info("handling incoming connection from %s via inetd", | |
5202 | sender_fullhost); | |
5203 | } | |
5204 | ||
5205 | /* If the sender host address has been set, build sender_fullhost if it hasn't | |
5206 | already been done (which it will have been for inetd). This caters for the | |
5207 | case when it is forced by -oMa. However, we must flag that it isn't a socket, | |
5208 | so that the test for IP options is skipped for -bs input. */ | |
5209 | ||
2d0dc929 | 5210 | if (sender_host_address && !sender_fullhost) |
059ec3d9 PH |
5211 | { |
5212 | host_build_sender_fullhost(); | |
5213 | set_process_info("handling incoming connection from %s via -oMa", | |
5214 | sender_fullhost); | |
8768d548 | 5215 | f.sender_host_notsocket = TRUE; |
059ec3d9 PH |
5216 | } |
5217 | ||
5218 | /* Otherwise, set the sender host as unknown except for inetd calls. This | |
5219 | prevents host checking in the case of -bs not from inetd and also for -bS. */ | |
5220 | ||
8768d548 | 5221 | else if (!f.is_inetd) f.sender_host_unknown = TRUE; |
059ec3d9 PH |
5222 | |
5223 | /* If stdout does not exist, then dup stdin to stdout. This can happen | |
5224 | if exim is started from inetd. In this case fd 0 will be set to the socket, | |
5225 | but fd 1 will not be set. This also happens for passed SMTP channels. */ | |
5226 | ||
1fe64dcc | 5227 | if (fstat(1, &statbuf) < 0) (void)dup2(0, 1); |
059ec3d9 | 5228 | |
273f34d0 PH |
5229 | /* Set up the incoming protocol name and the state of the program. Root is |
5230 | allowed to force received protocol via the -oMr option above. If we have come | |
5231 | via inetd, the process info has already been set up. We don't set | |
5232 | received_protocol here for smtp input, as it varies according to | |
5233 | batch/HELO/EHLO/AUTH/TLS. */ | |
059ec3d9 PH |
5234 | |
5235 | if (smtp_input) | |
5236 | { | |
8768d548 | 5237 | if (!f.is_inetd) set_process_info("accepting a local %sSMTP message from <%s>", |
273f34d0 PH |
5238 | smtp_batched_input? "batched " : "", |
5239 | (sender_address!= NULL)? sender_address : originator_login); | |
059ec3d9 PH |
5240 | } |
5241 | else | |
5242 | { | |
90341c71 JH |
5243 | int old_pool = store_pool; |
5244 | store_pool = POOL_PERM; | |
5245 | if (!received_protocol) | |
059ec3d9 | 5246 | received_protocol = string_sprintf("local%s", called_as); |
90341c71 | 5247 | store_pool = old_pool; |
059ec3d9 PH |
5248 | set_process_info("accepting a local non-SMTP message from <%s>", |
5249 | sender_address); | |
5250 | } | |
5251 | ||
8669f003 PH |
5252 | /* Initialize the session_local_queue-only flag (this will be ignored if |
5253 | mua_wrapper is set) */ | |
059ec3d9 PH |
5254 | |
5255 | queue_check_only(); | |
8669f003 | 5256 | session_local_queue_only = queue_only; |
059ec3d9 PH |
5257 | |
5258 | /* For non-SMTP and for batched SMTP input, check that there is enough space on | |
5259 | the spool if so configured. On failure, we must not attempt to send an error | |
5260 | message! (For interactive SMTP, the check happens at MAIL FROM and an SMTP | |
5261 | error code is given.) */ | |
5262 | ||
5263 | if ((!smtp_input || smtp_batched_input) && !receive_check_fs(0)) | |
9af3c549 | 5264 | exim_fail("exim: insufficient disk space\n"); |
059ec3d9 | 5265 | |
273f34d0 PH |
5266 | /* If this is smtp input of any kind, real or batched, handle the start of the |
5267 | SMTP session. | |
24796b8d PH |
5268 | |
5269 | NOTE: We do *not* call smtp_log_no_mail() if smtp_start_session() fails, | |
5270 | because a log line has already been written for all its failure exists | |
5271 | (usually "connection refused: <reason>") and writing another one is | |
5272 | unnecessary clutter. */ | |
059ec3d9 PH |
5273 | |
5274 | if (smtp_input) | |
5275 | { | |
5276 | smtp_in = stdin; | |
5277 | smtp_out = stdout; | |
ce325893 | 5278 | memset(sender_host_cache, 0, sizeof(sender_host_cache)); |
059ec3d9 | 5279 | if (verify_check_host(&hosts_connection_nolog) == OK) |
6c6d6e48 | 5280 | BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection); |
059ec3d9 PH |
5281 | log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info()); |
5282 | if (!smtp_start_session()) | |
5283 | { | |
5284 | mac_smtp_fflush(); | |
81022793 | 5285 | exim_exit(EXIT_SUCCESS); |
059ec3d9 PH |
5286 | } |
5287 | } | |
5288 | ||
45b91596 | 5289 | /* Otherwise, set up the input size limit here. */ |
059ec3d9 PH |
5290 | |
5291 | else | |
5292 | { | |
d45b1de8 | 5293 | thismessage_size_limit = expand_string_integer(message_size_limit, TRUE); |
57cc2785 | 5294 | if (expand_string_message) |
059ec3d9 PH |
5295 | if (thismessage_size_limit == -1) |
5296 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand " | |
5297 | "message_size_limit: %s", expand_string_message); | |
5298 | else | |
5299 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for " | |
5300 | "message_size_limit: %s", expand_string_message); | |
059ec3d9 PH |
5301 | } |
5302 | ||
5303 | /* Loop for several messages when reading SMTP input. If we fork any child | |
5304 | processes, we don't want to wait for them unless synchronous delivery is | |
5305 | requested, so set SIGCHLD to SIG_IGN in that case. This is not necessarily the | |
5306 | same as SIG_DFL, despite the fact that documentation often lists the default as | |
5307 | "ignore". This is a confusing area. This is what I know: | |
5308 | ||
5309 | At least on some systems (e.g. Solaris), just setting SIG_IGN causes child | |
5310 | processes that complete simply to go away without ever becoming defunct. You | |
5311 | can't then wait for them - but we don't want to wait for them in the | |
5312 | non-synchronous delivery case. However, this behaviour of SIG_IGN doesn't | |
5313 | happen for all OS (e.g. *BSD is different). | |
5314 | ||
5315 | But that's not the end of the story. Some (many? all?) systems have the | |
5316 | SA_NOCLDWAIT option for sigaction(). This requests the behaviour that Solaris | |
5317 | has by default, so it seems that the difference is merely one of default | |
5318 | (compare restarting vs non-restarting signals). | |
5319 | ||
5320 | To cover all cases, Exim sets SIG_IGN with SA_NOCLDWAIT here if it can. If not, | |
5321 | it just sets SIG_IGN. To be on the safe side it also calls waitpid() at the end | |
5322 | of the loop below. Paranoia rules. | |
5323 | ||
5324 | February 2003: That's *still* not the end of the story. There are now versions | |
5325 | of Linux (where SIG_IGN does work) that are picky. If, having set SIG_IGN, a | |
5326 | process then calls waitpid(), a grumble is written to the system log, because | |
5327 | this is logically inconsistent. In other words, it doesn't like the paranoia. | |
4c04137d | 5328 | As a consequence of this, the waitpid() below is now excluded if we are sure |
059ec3d9 PH |
5329 | that SIG_IGN works. */ |
5330 | ||
8768d548 | 5331 | if (!f.synchronous_delivery) |
059ec3d9 PH |
5332 | { |
5333 | #ifdef SA_NOCLDWAIT | |
5334 | struct sigaction act; | |
5335 | act.sa_handler = SIG_IGN; | |
5336 | sigemptyset(&(act.sa_mask)); | |
5337 | act.sa_flags = SA_NOCLDWAIT; | |
5338 | sigaction(SIGCHLD, &act, NULL); | |
5339 | #else | |
5340 | signal(SIGCHLD, SIG_IGN); | |
5341 | #endif | |
5342 | } | |
5343 | ||
5344 | /* Save the current store pool point, for resetting at the start of | |
5345 | each message, and save the real sender address, if any. */ | |
5346 | ||
059ec3d9 PH |
5347 | real_sender_address = sender_address; |
5348 | ||
5349 | /* Loop to receive messages; receive_msg() returns TRUE if there are more | |
5350 | messages to be read (SMTP input), or FALSE otherwise (not SMTP, or SMTP channel | |
5351 | collapsed). */ | |
5352 | ||
5353 | while (more) | |
5354 | { | |
137ae145 | 5355 | rmark reset_point = store_mark(); |
059ec3d9 PH |
5356 | message_id[0] = 0; |
5357 | ||
273f34d0 PH |
5358 | /* Handle the SMTP case; call smtp_setup_mst() to deal with the initial SMTP |
5359 | input and build the recipients list, before calling receive_msg() to read the | |
5360 | message proper. Whatever sender address is given in the SMTP transaction is | |
5361 | often ignored for local senders - we use the actual sender, which is normally | |
5362 | either the underlying user running this process or a -f argument provided by | |
5363 | a trusted caller. It is saved in real_sender_address. The test for whether to | |
5364 | accept the SMTP sender is encapsulated in receive_check_set_sender(). */ | |
059ec3d9 PH |
5365 | |
5366 | if (smtp_input) | |
5367 | { | |
5368 | int rc; | |
5369 | if ((rc = smtp_setup_msg()) > 0) | |
5370 | { | |
5371 | if (real_sender_address != NULL && | |
5372 | !receive_check_set_sender(sender_address)) | |
5373 | { | |
5374 | sender_address = raw_sender = real_sender_address; | |
5375 | sender_address_unrewritten = NULL; | |
5376 | } | |
273f34d0 PH |
5377 | |
5378 | /* For batched SMTP, we have to run the acl_not_smtp_start ACL, since it | |
5379 | isn't really SMTP, so no other ACL will run until the acl_not_smtp one at | |
5380 | the very end. The result of the ACL is ignored (as for other non-SMTP | |
5381 | messages). It is run for its potential side effects. */ | |
5382 | ||
5383 | if (smtp_batched_input && acl_not_smtp_start != NULL) | |
5384 | { | |
5385 | uschar *user_msg, *log_msg; | |
8768d548 | 5386 | f.enable_dollar_recipients = TRUE; |
273f34d0 PH |
5387 | (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start, |
5388 | &user_msg, &log_msg); | |
8768d548 | 5389 | f.enable_dollar_recipients = FALSE; |
273f34d0 PH |
5390 | } |
5391 | ||
5392 | /* Now get the data for the message */ | |
5393 | ||
059ec3d9 PH |
5394 | more = receive_msg(extract_recipients); |
5395 | if (message_id[0] == 0) | |
5396 | { | |
57cc2785 | 5397 | cancel_cutthrough_connection(TRUE, US"receive dropped"); |
90341c71 | 5398 | if (more) goto moreloop; |
b4ed4da0 | 5399 | smtp_log_no_mail(); /* Log no mail if configured */ |
81022793 | 5400 | exim_exit(EXIT_FAILURE); |
059ec3d9 PH |
5401 | } |
5402 | } | |
b4ed4da0 PH |
5403 | else |
5404 | { | |
57cc2785 | 5405 | cancel_cutthrough_connection(TRUE, US"message setup dropped"); |
b4ed4da0 | 5406 | smtp_log_no_mail(); /* Log no mail if configured */ |
81022793 | 5407 | exim_exit(rc ? EXIT_FAILURE : EXIT_SUCCESS); |
b4ed4da0 | 5408 | } |
059ec3d9 PH |
5409 | } |
5410 | ||
5411 | /* In the non-SMTP case, we have all the information from the command | |
5412 | line, but must process it in case it is in the more general RFC822 | |
5413 | format, and in any case, to detect syntax errors. Also, it appears that | |
5414 | the use of comma-separated lists as single arguments is common, so we | |
5415 | had better support them. */ | |
5416 | ||
5417 | else | |
5418 | { | |
059ec3d9 PH |
5419 | int rcount = 0; |
5420 | int count = argc - recipients_arg; | |
5421 | uschar **list = argv + recipients_arg; | |
eb2c0248 | 5422 | |
69358f02 | 5423 | /* These options cannot be changed dynamically for non-SMTP messages */ |
eb2c0248 | 5424 | |
8768d548 JH |
5425 | f.active_local_sender_retain = local_sender_retain; |
5426 | f.active_local_from_check = local_from_check; | |
059ec3d9 PH |
5427 | |
5428 | /* Save before any rewriting */ | |
5429 | ||
5430 | raw_sender = string_copy(sender_address); | |
5431 | ||
f0fe22cb | 5432 | /* Loop for each argument (supplied by user hence tainted) */ |
059ec3d9 | 5433 | |
d7978c0f | 5434 | for (int i = 0; i < count; i++) |
059ec3d9 PH |
5435 | { |
5436 | int start, end, domain; | |
f0fe22cb JH |
5437 | uschar * errmess; |
5438 | uschar * s = string_copy_taint(list[i], TRUE); | |
059ec3d9 PH |
5439 | |
5440 | /* Loop for each comma-separated address */ | |
5441 | ||
5442 | while (*s != 0) | |
5443 | { | |
5444 | BOOL finished = FALSE; | |
5445 | uschar *recipient; | |
5446 | uschar *ss = parse_find_address_end(s, FALSE); | |
5447 | ||
5448 | if (*ss == ',') *ss = 0; else finished = TRUE; | |
5449 | ||
5450 | /* Check max recipients - if -t was used, these aren't recipients */ | |
5451 | ||
5452 | if (recipients_max > 0 && ++rcount > recipients_max && | |
5453 | !extract_recipients) | |
059ec3d9 PH |
5454 | if (error_handling == ERRORS_STDERR) |
5455 | { | |
5456 | fprintf(stderr, "exim: too many recipients\n"); | |
81022793 | 5457 | exim_exit(EXIT_FAILURE); |
059ec3d9 PH |
5458 | } |
5459 | else | |
059ec3d9 PH |
5460 | return |
5461 | moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)? | |
5462 | errors_sender_rc : EXIT_FAILURE; | |
059ec3d9 | 5463 | |
8c5d388a | 5464 | #ifdef SUPPORT_I18N |
250b6871 JH |
5465 | { |
5466 | BOOL b = allow_utf8_domains; | |
5467 | allow_utf8_domains = TRUE; | |
5468 | #endif | |
059ec3d9 PH |
5469 | recipient = |
5470 | parse_extract_address(s, &errmess, &start, &end, &domain, FALSE); | |
5471 | ||
8c5d388a | 5472 | #ifdef SUPPORT_I18N |
250b6871 JH |
5473 | if (string_is_utf8(recipient)) |
5474 | message_smtputf8 = TRUE; | |
5475 | else | |
5476 | allow_utf8_domains = b; | |
5477 | } | |
5478 | #endif | |
8768d548 | 5479 | if (domain == 0 && !f.allow_unqualified_recipient) |
059ec3d9 PH |
5480 | { |
5481 | recipient = NULL; | |
5482 | errmess = US"unqualified recipient address not allowed"; | |
5483 | } | |
5484 | ||
5fcc791a | 5485 | if (!recipient) |
059ec3d9 PH |
5486 | if (error_handling == ERRORS_STDERR) |
5487 | { | |
5488 | fprintf(stderr, "exim: bad recipient address \"%s\": %s\n", | |
5489 | string_printing(list[i]), errmess); | |
81022793 | 5490 | exim_exit(EXIT_FAILURE); |
059ec3d9 PH |
5491 | } |
5492 | else | |
5493 | { | |
5494 | error_block eblock; | |
5495 | eblock.next = NULL; | |
5496 | eblock.text1 = string_printing(list[i]); | |
5497 | eblock.text2 = errmess; | |
5498 | return | |
5499 | moan_to_sender(ERRMESS_BADARGADDRESS, &eblock, NULL, stdin, TRUE)? | |
5500 | errors_sender_rc : EXIT_FAILURE; | |
5501 | } | |
059ec3d9 | 5502 | |
f3ebb786 | 5503 | receive_add_recipient(string_copy_taint(recipient, TRUE), -1); |
059ec3d9 PH |
5504 | s = ss; |
5505 | if (!finished) | |
5506 | while (*(++s) != 0 && (*s == ',' || isspace(*s))); | |
5507 | } | |
5508 | } | |
5509 | ||
5510 | /* Show the recipients when debugging */ | |
5511 | ||
5512 | DEBUG(D_receive) | |
5513 | { | |
a76d120a JH |
5514 | if (sender_address) debug_printf("Sender: %s\n", sender_address); |
5515 | if (recipients_list) | |
059ec3d9 PH |
5516 | { |
5517 | debug_printf("Recipients:\n"); | |
d7978c0f | 5518 | for (int i = 0; i < recipients_count; i++) |
059ec3d9 PH |
5519 | debug_printf(" %s\n", recipients_list[i].address); |
5520 | } | |
5521 | } | |
5522 | ||
45b91596 PH |
5523 | /* Run the acl_not_smtp_start ACL if required. The result of the ACL is |
5524 | ignored; rejecting here would just add complication, and it can just as | |
5525 | well be done later. Allow $recipients to be visible in the ACL. */ | |
5526 | ||
9cd319d9 | 5527 | if (acl_not_smtp_start) |
45b91596 PH |
5528 | { |
5529 | uschar *user_msg, *log_msg; | |
8768d548 | 5530 | f.enable_dollar_recipients = TRUE; |
45b91596 PH |
5531 | (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start, |
5532 | &user_msg, &log_msg); | |
8768d548 | 5533 | f.enable_dollar_recipients = FALSE; |
45b91596 PH |
5534 | } |
5535 | ||
9cd319d9 JH |
5536 | /* Pause for a while waiting for input. If none received in that time, |
5537 | close the logfile, if we had one open; then if we wait for a long-running | |
5538 | datasource (months, in one use-case) log rotation will not leave us holding | |
5539 | the file copy. */ | |
5540 | ||
5541 | if (!receive_timeout) | |
5542 | { | |
f2ed27cf | 5543 | struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 }; /* 30 minutes */ |
9cd319d9 JH |
5544 | fd_set r; |
5545 | ||
5546 | FD_ZERO(&r); FD_SET(0, &r); | |
5547 | if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close(); | |
5548 | } | |
5549 | ||
f05da2e8 PH |
5550 | /* Read the data for the message. If filter_test is not FTEST_NONE, this |
5551 | will just read the headers for the message, and not write anything onto the | |
5552 | spool. */ | |
059ec3d9 PH |
5553 | |
5554 | message_ended = END_NOTENDED; | |
5555 | more = receive_msg(extract_recipients); | |
5556 | ||
5557 | /* more is always FALSE here (not SMTP message) when reading a message | |
5558 | for real; when reading the headers of a message for filter testing, | |
5559 | it is TRUE if the headers were terminated by '.' and FALSE otherwise. */ | |
5560 | ||
81022793 | 5561 | if (message_id[0] == 0) exim_exit(EXIT_FAILURE); |
059ec3d9 PH |
5562 | } /* Non-SMTP message reception */ |
5563 | ||
5564 | /* If this is a filter testing run, there are headers in store, but | |
5565 | no message on the spool. Run the filtering code in testing mode, setting | |
5566 | the domain to the qualify domain and the local part to the current user, | |
5567 | unless they have been set by options. The prefix and suffix are left unset | |
5568 | unless specified. The the return path is set to to the sender unless it has | |
5569 | already been set from a return-path header in the message. */ | |
5570 | ||
f05da2e8 | 5571 | if (filter_test != FTEST_NONE) |
059ec3d9 | 5572 | { |
19849de0 | 5573 | deliver_domain = ftest_domain ? ftest_domain : qualify_domain_recipient; |
059ec3d9 | 5574 | deliver_domain_orig = deliver_domain; |
19849de0 | 5575 | deliver_localpart = ftest_localpart ? ftest_localpart : originator_login; |
059ec3d9 PH |
5576 | deliver_localpart_orig = deliver_localpart; |
5577 | deliver_localpart_prefix = ftest_prefix; | |
5578 | deliver_localpart_suffix = ftest_suffix; | |
5579 | deliver_home = originator_home; | |
5580 | ||
19849de0 | 5581 | if (!return_path) |
059ec3d9 PH |
5582 | { |
5583 | printf("Return-path copied from sender\n"); | |
5584 | return_path = string_copy(sender_address); | |
5585 | } | |
5586 | else | |
059ec3d9 | 5587 | printf("Return-path = %s\n", (return_path[0] == 0)? US"<>" : return_path); |
059ec3d9 PH |
5588 | printf("Sender = %s\n", (sender_address[0] == 0)? US"<>" : sender_address); |
5589 | ||
5590 | receive_add_recipient( | |
5591 | string_sprintf("%s%s%s@%s", | |
19849de0 | 5592 | ftest_prefix ? ftest_prefix : US"", |
059ec3d9 | 5593 | deliver_localpart, |
19849de0 | 5594 | ftest_suffix ? ftest_suffix : US"", |
059ec3d9 PH |
5595 | deliver_domain), -1); |
5596 | ||
5597 | printf("Recipient = %s\n", recipients_list[0].address); | |
19849de0 JH |
5598 | if (ftest_prefix) printf("Prefix = %s\n", ftest_prefix); |
5599 | if (ftest_suffix) printf("Suffix = %s\n", ftest_suffix); | |
059ec3d9 | 5600 | |
1ac6b2e7 JH |
5601 | if (chdir("/")) /* Get away from wherever the user is running this from */ |
5602 | { | |
5603 | DEBUG(D_receive) debug_printf("chdir(\"/\") failed\n"); | |
81022793 | 5604 | exim_exit(EXIT_FAILURE); |
1ac6b2e7 | 5605 | } |
8e669ac1 PH |
5606 | |
5607 | /* Now we run either a system filter test, or a user filter test, or both. | |
5608 | In the latter case, headers added by the system filter will persist and be | |
5609 | available to the user filter. We need to copy the filter variables | |
f05da2e8 | 5610 | explicitly. */ |
8e669ac1 | 5611 | |
19849de0 | 5612 | if (filter_test & FTEST_SYSTEM) |
f05da2e8 | 5613 | if (!filter_runtest(filter_sfd, filter_test_sfile, TRUE, more)) |
81022793 | 5614 | exim_exit(EXIT_FAILURE); |
8e669ac1 | 5615 | |
f05da2e8 | 5616 | memcpy(filter_sn, filter_n, sizeof(filter_sn)); |
8e669ac1 | 5617 | |
19849de0 | 5618 | if (filter_test & FTEST_USER) |
f05da2e8 | 5619 | if (!filter_runtest(filter_ufd, filter_test_ufile, FALSE, more)) |
81022793 | 5620 | exim_exit(EXIT_FAILURE); |
8e669ac1 | 5621 | |
81022793 | 5622 | exim_exit(EXIT_SUCCESS); |
059ec3d9 PH |
5623 | } |
5624 | ||
5625 | /* Else act on the result of message reception. We should not get here unless | |
8669f003 PH |
5626 | message_id[0] is non-zero. If queue_only is set, session_local_queue_only |
5627 | will be TRUE. If it is not, check on the number of messages received in this | |
5628 | connection. */ | |
5629 | ||
19849de0 JH |
5630 | if ( !session_local_queue_only |
5631 | && smtp_accept_queue_per_connection > 0 | |
5632 | && receive_messagecount > smtp_accept_queue_per_connection) | |
059ec3d9 | 5633 | { |
8669f003 PH |
5634 | session_local_queue_only = TRUE; |
5635 | queue_only_reason = 2; | |
5636 | } | |
5637 | ||
5638 | /* Initialize local_queue_only from session_local_queue_only. If it is false, | |
5639 | and queue_only_load is set, check that the load average is below it. If it is | |
5640 | not, set local_queue_only TRUE. If queue_only_load_latch is true (the | |
5641 | default), we put the whole session into queue_only mode. It then remains this | |
5642 | way for any subsequent messages on the same SMTP connection. This is a | |
5643 | deliberate choice; even though the load average may fall, it doesn't seem | |
5644 | right to deliver later messages on the same call when not delivering earlier | |
5645 | ones. However, there are odd cases where this is not wanted, so this can be | |
5646 | changed by setting queue_only_load_latch false. */ | |
5647 | ||
19849de0 JH |
5648 | if (!(local_queue_only = session_local_queue_only) && queue_only_load >= 0) |
5649 | if ((local_queue_only = (load_average = OS_GETLOADAVG()) > queue_only_load)) | |
059ec3d9 | 5650 | { |
8669f003 PH |
5651 | queue_only_reason = 3; |
5652 | if (queue_only_load_latch) session_local_queue_only = TRUE; | |
059ec3d9 | 5653 | } |
059ec3d9 PH |
5654 | |
5655 | /* If running as an MUA wrapper, all queueing options and freezing options | |
5656 | are ignored. */ | |
5657 | ||
5658 | if (mua_wrapper) | |
8768d548 | 5659 | local_queue_only = f.queue_only_policy = f.deliver_freeze = FALSE; |
059ec3d9 PH |
5660 | |
5661 | /* Log the queueing here, when it will get a message id attached, but | |
5662 | not if queue_only is set (case 0). Case 1 doesn't happen here (too many | |
5663 | connections). */ | |
5664 | ||
57cc2785 | 5665 | if (local_queue_only) |
059ec3d9 | 5666 | { |
57cc2785 JH |
5667 | cancel_cutthrough_connection(TRUE, US"no delivery; queueing"); |
5668 | switch(queue_only_reason) | |
5669 | { | |
5670 | case 2: | |
5671 | log_write(L_delay_delivery, | |
5672 | LOG_MAIN, "no immediate delivery: more than %d messages " | |
5673 | "received in one connection", smtp_accept_queue_per_connection); | |
5674 | break; | |
059ec3d9 | 5675 | |
57cc2785 JH |
5676 | case 3: |
5677 | log_write(L_delay_delivery, | |
5678 | LOG_MAIN, "no immediate delivery: load average %.2f", | |
5679 | (double)load_average/1000.0); | |
5680 | break; | |
5681 | } | |
059ec3d9 PH |
5682 | } |
5683 | ||
8768d548 | 5684 | else if (f.queue_only_policy || f.deliver_freeze) |
57cc2785 JH |
5685 | cancel_cutthrough_connection(TRUE, US"no delivery; queueing"); |
5686 | ||
059ec3d9 PH |
5687 | /* Else do the delivery unless the ACL or local_scan() called for queue only |
5688 | or froze the message. Always deliver in a separate process. A fork failure is | |
5689 | not a disaster, as the delivery will eventually happen on a subsequent queue | |
eb2c0248 PH |
5690 | run. The search cache must be tidied before the fork, as the parent will |
5691 | do it before exiting. The child will trigger a lookup failure and | |
5692 | thereby defer the delivery if it tries to use (for example) a cached ldap | |
5693 | connection that the parent has called unbind on. */ | |
059ec3d9 | 5694 | |
57cc2785 | 5695 | else |
059ec3d9 PH |
5696 | { |
5697 | pid_t pid; | |
eb2c0248 PH |
5698 | search_tidyup(); |
5699 | ||
32393657 | 5700 | if ((pid = exim_fork(US"local-accept-delivery")) == 0) |
059ec3d9 PH |
5701 | { |
5702 | int rc; | |
5703 | close_unwanted(); /* Close unwanted file descriptors and TLS */ | |
5704 | exim_nullstd(); /* Ensure std{in,out,err} exist */ | |
5705 | ||
5706 | /* Re-exec Exim if we need to regain privilege (note: in mua_wrapper | |
5707 | mode, deliver_drop_privilege is forced TRUE). */ | |
5708 | ||
5709 | if (geteuid() != root_uid && !deliver_drop_privilege && !unprivileged) | |
5710 | { | |
57cc2785 | 5711 | delivery_re_exec(CEE_EXEC_EXIT); |
059ec3d9 PH |
5712 | /* Control does not return here. */ |
5713 | } | |
5714 | ||
5715 | /* No need to re-exec */ | |
5716 | ||
5717 | rc = deliver_message(message_id, FALSE, FALSE); | |
5718 | search_tidyup(); | |
f3ebb786 | 5719 | exim_underbar_exit(!mua_wrapper || rc == DELIVER_MUA_SUCCEEDED |
81022793 | 5720 | ? EXIT_SUCCESS : EXIT_FAILURE); |
059ec3d9 PH |
5721 | } |
5722 | ||
5723 | if (pid < 0) | |
5724 | { | |
57cc2785 | 5725 | cancel_cutthrough_connection(TRUE, US"delivery fork failed"); |
059ec3d9 PH |
5726 | log_write(0, LOG_MAIN|LOG_PANIC, "failed to fork automatic delivery " |
5727 | "process: %s", strerror(errno)); | |
5728 | } | |
57cc2785 JH |
5729 | else |
5730 | { | |
5731 | release_cutthrough_connection(US"msg passed for delivery"); | |
059ec3d9 | 5732 | |
57cc2785 JH |
5733 | /* In the parent, wait if synchronous delivery is required. This will |
5734 | always be the case in MUA wrapper mode. */ | |
059ec3d9 | 5735 | |
8768d548 | 5736 | if (f.synchronous_delivery) |
57cc2785 JH |
5737 | { |
5738 | int status; | |
5739 | while (wait(&status) != pid); | |
5740 | if ((status & 0x00ff) != 0) | |
5741 | log_write(0, LOG_MAIN|LOG_PANIC, | |
5742 | "process %d crashed with signal %d while delivering %s", | |
5743 | (int)pid, status & 0x00ff, message_id); | |
81022793 | 5744 | if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE); |
57cc2785 | 5745 | } |
059ec3d9 PH |
5746 | } |
5747 | } | |
5748 | ||
5749 | /* The loop will repeat if more is TRUE. If we do not know know that the OS | |
5750 | automatically reaps children (see comments above the loop), clear away any | |
5751 | finished subprocesses here, in case there are lots of messages coming in | |
5752 | from the same source. */ | |
5753 | ||
5754 | #ifndef SIG_IGN_WORKS | |
5755 | while (waitpid(-1, NULL, WNOHANG) > 0); | |
5756 | #endif | |
90341c71 JH |
5757 | |
5758 | moreloop: | |
5759 | return_path = sender_address = NULL; | |
5760 | authenticated_sender = NULL; | |
5761 | deliver_localpart_orig = NULL; | |
5762 | deliver_domain_orig = NULL; | |
5763 | deliver_host = deliver_host_address = NULL; | |
5764 | dnslist_domain = dnslist_matched = NULL; | |
ac4824af | 5765 | #ifdef WITH_CONTENT_SCAN |
90341c71 | 5766 | malware_name = NULL; |
ac4824af | 5767 | #endif |
90341c71 JH |
5768 | callout_address = NULL; |
5769 | sending_ip_address = NULL; | |
5770 | acl_var_m = NULL; | |
d7978c0f | 5771 | for(int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; |
90341c71 JH |
5772 | |
5773 | store_reset(reset_point); | |
059ec3d9 PH |
5774 | } |
5775 | ||
81022793 | 5776 | exim_exit(EXIT_SUCCESS); /* Never returns */ |
059ec3d9 PH |
5777 | return 0; /* To stop compiler warning */ |
5778 | } | |
5779 | ||
2cee425a | 5780 | |
059ec3d9 | 5781 | /* End of exim.c */ |