Пример #1
0
static void qmgr_active_corrupt(const char *queue_id)
{
    const char *myname = "qmgr_active_corrupt";

    if (mail_queue_rename(queue_id, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_CORRUPT)) {
	if (errno != ENOENT)
	    msg_fatal("%s: save corrupt file queue %s id %s: %m",
		      myname, MAIL_QUEUE_ACTIVE, queue_id);
    } else {
	msg_warn("saving corrupt file \"%s\" from queue \"%s\" to queue \"%s\"",
		 queue_id, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_CORRUPT);
    }
}
Пример #2
0
void    qmgr_move(const char *src_queue, const char *dst_queue,
		          time_t time_stamp)
{
    const char *myname = "qmgr_move";
    SCAN_DIR *queue_dir;
    char   *queue_id;
    struct utimbuf tbuf;
    const char *path;

    if (strcmp(src_queue, dst_queue) == 0)
	msg_panic("%s: source queue %s is destination", myname, src_queue);
    if (msg_verbose)
	msg_info("start move queue %s -> %s", src_queue, dst_queue);

    queue_dir = scan_dir_open(src_queue);
    while ((queue_id = mail_scan_dir_next(queue_dir)) != 0) {
	if (mail_queue_id_ok(queue_id)) {
	    if (time_stamp > 0) {
		tbuf.actime = tbuf.modtime = time_stamp;
		path = mail_queue_path((VSTRING *) 0, src_queue, queue_id);
		if (utime(path, &tbuf) < 0) {
		    if (errno != ENOENT)
			msg_fatal("%s: update %s time stamps: %m", myname, path);
		    msg_warn("%s: update %s time stamps: %m", myname, path);
		    continue;
		}
	    }
	    if (mail_queue_rename(queue_id, src_queue, dst_queue)) {
		if (errno != ENOENT)
		    msg_fatal("%s: rename %s from %s to %s: %m",
			      myname, queue_id, src_queue, dst_queue);
		msg_warn("%s: rename %s from %s to %s: %m",
			 myname, queue_id, src_queue, dst_queue);
		continue;
	    }
	    if (msg_verbose)
		msg_info("%s: moved %s from %s to %s",
			 myname, queue_id, src_queue, dst_queue);
	} else {
	    msg_warn("%s: ignored: queue %s id %s",
		     myname, src_queue, queue_id);
	}
    }
    scan_dir_close(queue_dir);

    if (msg_verbose)
	msg_info("end move queue %s -> %s", src_queue, dst_queue);
}
Пример #3
0
static void qmgr_active_defer(const char *queue_name, const char *queue_id,
			              const char *dest_queue, int delay)
{
    const char *myname = "qmgr_active_defer";
    const char *path;
    struct utimbuf tbuf;

    if (msg_verbose)
	msg_info("wakeup %s after %ld secs", queue_id, (long) delay);

    tbuf.actime = tbuf.modtime = event_time() + delay;
    path = mail_queue_path((VSTRING *) 0, queue_name, queue_id);
    if (utime(path, &tbuf) < 0 && errno != ENOENT)
	msg_fatal("%s: update %s time stamps: %m", myname, path);
    if (mail_queue_rename(queue_id, queue_name, dest_queue)) {
	if (errno != ENOENT)
	    msg_fatal("%s: rename %s from %s to %s: %m", myname,
		      queue_id, queue_name, dest_queue);
	msg_warn("%s: rename %s from %s to %s: %m", myname,
		 queue_id, queue_name, dest_queue);
    } else if (msg_verbose) {
	msg_info("%s: defer %s", myname, queue_id);
    }
}
Пример #4
0
int     qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id)
{
    const char *myname = "qmgr_active_feed";
    QMGR_MESSAGE *message;
    struct stat st;
    const char *path;

    if (strcmp(scan_info->queue, MAIL_QUEUE_ACTIVE) == 0)
	msg_panic("%s: bad queue %s", myname, scan_info->queue);
    if (msg_verbose)
	msg_info("%s: queue %s", myname, scan_info->queue);

    /*
     * Make sure this is something we are willing to open.
     */
    if (mail_open_ok(scan_info->queue, queue_id, &st, &path) == MAIL_OPEN_NO)
	return (0);

    if (msg_verbose)
	msg_info("%s: %s", myname, path);

    /*
     * Skip files that have time stamps into the future. They need to cool
     * down. Incoming and deferred files can have future time stamps.
     */
    if ((scan_info->flags & QMGR_SCAN_ALL) == 0
	&& st.st_mtime > time((time_t *) 0) + 1) {
	if (msg_verbose)
	    msg_info("%s: skip %s (%ld seconds)", myname, queue_id,
		     (long) (st.st_mtime - event_time()));
	return (0);
    }

    /*
     * Move the message to the active queue. File access errors are fatal.
     */
    if (mail_queue_rename(queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE)) {
	if (errno != ENOENT)
	    msg_fatal("%s: %s: rename from %s to %s: %m", myname,
		      queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE);
	msg_warn("%s: %s: rename from %s to %s: %m", myname,
		 queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE);
	return (0);
    }

    /*
     * Extract envelope information: sender and recipients. At this point,
     * mail addresses have been processed by the cleanup service so they
     * should be in canonical form. Generate requests to deliver this
     * message.
     * 
     * Throwing away queue files seems bad, especially when they made it this
     * far into the mail system. Therefore we save bad files to a separate
     * directory for further inspection.
     * 
     * After queue manager restart it is possible that a queue file is still
     * being delivered. In that case (the file is locked), defer delivery by
     * a minimal amount of time.
     */
#define QMGR_FLUSH_AFTER	(QMGR_FLUSH_EACH | QMGR_FLUSH_DFXP)

    if ((message = qmgr_message_alloc(MAIL_QUEUE_ACTIVE, queue_id,
				 (st.st_mode & MAIL_QUEUE_STAT_UNTHROTTLE) ?
				      scan_info->flags | QMGR_FLUSH_AFTER :
				      scan_info->flags,
				 (st.st_mode & MAIL_QUEUE_STAT_UNTHROTTLE) ?
				  st.st_mode & ~MAIL_QUEUE_STAT_UNTHROTTLE :
				      0)) == 0) {
	qmgr_active_corrupt(queue_id);
	return (0);
    } else if (message == QMGR_MESSAGE_LOCKED) {
	qmgr_active_defer(MAIL_QUEUE_ACTIVE, queue_id, MAIL_QUEUE_INCOMING, 60);
	return (0);
    } else {

	/*
	 * Special case if all recipients were already delivered. Send any
	 * bounces and clean up.
	 */
	if (message->refcount == 0)
	    qmgr_active_done(message);
	return (1);
    }
}
Пример #5
0
static int flush_one_file(const char *queue_id, VSTRING *queue_file,
			          struct utimbuf * tbuf, int how)
{
    const char *myname = "flush_one_file";
    const char *queue_name;
    const char *path;

