コード例 #1
0
static int
fsqueue_envelope_load(enum queue_kind qkind, struct envelope *ep)
{
	char pathname[MAXPATHLEN];
	FILE *fp;
	int  ret;

	if (! bsnprintf(pathname, sizeof(pathname), "%s/%03x/%08x%s/%016llx",
		fsqueue_getpath(qkind),
		evpid_to_msgid(ep->id) & 0xfff,
		evpid_to_msgid(ep->id),
		PATH_ENVELOPES, ep->id))
		fatalx("fsqueue_envelope_load: snprintf");

	fp = fopen(pathname, "r");
	if (fp == NULL) {
		if (errno == ENOENT || errno == ENFILE)
			return 0;
		fatal("fsqueue_envelope_load: fopen");
	}
	ret = fsqueue_load_envelope_ascii(fp, ep);

	fclose(fp);

	return ret;
}
コード例 #2
0
static int
fsqueue_envelope_delete(enum queue_kind qkind, struct envelope *ep)
{
	char pathname[MAXPATHLEN];

	if (! bsnprintf(pathname, sizeof(pathname), "%s/%03x/%08x%s/%016llx",
		fsqueue_getpath(qkind),
		evpid_to_msgid(ep->id) & 0xfff,
		evpid_to_msgid(ep->id),
		PATH_ENVELOPES,
		ep->id))
		fatal("fsqueue_envelope_delete: snprintf");

	if (unlink(pathname) == -1) {
		log_debug("######: %s [errno: %d]", pathname, errno);
		fatal("fsqueue_envelope_delete: unlink");
	}

	if (! bsnprintf(pathname, sizeof(pathname), "%s/%03x/%08x%s", PATH_QUEUE,
		evpid_to_msgid(ep->id) & 0xfff,
		evpid_to_msgid(ep->id), PATH_ENVELOPES))
		fatal("fsqueue_envelope_delete: snprintf");

	if (rmdir(pathname) != -1)
		fsqueue_message_delete(qkind, evpid_to_msgid(ep->id));

	return 1;
}
コード例 #3
0
static int
fsqueue_envelope_update(enum queue_kind qkind, struct envelope *ep)
{
	char temp[MAXPATHLEN];
	char dest[MAXPATHLEN];
	FILE *fp;
	u_int64_t batch_id;

	batch_id = ep->batch_id;
	ep->batch_id = 0;

	if (! bsnprintf(temp, sizeof(temp), "%s/envelope.tmp", PATH_QUEUE))
		fatalx("fsqueue_envelope_update");

	if (! bsnprintf(dest, sizeof(dest), "%s/%03x/%08x%s/%016llx",
		fsqueue_getpath(qkind),
		evpid_to_msgid(ep->id) & 0xfff,
		evpid_to_msgid(ep->id),
		PATH_ENVELOPES, ep->id))
		fatal("fsqueue_envelope_update: snprintf");

	fp = fopen(temp, "w");
	if (fp == NULL) {
		if (errno == ENOSPC || errno == ENFILE)
			goto tempfail;
		fatal("fsqueue_envelope_update: open");
	}
	if (! fsqueue_dump_envelope_ascii(fp, ep)) {
		if (errno == ENOSPC)
			goto tempfail;
		fatal("fsqueue_dump_envelope_ascii: fwrite");
	}
	if (! safe_fclose(fp))
		goto tempfail;

	if (rename(temp, dest) == -1) {
		if (errno == ENOSPC)
			goto tempfail;
		fatal("fsqueue_envelope_update: rename");
	}

	ep->batch_id = batch_id;
	return 1;

tempfail:
	if (unlink(temp) == -1)
		fatal("fsqueue_envelope_update: unlink");
	if (fp)
		fclose(fp);

	ep->batch_id = batch_id;
	return 0;
}
コード例 #4
0
ファイル: queue_backend.c プロジェクト: 0xkag/OpenSMTPD
int
queue_envelope_walk(struct envelope *ep)
{
	const char	*e;
	uint64_t	 evpid;
	char		 evpbuf[sizeof(struct envelope)];
	int		 r;

	profile_enter("queue_envelope_walk");
	r = handler_envelope_walk(&evpid, evpbuf, sizeof evpbuf);
	profile_leave();

	log_trace(TRACE_QUEUE,
	    "queue-backend: queue_envelope_walk() -> %d (%016"PRIx64")",
	    r, evpid);

	if (r == -1)
		return (r);

	if (r && queue_envelope_load_buffer(ep, evpbuf, (size_t)r)) {
		if ((e = envelope_validate(ep)) == NULL) {
			ep->id = evpid;
			if (env->sc_queue_flags & QUEUE_EVPCACHE)
				queue_envelope_cache_add(ep);
			return (1);
		}
		log_debug("debug: invalid envelope %016" PRIx64 ": %s",
		    ep->id, e);
		(void)queue_message_corrupt(evpid_to_msgid(evpid));
	}

	return (0);
}
コード例 #5
0
ファイル: queue_backend.c プロジェクト: Sp1l/OpenSMTPD
int
queue_message_delete(uint32_t msgid)
{
	char	msgpath[PATH_MAX];
	uint64_t evpid;
	void   *iter;
	int	r;

	profile_enter("queue_message_delete");
	r = handler_message_delete(msgid);
	profile_leave();

	/* in case the message is incoming */
	queue_message_path(msgid, msgpath, sizeof(msgpath));
	unlink(msgpath);

	/* remove remaining envelopes from the cache if any (on rollback) */
	evpid = msgid_to_evpid(msgid);
	for (;;) {
		iter = NULL;
		if (!tree_iterfrom(&evpcache_tree, &iter, evpid, &evpid, NULL))
			break;
		if (evpid_to_msgid(evpid) != msgid)
			break;
		queue_envelope_cache_del(evpid);
	}

	log_trace(TRACE_QUEUE,
	    "queue-backend: queue_message_delete(%08"PRIx32") -> %d", msgid, r);

	return (r);
}
コード例 #6
0
ファイル: queue_ram.c プロジェクト: Drustan/OpenSMTPD
static int
queue_ram_envelope_update(uint64_t evpid, const char *buf, size_t len)
{
	struct qr_envelope	*evp;
	struct qr_message	*msg;
	void			*tmp;

	if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
		return (0);

	if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) {
		log_warn("warn: queue-ram: not found");
		return (0);
	}
	tmp = malloc(len);
	if (tmp == NULL) {
		log_warn("warn: queue-ram: malloc");
		return (0);
	}
	memmove(tmp, buf, len);
	free(evp->buf);
	evp->len = len;
	evp->buf = tmp;
	stat_decrement("queue.ram.envelope.size", evp->len);
	stat_increment("queue.ram.envelope.size", len);
	return (1);
}
コード例 #7
0
ファイル: queue_backend.c プロジェクト: 0xkag/OpenSMTPD
int
queue_envelope_create(struct envelope *ep)
{
	int		 r;
	char		 evpbuf[sizeof(struct envelope)];
	size_t		 evplen;
	uint64_t	 evpid;
	uint32_t	 msgid;

	ep->creation = time(NULL);
	evplen = queue_envelope_dump_buffer(ep, evpbuf, sizeof evpbuf);
	if (evplen == 0)
		return (0);

	evpid = ep->id;
	msgid = evpid_to_msgid(evpid);

	profile_enter("queue_envelope_create");
	r = handler_envelope_create(msgid, evpbuf, evplen, &ep->id);
	profile_leave();

	log_trace(TRACE_QUEUE,
	    "queue-backend: queue_envelope_create(%016"PRIx64", %zu) -> %d (%016"PRIx64")",
	    evpid, evplen, r, ep->id);

	if (!r) {
		ep->creation = 0;
		ep->id = 0;
	}

	if (r && env->sc_queue_flags & QUEUE_EVPCACHE)
		queue_envelope_cache_add(ep);

	return (r);
}
コード例 #8
0
ファイル: smtpctl.c プロジェクト: toddfries/OpenSMTPD
static void
show_envelope(const char *s)
{
	char	 buf[MAXPATHLEN];
	uint64_t evpid;

	evpid = strtoevpid(s);
	if (! bsnprintf(buf, sizeof(buf), "%s%s/%02x/%08x%s/%016" PRIx64,
	    PATH_SPOOL,
	    PATH_QUEUE,
	    evpid_to_msgid(evpid) & 0xff,
	    evpid_to_msgid(evpid),
	    PATH_ENVELOPES, evpid))
		errx(1, "unable to retrieve envelope");

	display(buf);
}
コード例 #9
0
ファイル: queue_backend.c プロジェクト: clongeau/opensmtpd
int
queue_envelope_incoming_path(uint64_t evpid, char *buf, size_t len)
{
	return bsnprintf(buf, len, "%s/%08x%s/%016" PRIx64,
	    PATH_INCOMING,
	    evpid_to_msgid(evpid),
	    PATH_ENVELOPES,
	    evpid);
}
コード例 #10
0
ファイル: queue.c プロジェクト: appleorange1/bitrig
static void
queue_bounce(struct envelope *e, struct delivery_bounce *d)
{
	struct envelope	b;

	b = *e;
	b.type = D_BOUNCE;
	b.agent.bounce = *d;
	b.retry = 0;
	b.lasttry = 0;
	b.creation = time(NULL);
	b.expire = 3600 * 24 * 7;

	if (e->dsn_notify & DSN_NEVER)
		return;

	if (b.id == 0)
		log_warnx("warn: queue_bounce: evpid=0");
	if (evpid_to_msgid(b.id) == 0)
		log_warnx("warn: queue_bounce: msgid=0, evpid=%016"PRIx64,
			b.id);
	if (e->type == D_BOUNCE) {
		log_warnx("warn: queue: double bounce!");
	} else if (e->sender.user[0] == '\0') {
		log_warnx("warn: queue: no return path!");
	} else if (!queue_envelope_create(&b)) {
		log_warnx("warn: queue: cannot bounce!");
	} else {
		log_debug("debug: queue: bouncing evp:%016" PRIx64
		    " as evp:%016" PRIx64, e->id, b.id);

		m_create(p_scheduler, IMSG_QUEUE_ENVELOPE_SUBMIT, 0, 0, -1);
		m_add_envelope(p_scheduler, &b);
		m_close(p_scheduler);

		m_create(p_scheduler, IMSG_QUEUE_MESSAGE_COMMIT, 0, 0, -1);
		m_add_msgid(p_scheduler, evpid_to_msgid(b.id));
		m_close(p_scheduler);

		stat_increment("queue.bounce", 1);
	}
}
コード例 #11
0
ファイル: smtp_session.c プロジェクト: clongeau/opensmtpd
void
session_destroy(struct session *s, const char * reason)
{
	uint32_t msgid;

	log_debug("smtp: %p: deleting session: %s", s, reason);

	if (s->s_flags & F_ZOMBIE)
		goto finalize;

	log_debug("session_destroy: s->datafp = %p", s->datafp);
	if (s->datafp != NULL)
		fclose(s->datafp);

	if (s->s_msg.id != 0 && s->s_state != S_DONE) {
		msgid = evpid_to_msgid(s->s_msg.id);
		imsg_compose_event(env->sc_ievs[PROC_QUEUE],
		    IMSG_QUEUE_REMOVE_MESSAGE, 0, 0, -1, &msgid, sizeof(msgid));
	}

	if (s->s_io.ssl) {
		if (s->s_l->flags & F_SMTPS)
			if (s->s_flags & F_SECURE)
				stat_decrement("smtp.smtps", 1);
		if (s->s_l->flags & F_STARTTLS)
			if (s->s_flags & F_SECURE)
				stat_decrement("smtp.tls", 1);
	}

	event_del(&s->s_ev); /* in case something was scheduled */
	io_clear(&s->s_io);
	iobuf_clear(&s->s_iobuf);

	/* resume when session count decreases to 95% */
	stat_decrement("smtp.session", 1);

	/* If the session is waiting for an imsg, do not kill it now, since
	 * the id must still be valid.
	 */
	if (s->s_flags & F_WAITIMSG) {
		s->s_flags = F_ZOMBIE;
		return;
	}

    finalize:

	smtp_destroy(s);

	SPLAY_REMOVE(sessiontree, &env->sc_sessions, s);
	bzero(s, sizeof(*s));
	free(s);
}
コード例 #12
0
ファイル: queue.c プロジェクト: appleorange1/bitrig
static void
queue_timeout(int fd, short event, void *p)
{
	static uint32_t	 msgid = 0;
	struct envelope	 evp;
	struct event	*ev = p;
	struct timeval	 tv;
	int		 r;

	r = queue_envelope_walk(&evp);
	if (r == -1) {
		if (msgid) {
			m_create(p_scheduler, IMSG_QUEUE_MESSAGE_COMMIT,
			    0, 0, -1);
			m_add_msgid(p_scheduler, msgid);
			m_close(p_scheduler);
		}
		log_debug("debug: queue: done loading queue into scheduler");
		return;
	}

	if (r) {
		if (msgid && evpid_to_msgid(evp.id) != msgid) {
			m_create(p_scheduler, IMSG_QUEUE_MESSAGE_COMMIT,
			    0, 0, -1);
			m_add_msgid(p_scheduler, msgid);
			m_close(p_scheduler);
		}
		msgid = evpid_to_msgid(evp.id);
		m_create(p_scheduler, IMSG_QUEUE_ENVELOPE_SUBMIT, 0, 0, -1);
		m_add_envelope(p_scheduler, &evp);
		m_close(p_scheduler);
	}

	tv.tv_sec = 0;
	tv.tv_usec = 10;
	evtimer_add(ev, &tv);
}
コード例 #13
0
ファイル: queue_ram.c プロジェクト: Drustan/OpenSMTPD
static int
queue_ram_envelope_delete(uint64_t evpid)
{
	struct qr_envelope	*evp;
	struct qr_message	*msg;

	if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
		return (0);

	if ((evp = tree_pop(&msg->envelopes, evpid)) == NULL) {
		log_warnx("warn: queue-ram: not found");
		return (0);
	}
	stat_decrement("queue.ram.envelope.size", evp->len);
	free(evp->buf);
	free(evp);
	if (tree_empty(&msg->envelopes)) {
		tree_xpop(&messages, evpid_to_msgid(evpid));
		stat_decrement("queue.ram.message.size", msg->len);
		free(msg->buf);
		free(msg);
	}
	return (1);
}
コード例 #14
0
ファイル: smtpctl.c プロジェクト: toddfries/OpenSMTPD
static void
show_message(const char *s)
{
	char	 buf[MAXPATHLEN];
	uint32_t msgid;

	msgid = evpid_to_msgid(strtoevpid(s));
	if (! bsnprintf(buf, sizeof(buf), "%s%s/%02x/%08x/message",
	    PATH_SPOOL,
	    PATH_QUEUE,
	    msgid & 0xff,
	    msgid))
		errx(1, "unable to retrieve message");

	display(buf);
}
コード例 #15
0
ファイル: queue_backend.c プロジェクト: 0xkag/OpenSMTPD
int
queue_envelope_load(uint64_t evpid, struct envelope *ep)
{
	const char	*e;
	char		 evpbuf[sizeof(struct envelope)];
	size_t		 evplen;
	struct envelope	*cached;

	if ((env->sc_queue_flags & QUEUE_EVPCACHE) &&
	    (cached = tree_get(&evpcache_tree, evpid))) {
		*ep = *cached;
		stat_increment("queue.evpcache.load.hit", 1);
		return (1);
	}

	ep->id = evpid;
	profile_enter("queue_envelope_load");
	evplen = handler_envelope_load(ep->id, evpbuf, sizeof evpbuf);
	profile_leave();

	log_trace(TRACE_QUEUE,
	    "queue-backend: queue_envelope_load(%016"PRIx64") -> %zu",
	    evpid, evplen);

	if (evplen == 0)
		return (0);

	if (queue_envelope_load_buffer(ep, evpbuf, evplen)) {
		if ((e = envelope_validate(ep)) == NULL) {
			ep->id = evpid;
			if (env->sc_queue_flags & QUEUE_EVPCACHE) {
				queue_envelope_cache_add(ep);
				stat_increment("queue.evpcache.load.missed", 1);
			}
			return (1);
		}
		log_debug("debug: invalid envelope %016" PRIx64 ": %s",
		    ep->id, e);
	}

	(void)queue_message_corrupt(evpid_to_msgid(evpid));
	return (0);
}
コード例 #16
0
ファイル: queue_ram.c プロジェクト: Drustan/OpenSMTPD
static int
queue_ram_envelope_load(uint64_t evpid, char *buf, size_t len)
{
	struct qr_envelope	*evp;
	struct qr_message	*msg;

	if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
		return (0);

	if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) {
		log_warn("warn: queue-ram: not found");
		return (0);
	}
	if (len < evp->len) {
		log_warnx("warn: queue-ram: buffer too small");
		return (0);
	}
	memmove(buf, evp->buf, evp->len);
	return (evp->len);
}
コード例 #17
0
ファイル: queue_backend.c プロジェクト: 0xkag/OpenSMTPD
int
queue_message_walk(struct envelope *ep, uint32_t msgid, int *done, void **data)
{
	char		 evpbuf[sizeof(struct envelope)];
	uint64_t	 evpid;
	int		 r;
	const char	*e;

	profile_enter("queue_message_walk");
	r = handler_message_walk(&evpid, evpbuf, sizeof evpbuf,
	    msgid, done, data);
	profile_leave();

	log_trace(TRACE_QUEUE,
	    "queue-backend: queue_message_walk() -> %d (%016"PRIx64")",
	    r, evpid);

	if (r == -1)
		return (r);

	if (r && queue_envelope_load_buffer(ep, evpbuf, (size_t)r)) {
		if ((e = envelope_validate(ep)) == NULL) {
			ep->id = evpid;
			/*
			 * do not cache the envelope here, while discovering
			 * envelopes one could re-run discover on already
			 * scheduled envelopes which leads to triggering of 
			 * strict checks in caching. Envelopes could anyway
			 * be loaded from backend if it isn't cached.
			 */
			return (1);
		}
		log_debug("debug: invalid envelope %016" PRIx64 ": %s",
		    ep->id, e);
		(void)queue_message_corrupt(evpid_to_msgid(evpid));
	}

	return (0);
}
コード例 #18
0
ファイル: queue_proc.c プロジェクト: nmandery/deb-opensmtpd
static int
queue_proc_envelope_create(uint32_t msgid, const char *buf, size_t len,
    uint64_t *evpid)
{
	struct ibuf	*b;
	int		 r;

	msgid = evpid_to_msgid(*evpid);
	b = imsg_create(&ibuf, PROC_QUEUE_ENVELOPE_CREATE, 0, 0,
	    sizeof(msgid) + len);
	if (imsg_add(b, &msgid, sizeof(msgid)) == -1 ||
	    imsg_add(b, buf, len) == -1)
		return (0);
	imsg_close(&ibuf, b);

	queue_proc_call();
	queue_proc_read(&r, sizeof(r));
	if (r == 1)
		queue_proc_read(evpid, sizeof(*evpid));
	queue_proc_end();

	return (r);
}
コード例 #19
0
ファイル: smtp_session.c プロジェクト: clongeau/opensmtpd
void
session_pickup(struct session *s, struct submit_status *ss)
{
	void	*ssl;

	s->s_flags &= ~F_WAITIMSG;

	if ((ss != NULL && ss->code == 421) ||
	    (s->s_dstatus & DS_TEMPFAILURE)) {
		stat_increment("smtp.tempfail", 1);
		session_respond(s, "421 Service temporarily unavailable");
		session_enter_state(s, S_QUIT);
		io_reload(&s->s_io);
		return;
	}

	switch (s->s_state) {

	case S_CONNECTED:
		session_enter_state(s, S_INIT);
		s->s_msg.session_id = s->s_id;
		s->s_msg.ss = s->s_ss;
		session_imsg(s, PROC_MFA, IMSG_MFA_CONNECT, 0, 0, -1,
			     &s->s_msg, sizeof(s->s_msg));
		break;

	case S_INIT:
		if (ss->code != 250) {
			session_destroy(s, "rejected by filter");
			return;
		}

		if (s->s_l->flags & F_SMTPS) {
			ssl = ssl_smtp_init(s->s_l->ssl_ctx);
			io_set_read(&s->s_io);
			io_start_tls(&s->s_io, ssl);
			return;
		}

		session_respond(s, SMTPD_BANNER, env->sc_hostname);
		session_enter_state(s, S_GREETED);
		break;

	case S_AUTH_FINALIZE:
		if (s->s_flags & F_AUTHENTICATED)
			session_respond(s, "235 Authentication succeeded");
		else
			session_respond(s, "535 Authentication failed");
		session_enter_state(s, S_HELO);
		break;

	case S_RSET:
		session_respond(s, "250 2.0.0 Reset state");
		session_enter_state(s, S_HELO);
		break;

	case S_HELO:
		if (ss->code != 250) {
			session_enter_state(s, S_GREETED);
			session_respond(s, "%d Helo rejected", ss->code);
			break;
		}

		session_respond(s, "250%c%s Hello %s [%s], pleased to meet you",
		    (s->s_flags & F_EHLO) ? '-' : ' ',
		    env->sc_hostname, s->s_msg.helo, ss_to_text(&s->s_ss));

		if (s->s_flags & F_EHLO) {
			/* unconditionnal extensions go first */
			session_respond(s, "250-8BITMIME");
			session_respond(s, "250-ENHANCEDSTATUSCODES");

			/* XXX - we also want to support reading SIZE from MAIL parameters */
			session_respond(s, "250-SIZE %zu", env->sc_maxsize);

			if (ADVERTISE_TLS(s))
				session_respond(s, "250-STARTTLS");

			if (ADVERTISE_AUTH(s))
				session_respond(s, "250-AUTH PLAIN LOGIN");
			session_respond(s, "250 HELP");
		}
		break;

	case S_MAIL_MFA:
		if (ss->code != 250) {
			session_enter_state(s, S_HELO);
			session_respond(s, "%d Sender rejected", ss->code);
			break;
		}

		session_enter_state(s, S_MAIL_QUEUE);
		s->s_msg.sender = ss->u.maddr;

		session_imsg(s, PROC_QUEUE, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1,
		    &s->s_msg, sizeof(s->s_msg));
		break;

	case S_MAIL_QUEUE:
		session_enter_state(s, S_MAIL);
		session_respond(s, "%d 2.1.0 Sender ok", ss->code);
		break;

	case S_RCPT_MFA:
		/* recipient was not accepted */
		if (ss->code != 250) {
			/* We do not have a valid recipient, downgrade state */
			if (s->rcptcount == 0)
				session_enter_state(s, S_MAIL);
			else
				session_enter_state(s, S_RCPT);
			session_respond(s, "%d 5.0.0 Recipient rejected: %s@%s", ss->code,
			    s->s_msg.rcpt.user,
			    s->s_msg.rcpt.domain);
			break;
		}

		session_enter_state(s, S_RCPT);
		s->rcptcount++;
		s->s_msg.dest = ss->u.maddr;
		session_respond(s, "%d 2.0.0 Recipient ok", ss->code);
		break;

	case S_DATA_QUEUE:
		session_enter_state(s, S_DATACONTENT);
		session_respond(s, "354 Enter mail, end with \".\" on a line by"
		    " itself");

		fprintf(s->datafp, "Received: from %s (%s [%s])\n",
		    s->s_msg.helo, s->s_hostname, ss_to_text(&s->s_ss));
		fprintf(s->datafp, "\tby %s (OpenSMTPD) with %sSMTP id %08x",
		    env->sc_hostname, s->s_flags & F_EHLO ? "E" : "",
		    evpid_to_msgid(s->s_msg.id));

		if (s->s_flags & F_SECURE) {
			fprintf(s->datafp, "\n\t(version=%s cipher=%s bits=%d)",
			    SSL_get_cipher_version(s->s_io.ssl),
			    SSL_get_cipher_name(s->s_io.ssl),
			    SSL_get_cipher_bits(s->s_io.ssl, NULL));
		}
		if (s->rcptcount == 1)
			fprintf(s->datafp, "\n\tfor <%s@%s>; ",
			    s->s_msg.rcpt.user,
			    s->s_msg.rcpt.domain);
		else
			fprintf(s->datafp, ";\n\t");

		fprintf(s->datafp, "%s\n", time_to_text(time(NULL)));
		break;

	case S_DATACONTENT:
		if (ss->code != 250)
			s->s_dstatus |= DS_PERMFAILURE;
		session_read_data(s, ss->u.dataline);
		break;

	case S_DONE:
		session_respond(s, "250 2.0.0 %08x Message accepted for delivery",
		    evpid_to_msgid(s->s_msg.id));
		log_info("%08x: from=<%s%s%s>, size=%ld, nrcpts=%zu, proto=%s, "
		    "relay=%s [%s]",
		    evpid_to_msgid(s->s_msg.id),
		    s->s_msg.sender.user,
		    s->s_msg.sender.user[0] == '\0' ? "" : "@",
		    s->s_msg.sender.domain,
		    s->s_datalen,
		    s->rcptcount,
		    s->s_flags & F_EHLO ? "ESMTP" : "SMTP",
		    s->s_hostname,
		    ss_to_text(&s->s_ss));

		session_enter_state(s, S_HELO);
		s->s_msg.id = 0;
		bzero(&s->s_nresp, sizeof(s->s_nresp));
		break;

	default:
		fatal("session_pickup: unknown state");
	}

	io_reload(&s->s_io);
}
コード例 #20
0
ファイル: queue.c プロジェクト: appleorange1/bitrig
static void
queue_imsg(struct mproc *p, struct imsg *imsg)
{
	struct delivery_bounce	 bounce;
	struct bounce_req_msg	*req_bounce;
	struct envelope		 evp;
	struct msg		 m;
	const char		*reason;
	uint64_t		 reqid, evpid, holdq;
	uint32_t		 msgid;
	time_t			 nexttry;
	int			 fd, mta_ext, ret, v, flags, code;

	memset(&bounce, 0, sizeof(struct delivery_bounce));
	if (p->proc == PROC_PONY) {

		switch (imsg->hdr.type) {
		case IMSG_SMTP_MESSAGE_CREATE:
			m_msg(&m, imsg);
			m_get_id(&m, &reqid);
			m_end(&m);

			ret = queue_message_create(&msgid);

			m_create(p, IMSG_SMTP_MESSAGE_CREATE, 0, 0, -1);
			m_add_id(p, reqid);
			if (ret == 0)
				m_add_int(p, 0);
			else {
				m_add_int(p, 1);
				m_add_msgid(p, msgid);
			}
			m_close(p);
			return;

		case IMSG_SMTP_MESSAGE_ROLLBACK:
			m_msg(&m, imsg);
			m_get_msgid(&m, &msgid);
			m_end(&m);

			queue_message_delete(msgid);

			m_create(p_scheduler, IMSG_QUEUE_MESSAGE_ROLLBACK,
			    0, 0, -1);
			m_add_msgid(p_scheduler, msgid);
			m_close(p_scheduler);
			return;

		case IMSG_SMTP_MESSAGE_COMMIT:
			m_msg(&m, imsg);
			m_get_id(&m, &reqid);
			m_get_msgid(&m, &msgid);
			m_end(&m);

			ret = queue_message_commit(msgid);

			m_create(p, IMSG_SMTP_MESSAGE_COMMIT, 0, 0, -1);
			m_add_id(p, reqid);
			m_add_int(p, (ret == 0) ? 0 : 1);
			m_close(p);

			if (ret) {
				m_create(p_scheduler, IMSG_QUEUE_MESSAGE_COMMIT,
				    0, 0, -1);
				m_add_msgid(p_scheduler, msgid);
				m_close(p_scheduler);
			}
			return;

		case IMSG_SMTP_MESSAGE_OPEN:
			m_msg(&m, imsg);
			m_get_id(&m, &reqid);
			m_get_msgid(&m, &msgid);
			m_end(&m);

			fd = queue_message_fd_rw(msgid);

			m_create(p, IMSG_SMTP_MESSAGE_OPEN, 0, 0, fd);
			m_add_id(p, reqid);
			m_add_int(p, (fd == -1) ? 0 : 1);
			m_close(p);
			return;

		case IMSG_QUEUE_SMTP_SESSION:
			bounce_fd(imsg->fd);
			return;
		}
	}

	if (p->proc == PROC_LKA) {
		switch (imsg->hdr.type) {
		case IMSG_LKA_ENVELOPE_SUBMIT:
			m_msg(&m, imsg);
			m_get_id(&m, &reqid);
			m_get_envelope(&m, &evp);
			m_end(&m);
		    
			if (evp.id == 0)
				log_warnx("warn: imsg_queue_submit_envelope: evpid=0");
			if (evpid_to_msgid(evp.id) == 0)
				log_warnx("warn: imsg_queue_submit_envelope: msgid=0, "
				    "evpid=%016"PRIx64, evp.id);
			ret = queue_envelope_create(&evp);
			m_create(p_pony, IMSG_QUEUE_ENVELOPE_SUBMIT, 0, 0, -1);
			m_add_id(p_pony, reqid);
			if (ret == 0)
				m_add_int(p_pony, 0);
			else {
				m_add_int(p_pony, 1);
				m_add_evpid(p_pony, evp.id);
			}
			m_close(p_pony);
			if (ret) {
				m_create(p_scheduler,
				    IMSG_QUEUE_ENVELOPE_SUBMIT, 0, 0, -1);
				m_add_envelope(p_scheduler, &evp);
				m_close(p_scheduler);

			}
			return;

		case IMSG_LKA_ENVELOPE_COMMIT:
			m_msg(&m, imsg);
			m_get_id(&m, &reqid);
			m_end(&m);
			m_create(p_pony, IMSG_QUEUE_ENVELOPE_COMMIT, 0, 0, -1);
			m_add_id(p_pony, reqid);
			m_add_int(p_pony, 1);
			m_close(p_pony);
			return;
		}
	}

	if (p->proc == PROC_SCHEDULER) {
		switch (imsg->hdr.type) {
		case IMSG_SCHED_ENVELOPE_REMOVE:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_end(&m);

			/* already removed by scheduler */
			if (queue_envelope_load(evpid, &evp) == 0)
				return;
			queue_log(&evp, "Remove", "Removed by administrator");
			queue_envelope_delete(evpid);
			return;

		case IMSG_SCHED_ENVELOPE_EXPIRE:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_end(&m);

			/* already removed by scheduler*/
			if (queue_envelope_load(evpid, &evp) == 0)
				return;

			bounce.type = B_ERROR;
			envelope_set_errormsg(&evp, "Envelope expired");
			envelope_set_esc_class(&evp, ESC_STATUS_TEMPFAIL);
			envelope_set_esc_code(&evp, ESC_DELIVERY_TIME_EXPIRED);
			queue_bounce(&evp, &bounce);
			queue_log(&evp, "Expire", "Envelope expired");
			queue_envelope_delete(evpid);
			return;

		case IMSG_SCHED_ENVELOPE_BOUNCE:
			req_bounce = imsg->data;
			evpid = req_bounce->evpid;

			if (queue_envelope_load(evpid, &evp) == 0) {
				log_warnx("queue: bounce: failed to load envelope");
				m_create(p_scheduler, IMSG_QUEUE_ENVELOPE_REMOVE, 0, 0, -1);
				m_add_evpid(p_scheduler, evpid);
				m_add_u32(p_scheduler, 0); /* not in-flight */
				m_close(p_scheduler);
				return;
			}
			queue_bounce(&evp, &req_bounce->bounce);
			evp.lastbounce = req_bounce->timestamp;
			if (!queue_envelope_update(&evp))
				log_warnx("warn: could not update envelope %016"PRIx64, evpid);
			return;

		case IMSG_SCHED_ENVELOPE_DELIVER:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_end(&m);
			if (queue_envelope_load(evpid, &evp) == 0) {
				log_warnx("queue: deliver: failed to load envelope");
				m_create(p_scheduler, IMSG_QUEUE_ENVELOPE_REMOVE, 0, 0, -1);
				m_add_evpid(p_scheduler, evpid);
				m_add_u32(p_scheduler, 1); /* in-flight */
				m_close(p_scheduler);
				return;
			}
			evp.lasttry = time(NULL);
			m_create(p_pony, IMSG_QUEUE_DELIVER, 0, 0, -1);
			m_add_envelope(p_pony, &evp);
			m_close(p_pony);
			return;

		case IMSG_SCHED_ENVELOPE_INJECT:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_end(&m);
			bounce_add(evpid);
			return;

		case IMSG_SCHED_ENVELOPE_TRANSFER:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_end(&m);
			if (queue_envelope_load(evpid, &evp) == 0) {
				log_warnx("queue: failed to load envelope");
				m_create(p_scheduler, IMSG_QUEUE_ENVELOPE_REMOVE, 0, 0, -1);
				m_add_evpid(p_scheduler, evpid);
				m_add_u32(p_scheduler, 1); /* in-flight */
				m_close(p_scheduler);
				return;
			}
			evp.lasttry = time(NULL);
			m_create(p_pony, IMSG_QUEUE_TRANSFER, 0, 0, -1);
			m_add_envelope(p_pony, &evp);
			m_close(p_pony);
			return;

		case IMSG_CTL_LIST_ENVELOPES:
			if (imsg->hdr.len == sizeof imsg->hdr) {
				m_forward(p_control, imsg);
				return;
			}

			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_get_int(&m, &flags);
			m_get_time(&m, &nexttry);
			m_end(&m);

			if (queue_envelope_load(evpid, &evp) == 0)
				return; /* Envelope is gone, drop it */

			/*
			 * XXX consistency: The envelope might already be on
			 * its way back to the scheduler.  We need to detect
			 * this properly and report that state.
			 */
			evp.flags |= flags;
			/* In the past if running or runnable */
			evp.nexttry = nexttry;
			if (flags & EF_INFLIGHT) {
				/*
				 * Not exactly correct but pretty close: The
				 * value is not recorded on the envelope unless
				 * a tempfail occurs.
				 */
				evp.lasttry = nexttry;
			}
			m_compose(p_control, IMSG_CTL_LIST_ENVELOPES,
			    imsg->hdr.peerid, 0, -1, &evp, sizeof evp);
			return;
		}
	}

	if (p->proc == PROC_PONY) {
		switch (imsg->hdr.type) {
		case IMSG_MDA_OPEN_MESSAGE:
		case IMSG_MTA_OPEN_MESSAGE:
			m_msg(&m, imsg);
			m_get_id(&m, &reqid);
			m_get_msgid(&m, &msgid);
			m_end(&m);
			fd = queue_message_fd_r(msgid);
			m_create(p, imsg->hdr.type, 0, 0, fd);
			m_add_id(p, reqid);
			m_close(p);
			return;

		case IMSG_MDA_DELIVERY_OK:
		case IMSG_MTA_DELIVERY_OK:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			if (imsg->hdr.type == IMSG_MTA_DELIVERY_OK)
				m_get_int(&m, &mta_ext);
			m_end(&m);
			if (queue_envelope_load(evpid, &evp) == 0) {
				log_warn("queue: dsn: failed to load envelope");
				return;
			}
			if (evp.dsn_notify & DSN_SUCCESS) {
				bounce.type = B_DSN;
				bounce.dsn_ret = evp.dsn_ret;

				if (imsg->hdr.type == IMSG_MDA_DELIVERY_OK)
					queue_bounce(&evp, &bounce);
				else if (imsg->hdr.type == IMSG_MTA_DELIVERY_OK &&
				    (mta_ext & MTA_EXT_DSN) == 0) {
					bounce.mta_without_dsn = 1;
					queue_bounce(&evp, &bounce);
				}
			}
			queue_envelope_delete(evpid);
			m_create(p_scheduler, IMSG_QUEUE_DELIVERY_OK, 0, 0, -1);
			m_add_evpid(p_scheduler, evpid);
			m_close(p_scheduler);
			return;

		case IMSG_MDA_DELIVERY_TEMPFAIL:
		case IMSG_MTA_DELIVERY_TEMPFAIL:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_get_string(&m, &reason);
			m_get_int(&m, &code);
			m_end(&m);
			if (queue_envelope_load(evpid, &evp) == 0) {
				log_warnx("queue: tempfail: failed to load envelope");
				m_create(p_scheduler, IMSG_QUEUE_ENVELOPE_REMOVE, 0, 0, -1);
				m_add_evpid(p_scheduler, evpid);
				m_add_u32(p_scheduler, 1); /* in-flight */
				m_close(p_scheduler);
				return;
			}
			envelope_set_errormsg(&evp, "%s", reason);
			envelope_set_esc_class(&evp, ESC_STATUS_TEMPFAIL);
			envelope_set_esc_code(&evp, code);
			evp.retry++;
			if (!queue_envelope_update(&evp))
				log_warnx("warn: could not update envelope %016"PRIx64, evpid);
			m_create(p_scheduler, IMSG_QUEUE_DELIVERY_TEMPFAIL, 0, 0, -1);
			m_add_envelope(p_scheduler, &evp);
			m_close(p_scheduler);
			return;

		case IMSG_MDA_DELIVERY_PERMFAIL:
		case IMSG_MTA_DELIVERY_PERMFAIL:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_get_string(&m, &reason);
			m_get_int(&m, &code);
			m_end(&m);
			if (queue_envelope_load(evpid, &evp) == 0) {
				log_warnx("queue: permfail: failed to load envelope");
				m_create(p_scheduler, IMSG_QUEUE_ENVELOPE_REMOVE, 0, 0, -1);
				m_add_evpid(p_scheduler, evpid);
				m_add_u32(p_scheduler, 1); /* in-flight */
				m_close(p_scheduler);
				return;
			}
			bounce.type = B_ERROR;
			envelope_set_errormsg(&evp, "%s", reason);
			envelope_set_esc_class(&evp, ESC_STATUS_PERMFAIL);
			envelope_set_esc_code(&evp, code);
			queue_bounce(&evp, &bounce);
			queue_envelope_delete(evpid);
			m_create(p_scheduler, IMSG_QUEUE_DELIVERY_PERMFAIL, 0, 0, -1);
			m_add_evpid(p_scheduler, evpid);
			m_close(p_scheduler);
			return;

		case IMSG_MDA_DELIVERY_LOOP:
		case IMSG_MTA_DELIVERY_LOOP:
			m_msg(&m, imsg);
			m_get_evpid(&m, &evpid);
			m_end(&m);
			if (queue_envelope_load(evpid, &evp) == 0) {
				log_warnx("queue: loop: failed to load envelope");
				m_create(p_scheduler, IMSG_QUEUE_ENVELOPE_REMOVE, 0, 0, -1);
				m_add_evpid(p_scheduler, evpid);
				m_add_u32(p_scheduler, 1); /* in-flight */
				m_close(p_scheduler);
				return;
			}
			envelope_set_errormsg(&evp, "%s", "Loop detected");
			envelope_set_esc_class(&evp, ESC_STATUS_TEMPFAIL);
			envelope_set_esc_code(&evp, ESC_ROUTING_LOOP_DETECTED);
			bounce.type = B_ERROR;
			queue_bounce(&evp, &bounce);
			queue_envelope_delete(evp.id);
			m_create(p_scheduler, IMSG_QUEUE_DELIVERY_LOOP, 0, 0, -1);
			m_add_evpid(p_scheduler, evp.id);
			m_close(p_scheduler);
			return;

		case IMSG_MTA_DELIVERY_HOLD:
		case IMSG_MDA_DELIVERY_HOLD:
			imsg->hdr.type = IMSG_QUEUE_HOLDQ_HOLD;
			m_forward(p_scheduler, imsg);
			return;

		case IMSG_MTA_SCHEDULE:
			imsg->hdr.type = IMSG_QUEUE_ENVELOPE_SCHEDULE;
			m_forward(p_scheduler, imsg);
			return;

		case IMSG_MTA_HOLDQ_RELEASE:
		case IMSG_MDA_HOLDQ_RELEASE:
			m_msg(&m, imsg);
			m_get_id(&m, &holdq);
			m_get_int(&m, &v);
			m_end(&m);
			m_create(p_scheduler, IMSG_QUEUE_HOLDQ_RELEASE, 0, 0, -1);
			if (imsg->hdr.type == IMSG_MTA_HOLDQ_RELEASE)
				m_add_int(p_scheduler, D_MTA);
			else
				m_add_int(p_scheduler, D_MDA);
			m_add_id(p_scheduler, holdq);
			m_add_int(p_scheduler, v);
			m_close(p_scheduler);
			return;
		}
	}

	if (p->proc == PROC_CONTROL) {
		switch (imsg->hdr.type) {
		case IMSG_CTL_PAUSE_MDA:
		case IMSG_CTL_PAUSE_MTA:
		case IMSG_CTL_RESUME_MDA:
		case IMSG_CTL_RESUME_MTA:
			m_forward(p_scheduler, imsg);
			return;
		}
	}

	if (p->proc == PROC_PARENT) {
		switch (imsg->hdr.type) {
		case IMSG_CTL_VERBOSE:
			m_msg(&m, imsg);
			m_get_int(&m, &v);
			m_end(&m);
			log_verbose(v);
			m_forward(p_scheduler, imsg);
			return;

		case IMSG_CTL_PROFILE:
			m_msg(&m, imsg);
			m_get_int(&m, &v);
			m_end(&m);
			profiling = v;
			return;
		}
	}

	errx(1, "queue_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
}
コード例 #21
0
ファイル: mta.c プロジェクト: clongeau/opensmtpd
void
mta_imsg(struct imsgev *iev, struct imsg *imsg)
{
	struct mta_route	*route;
	struct mta_batch2	*batch;
	struct mta_task		*task;
	struct envelope		*e;
	struct ssl		*ssl;
	uint64_t		 id;

	if (iev->proc == PROC_QUEUE) {
		switch (imsg->hdr.type) {

		case IMSG_BATCH_CREATE:
			id = *(uint64_t*)(imsg->data);
			batch = xmalloc(sizeof *batch, "mta_batch");
			batch->id = id;
			tree_init(&batch->tasks);
			tree_xset(&batches, batch->id, batch);
			log_trace(TRACE_MTA,
			    "mta: batch:%016" PRIx64 " created", batch->id);
			return;

		case IMSG_BATCH_APPEND:
			e = xmemdup(imsg->data, sizeof *e, "mta:envelope");
			route = mta_route_for(e);
			batch = tree_xget(&batches, e->batch_id);

			if ((task = tree_get(&batch->tasks, route->id)) == NULL) {
				log_trace(TRACE_MTA, "mta: new task for %s",
				    mta_route_to_text(route));
				task = xmalloc(sizeof *task, "mta_task");
				TAILQ_INIT(&task->envelopes);
				task->route = route;
				tree_xset(&batch->tasks, route->id, task);
				task->msgid = evpid_to_msgid(e->id);
				task->sender = e->sender;
				route->refcount += 1;
			}

			/* Technically, we could handle that by adding a msg
			 * level, but the batch sent by the scheduler should
			 * be valid.
			 */
			if (task->msgid != evpid_to_msgid(e->id))
				errx(1, "msgid mismatch in batch");

			/* XXX honour route->maxrcpt */
			TAILQ_INSERT_TAIL(&task->envelopes, e, entry);
			stat_increment("mta.envelope", 1);
			log_debug("mta: received evp:%016" PRIx64 " for <%s@%s>",
			    e->id, e->dest.user, e->dest.domain);
			return;

		case IMSG_BATCH_CLOSE:
			id = *(uint64_t*)(imsg->data);
			batch = tree_xpop(&batches, id);
			log_trace(TRACE_MTA, "mta: batch:%016" PRIx64 " closed",
			    batch->id);
			/* for all tasks, queue them on there route */
			while (tree_poproot(&batch->tasks, &id, (void**)&task)) {
				if (id != task->route->id)
					errx(1, "route id mismatch!");
				task->route->refcount -= 1;
				task->route->ntask += 1;
				TAILQ_INSERT_TAIL(&task->route->tasks, task, entry);
				stat_increment("mta.task", 1);
				mta_route_drain(task->route);
			}
			free(batch);
			return;

		case IMSG_QUEUE_MESSAGE_FD:
			mta_session_imsg(iev, imsg);
			return;
		}
	}

	if (iev->proc == PROC_LKA) {
		switch (imsg->hdr.type) {
		case IMSG_LKA_SECRET:
		case IMSG_DNS_HOST:
		case IMSG_DNS_HOST_END:
		case IMSG_DNS_PTR:
			mta_session_imsg(iev, imsg);
			return;
		}
	}

	if (iev->proc == PROC_PARENT) {
		switch (imsg->hdr.type) {
		case IMSG_CONF_START:
			if (env->sc_flags & SMTPD_CONFIGURING)
				return;
			env->sc_flags |= SMTPD_CONFIGURING;
			env->sc_ssl = xcalloc(1, sizeof *env->sc_ssl, "mta:sc_ssl");
			return;

		case IMSG_CONF_SSL:
			if (!(env->sc_flags & SMTPD_CONFIGURING))
				return;
			ssl = xmemdup(imsg->data, sizeof *ssl, "mta:ssl");
			ssl->ssl_cert = xstrdup((char*)imsg->data + sizeof *ssl,
			    "mta:ssl_cert");
			ssl->ssl_key = xstrdup((char*)imsg->data +
			    sizeof *ssl + ssl->ssl_cert_len, "mta:ssl_key");
			SPLAY_INSERT(ssltree, env->sc_ssl, ssl);
			return;

		case IMSG_CONF_END:
			if (!(env->sc_flags & SMTPD_CONFIGURING))
				return;
			env->sc_flags &= ~SMTPD_CONFIGURING;
			return;

		case IMSG_CTL_VERBOSE:
			log_verbose(*(int *)imsg->data);
			return;
		}
	}

	errx(1, "mta_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
}
コード例 #22
0
void
runner_imsg(struct imsgev *iev, struct imsg *imsg)
{
	struct envelope	*e, bounce;
	struct scheduler_info	si;

	log_imsg(PROC_RUNNER, iev->proc, imsg);

	switch (imsg->hdr.type) {
	case IMSG_QUEUE_COMMIT_MESSAGE:
		e = imsg->data;
		runner_message_to_scheduler(evpid_to_msgid(e->id));
		runner_reset_events();
		return;

	case IMSG_QUEUE_DELIVERY_OK:
		stat_decrement(STATS_RUNNER);
		e = imsg->data;
		log_debug("queue_delivery_ok: %016"PRIx64, e->id);
		scheduler->remove(e->id);
		queue_envelope_delete(e);
		return;

	case IMSG_QUEUE_DELIVERY_TEMPFAIL:
		stat_decrement(STATS_RUNNER);
		e = imsg->data;
		e->retry++;
		queue_envelope_update(e);
		log_debug("queue_delivery_tempfail: %016"PRIx64, e->id);
		scheduler_info(&si, e);
		scheduler->insert(&si);
		runner_reset_events();
		return;

	case IMSG_QUEUE_DELIVERY_PERMFAIL:
		stat_decrement(STATS_RUNNER);
		e = imsg->data;
		if (e->type != D_BOUNCE && e->sender.user[0] != '\0') {
			bounce_record_message(e, &bounce);
			log_debug("queue_delivery_permfail: %016"PRIx64,
			    bounce.id);
			scheduler_info(&si, &bounce);
			scheduler->insert(&si);
			runner_reset_events();
		}
		scheduler->remove(e->id);
		queue_envelope_delete(e);
		return;

	case IMSG_MDA_SESS_NEW:
		stat_decrement(STATS_MDA_SESSION);
		if (env->sc_maxconn - stat_get(STATS_MDA_SESSION, STAT_ACTIVE))
			env->sc_flags &= ~SMTPD_MDA_BUSY;
		runner_reset_events();
		return;

	case IMSG_BATCH_DONE:
		stat_decrement(STATS_MTA_SESSION);
		if (env->sc_maxconn - stat_get(STATS_MTA_SESSION, STAT_ACTIVE))
			env->sc_flags &= ~SMTPD_MTA_BUSY;
		runner_reset_events();
		return;

	case IMSG_SMTP_ENQUEUE:
		e = imsg->data;
		if (imsg->fd < 0 || !bounce_session(imsg->fd, e)) {
			queue_envelope_update(e);
			log_debug("smtp_enqueue: %016"PRIx64, e->id);
			scheduler_info(&si, e);
			scheduler->insert(&si);
			runner_reset_events();
			return;
		}
		return;

	case IMSG_QUEUE_PAUSE_MDA:
		env->sc_flags |= SMTPD_MDA_PAUSED;
		return;

	case IMSG_QUEUE_RESUME_MDA:
		env->sc_flags &= ~SMTPD_MDA_PAUSED;
		runner_reset_events();
		return;

	case IMSG_QUEUE_PAUSE_MTA:
		env->sc_flags |= SMTPD_MTA_PAUSED;
		return;

	case IMSG_QUEUE_RESUME_MTA:
		env->sc_flags &= ~SMTPD_MTA_PAUSED;
		runner_reset_events();
		return;

	case IMSG_CTL_VERBOSE:
		log_verbose(*(int *)imsg->data);
		return;

	case IMSG_RUNNER_SCHEDULE:
		scheduler->force(*(u_int64_t *)imsg->data);
		runner_reset_events();		
		return;

	case IMSG_RUNNER_REMOVE: {
		runner_remove(*(u_int64_t *)imsg->data);
		runner_reset_events();
		return;
	}
	}

	errx(1, "runner_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
}
コード例 #23
0
static int
runner_check_loop(struct envelope *ep)
{
	int fd;
	FILE *fp;
	char *buf, *lbuf;
	size_t len;
	struct mailaddr maddr;
	int ret = 0;
	int rcvcount = 0;

	fd = queue_message_fd_r(evpid_to_msgid(ep->id));
	if ((fp = fdopen(fd, "r")) == NULL)
		fatal("fdopen");

	lbuf = NULL;
	while ((buf = fgetln(fp, &len))) {
		if (buf[len - 1] == '\n')
			buf[len - 1] = '\0';
		else {
			/* EOF without EOL, copy and add the NUL */
			if ((lbuf = malloc(len + 1)) == NULL)
				err(1, NULL);
			memcpy(lbuf, buf, len);
			lbuf[len] = '\0';
			buf = lbuf;
		}

		if (strchr(buf, ':') == NULL && !isspace((int)*buf))
			break;

		if (strncasecmp("Received: ", buf, 10) == 0) {
			rcvcount++;
			if (rcvcount == MAX_HOPS_COUNT) {
				ret = 1;
				break;
			}
		}

		else if (strncasecmp("Delivered-To: ", buf, 14) == 0) {
			struct mailaddr dest;

			bzero(&maddr, sizeof (struct mailaddr));
			if (! email_to_mailaddr(&maddr, buf + 14))
				continue;
			
			dest = ep->dest;
			if (ep->type == D_BOUNCE)
				dest = ep->sender;

			if (strcasecmp(maddr.user, dest.user) == 0 &&
			    strcasecmp(maddr.domain, dest.domain) == 0) {
				ret = 1;
				break;
			}
		}
	}
	free(lbuf);

	fclose(fp);
	return ret;
}
コード例 #24
0
static int
runner_process_batch(enum delivery_type type, u_int64_t evpid)
{
	struct envelope evp;
	void *batch;
	int fd;

	batch = scheduler->batch(evpid);
	switch (type) {
	case D_BOUNCE:
		while (scheduler->fetch(batch, &evpid)) {
			if (! queue_envelope_load(evpid, &evp))
				goto end;

			evp.lasttry = time(NULL);
			imsg_compose_event(env->sc_ievs[PROC_QUEUE],
			    IMSG_SMTP_ENQUEUE, PROC_SMTP, 0, -1, &evp,
			    sizeof evp);
			scheduler->schedule(evpid);
		}
		stat_increment(STATS_RUNNER);
		stat_increment(STATS_RUNNER_BOUNCES);
		break;
		
	case D_MDA:
		scheduler->fetch(batch, &evpid);
		if (! queue_envelope_load(evpid, &evp))
			goto end;
		
		evp.lasttry = time(NULL);
		fd = queue_message_fd_r(evpid_to_msgid(evpid));
		imsg_compose_event(env->sc_ievs[PROC_QUEUE],
		    IMSG_MDA_SESS_NEW, PROC_MDA, 0, fd, &evp,
		    sizeof evp);
		scheduler->schedule(evpid);

		stat_increment(STATS_RUNNER);
		stat_increment(STATS_MDA_SESSION);
		break;

	case D_MTA: {
		struct mta_batch mta_batch;

		/* FIXME */
		if (! scheduler->fetch(batch, &evpid))
			goto end;
		if (! queue_envelope_load(evpid,
				&evp))
			goto end;

		bzero(&mta_batch, sizeof mta_batch);
		mta_batch.id    = arc4random();
		mta_batch.relay = evp.agent.mta.relay;

		imsg_compose_event(env->sc_ievs[PROC_QUEUE],
		    IMSG_BATCH_CREATE, PROC_MTA, 0, -1, &mta_batch,
		    sizeof mta_batch);

		while (scheduler->fetch(batch, &evpid)) {
			if (! queue_envelope_load(evpid,
				&evp))
				goto end;
			evp.lasttry = time(NULL); /* FIXME */
			evp.batch_id = mta_batch.id;

			imsg_compose_event(env->sc_ievs[PROC_QUEUE],
			    IMSG_BATCH_APPEND, PROC_MTA, 0, -1, &evp,
			    sizeof evp);

			scheduler->schedule(evpid);
			stat_increment(STATS_RUNNER);
		}

		imsg_compose_event(env->sc_ievs[PROC_QUEUE],
		    IMSG_BATCH_CLOSE, PROC_MTA, 0, -1, &mta_batch,
		    sizeof mta_batch);

		stat_increment(STATS_MTA_SESSION);
		break;
	}
		
	default:
		fatalx("runner_process_batchqueue: unknown type");
	}

end:
	scheduler->close(batch);
	return 1;
}
コード例 #25
0
static int
fsqueue_envelope_create(enum queue_kind qkind, struct envelope *ep)
{
	char evpname[MAXPATHLEN];
	FILE *fp;
	int fd;
	u_int32_t rnd;
	u_int64_t evpid;

	fp = NULL;

again:
	rnd = (u_int32_t)arc4random();
	if (rnd == 0)
		goto again;
	evpid = ep->id | rnd;

	if (! bsnprintf(evpname, sizeof(evpname), "%s/%08x%s/%016llx",
		fsqueue_getpath(qkind),
		evpid_to_msgid(evpid),
		PATH_ENVELOPES, evpid))
		fatalx("fsqueue_envelope_create: snprintf");

	fd = open(evpname, O_WRONLY|O_CREAT|O_EXCL, 0600);
	if (fd == -1) {
		if (errno == EEXIST)
			goto again;
		if (errno == ENOSPC || errno == ENFILE)
			goto tempfail;
		fatal("fsqueue_envelope_create: open");
	}

	fp = fdopen(fd, "w");
	if (fp == NULL)
		fatal("fsqueue_envelope_create: fdopen");
 
	ep->creation = time(NULL);
	ep->id = evpid;

	if (qkind == Q_BOUNCE) {
		ep->lasttry = 0;
		ep->retry = 0;
	}

	if (! fsqueue_dump_envelope_ascii(fp, ep)) {
		if (errno == ENOSPC)
			goto tempfail;
		fatal("fsqueue_dump_envelope_ascii: write");
	}

	if (! safe_fclose(fp)) {
		fp = NULL;
		fd = -1;
		goto tempfail;
	}

	return 1;

tempfail:
	unlink(evpname);
	if (fp)
		fclose(fp);
	else if (fd != -1)
		close(fd);
	ep->creation = 0;
	ep->id = 0;

	return 0;
}
コード例 #26
0
ファイル: smtp_session.c プロジェクト: clongeau/opensmtpd
void
session_respond(struct session *s, char *fmt, ...)
{
	va_list	 ap;
	int	 n, delay;
	char	 buf[SMTP_LINE_MAX];

	va_start(ap, fmt);
	n = vsnprintf(buf, sizeof buf, fmt, ap);
	va_end(ap);
	if (n == -1 || n >= SMTP_LINE_MAX)
		fatal("session_respond: line too long");
	if (n < 4)
		fatal("session_respond: response too short");

	log_trace(TRACE_SMTP, "smtp: %p: >>> %s", s, buf);

	iobuf_xfqueue(&s->s_iobuf, "session_respond", "%s\r\n", buf);

	/*
	 * Log failures.  Might be annoying in the long term, but it is a good
	 * development aid for now.
	 */
	switch (buf[0]) {
	case '5':
	case '4':
		log_info("%08x: from=<%s@%s>, relay=%s [%s], stat=LocalError (%.*s)",
		    evpid_to_msgid(s->s_msg.id),
		    s->s_msg.sender.user, s->s_msg.sender.domain,
		    s->s_hostname, ss_to_text(&s->s_ss),
		    n, buf);
		break;
	}

	/* Detect multi-line response. */
	switch (buf[3]) {
	case '-':
		return;
	case ' ':
		break;
	default:
		fatalx("session_respond: invalid response");
	}

	/*
	 * Deal with request flooding; avoid letting response rate keep up
	 * with incoming request rate.
	 */
	s->s_nresp[s->s_state]++;

	if (s->s_state == S_RCPT)
		delay = 0;
	else if ((n = s->s_nresp[s->s_state] - FAST_RESPONSES) > 0)
		delay = MIN(1 << (n - 1), MAX_RESPONSE_DELAY);
	else
		delay = 0;

	if (delay > 0) {
		struct timeval tv = { delay, 0 };

		io_pause(&s->s_io, IO_PAUSE_OUT);
		stat_increment("smtp.delays", 1);

		/* in case session_respond is called multiple times */
		evtimer_del(&s->s_ev);
		evtimer_set(&s->s_ev, session_respond_delayed, s);
		evtimer_add(&s->s_ev, &tv);
	}
}