From: Tom Kistner Date: Thu, 2 Dec 2004 16:33:30 +0000 (+0000) Subject: added demime code w/o TNEF X-Git-Url: https://git.exim.org/users/jgh/exim.git/commitdiff_plain/c09b95966e16e092453cdb797c8048579b3585bd added demime code w/o TNEF --- diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index af4472443..b00049e40 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/OS/Makefile-Base,v 1.1.2.2 2004/11/30 15:18:58 tom Exp $ +# $Cambridge: exim/src/OS/Makefile-Base,v 1.1.2.3 2004/12/02 16:33:30 tom Exp $ # This file is the basis of the main makefile for Exim and friends. The # makefile at the top level arranges to build the main makefile by calling @@ -287,7 +287,7 @@ convert4r4: Makefile ../src/convert4r4.src # Targets for final binaries; the main one has a build number which is # updated each time. We don't bother with that for the auxiliaries. -OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o +OBJ_WITH_CONTENT_SCAN = demime.o malware.o mime.o regex.o spam.o spool_mbox.o OBJ_EXIM = acl.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \ directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \ @@ -551,6 +551,7 @@ verify.o: $(HDRS) verify.c # Dependencies for WITH_CONTENT_SCAN modules +demime.o: $(HDRS) demime.c malware.o: $(HDRS) malware.c mime.o: $(HDRS) mime.c regex.o: $(HDRS) regex.c diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 7e2fee1a9..3a1192c2e 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -1,5 +1,5 @@ #!/bin/sh -# $Cambridge: exim/src/scripts/MakeLinks,v 1.1.2.2 2004/11/26 09:24:54 tom Exp $ +# $Cambridge: exim/src/scripts/MakeLinks,v 1.1.2.3 2004/12/02 16:33:30 tom Exp $ # Script to build links for all the exim source files from the system- # specific build directory. It should be run from within that directory. @@ -180,6 +180,9 @@ cd .. ln -s ../src/dbfunctions.h dbfunctions.h ln -s ../src/dbstuff.h dbstuff.h +# WITH_OLD_DEMIME +ln -s ../src/demime.h demime.h +# ln -s ../src/exim.h exim.h ln -s ../src/functions.h functions.h ln -s ../src/globals.h globals.h @@ -204,6 +207,9 @@ ln -s ../src/daemon.c daemon.c ln -s ../src/dbfn.c dbfn.c ln -s ../src/debug.c debug.c ln -s ../src/deliver.c deliver.c +# WITH_OLD_DEMIME +ln -s ../src/demime.c demime.c +# ln -s ../src/directory.c directory.c ln -s ../src/dns.c dns.c ln -s ../src/drtables.c drtables.c diff --git a/src/src/acl.c b/src/src/acl.c index 80ac7f036..1f80ee887 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/acl.c,v 1.5.2.2 2004/11/30 15:18:58 tom Exp $ */ +/* $Cambridge: exim/src/src/acl.c,v 1.5.2.3 2004/12/02 16:33:30 tom Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -38,7 +38,11 @@ enum { ACLC_ACL, ACLC_AUTHENTICATED, ACLC_CONDITION, ACLC_CONTROL, #ifdef WITH_CONTENT_SCAN ACLC_DECODE, #endif - ACLC_DELAY, ACLC_DNSLISTS, ACLC_DOMAINS, ACLC_ENCRYPTED, ACLC_ENDPASS, + ACLC_DELAY, +#ifdef WITH_OLD_DEMIME + ACLC_DEMIME, +#endif + ACLC_DNSLISTS, ACLC_DOMAINS, ACLC_ENCRYPTED, ACLC_ENDPASS, ACLC_HOSTS, ACLC_LOCAL_PARTS, ACLC_LOG_MESSAGE, ACLC_LOGWRITE, #ifdef WITH_CONTENT_SCAN ACLC_MALWARE, @@ -66,7 +70,11 @@ static uschar *conditions[] = { US"acl", US"authenticated", US"condition", #ifdef WITH_CONTENT_SCAN US"decode", #endif - US"delay", US"dnslists", US"domains", US"encrypted", + US"delay", +#ifdef WITH_OLD_DEMIME + US"demime", +#endif + US"dnslists", US"domains", US"encrypted", US"endpass", US"hosts", US"local_parts", US"log_message", US"logwrite", #ifdef WITH_CONTENT_SCAN US"malware", @@ -104,6 +112,9 @@ static uschar cond_expand_at_top[] = { TRUE, /* decode */ #endif TRUE, /* delay */ +#ifdef WITH_OLD_DEMIME + TRUE, /* demime */ +#endif TRUE, /* dnslists */ FALSE, /* domains */ FALSE, /* encrypted */ @@ -143,6 +154,9 @@ static uschar cond_modifiers[] = { FALSE, /* decode */ #endif TRUE, /* delay */ +#ifdef WITH_OLD_DEMIME + FALSE, /* demime */ +#endif FALSE, /* dnslists */ FALSE, /* domains */ FALSE, /* encrypted */ @@ -196,6 +210,17 @@ static unsigned int cond_forbids[] = { #endif 0, /* delay */ + +#ifdef WITH_CONTENT_SCAN + (1<next) } break; +#ifdef WITH_OLD_DEMIME + case ACLC_DEMIME: + rc = demime(&arg); + break; +#endif + case ACLC_DNSLISTS: rc = verify_check_dnsbl(&arg); break; diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index e5e9f08e6..afeaefe2f 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/config.h.defaults,v 1.2.2.2 2004/12/02 09:15:11 tom Exp $ */ +/* $Cambridge: exim/src/src/config.h.defaults,v 1.2.2.3 2004/12/02 16:33:30 tom Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -139,6 +139,7 @@ in config.h unless some value is defined in Local/Makefile. */ #define USE_TDB #define WITH_CONTENT_SCAN +#define WITH_OLD_DEMIME /* Things that are not routinely changed but are nevertheless configurable just in case. */ diff --git a/src/src/demime.c b/src/src/demime.c new file mode 100644 index 000000000..840e6273e --- /dev/null +++ b/src/src/demime.c @@ -0,0 +1,1245 @@ +/* $Cambridge: exim/src/src/demime.c,v 1.1.2.1 2004/12/02 16:33:30 tom Exp $ */ + +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) Tom Kistner 2003-???? */ +/* License: GPL */ + +/* Code for unpacking MIME containers. Called from acl.c. */ + +#include "exim.h" +#ifdef WITH_OLD_DEMIME + +#include "demime.h" + +uschar demime_reason_buffer[1024]; +struct file_extension *file_extensions = NULL; + +int demime(uschar **listptr) { + int sep = 0; + uschar *list = *listptr; + uschar *option; + uschar option_buffer[64]; + unsigned long long mbox_size; + FILE *mbox_file; + uschar defer_error_buffer[1024]; + int demime_rc = 0; + + /* reset found_extension variable */ + found_extension = NULL; + + /* try to find 1st option */ + if ((option = string_nextinlist(&list, &sep, + option_buffer, + sizeof(option_buffer))) != NULL) { + + /* parse 1st option */ + if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) { + /* explicitly no demimeing */ + return FAIL; + }; + } + else { + /* no options -> no demimeing */ + return FAIL; + }; + + /* make sure the eml mbox file is spooled up */ + mbox_file = spool_mbox(&mbox_size); + + if (mbox_file == NULL) { + /* error while spooling */ + log_write(0, LOG_MAIN|LOG_PANIC, + "demime acl condition: error while creating mbox spool file"); + return DEFER; + }; + + /* call demimer if not already done earlier */ + if (!demime_ok) + demime_rc = mime_demux(mbox_file, defer_error_buffer); + + fclose(mbox_file); + + if (demime_rc == DEFER) { + /* temporary failure (DEFER => DEFER) */ + log_write(0, LOG_MAIN, + "demime acl condition: %s", defer_error_buffer); + return DEFER; + }; + + /* set demime_ok to avoid unpacking again */ + demime_ok = 1; + + /* check for file extensions, if there */ + while (option != NULL) { + struct file_extension *this_extension = file_extensions; + + /* Look for the wildcard. If it is found, we always return true. + The user must then use a custom condition to evaluate demime_errorlevel */ + if (Ustrcmp(option,"*") == 0) { + found_extension = NULL; + return OK; + }; + + /* loop thru extension list */ + while (this_extension != NULL) { + if (strcmpic(option, this_extension->file_extension_string) == 0) { + /* found one */ + found_extension = this_extension->file_extension_string; + return OK; + }; + this_extension = this_extension->next; + }; + + /* grab next extension from option list */ + option = string_nextinlist(&list, &sep, + option_buffer, + sizeof(option_buffer)); + }; + + /* nothing found */ + return FAIL; +} + + +/************************************************* +* small hex_str -> integer conversion function * +*************************************************/ + +/* needed for quoted-printable +*/ + +unsigned int mime_hstr_i(uschar *cptr) { + unsigned int i, j = 0; + + while (cptr && *cptr && isxdigit(*cptr)) { + i = *cptr++ - '0'; + if (9 < i) i -= 7; + j <<= 4; + j |= (i & 0x0f); + } + + return(j); +} + + +/************************************************* +* decode quoted-printable chars * +*************************************************/ + +/* gets called when we hit a = + returns: new pointer position + result code in c: + -2 - decode error + -1 - soft line break, no char + 0-255 - char to write +*/ + +uschar *mime_decode_qp(uschar *qp_p,int *c) { + uschar hex[] = {0,0,0}; + int nan = 0; + uschar *initial_pos = qp_p; + + /* advance one char */ + qp_p++; + + REPEAT_FIRST: + if ( (*qp_p == '\t') || (*qp_p == ' ') || (*qp_p == '\r') ) { + /* tab or whitespace may follow + just ignore it, but remember + that this is not a valid hex + encoding any more */ + nan = 1; + qp_p++; + goto REPEAT_FIRST; + } + else if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) { + /* this is a valid hex char, if nan is unset */ + if (nan) { + /* this is illegal */ + *c = -2; + return initial_pos; + } + else { + hex[0] = *qp_p; + qp_p++; + }; + } + else if (*qp_p == '\n') { + /* hit soft line break already, continue */ + *c = -1; + return qp_p; + } + else { + /* illegal char here */ + *c = -2; + return initial_pos; + }; + + if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) { + if (hex[0] > 0) { + hex[1] = *qp_p; + /* do hex conversion */ + *c = mime_hstr_i(hex); + qp_p++; + return qp_p; + } + else { + /* huh ? */ + *c = -2; + return initial_pos; + }; + } + else { + /* illegal char */ + *c = -2; + return initial_pos; + }; + +} + + +/************************************************* +* open new dump file * +*************************************************/ + +/* open new dump file + returns: -2 soft error + or file #, FILE * in f +*/ + +int mime_get_dump_file(uschar *extension, FILE **f, uschar *info) { + uschar file_name[1024]; + int result; + unsigned int file_nr; + uschar default_extension[] = ".com"; + uschar *p; + + if (extension == NULL) + extension = default_extension; + + /* scan the proposed extension. + if it is longer than 4 chars, or + contains exotic chars, use the default extension */ + +/* if (Ustrlen(extension) > 4) { + extension = default_extension; + }; +*/ + + p = extension+1; + + while (*p != 0) { + *p = (uschar)tolower((uschar)*p); + if ( (*p < 97) || (*p > 122) ) { + extension = default_extension; + break; + }; + p++; + }; + + /* find a new file to write to */ + file_nr = 0; + do { + struct stat mystat; + + snprintf(CS file_name,1024,"%s/scan/%s/%s-%05u%s",spool_directory,message_id,message_id,file_nr,extension); + file_nr++; + if (file_nr >= MIME_SANITY_MAX_DUMP_FILES) { + /* max parts reached */ + mime_trigger_error(MIME_ERRORLEVEL_TOO_MANY_PARTS); + break; + }; + result = stat(CS file_name,&mystat); + } + while(result != -1); + + *f = fopen(CS file_name,"w+"); + if (*f == NULL) { + /* cannot open new dump file, disk full ? -> soft error */ + snprintf(CS info, 1024,"unable to open dump file"); + return -2; + }; + + return file_nr; +} + + +/************************************************* +* Find a string in a mime header * +*************************************************/ + +/* Find a string in a mime header, and optionally fill in + the value associated with it into *value + + returns: 0 - nothing found + 1 - found param + 2 - found param + value +*/ + +int mime_header_find(uschar *header, uschar *param, uschar **value) { + uschar *needle; + + needle = strstric(header,param,FALSE); + if (needle != NULL) { + if (value != NULL) { + needle += Ustrlen(param); + if (*needle == '=') { + uschar *value_start; + uschar *value_end; + + value_start = needle + 1; + value_end = strstric(value_start,US";",FALSE); + if (value_end != NULL) { + /* allocate mem for value */ + *value = (uschar *)malloc((value_end - value_start)+1); + if (*value == NULL) + return 0; + + Ustrncpy(*value,value_start,(value_end - value_start)); + (*value)[(value_end - value_start)] = '\0'; + return 2; + }; + }; + }; + return 1; + }; + return 0; +} + + +/************************************************* +* Read a line of MIME input * +*************************************************/ +/* returns status code, one of + MIME_READ_LINE_EOF 0 + MIME_READ_LINE_OK 1 + MIME_READ_LINE_OVERFLOW 2 + + In header mode, the line will be "cooked". +*/ + +int mime_read_line(FILE *f, int mime_demux_mode, uschar *buffer, long *num_copied) { + int c = EOF; + int done = 0; + int header_value_mode = 0; + int header_open_brackets = 0; + + *num_copied = 0; + + while(!done) { + + c = fgetc(f); + if (c == EOF) break; + + /* --------- header mode -------------- */ + if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) { + + /* always skip CRs */ + if (c == '\r') continue; + + if (c == '\n') { + if ((*num_copied) > 0) { + /* look if next char is '\t' or ' ' */ + c = fgetc(f); + if (c == EOF) break; + if ( (c == '\t') || (c == ' ') ) continue; + ungetc(c,f); + }; + /* end of the header, terminate with ';' */ + c = ';'; + done = 1; + }; + + /* skip control characters */ + if (c < 32) continue; + + /* skip whitespace + tabs */ + if ( (c == ' ') || (c == '\t') ) + continue; + + if (header_value_mode) { + /* --------- value mode ----------- */ + /* skip quotes */ + if (c == '"') continue; + + /* leave value mode on ';' */ + if (c == ';') { + header_value_mode = 0; + }; + /* -------------------------------- */ + } + else { + /* -------- non-value mode -------- */ + if (c == '\\') { + /* quote next char. can be used + to escape brackets. */ + c = fgetc(f); + if (c == EOF) break; + } + else if (c == '(') { + header_open_brackets++; + continue; + } + else if ((c == ')') && header_open_brackets) { + header_open_brackets--; + continue; + } + else if ( (c == '=') && !header_open_brackets ) { + /* enter value mode */ + header_value_mode = 1; + }; + + /* skip chars while we are in a comment */ + if (header_open_brackets > 0) + continue; + /* -------------------------------- */ + }; + } + /* ------------------------------------ */ + else { + /* ----------- non-header mode -------- */ + /* break on '\n' */ + if (c == '\n') + done = 1; + /* ------------------------------------ */ + }; + + /* copy the char to the buffer */ + buffer[*num_copied] = (uschar)c; + /* raise counter */ + (*num_copied)++; + + /* break if buffer is full */ + if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1) { + done = 1; + }; + } + + /* 0-terminate */ + buffer[*num_copied] = '\0'; + + if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1) + return MIME_READ_LINE_OVERFLOW; + else + if (c == EOF) + return MIME_READ_LINE_EOF; + else + return MIME_READ_LINE_OK; +} + + +/************************************************* +* Check for a MIME boundary * +*************************************************/ + +/* returns: 0 - no boundary found + 1 - start boundary found + 2 - end boundary found +*/ + +int mime_check_boundary(uschar *line, struct boundary *boundaries) { + struct boundary *thisboundary = boundaries; + uschar workbuf[MIME_SANITY_MAX_LINE_LENGTH+1]; + unsigned int i,j=0; + + /* check for '--' first */ + if (Ustrncmp(line,"--",2) == 0) { + + /* strip tab and space */ + for (i = 2; i < Ustrlen(line); i++) { + if ((line[i] != ' ') && (line[i] != '\t')) { + workbuf[j] = line[i]; + j++; + }; + }; + workbuf[j+1]='\0'; + + while(thisboundary != NULL) { + if (Ustrncmp(workbuf,thisboundary->boundary_string,Ustrlen(thisboundary->boundary_string)) == 0) { + if (Ustrncmp(&workbuf[Ustrlen(thisboundary->boundary_string)],"--",2) == 0) { + /* final boundary found */ + return 2; + }; + return 1; + }; + thisboundary = thisboundary->next; + }; + }; + + return 0; +} + + +/************************************************* +* Check for start of a UUENCODE block * +*************************************************/ + +/* returns 0 for no hit, + >0 for hit +*/ + +int mime_check_uu_start(uschar *line, uschar *uu_file_extension, int *has_tnef) { + + if ( (strncmpic(line,US"begin ",6) == 0)) { + uschar *uu_filename = &line[6]; + + /* skip perms, if present */ + Ustrtoul(&line[6],&uu_filename,10); + + /* advance one char */ + uu_filename++; + + /* This should be the filename. + Check if winmail.dat is present, + which indicates TNEF. */ + if (strncmpic(uu_filename,US"winmail.dat",11) == 0) { + *has_tnef = 1; + }; + + /* reverse to dot if present, + copy up to 4 chars for the extension */ + if (Ustrrchr(uu_filename,'.') != NULL) + uu_filename = Ustrrchr(uu_filename,'.'); + + return sscanf(CS uu_filename, "%4[.0-9A-Za-z]",CS uu_file_extension); + } + else { + /* nothing found */ + return 0; + }; +} + + +/************************************************* +* Decode a uu line * +*************************************************/ + +/* returns number of decoded bytes + -2 for soft errors +*/ + +int warned_about_uudec_line_sanity_1 = 0; +int warned_about_uudec_line_sanity_2 = 0; +long uu_decode_line(uschar *line, uschar **data, long line_len, uschar *info) { + uschar *p; + long num_decoded = 0; + uschar tmp_c; + uschar *work; + int uu_decoded_line_len, uu_encoded_line_len; + + /* allocate memory for data and work buffer */ + *data = (uschar *)malloc(line_len); + if (*data == NULL) { + snprintf(CS info, 1024,"unable to allocate %lu bytes",line_len); + return -2; + }; + + work = (uschar *)malloc(line_len); + if (work == NULL) { + snprintf(CS info, 1024,"unable to allocate %lu bytes",line_len); + return -2; + }; + + memcpy(work,line,line_len); + + /* First char is line length + This is microsofts way of getting it. Scary. */ + if (work[0] < 32) { + /* ignore this line */ + return 0; + } + else { + uu_decoded_line_len = uudec[work[0]]; + }; + + p = &work[1]; + + while (*p > 32) { + *p = uudec[*p]; + p++; + }; + + uu_encoded_line_len = (p - &work[1]); + p = &work[1]; + + /* check that resulting line length is a multiple of 4 */ + if ( ( uu_encoded_line_len % 4 ) != 0) { + if (!warned_about_uudec_line_sanity_1) { + mime_trigger_error(MIME_ERRORLEVEL_UU_MISALIGNED); + warned_about_uudec_line_sanity_1 = 1; + }; + return -1; + }; + + /* check that the line length matches */ + if ( ( (((uu_encoded_line_len/4)*3)-2) > uu_decoded_line_len ) || (((uu_encoded_line_len/4)*3) < uu_decoded_line_len) ) { + if (!warned_about_uudec_line_sanity_2) { + mime_trigger_error(MIME_ERRORLEVEL_UU_LINE_LENGTH); + warned_about_uudec_line_sanity_2 = 1; + }; + return -1; + }; + + while ( ((p - &work[1]) < uu_encoded_line_len) && (num_decoded < uu_decoded_line_len)) { + + /* byte 0 ---------------------- */ + if ((p - &work[1] + 1) >= uu_encoded_line_len) { + return 0; + } + + (*data)[num_decoded] = *p; + (*data)[num_decoded] <<= 2; + + tmp_c = *(p+1); + tmp_c >>= 4; + (*data)[num_decoded] |= tmp_c; + + num_decoded++; + p++; + + /* byte 1 ---------------------- */ + if ((p - &work[1] + 1) >= uu_encoded_line_len) { + return 0; + } + + (*data)[num_decoded] = *p; + (*data)[num_decoded] <<= 4; + + tmp_c = *(p+1); + tmp_c >>= 2; + (*data)[num_decoded] |= tmp_c; + + num_decoded++; + p++; + + /* byte 2 ---------------------- */ + if ((p - &work[1] + 1) >= uu_encoded_line_len) { + return 0; + } + + (*data)[num_decoded] = *p; + (*data)[num_decoded] <<= 6; + + (*data)[num_decoded] |= *(p+1); + + num_decoded++; + p+=2; + + }; + + return uu_decoded_line_len; +} + + +/************************************************* +* Decode a b64 or qp line * +*************************************************/ + +/* returns number of decoded bytes + -1 for hard errors + -2 for soft errors +*/ + +int warned_about_b64_line_length = 0; +int warned_about_b64_line_sanity = 0; +int warned_about_b64_illegal_char = 0; +int warned_about_qp_line_sanity = 0; +long mime_decode_line(int mime_demux_mode,uschar *line, uschar **data, long max_data_len, uschar *info) { + uschar *p; + long num_decoded = 0; + int offset = 0; + uschar tmp_c; + + /* allocate memory for data */ + *data = (uschar *)malloc(max_data_len); + if (*data == NULL) { + snprintf(CS info, 1024,"unable to allocate %lu bytes",max_data_len); + return -2; + }; + + if (mime_demux_mode == MIME_DEMUX_MODE_BASE64) { + /* ---------------------------------------------- */ + + /* NULL out trailing '\r' and '\n' chars */ + while (Ustrrchr(line,'\r') != NULL) { + *(Ustrrchr(line,'\r')) = '\0'; + }; + while (Ustrrchr(line,'\n') != NULL) { + *(Ustrrchr(line,'\n')) = '\0'; + }; + + /* check maximum base 64 line length */ + if (Ustrlen(line) > MIME_SANITY_MAX_B64_LINE_LENGTH ) { + if (!warned_about_b64_line_length) { + mime_trigger_error(MIME_ERRORLEVEL_B64_LINE_LENGTH); + warned_about_b64_line_length = 1; + }; + }; + + p = line; + offset = 0; + while (*(p+offset) != '\0') { + /* hit illegal char ? */ + if (b64[*(p+offset)] == 128) { + if (!warned_about_b64_illegal_char) { + mime_trigger_error(MIME_ERRORLEVEL_B64_ILLEGAL_CHAR); + warned_about_b64_illegal_char = 1; + }; + offset++; + } + else { + *p = b64[*(p+offset)]; + p++; + }; + }; + *p = 255; + + /* check that resulting line length is a multiple of 4 */ + if ( ( (p - &line[0]) % 4 ) != 0) { + if (!warned_about_b64_line_sanity) { + mime_trigger_error(MIME_ERRORLEVEL_B64_MISALIGNED); + warned_about_b64_line_sanity = 1; + }; + }; + + /* line is translated, start bit shifting */ + p = line; + num_decoded = 0; + + while(*p != 255) { + + /* byte 0 ---------------------- */ + if (*(p+1) == 255) { + break; + } + + (*data)[num_decoded] = *p; + (*data)[num_decoded] <<= 2; + + tmp_c = *(p+1); + tmp_c >>= 4; + (*data)[num_decoded] |= tmp_c; + + num_decoded++; + p++; + + /* byte 1 ---------------------- */ + if (*(p+1) == 255) { + break; + } + + (*data)[num_decoded] = *p; + (*data)[num_decoded] <<= 4; + + tmp_c = *(p+1); + tmp_c >>= 2; + (*data)[num_decoded] |= tmp_c; + + num_decoded++; + p++; + + /* byte 2 ---------------------- */ + if (*(p+1) == 255) { + break; + } + + (*data)[num_decoded] = *p; + (*data)[num_decoded] <<= 6; + + (*data)[num_decoded] |= *(p+1); + + num_decoded++; + p+=2; + + }; + return num_decoded; + /* ---------------------------------------------- */ + } + else if (mime_demux_mode == MIME_DEMUX_MODE_QP) { + /* ---------------------------------------------- */ + p = line; + + while (*p != 0) { + if (*p == '=') { + int decode_qp_result; + + p = mime_decode_qp(p,&decode_qp_result); + + if (decode_qp_result == -2) { + /* Error from decoder. p is unchanged. */ + if (!warned_about_qp_line_sanity) { + mime_trigger_error(MIME_ERRORLEVEL_QP_ILLEGAL_CHAR); + warned_about_qp_line_sanity = 1; + }; + (*data)[num_decoded] = '='; + num_decoded++; + p++; + } + else if (decode_qp_result == -1) { + /* End of the line with soft line break. + Bail out. */ + goto QP_RETURN; + } + else if (decode_qp_result >= 0) { + (*data)[num_decoded] = decode_qp_result; + num_decoded++; + }; + } + else { + (*data)[num_decoded] = *p; + num_decoded++; + p++; + }; + }; + QP_RETURN: + return num_decoded; + /* ---------------------------------------------- */ + }; + + return 0; +} + + + +/************************************************* +* Log demime errors and set mime error level * +*************************************************/ + +/* This sets the global demime_reason expansion +variable and the demime_errorlevel gauge. */ + +void mime_trigger_error(int level, uschar *format, ...) { + char *f; + va_list ap; + + if( (f = malloc(16384+23)) != NULL ) { + /* first log the incident */ + sprintf(f,"demime acl condition: "); + f+=22; + va_start(ap, format); + vsnprintf(f, 16383,(char *)format, ap); + va_end(ap); + f-=22; + log_write(0, LOG_MAIN, f); + /* then copy to demime_reason_buffer if new + level is greater than old level */ + if (level > demime_errorlevel) { + demime_errorlevel = level; + Ustrcpy(demime_reason_buffer, US f); + demime_reason = demime_reason_buffer; + }; + free(f); + }; +} + +/************************************************* +* Demultiplex MIME stream. * +*************************************************/ + +/* We can handle BASE64, QUOTED-PRINTABLE, and UUENCODE. + UUENCODE does not need to have a proper + transfer-encoding header, we detect it with "begin" + + This function will report human parsable errors in + *info. + + returns DEFER -> soft error (see *info) + OK -> EOF hit, all ok +*/ + +int mime_demux(FILE *f, uschar *info) { + int mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS; + int uu_mode = MIME_UU_MODE_OFF; + FILE *mime_dump_file = NULL; + FILE *uu_dump_file = NULL; + uschar *line; + int mime_read_line_status = MIME_READ_LINE_OK; + long line_len; + struct boundary *boundaries = NULL; + struct mime_part mime_part_p; + int has_tnef = 0; + int has_rfc822 = 0; + + /* allocate room for our linebuffer */ + line = (uschar *)malloc(MIME_SANITY_MAX_LINE_LENGTH); + if (line == NULL) { + snprintf(CS info, 1024,"unable to allocate %u bytes",MIME_SANITY_MAX_LINE_LENGTH); + return DEFER; + }; + + /* clear MIME header structure */ + memset(&mime_part_p,0,sizeof(mime_part)); + + /* ----------------------- start demux loop --------------------- */ + while (mime_read_line_status == MIME_READ_LINE_OK) { + + /* read a line of input. Depending on the mode we are in, + the returned format will differ. */ + mime_read_line_status = mime_read_line(f,mime_demux_mode,line,&line_len); + + if (mime_read_line_status == MIME_READ_LINE_OVERFLOW) { + mime_trigger_error(MIME_ERRORLEVEL_LONG_LINE); + /* despite the error, continue .. */ + mime_read_line_status = MIME_READ_LINE_OK; + continue; + } + else if (mime_read_line_status == MIME_READ_LINE_EOF) { + break; + }; + + if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) { + /* -------------- header mode --------------------- */ + + /* Check for an empty line, which is the end of the headers. + In HEADER mode, the line is returned "cooked", with the + final '\n' replaced by a ';' */ + if (line_len == 1) { + int tmp; + + /* We have reached the end of the headers. Start decoding + with the collected settings. */ + if (mime_part_p.seen_content_transfer_encoding > 1) { + mime_demux_mode = mime_part_p.seen_content_transfer_encoding; + } + else { + /* default to plain mode if no specific encoding type found */ + mime_demux_mode = MIME_DEMUX_MODE_PLAIN; + }; + + /* open new dump file */ + tmp = mime_get_dump_file(mime_part_p.extension, &mime_dump_file, info); + if (tmp < 0) { + return DEFER; + }; + + /* clear out mime_part */ + memset(&mime_part_p,0,sizeof(mime_part)); + } + else { + /* Another header to check for file extensions, + encoding type and boundaries */ + if (strncmpic(US"content-type:",line,Ustrlen("content-type:")) == 0) { + /* ---------------------------- Content-Type header ------------------------------- */ + uschar *value = line; + + /* check for message/partial MIME type and reject it */ + if (mime_header_find(line,US"message/partial",NULL) > 0) + mime_trigger_error(MIME_ERRORLEVEL_MESSAGE_PARTIAL); + + /* check for TNEF content type, remember to unpack TNEF later. */ + if (mime_header_find(line,US"application/ms-tnef",NULL) > 0) + has_tnef = 1; + + /* check for message/rfcxxx attachments */ + if (mime_header_find(line,US"message/rfc822",NULL) > 0) + has_rfc822 = 1; + + /* find the file extension, but do not fill it in + it is already set, since content-disposition has + precedence. */ + if (mime_part_p.extension == NULL) { + if (mime_header_find(line,US"name",&value) == 2) { + if (Ustrlen(value) > MIME_SANITY_MAX_FILENAME) + mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH); + mime_part_p.extension = value; + mime_part_p.extension = Ustrrchr(value,'.'); + if (mime_part_p.extension == NULL) { + /* file without extension, setting + NULL will use the default extension later */ + mime_part_p.extension = NULL; + } + else { + struct file_extension *this_extension = + (struct file_extension *)malloc(sizeof(file_extension)); + + this_extension->file_extension_string = + (uschar *)malloc(Ustrlen(mime_part_p.extension)+1); + Ustrcpy(this_extension->file_extension_string, + mime_part_p.extension+1); + this_extension->next = file_extensions; + file_extensions = this_extension; + }; + }; + }; + + /* find a boundary and add it to the list, if present */ + value = line; + if (mime_header_find(line,US"boundary",&value) == 2) { + struct boundary *thisboundary; + + if (Ustrlen(value) > MIME_SANITY_MAX_BOUNDARY_LENGTH) { + mime_trigger_error(MIME_ERRORLEVEL_BOUNDARY_LENGTH); + } + else { + thisboundary = (struct boundary*)malloc(sizeof(boundary)); + thisboundary->next = boundaries; + thisboundary->boundary_string = value; + boundaries = thisboundary; + }; + }; + + if (mime_part_p.seen_content_type == 0) { + mime_part_p.seen_content_type = 1; + } + else { + mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS); + }; + /* ---------------------------------------------------------------------------- */ + } + else if (strncmpic(US"content-transfer-encoding:",line,Ustrlen("content-transfer-encoding:")) == 0) { + /* ---------------------------- Content-Transfer-Encoding header -------------- */ + + if (mime_part_p.seen_content_transfer_encoding == 0) { + if (mime_header_find(line,US"base64",NULL) > 0) { + mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_BASE64; + } + else if (mime_header_find(line,US"quoted-printable",NULL) > 0) { + mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_QP; + } + else { + mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_PLAIN; + }; + } + else { + mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS); + }; + /* ---------------------------------------------------------------------------- */ + } + else if (strncmpic(US"content-disposition:",line,Ustrlen("content-disposition:")) == 0) { + /* ---------------------------- Content-Disposition header -------------------- */ + uschar *value = line; + + if (mime_part_p.seen_content_disposition == 0) { + mime_part_p.seen_content_disposition = 1; + + if (mime_header_find(line,US"filename",&value) == 2) { + if (Ustrlen(value) > MIME_SANITY_MAX_FILENAME) + mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH); + mime_part_p.extension = value; + mime_part_p.extension = Ustrrchr(value,'.'); + if (mime_part_p.extension == NULL) { + /* file without extension, setting + NULL will use the default extension later */ + mime_part_p.extension = NULL; + } + else { + struct file_extension *this_extension = + (struct file_extension *)malloc(sizeof(file_extension)); + + this_extension->file_extension_string = + (uschar *)malloc(Ustrlen(mime_part_p.extension)+1); + Ustrcpy(this_extension->file_extension_string, + mime_part_p.extension+1); + this_extension->next = file_extensions; + file_extensions = this_extension; + }; + }; + } + else { + mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS); + }; + /* ---------------------------------------------------------------------------- */ + }; + }; /* End of header checks */ + /* ------------------------------------------------ */ + } + else { + /* -------------- non-header mode ----------------- */ + int tmp; + + if (uu_mode == MIME_UU_MODE_OFF) { + uschar uu_file_extension[5]; + /* We are not currently decoding UUENCODE + Check for possible UUENCODE start tag. */ + if (mime_check_uu_start(line,uu_file_extension,&has_tnef)) { + /* possible UUENCODING start detected. + Set unconfirmed mode first. */ + uu_mode = MIME_UU_MODE_UNCONFIRMED; + /* open new uu dump file */ + tmp = mime_get_dump_file(uu_file_extension, &uu_dump_file, info); + if (tmp < 0) { + free(line); + return DEFER; + }; + }; + } + else { + uschar *data; + long data_len = 0; + + if (uu_mode == MIME_UU_MODE_UNCONFIRMED) { + /* We are in unconfirmed UUENCODE mode. */ + + data_len = uu_decode_line(line,&data,line_len,info); + + if (data_len == -2) { + /* temp error, turn off uudecode mode */ + if (uu_dump_file != NULL) { + fclose(uu_dump_file); uu_dump_file = NULL; + }; + uu_mode = MIME_UU_MODE_OFF; + return DEFER; + } + else if (data_len == -1) { + if (uu_dump_file != NULL) { + fclose(uu_dump_file); uu_dump_file = NULL; + }; + uu_mode = MIME_UU_MODE_OFF; + data_len = 0; + } + else if (data_len > 0) { + /* we have at least decoded a valid byte + turn on confirmed mode */ + uu_mode = MIME_UU_MODE_CONFIRMED; + }; + } + else if (uu_mode == MIME_UU_MODE_CONFIRMED) { + /* If we are in confirmed UU mode, + check for single "end" tag on line */ + if ((strncmpic(line,US"end",3) == 0) && (line[3] < 32)) { + if (uu_dump_file != NULL) { + fclose(uu_dump_file); uu_dump_file = NULL; + }; + uu_mode = MIME_UU_MODE_OFF; + } + else { + data_len = uu_decode_line(line,&data,line_len,info); + if (data_len == -2) { + /* temp error, turn off uudecode mode */ + if (uu_dump_file != NULL) { + fclose(uu_dump_file); uu_dump_file = NULL; + }; + uu_mode = MIME_UU_MODE_OFF; + return DEFER; + } + else if (data_len == -1) { + /* skip this line */ + data_len = 0; + }; + }; + }; + + /* write data to dump file, if available */ + if (data_len > 0) { + if (fwrite(data,1,data_len,uu_dump_file) < data_len) { + /* short write */ + snprintf(CS info, 1024,"short write on uudecode dump file"); + free(line); + return DEFER; + }; + }; + }; + + if (mime_demux_mode != MIME_DEMUX_MODE_SCANNING) { + /* Non-scanning and Non-header mode. That means + we are currently decoding data to the dump + file. */ + + /* Check for a known boundary. */ + tmp = mime_check_boundary(line,boundaries); + if (tmp == 1) { + /* We have hit a known start boundary. + That will put us back in header mode. */ + mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS; + if (mime_dump_file != NULL) { + /* if the attachment was a RFC822 message, recurse into it */ + if (has_rfc822) { + has_rfc822 = 0; + rewind(mime_dump_file); + mime_demux(mime_dump_file,info); + }; + + fclose(mime_dump_file); mime_dump_file = NULL; + }; + } + else if (tmp == 2) { + /* We have hit a known end boundary. + That puts us into scanning mode, which will end when we hit another known start boundary */ + mime_demux_mode = MIME_DEMUX_MODE_SCANNING; + if (mime_dump_file != NULL) { + /* if the attachment was a RFC822 message, recurse into it */ + if (has_rfc822) { + has_rfc822 = 0; + rewind(mime_dump_file); + mime_demux(mime_dump_file,info); + }; + + fclose(mime_dump_file); mime_dump_file = NULL; + }; + } + else { + uschar *data; + long data_len = 0; + + /* decode the line with the appropriate method */ + if (mime_demux_mode == MIME_DEMUX_MODE_PLAIN) { + /* in plain mode, just dump the line */ + data = line; + data_len = line_len; + } + else if ( (mime_demux_mode == MIME_DEMUX_MODE_QP) || (mime_demux_mode == MIME_DEMUX_MODE_BASE64) ) { + data_len = mime_decode_line(mime_demux_mode,line,&data,line_len,info); + if (data_len < 0) { + /* Error reported from the line decoder. */ + data_len = 0; + }; + }; + + /* write data to dump file */ + if (data_len > 0) { + if (fwrite(data,1,data_len,mime_dump_file) < data_len) { + /* short write */ + snprintf(CS info, 1024,"short write on dump file"); + free(line); + return DEFER; + }; + }; + + }; + } + else { + /* Scanning mode. We end up here after a end boundary. + This will usually be at the end of a message or at + the end of a MIME container. + We need to look for another start boundary to get + back into header mode. */ + if (mime_check_boundary(line,boundaries) == 1) { + mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS; + }; + + }; + /* ------------------------------------------------ */ + }; + }; + /* ----------------------- end demux loop ----------------------- */ + + /* close files, they could still be open */ + if (mime_dump_file != NULL) + fclose(mime_dump_file); + if (uu_dump_file != NULL) + fclose(uu_dump_file); + + /* release line buffer */ + free(line); + + /* FIXME: release boundary buffers. + Not too much of a problem since + this instance of exim is not resident. */ + + if (has_tnef) { + uschar file_name[1024]; + /* at least one file could be TNEF encoded. + attempt to send all decoded files thru the TNEF decoder */ + + snprintf(CS file_name,1024,"%s/scan/%s",spool_directory,message_id); + /* Removed FTTB. We need to decide on TNEF inclusion */ + /* mime_unpack_tnef(file_name); */ + }; + + return 0; +} + +#endif diff --git a/src/src/demime.h b/src/src/demime.h new file mode 100644 index 000000000..00c432ca9 --- /dev/null +++ b/src/src/demime.h @@ -0,0 +1,136 @@ +/* $Cambridge: exim/src/src/demime.h,v 1.1.2.1 2004/12/02 16:33:30 tom Exp $ */ + +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) Tom Kistner 2003-???? */ +/* License: GPL */ + +/* demime defines */ + +#ifdef WITH_OLD_DEMIME + +#define MIME_DEMUX_MODE_SCANNING 0 +#define MIME_DEMUX_MODE_MIME_HEADERS 1 +#define MIME_DEMUX_MODE_BASE64 2 +#define MIME_DEMUX_MODE_QP 3 +#define MIME_DEMUX_MODE_PLAIN 4 + +#define MIME_UU_MODE_OFF 0 +#define MIME_UU_MODE_UNCONFIRMED 1 +#define MIME_UU_MODE_CONFIRMED 2 + +#define MIME_MAX_EXTENSION 128 + +#define MIME_READ_LINE_EOF 0 +#define MIME_READ_LINE_OK 1 +#define MIME_READ_LINE_OVERFLOW 2 + +#define MIME_SANITY_MAX_LINE_LENGTH 131071 +#define MIME_SANITY_MAX_FILENAME 512 +#define MIME_SANITY_MAX_HEADER_OPTION_VALUE 1024 +#define MIME_SANITY_MAX_B64_LINE_LENGTH 76 +#define MIME_SANITY_MAX_BOUNDARY_LENGTH 1024 +#define MIME_SANITY_MAX_DUMP_FILES 1024 + + + +/* MIME errorlevel settings */ + +#define MIME_ERRORLEVEL_LONG_LINE 3,US"line length in message or single header size exceeds %u bytes",MIME_SANITY_MAX_LINE_LENGTH +#define MIME_ERRORLEVEL_TOO_MANY_PARTS 3,US"too many MIME parts (max %u)",MIME_SANITY_MAX_DUMP_FILES +#define MIME_ERRORLEVEL_MESSAGE_PARTIAL 3,US"'message/partial' MIME type" +#define MIME_ERRORLEVEL_FILENAME_LENGTH 3,US"proposed filename exceeds %u characters",MIME_SANITY_MAX_FILENAME +#define MIME_ERRORLEVEL_BOUNDARY_LENGTH 3,US"boundary length exceeds %u characters",MIME_SANITY_MAX_BOUNDARY_LENGTH +#define MIME_ERRORLEVEL_DOUBLE_HEADERS 2,US"double headers (content-type, content-disposition or content-transfer-encoding)" +#define MIME_ERRORLEVEL_UU_MISALIGNED 1,US"uuencoded line length is not a multiple of 4 characters" +#define MIME_ERRORLEVEL_UU_LINE_LENGTH 1,US"uuencoded line length does not match advertised number of bytes" +#define MIME_ERRORLEVEL_B64_LINE_LENGTH 1,US"base64 line length exceeds %u characters",MIME_SANITY_MAX_B64_LINE_LENGTH +#define MIME_ERRORLEVEL_B64_ILLEGAL_CHAR 2,US"base64 line contains illegal character" +#define MIME_ERRORLEVEL_B64_MISALIGNED 1,US"base64 line length is not a multiple of 4 characters" +#define MIME_ERRORLEVEL_QP_ILLEGAL_CHAR 1,US"quoted-printable encoding contains illegal character" + + +/* demime structures */ + +typedef struct mime_part { + /* true if there was a content-type header */ + int seen_content_type; + /* true if there was a content-transfer-encoding header + contains the encoding type */ + int seen_content_transfer_encoding; + /* true if there was a content-disposition header */ + int seen_content_disposition; + /* pointer to a buffer with the proposed file extension */ + uschar *extension; +} mime_part; + +typedef struct boundary { + struct boundary *next; + uschar *boundary_string; +} boundary; + +typedef struct file_extension { + struct file_extension *next; + uschar *file_extension_string; +} file_extension; + +/* demime.c prototypes */ + +unsigned int mime_hstr_i(uschar *); +uschar *mime_decode_qp(uschar *, int *); +int mime_get_dump_file(uschar *, FILE **, uschar *); +int mime_header_find(uschar *, uschar *, uschar **); +int mime_read_line(FILE *, int, uschar *, long *); +int mime_check_boundary(uschar *, struct boundary *); +int mime_check_uu_start(uschar *, uschar *, int *); +long uu_decode_line(uschar *, uschar **, long, uschar *); +long mime_decode_line(int ,uschar *, uschar **, long, uschar *); +void mime_trigger_error(int, uschar *, ...); +int mime_demux(FILE *, uschar *); + + + +/* BASE64 decoder matrix */ +static unsigned char b64[256]={ +/* 0 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +/* 16 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +/* 32 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 62, 128, 128, 128, 63, +/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 255, 128, 128, +/* 64 */ 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, +/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 128, 128, 128, 128, 128, +/* 96 */ 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 +}; + + +/* Microsoft-Style uudecode matrix */ +static unsigned char uudec[256]={ +/* 0 */ 0, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, +/* 16 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, +/* 32 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +/* 48 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, +/* 64 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, +/* 80 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, +/* 96 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +/* 112 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, +/* 128 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, +/* 144 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, +/* 160 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +/* 176 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, +/* 192 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, +/* 208 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, +/* 224 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +/* 240 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +#endif diff --git a/src/src/exim.c b/src/src/exim.c index 80857a698..189d5ef31 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/exim.c,v 1.9.2.1 2004/12/02 09:15:11 tom Exp $ */ +/* $Cambridge: exim/src/src/exim.c,v 1.9.2.2 2004/12/02 16:33:30 tom Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -842,6 +842,9 @@ fprintf(f, "Support for:"); #ifdef WITH_CONTENT_SCAN fprintf(f, " Content_Scanning"); #endif +#ifdef WITH_OLD_DEMIME + fprintf(f, " Old_Demime"); +#endif fprintf(f, "\n"); fprintf(f, "Lookups:"); diff --git a/src/src/exim.h b/src/src/exim.h index c46af2c58..48aa2d903 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/exim.h,v 1.2.2.1 2004/11/30 15:18:58 tom Exp $ */ +/* $Cambridge: exim/src/src/exim.h,v 1.2.2.2 2004/12/02 16:33:30 tom Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -379,9 +379,15 @@ extern int ferror(FILE *); /* Exim includes are in several files. Note that local_scan.h #includes mytypes.h and store.h, so we don't need to mention them explicitly. */ +#include "config.h" + +/* Before including the rest of the Exim headers, lets clear up some content +scanning dependencies. */ +#ifdef WITH_OLD_DEMIME +#define WITH_CONTENT_SCAN +#endif #include "local_scan.h" -#include "config.h" #include "macros.h" #include "dbstuff.h" #include "structs.h" diff --git a/src/src/receive.c b/src/src/receive.c index 99a918981..abde1ce9a 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/receive.c,v 1.4.2.1 2004/12/02 09:15:11 tom Exp $ */ +/* $Cambridge: exim/src/src/receive.c,v 1.4.2.2 2004/12/02 16:33:30 tom Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -3383,7 +3383,7 @@ if (smtp_input) { #ifndef WITH_CONTENT_SCAN smtp_printf("250 OK id=%s\r\n", message_id); -#elif +#else if (fake_reject) { smtp_printf("550-FAKE_REJECT id=%s\r\n", message_id); @@ -3399,7 +3399,7 @@ if (smtp_input) } #ifndef WITH_CONTENT_SCAN else if (smtp_reply[0] != 0) smtp_printf("%.1024s\r\n", smtp_reply); -#elif +#else else if (smtp_reply[0] != 0) { if (fake_reject && (smtp_reply[0] == '2')) diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index dd8747b92..755b2bacc 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/smtp_in.c,v 1.5.2.1 2004/12/02 09:15:11 tom Exp $ */ +/* $Cambridge: exim/src/src/smtp_in.c,v 1.5.2.2 2004/12/02 16:33:30 tom Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -1794,7 +1794,7 @@ address to retain backward compatibility. */ #ifndef WITH_CONTENT_SCAN if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA) -#elif +#else if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA || where == ACL_WHERE_MIME) #endif {