Exemple #1
0
      void operator() (const TVectorType& y, TVectorType& x)
      {
        typedef typename TVectorType::value_type value_type;

  //setVectorConstant(x, 0);
  // r = b
  // d = r
  TVectorType d = y;
  TVectorType r = y;
  TVectorType ro;
  TVectorType Ad;
  TVectorType Ar;
  TVectorType Aro;

  // Ar = A*r ;
  m_forward(r, Ar);
  Ad = Ar;

  // res0 = r'*r;
  value_type res0 = m_binary_measure(r, r);
  m_rho_0 = std::abs(res0);
        for (m_iteration = 0; m_iteration < m_max_iterations; ++m_iteration)
        {
      ro = r;
      Aro = Ar;
      // alpha = (r'*Ar) / (Ad'*Ad);
      value_type alpha = m_binary_measure(r, Ar) / m_binary_measure(Ad, Ad);
      // x = x + alpha*d;
      addScaledVector(x, alpha, d, x);
      // r = r - alpha*Ad;
      subScaledVector(r, alpha, Ad, r);
      // res = r'*r;
      value_type res = m_binary_measure(r, r);

      m_rho_k = std::abs(res);

      if (m_rho_k < (m_rel_tolerance*m_rel_tolerance*m_rho_0))
      {
        break;
      }
      //Ar = A*r;
      m_forward(r, Ar);
      // beta = (r'*Ar) / (ro'*Aro);
      value_type beta = m_binary_measure(r, Ar) / m_binary_measure(ro, Aro);
      // d =  r + beta*d;
      addScaledVector(r, beta, d, d);
      // Ad = Ar + beta*Ad;
      addScaledVector(Ar, beta, Ad, Ad);

        }
      }
