Example #1
0
pid_t
ca(void)
{
	pid_t		 pid;
	struct passwd	*pw;
	struct event	 ev_sigint;
	struct event	 ev_sigterm;

	switch (pid = fork()) {
	case -1:
		fatal("ca: cannot fork");
	case 0:
		post_fork(PROC_CA);
		break;
	default:
		return (pid);
	}

	purge_config(PURGE_LISTENERS|PURGE_TABLES|PURGE_RULES);

	if ((pw = getpwnam(SMTPD_USER)) == NULL)
		fatalx("unknown user " SMTPD_USER);

	if (chroot(PATH_CHROOT) == -1)
		fatal("ca: chroot");
	if (chdir("/") == -1)
		fatal("ca: chdir(\"/\")");

	config_process(PROC_CA);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("ca: cannot drop privileges");

	imsg_callback = ca_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, ca_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, ca_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	config_peer(PROC_CONTROL);
	config_peer(PROC_PARENT);
	config_peer(PROC_PONY);
	config_done();

	/* Ignore them until we get our config */
	mproc_disable(p_pony);

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	ca_shutdown();

	return (0);
}
Example #2
0
int
control(void)
{
	struct passwd		*pw;

	purge_config(PURGE_EVERYTHING);

	if ((pw = getpwnam(SMTPD_USER)) == NULL)
		fatalx("unknown user " SMTPD_USER);

	stat_backend = env->sc_stat;
	stat_backend->init();

	if (chroot(PATH_CHROOT) == -1)
		fatal("control: chroot");
	if (chdir("/") == -1)
		fatal("control: chdir(\"/\")");

	config_process(PROC_CONTROL);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("control: cannot drop privileges");

	imsg_callback = control_imsg;
	event_init();

	signal(SIGINT, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	tree_init(&ctl_conns);
	tree_init(&ctl_count);

	memset(&digest, 0, sizeof digest);
	digest.startup = time(NULL);

	config_peer(PROC_SCHEDULER);
	config_peer(PROC_QUEUE);
	config_peer(PROC_PARENT);
	config_peer(PROC_LKA);
	config_peer(PROC_PONY);
	config_peer(PROC_CA);

	control_listen();

	if (pledge("stdio unix recvfd sendfd", NULL) == -1)
		err(1, "pledge");

	event_dispatch();
	fatalx("exited event loop");

	return (0);
}
Example #3
0
pid_t
queue(void)
{
	pid_t		 pid;
	struct passwd	*pw;
	struct timeval	 tv;
	struct event	 ev_qload;
	struct event	 ev_sigint;
	struct event	 ev_sigterm;

	switch (pid = fork()) {
	case -1:
		fatal("queue: cannot fork");
	case 0:
		post_fork(PROC_QUEUE);
		break;
	default:
		return (pid);
	}

	purge_config(PURGE_EVERYTHING);

	if ((pw = getpwnam(SMTPD_QUEUE_USER)) == NULL)
		if ((pw = getpwnam(SMTPD_USER)) == NULL)
			fatalx("unknown user " SMTPD_USER);

	env->sc_queue_flags |= QUEUE_EVPCACHE;
	env->sc_queue_evpcache_size = 1024;

	if (chroot(PATH_SPOOL) == -1)
		fatal("queue: chroot");
	if (chdir("/") == -1)
		fatal("queue: chdir(\"/\")");

	config_process(PROC_QUEUE);

	if (env->sc_queue_flags & QUEUE_COMPRESSION)
		log_info("queue: queue compression enabled");

	if (env->sc_queue_key) {
		if (! crypto_setup(env->sc_queue_key, strlen(env->sc_queue_key)))
			fatalx("crypto_setup: invalid key for queue encryption");
		log_info("queue: queue encryption enabled");
	}

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("queue: cannot drop privileges");

	imsg_callback = queue_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, queue_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, queue_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	config_peer(PROC_PARENT);
	config_peer(PROC_CONTROL);
	config_peer(PROC_LKA);
	config_peer(PROC_SCHEDULER);
	config_peer(PROC_PONY);
	config_done();

	/* setup queue loading task */
	evtimer_set(&ev_qload, queue_timeout, &ev_qload);
	tv.tv_sec = 0;
	tv.tv_usec = 10;
	evtimer_add(&ev_qload, &tv);

	if (event_dispatch() <  0)
		fatal("event_dispatch");
	queue_shutdown();

	return (0);
}
Example #4
0
pid_t
mta(void)
{
	pid_t		 pid;

	struct passwd	*pw;
	struct event	 ev_sigint;
	struct event	 ev_sigterm;

	struct peer peers[] = {
		{ PROC_PARENT,	imsg_dispatch },
		{ PROC_QUEUE,	imsg_dispatch },
		{ PROC_LKA,	imsg_dispatch },
		{ PROC_CONTROL,	imsg_dispatch }
	};

	switch (pid = fork()) {
	case -1:
		fatal("mta: cannot fork");
	case 0:
		break;
	default:
		return (pid);
	}

	purge_config(PURGE_EVERYTHING);

	pw = env->sc_pw;
	if (chroot(pw->pw_dir) == -1)
		fatal("mta: chroot");
	if (chdir("/") == -1)
		fatal("mta: chdir(\"/\")");

	smtpd_process = PROC_MTA;
	log_debug("start %s",env->sc_title[smtpd_process]); 
	setproctitle("%s", env->sc_title[smtpd_process]);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("mta: cannot drop privileges");

	imsg_callback = mta_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, mta_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, mta_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	config_pipes(peers, nitems(peers));
	config_peers(peers, nitems(peers));

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	mta_shutdown();

	return (0);
}
Example #5
0
pid_t
control(void)
{
	pid_t			 pid;
	struct passwd		*pw;
	struct event		 ev_sigint;
	struct event		 ev_sigterm;

	switch (pid = fork()) {
	case -1:
		fatal("control: cannot fork");
	case 0:
		post_fork(PROC_CONTROL);
		break;
	default:
		return (pid);
	}

	purge_config(PURGE_EVERYTHING);

	if ((pw = getpwnam(SMTPD_USER)) == NULL)
		fatalx("unknown user " SMTPD_USER);

	stat_backend = env->sc_stat;
	stat_backend->init();

	if (chroot(PATH_CHROOT) == -1)
		fatal("control: chroot");
	if (chdir("/") == -1)
		fatal("control: chdir(\"/\")");

	config_process(PROC_CONTROL);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("control: cannot drop privileges");

	imsg_callback = control_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, control_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, control_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	tree_init(&ctl_conns);
	tree_init(&ctl_count);

	memset(&digest, 0, sizeof digest);
	digest.startup = time(NULL);

	config_peer(PROC_SCHEDULER);
	config_peer(PROC_QUEUE);
	config_peer(PROC_PARENT);
	config_peer(PROC_LKA);
	config_peer(PROC_PONY);
	config_peer(PROC_CA);
	config_done();

	control_listen();

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	control_shutdown();

	return (0);
}
Example #6
0
pid_t
runner(void)
{
	pid_t		 pid;
	struct passwd	*pw;

	struct event	 ev_sigint;
	struct event	 ev_sigterm;

	struct peer peers[] = {
		{ PROC_CONTROL,	imsg_dispatch },
		{ PROC_QUEUE,	imsg_dispatch }
	};

	switch (pid = fork()) {
	case -1:
		fatal("runner: cannot fork");
	case 0:
		break;
	default:
		return (pid);
	}

	purge_config(PURGE_EVERYTHING);

	pw = env->sc_pw;

	if (chroot(PATH_SPOOL) == -1)
		fatal("runner: chroot");
	if (chdir("/") == -1)
		fatal("runner: chdir(\"/\")");

	smtpd_process = PROC_RUNNER;
	setproctitle("%s", env->sc_title[smtpd_process]);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("runner: cannot drop privileges");

	/* see fdlimit()-related comment in queue.c */
	fdlimit(1.0);
	if ((env->sc_maxconn = availdesc() / 4) < 1)
		fatalx("runner: fd starvation");

	env->sc_scheduler = scheduler_backend_lookup(SCHED_RAMQUEUE);
	scheduler = env->sc_scheduler;

	scheduler->init();

	imsg_callback = runner_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, runner_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, runner_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	config_pipes(peers, nitems(peers));
	config_peers(peers, nitems(peers));

	runner_setup_events();
	event_dispatch();
	runner_disable_events();
	runner_shutdown();

	return (0);
}
Example #7
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));
}
Example #8
0
pid_t
lka(void)
{
    pid_t		 pid;
    struct passwd	*pw;
    struct event	 ev_sigint;
    struct event	 ev_sigterm;
    struct event	 ev_sigchld;

    switch (pid = fork()) {
    case -1:
        fatal("lka: cannot fork");
    case 0:
        break;
    default:
        return (pid);
    }

    purge_config(PURGE_EVERYTHING);

    if ((pw = getpwnam(SMTPD_USER)) == NULL)
        fatalx("unknown user " SMTPD_USER);

    config_process(PROC_LKA);

    if (setgroups(1, &pw->pw_gid) ||
            setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
            setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
        fatal("lka: cannot drop privileges");

    imsg_callback = lka_imsg;
    event_init();

    signal_set(&ev_sigint, SIGINT, lka_sig_handler, NULL);
    signal_set(&ev_sigterm, SIGTERM, lka_sig_handler, NULL);
    signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL);
    signal_add(&ev_sigint, NULL);
    signal_add(&ev_sigterm, NULL);
    signal_add(&ev_sigchld, NULL);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGHUP, SIG_IGN);

    /*
     * lka opens all kinds of files and sockets, so bump the limit to max.
     * XXX: need to analyse the exact hard limit.
     */
    fdlimit(1.0);

    config_peer(PROC_PARENT);
    config_peer(PROC_QUEUE);
    config_peer(PROC_SMTP);
    config_peer(PROC_MDA);
    config_peer(PROC_MTA);
    config_peer(PROC_CONTROL);
    config_done();

    /* Ignore them until we get our config */
    mproc_disable(p_mda);
    mproc_disable(p_mta);
    mproc_disable(p_smtp);

    if (event_dispatch() < 0)
        fatal("event_dispatch");
    lka_shutdown();

    return (0);
}
Example #9
0
pid_t
control(void)
{
	struct sockaddr_un	 sun;
	int			 fd;
	mode_t			 old_umask;
	pid_t			 pid;
	struct passwd		*pw;
	struct event		 ev_sigint;
	struct event		 ev_sigterm;
	struct peer		 peers [] = {
		{ PROC_RUNNER,	 imsg_dispatch },
		{ PROC_QUEUE,	 imsg_dispatch },
		{ PROC_SMTP,	 imsg_dispatch },
		{ PROC_MFA,	 imsg_dispatch },
		{ PROC_PARENT,	 imsg_dispatch },
	};

	switch (pid = fork()) {
	case -1:
		fatal("control: cannot fork");
	case 0:
		break;
	default:
		return (pid);
	}

	purge_config(PURGE_EVERYTHING);

	pw = env->sc_pw;

	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
		fatal("control: socket");

	bzero(&sun, sizeof(sun));
	sun.sun_family = AF_UNIX;
	if (strlcpy(sun.sun_path, SMTPD_SOCKET,
	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path))
		fatal("control: socket name too long");

	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0)
		fatalx("control socket already listening");

	if (unlink(SMTPD_SOCKET) == -1)
		if (errno != ENOENT)
			fatal("control: cannot unlink socket");

	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
		(void)umask(old_umask);
		fatal("control: bind");
	}
	(void)umask(old_umask);

	if (chmod(SMTPD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) {
		(void)unlink(SMTPD_SOCKET);
		fatal("control: chmod");
	}

	session_socket_blockmode(fd, BM_NONBLOCK);
	control_state.fd = fd;

	if (chroot(pw->pw_dir) == -1)
		fatal("control: chroot");
	if (chdir("/") == -1)
		fatal("control: chdir(\"/\")");

	smtpd_process = PROC_CONTROL;
	setproctitle("%s", env->sc_title[smtpd_process]);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("control: cannot drop privileges");

	imsg_callback = control_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, control_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, control_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	TAILQ_INIT(&ctl_conns);

	config_pipes(peers, nitems(peers));
	config_peers(peers, nitems(peers));
	control_listen();

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	control_shutdown();

	return (0);
}
Example #10
0
pid_t
pony(void)
{
	pid_t		 pid;
	struct passwd	*pw;
	struct event	 ev_sigint;
	struct event	 ev_sigterm;

	switch (pid = fork()) {
	case -1:
		fatal("pony: cannot fork");
	case 0:
		post_fork(PROC_PONY);
		break;
	default:
		return (pid);
	}

	mda_postfork();
	mta_postfork();
	smtp_postfork();
	filter_postfork();

	/* do not purge listeners and pki, they are purged
	 * in smtp_configure()
	 */
	purge_config(PURGE_TABLES|PURGE_RULES);

	if ((pw = getpwnam(SMTPD_USER)) == NULL)
		fatalx("unknown user " SMTPD_USER);

	if (chroot(PATH_CHROOT) == -1)
		fatal("pony: chroot");
	if (chdir("/") == -1)
		fatal("pony: chdir(\"/\")");

	config_process(PROC_PONY);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("pony: cannot drop privileges");


	imsg_callback = pony_imsg;
	event_init();

	mda_postprivdrop();
	mta_postprivdrop();
	smtp_postprivdrop();

	signal_set(&ev_sigint, SIGINT, pony_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, pony_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	config_peer(PROC_PARENT);
	config_peer(PROC_QUEUE);
	config_peer(PROC_LKA);
	config_peer(PROC_CONTROL);
	config_peer(PROC_CA);
	config_done();

	ca_engine_init();

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	pony_shutdown();

	return (0);
}
Example #11
0
pid_t
mfa(void)
{
	pid_t		 pid;
	struct passwd	*pw;
	struct event	 ev_sigint;
	struct event	 ev_sigterm;
	struct event	 ev_sigchld;

	switch (pid = fork()) {
	case -1:
		fatal("filter: cannot fork");
	case 0:
		break;
	default:
		return (pid);
	}

	mfa_filter_prepare();

	purge_config(PURGE_EVERYTHING);

	if ((pw =  getpwnam(SMTPD_USER)) == NULL)
		fatalx("unknown user " SMTPD_USER);

	config_process(PROC_MFA);

	if (chroot(PATH_CHROOT) == -1)
		fatal("scheduler: chroot");
	if (chdir("/") == -1)
		fatal("scheduler: chdir(\"/\")");

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("filter: cannot drop privileges");

	imsg_callback = mfa_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, mfa_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, mfa_sig_handler, NULL);
	signal_set(&ev_sigchld, SIGCHLD, mfa_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal_add(&ev_sigchld, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	config_peer(PROC_PARENT);
	config_peer(PROC_SMTP);
	config_peer(PROC_CONTROL);
	config_done();

	mproc_disable(p_smtp);

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	mfa_shutdown();

	return (0);
}
Example #12
0
int
queue(void)
{
	struct passwd	*pw;
	struct timeval	 tv;
	struct event	 ev_qload;

	purge_config(PURGE_EVERYTHING);

	if ((pw = getpwnam(SMTPD_QUEUE_USER)) == NULL)
		if ((pw = getpwnam(SMTPD_USER)) == NULL)
			fatalx("unknown user " SMTPD_USER);

	env->sc_queue_flags |= QUEUE_EVPCACHE;
	env->sc_queue_evpcache_size = 1024;

	if (chroot(PATH_SPOOL) == -1)
		fatal("queue: chroot");
	if (chdir("/") == -1)
		fatal("queue: chdir(\"/\")");

	config_process(PROC_QUEUE);

	if (env->sc_queue_flags & QUEUE_COMPRESSION)
		log_info("queue: queue compression enabled");

	if (env->sc_queue_key) {
		if (!crypto_setup(env->sc_queue_key, strlen(env->sc_queue_key)))
			fatalx("crypto_setup: invalid key for queue encryption");
		log_info("queue: queue encryption enabled");
	}

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("queue: cannot drop privileges");

	imsg_callback = queue_imsg;
	event_init();

	signal(SIGINT, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	config_peer(PROC_PARENT);
	config_peer(PROC_CONTROL);
	config_peer(PROC_LKA);
	config_peer(PROC_SCHEDULER);
	config_peer(PROC_PONY);

	/* setup queue loading task */
	evtimer_set(&ev_qload, queue_timeout, &ev_qload);
	tv.tv_sec = 0;
	tv.tv_usec = 10;
	evtimer_add(&ev_qload, &tv);

	if (pledge("stdio rpath wpath cpath flock recvfd sendfd", NULL) == -1)
		err(1, "pledge");

	event_dispatch();
	fatalx("exited event loop");

	return (0);
}
Example #13
0
static void
lka_imsg(struct imsgev *iev, struct imsg *imsg)
{
    struct submit_status	*ss;
    struct secret		*secret;
    struct mapel		*mapel;
    struct rule		*rule;
    struct map		*map;
    struct map		*mp;
    void			*tmp;

    if (imsg->hdr.type == IMSG_DNS_HOST || imsg->hdr.type == IMSG_DNS_MX ||
            imsg->hdr.type == IMSG_DNS_PTR) {
        dns_async(iev, imsg->hdr.type, imsg->data);
        return;
    }

    if (iev->proc == PROC_MFA) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_MAIL:
            ss = imsg->data;
            ss->code = 530;
            if (ss->u.maddr.user[0] == '\0' &&
                    ss->u.maddr.domain[0] == '\0')
                ss->code = 250;
            else if (lka_verify_mail(&ss->u.maddr))
                ss->code = 250;
            imsg_compose_event(iev, IMSG_LKA_MAIL, 0, 0, -1, ss,
                               sizeof *ss);
            return;

        case IMSG_LKA_RULEMATCH:
            ss = imsg->data;
            rule = ruleset_match(&ss->envelope);
            if (rule == NULL)
                ss->code = (errno == EAGAIN) ? 451 : 530;
            else
                ss->code = (rule->r_decision == R_ACCEPT) ?
                           250 : 530;
            imsg_compose_event(iev, IMSG_LKA_RULEMATCH, 0, 0, -1,
                               ss, sizeof *ss);
            return;

        case IMSG_LKA_RCPT:
            lka_session(imsg->data);
            return;
        }
    }

    if (iev->proc == PROC_MTA) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_SECRET: {
            struct map_credentials *map_credentials;

            secret = imsg->data;
            map = map_findbyname(secret->mapname);
            if (map == NULL) {
                log_warn("warn: lka: credentials map %s is missing",
                         secret->mapname);
                imsg_compose_event(iev, IMSG_LKA_SECRET, 0, 0,
                                   -1, secret, sizeof *secret);
                return;
            }
            map_credentials = map_lookup(map->m_id, secret->host,
                                         K_CREDENTIALS);
            log_debug("debug: lka: %s credentials lookup (%d)", secret->host,
                      map_credentials != NULL);
            secret->secret[0] = '\0';
            if (map_credentials == NULL)
                log_warnx("warn: %s credentials not found",
                          secret->host);
            else if (lka_encode_credentials(secret->secret,
                                            sizeof secret->secret, map_credentials) == 0)
                log_warnx("warn: %s credentials parse fail",
                          secret->host);
            imsg_compose_event(iev, IMSG_LKA_SECRET, 0, 0, -1, secret,
                               sizeof *secret);
            free(map_credentials);
            return;
        }
        }
    }

    if (iev->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");
            env->sc_maps_reload = xcalloc(1, sizeof *env->sc_maps,
                                          "lka:sc_maps_reload");
            TAILQ_INIT(env->sc_rules_reload);
            TAILQ_INIT(env->sc_maps_reload);
            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_MAP:
            map = xmemdup(imsg->data, sizeof *map, "lka:map");
            TAILQ_INIT(&map->m_contents);
            TAILQ_INSERT_TAIL(env->sc_maps_reload, map, m_entry);

            tmp = env->sc_maps;
            env->sc_maps = env->sc_maps_reload;

            mp = map_open(map);
            if (mp == NULL)
                errx(1, "lka: could not open map \"%s\"", map->m_name);
            map_close(map, mp);

            env->sc_maps = tmp;
            return;

        case IMSG_CONF_RULE_SOURCE:
            rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
            tmp = env->sc_maps;
            env->sc_maps = env->sc_maps_reload;
            rule->r_sources = map_findbyname(imsg->data);
            if (rule->r_sources == NULL)
                fatalx("lka: maps inconsistency");
            env->sc_maps = tmp;
            return;

        case IMSG_CONF_MAP_CONTENT:
            map = TAILQ_LAST(env->sc_maps_reload, maplist);
            mapel = xmemdup(imsg->data, sizeof *mapel, "lka:mapel");
            TAILQ_INSERT_TAIL(&map->m_contents, mapel, me_entry);
            return;

        case IMSG_CONF_END:
            if (env->sc_rules)
                purge_config(PURGE_RULES);
            if (env->sc_maps)
                purge_config(PURGE_MAPS);
            env->sc_rules = env->sc_rules_reload;
            env->sc_maps = env->sc_maps_reload;

            /* start fulfilling requests */
            event_add(&env->sc_ievs[PROC_MTA]->ev, NULL);
            event_add(&env->sc_ievs[PROC_MFA]->ev, NULL);
            event_add(&env->sc_ievs[PROC_SMTP]->ev, NULL);
            return;

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

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

        }
    }

    if (iev->proc == PROC_CONTROL) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_UPDATE_MAP:
            map = map_findbyname(imsg->data);
            if (map == NULL) {
                log_warnx("warn: lka: no such map \"%s\"",
                          (char *)imsg->data);
                return;
            }
            map_update(map);
            return;
        }
    }

    errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
}
Example #14
0
pid_t
lka(void)
{
    pid_t		 pid;
    struct passwd	*pw;

    struct event	 ev_sigint;
    struct event	 ev_sigterm;
    struct event	 ev_sigchld;

    struct peer peers[] = {
        { PROC_PARENT,	imsg_dispatch },
        { PROC_MFA,	imsg_dispatch },
        { PROC_QUEUE,	imsg_dispatch },
        { PROC_SMTP,	imsg_dispatch },
        { PROC_MTA,	imsg_dispatch },
        { PROC_CONTROL,	imsg_dispatch }
    };

    switch (pid = fork()) {
    case -1:
        fatal("lka: cannot fork");
    case 0:
        break;
    default:
        return (pid);
    }

    purge_config(PURGE_EVERYTHING);

    pw = env->sc_pw;

    smtpd_process = PROC_LKA;
    setproctitle("%s", env->sc_title[smtpd_process]);

    if (setgroups(1, &pw->pw_gid) ||
            setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
            setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
        fatal("lka: cannot drop privileges");

    imsg_callback = lka_imsg;
    event_init();
    SPLAY_INIT(&env->lka_sessions);

    signal_set(&ev_sigint, SIGINT, lka_sig_handler, NULL);
    signal_set(&ev_sigterm, SIGTERM, lka_sig_handler, NULL);
    signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL);
    signal_add(&ev_sigint, NULL);
    signal_add(&ev_sigterm, NULL);
    signal_add(&ev_sigchld, NULL);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGHUP, SIG_IGN);

    /*
     * lka opens all kinds of files and sockets, so bump the limit to max.
     * XXX: need to analyse the exact hard limit.
     */
    fdlimit(1.0);

    config_pipes(peers, nitems(peers));
    config_peers(peers, nitems(peers));

    /* ignore them until we get our config */
    event_del(&env->sc_ievs[PROC_MTA]->ev);
    event_del(&env->sc_ievs[PROC_MFA]->ev);
    event_del(&env->sc_ievs[PROC_SMTP]->ev);

    if (event_dispatch() < 0)
        fatal("event_dispatch");
    lka_shutdown();

    return (0);
}
Example #15
0
pid_t
control(void)
{
	struct sockaddr_un	 sun;
	int			 fd;
	mode_t			 old_umask;
	pid_t			 pid;
	struct passwd		*pw;
	struct event		 ev_sigint;
	struct event		 ev_sigterm;

	switch (pid = fork()) {
	case -1:
		fatal("control: cannot fork");
	case 0:
		break;
	default:
		return (pid);
	}

	purge_config(PURGE_EVERYTHING);

	pw = env->sc_pw;

	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
		fatal("control: socket");

	bzero(&sun, sizeof(sun));
	sun.sun_family = AF_UNIX;
	if (strlcpy(sun.sun_path, SMTPD_SOCKET,
	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path))
		fatal("control: socket name too long");

	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0)
		fatalx("control socket already listening");

	if (unlink(SMTPD_SOCKET) == -1)
		if (errno != ENOENT)
			fatal("control: cannot unlink socket");

	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
		(void)umask(old_umask);
		fatal("control: bind");
	}
	(void)umask(old_umask);

	if (chmod(SMTPD_SOCKET,
		S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) {
		(void)unlink(SMTPD_SOCKET);
		fatal("control: chmod");
	}

	session_socket_blockmode(fd, BM_NONBLOCK);
	control_state.fd = fd;

	stat_backend = env->sc_stat;
	stat_backend->init();

	if (chroot(PATH_CHROOT) == -1)
		fatal("control: chroot");
	if (chdir("/") == -1)
		fatal("control: chdir(\"/\")");

	config_process(PROC_CONTROL);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("control: cannot drop privileges");

	imsg_callback = control_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, control_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, control_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	tree_init(&ctl_conns);

	bzero(&digest, sizeof digest);
	digest.startup = time(NULL);

	config_peer(PROC_SCHEDULER);
	config_peer(PROC_QUEUE);
	config_peer(PROC_SMTP);
	config_peer(PROC_MFA);
	config_peer(PROC_PARENT);
	config_peer(PROC_LKA);
	config_peer(PROC_MDA);
	config_peer(PROC_MTA);
	config_done();

	control_listen();

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	control_shutdown();

	return (0);
}