1 /* $OpenBSD: control.c,v 1.21 2009/03/29 14:18:20 jacekm Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 #include <sys/param.h> 24 #include <sys/stat.h> 25 #include <sys/socket.h> 26 #include <sys/un.h> 27 28 #include <errno.h> 29 #include <event.h> 30 #include <fcntl.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 "smtpd.h" 39 40 #define CONTROL_BACKLOG 5 41 42 /* control specific headers */ 43 struct { 44 struct event ev; 45 int fd; 46 } control_state; 47 48 __dead void control_shutdown(void); 49 int control_init(void); 50 int control_listen(struct smtpd *); 51 void control_cleanup(void); 52 void control_accept(int, short, void *); 53 struct ctl_conn *control_connbyfd(int); 54 void control_close(int); 55 void control_sig_handler(int, short, void *); 56 void control_dispatch_ext(int, short, void *); 57 void control_dispatch_lka(int, short, void *); 58 void control_dispatch_mfa(int, short, void *); 59 void control_dispatch_queue(int, short, void *); 60 void control_dispatch_runner(int, short, void *); 61 void control_dispatch_smtp(int, short, void *); 62 void control_dispatch_parent(int, short, void *); 63 64 struct ctl_connlist ctl_conns; 65 66 void 67 control_sig_handler(int sig, short event, void *p) 68 { 69 switch (sig) { 70 case SIGINT: 71 case SIGTERM: 72 control_shutdown(); 73 break; 74 default: 75 fatalx("control_sig_handler: unexpected signal"); 76 } 77 } 78 79 80 pid_t 81 control(struct smtpd *env) 82 { 83 struct sockaddr_un sun; 84 int fd; 85 mode_t old_umask; 86 pid_t pid; 87 struct passwd *pw; 88 struct event ev_sigint; 89 struct event ev_sigterm; 90 struct peer peers [] = { 91 { PROC_QUEUE, control_dispatch_queue }, 92 { PROC_RUNNER, control_dispatch_runner }, 93 { PROC_SMTP, control_dispatch_smtp }, 94 { PROC_MFA, control_dispatch_mfa }, 95 { PROC_PARENT, control_dispatch_parent }, 96 }; 97 98 switch (pid = fork()) { 99 case -1: 100 fatal("control: cannot fork"); 101 case 0: 102 break; 103 default: 104 return (pid); 105 } 106 107 purge_config(env, PURGE_EVERYTHING); 108 109 pw = env->sc_pw; 110 111 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 112 fatal("control: socket"); 113 114 sun.sun_family = AF_UNIX; 115 if (strlcpy(sun.sun_path, SMTPD_SOCKET, 116 sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) 117 fatal("control: socket name too long"); 118 119 if (unlink(SMTPD_SOCKET) == -1) 120 if (errno != ENOENT) 121 fatal("control: cannot unlink socket"); 122 123 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 124 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 125 (void)umask(old_umask); 126 fatal("control: bind"); 127 } 128 (void)umask(old_umask); 129 130 if (chmod(SMTPD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) { 131 (void)unlink(SMTPD_SOCKET); 132 fatal("control: chmod"); 133 } 134 135 session_socket_blockmode(fd, BM_NONBLOCK); 136 control_state.fd = fd; 137 138 #ifndef DEBUG 139 if (chroot(pw->pw_dir) == -1) 140 fatal("control: chroot"); 141 if (chdir("/") == -1) 142 fatal("control: chdir(\"/\")"); 143 #else 144 #warning disabling privilege revocation and chroot in DEBUG MODE 145 #endif 146 147 setproctitle("control process"); 148 smtpd_process = PROC_CONTROL; 149 150 #ifndef DEBUG 151 if (setgroups(1, &pw->pw_gid) || 152 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 153 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 154 fatal("control: cannot drop privileges"); 155 #endif 156 157 event_init(); 158 159 signal_set(&ev_sigint, SIGINT, control_sig_handler, env); 160 signal_set(&ev_sigterm, SIGTERM, control_sig_handler, env); 161 signal_add(&ev_sigint, NULL); 162 signal_add(&ev_sigterm, NULL); 163 signal(SIGPIPE, SIG_IGN); 164 signal(SIGHUP, SIG_IGN); 165 166 TAILQ_INIT(&ctl_conns); 167 168 config_pipes(env, peers, 5); 169 config_peers(env, peers, 5); 170 control_listen(env); 171 event_dispatch(); 172 control_shutdown(); 173 174 return (0); 175 } 176 177 void 178 control_shutdown(void) 179 { 180 log_info("control process exiting"); 181 _exit(0); 182 } 183 184 int 185 control_listen(struct smtpd *env) 186 { 187 if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 188 log_warn("control_listen: listen"); 189 return (-1); 190 } 191 192 event_set(&control_state.ev, control_state.fd, EV_READ | EV_PERSIST, 193 control_accept, env); 194 event_add(&control_state.ev, NULL); 195 196 return (0); 197 } 198 199 void 200 control_cleanup(void) 201 { 202 (void)unlink(SMTPD_SOCKET); 203 } 204 205 /* ARGSUSED */ 206 void 207 control_accept(int listenfd, short event, void *arg) 208 { 209 int connfd; 210 socklen_t len; 211 struct sockaddr_un sun; 212 struct ctl_conn *c; 213 struct smtpd *env = arg; 214 215 len = sizeof(sun); 216 if ((connfd = accept(listenfd, 217 (struct sockaddr *)&sun, &len)) == -1) { 218 if (errno != EWOULDBLOCK && errno != EINTR) 219 log_warn("control_accept"); 220 return; 221 } 222 223 session_socket_blockmode(connfd, BM_NONBLOCK); 224 225 if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 226 close(connfd); 227 log_warn("control_accept"); 228 return; 229 } 230 231 imsg_init(&c->ibuf, connfd, control_dispatch_ext); 232 c->ibuf.events = EV_READ; 233 c->ibuf.data = env; 234 event_set(&c->ibuf.ev, c->ibuf.fd, c->ibuf.events, 235 c->ibuf.handler, env); 236 event_add(&c->ibuf.ev, NULL); 237 238 TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 239 } 240 241 struct ctl_conn * 242 control_connbyfd(int fd) 243 { 244 struct ctl_conn *c; 245 246 for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->ibuf.fd != fd; 247 c = TAILQ_NEXT(c, entry)) 248 ; /* nothing */ 249 250 return (c); 251 } 252 253 void 254 control_close(int fd) 255 { 256 struct ctl_conn *c; 257 258 if ((c = control_connbyfd(fd)) == NULL) { 259 log_warn("control_close: fd %d: not found", fd); 260 return; 261 } 262 263 msgbuf_clear(&c->ibuf.w); 264 TAILQ_REMOVE(&ctl_conns, c, entry); 265 266 event_del(&c->ibuf.ev); 267 close(c->ibuf.fd); 268 free(c); 269 } 270 271 /* ARGSUSED */ 272 void 273 control_dispatch_ext(int fd, short event, void *arg) 274 { 275 struct ctl_conn *c; 276 struct smtpd *env = arg; 277 struct imsg imsg; 278 int n; 279 uid_t euid; 280 gid_t egid; 281 282 if (getpeereid(fd, &euid, &egid) == -1) 283 fatal("getpeereid"); 284 285 if ((c = control_connbyfd(fd)) == NULL) { 286 log_warn("control_dispatch_ext: fd %d: not found", fd); 287 return; 288 } 289 290 switch (event) { 291 case EV_READ: 292 if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) { 293 control_close(fd); 294 return; 295 } 296 break; 297 case EV_WRITE: 298 if (msgbuf_write(&c->ibuf.w) < 0) { 299 control_close(fd); 300 return; 301 } 302 imsg_event_add(&c->ibuf); 303 return; 304 default: 305 fatalx("unknown event"); 306 } 307 308 for (;;) { 309 if ((n = imsg_get(&c->ibuf, &imsg)) == -1) { 310 control_close(fd); 311 return; 312 } 313 314 if (n == 0) 315 break; 316 317 switch (imsg.hdr.type) { 318 case IMSG_MFA_RCPT: { 319 struct message_recipient *mr; 320 321 if (c->state != CS_INIT && c->state != CS_RCPT) 322 goto badstate; 323 324 mr = imsg.data; 325 imsg_compose(env->sc_ibufs[PROC_MFA], IMSG_MFA_RCPT, 0, 0, -1, 326 mr, sizeof(*mr)); 327 event_del(&c->ibuf.ev); 328 break; 329 } 330 case IMSG_QUEUE_CREATE_MESSAGE: { 331 struct message *messagep; 332 333 if (c->state != CS_NONE && c->state != CS_DONE) 334 goto badstate; 335 336 messagep = imsg.data; 337 messagep->session_id = fd; 338 imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1, 339 messagep, sizeof(*messagep)); 340 event_del(&c->ibuf.ev); 341 break; 342 } 343 case IMSG_QUEUE_MESSAGE_FILE: { 344 struct message *messagep; 345 346 if (c->state != CS_RCPT) 347 goto badstate; 348 349 messagep = imsg.data; 350 messagep->session_id = fd; 351 imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_MESSAGE_FILE, 0, 0, -1, 352 messagep, sizeof(*messagep)); 353 event_del(&c->ibuf.ev); 354 break; 355 } 356 case IMSG_QUEUE_COMMIT_MESSAGE: { 357 struct message *messagep; 358 359 if (c->state != CS_FD) 360 goto badstate; 361 362 messagep = imsg.data; 363 messagep->session_id = fd; 364 imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, 365 messagep, sizeof(*messagep)); 366 event_del(&c->ibuf.ev); 367 break; 368 } 369 case IMSG_STATS: { 370 struct stats s; 371 372 if (euid) 373 goto badcred; 374 375 s.fd = fd; 376 imsg_compose(env->sc_ibufs[PROC_PARENT], IMSG_STATS, 0, 0, -1, &s, sizeof(s)); 377 imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_STATS, 0, 0, -1, &s, sizeof(s)); 378 imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_STATS, 0, 0, -1, &s, sizeof(s)); 379 imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_STATS, 0, 0, -1, &s, sizeof(s)); 380 break; 381 } 382 case IMSG_RUNNER_SCHEDULE: { 383 struct sched s; 384 385 if (euid) 386 goto badcred; 387 388 s = *(struct sched *)imsg.data; 389 s.fd = fd; 390 391 if (! valid_message_id(s.mid) && ! valid_message_uid(s.mid)) { 392 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 393 NULL, 0); 394 break; 395 } 396 397 imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_RUNNER_SCHEDULE, 0, 0, -1, &s, sizeof(s)); 398 break; 399 } 400 case IMSG_CTL_SHUTDOWN: 401 /* NEEDS_FIX */ 402 log_debug("received shutdown request"); 403 404 if (euid) 405 goto badcred; 406 407 if (env->sc_flags & SMTPD_EXITING) { 408 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 409 NULL, 0); 410 break; 411 } 412 env->sc_flags |= SMTPD_EXITING; 413 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 414 break; 415 case IMSG_MDA_PAUSE: 416 if (euid) 417 goto badcred; 418 419 if (env->sc_flags & SMTPD_MDA_PAUSED) { 420 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 421 NULL, 0); 422 break; 423 } 424 env->sc_flags |= SMTPD_MDA_PAUSED; 425 imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_MDA_PAUSE, 426 0, 0, -1, NULL, 0); 427 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 428 break; 429 case IMSG_MTA_PAUSE: 430 if (euid) 431 goto badcred; 432 433 if (env->sc_flags & SMTPD_MTA_PAUSED) { 434 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 435 NULL, 0); 436 break; 437 } 438 env->sc_flags |= SMTPD_MTA_PAUSED; 439 imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_MTA_PAUSE, 440 0, 0, -1, NULL, 0); 441 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 442 break; 443 case IMSG_SMTP_PAUSE: 444 if (euid) 445 goto badcred; 446 447 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 448 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 449 NULL, 0); 450 break; 451 } 452 env->sc_flags |= SMTPD_SMTP_PAUSED; 453 imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_SMTP_PAUSE, 454 0, 0, -1, NULL, 0); 455 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 456 break; 457 case IMSG_MDA_RESUME: 458 if (euid) 459 goto badcred; 460 461 if (! (env->sc_flags & SMTPD_MDA_PAUSED)) { 462 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 463 NULL, 0); 464 break; 465 } 466 env->sc_flags &= ~SMTPD_MDA_PAUSED; 467 imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_MTA_RESUME, 468 0, 0, -1, NULL, 0); 469 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 470 break; 471 case IMSG_MTA_RESUME: 472 if (euid) 473 goto badcred; 474 475 if (!(env->sc_flags & SMTPD_MTA_PAUSED)) { 476 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 477 NULL, 0); 478 break; 479 } 480 env->sc_flags &= ~SMTPD_MTA_PAUSED; 481 imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_MTA_RESUME, 482 0, 0, -1, NULL, 0); 483 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 484 break; 485 case IMSG_SMTP_RESUME: 486 if (euid) 487 goto badcred; 488 489 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) { 490 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 491 NULL, 0); 492 break; 493 } 494 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 495 imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_SMTP_RESUME, 496 0, 0, -1, NULL, 0); 497 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 498 break; 499 default: 500 log_debug("control_dispatch_ext: " 501 "error handling imsg %d", imsg.hdr.type); 502 break; 503 } 504 imsg_free(&imsg); 505 continue; 506 507 badstate: 508 badcred: 509 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 510 NULL, 0); 511 } 512 513 imsg_event_add(&c->ibuf); 514 } 515 516 void 517 control_dispatch_parent(int sig, short event, void *p) 518 { 519 struct smtpd *env = p; 520 struct imsgbuf *ibuf; 521 struct imsg imsg; 522 ssize_t n; 523 524 ibuf = env->sc_ibufs[PROC_PARENT]; 525 switch (event) { 526 case EV_READ: 527 if ((n = imsg_read(ibuf)) == -1) 528 fatal("imsg_read_error"); 529 if (n == 0) { 530 /* this pipe is dead, so remove the event handler */ 531 event_del(&ibuf->ev); 532 event_loopexit(NULL); 533 return; 534 } 535 break; 536 case EV_WRITE: 537 if (msgbuf_write(&ibuf->w) == -1) 538 fatal("msgbuf_write"); 539 imsg_event_add(ibuf); 540 return; 541 default: 542 fatalx("unknown event"); 543 } 544 545 for (;;) { 546 if ((n = imsg_get(ibuf, &imsg)) == -1) 547 fatal("control_dispatch_parent: imsg_read error"); 548 if (n == 0) 549 break; 550 551 switch (imsg.hdr.type) { 552 case IMSG_STATS: { 553 struct stats *s; 554 struct ctl_conn *c; 555 556 s = imsg.data; 557 if ((c = control_connbyfd(s->fd)) == NULL) { 558 log_warn("control_dispatch_parent: fd %d not found", s->fd); 559 return; 560 } 561 562 imsg_compose(&c->ibuf, IMSG_PARENT_STATS, 0, 0, -1, 563 &s->u.parent, sizeof(s->u.parent)); 564 565 break; 566 } 567 default: 568 log_warnx("control_dispatch_parent: got imsg %d", 569 imsg.hdr.type); 570 fatalx("control_dispatch_parent: unexpected imsg"); 571 } 572 imsg_free(&imsg); 573 } 574 imsg_event_add(ibuf); 575 } 576 577 void 578 control_dispatch_lka(int sig, short event, void *p) 579 { 580 struct smtpd *env = p; 581 struct imsgbuf *ibuf; 582 struct imsg imsg; 583 ssize_t n; 584 585 ibuf = env->sc_ibufs[PROC_LKA]; 586 switch (event) { 587 case EV_READ: 588 if ((n = imsg_read(ibuf)) == -1) 589 fatal("imsg_read_error"); 590 if (n == 0) { 591 /* this pipe is dead, so remove the event handler */ 592 event_del(&ibuf->ev); 593 event_loopexit(NULL); 594 return; 595 } 596 break; 597 case EV_WRITE: 598 if (msgbuf_write(&ibuf->w) == -1) 599 fatal("msgbuf_write"); 600 imsg_event_add(ibuf); 601 return; 602 default: 603 fatalx("unknown event"); 604 } 605 606 for (;;) { 607 if ((n = imsg_get(ibuf, &imsg)) == -1) 608 fatal("control_dispatch_lka: imsg_read error"); 609 if (n == 0) 610 break; 611 612 switch (imsg.hdr.type) { 613 case IMSG_QUEUE_TEMPFAIL: { 614 struct submit_status *ss; 615 616 log_debug("GOT LFA REPLY"); 617 ss = imsg.data; 618 if (ss->code != 250) 619 log_debug("LKA FAILED WITH TEMPORARY ERROR"); 620 621 break; 622 } 623 default: 624 log_warnx("control_dispatch_lka: got imsg %d", 625 imsg.hdr.type); 626 fatalx("control_dispatch_lka: unexpected imsg"); 627 } 628 imsg_free(&imsg); 629 } 630 imsg_event_add(ibuf); 631 } 632 633 void 634 control_dispatch_mfa(int sig, short event, void *p) 635 { 636 struct smtpd *env = p; 637 struct imsgbuf *ibuf; 638 struct imsg imsg; 639 ssize_t n; 640 641 ibuf = env->sc_ibufs[PROC_MFA]; 642 switch (event) { 643 case EV_READ: 644 if ((n = imsg_read(ibuf)) == -1) 645 fatal("imsg_read_error"); 646 if (n == 0) { 647 /* this pipe is dead, so remove the event handler */ 648 event_del(&ibuf->ev); 649 event_loopexit(NULL); 650 return; 651 } 652 break; 653 case EV_WRITE: 654 if (msgbuf_write(&ibuf->w) == -1) 655 fatal("msgbuf_write"); 656 imsg_event_add(ibuf); 657 return; 658 default: 659 fatalx("unknown event"); 660 } 661 662 for (;;) { 663 if ((n = imsg_get(ibuf, &imsg)) == -1) 664 fatal("control_dispatch_mfa: imsg_read error"); 665 if (n == 0) 666 break; 667 668 switch (imsg.hdr.type) { 669 case IMSG_MFA_RCPT: { 670 struct submit_status *ss; 671 struct ctl_conn *c; 672 673 ss = imsg.data; 674 if ((c = control_connbyfd(ss->id)) == NULL) { 675 log_warn("control_dispatch_queue: fd %lld: not found", ss->id); 676 return; 677 } 678 679 event_add(&c->ibuf.ev, NULL); 680 if (ss->code == 250) { 681 c->state = CS_RCPT; 682 break; 683 } 684 685 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 686 687 break; 688 } 689 default: 690 log_warnx("control_dispatch_mfa: got imsg %d", 691 imsg.hdr.type); 692 fatalx("control_dispatch_mfa: unexpected imsg"); 693 } 694 imsg_free(&imsg); 695 } 696 imsg_event_add(ibuf); 697 } 698 699 void 700 control_dispatch_queue(int sig, short event, void *p) 701 { 702 struct smtpd *env = p; 703 struct imsgbuf *ibuf; 704 struct imsg imsg; 705 ssize_t n; 706 707 ibuf = env->sc_ibufs[PROC_QUEUE]; 708 switch (event) { 709 case EV_READ: 710 if ((n = imsg_read(ibuf)) == -1) 711 fatal("imsg_read_error"); 712 if (n == 0) { 713 /* this pipe is dead, so remove the event handler */ 714 event_del(&ibuf->ev); 715 event_loopexit(NULL); 716 return; 717 } 718 break; 719 case EV_WRITE: 720 if (msgbuf_write(&ibuf->w) == -1) 721 fatal("msgbuf_write"); 722 imsg_event_add(ibuf); 723 return; 724 default: 725 fatalx("unknown event"); 726 } 727 728 for (;;) { 729 if ((n = imsg_get(ibuf, &imsg)) == -1) 730 fatal("control_dispatch_queue: imsg_read error"); 731 if (n == 0) 732 break; 733 734 switch (imsg.hdr.type) { 735 case IMSG_QUEUE_CREATE_MESSAGE: { 736 struct submit_status *ss; 737 struct ctl_conn *c; 738 739 ss = imsg.data; 740 if ((c = control_connbyfd(ss->id)) == NULL) { 741 log_warn("control_dispatch_queue: fd %lld: not found", ss->id); 742 return; 743 } 744 event_add(&c->ibuf.ev, NULL); 745 746 if (ss->code != 250) { 747 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 748 NULL, 0); 749 } 750 else { 751 c->state = CS_INIT; 752 ss->msg.session_id = ss->id; 753 strlcpy(ss->msg.message_id, ss->u.msgid, 754 sizeof(ss->msg.message_id)); 755 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, 756 &ss->msg, sizeof(struct message)); 757 } 758 759 break; 760 } 761 case IMSG_QUEUE_COMMIT_ENVELOPES: { 762 struct submit_status *ss; 763 struct ctl_conn *c; 764 765 ss = imsg.data; 766 if ((c = control_connbyfd(ss->id)) == NULL) { 767 log_warn("control_dispatch_queue: fd %lld: not found", ss->id); 768 return; 769 } 770 event_add(&c->ibuf.ev, NULL); 771 c->state = CS_RCPT; 772 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, 773 NULL, 0); 774 775 break; 776 } 777 case IMSG_QUEUE_MESSAGE_FILE: { 778 struct submit_status *ss; 779 struct ctl_conn *c; 780 int fd; 781 782 ss = imsg.data; 783 if ((c = control_connbyfd(ss->id)) == NULL) { 784 log_warn("control_dispatch_queue: fd %lld: not found", 785 ss->id); 786 return; 787 } 788 event_add(&c->ibuf.ev, NULL); 789 790 fd = imsg_get_fd(ibuf, &imsg); 791 if (ss->code == 250) { 792 c->state = CS_FD; 793 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, fd, 794 &ss->msg, sizeof(struct message)); 795 } 796 else 797 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 798 &ss->msg, sizeof(struct message)); 799 break; 800 } 801 case IMSG_QUEUE_COMMIT_MESSAGE: { 802 struct submit_status *ss; 803 struct ctl_conn *c; 804 805 ss = imsg.data; 806 if ((c = control_connbyfd(ss->id)) == NULL) { 807 log_warn("control_dispatch_queue: fd %lld: not found", 808 ss->id); 809 return; 810 } 811 event_add(&c->ibuf.ev, NULL); 812 813 if (ss->code == 250) { 814 c->state = CS_DONE; 815 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, 816 &ss->msg, sizeof(struct message)); 817 } 818 else 819 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, 820 &ss->msg, sizeof(struct message)); 821 break; 822 } 823 case IMSG_STATS: { 824 struct stats *s; 825 struct ctl_conn *c; 826 827 s = imsg.data; 828 if ((c = control_connbyfd(s->fd)) == NULL) { 829 log_warn("control_dispatch_queue: fd %d not found", s->fd); 830 return; 831 } 832 833 imsg_compose(&c->ibuf, IMSG_QUEUE_STATS, 0, 0, -1, 834 &s->u.queue, sizeof(s->u.queue)); 835 836 break; 837 } 838 default: 839 log_warnx("control_dispatch_queue: got imsg %d", 840 imsg.hdr.type); 841 fatalx("control_dispatch_queue: unexpected imsg"); 842 } 843 imsg_free(&imsg); 844 } 845 imsg_event_add(ibuf); 846 } 847 848 void 849 control_dispatch_runner(int sig, short event, void *p) 850 { 851 struct smtpd *env = p; 852 struct imsgbuf *ibuf; 853 struct imsg imsg; 854 ssize_t n; 855 856 ibuf = env->sc_ibufs[PROC_RUNNER]; 857 switch (event) { 858 case EV_READ: 859 if ((n = imsg_read(ibuf)) == -1) 860 fatal("imsg_read_error"); 861 if (n == 0) { 862 /* this pipe is dead, so remove the event handler */ 863 event_del(&ibuf->ev); 864 event_loopexit(NULL); 865 return; 866 } 867 break; 868 case EV_WRITE: 869 if (msgbuf_write(&ibuf->w) == -1) 870 fatal("msgbuf_write"); 871 imsg_event_add(ibuf); 872 return; 873 default: 874 fatalx("unknown event"); 875 } 876 877 for (;;) { 878 if ((n = imsg_get(ibuf, &imsg)) == -1) 879 fatal("control_dispatch_runner: imsg_read error"); 880 if (n == 0) 881 break; 882 883 switch (imsg.hdr.type) { 884 case IMSG_STATS: { 885 struct stats *s; 886 struct ctl_conn *c; 887 888 s = imsg.data; 889 if ((c = control_connbyfd(s->fd)) == NULL) { 890 log_warn("control_dispatch_runner: fd %d not found", s->fd); 891 return; 892 } 893 894 imsg_compose(&c->ibuf, IMSG_RUNNER_STATS, 0, 0, -1, 895 &s->u.runner, sizeof(s->u.runner)); 896 897 break; 898 } 899 case IMSG_RUNNER_SCHEDULE: { 900 struct sched *s; 901 struct ctl_conn *c; 902 903 s = imsg.data; 904 if ((c = control_connbyfd(s->fd)) == NULL) { 905 log_warn("control_dispatch_runner: fd %d not found", s->fd); 906 return; 907 } 908 909 if (s->ret) 910 imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 911 else 912 imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 913 break; 914 } 915 default: 916 log_warnx("control_dispatch_runner: got imsg %d", 917 imsg.hdr.type); 918 fatalx("control_dispatch_runner: unexpected imsg"); 919 } 920 imsg_free(&imsg); 921 } 922 imsg_event_add(ibuf); 923 } 924 925 void 926 control_dispatch_smtp(int sig, short event, void *p) 927 { 928 struct smtpd *env = p; 929 struct imsgbuf *ibuf; 930 struct imsg imsg; 931 ssize_t n; 932 933 ibuf = env->sc_ibufs[PROC_SMTP]; 934 switch (event) { 935 case EV_READ: 936 if ((n = imsg_read(ibuf)) == -1) 937 fatal("imsg_read_error"); 938 if (n == 0) { 939 /* this pipe is dead, so remove the event handler */ 940 event_del(&ibuf->ev); 941 event_loopexit(NULL); 942 return; 943 } 944 break; 945 case EV_WRITE: 946 if (msgbuf_write(&ibuf->w) == -1) 947 fatal("msgbuf_write"); 948 imsg_event_add(ibuf); 949 return; 950 default: 951 fatalx("unknown event"); 952 } 953 954 for (;;) { 955 if ((n = imsg_get(ibuf, &imsg)) == -1) 956 fatal("control_dispatch_smtp: imsg_read error"); 957 if (n == 0) 958 break; 959 960 switch (imsg.hdr.type) { 961 case IMSG_STATS: { 962 struct stats *s; 963 struct ctl_conn *c; 964 965 s = imsg.data; 966 if ((c = control_connbyfd(s->fd)) == NULL) { 967 log_warn("control_dispatch_queue: fd %d not found", s->fd); 968 return; 969 } 970 971 imsg_compose(&c->ibuf, IMSG_SMTP_STATS, 0, 0, -1, 972 &s->u.smtp, sizeof(s->u.smtp)); 973 974 break; 975 } 976 default: 977 log_warnx("control_dispatch_smtp: got imsg %d", 978 imsg.hdr.type); 979 fatalx("control_dispatch_smtp: unexpected imsg"); 980 } 981 imsg_free(&imsg); 982 } 983 imsg_event_add(ibuf); 984 } 985 986 void 987 session_socket_blockmode(int fd, enum blockmodes bm) 988 { 989 int flags; 990 991 if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 992 fatal("fcntl F_GETFL"); 993 994 if (bm == BM_NONBLOCK) 995 flags |= O_NONBLOCK; 996 else 997 flags &= ~O_NONBLOCK; 998 999 if ((flags = fcntl(fd, F_SETFL, flags)) == -1) 1000 fatal("fcntl F_SETFL"); 1001 } 1002