1 /*
2  *  Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3  *  Copyright (C) 2008-2013 Sourcefire, Inc.
4  *
5  *  Author: aCaB <acab@clamav.net>
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA 02110-1301, USA.
20  */
21 
22 #if HAVE_CONFIG_H
23 #include "clamav-config.h"
24 #endif
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/types.h>
29 
30 // libclamav
31 #include "regex/regex.h"
32 
33 // shared
34 #include "output.h"
35 
36 #include "whitelist.h"
37 
38 struct WHLST {
39     regex_t preg;
40     struct WHLST *next;
41 };
42 
43 struct WHLST *wfrom = NULL;
44 struct WHLST *wto   = NULL;
45 
46 int skipauth = 0;
47 regex_t authreg;
48 
whitelist_free(void)49 void whitelist_free(void)
50 {
51     struct WHLST *w;
52     while (wfrom) {
53         w = wfrom->next;
54         cli_regfree(&wfrom->preg);
55         free(wfrom);
56         wfrom = w;
57     }
58     while (wto) {
59         w = wto->next;
60         cli_regfree(&wto->preg);
61         free(wto);
62         wto = w;
63     }
64 }
65 
whitelist_init(const char * fname)66 int whitelist_init(const char *fname)
67 {
68     char buf[2048];
69     FILE *f;
70     struct WHLST *w;
71 
72     if (!(f = fopen(fname, "r"))) {
73         logg("!Cannot open whitelist file '%s'\n", fname);
74         return 1;
75     }
76 
77     while (fgets(buf, sizeof(buf), f) != NULL) {
78         struct WHLST **addto = &wto;
79         char *ptr            = buf;
80         int len;
81 
82         if (*buf == '#' || *buf == ':' || *buf == '!')
83             continue;
84 
85         if (!strncasecmp("From:", buf, 5)) {
86             ptr += 5;
87             addto = &wfrom;
88         } else if (!strncasecmp("To:", buf, 3))
89             ptr += 3;
90 
91         len = strlen(ptr) - 1;
92         for (; len >= 0; len--) {
93             if (ptr[len] != '\n' && ptr[len] != '\r') break;
94             ptr[len] = '\0';
95         }
96         if (!len) continue;
97         if (!(w = (struct WHLST *)malloc(sizeof(*w)))) {
98             logg("!Out of memory loading whitelist file\n");
99             whitelist_free();
100             fclose(f);
101             return 1;
102         }
103         w->next  = (*addto);
104         (*addto) = w;
105         if (cli_regcomp(&w->preg, ptr, REG_ICASE | REG_NOSUB)) {
106             logg("!Failed to compile regex '%s' in whitelist file\n", ptr);
107             whitelist_free();
108             fclose(f);
109             return 1;
110         }
111     }
112     fclose(f);
113     return 0;
114 }
115 
whitelisted(const char * addr,int from)116 int whitelisted(const char *addr, int from)
117 {
118     struct WHLST *w;
119 
120     if (from)
121         w = wfrom;
122     else
123         w = wto;
124 
125     while (w) {
126         if (!cli_regexec(&w->preg, addr, 0, NULL, 0))
127             return 1;
128         w = w->next;
129     }
130     return 0;
131 }
132 
smtpauth_init(const char * r)133 int smtpauth_init(const char *r)
134 {
135     char *regex = NULL;
136 
137     if (!strncmp(r, "file:", 5)) {
138         char buf[2048];
139         FILE *f    = fopen(r + 5, "r");
140         int rxsize = 0, rxavail = 0, rxused = 0;
141 
142         if (!f) {
143             logg("!Cannot open whitelist file '%s'\n", r + 5);
144             return 1;
145         }
146         while (fgets(buf, sizeof(buf), f) != NULL) {
147             int len;
148             char *ptr;
149 
150             if (*buf == '#' || *buf == ':' || *buf == '!')
151                 continue;
152             len = strlen(buf) - 1;
153             for (; len >= 0; len--) {
154                 if (buf[len] != '\n' && buf[len] != '\r') break;
155                 buf[len] = '\0';
156             }
157             if (len <= 0) continue;
158             if (len * 3 + 1 > rxavail) {
159                 ptr   = regex;
160                 regex = realloc(regex, rxsize + 2048);
161                 if (!regex) {
162                     logg("!Cannot allocate memory for SkipAuthenticated file\n");
163                     fclose(f);
164                     return 1;
165                 }
166                 rxavail = 2048;
167                 rxsize += 2048;
168                 if (!ptr) {
169                     regex[0] = '^';
170                     regex[1] = '(';
171                     rxavail -= 2;
172                     rxused = 2;
173                 }
174             }
175             ptr = buf;
176             while (*ptr) {
177                 if ((*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= 'a' && *ptr <= 'z') || (*ptr >= '0' && *ptr <= '9') || *ptr == '@') {
178                     regex[rxused] = *ptr;
179                     rxused++;
180                     rxavail--;
181                 } else {
182                     regex[rxused]     = '[';
183                     regex[rxused + 1] = *ptr;
184                     regex[rxused + 2] = ']';
185                     rxused += 3;
186                     rxavail -= 3;
187                 }
188                 ptr++;
189             }
190             regex[rxused++] = '|';
191             rxavail--;
192         }
193         if (rxavail < 4 && !(regex = realloc(regex, rxsize + 4))) {
194             logg("!Cannot allocate memory for SkipAuthenticated file\n");
195             fclose(f);
196             return 1;
197         }
198         regex[rxused - 1] = ')';
199         regex[rxused]     = '$';
200         regex[rxused + 1] = '\0';
201         r                 = regex;
202         fclose(f);
203     }
204 
205     if (cli_regcomp(&authreg, r, REG_ICASE | REG_NOSUB | REG_EXTENDED)) {
206         logg("!Failed to compile regex '%s' for SkipAuthenticated\n", r);
207         if (regex) free(regex);
208         return 1;
209     }
210     if (regex) free(regex);
211     skipauth = 1;
212     return 0;
213 }
214 
smtpauthed(const char * login)215 int smtpauthed(const char *login)
216 {
217     if (skipauth && !cli_regexec(&authreg, login, 0, NULL, 0))
218         return 1;
219     return 0;
220 }
221 
222 /*
223  * Local Variables:
224  * mode: c
225  * c-basic-offset: 4
226  * tab-width: 8
227  * End:
228  * vim: set cindent smartindent autoindent softtabstop=4 shiftwidth=4 tabstop=8:
229  */
230