Exemple #2
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));
}
Exemple #3
0
static void
control_imsg(struct mproc *p, struct imsg *imsg)
{
	struct ctl_conn		*c;
	struct stat_value	 val;
	struct msg		 m;
	const char		*key;
	const void		*data;
	size_t			 sz;

	if (p->proc == PROC_PONY) {
		switch (imsg->hdr.type) {
		case IMSG_CTL_SMTP_SESSION:
			c = tree_get(&ctl_conns, imsg->hdr.peerid);
			if (c == NULL)
				return;
			m_compose(&c->mproc, IMSG_CTL_OK, 0, 0, imsg->fd,
			    NULL, 0);
			return;
		}
	}
	if (p->proc == PROC_SCHEDULER) {
		switch (imsg->hdr.type) {
		case IMSG_CTL_OK:
		case IMSG_CTL_FAIL:
		case IMSG_CTL_LIST_MESSAGES:
			c = tree_get(&ctl_conns, imsg->hdr.peerid);
			if (c == NULL)
				return;
			imsg->hdr.peerid = 0;
			m_forward(&c->mproc, imsg);
			return;
		}
	}
	if (p->proc == PROC_QUEUE) {
		switch (imsg->hdr.type) {
		case IMSG_CTL_LIST_ENVELOPES:
		case IMSG_CTL_DISCOVER_EVPID:
		case IMSG_CTL_DISCOVER_MSGID:
		case IMSG_CTL_UNCORRUPT_MSGID:
			c = tree_get(&ctl_conns, imsg->hdr.peerid);
			if (c == NULL)
				return;
			m_forward(&c->mproc, imsg);
			return;
		}
	}
	if (p->proc == PROC_PONY) {
		switch (imsg->hdr.type) {
		case IMSG_CTL_OK:
		case IMSG_CTL_FAIL:
		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:
			c = tree_get(&ctl_conns, imsg->hdr.peerid);
			if (c == NULL)
				return;
			imsg->hdr.peerid = 0;
			m_forward(&c->mproc, imsg);
			return;
		}
	}

	switch (imsg->hdr.type) {
	case IMSG_STAT_INCREMENT:
		m_msg(&m, imsg);
		m_get_string(&m, &key);
		m_get_data(&m, &data, &sz);
		m_end(&m);
		memmove(&val, data, sz);
		if (stat_backend)
			stat_backend->increment(key, val.u.counter);
		control_digest_update(key, val.u.counter, 1);
		return;
	case IMSG_STAT_DECREMENT:
		m_msg(&m, imsg);
		m_get_string(&m, &key);
		m_get_data(&m, &data, &sz);
		m_end(&m);
		memmove(&val, data, sz);
		if (stat_backend)
			stat_backend->decrement(key, val.u.counter);
		control_digest_update(key, val.u.counter, 0);
		return;
	case IMSG_STAT_SET:
		m_msg(&m, imsg);
		m_get_string(&m, &key);
		m_get_data(&m, &data, &sz);
		m_end(&m);
		memmove(&val, data, sz);
		if (stat_backend)
			stat_backend->set(key, &val);
		return;
	}

	errx(1, "control_imsg: unexpected %s imsg",
	    imsg_to_str(imsg->hdr.type));
}
Exemple #4
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;
	uint64_t		 evpid;
	uint32_t		 msgid;

	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_CTL_SMTP_SESSION:
		if (env->sc_flags & (SMTPD_SMTP_PAUSED | SMTPD_EXITING)) {
			m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
			return;
		}
		m_compose(p_pony, IMSG_CTL_SMTP_SESSION, c->id, 0, -1,
		    &c->euid, sizeof(c->euid));
		return;

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

	case IMSG_CTL_GET_STATS:
		if (c->euid)
			goto badcred;
		kvp = imsg->data;
		if (! stat_backend->iter(&kvp->iter, &key, &val))
			kvp->iter = NULL;
		else {
			(void)strlcpy(kvp->key, key, sizeof kvp->key);
			kvp->val = val;
		}
		m_compose(p, IMSG_CTL_GET_STATS, 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);

		control_broadcast_verbose(IMSG_CTL_VERBOSE, verbose);

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

	case IMSG_CTL_TRACE_ENABLE:
		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);

		control_broadcast_verbose(IMSG_CTL_VERBOSE, verbose);

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

	case IMSG_CTL_TRACE_DISABLE:
		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);

		control_broadcast_verbose(IMSG_CTL_VERBOSE, verbose);

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

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

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

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

		control_broadcast_verbose(IMSG_CTL_PROFILE, profiling);

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

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

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

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

		control_broadcast_verbose(IMSG_CTL_PROFILE, profiling);

		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_pony, 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_pony, 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_pony, 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_pony, imsg);
		return;

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

		m_compose(p, IMSG_CTL_SHOW_STATUS, 0, 0, -1, &env->sc_flags,
		    sizeof(env->sc_flags));
		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_pony, imsg->hdr.type, c->id, 0, -1);
		m_add_sockaddr(p_pony, (struct sockaddr *)&ss);
		m_add_string(p_pony, (char *)imsg->data + sizeof(ss));
		m_close(p_pony);
		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_CTL_UPDATE_TABLE:
		if (c->euid)
			goto badcred;

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

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

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

		if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof evpid)
			goto invalid;

		memmove(&evpid, imsg->data, sizeof evpid);
		m_create(p_queue, imsg->hdr.type, c->id, 0, -1);
		m_add_evpid(p_queue, evpid);
		m_close(p_queue);
		return;

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

		if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof msgid)
			goto invalid;

		memmove(&msgid, imsg->data, sizeof msgid);
		m_create(p_queue, imsg->hdr.type, c->id, 0, -1);
		m_add_msgid(p_queue, msgid);
		m_close(p_queue);
		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);
}
Exemple #5
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));
}
Exemple #6
0
/* ARGSUSED */
static void
control_dispatch_ext(struct mproc *p, struct imsg *imsg)
{
	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:
		if (c->euid)
			goto badcred;

		imsg->hdr.peerid = c->id;
		m_forward(p_mta, imsg);
		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);
}
Exemple #7
0
      void operator() (const TVectorType& y, TVectorType& x)
      {
        typedef typename TVectorType::value_type value_type;
        typedef typename to_real_type<value_type>::type real_type;

        // no convergence at the beginning
        m_convergence = false;
        m_iteration = 0;

        real_type n2y = getL2NormOfDistributedVector(y);
        real_type toly = m_tolerance * n2y;

        // the residual y - F(x_k)
        TVectorType residual_k(y.size());

        // temporary vectors
        TVectorType t_sy(y.size());
        TVectorType t_sx(x.size());

        // compute the initial residual r_0 = y - F(x_0), now t_sy is distributed
        // u = b - A*x;
        m_forward(x, t_sy);
        subVector(y, t_sy, residual_k);

        // L2 norm of residual
        // beta = norm(u);
        real_type beta = getL2NormOfDistributedVector(residual_k);
        m_rho_0 = beta;
        m_rho_k = m_rho_0;
        real_type normr = beta;

        // normalize the residual
        // u = u / beta
        if (beta != 0)
        {
          scale(real_type(1) / beta, residual_k, residual_k);
        }

        // v = A'*u;
        TVectorType v(x.size(), value_type(0));
        adjoint(m_forward)(residual_k, v);

        // normalize v
        real_type alpha = getL2NormOfDistributedVector(v);
        if (alpha != 0)
        {
          scale(real_type(1) / alpha, v, v);
        }

        real_type normar = alpha * beta;

        if (normar == 0)
        {
          // stop if norm of residum is 0
          // => x0 is the exact solution
          return;
        }

        if (n2y == 0) {
          // rhs vector y is zero, so x is also a zero vector
          x.assign(x.size(), value_type(0));
          return;
        }

        real_type norma = 0;
        real_type c = 1;
        real_type s = 0;
        real_type phibar = beta;
        TVectorType d(x.size(), value_type(0)); //d must be initialized to zero
        for (m_iteration = 0; m_iteration < m_max_iterations; ++m_iteration)
        {
          // u = A*v - alpha * u;
          m_forward(v, t_sy);
          subScaledVector(t_sy, alpha, residual_k, residual_k);
          // beta = norm(u)
          // normalize the residual
          beta = getL2NormOfDistributedVector(residual_k);
          // Normalize residual
          scale(real_type(1) / beta, residual_k, residual_k);
          //m_rho_k = beta;

          // norma = norm([norma alpha beta]);
          norma = std::sqrt(norma*norma + alpha*alpha + beta*beta);

          // thet = -s * alpha;
          real_type thet = -s * alpha;
          // rhot = c * alpha;
          real_type rhot = c * alpha;
          // sqrt(rhot^2 + beta^2);
          real_type rho = std::sqrt(rhot*rhot + beta*beta);
          // c = rhot / rho;
          c = rhot / rho;
          // s = -beta / rho;
          s = -beta / rho;
          // phi = c * phibar
          real_type phi = c * phibar;

          if (phi == 0)
          {
            // Stagnation @see matlab implementation
            break;
          }

          // phibar = s * phibar;
          phibar = s * phibar;

          // d = (v - thet * d) / rho;
          subScaledVector(v, thet, d, d);
          scale(real_type(1) / rho, d, d);

          // check for convergence in min{|b-A*x|}
          // absolute convergence
          if (normar / (norma*normr) <= m_tolerance)
          {
            m_convergence = true;
            break;
          }

          // check for convergence in A*x=b
          // relative convergence
          if (normr <= toly)
          {
            m_convergence = true;
            break;
          }

          // x = x + phi * d;
          addScaledVector(x, phi, d, x);
          // normr = abs(s) * normr;
          normr = std::abs(s) * normr;
          m_rho_k = normr;
          // vt = A' * u;
          adjoint(m_forward)(residual_k, t_sx);
          // v = vt - beta * v;
          subScaledVector(t_sx, beta, v, v);
          // alpha = norm(v);
          alpha = getL2NormOfDistributedVector(v);
          // v = v / alpha;
          scale(real_type(1) / alpha, v, v);
          // normar = alpha * abs(s * phi);
          normar = alpha * std::abs(s * phi);
        }
      }