1 /* $OpenBSD: config.c,v 1.5 2009/02/16 12:10:25 jacekm 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 <stdio.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 30 #include "smtpd.h" 31 32 int is_peer(struct peer *, enum smtp_proc_type, u_int); 33 34 int 35 is_peer(struct peer *p, enum smtp_proc_type peer, u_int peercount) 36 { 37 u_int i; 38 39 for (i = 0; i < peercount; i++) 40 if (p[i].id == peer) 41 return (1); 42 return (0); 43 } 44 45 void 46 unconfigure(struct smtpd *env) 47 { 48 } 49 50 void 51 configure(struct smtpd *env) 52 { 53 } 54 55 void 56 purge_config(struct smtpd *env, u_int8_t what) 57 { 58 struct listener *l; 59 struct map *m; 60 struct rule *r; 61 struct cond *c; 62 struct opt *o; 63 struct ssl *s; 64 65 if (what & PURGE_LISTENERS) { 66 while ((l = TAILQ_FIRST(&env->sc_listeners)) != NULL) { 67 TAILQ_REMOVE(&env->sc_listeners, l, entry); 68 free(l); 69 } 70 TAILQ_INIT(&env->sc_listeners); 71 } 72 if (what & PURGE_MAPS) { 73 while ((m = TAILQ_FIRST(env->sc_maps)) != NULL) { 74 TAILQ_REMOVE(env->sc_maps, m, m_entry); 75 free(m); 76 } 77 free(env->sc_maps); 78 env->sc_maps = NULL; 79 } 80 if (what & PURGE_RULES) { 81 while ((r = TAILQ_FIRST(env->sc_rules)) != NULL) { 82 TAILQ_REMOVE(env->sc_rules, r, r_entry); 83 while ((c = TAILQ_FIRST(&r->r_conditions)) != NULL) { 84 TAILQ_REMOVE(&r->r_conditions, c, c_entry); 85 free(c); 86 } 87 while ((o = TAILQ_FIRST(&r->r_options)) != NULL) { 88 TAILQ_REMOVE(&r->r_options, o, o_entry); 89 free(o); 90 } 91 free(r); 92 } 93 env->sc_rules = NULL; 94 } 95 if (what & PURGE_SSL) { 96 while ((s = SPLAY_ROOT(&env->sc_ssl)) != NULL) { 97 SPLAY_REMOVE(ssltree, &env->sc_ssl, s); 98 free(s->ssl_cert); 99 free(s->ssl_key); 100 free(s); 101 } 102 SPLAY_INIT(&env->sc_ssl); 103 } 104 } 105 106 void 107 init_peers(struct smtpd *env) 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 smtpd *env, 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 smtpd *env, 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_ibufs[dst] = calloc(env->sc_instances[dst], 205 sizeof(struct imsgbuf))) == NULL) 206 fatal("config_peers"); 207 208 for (count = 0; count < env->sc_instances[dst]; count++) { 209 imsg_init(&(env->sc_ibufs[dst][count]), 210 env->sc_pipes[src][dst][count], p[i].cb); 211 212 env->sc_ibufs[dst][count].events = EV_READ; 213 env->sc_ibufs[dst][count].data = env; 214 215 event_set(&(env->sc_ibufs[dst][count].ev), 216 env->sc_ibufs[dst][count].fd, 217 env->sc_ibufs[dst][count].events, 218 env->sc_ibufs[dst][count].handler, 219 env->sc_ibufs[dst][count].data); 220 event_add(&(env->sc_ibufs[dst][count].ev), NULL); 221 } 222 } 223 } 224