    /*
     * Some other instance of this program may flush some logfile and may
     * just have moved this queue file to the incoming queue.
     */
    for (queue_name = MAIL_QUEUE_DEFERRED; /* see below */ ;
	 queue_name = MAIL_QUEUE_INCOMING) {
	path = mail_queue_path(queue_file, queue_name, queue_id);
	if (utime(path, tbuf) == 0)
	    break;
	if (errno != ENOENT)
	    msg_warn("%s: update %s time stamps: %m", myname, path);
	if (STREQ(queue_name, MAIL_QUEUE_INCOMING))
	    return (0);
    }

    /*
     * With the UNTHROTTLE_AFTER strategy, we leave it up to the queue
     * manager to unthrottle transports and queues as it reads recipients
     * from a queue file. We request this unthrottle operation by setting the
     * group read permission bit.
     * 
     * Note: we must avoid using chmod(). It is not only slower than fchmod()
     * but it is also less secure. With chmod(), an attacker could repeatedly
     * send requests to the flush server and trick it into changing
     * permissions of non-queue files, by exploiting a race condition.
     * 
     * We use safe_open() because we don't validate the file content before
     * modifying the file status.
     */
    if (how & UNTHROTTLE_AFTER) {
	VSTRING *why;
	struct stat st;
	VSTREAM *fp;

	for (why = vstring_alloc(1); /* see below */ ;
	     queue_name = MAIL_QUEUE_INCOMING,
	     path = mail_queue_path(queue_file, queue_name, queue_id)) {
	    if ((fp = safe_open(path, O_RDWR, 0, &st, -1, -1, why)) != 0)
		break;
	    if (errno != ENOENT)
		msg_warn("%s: open %s: %s", myname, path, STR(why));
	    if (errno != ENOENT || STREQ(queue_name, MAIL_QUEUE_INCOMING)) {
		vstring_free(why);
		return (0);
	    }
	}
	vstring_free(why);
	if ((st.st_mode & MAIL_QUEUE_STAT_READY) != MAIL_QUEUE_STAT_READY) {
	    (void) vstream_fclose(fp);
	    return (0);
	}
	if (fchmod(vstream_fileno(fp), st.st_mode | MAIL_QUEUE_STAT_UNTHROTTLE) < 0)
	    msg_warn("%s: fchmod %s: %m", myname, path);
	(void) vstream_fclose(fp);
    }

    /*
     * Move the file to the incoming queue, if it isn't already there.
     */
    if (STREQ(queue_name, MAIL_QUEUE_INCOMING) == 0
	&& mail_queue_rename(queue_id, queue_name, MAIL_QUEUE_INCOMING) < 0
	&& errno != ENOENT)
	msg_warn("%s: rename from %s to %s: %m",
		 path, queue_name, MAIL_QUEUE_INCOMING);

    /*
     * If we got here, we achieved something, so let's claim succes.
     */
    return (1);
}