xref: /openbsd-src/usr.sbin/smtpd/smtpctl.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: smtpctl.c,v 1.19 2009/03/23 21:48:40 jmc 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 int		enqueue(int, char **);
49 
50 /*
51 struct imsgname {
52 	int type;
53 	char *name;
54 	void (*func)(struct imsg *);
55 };
56 
57 struct imsgname imsgs[] = {
58 	{ IMSG_CTL_SHUTDOWN,		"stop",			NULL },
59 	{ IMSG_CONF_RELOAD,		"reload",		NULL },
60 	{ 0,				NULL,			NULL }
61 };
62 struct imsgname imsgunknown = {
63 	-1,				"<unknown>",		NULL
64 };
65 */
66 
67 int proctype;
68 struct imsgbuf	*ibuf;
69 
70 int sendmail = 0;
71 extern char *__progname;
72 
73 __dead void
74 usage(void)
75 {
76 	extern char *__progname;
77 
78 	if (sendmail)
79 		fprintf(stderr, "usage: %s [-i] rcpt [...]\n", __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 		err(1, "connect: %s", SMTPD_SOCKET);
137 
138 	if ((ibuf = calloc(1, sizeof(struct imsgbuf))) == NULL)
139 		err(1, NULL);
140 	imsg_init(ibuf, ctl_sock, NULL);
141 
142 	if (sendmail)
143 		return enqueue(argc, argv);
144 
145 	/* process user request */
146 	switch (res->action) {
147 	case NONE:
148 		usage();
149 		/* not reached */
150 	case SHUTDOWN:
151 		imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0);
152 		break;
153 	case RELOAD:
154 		imsg_compose(ibuf, IMSG_CONF_RELOAD, 0, 0, -1, NULL, 0);
155 		break;
156 	case PAUSE_MDA:
157 		imsg_compose(ibuf, IMSG_MDA_PAUSE, 0, 0, -1, NULL, 0);
158 		break;
159 	case PAUSE_MTA:
160 		imsg_compose(ibuf, IMSG_MTA_PAUSE, 0, 0, -1, NULL, 0);
161 		break;
162 	case PAUSE_SMTP:
163 		imsg_compose(ibuf, IMSG_SMTP_PAUSE, 0, 0, -1, NULL, 0);
164 		break;
165 	case RESUME_MDA:
166 		imsg_compose(ibuf, IMSG_MDA_RESUME, 0, 0, -1, NULL, 0);
167 		break;
168 	case RESUME_MTA:
169 		imsg_compose(ibuf, IMSG_MDA_RESUME, 0, 0, -1, NULL, 0);
170 		break;
171 	case RESUME_SMTP:
172 		imsg_compose(ibuf, IMSG_SMTP_RESUME, 0, 0, -1, NULL, 0);
173 		break;
174 	case SHOW_STATS:
175 		imsg_compose(ibuf, IMSG_STATS, 0, 0, -1, NULL, 0);
176 		break;
177 	case SCHEDULE: {
178 		struct sched s;
179 
180 		s.fd = -1;
181 		bzero(s.mid, sizeof (s.mid));
182 		strlcpy(s.mid, res->data, sizeof (s.mid));
183 		imsg_compose(ibuf, IMSG_RUNNER_SCHEDULE, 0, 0, -1, &s, sizeof (s));
184 		break;
185 	}
186 	case MONITOR:
187 		/* XXX */
188 		break;
189 	default:
190 		err(1, "unknown request (%d)", res->action);
191 	}
192 
193 	while (ibuf->w.queued)
194 		if (msgbuf_write(&ibuf->w) < 0)
195 			err(1, "write error");
196 
197 	while (!done) {
198 		if ((n = imsg_read(ibuf)) == -1)
199 			errx(1, "imsg_read error");
200 		if (n == 0)
201 			errx(1, "pipe closed");
202 
203 		while (!done) {
204 			if ((n = imsg_get(ibuf, &imsg)) == -1)
205 				errx(1, "imsg_get error");
206 			if (n == 0)
207 				break;
208 			switch(res->action) {
209 			case RELOAD:
210 			case SHUTDOWN:
211 			case SCHEDULE:
212 			case PAUSE_MDA:
213 			case PAUSE_MTA:
214 			case PAUSE_SMTP:
215 			case RESUME_MDA:
216 			case RESUME_MTA:
217 			case RESUME_SMTP:
218 				done = show_command_output(&imsg);
219 				break;
220 			case SHOW_STATS:
221 				done = show_stats_output(&imsg);
222 				break;
223 			case NONE:
224 				break;
225 			case MONITOR:
226 				break;
227 			default:
228 				err(1, "unexpected reply (%d)", res->action);
229 			}
230 			/* insert imsg replies switch here */
231 
232 			imsg_free(&imsg);
233 		}
234 	}
235 	close(ctl_sock);
236 	free(ibuf);
237 
238 	return (0);
239 }
240 
241 int
242 show_command_output(struct imsg *imsg)
243 {
244 	switch (imsg->hdr.type) {
245 	case IMSG_CTL_OK:
246 		printf("command succeeded\n");
247 		break;
248 	case IMSG_CTL_FAIL:
249 		printf("command failed\n");
250 		break;
251 	default:
252 		errx(1, "wrong message in summary: %u", imsg->hdr.type);
253 	}
254 	return (1);
255 }
256 
257 int
258 show_stats_output(struct imsg *imsg)
259 {
260 	static int	 	left = 4;
261 	static struct s_parent	s_parent;
262 	static struct s_queue	s_queue;
263 	static struct s_runner	s_runner;
264 	static struct s_session	s_smtp;
265 
266 	switch (imsg->hdr.type) {
267 	case IMSG_PARENT_STATS:
268 		s_parent = *(struct s_parent *)imsg->data;
269 		break;
270 	case IMSG_QUEUE_STATS:
271 		s_queue = *(struct s_queue *)imsg->data;
272 		break;
273 	case IMSG_RUNNER_STATS:
274 		s_runner = *(struct s_runner *)imsg->data;
275 		break;
276 	case IMSG_SMTP_STATS:
277 		s_smtp = *(struct s_session *)imsg->data;
278 		break;
279 	default:
280 		errx(1, "show_stats_output: bad hdr type (%d)", imsg->hdr.type);
281 	}
282 
283 	left--;
284 	if (left > 0)
285 		return (0);
286 
287 	printf("parent.uptime=%d\n", time(NULL) - s_parent.start);
288 
289 	printf("queue.inserts.local=%zd\n", s_queue.inserts_local);
290 	printf("queue.inserts.remote=%zd\n", s_queue.inserts_remote);
291 
292 	printf("runner.active=%zd\n", s_runner.active);
293 
294 	printf("smtp.sessions=%zd\n", s_smtp.sessions);
295 	printf("smtp.sessions.aborted=%zd\n", s_smtp.aborted);
296 	printf("smtp.sessions.active=%zd\n", s_smtp.sessions_active);
297 	printf("smtp.sessions.ssmtp=%zd\n", s_smtp.ssmtp);
298 	printf("smtp.sessions.ssmtp.active=%zd\n", s_smtp.ssmtp_active);
299 	printf("smtp.sessions.starttls=%zd\n", s_smtp.starttls);
300 	printf("smtp.sessions.starttls.active=%zd\n", s_smtp.starttls_active);
301 
302 	return (1);
303 }
304