1 /* $OpenBSD: control.c,v 1.109 2015/12/28 22:08:30 jung Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> 5 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 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/stat.h> 25 #include <sys/socket.h> 26 #include <sys/un.h> 27 28 #include <err.h> 29 #include <errno.h> 30 #include <event.h> 31 #include <fcntl.h> 32 #include <imsg.h> 33 #include <pwd.h> 34 #include <signal.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <time.h> 39 #include <unistd.h> 40 #include <limits.h> 41 42 #include "smtpd.h" 43 #include "log.h" 44 45 #define CONTROL_BACKLOG 5 46 47 struct ctl_conn { 48 uint32_t id; 49 uint8_t flags; 50 #define CTL_CONN_NOTIFY 0x01 51 struct mproc mproc; 52 uid_t euid; 53 gid_t egid; 54 }; 55 56 struct { 57 struct event ev; 58 int fd; 59 } control_state; 60 61 static void control_imsg(struct mproc *, struct imsg *); 62 static void control_shutdown(void); 63 static void control_listen(void); 64 static void control_accept(int, short, void *); 65 static void control_close(struct ctl_conn *); 66 static void control_sig_handler(int, short, void *); 67 static void control_dispatch_ext(struct mproc *, struct imsg *); 68 static void control_digest_update(const char *, size_t, int); 69 static void control_broadcast_verbose(int, int); 70 71 static struct stat_backend *stat_backend = NULL; 72 extern const char *backend_stat; 73 74 static uint64_t connid = 0; 75 static struct tree ctl_conns; 76 static struct tree ctl_count; 77 static struct stat_digest digest; 78 79 #define CONTROL_FD_RESERVE 5 80 #define CONTROL_MAXCONN_PER_CLIENT 32 81 82 static void 83 control_imsg(struct mproc *p, struct imsg *imsg) 84 { 85 struct ctl_conn *c; 86 struct stat_value val; 87 struct msg m; 88 const char *key; 89 const void *data; 90 size_t sz; 91 92 if (p->proc == PROC_PONY) { 93 switch (imsg->hdr.type) { 94 case IMSG_CTL_SMTP_SESSION: 95 c = tree_get(&ctl_conns, imsg->hdr.peerid); 96 if (c == NULL) 97 return; 98 m_compose(&c->mproc, IMSG_CTL_OK, 0, 0, imsg->fd, 99 NULL, 0); 100 return; 101 } 102 } 103 if (p->proc == PROC_SCHEDULER) { 104 switch (imsg->hdr.type) { 105 case IMSG_CTL_OK: 106 case IMSG_CTL_FAIL: 107 case IMSG_CTL_LIST_MESSAGES: 108 c = tree_get(&ctl_conns, imsg->hdr.peerid); 109 if (c == NULL) 110 return; 111 imsg->hdr.peerid = 0; 112 m_forward(&c->mproc, imsg); 113 return; 114 } 115 } 116 if (p->proc == PROC_QUEUE) { 117 switch (imsg->hdr.type) { 118 case IMSG_CTL_LIST_ENVELOPES: 119 case IMSG_CTL_DISCOVER_EVPID: 120 case IMSG_CTL_DISCOVER_MSGID: 121 case IMSG_CTL_UNCORRUPT_MSGID: 122 c = tree_get(&ctl_conns, imsg->hdr.peerid); 123 if (c == NULL) 124 return; 125 m_forward(&c->mproc, imsg); 126 return; 127 } 128 } 129 if (p->proc == PROC_PONY) { 130 switch (imsg->hdr.type) { 131 case IMSG_CTL_OK: 132 case IMSG_CTL_FAIL: 133 case IMSG_CTL_MTA_SHOW_HOSTS: 134 case IMSG_CTL_MTA_SHOW_RELAYS: 135 case IMSG_CTL_MTA_SHOW_ROUTES: 136 case IMSG_CTL_MTA_SHOW_HOSTSTATS: 137 case IMSG_CTL_MTA_SHOW_BLOCK: 138 c = tree_get(&ctl_conns, imsg->hdr.peerid); 139 if (c == NULL) 140 return; 141 imsg->hdr.peerid = 0; 142 m_forward(&c->mproc, imsg); 143 return; 144 } 145 } 146 147 switch (imsg->hdr.type) { 148 case IMSG_STAT_INCREMENT: 149 m_msg(&m, imsg); 150 m_get_string(&m, &key); 151 m_get_data(&m, &data, &sz); 152 m_end(&m); 153 memmove(&val, data, sz); 154 if (stat_backend) 155 stat_backend->increment(key, val.u.counter); 156 control_digest_update(key, val.u.counter, 1); 157 return; 158 case IMSG_STAT_DECREMENT: 159 m_msg(&m, imsg); 160 m_get_string(&m, &key); 161 m_get_data(&m, &data, &sz); 162 m_end(&m); 163 memmove(&val, data, sz); 164 if (stat_backend) 165 stat_backend->decrement(key, val.u.counter); 166 control_digest_update(key, val.u.counter, 0); 167 return; 168 case IMSG_STAT_SET: 169 m_msg(&m, imsg); 170 m_get_string(&m, &key); 171 m_get_data(&m, &data, &sz); 172 m_end(&m); 173 memmove(&val, data, sz); 174 if (stat_backend) 175 stat_backend->set(key, &val); 176 return; 177 } 178 179 errx(1, "control_imsg: unexpected %s imsg", 180 imsg_to_str(imsg->hdr.type)); 181 } 182 183 static void 184 control_sig_handler(int sig, short event, void *p) 185 { 186 switch (sig) { 187 case SIGINT: 188 case SIGTERM: 189 control_shutdown(); 190 break; 191 default: 192 fatalx("control_sig_handler: unexpected signal"); 193 } 194 } 195 196 int 197 control_create_socket(void) 198 { 199 struct sockaddr_un sun; 200 int fd; 201 mode_t old_umask; 202 203 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 204 fatal("control: socket"); 205 206 memset(&sun, 0, sizeof(sun)); 207 sun.sun_family = AF_UNIX; 208 if (strlcpy(sun.sun_path, SMTPD_SOCKET, 209 sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) 210 fatal("control: socket name too long"); 211 212 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0) 213 fatalx("control socket already listening"); 214 215 if (unlink(SMTPD_SOCKET) == -1) 216 if (errno != ENOENT) 217 fatal("control: cannot unlink socket"); 218 219 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 220 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 221 (void)umask(old_umask); 222 fatal("control: bind"); 223 } 224 (void)umask(old_umask); 225 226 if (chmod(SMTPD_SOCKET, 227 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) { 228 (void)unlink(SMTPD_SOCKET); 229 fatal("control: chmod"); 230 } 231 232 session_socket_blockmode(fd, BM_NONBLOCK); 233 control_state.fd = fd; 234 235 return fd; 236 } 237 238 pid_t 239 control(void) 240 { 241 pid_t pid; 242 struct passwd *pw; 243 struct event ev_sigint; 244 struct event ev_sigterm; 245 246 switch (pid = fork()) { 247 case -1: 248 fatal("control: cannot fork"); 249 case 0: 250 post_fork(PROC_CONTROL); 251 break; 252 default: 253 return (pid); 254 } 255 256 purge_config(PURGE_EVERYTHING); 257 258 if ((pw = getpwnam(SMTPD_USER)) == NULL) 259 fatalx("unknown user " SMTPD_USER); 260 261 stat_backend = env->sc_stat; 262 stat_backend->init(); 263 264 if (chroot(PATH_CHROOT) == -1) 265 fatal("control: chroot"); 266 if (chdir("/") == -1) 267 fatal("control: chdir(\"/\")"); 268 269 config_process(PROC_CONTROL); 270 271 if (setgroups(1, &pw->pw_gid) || 272 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 273 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 274 fatal("control: cannot drop privileges"); 275 276 imsg_callback = control_imsg; 277 event_init(); 278 279 signal_set(&ev_sigint, SIGINT, control_sig_handler, NULL); 280 signal_set(&ev_sigterm, SIGTERM, control_sig_handler, NULL); 281 signal_add(&ev_sigint, NULL); 282 signal_add(&ev_sigterm, NULL); 283 signal(SIGPIPE, SIG_IGN); 284 signal(SIGHUP, SIG_IGN); 285 286 tree_init(&ctl_conns); 287 tree_init(&ctl_count); 288 289 memset(&digest, 0, sizeof digest); 290 digest.startup = time(NULL); 291 292 config_peer(PROC_SCHEDULER); 293 config_peer(PROC_QUEUE); 294 config_peer(PROC_PARENT); 295 config_peer(PROC_LKA); 296 config_peer(PROC_PONY); 297 config_peer(PROC_CA); 298 config_done(); 299 300 control_listen(); 301 302 if (pledge("stdio unix recvfd sendfd", NULL) == -1) 303 err(1, "pledge"); 304 305 if (event_dispatch() < 0) 306 fatal("event_dispatch"); 307 control_shutdown(); 308 309 return (0); 310 } 311 312 static void 313 control_shutdown(void) 314 { 315 log_info("info: control process exiting"); 316 _exit(0); 317 } 318 319 static void 320 control_listen(void) 321 { 322 if (listen(control_state.fd, CONTROL_BACKLOG) == -1) 323 fatal("control_listen"); 324 325 event_set(&control_state.ev, control_state.fd, EV_READ|EV_PERSIST, 326 control_accept, NULL); 327 event_add(&control_state.ev, NULL); 328 } 329 330 /* ARGSUSED */ 331 static void 332 control_accept(int listenfd, short event, void *arg) 333 { 334 int connfd; 335 socklen_t len; 336 struct sockaddr_un sun; 337 struct ctl_conn *c; 338 size_t *count; 339 uid_t euid; 340 gid_t egid; 341 342 if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE) 343 goto pause; 344 345 len = sizeof(sun); 346 if ((connfd = accept(listenfd, (struct sockaddr *)&sun, &len)) == -1) { 347 if (errno == ENFILE || errno == EMFILE) 348 goto pause; 349 if (errno == EINTR || errno == EWOULDBLOCK || 350 errno == ECONNABORTED) 351 return; 352 fatal("control_accept: accept"); 353 } 354 355 session_socket_blockmode(connfd, BM_NONBLOCK); 356 357 if (getpeereid(connfd, &euid, &egid) == -1) 358 fatal("getpeereid"); 359 360 count = tree_get(&ctl_count, euid); 361 if (count == NULL) { 362 count = xcalloc(1, sizeof *count, "control_accept"); 363 tree_xset(&ctl_count, euid, count); 364 } 365 366 if (*count == CONTROL_MAXCONN_PER_CLIENT) { 367 close(connfd); 368 log_warnx("warn: too many connections to control socket " 369 "from user with uid %lu", (unsigned long int)euid); 370 return; 371 } 372 (*count)++; 373 374 do { 375 ++connid; 376 } while (tree_get(&ctl_conns, connid)); 377 378 c = xcalloc(1, sizeof(*c), "control_accept"); 379 c->euid = euid; 380 c->egid = egid; 381 c->id = connid; 382 c->mproc.proc = PROC_CLIENT; 383 c->mproc.handler = control_dispatch_ext; 384 c->mproc.data = c; 385 mproc_init(&c->mproc, connfd); 386 mproc_enable(&c->mproc); 387 tree_xset(&ctl_conns, c->id, c); 388 389 stat_backend->increment("control.session", 1); 390 return; 391 392 pause: 393 log_warnx("warn: ctl client limit hit, disabling new connections"); 394 event_del(&control_state.ev); 395 } 396 397 static void 398 control_close(struct ctl_conn *c) 399 { 400 size_t *count; 401 402 count = tree_xget(&ctl_count, c->euid); 403 (*count)--; 404 if (*count == 0) { 405 tree_xpop(&ctl_count, c->euid); 406 free(count); 407 } 408 tree_xpop(&ctl_conns, c->id); 409 mproc_clear(&c->mproc); 410 free(c); 411 412 stat_backend->decrement("control.session", 1); 413 414 if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE) 415 return; 416 417 if (!event_pending(&control_state.ev, EV_READ, NULL)) { 418 log_warnx("warn: re-enabling ctl connections"); 419 event_add(&control_state.ev, NULL); 420 } 421 } 422 423 static void 424 control_digest_update(const char *key, size_t value, int incr) 425 { 426 size_t *p; 427 428 p = NULL; 429 430 if (!strcmp(key, "smtp.session")) { 431 if (incr) 432 p = &digest.clt_connect; 433 else 434 digest.clt_disconnect += value; 435 } 436 else if (!strcmp(key, "scheduler.envelope")) { 437 if (incr) 438 p = &digest.evp_enqueued; 439 else 440 digest.evp_dequeued += value; 441 } 442 else if (!strcmp(key, "scheduler.envelope.expired")) 443 p = &digest.evp_expired; 444 else if (!strcmp(key, "scheduler.envelope.removed")) 445 p = &digest.evp_removed; 446 else if (!strcmp(key, "scheduler.delivery.ok")) 447 p = &digest.dlv_ok; 448 else if (!strcmp(key, "scheduler.delivery.permfail")) 449 p = &digest.dlv_permfail; 450 else if (!strcmp(key, "scheduler.delivery.tempfail")) 451 p = &digest.dlv_tempfail; 452 else if (!strcmp(key, "scheduler.delivery.loop")) 453 p = &digest.dlv_loop; 454 455 else if (!strcmp(key, "queue.bounce")) 456 p = &digest.evp_bounce; 457 458 if (p) { 459 if (incr) 460 *p = *p + value; 461 else 462 *p = *p - value; 463 } 464 } 465 466 /* ARGSUSED */ 467 static void 468 control_dispatch_ext(struct mproc *p, struct imsg *imsg) 469 { 470 struct sockaddr_storage ss; 471 struct ctl_conn *c; 472 int v; 473 struct stat_kv *kvp; 474 char *key; 475 struct stat_value val; 476 size_t len; 477 uint64_t evpid; 478 uint32_t msgid; 479 480 c = p->data; 481 482 if (imsg == NULL) { 483 control_close(c); 484 return; 485 } 486 487 if (imsg->hdr.peerid != IMSG_VERSION) { 488 m_compose(p, IMSG_CTL_FAIL, IMSG_VERSION, 0, -1, NULL, 0); 489 return; 490 } 491 492 switch (imsg->hdr.type) { 493 case IMSG_CTL_SMTP_SESSION: 494 if (env->sc_flags & (SMTPD_SMTP_PAUSED | SMTPD_EXITING)) { 495 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 496 return; 497 } 498 m_compose(p_pony, IMSG_CTL_SMTP_SESSION, c->id, 0, -1, 499 &c->euid, sizeof(c->euid)); 500 return; 501 502 case IMSG_CTL_GET_DIGEST: 503 if (c->euid) 504 goto badcred; 505 digest.timestamp = time(NULL); 506 m_compose(p, IMSG_CTL_GET_DIGEST, 0, 0, -1, &digest, sizeof digest); 507 return; 508 509 case IMSG_CTL_GET_STATS: 510 if (c->euid) 511 goto badcred; 512 kvp = imsg->data; 513 if (!stat_backend->iter(&kvp->iter, &key, &val)) 514 kvp->iter = NULL; 515 else { 516 (void)strlcpy(kvp->key, key, sizeof kvp->key); 517 kvp->val = val; 518 } 519 m_compose(p, IMSG_CTL_GET_STATS, 0, 0, -1, kvp, sizeof *kvp); 520 return; 521 522 case IMSG_CTL_SHUTDOWN: 523 /* NEEDS_FIX */ 524 log_debug("debug: received shutdown request"); 525 526 if (c->euid) 527 goto badcred; 528 529 if (env->sc_flags & SMTPD_EXITING) { 530 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 531 return; 532 } 533 env->sc_flags |= SMTPD_EXITING; 534 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 535 m_compose(p_parent, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0); 536 return; 537 538 case IMSG_CTL_VERBOSE: 539 if (c->euid) 540 goto badcred; 541 542 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose)) 543 goto badcred; 544 545 memcpy(&v, imsg->data, sizeof(v)); 546 verbose = v; 547 log_verbose(verbose); 548 549 control_broadcast_verbose(IMSG_CTL_VERBOSE, verbose); 550 551 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 552 return; 553 554 case IMSG_CTL_TRACE_ENABLE: 555 if (c->euid) 556 goto badcred; 557 558 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose)) 559 goto badcred; 560 561 memcpy(&v, imsg->data, sizeof(v)); 562 verbose |= v; 563 log_verbose(verbose); 564 565 control_broadcast_verbose(IMSG_CTL_VERBOSE, verbose); 566 567 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 568 return; 569 570 case IMSG_CTL_TRACE_DISABLE: 571 if (c->euid) 572 goto badcred; 573 574 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose)) 575 goto badcred; 576 577 memcpy(&v, imsg->data, sizeof(v)); 578 verbose &= ~v; 579 log_verbose(verbose); 580 581 control_broadcast_verbose(IMSG_CTL_VERBOSE, verbose); 582 583 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 584 return; 585 586 case IMSG_CTL_PROFILE_ENABLE: 587 if (c->euid) 588 goto badcred; 589 590 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose)) 591 goto badcred; 592 593 memcpy(&v, imsg->data, sizeof(v)); 594 profiling |= v; 595 596 control_broadcast_verbose(IMSG_CTL_PROFILE, profiling); 597 598 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 599 return; 600 601 case IMSG_CTL_PROFILE_DISABLE: 602 if (c->euid) 603 goto badcred; 604 605 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(verbose)) 606 goto badcred; 607 608 memcpy(&v, imsg->data, sizeof(v)); 609 profiling &= ~v; 610 611 control_broadcast_verbose(IMSG_CTL_PROFILE, profiling); 612 613 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 614 return; 615 616 case IMSG_CTL_PAUSE_EVP: 617 if (c->euid) 618 goto badcred; 619 620 imsg->hdr.peerid = c->id; 621 m_forward(p_scheduler, imsg); 622 return; 623 624 case IMSG_CTL_PAUSE_MDA: 625 if (c->euid) 626 goto badcred; 627 628 if (env->sc_flags & SMTPD_MDA_PAUSED) { 629 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 630 return; 631 } 632 log_info("info: mda paused"); 633 env->sc_flags |= SMTPD_MDA_PAUSED; 634 m_compose(p_queue, IMSG_CTL_PAUSE_MDA, 0, 0, -1, NULL, 0); 635 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 636 return; 637 638 case IMSG_CTL_PAUSE_MTA: 639 if (c->euid) 640 goto badcred; 641 642 if (env->sc_flags & SMTPD_MTA_PAUSED) { 643 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 644 return; 645 } 646 log_info("info: mta paused"); 647 env->sc_flags |= SMTPD_MTA_PAUSED; 648 m_compose(p_queue, IMSG_CTL_PAUSE_MTA, 0, 0, -1, NULL, 0); 649 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 650 return; 651 652 case IMSG_CTL_PAUSE_SMTP: 653 if (c->euid) 654 goto badcred; 655 656 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 657 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 658 return; 659 } 660 log_info("info: smtp paused"); 661 env->sc_flags |= SMTPD_SMTP_PAUSED; 662 m_compose(p_pony, IMSG_CTL_PAUSE_SMTP, 0, 0, -1, NULL, 0); 663 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 664 return; 665 666 case IMSG_CTL_RESUME_EVP: 667 if (c->euid) 668 goto badcred; 669 670 imsg->hdr.peerid = c->id; 671 m_forward(p_scheduler, imsg); 672 return; 673 674 case IMSG_CTL_RESUME_MDA: 675 if (c->euid) 676 goto badcred; 677 678 if (!(env->sc_flags & SMTPD_MDA_PAUSED)) { 679 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 680 return; 681 } 682 log_info("info: mda resumed"); 683 env->sc_flags &= ~SMTPD_MDA_PAUSED; 684 m_compose(p_queue, IMSG_CTL_RESUME_MDA, 0, 0, -1, NULL, 0); 685 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 686 return; 687 688 case IMSG_CTL_RESUME_MTA: 689 if (c->euid) 690 goto badcred; 691 692 if (!(env->sc_flags & SMTPD_MTA_PAUSED)) { 693 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 694 return; 695 } 696 log_info("info: mta resumed"); 697 env->sc_flags &= ~SMTPD_MTA_PAUSED; 698 m_compose(p_queue, IMSG_CTL_RESUME_MTA, 0, 0, -1, NULL, 0); 699 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 700 return; 701 702 case IMSG_CTL_RESUME_SMTP: 703 if (c->euid) 704 goto badcred; 705 706 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) { 707 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 708 return; 709 } 710 log_info("info: smtp resumed"); 711 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 712 m_forward(p_pony, imsg); 713 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 714 return; 715 716 case IMSG_CTL_RESUME_ROUTE: 717 if (c->euid) 718 goto badcred; 719 720 m_forward(p_pony, imsg); 721 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 722 return; 723 724 case IMSG_CTL_LIST_MESSAGES: 725 if (c->euid) 726 goto badcred; 727 m_compose(p_scheduler, IMSG_CTL_LIST_MESSAGES, c->id, 0, -1, 728 imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); 729 return; 730 731 case IMSG_CTL_LIST_ENVELOPES: 732 if (c->euid) 733 goto badcred; 734 m_compose(p_scheduler, IMSG_CTL_LIST_ENVELOPES, c->id, 0, -1, 735 imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); 736 return; 737 738 case IMSG_CTL_MTA_SHOW_HOSTS: 739 case IMSG_CTL_MTA_SHOW_RELAYS: 740 case IMSG_CTL_MTA_SHOW_ROUTES: 741 case IMSG_CTL_MTA_SHOW_HOSTSTATS: 742 case IMSG_CTL_MTA_SHOW_BLOCK: 743 if (c->euid) 744 goto badcred; 745 746 imsg->hdr.peerid = c->id; 747 m_forward(p_pony, imsg); 748 return; 749 750 case IMSG_CTL_SHOW_STATUS: 751 if (c->euid) 752 goto badcred; 753 754 m_compose(p, IMSG_CTL_SHOW_STATUS, 0, 0, -1, &env->sc_flags, 755 sizeof(env->sc_flags)); 756 return; 757 758 case IMSG_CTL_MTA_BLOCK: 759 case IMSG_CTL_MTA_UNBLOCK: 760 if (c->euid) 761 goto badcred; 762 763 if (imsg->hdr.len - IMSG_HEADER_SIZE <= sizeof(ss)) 764 goto invalid; 765 memmove(&ss, imsg->data, sizeof(ss)); 766 m_create(p_pony, imsg->hdr.type, c->id, 0, -1); 767 m_add_sockaddr(p_pony, (struct sockaddr *)&ss); 768 m_add_string(p_pony, (char *)imsg->data + sizeof(ss)); 769 m_close(p_pony); 770 return; 771 772 case IMSG_CTL_SCHEDULE: 773 if (c->euid) 774 goto badcred; 775 776 imsg->hdr.peerid = c->id; 777 m_forward(p_scheduler, imsg); 778 return; 779 780 case IMSG_CTL_REMOVE: 781 if (c->euid) 782 goto badcred; 783 784 imsg->hdr.peerid = c->id; 785 m_forward(p_scheduler, imsg); 786 return; 787 788 case IMSG_CTL_UPDATE_TABLE: 789 if (c->euid) 790 goto badcred; 791 792 /* table name too long */ 793 len = strlen(imsg->data); 794 if (len >= LINE_MAX) 795 goto invalid; 796 797 m_forward(p_lka, imsg); 798 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 799 return; 800 801 case IMSG_CTL_DISCOVER_EVPID: 802 if (c->euid) 803 goto badcred; 804 805 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof evpid) 806 goto invalid; 807 808 memmove(&evpid, imsg->data, sizeof evpid); 809 m_create(p_queue, imsg->hdr.type, c->id, 0, -1); 810 m_add_evpid(p_queue, evpid); 811 m_close(p_queue); 812 return; 813 814 case IMSG_CTL_DISCOVER_MSGID: 815 case IMSG_CTL_UNCORRUPT_MSGID: 816 if (c->euid) 817 goto badcred; 818 819 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof msgid) 820 goto invalid; 821 822 memmove(&msgid, imsg->data, sizeof msgid); 823 m_create(p_queue, imsg->hdr.type, c->id, 0, -1); 824 m_add_msgid(p_queue, msgid); 825 m_close(p_queue); 826 return; 827 828 default: 829 log_debug("debug: control_dispatch_ext: " 830 "error handling %s imsg", 831 imsg_to_str(imsg->hdr.type)); 832 return; 833 } 834 badcred: 835 invalid: 836 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 837 } 838 839 static void 840 control_broadcast_verbose(int msg, int v) 841 { 842 m_create(p_lka, msg, 0, 0, -1); 843 m_add_int(p_lka, v); 844 m_close(p_lka); 845 846 m_create(p_pony, msg, 0, 0, -1); 847 m_add_int(p_pony, v); 848 m_close(p_pony); 849 850 m_create(p_queue, msg, 0, 0, -1); 851 m_add_int(p_queue, v); 852 m_close(p_queue); 853 854 m_create(p_ca, msg, 0, 0, -1); 855 m_add_int(p_ca, v); 856 m_close(p_ca); 857 858 m_create(p_scheduler, msg, 0, 0, -1); 859 m_add_int(p_scheduler, v); 860 m_close(p_scheduler); 861 862 m_create(p_parent, msg, 0, 0, -1); 863 m_add_int(p_parent, v); 864 m_close(p_parent); 865 } 866