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