ze-filter  (ze-filter-0.8.0-develop-180218)
ze-scanmail.c
Go to the documentation of this file.
1 
2 /*
3  *
4  * ze-filter - Mail Server Filter for sendmail
5  *
6  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
7  *
8  * Auteur : Jose Marcio Martins da Cruz
9  * jose.marcio.mc@gmail.org
10  *
11  * Historique :
12  * Creation : janvier 2002
13  *
14  * This program is free software, but with restricted license :
15  *
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.
20  *
21  * More details about ze-filter license can be found at ze-filter
22  * web site : http://foss.jose-marcio.org
23  */
24 
25 #include <ze-sys.h>
26 
27 #include "ze-filter.h"
28 
29 #define SZ_P 65536
30 #define SZ_FREE 8192
31 #define SZ_WORK (SZ_P + SZ_FREE + 1)
32 
33 #ifndef TRUE
34 #define TRUE 1
35 #define FALSE 0
36 #endif
37 
38 /* ****************************************************************************
39  * *
40  * *
41  **************************************************************************** */
42 int new_scan_block(char *, char *, long, char *, long,
43  int *, content_field_T *,
44  content_field_T **);
45 
46 int old_scan_block(char *, char *, long, char *, long,
47  int *, content_field_T *,
48  content_field_T **);
49 
50 int
51 scan_block(id, chunk, sz_chunk, new, sz_new, state, content, list)
52  char *id;
53  char *chunk;
54  long sz_chunk;
55  char *new;
56  long sz_new;
57  int *state;
58  content_field_T *content;
59  content_field_T **list;
60 {
61 #if _FFR_NEW_SCAN_BLOCK
62  return new_scan_block(id, chunk, sz_chunk, new, sz_new, state, content, list);
63 #else
64  return old_scan_block(id, chunk, sz_chunk, new, sz_new, state, content, list);
65 #endif
66 }
67 
68 /* ****************************************************************************
69  * *
70  * *
71  **************************************************************************** */
72 
73 #ifndef MAX
74 #define MAX(a,b) ((a) > (b) ? (a) : (b))
75 #endif /* MAX */
76 #define MAX2(a,b) MAX((a),(b))
77 #define MAX3(a,b,c) MAX(a, MAX((b),(c)))
78 #define MAX4(a,b,c,d) MAX(MAX((a),(b)), MAX((c),(d)))
79 
80 #ifndef MIN
81 #define MIN(a,b) ((a) < (b) ? (a) : (b))
82 #endif /* MIN */
83 #define MIN2(a,b) MIN((a),(b))
84 #define MIN3(a,b,c) MIN(a, MIN((b),(c)))
85 #define MIN4(a,b,c,d) MIN(MIN((a),(b)), MIN((c),(d)))
86 
87 /* ****************************************************************************
88  * *
89  * *
90  **************************************************************************** */
91 long
92 min4(a, b, c, d)
93  long a;
94  long b;
95  long c;
96  long d;
97 {
98  long r = a;
99 
100  if (b < r)
101  r = b;
102  if (c < r)
103  r = c;
104  if (d < r)
105  r = d;
106  return r;
107 }
108 
109 /* ****************************************************************************
110  * *
111  * *
112  **************************************************************************** */
113 long
114 min3(a, b, c)
115  long a;
116  long b;
117  long c;
118 {
119  long r = a;
120 
121  if (b < r)
122  r = b;
123  if (c < r)
124  r = c;
125  return r;
126 }
127 
128 
129 /* ****************************************************************************
130  * *
131  * *
132  **************************************************************************** */
133 void
135  char *fname;
136 {
137  char *p, *q;
138 
139  if (fname == NULL)
140  return;
141 
142  p = q = fname;
143 
144  while (*p) {
145  switch (*p) {
146  case '"':
147  case '\r':
148  case '\n':
149  case '\t':
150  break;
151  default:
152  *q++ = *p;
153  }
154  p++;
155  }
156  *q = '\0';
157 }
158 
159 /* ****************************************************************************
160  * *
161  * *
162  **************************************************************************** */
163 
164 #define MAX_LINE 4096
165 
166 #define REGCOMP_FLAGS (REG_ICASE | REG_NEWLINE | REG_EXTENDED)
167 #if 0
168 #define REGEXEC_FLAGS (REG_NOTBOL | REG_NOTEOL)
169 #else
170 #define REGEXEC_FLAGS (0)
171 #endif
172 
173 #if 1
174 #define RE_CT "Content-type[ \t]*:"
175 #define RE_CD "Content-disposition[ \t]*:"
176 #else
177 #define RE_CT "^Content-type[ \t]*:"
178 #define RE_CD "^Content-disposition[ \t]*:"
179 #endif
180 
181 #if 1
182 #define RE_UU "^begin(-base64){0,1}[ \t]{1,}[0]{0,1}[0-7]{3,3}[ \t]{1,}[^\t\r\n]{1,}"
183 #else
184 #define RE_UU "^begin(-base64)?[ \t]{1,}[0]?[0-7]{3,3}[ \t]{1,}[^\t\r\n]{1,}"
185 #endif
186 
187 typedef struct REGEX_T {
188  bool ok;
189  pthread_mutex_t mutex;
190 
191  regex_t re_ct;
192  regex_t re_cd;
193  regex_t re_uu;
194 } REGEX_T;
195 
196 static REGEX_T RE = { FALSE, PTHREAD_MUTEX_INITIALIZER };
197 
198 #define SCAN_REGEX_LOCK() MUTEX_LOCK(&RE.mutex)
199 #define SCAN_REGEX_UNLOCK() MUTEX_UNLOCK(&RE.mutex)
200 
201 /* ****************************************************************************
202  * *
203  * *
204  **************************************************************************** */
205 static bool
206 init_regex()
207 {
208  SCAN_REGEX_LOCK();
209 
210  if (!RE.ok) {
211  int r = 0;
212  bool ok = TRUE;
213  char sout[256];
214 
215  memset(sout, 0, sizeof (sout));
216  if ((r = regcomp(&RE.re_ct, RE_CT, REGCOMP_FLAGS)) != 0) {
217  regerror(r, &RE.re_ct, sout, sizeof (sout));
218  ZE_LogMsgError(0, "regcomp error : %d %s", r, sout);
219  ok = FALSE;
220  }
221 
222  if ((r = regcomp(&RE.re_cd, RE_CD, REGCOMP_FLAGS)) != 0) {
223  regerror(r, &RE.re_cd, sout, sizeof (sout));
224  ZE_LogMsgError(0, "regcomp error : %d %s", r, sout);
225  ok = FALSE;
226  }
227 
228  if ((r = regcomp(&RE.re_uu, RE_UU, REGCOMP_FLAGS)) != 0) {
229  regerror(r, &RE.re_uu, sout, sizeof (sout));
230  ZE_LogMsgError(0, "regcomp error : %d %s", r, sout);
231  ok = FALSE;
232  }
233 
234  if (!ok) {
235  regfree(&RE.re_ct);
236  regfree(&RE.re_cd);
237  regfree(&RE.re_uu);
238  }
239 
240  RE.ok = ok;
241  }
243 
244  return RE.ok;
245 }
246 
247 static bool
248 regex_lookup(re, buf, pi, pf)
249  regex_t *re;
250  char *buf;
251  size_t *pi;
252  size_t *pf;
253 {
254  regmatch_t pm;
255  bool ok = FALSE;
256 
257  if (re == NULL)
258  return FALSE;
259  if (buf == NULL)
260  return FALSE;
261 
262  SCAN_REGEX_LOCK();
263  if ((ok = (regexec(re, buf, 1, &pm, REGEXEC_FLAGS) == 0)) == TRUE) {
264  if (pi != NULL)
265  *pi = pm.rm_so;
266  if (pf != NULL)
267  *pf = pm.rm_eo;
268  }
270 
271  return ok;
272 }
273 
274 /* ****************************************************************************
275  * *
276  * *
277  **************************************************************************** */
278 #define MALLOC_WORK 1
279 int
280 old_scan_block(id, chunk, sz_chunk, new, sz_new, state, content, list)
281  char *id;
282  char *chunk;
283  long sz_chunk;
284  char *new;
285  long sz_new;
286  int *state;
287  content_field_T *content;
288  content_field_T **list;
289 {
290  int result = 0;
291 
292 #if MALLOC_WORK == 1
293  char *work = NULL;
294 #else
295  char work[SZ_WORK];
296 #endif
297  char *p;
298  int szc, nok;
299  char old[SZ_CHUNK];
300  int i;
301 
302  if (id == NULL)
303  id = "";
304 
305  if (!RE.ok) {
306  ZE_LogMsgInfo(11, "Initialising REGEX structure");
307  if (!init_regex()) {
308  ZE_LogMsgError(0, "Unable to initialise REGEX structure");
309  return 9;
310  }
311  }
312 
313  nok = 0;
314 
315  p = new;
316  for (i = sz_new; i > 0; i--, p++) {
317  if (*p == '\0')
318  *p = ' ';
319  }
320 
321  memset(old, 0, sizeof (old));
322  strncpy(old, chunk, sizeof (old) - 1);
323 
324 #if MALLOC_WORK == 1
325  if ((work = malloc(SZ_WORK + 1)) == NULL) {
326  ZE_LogSysError("%-12s : malloc work error", id);
327  return 15;
328  }
329 #endif
330 
331  memset(work, 0, SZ_WORK + 1);
332  while (nok < sz_new) {
333  char *last_rc;
334 
335  if (strlen(old) > SZ_WORK) {
336  ZE_LogMsgNotice(0, "%-12s scan_block : strlen(old) = %ld", id,
337  (long) strlen(old));
338  *old = '\0';
339  result = 3;
340  break;
341  }
342  strlcpy(work, old, SZ_WORK);
343  p = work + strlen(work);
344  memset(old, 0, sizeof (old));
345  *old = '\0';
346 
347  /*
348  * a revoir ...
349  */
350  szc = (sz_new - nok) >= SZ_P ? SZ_P : sz_new - nok;
351 
352  if (strlen(work) + szc > SZ_WORK) {
353  /*
354  * Feb 24 00:30:08 paris ze-filter[19028]: [ID 447404 local5.warning] scan_block :
355  * strlen(work) + szc = 130975
356  * Feb 24 00:30:08 paris sendmail[17502]: [ID 801593 mail.error] g1NNU6WZ017502:
357  * milter_read(ze-filter): cmd read returned 0, expecting 5
358  */
359  ZE_LogMsgNotice(0, "%-12s scan_block : strlen(work) + szc = %ld, %ld",
360  id, (long) (strlen(work) + szc), (long) szc);
361  last_rc = NULL;
362  result = 4;
363  break;
364  }
365  memcpy(p, new + nok, szc);
366  nok += szc;
367  p[szc] = '\0';
368 
369  if (strcspn(p, "\r\n") > SZ_FREE) {
370  ZE_LogMsgNotice(0, "%-12s scan_block : trying a buffer overflow ??? "
371  "linelenght : %ld; strlen : %ld", id, (long) strcspn(p,
372  "\r\n"),
373  (long) strlen(p));
374 
375  last_rc = NULL;
376  result = 5;
377  break;
378  }
379 
380  /*
381  * trouver le dernier NL
382  */
383  last_rc = strrchr(work, '\n');
384  /*
385  * s'il n'y a pas de NL, on cherche le dernier RC
386  */
387  if (last_rc == NULL)
388  last_rc = strrchr(work, '\r');
389 
390  /*
391  * separer le buffer en deux : avant et apres le RC
392  */
393  if (last_rc != NULL)
394  *last_rc = '\0';
395 
396  if (last_rc == NULL && strlen(work) > SZ_P) {
397  ZE_LogMsgError(0, "ERROR : scanmail strlen(work) = %ld result = 6",
398  (long) strlen(work));
399  result = 6;
400  break;
401  }
402 
403  /*
404  * traiter la premiere partie
405  */
406  p = work;
407  while (result == 0) {
408  long d1, d2, d3, d4, d;
409  char sout[MAX_LINE];
410 
411  if (p == NULL || *p == '\0')
412  break;
413 
414  /*
415  ** ST_INIT
416  */
417  if (*state == ST_INIT) {
418  regmatch_t pm_cd, pm_ct, pm_uu;
419  bool ok_cd, ok_ct, ok_uu;
420 
421  ZE_MessageDebug(20, "STATE ---> ST_INIT");
422 
423  if (content->field_type != CT_NONE)
424  save_content_field(content, list);
425 
426  SCAN_REGEX_LOCK();
427  ok_cd = (regexec(&RE.re_cd, p, 1, &pm_cd, REGEXEC_FLAGS) == 0);
428  ok_ct = (regexec(&RE.re_ct, p, 1, &pm_ct, REGEXEC_FLAGS) == 0);
429  ok_uu = (regexec(&RE.re_uu, p, 1, &pm_uu, REGEXEC_FLAGS) == 0);
431 
432  if (ok_uu) {
433  long duu, dcd, dct;
434 
435  duu = pm_uu.rm_so;
436  dcd = LONG_MAX;
437  dct = LONG_MAX;
438  if (ok_cd)
439  dcd = pm_cd.rm_so;
440  if (ok_ct)
441  dct = pm_ct.rm_so;
442  if (min3(duu, dcd, dct) == duu) {
443  char *t = sout;
444  char fname[MAX_LINE];
445 
446  /*
447  * XXX
448  */
449  zeSafeStrnCpy(sout, sizeof (sout), &p[pm_uu.rm_so],
450  pm_uu.rm_eo - pm_uu.rm_so);
451  t += strcspn(t, " \t");
452  t += strspn(t, " \t");
453  t += strcspn(t, " \t");
454  t += strspn(t, " \t");
455  memset(fname, 0, sizeof (fname));
456  /*
457  * XXX
458  */
459  zeSafeStrnCpy(fname, sizeof (fname), t, strcspn(t, " \t\r\n"));
460 
461  ZE_MessageInfo(10, "fname : %s", fname);
462  if (is_rfc2047_encoded(fname)) {
463  char tmp[MAX_LINE];
464 
465  decode_rfc2047(tmp, fname, sizeof (tmp));
466  strlcpy(fname, tmp, sizeof (fname));
467 
468  ZE_MessageInfo(19, "fname 2047 : %s", fname);
469  }
470  if (is_rfc2231_encoded(fname)) {
471  char tmp[MAX_LINE];
472 
473  decode_rfc2231(tmp, fname, sizeof (tmp));
474  strlcpy(fname, tmp, sizeof (fname));
475 
476  ZE_MessageInfo(19, "fname 2231 : %s", fname);
477  }
478  content->field_type = CT_UUFILE;
479  content->value = strdup(fname);
480  if (content->value == NULL) {
481  ZE_LogSysError("Error strdup CT_UUFILE %s", fname);
482  }
483  p += pm_uu.rm_eo;
484  continue;
485  }
486  }
487 
488  if (ok_cd || ok_ct) {
489  int pi = 0;
490 
491  *state = ST_VALUE;
492  if (ok_cd) {
493  pi = pm_cd.rm_eo;
494  content->field_type = CT_DISP;
495  }
496  if (ok_ct) {
497  pi = pm_ct.rm_eo;
498  content->field_type = CT_TYPE;
499  }
500  if (ok_ct && ok_cd) {
501  if (pm_cd.rm_eo < pm_ct.rm_eo) {
502  pi = pm_cd.rm_eo;
503  content->field_type = CT_DISP;
504  } else {
505  pi = pm_ct.rm_eo;
506  content->field_type = CT_TYPE;
507  }
508  }
509  p += pi;
510  continue;
511  } else {
512  p += strlen(p);
513  break;
514  }
515  }
516 
517  /*
518  ** ST_VALUE
519  */
520  if (*state == ST_VALUE) {
521  ZE_MessageDebug(20, "STATE ---> ST_VALUE");
522  p += strspn(p, " \t\r\n");
523  if (*p == '\0')
524  break;
525 
526  d = strcspn(p, " \t\r\n;");
527  if (d >= sizeof (sout))
528  ZE_LogMsgNotice(0, "%-12s scan_block : d >= sizeof(sout) = %ld", id,
529  d);
530  d = zeSafeStrnCpy(sout, sizeof (sout), p, d);
531  /*
532  * sout[d] = '\0';
533  */
534  p += d;
535 
536  while (*state == ST_VALUE) {
537  /*
538  * end of buffer
539  */
540  if (*p == '\0') {
541  *state = ST_CHECK;
542  break;
543  }
544  /*
545  * end of line
546  */
547  if ((d = strspn(p, "\r\n")) > 0) {
548  p += d;
549  *state = ST_CHECK;
550  break;
551  }
552  /*
553  * another attribute
554  */
555  if ((d = strcspn(p, ";")) == 0) {
556  p++;
557  *state = ST_TOKEN;
558  break;
559  }
560  if ((d = strspn(p, " \t;")) > 0) {
561  d1 = strspn(p, " \t");
562  d2 = strspn(p, " \t;");
563  d3 = strspn(p, " \t\r\n");
564  d4 = strlen(p);
565 
566  /*
567  * XXX
568  */
569  d = min4(d1, d2, d3, d4);
570  if (d == d4) {
571  *state = ST_CHECK;
572  break;
573  }
574  if (d == d3) {
575  p += d;
576  *state = ST_CHECK;
577  break;
578  }
579  if (d == d2) {
580  p += d;
581  *state = ST_TOKEN;
582  break;
583  }
584  d = strlen(sout);
585  /*
586  * XXX a voir - JOE 31/01/02
587  */
588  if (d + d1 < sizeof (sout)) {
589  strncat(sout, p, d1);
590  sout[d + d1] = '\0';
591  } else
592  ZE_LogMsgNotice(0,
593  "%-12s scan_block : d + d1 >= sizeof(sout) = %ld",
594  id, d + d1);
595 
596  content->value = strdup(sout);
597  p += d;
598  }
599  *state = ST_INIT;
600  }
601 
602  ZE_MessageDebug(20, " *** TAG : %s", sout);
603 
604  if (content->value != NULL)
605  free(content->value);
606  content->value = strdup(sout);
607  continue;
608  }
609 
610  /*
611  ** ST_CHECK
612  */
613  if (*state == ST_CHECK) {
614  ZE_MessageDebug(20, "STATE ---> ST_CHECK");
615  d = strspn(p, " \t\r\n");
616  p += d;
617  if (*p == '\0') {
618  *state = ST_CHECK;
619  continue;
620  }
621  if (*p == ';') {
622  p++;
623  *state = ST_TOKEN;
624  continue;
625  }
626  *state = ST_INIT;
627  continue;
628  }
629 
630  /*
631  ** ST_TOKEN
632  */
633  if (*state == ST_TOKEN) {
634  char name[MAX_LINE];
635  char value[MAX_LINE];
636 
637  ZE_MessageDebug(20, "STATE ---> ST_TOKEN");
638  p += strspn(p, " \t\r\n");
639  if (*p == '\0')
640  continue;
641  d1 = strascii(p, TSPECIALS, "");
642  d2 = strcspn(p, "=");
643  d3 = strascii(p, TSPECIALS, "");
644  /*
645  * 27/07/2004 - bug from some virus - including spaces in tags... 8-(
646  */
647  d4 = strcspn(p, "\t");
648  d = min4(d1, d2, d3, d4);
649  /*
650  * why ???
651  */
652  if (d == strlen(p)) {
653  p += d;
654  continue;
655  }
656  /*
657  * deux champs
658  */
659  if (d == d2) {
660  int rfc2231_code = 0;
661 
662  if (d >= sizeof (name))
663  ZE_LogMsgNotice(0, "%-12s scan_block : d >= sizeof(name) = %ld", id,
664  d);
665  /*
666  * XXX
667  */
668  d = zeSafeStrnCpy(name, sizeof (name), p, d);
669  name[d] = '\0';
670  if (name[d - 1] == '*') {
671  rfc2231_code = 1;
672  name[d - 1] = '\0';
673  }
674  p += d;
675 #if 0
676  p += strspn(p, " ");
677 #endif
678 
679  ZE_MessageDebug(20, " NAME : %s", name);
680 
681  p++;
682  /*
683  * decoder le deuxieme champs
684  */
685  if (*p == '"') {
686  p++;
687  d = strcspn(p, "\"\r\n");
688  } else {
689  int dx = strcspn(p, "; \t\r\n");
690 
691  d = strascii(p, TSPECIALS, "");
692  if (dx > d)
693  d = dx;
694  /*
695  * bug de Klez
696  */
697  if (1) {
698  int da, db;
699 
700  da = strcspn(p, "\r\n");
701  db = strcspn(p, ";\r\n");
702  if (da == db && da > 0 && db > 0) {
703  char tmpstr[MAX_LINE];
704 
705  da = zeSafeStrnCpy(tmpstr, sizeof (tmpstr), p, da);
706  tmpstr[da] = '\0';
707  while (da > 0 && tmpstr[da - 1] == ' ')
708  da--;
709  if (da > d)
710  d = da;
711  }
712  }
713  }
714  if (d >= sizeof (value))
715  ZE_LogMsgNotice(0, "%-12s scan_block : d >= sizeof(value) = %ld",
716  id, d);
717  d = zeSafeStrnCpy(value, sizeof (value), p, d);
718  value[d] = '\0';
719  p += d;
720  if (*p == '"')
721  p++;
722 
723  if (is_rfc2047_encoded(value)) {
724  char sout[1024];
725 
726  decode_rfc2047(sout, value, sizeof (sout));
727  strlcpy(value, sout, sizeof (value));
728  }
729  if (is_rfc2231_encoded(value)) {
730  char sout[1024];
731 
732  decode_rfc2231(sout, value, sizeof (sout));
733  strlcpy(value, sout, sizeof (value));
734  }
735  clean_tag_value(value);
736 
737  ZE_MessageDebug(20, " VALEUR : %s", value);
738  add_content_field_attr(content, name, value);
739  *state = ST_CHECK;
740  continue;
741  }
742 
743  /*
744  * un seul champs
745  */
746  if (d == d4) {
747  if (d >= sizeof (sout))
748  ZE_LogMsgNotice(0, "%-12s scan_block : d >= sizeof(sout) = %ld (2)",
749  id, d);
750  d = zeSafeStrnCpy(sout, sizeof (sout), p, d);
751  sout[d] = '\0';
752 
753  ZE_MessageDebug(20, " NAME : %s ", sout);
754  add_content_field_attr(content, sout, "");
755  p += d;
756  *state = ST_CHECK;
757  continue;
758  }
759  *state = ST_INIT;
760  continue;
761  }
762 
763  break;
764  }
765 
766  /*
767  * retourner le reste dans old
768  */
769  if (last_rc != NULL) {
770  size_t sz;
771 
772  sz = strlen((char *) (last_rc + 1));
773  if (strlen((char *) (last_rc + 1)) >= sizeof (old)) {
774  strlcpy(old, "", sizeof (old));
775  ZE_LogMsgNotice(0, "scan_block : strlen(last_rc + 1) = %ld > SZ_CHUNK",
776  (long) sz);
777  result = 7;
778  break;
779  }
780  strlcpy(old, (char *) (last_rc + 1), sizeof (old));
781  *last_rc = '\n';
782  }
783  }
784 
785  memset(chunk, 0, sz_chunk);
786  if (strlen(old) < sz_chunk)
787  strlcpy(chunk, old, sz_chunk);
788  else
789  ZE_LogMsgNotice(0, "scan_block : sizeof(old) = %ld > SZ_CHUNK",
790  (long) strlen(old));
791 
792 #if MALLOC_WORK == 1
793  if (work != NULL)
794  free(work);
795 #endif
796 
797  ZE_LogMsgInfo(12, "returning %d", result);
798 
799  return result;
800 }
801 
802 
803 /* ****************************************************************************
804  * *
805  * *
806  **************************************************************************** */
807 #define LINESZ 2048
808 
809 #define NRE_CT "Content-type[ \t]*:"
810 #define NRE_CD "Content-disposition[ \t]*:"
811 #define NRE_UU "begin(-base64){0,1}[ \t]{1,}[0]{0,1}[0-7]{3,3}[ \t]{1,}[^\t\r\n]{1,}"
812 
813 struct scan_state_T {
814  char *buf;
815  size_t szbuf;
817  int state;
818 };
819 
820 typedef struct scan_state_T scan_state_T;
821 
822 static bool decode_mime_content_tag(char **, content_field_T *);
823 
824 #if 0
825 static bool decode_uuencoded(char **, content_field_T *);
826 #endif
827 
828 int
829 new_scan_block(id, old, sz_old, new, sz_new, state, content, list)
830  char *id;
831  char *old;
832  long sz_old;
833  char *new;
834  long sz_new;
835  int *state;
836  content_field_T *content;
838 {
839  int result = 0;
840 
841  char *work = NULL;
842  size_t sz_ok;
843  char *wptr, *lastcr;
844 
845  if (id == NULL)
846  id = "";
847 
848  if (!RE.ok) {
849  ZE_LogMsgInfo(10, "Initialising REGEX structure");
850  if (!init_regex()) {
851  ZE_LogMsgError(0, "Unable to initialise REGEX structure");
852  return 9;
853  }
854  }
855 
856  sz_ok = 0;
857 
858  {
859  char *p = new;
860  size_t i;
861 
862  for (i = sz_new; i > 0; i--, p++) {
863  if (*p == '\0')
864  *p = ' ';
865  }
866  }
867 
868  if ((work = malloc(SZ_WORK + 1)) == NULL) {
869  ZE_LogSysError("%-12s : malloc work error", id);
870  return 15;
871  }
872 
873  memset(work, 0, SZ_WORK + 1);
874 
875  while (sz_ok < sz_new) {
876  size_t work_len;
877 
878  work_len = strlen(old);
879  if (work_len > SZ_WORK) {
880  /*
881  ** result = ERROR;
882  ** LOG_MSG_ERROR
883  */
884  break;
885  }
886  strlcpy(work, old, SZ_WORK);
887  memset(old, 0, sz_old);
888 
889  {
890  size_t dx;
891 
892  dx = SZ_WORK - work_len;
893 
894  if (dx < 0);
895  memcpy(work + work_len, new + sz_ok, dx);
896  sz_ok += dx;
897  }
898 
899  wptr = work;
900  while ((lastcr = strrchr(wptr, '\n')) != NULL) {
901  size_t m = 0;
902 
903  if (content->field_type == CT_NONE) {
904  size_t n1, n2, n3;
905  size_t pi, pf;
906 
907  n1 = n2 = n3 = SZ_WORK + 1;
908 
909  if (regex_lookup(&RE.re_uu, wptr, &pi, &pf))
910  n1 = pi;
911  if (regex_lookup(&RE.re_ct, wptr, &pi, &pf))
912  n2 = pi;
913  if (regex_lookup(&RE.re_cd, wptr, &pi, &pf))
914  n3 = pi;
915 
916  ZE_MessageInfo(18, "N = %d %d %d (%d)", n1, n2, n3, SZ_WORK);
917  if ((m = MIN3(n1, n2, n3)) < SZ_WORK) {
918  wptr += m;
919 
920  /*
921  * handle uuencode
922  */
923  if (m == n1) {
924  char *s, *ptr;
925  int i = 0;
926 
927  char fname[MAX_LINE];
928  char line[MAX_LINE];
929 
930  memset(line, 0, sizeof (line));
931 
932  i = strcspn(wptr, "\r\n");
933 
934  if (i >= MAX_LINE) {
935  /*
936  * XXX
937  */
938  }
939 
940  strncpy(line, wptr, i);
941 
942  memset(fname, 0, sizeof (fname));
943 
944  content->field_type = CT_UUFILE;
945 
946  for (s = strtok_r(line, " \t", &ptr), i = 0;
947  s != NULL; s = strtok_r(NULL, " \t", &ptr), i++) {
948  switch (i) {
949  case 0:
950  break;
951  case 1:
952  break;
953  case 2:
954  strlcpy(fname, s, sizeof (fname));
955  break;
956  }
957  }
958 
959  if (strlen(fname) > 0) {
960  if (is_rfc2047_encoded(fname)) {
961  char tmp[MAX_LINE];
962 
963  decode_rfc2047(tmp, fname, sizeof (tmp));
964  strlcpy(fname, tmp, sizeof (fname));
965  }
966  if (is_rfc2231_encoded(fname)) {
967  char tmp[MAX_LINE];
968 
969  decode_rfc2231(tmp, fname, sizeof (tmp));
970  strlcpy(fname, tmp, sizeof (fname));
971  }
972  content->field_type = CT_UUFILE;
973 #if 0
974  content->value = strdup(fname);
975 #else
976  content->value = strdup("attachment/uuencoded");
977 #endif /* 1 */
978  if (content->value == NULL)
979  ZE_LogSysError("Error strdup CT_UUFILE %s", fname);
980 
981  if (!add_content_field_attr(content, "name", fname)) {
982  ZE_LogMsgNotice(0, "add_content_field_attr call error : %s",
983  fname);
984  }
985 
986  save_content_field(content, list);
987  memset(content, 0, sizeof (*content));
988  content->field_type = CT_NONE;
989  }
990 
991  wptr += strcspn(wptr, "\r\n");
992  }
993 
994  /*
995  * handle content-type
996  */
997  if (m == n2) {
998  char *p = strchr(wptr, ':');
999 
1000  if (p != NULL) {
1001  char str[256];
1002  int len;
1003 
1004  content->field_type = CT_TYPE;
1005 
1006  p += strspn(p, ": \t");
1007 
1008  memset(str, 0, sizeof (str));
1009  len = strcspn(p, "; \t\r\n");
1010  if (len >= sizeof (str)) {
1011  /*
1012  * XXX
1013  */
1014  }
1015  strncpy(str, p, len);
1016  ZE_MessageInfo(19, "CT_TYPE : %s", str);
1017  content->value = strdup(str);
1018  if (content->value == NULL) {
1019  /*
1020  * XXX
1021  */
1022  }
1023  p += len;
1024  wptr = p;
1025  } else
1026  wptr++;
1027  }
1028 
1029  /*
1030  * handle content-disposition
1031  */
1032  if (m == n3) {
1033  char *p = strchr(wptr, ':');
1034 
1035  if (p != NULL) {
1036  char str[256];
1037  int len;
1038 
1039  content->field_type = CT_DISP;
1040 
1041  p += strspn(p, ": \t");
1042 
1043  memset(str, 0, sizeof (str));
1044  len = strcspn(p, "; \t\r\n");
1045  if (len >= sizeof (str)) {
1046  /*
1047  * XXX
1048  */
1049  }
1050  strncpy(str, p, len);
1051  ZE_MessageInfo(19, "CT_DISP : %s", str);
1052  content->value = strdup(str);
1053  if (content->value == NULL) {
1054  /*
1055  * XXX
1056  */
1057  }
1058  p += len;
1059  wptr = p;
1060  } else
1061  wptr++;
1062  }
1063  } else {
1064  /*
1065  * nor CD, CT or UUENCODE...
1066  */
1067  if (*lastcr != '\0')
1068  lastcr++;
1069  wptr = lastcr;
1070  break;
1071  }
1072  }
1073  switch (content->field_type) {
1074  case CT_NONE:
1075  break;
1076  case CT_TYPE:
1077  if (decode_mime_content_tag(&wptr, content)) {
1078  save_content_field(content, list);
1079  memset(content, 0, sizeof (*content));
1080  content->field_type = CT_NONE;
1081  }
1082  break;
1083  case CT_DISP:
1084  if (decode_mime_content_tag(&wptr, content)) {
1085  save_content_field(content, list);
1086  memset(content, 0, sizeof (*content));
1087  content->field_type = CT_NONE;
1088  }
1089  break;
1090  case CT_UUFILE:
1091  content->field_type = CT_NONE;
1092  break;
1093  default:
1094  break;
1095  }
1096  }
1097  if (lastcr != NULL) {
1098  if (strlen(lastcr) + 1 <= sz_old)
1099  strlcpy(old, lastcr, sz_old);
1100  else {
1101 
1102  }
1103  } else
1104  *old = '\0';
1105  }
1106 
1107  FREE(work);
1108 
1109  return result;
1110 }
1111 
1112 /* ****************************************************************************
1113  * *
1114  * *
1115  **************************************************************************** */
1116 static void log_mime_attr_value(char *, char *, bool, bool);
1117 
1118 #define CHECK_DOUBLE_NAME(val) do \
1119  { \
1120  int i; \
1121  \
1122  already_there = FALSE; \
1123  for (i = 0; i < 16; i++) \
1124  { \
1125  if (pname[i] != NULL && strcasecmp(pname[i], val) == 0) \
1126  { \
1127  already_there = TRUE; \
1128  break; \
1129  } \
1130  } \
1131  } while (0);
1132 
1133 static bool
1134 decode_mime_content_tag(buf, content)
1135  char **buf;
1136  content_field_T *content;
1137 {
1138  char *p = (char *) *buf, *ps;
1139  char line[LINESZ];
1140  bool done = TRUE;
1141 
1142  if ((buf == NULL) || (strlen(*buf) == 0))
1143  return done;
1144 
1145  /*
1146  ** analysis end when
1147  ** - first character is \n or \r
1148  ** -> end of analysis
1149  ** - first character isn't \t
1150  ** -> end of analysis
1151  ** -> end of tag
1152  */
1153  for (;;) {
1154  char *ptr, *psep;
1155  long pi, pf;
1156  char key[256], val[256];
1157  int n;
1158  bool rfc2047, rfc2231;
1159 
1160  if ((*p == '\r') || (*p == '\n'))
1161  break;
1162 
1163  if (strcspn(p, "\r\n") >= LINESZ) {
1164  /*
1165  * XXX
1166  */
1167  break;
1168  }
1169  ps = p;
1170  p = buf_get_next_line(line, p, LINESZ);
1171  if ((strlen(line) == 0) || ((*line != ';') && (*line != '\t'))) {
1172  p = ps;
1173  break;
1174  }
1175  zeStr2Lower(line);
1177  ptr = line;
1178  ptr += strspn(ptr, " \t");
1179 
1180  ZE_MessageInfo(19, "-> LINE : %s", ptr);
1181 
1182  while ((*ptr == ';') || (strlen(ptr) > 0)) {
1183  bool doublequotes = FALSE;
1184  size_t valLength;
1185 
1186  ZE_MessageInfo(19, "??? %s", ptr);
1187  rfc2047 = rfc2231 = FALSE;
1188  ptr += strspn(ptr, "; \t\r\n");
1189  if (strlen(ptr) == 0)
1190  continue;
1191 
1192  if (zeStrRegex(ptr, "[a-z]*=", &pi, &pf, TRUE))
1193  ZE_MessageInfo(19, "-> TAG : %s", ptr);
1194 
1195  if (strchr(TSPECIALS, *ptr) != NULL) {
1196  ptr++;
1197  continue;
1198  }
1199 
1200  if ((psep = strchr(ptr, '=')) == NULL) {
1201  ptr++;
1202  continue;
1203  }
1204 
1205  n = strspn(ptr, "abcdefghijklmnopqrstuvwxyz");
1206  if (n >= sizeof (key)) {
1207  /*
1208  * XXX
1209  */
1210  break;
1211  }
1212  memset(key, 0, sizeof (key));
1213  strncpy(key, ptr, n);
1214 
1215  ptr += n;
1216 
1217  rfc2231 = strcspn(ptr, "*") < strcspn(ptr, "=");
1218 
1219  ptr += strspn(ptr, " *=");
1220 
1221  /*
1222  * XXX
1223  */
1224  if (*ptr == '"') {
1225  doublequotes = TRUE;
1226  ptr++;
1227  }
1228 
1229  rfc2047 = is_rfc2047_encoded(ptr);
1230  rfc2231 = is_rfc2231_encoded(ptr);
1231 
1232 
1233  if (doublequotes)
1234  valLength = strcspn(ptr, "\"");
1235  else
1236  valLength = strcspn(ptr, TSPECIALS);
1237 
1238  ZE_MessageInfo(9, "valLength %d", valLength);
1239 
1240  if (rfc2047)
1241  decode_rfc2047(val, ptr, sizeof (val));
1242  if (rfc2231)
1243  decode_rfc2231(val, ptr, sizeof (val));
1244 
1245  if (!rfc2047 && !rfc2231) {
1246  if (valLength >= sizeof (val)) {
1247  /*
1248  * XXX
1249  */
1250 
1251  }
1252  strncpy(val, ptr, valLength);
1253  val[valLength] = '\0';
1254  }
1255 
1256  /*
1257  ** Does value field begins with '"' ?
1258  ** - yes
1259  ** - first '"'
1260  ** - end of line
1261  ** - no
1262  ** - first non TSPECIALS
1263  ** - first ;
1264  ** - end of line
1265  ** - some special Klez (many tags without spaces inserted)
1266  */
1267 
1268  log_mime_attr_value(key, val, rfc2047, rfc2231);
1269 
1270  if (!add_content_field_attr(content, key, val)) {
1271  ZE_LogMsgNotice(0, "add_content_field_attr call error : %s", key);
1272  }
1273 
1274  /*
1275  * Cases to check
1276  * ** name=file.ext
1277  * ** name="file.ext"
1278  * ** name = file.ext
1279  * ** name = "file.ext"
1280  * ** name=file name.ext
1281  * ** name = file name.ext
1282  * ** name=file;width=300;toto=name[1].ext
1283  * ** name=file[1].ext
1284  */
1285  if (!doublequotes && !rfc2231 && !rfc2047) {
1286  if (strcasecmp(key, "name") == 0 || strcasecmp(key, "filename") == 0) {
1287  char *pname[16];
1288  bool already_there = FALSE;
1289 
1290  memset(pname, 0, sizeof (pname));
1291 
1292  /*
1293  * name = file name.ext
1294  */
1295  if ((strchr(ptr, ' ') != NULL) && (strchr(ptr, ';') == NULL)) {
1296  pname[0] = ptr;
1297  ZE_MessageInfo(19, "Case 1 detected : %s", ptr);
1298  log_mime_attr_value(key, ptr, FALSE, FALSE);
1299  if (!add_content_field_attr(content, key, ptr)) {
1300  ZE_LogMsgNotice(0, "add_content_field_attr call error : %s", key);
1301  }
1302  }
1303 
1304  /*
1305  * name=file;width=300;toto=name[1].ext
1306  */
1307  if ((strcspn(ptr, ";") < strlen(ptr)) && (strchr(ptr, ' ') == NULL)) {
1308  CHECK_DOUBLE_NAME(ptr);
1309  pname[1] = ptr;
1310  if (!already_there) {
1311  ZE_MessageInfo(19, "Case 2 detected : %s", ptr);
1312  log_mime_attr_value(key, ptr, FALSE, FALSE);
1313  if (!add_content_field_attr(content, key, ptr)) {
1314  ZE_LogMsgNotice(0, "add_content_field_attr call error : %s",
1315  key);
1316  }
1317  }
1318  }
1319 
1320  /*
1321  * name=file;width=300;toto=name[1].ext
1322  */
1323  if (strcspn(ptr, ";") < strlen(ptr)) {
1324  char *pwssep = strstr(ptr, " ;");
1325  char *psepws = strstr(ptr, "; ");
1326 
1327  if ((pwssep == NULL) && (psepws == NULL)) {
1328  CHECK_DOUBLE_NAME(ptr);
1329  pname[2] = ptr;
1330  if (!already_there) {
1331  ZE_MessageInfo(19, "Case 3a detected : %s", ptr);
1332  log_mime_attr_value(key, ptr, FALSE, FALSE);
1333  if (!add_content_field_attr(content, key, ptr)) {
1334  ZE_LogMsgNotice(0, "add_content_field_attr call error : %s",
1335  key);
1336  }
1337  }
1338  }
1339  }
1340 
1341  /*
1342  * name=file[1].ext
1343  */
1344  if (!doublequotes && strcspn(ptr, TSPECIALS) < strlen(ptr)) {
1345  CHECK_DOUBLE_NAME(ptr);
1346  pname[3] = ptr;
1347  if (!already_there) {
1348  ZE_MessageInfo(19, "Case 4 detected : %s", ptr);
1349  log_mime_attr_value(key, ptr, FALSE, FALSE);
1350  if (!add_content_field_attr(content, key, ptr)) {
1351  ZE_LogMsgNotice(0, "add_content_field_attr call error : %s",
1352  key);
1353  }
1354  }
1355  }
1356  }
1357  }
1358 
1359  ptr += valLength;
1360  if (doublequotes)
1361  ptr++;
1362  ZE_MessageInfo(9, " PTR : %s", ptr);
1363  }
1364  }
1365 
1366  if (strlen(p) == 0)
1367  done = FALSE;
1368 
1369  *buf = p;
1370  return done;
1371 }
1372 
1373 /* ****************************************************************************
1374  * *
1375  * *
1376  **************************************************************************** */
1377 #if 0
1378 static bool
1379 decode_uuencoded(buf, content)
1380  char **buf;
1381  content_field_T *content;
1382 {
1383 
1384  return TRUE;
1385 }
1386 #endif
1387 
1388 /* ****************************************************************************
1389  * *
1390  * *
1391  **************************************************************************** */
1392 static void
1393 log_mime_attr_value(key, value, rfc2047, rfc2231)
1394  char *key;
1395  char *value;
1396  bool rfc2047;
1397  bool rfc2231;
1398 {
1399  ZE_MessageInfo(19, " KEY : %s", key);
1400  ZE_MessageInfo(19, " VALUE : %s", value);
1401  ZE_MessageInfo(19, " RFC2231 : %s", STRBOOL(rfc2231, "YES", "NO"));
1402  ZE_MessageInfo(19, " RFC2047 : %s", STRBOOL(rfc2047, "YES", "NO"));
1403 }
void clean_tag_value(char *fname)
Definition: ze-scanmail.c:134
#define SZ_CHUNK
Definition: ze-filter.h:98
#define RE_UU
Definition: ze-scanmail.c:182
regex_t re_ct
Definition: ze-scanmail.c:191
#define STRBOOL(x, t, f)
Definition: macros.h:87
pthread_mutex_t mutex
Definition: ze-scanmail.c:189
#define ST_TOKEN
Definition: ze-scanmail.h:38
#define CT_TYPE
Definition: ze-scanmail.h:32
#define strrchr
Definition: ze-sys.h:219
content_field_T * list
Definition: ze-scanmail.c:816
int scan_block(char *id, char *chunk, long sz_chunk, char *new, long sz_new, int *state, content_field_T *content, content_field_T **list)
Definition: ze-scanmail.c:51
#define FREE(x)
Definition: macros.h:37
int decode_rfc2231(char *, char *, size_t)
Definition: ze-decode.c:200
char * zeStrClearTrailingBlanks(char *)
Definition: zeStrings.c:476
#define REGCOMP_FLAGS
Definition: ze-scanmail.c:166
#define SZ_WORK
Definition: ze-scanmail.c:31
#define ST_CHECK
Definition: ze-scanmail.h:39
#define ZE_LogMsgInfo(level,...)
Definition: zeSyslog.h:110
#define strlcpy
Definition: zeString.h:32
#define ZE_LogMsgError(level,...)
Definition: zeSyslog.h:113
bool zeStrRegex(char *, char *, long *, long *, bool)
Definition: zeStrings.c:544
#define RE_CD
Definition: ze-scanmail.c:175
#define ZE_LogMsgNotice(level,...)
Definition: zeSyslog.h:111
bool ok
Definition: ze-scanmail.c:188
#define SCAN_REGEX_LOCK()
Definition: ze-scanmail.c:198
#define RE_CT
Definition: ze-scanmail.c:174
long min4(long a, long b, long c, long d)
Definition: ze-scanmail.c:92
#define ZE_MessageDebug(level,...)
Definition: zeSyslog.h:89
#define strchr
Definition: ze-sys.h:218
#define MAX_LINE
Definition: ze-scanmail.c:164
bool is_rfc2047_encoded(char *)
Definition: ze-decode.c:38
regex_t re_cd
Definition: ze-scanmail.c:192
struct REGEX_T REGEX_T
#define TSPECIALS
Definition: ze-decode.h:42
#define SZ_FREE
Definition: ze-scanmail.c:30
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
int zeSafeStrnCpy(char *, size_t, char *, size_t)
Definition: zeStrings.c:136
int decode_rfc2047(char *, char *, size_t)
Definition: ze-decode.c:49
#define LINESZ
Definition: ze-scanmail.c:807
content_field_T * save_content_field(content_field_T *, content_field_T **)
Definition: ze-mimelist.c:116
#define memcpy(d, s, n)
Definition: ze-sys.h:224
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
#define CT_NONE
Definition: ze-scanmail.h:31
regex_t re_uu
Definition: ze-scanmail.c:193
char * buf_get_next_line(char *, char *, size_t)
Definition: ze-buffer.c:230
#define TRUE
Definition: ze-scanmail.c:34
#define CT_UUFILE
Definition: ze-scanmail.h:34
int new_scan_block(char *, char *, long, char *, long, int *, content_field_T *, content_field_T **)
Definition: ze-scanmail.c:829
size_t szbuf
Definition: ze-scanmail.c:815
long min3(long a, long b, long c)
Definition: ze-scanmail.c:114
char * zeStr2Lower(char *)
Definition: zeStrings.c:295
#define MIN3(a, b, c)
Definition: ze-scanmail.c:84
#define FALSE
Definition: ze-scanmail.c:35
bool is_rfc2231_encoded(char *)
Definition: ze-decode.c:175
#define SCAN_REGEX_UNLOCK()
Definition: ze-scanmail.c:199
#define CHECK_DOUBLE_NAME(val)
Definition: ze-scanmail.c:1118
#define ST_VALUE
Definition: ze-scanmail.h:37
bool add_content_field_attr(content_field_T *, char *, char *)
Definition: ze-mimelist.c:80
int strascii(char *, char *, char *)
Definition: ze-decode.c:327
#define REGEXEC_FLAGS
Definition: ze-scanmail.c:170
#define CT_DISP
Definition: ze-scanmail.h:33
#define SZ_P
Definition: ze-scanmail.c:29
#define ST_INIT
Definition: ze-scanmail.h:36
int old_scan_block(char *, char *, long, char *, long, int *, content_field_T *, content_field_T **)
Definition: ze-scanmail.c:280