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