xref: /openbsd/usr.sbin/smtpd/smtpctl.c (revision 3d8817e4)
1 /*	$OpenBSD: smtpctl.c,v 1.59 2011/04/17 13:36:07 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 <event.h>
31 #include <imsg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include "smtpd.h"
38 #include "parser.h"
39 
40 void usage(void);
41 static int show_command_output(struct imsg*);
42 static int show_stats_output(struct imsg *);
43 
44 int proctype;
45 struct imsgbuf	*ibuf;
46 
47 int sendmail = 0;
48 extern char *__progname;
49 
50 __dead void
51 usage(void)
52 {
53 	extern char *__progname;
54 
55 	if (sendmail)
56 		fprintf(stderr, "usage: %s [-tv] [-f from] [-F name] to ..\n",
57 		    __progname);
58 	else
59 		fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
60 	exit(1);
61 }
62 
63 int
64 main(int argc, char *argv[])
65 {
66 	struct sockaddr_un	sun;
67 	struct parse_result	*res = NULL;
68 	struct imsg		imsg;
69 	int			ctl_sock;
70 	int			done = 0;
71 	int			n, verbose = 0;
72 
73 	/* parse options */
74 	if (strcmp(__progname, "sendmail") == 0 || strcmp(__progname, "send-mail") == 0)
75 		sendmail = 1;
76 	else if (strcmp(__progname, "mailq") == 0) {
77 		if (geteuid())
78 			errx(1, "need root privileges");
79 		show_queue(PATH_QUEUE, 0);
80 		return 0;
81 	} else if (strcmp(__progname, "smtpctl") == 0) {
82 		/* check for root privileges */
83 		if (geteuid())
84 			errx(1, "need root privileges");
85 
86 		if ((res = parse(argc - 1, argv + 1)) == NULL)
87 			exit(1);
88 
89 		/* handle "disconnected" commands */
90 		switch (res->action) {
91 		case SHOW_QUEUE:
92 			show_queue(PATH_QUEUE, 0);
93 			break;
94 		case SHOW_RUNQUEUE:
95 			break;
96 		default:
97 			goto connected;
98 		}
99 		return 0;
100 	} else
101 		errx(1, "unsupported mode");
102 
103 connected:
104 	/* connect to smtpd control socket */
105 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
106 		err(1, "socket");
107 
108 	bzero(&sun, sizeof(sun));
109 	sun.sun_family = AF_UNIX;
110 	strlcpy(sun.sun_path, SMTPD_SOCKET, sizeof(sun.sun_path));
111 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
112 		if (sendmail)
113 			return enqueue_offline(argc, argv);
114 		err(1, "connect: %s", SMTPD_SOCKET);
115 	}
116 
117 	if ((ibuf = calloc(1, sizeof(struct imsgbuf))) == NULL)
118 		err(1, NULL);
119 	imsg_init(ibuf, ctl_sock);
120 
121 	if (sendmail)
122 		return enqueue(argc, argv);
123 
124 	/* process user request */
125 	switch (res->action) {
126 	case NONE:
127 		usage();
128 		/* not reached */
129 	case SHUTDOWN:
130 		imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0);
131 		break;
132 	case PAUSE_MDA:
133 		imsg_compose(ibuf, IMSG_QUEUE_PAUSE_LOCAL, 0, 0, -1, NULL, 0);
134 		break;
135 	case PAUSE_MTA:
136 		imsg_compose(ibuf, IMSG_QUEUE_PAUSE_OUTGOING, 0, 0, -1, NULL, 0);
137 		break;
138 	case PAUSE_SMTP:
139 		imsg_compose(ibuf, IMSG_SMTP_PAUSE, 0, 0, -1, NULL, 0);
140 		break;
141 	case RESUME_MDA:
142 		imsg_compose(ibuf, IMSG_QUEUE_RESUME_LOCAL, 0, 0, -1, NULL, 0);
143 		break;
144 	case RESUME_MTA:
145 		imsg_compose(ibuf, IMSG_QUEUE_RESUME_OUTGOING, 0, 0, -1, NULL, 0);
146 		break;
147 	case RESUME_SMTP:
148 		imsg_compose(ibuf, IMSG_SMTP_RESUME, 0, 0, -1, NULL, 0);
149 		break;
150 	case SHOW_STATS:
151 		imsg_compose(ibuf, IMSG_STATS, 0, 0, -1, NULL, 0);
152 		break;
153 	case MONITOR:
154 		/* XXX */
155 		break;
156 	case LOG_VERBOSE:
157 		verbose = 1;
158 		/* FALLTHROUGH */
159 	case LOG_BRIEF:
160 		imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &verbose,
161 		    sizeof(verbose));
162 		printf("logging request sent.\n");
163 		done = 1;
164 		break;
165 	default:
166 		err(1, "unknown request (%d)", res->action);
167 	}
168 
169 	while (ibuf->w.queued)
170 		if (msgbuf_write(&ibuf->w) < 0)
171 			err(1, "write error");
172 
173 	while (!done) {
174 		if ((n = imsg_read(ibuf)) == -1)
175 			errx(1, "imsg_read error");
176 		if (n == 0)
177 			errx(1, "pipe closed");
178 
179 		while (!done) {
180 			if ((n = imsg_get(ibuf, &imsg)) == -1)
181 				errx(1, "imsg_get error");
182 			if (n == 0)
183 				break;
184 			switch(res->action) {
185 			/* case RELOAD: */
186 			case SHUTDOWN:
187 			case PAUSE_MDA:
188 			case PAUSE_MTA:
189 			case PAUSE_SMTP:
190 			case RESUME_MDA:
191 			case RESUME_MTA:
192 			case RESUME_SMTP:
193 			case LOG_VERBOSE:
194 			case LOG_BRIEF:
195 				done = show_command_output(&imsg);
196 				break;
197 			case SHOW_STATS:
198 				done = show_stats_output(&imsg);
199 				break;
200 			case NONE:
201 				break;
202 			case MONITOR:
203 				break;
204 			default:
205 				err(1, "unexpected reply (%d)", res->action);
206 			}
207 			/* insert imsg replies switch here */
208 
209 			imsg_free(&imsg);
210 		}
211 	}
212 	close(ctl_sock);
213 	free(ibuf);
214 
215 	return (0);
216 }
217 
218 static int
219 show_command_output(struct imsg *imsg)
220 {
221 	switch (imsg->hdr.type) {
222 	case IMSG_CTL_OK:
223 		printf("command succeeded\n");
224 		break;
225 	case IMSG_CTL_FAIL:
226 		printf("command failed\n");
227 		break;
228 	default:
229 		errx(1, "wrong message in summary: %u", imsg->hdr.type);
230 	}
231 	return (1);
232 }
233 
234 static int
235 show_stats_output(struct imsg *imsg)
236 {
237 	struct stats	*stats;
238 
239 	if (imsg->hdr.type != IMSG_STATS)
240 		errx(1, "show_stats_output: bad hdr type (%d)", imsg->hdr.type);
241 
242 	if (IMSG_DATA_SIZE(imsg) != sizeof(*stats))
243 		errx(1, "show_stats_output: bad data size");
244 
245 	stats = imsg->data;
246 
247 	printf("control.sessions=%zd\n", stats->control.sessions);
248 	printf("control.sessions_active=%zd\n",
249 	    stats->control.sessions_active);
250 	printf("control.sessions_maxactive=%zd\n",
251 	    stats->control.sessions_maxactive);
252 
253 	printf("mda.sessions=%zd\n", stats->mda.sessions);
254 	printf("mda.sessions.active=%zd\n", stats->mda.sessions_active);
255 	printf("mda.sessions.maxactive=%zd\n", stats->mda.sessions_maxactive);
256 
257 	printf("mta.sessions=%zd\n", stats->mta.sessions);
258 	printf("mta.sessions.active=%zd\n", stats->mta.sessions_active);
259 	printf("mta.sessions.maxactive=%zd\n", stats->mta.sessions_maxactive);
260 
261 	printf("lka.queries=%zd\n", stats->lka.queries);
262 	printf("lka.queries.active=%zd\n", stats->lka.queries_active);
263 	printf("lka.queries.maxactive=%zd\n", stats->lka.queries_maxactive);
264 	printf("lka.queries.mx=%zd\n", stats->lka.queries_mx);
265 	printf("lka.queries.host=%zd\n", stats->lka.queries_host);
266 	printf("lka.queries.cname=%zd\n", stats->lka.queries_cname);
267 	printf("lka.queries.failure=%zd\n", stats->lka.queries_failure);
268 
269 	printf("parent.uptime=%d\n", time(NULL) - stats->parent.start);
270 
271 	printf("queue.inserts.local=%zd\n", stats->queue.inserts_local);
272 	printf("queue.inserts.remote=%zd\n", stats->queue.inserts_remote);
273 
274 	printf("runner.active=%zd\n", stats->runner.active);
275 	printf("runner.maxactive=%zd\n", stats->runner.maxactive);
276 	printf("runner.bounces=%zd\n", stats->runner.bounces);
277 	printf("runner.bounces.active=%zd\n", stats->runner.bounces_active);
278 	printf("runner.bounces.maxactive=%zd\n",
279 	    stats->runner.bounces_maxactive);
280 
281 	printf("ramqueue.hosts=%zd\n", stats->ramqueue.hosts);
282 	printf("ramqueue.batches=%zd\n", stats->ramqueue.batches);
283 	printf("ramqueue.envelopes=%zd\n", stats->ramqueue.envelopes);
284 	printf("ramqueue.hosts.max=%zd\n", stats->ramqueue.hosts_max);
285 	printf("ramqueue.batches.max=%zd\n", stats->ramqueue.batches_max);
286 	printf("ramqueue.envelopes.max=%zd\n", stats->ramqueue.envelopes_max);
287 	printf("ramqueue.size=%zd\n",
288 	    stats->ramqueue.hosts * sizeof(struct ramqueue_host) +
289 	    stats->ramqueue.batches * sizeof(struct ramqueue_batch) +
290 	    stats->ramqueue.envelopes * sizeof(struct ramqueue_envelope));
291 
292 	printf("smtp.errors.delays=%zd\n", stats->smtp.delays);
293 	printf("smtp.errors.linetoolong=%zd\n", stats->smtp.linetoolong);
294 	printf("smtp.errors.read_eof=%zd\n", stats->smtp.read_eof);
295 	printf("smtp.errors.read_system=%zd\n", stats->smtp.read_error);
296 	printf("smtp.errors.read_timeout=%zd\n", stats->smtp.read_timeout);
297 	printf("smtp.errors.tempfail=%zd\n", stats->smtp.tempfail);
298 	printf("smtp.errors.toofast=%zd\n", stats->smtp.toofast);
299 	printf("smtp.errors.write_eof=%zd\n", stats->smtp.write_eof);
300 	printf("smtp.errors.write_system=%zd\n", stats->smtp.write_error);
301 	printf("smtp.errors.write_timeout=%zd\n", stats->smtp.write_timeout);
302 
303 	printf("smtp.sessions.inet4=%zd\n", stats->smtp.sessions_inet4);
304 	printf("smtp.sessions.inet6=%zd\n", stats->smtp.sessions_inet6);
305 
306 	printf("smtp.sessions=%zd\n", stats->smtp.sessions);
307 	printf("smtp.sessions.aborted=%zd\n", stats->smtp.read_eof +
308 	    stats->smtp.read_error + stats->smtp.write_eof +
309 	    stats->smtp.write_error);
310 	printf("smtp.sessions.active=%zd\n", stats->smtp.sessions_active);
311 	printf("smtp.sessions.maxactive=%zd\n",
312 	    stats->smtp.sessions_maxactive);
313 	printf("smtp.sessions.timeout=%zd\n", stats->smtp.read_timeout +
314 	    stats->smtp.write_timeout);
315 	printf("smtp.sessions.smtps=%zd\n", stats->smtp.smtps);
316 	printf("smtp.sessions.smtps.active=%zd\n", stats->smtp.smtps_active);
317 	printf("smtp.sessions.smtps.maxactive=%zd\n",
318 	    stats->smtp.smtps_maxactive);
319 	printf("smtp.sessions.starttls=%zd\n", stats->smtp.starttls);
320 	printf("smtp.sessions.starttls.active=%zd\n",
321 	    stats->smtp.starttls_active);
322 	printf("smtp.sessions.starttls.maxactive=%zd\n",
323 	    stats->smtp.starttls_maxactive);
324 
325 	return (1);
326 }
327