GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/smtpd/smtpd/../control.c Lines: 0 426 0.0 %
Date: 2017-11-07 Branches: 0 263 0.0 %

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