1 /* $OpenBSD: control.c,v 1.60 2011/09/01 19:56:49 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 #include <sys/param.h> 24 #include <sys/stat.h> 25 #include <sys/socket.h> 26 #include <sys/un.h> 27 28 #include <errno.h> 29 #include <event.h> 30 #include <fcntl.h> 31 #include <imsg.h> 32 #include <pwd.h> 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "smtpd.h" 40 #include "log.h" 41 42 #define CONTROL_BACKLOG 5 43 44 /* control specific headers */ 45 struct { 46 struct event ev; 47 int fd; 48 } control_state; 49 50 void control_imsg(struct imsgev *, struct imsg *); 51 __dead void control_shutdown(void); 52 int control_init(void); 53 void control_listen(void); 54 void control_cleanup(void); 55 void control_accept(int, short, void *); 56 struct ctl_conn *control_connbyfd(int); 57 void control_close(int); 58 void control_sig_handler(int, short, void *); 59 void control_dispatch_ext(int, short, void *); 60 61 struct ctl_connlist ctl_conns; 62 63 void 64 control_imsg(struct imsgev *iev, struct imsg *imsg) 65 { 66 struct ctl_conn *c; 67 struct reload *reload; 68 69 if (iev->proc == PROC_SMTP) { 70 switch (imsg->hdr.type) { 71 case IMSG_SMTP_ENQUEUE: 72 c = control_connbyfd(imsg->hdr.peerid); 73 if (c == NULL) 74 return; 75 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, 76 imsg->fd, NULL, 0); 77 return; 78 } 79 } 80 81 if (iev->proc == PROC_PARENT) { 82 switch (imsg->hdr.type) { 83 case IMSG_CONF_RELOAD: 84 env->sc_flags &= ~SMTPD_CONFIGURING; 85 reload = imsg->data; 86 c = control_connbyfd(reload->fd); 87 if (c == NULL) 88 return; 89 imsg_compose_event(&c->iev, 90 reload->ret ? IMSG_CTL_OK : IMSG_CTL_FAIL, 0, 0, 91 -1, NULL, 0); 92 return; 93 } 94 } 95 96 fatalx("control_imsg: unexpected imsg"); 97 } 98 99 void 100 control_sig_handler(int sig, short event, void *p) 101 { 102 switch (sig) { 103 case SIGINT: 104 case SIGTERM: 105 control_shutdown(); 106 break; 107 default: 108 fatalx("control_sig_handler: unexpected signal"); 109 } 110 } 111 112 113 pid_t 114 control(void) 115 { 116 struct sockaddr_un sun; 117 int fd; 118 mode_t old_umask; 119 pid_t pid; 120 struct passwd *pw; 121 struct event ev_sigint; 122 struct event ev_sigterm; 123 struct peer peers [] = { 124 { PROC_RUNNER, imsg_dispatch }, 125 { PROC_QUEUE, imsg_dispatch }, 126 { PROC_SMTP, imsg_dispatch }, 127 { PROC_MFA, imsg_dispatch }, 128 { PROC_PARENT, imsg_dispatch }, 129 }; 130 131 switch (pid = fork()) { 132 case -1: 133 fatal("control: cannot fork"); 134 case 0: 135 break; 136 default: 137 return (pid); 138 } 139 140 purge_config(PURGE_EVERYTHING); 141 142 pw = env->sc_pw; 143 144 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 145 fatal("control: socket"); 146 147 bzero(&sun, sizeof(sun)); 148 sun.sun_family = AF_UNIX; 149 if (strlcpy(sun.sun_path, SMTPD_SOCKET, 150 sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) 151 fatal("control: socket name too long"); 152 153 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0) 154 fatalx("control socket already listening"); 155 156 if (unlink(SMTPD_SOCKET) == -1) 157 if (errno != ENOENT) 158 fatal("control: cannot unlink socket"); 159 160 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 161 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 162 (void)umask(old_umask); 163 fatal("control: bind"); 164 } 165 (void)umask(old_umask); 166 167 if (chmod(SMTPD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) { 168 (void)unlink(SMTPD_SOCKET); 169 fatal("control: chmod"); 170 } 171 172 session_socket_blockmode(fd, BM_NONBLOCK); 173 control_state.fd = fd; 174 175 if (chroot(pw->pw_dir) == -1) 176 fatal("control: chroot"); 177 if (chdir("/") == -1) 178 fatal("control: chdir(\"/\")"); 179 180 smtpd_process = PROC_CONTROL; 181 setproctitle("%s", env->sc_title[smtpd_process]); 182 183 if (setgroups(1, &pw->pw_gid) || 184 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 185 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 186 fatal("control: cannot drop privileges"); 187 188 imsg_callback = control_imsg; 189 event_init(); 190 191 signal_set(&ev_sigint, SIGINT, control_sig_handler, NULL); 192 signal_set(&ev_sigterm, SIGTERM, control_sig_handler, NULL); 193 signal_add(&ev_sigint, NULL); 194 signal_add(&ev_sigterm, NULL); 195 signal(SIGPIPE, SIG_IGN); 196 signal(SIGHUP, SIG_IGN); 197 198 TAILQ_INIT(&ctl_conns); 199 200 config_pipes(peers, nitems(peers)); 201 config_peers(peers, nitems(peers)); 202 control_listen(); 203 204 if (event_dispatch() < 0) 205 fatal("event_dispatch"); 206 control_shutdown(); 207 208 return (0); 209 } 210 211 void 212 control_shutdown(void) 213 { 214 log_info("control process exiting"); 215 _exit(0); 216 } 217 218 void 219 control_listen(void) 220 { 221 int avail = availdesc(); 222 223 if (listen(control_state.fd, CONTROL_BACKLOG) == -1) 224 fatal("control_listen"); 225 avail--; 226 227 event_set(&control_state.ev, control_state.fd, EV_READ|EV_PERSIST, 228 control_accept, NULL); 229 event_add(&control_state.ev, NULL); 230 231 /* guarantee 2 fds to each accepted client */ 232 if ((env->sc_maxconn = avail / 2) < 1) 233 fatalx("control_listen: fd starvation"); 234 } 235 236 void 237 control_cleanup(void) 238 { 239 (void)unlink(SMTPD_SOCKET); 240 } 241 242 /* ARGSUSED */ 243 void 244 control_accept(int listenfd, short event, void *arg) 245 { 246 int connfd; 247 socklen_t len; 248 struct sockaddr_un sun; 249 struct ctl_conn *c; 250 251 len = sizeof(sun); 252 if ((connfd = accept(listenfd, (struct sockaddr *)&sun, &len)) == -1) { 253 if (errno == EINTR || errno == ECONNABORTED) 254 return; 255 fatal("control_accept: accept"); 256 } 257 258 session_socket_blockmode(connfd, BM_NONBLOCK); 259 260 if ((c = calloc(1, sizeof(*c))) == NULL) 261 fatal(NULL); 262 imsg_init(&c->iev.ibuf, connfd); 263 c->iev.handler = control_dispatch_ext; 264 c->iev.events = EV_READ; 265 event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 266 c->iev.handler, NULL); 267 event_add(&c->iev.ev, NULL); 268 TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 269 270 if (stat_increment(STATS_CONTROL_SESSION) >= env->sc_maxconn) { 271 log_warnx("ctl client limit hit, disabling new connections"); 272 event_del(&control_state.ev); 273 } 274 } 275 276 struct ctl_conn * 277 control_connbyfd(int fd) 278 { 279 struct ctl_conn *c; 280 281 for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd; 282 c = TAILQ_NEXT(c, entry)) 283 ; /* nothing */ 284 285 return (c); 286 } 287 288 void 289 control_close(int fd) 290 { 291 struct ctl_conn *c; 292 293 if ((c = control_connbyfd(fd)) == NULL) { 294 log_warn("control_close: fd %d: not found", fd); 295 return; 296 } 297 TAILQ_REMOVE(&ctl_conns, c, entry); 298 event_del(&c->iev.ev); 299 imsg_clear(&c->iev.ibuf); 300 close(fd); 301 free(c); 302 303 if (stat_decrement(STATS_CONTROL_SESSION) < env->sc_maxconn && 304 !event_pending(&control_state.ev, EV_READ, NULL)) { 305 log_warnx("re-enabling ctl connections"); 306 event_add(&control_state.ev, NULL); 307 } 308 } 309 310 /* ARGSUSED */ 311 void 312 control_dispatch_ext(int fd, short event, void *arg) 313 { 314 struct ctl_conn *c; 315 struct imsg imsg; 316 int n; 317 uid_t euid; 318 gid_t egid; 319 320 if (getpeereid(fd, &euid, &egid) == -1) 321 fatal("getpeereid"); 322 323 if ((c = control_connbyfd(fd)) == NULL) { 324 log_warn("control_dispatch_ext: fd %d: not found", fd); 325 return; 326 } 327 328 if (event & EV_READ) { 329 if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { 330 control_close(fd); 331 return; 332 } 333 } 334 335 if (event & EV_WRITE) { 336 if (msgbuf_write(&c->iev.ibuf.w) < 0) { 337 control_close(fd); 338 return; 339 } 340 } 341 342 for (;;) { 343 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 344 control_close(fd); 345 return; 346 } 347 348 if (n == 0) 349 break; 350 351 switch (imsg.hdr.type) { 352 case IMSG_SMTP_ENQUEUE: 353 if (env->sc_flags & (SMTPD_SMTP_PAUSED | 354 SMTPD_CONFIGURING | SMTPD_EXITING)) { 355 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 356 NULL, 0); 357 break; 358 } 359 imsg_compose_event(env->sc_ievs[PROC_SMTP], 360 IMSG_SMTP_ENQUEUE, fd, 0, -1, &euid, sizeof(euid)); 361 break; 362 case IMSG_STATS: 363 if (euid) 364 goto badcred; 365 imsg_compose_event(&c->iev, IMSG_STATS, 0, 0, -1, 366 env->stats, sizeof(struct stats)); 367 break; 368 case IMSG_CTL_SHUTDOWN: 369 /* NEEDS_FIX */ 370 log_debug("received shutdown request"); 371 372 if (euid) 373 goto badcred; 374 375 if (env->sc_flags & SMTPD_EXITING) { 376 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 377 NULL, 0); 378 break; 379 } 380 env->sc_flags |= SMTPD_EXITING; 381 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 382 break; 383 case IMSG_CTL_VERBOSE: { 384 int verbose; 385 386 if (euid) 387 goto badcred; 388 389 if (IMSG_DATA_SIZE(&imsg) != sizeof(verbose)) 390 goto badcred; 391 392 memcpy(&verbose, imsg.data, sizeof(verbose)); 393 log_verbose(verbose); 394 imsg_compose_event(env->sc_ievs[PROC_PARENT], IMSG_CTL_VERBOSE, 395 0, 0, -1, &verbose, sizeof(verbose)); 396 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 397 break; 398 } 399 case IMSG_QUEUE_PAUSE_LOCAL: 400 if (euid) 401 goto badcred; 402 403 if (env->sc_flags & SMTPD_MDA_PAUSED) { 404 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 405 NULL, 0); 406 break; 407 } 408 env->sc_flags |= SMTPD_MDA_PAUSED; 409 imsg_compose_event(env->sc_ievs[PROC_QUEUE], 410 IMSG_QUEUE_PAUSE_LOCAL, 0, 0, -1, NULL, 0); 411 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 412 break; 413 case IMSG_QUEUE_PAUSE_OUTGOING: 414 if (euid) 415 goto badcred; 416 417 if (env->sc_flags & SMTPD_MTA_PAUSED) { 418 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 419 NULL, 0); 420 break; 421 } 422 env->sc_flags |= SMTPD_MTA_PAUSED; 423 imsg_compose_event(env->sc_ievs[PROC_QUEUE], 424 IMSG_QUEUE_PAUSE_OUTGOING, 0, 0, -1, NULL, 0); 425 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 426 break; 427 case IMSG_SMTP_PAUSE: 428 if (euid) 429 goto badcred; 430 431 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 432 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 433 NULL, 0); 434 break; 435 } 436 env->sc_flags |= SMTPD_SMTP_PAUSED; 437 imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_PAUSE, 438 0, 0, -1, NULL, 0); 439 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 440 break; 441 case IMSG_QUEUE_RESUME_LOCAL: 442 if (euid) 443 goto badcred; 444 445 if (! (env->sc_flags & SMTPD_MDA_PAUSED)) { 446 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 447 NULL, 0); 448 break; 449 } 450 env->sc_flags &= ~SMTPD_MDA_PAUSED; 451 imsg_compose_event(env->sc_ievs[PROC_QUEUE], 452 IMSG_QUEUE_RESUME_LOCAL, 0, 0, -1, NULL, 0); 453 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 454 break; 455 case IMSG_QUEUE_RESUME_OUTGOING: 456 if (euid) 457 goto badcred; 458 459 if (!(env->sc_flags & SMTPD_MTA_PAUSED)) { 460 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 461 NULL, 0); 462 break; 463 } 464 env->sc_flags &= ~SMTPD_MTA_PAUSED; 465 imsg_compose_event(env->sc_ievs[PROC_QUEUE], 466 IMSG_QUEUE_RESUME_OUTGOING, 0, 0, -1, NULL, 0); 467 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 468 break; 469 470 case IMSG_SMTP_RESUME: 471 if (euid) 472 goto badcred; 473 474 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) { 475 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 476 NULL, 0); 477 break; 478 } 479 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 480 imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_RESUME, 481 0, 0, -1, NULL, 0); 482 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 483 break; 484 485 case IMSG_RUNNER_SCHEDULE: { 486 u_int64_t ullval; 487 488 if (euid) 489 goto badcred; 490 491 ullval = *(u_int64_t *)imsg.data; 492 493 imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_RUNNER_SCHEDULE, 494 0, 0, -1, &ullval, sizeof(ullval)); 495 496 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 497 break; 498 } 499 500 case IMSG_RUNNER_REMOVE: { 501 u_int64_t ullval; 502 503 if (euid) 504 goto badcred; 505 506 ullval = *(u_int64_t *)imsg.data; 507 508 imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_RUNNER_REMOVE, 509 0, 0, -1, &ullval, sizeof(ullval)); 510 511 imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 512 break; 513 } 514 default: 515 log_debug("control_dispatch_ext: " 516 "error handling imsg %d", imsg.hdr.type); 517 break; 518 } 519 imsg_free(&imsg); 520 continue; 521 522 badcred: 523 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, 524 NULL, 0); 525 } 526 527 imsg_event_add(&c->iev); 528 } 529