Ejemplo n.º 1
0
static void
dns_dispatch_host(struct asr_result *ar, void *arg)
{
	struct dns_session	*s;
	struct dns_lookup	*lookup = arg;
	struct addrinfo		*ai;

	s = lookup->session;

	for (ai = ar->ar_addrinfo; ai; ai = ai->ai_next) {
		s->mxfound++;
		m_create(s->p, IMSG_MTA_DNS_HOST, 0, 0, -1);
		m_add_id(s->p, s->reqid);
		m_add_sockaddr(s->p, ai->ai_addr);
		m_add_int(s->p, lookup->preference);
		m_close(s->p);
	}
	free(lookup);
	if (ar->ar_addrinfo)
		asr_freeaddrinfo(ar->ar_addrinfo);

	if (ar->ar_gai_errno)
		s->error = ar->ar_gai_errno;

	if (--s->refcount)
		return;

	m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1);
	m_add_id(s->p, s->reqid);
	m_add_int(s->p, s->mxfound ? DNS_OK : DNS_ENOTFOUND);
	m_close(s->p);
	free(s);
}
Ejemplo n.º 2
0
static void
filter_send_response(struct filter_session *s)
{
	log_trace(TRACE_FILTERS, "filter-api:%s %016"PRIx64" %s filter_send_response() -> %d, %d, %s",
	    filter_name, s->id, query_to_str(s->qtype),
	    s->response.status,
	    s->response.code,
	    s->response.line);

	tree_xpop(&queries, s->qid);

	m_create(&fi.p, IMSG_FILTER_RESPONSE, 0, 0, -1);
	m_add_id(&fi.p, s->qid);
	m_add_int(&fi.p, s->qtype);
	if (s->qtype == QUERY_EOM)
		m_add_u32(&fi.p, s->datalen);
	m_add_int(&fi.p, s->response.status);
	m_add_int(&fi.p, s->response.code);
	if (s->response.line) {
		m_add_string(&fi.p, s->response.line);
		free(s->response.line);
		s->response.line = NULL;
	}
	m_close(&fi.p);

	s->qid = 0;
	s->response.ready = 0;
}
Ejemplo n.º 3
0
static void
dns_dispatch_mx_preference(struct asr_result *ar, void *arg)
{
	struct dns_session	*s = arg;
	struct unpack		 pack;
	struct dns_header	 h;
	struct dns_query	 q;
	struct dns_rr		 rr;
	char			 buf[512];
	int			 error;

	if (ar->ar_h_errno) {
		if (ar->ar_rcode == NXDOMAIN)
			error = DNS_ENONAME;
		else if (ar->ar_h_errno == NO_RECOVERY
		    || ar->ar_h_errno == NO_DATA)
			error = DNS_EINVAL;
		else
			error = DNS_RETRY;
	}
	else {
		error = DNS_ENOTFOUND;
		unpack_init(&pack, ar->ar_data, ar->ar_datalen);
		if (unpack_header(&pack, &h) != -1 &&
		    unpack_query(&pack, &q) != -1) {
			for (; h.ancount; h.ancount--) {
				if (unpack_rr(&pack, &rr) == -1)
					break;
				if (rr.rr_type != T_MX)
					continue;
				print_dname(rr.rr.mx.exchange, buf, sizeof(buf));
				buf[strlen(buf) - 1] = '\0';
				if (!strcasecmp(s->name, buf)) {
					error = DNS_OK;
					break;
				}
			}
		}
	}

	free(ar->ar_data);

	m_create(s->p, IMSG_MTA_DNS_MX_PREFERENCE, 0, 0, -1);
	m_add_id(s->p, s->reqid);
	m_add_int(s->p, error);
	if (error == DNS_OK)
		m_add_int(s->p, rr.rr.mx.preference);
	m_close(s->p);
	free(s);
}
Ejemplo n.º 4
0
static void
dns_dispatch_mx(struct asr_result *ar, void *arg)
{
	struct dns_session	*s = arg;
	struct unpack		 pack;
	struct dns_header	 h;
	struct dns_query	 q;
	struct dns_rr		 rr;
	char			 buf[512];
	size_t			 found;

	if (ar->ar_h_errno && ar->ar_h_errno != NO_DATA) {

		m_create(s->p,  IMSG_MTA_DNS_HOST_END, 0, 0, -1);
		m_add_id(s->p, s->reqid);
		if (ar->ar_rcode == NXDOMAIN)
			m_add_int(s->p, DNS_ENONAME);
		else if (ar->ar_h_errno == NO_RECOVERY)
			m_add_int(s->p, DNS_EINVAL);
		else
			m_add_int(s->p, DNS_RETRY);
		m_close(s->p);
		free(s);
		free(ar->ar_data);
		return;
	}

	found = 0;

	unpack_init(&pack, ar->ar_data, ar->ar_datalen);
	if (unpack_header(&pack, &h) == -1 || unpack_query(&pack, &q) == -1)
		return;

	for (; h.ancount; h.ancount--) {
		if (unpack_rr(&pack, &rr) == -1)
			break;
		if (rr.rr_type != T_MX)
			continue;
		print_dname(rr.rr.mx.exchange, buf, sizeof(buf));
		buf[strlen(buf) - 1] = '\0';
		dns_lookup_host(s, buf, rr.rr.mx.preference);
		found++;
	}
	free(ar->ar_data);

	/* fallback to host if no MX is found. */
	if (found == 0)
		dns_lookup_host(s, s->name, 0);
}
Ejemplo n.º 5
0
static void
filter_response(uint64_t qid, int status, int code, const char *line, int notify)
{
	struct filter_query	*q;

	q = tree_xpop(&queries, qid);
	free(q);

	m_create(&fi.p, IMSG_FILTER_RESPONSE, 0, 0, -1);
	m_add_id(&fi.p, qid);
	m_add_int(&fi.p, status);
	m_add_int(&fi.p, code);
	m_add_int(&fi.p, notify);
	if (line)
		m_add_string(&fi.p, line);
	m_close(&fi.p);
}
Ejemplo n.º 6
0
void
queue_permfail(uint64_t evpid, const char *reason, enum enhanced_status_code code)
{
	m_create(p_queue, IMSG_DELIVERY_PERMFAIL, 0, 0, -1);
	m_add_evpid(p_queue, evpid);
	m_add_string(p_queue, reason);
	m_add_int(p_queue, (int)code);
	m_close(p_queue);
}
Ejemplo n.º 7
0
static void
control_broadcast_verbose(int msg, int v)
{
	m_create(p_lka, msg, 0, 0, -1);
	m_add_int(p_lka, v);
	m_close(p_lka);

	m_create(p_pony, msg, 0, 0, -1);
	m_add_int(p_pony, v);
	m_close(p_pony);

	m_create(p_queue, msg, 0, 0, -1);
	m_add_int(p_queue, v);
	m_close(p_queue);

	m_create(p_ca, msg, 0, 0, -1);
	m_add_int(p_ca, v);
	m_close(p_ca);

	m_create(p_scheduler, msg, 0, 0, -1);
	m_add_int(p_scheduler, v);
	m_close(p_scheduler);

	m_create(p_parent, msg, 0, 0, -1);
	m_add_int(p_parent, v);
	m_close(p_parent);
}
Ejemplo n.º 8
0
static void
dns_dispatch_ptr(struct asr_result *ar, void *arg)
{
	struct dns_session	*s = arg;

	/* The error code could be more precise, but we don't currently care */
	m_create(s->p,  s->type, 0, 0, -1);
	m_add_id(s->p, s->reqid);
	m_add_int(s->p, ar->ar_gai_errno ? DNS_ENOTFOUND : DNS_OK);
	if (ar->ar_gai_errno == 0)
		m_add_string(s->p, s->name);
	m_close(s->p);
	free(s);
}
Ejemplo n.º 9
0
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));
}
Ejemplo n.º 10
0
static void
filter_dispatch(struct mproc *p, struct imsg *imsg)
{
	struct filter_connect	 q_connect;
	struct mailaddr		 maddr;
	struct msg		 m;
	const char		*line;
	uint32_t		 v;
	uint64_t		 id, qid;
	int			 status, event, hook;

	log_debug("debug: %s: imsg %i", filter_name, imsg->hdr.type);

	switch (imsg->hdr.type) {
	case IMSG_FILTER_REGISTER:
		m_msg(&m, imsg);
		m_get_u32(&m, &v);
		m_end(&m);
		if (v != FILTER_API_VERSION)
			errx(1, "API version mismatch");
		m_create(p, IMSG_FILTER_REGISTER, 0, 0, -1);
		m_add_int(p, fi.hooks);
		m_add_int(p, fi.flags);
		m_close(p);
		break;

	case IMSG_FILTER_EVENT:
		m_msg(&m, imsg);
		m_get_id(&m, &id);
		m_get_int(&m, &event);
		m_end(&m);
		filter_dispatch_event(id, event);
		break;

	case IMSG_FILTER_QUERY:
		m_msg(&m, imsg);
		m_get_id(&m, &id);
		m_get_id(&m, &qid);
		m_get_int(&m, &hook);
		tree_xset(&queries, qid, NULL);
		switch(hook) {
		case HOOK_CONNECT:
			m_get_sockaddr(&m, (struct sockaddr*)&q_connect.local);
			m_get_sockaddr(&m, (struct sockaddr*)&q_connect.remote);
			m_get_string(&m, &q_connect.hostname);
			m_end(&m);
			filter_dispatch_connect(id, qid, &q_connect);
			break;
		case HOOK_HELO:
			m_get_string(&m, &line);
			m_end(&m);
			filter_dispatch_helo(id, qid, line);
			break;
		case HOOK_MAIL:
			m_get_mailaddr(&m, &maddr);
			m_end(&m);
			filter_dispatch_mail(id, qid, &maddr);
			break;
		case HOOK_RCPT:
			m_get_mailaddr(&m, &maddr);
			m_end(&m);
			filter_dispatch_rcpt(id, qid, &maddr);
			break;
		case HOOK_DATA:
			m_end(&m);
			filter_dispatch_data(id, qid);
			break;
		case HOOK_EOM:
			m_end(&m);
			filter_dispatch_eom(id, qid);
			break;
		default:
			errx(1, "bad query hook: %d", hook);
		}
		break;

	case IMSG_FILTER_NOTIFY:
		m_msg(&m, imsg);
		m_get_id(&m, &qid);
		m_get_int(&m, &status);
		m_end(&m);
		filter_dispatch_notify(qid, status);
		break;

	case IMSG_FILTER_DATA:
		m_msg(&m, imsg);
		m_get_id(&m, &id);
		m_get_string(&m, &line);
		m_end(&m);
		filter_dispatch_dataline(id, line);
		break;
	}
}
Ejemplo n.º 11
0
static void
lka_imsg(struct mproc *p, struct imsg *imsg)
{
    struct rule		*rule;
    struct table		*table;
    void			*tmp;
    int			 ret;
    const char		*key, *val;
    struct ssl		*ssl;
    struct iovec		iov[3];
    static struct dict	*ssl_dict;
    static struct dict	*tables_dict;
    static struct table	*table_last;
    static struct ca_vrfy_req_msg	*req_ca_vrfy_smtp = NULL;
    static struct ca_vrfy_req_msg	*req_ca_vrfy_mta = NULL;
    struct ca_vrfy_req_msg		*req_ca_vrfy_chain;
    struct ca_vrfy_resp_msg		resp_ca_vrfy;
    struct ca_cert_req_msg		*req_ca_cert;
    struct ca_cert_resp_msg		 resp_ca_cert;
    struct sockaddr_storage	 ss;
    struct userinfo		 userinfo;
    struct addrname		 addrname;
    struct envelope		 evp;
    struct msg		 m;
    union lookup		 lk;
    char			 buf[SMTPD_MAXLINESIZE];
    const char		*tablename, *username, *password, *label;
    uint64_t		 reqid;
    size_t			 i;
    int			 v;

    if (imsg->hdr.type == IMSG_DNS_HOST ||
            imsg->hdr.type == IMSG_DNS_PTR ||
            imsg->hdr.type == IMSG_DNS_MX ||
            imsg->hdr.type == IMSG_DNS_MX_PREFERENCE) {
        dns_imsg(p, imsg);
        return;
    }

    if (p->proc == PROC_SMTP) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_EXPAND_RCPT:
            m_msg(&m, imsg);
            m_get_id(&m, &reqid);
            m_get_envelope(&m, &evp);
            m_end(&m);
            lka_session(reqid, &evp);
            return;

        case IMSG_LKA_SSL_INIT:
            req_ca_cert = imsg->data;
            resp_ca_cert.reqid = req_ca_cert->reqid;

            ssl = dict_get(env->sc_ssl_dict, req_ca_cert->name);
            if (ssl == NULL) {
                resp_ca_cert.status = CA_FAIL;
                m_compose(p, IMSG_LKA_SSL_INIT, 0, 0, -1, &resp_ca_cert,
                          sizeof(resp_ca_cert));
                return;
            }
            resp_ca_cert.status = CA_OK;
            resp_ca_cert.cert_len = ssl->ssl_cert_len;
            resp_ca_cert.key_len = ssl->ssl_key_len;
            iov[0].iov_base = &resp_ca_cert;
            iov[0].iov_len = sizeof(resp_ca_cert);
            iov[1].iov_base = ssl->ssl_cert;
            iov[1].iov_len = ssl->ssl_cert_len;
            iov[2].iov_base = ssl->ssl_key;
            iov[2].iov_len = ssl->ssl_key_len;
            m_composev(p, IMSG_LKA_SSL_INIT, 0, 0, -1, iov, nitems(iov));
            return;

        case IMSG_LKA_SSL_VERIFY_CERT:
            req_ca_vrfy_smtp = xmemdup(imsg->data, sizeof *req_ca_vrfy_smtp, "lka:ca_vrfy");
            if (req_ca_vrfy_smtp == NULL)
                fatal(NULL);
            req_ca_vrfy_smtp->cert = xmemdup((char *)imsg->data +
                                             sizeof *req_ca_vrfy_smtp, req_ca_vrfy_smtp->cert_len, "lka:ca_vrfy");
            req_ca_vrfy_smtp->chain_cert = xcalloc(req_ca_vrfy_smtp->n_chain,
                                                   sizeof (unsigned char *), "lka:ca_vrfy");
            req_ca_vrfy_smtp->chain_cert_len = xcalloc(req_ca_vrfy_smtp->n_chain,
                                               sizeof (off_t), "lka:ca_vrfy");
            return;

        case IMSG_LKA_SSL_VERIFY_CHAIN:
            if (req_ca_vrfy_smtp == NULL)
                fatalx("lka:ca_vrfy: chain without a certificate");
            req_ca_vrfy_chain = imsg->data;
            req_ca_vrfy_smtp->chain_cert[req_ca_vrfy_smtp->chain_offset] = xmemdup((char *)imsg->data +
                    sizeof *req_ca_vrfy_chain, req_ca_vrfy_chain->cert_len, "lka:ca_vrfy");
            req_ca_vrfy_smtp->chain_cert_len[req_ca_vrfy_smtp->chain_offset] = req_ca_vrfy_chain->cert_len;
            req_ca_vrfy_smtp->chain_offset++;
            return;

        case IMSG_LKA_SSL_VERIFY:
            if (req_ca_vrfy_smtp == NULL)
                fatalx("lka:ca_vrfy: verify without a certificate");

            resp_ca_vrfy.reqid = req_ca_vrfy_smtp->reqid;

            if (! lka_X509_verify(req_ca_vrfy_smtp, CA_FILE, NULL))
                resp_ca_vrfy.status = CA_FAIL;
            else
                resp_ca_vrfy.status = CA_OK;

            m_compose(p, IMSG_LKA_SSL_VERIFY, 0, 0, -1, &resp_ca_vrfy,
                      sizeof resp_ca_vrfy);

            for (i = 0; i < req_ca_vrfy_smtp->n_chain; ++i)
                free(req_ca_vrfy_smtp->chain_cert[i]);
            free(req_ca_vrfy_smtp->chain_cert);
            free(req_ca_vrfy_smtp->chain_cert_len);
            free(req_ca_vrfy_smtp->cert);
            free(req_ca_vrfy_smtp);
            return;

        case IMSG_LKA_AUTHENTICATE:
            m_msg(&m, imsg);
            m_get_id(&m, &reqid);
            m_get_string(&m, &tablename);
            m_get_string(&m, &username);
            m_get_string(&m, &password);
            m_end(&m);

            if (!tablename[0]) {
                m_create(p_parent, IMSG_LKA_AUTHENTICATE,
                         0, 0, -1);
                m_add_id(p_parent, reqid);
                m_add_string(p_parent, username);
                m_add_string(p_parent, password);
                m_close(p_parent);
                return;
            }

            ret = lka_authenticate(tablename, username, password);

            m_create(p, IMSG_LKA_AUTHENTICATE, 0, 0, -1);
            m_add_id(p, reqid);
            m_add_int(p, ret);
            m_close(p);
            return;
        }
    }

    if (p->proc == PROC_MDA) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_USERINFO:
            m_msg(&m, imsg);
            m_get_string(&m, &tablename);
            m_get_string(&m, &username);
            m_end(&m);

            ret = lka_userinfo(tablename, username, &userinfo);

            m_create(p, IMSG_LKA_USERINFO, 0, 0, -1);
            m_add_string(p, tablename);
            m_add_string(p, username);
            m_add_int(p, ret);
            if (ret == LKA_OK)
                m_add_data(p, &userinfo, sizeof(userinfo));
            m_close(p);
            return;
        }
    }

    if (p->proc == PROC_MTA) {
        switch (imsg->hdr.type) {

        case IMSG_LKA_SSL_INIT:
            req_ca_cert = imsg->data;
            resp_ca_cert.reqid = req_ca_cert->reqid;

            ssl = dict_get(env->sc_ssl_dict, req_ca_cert->name);
            if (ssl == NULL) {
                resp_ca_cert.status = CA_FAIL;
                m_compose(p, IMSG_LKA_SSL_INIT, 0, 0, -1, &resp_ca_cert,
                          sizeof(resp_ca_cert));
                return;
            }
            resp_ca_cert.status = CA_OK;
            resp_ca_cert.cert_len = ssl->ssl_cert_len;
            resp_ca_cert.key_len = ssl->ssl_key_len;
            iov[0].iov_base = &resp_ca_cert;
            iov[0].iov_len = sizeof(resp_ca_cert);
            iov[1].iov_base = ssl->ssl_cert;
            iov[1].iov_len = ssl->ssl_cert_len;
            iov[2].iov_base = ssl->ssl_key;
            iov[2].iov_len = ssl->ssl_key_len;
            m_composev(p, IMSG_LKA_SSL_INIT, 0, 0, -1, iov, nitems(iov));
            return;

        case IMSG_LKA_SSL_VERIFY_CERT:
            req_ca_vrfy_mta = xmemdup(imsg->data, sizeof *req_ca_vrfy_mta, "lka:ca_vrfy");
            if (req_ca_vrfy_mta == NULL)
                fatal(NULL);
            req_ca_vrfy_mta->cert = xmemdup((char *)imsg->data +
                                            sizeof *req_ca_vrfy_mta, req_ca_vrfy_mta->cert_len, "lka:ca_vrfy");
            req_ca_vrfy_mta->chain_cert = xcalloc(req_ca_vrfy_mta->n_chain,
                                                  sizeof (unsigned char *), "lka:ca_vrfy");
            req_ca_vrfy_mta->chain_cert_len = xcalloc(req_ca_vrfy_mta->n_chain,
                                              sizeof (off_t), "lka:ca_vrfy");
            return;

        case IMSG_LKA_SSL_VERIFY_CHAIN:
            if (req_ca_vrfy_mta == NULL)
                fatalx("lka:ca_vrfy: verify without a certificate");

            req_ca_vrfy_chain = imsg->data;
            req_ca_vrfy_mta->chain_cert[req_ca_vrfy_mta->chain_offset] = xmemdup((char *)imsg->data +
                    sizeof *req_ca_vrfy_chain, req_ca_vrfy_chain->cert_len, "lka:ca_vrfy");
            req_ca_vrfy_mta->chain_cert_len[req_ca_vrfy_mta->chain_offset] = req_ca_vrfy_chain->cert_len;
            req_ca_vrfy_mta->chain_offset++;
            return;

        case IMSG_LKA_SSL_VERIFY:
            if (req_ca_vrfy_mta == NULL)
                fatalx("lka:ca_vrfy: verify without a certificate");

            resp_ca_vrfy.reqid = req_ca_vrfy_mta->reqid;

            if (! lka_X509_verify(req_ca_vrfy_mta, CA_FILE, NULL))
                resp_ca_vrfy.status = CA_FAIL;
            else
                resp_ca_vrfy.status = CA_OK;

            m_compose(p, IMSG_LKA_SSL_VERIFY, 0, 0, -1, &resp_ca_vrfy,
                      sizeof resp_ca_vrfy);

            for (i = 0; i < req_ca_vrfy_mta->n_chain; ++i)
                free(req_ca_vrfy_mta->chain_cert[i]);
            free(req_ca_vrfy_mta->chain_cert);
            free(req_ca_vrfy_mta->chain_cert_len);
            free(req_ca_vrfy_mta->cert);
            free(req_ca_vrfy_mta);
            return;

        case IMSG_LKA_SECRET:
            m_msg(&m, imsg);
            m_get_id(&m, &reqid);
            m_get_string(&m, &tablename);
            m_get_string(&m, &label);
            m_end(&m);

            lka_credentials(tablename, label, buf, sizeof(buf));

            m_create(p, IMSG_LKA_SECRET, 0, 0, -1);
            m_add_id(p, reqid);
            m_add_string(p, buf);
            m_close(p);
            return;

        case IMSG_LKA_SOURCE:
            m_msg(&m, imsg);
            m_get_id(&m, &reqid);
            m_get_string(&m, &tablename);

            table = table_find(tablename, NULL);

            m_create(p, IMSG_LKA_SOURCE, 0, 0, -1);
            m_add_id(p, reqid);

            if (table == NULL) {
                log_warn("warn: source address table %s missing",
                         tablename);
                m_add_int(p, LKA_TEMPFAIL);
            }
            else {
                ret = table_fetch(table, K_SOURCE, &lk);
                if (ret == -1)
                    m_add_int(p, LKA_TEMPFAIL);
                else if (ret == 0)
                    m_add_int(p, LKA_PERMFAIL);
                else {
                    m_add_int(p, LKA_OK);
                    m_add_sockaddr(p,
                                   (struct sockaddr *)&lk.source.addr);
                }
            }
            m_close(p);
            return;

        case IMSG_LKA_HELO:
            m_msg(&m, imsg);
            m_get_id(&m, &reqid);
            m_get_string(&m, &tablename);
            m_get_sockaddr(&m, (struct sockaddr *)&ss);
            m_end(&m);

            ret = lka_addrname(tablename, (struct sockaddr*)&ss,
                               &addrname);

            m_create(p, IMSG_LKA_HELO, 0, 0, -1);
            m_add_id(p, reqid);
            m_add_int(p, ret);
            if (ret == LKA_OK)
                m_add_string(p, addrname.name);
            m_close(p);
            return;

        }
    }

    if (p->proc == PROC_PARENT) {
        switch (imsg->hdr.type) {
        case IMSG_CONF_START:
            env->sc_rules_reload = xcalloc(1,
                                           sizeof *env->sc_rules, "lka:sc_rules_reload");
            tables_dict = xcalloc(1,
                                  sizeof *tables_dict, "lka:tables_dict");

            ssl_dict = calloc(1, sizeof *ssl_dict);
            if (ssl_dict == NULL)
                fatal(NULL);
            dict_init(ssl_dict);
            dict_init(tables_dict);
            TAILQ_INIT(env->sc_rules_reload);

            return;

        case IMSG_CONF_SSL:
            ssl = calloc(1, sizeof *ssl);
            if (ssl == NULL)
                fatal(NULL);
            *ssl = *(struct ssl *)imsg->data;
            ssl->ssl_cert = xstrdup((char *)imsg->data +
                                    sizeof *ssl, "smtp:ssl_cert");
            ssl->ssl_key = xstrdup((char *)imsg->data +
                                   sizeof *ssl + ssl->ssl_cert_len, "smtp:ssl_key");
            if (ssl->ssl_dhparams_len) {
                ssl->ssl_dhparams = xstrdup((char *)imsg->data
                                            + sizeof *ssl + ssl->ssl_cert_len +
                                            ssl->ssl_key_len, "smtp:ssl_dhparams");
            }
            if (ssl->ssl_ca_len) {
                ssl->ssl_ca = xstrdup((char *)imsg->data
                                      + sizeof *ssl + ssl->ssl_cert_len +
                                      ssl->ssl_key_len + ssl->ssl_dhparams_len,
                                      "smtp:ssl_ca");
            }
            dict_set(ssl_dict, ssl->ssl_name, ssl);
            return;

        case IMSG_CONF_RULE:
            rule = xmemdup(imsg->data, sizeof *rule, "lka:rule");
            TAILQ_INSERT_TAIL(env->sc_rules_reload, rule, r_entry);
            return;

        case IMSG_CONF_TABLE:
            table_last = table = xmemdup(imsg->data, sizeof *table,
                                         "lka:table");
            dict_init(&table->t_dict);
            dict_set(tables_dict, table->t_name, table);
            return;

        case IMSG_CONF_RULE_SOURCE:
            rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
            tmp = env->sc_tables_dict;
            env->sc_tables_dict = tables_dict;
            rule->r_sources = table_find(imsg->data, NULL);
            if (rule->r_sources == NULL)
                fatalx("lka: tables inconsistency");
            env->sc_tables_dict = tmp;
            return;

        case IMSG_CONF_RULE_SENDER:
            rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
            tmp = env->sc_tables_dict;
            env->sc_tables_dict = tables_dict;
            rule->r_senders = table_find(imsg->data, NULL);
            if (rule->r_senders == NULL)
                fatalx("lka: tables inconsistency");
            env->sc_tables_dict = tmp;
            return;

        case IMSG_CONF_RULE_DESTINATION:
            rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
            tmp = env->sc_tables_dict;
            env->sc_tables_dict = tables_dict;
            rule->r_destination = table_find(imsg->data, NULL);
            if (rule->r_destination == NULL)
                fatalx("lka: tables inconsistency");
            env->sc_tables_dict = tmp;
            return;

        case IMSG_CONF_RULE_MAPPING:
            rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
            tmp = env->sc_tables_dict;
            env->sc_tables_dict = tables_dict;
            rule->r_mapping = table_find(imsg->data, NULL);
            if (rule->r_mapping == NULL)
                fatalx("lka: tables inconsistency");
            env->sc_tables_dict = tmp;
            return;

        case IMSG_CONF_RULE_USERS:
            rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
            tmp = env->sc_tables_dict;
            env->sc_tables_dict = tables_dict;
            rule->r_userbase = table_find(imsg->data, NULL);
            if (rule->r_userbase == NULL)
                fatalx("lka: tables inconsistency");
            env->sc_tables_dict = tmp;
            return;

        case IMSG_CONF_TABLE_CONTENT:
            table = table_last;
            if (table == NULL)
                fatalx("lka: tables inconsistency");

            key = imsg->data;
            if (table->t_type == T_HASH)
                val = key + strlen(key) + 1;
            else
                val = NULL;

            dict_set(&table->t_dict, key,
                     val ? xstrdup(val, "lka:dict_set") : NULL);
            return;

        case IMSG_CONF_END:

            if (env->sc_rules)
                purge_config(PURGE_RULES);
            if (env->sc_tables_dict) {
                table_close_all();
                purge_config(PURGE_TABLES);
            }
            env->sc_rules = env->sc_rules_reload;
            env->sc_ssl_dict = ssl_dict;
            env->sc_tables_dict = tables_dict;
            if (verbose & TRACE_TABLES)
                table_dump_all();
            table_open_all();

            ssl_dict = NULL;
            table_last = NULL;
            tables_dict = NULL;

            /* Start fulfilling requests */
            mproc_enable(p_mda);
            mproc_enable(p_mta);
            mproc_enable(p_smtp);
            return;

        case IMSG_CTL_VERBOSE:
            m_msg(&m, imsg);
            m_get_int(&m, &v);
            m_end(&m);
            log_verbose(v);
            return;

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

        case IMSG_PARENT_FORWARD_OPEN:
            lka_session_forward_reply(imsg->data, imsg->fd);
            return;

        case IMSG_LKA_AUTHENTICATE:
            m_forward(p_smtp, imsg);
            return;
        }
    }

    if (p->proc == PROC_CONTROL) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_UPDATE_TABLE:
            table = table_find(imsg->data, NULL);
            if (table == NULL) {
                log_warnx("warn: Lookup table not found: "
                          "\"%s\"", (char *)imsg->data);
                return;
            }
            table_update(table);
            return;
        }
    }

    errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
}
Ejemplo n.º 12
0
static void
lka_resume(struct lka_session *lks)
{
	struct envelope		*ep;
	struct expandnode	*xn;

	if (lks->error)
		goto error;

	/* pop next node and expand it */
	while ((xn = TAILQ_FIRST(&lks->nodes))) {
		TAILQ_REMOVE(&lks->nodes, xn, tq_entry);
		lka_expand(lks, xn->rule, xn);
		if (lks->flags & F_WAITING)
			return;
		if (lks->error)
			goto error;
	}

	/* delivery list is empty, reject */
	if (TAILQ_FIRST(&lks->deliverylist) == NULL) {
		log_trace(TRACE_EXPAND, "expand: lka_done: expanded to empty "
		    "delivery list");
		lks->error = LKA_PERMFAIL;
	}
    error:
	if (lks->error) {
		m_create(p_smtp, IMSG_LKA_EXPAND_RCPT, 0, 0, -1);
		m_add_id(p_smtp, lks->id);
		m_add_int(p_smtp, lks->error);

		if (lks->errormsg)
			m_add_string(p_smtp, lks->errormsg);
		else {
			if (lks->error == LKA_PERMFAIL)
				m_add_string(p_smtp, "550 Invalid recipient");
			else if (lks->error == LKA_TEMPFAIL)
				m_add_string(p_smtp, "451 Temporary failure");
		}

		m_close(p_smtp);
		while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) {
			TAILQ_REMOVE(&lks->deliverylist, ep, entry);
			free(ep);
		}
	}
	else {
		/* Process the delivery list and submit envelopes to queue */
		while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) {
			TAILQ_REMOVE(&lks->deliverylist, ep, entry);
			m_create(p_queue, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1);
			m_add_id(p_queue, lks->id);
			m_add_envelope(p_queue, ep);
			m_close(p_queue);
			free(ep);
		}

		m_create(p_queue, IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1);
		m_add_id(p_queue, lks->id);
		m_close(p_queue);
	}

	expand_clear(&lks->expand);
	tree_xpop(&sessions, lks->id);
	free(lks);
}
Ejemplo n.º 13
0
/* ARGSUSED */
static void
control_dispatch_ext(struct mproc *p, struct imsg *imsg)
{
	struct sockaddr_storage	 ss;
	struct ctl_conn		*c;
	int			 v;
	struct stat_kv		*kvp;
	char			*key;
	struct stat_value	 val;
	size_t			 len;

	c = p->data;

	if (imsg == NULL) {
		control_close(c);
		return;
	}

	if (imsg->hdr.peerid != IMSG_VERSION) {
		m_compose(p, IMSG_CTL_FAIL, IMSG_VERSION, 0, -1, NULL, 0);
		return;
	}

	switch (imsg->hdr.type) {
	case IMSG_SMTP_ENQUEUE_FD:
		if (env->sc_flags & (SMTPD_SMTP_PAUSED | SMTPD_EXITING)) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		m_compose(p_smtp, IMSG_SMTP_ENQUEUE_FD, c->id, 0, -1,
		    &c->euid, sizeof(c->euid));
		return;

	case IMSG_STATS:
		if (c->euid)
			goto badcred;
		m_compose(p, IMSG_STATS, 0, 0, -1, NULL, 0);
		return;

	case IMSG_DIGEST:
		if (c->euid)
			goto badcred;
		digest.timestamp = time(NULL);
		m_compose(p, IMSG_DIGEST, 0, 0, -1, &digest, sizeof digest);
		return;

	case IMSG_STATS_GET:
		if (c->euid)
			goto badcred;
		kvp = imsg->data;
		if (! stat_backend->iter(&kvp->iter, &key, &val))
			kvp->iter = NULL;
		else {
			strlcpy(kvp->key, key, sizeof kvp->key);
			kvp->val = val;
		}
		m_compose(p, IMSG_STATS_GET, 0, 0, -1, kvp, sizeof *kvp);
		return;

	case IMSG_CTL_SHUTDOWN:
		/* NEEDS_FIX */
		log_debug("debug: received shutdown request");

		if (c->euid)
			goto badcred;

		if (env->sc_flags & SMTPD_EXITING) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		env->sc_flags |= SMTPD_EXITING;
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		m_compose(p_parent, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_VERBOSE:
		if (c->euid)
			goto badcred;

		if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose))
			goto badcred;

		memcpy(&v, imsg->data, sizeof(v));
		verbose = v;
		log_verbose(verbose);

		m_create(p_parent, IMSG_CTL_VERBOSE, 0, 0, -1);
		m_add_int(p_parent, verbose);
		m_close(p_parent);

		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_TRACE:
		if (c->euid)
			goto badcred;

		if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose))
			goto badcred;

		memcpy(&v, imsg->data, sizeof(v));
		verbose |= v;
		log_verbose(verbose);

		m_create(p_parent, IMSG_CTL_TRACE, 0, 0, -1);
		m_add_int(p_parent, v);
		m_close(p_parent);

		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_UNTRACE:
		if (c->euid)
			goto badcred;

		if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose))
			goto badcred;

		memcpy(&v, imsg->data, sizeof(v));
		verbose &= ~v;
		log_verbose(verbose);

		m_create(p_parent, IMSG_CTL_UNTRACE, 0, 0, -1);
		m_add_int(p_parent, v);
		m_close(p_parent);

		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_PROFILE:
		if (c->euid)
			goto badcred;

		if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose))
			goto badcred;

		memcpy(&v, imsg->data, sizeof(v));
		profiling |= v;

		m_create(p_parent, IMSG_CTL_PROFILE, 0, 0, -1);
		m_add_int(p_parent, v);
		m_close(p_parent);

		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_UNPROFILE:
		if (c->euid)
			goto badcred;

		if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose))
			goto badcred;

		memcpy(&v, imsg->data, sizeof(v));
		profiling &= ~v;

		m_create(p_parent, IMSG_CTL_UNPROFILE, 0, 0, -1);
		m_add_int(p_parent, v);
		m_close(p_parent);

		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_PAUSE_EVP:
		if (c->euid)
			goto badcred;

		imsg->hdr.peerid = c->id;
		m_forward(p_scheduler, imsg);
		return;

	case IMSG_CTL_PAUSE_MDA:
		if (c->euid)
			goto badcred;

		if (env->sc_flags & SMTPD_MDA_PAUSED) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		log_info("info: mda paused");
		env->sc_flags |= SMTPD_MDA_PAUSED;
		m_compose(p_queue, IMSG_CTL_PAUSE_MDA, 0, 0, -1, NULL, 0);
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_PAUSE_MTA:
		if (c->euid)
			goto badcred;

		if (env->sc_flags & SMTPD_MTA_PAUSED) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		log_info("info: mta paused");
		env->sc_flags |= SMTPD_MTA_PAUSED;
		m_compose(p_queue, IMSG_CTL_PAUSE_MTA, 0, 0, -1, NULL, 0);
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_PAUSE_SMTP:
		if (c->euid)
			goto badcred;

		if (env->sc_flags & SMTPD_SMTP_PAUSED) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		log_info("info: smtp paused");
		env->sc_flags |= SMTPD_SMTP_PAUSED;
		m_compose(p_smtp, IMSG_CTL_PAUSE_SMTP, 0, 0, -1, NULL, 0);
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_RESUME_EVP:
		if (c->euid)
			goto badcred;

		imsg->hdr.peerid = c->id;
		m_forward(p_scheduler, imsg);
		return;

	case IMSG_CTL_RESUME_MDA:
		if (c->euid)
			goto badcred;

		if (! (env->sc_flags & SMTPD_MDA_PAUSED)) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		log_info("info: mda resumed");
		env->sc_flags &= ~SMTPD_MDA_PAUSED;
		m_compose(p_queue, IMSG_CTL_RESUME_MDA, 0, 0, -1, NULL, 0);
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_RESUME_MTA:
		if (c->euid)
			goto badcred;

		if (!(env->sc_flags & SMTPD_MTA_PAUSED)) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		log_info("info: mta resumed");
		env->sc_flags &= ~SMTPD_MTA_PAUSED;
		m_compose(p_queue, IMSG_CTL_RESUME_MTA, 0, 0, -1, NULL, 0);
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_RESUME_SMTP:
		if (c->euid)
			goto badcred;

		if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		log_info("info: smtp resumed");
		env->sc_flags &= ~SMTPD_SMTP_PAUSED;
		m_forward(p_smtp, imsg);
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_RESUME_ROUTE:
		if (c->euid)
			goto badcred;

		m_forward(p_mta, imsg);
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	case IMSG_CTL_LIST_MESSAGES:
		if (c->euid)
			goto badcred;
		m_compose(p_scheduler, IMSG_CTL_LIST_MESSAGES, c->id, 0, -1,
		    imsg->data, imsg->hdr.len - sizeof(imsg->hdr));
		return;

	case IMSG_CTL_LIST_ENVELOPES:
		if (c->euid)
			goto badcred;
		m_compose(p_scheduler, IMSG_CTL_LIST_ENVELOPES, c->id, 0, -1,
		    imsg->data, imsg->hdr.len - sizeof(imsg->hdr));
		return;

	case IMSG_CTL_MTA_SHOW_HOSTS:
	case IMSG_CTL_MTA_SHOW_RELAYS:
	case IMSG_CTL_MTA_SHOW_ROUTES:
	case IMSG_CTL_MTA_SHOW_HOSTSTATS:
	case IMSG_CTL_MTA_SHOW_BLOCK:
		if (c->euid)
			goto badcred;

		imsg->hdr.peerid = c->id;
		m_forward(p_mta, imsg);
		return;

	case IMSG_CTL_MTA_BLOCK:
	case IMSG_CTL_MTA_UNBLOCK:
		if (c->euid)
			goto badcred;

		if (imsg->hdr.len - IMSG_HEADER_SIZE <= sizeof(ss))
			goto invalid;
		memmove(&ss, imsg->data, sizeof(ss));
		m_create(p_mta, imsg->hdr.type, c->id, 0, -1);
		m_add_sockaddr(p_mta, (struct sockaddr *)&ss);
		m_add_string(p_mta, (char *)imsg->data + sizeof(ss));
		m_close(p_mta);
		return;

	case IMSG_CTL_SCHEDULE:
		if (c->euid)
			goto badcred;

		imsg->hdr.peerid = c->id;
		m_forward(p_scheduler, imsg);
		return;

	case IMSG_CTL_REMOVE:
		if (c->euid)
			goto badcred;

		imsg->hdr.peerid = c->id;
		m_forward(p_scheduler, imsg);
		return;

	case IMSG_LKA_UPDATE_TABLE:
		if (c->euid)
			goto badcred;

		/* table name too long */
		len = strlen(imsg->data);
		if (len >= SMTPD_MAXLINESIZE)
			goto invalid;

		m_forward(p_lka, imsg);
		m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
		return;

	default:
		log_debug("debug: control_dispatch_ext: "
		    "error handling %s imsg",
		    imsg_to_str(imsg->hdr.type));
		return;
	}
