tidying
[exim.git] / src / src / smtp_out.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2018 */
6 /* Copyright (c) The Exim Maintainers 2020 */
7 /* See the file NOTICE for conditions of use and distribution. */
8
9 /* A number of functions for driving outgoing SMTP calls. */
10
11
12 #include "exim.h"
13 #include "transports/smtp.h"
14
15
16
17 /*************************************************
18 *           Find an outgoing interface           *
19 *************************************************/
20
21 /* This function is called from the smtp transport and also from the callout
22 code in verify.c. Its job is to expand a string to get a list of interfaces,
23 and choose a suitable one (IPv4 or IPv6) for the outgoing address.
24
25 Arguments:
26   istring    string interface setting, may be NULL, meaning "any", in
27                which case the function does nothing
28   host_af    AF_INET or AF_INET6 for the outgoing IP address
29   addr       the mail address being handled (for setting errors)
30   interface  point this to the interface if there is one defined
31   msg        to add to any error message
32
33 Returns:     TRUE on success, FALSE on failure, with error message
34                set in addr and transport_return set to PANIC
35 */
36
37 BOOL
38 smtp_get_interface(uschar *istring, int host_af, address_item *addr,
39   uschar **interface, uschar *msg)
40 {
41 const uschar * expint;
42 uschar *iface;
43 int sep = 0;
44
45 if (!istring) return TRUE;
46
47 if (!(expint = expand_string(istring)))
48   {
49   if (f.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
56 if (is_tainted2(expint, LOG_MAIN|LOG_PANIC, "Tainted value '%s' from '%s' for interface", expint, istring))
57   {
58   addr->transport_return = PANIC;
59   addr->message = string_sprintf("failed to expand \"interface\" "
60       "option for %s: configuration error", msg);
61   return FALSE;
62   }
63
64 Uskip_whitespace(&expint);
65 if (!*expint) return TRUE;
66
67 while ((iface = string_nextinlist(&expint, &sep, NULL, 0)))
68   {
69   int if_af = string_is_ip_address(iface, NULL);
70   if (if_af == 0)
71     {
72     addr->transport_return = PANIC;
73     addr->message = string_sprintf("\"%s\" is not a valid IP "
74       "address for the \"interface\" option for %s",
75       iface, msg);
76     return FALSE;
77     }
78
79   if ((if_af == 4 ? AF_INET : AF_INET6) == host_af)
80     break;
81   }
82
83 *interface = iface;
84 return TRUE;
85 }
86
87
88
89 /*************************************************
90 *           Find an outgoing port                *
91 *************************************************/
92
93 /* This function is called from the smtp transport and also from the callout
94 code in verify.c. Its job is to find a port number. Note that getservbyname()
95 produces the number in network byte order.
96
97 Arguments:
98   rstring     raw (unexpanded) string representation of the port
99   addr        the mail address being handled (for setting errors)
100   port        stick the port in here
101   msg         for adding to error message
102
103 Returns:      TRUE on success, FALSE on failure, with error message set
104                 in addr, and transport_return set to PANIC
105 */
106
107 BOOL
108 smtp_get_port(uschar *rstring, address_item *addr, int *port, uschar *msg)
109 {
110 uschar *pstring = expand_string(rstring);
111
112 if (!pstring)
113   {
114   addr->transport_return = PANIC;
115   addr->message = string_sprintf("failed to expand \"%s\" (\"port\" option) "
116     "for %s: %s", rstring, msg, expand_string_message);
117   return FALSE;
118   }
119
120 if (isdigit(*pstring))
121   {
122   uschar *end;
123   *port = Ustrtol(pstring, &end, 0);
124   if (end != pstring + Ustrlen(pstring))
125     {
126     addr->transport_return = PANIC;
127     addr->message = string_sprintf("invalid port number for %s: %s", msg,
128       pstring);
129     return FALSE;
130     }
131   }
132
133 else
134   {
135   struct servent *smtp_service = getservbyname(CS pstring, "tcp");
136   if (!smtp_service)
137     {
138     addr->transport_return = PANIC;
139     addr->message = string_sprintf("TCP port \"%s\" is not defined for %s",
140       pstring, msg);
141     return FALSE;
142     }
143   *port = ntohs(smtp_service->s_port);
144   }
145
146 return TRUE;
147 }
148
149
150
151
152 #ifdef TCP_FASTOPEN
153 static void
154 tfo_out_check(int sock)
155 {
156 # ifdef __FreeBSD__
157 struct tcp_info tinfo;
158 socklen_t len = sizeof(tinfo);
159
160 /* A getsockopt TCP_FASTOPEN unfortunately returns "was-used" for a TFO/R as
161 well as a TFO/C.  Use what we can of the Linux hack below; reliability issues ditto. */
162 switch (tcp_out_fastopen)
163   {
164   case TFO_ATTEMPTED_NODATA:
165     if (  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
166        && tinfo.tcpi_state == TCPS_SYN_SENT
167        && tinfo.__tcpi_unacked > 0
168        )
169       {
170       DEBUG(D_transport|D_v)
171        debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.__tcpi_unacked);
172       tcp_out_fastopen = TFO_USED_NODATA;
173       }
174     break;
175   /*
176   case TFO_ATTEMPTED_DATA:
177   case TFO_ATTEMPTED_DATA:
178        if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA)   XXX no equvalent as of 12.2
179   */
180   }
181
182 switch (tcp_out_fastopen)
183   {
184   case TFO_ATTEMPTED_DATA:      tcp_out_fastopen = TFO_USED_DATA; break;
185   default: break; /* compiler quietening */
186   }
187
188 # else  /* Linux & Apple */
189 #  if defined(TCP_INFO) && defined(EXIM_HAVE_TCPI_UNACKED)
190 struct tcp_info tinfo;
191 socklen_t len = sizeof(tinfo);
192
193 switch (tcp_out_fastopen)
194   {
195     /* This is a somewhat dubious detection method; totally undocumented so likely
196     to fail in future kernels.  There seems to be no documented way.  What we really
197     want to know is if the server sent smtp-banner data before our ACK of his SYN,ACK
198     hit him.  What this (possibly?) detects is whether we sent a TFO cookie with our
199     SYN, as distinct from a TFO request.  This gets a false-positive when the server
200     key is rotated; we send the old one (which this test sees) but the server returns
201     the new one and does not send its SMTP banner before we ACK his SYN,ACK.
202      To force that rotation case:
203      '# echo -n "00000000-00000000-00000000-0000000" >/proc/sys/net/ipv4/tcp_fastopen_key'
204     The kernel seems to be counting unack'd packets. */
205
206   case TFO_ATTEMPTED_NODATA:
207     if (  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
208        && tinfo.tcpi_state == TCP_SYN_SENT
209        && tinfo.tcpi_unacked > 1
210        )
211       {
212       DEBUG(D_transport|D_v)
213         debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.tcpi_unacked);
214       tcp_out_fastopen = TFO_USED_NODATA;
215       }
216     break;
217
218     /* When called after waiting for received data we should be able
219     to tell if data we sent was accepted. */
220
221   case TFO_ATTEMPTED_DATA:
222     if (  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
223        && tinfo.tcpi_state == TCP_ESTABLISHED
224        )
225       if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA)
226         {
227         DEBUG(D_transport|D_v) debug_printf("TFO: data was acked\n");
228         tcp_out_fastopen = TFO_USED_DATA;
229         }
230       else
231         {
232         DEBUG(D_transport|D_v) debug_printf("TFO: had to retransmit\n");
233         tcp_out_fastopen = TFO_NOT_USED;
234         }
235     break;
236
237   default: break; /* compiler quietening */
238   }
239 #  endif
240 # endif /* Linux & Apple */
241 }
242 #endif
243
244
245 /* Arguments:
246   host        host item containing name and address and port
247   host_af     AF_INET or AF_INET6
248   port        TCP port number
249   interface   outgoing interface address or NULL
250   tb          transport
251   timeout     timeout value or 0
252   early_data    if non-NULL, idempotent data to be sent -
253                 preferably in the TCP SYN segment
254               Special case: non-NULL but with NULL blob.data - caller is
255               client-data-first (eg. TLS-on-connect) and a lazy-TCP-connect is
256               acceptable.
257
258 Returns:      connected socket number, or -1 with errno set
259 */
260
261 int
262 smtp_sock_connect(host_item * host, int host_af, int port, uschar * interface,
263   transport_instance * tb, int timeout, const blob * early_data)
264 {
265 smtp_transport_options_block * ob =
266   (smtp_transport_options_block *)tb->options_block;
267 const uschar * dscp = ob->dscp;
268 int dscp_value;
269 int dscp_level;
270 int dscp_option;
271 int sock;
272 int save_errno = 0;
273 const blob * fastopen_blob = NULL;
274
275
276 #ifndef DISABLE_EVENT
277 deliver_host_address = host->address;
278 deliver_host_port = port;
279 if (event_raise(tb->event_action, US"tcp:connect", NULL)) return -1;
280 #endif
281
282 if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return -1;
283
284 /* Set TCP_NODELAY; Exim does its own buffering. */
285
286 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on)))
287   HDEBUG(D_transport|D_acl|D_v)
288     debug_printf_indent("failed to set NODELAY: %s ", strerror(errno));
289
290 /* Set DSCP value, if we can. For now, if we fail to set the value, we don't
291 bomb out, just log it and continue in default traffic class. */
292
293 if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value))
294   {
295   HDEBUG(D_transport|D_acl|D_v)
296     debug_printf_indent("DSCP \"%s\"=%x ", dscp, dscp_value);
297   if (setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)) < 0)
298     HDEBUG(D_transport|D_acl|D_v)
299       debug_printf_indent("failed to set DSCP: %s ", strerror(errno));
300   /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the
301   option for both; ignore failures here */
302   if (host_af == AF_INET6 &&
303       dscp_lookup(dscp, AF_INET, &dscp_level, &dscp_option, &dscp_value))
304     (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
305   }
306
307 /* Bind to a specific interface if requested. Caller must ensure the interface
308 is the same type (IPv4 or IPv6) as the outgoing address. */
309
310 if (interface && ip_bind(sock, host_af, interface, 0) < 0)
311   {
312   save_errno = errno;
313   HDEBUG(D_transport|D_acl|D_v)
314     debug_printf_indent("unable to bind outgoing SMTP call to %s: %s", interface,
315     strerror(errno));
316   }
317
318 /* Connect to the remote host, and add keepalive to the socket before returning
319 it, if requested.  If the build supports TFO, request it - and if the caller
320 requested some early-data then include that in the TFO request.  If there is
321 early-data but no TFO support, send it after connecting. */
322
323 else
324   {
325 #ifdef TCP_FASTOPEN
326   /* See if TCP Fast Open usable.  Default is a traditional 3WHS connect */
327   if (verify_check_given_host(CUSS &ob->hosts_try_fastopen, host) == OK)
328     {
329     if (!early_data)
330       fastopen_blob = &tcp_fastopen_nodata;     /* TFO, with no data */
331     else if (early_data->data)
332       fastopen_blob = early_data;               /* TFO, with data */
333 # ifdef TCP_FASTOPEN_CONNECT
334     else
335       {                                         /* expecting client data */
336       debug_printf(" set up lazy-connect\n");
337       setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, US &on, sizeof(on));
338       /* fastopen_blob = NULL;           lazy TFO, triggered by data write */
339       }
340 # endif
341     }
342 #endif
343
344   if (ip_connect(sock, host_af, host->address, port, timeout, fastopen_blob) < 0)
345     save_errno = errno;
346   else if (early_data && !fastopen_blob && early_data->data && early_data->len)
347     {
348     /* We had some early-data to send, but couldn't do TFO */
349     HDEBUG(D_transport|D_acl|D_v)
350       debug_printf("sending %ld nonTFO early-data\n", (long)early_data->len);
351
352 #ifdef TCP_QUICKACK_notdef
353     (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
354 #endif
355     if (send(sock, early_data->data, early_data->len, 0) < 0)
356       save_errno = errno;
357     }
358 #ifdef TCP_QUICKACK_notdef
359   /* Under TFO (with openssl & pipe-conn; testcase 4069, as of
360   5.10.8-100.fc32.x86_64) this seems to be inop.
361   Perhaps overwritten when we (client) go -> ESTABLISHED on seeing the 3rd-ACK?
362   For that case, added at smtp_reap_banner(). */
363   (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
364 #endif
365   }
366
367 /* Either bind() or connect() failed */
368
369 if (save_errno != 0)
370   {
371   HDEBUG(D_transport|D_acl|D_v)
372     {
373     debug_printf_indent(" failed: %s", CUstrerror(save_errno));
374     if (save_errno == ETIMEDOUT)
375       debug_printf(" (timeout=%s)", readconf_printtime(timeout));
376     debug_printf("\n");
377     }
378   (void)close(sock);
379   errno = save_errno;
380   return -1;
381   }
382
383 /* Both bind() and connect() succeeded, and any early-data */
384
385 else
386   {
387   union sockaddr_46 interface_sock;
388   EXIM_SOCKLEN_T size = sizeof(interface_sock);
389
390   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" connected\n");
391   if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
392     sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
393   else
394     {
395     log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
396       "getsockname() failed: %s", strerror(errno));
397     close(sock);
398     return -1;
399     }
400
401   if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
402 #ifdef TCP_FASTOPEN
403   tfo_out_check(sock);
404 #endif
405   return sock;
406   }
407 }
408
409
410
411
412
413 void
414 smtp_port_for_connect(host_item * host, int port)
415 {
416 if (host->port != PORT_NONE)
417   {
418   HDEBUG(D_transport|D_acl|D_v) if (port != host->port)
419     debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", port,
420       host->port);
421   port = host->port;
422   }
423 else host->port = port;    /* Set the port actually used */
424 }
425
426
427 /*************************************************
428 *           Connect to remote host               *
429 *************************************************/
430
431 /* Create a socket, and connect it to a remote host. IPv6 addresses are
432 detected by checking for a colon in the address. AF_INET6 is defined even on
433 non-IPv6 systems, to enable the code to be less messy. However, on such systems
434 host->address will always be an IPv4 address.
435
436 Arguments:
437   sc          details for making connection: host, af, interface, transport
438   early_data  if non-NULL, data to be sent - preferably in the TCP SYN segment
439               Special case: non-NULL but with NULL blob.data - caller is
440               client-data-first (eg. TLS-on-connect) and a lazy-TCP-connect is
441               acceptable.
442
443 Returns:      connected socket number, or -1 with errno set
444 */
445
446 int
447 smtp_connect(smtp_connect_args * sc, const blob * early_data)
448 {
449 int port = sc->host->port;
450 smtp_transport_options_block * ob = sc->ob;
451
452 callout_address = string_sprintf("[%s]:%d", sc->host->address, port);
453
454 HDEBUG(D_transport|D_acl|D_v)
455   {
456   uschar * s = US" ";
457   if (sc->interface) s = string_sprintf(" from %s ", sc->interface);
458 #ifdef SUPPORT_SOCKS
459   if (ob->socks_proxy) s = string_sprintf("%svia proxy ", s);
460 #endif
461   debug_printf_indent("Connecting to %s %s%s... ", sc->host->name, callout_address, s);
462   }
463
464 /* Create and connect the socket */
465
466 #ifdef SUPPORT_SOCKS
467 if (ob->socks_proxy)
468   {
469   int sock = socks_sock_connect(sc->host, sc->host_af, port, sc->interface,
470                                 sc->tblock, ob->connect_timeout);
471
472   if (sock >= 0)
473     {
474     if (early_data && early_data->data && early_data->len)
475       if (send(sock, early_data->data, early_data->len, 0) < 0)
476         {
477         int save_errno = errno;
478         HDEBUG(D_transport|D_acl|D_v)
479           {
480           debug_printf_indent("failed: %s", CUstrerror(save_errno));
481           if (save_errno == ETIMEDOUT)
482             debug_printf(" (timeout=%s)", readconf_printtime(ob->connect_timeout));
483           debug_printf("\n");
484           }
485         (void)close(sock);
486         sock = -1;
487         errno = save_errno;
488         }
489     }
490   return sock;
491   }
492 #endif
493
494 return smtp_sock_connect(sc->host, sc->host_af, port, sc->interface,
495                           sc->tblock, ob->connect_timeout, early_data);
496 }
497
498
499 /*************************************************
500 *        Flush outgoing command buffer           *
501 *************************************************/
502
503 /* This function is called only from smtp_write_command() below. It flushes
504 the buffer of outgoing commands. There is more than one in the buffer only when
505 pipelining.
506
507 Argument:
508   outblock   the SMTP output block
509   mode       further data expected, or plain
510
511 Returns:     TRUE if OK, FALSE on error, with errno set
512 */
513
514 static BOOL
515 flush_buffer(smtp_outblock * outblock, int mode)
516 {
517 int rc;
518 int n = outblock->ptr - outblock->buffer;
519 BOOL more = mode == SCMD_MORE;
520
521 HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n,
522   more ? " (more expected)" : "");
523
524 #ifndef DISABLE_TLS
525 if (outblock->cctx->tls_ctx)
526   rc = tls_write(outblock->cctx->tls_ctx, outblock->buffer, n, more);
527 else
528 #endif
529
530   {
531   if (outblock->conn_args)
532     {
533     blob early_data = { .data = outblock->buffer, .len = n };
534
535     /* We ignore the more-flag if we're doing a connect with early-data, which
536     means we won't get BDAT+data. A pity, but wise due to the idempotency
537     requirement: TFO with data can, in rare cases, replay the data to the
538     receiver. */
539
540     if (  (outblock->cctx->sock = smtp_connect(outblock->conn_args, &early_data))
541        < 0)
542       return FALSE;
543     outblock->conn_args = NULL;
544     rc = n;
545     }
546   else
547     {
548     rc = send(outblock->cctx->sock, outblock->buffer, n,
549 #ifdef MSG_MORE
550               more ? MSG_MORE : 0
551 #else
552               0
553 #endif
554              );
555
556 #if defined(__linux__)
557     /* This is a workaround for a current linux kernel bug: as of
558     5.6.8-200.fc31.x86_64  small (<MSS) writes get delayed by about 200ms,
559     This is despite NODELAY being active.
560     https://bugzilla.redhat.com/show_bug.cgi?id=1803806 */
561
562     if (!more)
563       setsockopt(outblock->cctx->sock, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
564 #endif
565     }
566   }
567
568 if (rc <= 0)
569   {
570   HDEBUG(D_transport|D_acl) debug_printf_indent("send failed: %s\n", strerror(errno));
571   return FALSE;
572   }
573
574 outblock->ptr = outblock->buffer;
575 outblock->cmd_count = 0;
576 return TRUE;
577 }
578
579
580
581 /*************************************************
582 *             Write SMTP command                 *
583 *************************************************/
584
585 /* The formatted command is left in big_buffer so that it can be reflected in
586 any error message.
587
588 Arguments:
589   sx         SMTP connection, contains buffer for pipelining, and socket
590   mode       buffer, write-with-more-likely, write
591   format     a format, starting with one of
592              of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT.
593              If NULL, flush pipeline buffer only.
594   ...        data for the format
595
596 Returns:     0 if command added to pipelining buffer, with nothing transmitted
597             +n if n commands transmitted (may still have buffered the new one)
598             -1 on error, with errno set
599 */
600
601 int
602 smtp_write_command(void * sx, int mode, const char *format, ...)
603 {
604 smtp_outblock * outblock = &((smtp_context *)sx)->outblock;
605 int rc = 0;
606
607 if (format)
608   {
609   gstring gs = { .size = big_buffer_size, .ptr = 0, .s = big_buffer };
610   va_list ap;
611
612   /* Use taint-unchecked routines for writing into big_buffer, trusting that
613   we'll never expand the results.  Actually, the error-message use - leaving
614   the results in big_buffer for potential later use - is uncomfortably distant.
615   XXX Would be better to assume all smtp commands are short, use normal pool
616   alloc rather than big_buffer, and another global for the data-for-error. */
617
618   va_start(ap, format);
619   if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, CS format, ap))
620     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
621       "SMTP");
622   va_end(ap);
623   string_from_gstring(&gs);
624
625   if (gs.ptr > outblock->buffersize)
626     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
627       "SMTP");
628
629   if (gs.ptr > outblock->buffersize - (outblock->ptr - outblock->buffer))
630     {
631     rc = outblock->cmd_count;                 /* flush resets */
632     if (!flush_buffer(outblock, SCMD_FLUSH)) return -1;
633     }
634
635   Ustrncpy(outblock->ptr, gs.s, gs.ptr);
636   outblock->ptr += gs.ptr;
637   outblock->cmd_count++;
638   gs.ptr -= 2; string_from_gstring(&gs); /* remove \r\n for error message */
639
640   /* We want to hide the actual data sent in AUTH transactions from reflections
641   and logs. While authenticating, a flag is set in the outblock to enable this.
642   The AUTH command itself gets any data flattened. Other lines are flattened
643   completely. */
644
645   if (outblock->authenticating)
646     {
647     uschar *p = big_buffer;
648     if (Ustrncmp(big_buffer, "AUTH ", 5) == 0)
649       {
650       p += 5;
651       while (isspace(*p)) p++;
652       while (!isspace(*p)) p++;
653       while (isspace(*p)) p++;
654       }
655     while (*p) *p++ = '*';
656     }
657
658   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP%c> %s\n",
659     mode == SCMD_BUFFER ? '|' : mode == SCMD_MORE ? '+' : '>',
660     big_buffer);
661   }
662
663 if (mode != SCMD_BUFFER)
664   {
665   rc += outblock->cmd_count;                /* flush resets */
666   if (!flush_buffer(outblock, mode)) return -1;
667   }
668
669 return rc;
670 }
671
672
673
674 /*************************************************
675 *          Read one line of SMTP response        *
676 *************************************************/
677
678 /* This function reads one line of SMTP response from the server host. This may
679 not be a complete response - it could be just part of a multiline response. We
680 have to use a buffer for incoming packets, because when pipelining or using
681 LMTP, there may well be more than one response in a single packet. This
682 function is called only from the one that follows.
683
684 Arguments:
685   inblock   the SMTP input block (contains holding buffer, socket, etc.)
686   buffer    where to put the line
687   size      space available for the line
688   timelimit deadline for reading the lime, seconds past epoch
689
690 Returns:    length of a line that has been put in the buffer
691             -1 otherwise, with errno set, and inblock->ptr adjusted
692 */
693
694 static int
695 read_response_line(smtp_inblock *inblock, uschar *buffer, int size, time_t timelimit)
696 {
697 uschar *p = buffer;
698 uschar *ptr = inblock->ptr;
699 uschar *ptrend = inblock->ptrend;
700 client_conn_ctx * cctx = inblock->cctx;
701
702 /* Loop for reading multiple packets or reading another packet after emptying
703 a previously-read one. */
704
705 for (;;)
706   {
707   int rc;
708
709   /* If there is data in the input buffer left over from last time, copy
710   characters from it until the end of a line, at which point we can return,
711   having removed any whitespace (which will include CR) at the end of the line.
712   The rules for SMTP say that lines end in CRLF, but there are have been cases
713   of hosts using just LF, and other MTAs are reported to handle this, so we
714   just look for LF. If we run out of characters before the end of a line,
715   carry on to read the next incoming packet. */
716
717   while (ptr < ptrend)
718     {
719     int c = *ptr++;
720     if (c == '\n')
721       {
722       while (p > buffer && isspace(p[-1])) p--;
723       *p = 0;
724       inblock->ptr = ptr;
725       return p - buffer;
726       }
727     *p++ = c;
728     if (--size < 4)
729       {
730       *p = 0;                     /* Leave malformed line for error message */
731       errno = ERRNO_SMTPFORMAT;
732       inblock->ptr = ptr;
733       return -1;
734       }
735     }
736
737   /* Need to read a new input packet. */
738
739   if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timelimit)) <= 0)
740     {
741     DEBUG(D_deliver|D_transport|D_acl|D_v)
742       debug_printf_indent(errno ? "  SMTP(%s)<<\n" : "  SMTP(closed)<<\n",
743         strerror(errno));
744     break;
745     }
746
747   /* Another block of data has been successfully read. Set up the pointers
748   and let the loop continue. */
749
750   ptrend = inblock->ptrend = inblock->buffer + rc;
751   ptr = inblock->buffer;
752   DEBUG(D_transport|D_acl) debug_printf_indent("read response data: size=%d\n", rc);
753   }
754
755 /* Get here if there has been some kind of recv() error; errno is set, but we
756 ensure that the result buffer is empty before returning. */
757
758 inblock->ptr = inblock->ptrend = inblock->buffer;
759 *buffer = 0;
760 return -1;
761 }
762
763
764
765
766
767 /*************************************************
768 *              Read SMTP response                *
769 *************************************************/
770
771 /* This function reads an SMTP response with a timeout, and returns the
772 response in the given buffer, as a string. A multiline response will contain
773 newline characters between the lines. The function also analyzes the first
774 digit of the reply code and returns FALSE if it is not acceptable. FALSE is
775 also returned after a reading error. In this case buffer[0] will be zero, and
776 the error code will be in errno.
777
778 Arguments:
779   sx        the SMTP connection (contains input block with holding buffer,
780                 socket, etc.)
781   buffer    where to put the response
782   size      the size of the buffer
783   okdigit   the expected first digit of the response
784   timeout   the timeout to use, in seconds
785
786 Returns:    TRUE if a valid, non-error response was received; else FALSE
787 */
788 /*XXX could move to smtp transport; no other users */
789
790 BOOL
791 smtp_read_response(void * sx0, uschar * buffer, int size, int okdigit,
792    int timeout)
793 {
794 smtp_context * sx = sx0;
795 uschar * ptr = buffer;
796 int count = 0;
797 time_t timelimit = time(NULL) + timeout;
798
799 errno = 0;  /* Ensure errno starts out zero */
800
801 #ifndef DISABLE_PIPE_CONNECT
802 if (sx->pending_BANNER || sx->pending_EHLO)
803   {
804   int rc;
805   if ((rc = smtp_reap_early_pipe(sx, &count)) != OK)
806     {
807     DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n");
808     buffer[0] = '\0';
809     if (rc == DEFER) errno = ERRNO_TLSFAILURE;
810     return FALSE;
811     }
812   }
813 #endif
814
815 /* This is a loop to read and concatenate the lines that make up a multi-line
816 response. */
817
818 for (;;)
819   {
820   if ((count = read_response_line(&sx->inblock, ptr, size, timelimit)) < 0)
821     return FALSE;
822
823   HDEBUG(D_transport|D_acl|D_v)
824     debug_printf_indent("  %s %s\n", ptr == buffer ? "SMTP<<" : "      ", ptr);
825
826   /* Check the format of the response: it must start with three digits; if
827   these are followed by a space or end of line, the response is complete. If
828   they are followed by '-' this is a multi-line response and we must look for
829   another line until the final line is reached. The only use made of multi-line
830   responses is to pass them back as error messages. We therefore just
831   concatenate them all within the buffer, which should be large enough to
832   accept any reasonable number of lines. */
833
834   if (count < 3 ||
835      !isdigit(ptr[0]) ||
836      !isdigit(ptr[1]) ||
837      !isdigit(ptr[2]) ||
838      (ptr[3] != '-' && ptr[3] != ' ' && ptr[3] != 0))
839     {
840     errno = ERRNO_SMTPFORMAT;    /* format error */
841     return FALSE;
842     }
843
844   /* If the line we have just read is a terminal line, line, we are done.
845   Otherwise more data has to be read. */
846
847   if (ptr[3] != '-') break;
848
849   /* Move the reading pointer upwards in the buffer and insert \n between the
850   components of a multiline response. Space is left for this by read_response_
851   line(). */
852
853   ptr += count;
854   *ptr++ = '\n';
855   size -= count + 1;
856   }
857
858 #ifdef TCP_FASTOPEN
859   tfo_out_check(sx->cctx.sock);
860 #endif
861
862 /* Return a value that depends on the SMTP return code. On some systems a
863 non-zero value of errno has been seen at this point, so ensure it is zero,
864 because the caller of this function looks at errno when FALSE is returned, to
865 distinguish between an unexpected return code and other errors such as
866 timeouts, lost connections, etc. */
867
868 errno = 0;
869 return buffer[0] == okdigit;
870 }
871
872 /* End of smtp_out.c */
873 /* vi: aw ai sw=2
874 */