... | ... |
@@ -29,8 +29,8 @@ |
29 | 29 |
#endif |
30 | 30 |
|
31 | 31 |
#ifdef CL_THREAD_SAFE |
32 |
-#ifndef _REENTRANT |
|
33 |
-#define _REENTRANT /* for Solaris 2.8 */ |
|
32 |
+#ifndef _REENTRANT |
|
33 |
+#define _REENTRANT /* for Solaris 2.8 */ |
|
34 | 34 |
#endif |
35 | 35 |
#endif |
36 | 36 |
|
... | ... |
@@ -39,23 +39,23 @@ |
39 | 39 |
#include <errno.h> |
40 | 40 |
#include <assert.h> |
41 | 41 |
#include <string.h> |
42 |
-#ifdef HAVE_STRINGS_H |
|
42 |
+#ifdef HAVE_STRINGS_H |
|
43 | 43 |
#include <strings.h> |
44 | 44 |
#endif |
45 |
-#ifdef HAVE_STRING_H |
|
45 |
+#ifdef HAVE_STRING_H |
|
46 | 46 |
#include <string.h> |
47 | 47 |
#endif |
48 | 48 |
#include <ctype.h> |
49 | 49 |
#include <time.h> |
50 | 50 |
#include <fcntl.h> |
51 |
-#ifdef HAVE_SYS_PARAM_H |
|
51 |
+#ifdef HAVE_SYS_PARAM_H |
|
52 | 52 |
#include <sys/param.h> |
53 | 53 |
#endif |
54 | 54 |
#include <dirent.h> |
55 | 55 |
#include <limits.h> |
56 | 56 |
#include <signal.h> |
57 | 57 |
|
58 |
-#ifdef HAVE_UNISTD_H |
|
58 |
+#ifdef HAVE_UNISTD_H |
|
59 | 59 |
#include <unistd.h> |
60 | 60 |
#endif |
61 | 61 |
|
... | ... |
@@ -63,7 +63,7 @@ |
63 | 63 |
#include <stddef.h> |
64 | 64 |
#endif |
65 | 65 |
|
66 |
-#ifdef CL_THREAD_SAFE |
|
66 |
+#ifdef CL_THREAD_SAFE |
|
67 | 67 |
#include <pthread.h> |
68 | 68 |
#endif |
69 | 69 |
|
... | ... |
@@ -86,9 +86,9 @@ |
86 | 86 |
|
87 | 87 |
#define DCONF_PHISHING mctx->ctx->dconf->phishing |
88 | 88 |
|
89 |
-#ifdef CL_DEBUG |
|
89 |
+#ifdef CL_DEBUG |
|
90 | 90 |
|
91 |
-#if defined(C_LINUX) |
|
91 |
+#if defined(C_LINUX) |
|
92 | 92 |
#include <features.h> |
93 | 93 |
#endif |
94 | 94 |
|
... | ... |
@@ -101,52 +101,53 @@ |
101 | 101 |
#include <execinfo.h> |
102 | 102 |
#include <syslog.h> |
103 | 103 |
|
104 |
-static void sigsegv(int sig); |
|
105 |
-static void print_trace(int use_syslog); |
|
104 |
+static void sigsegv(int sig); |
|
105 |
+static void print_trace(int use_syslog); |
|
106 | 106 |
|
107 |
-/*#define SAVE_TMP */ /* Save the file being worked on in tmp */ |
|
107 |
+/*#define SAVE_TMP */ /* Save the file being worked on in tmp */ |
|
108 | 108 |
#endif |
109 | 109 |
|
110 |
-#if defined(NO_STRTOK_R) || !defined(CL_THREAD_SAFE) |
|
110 |
+#if defined(NO_STRTOK_R) || !defined(CL_THREAD_SAFE) |
|
111 | 111 |
#undef strtok_r |
112 | 112 |
#undef __strtok_r |
113 |
-#define strtok_r(a,b,c) strtok(a,b) |
|
113 |
+#define strtok_r(a, b, c) strtok(a, b) |
|
114 | 114 |
#endif |
115 | 115 |
|
116 |
-#ifdef HAVE_STDBOOL_H |
|
117 |
-#ifdef C_BEOS |
|
116 |
+#ifdef HAVE_STDBOOL_H |
|
117 |
+#ifdef C_BEOS |
|
118 | 118 |
#include "SupportDefs.h" |
119 | 119 |
#else |
120 | 120 |
#include <stdbool.h> |
121 | 121 |
#endif |
122 | 122 |
#else |
123 |
-#ifdef FALSE |
|
124 |
-typedef unsigned char bool; |
|
123 |
+#ifdef FALSE |
|
124 |
+typedef unsigned char bool; |
|
125 | 125 |
#else |
126 |
-typedef enum { FALSE = 0, TRUE = 1 } bool; |
|
126 |
+typedef enum { FALSE = 0, |
|
127 |
+ TRUE = 1 } bool; |
|
127 | 128 |
#endif |
128 | 129 |
#endif |
129 | 130 |
|
130 |
-typedef enum { |
|
131 |
- FAIL, |
|
132 |
- OK, |
|
133 |
- OK_ATTACHMENTS_NOT_SAVED, |
|
134 |
- VIRUS, |
|
135 |
- MAXREC, |
|
136 |
- MAXFILES |
|
131 |
+typedef enum { |
|
132 |
+ FAIL, |
|
133 |
+ OK, |
|
134 |
+ OK_ATTACHMENTS_NOT_SAVED, |
|
135 |
+ VIRUS, |
|
136 |
+ MAXREC, |
|
137 |
+ MAXFILES |
|
137 | 138 |
} mbox_status; |
138 | 139 |
|
139 | 140 |
#ifndef isblank |
140 |
-#define isblank(c) (((c) == ' ') || ((c) == '\t')) |
|
141 |
+#define isblank(c) (((c) == ' ') || ((c) == '\t')) |
|
141 | 142 |
#endif |
142 | 143 |
|
143 |
-#define SAVE_TO_DISC /* multipart/message are saved in a temporary file */ |
|
144 |
+#define SAVE_TO_DISC /* multipart/message are saved in a temporary file */ |
|
144 | 145 |
|
145 | 146 |
#include "htmlnorm.h" |
146 | 147 |
|
147 | 148 |
#include "phishcheck.h" |
148 | 149 |
|
149 |
-#ifndef _WIN32 |
|
150 |
+#ifndef _WIN32 |
|
150 | 151 |
#include <sys/time.h> |
151 | 152 |
#include <netdb.h> |
152 | 153 |
#include <sys/socket.h> |
... | ... |
@@ -170,19 +171,19 @@ typedef enum { |
170 | 170 |
*/ |
171 | 171 |
/*#define NEW_WORLD*/ |
172 | 172 |
|
173 |
-/*#define SCAN_UNENCODED_BOUNCES *//* |
|
173 |
+/*#define SCAN_UNENCODED_BOUNCES */ /* |
|
174 | 174 |
* Slows things down a lot and only catches unencoded copies |
175 | 175 |
* of EICAR within bounces, which don't matter |
176 | 176 |
*/ |
177 | 177 |
|
178 |
-typedef struct mbox_ctx { |
|
179 |
- const char *dir; |
|
180 |
- const table_t *rfc821Table; |
|
181 |
- const table_t *subtypeTable; |
|
182 |
- cli_ctx *ctx; |
|
183 |
- unsigned int files; /* number of files extracted */ |
|
178 |
+typedef struct mbox_ctx { |
|
179 |
+ const char *dir; |
|
180 |
+ const table_t *rfc821Table; |
|
181 |
+ const table_t *subtypeTable; |
|
182 |
+ cli_ctx *ctx; |
|
183 |
+ unsigned int files; /* number of files extracted */ |
|
184 | 184 |
#if HAVE_JSON |
185 |
- json_object *wrkobj; |
|
185 |
+ json_object *wrkobj; |
|
186 | 186 |
#endif |
187 | 187 |
} mbox_ctx; |
188 | 188 |
|
... | ... |
@@ -199,157 +200,134 @@ typedef struct mbox_ctx { |
199 | 199 |
#define UNLOCKFILE(fp) |
200 | 200 |
#endif |
201 | 201 |
|
202 |
-static int cli_parse_mbox(const char *dir, cli_ctx *ctx); |
|
203 |
-static message *parseEmailFile(fmap_t *map, size_t *at, const table_t *rfc821Table, const char *firstLine, const char *dir); |
|
204 |
-static message *parseEmailHeaders(message *m, const table_t *rfc821Table); |
|
205 |
-static int parseEmailHeader(message *m, const char *line, const table_t *rfc821Table); |
|
206 |
-static int parseMHTMLComment(const char *comment, cli_ctx *ctx, void *wrkjobj, void *cbdata); |
|
207 |
-static mbox_status parseRootMHTML(mbox_ctx *mctx, message *m, text *t); |
|
208 |
-static mbox_status parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int recursion_level); |
|
209 |
-static int boundaryStart(const char *line, const char *boundary); |
|
210 |
-static int boundaryEnd(const char *line, const char *boundary); |
|
211 |
-static int initialiseTables(table_t **rfc821Table, table_t **subtypeTable); |
|
212 |
-static int getTextPart(message *const messages[], size_t size); |
|
213 |
-static size_t strip(char *buf, int len); |
|
214 |
-static int parseMimeHeader(message *m, const char *cmd, const table_t *rfc821Table, const char *arg); |
|
215 |
-static int saveTextPart(mbox_ctx *mctx, message *m, int destroy_text); |
|
216 |
-static char *rfc2047(const char *in); |
|
217 |
-static char *rfc822comments(const char *in, char *out); |
|
218 |
-static int rfc1341(message *m, const char *dir); |
|
219 |
-static bool usefulHeader(int commandNumber, const char *cmd); |
|
220 |
-static char *getline_from_mbox(char *buffer, size_t len, fmap_t *map, size_t *at); |
|
221 |
-static bool isBounceStart(mbox_ctx *mctx, const char *line); |
|
222 |
-static bool exportBinhexMessage(mbox_ctx *mctx, message *m); |
|
223 |
-static int exportBounceMessage(mbox_ctx *ctx, text *start); |
|
224 |
-static const char *getMimeTypeStr(mime_type mimetype); |
|
225 |
-static const char *getEncTypeStr(encoding_type enctype); |
|
226 |
-static message *do_multipart(message *mainMessage, message **messages, int i, mbox_status *rc, mbox_ctx *mctx, message *messageIn, text **tptr, unsigned int recursion_level); |
|
227 |
-static int count_quotes(const char *buf); |
|
228 |
-static bool next_is_folded_header(const text *t); |
|
229 |
-static bool newline_in_header(const char *line); |
|
230 |
- |
|
231 |
-static blob *getHrefs(message *m, tag_arguments_t *hrefs); |
|
232 |
-static void hrefs_done(blob *b, tag_arguments_t *hrefs); |
|
233 |
-static void checkURLs(message *m, mbox_ctx *mctx, mbox_status *rc, int is_html); |
|
202 |
+static int cli_parse_mbox(const char *dir, cli_ctx *ctx); |
|
203 |
+static message *parseEmailFile(fmap_t *map, size_t *at, const table_t *rfc821Table, const char *firstLine, const char *dir); |
|
204 |
+static message *parseEmailHeaders(message *m, const table_t *rfc821Table); |
|
205 |
+static int parseEmailHeader(message *m, const char *line, const table_t *rfc821Table); |
|
206 |
+static int parseMHTMLComment(const char *comment, cli_ctx *ctx, void *wrkjobj, void *cbdata); |
|
207 |
+static mbox_status parseRootMHTML(mbox_ctx *mctx, message *m, text *t); |
|
208 |
+static mbox_status parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int recursion_level); |
|
209 |
+static int boundaryStart(const char *line, const char *boundary); |
|
210 |
+static int boundaryEnd(const char *line, const char *boundary); |
|
211 |
+static int initialiseTables(table_t **rfc821Table, table_t **subtypeTable); |
|
212 |
+static int getTextPart(message *const messages[], size_t size); |
|
213 |
+static size_t strip(char *buf, int len); |
|
214 |
+static int parseMimeHeader(message *m, const char *cmd, const table_t *rfc821Table, const char *arg); |
|
215 |
+static int saveTextPart(mbox_ctx *mctx, message *m, int destroy_text); |
|
216 |
+static char *rfc2047(const char *in); |
|
217 |
+static char *rfc822comments(const char *in, char *out); |
|
218 |
+static int rfc1341(message *m, const char *dir); |
|
219 |
+static bool usefulHeader(int commandNumber, const char *cmd); |
|
220 |
+static char *getline_from_mbox(char *buffer, size_t len, fmap_t *map, size_t *at); |
|
221 |
+static bool isBounceStart(mbox_ctx *mctx, const char *line); |
|
222 |
+static bool exportBinhexMessage(mbox_ctx *mctx, message *m); |
|
223 |
+static int exportBounceMessage(mbox_ctx *ctx, text *start); |
|
224 |
+static const char *getMimeTypeStr(mime_type mimetype); |
|
225 |
+static const char *getEncTypeStr(encoding_type enctype); |
|
226 |
+static message *do_multipart(message *mainMessage, message **messages, int i, mbox_status *rc, mbox_ctx *mctx, message *messageIn, text **tptr, unsigned int recursion_level); |
|
227 |
+static int count_quotes(const char *buf); |
|
228 |
+static bool next_is_folded_header(const text *t); |
|
229 |
+static bool newline_in_header(const char *line); |
|
230 |
+ |
|
231 |
+static blob *getHrefs(message *m, tag_arguments_t *hrefs); |
|
232 |
+static void hrefs_done(blob *b, tag_arguments_t *hrefs); |
|
233 |
+static void checkURLs(message *m, mbox_ctx *mctx, mbox_status *rc, int is_html); |
|
234 | 234 |
|
235 | 235 |
/* Maximum line length according to RFC2821 */ |
236 |
-#define RFC2821LENGTH 1000 |
|
236 |
+#define RFC2821LENGTH 1000 |
|
237 | 237 |
|
238 | 238 |
/* Hashcodes for our hash tables */ |
239 |
-#define CONTENT_TYPE 1 |
|
240 |
-#define CONTENT_TRANSFER_ENCODING 2 |
|
241 |
-#define CONTENT_DISPOSITION 3 |
|
239 |
+#define CONTENT_TYPE 1 |
|
240 |
+#define CONTENT_TRANSFER_ENCODING 2 |
|
241 |
+#define CONTENT_DISPOSITION 3 |
|
242 | 242 |
|
243 | 243 |
/* Mime sub types */ |
244 |
-#define PLAIN 1 |
|
245 |
-#define ENRICHED 2 |
|
246 |
-#define HTML 3 |
|
247 |
-#define RICHTEXT 4 |
|
248 |
-#define MIXED 5 |
|
249 |
-#define ALTERNATIVE 6 /* RFC1521*/ |
|
250 |
-#define DIGEST 7 |
|
251 |
-#define SIGNED 8 |
|
252 |
-#define PARALLEL 9 |
|
253 |
-#define RELATED 10 /* RFC2387 */ |
|
254 |
-#define REPORT 11 /* RFC1892 */ |
|
255 |
-#define APPLEDOUBLE 12 /* Handling of this in only noddy for now */ |
|
256 |
-#define FAX MIXED /* |
|
257 |
- * RFC3458 |
|
258 |
- * Drafts stated to treat is as mixed if it is |
|
259 |
- * not known. This disappeared in the final |
|
260 |
- * version (except when talking about |
|
261 |
- * voice-message), but it is good enough for us |
|
262 |
- * since we do no validation of coversheet |
|
263 |
- * presence etc. (which also has disappeared |
|
264 |
- * in the final version) |
|
265 |
- */ |
|
266 |
-#define ENCRYPTED 13 /* |
|
267 |
- * e.g. RFC2015 |
|
268 |
- * Content-Type: multipart/encrypted; |
|
269 |
- * boundary="nextPart1383049.XCRrrar2yq"; |
|
270 |
- * protocol="application/pgp-encrypted" |
|
271 |
- */ |
|
272 |
-#define X_BFILE RELATED /* |
|
273 |
- * BeOS, expert two parts: the file and it's |
|
274 |
- * attributes. The attributes part comes as |
|
275 |
- * Content-Type: application/x-be_attribute |
|
276 |
- * name="foo" |
|
277 |
- * I can't find where it is defined, any |
|
278 |
- * pointers would be appreciated. For now |
|
279 |
- * we treat it as multipart/related |
|
280 |
- */ |
|
281 |
-#define KNOWBOT 14 /* Unknown and undocumented format? */ |
|
282 |
- |
|
283 |
-static const struct tableinit { |
|
284 |
- const char *key; |
|
285 |
- int value; |
|
244 |
+#define PLAIN 1 |
|
245 |
+#define ENRICHED 2 |
|
246 |
+#define HTML 3 |
|
247 |
+#define RICHTEXT 4 |
|
248 |
+#define MIXED 5 |
|
249 |
+#define ALTERNATIVE 6 /* RFC1521*/ |
|
250 |
+#define DIGEST 7 |
|
251 |
+#define SIGNED 8 |
|
252 |
+#define PARALLEL 9 |
|
253 |
+#define RELATED 10 /* RFC2387 */ |
|
254 |
+#define REPORT 11 /* RFC1892 */ |
|
255 |
+#define APPLEDOUBLE 12 /* Handling of this in only noddy for now */ |
|
256 |
+#define FAX MIXED /* \ |
|
257 |
+ * RFC3458 \ |
|
258 |
+ * Drafts stated to treat is as mixed if it is \ |
|
259 |
+ * not known. This disappeared in the final \ |
|
260 |
+ * version (except when talking about \ |
|
261 |
+ * voice-message), but it is good enough for us \ |
|
262 |
+ * since we do no validation of coversheet \ |
|
263 |
+ * presence etc. (which also has disappeared \ |
|
264 |
+ * in the final version) \ |
|
265 |
+ */ |
|
266 |
+#define ENCRYPTED 13 /* \ |
|
267 |
+ * e.g. RFC2015 \ |
|
268 |
+ * Content-Type: multipart/encrypted; \ |
|
269 |
+ * boundary="nextPart1383049.XCRrrar2yq"; \ |
|
270 |
+ * protocol="application/pgp-encrypted" \ |
|
271 |
+ */ |
|
272 |
+#define X_BFILE RELATED /* \ |
|
273 |
+ * BeOS, expert two parts: the file and it's \ |
|
274 |
+ * attributes. The attributes part comes as \ |
|
275 |
+ * Content-Type: application/x-be_attribute \ |
|
276 |
+ * name="foo" \ |
|
277 |
+ * I can't find where it is defined, any \ |
|
278 |
+ * pointers would be appreciated. For now \ |
|
279 |
+ * we treat it as multipart/related \ |
|
280 |
+ */ |
|
281 |
+#define KNOWBOT 14 /* Unknown and undocumented format? */ |
|
282 |
+ |
|
283 |
+static const struct tableinit { |
|
284 |
+ const char *key; |
|
285 |
+ int value; |
|
286 | 286 |
} rfc821headers[] = { |
287 |
- /* TODO: make these regular expressions */ |
|
288 |
- { "Content-Type", CONTENT_TYPE }, |
|
289 |
- { "Content-Transfer-Encoding", CONTENT_TRANSFER_ENCODING }, |
|
290 |
- { "Content-Disposition", CONTENT_DISPOSITION }, |
|
291 |
- { NULL, 0 } |
|
292 |
-}, mimeSubtypes[] = { /* see RFC2045 */ |
|
293 |
- /* subtypes of Text */ |
|
294 |
- { "plain", PLAIN }, |
|
295 |
- { "enriched", ENRICHED }, |
|
296 |
- { "html", HTML }, |
|
297 |
- { "richtext", RICHTEXT }, |
|
298 |
- /* subtypes of Multipart */ |
|
299 |
- { "mixed", MIXED }, |
|
300 |
- { "alternative", ALTERNATIVE }, |
|
301 |
- { "digest", DIGEST }, |
|
302 |
- { "signed", SIGNED }, |
|
303 |
- { "parallel", PARALLEL }, |
|
304 |
- { "related", RELATED }, |
|
305 |
- { "report", REPORT }, |
|
306 |
- { "appledouble", APPLEDOUBLE }, |
|
307 |
- { "fax-message", FAX }, |
|
308 |
- { "encrypted", ENCRYPTED }, |
|
309 |
- { "x-bfile", X_BFILE }, /* BeOS */ |
|
310 |
- { "knowbot", KNOWBOT }, /* ??? */ |
|
311 |
- { "knowbot-metadata", KNOWBOT }, /* ??? */ |
|
312 |
- { "knowbot-code", KNOWBOT }, /* ??? */ |
|
313 |
- { "knowbot-state", KNOWBOT }, /* ??? */ |
|
314 |
- { NULL, 0 } |
|
315 |
-}, mimeTypeStr[] = { |
|
316 |
- { "NOMIME", NOMIME }, |
|
317 |
- { "APPLICATION", APPLICATION }, |
|
318 |
- { "AUDIO", AUDIO }, |
|
319 |
- { "IMAGE", IMAGE }, |
|
320 |
- { "MESSAGE", MESSAGE }, |
|
321 |
- { "MULTIPART", MULTIPART }, |
|
322 |
- { "TEXT", TEXT }, |
|
323 |
- { "VIDEO", VIDEO }, |
|
324 |
- { "MEXTENSION", MEXTENSION }, |
|
325 |
- { NULL, 0 } |
|
326 |
-}, encTypeStr[] = { |
|
327 |
- { "NOENCODING", NOENCODING }, |
|
328 |
- { "QUOTEDPRINTABLE", QUOTEDPRINTABLE }, |
|
329 |
- { "BASE64", BASE64 }, |
|
330 |
- { "EIGHTBIT", EIGHTBIT }, |
|
331 |
- { "BINARY", BINARY }, |
|
332 |
- { "UUENCODE", UUENCODE }, |
|
333 |
- { "YENCODE", YENCODE }, |
|
334 |
- { "EEXTENSION", EEXTENSION }, |
|
335 |
- { "BINHEX", BINHEX }, |
|
336 |
- { NULL, 0 } |
|
337 |
-}; |
|
338 |
- |
|
339 |
-#ifdef CL_THREAD_SAFE |
|
340 |
-static pthread_mutex_t tables_mutex = PTHREAD_MUTEX_INITIALIZER; |
|
287 |
+ /* TODO: make these regular expressions */ |
|
288 |
+ {"Content-Type", CONTENT_TYPE}, |
|
289 |
+ {"Content-Transfer-Encoding", CONTENT_TRANSFER_ENCODING}, |
|
290 |
+ {"Content-Disposition", CONTENT_DISPOSITION}, |
|
291 |
+ {NULL, 0}}, |
|
292 |
+ mimeSubtypes[] = {/* see RFC2045 */ |
|
293 |
+ /* subtypes of Text */ |
|
294 |
+ {"plain", PLAIN}, |
|
295 |
+ {"enriched", ENRICHED}, |
|
296 |
+ {"html", HTML}, |
|
297 |
+ {"richtext", RICHTEXT}, |
|
298 |
+ /* subtypes of Multipart */ |
|
299 |
+ {"mixed", MIXED}, |
|
300 |
+ {"alternative", ALTERNATIVE}, |
|
301 |
+ {"digest", DIGEST}, |
|
302 |
+ {"signed", SIGNED}, |
|
303 |
+ {"parallel", PARALLEL}, |
|
304 |
+ {"related", RELATED}, |
|
305 |
+ {"report", REPORT}, |
|
306 |
+ {"appledouble", APPLEDOUBLE}, |
|
307 |
+ {"fax-message", FAX}, |
|
308 |
+ {"encrypted", ENCRYPTED}, |
|
309 |
+ {"x-bfile", X_BFILE}, /* BeOS */ |
|
310 |
+ {"knowbot", KNOWBOT}, /* ??? */ |
|
311 |
+ {"knowbot-metadata", KNOWBOT}, /* ??? */ |
|
312 |
+ {"knowbot-code", KNOWBOT}, /* ??? */ |
|
313 |
+ {"knowbot-state", KNOWBOT}, /* ??? */ |
|
314 |
+ {NULL, 0}}, |
|
315 |
+ mimeTypeStr[] = {{"NOMIME", NOMIME}, {"APPLICATION", APPLICATION}, {"AUDIO", AUDIO}, {"IMAGE", IMAGE}, {"MESSAGE", MESSAGE}, {"MULTIPART", MULTIPART}, {"TEXT", TEXT}, {"VIDEO", VIDEO}, {"MEXTENSION", MEXTENSION}, {NULL, 0}}, encTypeStr[] = {{"NOENCODING", NOENCODING}, {"QUOTEDPRINTABLE", QUOTEDPRINTABLE}, {"BASE64", BASE64}, {"EIGHTBIT", EIGHTBIT}, {"BINARY", BINARY}, {"UUENCODE", UUENCODE}, {"YENCODE", YENCODE}, {"EEXTENSION", EEXTENSION}, {"BINHEX", BINHEX}, {NULL, 0}}; |
|
316 |
+ |
|
317 |
+#ifdef CL_THREAD_SAFE |
|
318 |
+static pthread_mutex_t tables_mutex = PTHREAD_MUTEX_INITIALIZER; |
|
341 | 319 |
#endif |
342 |
-static table_t *rfc821 = NULL; |
|
343 |
-static table_t *subtype = NULL; |
|
320 |
+static table_t *rfc821 = NULL; |
|
321 |
+static table_t *subtype = NULL; |
|
344 | 322 |
|
345 |
-int |
|
346 |
-cli_mbox(const char *dir, cli_ctx *ctx) |
|
323 |
+int cli_mbox(const char *dir, cli_ctx *ctx) |
|
347 | 324 |
{ |
348 |
- if(dir == NULL) { |
|
349 |
- cli_dbgmsg("cli_mbox called with NULL dir\n"); |
|
350 |
- return CL_ENULLARG; |
|
351 |
- } |
|
352 |
- return cli_parse_mbox(dir, ctx); |
|
325 |
+ if (dir == NULL) { |
|
326 |
+ cli_dbgmsg("cli_mbox called with NULL dir\n"); |
|
327 |
+ return CL_ENULLARG; |
|
328 |
+ } |
|
329 |
+ return cli_parse_mbox(dir, ctx); |
|
353 | 330 |
} |
354 | 331 |
|
355 | 332 |
/* |
... | ... |
@@ -370,51 +348,51 @@ cli_mbox(const char *dir, cli_ctx *ctx) |
370 | 370 |
static int |
371 | 371 |
cli_parse_mbox(const char *dir, cli_ctx *ctx) |
372 | 372 |
{ |
373 |
- int retcode; |
|
374 |
- message *body; |
|
375 |
- char buffer[RFC2821LENGTH + 1]; |
|
376 |
- mbox_ctx mctx; |
|
377 |
- size_t at = 0; |
|
378 |
- fmap_t *map = *ctx->fmap; |
|
379 |
- |
|
380 |
- cli_dbgmsg("in mbox()\n"); |
|
381 |
- |
|
382 |
- if(!fmap_gets(map, buffer, &at, sizeof(buffer) - 1)) { |
|
383 |
- /* empty message */ |
|
384 |
- return CL_CLEAN; |
|
385 |
- } |
|
386 |
-#ifdef CL_THREAD_SAFE |
|
387 |
- pthread_mutex_lock(&tables_mutex); |
|
373 |
+ int retcode; |
|
374 |
+ message *body; |
|
375 |
+ char buffer[RFC2821LENGTH + 1]; |
|
376 |
+ mbox_ctx mctx; |
|
377 |
+ size_t at = 0; |
|
378 |
+ fmap_t *map = *ctx->fmap; |
|
379 |
+ |
|
380 |
+ cli_dbgmsg("in mbox()\n"); |
|
381 |
+ |
|
382 |
+ if (!fmap_gets(map, buffer, &at, sizeof(buffer) - 1)) { |
|
383 |
+ /* empty message */ |
|
384 |
+ return CL_CLEAN; |
|
385 |
+ } |
|
386 |
+#ifdef CL_THREAD_SAFE |
|
387 |
+ pthread_mutex_lock(&tables_mutex); |
|
388 | 388 |
#endif |
389 |
- if(rfc821 == NULL) { |
|
390 |
- assert(subtype == NULL); |
|
391 |
- |
|
392 |
- if(initialiseTables(&rfc821, &subtype) < 0) { |
|
393 |
- rfc821 = NULL; |
|
394 |
- subtype = NULL; |
|
395 |
-#ifdef CL_THREAD_SAFE |
|
396 |
- pthread_mutex_unlock(&tables_mutex); |
|
389 |
+ if (rfc821 == NULL) { |
|
390 |
+ assert(subtype == NULL); |
|
391 |
+ |
|
392 |
+ if (initialiseTables(&rfc821, &subtype) < 0) { |
|
393 |
+ rfc821 = NULL; |
|
394 |
+ subtype = NULL; |
|
395 |
+#ifdef CL_THREAD_SAFE |
|
396 |
+ pthread_mutex_unlock(&tables_mutex); |
|
397 | 397 |
#endif |
398 |
- return CL_EMEM; |
|
399 |
- } |
|
400 |
- } |
|
401 |
-#ifdef CL_THREAD_SAFE |
|
402 |
- pthread_mutex_unlock(&tables_mutex); |
|
398 |
+ return CL_EMEM; |
|
399 |
+ } |
|
400 |
+ } |
|
401 |
+#ifdef CL_THREAD_SAFE |
|
402 |
+ pthread_mutex_unlock(&tables_mutex); |
|
403 | 403 |
#endif |
404 | 404 |
|
405 |
- retcode = CL_SUCCESS; |
|
406 |
- body = NULL; |
|
405 |
+ retcode = CL_SUCCESS; |
|
406 |
+ body = NULL; |
|
407 | 407 |
|
408 |
- mctx.dir = dir; |
|
409 |
- mctx.rfc821Table = rfc821; |
|
410 |
- mctx.subtypeTable = subtype; |
|
411 |
- mctx.ctx = ctx; |
|
412 |
- mctx.files = 0; |
|
408 |
+ mctx.dir = dir; |
|
409 |
+ mctx.rfc821Table = rfc821; |
|
410 |
+ mctx.subtypeTable = subtype; |
|
411 |
+ mctx.ctx = ctx; |
|
412 |
+ mctx.files = 0; |
|
413 | 413 |
#if HAVE_JSON |
414 |
- mctx.wrkobj = ctx->wrkproperty; |
|
414 |
+ mctx.wrkobj = ctx->wrkproperty; |
|
415 | 415 |
#endif |
416 | 416 |
|
417 |
- /* |
|
417 |
+ /* |
|
418 | 418 |
* Is it a UNIX style mbox with more than one |
419 | 419 |
* mail message, or just a single mail message? |
420 | 420 |
* |
... | ... |
@@ -423,9 +401,9 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx) |
423 | 423 |
* than one message is handled, e.g. giving a better indication of |
424 | 424 |
* which message within the mailbox is infected |
425 | 425 |
*/ |
426 |
- /*if((strncmp(buffer, "From ", 5) == 0) && isalnum(buffer[5])) {*/ |
|
427 |
- if(strncmp(buffer, "From ", 5) == 0) { |
|
428 |
- /* |
|
426 |
+ /*if((strncmp(buffer, "From ", 5) == 0) && isalnum(buffer[5])) {*/ |
|
427 |
+ if (strncmp(buffer, "From ", 5) == 0) { |
|
428 |
+ /* |
|
429 | 429 |
* Have been asked to check a UNIX style mbox file, which |
430 | 430 |
* may contain more than one e-mail message to decode |
431 | 431 |
* |
... | ... |
@@ -443,47 +421,47 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx) |
443 | 443 |
* This would remove a problem with this code that it can |
444 | 444 |
* fill up the tmp directory before it starts scanning |
445 | 445 |
*/ |
446 |
- bool lastLineWasEmpty; |
|
447 |
- int messagenumber; |
|
448 |
- message *m = messageCreate(); |
|
449 |
- |
|
450 |
- if(m == NULL) |
|
451 |
- return CL_EMEM; |
|
452 |
- |
|
453 |
- lastLineWasEmpty = FALSE; |
|
454 |
- messagenumber = 1; |
|
455 |
- messageSetCTX(m, ctx); |
|
456 |
- |
|
457 |
- do { |
|
458 |
- cli_chomp(buffer); |
|
459 |
- /*if(lastLineWasEmpty && (strncmp(buffer, "From ", 5) == 0) && isalnum(buffer[5])) {*/ |
|
460 |
- if(lastLineWasEmpty && (strncmp(buffer, "From ", 5) == 0)) { |
|
461 |
- cli_dbgmsg("Deal with message number %d\n", messagenumber++); |
|
462 |
- /* |
|
446 |
+ bool lastLineWasEmpty; |
|
447 |
+ int messagenumber; |
|
448 |
+ message *m = messageCreate(); |
|
449 |
+ |
|
450 |
+ if (m == NULL) |
|
451 |
+ return CL_EMEM; |
|
452 |
+ |
|
453 |
+ lastLineWasEmpty = FALSE; |
|
454 |
+ messagenumber = 1; |
|
455 |
+ messageSetCTX(m, ctx); |
|
456 |
+ |
|
457 |
+ do { |
|
458 |
+ cli_chomp(buffer); |
|
459 |
+ /*if(lastLineWasEmpty && (strncmp(buffer, "From ", 5) == 0) && isalnum(buffer[5])) {*/ |
|
460 |
+ if (lastLineWasEmpty && (strncmp(buffer, "From ", 5) == 0)) { |
|
461 |
+ cli_dbgmsg("Deal with message number %d\n", messagenumber++); |
|
462 |
+ /* |
|
463 | 463 |
* End of a message in the mail box |
464 | 464 |
*/ |
465 |
- body = parseEmailHeaders(m, rfc821); |
|
466 |
- if(body == NULL) { |
|
467 |
- messageReset(m); |
|
468 |
- continue; |
|
469 |
- } |
|
470 |
- messageSetCTX(body, ctx); |
|
471 |
- messageDestroy(m); |
|
472 |
- if(messageGetBody(body)) { |
|
473 |
- mbox_status rc = parseEmailBody(body, NULL, &mctx, 0); |
|
474 |
- if(rc == FAIL) { |
|
475 |
- messageReset(body); |
|
476 |
- m = body; |
|
477 |
- continue; |
|
478 |
- } else if(rc == VIRUS) { |
|
479 |
- cli_dbgmsg("Message number %d is infected\n", |
|
480 |
- messagenumber-1); |
|
481 |
- retcode = CL_VIRUS; |
|
482 |
- m = NULL; |
|
483 |
- break; |
|
484 |
- } |
|
485 |
- } |
|
486 |
- /* |
|
465 |
+ body = parseEmailHeaders(m, rfc821); |
|
466 |
+ if (body == NULL) { |
|
467 |
+ messageReset(m); |
|
468 |
+ continue; |
|
469 |
+ } |
|
470 |
+ messageSetCTX(body, ctx); |
|
471 |
+ messageDestroy(m); |
|
472 |
+ if (messageGetBody(body)) { |
|
473 |
+ mbox_status rc = parseEmailBody(body, NULL, &mctx, 0); |
|
474 |
+ if (rc == FAIL) { |
|
475 |
+ messageReset(body); |
|
476 |
+ m = body; |
|
477 |
+ continue; |
|
478 |
+ } else if (rc == VIRUS) { |
|
479 |
+ cli_dbgmsg("Message number %d is infected\n", |
|
480 |
+ messagenumber - 1); |
|
481 |
+ retcode = CL_VIRUS; |
|
482 |
+ m = NULL; |
|
483 |
+ break; |
|
484 |
+ } |
|
485 |
+ } |
|
486 |
+ /* |
|
487 | 487 |
* Starting a new message, throw away all the |
488 | 488 |
* information about the old one. It would |
489 | 489 |
* be best to be able to scan this message |
... | ... |
@@ -491,72 +469,72 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx) |
491 | 491 |
* that haven't been passed here so it can't be |
492 | 492 |
* called |
493 | 493 |
*/ |
494 |
- m = body; |
|
495 |
- messageReset(body); |
|
496 |
- messageSetCTX(body, ctx); |
|
494 |
+ m = body; |
|
495 |
+ messageReset(body); |
|
496 |
+ messageSetCTX(body, ctx); |
|
497 | 497 |
|
498 |
- cli_dbgmsg("Finished processing message\n"); |
|
499 |
- } else |
|
500 |
- lastLineWasEmpty = (bool)(buffer[0] == '\0'); |
|
498 |
+ cli_dbgmsg("Finished processing message\n"); |
|
499 |
+ } else |
|
500 |
+ lastLineWasEmpty = (bool)(buffer[0] == '\0'); |
|
501 | 501 |
|
502 |
- if(isuuencodebegin(buffer)) { |
|
503 |
- /* |
|
502 |
+ if (isuuencodebegin(buffer)) { |
|
503 |
+ /* |
|
504 | 504 |
* Fast track visa to uudecode. |
505 | 505 |
* TODO: binhex, yenc |
506 | 506 |
*/ |
507 |
- if(uudecodeFile(m, buffer, dir, map, &at) < 0) |
|
508 |
- if(messageAddStr(m, buffer) < 0) |
|
509 |
- break; |
|
510 |
- } else |
|
511 |
- /* at this point, the \n has been removed */ |
|
512 |
- if(messageAddStr(m, buffer) < 0) |
|
513 |
- break; |
|
514 |
- } while(fmap_gets(map, buffer, &at, sizeof(buffer) - 1)); |
|
515 |
- |
|
516 |
- if(retcode == CL_SUCCESS) { |
|
517 |
- cli_dbgmsg("Extract attachments from email %d\n", messagenumber); |
|
518 |
- body = parseEmailHeaders(m, rfc821); |
|
519 |
- } |
|
520 |
- if(m) |
|
521 |
- messageDestroy(m); |
|
522 |
- } else { |
|
523 |
- /* |
|
507 |
+ if (uudecodeFile(m, buffer, dir, map, &at) < 0) |
|
508 |
+ if (messageAddStr(m, buffer) < 0) |
|
509 |
+ break; |
|
510 |
+ } else |
|
511 |
+ /* at this point, the \n has been removed */ |
|
512 |
+ if (messageAddStr(m, buffer) < 0) |
|
513 |
+ break; |
|
514 |
+ } while (fmap_gets(map, buffer, &at, sizeof(buffer) - 1)); |
|
515 |
+ |
|
516 |
+ if (retcode == CL_SUCCESS) { |
|
517 |
+ cli_dbgmsg("Extract attachments from email %d\n", messagenumber); |
|
518 |
+ body = parseEmailHeaders(m, rfc821); |
|
519 |
+ } |
|
520 |
+ if (m) |
|
521 |
+ messageDestroy(m); |
|
522 |
+ } else { |
|
523 |
+ /* |
|
524 | 524 |
* It's a single message, parse the headers then the body |
525 | 525 |
*/ |
526 |
- if(strncmp(buffer, "P I ", 4) == 0) |
|
527 |
- /* |
|
526 |
+ if (strncmp(buffer, "P I ", 4) == 0) |
|
527 |
+ /* |
|
528 | 528 |
* CommuniGate Pro format: ignore headers until |
529 | 529 |
* blank line |
530 | 530 |
*/ |
531 |
- while(fmap_gets(map, buffer, &at, sizeof(buffer) - 1) && |
|
532 |
- (strchr("\r\n", buffer[0]) == NULL)) |
|
533 |
- ; |
|
534 |
- /* getline_from_mbox could be using unlocked_stdio(3), |
|
531 |
+ while (fmap_gets(map, buffer, &at, sizeof(buffer) - 1) && |
|
532 |
+ (strchr("\r\n", buffer[0]) == NULL)) |
|
533 |
+ ; |
|
534 |
+ /* getline_from_mbox could be using unlocked_stdio(3), |
|
535 | 535 |
* so lock file here */ |
536 |
- /* |
|
536 |
+ /* |
|
537 | 537 |
* Ignore any blank lines at the top of the message |
538 | 538 |
*/ |
539 |
- while(strchr("\r\n", buffer[0]) && |
|
540 |
- (getline_from_mbox(buffer, sizeof(buffer) - 1, map, &at) != NULL)) |
|
541 |
- ; |
|
539 |
+ while (strchr("\r\n", buffer[0]) && |
|
540 |
+ (getline_from_mbox(buffer, sizeof(buffer) - 1, map, &at) != NULL)) |
|
541 |
+ ; |
|
542 | 542 |
|
543 |
- buffer[sizeof(buffer) - 1] = '\0'; |
|
543 |
+ buffer[sizeof(buffer) - 1] = '\0'; |
|
544 | 544 |
|
545 |
- body = parseEmailFile(map, &at, rfc821, buffer, dir); |
|
546 |
- } |
|
545 |
+ body = parseEmailFile(map, &at, rfc821, buffer, dir); |
|
546 |
+ } |
|
547 | 547 |
|
548 |
- if(body) { |
|
549 |
- /* |
|
548 |
+ if (body) { |
|
549 |
+ /* |
|
550 | 550 |
* Write out the last entry in the mailbox |
551 | 551 |
*/ |
552 |
- if((retcode == CL_SUCCESS) && messageGetBody(body)) { |
|
553 |
- messageSetCTX(body, ctx); |
|
554 |
- switch(parseEmailBody(body, NULL, &mctx, 0)) { |
|
555 |
- case OK: |
|
556 |
- case OK_ATTACHMENTS_NOT_SAVED: |
|
557 |
- break; |
|
558 |
- case FAIL: |
|
559 |
- /* |
|
552 |
+ if ((retcode == CL_SUCCESS) && messageGetBody(body)) { |
|
553 |
+ messageSetCTX(body, ctx); |
|
554 |
+ switch (parseEmailBody(body, NULL, &mctx, 0)) { |
|
555 |
+ case OK: |
|
556 |
+ case OK_ATTACHMENTS_NOT_SAVED: |
|
557 |
+ break; |
|
558 |
+ case FAIL: |
|
559 |
+ /* |
|
560 | 560 |
* beware: cli_magic_scandesc(), |
561 | 561 |
* changes this into CL_CLEAN, so only |
562 | 562 |
* use it to inform the higher levels |
... | ... |
@@ -565,37 +543,37 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx) |
565 | 565 |
* decoding errors on what *is* a valid |
566 | 566 |
* mbox |
567 | 567 |
*/ |
568 |
- retcode = CL_EFORMAT; |
|
569 |
- break; |
|
570 |
- case MAXREC: |
|
571 |
- retcode = CL_EMAXREC; |
|
572 |
- break; |
|
573 |
- case MAXFILES: |
|
574 |
- retcode = CL_EMAXFILES; |
|
575 |
- break; |
|
576 |
- case VIRUS: |
|
577 |
- retcode = CL_VIRUS; |
|
578 |
- break; |
|
579 |
- } |
|
580 |
- } |
|
581 |
- |
|
582 |
- if(body->isTruncated && retcode == CL_SUCCESS) |
|
583 |
- retcode = CL_EMEM; |
|
584 |
- /* |
|
568 |
+ retcode = CL_EFORMAT; |
|
569 |
+ break; |
|
570 |
+ case MAXREC: |
|
571 |
+ retcode = CL_EMAXREC; |
|
572 |
+ break; |
|
573 |
+ case MAXFILES: |
|
574 |
+ retcode = CL_EMAXFILES; |
|
575 |
+ break; |
|
576 |
+ case VIRUS: |
|
577 |
+ retcode = CL_VIRUS; |
|
578 |
+ break; |
|
579 |
+ } |
|
580 |
+ } |
|
581 |
+ |
|
582 |
+ if (body->isTruncated && retcode == CL_SUCCESS) |
|
583 |
+ retcode = CL_EMEM; |
|
584 |
+ /* |
|
585 | 585 |
* Tidy up and quit |
586 | 586 |
*/ |
587 |
- messageDestroy(body); |
|
588 |
- } |
|
587 |
+ messageDestroy(body); |
|
588 |
+ } |
|
589 | 589 |
|
590 |
- if((retcode == CL_CLEAN) && ctx->found_possibly_unwanted && |
|
591 |
- (*ctx->virname == NULL || SCAN_ALLMATCHES)) { |
|
592 |
- retcode = cli_append_virus(ctx, "Heuristics.Phishing.Email"); |
|
593 |
- ctx->found_possibly_unwanted = 0; |
|
594 |
- } |
|
590 |
+ if ((retcode == CL_CLEAN) && ctx->found_possibly_unwanted && |
|
591 |
+ (*ctx->virname == NULL || SCAN_ALLMATCHES)) { |
|
592 |
+ retcode = cli_append_virus(ctx, "Heuristics.Phishing.Email"); |
|
593 |
+ ctx->found_possibly_unwanted = 0; |
|
594 |
+ } |
|
595 | 595 |
|
596 |
- cli_dbgmsg("cli_mbox returning %d\n", retcode); |
|
596 |
+ cli_dbgmsg("cli_mbox returning %d\n", retcode); |
|
597 | 597 |
|
598 |
- return retcode; |
|
598 |
+ return retcode; |
|
599 | 599 |
} |
600 | 600 |
|
601 | 601 |
/* |
... | ... |
@@ -607,58 +585,58 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx) |
607 | 607 |
static message * |
608 | 608 |
parseEmailFile(fmap_t *map, size_t *at, const table_t *rfc821, const char *firstLine, const char *dir) |
609 | 609 |
{ |
610 |
- bool inHeader = TRUE; |
|
611 |
- bool bodyIsEmpty = TRUE; |
|
612 |
- bool lastWasBlank = FALSE, lastBodyLineWasBlank = FALSE; |
|
613 |
- message *ret; |
|
614 |
- bool anyHeadersFound = FALSE; |
|
615 |
- int commandNumber = -1; |
|
616 |
- char *fullline = NULL, *boundary = NULL; |
|
617 |
- size_t fulllinelength = 0; |
|
618 |
- char buffer[RFC2821LENGTH + 1]; |
|
619 |
- |
|
620 |
- cli_dbgmsg("parseEmailFile\n"); |
|
621 |
- |
|
622 |
- ret = messageCreate(); |
|
623 |
- if(ret == NULL) |
|
624 |
- return NULL; |
|
625 |
- |
|
626 |
- strncpy(buffer, firstLine, sizeof(buffer)-1); |
|
627 |
- do { |
|
628 |
- const char *line; |
|
629 |
- |
|
630 |
- (void)cli_chomp(buffer); |
|
631 |
- |
|
632 |
- if(buffer[0] == '\0') |
|
633 |
- line = NULL; |
|
634 |
- else |
|
635 |
- line = buffer; |
|
636 |
- |
|
637 |
- /* |
|
610 |
+ bool inHeader = TRUE; |
|
611 |
+ bool bodyIsEmpty = TRUE; |
|
612 |
+ bool lastWasBlank = FALSE, lastBodyLineWasBlank = FALSE; |
|
613 |
+ message *ret; |
|
614 |
+ bool anyHeadersFound = FALSE; |
|
615 |
+ int commandNumber = -1; |
|
616 |
+ char *fullline = NULL, *boundary = NULL; |
|
617 |
+ size_t fulllinelength = 0; |
|
618 |
+ char buffer[RFC2821LENGTH + 1]; |
|
619 |
+ |
|
620 |
+ cli_dbgmsg("parseEmailFile\n"); |
|
621 |
+ |
|
622 |
+ ret = messageCreate(); |
|
623 |
+ if (ret == NULL) |
|
624 |
+ return NULL; |
|
625 |
+ |
|
626 |
+ strncpy(buffer, firstLine, sizeof(buffer) - 1); |
|
627 |
+ do { |
|
628 |
+ const char *line; |
|
629 |
+ |
|
630 |
+ (void)cli_chomp(buffer); |
|
631 |
+ |
|
632 |
+ if (buffer[0] == '\0') |
|
633 |
+ line = NULL; |
|
634 |
+ else |
|
635 |
+ line = buffer; |
|
636 |
+ |
|
637 |
+ /* |
|
638 | 638 |
* Don't blank lines which are only spaces from headers, |
639 | 639 |
* otherwise they'll be treated as the end of header marker |
640 | 640 |
*/ |
641 |
- if(lastWasBlank) { |
|
642 |
- lastWasBlank = FALSE; |
|
643 |
- if(boundaryStart(buffer, boundary)) { |
|
644 |
- cli_dbgmsg("Found a header line with space that should be blank\n"); |
|
645 |
- inHeader = FALSE; |
|
646 |
- } |
|
647 |
- } |
|
648 |
- if(inHeader) { |
|
649 |
- cli_dbgmsg("parseEmailFile: check '%s' fullline %p\n", |
|
650 |
- buffer, fullline); |
|
651 |
- /* |
|
641 |
+ if (lastWasBlank) { |
|
642 |
+ lastWasBlank = FALSE; |
|
643 |
+ if (boundaryStart(buffer, boundary)) { |
|
644 |
+ cli_dbgmsg("Found a header line with space that should be blank\n"); |
|
645 |
+ inHeader = FALSE; |
|
646 |
+ } |
|
647 |
+ } |
|
648 |
+ if (inHeader) { |
|
649 |
+ cli_dbgmsg("parseEmailFile: check '%s' fullline %p\n", |
|
650 |
+ buffer, fullline); |
|
651 |
+ /* |
|
652 | 652 |
* Ensure wide characters are handled where |
653 | 653 |
* sizeof(char) > 1 |
654 | 654 |
*/ |
655 |
- if(line && isspace(line[0] & 0xFF)) { |
|
656 |
- char copy[sizeof(buffer)]; |
|
655 |
+ if (line && isspace(line[0] & 0xFF)) { |
|
656 |
+ char copy[sizeof(buffer)]; |
|
657 | 657 |
|
658 |
- strcpy(copy, buffer); |
|
659 |
- strstrip(copy); |
|
660 |
- if(copy[0] == '\0') { |
|
661 |
- /* |
|
658 |
+ strcpy(copy, buffer); |
|
659 |
+ strstrip(copy); |
|
660 |
+ if (copy[0] == '\0') { |
|
661 |
+ /* |
|
662 | 662 |
* The header line contains only white |
663 | 663 |
* space. This is not the end of the |
664 | 664 |
* headers according to RFC2822, but |
... | ... |
@@ -671,189 +649,189 @@ parseEmailFile(fmap_t *map, size_t *at, const table_t *rfc821, const char *first |
671 | 671 |
* content-type line. So we just have |
672 | 672 |
* to make a best guess. Sigh. |
673 | 673 |
*/ |
674 |
- if(fullline) { |
|
675 |
- if(parseEmailHeader(ret, fullline, rfc821) < 0) |
|
676 |
- continue; |
|
677 |
- |
|
678 |
- free(fullline); |
|
679 |
- fullline = NULL; |
|
680 |
- } |
|
681 |
- if(boundary || |
|
682 |
- ((boundary = (char *)messageFindArgument(ret, "boundary")) != NULL)) { |
|
683 |
- lastWasBlank = TRUE; |
|
684 |
- continue; |
|
685 |
- } |
|
686 |
- } |
|
687 |
- } |
|
688 |
- if((line == NULL) && (fullline == NULL)) { /* empty line */ |
|
689 |
- /* |
|
674 |
+ if (fullline) { |
|
675 |
+ if (parseEmailHeader(ret, fullline, rfc821) < 0) |
|
676 |
+ continue; |
|
677 |
+ |
|
678 |
+ free(fullline); |
|
679 |
+ fullline = NULL; |
|
680 |
+ } |
|
681 |
+ if (boundary || |
|
682 |
+ ((boundary = (char *)messageFindArgument(ret, "boundary")) != NULL)) { |
|
683 |
+ lastWasBlank = TRUE; |
|
684 |
+ continue; |
|
685 |
+ } |
|
686 |
+ } |
|
687 |
+ } |
|
688 |
+ if ((line == NULL) && (fullline == NULL)) { /* empty line */ |
|
689 |
+ /* |
|
690 | 690 |
* A blank line signifies the end of |
691 | 691 |
* the header and the start of the text |
692 | 692 |
*/ |
693 |
- if(!anyHeadersFound) |
|
694 |
- /* Ignore the junk at the top */ |
|
695 |
- continue; |
|
693 |
+ if (!anyHeadersFound) |
|
694 |
+ /* Ignore the junk at the top */ |
|
695 |
+ continue; |
|
696 | 696 |
|
697 |
- cli_dbgmsg("End of header information\n"); |
|
698 |
- inHeader = FALSE; |
|
699 |
- bodyIsEmpty = TRUE; |
|
700 |
- } else { |
|
701 |
- char *ptr; |
|
702 |
- const char *lookahead; |
|
697 |
+ cli_dbgmsg("End of header information\n"); |
|
698 |
+ inHeader = FALSE; |
|
699 |
+ bodyIsEmpty = TRUE; |
|
700 |
+ } else { |
|
701 |
+ char *ptr; |
|
702 |
+ const char *lookahead; |
|
703 | 703 |
|
704 |
- if(fullline == NULL) { |
|
705 |
- char cmd[RFC2821LENGTH + 1], out[RFC2821LENGTH + 1]; |
|
704 |
+ if (fullline == NULL) { |
|
705 |
+ char cmd[RFC2821LENGTH + 1], out[RFC2821LENGTH + 1]; |
|
706 | 706 |
|
707 |
- /* |
|
707 |
+ /* |
|
708 | 708 |
* Continuation of line we're ignoring? |
709 | 709 |
*/ |
710 |
- if(isblank(line[0])) |
|
711 |
- continue; |
|
710 |
+ if (isblank(line[0])) |
|
711 |
+ continue; |
|
712 | 712 |
|
713 |
- /* |
|
713 |
+ /* |
|
714 | 714 |
* Is this a header we're interested in? |
715 | 715 |
*/ |
716 |
- if((strchr(line, ':') == NULL) || |
|
717 |
- (cli_strtokbuf(line, 0, ":", cmd) == NULL)) { |
|
718 |
- if(strncmp(line, "From ", 5) == 0) |
|
719 |
- anyHeadersFound = TRUE; |
|
720 |
- continue; |
|
721 |
- } |
|
722 |
- |
|
723 |
- ptr = rfc822comments(cmd, out); |
|
724 |
- commandNumber = tableFind(rfc821, ptr ? ptr : cmd); |
|
725 |
- |
|
726 |
- switch(commandNumber) { |
|
727 |
- case CONTENT_TRANSFER_ENCODING: |
|
728 |
- case CONTENT_DISPOSITION: |
|
729 |
- case CONTENT_TYPE: |
|
730 |
- anyHeadersFound = TRUE; |
|
731 |
- break; |
|
732 |
- default: |
|
733 |
- if(!anyHeadersFound) |
|
734 |
- anyHeadersFound = usefulHeader(commandNumber, cmd); |
|
735 |
- continue; |
|
736 |
- } |
|
737 |
- fullline = cli_strdup(line); |
|
738 |
- fulllinelength = strlen(line) + 1; |
|
739 |
- if(!fullline) { |
|
740 |
- if(ret) |
|
741 |
- ret->isTruncated = TRUE; |
|
742 |
- break; |
|
743 |
- } |
|
744 |
- } else if(line != NULL) { |
|
745 |
- fulllinelength += strlen(line) + 1; |
|
746 |
- ptr = cli_realloc(fullline, fulllinelength); |
|
747 |
- if(ptr == NULL) |
|
748 |
- continue; |
|
749 |
- fullline = ptr; |
|
750 |
- cli_strlcat(fullline, line, fulllinelength); |
|
751 |
- } |
|
752 |
- |
|
753 |
- assert(fullline != NULL); |
|
754 |
- |
|
755 |
- if((lookahead = fmap_need_off_once(map, *at, 1))) { |
|
756 |
- /* |
|
716 |
+ if ((strchr(line, ':') == NULL) || |
|
717 |
+ (cli_strtokbuf(line, 0, ":", cmd) == NULL)) { |
|
718 |
+ if (strncmp(line, "From ", 5) == 0) |
|
719 |
+ anyHeadersFound = TRUE; |
|
720 |
+ continue; |
|
721 |
+ } |
|
722 |
+ |
|
723 |
+ ptr = rfc822comments(cmd, out); |
|
724 |
+ commandNumber = tableFind(rfc821, ptr ? ptr : cmd); |
|
725 |
+ |
|
726 |
+ switch (commandNumber) { |
|
727 |
+ case CONTENT_TRANSFER_ENCODING: |
|
728 |
+ case CONTENT_DISPOSITION: |
|
729 |
+ case CONTENT_TYPE: |
|
730 |
+ anyHeadersFound = TRUE; |
|
731 |
+ break; |
|
732 |
+ default: |
|
733 |
+ if (!anyHeadersFound) |
|
734 |
+ anyHeadersFound = usefulHeader(commandNumber, cmd); |
|
735 |
+ continue; |
|
736 |
+ } |
|
737 |
+ fullline = cli_strdup(line); |
|
738 |
+ fulllinelength = strlen(line) + 1; |
|
739 |
+ if (!fullline) { |
|
740 |
+ if (ret) |
|
741 |
+ ret->isTruncated = TRUE; |
|
742 |
+ break; |
|
743 |
+ } |
|
744 |
+ } else if (line != NULL) { |
|
745 |
+ fulllinelength += strlen(line) + 1; |
|
746 |
+ ptr = cli_realloc(fullline, fulllinelength); |
|
747 |
+ if (ptr == NULL) |
|
748 |
+ continue; |
|
749 |
+ fullline = ptr; |
|
750 |
+ cli_strlcat(fullline, line, fulllinelength); |
|
751 |
+ } |
|
752 |
+ |
|
753 |
+ assert(fullline != NULL); |
|
754 |
+ |
|
755 |
+ if ((lookahead = fmap_need_off_once(map, *at, 1))) { |
|
756 |
+ /* |
|
757 | 757 |
* Section B.2 of RFC822 says TAB or |
758 | 758 |
* SPACE means a continuation of the |
759 | 759 |
* previous entry. |
760 | 760 |
* |
761 | 761 |
* Add all the arguments on the line |
762 | 762 |
*/ |
763 |
- if(isblank(*lookahead)) |
|
764 |
- continue; |
|
765 |
- } |
|
763 |
+ if (isblank(*lookahead)) |
|
764 |
+ continue; |
|
765 |
+ } |
|
766 | 766 |
|
767 |
- /* |
|
767 |
+ /* |
|
768 | 768 |
* Handle broken headers, where the next |
769 | 769 |
* line isn't indented by whitespace |
770 | 770 |
*/ |
771 |
- if(fullline[strlen(fullline) - 1] == ';') |
|
772 |
- /* Add arguments to this line */ |
|
773 |
- continue; |
|
774 |
- |
|
775 |
- if(line && (count_quotes(fullline) & 1)) |
|
776 |
- continue; |
|
777 |
- |
|
778 |
- ptr = rfc822comments(fullline, NULL); |
|
779 |
- if(ptr) { |
|
780 |
- free(fullline); |
|
781 |
- fullline = ptr; |
|
782 |
- } |
|
783 |
- |
|
784 |
- if(parseEmailHeader(ret, fullline, rfc821) < 0) |
|
785 |
- continue; |
|
786 |
- |
|
787 |
- free(fullline); |
|
788 |
- fullline = NULL; |
|
789 |
- } |
|
790 |
- } else if(line && isuuencodebegin(line)) { |
|
791 |
- /* |
|
771 |
+ if (fullline[strlen(fullline) - 1] == ';') |
|
772 |
+ /* Add arguments to this line */ |
|
773 |
+ continue; |
|
774 |
+ |
|
775 |
+ if (line && (count_quotes(fullline) & 1)) |
|
776 |
+ continue; |
|
777 |
+ |
|
778 |
+ ptr = rfc822comments(fullline, NULL); |
|
779 |
+ if (ptr) { |
|
780 |
+ free(fullline); |
|
781 |
+ fullline = ptr; |
|
782 |
+ } |
|
783 |
+ |
|
784 |
+ if (parseEmailHeader(ret, fullline, rfc821) < 0) |
|
785 |
+ continue; |
|
786 |
+ |
|
787 |
+ free(fullline); |
|
788 |
+ fullline = NULL; |
|
789 |
+ } |
|
790 |
+ } else if (line && isuuencodebegin(line)) { |
|
791 |
+ /* |
|
792 | 792 |
* Fast track visa to uudecode. |
793 | 793 |
* TODO: binhex, yenc |
794 | 794 |
*/ |
795 |
- bodyIsEmpty = FALSE; |
|
796 |
- if(uudecodeFile(ret, line, dir, map, at) < 0) |
|
797 |
- if(messageAddStr(ret, line) < 0) |
|
798 |
- break; |
|
799 |
- } else { |
|
800 |
- if(line == NULL) { |
|
801 |
- /* |
|
795 |
+ bodyIsEmpty = FALSE; |
|
796 |
+ if (uudecodeFile(ret, line, dir, map, at) < 0) |
|
797 |
+ if (messageAddStr(ret, line) < 0) |
|
798 |
+ break; |
|
799 |
+ } else { |
|
800 |
+ if (line == NULL) { |
|
801 |
+ /* |
|
802 | 802 |
* Although this would save time and RAM, some |
803 | 803 |
* phish signatures have been built which need |
804 | 804 |
* the blank lines |
805 | 805 |
*/ |
806 |
- if(lastBodyLineWasBlank && |
|
807 |
- (messageGetMimeType(ret) != TEXT)) { |
|
808 |
- cli_dbgmsg("Ignoring consecutive blank lines in the body\n"); |
|
809 |
- continue; |
|
810 |
- } |
|
811 |
- lastBodyLineWasBlank = TRUE; |
|
812 |
- } else { |
|
813 |
- if(bodyIsEmpty) { |
|
814 |
- /* |
|
806 |
+ if (lastBodyLineWasBlank && |
|
807 |
+ (messageGetMimeType(ret) != TEXT)) { |
|
808 |
+ cli_dbgmsg("Ignoring consecutive blank lines in the body\n"); |
|
809 |
+ continue; |
|
810 |
+ } |
|
811 |
+ lastBodyLineWasBlank = TRUE; |
|
812 |
+ } else { |
|
813 |
+ if (bodyIsEmpty) { |
|
814 |
+ /* |
|
815 | 815 |
* Broken message: new line in the |
816 | 816 |
* middle of the headers, so the first |
817 | 817 |
* line of the body is in fact |
818 | 818 |
* the last lines of the header |
819 | 819 |
*/ |
820 |
- if(newline_in_header(line)) |
|
821 |
- continue; |
|
822 |
- bodyIsEmpty = FALSE; |
|
823 |
- } |
|
824 |
- lastBodyLineWasBlank = FALSE; |
|
825 |
- } |
|
826 |
- |
|
827 |
- if(messageAddStr(ret, line) < 0) |
|
828 |
- break; |
|
829 |
- } |
|
830 |
- } while(getline_from_mbox(buffer, sizeof(buffer) - 1, map, at) != NULL); |
|
831 |
- |
|
832 |
- if(boundary) |
|
833 |
- free(boundary); |
|
834 |
- |
|
835 |
- if(fullline) { |
|
836 |
- if(*fullline) switch(commandNumber) { |
|
837 |
- case CONTENT_TRANSFER_ENCODING: |
|
838 |
- case CONTENT_DISPOSITION: |
|
839 |
- case CONTENT_TYPE: |
|
840 |
- cli_dbgmsg("parseEmailFile: Fullline unparsed '%s'\n", fullline); |
|
841 |
- } |
|
842 |
- free(fullline); |
|
843 |
- } |
|
844 |
- |
|
845 |
- if(!anyHeadersFound) { |
|
846 |
- /* |
|
820 |
+ if (newline_in_header(line)) |
|
821 |
+ continue; |
|
822 |
+ bodyIsEmpty = FALSE; |
|
823 |
+ } |
|
824 |
+ lastBodyLineWasBlank = FALSE; |
|
825 |
+ } |
|
826 |
+ |
|
827 |
+ if (messageAddStr(ret, line) < 0) |
|
828 |
+ break; |
|
829 |
+ } |
|
830 |
+ } while (getline_from_mbox(buffer, sizeof(buffer) - 1, map, at) != NULL); |
|
831 |
+ |
|
832 |
+ if (boundary) |
|
833 |
+ free(boundary); |
|
834 |
+ |
|
835 |
+ if (fullline) { |
|
836 |
+ if (*fullline) switch (commandNumber) { |
|
837 |
+ case CONTENT_TRANSFER_ENCODING: |
|
838 |
+ case CONTENT_DISPOSITION: |
|
839 |
+ case CONTENT_TYPE: |
|
840 |
+ cli_dbgmsg("parseEmailFile: Fullline unparsed '%s'\n", fullline); |
|
841 |
+ } |
|
842 |
+ free(fullline); |
|
843 |
+ } |
|
844 |
+ |
|
845 |
+ if (!anyHeadersFound) { |
|
846 |
+ /* |
|
847 | 847 |
* False positive in believing we have an e-mail when we don't |
848 | 848 |
*/ |
849 |
- messageDestroy(ret); |
|
850 |
- cli_dbgmsg("parseEmailFile: no headers found, assuming it isn't an email\n"); |
|
851 |
- return NULL; |
|
852 |
- } |
|
849 |
+ messageDestroy(ret); |
|
850 |
+ cli_dbgmsg("parseEmailFile: no headers found, assuming it isn't an email\n"); |
|
851 |
+ return NULL; |
|
852 |
+ } |
|
853 | 853 |
|
854 |
- cli_dbgmsg("parseEmailFile: return\n"); |
|
854 |
+ cli_dbgmsg("parseEmailFile: return\n"); |
|
855 | 855 |
|
856 |
- return ret; |
|
856 |
+ return ret; |
|
857 | 857 |
} |
858 | 858 |
|
859 | 859 |
/* |
... | ... |
@@ -867,162 +845,162 @@ parseEmailFile(fmap_t *map, size_t *at, const table_t *rfc821, const char *first |
867 | 867 |
static message * |
868 | 868 |
parseEmailHeaders(message *m, const table_t *rfc821) |
869 | 869 |
{ |
870 |
- bool inHeader = TRUE; |
|
871 |
- bool bodyIsEmpty = TRUE; |
|
872 |
- text *t; |
|
873 |
- message *ret; |
|
874 |
- bool anyHeadersFound = FALSE; |
|
875 |
- int commandNumber = -1; |
|
876 |
- char *fullline = NULL; |
|
877 |
- size_t fulllinelength = 0; |
|
878 |
- |
|
879 |
- cli_dbgmsg("parseEmailHeaders\n"); |
|
880 |
- |
|
881 |
- if(m == NULL) |
|
882 |
- return NULL; |
|
883 |
- |
|
884 |
- ret = messageCreate(); |
|
885 |
- |
|
886 |
- for(t = messageGetBody(m); t; t = t->t_next) { |
|
887 |
- const char *line; |
|
888 |
- |
|
889 |
- if(t->t_line) |
|
890 |
- line = lineGetData(t->t_line); |
|
891 |
- else |
|
892 |
- line = NULL; |
|
893 |
- |
|
894 |
- if(inHeader) { |
|
895 |
- cli_dbgmsg("parseEmailHeaders: check '%s'\n", |
|
896 |
- line ? line : ""); |
|
897 |
- if(line == NULL) { |
|
898 |
- /* |
|
870 |
+ bool inHeader = TRUE; |
|
871 |
+ bool bodyIsEmpty = TRUE; |
|
872 |
+ text *t; |
|
873 |
+ message *ret; |
|
874 |
+ bool anyHeadersFound = FALSE; |
|
875 |
+ int commandNumber = -1; |
|
876 |
+ char *fullline = NULL; |
|
877 |
+ size_t fulllinelength = 0; |
|
878 |
+ |
|
879 |
+ cli_dbgmsg("parseEmailHeaders\n"); |
|
880 |
+ |
|
881 |
+ if (m == NULL) |
|
882 |
+ return NULL; |
|
883 |
+ |
|
884 |
+ ret = messageCreate(); |
|
885 |
+ |
|
886 |
+ for (t = messageGetBody(m); t; t = t->t_next) { |
|
887 |
+ const char *line; |
|
888 |
+ |
|
889 |
+ if (t->t_line) |
|
890 |
+ line = lineGetData(t->t_line); |
|
891 |
+ else |
|
892 |
+ line = NULL; |
|
893 |
+ |
|
894 |
+ if (inHeader) { |
|
895 |
+ cli_dbgmsg("parseEmailHeaders: check '%s'\n", |
|
896 |
+ line ? line : ""); |
|
897 |
+ if (line == NULL) { |
|
898 |
+ /* |
|
899 | 899 |
* A blank line signifies the end of |
900 | 900 |
* the header and the start of the text |
901 | 901 |
*/ |
902 |
- cli_dbgmsg("End of header information\n"); |
|
903 |
- if(!anyHeadersFound) { |
|
904 |
- cli_dbgmsg("Nothing interesting in the header\n"); |
|
905 |
- break; |
|
906 |
- } |
|
907 |
- inHeader = FALSE; |
|
908 |
- bodyIsEmpty = TRUE; |
|
909 |
- } else { |
|
910 |
- char *ptr; |
|
911 |
- |
|
912 |
- if(fullline == NULL) { |
|
913 |
- char cmd[RFC2821LENGTH + 1]; |
|
914 |
- |
|
915 |
- /* |
|
902 |
+ cli_dbgmsg("End of header information\n"); |
|
903 |
+ if (!anyHeadersFound) { |
|
904 |
+ cli_dbgmsg("Nothing interesting in the header\n"); |
|
905 |
+ break; |
|
906 |
+ } |
|
907 |
+ inHeader = FALSE; |
|
908 |
+ bodyIsEmpty = TRUE; |
|
909 |
+ } else { |
|
910 |
+ char *ptr; |
|
911 |
+ |
|
912 |
+ if (fullline == NULL) { |
|
913 |
+ char cmd[RFC2821LENGTH + 1]; |
|
914 |
+ |
|
915 |
+ /* |
|
916 | 916 |
* Continuation of line we're ignoring? |
917 | 917 |
*/ |
918 |
- if(isblank(line[0])) |
|
919 |
- continue; |
|
918 |
+ if (isblank(line[0])) |
|
919 |
+ continue; |
|
920 | 920 |
|
921 |
- /* |
|
921 |
+ /* |
|
922 | 922 |
* Is this a header we're interested in? |
923 | 923 |
*/ |
924 |
- if((strchr(line, ':') == NULL) || |
|
925 |
- (cli_strtokbuf(line, 0, ":", cmd) == NULL)) { |
|
926 |
- if(strncmp(line, "From ", 5) == 0) |
|
927 |
- anyHeadersFound = TRUE; |
|
928 |
- continue; |
|
929 |
- } |
|
930 |
- |
|
931 |
- ptr = rfc822comments(cmd, NULL); |
|
932 |
- commandNumber = tableFind(rfc821, ptr ? ptr : cmd); |
|
933 |
- if(ptr) |
|
934 |
- free(ptr); |
|
935 |
- |
|
936 |
- switch(commandNumber) { |
|
937 |
- case CONTENT_TRANSFER_ENCODING: |
|
938 |
- case CONTENT_DISPOSITION: |
|
939 |
- case CONTENT_TYPE: |
|
940 |
- anyHeadersFound = TRUE; |
|
941 |
- break; |
|
942 |
- default: |
|
943 |
- if(!anyHeadersFound) |
|
944 |
- anyHeadersFound = usefulHeader(commandNumber, cmd); |
|
945 |
- continue; |
|
946 |
- } |
|
947 |
- fullline = cli_strdup(line); |
|
948 |
- fulllinelength = strlen(line) + 1; |
|
949 |
- } else if(line) { |
|
950 |
- fulllinelength += strlen(line) + 1; |
|
951 |
- ptr = cli_realloc(fullline, fulllinelength); |
|
952 |
- if(ptr == NULL) |
|
953 |
- continue; |
|
954 |
- fullline = ptr; |
|
955 |
- cli_strlcat(fullline, line, fulllinelength); |
|
956 |
- } |
|
957 |
- assert(fullline != NULL); |
|
958 |
- |
|
959 |
- if(next_is_folded_header(t)) |
|
960 |
- /* Add arguments to this line */ |
|
961 |
- continue; |
|
962 |
- |
|
963 |
- lineUnlink(t->t_line); |
|
964 |
- t->t_line = NULL; |
|
965 |
- |
|
966 |
- if(count_quotes(fullline) & 1) |
|
967 |
- continue; |
|
968 |
- |
|
969 |
- ptr = rfc822comments(fullline, NULL); |
|
970 |
- if(ptr) { |
|
971 |
- free(fullline); |
|
972 |
- fullline = ptr; |
|
973 |
- } |
|
974 |
- |
|
975 |
- if(parseEmailHeader(ret, fullline, rfc821) < 0) |
|
976 |
- continue; |
|
977 |
- |
|
978 |
- free(fullline); |
|
979 |
- fullline = NULL; |
|
980 |
- } |
|
981 |
- } else { |
|
982 |
- if(bodyIsEmpty) { |
|
983 |
- if(line == NULL) |