1 /*
2  * conf.c
3  *
4  * This file is part of msmtp, an SMTP client.
5  *
6  * Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012,
7  * 2014, 2015, 2016, 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 <stdlib.h>
31 #include <limits.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #ifdef HAVE_FNMATCH_H
38 # include <fnmatch.h>
39 #endif
40 
41 #include "gettext.h"
42 #define _(string) gettext(string)
43 
44 #include "list.h"
45 #include "smtp.h"
46 #include "tools.h"
47 #include "net.h"
48 #include "xalloc.h"
49 #include "conf.h"
50 
51 /* buffer size for configuration file lines */
52 #define LINEBUFSIZE 501
53 
54 
55 /*
56  * account_new()
57  *
58  * see conf.h
59  */
60 
account_new(const char * conffile,const char * id)61 account_t *account_new(const char *conffile, const char *id)
62 {
63     account_t *a;
64     a = xmalloc(sizeof(account_t));
65     a->id = id ? xstrdup(id) : NULL;
66     a->conffile = conffile ? xstrdup(conffile) : NULL;
67     a->mask = 0LL;
68     a->host = NULL;
69     a->port = 0;                /* this must be set later */
70     a->timeout = 0;
71     a->protocol = SMTP_PROTO_SMTP;
72     a->domain = xstrdup("localhost");
73     a->auto_from = 0;
74     a->from = NULL;
75     a->maildomain = NULL;
76     a->dsn_return = NULL;
77     a->dsn_notify = NULL;
78     a->auth_mech = NULL;
79     a->username = NULL;
80     a->password = NULL;
81     a->passwordeval = NULL;
82     a->ntlmdomain = NULL;
83     a->tls = 0;
84     a->tls_nostarttls = 0;
85     a->tls_key_file = NULL;
86     a->tls_cert_file = NULL;
87     a->tls_trust_file = NULL;
88     a->tls_crl_file = NULL;
89     a->tls_sha256_fingerprint = NULL;
90     a->tls_sha1_fingerprint = NULL;
91     a->tls_md5_fingerprint = NULL;
92     a->tls_nocertcheck = 0;
93     a->tls_min_dh_prime_bits = -1;
94     a->tls_priorities = NULL;
95     a->tls_host_override = NULL;
96     a->logfile = NULL;
97     a->logfile_time_format = NULL;
98     a->syslog = NULL;
99     a->aliases = NULL;
100     a->proxy_host = NULL;
101     a->proxy_port = 0;
102     a->set_from_header = 2;
103     a->set_date_header = 2;
104     a->remove_bcc_headers = 1;
105     a->undisclosed_recipients = 0;
106     a->source_ip = NULL;
107     a->socketname = NULL;
108     return a;
109 }
110 
111 
112 /*
113  * account_copy()
114  *
115  * see conf.h
116  */
117 
account_copy(account_t * acc)118 account_t *account_copy(account_t *acc)
119 {
120     account_t *a = NULL;
121 
122     if (acc)
123     {
124         a = xmalloc(sizeof(account_t));
125         a->id = acc->id ? xstrdup(acc->id) : NULL;
126         a->conffile = acc->conffile ? xstrdup(acc->conffile) : NULL;
127         a->mask = acc->mask;
128         a->host = acc->host ? xstrdup(acc->host) : NULL;
129         a->port = acc->port;
130         a->timeout = acc->timeout;
131         a->protocol = acc->protocol;
132         a->domain = acc->domain ? xstrdup(acc->domain) : NULL;
133         a->auto_from = acc->auto_from;
134         a->from = acc->from ? xstrdup(acc->from) : NULL;
135         a->maildomain = acc->maildomain ? xstrdup(acc->maildomain) : NULL;
136         a->dsn_return = acc->dsn_return ? xstrdup(acc->dsn_return) : NULL;
137         a->dsn_notify = acc->dsn_notify ? xstrdup(acc->dsn_notify) : NULL;
138         a->auth_mech = acc->auth_mech ? xstrdup(acc->auth_mech) : NULL;
139         a->username = acc->username ? xstrdup(acc->username) : NULL;
140         a->password = acc->password ? xstrdup(acc->password) : NULL;
141         a->passwordeval = acc->passwordeval ? xstrdup(acc->passwordeval) : NULL;
142         a->ntlmdomain = acc->ntlmdomain ? xstrdup(acc->ntlmdomain) : NULL;
143         a->tls = acc->tls;
144         a->tls_nostarttls = acc->tls_nostarttls;
145         a->tls_key_file = acc->tls_key_file ? xstrdup(acc->tls_key_file) : NULL;
146         a->tls_cert_file =
147             acc->tls_cert_file ? xstrdup(acc->tls_cert_file) : NULL;
148         a->tls_trust_file =
149             acc->tls_trust_file ? xstrdup(acc->tls_trust_file) : NULL;
150         a->tls_crl_file =
151             acc->tls_crl_file ? xstrdup(acc->tls_crl_file) : NULL;
152         if (acc->tls_sha256_fingerprint)
153         {
154             a->tls_sha256_fingerprint = xmalloc(32);
155             memcpy(a->tls_sha256_fingerprint, acc->tls_sha256_fingerprint, 32);
156         }
157         else
158         {
159             a->tls_sha256_fingerprint = NULL;
160         }
161         if (acc->tls_sha1_fingerprint)
162         {
163             a->tls_sha1_fingerprint = xmalloc(20);
164             memcpy(a->tls_sha1_fingerprint, acc->tls_sha1_fingerprint, 20);
165         }
166         else
167         {
168             a->tls_sha1_fingerprint = NULL;
169         }
170         if (acc->tls_md5_fingerprint)
171         {
172             a->tls_md5_fingerprint = xmalloc(16);
173             memcpy(a->tls_md5_fingerprint, acc->tls_md5_fingerprint, 16);
174         }
175         else
176         {
177             a->tls_md5_fingerprint = NULL;
178         }
179         a->tls_nocertcheck = acc->tls_nocertcheck;
180         a->tls_min_dh_prime_bits = acc->tls_min_dh_prime_bits;
181         a->tls_priorities =
182             acc->tls_priorities ? xstrdup(acc->tls_priorities) : NULL;
183         a->tls_host_override =
184             acc->tls_host_override ? xstrdup(acc->tls_host_override) : NULL;
185         a->logfile = acc->logfile ? xstrdup(acc->logfile) : NULL;
186         a->logfile_time_format =
187             acc->logfile_time_format ? xstrdup(acc->logfile_time_format) : NULL;
188         a->syslog = acc->syslog ? xstrdup(acc->syslog) : NULL;
189         a->aliases = acc->aliases ? xstrdup(acc->aliases) : NULL;
190         a->proxy_host = acc->proxy_host ? xstrdup(acc->proxy_host) : NULL;
191         a->proxy_port = acc->proxy_port;
192         a->set_from_header = acc->set_from_header;
193         a->set_date_header = acc->set_date_header;
194         a->remove_bcc_headers = acc->remove_bcc_headers;
195         a->undisclosed_recipients = acc->undisclosed_recipients;
196         a->source_ip = acc->source_ip ? xstrdup(acc->source_ip) : NULL;
197         a->socketname = acc->socketname ? xstrdup(acc->socketname) : NULL;
198     }
199     return a;
200 }
201 
202 
203 /*
204  * account_free()
205  *
206  * see conf.h
207  */
208 
account_free(void * a)209 void account_free(void *a)
210 {
211     account_t *p = a;
212     if (p)
213     {
214         free(p->id);
215         free(p->conffile);
216         free(p->host);
217         free(p->domain);
218         free(p->from);
219         free(p->maildomain);
220         free(p->auth_mech);
221         free(p->username);
222         free(p->password);
223         free(p->passwordeval);
224         free(p->ntlmdomain);
225         free(p->tls_key_file);
226         free(p->tls_cert_file);
227         free(p->tls_trust_file);
228         free(p->tls_crl_file);
229         free(p->tls_sha256_fingerprint);
230         free(p->tls_sha1_fingerprint);
231         free(p->tls_md5_fingerprint);
232         free(p->tls_priorities);
233         free(p->tls_host_override);
234         free(p->dsn_return);
235         free(p->dsn_notify);
236         free(p->logfile);
237         free(p->logfile_time_format);
238         free(p->syslog);
239         free(p->aliases);
240         free(p->proxy_host);
241         free(p->source_ip);
242         free(p->socketname);
243         free(p);
244     }
245 }
246 
247 
248 /*
249  * find_account()
250  *
251  * see conf.h
252  */
253 
find_account(list_t * acc_list,const char * id)254 account_t *find_account(list_t *acc_list, const char *id)
255 {
256     account_t *a = NULL;
257     char *acc_id;
258 
259     while (!list_is_empty(acc_list))
260     {
261         acc_list = acc_list->next;
262         acc_id = ((account_t *)(acc_list->data))->id;
263         if (acc_id && strcmp(id, acc_id) == 0)
264         {
265             a = acc_list->data;
266             break;
267         }
268     }
269 
270     return a;
271 }
272 
273 
274 /*
275  * find_account_by_envelope_from()
276  *
277  * see conf.h
278  */
279 
find_account_by_envelope_from(list_t * acc_list,const char * from)280 account_t *find_account_by_envelope_from(list_t *acc_list, const char *from)
281 {
282     account_t *a = NULL;
283     const char *from_detail = strchr(from, '+');
284     const char *from_domain = strchr(from, '@');
285     const char *acc_from, *acc_domain;
286 
287     while (!list_is_empty(acc_list))
288     {
289         acc_list = acc_list->next;
290         acc_from = ((account_t *)(acc_list->data))->from;
291         if (!acc_from)
292         {
293             continue;
294         }
295         if (from_detail && from_domain && !strchr(acc_from, '+'))
296         {
297             /*
298              * Subaddressing matches the pattern /user+detail@domain/. Take `from` to
299              * match `acc_from` iff both user and domain match; i.e., ignore the detail.
300              */
301             acc_domain = strchr(acc_from, '@');
302             if (acc_domain
303                     && (acc_domain - acc_from == from_detail - from)
304                     && strncasecmp(from, acc_from, from_detail - from) == 0
305                     && strcasecmp(from_domain, acc_domain) == 0)
306             {
307                 a = acc_list->data;
308                 break;
309             }
310         }
311 #ifdef HAVE_FNMATCH_H
312         else if (strchr(acc_from, '?') || strchr(acc_from, '*') || strchr(acc_from, '['))
313         {
314             /* This is a wildcard pattern according to glob(7) */
315             if (fnmatch(acc_from, from, 0) != FNM_NOMATCH)
316             {
317                 a = acc_list->data;
318                 break;
319             }
320         }
321 #endif
322         else
323         {
324             /* simple matching */
325             if (strcasecmp(from, acc_from) == 0)
326             {
327                 a = acc_list->data;
328                 break;
329             }
330         }
331     }
332 
333     return a;
334 }
335 
336 
337 /*
338  * is_on(), is_off(), is_auto()
339  *
340  * see conf.h
341  */
342 
is_on(const char * s)343 int is_on(const char *s)
344 {
345     return (strcmp(s, "on") == 0);
346 }
347 
is_off(const char * s)348 int is_off(const char *s)
349 {
350     return (strcmp(s, "off") == 0);
351 }
352 
is_auto(const char * s)353 int is_auto(const char *s)
354 {
355     return (strcmp(s, "auto") == 0);
356 }
357 
358 
359 /*
360  * get_pos_int()
361  *
362  * see conf.h
363  */
364 
get_pos_int(const char * s)365 int get_pos_int(const char *s)
366 {
367     long x;
368     char *p;
369 
370     errno = 0;
371     x = strtol(s, &p, 0);
372     if (p == s || x <= 0 || (x == LONG_MAX && errno == ERANGE) || x > INT_MAX)
373     {
374         x = -1;
375     }
376     else if (*p != '\0')
377     {
378         /* trailing garbage */
379         x = -1;
380     }
381 
382     return x;
383 }
384 
385 
386 /*
387  * get_fingerprint()
388  *
389  * see conf.h
390  */
391 
get_fingerprint(const char * s,size_t len)392 unsigned char *get_fingerprint(const char *s, size_t len)
393 {
394     unsigned char *fingerprint = xmalloc(len);
395     unsigned char hex[2];
396     size_t i, j;
397     char c;
398 
399     if (strlen(s) != 2 * len + (len - 1))
400     {
401         free(fingerprint);
402         return NULL;
403     }
404     for (i = 0; i < len; i++)
405     {
406         for (j = 0; j < 2; j++)
407         {
408             c = toupper((unsigned char)s[3 * i + j]);
409             if (c >= '0' && c <= '9')
410             {
411                 hex[j] = c - '0';
412             }
413             else if (c >= 'A' && c <= 'F')
414             {
415                 hex[j] = c - 'A' + 10;
416             }
417             else
418             {
419                 free(fingerprint);
420                 return NULL;
421             }
422         }
423         if (i < len - 1 && s[3 * i + 2] != ':' && s[3 * i + 2] != ' ')
424         {
425             free(fingerprint);
426             return NULL;
427         }
428         fingerprint[i] = (hex[0] << 4) | hex[1];
429     }
430     return fingerprint;
431 }
432 
433 
434 /*
435  * check_auth_arg()
436  *
437  * see conf.h
438  */
439 
check_auth_arg(char * arg)440 int check_auth_arg(char *arg)
441 {
442     size_t l, i;
443 
444     if (*arg == '\0')
445     {
446         return 0;
447     }
448     else if (strcmp(arg, "plain") == 0
449             || strcmp(arg, "cram-md5") == 0
450             || strcmp(arg, "digest-md5") == 0
451             || strcmp(arg, "scram-sha-1") == 0
452             || strcmp(arg, "scram-sha-256") == 0
453             || strcmp(arg, "gssapi") == 0
454             || strcmp(arg, "external") == 0
455             || strcmp(arg, "login") == 0
456             || strcmp(arg, "ntlm") == 0
457             || strcmp(arg, "oauthbearer") == 0
458             || strcmp(arg, "xoauth2") == 0)
459     {
460         l = strlen(arg);
461         for (i = 0; i < l; i++)
462         {
463             arg[i] = toupper((unsigned char)arg[i]);
464         }
465         return 0;
466     }
467     else
468     {
469         return 1;
470     }
471 }
472 
473 
474 /*
475  * check_dsn_notify_arg()
476  *
477  * see conf.h
478  */
479 
check_dsn_notify_arg(char * arg)480 int check_dsn_notify_arg(char *arg)
481 {
482     int count;
483     size_t i;
484     size_t l;
485 
486     if (strcmp(arg, "never") != 0)
487     {
488         l = 0;
489         count = 0;
490         if (strstr(arg, "failure"))
491         {
492             count++;
493             l += 7;
494         }
495         if (strstr(arg, "delay"))
496         {
497             count++;
498             l += 5;
499         }
500         if (strstr(arg, "success"))
501         {
502             count++;
503             l += 7;
504         }
505         if (count == 0
506                 || (strlen(arg) != l + count - 1)
507                 || (count == 2 && !strchr(arg, ','))
508                 || (count == 3 && !(strchr(arg, ',')
509                         && strchr(strchr(arg, ',') + 1, ','))))
510         {
511             return 1;
512         }
513     }
514     l = strlen(arg);
515     for (i = 0; i < l; i++)
516     {
517         arg[i] = toupper((unsigned char)arg[i]);
518     }
519     return 0;
520 }
521 
522 
523 /*
524  * check_syslog_arg()
525  *
526  * see conf.h
527  */
528 
check_syslog_arg(const char * arg)529 int check_syslog_arg(const char *arg)
530 {
531     if (strcmp(arg, "LOG_USER") == 0
532             || strcmp(arg, "LOG_MAIL") == 0
533             || (strncmp(arg, "LOG_LOCAL", 9) == 0
534                 && strlen(arg) == 10
535                 && (arg[9] == '0'
536                     || arg[9] == '1'
537                     || arg[9] == '2'
538                     || arg[9] == '3'
539                     || arg[9] == '4'
540                     || arg[9] == '5'
541                     || arg[9] == '6'
542                     || arg[9] == '7')))
543     {
544         return 0;
545     }
546     else
547     {
548         return 1;
549     }
550 }
551 
552 
553 /*
554  * get_default_syslog_facility()
555  *
556  * Returns a pointer to an allocated string containing the default syslog
557  * facility.
558  */
559 
get_default_syslog_facility(void)560 char *get_default_syslog_facility(void)
561 {
562     return xstrdup("LOG_USER");
563 }
564 
565 
566 /*
567  * override_account()
568  *
569  * see conf.h
570  */
571 
override_account(account_t * acc1,account_t * acc2)572 void override_account(account_t *acc1, account_t *acc2)
573 {
574     if (acc2->conffile)
575     {
576         free(acc1->conffile);
577         acc1->conffile = xstrdup(acc2->conffile);
578     }
579     if (acc2->mask & ACC_HOST)
580     {
581         free(acc1->host);
582         acc1->host = acc2->host ? xstrdup(acc2->host) : NULL;
583     }
584     if (acc2->mask & ACC_PORT)
585     {
586         acc1->port = acc2->port;
587     }
588     if (acc2->mask & ACC_TIMEOUT)
589     {
590         acc1->timeout = acc2->timeout;
591     }
592     if (acc2->mask & ACC_PROTOCOL)
593     {
594         acc1->protocol = acc2->protocol;
595     }
596     if (acc2->mask & ACC_DOMAIN)
597     {
598         free(acc1->domain);
599         acc1->domain = acc2->domain ? xstrdup(acc2->domain) : NULL;
600     }
601     if (acc2->mask & ACC_AUTO_FROM)
602     {
603         acc1->auto_from = acc2->auto_from;
604     }
605     if (acc2->mask & ACC_FROM)
606     {
607         free(acc1->from);
608         acc1->from = acc2->from ? xstrdup(acc2->from) : NULL;
609     }
610     if (acc2->mask & ACC_MAILDOMAIN)
611     {
612         free(acc1->maildomain);
613         acc1->maildomain = acc2->maildomain ? xstrdup(acc2->maildomain) : NULL;
614     }
615     if (acc2->mask & ACC_AUTH_MECH)
616     {
617         free(acc1->auth_mech);
618         acc1->auth_mech = acc2->auth_mech ? xstrdup(acc2->auth_mech) : NULL;
619     }
620     if (acc2->mask & ACC_USERNAME)
621     {
622         free(acc1->username);
623         acc1->username = acc2->username ? xstrdup(acc2->username) : NULL;
624     }
625     if (acc2->mask & ACC_PASSWORD)
626     {
627         free(acc1->password);
628         acc1->password = acc2->password ? xstrdup(acc2->password) : NULL;
629     }
630     if (acc2->mask & ACC_PASSWORDEVAL)
631     {
632         free(acc1->passwordeval);
633         acc1->passwordeval =
634             acc2->passwordeval ? xstrdup(acc2->passwordeval) : NULL;
635     }
636     if (acc2->mask & ACC_NTLMDOMAIN)
637     {
638         free(acc1->ntlmdomain);
639         acc1->ntlmdomain = acc2->ntlmdomain ? xstrdup(acc2->ntlmdomain) : NULL;
640     }
641     if (acc2->mask & ACC_TLS)
642     {
643         acc1->tls = acc2->tls;
644     }
645     if (acc2->mask & ACC_TLS_NOSTARTTLS)
646     {
647         acc1->tls_nostarttls = acc2->tls_nostarttls;
648     }
649     if (acc2->mask & ACC_TLS_KEY_FILE)
650     {
651         free(acc1->tls_key_file);
652         acc1->tls_key_file =
653             acc2->tls_key_file ? xstrdup(acc2->tls_key_file) : NULL;
654     }
655     if (acc2->mask & ACC_TLS_CERT_FILE)
656     {
657         free(acc1->tls_cert_file);
658         acc1->tls_cert_file =
659             acc2->tls_cert_file ? xstrdup(acc2->tls_cert_file) : NULL;
660     }
661     if (acc2->mask & ACC_TLS_TRUST_FILE)
662     {
663         free(acc1->tls_trust_file);
664         acc1->tls_trust_file =
665             acc2->tls_trust_file ? xstrdup(acc2->tls_trust_file) : NULL;
666     }
667     if (acc2->mask & ACC_TLS_CRL_FILE)
668     {
669         free(acc1->tls_crl_file);
670         acc1->tls_crl_file =
671             acc2->tls_crl_file ? xstrdup(acc2->tls_crl_file) : NULL;
672     }
673     if (acc2->mask & ACC_TLS_FINGERPRINT)
674     {
675         free(acc1->tls_sha256_fingerprint);
676         if (acc2->tls_sha256_fingerprint)
677         {
678             acc1->tls_sha256_fingerprint = xmalloc(32);
679             memcpy(acc1->tls_sha256_fingerprint, acc2->tls_sha256_fingerprint, 32);
680         }
681         else
682         {
683             acc1->tls_sha256_fingerprint = NULL;
684         }
685         free(acc1->tls_sha1_fingerprint);
686         if (acc2->tls_sha1_fingerprint)
687         {
688             acc1->tls_sha1_fingerprint = xmalloc(20);
689             memcpy(acc1->tls_sha1_fingerprint, acc2->tls_sha1_fingerprint, 20);
690         }
691         else
692         {
693             acc1->tls_sha1_fingerprint = NULL;
694         }
695         free(acc1->tls_md5_fingerprint);
696         if (acc2->tls_md5_fingerprint)
697         {
698             acc1->tls_md5_fingerprint = xmalloc(16);
699             memcpy(acc1->tls_md5_fingerprint, acc2->tls_md5_fingerprint, 16);
700         }
701         else
702         {
703             acc1->tls_md5_fingerprint = NULL;
704         }
705     }
706     if (acc2->mask & ACC_TLS_NOCERTCHECK)
707     {
708         acc1->tls_nocertcheck = acc2->tls_nocertcheck;
709     }
710     if (acc2->mask & ACC_TLS_MIN_DH_PRIME_BITS)
711     {
712         acc1->tls_min_dh_prime_bits = acc2->tls_min_dh_prime_bits;
713     }
714     if (acc2->mask & ACC_TLS_PRIORITIES)
715     {
716         free(acc1->tls_priorities);
717         acc1->tls_priorities = acc2->tls_priorities
718             ? xstrdup(acc2->tls_priorities) : NULL;
719     }
720     if (acc2->mask & ACC_TLS_HOST_OVERRIDE)
721     {
722         free(acc1->tls_host_override);
723         acc1->tls_host_override = acc2->tls_host_override
724             ? xstrdup(acc2->tls_host_override) : NULL;
725     }
726     if (acc2->mask & ACC_DSN_RETURN)
727     {
728         free(acc1->dsn_return);
729         acc1->dsn_return = acc2->dsn_return ? xstrdup(acc2->dsn_return) : NULL;
730     }
731     if (acc2->mask & ACC_DSN_NOTIFY)
732     {
733         free(acc1->dsn_notify);
734         acc1->dsn_notify = acc2->dsn_notify ? xstrdup(acc2->dsn_notify) : NULL;
735     }
736     if (acc2->mask & ACC_REMOVE_BCC_HEADERS)
737     {
738         acc1->remove_bcc_headers = acc2->remove_bcc_headers;
739     }
740     if (acc2->mask & ACC_UNDISCLOSED_RECIPIENTS)
741     {
742         acc1->undisclosed_recipients = acc2->undisclosed_recipients;
743     }
744     if (acc2->mask & ACC_LOGFILE)
745     {
746         free(acc1->logfile);
747         acc1->logfile = acc2->logfile ? xstrdup(acc2->logfile) : NULL;
748     }
749     if (acc2->mask & ACC_LOGFILE_TIME_FORMAT)
750     {
751         free(acc1->logfile_time_format);
752         acc1->logfile_time_format =
753             acc2->logfile_time_format ? xstrdup(acc2->logfile_time_format) : NULL;
754     }
755     if (acc2->mask & ACC_SYSLOG)
756     {
757         free(acc1->syslog);
758         acc1->syslog = acc2->syslog ? xstrdup(acc2->syslog) : NULL;
759     }
760     if (acc2->mask & ACC_ALIASES)
761     {
762         free(acc1->aliases);
763         acc1->aliases = acc2->aliases ? xstrdup(acc2->aliases) : NULL;
764     }
765     if (acc2->mask & ACC_PROXY_HOST)
766     {
767         free(acc1->proxy_host);
768         acc1->proxy_host = acc2->proxy_host ? xstrdup(acc2->proxy_host) : NULL;
769     }
770     if (acc2->mask & ACC_PROXY_PORT)
771     {
772         acc1->proxy_port = acc2->proxy_port;
773     }
774     if (acc2->mask & ACC_SET_FROM_HEADER)
775     {
776         acc1->set_from_header = acc2->set_from_header;
777     }
778     if (acc2->mask & ACC_SET_DATE_HEADER)
779     {
780         acc1->set_date_header = acc2->set_date_header;
781     }
782     if (acc2->mask & ACC_SOURCE_IP)
783     {
784         free(acc1->source_ip);
785         acc1->source_ip = acc2->source_ip ? xstrdup(acc2->source_ip) : NULL;
786     }
787     if (acc2->mask & ACC_SOCKET)
788     {
789         free(acc1->socketname);
790         acc1->socketname = acc2->socketname ? xstrdup(acc2->socketname) : NULL;
791     }
792     acc1->mask |= acc2->mask;
793 }
794 
795 
796 /*
797  * check_account()
798  *
799  * see conf.h
800  */
801 
check_account(account_t * acc,int sendmail_mode,char ** errstr)802 int check_account(account_t *acc, int sendmail_mode, char **errstr)
803 {
804     if (!acc->host && !acc->socketname)
805     {
806         *errstr = xasprintf(_("host not set"));
807         return CONF_ESYNTAX;
808     }
809     if (acc->port == 0)
810     {
811         *errstr = xasprintf(_("port not set"));
812         return CONF_ESYNTAX;
813     }
814     if (sendmail_mode && !acc->from)
815     {
816         *errstr = xasprintf(_("envelope-from address is missing"));
817         return CONF_ESYNTAX;
818     }
819     if (acc->tls && !(acc->host || acc->tls_host_override))
820     {
821         *errstr = xasprintf(_("host not set"));
822         return CONF_ESYNTAX;
823     }
824     if (acc->tls_key_file && !acc->tls_cert_file)
825     {
826         *errstr = xasprintf(_("tls_key_file requires tls_cert_file"));
827         return CONF_ESYNTAX;
828     }
829     if (!acc->tls_key_file && acc->tls_cert_file)
830     {
831         *errstr = xasprintf(_("tls_cert_file requires tls_key_file"));
832         return CONF_ESYNTAX;
833     }
834     if (acc->tls && !acc->tls_trust_file
835             && !acc->tls_sha256_fingerprint && !acc->tls_sha1_fingerprint
836             && !acc->tls_md5_fingerprint && !acc->tls_nocertcheck)
837     {
838         *errstr = xasprintf(
839                 _("tls requires either tls_trust_file (highly recommended) "
840                     "or tls_fingerprint or a disabled tls_certcheck"));
841         return CONF_ESYNTAX;
842     }
843     if (acc->tls_crl_file && !acc->tls_trust_file)
844     {
845         *errstr = xasprintf(_("tls_crl_file requires tls_trust_file"));
846         return CONF_ESYNTAX;
847     }
848 
849     return CONF_EOK;
850 }
851 
852 
853 /*
854  * helper function for expand_from() and expand_domain()
855  */
856 
expand_from_or_domain(char ** str,int expand_U,char ** errstr)857 static int expand_from_or_domain(char **str, int expand_U, char **errstr)
858 {
859     char* M = NULL;
860     char* U = NULL;
861     char* H = NULL;
862     char* C = NULL;
863 
864     if (strstr(*str, "%M"))
865     {
866         char *sysconfdir;
867         char *filename;
868         FILE *f;
869         char buf[256];
870         size_t buflen;
871 
872         sysconfdir = get_sysconfdir();
873         filename = get_filename(sysconfdir, "mailname");
874         free(sysconfdir);
875         if (!(f = fopen(filename, "r")))
876         {
877             *errstr = xasprintf(_("%s: %s"), filename, strerror(errno));
878             free(filename);
879             return CONF_ECANTOPEN;
880         }
881         buf[0] = '\0';
882         if (!fgets(buf, sizeof(buf), f) && ferror(f))
883         {
884             *errstr = xasprintf(_("%s: %s"), filename, strerror(errno));
885             free(filename);
886             fclose(f);
887             return CONF_EIO;
888         }
889         fclose(f);
890         buflen = strlen(buf);
891         if (buflen > 0 && buf[buflen - 1] == '\n')
892         {
893             buf[--buflen] = '\0';
894         }
895         if (buflen > 0 && buf[buflen - 1] == '\r')
896         {
897             buf[--buflen] = '\0';
898         }
899         if (buflen == 0)
900         {
901             *errstr = xasprintf(_("%s: %s"), filename, strerror(EINVAL));
902             free(filename);
903             return CONF_EPARSE;
904         }
905         free(filename);
906         M = xstrdup(buf);
907         sanitize_string(M);
908     }
909     if (expand_U && strstr(*str, "%U"))
910     {
911         U = get_username();
912         sanitize_string(U);
913     }
914     if (strstr(*str, "%H") || strstr(*str, "%C"))
915     {
916         H = get_hostname();
917         sanitize_string(H);
918     }
919     if (strstr(*str, "%C"))
920     {
921         C = net_get_canonical_hostname(H);
922     }
923 
924     if (M)
925     {
926         *str = string_replace(*str, "%M", M);
927         free(M);
928     }
929     if (U)
930     {
931         *str = string_replace(*str, "%U", U);
932         free(U);
933     }
934     if (H)
935     {
936         *str = string_replace(*str, "%H", H);
937         free(H);
938     }
939     if (C)
940     {
941         *str = string_replace(*str, "%C", C);
942         free(C);
943     }
944 
945     return CONF_EOK;
946 }
947 
948 
949 /*
950  * expand_from()
951  *
952  * see conf.h
953  */
954 
expand_from(char ** from,char ** errstr)955 int expand_from(char **from, char **errstr)
956 {
957     return expand_from_or_domain(from, 1, errstr);
958 }
959 
960 
961 /*
962  * expand_domain()
963  *
964  * see conf.h
965  */
966 
expand_domain(char ** domain,char ** errstr)967 int expand_domain(char **domain, char **errstr)
968 {
969     return expand_from_or_domain(domain, 0, errstr);
970 }
971 
972 
973 /*
974  * some small helper functions
975  */
976 
is_blank(int c)977 int is_blank(int c)
978 {
979     return (c == ' ' || c == '\t');
980 }
981 
skip_blanks(const char * s,int i)982 int skip_blanks(const char *s, int i)
983 {
984     while (is_blank(s[i]))
985     {
986         i++;
987     }
988     return i;
989 }
990 
get_cmd_length(const char * s)991 int get_cmd_length(const char *s)
992 {
993     int i = 0;
994 
995     while (s[i] != '\0' && !is_blank(s[i]))
996     {
997         i++;
998     }
999     return i;
1000 }
1001 
1002 /* get index of last non-blank character. -1 means there is none. */
get_last_nonblank(const char * s)1003 int get_last_nonblank(const char *s)
1004 {
1005     int i;
1006 
1007     i = (int)strlen(s) - 1;
1008     while (i >= 0 && is_blank(s[i]))
1009     {
1010         i--;
1011     }
1012     return i;
1013 }
1014 
1015 /* Return string without whitespace at beginning and end. If the string is
1016  * enclosed in double quotes, remove these, too. String is allocated. */
trim_string(const char * s)1017 char *trim_string(const char *s)
1018 {
1019     char *t;
1020     int i;
1021     int l;
1022 
1023     i = skip_blanks(s, 0);
1024     l = get_last_nonblank(s + i);
1025     if (l >= 1 && s[i] == '"' && s[i + l] == '"')
1026     {
1027         t = xmalloc(l * sizeof(char));
1028         strncpy(t, s + i + 1, l - 1);
1029         t[l - 1] = '\0';
1030     }
1031     else
1032     {
1033         t = xmalloc((l + 2) * sizeof(char));
1034         strncpy(t, s + i, l + 1);
1035         t[l + 1] = '\0';
1036     }
1037     return t;
1038 }
1039 
1040 
1041 /*
1042  * get_next_cmd()
1043  *
1044  * Read a line from 'f'. Split it in a command part (first word after
1045  * whitespace) and an argument part (the word after the command).
1046  * Whitespace is ignored.
1047  * Sets the flag 'empty_line' if the line is empty.
1048  * Sets the flag 'eof' if EOF occurred.
1049  * On errors, 'empty_line' and 'eof', 'cmd' and 'arg' NULL.
1050  * On success, 'cmd' and 'arg' are allocated strings.
1051  * Used error codes: CONF_EIO, CONF_EPARSE
1052  */
1053 
get_next_cmd(FILE * f,char ** cmd,char ** arg,int * empty_line,int * eof,char ** errstr)1054 int get_next_cmd(FILE *f, char **cmd, char **arg, int *empty_line, int *eof,
1055         char **errstr)
1056 {
1057     char line[LINEBUFSIZE];
1058     char *p;
1059     int i;
1060     int l;
1061 
1062     *eof = 0;
1063     *empty_line = 0;
1064     *cmd = NULL;
1065     *arg = NULL;
1066     if (!fgets(line, (int)sizeof(line), f))
1067     {
1068         if (ferror(f))
1069         {
1070             *errstr = xasprintf(_("input error"));
1071             return CONF_EIO;
1072         }
1073         else /* EOF */
1074         {
1075             *eof = 1;
1076             return CONF_EOK;
1077         }
1078     }
1079 
1080     /* Kill '\n'. Beware: sometimes the last line of a file has no '\n' */
1081     if ((p = strchr(line, '\n')))
1082     {
1083         *p = '\0';
1084         /* Kill '\r' (if CRLF line endings are used) */
1085         if (p > line && *(p - 1) == '\r')
1086         {
1087             *(p - 1) = '\0';
1088         }
1089     }
1090     else if (strlen(line) == LINEBUFSIZE - 1)
1091     {
1092         *errstr = xasprintf(_("line longer than %d characters"),
1093                 LINEBUFSIZE - 1);
1094         return CONF_EPARSE;
1095     }
1096 
1097     i = skip_blanks(line, 0);
1098 
1099     if (line[i] == '#' || line[i] == '\0')
1100     {
1101         *empty_line = 1;
1102         return CONF_EOK;
1103     }
1104 
1105     l = get_cmd_length(line + i);
1106     *cmd = xmalloc((l + 1) * sizeof(char));
1107     strncpy(*cmd, line + i, (size_t)l);
1108     (*cmd)[l] = '\0';
1109 
1110     *arg = trim_string(line + i + l);
1111 
1112     return CONF_EOK;
1113 }
1114 
1115 
1116 /*
1117  * read_account_list()
1118  *
1119  * Helper function for the account command: For every account name in the comma
1120  * separated string 's' search the account in 'acc_list' and add a pointer to
1121  * it to 'l'.
1122  */
1123 
read_account_list(int line,list_t * acc_list,char * s,list_t * l,char ** errstr)1124 int read_account_list(int line, list_t *acc_list, char *s, list_t *l,
1125         char **errstr)
1126 {
1127     list_t *lp = l;
1128     char *comma;
1129     char *acc_id;
1130     account_t *acc;
1131 
1132     for (;;)
1133     {
1134         comma = strchr(s, ',');
1135         if (comma)
1136         {
1137             *comma = '\0';
1138         }
1139         acc_id = trim_string(s);
1140         if (*acc_id == '\0')
1141         {
1142             free(acc_id);
1143             *errstr = xasprintf(_("line %d: missing account name"), line);
1144             return CONF_ESYNTAX;
1145         }
1146         if (!(acc = find_account(acc_list, acc_id)))
1147         {
1148             *errstr = xasprintf(_("line %d: account %s not (yet) defined"),
1149                     line, acc_id);
1150             free(acc_id);
1151             return CONF_ESYNTAX;
1152         }
1153         free(acc_id);
1154         list_insert(lp, acc);
1155         lp = lp->next;
1156         if (comma)
1157         {
1158             s = comma + 1;
1159         }
1160         else
1161         {
1162             break;
1163         }
1164     }
1165     return CONF_EOK;
1166 }
1167 
1168 
1169 /*
1170  * read_conffile()
1171  *
1172  * Read configuration data from 'f' and store it in 'acc_list'.
1173  * The name of the configuration file, 'conffile', will be stored in the
1174  * "conffile" field of each account.
1175  * Unless an error code is returned, 'acc_list' will always be a new list;
1176  * it may be empty if no accounts were found.
1177  * If the file contains secrets (e.g. passwords), then the flag
1178  * 'conffile_contains_secrets' will be set to 1, else to 0.
1179  * Used error codes: CONF_EIO, CONF_EPARSE, CONF_ESYNTAX
1180  */
1181 
read_conffile(const char * conffile,FILE * f,list_t ** acc_list,int * conffile_contains_secrets,char ** errstr)1182 int read_conffile(const char *conffile, FILE *f, list_t **acc_list,
1183         int *conffile_contains_secrets, char **errstr)
1184 {
1185     int e;
1186     list_t *p;
1187     account_t *defaults;
1188     account_t *acc;
1189     int line;
1190     char *cmd;
1191     char *arg;
1192     int empty_line;
1193     int eof;
1194     /* for the account command: */
1195     char *acc_id;
1196     char *t;
1197     list_t *copy_from;
1198     list_t *lp;
1199 
1200 
1201     *conffile_contains_secrets = 0;
1202     defaults = account_new(NULL, NULL);
1203     *acc_list = list_new();
1204     p = *acc_list;
1205     acc = NULL;
1206     e = CONF_EOK;
1207 
1208     for (line = 1; ; line++)
1209     {
1210         if ((e = get_next_cmd(f, &cmd, &arg, &empty_line, &eof,
1211                         errstr)) != CONF_EOK)
1212         {
1213             break;
1214         }
1215         if (empty_line)
1216         {
1217             continue;
1218         }
1219         if (eof)
1220         {
1221             break;
1222         }
1223 
1224         /* compatibility with 1.2.x: if no account command is given, the first
1225          * account will be named "default". */
1226         if (!acc && strcmp(cmd, "account") != 0 && strcmp(cmd, "defaults") != 0)
1227         {
1228             acc = account_copy(defaults);
1229             acc->id = xstrdup("default");
1230             acc->conffile = xstrdup(conffile);
1231             acc->mask = 0LL;
1232             list_insert(p, acc);
1233             p = p->next;
1234         }
1235         if (strcmp(cmd, "defaults") == 0)
1236         {
1237             if (*arg != '\0')
1238             {
1239                 *errstr = xasprintf(
1240                         _("line %d: command %s does not take an argument"),
1241                         line, cmd);
1242                 e = CONF_ESYNTAX;
1243                 break;
1244             }
1245             acc = defaults;
1246         }
1247         else if (strcmp(cmd, "account") == 0)
1248         {
1249             copy_from = list_new();
1250             if ((t = strchr(arg, ':')))
1251             {
1252                 if ((e = read_account_list(line, *acc_list, t + 1, copy_from,
1253                                 errstr)) != CONF_EOK)
1254                 {
1255                     list_free(copy_from);
1256                     break;
1257                 }
1258                 *t = '\0';
1259                 acc_id = trim_string(arg);
1260             }
1261             else
1262             {
1263                 acc_id = xstrdup(arg);
1264             }
1265             if (*acc_id == '\0')
1266             {
1267                 list_free(copy_from);
1268                 *errstr = xasprintf(_("line %d: missing account name"), line);
1269                 e = CONF_ESYNTAX;
1270                 free(acc_id);
1271                 break;
1272             }
1273             if (strchr(acc_id, ':') || strchr(acc_id, ','))
1274             {
1275                 list_free(copy_from);
1276                 *errstr = xasprintf(_("line %d: an account name must not "
1277                             "contain colons or commas"), line);
1278                 e = CONF_ESYNTAX;
1279                 free(acc_id);
1280                 break;
1281             }
1282             if (find_account(*acc_list, acc_id))
1283             {
1284                 list_free(copy_from);
1285                 *errstr = xasprintf(
1286                         _("line %d: account %s was already defined"),
1287                         line, acc_id);
1288                 e = CONF_ESYNTAX;
1289                 free(acc_id);
1290                 break;
1291             }
1292             acc = account_copy(defaults);
1293             acc->id = acc_id;
1294             acc->conffile = xstrdup(conffile);
1295             acc->mask = 0LL;
1296             list_insert(p, acc);
1297             p = p->next;
1298             lp = copy_from;
1299             while (!list_is_empty(lp))
1300             {
1301                 lp = lp->next;
1302                 override_account(acc, lp->data);
1303             }
1304             list_free(copy_from);
1305         }
1306         else if (strcmp(cmd, "host") == 0)
1307         {
1308             acc->mask |= ACC_HOST;
1309             if (*arg == '\0')
1310             {
1311                 *errstr = xasprintf(_("line %d: command %s needs an argument"),
1312                         line, cmd);
1313                 e = CONF_ESYNTAX;
1314                 break;
1315             }
1316             else
1317             {
1318                 free(acc->host);
1319                 acc->host = xstrdup(arg);
1320             }
1321         }
1322         else if (strcmp(cmd, "port") == 0)
1323         {
1324             acc->mask |= ACC_PORT;
1325             if (*arg == '\0')
1326             {
1327                 /* We should go back to the default, which is to call
1328                  * get_default_port(), but we cannot since the account is not
1329                  * complete yet. So demand an argument here. */
1330                 *errstr = xasprintf(_("line %d: command %s needs an argument"),
1331                         line, cmd);
1332                 e = CONF_ESYNTAX;
1333                 break;
1334             }
1335             else
1336             {
1337                 acc->port = get_pos_int(arg);
1338                 if (acc->port < 1 || acc->port > 65535)
1339                 {
1340                     *errstr = xasprintf(
1341                             _("line %d: invalid argument %s for command %s"),
1342                             line, arg, cmd);
1343                     e = CONF_ESYNTAX;
1344                     break;
1345                 }
1346             }
1347         }
1348         else if (strcmp(cmd, "timeout") == 0
1349                 || strcmp(cmd, "connect_timeout") == 0)
1350         {
1351             /* For compatibility with versions <= 1.4.1, connect_timeout is
1352              * accepted as an alias for timeout, though it had a slightly
1353              * different meaning. */
1354             acc->mask |= ACC_TIMEOUT;
1355             if (*arg == '\0')
1356             {
1357                 *errstr = xasprintf(_("line %d: command %s needs an argument"),
1358                         line, cmd);
1359                 e = CONF_ESYNTAX;
1360                 break;
1361             }
1362             else
1363             {
1364                 if (is_off(arg))
1365                 {
1366                     acc->timeout = 0;
1367                 }
1368                 else
1369                 {
1370                     acc->timeout = get_pos_int(arg);
1371                     if (acc->timeout < 1)
1372                     {
1373                         *errstr = xasprintf(_("line %d: invalid argument %s "
1374                                     "for command %s"), line, arg, cmd);
1375                         e = CONF_ESYNTAX;
1376                         break;
1377                     }
1378                 }
1379             }
1380         }
1381         else if (strcmp(cmd, "protocol") == 0)
1382         {
1383             acc->mask |= ACC_PROTOCOL;
1384             if (*arg == '\0')
1385             {
1386                 *errstr = xasprintf(_("line %d: command %s needs an argument"),
1387                         line, cmd);
1388                 e = CONF_ESYNTAX;
1389                 break;
1390             }
1391             else
1392             {
1393                 if (strcmp(arg, "smtp") == 0)
1394                 {
1395                     acc->protocol = SMTP_PROTO_SMTP;
1396                 }
1397                 else if (strcmp(arg, "lmtp") == 0)
1398                 {
1399                     acc->protocol = SMTP_PROTO_LMTP;
1400                 }
1401                 else
1402                 {
1403                     *errstr = xasprintf(
1404                             _("line %d: invalid argument %s for command %s"),
1405                             line, arg, cmd);
1406                     e = CONF_ESYNTAX;
1407                     break;
1408                 }
1409             }
1410         }
1411         else if (strcmp(cmd, "domain") == 0)
1412         {
1413             acc->mask |= ACC_DOMAIN;
1414             free(acc->domain);
1415             acc->domain = xstrdup(arg);
1416         }
1417         else if (strcmp(cmd, "from") == 0)
1418         {
1419             acc->mask |= ACC_FROM;
1420             free(acc->from);
1421             acc->from = xstrdup(arg);
1422         }
1423         else if (strcmp(cmd, "auth") == 0)
1424         {
1425             acc->mask |= ACC_AUTH_MECH;
1426             free(acc->auth_mech);
1427             if (*arg == '\0' || is_on(arg))
1428             {
1429                 acc->auth_mech = xstrdup("");
1430             }
1431             else if (is_off(arg))
1432             {
1433                 acc->auth_mech = NULL;
1434             }
1435             else if (check_auth_arg(arg) == 0)
1436             {
1437                 acc->auth_mech = xstrdup(arg);
1438             }
1439             else
1440             {
1441                 acc->auth_mech = NULL;
1442                 *errstr = xasprintf(
1443                         _("line %d: invalid argument %s for command %s"),
1444                         line, arg, cmd);
1445                 e = CONF_ESYNTAX;
1446                 break;
1447             }
1448         }
1449         else if (strcmp(cmd, "user") == 0)
1450         {
1451             acc->mask |= ACC_USERNAME;
1452             free(acc->username);
1453             acc->username = (*arg == '\0') ? NULL : xstrdup(arg);
1454         }
1455         else if (strcmp(cmd, "password") == 0)
1456         {
1457             *conffile_contains_secrets = 1;
1458             acc->mask |= ACC_PASSWORD;
1459             free(acc->password);
1460             acc->password = (*arg == '\0') ? NULL : xstrdup(arg);
1461         }
1462         else if (strcmp(cmd, "passwordeval") == 0)
1463         {
1464             acc->mask |= ACC_PASSWORDEVAL;
1465             free(acc->passwordeval);
1466             acc->passwordeval = (*arg == '\0') ? NULL : xstrdup(arg);
1467         }
1468         else if (strcmp(cmd, "ntlmdomain") == 0)
1469         {
1470             acc->mask |= ACC_NTLMDOMAIN;
1471             free(acc->ntlmdomain);
1472             acc->ntlmdomain = (*arg == '\0') ? NULL : xstrdup(arg);
1473         }
1474         else if (strcmp(cmd, "tls") == 0)
1475         {
1476             acc->mask |= ACC_TLS;
1477             if (*arg == '\0' || is_on(arg))
1478             {
1479                 acc->tls = 1;
1480             }
1481             else if (is_off(arg))
1482             {
1483                 acc->tls = 0;
1484             }
1485             else
1486             {
1487                 *errstr = xasprintf(
1488                         _("line %d: invalid argument %s for command %s"),
1489                         line, arg, cmd);
1490                 e = CONF_ESYNTAX;
1491                 break;
1492             }
1493         }
1494         else if (strcmp(cmd, "tls_starttls") == 0)
1495         {
1496             acc->mask |= ACC_TLS_NOSTARTTLS;
1497             if (*arg == '\0' || is_on(arg))
1498             {
1499                 acc->tls_nostarttls = 0;
1500             }
1501             else if (is_off(arg))
1502             {
1503                 acc->tls_nostarttls = 1;
1504             }
1505             else
1506             {
1507                 *errstr = xasprintf(
1508                         _("line %d: invalid argument %s for command %s"),
1509                         line, arg, cmd);
1510                 e = CONF_ESYNTAX;
1511                 break;
1512             }
1513         }
1514         else if (strcmp(cmd, "tls_key_file") == 0)
1515         {
1516             acc->mask |= ACC_TLS_KEY_FILE;
1517             free(acc->tls_key_file);
1518             if (*arg == '\0')
1519             {
1520                 acc->tls_key_file = NULL;
1521             }
1522             else
1523             {
1524                 acc->tls_key_file = expand_tilde(arg);
1525             }
1526         }
1527         else if (strcmp(cmd, "tls_cert_file") == 0)
1528         {
1529             acc->mask |= ACC_TLS_CERT_FILE;
1530             free(acc->tls_cert_file);
1531             if (*arg == '\0')
1532             {
1533                 acc->tls_cert_file = NULL;
1534             }
1535             else
1536             {
1537                 acc->tls_cert_file = expand_tilde(arg);
1538             }
1539         }
1540         else if (strcmp(cmd, "tls_trust_file") == 0)
1541         {
1542             acc->mask |= ACC_TLS_TRUST_FILE;
1543             free(acc->tls_trust_file);
1544             if (*arg == '\0')
1545             {
1546                 acc->tls_trust_file = NULL;
1547             }
1548             else
1549             {
1550                 acc->tls_trust_file = expand_tilde(arg);
1551             }
1552         }
1553         else if (strcmp(cmd, "tls_crl_file") == 0)
1554         {
1555             acc->mask |= ACC_TLS_CRL_FILE;
1556             free(acc->tls_crl_file);
1557             if (*arg == '\0')
1558             {
1559                 acc->tls_crl_file = NULL;
1560             }
1561             else
1562             {
1563                 acc->tls_crl_file = expand_tilde(arg);
1564             }
1565         }
1566         else if (strcmp(cmd, "tls_fingerprint") == 0)
1567         {
1568             acc->mask |= ACC_TLS_FINGERPRINT;
1569             free(acc->tls_sha256_fingerprint);
1570             acc->tls_sha256_fingerprint = NULL;
1571             free(acc->tls_sha1_fingerprint);
1572             acc->tls_sha1_fingerprint = NULL;
1573             free(acc->tls_md5_fingerprint);
1574             acc->tls_md5_fingerprint = NULL;
1575             if (*arg != '\0')
1576             {
1577                 if (strlen(arg) == 2 * 32 + 31)
1578                 {
1579                     acc->tls_sha256_fingerprint = get_fingerprint(arg, 32);
1580                 }
1581                 else if (strlen(arg) == 2 * 20 + 19)
1582                 {
1583                     acc->tls_sha1_fingerprint = get_fingerprint(arg, 20);
1584                 }
1585                 else if (strlen(arg) == 2 * 16 + 15)
1586                 {
1587                     acc->tls_md5_fingerprint = get_fingerprint(arg, 16);
1588                 }
1589                 if (!acc->tls_sha256_fingerprint && !acc->tls_sha1_fingerprint
1590                         && !acc->tls_md5_fingerprint)
1591                 {
1592                     *errstr = xasprintf(
1593                             _("line %d: invalid argument %s for command %s"),
1594                             line, arg, cmd);
1595                     e = CONF_ESYNTAX;
1596                     break;
1597                 }
1598             }
1599         }
1600         else if (strcmp(cmd, "tls_certcheck") == 0)
1601         {
1602             acc->mask |= ACC_TLS_NOCERTCHECK;
1603             if (*arg == '\0' || is_on(arg))
1604             {
1605                 acc->tls_nocertcheck = 0;
1606             }
1607             else if (is_off(arg))
1608             {
1609                 acc->tls_nocertcheck = 1;
1610             }
1611             else
1612             {
1613                 *errstr = xasprintf(
1614                         _("line %d: invalid argument %s for command %s"),
1615                         line, arg, cmd);
1616                 e = CONF_ESYNTAX;
1617                 break;
1618             }
1619         }
1620         else if (strcmp(cmd, "tls_min_dh_prime_bits") == 0)
1621         {
1622             acc->mask |= ACC_TLS_MIN_DH_PRIME_BITS;
1623             if (*arg == '\0')
1624             {
1625                 acc->tls_min_dh_prime_bits = -1;
1626             }
1627             else
1628             {
1629                 acc->tls_min_dh_prime_bits = get_pos_int(arg);
1630                 if (acc->tls_min_dh_prime_bits < 1)
1631                 {
1632                     *errstr = xasprintf(
1633                             _("line %d: invalid argument %s for command %s"),
1634                             line, arg, cmd);
1635                     e = CONF_ESYNTAX;
1636                     break;
1637                 }
1638             }
1639         }
1640         else if (strcmp(cmd, "tls_priorities") == 0)
1641         {
1642             acc->mask |= ACC_TLS_PRIORITIES;
1643             free(acc->tls_priorities);
1644             if (*arg == '\0')
1645             {
1646                 acc->tls_priorities = NULL;
1647             }
1648             else
1649             {
1650                 acc->tls_priorities = xstrdup(arg);
1651             }
1652         }
1653         else if (strcmp(cmd, "tls_host_override") == 0)
1654         {
1655             acc->mask |= ACC_TLS_HOST_OVERRIDE;
1656             free(acc->tls_host_override);
1657             if (*arg == '\0')
1658             {
1659                 acc->tls_host_override = NULL;
1660             }
1661             else
1662             {
1663                 acc->tls_host_override = xstrdup(arg);
1664             }
1665         }
1666         else if (strcmp(cmd, "dsn_return") == 0)
1667         {
1668             acc->mask |= ACC_DSN_RETURN;
1669             free(acc->dsn_return);
1670             if (*arg == '\0')
1671             {
1672                 *errstr = xasprintf(_("line %d: command %s needs an argument"),
1673                         line, cmd);
1674                 e = CONF_ESYNTAX;
1675                 break;
1676             }
1677             else
1678             {
1679                 if (is_off(arg))
1680                 {
1681                     acc->dsn_return = NULL;
1682                 }
1683                 else if (strcmp(arg, "headers") == 0)
1684                 {
1685                     acc->dsn_return = xstrdup("HDRS");
1686                 }
1687                 else if (strcmp(arg, "full") == 0)
1688                 {
1689                     acc->dsn_return = xstrdup("FULL");
1690                 }
1691                 else
1692                 {
1693                     *errstr = xasprintf(
1694                             _("line %d: invalid argument %s for command %s"),
1695                             line, arg, cmd);
1696                     e = CONF_ESYNTAX;
1697                     break;
1698                 }
1699             }
1700         }
1701         else if (strcmp(cmd, "dsn_notify") == 0)
1702         {
1703             acc->mask |= ACC_DSN_NOTIFY;
1704             free(acc->dsn_notify);
1705             if (*arg == '\0')
1706             {
1707                 *errstr = xasprintf(_("line %d: command %s needs an argument"),
1708                         line, cmd);
1709                 e = CONF_ESYNTAX;
1710                 break;
1711             }
1712             else
1713             {
1714                 if (is_off(arg))
1715                 {
1716                     acc->dsn_notify = NULL;
1717                 }
1718                 else if (check_dsn_notify_arg(arg) == 0)
1719                 {
1720                     acc->dsn_notify = xstrdup(arg);
1721                 }
1722                 else
1723                 {
1724                     *errstr = xasprintf(
1725                             _("line %d: invalid argument %s for command %s"),
1726                             line, arg, cmd);
1727                     e = CONF_ESYNTAX;
1728                     break;
1729                 }
1730             }
1731         }
1732         else if (strcmp(cmd, "logfile") == 0)
1733         {
1734             acc->mask |= ACC_LOGFILE;
1735             free(acc->logfile);
1736             if (*arg == '\0')
1737             {
1738                 acc->logfile = NULL;
1739             }
1740             else
1741             {
1742                 acc->logfile = expand_tilde(arg);
1743             }
1744         }
1745         else if (strcmp(cmd, "logfile_time_format") == 0)
1746         {
1747             acc->mask |= ACC_LOGFILE_TIME_FORMAT;
1748             free(acc->logfile_time_format);
1749             if (*arg == '\0')
1750             {
1751                 acc->logfile_time_format = NULL;
1752             }
1753             else
1754             {
1755                 acc->logfile_time_format = xstrdup(arg);
1756             }
1757         }
1758         else if (strcmp(cmd, "syslog") == 0)
1759         {
1760             acc->mask |= ACC_SYSLOG;
1761             free(acc->syslog);
1762             if (*arg == '\0' || is_on(arg))
1763             {
1764                 acc->syslog = get_default_syslog_facility();
1765             }
1766             else if (is_off(arg))
1767             {
1768                 acc->syslog = NULL;
1769             }
1770             else
1771             {
1772                 if (check_syslog_arg(arg) != 0)
1773                 {
1774                     *errstr = xasprintf(
1775                             _("line %d: invalid argument %s for command %s"),
1776                             line, arg, cmd);
1777                     e = CONF_ESYNTAX;
1778                     break;
1779                 }
1780                 acc->syslog = xstrdup(arg);
1781             }
1782         }
1783         else if (strcmp(cmd, "aliases") == 0)
1784         {
1785             acc->mask |= ACC_ALIASES;
1786             free(acc->aliases);
1787             if (*arg == '\0')
1788             {
1789                 acc->aliases = NULL;
1790             }
1791             else
1792             {
1793                 acc->aliases = expand_tilde(arg);
1794             }
1795         }
1796         else if (strcmp(cmd, "proxy_host") == 0)
1797         {
1798             acc->mask |= ACC_PROXY_HOST;
1799             free(acc->proxy_host);
1800             if (*arg == '\0')
1801             {
1802                 acc->proxy_host = NULL;
1803             }
1804             else
1805             {
1806                 acc->proxy_host = xstrdup(arg);
1807             }
1808         }
1809         else if (strcmp(cmd, "proxy_port") == 0)
1810         {
1811             acc->mask |= ACC_PROXY_PORT;
1812             if (*arg == '\0')
1813             {
1814                 acc->proxy_port = 0;
1815             }
1816             else
1817             {
1818                 acc->proxy_port = get_pos_int(arg);
1819                 if (acc->proxy_port < 1 || acc->proxy_port > 65535)
1820                 {
1821                     *errstr = xasprintf(
1822                             _("line %d: invalid argument %s for command %s"),
1823                             line, arg, cmd);
1824                     e = CONF_ESYNTAX;
1825                     break;
1826                 }
1827             }
1828         }
1829         else if (strcmp(cmd, "set_from_header") == 0)
1830         {
1831             acc->mask |= ACC_SET_FROM_HEADER;
1832             if (*arg == '\0' || is_auto(arg))
1833             {
1834                 acc->set_from_header = 2;
1835             }
1836             else if (is_on(arg))
1837             {
1838                 acc->set_from_header = 1;
1839             }
1840             else if (is_off(arg))
1841             {
1842                 acc->set_from_header = 0;
1843             }
1844             else
1845             {
1846                 *errstr = xasprintf(
1847                         _("line %d: invalid argument %s for command %s"),
1848                         line, arg, cmd);
1849                 e = CONF_ESYNTAX;
1850                 break;
1851             }
1852         }
1853         else if (strcmp(cmd, "set_date_header") == 0)
1854         {
1855             acc->mask |= ACC_SET_DATE_HEADER;
1856             if (*arg == '\0' || is_auto(arg))
1857             {
1858                 acc->set_date_header = 2;
1859             }
1860             else if (is_off(arg))
1861             {
1862                 acc->set_date_header = 0;
1863             }
1864             else
1865             {
1866                 *errstr = xasprintf(
1867                         _("line %d: invalid argument %s for command %s"),
1868                         line, arg, cmd);
1869                 e = CONF_ESYNTAX;
1870                 break;
1871             }
1872         }
1873         else if (strcmp(cmd, "remove_bcc_headers") == 0)
1874         {
1875             acc->mask |= ACC_REMOVE_BCC_HEADERS;
1876             if (*arg == '\0' || is_on(arg))
1877             {
1878                 acc->remove_bcc_headers = 1;
1879             }
1880             else if (is_off(arg))
1881             {
1882                 acc->remove_bcc_headers = 0;
1883             }
1884             else
1885             {
1886                 *errstr = xasprintf(
1887                         _("line %d: invalid argument %s for command %s"),
1888                         line, arg, cmd);
1889                 e = CONF_ESYNTAX;
1890                 break;
1891             }
1892         }
1893         else if (strcmp(cmd, "undisclosed_recipients") == 0)
1894         {
1895             acc->mask |= ACC_UNDISCLOSED_RECIPIENTS;
1896             if (*arg == '\0' || is_on(arg))
1897             {
1898                 acc->undisclosed_recipients = 1;
1899             }
1900             else if (is_off(arg))
1901             {
1902                 acc->undisclosed_recipients = 0;
1903             }
1904             else
1905             {
1906                 *errstr = xasprintf(
1907                         _("line %d: invalid argument %s for command %s"),
1908                         line, arg, cmd);
1909                 e = CONF_ESYNTAX;
1910                 break;
1911             }
1912         }
1913         else if (strcmp(cmd, "source_ip") == 0)
1914         {
1915             acc->mask |= ACC_SOURCE_IP;
1916             free(acc->source_ip);
1917             if (*arg == '\0')
1918             {
1919                 acc->source_ip = NULL;
1920             }
1921             else
1922             {
1923                 acc->source_ip = xstrdup(arg);
1924             }
1925         }
1926         else if (strcmp(cmd, "socket") == 0)
1927         {
1928             acc->mask |= ACC_SOCKET;
1929             free(acc->socketname);
1930             if (*arg == '\0')
1931             {
1932                 acc->socketname = NULL;
1933             }
1934             else
1935             {
1936                 acc->socketname = xstrdup(arg);
1937             }
1938         }
1939         else if (strcmp(cmd, "add_missing_from_header") == 0)
1940         {
1941             /* compatibility with < 1.8.8 */
1942             acc->mask |= ACC_SET_FROM_HEADER;
1943             if (*arg == '\0' || is_on(arg))
1944             {
1945                 acc->set_from_header = 2;
1946             }
1947             else if (is_off(arg))
1948             {
1949                 acc->set_from_header = 0;
1950             }
1951             else
1952             {
1953                 *errstr = xasprintf(
1954                         _("line %d: invalid argument %s for command %s"),
1955                         line, arg, cmd);
1956                 e = CONF_ESYNTAX;
1957                 break;
1958             }
1959         }
1960         else if (strcmp(cmd, "add_missing_date_header") == 0)
1961         {
1962             /* compatibility with < 1.8.8 */
1963             acc->mask |= ACC_SET_DATE_HEADER;
1964             if (*arg == '\0' || is_on(arg))
1965             {
1966                 acc->set_date_header = 2;
1967             }
1968             else if (is_off(arg))
1969             {
1970                 acc->set_date_header = 0;
1971             }
1972             else
1973             {
1974                 *errstr = xasprintf(
1975                         _("line %d: invalid argument %s for command %s"),
1976                         line, arg, cmd);
1977                 e = CONF_ESYNTAX;
1978                 break;
1979             }
1980         }
1981         else if (strcmp(cmd, "auto_from") == 0)
1982         {
1983             /* compatibility with <= 1.8.7 */
1984             acc->mask |= ACC_AUTO_FROM;
1985             if (*arg == '\0' || is_on(arg))
1986             {
1987                 acc->auto_from = 1;
1988             }
1989             else if (is_off(arg))
1990             {
1991                 acc->auto_from = 0;
1992             }
1993             else
1994             {
1995                 *errstr = xasprintf(
1996                         _("line %d: invalid argument %s for command %s"),
1997                         line, arg, cmd);
1998                 e = CONF_ESYNTAX;
1999                 break;
2000             }
2001         }
2002         else if (strcmp(cmd, "maildomain") == 0)
2003         {
2004             /* compatibility with <= 1.8.7 */
2005             acc->mask |= ACC_MAILDOMAIN;
2006             free(acc->maildomain);
2007             acc->maildomain = xstrdup(arg);
2008         }
2009         else if (strcmp(cmd, "keepbcc") == 0)
2010         {
2011             /* compatibility with 1.4.x */
2012             acc->mask |= ACC_REMOVE_BCC_HEADERS;
2013             if (*arg == '\0' || is_on(arg))
2014             {
2015                 acc->remove_bcc_headers = 0;
2016             }
2017             else if (is_off(arg))
2018             {
2019                 acc->remove_bcc_headers = 1;
2020             }
2021             else
2022             {
2023                 *errstr = xasprintf(
2024                         _("line %d: invalid argument %s for command %s"),
2025                         line, arg, cmd);
2026                 e = CONF_ESYNTAX;
2027                 break;
2028             }
2029         }
2030         else if (strcmp(cmd, "tls_nocertcheck") == 0)
2031         {
2032             /* compatibility with 1.2.x */
2033             acc->mask |= ACC_TLS_NOCERTCHECK;
2034             if (*arg != '\0')
2035             {
2036                 *errstr = xasprintf(
2037                         _("line %d: command %s does not take an argument"),
2038                         line, cmd);
2039                 e = CONF_ESYNTAX;
2040                 break;
2041             }
2042             else
2043             {
2044                 acc->tls_nocertcheck = 1;
2045             }
2046         }
2047         else if (strcmp(cmd, "tls_nostarttls") == 0)
2048         {
2049             /* compatibility with 1.2.x */
2050             acc->mask |= ACC_TLS_NOSTARTTLS;
2051             if (*arg != '\0')
2052             {
2053                 *errstr = xasprintf(
2054                         _("line %d: command %s does not take an argument"),
2055                         line, cmd);
2056                 e = CONF_ESYNTAX;
2057                 break;
2058             }
2059             else
2060             {
2061                 acc->tls_nostarttls = 1;
2062             }
2063         }
2064         else if (strcmp(cmd, "tls_force_sslv3") == 0)
2065         {
2066             /* compatibility with versions <= 1.4.32: silently ignore */
2067         }
2068         else
2069         {
2070             *errstr = xasprintf(_("line %d: unknown command %s"), line, cmd);
2071             e = CONF_ESYNTAX;
2072             break;
2073         }
2074         free(cmd);
2075         free(arg);
2076     }
2077     free(cmd);
2078     free(arg);
2079 
2080     if (e != CONF_EOK)
2081     {
2082         list_xfree(*acc_list, account_free);
2083         *acc_list = NULL;
2084     }
2085     account_free(defaults);
2086 
2087     return e;
2088 }
2089 
2090 
2091 /*
2092  * get_conf()
2093  *
2094  * see conf.h
2095  */
2096 
get_conf(const char * conffile,int securitycheck,list_t ** acc_list,char ** errstr)2097 int get_conf(const char *conffile, int securitycheck, list_t **acc_list,
2098         char **errstr)
2099 {
2100     FILE *f;
2101     int conffile_contains_secrets;
2102     int e;
2103 
2104     if (!(f = fopen(conffile, "r")))
2105     {
2106         *errstr = xasprintf("%s", strerror(errno));
2107         return CONF_ECANTOPEN;
2108     }
2109     if ((e = read_conffile(conffile, f, acc_list, &conffile_contains_secrets,
2110                     errstr)) != CONF_EOK)
2111     {
2112         fclose(f);
2113         return e;
2114     }
2115     fclose(f);
2116     e = CONF_EOK;
2117     if (securitycheck && conffile_contains_secrets)
2118     {
2119         switch (check_secure(conffile))
2120         {
2121             case 1:
2122                 *errstr = xasprintf(_("contains secrets and therefore "
2123                             "must be owned by you"));
2124                 e = CONF_EINSECURE;
2125                 break;
2126 
2127             case 2:
2128                 *errstr = xasprintf(_("contains secrets and therefore "
2129                             "must have no more than user "
2130                             "read/write permissions"));
2131                 e = CONF_EINSECURE;
2132                 break;
2133 
2134             case 3:
2135                 *errstr = xasprintf("%s", strerror(errno));
2136                 e = CONF_EIO;
2137                 break;
2138         }
2139     }
2140 
2141     return e;
2142 }
2143