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