1 /*
2  * msmtp.c
3  *
4  * This file is part of msmtp, an SMTP client.
5  *
6  * Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
7  * 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021
8  * Martin Lambers <marlam@marlam.de>
9  * Martin Stenberg <martin@gnutiken.se> (passwordeval support)
10  * Scott Shumate <sshumate@austin.rr.com> (aliases support)
11  *
12  *   This program is free software; you can redistribute it and/or modify
13  *   it under the terms of the GNU General Public License as published by
14  *   the Free Software Foundation; either version 3 of the License, or
15  *   (at your option) any later version.
16  *
17  *   This program is distributed in the hope that it will be useful,
18  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *   GNU General Public License for more details.
21  *
22  *   You should have received a copy of the GNU General Public License
23  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <time.h>
37 #include <getopt.h>
38 extern char *optarg;
39 extern int optind;
40 #include <unistd.h>
41 #include <fcntl.h>
42 #ifdef ENABLE_NLS
43 # include <locale.h>
44 #endif
45 #ifdef HAVE_SYSLOG
46 # include <syslog.h>
47 #endif
48 #ifdef HAVE_SIGNAL
49 # include <signal.h>
50 #endif
51 
52 #include "gettext.h"
53 #define _(string) gettext(string)
54 
55 #include "xalloc.h"
56 #include "conf.h"
57 #include "list.h"
58 #include "net.h"
59 #include "smtp.h"
60 #include "tools.h"
61 #include "aliases.h"
62 #include "password.h"
63 #ifdef HAVE_TLS
64 # include "mtls.h"
65 #endif /* HAVE_TLS */
66 
67 /* Default file names. */
68 #ifdef W32_NATIVE
69 #define SYSCONFFILE     "msmtprc.txt"
70 #define USERCONFFILE    "msmtprc.txt"
71 #else /* UNIX */
72 #define SYSCONFFILE     "msmtprc"
73 #define USERCONFFILE    ".msmtprc"
74 #endif
75 
76 /* The name of this program */
77 const char *prgname;
78 
79 
80 /*
81  * Die if memory allocation fails
82  */
83 
xalloc_die(void)84 void xalloc_die(void)
85 {
86     /* TRANSLATORS: msmtp shares a lot of code and translatable strings with
87        mpop <https://marlam.de/mpop>. */
88     fprintf(stderr, _("%s: FATAL: %s\n"), prgname, strerror(ENOMEM));
89     exit(EX_OSERR);
90 }
91 
92 
93 /*
94  * msmtp_password_callback()
95  *
96  * This function will be called by smtp_auth() to get a password if none was
97  * given.
98  */
99 
msmtp_password_callback(const char * hostname,const char * user)100 char *msmtp_password_callback(const char *hostname, const char *user)
101 {
102     return password_get(hostname, user, password_service_smtp, 1, 1);
103 }
104 
105 
106 /*
107  * msmtp_endsession()
108  *
109  * Quit an SMTP session and close the connection.
110  * QUIT is only sent when the flag 'quit' is set.
111  */
112 
msmtp_endsession(smtp_server_t * srv,int quit)113 void msmtp_endsession(smtp_server_t *srv, int quit)
114 {
115     char *tmp_errstr;
116 
117     if (quit)
118     {
119         tmp_errstr = NULL;
120         (void)smtp_quit(srv, &tmp_errstr);
121         free(tmp_errstr);
122     }
123     smtp_close(srv);
124 }
125 
126 
127 /*
128  * msmtp_rmqs()
129  *
130  * Sends an ETRN request to the SMTP server specified in the account 'acc'.
131  * If an error occurred, '*errstr' points to an allocated string that describes
132  * the error or is NULL, and '*msg' may contain the offending message from the
133  * SMTP server (or be NULL).
134  */
135 
msmtp_rmqs(account_t * acc,int debug,const char * rmqs_argument,list_t ** msg,char ** errstr)136 int msmtp_rmqs(account_t *acc, int debug, const char *rmqs_argument,
137         list_t **msg, char **errstr)
138 {
139     smtp_server_t srv;
140     int e;
141 #ifdef HAVE_TLS
142     mtls_cert_info_t *tci = NULL;
143     char *mtls_parameter_description = NULL;
144 #endif /* HAVE_TLS */
145 
146     *errstr = NULL;
147     *msg = NULL;
148 
149     /* create a new smtp_server_t */
150     srv = smtp_new(debug ? stdout : NULL, acc->protocol);
151 
152     /* connect */
153     if ((e = smtp_connect(&srv, acc->socketname, acc->proxy_host, acc->proxy_port,
154                     acc->host, acc->port, acc->source_ip, acc->timeout,
155                     NULL, NULL, errstr)) != NET_EOK)
156     {
157         return net_exitcode(e);
158     }
159 
160     /* prepare tls */
161 #ifdef HAVE_TLS
162     if (acc->tls)
163     {
164         if ((e = smtp_tls_init(&srv,
165                         acc->tls_key_file, acc->tls_cert_file, acc->password,
166                         acc->tls_trust_file, acc->tls_crl_file,
167                         acc->tls_sha256_fingerprint,
168                         acc->tls_sha1_fingerprint, acc->tls_md5_fingerprint,
169                         acc->tls_min_dh_prime_bits,
170                         acc->tls_priorities,
171                         acc->tls_host_override ? acc->tls_host_override : acc->host,
172                         acc->tls_nocertcheck,
173                         errstr)) != TLS_EOK)
174         {
175             return mtls_exitcode(e);
176         }
177     }
178 #endif /* HAVE_TLS */
179 
180     /* start tls for smtps servers */
181 #ifdef HAVE_TLS
182     if (acc->tls && acc->tls_nostarttls)
183     {
184         if (debug)
185         {
186             tci = mtls_cert_info_new();
187         }
188         if ((e = smtp_tls(&srv, tci,
189                         &mtls_parameter_description, errstr)) != TLS_EOK)
190         {
191             if (debug)
192             {
193                 mtls_cert_info_free(tci);
194                 free(mtls_parameter_description);
195             }
196             msmtp_endsession(&srv, 0);
197             return mtls_exitcode(e);
198         }
199         if (debug)
200         {
201             mtls_print_info(mtls_parameter_description, tci);
202             mtls_cert_info_free(tci);
203             free(mtls_parameter_description);
204         }
205     }
206 #endif /* HAVE_TLS */
207 
208     /* get greeting */
209     if ((e = smtp_get_greeting(&srv, msg, NULL, errstr)) != SMTP_EOK)
210     {
211         msmtp_endsession(&srv, 0);
212         return smtp_exitcode(e);
213     }
214 
215     /* initialize session */
216     if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
217     {
218         msmtp_endsession(&srv, 0);
219         return smtp_exitcode(e);
220     }
221 
222     /* start tls for starttls servers */
223 #ifdef HAVE_TLS
224     if (acc->tls && !acc->tls_nostarttls)
225     {
226         if (!(srv.cap.flags & SMTP_CAP_STARTTLS))
227         {
228             *errstr = xasprintf(_("the server does not support TLS "
229                         "via the STARTTLS command"));
230             msmtp_endsession(&srv, 1);
231             return EX_UNAVAILABLE;
232         }
233         if ((e = smtp_tls_starttls(&srv, msg, errstr)) != SMTP_EOK)
234         {
235             msmtp_endsession(&srv, 0);
236             return smtp_exitcode(e);
237         }
238         if (debug)
239         {
240             tci = mtls_cert_info_new();
241         }
242         if ((e = smtp_tls(&srv, tci,
243                         &mtls_parameter_description, errstr)) != TLS_EOK)
244         {
245             if (debug)
246             {
247                 mtls_cert_info_free(tci);
248                 free(mtls_parameter_description);
249             }
250             msmtp_endsession(&srv, 0);
251             return mtls_exitcode(e);
252         }
253         if (debug)
254         {
255             mtls_print_info(mtls_parameter_description, tci);
256             mtls_cert_info_free(tci);
257             free(mtls_parameter_description);
258         }
259         /* initialize again */
260         if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
261         {
262             msmtp_endsession(&srv, 0);
263             return smtp_exitcode(e);
264         }
265     }
266 #endif /* HAVE_TLS */
267 
268     if (!(srv.cap.flags & SMTP_CAP_ETRN))
269     {
270         *errstr = xasprintf(_("the server does not support "
271                     "Remote Message Queue Starting"));
272         msmtp_endsession(&srv, 1);
273         return EX_UNAVAILABLE;
274     }
275 
276     /* authenticate */
277     if (acc->auth_mech)
278     {
279         if (!(srv.cap.flags & SMTP_CAP_AUTH))
280         {
281             *errstr = xasprintf(
282                     _("the server does not support authentication"));
283             msmtp_endsession(&srv, 1);
284             return EX_UNAVAILABLE;
285         }
286         if ((e = smtp_auth(&srv, acc->host, acc->port,
287                         acc->username, acc->password,
288                         acc->ntlmdomain, acc->auth_mech,
289                         msmtp_password_callback, msg, errstr))
290                 != SMTP_EOK)
291         {
292             msmtp_endsession(&srv, 0);
293             return smtp_exitcode(e);
294         }
295     }
296 
297     /* send the ETRN request */
298     if ((e = smtp_etrn(&srv, rmqs_argument, msg, errstr)) != SMTP_EOK)
299     {
300         msmtp_endsession(&srv, 0);
301         return smtp_exitcode(e);
302     }
303 
304     /* end session */
305     msmtp_endsession(&srv, 1);
306     return EX_OK;
307 }
308 
309 
310 /*
311  * msmtp_serverinfo()
312  *
313  * Prints information about the SMTP server specified in the account 'acc'.
314  * If an error occurred, '*errstr' points to an allocated string that describes
315  * the error or is NULL, and '*msg' may contain the offending message from the
316  * SMTP server (or be NULL).
317  */
318 
msmtp_serverinfo(account_t * acc,int debug,list_t ** msg,char ** errstr)319 int msmtp_serverinfo(account_t *acc, int debug, list_t **msg, char **errstr)
320 {
321     smtp_server_t srv;
322     char *server_canonical_name = NULL;
323     char *server_address = NULL;
324     char *server_greeting = NULL;
325     int e;
326 #ifdef HAVE_TLS
327     mtls_cert_info_t *tci = NULL;
328     char *mtls_parameter_description = NULL;
329 #endif /* HAVE_TLS */
330 
331     *errstr = NULL;
332     *msg = NULL;
333 
334     /* create a new smtp_server_t */
335     srv = smtp_new(debug ? stdout : NULL, acc->protocol);
336 
337     /* connect */
338     if ((e = smtp_connect(&srv, acc->socketname, acc->proxy_host, acc->proxy_port,
339                     acc->host, acc->port, acc->source_ip, acc->timeout,
340                     &server_canonical_name, &server_address, errstr))
341             != NET_EOK)
342     {
343         e = net_exitcode(e);
344         goto error_exit;
345     }
346 
347     /* prepare tls */
348 #ifdef HAVE_TLS
349     if (acc->tls)
350     {
351         tci = mtls_cert_info_new();
352         if ((e = smtp_tls_init(&srv,
353                         acc->tls_key_file, acc->tls_cert_file, acc->password,
354                         acc->tls_trust_file, acc->tls_crl_file,
355                         acc->tls_sha256_fingerprint,
356                         acc->tls_sha1_fingerprint, acc->tls_md5_fingerprint,
357                         acc->tls_min_dh_prime_bits,
358                         acc->tls_priorities,
359                         acc->tls_host_override ? acc->tls_host_override : acc->host,
360                         acc->tls_nocertcheck,
361                         errstr)) != TLS_EOK)
362         {
363             e = mtls_exitcode(e);
364             goto error_exit;
365         }
366     }
367 #endif /* HAVE_TLS */
368 
369     /* start tls for smtps servers */
370 #ifdef HAVE_TLS
371     if (acc->tls && acc->tls_nostarttls)
372     {
373         if ((e = smtp_tls(&srv, tci,
374                         &mtls_parameter_description, errstr)) != TLS_EOK)
375         {
376             msmtp_endsession(&srv, 0);
377             e = mtls_exitcode(e);
378             goto error_exit;
379         }
380     }
381 #endif /* HAVE_TLS */
382 
383     /* get greeting */
384     if ((e = smtp_get_greeting(&srv, msg, &server_greeting,
385                     errstr)) != SMTP_EOK)
386     {
387         msmtp_endsession(&srv, 0);
388         e = smtp_exitcode(e);
389         goto error_exit;
390     }
391 
392     /* initialize session */
393     if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
394     {
395         msmtp_endsession(&srv, 0);
396         e = smtp_exitcode(e);
397         goto error_exit;
398     }
399 
400     /* start tls for starttls servers */
401 #ifdef HAVE_TLS
402     if (acc->tls && !acc->tls_nostarttls)
403     {
404         if (!(srv.cap.flags & SMTP_CAP_STARTTLS))
405         {
406             *errstr = xasprintf(_("the server does not support TLS "
407                         "via the STARTTLS command"));
408             msmtp_endsession(&srv, 1);
409             e = EX_UNAVAILABLE;
410             goto error_exit;
411         }
412         if ((e = smtp_tls_starttls(&srv, msg, errstr)) != SMTP_EOK)
413         {
414             msmtp_endsession(&srv, 0);
415             e = smtp_exitcode(e);
416             goto error_exit;
417         }
418         if ((e = smtp_tls(&srv, tci,
419                         &mtls_parameter_description, errstr)) != TLS_EOK)
420         {
421             msmtp_endsession(&srv, 0);
422             e = mtls_exitcode(e);
423             goto error_exit;
424         }
425         /* initialize again */
426         if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
427         {
428             msmtp_endsession(&srv, 0);
429             e = smtp_exitcode(e);
430             goto error_exit;
431         }
432     }
433 #endif /* HAVE_TLS */
434 
435     /* end session */
436     msmtp_endsession(&srv, 1);
437 
438     /* print results */
439     if (server_canonical_name && server_address)
440     {
441         printf(_("%s server at %s (%s [%s]), port %d:\n"),
442                 acc->protocol == SMTP_PROTO_SMTP ? "SMTP" : "LMTP",
443                 acc->host, server_canonical_name, server_address, acc->port);
444     }
445     else if (server_canonical_name)
446     {
447         printf(_("%s server at %s (%s), port %d:\n"),
448                 acc->protocol == SMTP_PROTO_SMTP ? "SMTP" : "LMTP",
449                 acc->host, server_canonical_name, acc->port);
450     }
451     else if (server_address)
452     {
453         printf(_("%s server at %s ([%s]), port %d:\n"),
454                 acc->protocol == SMTP_PROTO_SMTP ? "SMTP" : "LMTP",
455                 acc->host, server_address, acc->port);
456     }
457     else
458     {
459         printf(_("%s server at %s, port %d:\n"),
460                 acc->protocol == SMTP_PROTO_SMTP ? "SMTP" : "LMTP",
461                 acc->host, acc->port);
462     }
463     if (*server_greeting != '\0')
464     {
465         printf("    %s\n", sanitize_string(server_greeting));
466     }
467 #ifdef HAVE_TLS
468     if (acc->tls)
469     {
470         mtls_print_info(mtls_parameter_description, tci);
471     }
472 #endif /* HAVE_TLS */
473 #ifdef HAVE_TLS
474     if (srv.cap.flags == 0 && !(acc->tls && !acc->tls_nostarttls))
475 #else /* not HAVE_TLS */
476     if (srv.cap.flags == 0)
477 #endif /* not HAVE_TLS */
478     {
479         printf(_("No special capabilities.\n"));
480     }
481     else
482     {
483         printf(_("Capabilities:\n"));
484         if (srv.cap.flags & SMTP_CAP_SIZE)
485         {
486             printf("    SIZE %ld:\n        %s", srv.cap.size,
487                     _("Maximum message size is "));
488             if (srv.cap.size == 0)
489             {
490                 printf(_("unlimited\n"));
491             }
492             else
493             {
494                 printf(_("%ld bytes"), srv.cap.size);
495                 if (srv.cap.size > 1024 * 1024)
496                 {
497                     printf(_(" = %.2f MiB"),
498                             (float)srv.cap.size / (float)(1024 * 1024));
499                 }
500                 else if (srv.cap.size > 1024)
501                 {
502                     printf(_(" = %.2f KiB"), (float)srv.cap.size / 1024.0f);
503                 }
504                 printf("\n");
505             }
506         }
507         if (srv.cap.flags & SMTP_CAP_PIPELINING)
508         {
509             printf("    PIPELINING:\n        %s\n", _("Support for command "
510                         "grouping for faster transmission"));
511         }
512         if (srv.cap.flags & SMTP_CAP_ETRN)
513         {
514             printf("    ETRN:\n        %s\n", _("Support for RMQS "
515                         "(Remote Message Queue Starting)"));
516         }
517         if (srv.cap.flags & SMTP_CAP_DSN)
518         {
519             printf("    DSN:\n        %s\n", _("Support for "
520                         "Delivery Status Notifications"));
521         }
522 #ifdef HAVE_TLS
523         if ((acc->tls && !acc->tls_nostarttls)
524                 || (srv.cap.flags & SMTP_CAP_STARTTLS))
525 #else /* not HAVE_TLS */
526         if (srv.cap.flags & SMTP_CAP_STARTTLS)
527 #endif /* not HAVE_TLS */
528         {
529             printf("    STARTTLS:\n        %s\n", _("Support for "
530                         "TLS encryption via the STARTTLS command"));
531         }
532         if (srv.cap.flags & SMTP_CAP_AUTH)
533         {
534             printf("    AUTH:\n        %s\n        ",
535                     _("Supported authentication methods:"));
536             if (srv.cap.flags & SMTP_CAP_AUTH_PLAIN)
537             {
538                 printf("PLAIN ");
539             }
540             if (srv.cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_1)
541             {
542                 printf("SCRAM-SHA-1 ");
543             }
544             if (srv.cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_256)
545             {
546                 printf("SCRAM-SHA-256 ");
547             }
548             if (srv.cap.flags & SMTP_CAP_AUTH_EXTERNAL)
549             {
550                 printf("EXTERNAL ");
551             }
552             if (srv.cap.flags & SMTP_CAP_AUTH_GSSAPI)
553             {
554                 printf("GSSAPI ");
555             }
556             if (srv.cap.flags & SMTP_CAP_AUTH_CRAM_MD5)
557             {
558                 printf("CRAM-MD5 ");
559             }
560             if (srv.cap.flags & SMTP_CAP_AUTH_DIGEST_MD5)
561             {
562                 printf("DIGEST-MD5 ");
563             }
564             if (srv.cap.flags & SMTP_CAP_AUTH_LOGIN)
565             {
566                 printf("LOGIN ");
567             }
568             if (srv.cap.flags & SMTP_CAP_AUTH_NTLM)
569             {
570                 printf("NTLM ");
571             }
572             if (srv.cap.flags & SMTP_CAP_AUTH_OAUTHBEARER)
573             {
574                 printf("OAUTHBEARER ");
575             }
576             if (srv.cap.flags & SMTP_CAP_AUTH_XOAUTH2)
577             {
578                 printf("XOAUTH2 ");
579             }
580             printf("\n");
581         }
582 #ifdef HAVE_TLS
583         if ((srv.cap.flags & SMTP_CAP_STARTTLS) && !acc->tls)
584 #else /* not HAVE_TLS */
585         if (srv.cap.flags & SMTP_CAP_STARTTLS)
586 #endif /* not HAVE_TLS */
587         {
588             printf(_("This server might advertise more or other "
589                     "capabilities when TLS is active.\n"));
590         }
591     }
592 
593     e = EX_OK;
594 
595 error_exit:
596     free(server_canonical_name);
597     free(server_address);
598 #ifdef HAVE_TLS
599     if (tci)
600     {
601         mtls_cert_info_free(tci);
602     }
603     free(mtls_parameter_description);
604 #endif /* HAVE_TLS */
605     free(server_greeting);
606     return e;
607 }
608 
609 
610 /*
611  * msmtp_read_headers()
612  *
613  * Copies the headers of the mail from 'mailf' to a temporary file 'tmpf',
614  * including the blank line that separates the header from the body of the mail.
615  *
616  * If 'recipients' is not NULL: extracts all recipients from the To, Cc, and Bcc
617  * headers and adds them to 'recipients'. If Resent-* headers are present, all
618  * recipients from the Resent-To, Resent-Cc, Resent-Bcc headers in the first
619  * block of Resent- headers are extracted instead.
620  *
621  * If 'from' is not NULL: extracts the address from the From header and stores
622  * it in an allocated string. A pointer to this string is stored in 'from'.
623  *
624  * If 'have_date' is not NULL: set this flag to 1 if a Date header is present
625  * , and to 0 otherwise.
626  *
627  * See RFC2822, section 3 for the format of these headers.
628  *
629  * Return codes: EX_OK, EX_IOERR
630  */
631 
632 #define STATE_LINESTART_FRESH           0       /* a new line started; the
633                                                    previous line was not a
634                                                    recipient header */
635 #define STATE_LINESTART_AFTER_ADDRHDR   1       /* a new line started; the
636                                                    previous line was a
637                                                    recipient header */
638 #define STATE_OTHER_HDR                 2       /* a header we don't
639                                                    care about */
640 #define STATE_DATE1                     3       /* we saw "^D" */
641 #define STATE_DATE2                     4       /* we saw "^Da" */
642 #define STATE_DATE3                     5       /* we saw "^Dat" */
643 #define STATE_DATE4                     6       /* we saw "^Date" */
644 #define STATE_FROM1                     7       /* we saw "^F" */
645 #define STATE_FROM2                     8       /* we saw "^Fr" */
646 #define STATE_FROM3                     9       /* we saw "^Fro" */
647 #define STATE_TO                        10      /* we saw "^T" */
648 #define STATE_CC                        11      /* we saw "^C" */
649 #define STATE_BCC1                      12      /* we saw "^B" */
650 #define STATE_BCC2                      13      /* we saw "^Bc" */
651 #define STATE_ADDRHDR_ALMOST            14      /* we saw "^To", "^Cc"
652                                                    or "^Bcc" */
653 #define STATE_RESENT                    15      /* we saw part of "^Resent-" */
654 #define STATE_ADDRHDR_DEFAULT           16      /* in_rcpt_hdr and in_rcpt
655                                                    state our position */
656 #define STATE_ADDRHDR_DQUOTE            17      /* duoble quotes */
657 #define STATE_ADDRHDR_BRACKETS_START    18      /* entering <...> */
658 #define STATE_ADDRHDR_IN_BRACKETS       19      /* an address inside <> */
659 #define STATE_ADDRHDR_PARENTH_START     20      /* entering (...) */
660 #define STATE_ADDRHDR_IN_PARENTH        21      /* a comment inside () */
661 #define STATE_ADDRHDR_IN_ADDRESS        22      /* a bare address */
662 #define STATE_ADDRHDR_BACKQUOTE         23      /* we saw a '\\' */
663 #define STATE_HEADERS_END               24      /* we saw "^$", the blank line
664                                                    between headers and body */
665 
msmtp_read_headers(FILE * mailf,FILE * tmpf,list_t * recipients,char ** from,int * have_date,char ** errstr)666 int msmtp_read_headers(FILE *mailf, FILE *tmpf,
667         list_t *recipients,
668         char **from,
669         int *have_date,
670         char **errstr)
671 {
672     int c;
673     int state = STATE_LINESTART_FRESH;
674     int oldstate = STATE_LINESTART_FRESH;
675     int backquote_savestate = STATE_LINESTART_FRESH;
676     int parentheses_depth = 0;
677     int parentheses_savestate = STATE_LINESTART_FRESH;
678     int folded_rcpthdr_savestate = STATE_LINESTART_FRESH;
679     int from_hdr = -1;          /* -1 = before, 0 = in, 1 = after first From: */
680     int resent_index = -1;
681     int resent_block = -1;      /* -1 = before, 0 = in, 1 = after first block */
682     char *current_recipient = NULL;
683     size_t current_recipient_len = 0;
684     int forget_current_recipient = 0;
685     int finish_current_recipient = 0;
686     size_t bufsize = 0;
687     /* The buffer that is filled with the current recipient grows by
688      * 'bufsize_step' if the remaining space becomes too small. This value must
689      * be at least 2. Wasted characters are at most (bufsize_step - 1). A value
690      * of 10 means low wasted space and a low number of realloc()s per
691      * recipient. */
692     const size_t bufsize_step = 10;
693     /* We need two recipient lists: one for normal To, Cc, Bcc headers, and one
694      * for Resent-To, Resent-Cc, Resent-Bcc. The first list gathers adresses
695      * from all To, Cc, Bcc headers that are found. The second list gathers
696      * adresses only for the first block of Resent-* headers. If a Resent- block
697      * was seen, then the first list is ignored, and only the second list is
698      * appended to the recipient list given by the caller. */
699     list_t *normal_recipients_list = NULL;
700     list_t *normal_recipients = NULL;
701     list_t *resent_recipients_list = NULL;
702     list_t *resent_recipients = NULL;
703 
704     if (from)
705     {
706         *from = NULL;
707     }
708     if (have_date)
709     {
710         *have_date = 0;
711     }
712     if (recipients)
713     {
714         normal_recipients_list = list_new();
715         normal_recipients = normal_recipients_list;
716         resent_recipients_list = list_new();
717         resent_recipients = resent_recipients_list;
718     }
719 
720     for (;;)
721     {
722         c = fgetc(mailf);
723         /* Convert CRLF to LF. According to RFC 2822, CRs may only occur in a
724          * mail when they are followed by LF, so just ignoring CRs is ok. */
725         if (c == '\r')
726         {
727             continue;
728         }
729         oldstate = state;
730         if (c == EOF)
731         {
732             state = STATE_HEADERS_END;
733             if (current_recipient)
734                 finish_current_recipient = 1;
735         }
736         else
737         {
738             switch (state)
739             {
740                 case STATE_LINESTART_FRESH:
741                     parentheses_depth = 0;
742                     resent_index = -1;
743                     if (have_date && (c == 'd' || c == 'D'))
744                         state = STATE_DATE1;
745                     else if (from && from_hdr < 0 && (c == 'f' || c == 'F'))
746                         state = STATE_FROM1;
747                     else if (recipients && (c == 't' || c == 'T'))
748                         state = STATE_TO;
749                     else if (recipients && (c == 'c' || c == 'C'))
750                         state = STATE_CC;
751                     else if (recipients && (c == 'b' || c == 'B'))
752                         state = STATE_BCC1;
753                     else if (recipients && resent_block <= 0
754                             && (c == 'r' || c == 'R'))
755                     {
756                         resent_index = 0;
757                         state = STATE_RESENT;
758                     }
759                     else if (c == '\n')
760                         state = STATE_HEADERS_END;
761                     else
762                         state = STATE_OTHER_HDR;
763                     break;
764 
765                 case STATE_LINESTART_AFTER_ADDRHDR:
766                     resent_index = -1;
767                     if (c != ' ' && c != '\t')
768                     {
769                         if (current_recipient)
770                             finish_current_recipient = 1;
771                         else if (from_hdr == 0)
772                             from_hdr = -1; /* the preceding From: header was empty */
773                     }
774                     if (c == ' ' || c == '\t')
775                         state = folded_rcpthdr_savestate;
776                     else if (have_date && (c == 'd' || c == 'D'))
777                         state = STATE_DATE1;
778                     else if (from && from_hdr < 0 && (c == 'f' || c == 'F'))
779                         state = STATE_FROM1;
780                     else if (recipients && (c == 't' || c == 'T'))
781                         state = STATE_TO;
782                     else if (recipients && (c == 'c' || c == 'C'))
783                         state = STATE_CC;
784                     else if (recipients && (c == 'b' || c == 'B'))
785                         state = STATE_BCC1;
786                     else if (recipients && resent_block <= 0
787                         && (c == 'r' || c == 'R'))
788                     {
789                         resent_index = 0;
790                         state = STATE_RESENT;
791                     }
792                     else if (c == '\n')
793                         state = STATE_HEADERS_END;
794                     else
795                         state = STATE_OTHER_HDR;
796                     break;
797 
798                 case STATE_OTHER_HDR:
799                     if (resent_block == 0 && resent_index != 6)
800                         resent_block = 1;
801                     if (c == '\n')
802                         state = STATE_LINESTART_FRESH;
803                     break;
804 
805                 case STATE_RESENT:
806                     if (resent_index == 0 && (c == 'e' || c == 'E'))
807                         resent_index++;
808                     else if (resent_index == 1 && (c == 's' || c == 'S'))
809                         resent_index++;
810                     else if (resent_index == 2 && (c == 'e' || c == 'E'))
811                         resent_index++;
812                     else if (resent_index == 3 && (c == 'n' || c == 'N'))
813                         resent_index++;
814                     else if (resent_index == 4 && (c == 't' || c == 'T'))
815                         resent_index++;
816                     else if (resent_index == 5 && c == '-')
817                     {
818                         if (resent_block == -1)
819                             resent_block = 0;
820                         resent_index++;
821                     }
822                     else if (resent_index == 6 && (c == 't' || c == 'T'))
823                         state = STATE_TO;
824                     else if (resent_index == 6 && (c == 'c' || c == 'C'))
825                         state = STATE_CC;
826                     else if (resent_index == 6 && (c == 'b' || c == 'B'))
827                         state = STATE_BCC1;
828                     else if (c == '\n')
829                         state = STATE_LINESTART_FRESH;
830                     else
831                         state = STATE_OTHER_HDR;
832                     break;
833 
834                 case STATE_DATE1:
835                     if (c == 'a' || c == 'A')
836                         state = STATE_DATE2;
837                     else if (c == '\n')
838                         state = STATE_LINESTART_FRESH;
839                     else
840                         state = STATE_OTHER_HDR;
841                     break;
842 
843                 case STATE_DATE2:
844                     if (c == 't' || c == 'T')
845                         state = STATE_DATE3;
846                     else if (c == '\n')
847                         state = STATE_LINESTART_FRESH;
848                     else
849                         state = STATE_OTHER_HDR;
850                     break;
851 
852                 case STATE_DATE3:
853                     if (c == 'e' || c == 'E')
854                         state = STATE_DATE4;
855                     else if (c == '\n')
856                         state = STATE_LINESTART_FRESH;
857                     else
858                         state = STATE_OTHER_HDR;
859                     break;
860 
861                 case STATE_DATE4:
862                     if (c == ':')
863                     {
864                         *have_date = 1;
865                         state = STATE_OTHER_HDR;
866                     }
867                     else if (c == '\n')
868                         state = STATE_LINESTART_FRESH;
869                     else
870                         state = STATE_OTHER_HDR;
871                     break;
872 
873                 case STATE_FROM1:
874                     if (resent_block == 0 && resent_index != 6)
875                         resent_block = 1;
876                     if (c == 'r' || c == 'R')
877                         state = STATE_FROM2;
878                     else if (c == '\n')
879                         state = STATE_LINESTART_FRESH;
880                     else
881                         state = STATE_OTHER_HDR;
882                     break;
883 
884                 case STATE_FROM2:
885                     if (c == 'o' || c == 'O')
886                         state = STATE_FROM3;
887                     else if (c == '\n')
888                         state = STATE_LINESTART_FRESH;
889                     else
890                         state = STATE_OTHER_HDR;
891                     break;
892 
893                 case STATE_FROM3:
894                     if (c == 'm' || c == 'M')
895                     {
896                         from_hdr = 0;
897                         state = STATE_ADDRHDR_ALMOST;
898                     }
899                     else if (c == '\n')
900                         state = STATE_LINESTART_FRESH;
901                     else
902                         state = STATE_OTHER_HDR;
903                     break;
904 
905                 case STATE_TO:
906                     if (resent_block == 0 && resent_index != 6)
907                         resent_block = 1;
908                     if (c == 'o' || c == 'O')
909                         state = STATE_ADDRHDR_ALMOST;
910                     else if (c == '\n')
911                         state = STATE_LINESTART_FRESH;
912                     else
913                         state = STATE_OTHER_HDR;
914                     break;
915 
916                 case STATE_CC:
917                     if (resent_block == 0 && resent_index != 6)
918                         resent_block = 1;
919                     if (c == 'c' || c == 'C')
920                         state = STATE_ADDRHDR_ALMOST;
921                     else if (c == '\n')
922                         state = STATE_LINESTART_FRESH;
923                     else
924                         state = STATE_OTHER_HDR;
925                     break;
926 
927                 case STATE_BCC1:
928                     if (resent_block == 0 && resent_index != 6)
929                         resent_block = 1;
930                     if (c == 'c' || c == 'C')
931                         state = STATE_BCC2;
932                     else if (c == '\n')
933                         state = STATE_LINESTART_FRESH;
934                     else
935                         state = STATE_OTHER_HDR;
936                     break;
937 
938                 case STATE_BCC2:
939                     if (c == 'c' || c == 'C')
940                         state = STATE_ADDRHDR_ALMOST;
941                     else if (c == '\n')
942                         state = STATE_LINESTART_FRESH;
943                     else
944                         state = STATE_OTHER_HDR;
945                     break;
946 
947                 case STATE_ADDRHDR_ALMOST:
948                     if (from_hdr == 0 && c != ':')
949                         from_hdr = -1;
950                     if (c == ':')
951                         state = STATE_ADDRHDR_DEFAULT;
952                     else if (c == '\n')
953                         state = STATE_LINESTART_FRESH;
954                     else
955                         state = STATE_OTHER_HDR;
956                     break;
957 
958                 case STATE_ADDRHDR_DEFAULT:
959                     if (c == '\n')
960                     {
961                         if (current_recipient)
962                             finish_current_recipient = 1;
963                         folded_rcpthdr_savestate = state;
964                         state = STATE_LINESTART_AFTER_ADDRHDR;
965                     }
966                     else if (c == '\\')
967                     {
968                         backquote_savestate = state;
969                         state = STATE_ADDRHDR_BACKQUOTE;
970                     }
971                     else if (c == '(')
972                     {
973                         parentheses_savestate = state;
974                         state = STATE_ADDRHDR_PARENTH_START;
975                     }
976                     else if (c == '"')
977                     {
978                         if (current_recipient)
979                             forget_current_recipient = 1;
980                         state = STATE_ADDRHDR_DQUOTE;
981                     }
982                     else if (c == '<')
983                     {
984                         if (current_recipient)
985                             forget_current_recipient = 1;
986                         state = STATE_ADDRHDR_BRACKETS_START;
987                     }
988                     else if (c == ' ' || c == '\t')
989                         ; /* keep state */
990                     else if (c == ':')
991                     {
992                         if (current_recipient)
993                             forget_current_recipient = 1;
994                     }
995                     else if (c == ';' || c == ',')
996                     {
997                         if (current_recipient)
998                             finish_current_recipient = 1;
999                     }
1000                     else
1001                     {
1002                         if (current_recipient)
1003                             forget_current_recipient = 1;
1004                         state = STATE_ADDRHDR_IN_ADDRESS;
1005                     }
1006                     break;
1007 
1008                 case STATE_ADDRHDR_DQUOTE:
1009                     if (c == '\n')
1010                     {
1011                         folded_rcpthdr_savestate = state;
1012                         state = STATE_LINESTART_AFTER_ADDRHDR;
1013                     }
1014                     else if (c == '\\')
1015                     {
1016                         backquote_savestate = state;
1017                         state = STATE_ADDRHDR_BACKQUOTE;
1018                     }
1019                     else if (c == '"')
1020                         state = STATE_ADDRHDR_DEFAULT;
1021                     break;
1022 
1023                 case STATE_ADDRHDR_BRACKETS_START:
1024                     if (c == '\n')
1025                     {
1026                         folded_rcpthdr_savestate = state;
1027                         state = STATE_LINESTART_AFTER_ADDRHDR;
1028                     }
1029                     else if (c == '(')
1030                     {
1031                         parentheses_savestate = state;
1032                         state = STATE_ADDRHDR_PARENTH_START;
1033                     }
1034                     else if (c == '>')
1035                         state = STATE_ADDRHDR_DEFAULT;
1036                     else
1037                         state = STATE_ADDRHDR_IN_BRACKETS;
1038                     break;
1039 
1040                 case STATE_ADDRHDR_IN_BRACKETS:
1041                     if (c == '\n')
1042                     {
1043                         folded_rcpthdr_savestate = state;
1044                         state = STATE_LINESTART_AFTER_ADDRHDR;
1045                     }
1046                     else if (c == '\\')
1047                     {
1048                         backquote_savestate = state;
1049                         state = STATE_ADDRHDR_BACKQUOTE;
1050                     }
1051                     else if (c == '(')
1052                     {
1053                         parentheses_savestate = state;
1054                         state = STATE_ADDRHDR_PARENTH_START;
1055                     }
1056                     else if (c == '>')
1057                     {
1058                         finish_current_recipient = 1;
1059                         state = STATE_ADDRHDR_DEFAULT;
1060                     }
1061                     break;
1062 
1063                 case STATE_ADDRHDR_PARENTH_START:
1064                     if (c == '\n')
1065                     {
1066                         folded_rcpthdr_savestate = state;
1067                         state = STATE_LINESTART_AFTER_ADDRHDR;
1068                     }
1069                     else if (c == ')')
1070                         state = parentheses_savestate;
1071                     else
1072                     {
1073                         parentheses_depth++;
1074                         state = STATE_ADDRHDR_IN_PARENTH;
1075                     }
1076                     break;
1077 
1078                 case STATE_ADDRHDR_IN_PARENTH:
1079                     if (c == '\n')
1080                     {
1081                         folded_rcpthdr_savestate = state;
1082                         state = STATE_LINESTART_AFTER_ADDRHDR;
1083                     }
1084                     else if (c == '\\')
1085                     {
1086                         backquote_savestate = state;
1087                         state = STATE_ADDRHDR_BACKQUOTE;
1088                     }
1089                     else if (c == '(')
1090                         state = STATE_ADDRHDR_PARENTH_START;
1091                     else if (c == ')')
1092                     {
1093                         parentheses_depth--;
1094                         if (parentheses_depth == 0)
1095                             state = parentheses_savestate;
1096                     }
1097                     break;
1098 
1099                 case STATE_ADDRHDR_IN_ADDRESS:
1100                     if (c == '\n')
1101                     {
1102                         folded_rcpthdr_savestate = STATE_ADDRHDR_DEFAULT;
1103                         state = STATE_LINESTART_AFTER_ADDRHDR;
1104                     }
1105                     else if (c == '\\')
1106                     {
1107                         backquote_savestate = state;
1108                         state = STATE_ADDRHDR_BACKQUOTE;
1109                     }
1110                     else if (c == '"')
1111                     {
1112                         forget_current_recipient = 1;
1113                         state = STATE_ADDRHDR_DQUOTE;
1114                     }
1115                     else if (c == '(')
1116                     {
1117                         parentheses_savestate = state;
1118                         state = STATE_ADDRHDR_PARENTH_START;
1119                     }
1120                     else if (c == '<')
1121                     {
1122                         forget_current_recipient = 1;
1123                         state = STATE_ADDRHDR_BRACKETS_START;
1124                     }
1125                     else if (c == ' ' || c == '\t')
1126                         state = STATE_ADDRHDR_DEFAULT;
1127                     else if (c == ':')
1128                     {
1129                         forget_current_recipient = 1;
1130                         state = STATE_ADDRHDR_DEFAULT;
1131                     }
1132                     else if (c == ',' || c == ';')
1133                     {
1134                         finish_current_recipient = 1;
1135                         state = STATE_ADDRHDR_DEFAULT;
1136                     }
1137                     break;
1138 
1139                 case STATE_ADDRHDR_BACKQUOTE:
1140                     if (c == '\n')
1141                     {
1142                         folded_rcpthdr_savestate = STATE_ADDRHDR_DEFAULT;
1143                         state = STATE_LINESTART_AFTER_ADDRHDR;
1144                     }
1145                     else
1146                         state = backquote_savestate;
1147                     break;
1148             }
1149         }
1150 
1151         if (tmpf && c != EOF && fputc(c, tmpf) == EOF)
1152         {
1153             *errstr = xasprintf(_("cannot write mail headers to temporary "
1154                         "file: output error"));
1155             goto error_exit;
1156         }
1157 
1158         if (forget_current_recipient)
1159         {
1160             /* this was just junk */
1161             free(current_recipient);
1162             current_recipient = NULL;
1163             current_recipient_len = 0;
1164             bufsize = 0;
1165             forget_current_recipient = 0;
1166         }
1167         if (finish_current_recipient)
1168         {
1169             /* The current recipient just ended. Add it to the list */
1170             current_recipient[current_recipient_len] = '\0';
1171             if (from_hdr == 0)
1172             {
1173                 *from = current_recipient;
1174                 from_hdr = 1;
1175             }
1176             else if (recipients && resent_block == 0)
1177             {
1178                 list_insert(resent_recipients, current_recipient);
1179                 resent_recipients = resent_recipients->next;
1180             }
1181             else if (recipients)
1182             {
1183                 list_insert(normal_recipients, current_recipient);
1184                 normal_recipients = normal_recipients->next;
1185             }
1186             /* Reset for the next recipient */
1187             current_recipient = NULL;
1188             current_recipient_len = 0;
1189             bufsize = 0;
1190             finish_current_recipient = 0;
1191         }
1192         if ((state == STATE_ADDRHDR_IN_ADDRESS
1193                     || state == STATE_ADDRHDR_IN_BRACKETS)
1194                 && oldstate != STATE_ADDRHDR_PARENTH_START
1195                 && oldstate != STATE_ADDRHDR_IN_PARENTH
1196                 && oldstate != STATE_LINESTART_AFTER_ADDRHDR)
1197         {
1198             /* Add this character to the current recipient */
1199             current_recipient_len++;
1200             if (bufsize < current_recipient_len + 1)
1201             {
1202                 bufsize += bufsize_step;
1203                 current_recipient = xrealloc(current_recipient,
1204                         bufsize * sizeof(char));
1205             }
1206             /* sanitize characters */
1207             if (!iscntrl((unsigned char)c) && !isspace((unsigned char)c))
1208             {
1209                 current_recipient[current_recipient_len - 1] = (char)c;
1210             }
1211             else
1212             {
1213                 current_recipient[current_recipient_len - 1] = '_';
1214             }
1215         }
1216 
1217         if (state == STATE_HEADERS_END)
1218         {
1219             break;
1220         }
1221     }
1222 
1223     /* Corner case: we saw a "From: " header without a recipient. */
1224     if (from_hdr == 0)
1225     {
1226         *from = xstrdup("");
1227     }
1228 
1229     if (recipients)
1230     {
1231         if (resent_block >= 0)
1232         {
1233             list_xfree(normal_recipients_list, free);
1234             resent_recipients = resent_recipients_list;
1235             while (!list_is_empty(resent_recipients))
1236             {
1237                 resent_recipients = resent_recipients->next;
1238                 list_insert(recipients, resent_recipients->data);
1239                 recipients = recipients->next;
1240             }
1241             list_free(resent_recipients_list);
1242         }
1243         else
1244         {
1245             list_xfree(resent_recipients_list, free);
1246             normal_recipients = normal_recipients_list;
1247             while (!list_is_empty(normal_recipients))
1248             {
1249                 normal_recipients = normal_recipients->next;
1250                 list_insert(recipients, normal_recipients->data);
1251                 recipients = recipients->next;
1252             }
1253             list_free(normal_recipients_list);
1254         }
1255         normal_recipients_list = NULL;
1256         resent_recipients_list = NULL;
1257     }
1258 
1259     if (ferror(mailf))
1260     {
1261         *errstr = xasprintf(_("input error while reading the mail"));
1262         goto error_exit;
1263     }
1264 
1265     return EX_OK;
1266 
1267 error_exit:
1268     if (normal_recipients_list)
1269     {
1270         list_xfree(normal_recipients_list, free);
1271     }
1272     if (resent_recipients_list)
1273     {
1274         list_xfree(resent_recipients_list, free);
1275     }
1276     if (from)
1277     {
1278         free(*from);
1279         *from = NULL;
1280     }
1281     free(current_recipient);
1282     return EX_IOERR;
1283 }
1284 
1285 
1286 /*
1287  * msmtp_sendmail()
1288  *
1289  * Sends a mail. Returns a value from sysexits.h.
1290  * If an error occurred, '*errstr' points to an allocated string that describes
1291  * the error or is NULL, and '*msg' may contain the offending message from the
1292  * SMTP server (or be NULL).
1293  * In case of success, 'mailsize' contains the number of bytes of the mail
1294  * transferred to the SMTP server. In case of failure, its contents are
1295  * undefined.
1296  */
1297 
msmtp_sendmail(account_t * acc,list_t * recipients,FILE * prepend_header_file,int prepend_header_contains_from,FILE * header_file,FILE * f,int debug,long * mailsize,list_t ** lmtp_errstrs,list_t ** lmtp_error_msgs,list_t ** msg,char ** errstr)1298 int msmtp_sendmail(account_t *acc, list_t *recipients,
1299         FILE *prepend_header_file, int prepend_header_contains_from,
1300         FILE *header_file, FILE *f,
1301         int debug, long *mailsize,
1302         list_t **lmtp_errstrs, list_t **lmtp_error_msgs,
1303         list_t **msg, char **errstr)
1304 {
1305     smtp_server_t srv;
1306     int e;
1307 #ifdef HAVE_TLS
1308     mtls_cert_info_t *tci = NULL;
1309     char *mtls_parameter_description = NULL;
1310 #endif /* HAVE_TLS */
1311 
1312     *errstr = NULL;
1313     *msg = NULL;
1314     *lmtp_errstrs = NULL;
1315     *lmtp_error_msgs = NULL;
1316 
1317     /* create a new smtp_server_t */
1318     srv = smtp_new(debug ? stdout : NULL, acc->protocol);
1319 
1320     /* prepare tls */
1321 #ifdef HAVE_TLS
1322     if (acc->tls)
1323     {
1324         if ((e = smtp_tls_init(&srv,
1325                         acc->tls_key_file, acc->tls_cert_file, acc->password,
1326                         acc->tls_trust_file, acc->tls_crl_file,
1327                         acc->tls_sha256_fingerprint,
1328                         acc->tls_sha1_fingerprint, acc->tls_md5_fingerprint,
1329                         acc->tls_min_dh_prime_bits,
1330                         acc->tls_priorities,
1331                         acc->tls_host_override ? acc->tls_host_override : acc->host,
1332                         acc->tls_nocertcheck,
1333                         errstr)) != TLS_EOK)
1334         {
1335             e = mtls_exitcode(e);
1336             return e;
1337         }
1338     }
1339 #endif /* HAVE_TLS */
1340 
1341     /* connect */
1342     if ((e = smtp_connect(&srv, acc->socketname, acc->proxy_host, acc->proxy_port,
1343                     acc->host, acc->port, acc->source_ip, acc->timeout,
1344                     NULL, NULL, errstr)) != NET_EOK)
1345     {
1346         e = net_exitcode(e);
1347         return e;
1348     }
1349 
1350     /* start tls for smtps servers */
1351 #ifdef HAVE_TLS
1352     if (acc->tls && acc->tls_nostarttls)
1353     {
1354         if (debug)
1355         {
1356             tci = mtls_cert_info_new();
1357         }
1358         if ((e = smtp_tls(&srv, tci,
1359                         &mtls_parameter_description, errstr)) != TLS_EOK)
1360         {
1361             if (debug)
1362             {
1363                 mtls_cert_info_free(tci);
1364                 free(mtls_parameter_description);
1365             }
1366             msmtp_endsession(&srv, 0);
1367             e = mtls_exitcode(e);
1368             return e;
1369         }
1370         if (debug)
1371         {
1372             mtls_print_info(mtls_parameter_description, tci);
1373             mtls_cert_info_free(tci);
1374             free(mtls_parameter_description);
1375         }
1376     }
1377 #endif /* HAVE_TLS */
1378 
1379     /* get greeting */
1380     if ((e = smtp_get_greeting(&srv, msg, NULL, errstr)) != SMTP_EOK)
1381     {
1382         msmtp_endsession(&srv, 0);
1383         e = smtp_exitcode(e);
1384         return e;
1385     }
1386 
1387     /* initialize session */
1388     if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
1389     {
1390         msmtp_endsession(&srv, 0);
1391         e = smtp_exitcode(e);
1392         return e;
1393     }
1394 
1395     /* start tls for starttls servers */
1396 #ifdef HAVE_TLS
1397     if (acc->tls && !acc->tls_nostarttls)
1398     {
1399         if (!(srv.cap.flags & SMTP_CAP_STARTTLS))
1400         {
1401             *errstr = xasprintf(_("the server does not support TLS "
1402                         "via the STARTTLS command"));
1403             msmtp_endsession(&srv, 1);
1404             e = EX_UNAVAILABLE;
1405             return e;
1406         }
1407         if ((e = smtp_tls_starttls(&srv, msg, errstr)) != SMTP_EOK)
1408         {
1409             msmtp_endsession(&srv, 0);
1410             e = smtp_exitcode(e);
1411             return e;
1412         }
1413         if (debug)
1414         {
1415             tci = mtls_cert_info_new();
1416         }
1417         if ((e = smtp_tls(&srv, tci,
1418                         &mtls_parameter_description, errstr)) != TLS_EOK)
1419         {
1420             if (debug)
1421             {
1422                 mtls_cert_info_free(tci);
1423                 free(mtls_parameter_description);
1424             }
1425             msmtp_endsession(&srv, 0);
1426             e = mtls_exitcode(e);
1427             return e;
1428         }
1429         if (debug)
1430         {
1431             mtls_print_info(mtls_parameter_description, tci);
1432             mtls_cert_info_free(tci);
1433             free(mtls_parameter_description);
1434         }
1435         /* initialize again */
1436         if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
1437         {
1438             msmtp_endsession(&srv, 0);
1439             e = smtp_exitcode(e);
1440             return e;
1441         }
1442     }
1443 #endif /* HAVE_TLS */
1444 
1445     /* test for needed features */
1446     if ((acc->dsn_return || acc->dsn_notify) && !(srv.cap.flags & SMTP_CAP_DSN))
1447     {
1448         *errstr = xasprintf(_("the server does not support DSN"));
1449         msmtp_endsession(&srv, 1);
1450         e = EX_UNAVAILABLE;
1451         return e;
1452     }
1453     /* authenticate */
1454     if (acc->auth_mech)
1455     {
1456         if (!(srv.cap.flags & SMTP_CAP_AUTH))
1457         {
1458             *errstr = xasprintf(
1459                     _("the server does not support authentication"));
1460             msmtp_endsession(&srv, 1);
1461             e = EX_UNAVAILABLE;
1462             return e;
1463         }
1464         if ((e = smtp_auth(&srv, acc->host, acc->port,
1465                         acc->username, acc->password,
1466                         acc->ntlmdomain, acc->auth_mech,
1467                         msmtp_password_callback, msg, errstr))
1468                 != SMTP_EOK)
1469         {
1470             msmtp_endsession(&srv, 0);
1471             e = smtp_exitcode(e);
1472             return e;
1473         }
1474     }
1475 
1476     /* send the envelope */
1477     if ((e = smtp_send_envelope(&srv, acc->from, recipients,
1478                     acc->dsn_notify, acc->dsn_return, msg, errstr)) != SMTP_EOK)
1479     {
1480         msmtp_endsession(&srv, 0);
1481         e = smtp_exitcode(e);
1482         return e;
1483     }
1484     /* send header and body */
1485     *mailsize = 0;
1486     if (prepend_header_file)
1487     {
1488         /* first: prepended headers, if any */
1489         if ((e = smtp_send_mail(&srv, prepend_header_file,
1490                         1, 1, 1, 1, mailsize,
1491                         errstr)) != SMTP_EOK)
1492         {
1493             msmtp_endsession(&srv, 0);
1494             e = smtp_exitcode(e);
1495             return e;
1496         }
1497     }
1498     /* next: original mail headers */
1499     if ((e = smtp_send_mail(&srv, header_file,
1500                     !prepend_header_contains_from, /* keep_from */
1501                     !acc->undisclosed_recipients,  /* keep_to */
1502                     !acc->undisclosed_recipients,  /* keep_cc */
1503                     !acc->undisclosed_recipients
1504                     && !acc->remove_bcc_headers,   /* keep_bcc */
1505                     mailsize, errstr)) != SMTP_EOK)
1506     {
1507         msmtp_endsession(&srv, 0);
1508         e = smtp_exitcode(e);
1509         return e;
1510     }
1511     /* then: the body from the original file */
1512     if ((e = smtp_send_mail(&srv, f, 1, 1, 1, 1, mailsize, errstr)) != SMTP_EOK)
1513     {
1514         msmtp_endsession(&srv, 0);
1515         e = smtp_exitcode(e);
1516         return e;
1517     }
1518     /* end the mail */
1519     if (acc->protocol == SMTP_PROTO_SMTP)
1520     {
1521         e = smtp_end_mail(&srv, msg, errstr);
1522     }
1523     else
1524     {
1525         e = smtp_end_mail_lmtp(&srv, recipients,
1526                 lmtp_errstrs, lmtp_error_msgs, errstr);
1527     }
1528     if (e != SMTP_EOK)
1529     {
1530         msmtp_endsession(&srv, 0);
1531         e = smtp_exitcode(e);
1532         return e;
1533     }
1534 
1535     /* end session */
1536     msmtp_endsession(&srv, 1);
1537 
1538     return EX_OK;
1539 }
1540 
1541 
1542 /*
1543  * print_error()
1544  *
1545  * Print an error message
1546  */
1547 
1548 /* make gcc print format warnings for this function */
1549 #ifdef __GNUC__
1550 void print_error(const char *format, ...)
1551     __attribute__ ((format (printf, 1, 2)));
1552 #endif
1553 
print_error(const char * format,...)1554 void print_error(const char *format, ...)
1555 {
1556     va_list args;
1557     fprintf(stderr, "%s: ", prgname);
1558     va_start(args, format);
1559     vfprintf(stderr, format, args);
1560     va_end(args);
1561     fprintf(stderr, "\n");
1562 }
1563 
1564 
1565 /*
1566  * msmtp_configure()
1567  *
1568  * Tries autoconfiguration for the given mail address based on the methods
1569  * described in RFC 8314 (SRV records).
1570  * If successfull, this function will print a configuration file excerpt to
1571  * standard output and return EX_OK.
1572  * Otherwise, it will print an appropriate error message to standard error
1573  * and return an EX_* status.
1574  */
1575 
msmtp_configure(const char * address,const char * conffile)1576 int msmtp_configure(const char *address, const char *conffile)
1577 {
1578 #ifdef HAVE_LIBRESOLV
1579 
1580     int e;
1581 
1582     char *local_part;
1583     char *domain_part;
1584 
1585     char *submissions_query;
1586     char *submission_query;
1587 
1588     char *hostname = NULL;
1589     int port = -1;
1590     int starttls = -1;
1591 
1592     char *tmpstr;
1593 
1594     split_mail_address(address, &local_part, &domain_part);
1595     if (!domain_part || domain_part[0] == '\0' || local_part[0] == '\0')
1596     {
1597         print_error(_("automatic configuration based on SRV records failed: %s"),
1598                 _("invalid mail address"));
1599         free(local_part);
1600         free(domain_part);
1601         return EX_DATAERR;
1602     }
1603 
1604     submissions_query = net_get_srv_query(domain_part, "submissions");
1605     e = net_get_srv_record(submissions_query, &hostname, &port);
1606     if (e == NET_EOK) {
1607         starttls = 0;
1608     } else {
1609         submission_query = net_get_srv_query(domain_part, "submission");
1610         e = net_get_srv_record(submission_query, &hostname, &port);
1611         if (e == NET_EOK) {
1612             starttls = 1;
1613         } else {
1614             char *errstr = xasprintf(_("no SRV records for %s or %s"),
1615                     submissions_query, submission_query);
1616             print_error(_("automatic configuration based on SRV records failed: %s"),
1617                     errstr);
1618             free(errstr);
1619             free(submissions_query);
1620             free(submission_query);
1621             free(local_part);
1622             free(domain_part);
1623             return EX_NOHOST;
1624         }
1625         free(submission_query);
1626     }
1627     free(submissions_query);
1628 
1629     /* comment header */
1630 
1631     tmpstr = xasprintf(_("copy this to your configuration file %s"), conffile);
1632     printf("# - %s\n", tmpstr);
1633     free(tmpstr);
1634     if (!check_hostname_matches_domain(hostname, domain_part))
1635         printf("# - %s\n", _("warning: the host does not match the mail domain; please check"));
1636 #if defined HAVE_LIBSECRET
1637     tmpstr = xasprintf("secret-tool store --label=msmtp host %s service smtp user %s", hostname, local_part);
1638     printf("# - %s\n#   %s\n", _("add your password to the key ring:"), tmpstr);
1639     free(tmpstr);
1640 #elif defined HAVE_MACOSXKEYRING
1641     tmpstr = xasprintf("security add-internet-password -s %s -r smtp -a %s -w", hostname, local_part);
1642     printf("# - %s\n#   %s\n", _("add your password to the key ring:"), tmpstr);
1643     free(tmpstr);
1644 #else
1645     printf("# - %s\n#   %s\n", _("encrypt your password:"), "gpg -e -o ~/.msmtp-password.gpg");
1646 #endif
1647 
1648     /* account definition */
1649     printf("account %s\n", address);
1650     printf("host %s\n", hostname);
1651     printf("port %d\n", port);
1652     printf("tls on\n");
1653     printf("tls_starttls %s\n", starttls ? "on" : "off");
1654     printf("auth on\n");
1655     printf("user %s\n", local_part);
1656 #if !defined HAVE_LIBSECRET && !defined HAVE_MACOSXKEYRING
1657     printf("passwordeval gpg --no-tty -q -d ~/.msmtp-password.gpg\n");
1658 #endif
1659     printf("from %s\n", address);
1660 
1661     free(local_part);
1662     free(domain_part);
1663     free(hostname);
1664     return EX_OK;
1665 
1666 #else
1667 
1668     print_error(_("automatic configuration based on SRV records failed: %s"),
1669             _("this system lacks libresolv"));
1670     return EX_UNAVAILABLE;
1671 
1672 #endif
1673 }
1674 
1675 
1676 /*
1677  * msmtp_get_log_info()
1678  *
1679  * Gather log information for syslog or logfile and put it in a string:
1680  * - host=%s
1681  * - tls=on|off
1682  * - auth=on|off
1683  * - user=%s (only if auth == on and username != NULL)
1684  * - from=%s
1685  * - recipients=%s,%s,...
1686  * - mailsize=%s (only if exitcode == EX_OK)
1687  * - smtpstatus=%s (only if a smtp msg is available)
1688  * - smtpmsg='%s' (only if a smtp msg is available)
1689  * - errormsg='%s' (only if exitcode != EX_OK and an error msg is available)
1690  * - exitcode=%s
1691  * 'exitcode' must be one of the sysexits.h exitcodes.
1692  * This function cannot fail.
1693  */
1694 
msmtp_get_log_info(account_t * acc,list_t * recipients,long mailsize,list_t * errmsg,char * errstr,int exitcode)1695 char *msmtp_get_log_info(account_t *acc, list_t *recipients, long mailsize,
1696         list_t *errmsg, char *errstr, int exitcode)
1697 {
1698     int i;
1699     size_t s;
1700     list_t *l;
1701     char *line;
1702     int n;
1703     char *p;
1704     char *tmp;
1705     /* temporary strings: */
1706     char *mailsize_str = NULL;
1707     const char *exitcode_str;
1708     char *smtpstatus_str = NULL;
1709     char *smtperrmsg_str = NULL;
1710 
1711 
1712     /* gather information */
1713 
1714     line = NULL;
1715     /* mailsize */
1716     if (exitcode == EX_OK)
1717     {
1718         mailsize_str = xasprintf("%ld", mailsize);
1719     }
1720     /* exitcode */
1721     exitcode_str = exitcode_to_string(exitcode);
1722     /* smtp status and smtp error message */
1723     if (errmsg)
1724     {
1725         smtpstatus_str = xasprintf("%d", smtp_msg_status(errmsg));
1726         l = errmsg;
1727         s = 0;
1728         while (!list_is_empty(l))
1729         {
1730             l = l->next;
1731             s += strlen(l->data) + 2;
1732         }
1733         s += 1;
1734         smtperrmsg_str = xmalloc(s * sizeof(char));
1735         smtperrmsg_str[0] = '\'';
1736         i = 1;
1737         l = errmsg;
1738         while (!list_is_empty(l))
1739         {
1740             l = l->next;
1741             p = sanitize_string(l->data);
1742             while (*p != '\0')
1743             {
1744                 /* hide single quotes to make the info easy to parse */
1745                 smtperrmsg_str[i] = (*p == '\'') ? '?' : *p;
1746                 p++;
1747                 i++;
1748             }
1749             smtperrmsg_str[i++] = '\\';
1750             smtperrmsg_str[i++] = 'n';
1751         }
1752         i -= 2;
1753         smtperrmsg_str[i++] = '\'';
1754         smtperrmsg_str[i++] = '\0';
1755     }
1756 
1757     /* calculate the length of the log line */
1758 
1759     s = 0;
1760     /* "host=%s " */
1761     s += 5 + strlen(acc->host) + 1;
1762     /* "tls=on|off " */
1763     s += 4 + (acc->tls ? 2 : 3) + 1;
1764     /* "auth=on|off " */
1765     s += 5 + (acc->auth_mech ? 2 : 3) + 1;
1766     /* "user=%s " */
1767     if (acc->auth_mech && acc->username)
1768     {
1769         s += 5 + strlen(acc->username) + 1;
1770     }
1771     /* "from=%s " */
1772     s += 5 + strlen(acc->from) + 1;
1773     /* "recipients=%s,%s,... " */
1774     s += 11;
1775     l = recipients;
1776     while (!list_is_empty(l))
1777     {
1778         l = l->next;
1779         s += strlen(l->data) + 1;
1780     }
1781     /* "mailsize=%s " */
1782     if (exitcode == EX_OK)
1783     {
1784         s += 9 + strlen(mailsize_str) + 1;
1785     }
1786     /* "smtpstatus=%s smtpmsg=%s " */
1787     if (errmsg)
1788     {
1789         s += 11 + strlen(smtpstatus_str) + 1 + 8 + strlen(smtperrmsg_str) + 1;
1790     }
1791     /* "errormsg='%s' */
1792     if (exitcode != EX_OK && errstr[0] != '\0')
1793     {
1794         s += 10 + strlen(errstr) + 2;
1795     }
1796     /* "exitcode=%s" */
1797     s += 9 + strlen(exitcode_str);
1798     /* '\0' */
1799     s++;
1800 
1801     line = xmalloc(s * sizeof(char));
1802 
1803     /* build the log line */
1804 
1805     p = line;
1806     n = snprintf(p, s, "host=%s tls=%s auth=%s ",
1807             acc->host, (acc->tls ? "on" : "off"),
1808             (acc->auth_mech ? "on" : "off"));
1809     s -= n;
1810     p += n;
1811     if (acc->auth_mech && acc->username)
1812     {
1813         n = snprintf(p, s, "user=%s ", acc->username);
1814         s -= n;
1815         p += n;
1816     }
1817     n = snprintf(p, s, "from=%s recipients=", acc->from);
1818     s -= n;
1819     p += n;
1820     l = recipients;
1821     while (!list_is_empty(l))
1822     {
1823         l = l->next;
1824         n = snprintf(p, s, "%s,", (char *)(l->data));
1825         s -= n;
1826         p += n;
1827     }
1828     /* delete the last ',' */
1829     *(p - 1) = ' ';
1830     if (exitcode == EX_OK)
1831     {
1832         n = snprintf(p, s, "mailsize=%s ", mailsize_str);
1833         s -= n;
1834         p += n;
1835     }
1836     if (errmsg)
1837     {
1838         n = snprintf(p, s, "smtpstatus=%s smtpmsg=%s ",
1839                 smtpstatus_str, smtperrmsg_str);
1840         s -= n;
1841         p += n;
1842     }
1843     if (exitcode != EX_OK && errstr[0] != '\0')
1844     {
1845         /* hide single quotes to make the info easy to parse */
1846         tmp = errstr;
1847         while (*tmp)
1848         {
1849             if (*tmp == '\'')
1850             {
1851                 *tmp = '?';
1852             }
1853             tmp++;
1854         }
1855         n = snprintf(p, s, "errormsg='%s' ", sanitize_string(errstr));
1856         s -= n;
1857         p += n;
1858     }
1859     (void)snprintf(p, s, "exitcode=%s", exitcode_str);
1860 
1861     free(mailsize_str);
1862     free(smtpstatus_str);
1863     free(smtperrmsg_str);
1864     return line;
1865 }
1866 
1867 
1868 /*
1869  * msmtp_log_to_file()
1870  *
1871  * Append a log entry to 'logfile' with the following information:
1872  * - date/time in the format given by 'logfile_time_format' (may be NULL)
1873  * - the log line as delivered by msmtp_get_log_info
1874  */
1875 
msmtp_log_to_file(const char * logfile,const char * logfile_time_format,const char * loginfo)1876 void msmtp_log_to_file(const char *logfile, const char *logfile_time_format,
1877         const char *loginfo)
1878 {
1879     FILE *f = NULL;
1880     time_t t;
1881     struct tm *tm;
1882     char *failure_reason;
1883     const char *time_fmt;
1884     char time_str[128];
1885     int e;
1886 
1887     /* get time */
1888     t = time(NULL); /* cannot fail */
1889     tm = localtime(&t); /* cannot fail */
1890     time_fmt = logfile_time_format ? logfile_time_format : "%b %d %H:%M:%S";
1891     if (strftime(time_str, sizeof(time_str), time_fmt, tm) == 0)
1892     {
1893         /* a return value of 0 is only an error with a non-empty time_fmt,
1894          * but we know it is non-empty since we cannot configure an empty
1895          * logfile_time_format in msmtp (it would be set to NULL). */
1896         failure_reason = xasprintf(_("invalid logfile_time_format"));
1897         goto log_failure;
1898     }
1899 
1900     /* write log to file */
1901     if (strcmp(logfile, "-") == 0)
1902     {
1903         f = stdout;
1904     }
1905     else
1906     {
1907         if (!(f = fopen(logfile, "a")))
1908         {
1909             failure_reason = xasprintf(_("cannot open: %s"), strerror(errno));
1910             goto log_failure;
1911         }
1912         if ((e = lock_file(f, TOOLS_LOCK_WRITE, 10)) != 0)
1913         {
1914             if (e == 1)
1915             {
1916                 failure_reason = xasprintf(
1917                         _("cannot lock (tried for %d seconds): %s"),
1918                         10, strerror(errno));
1919             }
1920             else
1921             {
1922                 failure_reason = xasprintf(_("cannot lock: %s"),
1923                         strerror(errno));
1924             }
1925             goto log_failure;
1926         }
1927     }
1928     if ((fputs(time_str, f) == EOF) || (fputc(' ', f) == EOF)
1929         || (fputs(loginfo, f) == EOF) || (fputc('\n', f) == EOF))
1930     {
1931         failure_reason = xstrdup(_("output error"));
1932         goto log_failure;
1933     }
1934     if (f != stdout && fclose(f) != 0)
1935     {
1936         failure_reason = xstrdup(strerror(errno));
1937         goto log_failure;
1938     }
1939 
1940     return;
1941 
1942     /* error exit target */
1943 log_failure:
1944     if (f && f != stdout)
1945     {
1946         fclose(f);
1947     }
1948     print_error(_("cannot log to %s: %s"), logfile, failure_reason);
1949     free(failure_reason);
1950     if (loginfo)
1951     {
1952         print_error(_("log info was: %s"), loginfo);
1953     }
1954 }
1955 
1956 
1957 /*
1958  * msmtp_log_to_syslog()
1959  *
1960  * Log the information delivered by msmtp_get_log_info() to syslog
1961  * the facility_str must be one of "LOG_MAIL", "LOG_USER", "LOG_LOCAL0", ...
1962  * "LOG_LOCAL7"
1963  * If 'error' is set, LOG_ERR is used, else LOG_INFO is used.
1964  */
1965 
1966 #ifdef HAVE_SYSLOG
msmtp_log_to_syslog(const char * facility_str,const char * loginfo,int error)1967 void msmtp_log_to_syslog(const char *facility_str,
1968         const char *loginfo, int error)
1969 {
1970     int facility;
1971 
1972     if (facility_str[4] == 'M')
1973     {
1974         facility = LOG_MAIL;
1975     }
1976     else if (facility_str[4] == 'U')
1977     {
1978         facility = LOG_USER;
1979     }
1980     else if (facility_str[9] == '0')
1981     {
1982         facility = LOG_LOCAL0;
1983     }
1984     else if (facility_str[9] == '1')
1985     {
1986         facility = LOG_LOCAL1;
1987     }
1988     else if (facility_str[9] == '2')
1989     {
1990         facility = LOG_LOCAL2;
1991     }
1992     else if (facility_str[9] == '3')
1993     {
1994         facility = LOG_LOCAL3;
1995     }
1996     else if (facility_str[9] == '4')
1997     {
1998         facility = LOG_LOCAL4;
1999     }
2000     else if (facility_str[9] == '5')
2001     {
2002         facility = LOG_LOCAL5;
2003     }
2004     else if (facility_str[9] == '6')
2005     {
2006         facility = LOG_LOCAL6;
2007     }
2008     else
2009     {
2010         facility = LOG_LOCAL7;
2011     }
2012 
2013     openlog(PACKAGE_NAME, 0, facility);
2014     syslog(error ? LOG_ERR : LOG_INFO, "%s", loginfo);
2015     closelog();
2016 }
2017 #endif /* HAVE_SYSLOG */
2018 
2019 
2020 /*
2021  * msmtp_construct_env_from()
2022  *
2023  * OBSOLETE: triggered by auto_from, uses maildomain. both are replaced
2024  * with substitution patterns supported in from.
2025  *
2026  * Build an envelope from address for the current user.
2027  * If maildomain is not NULL and not the empty string, it will be the domain
2028  * part of the address. Otherwise, the address won't have a domain part.
2029  */
2030 
msmtp_construct_env_from(const char * maildomain)2031 char *msmtp_construct_env_from(const char *maildomain)
2032 {
2033     char *envelope_from;
2034     size_t len;
2035 
2036     envelope_from = get_username();
2037     if (maildomain && *maildomain != '\0')
2038     {
2039         len = strlen(envelope_from);
2040         envelope_from = xrealloc(envelope_from,
2041                 ((len + 1 + strlen(maildomain) + 1) * sizeof(char)));
2042         envelope_from[len] = '@';
2043         strcpy(envelope_from + len + 1, maildomain);
2044     }
2045     return envelope_from;
2046 }
2047 
2048 
2049 /*
2050  * msmtp_print_version()
2051  *
2052  * Print --version information
2053  */
2054 
msmtp_print_version(void)2055 void msmtp_print_version(void)
2056 {
2057     char *sysconfdir;
2058     char *sysconffile;
2059     char *userconffile;
2060 
2061     printf(_("%s version %s\n"), PACKAGE_NAME, VERSION);
2062     printf(_("Platform: %s\n"), PLATFORM);
2063     /* TLS/SSL support */
2064     printf(_("TLS/SSL library: %s\n"),
2065 #ifdef HAVE_LIBGNUTLS
2066             "GnuTLS"
2067 #elif defined (HAVE_LIBSSL)
2068             "OpenSSL"
2069 #elif defined (HAVE_LIBTLS)
2070             "libtls"
2071 #else
2072             _("none")
2073 #endif
2074           );
2075     /* Authentication support */
2076     printf(_("Authentication library: %s\n"
2077                 "Supported authentication methods:\n"),
2078 #ifdef HAVE_LIBGSASL
2079             _("GNU SASL; oauthbearer and xoauth2: built-in")
2080 #else
2081             _("built-in")
2082 #endif /* HAVE_LIBGSASL */
2083           );
2084     if (smtp_client_supports_authmech("PLAIN"))
2085     {
2086         printf("plain ");
2087     }
2088     if (smtp_client_supports_authmech("SCRAM-SHA-1"))
2089     {
2090         printf("scram-sha-1 ");
2091     }
2092     if (smtp_client_supports_authmech("SCRAM-SHA-256"))
2093     {
2094         printf("scram-sha-256 ");
2095     }
2096     if (smtp_client_supports_authmech("EXTERNAL"))
2097     {
2098         printf("external ");
2099     }
2100     if (smtp_client_supports_authmech("GSSAPI"))
2101     {
2102         printf("gssapi ");
2103     }
2104     if (smtp_client_supports_authmech("CRAM-MD5"))
2105     {
2106         printf("cram-md5 ");
2107     }
2108     if (smtp_client_supports_authmech("DIGEST-MD5"))
2109     {
2110         printf("digest-md5 ");
2111     }
2112     if (smtp_client_supports_authmech("LOGIN"))
2113     {
2114         printf("login ");
2115     }
2116     if (smtp_client_supports_authmech("NTLM"))
2117     {
2118         printf("ntlm ");
2119     }
2120     if (smtp_client_supports_authmech("OAUTHBEARER"))
2121     {
2122         printf("oauthbearer ");
2123     }
2124     if (smtp_client_supports_authmech("XOAUTH2"))
2125     {
2126         printf("xoauth2 ");
2127     }
2128     printf("\n");
2129     /* Internationalized Domain Names support */
2130     printf(_("IDN support: "));
2131 #if defined(HAVE_LIBIDN) \
2132         || (defined(HAVE_GAI_IDN) && (!defined(HAVE_TLS) \
2133             || (defined(HAVE_LIBGNUTLS) && GNUTLS_VERSION_NUMBER >= 0x030400)))
2134     printf(_("enabled"));
2135 #else
2136     printf(_("disabled"));
2137 #endif
2138     printf("\n");
2139     /* Native language support */
2140     printf(_("NLS: "));
2141 #ifdef ENABLE_NLS
2142     printf(_("enabled"));
2143     printf(_(", LOCALEDIR is %s"), LOCALEDIR);
2144 #else
2145     printf(_("disabled"));
2146 #endif
2147     printf("\n");
2148     printf(_("Keyring support: "));
2149 #if !defined HAVE_LIBSECRET && !defined HAVE_MACOSXKEYRING
2150     printf(_("none"));
2151 #else
2152 # ifdef HAVE_LIBSECRET
2153     printf(_("Gnome "));
2154 # endif
2155 # ifdef HAVE_MACOSXKEYRING
2156     printf(_("MacOS "));
2157 # endif
2158 #endif
2159     printf("\n");
2160     sysconfdir = get_sysconfdir();
2161     sysconffile = get_filename(sysconfdir, SYSCONFFILE);
2162     printf(_("System configuration file name: %s\n"), sysconffile);
2163     free(sysconffile);
2164     free(sysconfdir);
2165     userconffile = get_userconfig(USERCONFFILE);
2166     printf(_("User configuration file name: %s\n"), userconffile);
2167     free(userconffile);
2168     printf("\n");
2169     printf(_("Copyright (C) %d Martin Lambers and others.\n"
2170                 "This is free software.  You may redistribute copies of "
2171                     "it under the terms of\n"
2172                 "the GNU General Public License "
2173                     "<http://www.gnu.org/licenses/gpl.html>.\n"
2174                 "There is NO WARRANTY, to the extent permitted by law.\n"), 2021);
2175 }
2176 
2177 
2178 /*
2179  * msmtp_print_help()
2180  *
2181  * Print --help information
2182  */
2183 
msmtp_print_help(void)2184 void msmtp_print_help(void)
2185 {
2186     printf(_("Usage:\n\n"));
2187     printf(_("Sendmail mode (default):\n"
2188              "  %s [option...] [--] recipient...\n"
2189              "  %s [option...] -t [--] [recipient...]\n"
2190              "  Read a mail from standard input and transmit it to an SMTP "
2191                 "or LMTP server.\n"), prgname, prgname);
2192     printf(_("Configuration mode:\n"
2193              "  %s --configure=mailadress\n"
2194              "  Generate and print configuration for address.\n"), prgname);
2195     printf(_("Server information mode:\n"
2196              "  %s [option...] --serverinfo\n"
2197              "  Print information about a server.\n"), prgname);
2198     printf(_("Remote Message Queue Starting mode:\n"
2199              "  %s [option...] --rmqs=host|@domain|#queue\n"
2200              "  Send a Remote Message Queue Starting request to a server.\n\n"),
2201              prgname);
2202     printf(_("General options:\n"));
2203     printf(_("  --version                    print version\n"));
2204     printf(_("  --help                       print help\n"));
2205     printf(_("  -P, --pretend                print configuration info and exit\n"));
2206     printf(_("  -d, --debug                  print debugging information\n"));
2207     printf(_("Changing the mode of operation:\n"));
2208     printf(_("  --configure=mailaddress      generate and print configuration for address\n"));
2209     printf(_("  -S, --serverinfo             print information about the server\n"));
2210     printf(_("  --rmqs=host|@domain|#queue   send a Remote Message Queue Starting request\n"));
2211     printf(_("Configuration options:\n"));
2212     printf(_("  -C, --file=filename          set configuration file\n"));
2213     printf(_("  -a, --account=id             use the given account instead of the account\n"
2214              "                               named \"default\"; its settings may be changed\n"
2215              "                               with command-line options\n"));
2216     printf(_("  --host=hostname              set the server, use only command-line settings;\n"
2217              "                               do not use any configuration file data\n"));
2218     printf(_("  --port=number                set port number\n"));
2219     printf(_("  --source-ip=[IP]             set/unset source ip address to bind the socket to\n"));
2220     printf(_("  --proxy-host=[IP|hostname]   set/unset proxy\n"));
2221     printf(_("  --proxy-port=[number]        set/unset proxy port\n"));
2222     printf(_("  --socket=[socketname]        set/unset local socket to connect to\n"));
2223     printf(_("  --timeout=(off|seconds)      set/unset network timeout in seconds\n"));
2224     printf(_("  --protocol=(smtp|lmtp)       use the given sub protocol\n"));
2225     printf(_("  --domain=string              set the argument of EHLO or LHLO command\n"));
2226     printf(_("  --auth[=(on|off|method)]     enable/disable authentication and optionally\n"
2227              "                               choose the method\n"));
2228     printf(_("  --user=[username]            set/unset user name for authentication\n"));
2229     printf(_("  --passwordeval=[eval]        evaluate password for authentication\n"));
2230     printf(_("  --tls[=(on|off)]             enable/disable TLS encryption\n"));
2231     printf(_("  --tls-starttls[=(on|off)]    enable/disable STARTTLS for TLS\n"));
2232     printf(_("  --tls-trust-file=[file]      set/unset trust file for TLS\n"));
2233     printf(_("  --tls-crl-file=[file]        set/unset revocation file for TLS\n"));
2234     printf(_("  --tls-fingerprint=[f]        set/unset trusted certificate fingerprint for TLS\n"));
2235     printf(_("  --tls-certcheck[=(on|off)]   enable/disable server certificate checks for TLS\n"));
2236     printf(_("  --tls-key-file=[file]        set/unset private key file for TLS\n"));
2237     printf(_("  --tls-cert-file=[file]       set/unset private cert file for TLS\n"));
2238     printf(_("  --tls-priorities=[prios]     set/unset TLS priorities.\n"));
2239     printf(_("  --tls-host-override=[host]   set/unset override for TLS host verification.\n"));
2240     printf(_("  --tls-min-dh-prime-bits=[b]  set/unset minimum bit size of DH prime\n"));
2241     printf(_("Options specific to sendmail mode:\n"));
2242     printf(_("  --auto-from[=(on|off)]       enable/disable automatic envelope-from addresses\n"));
2243     printf(_("  -f, --from=address           set envelope from address\n"));
2244     printf(_("  --maildomain=[domain]        set the domain for automatic envelope from\n"
2245              "                               addresses\n"));
2246     printf(_("  -N, --dsn-notify=(off|cond)  set/unset DSN conditions\n"));
2247     printf(_("  -R, --dsn-return=(off|ret)   set/unset DSN amount\n"));
2248     printf(_("  -X, --logfile=[file]         set/unset log file\n"));
2249     printf(_("  --logfile-time-format=[fmt]  set/unset log file time format for strftime()\n"));
2250     printf(_("  --syslog[=(on|off|facility)] enable/disable/configure syslog logging\n"));
2251     printf(_("  -t, --read-recipients        read additional recipients from the mail\n"));
2252     printf(_("  --read-envelope-from         read envelope from address from the mail\n"));
2253     printf(_("  --aliases=[file]             set/unset aliases file\n"));
2254     printf(_("  --set-from-header[=(auto|on|off)] set From header handling\n"));
2255     printf(_("  --set-date-header[=(auto|off)] set Date header handling\n"));
2256     printf(_("  --remove-bcc-headers[=(on|off)] enable/disable removal of Bcc headers\n"));
2257     printf(_("  --undisclosed-recipients[=(on|off)] enable/disable replacement of To/Cc/Bcc\n"
2258              "                               with To: undisclosed-recipients:;\n"));
2259     printf(_("  --                           end of options\n"));
2260     printf(_("Accepted but ignored: -A, -B, -bm, -F, -G, -h, -i, -L, -m, -n, -O, -o, -v\n"));
2261     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
2262 }
2263 
2264 
2265 /*
2266  * msmtp_cmdline()
2267  *
2268  * Process the command line
2269  */
2270 
2271 typedef struct
2272 {
2273     /* the configuration */
2274     int print_version;
2275     int print_help;
2276     int print_conf;
2277     int debug;
2278     int pretend;
2279     int read_recipients;
2280     int read_envelope_from;
2281     /* mode of operation */
2282     int sendmail;
2283     int configure;
2284     char *configure_address;
2285     int serverinfo;
2286     int rmqs;
2287     char *rmqs_argument;
2288     /* account information from the command line */
2289     account_t *cmdline_account;
2290     const char *account_id;
2291     char *user_conffile;
2292     /* additional information */
2293     char *full_name;
2294     /* the list of recipients */
2295     list_t *recipients;
2296 } msmtp_cmdline_conf_t;
2297 
2298 /* long options without a corresponding short option */
2299 #define LONGONLYOPT_VERSION                     (256 + 0)
2300 #define LONGONLYOPT_HELP                        (256 + 1)
2301 #define LONGONLYOPT_HOST                        (256 + 2)
2302 #define LONGONLYOPT_PORT                        (256 + 3)
2303 #define LONGONLYOPT_TIMEOUT                     (256 + 4)
2304 #define LONGONLYOPT_AUTH                        (256 + 5)
2305 #define LONGONLYOPT_USER                        (256 + 6)
2306 #define LONGONLYOPT_PASSWORDEVAL                (256 + 7)
2307 #define LONGONLYOPT_TLS                         (256 + 8)
2308 #define LONGONLYOPT_TLS_STARTTLS                (256 + 9)
2309 #define LONGONLYOPT_TLS_TRUST_FILE              (256 + 10)
2310 #define LONGONLYOPT_TLS_CRL_FILE                (256 + 11)
2311 #define LONGONLYOPT_TLS_FINGERPRINT             (256 + 12)
2312 #define LONGONLYOPT_TLS_KEY_FILE                (256 + 13)
2313 #define LONGONLYOPT_TLS_CERT_FILE               (256 + 14)
2314 #define LONGONLYOPT_TLS_CERTCHECK               (256 + 15)
2315 #define LONGONLYOPT_TLS_FORCE_SSLV3             (256 + 16)
2316 #define LONGONLYOPT_TLS_MIN_DH_PRIME_BITS       (256 + 17)
2317 #define LONGONLYOPT_TLS_PRIORITIES              (256 + 18)
2318 #define LONGONLYOPT_TLS_HOST_OVERRIDE           (256 + 19)
2319 #define LONGONLYOPT_PROTOCOL                    (256 + 20)
2320 #define LONGONLYOPT_DOMAIN                      (256 + 21)
2321 #define LONGONLYOPT_KEEPBCC                     (256 + 22)
2322 #define LONGONLYOPT_RMQS                        (256 + 23)
2323 #define LONGONLYOPT_SYSLOG                      (256 + 24)
2324 #define LONGONLYOPT_MAILDOMAIN                  (256 + 25)
2325 #define LONGONLYOPT_AUTO_FROM                   (256 + 26)
2326 #define LONGONLYOPT_READ_ENVELOPE_FROM          (256 + 27)
2327 #define LONGONLYOPT_ALIASES                     (256 + 28)
2328 #define LONGONLYOPT_PROXY_HOST                  (256 + 29)
2329 #define LONGONLYOPT_PROXY_PORT                  (256 + 30)
2330 #define LONGONLYOPT_ADD_MISSING_FROM_HEADER     (256 + 31)
2331 #define LONGONLYOPT_ADD_MISSING_DATE_HEADER     (256 + 32)
2332 #define LONGONLYOPT_REMOVE_BCC_HEADERS          (256 + 33)
2333 #define LONGONLYOPT_UNDISCLOSED_RECIPIENTS      (256 + 34)
2334 #define LONGONLYOPT_SOURCE_IP                   (256 + 35)
2335 #define LONGONLYOPT_LOGFILE_TIME_FORMAT         (256 + 36)
2336 #define LONGONLYOPT_CONFIGURE                   (256 + 37)
2337 #define LONGONLYOPT_SOCKET                      (256 + 38)
2338 #define LONGONLYOPT_SET_FROM_HEADER             (256 + 39)
2339 #define LONGONLYOPT_SET_DATE_HEADER             (256 + 40)
2340 
msmtp_cmdline(msmtp_cmdline_conf_t * conf,int argc,char * argv[])2341 int msmtp_cmdline(msmtp_cmdline_conf_t *conf, int argc, char *argv[])
2342 {
2343     struct option options[] =
2344     {
2345         { "version", no_argument, 0, LONGONLYOPT_VERSION },
2346         { "help", no_argument, 0, LONGONLYOPT_HELP },
2347         { "configure", required_argument, 0, LONGONLYOPT_CONFIGURE },
2348         { "pretend", no_argument, 0, 'P' },
2349         /* accept an optional argument for sendmail compatibility: */
2350         { "debug", optional_argument, 0, 'd' },
2351         { "serverinfo", no_argument, 0, 'S' },
2352         { "rmqs", required_argument, 0, LONGONLYOPT_RMQS },
2353         { "file", required_argument, 0, 'C' },
2354         { "account", required_argument, 0, 'a' },
2355         { "host", required_argument, 0, LONGONLYOPT_HOST },
2356         { "port", required_argument, 0, LONGONLYOPT_PORT },
2357         { "timeout", required_argument, 0, LONGONLYOPT_TIMEOUT},
2358         /* for compatibility with versions <= 1.4.1: */
2359         { "connect-timeout", required_argument, 0, LONGONLYOPT_TIMEOUT},
2360         { "auto-from", optional_argument, 0, LONGONLYOPT_AUTO_FROM },
2361         { "from", required_argument, 0, 'f' },
2362         { "maildomain", required_argument, 0, LONGONLYOPT_MAILDOMAIN },
2363         { "auth", optional_argument, 0, LONGONLYOPT_AUTH },
2364         { "user", required_argument, 0, LONGONLYOPT_USER },
2365         { "passwordeval", required_argument, 0, LONGONLYOPT_PASSWORDEVAL },
2366         { "tls", optional_argument, 0, LONGONLYOPT_TLS },
2367         { "tls-starttls", optional_argument, 0, LONGONLYOPT_TLS_STARTTLS },
2368         { "tls-trust-file", required_argument, 0, LONGONLYOPT_TLS_TRUST_FILE },
2369         { "tls-crl-file", required_argument, 0, LONGONLYOPT_TLS_CRL_FILE },
2370         { "tls-fingerprint", required_argument, 0,
2371             LONGONLYOPT_TLS_FINGERPRINT },
2372         { "tls-key-file", required_argument, 0, LONGONLYOPT_TLS_KEY_FILE },
2373         { "tls-cert-file", required_argument, 0, LONGONLYOPT_TLS_CERT_FILE },
2374         { "tls-certcheck", optional_argument, 0, LONGONLYOPT_TLS_CERTCHECK },
2375         { "tls-force-sslv3", optional_argument, 0,
2376             LONGONLYOPT_TLS_FORCE_SSLV3 },
2377         { "tls-min-dh-prime-bits", required_argument, 0,
2378             LONGONLYOPT_TLS_MIN_DH_PRIME_BITS },
2379         { "tls-priorities", required_argument, 0, LONGONLYOPT_TLS_PRIORITIES },
2380         { "tls-host-override", required_argument, 0, LONGONLYOPT_TLS_HOST_OVERRIDE },
2381         { "dsn-notify", required_argument, 0, 'N' },
2382         { "dsn-return", required_argument, 0, 'R' },
2383         { "protocol", required_argument, 0, LONGONLYOPT_PROTOCOL },
2384         { "domain", required_argument, 0, LONGONLYOPT_DOMAIN },
2385         { "logfile", required_argument, 0, 'X' },
2386         { "logfile-time-format", required_argument, 0,
2387             LONGONLYOPT_LOGFILE_TIME_FORMAT },
2388         { "syslog", optional_argument, 0, LONGONLYOPT_SYSLOG },
2389         { "aliases", required_argument, 0, LONGONLYOPT_ALIASES },
2390         { "proxy-host", required_argument, 0, LONGONLYOPT_PROXY_HOST },
2391         { "proxy-port", required_argument, 0, LONGONLYOPT_PROXY_PORT },
2392         { "add-missing-from-header", optional_argument, 0,
2393             LONGONLYOPT_ADD_MISSING_FROM_HEADER },
2394         { "add-missing-date-header", optional_argument, 0,
2395             LONGONLYOPT_ADD_MISSING_DATE_HEADER },
2396         { "set-from-header", optional_argument, 0,
2397             LONGONLYOPT_SET_FROM_HEADER },
2398         { "set-date-header", optional_argument, 0,
2399             LONGONLYOPT_SET_DATE_HEADER },
2400         { "remove-bcc-headers", optional_argument, 0,
2401             LONGONLYOPT_REMOVE_BCC_HEADERS },
2402         { "undisclosed-recipients", optional_argument, 0,
2403             LONGONLYOPT_UNDISCLOSED_RECIPIENTS },
2404         { "source-ip", required_argument, 0, LONGONLYOPT_SOURCE_IP },
2405         { "socket", required_argument, 0, LONGONLYOPT_SOCKET },
2406         { "keepbcc", optional_argument, 0, LONGONLYOPT_KEEPBCC },
2407         { "read-recipients", no_argument, 0, 't' },
2408         { "read-envelope-from", no_argument, 0,
2409             LONGONLYOPT_READ_ENVELOPE_FROM },
2410         { 0, 0, 0, 0 }
2411     };
2412     int error_code;
2413     int c;
2414     int i;
2415     int rcptc;
2416     char **rcptv;
2417     FILE *tmpf = NULL;
2418     char *errstr;
2419 #ifdef HAVE_FMEMOPEN
2420     size_t rcptf_size;
2421     void *rcptf_buf = NULL;
2422 #endif
2423 
2424     /* the program name */
2425     prgname = get_prgname(argv[0]);
2426     /* the configuration */
2427     conf->print_version = 0;
2428     conf->print_help = 0;
2429     conf->print_conf = 0;
2430     conf->debug = 0;
2431     conf->pretend = 0;
2432     conf->read_recipients = 0;
2433     conf->read_envelope_from = 0;
2434     /* mode of operation */
2435     conf->sendmail = 1;
2436     conf->configure = 0;
2437     conf->configure_address = NULL;
2438     conf->serverinfo = 0;
2439     conf->rmqs = 0;
2440     conf->rmqs_argument = NULL;
2441     /* account information from the command line */
2442     conf->cmdline_account = account_new(NULL, NULL);
2443     conf->account_id = NULL;
2444     conf->user_conffile = NULL;
2445     /* additional information */
2446     conf->full_name = NULL;
2447     /* the recipients */
2448     conf->recipients = NULL;
2449 
2450     /* process the command line */
2451     error_code = 0;
2452     for (;;)
2453     {
2454         c = getopt_long(argc, argv, "Pd::SC:a:f:N:R:X:tA:B:b:F:Gh:iL:mnO:o:v",
2455                 options, NULL);
2456         if (c == -1)
2457         {
2458             break;
2459         }
2460         switch(c)
2461         {
2462             case LONGONLYOPT_VERSION:
2463                 conf->print_version = 1;
2464                 conf->sendmail = 0;
2465                 conf->serverinfo = 0;
2466                 break;
2467 
2468             case LONGONLYOPT_HELP:
2469                 conf->print_help = 1;
2470                 conf->sendmail = 0;
2471                 conf->serverinfo = 0;
2472                 break;
2473 
2474             case LONGONLYOPT_CONFIGURE:
2475                 conf->configure = 1;
2476                 free(conf->configure_address);
2477                 conf->configure_address = xstrdup(optarg);
2478                 conf->sendmail = 0;
2479                 conf->serverinfo = 0;
2480                 break;
2481 
2482             case 'P':
2483                 conf->print_conf = 1;
2484                 conf->pretend = 1;
2485                 break;
2486 
2487             case 'v':
2488             case 'd':
2489                 conf->print_conf = 1;
2490                 conf->debug = 1;
2491                 /* only care about the optional argument if it's "0.1", which is
2492                  * the only argument that's documented for sendmail: it prints
2493                  * version information */
2494                 if (optarg && strcmp(optarg, "0.1") == 0)
2495                 {
2496                     conf->print_version = 1;
2497                 }
2498                 break;
2499 
2500             case 'S':
2501                 if (conf->rmqs)
2502                 {
2503                     print_error(_("cannot use both --serverinfo and --rmqs"));
2504                     error_code = 1;
2505                 }
2506                 else
2507                 {
2508                     conf->serverinfo = 1;
2509                     conf->sendmail = 0;
2510                     conf->rmqs = 0;
2511                 }
2512                 break;
2513 
2514             case LONGONLYOPT_RMQS:
2515                 if (conf->serverinfo)
2516                 {
2517                     print_error(_("cannot use both --serverinfo and --rmqs"));
2518                     error_code = 1;
2519                 }
2520                 else
2521                 {
2522                     conf->rmqs = 1;
2523                     conf->rmqs_argument = optarg;
2524                     conf->sendmail = 0;
2525                     conf->serverinfo = 0;
2526                 }
2527                 break;
2528 
2529             case 'C':
2530                 free(conf->user_conffile);
2531                 conf->user_conffile = xstrdup(optarg);
2532                 break;
2533 
2534             case 'a':
2535                 if (conf->cmdline_account->host)
2536                 {
2537                     print_error(_("cannot use both --host and --account"));
2538                     error_code = 1;
2539                 }
2540                 else
2541                 {
2542                     conf->account_id = optarg;
2543                 }
2544                 break;
2545 
2546             case LONGONLYOPT_HOST:
2547                 if (conf->account_id)
2548                 {
2549                     print_error(_("cannot use both --host and --account"));
2550                     error_code = 1;
2551                 }
2552                 else
2553                 {
2554                     free(conf->cmdline_account->host);
2555                     conf->cmdline_account->host = xstrdup(optarg);
2556                     conf->cmdline_account->mask |= ACC_HOST;
2557                 }
2558                 break;
2559 
2560             case LONGONLYOPT_PORT:
2561                 conf->cmdline_account->port = get_pos_int(optarg);
2562                 if (conf->cmdline_account->port < 1
2563                         || conf->cmdline_account->port > 65535)
2564                 {
2565                     print_error(_("invalid argument %s for %s"),
2566                             optarg, "--port");
2567                     error_code = 1;
2568                 }
2569                 conf->cmdline_account->mask |= ACC_PORT;
2570                 break;
2571 
2572             case LONGONLYOPT_TIMEOUT:
2573                 if (is_off(optarg))
2574                 {
2575                     conf->cmdline_account->timeout = 0;
2576                 }
2577                 else
2578                 {
2579                     conf->cmdline_account->timeout =
2580                         get_pos_int(optarg);
2581                     if (conf->cmdline_account->timeout < 1)
2582                     {
2583                         print_error(_("invalid argument %s for %s"),
2584                                 optarg, "--timeout");
2585                         error_code = 1;
2586                     }
2587                 }
2588                 conf->cmdline_account->mask |= ACC_TIMEOUT;
2589                 break;
2590 
2591             case LONGONLYOPT_AUTO_FROM:
2592                 if (!optarg || is_on(optarg))
2593                 {
2594                     conf->cmdline_account->auto_from = 1;
2595                 }
2596                 else if (is_off(optarg))
2597                 {
2598                     conf->cmdline_account->auto_from = 0;
2599                 }
2600                 else
2601                 {
2602                     print_error(_("invalid argument %s for %s"),
2603                             optarg, "--auto-from");
2604                     error_code = 1;
2605                 }
2606                 conf->cmdline_account->mask |= ACC_AUTO_FROM;
2607                 break;
2608 
2609             case 'f':
2610                 if (conf->read_envelope_from)
2611                 {
2612                     print_error(_("cannot use both --from and "
2613                                 "--read-envelope-from"));
2614                     error_code = 1;
2615                 }
2616                 else
2617                 {
2618                     free(conf->cmdline_account->from);
2619                     /* Accept '<>' to mean an empty from address, to fix Debian
2620                      * bug 612679. */
2621                     if (strcmp(optarg, "<>") == 0)
2622                     {
2623                         conf->cmdline_account->from = xstrdup("");
2624                     }
2625                     else
2626                     {
2627                         conf->cmdline_account->from = xstrdup(optarg);
2628                     }
2629                     conf->cmdline_account->mask |= ACC_FROM;
2630                 }
2631                 break;
2632 
2633             case LONGONLYOPT_MAILDOMAIN:
2634                 free(conf->cmdline_account->maildomain);
2635                 conf->cmdline_account->maildomain =
2636                     (*optarg == '\0') ? NULL : xstrdup(optarg);
2637                 conf->cmdline_account->mask |= ACC_MAILDOMAIN;
2638                 break;
2639 
2640             case LONGONLYOPT_AUTH:
2641                 free(conf->cmdline_account->auth_mech);
2642                 if (!optarg || is_on(optarg))
2643                 {
2644                     conf->cmdline_account->auth_mech = xstrdup("");
2645                 }
2646                 else if (is_off(optarg))
2647                 {
2648                     conf->cmdline_account->auth_mech = NULL;
2649                 }
2650                 else if (check_auth_arg(optarg) == 0)
2651                 {
2652                     conf->cmdline_account->auth_mech = xstrdup(optarg);
2653                 }
2654                 else
2655                 {
2656                     conf->cmdline_account->auth_mech = NULL;
2657                     print_error(_("invalid argument %s for %s"),
2658                             optarg, "--auth");
2659                     error_code = 1;
2660                 }
2661                 conf->cmdline_account->mask |= ACC_AUTH_MECH;
2662                 break;
2663 
2664             case LONGONLYOPT_USER:
2665                 free(conf->cmdline_account->username);
2666                 conf->cmdline_account->username =
2667                     (*optarg == '\0') ? NULL : xstrdup(optarg);
2668                 conf->cmdline_account->mask |= ACC_USERNAME;
2669                 break;
2670 
2671             case LONGONLYOPT_PASSWORDEVAL:
2672                 free(conf->cmdline_account->passwordeval);
2673                 conf->cmdline_account->passwordeval =
2674                     (*optarg == '\0') ? NULL : xstrdup(optarg);
2675                 conf->cmdline_account->mask |= ACC_PASSWORDEVAL;
2676                 break;
2677 
2678             case LONGONLYOPT_TLS:
2679                 if (!optarg || is_on(optarg))
2680                 {
2681                     conf->cmdline_account->tls = 1;
2682                 }
2683                 else if (is_off(optarg))
2684                 {
2685                     conf->cmdline_account->tls = 0;
2686                 }
2687                 else
2688                 {
2689                     print_error(_("invalid argument %s for %s"),
2690                             optarg, "--tls");
2691                     error_code = 1;
2692                 }
2693                 conf->cmdline_account->mask |= ACC_TLS;
2694                 break;
2695 
2696             case LONGONLYOPT_TLS_STARTTLS:
2697                 if (!optarg || is_on(optarg))
2698                 {
2699                     conf->cmdline_account->tls_nostarttls = 0;
2700                 }
2701                 else if (is_off(optarg))
2702                 {
2703                     conf->cmdline_account->tls_nostarttls = 1;
2704                 }
2705                 else
2706                 {
2707                     print_error(_("invalid argument %s for %s"),
2708                             optarg, "--tls-starttls");
2709                     error_code = 1;
2710                 }
2711                 conf->cmdline_account->mask |= ACC_TLS_NOSTARTTLS;
2712                 break;
2713 
2714             case LONGONLYOPT_TLS_TRUST_FILE:
2715                 free(conf->cmdline_account->tls_trust_file);
2716                 if (*optarg)
2717                 {
2718                     conf->cmdline_account->tls_trust_file =
2719                         expand_tilde(optarg);
2720                 }
2721                 else
2722                 {
2723                     conf->cmdline_account->tls_trust_file = NULL;
2724                 }
2725                 conf->cmdline_account->mask |= ACC_TLS_TRUST_FILE;
2726                 break;
2727 
2728             case LONGONLYOPT_TLS_CRL_FILE:
2729                 free(conf->cmdline_account->tls_crl_file);
2730                 if (*optarg)
2731                 {
2732                     conf->cmdline_account->tls_crl_file =
2733                         expand_tilde(optarg);
2734                 }
2735                 else
2736                 {
2737                     conf->cmdline_account->tls_crl_file = NULL;
2738                 }
2739                 conf->cmdline_account->mask |= ACC_TLS_CRL_FILE;
2740                 break;
2741 
2742             case LONGONLYOPT_TLS_FINGERPRINT:
2743                 free(conf->cmdline_account->tls_sha256_fingerprint);
2744                 conf->cmdline_account->tls_sha256_fingerprint = NULL;
2745                 free(conf->cmdline_account->tls_sha1_fingerprint);
2746                 conf->cmdline_account->tls_sha1_fingerprint = NULL;
2747                 free(conf->cmdline_account->tls_md5_fingerprint);
2748                 conf->cmdline_account->tls_md5_fingerprint = NULL;
2749                 if (*optarg)
2750                 {
2751                     if (strlen(optarg) == 2 * 32 + 31)
2752                     {
2753                         conf->cmdline_account->tls_sha256_fingerprint =
2754                             get_fingerprint(optarg, 32);
2755                     }
2756                     else if (strlen(optarg) == 2 * 20 + 19)
2757                     {
2758                         conf->cmdline_account->tls_sha1_fingerprint =
2759                             get_fingerprint(optarg, 20);
2760                     }
2761                     else if (strlen(optarg) == 2 * 16 + 15)
2762                     {
2763                         conf->cmdline_account->tls_md5_fingerprint =
2764                             get_fingerprint(optarg, 16);
2765                     }
2766                     if (!conf->cmdline_account->tls_sha256_fingerprint
2767                             && !conf->cmdline_account->tls_sha1_fingerprint
2768                             && !conf->cmdline_account->tls_md5_fingerprint)
2769                     {
2770                         print_error(_("invalid argument %s for %s"),
2771                                 optarg, "--tls-fingerprint");
2772                         error_code = 1;
2773                     }
2774                 }
2775                 conf->cmdline_account->mask |= ACC_TLS_FINGERPRINT;
2776                 break;
2777 
2778             case LONGONLYOPT_TLS_KEY_FILE:
2779                 free(conf->cmdline_account->tls_key_file);
2780                 if (*optarg)
2781                 {
2782                     conf->cmdline_account->tls_key_file = expand_tilde(optarg);
2783                 }
2784                 else
2785                 {
2786                     conf->cmdline_account->tls_key_file = NULL;
2787                 }
2788                 conf->cmdline_account->mask |= ACC_TLS_KEY_FILE;
2789                 break;
2790 
2791             case LONGONLYOPT_TLS_CERT_FILE:
2792                 free(conf->cmdline_account->tls_cert_file);
2793                 if (*optarg)
2794                 {
2795                     conf->cmdline_account->tls_cert_file = expand_tilde(optarg);
2796                 }
2797                 else
2798                 {
2799                     conf->cmdline_account->tls_cert_file = NULL;
2800                 }
2801                 conf->cmdline_account->mask |= ACC_TLS_CERT_FILE;
2802                 break;
2803 
2804             case LONGONLYOPT_TLS_CERTCHECK:
2805                 if (!optarg || is_on(optarg))
2806                 {
2807                     conf->cmdline_account->tls_nocertcheck = 0;
2808                 }
2809                 else if (is_off(optarg))
2810                 {
2811                     conf->cmdline_account->tls_nocertcheck = 1;
2812                 }
2813                 else
2814                 {
2815                     print_error(_("invalid argument %s for %s"),
2816                             optarg, "--tls-certcheck");
2817                     error_code = 1;
2818                 }
2819                 conf->cmdline_account->mask |= ACC_TLS_NOCERTCHECK;
2820                 break;
2821 
2822             case LONGONLYOPT_TLS_FORCE_SSLV3:
2823                 /* silently ignored for compatibility with versions <= 1.4.32 */
2824                 break;
2825 
2826             case LONGONLYOPT_TLS_MIN_DH_PRIME_BITS:
2827                 if (*optarg == '\0')
2828                 {
2829                     conf->cmdline_account->tls_min_dh_prime_bits = -1;
2830                 }
2831                 else
2832                 {
2833                     conf->cmdline_account->tls_min_dh_prime_bits =
2834                         get_pos_int(optarg);
2835                     if (conf->cmdline_account->tls_min_dh_prime_bits < 1)
2836                     {
2837                         print_error(_("invalid argument %s for %s"),
2838                                 optarg, "--tls-min-dh-prime-bits");
2839                         error_code = 1;
2840                     }
2841                 }
2842                 conf->cmdline_account->mask |= ACC_TLS_MIN_DH_PRIME_BITS;
2843                 break;
2844 
2845             case LONGONLYOPT_TLS_PRIORITIES:
2846                 free(conf->cmdline_account->tls_priorities);
2847                 if (*optarg)
2848                 {
2849                     conf->cmdline_account->tls_priorities = xstrdup(optarg);
2850                 }
2851                 else
2852                 {
2853                     conf->cmdline_account->tls_priorities = NULL;
2854                 }
2855                 conf->cmdline_account->mask |= ACC_TLS_PRIORITIES;
2856                 break;
2857 
2858             case LONGONLYOPT_TLS_HOST_OVERRIDE:
2859                 free(conf->cmdline_account->tls_host_override);
2860                 if (*optarg)
2861                 {
2862                     conf->cmdline_account->tls_host_override = xstrdup(optarg);
2863                 }
2864                 else
2865                 {
2866                     conf->cmdline_account->tls_host_override = NULL;
2867                 }
2868                 conf->cmdline_account->mask |= ACC_TLS_HOST_OVERRIDE;
2869                 break;
2870 
2871             case 'N':
2872                 free(conf->cmdline_account->dsn_notify);
2873                 if (is_off(optarg))
2874                 {
2875                     conf->cmdline_account->dsn_notify = NULL;
2876                 }
2877                 else if (check_dsn_notify_arg(optarg) == 0)
2878                 {
2879                     conf->cmdline_account->dsn_notify = xstrdup(optarg);
2880                 }
2881                 else
2882                 {
2883                     print_error(_("invalid argument %s for %s"),
2884                             optarg, "--dsn-notify");
2885                     error_code = 1;
2886                 }
2887                 conf->cmdline_account->mask |= ACC_DSN_NOTIFY;
2888                 break;
2889 
2890             case 'R':
2891                 /* be compatible to both sendmail and the dsn_notify command */
2892                 free(conf->cmdline_account->dsn_return);
2893                 if (is_off(optarg))
2894                 {
2895                     conf->cmdline_account->dsn_return = NULL;
2896                 }
2897                 else if (strcmp(optarg, "hdrs") == 0
2898                         || strcmp(optarg, "headers") == 0)
2899                 {
2900                     conf->cmdline_account->dsn_return = xstrdup("HDRS");
2901                 }
2902                 else if (strcmp(optarg, "full") == 0)
2903                 {
2904                     conf->cmdline_account->dsn_return = xstrdup("FULL");
2905                 }
2906                 else
2907                 {
2908                     print_error(_("invalid argument %s for %s"),
2909                             optarg, "--dsn-return");
2910                     error_code = 1;
2911                 }
2912                 conf->cmdline_account->mask |= ACC_DSN_RETURN;
2913                 break;
2914 
2915             case LONGONLYOPT_PROTOCOL:
2916                 conf->cmdline_account->mask |= ACC_PROTOCOL;
2917                 if (strcmp(optarg, "smtp") == 0)
2918                 {
2919                     conf->cmdline_account->protocol = SMTP_PROTO_SMTP;
2920                 }
2921                 else if (strcmp(optarg, "lmtp") == 0)
2922                 {
2923                     conf->cmdline_account->protocol = SMTP_PROTO_LMTP;
2924                 }
2925                 else
2926                 {
2927                     print_error(_("invalid argument %s for %s"),
2928                             optarg, "--protocol");
2929                     error_code = 1;
2930                 }
2931                 break;
2932 
2933             case LONGONLYOPT_DOMAIN:
2934                 free(conf->cmdline_account->domain);
2935                 conf->cmdline_account->domain = xstrdup(optarg);
2936                 conf->cmdline_account->mask |= ACC_DOMAIN;
2937                 break;
2938 
2939             case 'X':
2940                 free(conf->cmdline_account->logfile);
2941                 if (*optarg)
2942                 {
2943                     conf->cmdline_account->logfile = expand_tilde(optarg);
2944                 }
2945                 else
2946                 {
2947                     conf->cmdline_account->logfile = NULL;
2948                 }
2949                 conf->cmdline_account->mask |= ACC_LOGFILE;
2950                 break;
2951 
2952             case LONGONLYOPT_LOGFILE_TIME_FORMAT:
2953                 free(conf->cmdline_account->logfile_time_format);
2954                 if (*optarg)
2955                 {
2956                     conf->cmdline_account->logfile_time_format = xstrdup(optarg);
2957                 }
2958                 else
2959                 {
2960                     conf->cmdline_account->logfile_time_format = NULL;
2961                 }
2962                 conf->cmdline_account->mask |= ACC_LOGFILE_TIME_FORMAT;
2963                 break;
2964 
2965             case LONGONLYOPT_SYSLOG:
2966                 free(conf->cmdline_account->syslog);
2967                 if (!optarg || is_on(optarg))
2968                 {
2969                     conf->cmdline_account->syslog =
2970                         get_default_syslog_facility();
2971                 }
2972                 else if (is_off(optarg))
2973                 {
2974                     conf->cmdline_account->syslog = NULL;
2975                 }
2976                 else
2977                 {
2978                     if (check_syslog_arg(optarg) != 0)
2979                     {
2980                         print_error(_("invalid argument %s for %s"),
2981                                 optarg, "--syslog");
2982                         error_code = 1;
2983                     }
2984                     else
2985                     {
2986                         conf->cmdline_account->syslog = xstrdup(optarg);
2987                     }
2988                 }
2989                 conf->cmdline_account->mask |= ACC_SYSLOG;
2990                 break;
2991 
2992             case LONGONLYOPT_ALIASES:
2993                 free(conf->cmdline_account->aliases);
2994                 if (*optarg)
2995                 {
2996                     conf->cmdline_account->aliases = expand_tilde(optarg);
2997                 }
2998                 else
2999                 {
3000                     conf->cmdline_account->aliases = NULL;
3001                 }
3002                 conf->cmdline_account->mask |= ACC_ALIASES;
3003                 break;
3004 
3005             case LONGONLYOPT_PROXY_HOST:
3006                 free(conf->cmdline_account->proxy_host);
3007                 if (*optarg)
3008                 {
3009                     conf->cmdline_account->proxy_host = xstrdup(optarg);
3010                 }
3011                 else
3012                 {
3013                     conf->cmdline_account->proxy_host = NULL;
3014                 }
3015                 conf->cmdline_account->mask |= ACC_PROXY_HOST;
3016                 break;
3017 
3018             case LONGONLYOPT_PROXY_PORT:
3019                 if (*optarg)
3020                 {
3021                     conf->cmdline_account->proxy_port = get_pos_int(optarg);
3022                     if (conf->cmdline_account->proxy_port < 1
3023                             || conf->cmdline_account->proxy_port > 65535)
3024                     {
3025                         print_error(_("invalid argument %s for %s"),
3026                                 optarg, "--proxy-port");
3027                         error_code = 1;
3028                     }
3029                 }
3030                 else
3031                 {
3032                     conf->cmdline_account->proxy_port = 0;
3033                 }
3034                 conf->cmdline_account->mask |= ACC_PROXY_PORT;
3035                 break;
3036 
3037             case LONGONLYOPT_SET_FROM_HEADER:
3038                 if (!optarg || is_auto(optarg))
3039                 {
3040                     conf->cmdline_account->set_from_header = 2;
3041                 }
3042                 else if (is_on(optarg))
3043                 {
3044                     conf->cmdline_account->set_from_header = 1;
3045                 }
3046                 else if (is_off(optarg))
3047                 {
3048                     conf->cmdline_account->set_from_header = 0;
3049                 }
3050                 else
3051                 {
3052                     print_error(_("invalid argument %s for %s"),
3053                             optarg, "--set-from-header");
3054                     error_code = 1;
3055                 }
3056                 conf->cmdline_account->mask |= ACC_SET_FROM_HEADER;
3057                 break;
3058 
3059             case LONGONLYOPT_SET_DATE_HEADER:
3060                 if (!optarg || is_auto(optarg))
3061                 {
3062                     conf->cmdline_account->set_date_header = 2;
3063                 }
3064                 else if (is_off(optarg))
3065                 {
3066                     conf->cmdline_account->set_date_header = 0;
3067                 }
3068                 else
3069                 {
3070                     print_error(_("invalid argument %s for %s"),
3071                             optarg, "--set-date-header");
3072                     error_code = 1;
3073                 }
3074                 conf->cmdline_account->mask |= ACC_SET_DATE_HEADER;
3075                 break;
3076 
3077             case LONGONLYOPT_ADD_MISSING_FROM_HEADER:
3078                 /* compatibility with < 1.8.8 */
3079                 if (!optarg || is_on(optarg))
3080                 {
3081                     conf->cmdline_account->set_from_header = 2;
3082                 }
3083                 else if (is_off(optarg))
3084                 {
3085                     conf->cmdline_account->set_from_header = 0;
3086                 }
3087                 else
3088                 {
3089                     print_error(_("invalid argument %s for %s"),
3090                             optarg, "--add-missing-from-header");
3091                     error_code = 1;
3092                 }
3093                 conf->cmdline_account->mask |= ACC_SET_FROM_HEADER;
3094                 break;
3095 
3096             case LONGONLYOPT_ADD_MISSING_DATE_HEADER:
3097                 /* compatibility with < 1.8.8 */
3098                 if (!optarg || is_on(optarg))
3099                 {
3100                     conf->cmdline_account->set_date_header = 2;
3101                 }
3102                 else if (is_off(optarg))
3103                 {
3104                     conf->cmdline_account->set_date_header = 0;
3105                 }
3106                 else
3107                 {
3108                     print_error(_("invalid argument %s for %s"),
3109                             optarg, "--add-missing-date-header");
3110                     error_code = 1;
3111                 }
3112                 conf->cmdline_account->mask |= ACC_SET_DATE_HEADER;
3113                 break;
3114 
3115             case LONGONLYOPT_REMOVE_BCC_HEADERS:
3116                 if (!optarg || is_on(optarg))
3117                 {
3118                     conf->cmdline_account->remove_bcc_headers = 1;
3119                 }
3120                 else if (is_off(optarg))
3121                 {
3122                     conf->cmdline_account->remove_bcc_headers = 0;
3123                 }
3124                 else
3125                 {
3126                     print_error(_("invalid argument %s for %s"),
3127                             optarg, "--remove-bcc-headers");
3128                     error_code = 1;
3129                 }
3130                 conf->cmdline_account->mask |= ACC_REMOVE_BCC_HEADERS;
3131                 break;
3132 
3133             case LONGONLYOPT_UNDISCLOSED_RECIPIENTS:
3134                 if (!optarg || is_on(optarg))
3135                 {
3136                     conf->cmdline_account->undisclosed_recipients = 1;
3137                 }
3138                 else if (is_off(optarg))
3139                 {
3140                     conf->cmdline_account->undisclosed_recipients = 0;
3141                 }
3142                 else
3143                 {
3144                     print_error(_("invalid argument %s for %s"),
3145                             optarg, "--undisclosed-recipients");
3146                     error_code = 1;
3147                 }
3148                 conf->cmdline_account->mask |= ACC_UNDISCLOSED_RECIPIENTS;
3149                 break;
3150 
3151             case LONGONLYOPT_SOURCE_IP:
3152                 free(conf->cmdline_account->source_ip);
3153                 if (*optarg)
3154                 {
3155                     conf->cmdline_account->source_ip = xstrdup(optarg);
3156                 }
3157                 else
3158                 {
3159                     conf->cmdline_account->source_ip = NULL;
3160                 }
3161                 conf->cmdline_account->mask |= ACC_SOURCE_IP;
3162                 break;
3163 
3164             case LONGONLYOPT_SOCKET:
3165                 free(conf->cmdline_account->socketname);
3166                 if (*optarg)
3167                 {
3168                     conf->cmdline_account->socketname = xstrdup(optarg);
3169                 }
3170                 else
3171                 {
3172                     conf->cmdline_account->socketname = NULL;
3173                 }
3174                 conf->cmdline_account->mask |= ACC_SOCKET;
3175                 break;
3176 
3177             case 't':
3178                 conf->read_recipients = 1;
3179                 break;
3180 
3181             case LONGONLYOPT_READ_ENVELOPE_FROM:
3182                 if (conf->cmdline_account->from)
3183                 {
3184                     print_error(_("cannot use both --from and "
3185                                 "--read-envelope-from"));
3186                     error_code = 1;
3187                 }
3188                 else
3189                 {
3190                     conf->read_envelope_from = 1;
3191                     conf->cmdline_account->mask |= ACC_FROM;
3192                 }
3193                 break;
3194 
3195             case 'b':
3196                 /* only m makes sense */
3197                 if (strcmp(optarg, "m") != 0)
3198                 {
3199                     print_error(_("unsupported operation mode b%s"), optarg);
3200                     error_code = 1;
3201                 }
3202                 break;
3203 
3204             case 'F':
3205                 free(conf->full_name);
3206                 conf->full_name = xstrdup(optarg);
3207                 break;
3208 
3209             case LONGONLYOPT_KEEPBCC:
3210                 /* compatibility with 1.4.x */
3211                 if (!optarg || is_on(optarg))
3212                 {
3213                     conf->cmdline_account->remove_bcc_headers = 0;
3214                 }
3215                 else if (is_off(optarg))
3216                 {
3217                     conf->cmdline_account->remove_bcc_headers = 1;
3218                 }
3219                 else
3220                 {
3221                     print_error(_("invalid argument %s for %s"),
3222                             optarg, "--keepbcc");
3223                     error_code = 1;
3224                 }
3225                 conf->cmdline_account->mask |= ACC_REMOVE_BCC_HEADERS;
3226                 break;
3227 
3228             case 'A':
3229             case 'B':
3230             case 'G':
3231             case 'h':
3232             case 'i':
3233             case 'L':
3234             case 'm':
3235             case 'n':
3236             case 'O':
3237             case 'o':
3238                 break;
3239 
3240             /* unknown option */
3241             default:
3242                 error_code = 1;
3243                 break;
3244         }
3245         if (error_code)
3246         {
3247             break;
3248         }
3249     }
3250     if (error_code)
3251     {
3252         return EX_USAGE;
3253     }
3254 
3255     /* The list of recipients.
3256      * Write these to a temporary mail header so that msmtp_read_headers() can
3257      * parse them. */
3258     conf->recipients = list_new();
3259     rcptc = argc - optind;
3260     rcptv = &(argv[optind]);
3261     if (rcptc > 0)
3262     {
3263 #ifdef HAVE_FMEMOPEN
3264         rcptf_size = 2;     /* terminating "\n\0" */
3265         for (i = 0; i < rcptc; i++)
3266         {
3267             rcptf_size += 4 + strlen(rcptv[i]) + 1;
3268         }
3269         rcptf_buf = xmalloc(rcptf_size);
3270         tmpf = fmemopen(rcptf_buf, rcptf_size, "w+");
3271 #else
3272         tmpf = tmpfile();
3273 #endif
3274         if (!tmpf)
3275         {
3276             print_error(_("cannot create temporary file: %s"),
3277                     sanitize_string(strerror(errno)));
3278             error_code = EX_IOERR;
3279             goto error_exit;
3280         }
3281         for (i = 0; i < rcptc && error_code != EOF; i++)
3282         {
3283             error_code = fputs("To: ", tmpf);
3284             if (error_code != EOF)
3285             {
3286                 error_code = fputs(rcptv[i], tmpf);
3287             }
3288             if (error_code != EOF)
3289             {
3290                 error_code = fputc('\n', tmpf);
3291             }
3292         }
3293         if (error_code != EOF)
3294         {
3295             error_code = fputc('\n', tmpf);
3296         }
3297         if (error_code == EOF)
3298         {
3299             print_error(_("cannot write mail headers to temporary "
3300                         "file: output error"));
3301             error_code = EX_IOERR;
3302             goto error_exit;
3303         }
3304         if (fseeko(tmpf, 0, SEEK_SET) != 0)
3305         {
3306             print_error(_("cannot rewind temporary file: %s"),
3307                     sanitize_string(strerror(errno)));
3308             error_code = EX_IOERR;
3309             goto error_exit;
3310         }
3311         if ((error_code = msmtp_read_headers(tmpf, NULL,
3312                         list_last(conf->recipients), NULL, NULL, &errstr))
3313                 != EX_OK)
3314         {
3315             print_error("%s", sanitize_string(errstr));
3316             goto error_exit;
3317         }
3318     }
3319     error_code = EX_OK;
3320 
3321 error_exit:
3322     if (tmpf)
3323     {
3324         fclose(tmpf);
3325     }
3326 #ifdef HAVE_FMEMOPEN
3327     free(rcptf_buf);
3328 #endif
3329     return error_code;
3330 }
3331 
3332 
3333 /*
3334  * msmtp_get_conffile_accounts()
3335  * Read the system and user configuration files and merge the data
3336  */
3337 
msmtp_get_conffile_accounts(list_t ** account_list,int print_info,const char * user_conffile,char ** loaded_system_conffile,char ** loaded_user_conffile)3338 int msmtp_get_conffile_accounts(list_t **account_list,
3339         int print_info, const char *user_conffile,
3340         char **loaded_system_conffile, char **loaded_user_conffile)
3341 {
3342     char *errstr;
3343     char *system_confdir;
3344     char *system_conffile;
3345     char *real_user_conffile;
3346     list_t *system_account_list;
3347     list_t *user_account_list;
3348     list_t *lps;
3349     list_t *lpu;
3350     int securitycheck;
3351     int e;
3352 
3353 
3354     *loaded_system_conffile = NULL;
3355     *loaded_user_conffile = NULL;
3356 
3357     /* Read the system configuration file.
3358      * It is not an error if system_conffile cannot be opened,
3359      * but it is an error is the file content is invalid */
3360     system_confdir = get_sysconfdir();
3361     system_conffile = get_filename(system_confdir, SYSCONFFILE);
3362     free(system_confdir);
3363     securitycheck = 0;
3364     if ((e = get_conf(system_conffile, securitycheck,
3365                     &system_account_list, &errstr)) != CONF_EOK)
3366     {
3367         if (e == CONF_ECANTOPEN)
3368         {
3369             if (print_info)
3370             {
3371                 printf(_("ignoring system configuration file %s: %s\n"),
3372                         system_conffile, sanitize_string(errstr));
3373             }
3374         }
3375         else
3376         {
3377             print_error("%s: %s", system_conffile,
3378                     sanitize_string(errstr));
3379             return (e == CONF_EIO) ? EX_IOERR : EX_CONFIG;
3380         }
3381     }
3382     else
3383     {
3384         if (print_info)
3385         {
3386             printf(_("loaded system configuration file %s\n"), system_conffile);
3387         }
3388         *loaded_system_conffile = xstrdup(system_conffile);
3389     }
3390     free(system_conffile);
3391 
3392     /* Read the user configuration file.
3393      * It is not an error if user_conffile cannot be opened (unless it was
3394      * chosen with -C/--file), but it is an error is the file content is
3395      * invalid */
3396     if (user_conffile)
3397     {
3398         real_user_conffile = xstrdup(user_conffile);
3399     }
3400     else
3401     {
3402         real_user_conffile = get_userconfig(USERCONFFILE);
3403     }
3404 #ifdef W32_NATIVE
3405     securitycheck = 1;
3406 #else
3407     securitycheck = (geteuid() != 0);
3408 #endif
3409     if ((e = get_conf(real_user_conffile, securitycheck,
3410                     &user_account_list, &errstr)) != CONF_EOK)
3411     {
3412         if (e == CONF_ECANTOPEN)
3413         {
3414             /* If the configuration file was set with -C/--file, it is an
3415              * error if we cannot open it */
3416             if (user_conffile)
3417             {
3418                 print_error("%s: %s", real_user_conffile,
3419                         sanitize_string(errstr));
3420                 return EX_IOERR;
3421             }
3422             /* otherwise, we can ignore it */
3423             if (print_info)
3424             {
3425                 printf(_("ignoring user configuration file %s: %s\n"),
3426                         real_user_conffile, sanitize_string(errstr));
3427             }
3428         }
3429         else
3430         {
3431             print_error("%s: %s", real_user_conffile,
3432                     sanitize_string(errstr));
3433             return (e == CONF_EIO) ? EX_IOERR : EX_CONFIG;
3434         }
3435     }
3436     else
3437     {
3438         if (print_info)
3439         {
3440             printf(_("loaded user configuration file %s\n"),
3441                     real_user_conffile);
3442         }
3443         *loaded_user_conffile = xstrdup(real_user_conffile);
3444     }
3445     free(real_user_conffile);
3446 
3447     /* Merge system_account_list and user_account_list into account_list.
3448      * If an account exist in both files, only the one from the user conffile is
3449      * kept. It is important that the order of accounts is maintained, so that
3450      * --from can choose the *first* account with a matching envelope from
3451      * address. */
3452     if (*loaded_system_conffile && *loaded_user_conffile)
3453     {
3454         lpu = user_account_list;
3455         lps = system_account_list;
3456         while (!list_is_empty(lps))
3457         {
3458             lps = lps->next;
3459             if (!find_account(user_account_list, ((account_t *)lps->data)->id))
3460             {
3461                 list_insert(lpu, account_copy(lps->data));
3462                 lpu = lpu->next;
3463             }
3464         }
3465         *account_list = user_account_list;
3466         list_xfree(system_account_list, account_free);
3467     }
3468     else if (*loaded_system_conffile)
3469     {
3470         *account_list = system_account_list;
3471     }
3472     else if (*loaded_user_conffile)
3473     {
3474         *account_list = user_account_list;
3475     }
3476     else
3477     {
3478         *account_list = list_new();
3479     }
3480 
3481     return EX_OK;
3482 }
3483 
3484 
3485 /*
3486  * msmtp_print_conf
3487  *
3488  * Print configuration information, for example for --pretend
3489  */
3490 
msmtp_print_conf(msmtp_cmdline_conf_t conf,account_t * account)3491 void msmtp_print_conf(msmtp_cmdline_conf_t conf, account_t *account)
3492 {
3493     char fingerprint_string[2 * 32 + 31 + 1];
3494 
3495     if (account->id && account->conffile)
3496     {
3497         printf(_("using account %s from %s\n"),
3498                 account->id, account->conffile);
3499     }
3500     printf("host = %s\n", account->host);
3501     printf("port = %d\n", account->port);
3502     printf("source ip = %s\n",
3503             account->source_ip ? account->source_ip : _("(not set)"));
3504     printf("proxy host = %s\n",
3505             account->proxy_host ? account->proxy_host : _("(not set)"));
3506     printf("proxy port = %d\n", account->proxy_port);
3507     printf("socket = %s\n",
3508             account->socketname ? account->socketname : _("(not set)"));
3509     printf("timeout = ");
3510     if (account->timeout <= 0)
3511     {
3512         printf(_("off\n"));
3513     }
3514     else
3515     {
3516         if (account->timeout > 1)
3517         {
3518             printf(_("%d seconds\n"), account->timeout);
3519         }
3520         else
3521         {
3522             printf(_("1 second\n"));
3523         }
3524     }
3525     printf("protocol = %s\n",
3526             account->protocol == SMTP_PROTO_SMTP ? "smtp" : "lmtp");
3527     printf("domain = %s\n", account->domain);
3528     printf("auth = ");
3529     if (!account->auth_mech)
3530     {
3531         printf(_("none\n"));
3532     }
3533     else if (account->auth_mech[0] == '\0')
3534     {
3535         printf(_("choose\n"));
3536     }
3537     else
3538     {
3539         printf("%s\n", account->auth_mech);
3540     }
3541     printf("user = %s\n",
3542             account->username ? account->username : _("(not set)"));
3543     printf("password = %s\n", account->password ? "*" : _("(not set)"));
3544     printf("passwordeval = %s\n",
3545             account->passwordeval ? account->passwordeval : _("(not set)"));
3546     printf("ntlmdomain = %s\n",
3547             account->ntlmdomain ? account->ntlmdomain : _("(not set)"));
3548     printf("tls = %s\n", account->tls ? _("on") : _("off"));
3549     printf("tls_starttls = %s\n", account->tls_nostarttls ? _("off") : _("on"));
3550     printf("tls_trust_file = %s\n",
3551             account->tls_trust_file ? account->tls_trust_file : _("(not set)"));
3552     printf("tls_crl_file = %s\n",
3553             account->tls_crl_file ? account->tls_crl_file : _("(not set)"));
3554     if (account->tls_sha256_fingerprint)
3555     {
3556         print_fingerprint(fingerprint_string,
3557                 account->tls_sha256_fingerprint, 32);
3558     }
3559     else if (account->tls_sha1_fingerprint)
3560     {
3561         print_fingerprint(fingerprint_string,
3562                 account->tls_sha1_fingerprint, 20);
3563     }
3564     else if (account->tls_md5_fingerprint)
3565     {
3566         print_fingerprint(fingerprint_string,
3567                 account->tls_md5_fingerprint, 16);
3568     }
3569     printf("tls_fingerprint = %s\n",
3570             account->tls_sha256_fingerprint
3571             || account->tls_sha1_fingerprint || account->tls_md5_fingerprint
3572             ? fingerprint_string : _("(not set)"));
3573     printf("tls_key_file = %s\n",
3574             account->tls_key_file ? account->tls_key_file : _("(not set)"));
3575     printf("tls_cert_file = %s\n",
3576             account->tls_cert_file ? account->tls_cert_file : _("(not set)"));
3577     printf("tls_certcheck = %s\n",
3578             account->tls_nocertcheck ? _("off") : _("on"));
3579     printf("tls_min_dh_prime_bits = ");
3580     if (account->tls_min_dh_prime_bits >= 0)
3581     {
3582         printf("%d\n", account->tls_min_dh_prime_bits);
3583     }
3584     else
3585     {
3586         printf("%s\n", _("(not set)"));
3587     }
3588     printf("tls_priorities = %s\n",
3589             account->tls_priorities ? account->tls_priorities : _("(not set)"));
3590     printf("tls_host_override = %s\n",
3591             account->tls_host_override ? account->tls_host_override : _("(not set)"));
3592     if (conf.sendmail)
3593     {
3594         printf("auto_from = %s\n", account->auto_from ? _("on") : _("off"));
3595         printf("maildomain = %s\n",
3596                 account->maildomain ? account->maildomain : _("(not set)"));
3597         printf("from = %s\n",
3598                 account->from ? account->from : conf.read_envelope_from
3599                 ? _("(read from mail)") : _("(not set)"));
3600         printf("set_from_header = %s\n",
3601                 account->set_from_header == 2 ? _("auto")
3602                 : account->set_from_header == 1 ? _("on") : _("off"));
3603         printf("set_date_header = %s\n",
3604                 account->set_date_header == 2 ? _("auto")
3605                 : _("off"));
3606         printf("remove_bcc_headers = %s\n",
3607                 account->remove_bcc_headers ? _("on") : _("off"));
3608         printf("undisclosed_recipients = %s\n",
3609                 account->undisclosed_recipients ? _("on") : _("off"));
3610         printf("dsn_notify = %s\n",
3611                 account->dsn_notify ? account->dsn_notify : _("(not set)"));
3612         printf("dsn_return = %s\n",
3613                 account->dsn_return ? account->dsn_return : _("(not set)"));
3614         printf("logfile = %s\n",
3615                 account->logfile ? account->logfile : _("(not set)"));
3616         printf("logfile_time_format = %s\n",
3617                 account->logfile_time_format ? account->logfile_time_format
3618                 : _("(not set)"));
3619         printf("syslog = %s\n",
3620                 account->syslog ? account->syslog : _("(not set)"));
3621         printf("aliases = %s\n",
3622                 account->aliases ? account->aliases : _("(not set)"));
3623         if (conf.read_recipients)
3624         {
3625             printf(_("reading recipients from the command line "
3626                         "and the mail\n"));
3627         }
3628         else
3629         {
3630             printf(_("reading recipients from the command line\n"));
3631         }
3632     }
3633     if (conf.rmqs)
3634     {
3635         printf("RMQS argument = %s\n", conf.rmqs_argument);
3636     }
3637 }
3638 
3639 
3640 /*
3641  * The main function.
3642  * It returns values from sysexits.h (like sendmail does).
3643  */
3644 
main(int argc,char * argv[])3645 int main(int argc, char *argv[])
3646 {
3647     msmtp_cmdline_conf_t conf;
3648     /* account information from the configuration file(s) */
3649     list_t *account_list = NULL;
3650     char *loaded_system_conffile = NULL;
3651     char *loaded_user_conffile = NULL;
3652     /* environment variables */
3653     int allow_fallback_to_env;
3654     char *env_email;
3655     char *env_smtpserver;
3656     /* the account data that will be used */
3657     account_t *account = NULL;
3658     /* error handling */
3659     char *errstr;
3660     list_t *errmsg;
3661     int error_code;
3662     int e;
3663     list_t *lp;
3664     /* misc */
3665 #ifdef HAVE_TLS
3666     int tls_lib_initialized = 0;
3667 #endif
3668     int net_lib_initialized = 0;
3669     /* the size of a sent mail */
3670     long mailsize = 0;
3671     /* special LMTP error info */
3672     list_t *lmtp_errstrs;
3673     list_t *lmtp_error_msgs;
3674     list_t *lp_lmtp_errstrs;
3675     list_t *lp_lmtp_error_msgs;
3676     /* log information */
3677     char *log_info;
3678     /* needed to read the headers and extract addresses */
3679     FILE *header_tmpfile = NULL;
3680     FILE *prepend_header_tmpfile = NULL;
3681     int have_from_header = 0;
3682     int have_date_header = 0;
3683 
3684 
3685     /* Avoid the side effects of text mode interpretations on DOS systems. */
3686 #if defined W32_NATIVE
3687     setmode(fileno(stdin), O_BINARY);
3688     _fmode = O_BINARY;
3689 #endif
3690 
3691     errstr = NULL;
3692     errmsg = NULL;
3693 
3694     /* internationalization with gettext */
3695 #ifdef ENABLE_NLS
3696     setlocale(LC_ALL, "");
3697     bindtextdomain(PACKAGE, LOCALEDIR);
3698     textdomain(PACKAGE);
3699 #endif
3700 
3701     /* Avoid receiving SIGPIPE when writing to sockets that were closed by the
3702      * remote end; we handle write errors where they occur. */
3703 #ifdef HAVE_SIGNAL
3704 #ifdef SIGPIPE
3705     signal(SIGPIPE, SIG_IGN);
3706 #endif
3707 #endif
3708 
3709     /* the command line */
3710     if ((error_code = msmtp_cmdline(&conf, argc, argv)) != EX_OK)
3711     {
3712         goto exit;
3713     }
3714 
3715     if (conf.print_version)
3716     {
3717         msmtp_print_version();
3718     }
3719     if (conf.print_help)
3720     {
3721         msmtp_print_help();
3722     }
3723 
3724     if (conf.configure)
3725     {
3726         char *userconfigfile = conf.user_conffile ? xstrdup(conf.user_conffile) : get_userconfig(USERCONFFILE);
3727         error_code = msmtp_configure(conf.configure_address, userconfigfile);
3728         free(userconfigfile);
3729         free(conf.configure_address);
3730         goto exit;
3731     }
3732 
3733     if (conf.print_help || conf.print_version
3734             || (!conf.sendmail && !conf.serverinfo && !conf.rmqs
3735                 && !conf.print_conf))
3736     {
3737         error_code = EX_OK;
3738         goto exit;
3739     }
3740 
3741     if ((conf.serverinfo || conf.rmqs) && !list_is_empty(conf.recipients))
3742     {
3743         print_error(_("too many arguments"));
3744         error_code = EX_USAGE;
3745         goto exit;
3746     }
3747     /* Read recipients and/or the envelope from address from the mail. */
3748     if (conf.sendmail)
3749     {
3750         char *envelope_from = NULL;
3751         if (!(header_tmpfile = tmpfile()))
3752         {
3753             print_error(_("cannot create temporary file: %s"),
3754                     sanitize_string(strerror(errno)));
3755             error_code = EX_IOERR;
3756             goto exit;
3757         }
3758         if ((error_code = msmtp_read_headers(stdin, header_tmpfile,
3759                         conf.read_recipients
3760                             ? list_last(conf.recipients) : NULL,
3761                         &envelope_from, &have_date_header, &errstr)) != EX_OK)
3762         {
3763             print_error("%s", sanitize_string(errstr));
3764             goto exit;
3765         }
3766         have_from_header = (envelope_from ? 1 : 0);
3767         if (conf.read_envelope_from)
3768         {
3769             conf.cmdline_account->from = envelope_from;
3770             if (conf.pretend || conf.debug)
3771             {
3772                 printf(_("envelope from address extracted from mail: %s\n"),
3773                         conf.cmdline_account->from);
3774             }
3775         }
3776         if (fseeko(header_tmpfile, 0, SEEK_SET) != 0)
3777         {
3778             print_error(_("cannot rewind temporary file: %s"),
3779                     sanitize_string(strerror(errno)));
3780             error_code = EX_IOERR;
3781             goto exit;
3782         }
3783     }
3784     /* check the list of recipients */
3785     if (conf.sendmail && list_is_empty(conf.recipients) && !conf.pretend)
3786     {
3787         print_error(_("no recipients found"));
3788         error_code = EX_USAGE;
3789         goto exit;
3790     }
3791 
3792     /* get the account to be used, either from the conffile(s) or from the
3793      * command line */
3794     allow_fallback_to_env = 0;
3795     if (!conf.cmdline_account->host)
3796     {
3797         if ((error_code = msmtp_get_conffile_accounts(&account_list,
3798                         (conf.pretend || conf.debug), conf.user_conffile,
3799                         &loaded_system_conffile, &loaded_user_conffile))
3800                 != EX_OK)
3801         {
3802             goto exit;
3803         }
3804         if (!conf.account_id)
3805         {
3806             if (conf.cmdline_account->from)
3807             {
3808                 /* No account was chosen, but the envelope from address is
3809                  * given. Choose the right account with this address.
3810                  */
3811                 account = account_copy(find_account_by_envelope_from(
3812                             account_list, conf.cmdline_account->from));
3813                 if (account)
3814                 {
3815                     if (conf.pretend || conf.debug)
3816                     {
3817                         printf(_("account chosen by "
3818                                     "envelope from address %s: %s\n"),
3819                                 conf.cmdline_account->from, account->id);
3820                     }
3821                 }
3822             }
3823             if (!account)
3824             {
3825                 /* No envelope from address or no matching account.
3826                  * Use default if available, but allow fallback to environment
3827                  * variables. */
3828                 conf.account_id = "default";
3829                 if (conf.pretend || conf.debug)
3830                 {
3831                     printf(_("falling back to default account\n"));
3832                 }
3833                 allow_fallback_to_env = 1;
3834             }
3835         }
3836         if (!account && !(account =
3837                     account_copy(find_account(account_list, conf.account_id))))
3838         {
3839             env_email = getenv("EMAIL");
3840             env_smtpserver = getenv("SMTPSERVER");
3841             if (allow_fallback_to_env
3842                     && (!conf.sendmail
3843                         || conf.cmdline_account->from || env_email)
3844                     && env_smtpserver)
3845             {
3846                 if (conf.sendmail && !conf.cmdline_account->from)
3847                 {
3848                     conf.cmdline_account->from = xstrdup(env_email);
3849                 }
3850                 conf.cmdline_account->host = xstrdup(env_smtpserver);
3851                 account = account_copy(conf.cmdline_account);
3852                 if (conf.pretend || conf.debug)
3853                 {
3854                     printf(_("using environment variables "
3855                                 "EMAIL and SMTPSERVER\n"));
3856                 }
3857             }
3858             else
3859             {
3860                 if (loaded_system_conffile && loaded_user_conffile)
3861                 {
3862                     print_error(_("account %s not found in %s and %s"),
3863                             conf.account_id, loaded_system_conffile,
3864                             loaded_user_conffile);
3865                 }
3866                 else if (loaded_system_conffile)
3867                 {
3868                     print_error(_("account %s not found in %s"),
3869                             conf.account_id, loaded_system_conffile);
3870                 }
3871                 else if (loaded_user_conffile)
3872                 {
3873                     print_error(_("account %s not found in %s"),
3874                             conf.account_id, loaded_user_conffile);
3875                 }
3876                 else /* no conffile was read */
3877                 {
3878                     print_error(_("account %s not found: "
3879                                 "no configuration file available"),
3880                             conf.account_id);
3881                 }
3882                 error_code = EX_CONFIG;
3883                 goto exit;
3884             }
3885         }
3886         override_account(account, conf.cmdline_account);
3887     }
3888     else
3889     {
3890         account = account_copy(conf.cmdline_account);
3891         if (conf.pretend || conf.debug)
3892         {
3893             printf(_("using account specified on command line\n"));
3894         }
3895     }
3896 
3897     /* OK, we're using the settings in 'account'. Complete them and check
3898      * them. */
3899     if (account->auth_mech && !account->password && account->passwordeval)
3900     {
3901         if (password_eval(account->passwordeval,
3902                     &account->password, &errstr) != 0)
3903         {
3904             print_error("%s", sanitize_string(errstr));
3905             error_code = EX_CONFIG;
3906             goto exit;
3907         }
3908     }
3909     if (account->port == 0)
3910     {
3911         if (account->protocol == SMTP_PROTO_SMTP)
3912         {
3913             if (account->tls && account->tls_nostarttls)
3914             {
3915                 account->port = 465;
3916             }
3917             else
3918             {
3919                 account->port = 25;
3920             }
3921         }
3922         else /* LMTP. Has no default port as of 2006-06-17. */
3923         {
3924         }
3925     }
3926     if (!account->tls_trust_file && !(account->mask & ACC_TLS_TRUST_FILE))
3927     {
3928         account->tls_trust_file = xstrdup("system");
3929     }
3930     if (account->proxy_host && account->proxy_port == 0)
3931     {
3932         account->proxy_port = 1080;
3933     }
3934     if (expand_domain(&(account->domain), &errstr) != CONF_EOK)
3935     {
3936         print_error("%s", sanitize_string(errstr));
3937         error_code = EX_CONFIG;
3938         goto exit;
3939     }
3940     if (conf.sendmail && account->from)
3941     {
3942         if (expand_from(&(account->from), &errstr) != CONF_EOK)
3943         {
3944             print_error("%s", sanitize_string(errstr));
3945             error_code = EX_CONFIG;
3946             goto exit;
3947         }
3948     }
3949     if (conf.sendmail && account->auto_from /* obsolete */)
3950     {
3951         free(account->from);
3952         account->from = msmtp_construct_env_from(account->maildomain);
3953     }
3954     if (check_account(account, (conf.sendmail && !conf.pretend),
3955                 &errstr) != CONF_EOK)
3956     {
3957         if (account->id && account->conffile)
3958         {
3959             print_error(_("account %s from %s: %s"), account->id,
3960                     account->conffile, sanitize_string(errstr));
3961         }
3962         else
3963         {
3964             print_error("%s", sanitize_string(errstr));
3965         }
3966         error_code = EX_CONFIG;
3967         goto exit;
3968     }
3969 
3970     /* print configuration */
3971     if (conf.print_conf)
3972     {
3973         msmtp_print_conf(conf, account);
3974     }
3975 
3976     /* replace aliases */
3977     if (conf.sendmail && account->aliases)
3978     {
3979         if ((e = aliases_replace(account->aliases, conf.recipients,
3980                          &errstr)) != ALIASES_EOK)
3981         {
3982             print_error("%s: %s", account->aliases,
3983                     sanitize_string(errstr));
3984             error_code = EX_CONFIG;
3985             goto exit;
3986         }
3987     }
3988 
3989     /* stop if there's nothing to do */
3990     if (conf.pretend || (!conf.sendmail && !conf.serverinfo && !conf.rmqs))
3991     {
3992         error_code = EX_OK;
3993         goto exit;
3994     }
3995 
3996     /* initialize libraries */
3997 #ifndef HAVE_SYSLOG
3998     if (conf.sendmail && account->syslog)
3999     {
4000         print_error(_("this platform does not support syslog logging"));
4001         error_code = EX_UNAVAILABLE;
4002         goto exit;
4003     }
4004 #endif /* not HAVE_SYSLOG */
4005     if ((conf.sendmail || conf.rmqs) /* serverinfo does not use auth */
4006             && account->auth_mech && (strcmp(account->auth_mech, "") != 0)
4007             && !smtp_client_supports_authmech(account->auth_mech))
4008     {
4009         print_error(_("support for authentication method %s "
4010                     "is not compiled in"),
4011                 account->auth_mech);
4012         error_code = EX_UNAVAILABLE;
4013         goto exit;
4014     }
4015     if ((e = net_lib_init(&errstr)) != NET_EOK)
4016     {
4017         print_error(_("cannot initialize networking: %s"),
4018                 sanitize_string(errstr));
4019         error_code = EX_SOFTWARE;
4020         goto exit;
4021     }
4022     net_lib_initialized = 1;
4023     if (account->tls)
4024     {
4025 #ifdef HAVE_TLS
4026         if ((e = mtls_lib_init(&errstr)) != TLS_EOK)
4027         {
4028             print_error(_("cannot initialize TLS library: %s"),
4029                     sanitize_string(errstr));
4030             error_code = EX_SOFTWARE;
4031             goto exit;
4032         }
4033         tls_lib_initialized = 1;
4034 #else /* not HAVE_TLS */
4035         print_error(_("support for TLS is not compiled in"));
4036         error_code = EX_UNAVAILABLE;
4037         goto exit;
4038 #endif /* not HAVE_TLS */
4039     }
4040 
4041     /* do the work */
4042     if (conf.sendmail)
4043     {
4044         int prepend_header_contains_from = 0;
4045         if (account->undisclosed_recipients
4046                 || account->set_from_header == 1
4047                 || (!have_from_header && account->set_from_header == 2)
4048                 || (!have_date_header && account->set_date_header == 2))
4049         {
4050             if (!(prepend_header_tmpfile = tmpfile()))
4051             {
4052                 print_error(_("cannot create temporary file: %s"),
4053                         sanitize_string(strerror(errno)));
4054                 error_code = EX_IOERR;
4055                 goto exit;
4056             }
4057         }
4058         if (account->set_from_header == 1
4059                 || (!have_from_header && account->set_from_header == 2))
4060         {
4061             if (conf.full_name)
4062             {
4063                 fprintf(prepend_header_tmpfile, "From: %s <%s>\n",
4064                         conf.full_name, account->from);
4065             }
4066             else
4067             {
4068                 fprintf(prepend_header_tmpfile, "From: %s\n", account->from);
4069             }
4070             prepend_header_contains_from = 1;
4071         }
4072         if (account->undisclosed_recipients)
4073         {
4074             fputs("To: undisclosed-recipients:;\n", prepend_header_tmpfile);
4075         }
4076         if (!have_date_header && account->set_date_header == 2)
4077         {
4078             char rfc2822_timestamp[32];
4079             print_time_rfc2822(time(NULL), rfc2822_timestamp);
4080             fprintf(prepend_header_tmpfile, "Date: %s\n", rfc2822_timestamp);
4081         }
4082         if (prepend_header_tmpfile
4083                 && fseeko(prepend_header_tmpfile, 0, SEEK_SET) != 0)
4084         {
4085             print_error(_("cannot rewind temporary file: %s"),
4086                     sanitize_string(strerror(errno)));
4087             error_code = EX_IOERR;
4088             goto exit;
4089         }
4090         if ((error_code = msmtp_sendmail(account, conf.recipients,
4091                         prepend_header_tmpfile, prepend_header_contains_from,
4092                         header_tmpfile, stdin,
4093                         conf.debug, &mailsize,
4094                         &lmtp_errstrs, &lmtp_error_msgs,
4095                         &errmsg, &errstr)) != EX_OK)
4096         {
4097             if (account->protocol == SMTP_PROTO_LMTP && lmtp_errstrs)
4098             {
4099                 lp_lmtp_errstrs = lmtp_errstrs;
4100                 lp_lmtp_error_msgs = lmtp_error_msgs;
4101                 while (!list_is_empty(lp_lmtp_errstrs))
4102                 {
4103                     lp_lmtp_errstrs = lp_lmtp_errstrs->next;
4104                     lp_lmtp_error_msgs = lp_lmtp_error_msgs->next;
4105                     if (lp_lmtp_errstrs->data)
4106                     {
4107                         print_error("%s", sanitize_string(
4108                                     lp_lmtp_errstrs->data));
4109                         if ((lp = lp_lmtp_error_msgs->data))
4110                         {
4111                             while (!list_is_empty(lp))
4112                             {
4113                                 lp = lp->next;
4114                                 print_error(_("LMTP server message: %s"),
4115                                         sanitize_string(lp->data));
4116                             }
4117                             list_xfree(lp_lmtp_error_msgs->data, free);
4118                         }
4119                     }
4120                 }
4121                 list_xfree(lmtp_errstrs, free);
4122                 list_free(lmtp_error_msgs);
4123                 if (account->id && account->conffile)
4124                 {
4125                     print_error(_("could not send mail to all recipients "
4126                                 "(account %s from %s)"),
4127                             account->id, account->conffile);
4128                 }
4129                 else
4130                 {
4131                     print_error(_("could not send mail to all recipients"));
4132                 }
4133             }
4134             else
4135             {
4136                 if (errstr)
4137                 {
4138                     print_error("%s", sanitize_string(errstr));
4139                 }
4140                 if (errmsg)
4141                 {
4142                     lp = errmsg;
4143                     while (!list_is_empty(lp))
4144                     {
4145                         lp = lp->next;
4146                         print_error(_("server message: %s"),
4147                                 sanitize_string(lp->data));
4148                     }
4149                 }
4150                 if (account->id && account->conffile)
4151                 {
4152                     print_error(_("could not send mail (account %s from %s)"),
4153                             account->id, account->conffile);
4154                 }
4155                 else
4156                 {
4157                     print_error(_("could not send mail"));
4158                 }
4159             }
4160         }
4161         if (account->logfile || account->syslog)
4162         {
4163             if (account->protocol == SMTP_PROTO_LMTP && lmtp_errstrs)
4164             {
4165                 /* errstr is NULL; print short info to it */
4166                 errstr = xasprintf(
4167                         _("delivery to one or more recipients failed"));
4168                 /* we know that errmsg is NULL. that's ok. */
4169             }
4170             log_info = msmtp_get_log_info(account, conf.recipients, mailsize,
4171                     errmsg, errstr, error_code);
4172             if (account->logfile)
4173             {
4174                 msmtp_log_to_file(account->logfile, account->logfile_time_format, log_info);
4175             }
4176 #ifdef HAVE_SYSLOG
4177             if (account->syslog)
4178             {
4179                 msmtp_log_to_syslog(account->syslog, log_info,
4180                         (error_code != EX_OK));
4181             }
4182 #endif
4183             free(log_info);
4184         }
4185     }
4186     else if (conf.serverinfo)
4187     {
4188         if ((error_code = msmtp_serverinfo(account, conf.debug,
4189                         &errmsg, &errstr)) != EX_OK)
4190         {
4191             if (errstr)
4192             {
4193                 print_error("%s", sanitize_string(errstr));
4194             }
4195             if (errmsg)
4196             {
4197                 lp = errmsg;
4198                 while (!list_is_empty(lp))
4199                 {
4200                     lp = lp->next;
4201                     print_error(_("server message: %s"),
4202                             sanitize_string(lp->data));
4203                 }
4204             }
4205         }
4206     }
4207     else /* rmqs */
4208     {
4209         if ((error_code = msmtp_rmqs(account, conf.debug, conf.rmqs_argument,
4210                         &errmsg, &errstr)) != EX_OK)
4211         {
4212             if (errstr)
4213             {
4214                 print_error("%s", sanitize_string(errstr));
4215             }
4216             if (errmsg)
4217             {
4218                 lp = errmsg;
4219                 while (!list_is_empty(lp))
4220                 {
4221                     lp = lp->next;
4222                     print_error(_("server message: %s"),
4223                             sanitize_string(lp->data));
4224                 }
4225             }
4226         }
4227     }
4228 
4229 
4230 exit:
4231 
4232     /* clean up */
4233     if (header_tmpfile)
4234     {
4235         fclose(header_tmpfile);
4236     }
4237     if (prepend_header_tmpfile)
4238     {
4239         fclose(prepend_header_tmpfile);
4240     }
4241     free(loaded_system_conffile);
4242     free(loaded_user_conffile);
4243 #ifdef HAVE_TLS
4244     if (tls_lib_initialized)
4245     {
4246         mtls_lib_deinit();
4247     }
4248 #endif /* HAVE_TLS */
4249     if (net_lib_initialized)
4250     {
4251         net_lib_deinit();
4252     }
4253     if (account_list)
4254     {
4255         list_xfree(account_list, account_free);
4256     }
4257     account_free(conf.cmdline_account);
4258     account_free(account);
4259     if (conf.recipients)
4260     {
4261         list_xfree(conf.recipients, free);
4262     }
4263     free(errstr);
4264     if (errmsg)
4265     {
4266         list_xfree(errmsg, free);
4267     }
4268 
4269     return error_code;
4270 }
4271