1 /* $OpenBSD: smtp.c,v 1.133 2014/02/04 13:44:41 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> 5 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 6 * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/queue.h> 23 #include <sys/tree.h> 24 #include <sys/socket.h> 25 26 #include <err.h> 27 #include <errno.h> 28 #include <event.h> 29 #include <imsg.h> 30 #include <netdb.h> 31 #include <pwd.h> 32 #include <signal.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include <openssl/ssl.h> 39 40 #include "smtpd.h" 41 #include "log.h" 42 #include "ssl.h" 43 44 static void smtp_imsg(struct mproc *, struct imsg *); 45 static void smtp_shutdown(void); 46 static void smtp_sig_handler(int, short, void *); 47 static void smtp_setup_events(void); 48 static void smtp_pause(void); 49 static void smtp_resume(void); 50 static void smtp_accept(int, short, void *); 51 static int smtp_enqueue(uid_t *); 52 static int smtp_can_accept(void); 53 static void smtp_setup_listeners(void); 54 55 #define SMTP_FD_RESERVE 5 56 static size_t sessions; 57 58 static void 59 smtp_imsg(struct mproc *p, struct imsg *imsg) 60 { 61 struct msg m; 62 int v; 63 64 if (p->proc == PROC_LKA) { 65 switch (imsg->hdr.type) { 66 case IMSG_DNS_PTR: 67 case IMSG_LKA_EXPAND_RCPT: 68 case IMSG_LKA_HELO: 69 case IMSG_LKA_AUTHENTICATE: 70 case IMSG_LKA_SSL_INIT: 71 case IMSG_LKA_SSL_VERIFY: 72 smtp_session_imsg(p, imsg); 73 return; 74 } 75 } 76 77 if (p->proc == PROC_MFA) { 78 switch (imsg->hdr.type) { 79 case IMSG_MFA_SMTP_RESPONSE: 80 smtp_session_imsg(p, imsg); 81 return; 82 } 83 } 84 85 if (p->proc == PROC_QUEUE) { 86 switch (imsg->hdr.type) { 87 case IMSG_QUEUE_CREATE_MESSAGE: 88 case IMSG_QUEUE_MESSAGE_FILE: 89 case IMSG_QUEUE_SUBMIT_ENVELOPE: 90 case IMSG_QUEUE_COMMIT_ENVELOPES: 91 case IMSG_QUEUE_COMMIT_MESSAGE: 92 smtp_session_imsg(p, imsg); 93 return; 94 95 case IMSG_SMTP_ENQUEUE_FD: 96 m_compose(p, IMSG_SMTP_ENQUEUE_FD, 0, 0, 97 smtp_enqueue(NULL), imsg->data, 98 imsg->hdr.len - sizeof imsg->hdr); 99 return; 100 } 101 } 102 103 if (p->proc == PROC_PARENT) { 104 switch (imsg->hdr.type) { 105 106 case IMSG_CONF_START: 107 return; 108 109 case IMSG_CONF_END: 110 smtp_setup_events(); 111 return; 112 113 case IMSG_CTL_VERBOSE: 114 m_msg(&m, imsg); 115 m_get_int(&m, &v); 116 m_end(&m); 117 log_verbose(v); 118 return; 119 120 case IMSG_CTL_PROFILE: 121 m_msg(&m, imsg); 122 m_get_int(&m, &v); 123 m_end(&m); 124 profiling = v; 125 return; 126 } 127 } 128 129 if (p->proc == PROC_CONTROL) { 130 switch (imsg->hdr.type) { 131 case IMSG_SMTP_ENQUEUE_FD: 132 m_compose(p, IMSG_SMTP_ENQUEUE_FD, imsg->hdr.peerid, 0, 133 smtp_enqueue(imsg->data), NULL, 0); 134 return; 135 136 case IMSG_CTL_PAUSE_SMTP: 137 log_debug("debug: smtp: pausing listening sockets"); 138 smtp_pause(); 139 env->sc_flags |= SMTPD_SMTP_PAUSED; 140 return; 141 142 case IMSG_CTL_RESUME_SMTP: 143 log_debug("debug: smtp: resuming listening sockets"); 144 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 145 smtp_resume(); 146 return; 147 } 148 } 149 150 errx(1, "smtp_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); 151 } 152 153 static void 154 smtp_sig_handler(int sig, short event, void *p) 155 { 156 switch (sig) { 157 case SIGINT: 158 case SIGTERM: 159 smtp_shutdown(); 160 break; 161 default: 162 fatalx("smtp_sig_handler: unexpected signal"); 163 } 164 } 165 166 static void 167 smtp_shutdown(void) 168 { 169 log_info("info: smtp server exiting"); 170 _exit(0); 171 } 172 173 pid_t 174 smtp(void) 175 { 176 pid_t pid; 177 struct passwd *pw; 178 struct event ev_sigint; 179 struct event ev_sigterm; 180 181 switch (pid = fork()) { 182 case -1: 183 fatal("smtp: cannot fork"); 184 case 0: 185 post_fork(PROC_SMTP); 186 break; 187 default: 188 return (pid); 189 } 190 191 smtp_setup_listeners(); 192 193 /* SSL will be purged later */ 194 purge_config(PURGE_TABLES|PURGE_RULES); 195 196 if ((pw = getpwnam(SMTPD_USER)) == NULL) 197 fatalx("unknown user " SMTPD_USER); 198 199 if (chroot(PATH_CHROOT) == -1) 200 fatal("smtp: chroot"); 201 if (chdir("/") == -1) 202 fatal("smtp: chdir(\"/\")"); 203 204 config_process(PROC_SMTP); 205 206 if (setgroups(1, &pw->pw_gid) || 207 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 208 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 209 fatal("smtp: cannot drop privileges"); 210 211 imsg_callback = smtp_imsg; 212 event_init(); 213 214 signal_set(&ev_sigint, SIGINT, smtp_sig_handler, NULL); 215 signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, NULL); 216 signal_add(&ev_sigint, NULL); 217 signal_add(&ev_sigterm, NULL); 218 signal(SIGPIPE, SIG_IGN); 219 signal(SIGHUP, SIG_IGN); 220 221 config_peer(PROC_CONTROL); 222 config_peer(PROC_PARENT); 223 config_peer(PROC_LKA); 224 config_peer(PROC_MFA); 225 config_peer(PROC_QUEUE); 226 config_done(); 227 228 if (event_dispatch() < 0) 229 fatal("event_dispatch"); 230 smtp_shutdown(); 231 232 return (0); 233 } 234 235 static void 236 smtp_setup_listeners(void) 237 { 238 struct listener *l; 239 int opt; 240 241 TAILQ_FOREACH(l, env->sc_listeners, entry) { 242 if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1) { 243 if (errno == EAFNOSUPPORT) { 244 log_warn("smtpd: socket"); 245 continue; 246 } 247 fatal("smtpd: socket"); 248 } 249 opt = 1; 250 if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt, 251 sizeof(opt)) < 0) 252 fatal("smtpd: setsockopt"); 253 if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1) 254 fatal("smtpd: bind"); 255 } 256 } 257 258 static void 259 smtp_setup_events(void) 260 { 261 struct listener *l; 262 struct pki *pki; 263 SSL_CTX *ssl_ctx; 264 void *iter; 265 const char *k; 266 267 TAILQ_FOREACH(l, env->sc_listeners, entry) { 268 log_debug("debug: smtp: listen on %s port %d flags 0x%01x" 269 " pki \"%s\"", ss_to_text(&l->ss), ntohs(l->port), 270 l->flags, l->pki_name); 271 272 session_socket_blockmode(l->fd, BM_NONBLOCK); 273 if (listen(l->fd, SMTPD_BACKLOG) == -1) 274 fatal("listen"); 275 event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l); 276 277 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) 278 event_add(&l->ev, NULL); 279 } 280 281 iter = NULL; 282 while (dict_iter(env->sc_pki_dict, &iter, &k, (void **)&pki)) { 283 if (! ssl_setup((SSL_CTX **)&ssl_ctx, pki)) 284 fatal("smtp_setup_events: ssl_setup failure"); 285 dict_xset(env->sc_ssl_dict, k, ssl_ctx); 286 } 287 288 purge_config(PURGE_PKI); 289 290 log_debug("debug: smtp: will accept at most %d clients", 291 (getdtablesize() - getdtablecount())/2 - SMTP_FD_RESERVE); 292 } 293 294 static void 295 smtp_pause(void) 296 { 297 struct listener *l; 298 299 if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED)) 300 return; 301 302 TAILQ_FOREACH(l, env->sc_listeners, entry) 303 event_del(&l->ev); 304 } 305 306 static void 307 smtp_resume(void) 308 { 309 struct listener *l; 310 311 if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED)) 312 return; 313 314 TAILQ_FOREACH(l, env->sc_listeners, entry) 315 event_add(&l->ev, NULL); 316 } 317 318 static int 319 smtp_enqueue(uid_t *euid) 320 { 321 static struct listener local, *listener = NULL; 322 char buf[SMTPD_MAXHOSTNAMELEN], *hostname; 323 int fd[2]; 324 325 if (listener == NULL) { 326 listener = &local; 327 strlcpy(listener->tag, "local", sizeof(listener->tag)); 328 listener->ss.ss_family = AF_LOCAL; 329 listener->ss.ss_len = sizeof(struct sockaddr *); 330 strlcpy(listener->hostname, "localhost", 331 sizeof(listener->hostname)); 332 } 333 334 /* 335 * Some enqueue requests buffered in IMSG may still arrive even after 336 * call to smtp_pause() because enqueue listener is not a real socket 337 * and thus cannot be paused properly. 338 */ 339 if (env->sc_flags & SMTPD_SMTP_PAUSED) 340 return (-1); 341 342 /* XXX dont' fatal here */ 343 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd)) 344 fatal("socketpair"); 345 346 hostname = "localhost"; 347 if (euid) { 348 snprintf(buf, sizeof(buf), "%d@localhost", *euid); 349 hostname = buf; 350 } 351 352 if ((smtp_session(listener, fd[0], &listener->ss, hostname)) == -1) { 353 close(fd[0]); 354 close(fd[1]); 355 return (-1); 356 } 357 358 sessions++; 359 stat_increment("smtp.session", 1); 360 stat_increment("smtp.session.local", 1); 361 362 return (fd[1]); 363 } 364 365 static void 366 smtp_accept(int fd, short event, void *p) 367 { 368 struct listener *listener = p; 369 struct sockaddr_storage ss; 370 socklen_t len; 371 int sock; 372 373 if (env->sc_flags & SMTPD_SMTP_PAUSED) 374 fatalx("smtp_session: unexpected client"); 375 376 if (! smtp_can_accept()) { 377 log_warnx("warn: Disabling incoming SMTP connections: " 378 "Client limit reached"); 379 goto pause; 380 } 381 382 len = sizeof(ss); 383 if ((sock = accept(fd, (struct sockaddr *)&ss, &len)) == -1) { 384 if (errno == ENFILE || errno == EMFILE) { 385 log_warn("warn: Disabling incoming SMTP connections"); 386 goto pause; 387 } 388 if (errno == EINTR || errno == EWOULDBLOCK || 389 errno == ECONNABORTED) 390 return; 391 fatal("smtp_accept"); 392 } 393 394 if (smtp_session(listener, sock, &ss, NULL) == -1) { 395 log_warn("warn: Failed to create SMTP session"); 396 close(sock); 397 return; 398 } 399 io_set_blocking(sock, 0); 400 401 sessions++; 402 stat_increment("smtp.session", 1); 403 if (listener->ss.ss_family == AF_LOCAL) 404 stat_increment("smtp.session.local", 1); 405 if (listener->ss.ss_family == AF_INET) 406 stat_increment("smtp.session.inet4", 1); 407 if (listener->ss.ss_family == AF_INET6) 408 stat_increment("smtp.session.inet6", 1); 409 return; 410 411 pause: 412 smtp_pause(); 413 env->sc_flags |= SMTPD_SMTP_DISABLED; 414 return; 415 } 416 417 static int 418 smtp_can_accept(void) 419 { 420 size_t max; 421 422 max = (getdtablesize() - getdtablecount()) / 2 - SMTP_FD_RESERVE; 423 424 return (sessions < max); 425 } 426 427 void 428 smtp_collect(void) 429 { 430 sessions--; 431 stat_decrement("smtp.session", 1); 432 433 if (!smtp_can_accept()) 434 return; 435 436 if (env->sc_flags & SMTPD_SMTP_DISABLED) { 437 log_warnx("warn: smtp: " 438 "fd exaustion over, re-enabling incoming connections"); 439 env->sc_flags &= ~SMTPD_SMTP_DISABLED; 440 smtp_resume(); 441 } 442 } 443