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