masqmail

annotate src/smtp_out.c @ 421:f37384470855

Changed lockdir to /var/lock/masqmail; Create lockdir and piddir on startup. Moved the lockdir out of the spool dir. (When /var/lock is a ramdisk we do well to have the lock files there.) Added the new configure option --with-lockdir to change that location. Nontheless, if we run_as_user, then lock files are always stored in the spool dir directly. Instead of installing the lockdir and piddir at installation time, we create them on startup time now if they are missing. This is necessary if lockdir or piddir are a tmpfs.
author markus schnalke <meillo@marmaro.de>
date Wed, 30 May 2012 09:38:38 +0200
parents f122535c589e
children
rev   line source
meillo@367 1 /*
meillo@367 2 ** smtp_out.c
meillo@367 3 ** Copyright (C) 1999-2001 Oliver Kurth
meillo@367 4 ** Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
meillo@367 5 **
meillo@367 6 ** This program is free software; you can redistribute it and/or modify
meillo@367 7 ** it under the terms of the GNU General Public License as published by
meillo@367 8 ** the Free Software Foundation; either version 2 of the License, or
meillo@367 9 ** (at your option) any later version.
meillo@367 10 **
meillo@367 11 ** This program is distributed in the hope that it will be useful,
meillo@367 12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@367 13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
meillo@367 14 ** GNU General Public License for more details.
meillo@367 15 **
meillo@367 16 ** You should have received a copy of the GNU General Public License
meillo@367 17 ** along with this program; if not, write to the Free Software
meillo@367 18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
meillo@367 19 */
meillo@0 20
meillo@0 21 /*
meillo@367 22 ** I always forget these rfc numbers:
meillo@367 23 ** RFC 821 (SMTP)
meillo@367 24 ** RFC 1869 (ESMTP)
meillo@367 25 ** RFC 1870 (ESMTP SIZE)
meillo@367 26 ** RFC 2197 (ESMTP PIPELINE)
meillo@367 27 ** RFC 2554 (ESMTP AUTH)
meillo@0 28 */
meillo@0 29
meillo@0 30 #include "masqmail.h"
meillo@0 31 #include "smtp_out.h"
meillo@0 32 #include "readsock.h"
meillo@0 33
meillo@0 34 #ifdef ENABLE_AUTH
meillo@0 35 #include "md5/md5.h"
meillo@0 36 #include "md5/hmac_md5.h"
meillo@0 37 #include "base64/base64.h"
meillo@0 38 #endif
meillo@0 39
meillo@10 40 void
meillo@366 41 destroy_smtpbase(smtp_base *psb)
meillo@0 42 {
meillo@10 43 fclose(psb->in);
meillo@10 44 fclose(psb->out);
meillo@0 45
meillo@10 46 close(psb->sock);
meillo@0 47
meillo@10 48 if (psb->helo_name)
meillo@10 49 g_free(psb->helo_name);
meillo@10 50 if (psb->buffer)
meillo@10 51 g_free(psb->buffer);
meillo@10 52 if (psb->auth_names)
meillo@10 53 g_strfreev(psb->auth_names);
meillo@0 54
meillo@10 55 if (psb->auth_name)
meillo@10 56 g_free(psb->auth_name);
meillo@10 57 if (psb->auth_login)
meillo@10 58 g_free(psb->auth_login);
meillo@10 59 if (psb->auth_secret)
meillo@10 60 g_free(psb->auth_secret);
meillo@0 61 }
meillo@0 62
meillo@10 63 gchar*
meillo@366 64 set_heloname(smtp_base *psb, gchar *default_name, gboolean do_correct)
meillo@0 65 {
meillo@10 66 struct sockaddr_in sname;
meillo@10 67 int len = sizeof(struct sockaddr_in);
meillo@10 68 struct hostent *host_entry;
meillo@0 69
meillo@10 70 if (do_correct) {
meillo@10 71 getsockname(psb->sock, (struct sockaddr *) (&sname), &len);
meillo@10 72 DEBUG(5) debugf("socket: name.sin_addr = %s\n", inet_ntoa(sname.sin_addr));
meillo@10 73 host_entry = gethostbyaddr((const char *) &(sname.sin_addr), sizeof(sname.sin_addr), AF_INET);
meillo@10 74 if (host_entry) {
meillo@10 75 psb->helo_name = g_strdup(host_entry->h_name);
meillo@10 76 } else {
meillo@367 77 /*
meillo@367 78 ** we failed to look up our own name. Instead of
meillo@367 79 ** giving our local hostname, we may give our IP
meillo@367 80 ** number to show the server that we are at least
meillo@367 81 ** willing to be honest. For the really picky ones.
meillo@367 82 */
meillo@10 83 DEBUG(5) debugf("failed to look up own host name.\n");
meillo@10 84 psb->helo_name = g_strdup_printf("[%s]", inet_ntoa(sname.sin_addr));
meillo@10 85 }
meillo@10 86 DEBUG(5) debugf("helo_name = %s\n", psb->helo_name);
meillo@10 87 }
meillo@10 88 if (psb->helo_name == NULL) {
meillo@10 89 psb->helo_name = g_strdup(default_name);
meillo@10 90 }
meillo@10 91 return psb->helo_name;
meillo@10 92 }
meillo@0 93
meillo@0 94 #ifdef ENABLE_AUTH
meillo@0 95
meillo@10 96 gboolean
meillo@366 97 set_auth(smtp_base *psb, gchar *name, gchar *login, gchar *secret)
meillo@0 98 {
meillo@10 99 if ((strcasecmp(name, "CRAM-MD5") == 0) || (strcasecmp(name, "LOGIN") == 0)) {
meillo@10 100 psb->auth_name = g_strdup(name);
meillo@10 101 psb->auth_login = g_strdup(login);
meillo@10 102 psb->auth_secret = g_strdup(secret);
meillo@10 103
meillo@10 104 return TRUE;
meillo@10 105 }
meillo@10 106 return FALSE;
meillo@0 107 }
meillo@0 108
meillo@0 109 #endif
meillo@0 110
meillo@10 111 static smtp_base*
meillo@10 112 create_smtpbase(gint sock)
meillo@0 113 {
meillo@10 114 gint dup_sock;
meillo@0 115
meillo@10 116 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
meillo@0 117
meillo@10 118 psb->sock = sock;
meillo@0 119
meillo@10 120 psb->use_size = FALSE;
meillo@10 121 psb->use_pipelining = FALSE;
meillo@10 122 psb->use_auth = FALSE;
meillo@0 123
meillo@10 124 psb->max_size = 0;
meillo@10 125 psb->auth_names = NULL;
meillo@0 126
meillo@10 127 psb->buffer = (gchar *) g_malloc(SMTP_BUF_LEN);
meillo@0 128
meillo@10 129 dup_sock = dup(sock);
meillo@10 130 psb->out = fdopen(sock, "w");
meillo@10 131 psb->in = fdopen(dup_sock, "r");
meillo@0 132
meillo@10 133 psb->error = smtp_ok;
meillo@0 134
meillo@10 135 psb->helo_name = NULL;
meillo@0 136
meillo@10 137 psb->auth_name = psb->auth_login = psb->auth_secret = NULL;
meillo@10 138
meillo@10 139 return psb;
meillo@0 140 }
meillo@0 141
meillo@10 142 static gboolean
meillo@366 143 read_response(smtp_base *psb, int timeout)
meillo@0 144 {
meillo@10 145 gint buf_pos = 0;
meillo@10 146 gchar code[5];
meillo@10 147 gint i, len;
meillo@0 148
meillo@10 149 do {
meillo@10 150 len = read_sockline(psb->in, &(psb->buffer[buf_pos]), SMTP_BUF_LEN - buf_pos, timeout, READSOCKL_CHUG);
meillo@10 151 if (len == -3) {
meillo@10 152 psb->error = smtp_timeout;
meillo@10 153 return FALSE;
meillo@10 154 } else if (len == -2) {
meillo@10 155 psb->error = smtp_syntax;
meillo@10 156 return FALSE;
meillo@10 157 } else if (len == -1) {
meillo@10 158 psb->error = smtp_eof;
meillo@10 159 return FALSE;
meillo@10 160 }
meillo@10 161 for (i = 0; i < 4; i++)
meillo@10 162 code[i] = psb->buffer[buf_pos + i];
meillo@15 163 code[i] = '\0';
meillo@10 164 psb->last_code = atoi(code);
meillo@0 165
meillo@10 166 buf_pos += len;
meillo@0 167
meillo@10 168 } while (code[3] == '-');
meillo@177 169 if (psb->buffer) {
meillo@177 170 DEBUG(4) debugf("S: %s\n", psb->buffer);
meillo@177 171 }
meillo@0 172
meillo@10 173 return TRUE;
meillo@0 174 }
meillo@0 175
meillo@10 176 static gboolean
meillo@366 177 check_response(smtp_base *psb, gboolean after_data)
meillo@0 178 {
meillo@10 179 char c = psb->buffer[0];
meillo@0 180
meillo@10 181 if (((c == '2') && !after_data) || ((c == '3') && after_data)) {
meillo@10 182 psb->error = smtp_ok;
meillo@176 183 DEBUG(6) debugf("response OK:'%s' after_data = %d\n", psb->buffer, (int) after_data);
meillo@10 184 return TRUE;
meillo@10 185 } else {
meillo@10 186 if (c == '4')
meillo@10 187 psb->error = smtp_trylater;
meillo@10 188 else if (c == '5')
meillo@10 189 psb->error = smtp_fail;
meillo@10 190 else
meillo@10 191 psb->error = smtp_syntax;
meillo@176 192 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data);
meillo@10 193 return FALSE;
meillo@10 194 }
meillo@0 195 }
meillo@0 196
meillo@10 197 static gchar*
meillo@366 198 get_response_arg(gchar *response)
meillo@0 199 {
meillo@10 200 gchar buf[SMTP_BUF_LEN];
meillo@10 201 gchar *p = response, *q = buf;
meillo@0 202
meillo@10 203 while (*p && (*p != '\n') && isspace(*p))
meillo@10 204 p++;
meillo@10 205 if (*p && (*p != '\n')) {
meillo@10 206 while (*p && (*p != '\n') && (*p != '\r') && (q < buf + SMTP_BUF_LEN - 1))
meillo@10 207 *(q++) = *(p++);
meillo@15 208 *q = '\0';
meillo@10 209 return g_strdup(buf);
meillo@10 210 }
meillo@10 211 return NULL;
meillo@0 212 }
meillo@0 213
meillo@10 214 static gboolean
meillo@366 215 check_helo_response(smtp_base *psb)
meillo@0 216 {
meillo@222 217 gchar *ptr;
meillo@0 218
meillo@10 219 if (!check_response(psb, FALSE))
meillo@10 220 return FALSE;
meillo@0 221
meillo@222 222 if (psb->last_code == 220) {
meillo@222 223 logwrite(LOG_NOTICE, "received a 220 greeting after sending EHLO,\n");
meillo@222 224 logwrite(LOG_NOTICE, "please remove `instant_helo' from your route config\n");
meillo@222 225 /* read the next response, cause that's the actual helo response */
meillo@222 226 if (!read_response(psb, SMTP_CMD_TIMEOUT) || !check_response(psb, FALSE)) {
meillo@222 227 return FALSE;
meillo@222 228 }
meillo@222 229 }
meillo@222 230
meillo@222 231 ptr = psb->buffer;
meillo@222 232
meillo@10 233 while (*ptr) {
meillo@10 234 if (strncasecmp(&(ptr[4]), "SIZE", 4) == 0) {
meillo@10 235 gchar *arg;
meillo@10 236 psb->use_size = TRUE;
meillo@10 237 arg = get_response_arg(&(ptr[8]));
meillo@10 238 if (arg) {
meillo@10 239 psb->max_size = atoi(arg);
meillo@10 240 g_free(arg);
meillo@10 241 }
meillo@10 242 }
meillo@0 243
meillo@10 244 if (strncasecmp(&(ptr[4]), "PIPELINING", 10) == 0)
meillo@10 245 psb->use_pipelining = TRUE;
meillo@0 246
meillo@10 247 if (strncasecmp(&(ptr[4]), "AUTH", 4) == 0) {
meillo@10 248 if ((ptr[8] == ' ') || (ptr[8] == '=') || (ptr[8] == '\t')) { /* not sure about '\t' */
meillo@10 249 gchar *arg;
meillo@10 250 psb->use_auth = TRUE;
meillo@10 251 arg = get_response_arg(&(ptr[9])); /* after several years I finally learnt to count */
meillo@10 252 if (arg) {
meillo@10 253 psb->auth_names = g_strsplit(arg, " ", 0);
meillo@10 254 g_free(arg);
meillo@10 255
meillo@10 256 DEBUG(4) {
meillo@10 257 gint i = 0;
meillo@114 258 debugf("in check_helo_response()\n");
meillo@10 259 while (psb->auth_names[i]) {
meillo@114 260 debugf(" offered AUTH %s\n", psb->auth_names[i]);
meillo@10 261 i++;
meillo@10 262 }
meillo@10 263 }
meillo@10 264 }
meillo@10 265 }
meillo@10 266 }
meillo@10 267
meillo@10 268 while (*ptr != '\n')
meillo@10 269 ptr++;
meillo@10 270 ptr++;
meillo@0 271 }
meillo@0 272
meillo@10 273 DEBUG(4) {
meillo@114 274 debugf(" %s\n", psb->use_size ? "uses SIZE" : "no size");
meillo@114 275 debugf(" %s\n", psb->use_pipelining ? "uses PIPELINING" : "no pipelining");
meillo@114 276 debugf(" %s\n", psb->use_auth ? "uses AUTH" : "no auth");
meillo@10 277 }
meillo@0 278
meillo@10 279 return TRUE;
meillo@0 280 }
meillo@0 281
meillo@246 282 /*
meillo@367 283 ** We first try EHLO, but if it fails HELO in a second fall back try.
meillo@367 284 ** This is what is requested by RFC 2821 (sec 3.2):
meillo@367 285 **
meillo@367 286 ** Once the server has sent the welcoming message and
meillo@367 287 ** the client has received it, the client normally sends
meillo@367 288 ** the EHLO command to the server, [...]
meillo@367 289 ** For a particular connection attempt, if the server
meillo@367 290 ** returns a "command not recognized" response to EHLO,
meillo@367 291 ** the client SHOULD be able to fall back and send HELO.
meillo@367 292 **
meillo@367 293 ** Up to and including version 0.3.0 masqmail used ESMTP only if the
meillo@367 294 ** string ``ESMTP'' appeared within the server's greeting message. This
meillo@367 295 ** made it impossible to use AUTH with servers that would send odd
meillo@367 296 ** greeting messages.
meillo@246 297 */
meillo@10 298 static gboolean
meillo@366 299 smtp_helo(smtp_base *psb, gchar *helo)
meillo@0 300 {
meillo@246 301 fprintf(psb->out, "EHLO %s\r\n", helo);
meillo@246 302 fflush(psb->out);
meillo@246 303 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
meillo@0 304
meillo@246 305 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
meillo@246 306 return FALSE;
meillo@246 307 }
meillo@246 308 if (check_helo_response(psb)) {
meillo@246 309 DEBUG(4) debugf("uses esmtp\n");
meillo@246 310 return TRUE;
meillo@246 311 }
meillo@0 312
meillo@246 313 if (psb->error != smtp_fail) {
meillo@246 314 return FALSE;
meillo@246 315 }
meillo@0 316
meillo@367 317 /*
meillo@367 318 ** our guess that server understands EHLO could have been wrong,
meillo@367 319 ** try again with HELO
meillo@367 320 */
meillo@0 321
meillo@246 322 fprintf(psb->out, "HELO %s\r\n", helo);
meillo@246 323 fflush(psb->out);
meillo@246 324 DEBUG(4) debugf("C: HELO %s\r\n", helo);
meillo@0 325
meillo@246 326 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
meillo@246 327 return FALSE;
meillo@246 328 }
meillo@246 329 if (check_helo_response(psb)) {
meillo@246 330 DEBUG(4) debugf("uses smtp\n");
meillo@246 331 return TRUE;
meillo@246 332 }
meillo@10 333
meillo@246 334 /* what sort of server ist THAT ?! give up... */
meillo@246 335 return FALSE;
meillo@0 336 }
meillo@0 337
meillo@10 338 static void
meillo@366 339 smtp_cmd_mailfrom(smtp_base *psb, address *return_path, guint size)
meillo@0 340 {
meillo@10 341 if (psb->use_size) {
meillo@10 342 fprintf(psb->out, "MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
meillo@10 343 fflush(psb->out);
meillo@0 344
meillo@177 345 DEBUG(4) debugf("C: MAIL FROM:%s SIZE=%d\r\n", addr_string(return_path), size);
meillo@0 346
meillo@10 347 } else {
meillo@10 348 fprintf(psb->out, "MAIL FROM:%s\r\n", addr_string(return_path));
meillo@10 349 fflush(psb->out);
meillo@0 350
meillo@177 351 DEBUG(4) debugf("C: MAIL FROM:%s\r\n", addr_string(return_path));
meillo@10 352 }
meillo@0 353 }
meillo@0 354
meillo@10 355 static void
meillo@366 356 smtp_cmd_rcptto(smtp_base *psb, address *rcpt)
meillo@0 357 {
meillo@10 358 fprintf(psb->out, "RCPT TO:%s\r\n", addr_string(rcpt));
meillo@10 359 fflush(psb->out);
meillo@177 360 DEBUG(4) debugf("C: RCPT TO:%s\n", addr_string(rcpt));
meillo@0 361 }
meillo@0 362
meillo@10 363 static void
meillo@366 364 send_data_line(smtp_base *psb, gchar *data)
meillo@0 365 {
meillo@367 366 /*
meillo@367 367 ** According to RFC 821 each line should be terminated with CRLF.
meillo@367 368 ** Since a dot on a line itself marks the end of data, each line
meillo@367 369 ** beginning with a dot is prepended with another dot.
meillo@367 370 */
meillo@10 371 gchar *ptr;
meillo@367 372 gboolean new_line = TRUE; /* previous versions assumed that each item was exactly one line. This is no longer the case */
meillo@0 373
meillo@10 374 ptr = data;
meillo@10 375 while (*ptr) {
meillo@10 376 int c = (int) (*ptr);
meillo@119 377 if (c == '.' && new_line) {
meillo@119 378 /* dot-stuffing */
meillo@119 379 putc('.', psb->out);
meillo@119 380 }
meillo@10 381 if (c == '\n') {
meillo@119 382 /* CRLF line terminators */
meillo@10 383 putc('\r', psb->out);
meillo@10 384 putc('\n', psb->out);
meillo@10 385 new_line = TRUE;
meillo@10 386 } else {
meillo@10 387 putc(c, psb->out);
meillo@10 388 new_line = FALSE;
meillo@10 389 }
meillo@10 390 ptr++;
meillo@10 391 }
meillo@0 392 }
meillo@0 393
meillo@10 394 static void
meillo@366 395 send_header(smtp_base *psb, GList *hdr_list)
meillo@0 396 {
meillo@10 397 GList *node;
meillo@10 398 gint num_hdrs = 0;
meillo@0 399
meillo@10 400 /* header */
meillo@10 401 if (hdr_list) {
meillo@10 402 foreach(hdr_list, node) {
meillo@10 403 if (node->data) {
meillo@10 404 header *hdr = (header *) (node->data);
meillo@10 405 if (hdr->header) {
meillo@10 406 send_data_line(psb, hdr->header);
meillo@10 407 num_hdrs++;
meillo@10 408 }
meillo@10 409 }
meillo@10 410 }
meillo@0 411 }
meillo@0 412
meillo@10 413 /* empty line separating headers from data: */
meillo@10 414 putc('\r', psb->out);
meillo@10 415 putc('\n', psb->out);
meillo@0 416
meillo@10 417 DEBUG(4) debugf("sent %d headers\n", num_hdrs);
meillo@0 418 }
meillo@0 419
meillo@10 420 static void
meillo@366 421 send_data(smtp_base *psb, message *msg)
meillo@0 422 {
meillo@10 423 GList *node;
meillo@10 424 gint num_lines = 0;
meillo@0 425
meillo@10 426 /* data */
meillo@10 427 if (msg->data_list) {
meillo@10 428 for (node = g_list_first(msg->data_list); node; node = g_list_next(node)) {
meillo@10 429 if (node->data) {
meillo@10 430 send_data_line(psb, node->data);
meillo@10 431 num_lines++;
meillo@10 432 }
meillo@10 433 }
meillo@10 434 }
meillo@0 435
meillo@10 436 DEBUG(4) debugf("sent %d lines of data\n", num_lines);
meillo@0 437
meillo@10 438 fprintf(psb->out, ".\r\n");
meillo@10 439 fflush(psb->out);
meillo@177 440 DEBUG(4) debugf("C: .\n");
meillo@0 441 }
meillo@0 442
meillo@10 443 void
meillo@366 444 smtp_out_mark_rcpts(smtp_base *psb, GList *rcpt_list)
meillo@0 445 {
meillo@10 446 GList *rcpt_node;
meillo@10 447 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
meillo@10 448 address *rcpt = (address *) (rcpt_node->data);
meillo@0 449
meillo@10 450 addr_unmark_delivered(rcpt);
meillo@0 451
meillo@10 452 if ((psb->error == smtp_trylater) || (psb->error == smtp_timeout) || (psb->error == smtp_eof)) {
meillo@10 453 addr_mark_defered(rcpt);
meillo@10 454 } else {
meillo@10 455 addr_mark_failed(rcpt);
meillo@10 456 }
meillo@10 457 }
meillo@0 458 }
meillo@0 459
meillo@10 460 void
meillo@366 461 smtp_out_log_failure(smtp_base *psb, message *msg)
meillo@0 462 {
meillo@10 463 gchar *err_str;
meillo@0 464
meillo@10 465 if (psb->error == smtp_timeout)
meillo@10 466 err_str = g_strdup("connection timed out.");
meillo@10 467 else if (psb->error == smtp_eof)
meillo@10 468 err_str = g_strdup("connection terminated prematurely.");
meillo@10 469 else if (psb->error == smtp_syntax)
meillo@10 470 err_str = g_strdup_printf("got unexpected response: %s", psb->buffer);
meillo@10 471 else if (psb->error == smtp_cancel)
meillo@10 472 err_str = g_strdup("delivery was canceled.\n");
meillo@10 473 else
meillo@10 474 /* error message should still be in the buffer */
meillo@10 475 err_str = g_strdup_printf("failed: %s\n", psb->buffer);
meillo@0 476
meillo@10 477 if (msg == NULL)
meillo@10 478 logwrite(LOG_NOTICE, "host=%s %s\n", psb->remote_host, err_str);
meillo@10 479 else
meillo@10 480 logwrite(LOG_NOTICE, "%s == host=%s %s\n", msg->uid, psb->remote_host, err_str);
meillo@0 481
meillo@10 482 g_free(err_str);
meillo@0 483 }
meillo@0 484
meillo@10 485 smtp_base*
meillo@366 486 smtp_out_open(gchar *host, gint port, GList *resolve_list)
meillo@0 487 {
meillo@10 488 smtp_base *psb;
meillo@10 489 gint sock;
meillo@10 490 mxip_addr *addr;
meillo@0 491
meillo@10 492 DEBUG(5) debugf("smtp_out_open entered, host = %s\n", host);
meillo@0 493
meillo@10 494 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
meillo@10 495 /* create structure to hold status data: */
meillo@10 496 psb = create_smtpbase(sock);
meillo@10 497 psb->remote_host = addr->name;
meillo@0 498
meillo@10 499 DEBUG(5) {
meillo@10 500 struct sockaddr_in name;
meillo@10 501 int len = sizeof(struct sockaddr);
meillo@10 502 getsockname(sock, (struct sockaddr *) (&name), &len);
meillo@10 503 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
meillo@10 504 }
meillo@10 505 return psb;
meillo@10 506 } else {
meillo@10 507 DEBUG(5) debugf("connect_resolvelist failed: %s %s\n", strerror(errno), hstrerror(h_errno));
meillo@10 508 }
meillo@0 509
meillo@10 510 return NULL;
meillo@0 511 }
meillo@0 512
meillo@10 513 smtp_base*
meillo@372 514 smtp_out_open_child(gchar *cmd)
meillo@0 515 {
meillo@10 516 smtp_base *psb;
meillo@10 517 gint sock;
meillo@0 518
meillo@10 519 DEBUG(5) debugf("smtp_out_open_child entered, cmd = %s\n", cmd);
meillo@10 520 sock = child(cmd);
meillo@371 521 if (sock <= 0) {
meillo@371 522 return NULL;
meillo@371 523 }
meillo@371 524 psb = create_smtpbase(sock);
meillo@371 525 psb->remote_host = NULL;
meillo@0 526
meillo@371 527 return psb;
meillo@0 528 }
meillo@0 529
meillo@10 530 gboolean
meillo@366 531 smtp_out_rset(smtp_base *psb)
meillo@0 532 {
meillo@10 533 gboolean ok;
meillo@0 534
meillo@10 535 fprintf(psb->out, "RSET\r\n");
meillo@10 536 fflush(psb->out);
meillo@177 537 DEBUG(4) debugf("C: RSET\n");
meillo@0 538
meillo@10 539 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
meillo@10 540 if (check_response(psb, FALSE))
meillo@10 541 return TRUE;
meillo@0 542
meillo@10 543 smtp_out_log_failure(psb, NULL);
meillo@10 544
meillo@10 545 return FALSE;
meillo@0 546 }
meillo@0 547
meillo@0 548 #ifdef ENABLE_AUTH
meillo@0 549
meillo@10 550 static gboolean
meillo@366 551 smtp_out_auth_cram_md5(smtp_base *psb)
meillo@0 552 {
meillo@10 553 gboolean ok = FALSE;
meillo@0 554
meillo@177 555 fprintf(psb->out, "C: AUTH CRAM-MD5\r\n");
meillo@10 556 fflush(psb->out);
meillo@10 557 DEBUG(4) debugf("AUTH CRAM-MD5\n");
meillo@10 558 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
meillo@10 559 if ((ok = check_response(psb, TRUE))) {
meillo@10 560 gchar *chall64 = get_response_arg(&(psb->buffer[4]));
meillo@10 561 gint chall_size;
meillo@10 562 gchar *chall = base64_decode(chall64, &chall_size);
meillo@10 563 guchar digest[16], *reply64, *reply;
meillo@10 564 gchar digest_string[33];
meillo@10 565 gint i;
meillo@10 566
meillo@114 567 DEBUG(5) debugf("smtp_out_auth_cram_md5():\n");
meillo@114 568 DEBUG(5) debugf(" encoded challenge = %s\n", chall64);
meillo@114 569 DEBUG(5) debugf(" decoded challenge = %s, size = %d\n", chall, chall_size);
meillo@114 570 DEBUG(5) debugf(" secret = %s\n", psb->auth_secret);
meillo@10 571
meillo@10 572 hmac_md5(chall, chall_size, psb->auth_secret, strlen(psb->auth_secret), digest);
meillo@10 573 for (i = 0; i < 16; i++)
meillo@10 574 sprintf(&(digest_string[i + i]), "%02x", (unsigned int) (digest[i]));
meillo@15 575 digest_string[32] = '\0';
meillo@10 576
meillo@114 577 DEBUG(5) debugf(" digest = %s\n", digest_string);
meillo@10 578
meillo@10 579 reply = g_strdup_printf("%s %s", psb->auth_login, digest_string);
meillo@114 580 DEBUG(5) debugf(" unencoded reply = %s\n", reply);
meillo@10 581
meillo@10 582 reply64 = base64_encode(reply, strlen(reply));
meillo@114 583 DEBUG(5) debugf(" encoded reply = %s\n", reply64);
meillo@10 584
meillo@10 585 fprintf(psb->out, "%s\r\n", reply64);
meillo@10 586 fflush(psb->out);
meillo@177 587 DEBUG(6) debugf(" reply64 = %s\n", reply64);
meillo@177 588 DEBUG(6) debugf("C: %s\n", reply64);
meillo@10 589
meillo@10 590 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
meillo@10 591 ok = check_response(psb, FALSE);
meillo@10 592
meillo@10 593 g_free(reply64);
meillo@10 594 g_free(reply);
meillo@10 595 g_free(chall);
meillo@10 596 g_free(chall64);
meillo@10 597 }
meillo@10 598 }
meillo@10 599 return ok;
meillo@0 600 }
meillo@0 601
meillo@10 602 static gboolean
meillo@366 603 smtp_out_auth_login(smtp_base *psb)
meillo@0 604 {
meillo@10 605 gboolean ok = FALSE;
meillo@10 606 fprintf(psb->out, "AUTH LOGIN\r\n");
meillo@10 607 fflush(psb->out);
meillo@177 608 DEBUG(4) debugf("C: AUTH LOGIN\r\n");
meillo@10 609 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
meillo@10 610 if ((ok = check_response(psb, TRUE))) {
meillo@10 611 gchar *resp64;
meillo@10 612 guchar *resp;
meillo@10 613 gint resp_size;
meillo@10 614 gchar *reply64;
meillo@10 615
meillo@114 616 DEBUG(5) debugf("smtp_out_auth_login():\n");
meillo@10 617 resp64 = get_response_arg(&(psb->buffer[4]));
meillo@312 618 DEBUG(5) debugf(" encoded response = `%s'\n", resp64);
meillo@10 619 resp = base64_decode(resp64, &resp_size);
meillo@10 620 g_free(resp64);
meillo@312 621 DEBUG(5) debugf(" decoded response = `%s', size = %d\n", resp, resp_size);
meillo@10 622 g_free(resp);
meillo@10 623 reply64 = base64_encode(psb->auth_login, strlen(psb->auth_login));
meillo@10 624 fprintf(psb->out, "%s\r\n", reply64);
meillo@10 625 fflush(psb->out);
meillo@177 626 DEBUG(6) debugf("C: %s\n", reply64);
meillo@10 627 g_free(reply64);
meillo@10 628 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
meillo@10 629 if ((ok = check_response(psb, TRUE))) {
meillo@10 630 resp64 = get_response_arg(&(psb->buffer[4]));
meillo@312 631 DEBUG(5) debugf(" encoded response = `%s'\n", resp64);
meillo@10 632 resp = base64_decode(resp64, &resp_size);
meillo@10 633 g_free(resp64);
meillo@312 634 DEBUG(5) debugf(" decoded response = `%s', size = %d\n", resp, resp_size);
meillo@10 635 g_free(resp);
meillo@10 636 reply64 = base64_encode(psb->auth_secret, strlen(psb->auth_secret));
meillo@10 637 fprintf(psb->out, "%s\r\n", reply64);
meillo@10 638 fflush(psb->out);
meillo@177 639 DEBUG(6) debugf("C: %s\n", reply64);
meillo@10 640 g_free(reply64);
meillo@10 641 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
meillo@10 642 ok = check_response(psb, FALSE);
meillo@10 643 }
meillo@10 644 }
meillo@10 645 }
meillo@0 646 }
meillo@10 647 return ok;
meillo@0 648 }
meillo@0 649
meillo@10 650 gboolean
meillo@366 651 smtp_out_auth(smtp_base *psb)
meillo@0 652 {
meillo@10 653 gboolean ok = FALSE;
meillo@10 654 gint i = 0;
meillo@10 655 while (psb->auth_names[i]) {
meillo@10 656 if (strcasecmp(psb->auth_names[i], psb->auth_name) == 0)
meillo@10 657 break;
meillo@10 658 i++;
meillo@10 659 }
meillo@10 660 if (psb->auth_names[i]) {
meillo@10 661 if (strcasecmp(psb->auth_name, "cram-md5") == 0) {
meillo@10 662 smtp_out_auth_cram_md5(psb);
meillo@10 663 } else if (strcasecmp(psb->auth_name, "login") == 0) {
meillo@10 664 smtp_out_auth_login(psb);
meillo@10 665 } else {
meillo@10 666 logwrite(LOG_ERR, "auth method %s not supported\n", psb->auth_name);
meillo@10 667 }
meillo@10 668 } else {
meillo@10 669 logwrite(LOG_ERR, "no auth method %s found.\n", psb->auth_name);
meillo@10 670 }
meillo@10 671 return ok;
meillo@0 672 }
meillo@0 673
meillo@0 674 #endif
meillo@0 675
meillo@10 676 gboolean
meillo@366 677 smtp_out_init(smtp_base *psb, gboolean instant_helo)
meillo@0 678 {
meillo@10 679 gboolean ok;
meillo@0 680
meillo@222 681 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
meillo@10 682
meillo@246 683 if (!instant_helo) {
meillo@222 684 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
meillo@246 685 ok = check_response(psb, FALSE);
meillo@222 686 }
meillo@222 687 if (!ok) {
meillo@222 688 smtp_out_log_failure(psb, NULL);
meillo@222 689 return ok;
meillo@222 690 }
meillo@222 691 }
meillo@222 692
meillo@222 693 if ((ok = smtp_helo(psb, psb->helo_name))) {
meillo@0 694 #ifdef ENABLE_AUTH
meillo@222 695 if (psb->auth_name && psb->use_auth) {
meillo@222 696 /* we completely disregard the response of server here. If
meillo@222 697 authentication fails, the server will complain later
meillo@222 698 anyway. I know, this is not polite... */
meillo@222 699 smtp_out_auth(psb);
meillo@222 700 }
meillo@10 701 #endif
meillo@0 702 }
meillo@10 703 if (!ok)
meillo@10 704 smtp_out_log_failure(psb, NULL);
meillo@10 705 return ok;
meillo@0 706 }
meillo@0 707
meillo@10 708 gint
meillo@367 709 smtp_out_msg(smtp_base *psb, message *msg, address *return_path,
meillo@367 710 GList *rcpt_list, GList *hdr_list)
meillo@0 711 {
meillo@10 712 gint i, size;
meillo@10 713 gboolean ok = TRUE;
meillo@10 714 int rcpt_cnt;
meillo@10 715 int rcpt_accept = 0;
meillo@0 716
meillo@10 717 DEBUG(5) debugf("smtp_out_msg entered\n");
meillo@0 718
meillo@10 719 /* defaults: */
meillo@10 720 if (return_path == NULL)
meillo@10 721 return_path = msg->return_path;
meillo@10 722 if (hdr_list == NULL)
meillo@10 723 hdr_list = msg->hdr_list;
meillo@10 724 if (rcpt_list == NULL)
meillo@10 725 rcpt_list = msg->rcpt_list;
meillo@10 726 rcpt_cnt = g_list_length(rcpt_list);
meillo@0 727
meillo@10 728 size = msg_calc_size(msg, TRUE);
meillo@0 729
meillo@10 730 /* respect maximum size given by server: */
meillo@10 731 if ((psb->max_size > 0) && (size > psb->max_size)) {
meillo@114 732 logwrite(LOG_WARNING, "%s == host=%s message size (%d) > "
meillo@114 733 "fixed maximum message size of server (%d)",
meillo@10 734 msg->uid, psb->remote_host, size, psb->max_size);
meillo@10 735 psb->error = smtp_cancel;
meillo@10 736 ok = FALSE;
meillo@10 737 }
meillo@0 738
meillo@10 739 if (ok) {
meillo@367 740 /*
meillo@367 741 ** pretend the message is a bit larger,
meillo@367 742 ** just in case the size calculation is buggy
meillo@367 743 */
meillo@119 744 smtp_cmd_mailfrom(psb, return_path, psb->use_size ? size+SMTP_SIZE_ADD : 0);
meillo@0 745
meillo@10 746 if (!psb->use_pipelining) {
meillo@10 747 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
meillo@10 748 ok = check_response(psb, FALSE);
meillo@10 749 }
meillo@10 750 }
meillo@10 751 if (ok) {
meillo@10 752 GList *rcpt_node;
meillo@10 753 rcpt_accept = 0;
meillo@0 754
meillo@10 755 for (rcpt_node = g_list_first(rcpt_list); rcpt_node != NULL; rcpt_node = g_list_next(rcpt_node)) {
meillo@10 756 address *rcpt = (address *) (rcpt_node->data);
meillo@10 757 smtp_cmd_rcptto(psb, rcpt);
meillo@10 758 if (!psb->use_pipelining) {
meillo@10 759 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT)))
meillo@10 760 if (check_response(psb, FALSE)) {
meillo@10 761 rcpt_accept++;
meillo@10 762 addr_mark_delivered(rcpt);
meillo@10 763 } else {
meillo@10 764 /* if server returned an error for one recp. we
meillo@10 765 may still try the others. But if it is a timeout, eof
meillo@10 766 or unexpected response, it is more serious and we should
meillo@10 767 give up. */
meillo@10 768 if ((psb->error != smtp_trylater) && (psb->error != smtp_fail)) {
meillo@10 769 ok = FALSE;
meillo@10 770 break;
meillo@10 771 } else {
meillo@114 772 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n",
meillo@15 773 msg->uid, addr_string(rcpt), psb->remote_host, psb->buffer);
meillo@10 774 if (psb->error == smtp_trylater) {
meillo@10 775 addr_mark_defered(rcpt);
meillo@10 776 } else {
meillo@10 777 addr_mark_failed(rcpt);
meillo@10 778 }
meillo@10 779 }
meillo@10 780 } else
meillo@10 781 break;
meillo@10 782 }
meillo@10 783 }
meillo@0 784
meillo@367 785 /*
meillo@367 786 ** There is no point in going on if no recp.s were accpted.
meillo@367 787 ** But we can check that at this point only if not pipelining:
meillo@367 788 */
meillo@10 789 ok = (ok && (psb->use_pipelining || (rcpt_accept > 0)));
meillo@10 790 if (ok) {
meillo@0 791
meillo@10 792 fprintf(psb->out, "DATA\r\n");
meillo@10 793 fflush(psb->out);
meillo@0 794
meillo@177 795 DEBUG(4) debugf("C: DATA\r\n");
meillo@10 796
meillo@10 797 if (psb->use_pipelining) {
meillo@367 798 /*
meillo@367 799 ** the first pl'ed command was MAIL FROM
meillo@367 800 ** the last was DATA, whose response can be
meillo@367 801 ** handled by the 'normal' code all in
meillo@367 802 ** between were RCPT TO:
meillo@367 803 */
meillo@10 804 /* response to MAIL FROM: */
meillo@10 805 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
meillo@10 806 if ((ok = check_response(psb, FALSE))) {
meillo@10 807
meillo@367 808 /*
meillo@367 809 ** response(s) to RCPT TO:
meillo@367 810 ** this is very similar to
meillo@367 811 ** the sequence above for no
meillo@367 812 ** pipeline
meillo@367 813 */
meillo@10 814 for (i = 0; i < rcpt_cnt; i++) {
meillo@10 815 if ((ok = read_response(psb, SMTP_CMD_TIMEOUT))) {
meillo@10 816 address *rcpt = g_list_nth_data(rcpt_list, i);
meillo@10 817 if (check_response(psb, FALSE)) {
meillo@10 818 rcpt_accept++;
meillo@10 819 addr_mark_delivered(rcpt);
meillo@10 820 } else {
meillo@367 821 /*
meillo@367 822 ** if server returned an error 4xx or 5xx for one recp. we
meillo@367 823 ** may still try the others. But if it is a timeout, eof
meillo@367 824 ** or unexpected response, it is more serious and we
meillo@367 825 ** should give up.
meillo@367 826 */
meillo@10 827 if ((psb->error != smtp_trylater) &&
meillo@10 828 (psb->error != smtp_fail)) {
meillo@10 829 ok = FALSE;
meillo@10 830 break;
meillo@10 831 } else {
meillo@114 832 logwrite(LOG_NOTICE, "%s == %s host=%s failed: %s\n", msg->uid,
meillo@10 833 addr_string(rcpt), psb->remote_host, psb->buffer);
meillo@10 834 if (psb->error == smtp_trylater) {
meillo@10 835 addr_mark_defered(rcpt);
meillo@10 836 } else {
meillo@10 837 addr_mark_failed(rcpt);
meillo@10 838 }
meillo@10 839 }
meillo@10 840 }
meillo@10 841 } else {
meillo@10 842 DEBUG(5) debugf("check_response failed after RCPT TO\n");
meillo@10 843 break;
meillo@10 844 }
meillo@10 845 }
meillo@10 846 if (rcpt_accept == 0)
meillo@10 847 ok = FALSE;
meillo@10 848 } else {
meillo@10 849 DEBUG(5) debugf("check_response failed after MAIL FROM\n");
meillo@10 850 }
meillo@10 851 } else {
meillo@10 852 DEBUG(5)
meillo@10 853 debugf("read_response failed after MAIL FROM\n");
meillo@10 854 }
meillo@10 855 }
meillo@10 856
meillo@10 857 /* if(psb->use_pipelining) */
meillo@10 858 /* response to the DATA cmd */
meillo@10 859 if (ok) {
meillo@10 860 if (read_response(psb, SMTP_DATA_TIMEOUT)) {
meillo@10 861 if (check_response(psb, TRUE)) {
meillo@10 862 send_header(psb, hdr_list);
meillo@10 863 send_data(psb, msg);
meillo@10 864
meillo@10 865 if (read_response(psb, SMTP_FINAL_TIMEOUT))
meillo@10 866 ok = check_response(psb, FALSE);
meillo@10 867 }
meillo@10 868 }
meillo@10 869 }
meillo@0 870 }
meillo@10 871 }
meillo@10 872
meillo@10 873 DEBUG(5) {
meillo@114 874 debugf("smtp_out_msg():\n");
meillo@114 875 debugf(" psb->error = %d\n", psb->error);
meillo@114 876 debugf(" ok = %d\n", ok);
meillo@114 877 debugf(" rcpt_accept = %d\n", rcpt_accept);
meillo@10 878 }
meillo@10 879
meillo@10 880 if (psb->error == smtp_ok) {
meillo@10 881 GList *rcpt_node;
meillo@10 882 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
meillo@10 883 address *rcpt = (address *) (rcpt_node->data);
meillo@10 884 if (addr_is_delivered(rcpt))
meillo@246 885 logwrite(LOG_NOTICE, "%s => %s host=%s\n",
meillo@246 886 msg->uid, addr_string(rcpt), psb->remote_host);
meillo@0 887 }
meillo@10 888 } else {
meillo@367 889 /*
meillo@367 890 ** if something went wrong,
meillo@367 891 ** we have to unmark the rcpts prematurely marked as
meillo@367 892 ** delivered and mark the status
meillo@367 893 */
meillo@10 894 smtp_out_mark_rcpts(psb, rcpt_list);
meillo@10 895
meillo@10 896 /* log the failure: */
meillo@10 897 smtp_out_log_failure(psb, msg);
meillo@0 898 }
meillo@10 899 return rcpt_accept;
meillo@0 900 }
meillo@0 901
meillo@10 902 gboolean
meillo@366 903 smtp_out_quit(smtp_base *psb)
meillo@0 904 {
meillo@10 905 fprintf(psb->out, "QUIT\r\n");
meillo@10 906 fflush(psb->out);
meillo@0 907
meillo@177 908 DEBUG(4) debugf("C: QUIT\n");
meillo@0 909
meillo@10 910 signal(SIGALRM, SIG_DFL);
meillo@10 911
meillo@10 912 return TRUE;
meillo@0 913 }
meillo@10 914
meillo@10 915 gint
meillo@367 916 smtp_deliver(gchar *host, gint port, GList *resolve_list, message *msg,
meillo@367 917 address *return_path, GList *rcpt_list)
meillo@0 918 {
meillo@10 919 smtp_base *psb;
meillo@10 920 smtp_error err;
meillo@0 921
meillo@10 922 DEBUG(5) debugf("smtp_deliver entered\n");
meillo@0 923
meillo@10 924 if (return_path == NULL)
meillo@10 925 return_path = msg->return_path;
meillo@0 926
meillo@10 927 if ((psb = smtp_out_open(host, port, resolve_list))) {
meillo@10 928 set_heloname(psb, return_path->domain, TRUE);
meillo@10 929 /* initiate connection, send message and quit: */
meillo@222 930 if (smtp_out_init(psb, FALSE)) {
meillo@10 931 smtp_out_msg(psb, msg, return_path, rcpt_list, NULL);
meillo@10 932 if (psb->error == smtp_ok || (psb->error == smtp_fail) || (psb->error == smtp_trylater)
meillo@10 933 || (psb->error == smtp_syntax) || (psb->error == smtp_cancel))
meillo@10 934 smtp_out_quit(psb);
meillo@10 935 }
meillo@10 936
meillo@10 937 err = psb->error;
meillo@10 938 destroy_smtpbase(psb);
meillo@10 939
meillo@10 940 return err;
meillo@10 941 }
meillo@10 942 return -1;
meillo@0 943 }