xref: /netbsd-src/external/ibm-public/postfix/dist/src/pickup/pickup.c (revision 46f5119e40af2e51998f686b2fdcc76b5488f7f3)
1 /*	$NetBSD: pickup.c,v 1.1.1.4 2011/03/02 19:32:24 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	pickup 8
6 /* SUMMARY
7 /*	Postfix local mail pickup
8 /* SYNOPSIS
9 /*	\fBpickup\fR [generic Postfix daemon options]
10 /* DESCRIPTION
11 /*	The \fBpickup\fR(8) daemon waits for hints that new mail has been
12 /*	dropped into the \fBmaildrop\fR directory, and feeds it into the
13 /*	\fBcleanup\fR(8) daemon.
14 /*	Ill-formatted files are deleted without notifying the originator.
15 /*	This program expects to be run from the \fBmaster\fR(8) process
16 /*	manager.
17 /* STANDARDS
18 /* .ad
19 /* .fi
20 /*	None. The \fBpickup\fR(8) daemon does not interact with
21 /*	the outside world.
22 /* SECURITY
23 /* .ad
24 /* .fi
25 /*	The \fBpickup\fR(8) daemon is moderately security sensitive. It runs
26 /*	with fixed low privilege and can run in a chrooted environment.
27 /*	However, the program reads files from potentially hostile users.
28 /*	The \fBpickup\fR(8) daemon opens no files for writing, is careful about
29 /*	what files it opens for reading, and does not actually touch any data
30 /*	that is sent to its public service endpoint.
31 /* DIAGNOSTICS
32 /*	Problems and transactions are logged to \fBsyslogd\fR(8).
33 /* BUGS
34 /*	The \fBpickup\fR(8) daemon copies mail from file to the \fBcleanup\fR(8)
35 /*	daemon.  It could avoid message copying overhead by sending a file
36 /*	descriptor instead of file data, but then the already complex
37 /*	\fBcleanup\fR(8) daemon would have to deal with unfiltered user data.
38 /* CONFIGURATION PARAMETERS
39 /* .ad
40 /* .fi
41 /*	As the \fBpickup\fR(8) daemon is a relatively long-running process, up
42 /*	to an hour may pass before a \fBmain.cf\fR change takes effect.
43 /*	Use the command "\fBpostfix reload\fR" command to speed up a change.
44 /*
45 /*	The text below provides only a parameter summary. See
46 /*	\fBpostconf\fR(5) for more details including examples.
47 /* CONTENT INSPECTION CONTROLS
48 /* .ad
49 /* .fi
50 /* .IP "\fBcontent_filter (empty)\fR"
51 /*	After the message is queued, send the entire message to the
52 /*	specified \fItransport:destination\fR.
53 /* .IP "\fBreceive_override_options (empty)\fR"
54 /*	Enable or disable recipient validation, built-in content
55 /*	filtering, or address mapping.
56 /* MISCELLANEOUS CONTROLS
57 /* .ad
58 /* .fi
59 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
60 /*	The default location of the Postfix main.cf and master.cf
61 /*	configuration files.
62 /* .IP "\fBipc_timeout (3600s)\fR"
63 /*	The time limit for sending or receiving information over an internal
64 /*	communication channel.
65 /* .IP "\fBline_length_limit (2048)\fR"
66 /*	Upon input, long lines are chopped up into pieces of at most
67 /*	this length; upon delivery, long lines are reconstructed.
68 /* .IP "\fBmax_idle (100s)\fR"
69 /*	The maximum amount of time that an idle Postfix daemon process waits
70 /*	for an incoming connection before terminating voluntarily.
71 /* .IP "\fBmax_use (100)\fR"
72 /*	The maximal number of incoming connections that a Postfix daemon
73 /*	process will service before terminating voluntarily.
74 /* .IP "\fBprocess_id (read-only)\fR"
75 /*	The process ID of a Postfix command or daemon process.
76 /* .IP "\fBprocess_name (read-only)\fR"
77 /*	The process name of a Postfix command or daemon process.
78 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
79 /*	The location of the Postfix top-level queue directory.
80 /* .IP "\fBsyslog_facility (mail)\fR"
81 /*	The syslog facility of Postfix logging.
82 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
83 /*	The mail system name that is prepended to the process name in syslog
84 /*	records, so that "smtpd" becomes, for example, "postfix/smtpd".
85 /* SEE ALSO
86 /*	cleanup(8), message canonicalization
87 /*	sendmail(1), Sendmail-compatible interface
88 /*	postdrop(1), mail posting agent
89 /*	postconf(5), configuration parameters
90 /*	master(5), generic daemon options
91 /*	master(8), process manager
92 /*	syslogd(8), system logging
93 /* LICENSE
94 /* .ad
95 /* .fi
96 /*	The Secure Mailer license must be distributed with this software.
97 /* AUTHOR(S)
98 /*	Wietse Venema
99 /*	IBM T.J. Watson Research
100 /*	P.O. Box 704
101 /*	Yorktown Heights, NY 10598, USA
102 /*--*/
103 
104 /* System library. */
105 
106 #include <sys_defs.h>
107 #include <sys/stat.h>
108 #include <dirent.h>
109 #include <unistd.h>
110 #include <stdlib.h>
111 #include <time.h>
112 #include <string.h>
113 #include <fcntl.h>
114 #include <errno.h>
115 #include <ctype.h>
116 
117 /* Utility library. */
118 
119 #include <msg.h>
120 #include <scan_dir.h>
121 #include <vstring.h>
122 #include <vstream.h>
123 #include <set_ugid.h>
124 #include <safe_open.h>
125 #include <watchdog.h>
126 #include <stringops.h>
127 
128 /* Global library. */
129 
130 #include <mail_queue.h>
131 #include <mail_open_ok.h>
132 #include <mymalloc.h>
133 #include <mail_proto.h>
134 #include <cleanup_user.h>
135 #include <mail_date.h>
136 #include <mail_params.h>
137 #include <mail_conf.h>
138 #include <record.h>
139 #include <rec_type.h>
140 #include <lex_822.h>
141 #include <input_transp.h>
142 #include <rec_attr_map.h>
143 #include <mail_version.h>
144 
145 /* Single-threaded server skeleton. */
146 
147 #include <mail_server.h>
148 
149 /* Application-specific. */
150 
151 char   *var_filter_xport;
152 char   *var_input_transp;
153 
154  /*
155   * Structure to bundle a bunch of information about a queue file.
156   */
157 typedef struct {
158     char   *id;				/* queue file basename */
159     struct stat st;			/* queue file status */
160     char   *path;			/* name for open/remove */
161     char   *sender;			/* sender address */
162 } PICKUP_INFO;
163 
164  /*
165   * What action should be taken after attempting to deliver a message: remove
166   * the file from the maildrop, or leave it alone. The latter is also used
167   * for files that are still being written to.
168   */
169 #define REMOVE_MESSAGE_FILE	1
170 #define KEEP_MESSAGE_FILE	2
171 
172  /*
173   * Transparency: before mail is queued, do we allow address mapping,
174   * automatic bcc, header/body checks?
175   */
176 int     pickup_input_transp_mask;
177 
178 /* file_read_error - handle error while reading queue file */
179 
180 static int file_read_error(PICKUP_INFO *info, int type)
181 {
182     msg_warn("uid=%ld: unexpected or malformed record type %d",
183 	     (long) info->st.st_uid, type);
184     return (REMOVE_MESSAGE_FILE);
185 }
186 
187 /* cleanup_service_error_reason - handle error writing to cleanup service. */
188 
189 static int cleanup_service_error_reason(PICKUP_INFO *info, int status,
190 					        const char *reason)
191 {
192 
193     /*
194      * XXX If the cleanup server gave a reason, then it was already logged.
195      * Don't bother logging it another time.
196      *
197      * XXX Discard a message without recipient. This can happen with "postsuper
198      * -r" when a message is already delivered (or bounced). The Postfix
199      * sendmail command rejects submissions without recipients.
200      */
201     if (reason == 0 || *reason == 0)
202 	msg_warn("%s: error writing %s: %s",
203 		  info->path, info->id, cleanup_strerror(status));
204     return ((status & (CLEANUP_STAT_BAD | CLEANUP_STAT_RCPT)) ?
205 	    REMOVE_MESSAGE_FILE : KEEP_MESSAGE_FILE);
206 }
207 
208 #define cleanup_service_error(info, status) \
209 	cleanup_service_error_reason((info), (status), (char *) 0)
210 
211 /* copy_segment - copy a record group */
212 
213 static int copy_segment(VSTREAM *qfile, VSTREAM *cleanup, PICKUP_INFO *info,
214 			        VSTRING *buf, char *expected)
215 {
216     int     type;
217     int     check_first = (*expected == REC_TYPE_CONTENT[0]);
218     int     time_seen = 0;
219     char   *attr_name;
220     char   *attr_value;
221     char   *saved_attr;
222     int     skip_attr;
223 
224     /*
225      * Limit the input record size. All front-end programs should protect the
226      * mail system against unreasonable inputs. This also requires that we
227      * limit the size of envelope records written by the local posting agent.
228      *
229      * Records with named attributes are filtered by postdrop(1).
230      *
231      * We must allow PTR records here because of "postsuper -r".
232      */
233     for (;;) {
234 	if ((type = rec_get(qfile, buf, var_line_limit)) < 0
235 	    || strchr(expected, type) == 0)
236 	    return (file_read_error(info, type));
237 	if (msg_verbose)
238 	    msg_info("%s: read %c %s", info->id, type, vstring_str(buf));
239 	if (type == *expected)
240 	    break;
241 	if (type == REC_TYPE_FROM) {
242 	    if (info->sender == 0)
243 		info->sender = mystrdup(vstring_str(buf));
244 	    /* Compatibility with Postfix < 2.3. */
245 	    if (time_seen == 0)
246 		rec_fprintf(cleanup, REC_TYPE_TIME, "%ld",
247 			    (long) info->st.st_mtime);
248 	}
249 	if (type == REC_TYPE_TIME)
250 	    time_seen = 1;
251 
252 	/*
253 	 * XXX Workaround: REC_TYPE_FILT (used in envelopes) == REC_TYPE_CONT
254 	 * (used in message content).
255 	 *
256 	 * As documented in postsuper(1), ignore content filter record.
257 	 */
258 	if (*expected != REC_TYPE_CONTENT[0]) {
259 	    if (type == REC_TYPE_FILT)
260 		/* Discard FILTER record after "postsuper -r". */
261 		continue;
262 	    if (type == REC_TYPE_RDR)
263 		/* Discard REDIRECT record after "postsuper -r". */
264 		continue;
265 	}
266 	if (*expected == REC_TYPE_EXTRACT[0]) {
267 	    if (type == REC_TYPE_RRTO)
268 		/* Discard return-receipt record after "postsuper -r". */
269 		continue;
270 	    if (type == REC_TYPE_ERTO)
271 		/* Discard errors-to record after "postsuper -r". */
272 		continue;
273 	    if (type == REC_TYPE_ATTR) {
274 		saved_attr = mystrdup(vstring_str(buf));
275 		skip_attr = (split_nameval(saved_attr,
276 					   &attr_name, &attr_value) == 0
277 			     && rec_attr_map(attr_name) == 0);
278 		myfree(saved_attr);
279 		/* Discard other/header/body action after "postsuper -r". */
280 		if (skip_attr)
281 		    continue;
282 	    }
283 	}
284 
285 	/*
286 	 * XXX Force an empty record when the queue file content begins with
287 	 * whitespace, so that it won't be considered as being part of our
288 	 * own Received: header. What an ugly Kluge.
289 	 */
290 	if (check_first
291 	    && (type == REC_TYPE_NORM || type == REC_TYPE_CONT)) {
292 	    check_first = 0;
293 	    if (VSTRING_LEN(buf) > 0 && IS_SPACE_TAB(vstring_str(buf)[0]))
294 		rec_put(cleanup, REC_TYPE_NORM, "", 0);
295 	}
296 	if ((REC_PUT_BUF(cleanup, type, buf)) < 0)
297 	    return (cleanup_service_error(info, CLEANUP_STAT_WRITE));
298     }
299     return (0);
300 }
301 
302 /* pickup_copy - copy message to cleanup service */
303 
304 static int pickup_copy(VSTREAM *qfile, VSTREAM *cleanup,
305 		               PICKUP_INFO *info, VSTRING *buf)
306 {
307     time_t  now = time((time_t *) 0);
308     int     status;
309     char   *name;
310 
311     /*
312      * Protect against time-warped time stamps. Warn about mail that has been
313      * queued for an excessive amount of time. Allow for some time drift with
314      * network clients that mount the maildrop remotely - especially clients
315      * that can't get their daylight savings offsets right.
316      */
317 #define DAY_SECONDS 86400
318 #define HOUR_SECONDS 3600
319 
320     if (info->st.st_mtime > now + 2 * HOUR_SECONDS) {
321 	msg_warn("%s: message dated %ld seconds into the future",
322 		 info->id, (long) (info->st.st_mtime - now));
323 	info->st.st_mtime = now;
324     } else if (info->st.st_mtime < now - DAY_SECONDS) {
325 	msg_warn("%s: message has been queued for %d days",
326 		 info->id, (int) ((now - info->st.st_mtime) / DAY_SECONDS));
327     }
328 
329     /*
330      * Add content inspection transport. See also postsuper(1).
331      */
332     if (*var_filter_xport)
333 	rec_fprintf(cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
334 
335     /*
336      * Copy the message envelope segment. Allow only those records that we
337      * expect to see in the envelope section. The envelope segment must
338      * contain an envelope sender address.
339      */
340     if ((status = copy_segment(qfile, cleanup, info, buf, REC_TYPE_ENVELOPE)) != 0)
341 	return (status);
342     if (info->sender == 0) {
343 	msg_warn("%s: uid=%ld: no envelope sender",
344 		 info->id, (long) info->st.st_uid);
345 	return (REMOVE_MESSAGE_FILE);
346     }
347 
348     /*
349      * For messages belonging to $mail_owner also log the maildrop queue id.
350      * This supports message tracking for mail requeued via "postsuper -r".
351      */
352 #define MAIL_IS_REQUEUED(info) \
353     ((info)->st.st_uid == var_owner_uid && ((info)->st.st_mode & S_IROTH) == 0)
354 
355     if (MAIL_IS_REQUEUED(info)) {
356 	msg_info("%s: uid=%d from=<%s> orig_id=%s", info->id,
357 		 (int) info->st.st_uid, info->sender,
358 		 ((name = strrchr(info->path, '/')) != 0 ?
359 		  name + 1 : info->path));
360     } else {
361 	msg_info("%s: uid=%d from=<%s>", info->id,
362 		 (int) info->st.st_uid, info->sender);
363     }
364 
365     /*
366      * Message content segment. Send a dummy message length. Prepend a
367      * Received: header to the message contents. For tracing purposes,
368      * include the message file ownership, without revealing the login name.
369      */
370     rec_fputs(cleanup, REC_TYPE_MESG, "");
371     rec_fprintf(cleanup, REC_TYPE_NORM, "Received: by %s (%s, from userid %ld)",
372 		var_myhostname, var_mail_name, (long) info->st.st_uid);
373     rec_fprintf(cleanup, REC_TYPE_NORM, "\tid %s; %s", info->id,
374 		mail_date(info->st.st_mtime));
375 
376     /*
377      * Copy the message content segment. Allow only those records that we
378      * expect to see in the message content section.
379      */
380     if ((status = copy_segment(qfile, cleanup, info, buf, REC_TYPE_CONTENT)) != 0)
381 	return (status);
382 
383     /*
384      * Send the segment with information extracted from message headers.
385      * Permit a non-empty extracted segment, so that list manager software
386      * can to output recipients after the message, and so that sysadmins can
387      * re-inject messages after a change of configuration.
388      */
389     rec_fputs(cleanup, REC_TYPE_XTRA, "");
390     if ((status = copy_segment(qfile, cleanup, info, buf, REC_TYPE_EXTRACT)) != 0)
391 	return (status);
392 
393     /*
394      * There are no errors. Send the end-of-data marker, and get the cleanup
395      * service completion status. XXX Since the pickup service is unable to
396      * bounce, the cleanup service can report only soft errors here.
397      */
398     rec_fputs(cleanup, REC_TYPE_END, "");
399     if (attr_scan(cleanup, ATTR_FLAG_MISSING,
400 		  ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
401 		  ATTR_TYPE_STR, MAIL_ATTR_WHY, buf,
402 		  ATTR_TYPE_END) != 2)
403 	return (cleanup_service_error(info, CLEANUP_STAT_WRITE));
404 
405     /*
406      * Depending on the cleanup service completion status, delete the message
407      * file, or try again later. Bounces are dealt with by the cleanup
408      * service itself. The master process wakes up the cleanup service every
409      * now and then.
410      */
411     if (status) {
412 	return (cleanup_service_error_reason(info, status, vstring_str(buf)));
413     } else {
414 	return (REMOVE_MESSAGE_FILE);
415     }
416 }
417 
418 /* pickup_file - initialize for file copy and cleanup */
419 
420 static int pickup_file(PICKUP_INFO *info)
421 {
422     VSTRING *buf = vstring_alloc(100);
423     int     status;
424     VSTREAM *qfile;
425     VSTREAM *cleanup;
426     int     cleanup_flags;
427 
428     /*
429      * Open the submitted file. If we cannot open it, and we're not having a
430      * file descriptor leak problem, delete the submitted file, so that we
431      * won't keep complaining about the same file again and again. XXX
432      * Perhaps we should save "bad" files elsewhere for further inspection.
433      * XXX How can we delete a file when open() fails with ENOENT?
434      */
435     qfile = safe_open(info->path, O_RDONLY | O_NONBLOCK, 0,
436 		      (struct stat *) 0, -1, -1, buf);
437     if (qfile == 0) {
438 	if (errno != ENOENT)
439 	    msg_warn("open input file %s: %s", info->path, vstring_str(buf));
440 	vstring_free(buf);
441 	if (errno == EACCES)
442 	    msg_warn("if this file was created by Postfix < 1.1, then you may have to chmod a+r %s/%s",
443 		     var_queue_dir, info->path);
444 	return (errno == EACCES ? KEEP_MESSAGE_FILE : REMOVE_MESSAGE_FILE);
445     }
446 
447     /*
448      * Contact the cleanup service and read the queue ID that it has
449      * allocated. In case of trouble, request that the cleanup service
450      * bounces its copy of the message. because the original input file is
451      * not readable by the bounce service.
452      *
453      * If mail is re-injected with "postsuper -r", disable Milter applications.
454      * If they were run before the mail was queued then there is no need to
455      * run them again. Moreover, the queue file does not contain enough
456      * information to reproduce the exact same SMTP events and Sendmail
457      * macros that Milters received when the mail originally arrived in
458      * Postfix.
459      *
460      * The actual message copying code is in a separate routine, so that it is
461      * easier to implement the many possible error exits without forgetting
462      * to close files, or to release memory.
463      */
464     cleanup_flags =
465 	input_transp_cleanup(CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_MASK_EXTERNAL,
466 			     pickup_input_transp_mask);
467     /* As documented in postsuper(1). */
468     if (MAIL_IS_REQUEUED(info))
469 	cleanup_flags &= ~CLEANUP_FLAG_MILTER;
470 
471     cleanup = mail_connect_wait(MAIL_CLASS_PUBLIC, var_cleanup_service);
472     if (attr_scan(cleanup, ATTR_FLAG_STRICT,
473 		  ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, buf,
474 		  ATTR_TYPE_END) != 1
475 	|| attr_print(cleanup, ATTR_FLAG_NONE,
476 		      ATTR_TYPE_INT, MAIL_ATTR_FLAGS, cleanup_flags,
477 		      ATTR_TYPE_END) != 0) {
478 	status = KEEP_MESSAGE_FILE;
479     } else {
480 	info->id = mystrdup(vstring_str(buf));
481 	status = pickup_copy(qfile, cleanup, info, buf);
482     }
483     vstream_fclose(qfile);
484     vstream_fclose(cleanup);
485     vstring_free(buf);
486     return (status);
487 }
488 
489 /* pickup_init - init info structure */
490 
491 static void pickup_init(PICKUP_INFO *info)
492 {
493     info->id = 0;
494     info->path = 0;
495     info->sender = 0;
496 }
497 
498 /* pickup_free - wipe info structure */
499 
500 static void pickup_free(PICKUP_INFO *info)
501 {
502 #define SAFE_FREE(x) { if (x) myfree(x); }
503 
504     SAFE_FREE(info->id);
505     SAFE_FREE(info->path);
506     SAFE_FREE(info->sender);
507 }
508 
509 /* pickup_service - service client */
510 
511 static void pickup_service(char *unused_buf, int unused_len,
512 			           char *unused_service, char **argv)
513 {
514     SCAN_DIR *scan;
515     char   *queue_name;
516     PICKUP_INFO info;
517     const char *path;
518     char   *id;
519     int     file_count;
520 
521     /*
522      * Sanity check. This service takes no command-line arguments.
523      */
524     if (argv[0])
525 	msg_fatal("unexpected command-line argument: %s", argv[0]);
526 
527     /*
528      * Skip over things that we don't want to open, such as files that are
529      * still being written, or garbage. Leave it up to the sysadmin to remove
530      * garbage. Keep scanning the queue directory until we stop removing
531      * files from it.
532      *
533      * When we find a file, stroke the watchdog so that it will not bark while
534      * some application is keeping us busy by injecting lots of mail into the
535      * maildrop directory.
536      */
537     queue_name = MAIL_QUEUE_MAILDROP;		/* XXX should be a list */
538     do {
539 	file_count = 0;
540 	scan = scan_dir_open(queue_name);
541 	while ((id = scan_dir_next(scan)) != 0) {
542 	    if (mail_open_ok(queue_name, id, &info.st, &path) == MAIL_OPEN_YES) {
543 		pickup_init(&info);
544 		info.path = mystrdup(path);
545 		watchdog_pat();
546 		if (pickup_file(&info) == REMOVE_MESSAGE_FILE) {
547 		    if (REMOVE(info.path))
548 			msg_warn("remove %s: %m", info.path);
549 		    else
550 			file_count++;
551 		}
552 		pickup_free(&info);
553 	    }
554 	}
555 	scan_dir_close(scan);
556     } while (file_count);
557 }
558 
559 /* post_jail_init - drop privileges */
560 
561 static void post_jail_init(char *unused_name, char **unused_argv)
562 {
563 
564     /*
565      * In case master.cf was not updated for unprivileged service.
566      */
567     if (getuid() != var_owner_uid)
568 	set_ugid(var_owner_uid, var_owner_gid);
569 
570     /*
571      * Initialize the receive transparency options: do we want unknown
572      * recipient checks, do we want address mapping.
573      */
574     pickup_input_transp_mask =
575 	input_transp_mask(VAR_INPUT_TRANSP, var_input_transp);
576 }
577 
578 MAIL_VERSION_STAMP_DECLARE;
579 
580 /* main - pass control to the multi-threaded server skeleton */
581 
582 int     main(int argc, char **argv)
583 {
584     static const CONFIG_STR_TABLE str_table[] = {
585 	VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
586 	VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0,
587 	0,
588     };
589 
590     /*
591      * Fingerprint executables and core dumps.
592      */
593     MAIL_VERSION_STAMP_ALLOCATE;
594 
595     /*
596      * Use the multi-threaded skeleton, because no-one else should be
597      * monitoring our service socket while this process runs.
598      *
599      * XXX The default watchdog timeout for trigger servers is 1000s, while the
600      * cleanup server watchdog timeout is $daemon_timeout (i.e. several
601      * hours). We override the default 1000s timeout to avoid problems with
602      * slow mail submission. The real problem is of course that the
603      * single-threaded pickup server is not a good solution for mail
604      * submissions.
605      */
606     trigger_server_main(argc, argv, pickup_service,
607 			MAIL_SERVER_STR_TABLE, str_table,
608 			MAIL_SERVER_POST_INIT, post_jail_init,
609 			MAIL_SERVER_SOLITARY,
610 			MAIL_SERVER_WATCHDOG, &var_daemon_timeout,
611 			0);
612 }
613