xref: /openbsd-src/usr.sbin/smtpd/smtpctl.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: smtpctl.c,v 1.24 2009/04/23 08:28:45 jacekm 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 
28 #include <net/if.h>
29 #include <net/if_media.h>
30 #include <net/if_types.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 
34 #include <err.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <event.h>
41 
42 #include "smtpd.h"
43 #include "parser.h"
44 
45 __dead void	usage(void);
46 int		show_command_output(struct imsg*);
47 int		show_stats_output(struct imsg *);
48 
49 /*
50 struct imsgname {
51 	int type;
52 	char *name;
53 	void (*func)(struct imsg *);
54 };
55 
56 struct imsgname imsgs[] = {
57 	{ IMSG_CTL_SHUTDOWN,		"stop",			NULL },
58 	{ IMSG_CONF_RELOAD,		"reload",		NULL },
59 	{ 0,				NULL,			NULL }
60 };
61 struct imsgname imsgunknown = {
62 	-1,				"<unknown>",		NULL
63 };
64 */
65 
66 int proctype;
67 struct imsgbuf	*ibuf;
68 
69 int sendmail = 0;
70 extern char *__progname;
71 
72 __dead void
73 usage(void)
74 {
75 	extern char *__progname;
76 
77 	if (sendmail)
78 		fprintf(stderr, "usage: %s [-tv] [-f from] [-F name] to ..\n",
79 		    __progname);
80 	else
81 		fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
82 	exit(1);
83 }
84 
85 /* dummy function so that smtpctl does not need libevent */
86 void
87 imsg_event_add(struct imsgbuf *i)
88 {
89 	/* nothing */
90 }
91 
92 int
93 main(int argc, char *argv[])
94 {
95 	struct sockaddr_un	sun;
96 	struct parse_result	*res = NULL;
97 	struct imsg		imsg;
98 	int			ctl_sock;
99 	int			done = 0;
100 	int			n;
101 
102 	/* parse options */
103 	if (strcmp(__progname, "sendmail") == 0 || strcmp(__progname, "send-mail") == 0)
104 		sendmail = 1;
105 	else {
106 		/* check for root privileges */
107 		if (geteuid())
108 			errx(1, "need root privileges");
109 
110 		if ((res = parse(argc - 1, argv + 1)) == NULL)
111 			exit(1);
112 
113 		/* handle "disconnected" commands */
114 		switch (res->action) {
115 		case SHOW_QUEUE:
116 			show_queue(PATH_QUEUE, 0);
117 			break;
118 		case SHOW_RUNQUEUE:
119 			show_queue(PATH_RUNQUEUE, 0);
120 			break;
121 		default:
122 			goto connected;
123 		}
124 		return 0;
125 	}
126 
127 connected:
128 	/* connect to relayd control socket */
129 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
130 		err(1, "socket");
131 
132 	bzero(&sun, sizeof(sun));
133 	sun.sun_family = AF_UNIX;
134 	strlcpy(sun.sun_path, SMTPD_SOCKET, sizeof(sun.sun_path));
135 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
136 		if (sendmail)
137 			return enqueue_offline(argc, argv);
138 		err(1, "connect: %s", SMTPD_SOCKET);
139 	}
140 
141 	if ((ibuf = calloc(1, sizeof(struct imsgbuf))) == NULL)
142 		err(1, NULL);
143 	imsg_init(ibuf, ctl_sock, NULL);
144 
145 	if (sendmail)
146 		return enqueue(argc, argv);
147 
148 	/* process user request */
149 	switch (res->action) {
150 	case NONE:
151 		usage();
152 		/* not reached */
153 	case SHUTDOWN:
154 		imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0);
155 		break;
156 	case RELOAD:
157 		imsg_compose(ibuf, IMSG_CONF_RELOAD, 0, 0, -1, NULL, 0);
158 		break;
159 	case PAUSE_MDA:
160 		imsg_compose(ibuf, IMSG_MDA_PAUSE, 0, 0, -1, NULL, 0);
161 		break;
162 	case PAUSE_MTA:
163 		imsg_compose(ibuf, IMSG_MTA_PAUSE, 0, 0, -1, NULL, 0);
164 		break;
165 	case PAUSE_SMTP:
166 		imsg_compose(ibuf, IMSG_SMTP_PAUSE, 0, 0, -1, NULL, 0);
167 		break;
168 	case RESUME_MDA:
169 		imsg_compose(ibuf, IMSG_MDA_RESUME, 0, 0, -1, NULL, 0);
170 		break;
171 	case RESUME_MTA:
172 		imsg_compose(ibuf, IMSG_MDA_RESUME, 0, 0, -1, NULL, 0);
173 		break;
174 	case RESUME_SMTP:
175 		imsg_compose(ibuf, IMSG_SMTP_RESUME, 0, 0, -1, NULL, 0);
176 		break;
177 	case SHOW_STATS:
178 		imsg_compose(ibuf, IMSG_STATS, 0, 0, -1, NULL, 0);
179 		break;
180 	case SCHEDULE: {
181 		struct sched s;
182 
183 		s.fd = -1;
184 		bzero(s.mid, sizeof (s.mid));
185 		strlcpy(s.mid, res->data, sizeof (s.mid));
186 		imsg_compose(ibuf, IMSG_RUNNER_SCHEDULE, 0, 0, -1, &s, sizeof (s));
187 		break;
188 	}
189 	case MONITOR:
190 		/* XXX */
191 		break;
192 	default:
193 		err(1, "unknown request (%d)", res->action);
194 	}
195 
196 	while (ibuf->w.queued)
197 		if (msgbuf_write(&ibuf->w) < 0)
198 			err(1, "write error");
199 
200 	while (!done) {
201 		if ((n = imsg_read(ibuf)) == -1)
202 			errx(1, "imsg_read error");
203 		if (n == 0)
204 			errx(1, "pipe closed");
205 
206 		while (!done) {
207 			if ((n = imsg_get(ibuf, &imsg)) == -1)
208 				errx(1, "imsg_get error");
209 			if (n == 0)
210 				break;
211 			switch(res->action) {
212 			case RELOAD:
213 			case SHUTDOWN:
214 			case SCHEDULE:
215 			case PAUSE_MDA:
216 			case PAUSE_MTA:
217 			case PAUSE_SMTP:
218 			case RESUME_MDA:
219 			case RESUME_MTA:
220 			case RESUME_SMTP:
221 				done = show_command_output(&imsg);
222 				break;
223 			case SHOW_STATS:
224 				done = show_stats_output(&imsg);
225 				break;
226 			case NONE:
227 				break;
228 			case MONITOR:
229 				break;
230 			default:
231 				err(1, "unexpected reply (%d)", res->action);
232 			}
233 			/* insert imsg replies switch here */
234 
235 			imsg_free(&imsg);
236 		}
237 	}
238 	close(ctl_sock);
239 	free(ibuf);
240 
241 	return (0);
242 }
243 
244 int
245 show_command_output(struct imsg *imsg)
246 {
247 	switch (imsg->hdr.type) {
248 	case IMSG_CTL_OK:
249 		printf("command succeeded\n");
250 		break;
251 	case IMSG_CTL_FAIL:
252 		printf("command failed\n");
253 		break;
254 	default:
255 		errx(1, "wrong message in summary: %u", imsg->hdr.type);
256 	}
257 	return (1);
258 }
259 
260 int
261 show_stats_output(struct imsg *imsg)
262 {
263 	static int	 	left = 4;
264 	static struct s_parent	s_parent;
265 	static struct s_queue	s_queue;
266 	static struct s_runner	s_runner;
267 	static struct s_session	s_smtp;
268 
269 	switch (imsg->hdr.type) {
270 	case IMSG_PARENT_STATS:
271 		s_parent = *(struct s_parent *)imsg->data;
272 		break;
273 	case IMSG_QUEUE_STATS:
274 		s_queue = *(struct s_queue *)imsg->data;
275 		break;
276 	case IMSG_RUNNER_STATS:
277 		s_runner = *(struct s_runner *)imsg->data;
278 		break;
279 	case IMSG_SMTP_STATS:
280 		s_smtp = *(struct s_session *)imsg->data;
281 		break;
282 	default:
283 		errx(1, "show_stats_output: bad hdr type (%d)", imsg->hdr.type);
284 	}
285 
286 	left--;
287 	if (left > 0)
288 		return (0);
289 
290 	printf("parent.uptime=%d\n", time(NULL) - s_parent.start);
291 
292 	printf("queue.inserts.local=%zd\n", s_queue.inserts_local);
293 	printf("queue.inserts.remote=%zd\n", s_queue.inserts_remote);
294 
295 	printf("runner.active=%zd\n", s_runner.active);
296 
297 	printf("smtp.sessions=%zd\n", s_smtp.sessions);
298 	printf("smtp.sessions.aborted=%zd\n", s_smtp.aborted);
299 	printf("smtp.sessions.active=%zd\n", s_smtp.sessions_active);
300 	printf("smtp.sessions.timeout=%zd\n", s_smtp.timeout);
301 	printf("smtp.sessions.smtps=%zd\n", s_smtp.smtps);
302 	printf("smtp.sessions.smtps.active=%zd\n", s_smtp.smtps_active);
303 	printf("smtp.sessions.starttls=%zd\n", s_smtp.starttls);
304 	printf("smtp.sessions.starttls.active=%zd\n", s_smtp.starttls_active);
305 
306 	return (1);
307 }
308