1 /* $OpenBSD: smtp.c,v 1.101 2012/01/31 21:05:26 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.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/param.h> 25 #include <sys/socket.h> 26 27 #include <err.h> 28 #include <errno.h> 29 #include <event.h> 30 #include <imsg.h> 31 #include <netdb.h> 32 #include <pwd.h> 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "smtpd.h" 40 #include "log.h" 41 42 static void smtp_imsg(struct imsgev *, struct imsg *); 43 static void smtp_shutdown(void); 44 static void smtp_sig_handler(int, short, void *); 45 static void smtp_setup_events(void); 46 static void smtp_pause(void); 47 static int smtp_enqueue(uid_t *); 48 static void smtp_accept(int, short, void *); 49 static struct session *smtp_new(struct listener *); 50 static struct session *session_lookup(u_int64_t); 51 52 53 static void 54 smtp_imsg(struct imsgev *iev, struct imsg *imsg) 55 { 56 struct session skey; 57 struct submit_status *ss; 58 struct listener *l; 59 struct session *s; 60 struct auth *auth; 61 struct ssl *ssl; 62 struct dns *dns; 63 64 log_imsg(PROC_SMTP, iev->proc, imsg); 65 66 if (iev->proc == PROC_LKA) { 67 switch (imsg->hdr.type) { 68 case IMSG_DNS_PTR: 69 dns = imsg->data; 70 s = session_lookup(dns->id); 71 if (s == NULL) 72 fatalx("smtp: impossible quit"); 73 strlcpy(s->s_hostname, 74 dns->error ? "<unknown>" : dns->host, 75 sizeof s->s_hostname); 76 strlcpy(s->s_msg.hostname, s->s_hostname, 77 sizeof s->s_msg.hostname); 78 session_pickup(s, NULL); 79 return; 80 } 81 } 82 83 if (iev->proc == PROC_MFA) { 84 switch (imsg->hdr.type) { 85 case IMSG_MFA_CONNECT: 86 case IMSG_MFA_HELO: 87 case IMSG_MFA_MAIL: 88 case IMSG_MFA_RCPT: 89 case IMSG_MFA_DATALINE: 90 case IMSG_MFA_QUIT: 91 case IMSG_MFA_RSET: 92 ss = imsg->data; 93 s = session_lookup(ss->id); 94 if (s == NULL) 95 return; 96 session_pickup(s, ss); 97 return; 98 case IMSG_MFA_CLOSE: 99 return; 100 } 101 } 102 103 if (iev->proc == PROC_QUEUE) { 104 ss = imsg->data; 105 106 switch (imsg->hdr.type) { 107 case IMSG_QUEUE_CREATE_MESSAGE: 108 s = session_lookup(ss->id); 109 if (s == NULL) 110 return; 111 s->s_msg.id = ((u_int64_t)ss->u.msgid) << 32; 112 session_pickup(s, ss); 113 return; 114 115 case IMSG_QUEUE_MESSAGE_FILE: 116 s = session_lookup(ss->id); 117 if (s == NULL) { 118 close(imsg->fd); 119 return; 120 } 121 s->datafp = fdopen(imsg->fd, "w"); 122 if (s->datafp == NULL) { 123 /* queue may have experienced tempfail. */ 124 if (ss->code != 421) 125 fatalx("smtp: fdopen"); 126 close(imsg->fd); 127 } 128 session_pickup(s, ss); 129 return; 130 131 case IMSG_QUEUE_TEMPFAIL: 132 skey.s_id = ss->id; 133 /* do not use lookup since this is not a expected imsg -- eric@ */ 134 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &skey); 135 if (s == NULL) 136 fatalx("smtp: session is gone"); 137 s->s_dstatus |= DS_TEMPFAILURE; 138 return; 139 140 case IMSG_QUEUE_COMMIT_ENVELOPES: 141 s = session_lookup(ss->id); 142 if (s == NULL) 143 return; 144 session_pickup(s, ss); 145 return; 146 147 case IMSG_QUEUE_COMMIT_MESSAGE: 148 s = session_lookup(ss->id); 149 if (s == NULL) 150 return; 151 session_pickup(s, ss); 152 return; 153 154 case IMSG_SMTP_ENQUEUE: 155 imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 0, 0, 156 smtp_enqueue(NULL), imsg->data, 157 sizeof(struct envelope)); 158 return; 159 } 160 } 161 162 if (iev->proc == PROC_PARENT) { 163 switch (imsg->hdr.type) { 164 165 case IMSG_CONF_START: 166 if (env->sc_flags & SMTPD_CONFIGURING) 167 return; 168 env->sc_flags |= SMTPD_CONFIGURING; 169 env->sc_listeners = calloc(1, sizeof *env->sc_listeners); 170 env->sc_ssl = calloc(1, sizeof *env->sc_ssl); 171 if (env->sc_listeners == NULL || env->sc_ssl == NULL) 172 fatal(NULL); 173 TAILQ_INIT(env->sc_listeners); 174 return; 175 176 case IMSG_CONF_SSL: 177 if (!(env->sc_flags & SMTPD_CONFIGURING)) 178 return; 179 ssl = calloc(1, sizeof *ssl); 180 if (ssl == NULL) 181 fatal(NULL); 182 *ssl = *(struct ssl *)imsg->data; 183 ssl->ssl_cert = strdup((char *)imsg->data + 184 sizeof *ssl); 185 if (ssl->ssl_cert == NULL) 186 fatal(NULL); 187 ssl->ssl_key = strdup((char *)imsg->data + sizeof *ssl + 188 ssl->ssl_cert_len); 189 if (ssl->ssl_key == NULL) 190 fatal(NULL); 191 if (ssl->ssl_dhparams_len) { 192 ssl->ssl_dhparams = strdup((char *)imsg->data 193 + sizeof *ssl + ssl->ssl_cert_len + 194 ssl->ssl_key_len); 195 if (ssl->ssl_dhparams == NULL) 196 fatal(NULL); 197 } 198 if (ssl->ssl_ca_len) { 199 ssl->ssl_ca = strdup((char *)imsg->data 200 + sizeof *ssl + ssl->ssl_cert_len + 201 ssl->ssl_key_len + ssl->ssl_dhparams_len); 202 if (ssl->ssl_ca == NULL) 203 fatal(NULL); 204 } 205 206 SPLAY_INSERT(ssltree, env->sc_ssl, ssl); 207 return; 208 209 case IMSG_CONF_LISTENER: 210 if (!(env->sc_flags & SMTPD_CONFIGURING)) 211 return; 212 l = calloc(1, sizeof *l); 213 if (l == NULL) 214 fatal(NULL); 215 *l = *(struct listener *)imsg->data; 216 l->fd = imsg->fd; 217 if (l->fd < 0) 218 fatalx("smtp: listener pass failed"); 219 if (l->flags & F_SSL) { 220 struct ssl key; 221 222 strlcpy(key.ssl_name, l->ssl_cert_name, 223 sizeof key.ssl_name); 224 l->ssl = SPLAY_FIND(ssltree, env->sc_ssl, &key); 225 if (l->ssl == NULL) 226 fatalx("smtp: ssltree out of sync"); 227 } 228 TAILQ_INSERT_TAIL(env->sc_listeners, l, entry); 229 return; 230 231 case IMSG_CONF_END: 232 if (!(env->sc_flags & SMTPD_CONFIGURING)) 233 return; 234 smtp_setup_events(); 235 env->sc_flags &= ~SMTPD_CONFIGURING; 236 return; 237 238 case IMSG_PARENT_AUTHENTICATE: 239 auth = imsg->data; 240 s = session_lookup(auth->id); 241 if (s == NULL) 242 return; 243 if (auth->success) { 244 s->s_flags |= F_AUTHENTICATED; 245 s->s_msg.flags |= DF_AUTHENTICATED; 246 } else { 247 s->s_flags &= ~F_AUTHENTICATED; 248 s->s_msg.flags &= ~DF_AUTHENTICATED; 249 } 250 session_pickup(s, NULL); 251 return; 252 253 case IMSG_CTL_VERBOSE: 254 log_verbose(*(int *)imsg->data); 255 return; 256 } 257 } 258 259 if (iev->proc == PROC_CONTROL) { 260 switch (imsg->hdr.type) { 261 case IMSG_SMTP_ENQUEUE: 262 imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 263 imsg->hdr.peerid, 0, smtp_enqueue(imsg->data), 264 NULL, 0); 265 return; 266 267 case IMSG_SMTP_PAUSE: 268 smtp_pause(); 269 return; 270 271 case IMSG_SMTP_RESUME: 272 smtp_resume(); 273 return; 274 } 275 } 276 277 errx(1, "smtp_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); 278 } 279 280 static void 281 smtp_sig_handler(int sig, short event, void *p) 282 { 283 switch (sig) { 284 case SIGINT: 285 case SIGTERM: 286 smtp_shutdown(); 287 break; 288 default: 289 fatalx("smtp_sig_handler: unexpected signal"); 290 } 291 } 292 293 static void 294 smtp_shutdown(void) 295 { 296 log_info("smtp server exiting"); 297 _exit(0); 298 } 299 300 pid_t 301 smtp(void) 302 { 303 pid_t pid; 304 struct passwd *pw; 305 306 struct event ev_sigint; 307 struct event ev_sigterm; 308 309 struct peer peers[] = { 310 { PROC_PARENT, imsg_dispatch }, 311 { PROC_MFA, imsg_dispatch }, 312 { PROC_QUEUE, imsg_dispatch }, 313 { PROC_LKA, imsg_dispatch }, 314 { PROC_CONTROL, imsg_dispatch } 315 }; 316 317 switch (pid = fork()) { 318 case -1: 319 fatal("smtp: cannot fork"); 320 case 0: 321 break; 322 default: 323 return (pid); 324 } 325 326 ssl_init(); 327 purge_config(PURGE_EVERYTHING); 328 329 pw = env->sc_pw; 330 331 if (chroot(pw->pw_dir) == -1) 332 fatal("smtp: chroot"); 333 if (chdir("/") == -1) 334 fatal("smtp: chdir(\"/\")"); 335 336 smtpd_process = PROC_SMTP; 337 setproctitle("%s", env->sc_title[smtpd_process]); 338 339 if (setgroups(1, &pw->pw_gid) || 340 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 341 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 342 fatal("smtp: cannot drop privileges"); 343 344 imsg_callback = smtp_imsg; 345 event_init(); 346 347 signal_set(&ev_sigint, SIGINT, smtp_sig_handler, NULL); 348 signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, NULL); 349 signal_add(&ev_sigint, NULL); 350 signal_add(&ev_sigterm, NULL); 351 signal(SIGPIPE, SIG_IGN); 352 signal(SIGHUP, SIG_IGN); 353 354 /* Initial limit for use by IMSG_SMTP_ENQUEUE, will be tuned later once 355 * the listening sockets arrive. */ 356 env->sc_maxconn = availdesc() / 2; 357 358 config_pipes(peers, nitems(peers)); 359 config_peers(peers, nitems(peers)); 360 361 if (event_dispatch() < 0) 362 fatal("event_dispatch"); 363 smtp_shutdown(); 364 365 return (0); 366 } 367 368 static void 369 smtp_setup_events(void) 370 { 371 struct listener *l; 372 int avail = availdesc(); 373 374 TAILQ_FOREACH(l, env->sc_listeners, entry) { 375 log_debug("smtp: listen on %s port %d flags 0x%01x" 376 " cert \"%s\"", ss_to_text(&l->ss), ntohs(l->port), 377 l->flags, l->ssl_cert_name); 378 379 session_socket_blockmode(l->fd, BM_NONBLOCK); 380 if (listen(l->fd, SMTPD_BACKLOG) == -1) 381 fatal("listen"); 382 event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l); 383 event_add(&l->ev, NULL); 384 ssl_setup(l); 385 avail--; 386 } 387 388 /* guarantee 2 fds to each accepted client */ 389 if ((env->sc_maxconn = avail / 2) < 1) 390 fatalx("smtp_setup_events: fd starvation"); 391 392 log_debug("smtp: will accept at most %d clients", env->sc_maxconn); 393 } 394 395 static void 396 smtp_pause(void) 397 { 398 struct listener *l; 399 400 log_debug("smtp: pausing listening sockets"); 401 env->sc_flags |= SMTPD_SMTP_PAUSED; 402 403 TAILQ_FOREACH(l, env->sc_listeners, entry) 404 event_del(&l->ev); 405 } 406 407 void 408 smtp_resume(void) 409 { 410 struct listener *l; 411 412 log_debug("smtp: resuming listening sockets"); 413 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 414 415 TAILQ_FOREACH(l, env->sc_listeners, entry) 416 event_add(&l->ev, NULL); 417 } 418 419 static int 420 smtp_enqueue(uid_t *euid) 421 { 422 static struct listener local, *l; 423 static struct sockaddr_storage sa; 424 struct session *s; 425 int fd[2]; 426 427 if (l == NULL) { 428 struct addrinfo hints, *res; 429 430 l = &local; 431 strlcpy(l->tag, "local", sizeof(l->tag)); 432 433 bzero(&hints, sizeof(hints)); 434 hints.ai_family = PF_UNSPEC; 435 hints.ai_flags = AI_NUMERICHOST; 436 437 if (getaddrinfo("::1", NULL, &hints, &res)) 438 fatal("getaddrinfo"); 439 memcpy(&sa, res->ai_addr, res->ai_addrlen); 440 freeaddrinfo(res); 441 } 442 443 /* 444 * Some enqueue requests buffered in IMSG may still arrive even after 445 * call to smtp_pause() because enqueue listener is not a real socket 446 * and thus cannot be paused properly. 447 */ 448 if (env->sc_flags & SMTPD_SMTP_PAUSED) 449 return (-1); 450 451 if ((s = smtp_new(l)) == NULL) 452 return (-1); 453 454 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd)) 455 fatal("socketpair"); 456 457 s->s_io.sock = fd[0]; 458 s->s_ss = sa; 459 s->s_msg.flags |= DF_ENQUEUED; 460 461 if (euid) 462 bsnprintf(s->s_hostname, sizeof(s->s_hostname), "%d@localhost", 463 *euid); 464 else { 465 strlcpy(s->s_hostname, "localhost", sizeof(s->s_hostname)); 466 s->s_msg.flags |= DF_BOUNCE; 467 } 468 469 strlcpy(s->s_msg.hostname, s->s_hostname, 470 sizeof(s->s_msg.hostname)); 471 472 session_pickup(s, NULL); 473 474 return (fd[1]); 475 } 476 477 static void 478 smtp_accept(int fd, short event, void *p) 479 { 480 struct listener *l = p; 481 struct session *s; 482 socklen_t len; 483 484 if ((s = smtp_new(l)) == NULL) 485 return; 486 487 len = sizeof(s->s_ss); 488 if ((s->s_io.sock = accept(fd, (struct sockaddr *)&s->s_ss, &len)) == -1) { 489 if (errno == EINTR || errno == ECONNABORTED) 490 return; 491 fatal("smtp_accept"); 492 } 493 494 io_set_timeout(&s->s_io, SMTPD_SESSION_TIMEOUT * 1000); 495 io_set_write(&s->s_io); 496 dns_query_ptr(&s->s_ss, s->s_id); 497 } 498 499 500 static struct session * 501 smtp_new(struct listener *l) 502 { 503 struct session *s; 504 505 log_debug("smtp: new client on listener: %p", l); 506 507 if (env->sc_flags & SMTPD_SMTP_PAUSED) 508 fatalx("smtp_new: unexpected client"); 509 510 if ((s = calloc(1, sizeof(*s))) == NULL) 511 fatal(NULL); 512 s->s_id = generate_uid(); 513 s->s_l = l; 514 strlcpy(s->s_msg.tag, l->tag, sizeof(s->s_msg.tag)); 515 SPLAY_INSERT(sessiontree, &env->sc_sessions, s); 516 517 if (stat_increment(STATS_SMTP_SESSION) >= env->sc_maxconn) { 518 log_warnx("client limit hit, disabling incoming connections"); 519 smtp_pause(); 520 } 521 522 if (s->s_l->ss.ss_family == AF_INET) 523 stat_increment(STATS_SMTP_SESSION_INET4); 524 if (s->s_l->ss.ss_family == AF_INET6) 525 stat_increment(STATS_SMTP_SESSION_INET6); 526 527 iobuf_init(&s->s_iobuf, MAX_LINE_SIZE, MAX_LINE_SIZE); 528 io_init(&s->s_io, -1, s, session_io, &s->s_iobuf); 529 s->s_state = S_CONNECTED; 530 531 return (s); 532 } 533 534 /* 535 * Helper function for handling IMSG replies. 536 */ 537 static struct session * 538 session_lookup(u_int64_t id) 539 { 540 struct session key; 541 struct session *s; 542 543 key.s_id = id; 544 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); 545 if (s == NULL) 546 fatalx("session_lookup: session is gone"); 547 548 if (s->s_flags & F_ZOMBIE) { 549 session_destroy(s, "(finalizing)"); 550 s = NULL; 551 } 552 553 return (s); 554 } 555