1 /* $OpenBSD: config.c,v 1.15 2011/05/01 12:57:11 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/tree.h> 22 #include <sys/param.h> 23 #include <sys/socket.h> 24 25 #include <event.h> 26 #include <imsg.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 31 #include "smtpd.h" 32 #include "log.h" 33 34 static int is_peer(struct peer *, enum smtp_proc_type, u_int); 35 36 static int 37 is_peer(struct peer *p, enum smtp_proc_type peer, u_int peercount) 38 { 39 u_int i; 40 41 for (i = 0; i < peercount; i++) 42 if (p[i].id == peer) 43 return (1); 44 return (0); 45 } 46 47 void 48 unconfigure(void) 49 { 50 } 51 52 void 53 configure(void) 54 { 55 } 56 57 void 58 purge_config(u_int8_t what) 59 { 60 struct listener *l; 61 struct map *m; 62 struct rule *r; 63 struct ssl *s; 64 struct mapel *me; 65 66 if (what & PURGE_LISTENERS) { 67 while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) { 68 TAILQ_REMOVE(env->sc_listeners, l, entry); 69 free(l); 70 } 71 free(env->sc_listeners); 72 env->sc_listeners = NULL; 73 } 74 if (what & PURGE_MAPS) { 75 while ((m = TAILQ_FIRST(env->sc_maps)) != NULL) { 76 TAILQ_REMOVE(env->sc_maps, m, m_entry); 77 while ((me = TAILQ_FIRST(&m->m_contents))) { 78 TAILQ_REMOVE(&m->m_contents, me, me_entry); 79 free(me); 80 } 81 free(m); 82 } 83 free(env->sc_maps); 84 env->sc_maps = NULL; 85 } 86 if (what & PURGE_RULES) { 87 while ((r = TAILQ_FIRST(env->sc_rules)) != NULL) { 88 TAILQ_REMOVE(env->sc_rules, r, r_entry); 89 free(r); 90 } 91 free(env->sc_rules); 92 env->sc_rules = NULL; 93 } 94 if (what & PURGE_SSL) { 95 while ((s = SPLAY_ROOT(env->sc_ssl)) != NULL) { 96 SPLAY_REMOVE(ssltree, env->sc_ssl, s); 97 free(s->ssl_cert); 98 free(s->ssl_key); 99 free(s); 100 } 101 free(env->sc_ssl); 102 env->sc_ssl = NULL; 103 } 104 } 105 106 void 107 init_pipes(void) 108 { 109 int i; 110 int j; 111 int count; 112 int sockpair[2]; 113 114 for (i = 0; i < PROC_COUNT; i++) 115 for (j = 0; j < PROC_COUNT; j++) { 116 /* 117 * find out how many instances of this peer there are. 118 */ 119 if (i >= j || env->sc_instances[i] == 0|| 120 env->sc_instances[j] == 0) 121 continue; 122 123 if (env->sc_instances[i] > 1 && 124 env->sc_instances[j] > 1) 125 fatalx("N:N peering not supported"); 126 127 count = env->sc_instances[i] * env->sc_instances[j]; 128 129 if ((env->sc_pipes[i][j] = 130 calloc(count, sizeof(int))) == NULL || 131 (env->sc_pipes[j][i] = 132 calloc(count, sizeof(int))) == NULL) 133 fatal(NULL); 134 135 while (--count >= 0) { 136 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, 137 sockpair) == -1) 138 fatal("socketpair"); 139 env->sc_pipes[i][j][count] = sockpair[0]; 140 env->sc_pipes[j][i][count] = sockpair[1]; 141 session_socket_blockmode( 142 env->sc_pipes[i][j][count], 143 BM_NONBLOCK); 144 session_socket_blockmode( 145 env->sc_pipes[j][i][count], 146 BM_NONBLOCK); 147 } 148 } 149 } 150 151 void 152 config_pipes(struct peer *p, u_int peercount) 153 { 154 u_int i; 155 u_int j; 156 int count; 157 158 /* 159 * close pipes 160 */ 161 for (i = 0; i < PROC_COUNT; i++) { 162 for (j = 0; j < PROC_COUNT; j++) { 163 if (i == j || 164 env->sc_instances[i] == 0 || 165 env->sc_instances[j] == 0) 166 continue; 167 168 for (count = 0; 169 count < env->sc_instances[i]*env->sc_instances[j]; 170 count++) { 171 if (i == smtpd_process && 172 is_peer(p, j, peercount) && 173 count == env->sc_instance) 174 continue; 175 if (i == smtpd_process && 176 is_peer(p, j, peercount) && 177 env->sc_instances[i] == 1) 178 continue; 179 close(env->sc_pipes[i][j][count]); 180 env->sc_pipes[i][j][count] = -1; 181 } 182 } 183 } 184 } 185 186 void 187 config_peers(struct peer *p, u_int peercount) 188 { 189 int count; 190 u_int src; 191 u_int dst; 192 u_int i; 193 /* 194 * listen on appropriate pipes 195 */ 196 for (i = 0; i < peercount; i++) { 197 198 src = smtpd_process; 199 dst = p[i].id; 200 201 if (dst == smtpd_process) 202 fatal("config_peers: cannot peer with oneself"); 203 204 if ((env->sc_ievs[dst] = calloc(env->sc_instances[dst], 205 sizeof(struct imsgev))) == NULL) 206 fatal("config_peers"); 207 208 for (count = 0; count < env->sc_instances[dst]; count++) { 209 imsg_init(&(env->sc_ievs[dst][count].ibuf), 210 env->sc_pipes[src][dst][count]); 211 env->sc_ievs[dst][count].handler = p[i].cb; 212 env->sc_ievs[dst][count].events = EV_READ; 213 env->sc_ievs[dst][count].proc = dst; 214 env->sc_ievs[dst][count].data = &env->sc_ievs[dst][count]; 215 216 event_set(&(env->sc_ievs[dst][count].ev), 217 env->sc_ievs[dst][count].ibuf.fd, 218 env->sc_ievs[dst][count].events, 219 env->sc_ievs[dst][count].handler, 220 env->sc_ievs[dst][count].data); 221 event_add(&(env->sc_ievs[dst][count].ev), NULL); 222 } 223 } 224 } 225