Mercurial > masqmail
comparison src/smtp_out.c @ 246:4cff8638dd9b
SMTP client: tries EHLO now always first
Changed the behavior of the SMTP client. Now always an EHLO greeting
is sent, no matter what kind of greeting text the server had sent. If
the EHLO failed, an HELO greeting is tried as fall back. This is the
behavior RFC 2821 requires (section 3.2).
This change will fix setups that were not possible to sent to a
server because that requires AUTH but hadn't said ``ESMTP'' in its
greeting message.
See also: Debian bug #349211
Thanks to Steffen (inne)
author | markus schnalke <meillo@marmaro.de> |
---|---|
date | Thu, 28 Oct 2010 16:40:02 -0300 |
parents | 589c365d90b1 |
children | c74adb7c4f50 |
comparison
equal
deleted
inserted
replaced
245:2f5e2b6a3a39 | 246:4cff8638dd9b |
---|---|
119 | 119 |
120 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base)); | 120 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base)); |
121 | 121 |
122 psb->sock = sock; | 122 psb->sock = sock; |
123 | 123 |
124 psb->use_esmtp = FALSE; | |
125 psb->use_size = FALSE; | 124 psb->use_size = FALSE; |
126 psb->use_pipelining = FALSE; | 125 psb->use_pipelining = FALSE; |
127 psb->use_auth = FALSE; | 126 psb->use_auth = FALSE; |
128 | 127 |
129 psb->max_size = 0; | 128 psb->max_size = 0; |
197 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data); | 196 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data); |
198 return FALSE; | 197 return FALSE; |
199 } | 198 } |
200 } | 199 } |
201 | 200 |
202 static gboolean | |
203 check_init_response(smtp_base * psb) | |
204 { | |
205 if (check_response(psb, FALSE)) { | |
206 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL); | |
207 | |
208 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n"); | |
209 | |
210 return TRUE; | |
211 } | |
212 return FALSE; | |
213 } | |
214 | |
215 static gchar* | 201 static gchar* |
216 get_response_arg(gchar * response) | 202 get_response_arg(gchar * response) |
217 { | 203 { |
218 gchar buf[SMTP_BUF_LEN]; | 204 gchar buf[SMTP_BUF_LEN]; |
219 gchar *p = response, *q = buf; | 205 gchar *p = response, *q = buf; |
295 } | 281 } |
296 | 282 |
297 return TRUE; | 283 return TRUE; |
298 } | 284 } |
299 | 285 |
286 /* | |
287 We first try EHLO, but if it fails HELO in a second fall back try. | |
288 This is what is requested by RFC 2821 (sec 3.2): | |
289 | |
290 Once the server has sent the welcoming message and | |
291 the client has received it, the client normally sends | |
292 the EHLO command to the server, [...] | |
293 For a particular connection attempt, if the server | |
294 returns a "command not recognized" response to EHLO, | |
295 the client SHOULD be able to fall back and send HELO. | |
296 | |
297 Up to and including version 0.3.0 masqmail used ESMTP only if the | |
298 string ``ESMTP'' appeared within the server's greeting message. This | |
299 made it impossible to use AUTH with servers that would send odd | |
300 greeting messages. | |
301 */ | |
300 static gboolean | 302 static gboolean |
301 smtp_helo(smtp_base * psb, gchar * helo) | 303 smtp_helo(smtp_base * psb, gchar * helo) |
302 { | 304 { |
303 while (TRUE) { | 305 fprintf(psb->out, "EHLO %s\r\n", helo); |
304 if (psb->use_esmtp) { | 306 fflush(psb->out); |
305 fprintf(psb->out, "EHLO %s\r\n", helo); | 307 DEBUG(4) debugf("C: EHLO %s\r\n", helo); |
306 fflush(psb->out); | 308 |
307 | 309 if (!read_response(psb, SMTP_CMD_TIMEOUT)) { |
308 DEBUG(4) debugf("C: EHLO %s\r\n", helo); | 310 return FALSE; |
309 | 311 } |
310 } else { | 312 if (check_helo_response(psb)) { |
311 fprintf(psb->out, "HELO %s\r\n", helo); | 313 DEBUG(4) debugf("uses esmtp\n"); |
312 fflush(psb->out); | 314 return TRUE; |
313 | 315 } |
314 DEBUG(4) debugf("C: HELO %s\r\n", helo); | 316 |
315 | 317 if (psb->error != smtp_fail) { |
316 } | 318 return FALSE; |
317 | 319 } |
318 if (!read_response(psb, SMTP_CMD_TIMEOUT)) | 320 |
319 return FALSE; | 321 /* our guess that server understands EHLO could have been wrong, |
320 | 322 try again with HELO */ |
321 if (check_helo_response(psb)) | 323 |
322 return TRUE; | 324 fprintf(psb->out, "HELO %s\r\n", helo); |
323 else { | 325 fflush(psb->out); |
324 if (psb->error == smtp_fail) { | 326 DEBUG(4) debugf("C: HELO %s\r\n", helo); |
325 if (psb->use_esmtp) { | 327 |
326 /* our guess that server understands EHLO was wrong, try again with HELO */ | 328 if (!read_response(psb, SMTP_CMD_TIMEOUT)) { |
327 psb->use_esmtp = FALSE; | 329 return FALSE; |
328 } else { | 330 } |
329 /* what sort of server ist THAT ?! give up... */ | 331 if (check_helo_response(psb)) { |
330 return FALSE; | 332 DEBUG(4) debugf("uses smtp\n"); |
331 } | 333 return TRUE; |
332 } else | 334 } |
333 return FALSE; | 335 |
334 } | 336 /* what sort of server ist THAT ?! give up... */ |
335 } | 337 return FALSE; |
336 } | 338 } |
337 | 339 |
338 static void | 340 static void |
339 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size) | 341 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size) |
340 { | 342 { |
689 { | 691 { |
690 gboolean ok; | 692 gboolean ok; |
691 | 693 |
692 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo); | 694 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo); |
693 | 695 |
694 if (instant_helo) { | 696 if (!instant_helo) { |
695 /* we say hello right away, hence we don't know if | |
696 ESMTP is supported; we just assume it */ | |
697 psb->use_esmtp = 1; | |
698 } else { | |
699 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) { | 697 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) { |
700 ok = check_init_response(psb); | 698 ok = check_response(psb, FALSE); |
701 } | 699 } |
702 if (!ok) { | 700 if (!ok) { |
703 smtp_out_log_failure(psb, NULL); | 701 smtp_out_log_failure(psb, NULL); |
704 return ok; | 702 return ok; |
705 } | 703 } |
883 if (psb->error == smtp_ok) { | 881 if (psb->error == smtp_ok) { |
884 GList *rcpt_node; | 882 GList *rcpt_node; |
885 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) { | 883 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) { |
886 address *rcpt = (address *) (rcpt_node->data); | 884 address *rcpt = (address *) (rcpt_node->data); |
887 if (addr_is_delivered(rcpt)) | 885 if (addr_is_delivered(rcpt)) |
888 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt), | 886 logwrite(LOG_NOTICE, "%s => %s host=%s\n", |
889 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp"); | 887 msg->uid, addr_string(rcpt), psb->remote_host); |
890 } | 888 } |
891 } else { | 889 } else { |
892 /* if something went wrong, | 890 /* if something went wrong, |
893 we have to unmark the rcpts prematurely marked as delivered | 891 we have to unmark the rcpts prematurely marked as delivered |
894 and mark the status */ | 892 and mark the status */ |