xref: /openbsd-src/usr.sbin/smtpd/smtpctl.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: smtpctl.c,v 1.83 2012/07/09 09:57:53 gilles Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/queue.h>
25 #include <sys/tree.h>
26 #include <sys/un.h>
27 #include <sys/param.h>
28 
29 #include <err.h>
30 #include <errno.h>
31 #include <event.h>
32 #include <imsg.h>
33 #include <inttypes.h>
34 #include <pwd.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39 #include <unistd.h>
40 
41 #include "smtpd.h"
42 #include "parser.h"
43 #include "log.h"
44 
45 void usage(void);
46 static void setup_env(struct smtpd *);
47 static int show_command_output(struct imsg *);
48 static int show_stats_output(struct imsg *);
49 static void show_queue(int);
50 static void show_envelope(struct envelope *, int);
51 static void getflag(u_int *, int, char *, char *, size_t);
52 
53 int proctype;
54 struct imsgbuf	*ibuf;
55 
56 int sendmail = 0;
57 extern char *__progname;
58 
59 struct smtpd	*env = NULL;
60 
61 __dead void
62 usage(void)
63 {
64 	extern char *__progname;
65 
66 	if (sendmail)
67 		fprintf(stderr, "usage: %s [-tv] [-f from] [-F name] to ..\n",
68 		    __progname);
69 	else
70 		fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
71 	exit(1);
72 }
73 
74 static void
75 setup_env(struct smtpd *smtpd)
76 {
77 	bzero(smtpd, sizeof (*smtpd));
78 	env = smtpd;
79 
80 	if ((env->sc_pw = getpwnam(SMTPD_USER)) == NULL)
81 		errx(1, "unknown user %s", SMTPD_USER);
82 
83 	env->sc_queue = queue_backend_lookup("fs");
84 	if (env->sc_queue == NULL)
85 		errx(1, "could not find queue backend");
86 
87 	if (!env->sc_queue->init(0))
88 		errx(1, "invalid directory permissions");
89 }
90 
91 int
92 main(int argc, char *argv[])
93 {
94 	struct sockaddr_un	sun;
95 	struct parse_result	*res = NULL;
96 	struct imsg		imsg;
97 	struct smtpd		smtpd;
98 	int			ctl_sock;
99 	int			done = 0;
100 	int			n, verbose = 0;
101 
102 	/* parse options */
103 	if (strcmp(__progname, "sendmail") == 0 || strcmp(__progname, "send-mail") == 0)
104 		sendmail = 1;
105 	else if (strcmp(__progname, "mailq") == 0) {
106 		if (geteuid())
107 			errx(1, "need root privileges");
108 		setup_env(&smtpd);
109 		show_queue(0);
110 		return 0;
111 	} else if (strcmp(__progname, "smtpctl") == 0) {
112 
113 		/* check for root privileges */
114 		if (geteuid())
115 			errx(1, "need root privileges");
116 
117 		setup_env(&smtpd);
118 
119 		if ((res = parse(argc - 1, argv + 1)) == NULL)
120 			exit(1);
121 
122 		/* handle "disconnected" commands */
123 		switch (res->action) {
124 		case SHOW_QUEUE:
125 			show_queue(0);
126 			break;
127 		case SHOW_RUNQUEUE:
128 			break;
129 		default:
130 			goto connected;
131 		}
132 		return 0;
133 	} else
134 		errx(1, "unsupported mode");
135 
136 connected:
137 	/* connect to smtpd control socket */
138 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
139 		err(1, "socket");
140 
141 	bzero(&sun, sizeof(sun));
142 	sun.sun_family = AF_UNIX;
143 	strlcpy(sun.sun_path, SMTPD_SOCKET, sizeof(sun.sun_path));
144 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
145 		if (sendmail)
146 			return enqueue_offline(argc, argv);
147 		err(1, "connect: %s", SMTPD_SOCKET);
148 	}
149 
150 	if ((ibuf = calloc(1, sizeof(struct imsgbuf))) == NULL)
151 		err(1, NULL);
152 	imsg_init(ibuf, ctl_sock);
153 
154 	if (sendmail)
155 		return enqueue(argc, argv);
156 
157 	/* process user request */
158 	switch (res->action) {
159 	case NONE:
160 		usage();
161 		/* not reached */
162 
163 	case SCHEDULE:
164 	case REMOVE: {
165 		u_int64_t ulval;
166 		char *ep;
167 
168 		errno = 0;
169 		ulval = strtoul(res->data, &ep, 16);
170 		if (res->data[0] == '\0' || *ep != '\0')
171 			errx(1, "invalid msgid/evpid");
172 		if (errno == ERANGE && ulval == ULLONG_MAX)
173 			errx(1, "invalid msgid/evpid");
174 		if (ulval == 0)
175 			errx(1, "invalid msgid/evpid");
176 
177 		if (res->action == SCHEDULE)
178 			imsg_compose(ibuf, IMSG_SCHEDULER_SCHEDULE, 0, 0, -1, &ulval,
179 			    sizeof(ulval));
180 		if (res->action == REMOVE)
181 			imsg_compose(ibuf, IMSG_SCHEDULER_REMOVE, 0, 0, -1, &ulval,
182 			    sizeof(ulval));
183 		break;
184 	}
185 
186 	case SCHEDULE_ALL: {
187 		u_int64_t ulval = 0;
188 
189 		imsg_compose(ibuf, IMSG_SCHEDULER_SCHEDULE, 0, 0, -1, &ulval,
190 		    sizeof(ulval));
191 		break;
192 	}
193 
194 	case SHUTDOWN:
195 		imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0);
196 		break;
197 	case PAUSE_MDA:
198 		imsg_compose(ibuf, IMSG_QUEUE_PAUSE_MDA, 0, 0, -1, NULL, 0);
199 		break;
200 	case PAUSE_MTA:
201 		imsg_compose(ibuf, IMSG_QUEUE_PAUSE_MTA, 0, 0, -1, NULL, 0);
202 		break;
203 	case PAUSE_SMTP:
204 		imsg_compose(ibuf, IMSG_SMTP_PAUSE, 0, 0, -1, NULL, 0);
205 		break;
206 	case RESUME_MDA:
207 		imsg_compose(ibuf, IMSG_QUEUE_RESUME_MDA, 0, 0, -1, NULL, 0);
208 		break;
209 	case RESUME_MTA:
210 		imsg_compose(ibuf, IMSG_QUEUE_RESUME_MTA, 0, 0, -1, NULL, 0);
211 		break;
212 	case RESUME_SMTP:
213 		imsg_compose(ibuf, IMSG_SMTP_RESUME, 0, 0, -1, NULL, 0);
214 		break;
215 	case SHOW_STATS:
216 		imsg_compose(ibuf, IMSG_STATS, 0, 0, -1, NULL, 0);
217 		break;
218 	case MONITOR:
219 		/* XXX */
220 		break;
221 	case LOG_VERBOSE:
222 		verbose = 1;
223 		/* FALLTHROUGH */
224 	case LOG_BRIEF:
225 		imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &verbose,
226 		    sizeof(verbose));
227 		printf("logging request sent.\n");
228 		done = 1;
229 		break;
230 	default:
231 		errx(1, "unknown request (%d)", res->action);
232 	}
233 
234 	while (ibuf->w.queued)
235 		if (msgbuf_write(&ibuf->w) < 0)
236 			err(1, "write error");
237 
238 	while (!done) {
239 		if ((n = imsg_read(ibuf)) == -1)
240 			errx(1, "imsg_read error");
241 		if (n == 0)
242 			errx(1, "pipe closed");
243 
244 		while (!done) {
245 			if ((n = imsg_get(ibuf, &imsg)) == -1)
246 				errx(1, "imsg_get error");
247 			if (n == 0)
248 				break;
249 			switch(res->action) {
250 			case REMOVE:
251 			case SCHEDULE:
252 			case SCHEDULE_ALL:
253 			case SHUTDOWN:
254 			case PAUSE_MDA:
255 			case PAUSE_MTA:
256 			case PAUSE_SMTP:
257 			case RESUME_MDA:
258 			case RESUME_MTA:
259 			case RESUME_SMTP:
260 			case LOG_VERBOSE:
261 			case LOG_BRIEF:
262 				done = show_command_output(&imsg);
263 				break;
264 			case SHOW_STATS:
265 				done = show_stats_output(&imsg);
266 				break;
267 			case NONE:
268 				break;
269 			case MONITOR:
270 				break;
271 			default:
272 				err(1, "unexpected reply (%d)", res->action);
273 			}
274 			/* insert imsg replies switch here */
275 
276 			imsg_free(&imsg);
277 		}
278 	}
279 	close(ctl_sock);
280 	free(ibuf);
281 
282 	return (0);
283 }
284 
285 static int
286 show_command_output(struct imsg *imsg)
287 {
288 	switch (imsg->hdr.type) {
289 	case IMSG_CTL_OK:
290 		printf("command succeeded\n");
291 		break;
292 	case IMSG_CTL_FAIL:
293 		printf("command failed\n");
294 		break;
295 	default:
296 		errx(1, "wrong message in summary: %u", imsg->hdr.type);
297 	}
298 	return (1);
299 }
300 
301 static void
302 stat_print(int stat, int what)
303 {
304 	static const char *names[STATS_MAX] = {
305 		"smtp.sessions",
306 		"smtp.sessions.inet4",
307 		"smtp.sessions.inet6",
308 		"smtp.sessions.smtps",
309 		"smtp.sessions.starttls",
310 
311 		"mta.sessions",
312 
313 		"mda.sessions",
314 
315 		"control.sessions",
316 
317 		"lka.sessions",
318 		"lka.sessions.mx",
319 		"lka.sessions.host",
320 		"lka.sessions.cname",
321 		"lka.sessions.failure",
322 
323 		"scheduler",
324 		"scheduler.bounces",
325 
326 		"queue.inserts.local",
327 		"queue.inserts.remote",
328 
329 		"ramqueue.envelopes",
330 		"ramqueue.messages",
331 		"ramqueue.batches",
332 		"ramqueue.hosts",
333 	};
334 	const char *sfx;
335 
336 	if (what == STAT_ACTIVE)
337 		sfx = ".active";
338 	else if (what == STAT_MAXACTIVE)
339 		sfx = ".maxactive";
340 	else
341 		sfx = "";
342 
343 	printf("%s%s=%zd\n", names[stat], sfx, stat_get(stat, what));
344 }
345 
346 static int
347 show_stats_output(struct imsg *imsg)
348 {
349 	struct stats	*stats;
350 
351 	if (imsg->hdr.type != IMSG_STATS)
352 		errx(1, "show_stats_output: bad hdr type (%d)", imsg->hdr.type);
353 
354 	if (IMSG_DATA_SIZE(imsg) != sizeof(*stats))
355 		errx(1, "show_stats_output: bad data size");
356 
357 	stats = imsg->data;
358 	stat_init(stats->counters, STATS_MAX);
359 
360 	stat_print(STATS_CONTROL_SESSION, STAT_COUNT);
361 	stat_print(STATS_CONTROL_SESSION, STAT_ACTIVE);
362 	stat_print(STATS_CONTROL_SESSION, STAT_MAXACTIVE);
363 
364 	stat_print(STATS_MDA_SESSION, STAT_COUNT);
365 	stat_print(STATS_MDA_SESSION, STAT_ACTIVE);
366 	stat_print(STATS_MDA_SESSION, STAT_MAXACTIVE);
367 
368 	stat_print(STATS_MTA_SESSION, STAT_COUNT);
369 	stat_print(STATS_MTA_SESSION, STAT_ACTIVE);
370 	stat_print(STATS_MTA_SESSION, STAT_MAXACTIVE);
371 
372 	stat_print(STATS_LKA_SESSION, STAT_COUNT);
373 	stat_print(STATS_LKA_SESSION, STAT_ACTIVE);
374 	stat_print(STATS_LKA_SESSION, STAT_MAXACTIVE);
375 	stat_print(STATS_LKA_SESSION_MX, STAT_COUNT);
376 	stat_print(STATS_LKA_SESSION_HOST, STAT_COUNT);
377 	stat_print(STATS_LKA_SESSION_CNAME, STAT_COUNT);
378 	stat_print(STATS_LKA_FAILURE, STAT_COUNT);
379 
380 	printf("parent.uptime=%lld\n",
381 	    (long long int) (time(NULL) - stats->parent.start));
382 
383 	stat_print(STATS_QUEUE_LOCAL, STAT_COUNT);
384 	stat_print(STATS_QUEUE_REMOTE, STAT_COUNT);
385 
386 	stat_print(STATS_SCHEDULER, STAT_COUNT);
387 	stat_print(STATS_SCHEDULER, STAT_ACTIVE);
388 	stat_print(STATS_SCHEDULER, STAT_MAXACTIVE);
389 
390 	stat_print(STATS_SCHEDULER_BOUNCES, STAT_COUNT);
391 	stat_print(STATS_SCHEDULER_BOUNCES, STAT_ACTIVE);
392 	stat_print(STATS_SCHEDULER_BOUNCES, STAT_MAXACTIVE);
393 
394 	stat_print(STATS_RAMQUEUE_HOST, STAT_ACTIVE);
395 	stat_print(STATS_RAMQUEUE_BATCH, STAT_ACTIVE);
396 	stat_print(STATS_RAMQUEUE_MESSAGE, STAT_ACTIVE);
397 	stat_print(STATS_RAMQUEUE_ENVELOPE, STAT_ACTIVE);
398 
399 	stat_print(STATS_RAMQUEUE_HOST, STAT_MAXACTIVE);
400 	stat_print(STATS_RAMQUEUE_BATCH, STAT_MAXACTIVE);
401 	stat_print(STATS_RAMQUEUE_MESSAGE, STAT_MAXACTIVE);
402 	stat_print(STATS_RAMQUEUE_ENVELOPE, STAT_MAXACTIVE);
403 
404 	printf("smtp.errors.delays=%zd\n", stats->smtp.delays);
405 	printf("smtp.errors.linetoolong=%zd\n", stats->smtp.linetoolong);
406 	printf("smtp.errors.read_eof=%zd\n", stats->smtp.read_eof);
407 	printf("smtp.errors.read_system=%zd\n", stats->smtp.read_error);
408 	printf("smtp.errors.read_timeout=%zd\n", stats->smtp.read_timeout);
409 	printf("smtp.errors.tempfail=%zd\n", stats->smtp.tempfail);
410 	printf("smtp.errors.toofast=%zd\n", stats->smtp.toofast);
411 	printf("smtp.errors.write_eof=%zd\n", stats->smtp.write_eof);
412 	printf("smtp.errors.write_system=%zd\n", stats->smtp.write_error);
413 	printf("smtp.errors.write_timeout=%zd\n", stats->smtp.write_timeout);
414 
415 	stat_print(STATS_SMTP_SESSION, STAT_COUNT);
416 	stat_print(STATS_SMTP_SESSION_INET4, STAT_COUNT);
417 	stat_print(STATS_SMTP_SESSION_INET6, STAT_COUNT);
418 	printf("smtp.sessions.aborted=%zd\n", stats->smtp.read_eof +
419 	    stats->smtp.read_error + stats->smtp.write_eof +
420 	    stats->smtp.write_error);
421 
422 	stat_print(STATS_SMTP_SESSION, STAT_ACTIVE);
423 	stat_print(STATS_SMTP_SESSION, STAT_MAXACTIVE);
424 
425 	printf("smtp.sessions.timeout=%zd\n", stats->smtp.read_timeout +
426 	    stats->smtp.write_timeout);
427 
428 	stat_print(STATS_SMTP_SMTPS, STAT_COUNT);
429 	stat_print(STATS_SMTP_SMTPS, STAT_ACTIVE);
430 	stat_print(STATS_SMTP_SMTPS, STAT_MAXACTIVE);
431 
432 	stat_print(STATS_SMTP_STARTTLS, STAT_COUNT);
433 	stat_print(STATS_SMTP_STARTTLS, STAT_ACTIVE);
434 	stat_print(STATS_SMTP_STARTTLS, STAT_MAXACTIVE);
435 
436 	return (1);
437 }
438 
439 static void
440 show_queue(int flags)
441 {
442 	struct qwalk	*q;
443 	struct envelope	 envelope;
444 	u_int64_t	 evpid;
445 
446 	log_init(1);
447 
448 	if (chroot(PATH_SPOOL) == -1 || chdir(".") == -1)
449 		err(1, "%s", PATH_SPOOL);
450 
451 	q = qwalk_new(0);
452 
453 	while (qwalk(q, &evpid)) {
454 		if (! queue_envelope_load(evpid, &envelope))
455 			continue;
456 		show_envelope(&envelope, flags);
457 	}
458 
459 	qwalk_close(q);
460 }
461 
462 static void
463 show_envelope(struct envelope *e, int flags)
464 {
465 	char	 status[128];
466 
467 	status[0] = '\0';
468 
469 	getflag(&e->flags, DF_BOUNCE, "BOUNCE",
470 	    status, sizeof(status));
471 	getflag(&e->flags, DF_AUTHENTICATED, "AUTH",
472 	    status, sizeof(status));
473 	getflag(&e->flags, DF_ENQUEUED, "ENQUEUED",
474 	    status, sizeof(status));
475 	getflag(&e->flags, DF_INTERNAL, "INTERNAL",
476 	    status, sizeof(status));
477 
478 	if (e->flags)
479 		errx(1, "%016" PRIx64 ": unexpected flags 0x%04x", e->id,
480 		    e->flags);
481 
482 	if (status[0])
483 		status[strlen(status) - 1] = '\0';
484 	else
485 		strlcpy(status, "-", sizeof(status));
486 
487 	switch (e->type) {
488 	case D_MDA:
489 		printf("MDA");
490 		break;
491 	case D_MTA:
492 		printf("MTA");
493 		break;
494 	case D_BOUNCE:
495 		printf("BOUNCE");
496 		break;
497 	default:
498 		printf("UNKNOWN");
499 	}
500 
501 	printf("|%016" PRIx64 "|%s|%s@%s|%s@%s|%" PRId64 "|%" PRId64 "|%u",
502 	    e->id,
503 	    status,
504 	    e->sender.user, e->sender.domain,
505 	    e->dest.user, e->dest.domain,
506 	    (int64_t) e->lasttry,
507 	    (int64_t) e->expire,
508 	    e->retry);
509 
510 	if (e->errorline[0] != '\0')
511 		printf("|%s", e->errorline);
512 
513 	printf("\n");
514 }
515 
516 static void
517 getflag(u_int *bitmap, int bit, char *bitstr, char *buf, size_t len)
518 {
519 	if (*bitmap & bit) {
520 		*bitmap &= ~bit;
521 		strlcat(buf, bitstr, len);
522 		strlcat(buf, ",", len);
523 	}
524 }
525