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