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