1 /* $OpenBSD: control.c,v 1.38 2009/09/18 00:04:26 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 smtpd_process = PROC_CONTROL; 148 setproctitle("%s", env->sc_title[smtpd_process]); 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, nitems(peers)); 169 config_peers(env, peers, nitems(peers)); 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->iev.ibuf, connfd); 232 c->iev.handler = control_dispatch_ext; 233 c->iev.events = EV_READ; 234 c->iev.data = env; 235 event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 236 c->iev.handler, env); 237 event_add(&c->iev.ev, NULL); 238 239 TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 240 } 241 242 struct ctl_conn * 243 control_connbyfd(int fd) 244 { 245 struct ctl_conn *c; 246 247 for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd; 248 c = TAILQ_NEXT(c, entry)) 249 ; /* nothing */ 250 251 return (c); 252 } 253 254 void 255 control_close(int fd) 256 { 257 struct ctl_conn *c; 258 259 if ((c = control_connbyfd(fd)) == NULL) { 260 log_warn("control_close: fd %d: not found", fd); 261 return; 262 } 263 264 msgbuf_clear(&c->iev.ibuf.w); 265 TAILQ_REMOVE(&ctl_conns, c, entry); 266 267 event_del(&c->iev.ev); 268 close(c->iev.ibuf.fd); 269 free(c); 270 } 271 272 /* ARGSUSED */ 273 void 274 control_dispatch_ext(int fd, short event, void *arg) 275 { 276 struct ctl_conn *c; 277 struct smtpd *env = arg; 278 struct imsg imsg; 279 int n; 280 uid_t euid; 281 gid_t egid; 282 283 if (getpeereid(fd, &euid, &egid) == -1) 284 fatal("getpeereid"); 285 286 if ((c = control_connbyfd(fd)) == NULL) { 287 log_warn("control_dispatch_ext: fd %d: not found", fd); 288 return; 289 } 290 291 if (event & EV_READ) { 292 if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { 293 control_close(fd); 294 return; 295 } 296 } 297 298 if (event & EV_WRITE) { 299 if (msgbuf_write(&c->iev.ibuf.w) < 0) { 300 control_close(fd); 301 return; 302 } 303 } 304 305 for (;;) { 306 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 307 control_close(fd); 308 return; 309 } 310 311 if (n == 0) 312 break; 313 314 switch (imsg.hdr.type) { 315 case IMSG_SMTP_ENQUEUE: 316 if (env->sc_flags & (SMTPD_SMTP_PAUSED | 317 SMTPD_CONFIGURING | SMTPD_EXITING)) { 318 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 319 NULL, 0); 320 break; 321 } 322 imsg_compose_event(env->sc_ievs[PROC_SMTP], 323 IMSG_SMTP_ENQUEUE, fd, 0, -1, &euid, sizeof(euid)); 324 break; 325 case IMSG_STATS: 326 if (euid) 327 goto badcred; 328 imsg_compose_event(&c->iev, IMSG_STATS, 0, 0, -1, 329 env->stats, sizeof(struct stats)); 330 break; 331 case IMSG_RUNNER_SCHEDULE: { 332 struct sched *s = imsg.data; 333 334 if (euid) 335 goto badcred; 336 337 if (IMSG_DATA_SIZE(&imsg) != sizeof(*s)) 338 goto badcred; 339 340 s->fd = fd; 341 342 if (! valid_message_id(s->mid) && ! valid_message_uid(s->mid)) { 343 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 344 NULL, 0); 345 break; 346 } 347 348 imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_RUNNER_SCHEDULE, 0, 0, -1, s, sizeof(*s)); 349 break; 350 } 351 case IMSG_CONF_RELOAD: { 352 struct reload r; 353 354 log_debug("received reload request"); 355 356 if (euid) 357 goto badcred; 358 359 if (env->sc_flags & SMTPD_CONFIGURING) { 360 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 361 NULL, 0); 362 break; 363 } 364 env->sc_flags |= SMTPD_CONFIGURING; 365 366 r.fd = fd; 367 imsg_compose_event(env->sc_ievs[PROC_PARENT], IMSG_CONF_RELOAD, 0, 0, -1, &r, sizeof(r)); 368 break; 369 } 370 case IMSG_CTL_SHUTDOWN: 371 /* NEEDS_FIX */ 372 log_debug("received shutdown request"); 373 374 if (euid) 375 goto badcred; 376 377 if (env->sc_flags & SMTPD_EXITING) { 378 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 379 NULL, 0); 380 break; 381 } 382 env->sc_flags |= SMTPD_EXITING; 383 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 384 break; 385 case IMSG_MDA_PAUSE: 386 if (euid) 387 goto badcred; 388 389 if (env->sc_flags & SMTPD_MDA_PAUSED) { 390 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 391 NULL, 0); 392 break; 393 } 394 env->sc_flags |= SMTPD_MDA_PAUSED; 395 imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MDA_PAUSE, 396 0, 0, -1, NULL, 0); 397 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 398 break; 399 case IMSG_MTA_PAUSE: 400 if (euid) 401 goto badcred; 402 403 if (env->sc_flags & SMTPD_MTA_PAUSED) { 404 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 405 NULL, 0); 406 break; 407 } 408 env->sc_flags |= SMTPD_MTA_PAUSED; 409 imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_PAUSE, 410 0, 0, -1, NULL, 0); 411 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 412 break; 413 case IMSG_SMTP_PAUSE: 414 if (euid) 415 goto badcred; 416 417 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 418 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 419 NULL, 0); 420 break; 421 } 422 env->sc_flags |= SMTPD_SMTP_PAUSED; 423 imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_PAUSE, 424 0, 0, -1, NULL, 0); 425 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 426 break; 427 case IMSG_MDA_RESUME: 428 if (euid) 429 goto badcred; 430 431 if (! (env->sc_flags & SMTPD_MDA_PAUSED)) { 432 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 433 NULL, 0); 434 break; 435 } 436 env->sc_flags &= ~SMTPD_MDA_PAUSED; 437 imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_RESUME, 438 0, 0, -1, NULL, 0); 439 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 440 break; 441 case IMSG_MTA_RESUME: 442 if (euid) 443 goto badcred; 444 445 if (!(env->sc_flags & SMTPD_MTA_PAUSED)) { 446 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 447 NULL, 0); 448 break; 449 } 450 env->sc_flags &= ~SMTPD_MTA_PAUSED; 451 imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_MTA_RESUME, 452 0, 0, -1, NULL, 0); 453 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 454 break; 455 case IMSG_SMTP_RESUME: 456 if (euid) 457 goto badcred; 458 459 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) { 460 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 461 NULL, 0); 462 break; 463 } 464 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 465 imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_RESUME, 466 0, 0, -1, NULL, 0); 467 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 468 break; 469 default: 470 log_debug("control_dispatch_ext: " 471 "error handling imsg %d", imsg.hdr.type); 472 break; 473 } 474 imsg_free(&imsg); 475 continue; 476 477 badcred: 478 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 479 NULL, 0); 480 } 481 482 imsg_event_add(&c->iev); 483 } 484 485 void 486 control_dispatch_parent(int sig, short event, void *p) 487 { 488 struct smtpd *env = p; 489 struct imsgev *iev; 490 struct imsgbuf *ibuf; 491 struct imsg imsg; 492 ssize_t n; 493 494 iev = env->sc_ievs[PROC_PARENT]; 495 ibuf = &iev->ibuf; 496 497 if (event & EV_READ) { 498 if ((n = imsg_read(ibuf)) == -1) 499 fatal("imsg_read_error"); 500 if (n == 0) { 501 /* this pipe is dead, so remove the event handler */ 502 event_del(&iev->ev); 503 event_loopexit(NULL); 504 return; 505 } 506 } 507 508 if (event & EV_WRITE) { 509 if (msgbuf_write(&ibuf->w) == -1) 510 fatal("msgbuf_write"); 511 } 512 513 for (;;) { 514 if ((n = imsg_get(ibuf, &imsg)) == -1) 515 fatal("control_dispatch_parent: imsg_get error"); 516 if (n == 0) 517 break; 518 519 switch (imsg.hdr.type) { 520 case IMSG_CONF_RELOAD: { 521 struct reload *r = imsg.data; 522 struct ctl_conn *c; 523 524 IMSG_SIZE_CHECK(r); 525 526 env->sc_flags &= ~SMTPD_CONFIGURING; 527 if ((c = control_connbyfd(r->fd)) == NULL) { 528 log_warn("control_dispatch_parent: fd %d not found", r->fd); 529 return; 530 } 531 532 if (r->ret) 533 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 534 else 535 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 536 break; 537 } 538 default: 539 log_warnx("control_dispatch_parent: got imsg %d", 540 imsg.hdr.type); 541 fatalx("control_dispatch_parent: unexpected imsg"); 542 } 543 imsg_free(&imsg); 544 } 545 imsg_event_add(iev); 546 } 547 548 void 549 control_dispatch_lka(int sig, short event, void *p) 550 { 551 struct smtpd *env = p; 552 struct imsgev *iev; 553 struct imsgbuf *ibuf; 554 struct imsg imsg; 555 ssize_t n; 556 557 iev = env->sc_ievs[PROC_LKA]; 558 ibuf = &iev->ibuf; 559 560 if (event & EV_READ) { 561 if ((n = imsg_read(ibuf)) == -1) 562 fatal("imsg_read_error"); 563 if (n == 0) { 564 /* this pipe is dead, so remove the event handler */ 565 event_del(&iev->ev); 566 event_loopexit(NULL); 567 return; 568 } 569 } 570 571 if (event & EV_WRITE) { 572 if (msgbuf_write(&ibuf->w) == -1) 573 fatal("msgbuf_write"); 574 } 575 576 for (;;) { 577 if ((n = imsg_get(ibuf, &imsg)) == -1) 578 fatal("control_dispatch_lka: imsg_get error"); 579 if (n == 0) 580 break; 581 582 switch (imsg.hdr.type) { 583 default: 584 log_warnx("control_dispatch_lka: got imsg %d", 585 imsg.hdr.type); 586 fatalx("control_dispatch_lka: unexpected imsg"); 587 } 588 imsg_free(&imsg); 589 } 590 imsg_event_add(iev); 591 } 592 593 void 594 control_dispatch_mfa(int sig, short event, void *p) 595 { 596 struct smtpd *env = p; 597 struct imsgev *iev; 598 struct imsgbuf *ibuf; 599 struct imsg imsg; 600 ssize_t n; 601 602 iev = env->sc_ievs[PROC_MFA]; 603 ibuf = &iev->ibuf; 604 605 if (event & EV_READ) { 606 if ((n = imsg_read(ibuf)) == -1) 607 fatal("imsg_read_error"); 608 if (n == 0) { 609 /* this pipe is dead, so remove the event handler */ 610 event_del(&iev->ev); 611 event_loopexit(NULL); 612 return; 613 } 614 } 615 616 if (event & EV_WRITE) { 617 if (msgbuf_write(&ibuf->w) == -1) 618 fatal("msgbuf_write"); 619 } 620 621 for (;;) { 622 if ((n = imsg_get(ibuf, &imsg)) == -1) 623 fatal("control_dispatch_mfa: imsg_get error"); 624 if (n == 0) 625 break; 626 627 switch (imsg.hdr.type) { 628 default: 629 log_warnx("control_dispatch_mfa: got imsg %d", 630 imsg.hdr.type); 631 fatalx("control_dispatch_mfa: unexpected imsg"); 632 } 633 imsg_free(&imsg); 634 } 635 imsg_event_add(iev); 636 } 637 638 void 639 control_dispatch_queue(int sig, short event, void *p) 640 { 641 struct smtpd *env = p; 642 struct imsgev *iev; 643 struct imsgbuf *ibuf; 644 struct imsg imsg; 645 ssize_t n; 646 647 iev = env->sc_ievs[PROC_QUEUE]; 648 ibuf = &iev->ibuf; 649 650 if (event & EV_READ) { 651 if ((n = imsg_read(ibuf)) == -1) 652 fatal("imsg_read_error"); 653 if (n == 0) { 654 /* this pipe is dead, so remove the event handler */ 655 event_del(&iev->ev); 656 event_loopexit(NULL); 657 return; 658 } 659 } 660 661 if (event & EV_WRITE) { 662 if (msgbuf_write(&ibuf->w) == -1) 663 fatal("msgbuf_write"); 664 } 665 666 for (;;) { 667 if ((n = imsg_get(ibuf, &imsg)) == -1) 668 fatal("control_dispatch_queue: imsg_get error"); 669 if (n == 0) 670 break; 671 672 switch (imsg.hdr.type) { 673 default: 674 log_warnx("control_dispatch_queue: got imsg %d", 675 imsg.hdr.type); 676 fatalx("control_dispatch_queue: unexpected imsg"); 677 } 678 imsg_free(&imsg); 679 } 680 imsg_event_add(iev); 681 } 682 683 void 684 control_dispatch_runner(int sig, short event, void *p) 685 { 686 struct smtpd *env = p; 687 struct imsgev *iev; 688 struct imsgbuf *ibuf; 689 struct imsg imsg; 690 ssize_t n; 691 692 iev = env->sc_ievs[PROC_RUNNER]; 693 ibuf = &iev->ibuf; 694 695 if (event & EV_READ) { 696 if ((n = imsg_read(ibuf)) == -1) 697 fatal("imsg_read_error"); 698 if (n == 0) { 699 /* this pipe is dead, so remove the event handler */ 700 event_del(&iev->ev); 701 event_loopexit(NULL); 702 return; 703 } 704 } 705 706 if (event & EV_WRITE) { 707 if (msgbuf_write(&ibuf->w) == -1) 708 fatal("msgbuf_write"); 709 } 710 711 for (;;) { 712 if ((n = imsg_get(ibuf, &imsg)) == -1) 713 fatal("control_dispatch_runner: imsg_get error"); 714 if (n == 0) 715 break; 716 717 switch (imsg.hdr.type) { 718 case IMSG_RUNNER_SCHEDULE: { 719 struct sched *s = imsg.data; 720 struct ctl_conn *c; 721 722 IMSG_SIZE_CHECK(s); 723 724 if ((c = control_connbyfd(s->fd)) == NULL) { 725 log_warn("control_dispatch_runner: fd %d not found", s->fd); 726 imsg_free(&imsg); 727 return; 728 } 729 730 if (s->ret) 731 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 732 else 733 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 734 break; 735 } 736 default: 737 log_warnx("control_dispatch_runner: got imsg %d", 738 imsg.hdr.type); 739 fatalx("control_dispatch_runner: unexpected imsg"); 740 } 741 imsg_free(&imsg); 742 } 743 imsg_event_add(iev); 744 } 745 746 void 747 control_dispatch_smtp(int sig, short event, void *p) 748 { 749 struct smtpd *env = p; 750 struct imsgev *iev; 751 struct imsgbuf *ibuf; 752 struct imsg imsg; 753 ssize_t n; 754 755 iev = env->sc_ievs[PROC_SMTP]; 756 ibuf = &iev->ibuf; 757 758 if (event & EV_READ) { 759 if ((n = imsg_read(ibuf)) == -1) 760 fatal("imsg_read_error"); 761 if (n == 0) { 762 /* this pipe is dead, so remove the event handler */ 763 event_del(&iev->ev); 764 event_loopexit(NULL); 765 return; 766 } 767 } 768 769 if (event & EV_WRITE) { 770 if (msgbuf_write(&ibuf->w) == -1) 771 fatal("msgbuf_write"); 772 } 773 774 for (;;) { 775 if ((n = imsg_get(ibuf, &imsg)) == -1) 776 fatal("control_dispatch_smtp: imsg_get error"); 777 if (n == 0) 778 break; 779 780 switch (imsg.hdr.type) { 781 case IMSG_SMTP_ENQUEUE: { 782 struct ctl_conn *c; 783 int client_fd; 784 785 client_fd = imsg.hdr.peerid; 786 787 if ((c = control_connbyfd(client_fd)) == NULL) { 788 log_warn("control_dispatch_smtp: fd %d not found", client_fd); 789 imsg_free(&imsg); 790 return; 791 } 792 793 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, 794 imsg.fd, NULL, 0); 795 break; 796 } 797 default: 798 log_warnx("control_dispatch_smtp: got imsg %d", 799 imsg.hdr.type); 800 fatalx("control_dispatch_smtp: unexpected imsg"); 801 } 802 imsg_free(&imsg); 803 } 804 imsg_event_add(iev); 805 } 806 807 void 808 session_socket_blockmode(int fd, enum blockmodes bm) 809 { 810 int flags; 811 812 if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 813 fatal("fcntl F_GETFL"); 814 815 if (bm == BM_NONBLOCK) 816 flags |= O_NONBLOCK; 817 else 818 flags &= ~O_NONBLOCK; 819 820 if ((flags = fcntl(fd, F_SETFL, flags)) == -1) 821 fatal("fcntl F_SETFL"); 822 } 823 824 void 825 session_socket_no_linger(int fd) 826 { 827 struct linger lng; 828 829 bzero(&lng, sizeof(lng)); 830 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1) 831 fatal("session_socket_no_linger"); 832 } 833 834 int 835 session_socket_error(int fd) 836 { 837 int err, len; 838 839 len = sizeof(err); 840 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == -1) 841 fatal("session_socket_error: getsockopt"); 842 843 return (err); 844 } 845