1/* $OpenBSD: config.c,v 1.58 2024/01/04 09:30:09 op 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/resource.h> 20 21#include <ifaddrs.h> 22#include <stdlib.h> 23#include <string.h> 24 25#include "smtpd.h" 26#include "log.h" 27#include "ssl.h" 28 29void set_local(struct smtpd *, const char *); 30void set_localaddrs(struct smtpd *, struct table *); 31 32struct smtpd * 33config_default(void) 34{ 35 struct smtpd *conf = NULL; 36 struct mta_limits *limits = NULL; 37 struct table *t = NULL; 38 char hostname[HOST_NAME_MAX+1]; 39 40 if (getmailname(hostname, sizeof hostname) == -1) 41 return NULL; 42 43 if ((conf = calloc(1, sizeof(*conf))) == NULL) 44 return conf; 45 46 (void)strlcpy(conf->sc_hostname, hostname, sizeof(conf->sc_hostname)); 47 48 conf->sc_maxsize = DEFAULT_MAX_BODY_SIZE; 49 conf->sc_subaddressing_delim = SUBADDRESSING_DELIMITER; 50 conf->sc_ttl = SMTPD_QUEUE_EXPIRY; 51 conf->sc_srs_ttl = SMTPD_QUEUE_EXPIRY / 86400; 52 53 conf->sc_mta_max_deferred = 100; 54 conf->sc_scheduler_max_inflight = 5000; 55 conf->sc_scheduler_max_schedule = 10; 56 conf->sc_scheduler_max_evp_batch_size = 256; 57 conf->sc_scheduler_max_msg_batch_size = 1024; 58 59 conf->sc_session_max_rcpt = 1000; 60 conf->sc_session_max_mails = 100; 61 62 conf->sc_mda_max_session = 50; 63 conf->sc_mda_max_user_session = 7; 64 conf->sc_mda_task_hiwat = 50; 65 conf->sc_mda_task_lowat = 30; 66 conf->sc_mda_task_release = 10; 67 68 /* Report mails delayed for more than 4 hours */ 69 conf->sc_bounce_warn[0] = 3600 * 4; 70 71 conf->sc_tables_dict = calloc(1, sizeof(*conf->sc_tables_dict)); 72 conf->sc_rules = calloc(1, sizeof(*conf->sc_rules)); 73 conf->sc_dispatchers = calloc(1, sizeof(*conf->sc_dispatchers)); 74 conf->sc_listeners = calloc(1, sizeof(*conf->sc_listeners)); 75 conf->sc_ca_dict = calloc(1, sizeof(*conf->sc_ca_dict)); 76 conf->sc_pki_dict = calloc(1, sizeof(*conf->sc_pki_dict)); 77 conf->sc_ssl_dict = calloc(1, sizeof(*conf->sc_ssl_dict)); 78 conf->sc_limits_dict = calloc(1, sizeof(*conf->sc_limits_dict)); 79 conf->sc_mda_wrappers = calloc(1, sizeof(*conf->sc_mda_wrappers)); 80 conf->sc_filter_processes_dict = calloc(1, sizeof(*conf->sc_filter_processes_dict)); 81 conf->sc_dispatcher_bounce = calloc(1, sizeof(*conf->sc_dispatcher_bounce)); 82 conf->sc_filters_dict = calloc(1, sizeof(*conf->sc_filters_dict)); 83 limits = calloc(1, sizeof(*limits)); 84 85 if (conf->sc_tables_dict == NULL || 86 conf->sc_rules == NULL || 87 conf->sc_dispatchers == NULL || 88 conf->sc_listeners == NULL || 89 conf->sc_ca_dict == NULL || 90 conf->sc_pki_dict == NULL || 91 conf->sc_ssl_dict == NULL || 92 conf->sc_limits_dict == NULL || 93 conf->sc_mda_wrappers == NULL || 94 conf->sc_filter_processes_dict == NULL || 95 conf->sc_dispatcher_bounce == NULL || 96 conf->sc_filters_dict == NULL || 97 limits == NULL) 98 goto error; 99 100 dict_init(conf->sc_dispatchers); 101 dict_init(conf->sc_mda_wrappers); 102 dict_init(conf->sc_ca_dict); 103 dict_init(conf->sc_pki_dict); 104 dict_init(conf->sc_ssl_dict); 105 dict_init(conf->sc_tables_dict); 106 dict_init(conf->sc_limits_dict); 107 dict_init(conf->sc_filter_processes_dict); 108 109 limit_mta_set_defaults(limits); 110 111 dict_xset(conf->sc_limits_dict, "default", limits); 112 113 TAILQ_INIT(conf->sc_listeners); 114 TAILQ_INIT(conf->sc_rules); 115 116 117 /* bounce dispatcher */ 118 conf->sc_dispatcher_bounce->type = DISPATCHER_BOUNCE; 119 120 /* 121 * declare special "localhost", "anyhost" and "localnames" tables 122 */ 123 set_local(conf, conf->sc_hostname); 124 125 t = table_create(conf, "static", "<anydestination>", NULL); 126 table_add(t, "*", NULL); 127 128 hostname[strcspn(hostname, ".")] = '\0'; 129 if (strcmp(conf->sc_hostname, hostname) != 0) 130 table_add(t, hostname, NULL); 131 132 table_create(conf, "getpwnam", "<getpwnam>", NULL); 133 134 return conf; 135 136error: 137 free(conf->sc_tables_dict); 138 free(conf->sc_rules); 139 free(conf->sc_dispatchers); 140 free(conf->sc_listeners); 141 free(conf->sc_ca_dict); 142 free(conf->sc_pki_dict); 143 free(conf->sc_ssl_dict); 144 free(conf->sc_limits_dict); 145 free(conf->sc_mda_wrappers); 146 free(conf->sc_filter_processes_dict); 147 free(conf->sc_dispatcher_bounce); 148 free(conf->sc_filters_dict); 149 free(limits); 150 free(conf); 151 return NULL; 152} 153 154void 155set_local(struct smtpd *conf, const char *hostname) 156{ 157 struct table *t; 158 159 t = table_create(conf, "static", "<localnames>", NULL); 160 table_add(t, "localhost", NULL); 161 table_add(t, hostname, NULL); 162 163 set_localaddrs(conf, t); 164} 165 166void 167set_localaddrs(struct smtpd *conf, struct table *localnames) 168{ 169 struct ifaddrs *ifap, *p; 170 struct sockaddr_storage ss; 171 struct sockaddr_in *sain; 172 struct sockaddr_in6 *sin6; 173 struct table *t; 174 175 t = table_create(conf, "static", "<anyhost>", NULL); 176 table_add(t, "local", NULL); 177 table_add(t, "0.0.0.0/0", NULL); 178 table_add(t, "::/0", NULL); 179 180 if (getifaddrs(&ifap) == -1) 181 fatal("getifaddrs"); 182 183 t = table_create(conf, "static", "<localhost>", NULL); 184 table_add(t, "local", NULL); 185 186 for (p = ifap; p != NULL; p = p->ifa_next) { 187 if (p->ifa_addr == NULL) 188 continue; 189 switch (p->ifa_addr->sa_family) { 190 case AF_INET: 191 sain = (struct sockaddr_in *)&ss; 192 *sain = *(struct sockaddr_in *)p->ifa_addr; 193 sain->sin_len = sizeof(struct sockaddr_in); 194 table_add(t, ss_to_text(&ss), NULL); 195 table_add(localnames, ss_to_text(&ss), NULL); 196 break; 197 198 case AF_INET6: 199 sin6 = (struct sockaddr_in6 *)&ss; 200 *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; 201 sin6->sin6_len = sizeof(struct sockaddr_in6); 202#ifdef __KAME__ 203 if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 204 IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) || 205 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) && 206 sin6->sin6_scope_id == 0) { 207 sin6->sin6_scope_id = ntohs( 208 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); 209 sin6->sin6_addr.s6_addr[2] = 0; 210 sin6->sin6_addr.s6_addr[3] = 0; 211 } 212#endif 213 table_add(t, ss_to_text(&ss), NULL); 214 table_add(localnames, ss_to_text(&ss), NULL); 215 break; 216 } 217 } 218 219 freeifaddrs(ifap); 220} 221 222void 223purge_config(uint8_t what) 224{ 225 struct dispatcher *d; 226 struct listener *l; 227 struct table *t; 228 struct rule *r; 229 struct pki *p; 230 const char *k; 231 void *iter_dict; 232 233 if (what & PURGE_LISTENERS) { 234 while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) { 235 TAILQ_REMOVE(env->sc_listeners, l, entry); 236 free(l->tls_ciphers); 237 free(l->tls_protocols); 238 free(l->pki); 239 free(l); 240 } 241 free(env->sc_listeners); 242 env->sc_listeners = NULL; 243 } 244 if (what & PURGE_TABLES) { 245 while (dict_root(env->sc_tables_dict, NULL, (void **)&t)) 246 table_destroy(env, t); 247 free(env->sc_tables_dict); 248 env->sc_tables_dict = NULL; 249 } 250 if (what & PURGE_RULES) { 251 while ((r = TAILQ_FIRST(env->sc_rules)) != NULL) { 252 TAILQ_REMOVE(env->sc_rules, r, r_entry); 253 free(r); 254 } 255 free(env->sc_rules); 256 env->sc_rules = NULL; 257 } 258 if (what & PURGE_DISPATCHERS) { 259 while (dict_poproot(env->sc_dispatchers, (void **)&d)) { 260 free(d); 261 } 262 free(env->sc_dispatchers); 263 env->sc_dispatchers = NULL; 264 } 265 if (what & PURGE_PKI) { 266 while (dict_poproot(env->sc_pki_dict, (void **)&p)) { 267 freezero(p->pki_cert, p->pki_cert_len); 268 freezero(p->pki_key, p->pki_key_len); 269 free(p); 270 } 271 free(env->sc_pki_dict); 272 env->sc_pki_dict = NULL; 273 } else if (what & PURGE_PKI_KEYS) { 274 iter_dict = NULL; 275 while (dict_iter(env->sc_pki_dict, &iter_dict, &k, 276 (void **)&p)) { 277 freezero(p->pki_cert, p->pki_cert_len); 278 p->pki_cert = NULL; 279 freezero(p->pki_key, p->pki_key_len); 280 p->pki_key = NULL; 281 } 282 } 283} 284 285#ifndef CONFIG_MINIMUM 286 287void 288config_process(enum smtp_proc_type proc) 289{ 290 struct rlimit rl; 291 292 smtpd_process = proc; 293 setproctitle("%s", proc_title(proc)); 294 295 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) 296 fatal("fdlimit: getrlimit"); 297 rl.rlim_cur = rl.rlim_max; 298 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) 299 fatal("fdlimit: setrlimit"); 300} 301 302void 303config_peer(enum smtp_proc_type proc) 304{ 305 struct mproc *p; 306 307 if (proc == smtpd_process) 308 fatal("config_peers: cannot peer with oneself"); 309 310 if (proc == PROC_CONTROL) 311 p = p_control; 312 else if (proc == PROC_LKA) 313 p = p_lka; 314 else if (proc == PROC_PARENT) 315 p = p_parent; 316 else if (proc == PROC_QUEUE) 317 p = p_queue; 318 else if (proc == PROC_SCHEDULER) 319 p = p_scheduler; 320 else if (proc == PROC_DISPATCHER) 321 p = p_dispatcher; 322 else if (proc == PROC_CA) 323 p = p_ca; 324 else 325 fatalx("bad peer"); 326 327 mproc_enable(p); 328} 329 330#else 331 332void config_process(enum smtp_proc_type proc) {} 333void config_peer(enum smtp_proc_type proc) {} 334 335#endif 336