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