1 /* $OpenBSD: control.c,v 1.130 2023/05/31 16:51:46 op 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 <time.h> 30 #include <unistd.h> 31 32 #include "smtpd.h" 33 #include "log.h" 34 35 #define CONTROL_BACKLOG 5 36 37 struct ctl_conn { 38 uint32_t id; 39 uint8_t flags; 40 #define CTL_CONN_NOTIFY 0x01 41 struct mproc mproc; 42 uid_t euid; 43 gid_t egid; 44 }; 45 46 struct { 47 struct event ev; 48 int fd; 49 } control_state; 50 51 static void control_imsg(struct mproc *, struct imsg *); 52 static void control_shutdown(void); 53 static void control_listen(void); 54 static void control_accept(int, short, void *); 55 static void control_close(struct ctl_conn *); 56 static void control_dispatch_ext(struct mproc *, struct imsg *); 57 static void control_digest_update(const char *, size_t, int); 58 static void control_broadcast_verbose(int, int); 59 60 static struct stat_backend *stat_backend = NULL; 61 extern const char *backend_stat; 62 63 static uint64_t connid = 0; 64 static struct tree ctl_conns; 65 static struct tree ctl_count; 66 static struct stat_digest digest; 67 68 #define CONTROL_FD_RESERVE 5 69 #define CONTROL_MAXCONN_PER_CLIENT 32 70 71 static void 72 control_imsg(struct mproc *p, struct imsg *imsg) 73 { 74 struct ctl_conn *c; 75 struct stat_value val; 76 struct msg m; 77 const char *key; 78 const void *data; 79 size_t sz; 80 81 if (imsg == NULL) { 82 if (p->proc != PROC_CLIENT) 83 control_shutdown(); 84 return; 85 } 86 87 switch (imsg->hdr.type) { 88 case IMSG_CTL_OK: 89 case IMSG_CTL_FAIL: 90 case IMSG_CTL_LIST_MESSAGES: 91 case IMSG_CTL_LIST_ENVELOPES: 92 case IMSG_CTL_DISCOVER_EVPID: 93 case IMSG_CTL_DISCOVER_MSGID: 94 case IMSG_CTL_MTA_SHOW_HOSTS: 95 case IMSG_CTL_MTA_SHOW_RELAYS: 96 case IMSG_CTL_MTA_SHOW_ROUTES: 97 case IMSG_CTL_MTA_SHOW_HOSTSTATS: 98 case IMSG_CTL_MTA_SHOW_BLOCK: 99 c = tree_get(&ctl_conns, imsg->hdr.peerid); 100 if (c == NULL) 101 return; 102 imsg->hdr.peerid = 0; 103 m_forward(&c->mproc, imsg); 104 return; 105 106 case IMSG_CTL_SMTP_SESSION: 107 c = tree_get(&ctl_conns, imsg->hdr.peerid); 108 if (c == NULL) 109 return; 110 m_compose(&c->mproc, IMSG_CTL_OK, 0, 0, imsg->fd, NULL, 0); 111 return; 112 113 case IMSG_STAT_INCREMENT: 114 m_msg(&m, imsg); 115 m_get_string(&m, &key); 116 m_get_data(&m, &data, &sz); 117 m_end(&m); 118 if (sz != sizeof(val)) 119 fatalx("control: IMSG_STAT_INCREMENT size mismatch"); 120 memmove(&val, data, sz); 121 if (stat_backend) 122 stat_backend->increment(key, val.u.counter); 123 control_digest_update(key, val.u.counter, 1); 124 return; 125 126 case IMSG_STAT_DECREMENT: 127 m_msg(&m, imsg); 128 m_get_string(&m, &key); 129 m_get_data(&m, &data, &sz); 130 m_end(&m); 131 if (sz != sizeof(val)) 132 fatalx("control: IMSG_STAT_DECREMENT size mismatch"); 133 memmove(&val, data, sz); 134 if (stat_backend) 135 stat_backend->decrement(key, val.u.counter); 136 control_digest_update(key, val.u.counter, 0); 137 return; 138 139 case IMSG_STAT_SET: 140 m_msg(&m, imsg); 141 m_get_string(&m, &key); 142 m_get_data(&m, &data, &sz); 143 m_end(&m); 144 if (sz != sizeof(val)) 145 fatalx("control: IMSG_STAT_SET size mismatch"); 146 memmove(&val, data, sz); 147 if (stat_backend) 148 stat_backend->set(key, &val); 149 return; 150 } 151 152 fatalx("control_imsg: unexpected %s imsg", 153 imsg_to_str(imsg->hdr.type)); 154 } 155 156 int 157 control_create_socket(void) 158 { 159 struct sockaddr_un s_un; 160 int fd; 161 mode_t old_umask; 162 163 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 164 fatal("control: socket"); 165 166 memset(&s_un, 0, sizeof(s_un)); 167 s_un.sun_family = AF_UNIX; 168 if (strlcpy(s_un.sun_path, SMTPD_SOCKET, 169 sizeof(s_un.sun_path)) >= sizeof(s_un.sun_path)) 170 fatal("control: socket name too long"); 171 172 if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0) 173 fatalx("control socket already listening"); 174 175 if (unlink(SMTPD_SOCKET) == -1) 176 if (errno != ENOENT) 177 fatal("control: cannot unlink socket"); 178 179 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 180 if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { 181 (void)umask(old_umask); 182 fatal("control: bind"); 183 } 184 (void)umask(old_umask); 185 186 if (chmod(SMTPD_SOCKET, 187 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) { 188 (void)unlink(SMTPD_SOCKET); 189 fatal("control: chmod"); 190 } 191 192 io_set_nonblocking(fd); 193 control_state.fd = fd; 194 195 return fd; 196 } 197 198 int 199 control(void) 200 { 201 struct passwd *pw; 202 203 purge_config(PURGE_EVERYTHING); 204 205 if ((pw = getpwnam(SMTPD_USER)) == NULL) 206 fatalx("unknown user " SMTPD_USER); 207 208 stat_backend = env->sc_stat; 209 stat_backend->init(); 210 211 if (chroot(PATH_CHROOT) == -1) 212 fatal("control: chroot"); 213 if (chdir("/") == -1) 214 fatal("control: chdir(\"/\")"); 215 216 config_process(PROC_CONTROL); 217 218 if (setgroups(1, &pw->pw_gid) || 219 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 220 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 221 fatal("control: cannot drop privileges"); 222 223 imsg_callback = control_imsg; 224 event_init(); 225 226 signal(SIGINT, SIG_IGN); 227 signal(SIGTERM, SIG_IGN); 228 signal(SIGPIPE, SIG_IGN); 229 signal(SIGHUP, SIG_IGN); 230 231 tree_init(&ctl_conns); 232 tree_init(&ctl_count); 233 234 memset(&digest, 0, sizeof digest); 235 digest.startup = time(NULL); 236 237 config_peer(PROC_SCHEDULER); 238 config_peer(PROC_QUEUE); 239 config_peer(PROC_PARENT); 240 config_peer(PROC_LKA); 241 config_peer(PROC_DISPATCHER); 242 config_peer(PROC_CA); 243 244 control_listen(); 245 246 if (pledge("stdio unix recvfd sendfd", NULL) == -1) 247 fatal("pledge"); 248 249 event_dispatch(); 250 fatalx("exited event loop"); 251 252 return (0); 253 } 254 255 static void 256 control_shutdown(void) 257 { 258 log_debug("debug: control agent exiting"); 259 _exit(0); 260 } 261 262 static void 263 control_listen(void) 264 { 265 if (listen(control_state.fd, CONTROL_BACKLOG) == -1) 266 fatal("control_listen"); 267 268 event_set(&control_state.ev, control_state.fd, EV_READ|EV_PERSIST, 269 control_accept, NULL); 270 event_add(&control_state.ev, NULL); 271 } 272 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 static void 411 control_dispatch_ext(struct mproc *p, struct imsg *imsg) 412 { 413 struct sockaddr_storage ss; 414 struct ctl_conn *c; 415 int v; 416 struct stat_kv *kvp; 417 char *key; 418 struct stat_value val; 419 size_t len; 420 uint64_t evpid; 421 uint32_t msgid; 422 423 c = p->data; 424 425 if (imsg == NULL) { 426 control_close(c); 427 return; 428 } 429 430 if (imsg->hdr.peerid != IMSG_VERSION) { 431 m_compose(p, IMSG_CTL_FAIL, IMSG_VERSION, 0, -1, NULL, 0); 432 return; 433 } 434 435 switch (imsg->hdr.type) { 436 case IMSG_CTL_SMTP_SESSION: 437 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 438 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 439 return; 440 } 441 m_compose(p_dispatcher, IMSG_CTL_SMTP_SESSION, c->id, 0, -1, 442 &c->euid, sizeof(c->euid)); 443 return; 444 445 case IMSG_CTL_GET_DIGEST: 446 if (c->euid) 447 goto badcred; 448 digest.timestamp = time(NULL); 449 m_compose(p, IMSG_CTL_GET_DIGEST, 0, 0, -1, &digest, sizeof digest); 450 return; 451 452 case IMSG_CTL_GET_STATS: 453 if (c->euid) 454 goto badcred; 455 kvp = imsg->data; 456 if (!stat_backend->iter(&kvp->iter, &key, &val)) 457 kvp->iter = NULL; 458 else { 459 (void)strlcpy(kvp->key, key, sizeof kvp->key); 460 kvp->val = val; 461 } 462 m_compose(p, IMSG_CTL_GET_STATS, 0, 0, -1, kvp, sizeof *kvp); 463 return; 464 465 case IMSG_CTL_VERBOSE: 466 if (c->euid) 467 goto badcred; 468 469 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 470 goto badcred; 471 472 memcpy(&v, imsg->data, sizeof(v)); 473 log_trace_verbose(v); 474 475 control_broadcast_verbose(IMSG_CTL_VERBOSE, v); 476 477 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 478 return; 479 480 case IMSG_CTL_TRACE_ENABLE: 481 if (c->euid) 482 goto badcred; 483 484 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 485 goto badcred; 486 487 memcpy(&v, imsg->data, sizeof(v)); 488 tracing |= v; 489 log_trace_verbose(tracing); 490 491 control_broadcast_verbose(IMSG_CTL_VERBOSE, tracing); 492 493 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 494 return; 495 496 case IMSG_CTL_TRACE_DISABLE: 497 if (c->euid) 498 goto badcred; 499 500 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 501 goto badcred; 502 503 memcpy(&v, imsg->data, sizeof(v)); 504 tracing &= ~v; 505 log_trace_verbose(tracing); 506 507 control_broadcast_verbose(IMSG_CTL_VERBOSE, tracing); 508 509 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 510 return; 511 512 case IMSG_CTL_PROFILE_ENABLE: 513 if (c->euid) 514 goto badcred; 515 516 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 517 goto badcred; 518 519 memcpy(&v, imsg->data, sizeof(v)); 520 profiling |= v; 521 522 control_broadcast_verbose(IMSG_CTL_PROFILE, profiling); 523 524 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 525 return; 526 527 case IMSG_CTL_PROFILE_DISABLE: 528 if (c->euid) 529 goto badcred; 530 531 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 532 goto badcred; 533 534 memcpy(&v, imsg->data, sizeof(v)); 535 profiling &= ~v; 536 537 control_broadcast_verbose(IMSG_CTL_PROFILE, profiling); 538 539 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 540 return; 541 542 case IMSG_CTL_PAUSE_EVP: 543 if (c->euid) 544 goto badcred; 545 546 imsg->hdr.peerid = c->id; 547 m_forward(p_scheduler, imsg); 548 return; 549 550 case IMSG_CTL_PAUSE_MDA: 551 if (c->euid) 552 goto badcred; 553 554 if (env->sc_flags & SMTPD_MDA_PAUSED) { 555 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 556 return; 557 } 558 log_info("info: mda paused"); 559 env->sc_flags |= SMTPD_MDA_PAUSED; 560 m_compose(p_queue, IMSG_CTL_PAUSE_MDA, 0, 0, -1, NULL, 0); 561 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 562 return; 563 564 case IMSG_CTL_PAUSE_MTA: 565 if (c->euid) 566 goto badcred; 567 568 if (env->sc_flags & SMTPD_MTA_PAUSED) { 569 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 570 return; 571 } 572 log_info("info: mta paused"); 573 env->sc_flags |= SMTPD_MTA_PAUSED; 574 m_compose(p_queue, IMSG_CTL_PAUSE_MTA, 0, 0, -1, NULL, 0); 575 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 576 return; 577 578 case IMSG_CTL_PAUSE_SMTP: 579 if (c->euid) 580 goto badcred; 581 582 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 583 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 584 return; 585 } 586 log_info("info: smtp paused"); 587 env->sc_flags |= SMTPD_SMTP_PAUSED; 588 m_compose(p_dispatcher, IMSG_CTL_PAUSE_SMTP, 0, 0, -1, NULL, 0); 589 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 590 return; 591 592 case IMSG_CTL_RESUME_EVP: 593 if (c->euid) 594 goto badcred; 595 596 imsg->hdr.peerid = c->id; 597 m_forward(p_scheduler, imsg); 598 return; 599 600 case IMSG_CTL_RESUME_MDA: 601 if (c->euid) 602 goto badcred; 603 604 if (!(env->sc_flags & SMTPD_MDA_PAUSED)) { 605 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 606 return; 607 } 608 log_info("info: mda resumed"); 609 env->sc_flags &= ~SMTPD_MDA_PAUSED; 610 m_compose(p_queue, IMSG_CTL_RESUME_MDA, 0, 0, -1, NULL, 0); 611 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 612 return; 613 614 case IMSG_CTL_RESUME_MTA: 615 if (c->euid) 616 goto badcred; 617 618 if (!(env->sc_flags & SMTPD_MTA_PAUSED)) { 619 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 620 return; 621 } 622 log_info("info: mta resumed"); 623 env->sc_flags &= ~SMTPD_MTA_PAUSED; 624 m_compose(p_queue, IMSG_CTL_RESUME_MTA, 0, 0, -1, NULL, 0); 625 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 626 return; 627 628 case IMSG_CTL_RESUME_SMTP: 629 if (c->euid) 630 goto badcred; 631 632 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) { 633 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 634 return; 635 } 636 log_info("info: smtp resumed"); 637 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 638 m_forward(p_dispatcher, imsg); 639 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 640 return; 641 642 case IMSG_CTL_RESUME_ROUTE: 643 if (c->euid) 644 goto badcred; 645 646 m_forward(p_dispatcher, imsg); 647 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 648 return; 649 650 case IMSG_CTL_LIST_MESSAGES: 651 if (c->euid) 652 goto badcred; 653 m_compose(p_scheduler, IMSG_CTL_LIST_MESSAGES, c->id, 0, -1, 654 imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); 655 return; 656 657 case IMSG_CTL_LIST_ENVELOPES: 658 if (c->euid) 659 goto badcred; 660 m_compose(p_scheduler, IMSG_CTL_LIST_ENVELOPES, c->id, 0, -1, 661 imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); 662 return; 663 664 case IMSG_CTL_MTA_SHOW_HOSTS: 665 case IMSG_CTL_MTA_SHOW_RELAYS: 666 case IMSG_CTL_MTA_SHOW_ROUTES: 667 case IMSG_CTL_MTA_SHOW_HOSTSTATS: 668 case IMSG_CTL_MTA_SHOW_BLOCK: 669 if (c->euid) 670 goto badcred; 671 672 imsg->hdr.peerid = c->id; 673 m_forward(p_dispatcher, imsg); 674 return; 675 676 case IMSG_CTL_SHOW_STATUS: 677 if (c->euid) 678 goto badcred; 679 680 m_compose(p, IMSG_CTL_SHOW_STATUS, 0, 0, -1, &env->sc_flags, 681 sizeof(env->sc_flags)); 682 return; 683 684 case IMSG_CTL_MTA_BLOCK: 685 case IMSG_CTL_MTA_UNBLOCK: 686 if (c->euid) 687 goto badcred; 688 689 if (imsg->hdr.len - IMSG_HEADER_SIZE <= sizeof(ss)) 690 goto invalid; 691 memmove(&ss, imsg->data, sizeof(ss)); 692 m_create(p_dispatcher, imsg->hdr.type, c->id, 0, -1); 693 m_add_sockaddr(p_dispatcher, (struct sockaddr *)&ss); 694 m_add_string(p_dispatcher, (char *)imsg->data + sizeof(ss)); 695 m_close(p_dispatcher); 696 return; 697 698 case IMSG_CTL_SCHEDULE: 699 if (c->euid) 700 goto badcred; 701 702 imsg->hdr.peerid = c->id; 703 m_forward(p_scheduler, imsg); 704 return; 705 706 case IMSG_CTL_REMOVE: 707 if (c->euid) 708 goto badcred; 709 710 imsg->hdr.peerid = c->id; 711 m_forward(p_scheduler, imsg); 712 return; 713 714 case IMSG_CTL_UPDATE_TABLE: 715 if (c->euid) 716 goto badcred; 717 718 /* table name too long */ 719 len = strlen(imsg->data); 720 if (len >= LINE_MAX) 721 goto invalid; 722 723 imsg->hdr.peerid = c->id; 724 m_forward(p_lka, imsg); 725 return; 726 727 case IMSG_CTL_DISCOVER_EVPID: 728 if (c->euid) 729 goto badcred; 730 731 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof evpid) 732 goto invalid; 733 734 memmove(&evpid, imsg->data, sizeof evpid); 735 m_create(p_queue, imsg->hdr.type, c->id, 0, -1); 736 m_add_evpid(p_queue, evpid); 737 m_close(p_queue); 738 return; 739 740 case IMSG_CTL_DISCOVER_MSGID: 741 if (c->euid) 742 goto badcred; 743 744 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof msgid) 745 goto invalid; 746 747 memmove(&msgid, imsg->data, sizeof msgid); 748 m_create(p_queue, imsg->hdr.type, c->id, 0, -1); 749 m_add_msgid(p_queue, msgid); 750 m_close(p_queue); 751 return; 752 753 default: 754 log_debug("debug: control_dispatch_ext: " 755 "error handling %s imsg", 756 imsg_to_str(imsg->hdr.type)); 757 return; 758 } 759 badcred: 760 invalid: 761 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 762 } 763 764 static void 765 control_broadcast_verbose(int msg, int v) 766 { 767 m_create(p_lka, msg, 0, 0, -1); 768 m_add_int(p_lka, v); 769 m_close(p_lka); 770 771 m_create(p_dispatcher, msg, 0, 0, -1); 772 m_add_int(p_dispatcher, v); 773 m_close(p_dispatcher); 774 775 m_create(p_queue, msg, 0, 0, -1); 776 m_add_int(p_queue, v); 777 m_close(p_queue); 778 779 m_create(p_ca, msg, 0, 0, -1); 780 m_add_int(p_ca, v); 781 m_close(p_ca); 782 783 m_create(p_scheduler, msg, 0, 0, -1); 784 m_add_int(p_scheduler, v); 785 m_close(p_scheduler); 786 787 m_create(p_parent, msg, 0, 0, -1); 788 m_add_int(p_parent, v); 789 m_close(p_parent); 790 } 791