/* $OpenBSD: config.c,v 1.17 2012/09/27 17:47:49 chl Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #include #include "sys-queue.h" #include "sys-tree.h" #include #include #include #include #include #include #include #include "smtpd.h" #include "log.h" static int is_peer(struct peer *, enum smtp_proc_type, uint); static int is_peer(struct peer *p, enum smtp_proc_type peer, uint peercount) { uint i; for (i = 0; i < peercount; i++) if (p[i].id == peer) return (1); return (0); } void unconfigure(void) { } void configure(void) { } void purge_config(uint8_t what) { struct listener *l; struct map *m; struct rule *r; struct ssl *s; struct mapel *me; if (what & PURGE_LISTENERS) { while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) { TAILQ_REMOVE(env->sc_listeners, l, entry); free(l); } free(env->sc_listeners); env->sc_listeners = NULL; } if (what & PURGE_MAPS) { while ((m = TAILQ_FIRST(env->sc_maps)) != NULL) { TAILQ_REMOVE(env->sc_maps, m, m_entry); while ((me = TAILQ_FIRST(&m->m_contents))) { TAILQ_REMOVE(&m->m_contents, me, me_entry); free(me); } free(m); } free(env->sc_maps); env->sc_maps = NULL; } if (what & PURGE_RULES) { while ((r = TAILQ_FIRST(env->sc_rules)) != NULL) { TAILQ_REMOVE(env->sc_rules, r, r_entry); free(r); } free(env->sc_rules); env->sc_rules = NULL; } if (what & PURGE_SSL) { while ((s = SPLAY_ROOT(env->sc_ssl)) != NULL) { SPLAY_REMOVE(ssltree, env->sc_ssl, s); free(s->ssl_cert); free(s->ssl_key); free(s); } free(env->sc_ssl); env->sc_ssl = NULL; } } void init_pipes(void) { int i; int j; int count; int sockpair[2]; for (i = 0; i < PROC_COUNT; i++) for (j = 0; j < PROC_COUNT; j++) { /* * find out how many instances of this peer there are. */ if (i >= j || env->sc_instances[i] == 0|| env->sc_instances[j] == 0) continue; if (env->sc_instances[i] > 1 && env->sc_instances[j] > 1) fatalx("N:N peering not supported"); count = env->sc_instances[i] * env->sc_instances[j]; env->sc_pipes[i][j] = xcalloc(count, sizeof(int), "init_pipes"); env->sc_pipes[j][i] = xcalloc(count, sizeof(int), "init_pipes"); while (--count >= 0) { if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sockpair) == -1) fatal("socketpair"); env->sc_pipes[i][j][count] = sockpair[0]; env->sc_pipes[j][i][count] = sockpair[1]; session_socket_blockmode( env->sc_pipes[i][j][count], BM_NONBLOCK); session_socket_blockmode( env->sc_pipes[j][i][count], BM_NONBLOCK); } } } void config_pipes(struct peer *p, uint peercount) { uint i; uint j; int count; /* * close pipes */ for (i = 0; i < PROC_COUNT; i++) { for (j = 0; j < PROC_COUNT; j++) { if (i == j || env->sc_instances[i] == 0 || env->sc_instances[j] == 0) continue; for (count = 0; count < env->sc_instances[i]*env->sc_instances[j]; count++) { if (i == smtpd_process && is_peer(p, j, peercount) && count == env->sc_instance) continue; if (i == smtpd_process && is_peer(p, j, peercount) && env->sc_instances[i] == 1) continue; close(env->sc_pipes[i][j][count]); env->sc_pipes[i][j][count] = -1; } } } } void config_peers(struct peer *p, uint peercount) { int count; uint src; uint dst; uint i; /* * listen on appropriate pipes */ for (i = 0; i < peercount; i++) { src = smtpd_process; dst = p[i].id; if (dst == smtpd_process) fatal("config_peers: cannot peer with oneself"); env->sc_ievs[dst] = xcalloc(env->sc_instances[dst], sizeof(struct imsgev), "config_peers"); for (count = 0; count < env->sc_instances[dst]; count++) { imsg_init(&(env->sc_ievs[dst][count].ibuf), env->sc_pipes[src][dst][count]); env->sc_ievs[dst][count].handler = p[i].cb; env->sc_ievs[dst][count].events = EV_READ; env->sc_ievs[dst][count].proc = dst; env->sc_ievs[dst][count].data = &env->sc_ievs[dst][count]; event_set(&(env->sc_ievs[dst][count].ev), env->sc_ievs[dst][count].ibuf.fd, env->sc_ievs[dst][count].events, env->sc_ievs[dst][count].handler, env->sc_ievs[dst][count].data); event_add(&(env->sc_ievs[dst][count].ev), NULL); } } } #ifdef VALGRIND void free_peers(void) { u_int i; for (i = 0; i < PROC_COUNT; i++) if (env->sc_ievs[i]) free(env->sc_ievs[i]); } void free_pipes(void) { u_int i; u_int j; for (i = 0; i < PROC_COUNT; i++) for (j = 0; j < PROC_COUNT; j++) { if (i >= j || env->sc_instances[i] == 0 || env->sc_instances[j] == 0) continue; free(env->sc_pipes[i][j]); free(env->sc_pipes[j][i]); } } #endif