Commit | Line | Data |
---|---|---|
8523533c TK |
1 | /************************************************* |
2 | * Exim - an Internet mail transport agent * | |
3 | *************************************************/ | |
4 | ||
80fea873 JH |
5 | /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-2015 |
6 | * License: GPL | |
f9ba5e22 | 7 | * Copyright (c) The Exim Maintainers 2016 - 2018 |
80fea873 | 8 | */ |
8523533c TK |
9 | |
10 | /* Code for matching regular expressions against headers and body. | |
11 | Called from acl.c. */ | |
12 | ||
13 | #include "exim.h" | |
14 | #ifdef WITH_CONTENT_SCAN | |
15 | #include <unistd.h> | |
16 | #include <sys/mman.h> | |
17 | ||
18 | /* Structure to hold a list of Regular expressions */ | |
19 | typedef struct pcre_list { | |
20 | pcre *re; | |
21 | uschar *pcre_text; | |
22 | struct pcre_list *next; | |
23 | } pcre_list; | |
24 | ||
25 | uschar regex_match_string_buffer[1024]; | |
26 | ||
27 | extern FILE *mime_stream; | |
28 | extern uschar *mime_current_boundary; | |
29 | ||
f38917cc JH |
30 | static pcre_list * |
31 | compile(const uschar * list) | |
55414b25 | 32 | { |
10a831a3 JH |
33 | int sep = 0; |
34 | uschar *regex_string; | |
35 | const char *pcre_error; | |
36 | int pcre_erroffset; | |
37 | pcre_list *re_list_head = NULL; | |
38 | pcre_list *ri; | |
39 | ||
40 | /* precompile our regexes */ | |
41 | while ((regex_string = string_nextinlist(&list, &sep, NULL, 0))) | |
42 | if (strcmpic(regex_string, US"false") != 0 && Ustrcmp(regex_string, "0") != 0) | |
43 | { | |
f38917cc JH |
44 | pcre *re; |
45 | ||
f38917cc JH |
46 | /* compile our regular expression */ |
47 | if (!(re = pcre_compile( CS regex_string, | |
10a831a3 JH |
48 | 0, &pcre_error, &pcre_erroffset, NULL ))) |
49 | { | |
f38917cc | 50 | log_write(0, LOG_MAIN, |
10a831a3 | 51 | "regex acl condition warning - error in regex '%s': %s at offset %d, skipped.", |
f38917cc JH |
52 | regex_string, pcre_error, pcre_erroffset); |
53 | continue; | |
10a831a3 | 54 | } |
f38917cc | 55 | |
f3ebb786 | 56 | ri = store_get(sizeof(pcre_list), FALSE); |
f38917cc | 57 | ri->re = re; |
10a831a3 | 58 | ri->pcre_text = regex_string; |
f38917cc JH |
59 | ri->next = re_list_head; |
60 | re_list_head = ri; | |
10a831a3 JH |
61 | } |
62 | return re_list_head; | |
f38917cc JH |
63 | } |
64 | ||
65 | static int | |
66 | matcher(pcre_list * re_list_head, uschar * linebuffer, int len) | |
67 | { | |
d7978c0f | 68 | for(pcre_list * ri = re_list_head; ri; ri = ri->next) |
10a831a3 JH |
69 | { |
70 | int ovec[3*(REGEX_VARS+1)]; | |
d7978c0f | 71 | int n; |
f38917cc | 72 | |
10a831a3 | 73 | /* try matcher on the line */ |
d7978c0f | 74 | if ((n = pcre_exec(ri->re, NULL, CS linebuffer, len, 0, 0, ovec, nelem(ovec))) > 0) |
f38917cc | 75 | { |
10a831a3 JH |
76 | Ustrncpy(regex_match_string_buffer, ri->pcre_text, |
77 | sizeof(regex_match_string_buffer)-1); | |
78 | regex_match_string = regex_match_string_buffer; | |
f38917cc | 79 | |
d7978c0f | 80 | for (int nn = 1; nn < n; nn++) |
10a831a3 JH |
81 | regex_vars[nn-1] = |
82 | string_copyn(linebuffer + ovec[nn*2], ovec[nn*2+1] - ovec[nn*2]); | |
f38917cc | 83 | |
10a831a3 | 84 | return OK; |
f38917cc | 85 | } |
10a831a3 JH |
86 | } |
87 | return FAIL; | |
f38917cc JH |
88 | } |
89 | ||
90 | int | |
91 | regex(const uschar **listptr) | |
92 | { | |
10a831a3 JH |
93 | unsigned long mbox_size; |
94 | FILE *mbox_file; | |
95 | pcre_list *re_list_head; | |
96 | uschar *linebuffer; | |
97 | long f_pos = 0; | |
98 | int ret = FAIL; | |
99 | ||
100 | /* reset expansion variable */ | |
101 | regex_match_string = NULL; | |
102 | ||
103 | if (!mime_stream) /* We are in the DATA ACL */ | |
104 | { | |
040721f2 | 105 | if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL))) |
10a831a3 JH |
106 | { /* error while spooling */ |
107 | log_write(0, LOG_MAIN|LOG_PANIC, | |
108 | "regex acl condition: error while creating mbox spool file"); | |
109 | return DEFER; | |
f38917cc | 110 | } |
8523533c | 111 | } |
10a831a3 JH |
112 | else |
113 | { | |
cb570b5e JH |
114 | if ((f_pos = ftell(mime_stream)) < 0) |
115 | { | |
116 | log_write(0, LOG_MAIN|LOG_PANIC, | |
117 | "regex acl condition: mime_stream: %s", strerror(errno)); | |
118 | return DEFER; | |
119 | } | |
10a831a3 | 120 | mbox_file = mime_stream; |
f38917cc | 121 | } |
8e669ac1 | 122 | |
10a831a3 JH |
123 | /* precompile our regexes */ |
124 | if (!(re_list_head = compile(*listptr))) | |
125 | return FAIL; /* no regexes -> nothing to do */ | |
126 | ||
127 | /* match each line against all regexes */ | |
f3ebb786 | 128 | linebuffer = store_get(32767, TRUE); /* tainted */ |
10a831a3 JH |
129 | while (fgets(CS linebuffer, 32767, mbox_file)) |
130 | { | |
131 | if ( mime_stream && mime_current_boundary /* check boundary */ | |
132 | && Ustrncmp(linebuffer, "--", 2) == 0 | |
133 | && Ustrncmp((linebuffer+2), mime_current_boundary, | |
134 | Ustrlen(mime_current_boundary)) == 0) | |
135 | break; /* found boundary */ | |
136 | ||
137 | if ((ret = matcher(re_list_head, linebuffer, (int)Ustrlen(linebuffer))) == OK) | |
138 | goto done; | |
f38917cc | 139 | } |
10a831a3 | 140 | /* no matches ... */ |
f38917cc JH |
141 | |
142 | done: | |
10a831a3 JH |
143 | if (!mime_stream) |
144 | (void)fclose(mbox_file); | |
145 | else | |
146 | { | |
147 | clearerr(mime_stream); | |
4dc2379a JH |
148 | if (fseek(mime_stream, f_pos, SEEK_SET) == -1) |
149 | { | |
150 | log_write(0, LOG_MAIN|LOG_PANIC, | |
151 | "regex acl condition: mime_stream: %s", strerror(errno)); | |
152 | clearerr(mime_stream); | |
153 | } | |
10a831a3 JH |
154 | } |
155 | ||
156 | return ret; | |
8523533c TK |
157 | } |
158 | ||
159 | ||
55414b25 JH |
160 | int |
161 | mime_regex(const uschar **listptr) | |
162 | { | |
10a831a3 JH |
163 | pcre_list *re_list_head = NULL; |
164 | FILE *f; | |
165 | uschar *mime_subject = NULL; | |
166 | int mime_subject_len = 0; | |
167 | int ret; | |
168 | ||
169 | /* reset expansion variable */ | |
170 | regex_match_string = NULL; | |
171 | ||
172 | /* precompile our regexes */ | |
173 | if (!(re_list_head = compile(*listptr))) | |
174 | return FAIL; /* no regexes -> nothing to do */ | |
175 | ||
176 | /* check if the file is already decoded */ | |
177 | if (!mime_decoded_filename) | |
178 | { /* no, decode it first */ | |
179 | const uschar *empty = US""; | |
180 | mime_decode(&empty); | |
181 | if (!mime_decoded_filename) | |
182 | { /* decoding failed */ | |
183 | log_write(0, LOG_MAIN, | |
184 | "mime_regex acl condition warning - could not decode MIME part to file"); | |
185 | return DEFER; | |
f38917cc JH |
186 | } |
187 | } | |
8523533c | 188 | |
10a831a3 JH |
189 | /* open file */ |
190 | if (!(f = fopen(CS mime_decoded_filename, "rb"))) | |
191 | { | |
192 | log_write(0, LOG_MAIN, | |
193 | "mime_regex acl condition warning - can't open '%s' for reading", | |
194 | mime_decoded_filename); | |
195 | return DEFER; | |
f38917cc | 196 | } |
8e669ac1 | 197 | |
f3ebb786 JH |
198 | /* get 32k memory, tainted */ |
199 | mime_subject = store_get(32767, TRUE); | |
8e669ac1 | 200 | |
10a831a3 | 201 | mime_subject_len = fread(mime_subject, 1, 32766, f); |
8e669ac1 | 202 | |
10a831a3 JH |
203 | ret = matcher(re_list_head, mime_subject, mime_subject_len); |
204 | (void)fclose(f); | |
205 | return ret; | |
8523533c TK |
206 | } |
207 | ||
476be7e2 | 208 | #endif /* WITH_CONTENT_SCAN */ |