DKIM: reduce memory usage
[exim.git] / src / src / smtp_out.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
80fea873 5/* Copyright (c) University of Cambridge 1995 - 2016 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* A number of functions for driving outgoing SMTP calls. */
9
10
11#include "exim.h"
7eb6c37c 12#include "transports/smtp.h"
059ec3d9
PH
13
14
15
16/*************************************************
17* Find an outgoing interface *
18*************************************************/
19
20/* This function is called from the smtp transport and also from the callout
21code in verify.c. Its job is to expand a string to get a list of interfaces,
22and choose a suitable one (IPv4 or IPv6) for the outgoing address.
23
24Arguments:
25 istring string interface setting, may be NULL, meaning "any", in
26 which case the function does nothing
27 host_af AF_INET or AF_INET6 for the outgoing IP address
28 addr the mail address being handled (for setting errors)
059ec3d9
PH
29 interface point this to the interface
30 msg to add to any error message
31
32Returns: TRUE on success, FALSE on failure, with error message
33 set in addr and transport_return set to PANIC
34*/
35
36BOOL
37smtp_get_interface(uschar *istring, int host_af, address_item *addr,
6f6dedcc 38 uschar **interface, uschar *msg)
059ec3d9 39{
55414b25 40const uschar * expint;
059ec3d9
PH
41uschar *iface;
42int sep = 0;
43
44if (istring == NULL) return TRUE;
45
46expint = expand_string(istring);
47if (expint == NULL)
48 {
49 if (expand_string_forcedfail) return TRUE;
50 addr->transport_return = PANIC;
51 addr->message = string_sprintf("failed to expand \"interface\" "
52 "option for %s: %s", msg, expand_string_message);
53 return FALSE;
54 }
55
059ec3d9
PH
56while (isspace(*expint)) expint++;
57if (*expint == 0) return TRUE;
58
59while ((iface = string_nextinlist(&expint, &sep, big_buffer,
60 big_buffer_size)) != NULL)
61 {
62 if (string_is_ip_address(iface, NULL) == 0)
63 {
64 addr->transport_return = PANIC;
65 addr->message = string_sprintf("\"%s\" is not a valid IP "
66 "address for the \"interface\" option for %s",
67 iface, msg);
68 return FALSE;
69 }
70
71 if (((Ustrchr(iface, ':') == NULL)? AF_INET:AF_INET6) == host_af)
72 break;
73 }
74
75if (iface != NULL) *interface = string_copy(iface);
76return TRUE;
77}
78
79
80
81/*************************************************
82* Find an outgoing port *
83*************************************************/
84
85/* This function is called from the smtp transport and also from the callout
86code in verify.c. Its job is to find a port number. Note that getservbyname()
87produces the number in network byte order.
88
89Arguments:
90 rstring raw (unexpanded) string representation of the port
91 addr the mail address being handled (for setting errors)
92 port stick the port in here
93 msg for adding to error message
94
95Returns: TRUE on success, FALSE on failure, with error message set
96 in addr, and transport_return set to PANIC
97*/
98
99BOOL
100smtp_get_port(uschar *rstring, address_item *addr, int *port, uschar *msg)
101{
102uschar *pstring = expand_string(rstring);
103
104if (pstring == NULL)
105 {
106 addr->transport_return = PANIC;
107 addr->message = string_sprintf("failed to expand \"%s\" (\"port\" option) "
108 "for %s: %s", rstring, msg, expand_string_message);
109 return FALSE;
110 }
111
112if (isdigit(*pstring))
113 {
114 uschar *end;
115 *port = Ustrtol(pstring, &end, 0);
116 if (end != pstring + Ustrlen(pstring))
117 {
118 addr->transport_return = PANIC;
119 addr->message = string_sprintf("invalid port number for %s: %s", msg,
120 pstring);
121 return FALSE;
122 }
123 }
124
125else
126 {
127 struct servent *smtp_service = getservbyname(CS pstring, "tcp");
128 if (smtp_service == NULL)
129 {
130 addr->transport_return = PANIC;
131 addr->message = string_sprintf("TCP port \"%s\" is not defined for %s",
132 pstring, msg);
133 return FALSE;
134 }
135 *port = ntohs(smtp_service->s_port);
136 }
137
138return TRUE;
139}
140
141
142
143
059ec3d9 144int
7eb6c37c
JH
145smtp_sock_connect(host_item * host, int host_af, int port, uschar * interface,
146 transport_instance * tb, int timeout)
059ec3d9 147{
7eb6c37c
JH
148smtp_transport_options_block * ob =
149 (smtp_transport_options_block *)tb->options_block;
150const uschar * dscp = ob->dscp;
9e4f5962
PP
151int dscp_value;
152int dscp_level;
153int dscp_option;
059ec3d9 154int sock;
7eb6c37c
JH
155int on = 1;
156int save_errno = 0;
059ec3d9 157
0cbf2b82 158#ifndef DISABLE_EVENT
7eb6c37c
JH
159deliver_host_address = host->address;
160deliver_host_port = port;
161if (event_raise(tb->event_action, US"tcp:connect", NULL)) return -1;
a7538db1
JH
162#endif
163
059ec3d9
PH
164if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return -1;
165
166/* Set TCP_NODELAY; Exim does its own buffering. */
167
d4ff61d1
JH
168if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on)))
169 HDEBUG(D_transport|D_acl|D_v)
170 debug_printf("failed to set NODELAY: %s ", strerror(errno));
059ec3d9 171
9e4f5962
PP
172/* Set DSCP value, if we can. For now, if we fail to set the value, we don't
173bomb out, just log it and continue in default traffic class. */
174
175if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value))
176 {
177 HDEBUG(D_transport|D_acl|D_v)
36a3ae5f 178 debug_printf("DSCP \"%s\"=%x ", dscp, dscp_value);
9e4f5962
PP
179 if (setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)) < 0)
180 HDEBUG(D_transport|D_acl|D_v)
181 debug_printf("failed to set DSCP: %s ", strerror(errno));
182 /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the
183 option for both; ignore failures here */
184 if (host_af == AF_INET6 &&
185 dscp_lookup(dscp, AF_INET, &dscp_level, &dscp_option, &dscp_value))
9e4f5962 186 (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
9e4f5962
PP
187 }
188
059ec3d9
PH
189/* Bind to a specific interface if requested. Caller must ensure the interface
190is the same type (IPv4 or IPv6) as the outgoing address. */
191
7eb6c37c 192if (interface && ip_bind(sock, host_af, interface, 0) < 0)
059ec3d9
PH
193 {
194 save_errno = errno;
195 HDEBUG(D_transport|D_acl|D_v)
196 debug_printf("unable to bind outgoing SMTP call to %s: %s", interface,
197 strerror(errno));
198 }
199
200/* Connect to the remote host, and add keepalive to the socket before returning
201it, if requested. */
202
203else if (ip_connect(sock, host_af, host->address, port, timeout) < 0)
204 save_errno = errno;
205
206/* Either bind() or connect() failed */
207
208if (save_errno != 0)
209 {
8e669ac1 210 HDEBUG(D_transport|D_acl|D_v)
4deaf07d
PH
211 {
212 debug_printf("failed: %s", CUstrerror(save_errno));
8e669ac1 213 if (save_errno == ETIMEDOUT)
4deaf07d 214 debug_printf(" (timeout=%s)", readconf_printtime(timeout));
8e669ac1
PH
215 debug_printf("\n");
216 }
f1e894f3 217 (void)close(sock);
059ec3d9
PH
218 errno = save_errno;
219 return -1;
220 }
221
222/* Both bind() and connect() succeeded */
223
224else
225 {
41c7c167
PH
226 union sockaddr_46 interface_sock;
227 EXIM_SOCKLEN_T size = sizeof(interface_sock);
059ec3d9 228 HDEBUG(D_transport|D_acl|D_v) debug_printf("connected\n");
41c7c167
PH
229 if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
230 sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
231 else
232 {
233 log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
234 "getsockname() failed: %s", strerror(errno));
235 close(sock);
236 return -1;
237 }
7eb6c37c 238 if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
059ec3d9
PH
239 return sock;
240 }
241}
242
7eb6c37c
JH
243/*************************************************
244* Connect to remote host *
245*************************************************/
246
247/* Create a socket, and connect it to a remote host. IPv6 addresses are
248detected by checking for a colon in the address. AF_INET6 is defined even on
249non-IPv6 systems, to enable the code to be less messy. However, on such systems
250host->address will always be an IPv4 address.
251
252The port field in the host item is used if it is set (usually router from SRV
253records or elsewhere). In other cases, the default passed as an argument is
254used, and the host item is updated with its value.
255
256Arguments:
257 host host item containing name and address (and sometimes port)
258 host_af AF_INET or AF_INET6
259 port default remote port to connect to, in host byte order, for those
260 hosts whose port setting is PORT_NONE
261 interface outgoing interface address or NULL
262 timeout timeout value or 0
263 tb transport
264
265Returns: connected socket number, or -1 with errno set
266*/
267
268int
269smtp_connect(host_item *host, int host_af, int port, uschar *interface,
270 int timeout, transport_instance * tb)
271{
f0989ec0 272#ifdef SUPPORT_SOCKS
7eb6c37c
JH
273smtp_transport_options_block * ob =
274 (smtp_transport_options_block *)tb->options_block;
0539a19d 275#endif
7eb6c37c
JH
276
277if (host->port != PORT_NONE)
278 {
279 HDEBUG(D_transport|D_acl|D_v)
280 debug_printf("Transport port=%d replaced by host-specific port=%d\n", port,
281 host->port);
282 port = host->port;
283 }
284else host->port = port; /* Set the port actually used */
285
055e2cb4
JH
286callout_address = string_sprintf("[%s]:%d", host->address, port);
287
7eb6c37c
JH
288HDEBUG(D_transport|D_acl|D_v)
289 {
290 uschar * s = US" ";
291 if (interface) s = string_sprintf(" from %s ", interface);
f0989ec0 292#ifdef SUPPORT_SOCKS
7eb6c37c
JH
293 if (ob->socks_proxy) s = string_sprintf("%svia proxy ", s);
294#endif
055e2cb4 295 debug_printf("Connecting to %s %s%s... ", host->name, callout_address, s);
7eb6c37c
JH
296 }
297
298/* Create and connect the socket */
299
f0989ec0 300#ifdef SUPPORT_SOCKS
7eb6c37c
JH
301if (ob->socks_proxy)
302 return socks_sock_connect(host, host_af, port, interface, tb, timeout);
303#endif
304
305return smtp_sock_connect(host, host_af, port, interface, tb, timeout);
306}
307
059ec3d9
PH
308
309/*************************************************
310* Flush outgoing command buffer *
311*************************************************/
312
313/* This function is called only from smtp_write_command() below. It flushes
314the buffer of outgoing commands. There is more than one in the buffer only when
315pipelining.
316
317Argument:
318 outblock the SMTP output block
319
320Returns: TRUE if OK, FALSE on error, with errno set
321*/
322
323static BOOL
324flush_buffer(smtp_outblock *outblock)
325{
326int rc;
327
328#ifdef SUPPORT_TLS
817d9f57
JH
329if (tls_out.active == outblock->sock)
330 rc = tls_write(FALSE, outblock->buffer, outblock->ptr - outblock->buffer);
059ec3d9
PH
331else
332#endif
333
334rc = send(outblock->sock, outblock->buffer, outblock->ptr - outblock->buffer, 0);
335if (rc <= 0)
336 {
337 HDEBUG(D_transport|D_acl) debug_printf("send failed: %s\n", strerror(errno));
338 return FALSE;
339 }
340
341outblock->ptr = outblock->buffer;
342outblock->cmd_count = 0;
343return TRUE;
344}
345
346
347
348/*************************************************
349* Write SMTP command *
350*************************************************/
351
352/* The formatted command is left in big_buffer so that it can be reflected in
353any error message.
354
355Arguments:
356 outblock contains buffer for pipelining, and socket
357 noflush if TRUE, save the command in the output buffer, for pipelining
358 format a format, starting with one of
359 of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT.
6d5c916c 360 If NULL, flush pipeline buffer only.
059ec3d9
PH
361 ... data for the format
362
363Returns: 0 if command added to pipelining buffer, with nothing transmitted
364 +n if n commands transmitted (may still have buffered the new one)
365 -1 on error, with errno set
366*/
367
368int
1ba28e2b 369smtp_write_command(smtp_outblock *outblock, BOOL noflush, const char *format, ...)
059ec3d9
PH
370{
371int count;
372int rc = 0;
373va_list ap;
374
6d5c916c 375if (format)
059ec3d9 376 {
6d5c916c
JH
377 va_start(ap, format);
378 if (!string_vformat(big_buffer, big_buffer_size, CS format, ap))
379 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
380 "SMTP");
381 va_end(ap);
382 count = Ustrlen(big_buffer);
383
384 if (count > outblock->buffersize)
385 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
386 "SMTP");
387
388 if (count > outblock->buffersize - (outblock->ptr - outblock->buffer))
389 {
390 rc = outblock->cmd_count; /* flush resets */
391 if (!flush_buffer(outblock)) return -1;
392 }
059ec3d9 393
6d5c916c
JH
394 Ustrncpy(CS outblock->ptr, big_buffer, count);
395 outblock->ptr += count;
396 outblock->cmd_count++;
397 count -= 2;
398 big_buffer[count] = 0; /* remove \r\n for error message */
059ec3d9 399
6d5c916c
JH
400 /* We want to hide the actual data sent in AUTH transactions from reflections
401 and logs. While authenticating, a flag is set in the outblock to enable this.
402 The AUTH command itself gets any data flattened. Other lines are flattened
403 completely. */
059ec3d9 404
6d5c916c 405 if (outblock->authenticating)
059ec3d9 406 {
6d5c916c
JH
407 uschar *p = big_buffer;
408 if (Ustrncmp(big_buffer, "AUTH ", 5) == 0)
409 {
410 p += 5;
411 while (isspace(*p)) p++;
412 while (!isspace(*p)) p++;
413 while (isspace(*p)) p++;
414 }
415 while (*p != 0) *p++ = '*';
059ec3d9 416 }
059ec3d9 417
6d5c916c
JH
418 HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP>> %s\n", big_buffer);
419 }
059ec3d9
PH
420
421if (!noflush)
422 {
423 rc += outblock->cmd_count; /* flush resets */
424 if (!flush_buffer(outblock)) return -1;
425 }
426
427return rc;
428}
429
430
431
432/*************************************************
433* Read one line of SMTP response *
434*************************************************/
435
436/* This function reads one line of SMTP response from the server host. This may
437not be a complete response - it could be just part of a multiline response. We
438have to use a buffer for incoming packets, because when pipelining or using
439LMTP, there may well be more than one response in a single packet. This
440function is called only from the one that follows.
441
442Arguments:
443 inblock the SMTP input block (contains holding buffer, socket, etc.)
444 buffer where to put the line
445 size space available for the line
446 timeout the timeout to use when reading a packet
447
448Returns: length of a line that has been put in the buffer
449 -1 otherwise, with errno set
450*/
451
452static int
453read_response_line(smtp_inblock *inblock, uschar *buffer, int size, int timeout)
454{
455uschar *p = buffer;
456uschar *ptr = inblock->ptr;
457uschar *ptrend = inblock->ptrend;
458int sock = inblock->sock;
459
460/* Loop for reading multiple packets or reading another packet after emptying
461a previously-read one. */
462
463for (;;)
464 {
465 int rc;
466
467 /* If there is data in the input buffer left over from last time, copy
468 characters from it until the end of a line, at which point we can return,
469 having removed any whitespace (which will include CR) at the end of the line.
470 The rules for SMTP say that lines end in CRLF, but there are have been cases
471 of hosts using just LF, and other MTAs are reported to handle this, so we
472 just look for LF. If we run out of characters before the end of a line,
473 carry on to read the next incoming packet. */
474
475 while (ptr < ptrend)
476 {
477 int c = *ptr++;
478 if (c == '\n')
479 {
480 while (p > buffer && isspace(p[-1])) p--;
481 *p = 0;
482 inblock->ptr = ptr;
483 return p - buffer;
484 }
485 *p++ = c;
486 if (--size < 4)
487 {
488 *p = 0; /* Leave malformed line for error message */
489 errno = ERRNO_SMTPFORMAT;
490 return -1;
491 }
492 }
493
494 /* Need to read a new input packet. */
495
496 rc = ip_recv(sock, inblock->buffer, inblock->buffersize, timeout);
497 if (rc <= 0) break;
498
499 /* Another block of data has been successfully read. Set up the pointers
500 and let the loop continue. */
501
502 ptrend = inblock->ptrend = inblock->buffer + rc;
503 ptr = inblock->buffer;
504 DEBUG(D_transport|D_acl) debug_printf("read response data: size=%d\n", rc);
505 }
506
507/* Get here if there has been some kind of recv() error; errno is set, but we
508ensure that the result buffer is empty before returning. */
509
510*buffer = 0;
511return -1;
512}
513
514
515
516
517
518/*************************************************
519* Read SMTP response *
520*************************************************/
521
522/* This function reads an SMTP response with a timeout, and returns the
523response in the given buffer, as a string. A multiline response will contain
524newline characters between the lines. The function also analyzes the first
525digit of the reply code and returns FALSE if it is not acceptable. FALSE is
526also returned after a reading error. In this case buffer[0] will be zero, and
527the error code will be in errno.
528
529Arguments:
530 inblock the SMTP input block (contains holding buffer, socket, etc.)
531 buffer where to put the response
532 size the size of the buffer
533 okdigit the expected first digit of the response
534 timeout the timeout to use
535
536Returns: TRUE if a valid, non-error response was received; else FALSE
537*/
538
539BOOL
540smtp_read_response(smtp_inblock *inblock, uschar *buffer, int size, int okdigit,
541 int timeout)
542{
543uschar *ptr = buffer;
544int count;
545
546errno = 0; /* Ensure errno starts out zero */
547
548/* This is a loop to read and concatentate the lines that make up a multi-line
549response. */
550
551for (;;)
552 {
553 if ((count = read_response_line(inblock, ptr, size, timeout)) < 0)
554 return FALSE;
555
556 HDEBUG(D_transport|D_acl|D_v)
557 debug_printf(" %s %s\n", (ptr == buffer)? "SMTP<<" : " ", ptr);
558
559 /* Check the format of the response: it must start with three digits; if
560 these are followed by a space or end of line, the response is complete. If
561 they are followed by '-' this is a multi-line response and we must look for
562 another line until the final line is reached. The only use made of multi-line
563 responses is to pass them back as error messages. We therefore just
564 concatenate them all within the buffer, which should be large enough to
565 accept any reasonable number of lines. */
566
567 if (count < 3 ||
568 !isdigit(ptr[0]) ||
569 !isdigit(ptr[1]) ||
570 !isdigit(ptr[2]) ||
571 (ptr[3] != '-' && ptr[3] != ' ' && ptr[3] != 0))
572 {
573 errno = ERRNO_SMTPFORMAT; /* format error */
574 return FALSE;
575 }
576
577 /* If the line we have just read is a terminal line, line, we are done.
578 Otherwise more data has to be read. */
579
580 if (ptr[3] != '-') break;
581
582 /* Move the reading pointer upwards in the buffer and insert \n between the
583 components of a multiline response. Space is left for this by read_response_
584 line(). */
585
586 ptr += count;
587 *ptr++ = '\n';
588 size -= count + 1;
589 }
590
591/* Return a value that depends on the SMTP return code. On some systems a
592non-zero value of errno has been seen at this point, so ensure it is zero,
593because the caller of this function looks at errno when FALSE is returned, to
594distinguish between an unexpected return code and other errors such as
595timeouts, lost connections, etc. */
596
597errno = 0;
598return buffer[0] == okdigit;
599}
600
601/* End of smtp_out.c */
7eb6c37c
JH
602/* vi: aw ai sw=2
603*/