1 /* $OpenBSD: control.c,v 1.118 2017/01/09 09:53:23 reyk 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(v)) 508 goto badcred; 509 510 memcpy(&v, imsg->data, sizeof(v)); 511 log_trace_verbose(v); 512 513 control_broadcast_verbose(IMSG_CTL_VERBOSE, v); 514 515 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 516 return; 517 518 case IMSG_CTL_TRACE_ENABLE: 519 if (c->euid) 520 goto badcred; 521 522 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 523 goto badcred; 524 525 memcpy(&v, imsg->data, sizeof(v)); 526 tracing |= v; 527 log_trace_verbose(tracing); 528 529 control_broadcast_verbose(IMSG_CTL_VERBOSE, tracing); 530 531 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 532 return; 533 534 case IMSG_CTL_TRACE_DISABLE: 535 if (c->euid) 536 goto badcred; 537 538 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 539 goto badcred; 540 541 memcpy(&v, imsg->data, sizeof(v)); 542 tracing &= ~v; 543 log_trace_verbose(tracing); 544 545 control_broadcast_verbose(IMSG_CTL_VERBOSE, tracing); 546 547 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 548 return; 549 550 case IMSG_CTL_PROFILE_ENABLE: 551 if (c->euid) 552 goto badcred; 553 554 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 555 goto badcred; 556 557 memcpy(&v, imsg->data, sizeof(v)); 558 profiling |= v; 559 560 control_broadcast_verbose(IMSG_CTL_PROFILE, profiling); 561 562 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 563 return; 564 565 case IMSG_CTL_PROFILE_DISABLE: 566 if (c->euid) 567 goto badcred; 568 569 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 570 goto badcred; 571 572 memcpy(&v, imsg->data, sizeof(v)); 573 profiling &= ~v; 574 575 control_broadcast_verbose(IMSG_CTL_PROFILE, profiling); 576 577 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 578 return; 579 580 case IMSG_CTL_PAUSE_EVP: 581 if (c->euid) 582 goto badcred; 583 584 imsg->hdr.peerid = c->id; 585 m_forward(p_scheduler, imsg); 586 return; 587 588 case IMSG_CTL_PAUSE_MDA: 589 if (c->euid) 590 goto badcred; 591 592 if (env->sc_flags & SMTPD_MDA_PAUSED) { 593 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 594 return; 595 } 596 log_info("info: mda paused"); 597 env->sc_flags |= SMTPD_MDA_PAUSED; 598 m_compose(p_queue, IMSG_CTL_PAUSE_MDA, 0, 0, -1, NULL, 0); 599 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 600 return; 601 602 case IMSG_CTL_PAUSE_MTA: 603 if (c->euid) 604 goto badcred; 605 606 if (env->sc_flags & SMTPD_MTA_PAUSED) { 607 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 608 return; 609 } 610 log_info("info: mta paused"); 611 env->sc_flags |= SMTPD_MTA_PAUSED; 612 m_compose(p_queue, IMSG_CTL_PAUSE_MTA, 0, 0, -1, NULL, 0); 613 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 614 return; 615 616 case IMSG_CTL_PAUSE_SMTP: 617 if (c->euid) 618 goto badcred; 619 620 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 621 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 622 return; 623 } 624 log_info("info: smtp paused"); 625 env->sc_flags |= SMTPD_SMTP_PAUSED; 626 m_compose(p_pony, IMSG_CTL_PAUSE_SMTP, 0, 0, -1, NULL, 0); 627 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 628 return; 629 630 case IMSG_CTL_RESUME_EVP: 631 if (c->euid) 632 goto badcred; 633 634 imsg->hdr.peerid = c->id; 635 m_forward(p_scheduler, imsg); 636 return; 637 638 case IMSG_CTL_RESUME_MDA: 639 if (c->euid) 640 goto badcred; 641 642 if (!(env->sc_flags & SMTPD_MDA_PAUSED)) { 643 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 644 return; 645 } 646 log_info("info: mda resumed"); 647 env->sc_flags &= ~SMTPD_MDA_PAUSED; 648 m_compose(p_queue, IMSG_CTL_RESUME_MDA, 0, 0, -1, NULL, 0); 649 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 650 return; 651 652 case IMSG_CTL_RESUME_MTA: 653 if (c->euid) 654 goto badcred; 655 656 if (!(env->sc_flags & SMTPD_MTA_PAUSED)) { 657 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 658 return; 659 } 660 log_info("info: mta resumed"); 661 env->sc_flags &= ~SMTPD_MTA_PAUSED; 662 m_compose(p_queue, IMSG_CTL_RESUME_MTA, 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_SMTP: 667 if (c->euid) 668 goto badcred; 669 670 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) { 671 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 672 return; 673 } 674 log_info("info: smtp resumed"); 675 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 676 m_forward(p_pony, imsg); 677 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 678 return; 679 680 case IMSG_CTL_RESUME_ROUTE: 681 if (c->euid) 682 goto badcred; 683 684 m_forward(p_pony, imsg); 685 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 686 return; 687 688 case IMSG_CTL_LIST_MESSAGES: 689 if (c->euid) 690 goto badcred; 691 m_compose(p_scheduler, IMSG_CTL_LIST_MESSAGES, c->id, 0, -1, 692 imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); 693 return; 694 695 case IMSG_CTL_LIST_ENVELOPES: 696 if (c->euid) 697 goto badcred; 698 m_compose(p_scheduler, IMSG_CTL_LIST_ENVELOPES, c->id, 0, -1, 699 imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); 700 return; 701 702 case IMSG_CTL_MTA_SHOW_HOSTS: 703 case IMSG_CTL_MTA_SHOW_RELAYS: 704 case IMSG_CTL_MTA_SHOW_ROUTES: 705 case IMSG_CTL_MTA_SHOW_HOSTSTATS: 706 case IMSG_CTL_MTA_SHOW_BLOCK: 707 if (c->euid) 708 goto badcred; 709 710 imsg->hdr.peerid = c->id; 711 m_forward(p_pony, imsg); 712 return; 713 714 case IMSG_CTL_SHOW_STATUS: 715 if (c->euid) 716 goto badcred; 717 718 m_compose(p, IMSG_CTL_SHOW_STATUS, 0, 0, -1, &env->sc_flags, 719 sizeof(env->sc_flags)); 720 return; 721 722 case IMSG_CTL_MTA_BLOCK: 723 case IMSG_CTL_MTA_UNBLOCK: 724 if (c->euid) 725 goto badcred; 726 727 if (imsg->hdr.len - IMSG_HEADER_SIZE <= sizeof(ss)) 728 goto invalid; 729 memmove(&ss, imsg->data, sizeof(ss)); 730 m_create(p_pony, imsg->hdr.type, c->id, 0, -1); 731 m_add_sockaddr(p_pony, (struct sockaddr *)&ss); 732 m_add_string(p_pony, (char *)imsg->data + sizeof(ss)); 733 m_close(p_pony); 734 return; 735 736 case IMSG_CTL_SCHEDULE: 737 if (c->euid) 738 goto badcred; 739 740 imsg->hdr.peerid = c->id; 741 m_forward(p_scheduler, imsg); 742 return; 743 744 case IMSG_CTL_REMOVE: 745 if (c->euid) 746 goto badcred; 747 748 imsg->hdr.peerid = c->id; 749 m_forward(p_scheduler, imsg); 750 return; 751 752 case IMSG_CTL_UPDATE_TABLE: 753 if (c->euid) 754 goto badcred; 755 756 /* table name too long */ 757 len = strlen(imsg->data); 758 if (len >= LINE_MAX) 759 goto invalid; 760 761 m_forward(p_lka, imsg); 762 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 763 return; 764 765 case IMSG_CTL_DISCOVER_EVPID: 766 if (c->euid) 767 goto badcred; 768 769 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof evpid) 770 goto invalid; 771 772 memmove(&evpid, imsg->data, sizeof evpid); 773 m_create(p_queue, imsg->hdr.type, c->id, 0, -1); 774 m_add_evpid(p_queue, evpid); 775 m_close(p_queue); 776 return; 777 778 case IMSG_CTL_DISCOVER_MSGID: 779 case IMSG_CTL_UNCORRUPT_MSGID: 780 if (c->euid) 781 goto badcred; 782 783 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof msgid) 784 goto invalid; 785 786 memmove(&msgid, imsg->data, sizeof msgid); 787 m_create(p_queue, imsg->hdr.type, c->id, 0, -1); 788 m_add_msgid(p_queue, msgid); 789 m_close(p_queue); 790 return; 791 792 default: 793 log_debug("debug: control_dispatch_ext: " 794 "error handling %s imsg", 795 imsg_to_str(imsg->hdr.type)); 796 return; 797 } 798 badcred: 799 invalid: 800 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 801 } 802 803 static void 804 control_broadcast_verbose(int msg, int v) 805 { 806 m_create(p_lka, msg, 0, 0, -1); 807 m_add_int(p_lka, v); 808 m_close(p_lka); 809 810 m_create(p_pony, msg, 0, 0, -1); 811 m_add_int(p_pony, v); 812 m_close(p_pony); 813 814 m_create(p_queue, msg, 0, 0, -1); 815 m_add_int(p_queue, v); 816 m_close(p_queue); 817 818 m_create(p_ca, msg, 0, 0, -1); 819 m_add_int(p_ca, v); 820 m_close(p_ca); 821 822 m_create(p_scheduler, msg, 0, 0, -1); 823 m_add_int(p_scheduler, v); 824 m_close(p_scheduler); 825 826 m_create(p_parent, msg, 0, 0, -1); 827 m_add_int(p_parent, v); 828 m_close(p_parent); 829 } 830