1 /* $OpenBSD: enqueue.c,v 1.11 2009/04/05 16:10:42 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/tree.h> 22 #include <sys/param.h> 23 #include <sys/socket.h> 24 #include <sys/stat.h> 25 26 #include <netinet/in.h> 27 #include <arpa/inet.h> 28 29 #include <ctype.h> 30 #include <err.h> 31 #include <errno.h> 32 #include <event.h> 33 #include <pwd.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "smtpd.h" 40 41 extern struct imsgbuf *ibuf; 42 43 __dead void usage(void); 44 int enqueue(int, char **); 45 int enqueue_init(struct message *); 46 int enqueue_add_recipient(struct message *, char *); 47 int enqueue_messagefd(struct message *); 48 int enqueue_write_message(FILE *, FILE *); 49 int enqueue_commit(struct message *); 50 51 int 52 enqueue(int argc, char *argv[]) 53 { 54 int ch; 55 int fd; 56 FILE *fpout; 57 struct message message; 58 char sender[MAX_PATH_SIZE]; 59 60 uid_t uid; 61 char *username; 62 char hostname[MAXHOSTNAMELEN]; 63 struct passwd *pw; 64 65 uid = getuid(); 66 pw = safe_getpwuid(uid); 67 if (pw == NULL) 68 errx(1, "you don't exist, go away."); 69 70 username = pw->pw_name; 71 gethostname(hostname, sizeof(hostname)); 72 73 if (! bsnprintf(sender, sizeof(sender), "%s@%s", username, hostname)) 74 errx(1, "sender address too long."); 75 76 while ((ch = getopt(argc, argv, "f:i")) != -1) { 77 switch (ch) { 78 case 'f': 79 if (strlcpy(sender, optarg, sizeof(sender)) 80 >= sizeof(sender)) 81 errx(1, "sender address too long."); 82 break; 83 case 'i': /* ignore, interface compatibility */ 84 case 'o': 85 break; 86 default: 87 usage(); 88 } 89 } 90 91 argc -= optind; 92 argv += optind; 93 94 bzero(&message, sizeof(struct message)); 95 96 strlcpy(message.session_helo, "localhost", 97 sizeof(message.session_helo)); 98 strlcpy(message.session_hostname, hostname, 99 sizeof(message.session_hostname)); 100 101 /* build sender */ 102 if (! recipient_to_path(&message.sender, sender)) 103 errx(1, "invalid sender address."); 104 105 if (! enqueue_init(&message)) 106 errx(1, "failed to initialize enqueue message."); 107 108 if (argc == 0) 109 errx(1, "no recipient."); 110 111 while (argc--) { 112 if (! enqueue_add_recipient(&message, *argv)) 113 errx(1, "invalid recipient."); 114 ++argv; 115 } 116 117 fd = enqueue_messagefd(&message); 118 if (fd == -1 || (fpout = fdopen(fd, "w")) == NULL) 119 errx(1, "failed to open message file for writing."); 120 121 if (! enqueue_write_message(stdin, fpout)) 122 errx(1, "failed to write message to message file."); 123 124 if (! safe_fclose(fpout)) 125 errx(1, "error while writing to message file."); 126 127 if (! enqueue_commit(&message)) 128 errx(1, "failed to commit message to queue."); 129 130 return 0; 131 } 132 133 int 134 enqueue_add_recipient(struct message *messagep, char *recipient) 135 { 136 char buffer[MAX_PATH_SIZE]; 137 struct message_recipient mr; 138 struct sockaddr_in6 *ssin6; 139 struct sockaddr_in *ssin; 140 struct message message; 141 int done = 0; 142 int n; 143 struct imsg imsg; 144 145 bzero(&mr, sizeof(mr)); 146 147 message = *messagep; 148 149 if (strlcpy(buffer, recipient, sizeof(buffer)) >= sizeof(buffer)) 150 errx(1, "recipient address too long."); 151 152 if (strchr(buffer, '@') == NULL) { 153 if (! bsnprintf(buffer, sizeof(buffer), "%s@%s", 154 buffer, messagep->sender.domain)) 155 errx(1, "recipient address too long."); 156 } 157 158 if (! recipient_to_path(&message.recipient, buffer)) 159 errx(1, "invalid recipient address."); 160 161 message.session_rcpt = message.recipient; 162 163 mr.ss.ss_family = AF_INET6; 164 mr.ss.ss_len = sizeof(*ssin6); 165 ssin6 = (struct sockaddr_in6 *)&mr.ss; 166 if (inet_pton(AF_INET6, "::1", &ssin6->sin6_addr) != 1) { 167 mr.ss.ss_family = AF_INET; 168 mr.ss.ss_len = sizeof(*ssin); 169 ssin = (struct sockaddr_in *)&mr.ss; 170 if (inet_pton(AF_INET, "127.0.0.1", &ssin->sin_addr) != 1) 171 return 0; 172 } 173 message.session_ss = mr.ss; 174 175 mr.path = message.recipient; 176 mr.id = message.session_id; 177 mr.msg = message; 178 mr.msg.flags |= F_MESSAGE_ENQUEUED; 179 180 imsg_compose(ibuf, IMSG_MFA_RCPT, 0, 0, -1, &mr, sizeof (mr)); 181 while (ibuf->w.queued) 182 if (msgbuf_write(&ibuf->w) < 0) 183 err(1, "write error"); 184 185 while (!done) { 186 if ((n = imsg_read(ibuf)) == -1) 187 errx(1, "imsg_read error"); 188 if (n == 0) 189 errx(1, "pipe closed"); 190 191 if ((n = imsg_get(ibuf, &imsg)) == -1) 192 errx(1, "imsg_get error"); 193 194 if (n == 0) 195 continue; 196 197 done = 1; 198 switch (imsg.hdr.type) { 199 case IMSG_CTL_OK: { 200 return 1; 201 } 202 case IMSG_CTL_FAIL: 203 return 0; 204 default: 205 errx(1, "unexpected reply (%d)", imsg.hdr.type); 206 } 207 imsg_free(&imsg); 208 } 209 210 return 1; 211 } 212 213 int 214 enqueue_write_message(FILE *fpin, FILE *fpout) 215 { 216 char *buf, *lbuf; 217 size_t len; 218 219 lbuf = NULL; 220 while ((buf = fgetln(fpin, &len))) { 221 if (buf[len - 1] == '\n') { 222 buf[len - 1] = '\0'; 223 len--; 224 } 225 else { 226 /* EOF without EOL, copy and add the NUL */ 227 if ((lbuf = malloc(len + 1)) == NULL) 228 err(1, NULL); 229 memcpy(lbuf, buf, len); 230 lbuf[len] = '\0'; 231 buf = lbuf; 232 } 233 if (fprintf(fpout, "%s\n", buf) != (int)len + 1) 234 return 0; 235 } 236 free(lbuf); 237 return 1; 238 } 239 240 int 241 enqueue_init(struct message *messagep) 242 { 243 int done = 0; 244 int n; 245 struct imsg imsg; 246 247 imsg_compose(ibuf, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1, messagep, sizeof(*messagep)); 248 while (ibuf->w.queued) 249 if (msgbuf_write(&ibuf->w) < 0) 250 err(1, "write error"); 251 252 while (!done) { 253 if ((n = imsg_read(ibuf)) == -1) 254 errx(1, "imsg_read error"); 255 if (n == 0) 256 errx(1, "pipe closed"); 257 258 if ((n = imsg_get(ibuf, &imsg)) == -1) 259 errx(1, "imsg_get error"); 260 261 if (n == 0) 262 continue; 263 264 done = 1; 265 switch (imsg.hdr.type) { 266 case IMSG_CTL_OK: { 267 struct message *mp; 268 269 mp = imsg.data; 270 messagep->session_id = mp->session_id; 271 strlcpy(messagep->message_id, mp->message_id, 272 sizeof(messagep->message_id)); 273 274 return 1; 275 } 276 case IMSG_CTL_FAIL: 277 return 0; 278 default: 279 err(1, "unexpected reply (%d)", imsg.hdr.type); 280 } 281 imsg_free(&imsg); 282 } 283 284 return 0; 285 } 286 287 int 288 enqueue_messagefd(struct message *messagep) 289 { 290 int done = 0; 291 int n; 292 struct imsg imsg; 293 294 imsg_compose(ibuf, IMSG_QUEUE_MESSAGE_FILE, 0, 0, -1, messagep, sizeof(*messagep)); 295 while (ibuf->w.queued) 296 if (msgbuf_write(&ibuf->w) < 0) 297 err(1, "write error"); 298 299 while (!done) { 300 if ((n = imsg_read(ibuf)) == -1) 301 errx(1, "imsg_read error"); 302 if (n == 0) 303 errx(1, "pipe closed"); 304 305 if ((n = imsg_get(ibuf, &imsg)) == -1) 306 errx(1, "imsg_get error"); 307 308 if (n == 0) 309 continue; 310 311 done = 1; 312 switch (imsg.hdr.type) { 313 case IMSG_CTL_OK: 314 return imsg_get_fd(ibuf, &imsg); 315 case IMSG_CTL_FAIL: 316 return -1; 317 default: 318 err(1, "unexpected reply (%d)", imsg.hdr.type); 319 } 320 imsg_free(&imsg); 321 } 322 323 return -1; 324 } 325 326 327 int 328 enqueue_commit(struct message *messagep) 329 { 330 int done = 0; 331 int n; 332 struct imsg imsg; 333 334 imsg_compose(ibuf, IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, messagep, sizeof(*messagep)); 335 while (ibuf->w.queued) 336 if (msgbuf_write(&ibuf->w) < 0) 337 err(1, "write error"); 338 339 while (!done) { 340 if ((n = imsg_read(ibuf)) == -1) 341 errx(1, "imsg_read error"); 342 if (n == 0) 343 errx(1, "pipe closed"); 344 345 if ((n = imsg_get(ibuf, &imsg)) == -1) 346 errx(1, "imsg_get error"); 347 348 if (n == 0) 349 continue; 350 351 done = 1; 352 switch (imsg.hdr.type) { 353 case IMSG_CTL_OK: { 354 return 1; 355 } 356 case IMSG_CTL_FAIL: { 357 return 0; 358 } 359 default: 360 err(1, "unexpected reply (%d)", imsg.hdr.type); 361 } 362 imsg_free(&imsg); 363 } 364 365 return 0; 366 } 367