badcred:
invalid:
	m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
}
Ejemplo n.º 14
0
void
dns_imsg(struct mproc *p, struct imsg *imsg)
{
	struct sockaddr_storage	 ss;
	struct dns_session	*s;
	struct sockaddr		*sa;
	struct asr_query	*as;
	struct msg		 m;
	const char		*domain, *mx, *host;
	socklen_t		 sl;

	s = xcalloc(1, sizeof *s, "dns_imsg");
	s->type = imsg->hdr.type;
	s->p = p;

	m_msg(&m, imsg);
	m_get_id(&m, &s->reqid);

	switch (s->type) {

	case IMSG_MTA_DNS_HOST:
		m_get_string(&m, &host);
		m_end(&m);
		dns_lookup_host(s, host, -1);
		return;

	case IMSG_MTA_DNS_PTR:
	case IMSG_SMTP_DNS_PTR:
		sa = (struct sockaddr *)&ss;
		m_get_sockaddr(&m, sa);
		m_end(&m);
		as = getnameinfo_async(sa, SA_LEN(sa), s->name, sizeof(s->name),
		    NULL, 0, 0, NULL);
		event_asr_run(as, dns_dispatch_ptr, s);
		return;

	case IMSG_MTA_DNS_MX:
		m_get_string(&m, &domain);
		m_end(&m);
		(void)strlcpy(s->name, domain, sizeof(s->name));

		sa = (struct sockaddr *)&ss;
		sl = sizeof(ss);

		if (domainname_is_addr(domain, sa, &sl)) {
			m_create(s->p, IMSG_MTA_DNS_HOST, 0, 0, -1);
			m_add_id(s->p, s->reqid);
			m_add_sockaddr(s->p, sa);
			m_add_int(s->p, -1);
			m_close(s->p);

			m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1);
			m_add_id(s->p, s->reqid);
			m_add_int(s->p, DNS_OK);
			m_close(s->p);
			free(s);
			return;
		}

		as = res_query_async(s->name, C_IN, T_MX, NULL);
		if (as == NULL) {
			log_warn("warn: req_query_async: %s", s->name);
			m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1);
			m_add_id(s->p, s->reqid);
			m_add_int(s->p, DNS_EINVAL);
			m_close(s->p);
			free(s);
			return;
		}

		event_asr_run(as, dns_dispatch_mx, s);
		return;

	case IMSG_MTA_DNS_MX_PREFERENCE:
		m_get_string(&m, &domain);
		m_get_string(&m, &mx);
		m_end(&m);
		(void)strlcpy(s->name, mx, sizeof(s->name));

		as = res_query_async(domain, C_IN, T_MX, NULL);
		if (as == NULL) {
			m_create(s->p, IMSG_MTA_DNS_MX_PREFERENCE, 0, 0, -1);
			m_add_id(s->p, s->reqid);
			m_add_int(s->p, DNS_ENOTFOUND);
			m_close(s->p);
			free(s);
			return;
		}

		event_asr_run(as, dns_dispatch_mx_preference, s);
		return;

	default:
		log_warnx("warn: bad dns request %d", s->type);
		fatal(NULL);
	}
}
Ejemplo n.º 15
0
static void
filter_dispatch(struct mproc *p, struct imsg *imsg)
{
	struct filter_session	*s;
	struct filter_connect	 q_connect;
	struct mailaddr		 maddr;
	struct msg		 m;
	const char		*line, *name;
	uint32_t		 v, datalen;
	uint64_t		 id, qid;
	int			 status, type;
	int			 fds[2], fdin, fdout;

	log_trace(TRACE_FILTERS, "filter-api:%s imsg %s", filter_name,
	    filterimsg_to_str(imsg->hdr.type));

	switch (imsg->hdr.type) {
	case IMSG_FILTER_REGISTER:
		m_msg(&m, imsg);
		m_get_u32(&m, &v);
		m_get_string(&m, &name);
		filter_name = strdup(name);
		m_end(&m);
		if (v != FILTER_API_VERSION) {
			log_warnx("warn: filter-api:%s API mismatch", filter_name);
			fatalx("filter-api: exiting");
		}
		m_create(p, IMSG_FILTER_REGISTER, 0, 0, -1);
		m_add_int(p, fi.hooks);
		m_add_int(p, fi.flags);
		m_close(p);
		break;

	case IMSG_FILTER_EVENT:
		m_msg(&m, imsg);
		m_get_id(&m, &id);
		m_get_int(&m, &type);
		m_end(&m);
		switch (type) {
		case EVENT_CONNECT:
			s = xcalloc(1, sizeof(*s), "filter_dispatch");
			s->id = id;
			s->pipe.iev.sock = -1;
			s->pipe.oev.sock = -1;
			tree_xset(&sessions, id, s);
			break;
		case EVENT_DISCONNECT:
			filter_dispatch_disconnect(id);
			s = tree_xpop(&sessions, id);
			free(s);
			break;
		case EVENT_RESET:
			filter_dispatch_reset(id);
			break;
		case EVENT_COMMIT:
			filter_dispatch_commit(id);
			break;
		case EVENT_ROLLBACK:
			filter_dispatch_rollback(id);
			break;
		default:
			log_warnx("warn: filter-api:%s bad event %d", filter_name, type);
			fatalx("filter-api: exiting");
		}
		break;

	case IMSG_FILTER_QUERY:
		m_msg(&m, imsg);
		m_get_id(&m, &id);
		m_get_id(&m, &qid);
		m_get_int(&m, &type);
		switch(type) {
		case QUERY_CONNECT:
			m_get_sockaddr(&m, (struct sockaddr*)&q_connect.local);
			m_get_sockaddr(&m, (struct sockaddr*)&q_connect.remote);
			m_get_string(&m, &q_connect.hostname);
			m_end(&m);
			filter_register_query(id, qid, type);
			filter_dispatch_connect(id, &q_connect);
			break;
		case QUERY_HELO:
			m_get_string(&m, &line);
			m_end(&m);
			filter_register_query(id, qid, type);
			filter_dispatch_helo(id, line);
			break;
		case QUERY_MAIL:
			m_get_mailaddr(&m, &maddr);
			m_end(&m);
			filter_register_query(id, qid, type);
			filter_dispatch_mail(id, &maddr);
			break;
		case QUERY_RCPT:
			m_get_mailaddr(&m, &maddr);
			m_end(&m);
			filter_register_query(id, qid, type);
			filter_dispatch_rcpt(id, &maddr);
			break;
		case QUERY_DATA:
			m_end(&m);
			filter_register_query(id, qid, type);
			filter_dispatch_data(id);
			break;
		case QUERY_EOM:
			m_get_u32(&m, &datalen);
			m_end(&m);
			filter_register_query(id, qid, type);
			filter_dispatch_eom(id, datalen);
			break;
		default:
			log_warnx("warn: filter-api:%s bad query %d", filter_name, type);
			fatalx("filter-api: exiting");
		}
		break;

	case IMSG_FILTER_PIPE:
		m_msg(&m, imsg);
		m_get_id(&m, &id);
		m_end(&m);

		fdout = imsg->fd;
		fdin = -1;

		if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) == -1) {
			log_warn("warn: filter-api:%s socketpair", filter_name);
			close(fdout);
		}
		else {
			s = tree_xget(&sessions, id);

			s->pipe.eom_called = 0;
			s->pipe.error = 0;
			s->pipe.idatalen = 0;
			s->pipe.odatalen = 0;

			iobuf_init(&s->pipe.obuf, 0, 0);
			io_init(&s->pipe.oev, fdout, s, filter_io_out, &s->pipe.obuf);
			io_set_write(&s->pipe.oev);

			iobuf_init(&s->pipe.ibuf, 0, 0);
			io_init(&s->pipe.iev, fds[0], s, filter_io_in, &s->pipe.ibuf);
			io_set_read(&s->pipe.iev);

			fdin = fds[1];
		}

		log_trace(TRACE_FILTERS, "filter-api:%s %016"PRIx64" tx pipe %d -> %d",
		    filter_name, id, fdin, fdout);

		m_create(&fi.p, IMSG_FILTER_PIPE, 0, 0, fdin);
		m_add_id(&fi.p, id);
		m_close(&fi.p);

		break;
	}
}
Ejemplo n.º 16
0
Archivo: ca.c Proyecto: gunhu/OpenSMTPD
void
ca_imsg(struct mproc *p, struct imsg *imsg)
{
	RSA			*rsa;
	const void		*from = NULL;
	unsigned char		*to = NULL;
	struct msg		 m;
	const char		*pkiname;
	size_t			 flen, tlen, padding;
	struct pki		*pki;
	int			 ret = 0;
	uint64_t		 id;
	int			 v;

	if (p->proc == PROC_PARENT) {
		switch (imsg->hdr.type) {
		case IMSG_CONF_START:
			return;
		case IMSG_CONF_END:
			ca_init();

			/* Start fulfilling requests */
			mproc_enable(p_pony);
			return;
		}
	}

	if (p->proc == PROC_CONTROL) {
		switch (imsg->hdr.type) {
		case IMSG_CTL_VERBOSE:
			m_msg(&m, imsg);
			m_get_int(&m, &v);
			m_end(&m);
			log_verbose(v);
			return;
		case IMSG_CTL_PROFILE:
			m_msg(&m, imsg);
			m_get_int(&m, &v);
			m_end(&m);
			profiling = v;
			return;
		}
	}

	if (p->proc == PROC_PONY) {
		switch (imsg->hdr.type) {
		case IMSG_CA_PRIVENC:
		case IMSG_CA_PRIVDEC:
			m_msg(&m, imsg);
			m_get_id(&m, &id);
			m_get_string(&m, &pkiname);
			m_get_data(&m, &from, &flen);
			m_get_size(&m, &tlen);
			m_get_size(&m, &padding);
			m_end(&m);

			pki = dict_get(env->sc_pki_dict, pkiname);
			if (pki == NULL || pki->pki_pkey == NULL ||
			    (rsa = EVP_PKEY_get1_RSA(pki->pki_pkey)) == NULL)
				fatalx("ca_imsg: invalid pki");

			if ((to = calloc(1, tlen)) == NULL)
				fatalx("ca_imsg: calloc");

			switch (imsg->hdr.type) {
			case IMSG_CA_PRIVENC:
				ret = RSA_private_encrypt(flen, from, to, rsa,
				    padding);
				break;
			case IMSG_CA_PRIVDEC:
				ret = RSA_private_decrypt(flen, from, to, rsa,
				    padding);
				break;
			}

			m_create(p, imsg->hdr.type, 0, 0, -1);
			m_add_id(p, id);
			m_add_int(p, ret);
			if (ret > 0)
				m_add_data(p, to, (size_t)ret);
			m_close(p);

			free(to);
			RSA_free(rsa);

			return;
		}
	}

	errx(1, "ca_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
}