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