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