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