mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

pool.c (22338B)


      1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
      2 
      3    Mixmaster may be redistributed and modified under certain conditions.
      4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
      5    ANY KIND, either express or implied. See the file COPYRIGHT for
      6    details.
      7 
      8    Send messages from pool
      9    $Id: pool.c 934 2006-06-24 13:40:39Z rabbi $ */
     10 
     11 #include "mix3.h"
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <ctype.h>
     15 #include <sys/types.h>
     16 #include <time.h>
     17 #ifdef POSIX
     18 #include <unistd.h>
     19 #else /* end of POSIX */
     20 #include <io.h>
     21 #endif /* else if not POSIX */
     22 #ifndef _MSC
     23 #include <dirent.h>
     24 #endif /* not _MSC */
     25 #include <assert.h>
     26 #include <sys/stat.h>
     27 #include <sys/types.h>
     28 
     29 #ifdef USE_PCRE
     30 #include "pcre.h"
     31 #endif /* USE_PCRE */
     32 
     33 int msg_send(char *name);
     34 
     35 int mix_send(void)
     36 {
     37   return (mix_regular(FORCE_POOL));
     38 }
     39 
     40 /* Message pool:       Unix  DOS
     41  * latent messages:      l*  *.lat
     42  * pooled messages:      m*  *.msg
     43  * messages to be sent:  s*  *.snd
     44  * temporary files:      t*  *.tmp
     45  * files in user editor: x*
     46  * incoming mail:        i*  *.inf
     47  * partial messages:     p*  p*.*
     48  * error messages:       e*  *.err
     49  * outgoing messages:    out *.txt (to be used by external program)
     50  */
     51 
     52 static int is(char *path, char *type)
     53 {
     54 #ifdef SHORTNAMES
     55   int s;
     56 
     57   s = strlen(path);
     58   if (s <= 4)
     59     return 0;
     60   return (path[s - 4] == '.' && streq(path + s - 3, type));
     61 #else /* end of SHORTNAMES */
     62   return (path[0] == type[0]);
     63 #endif /* else if not SHORTNAMES */
     64 }
     65 
     66 static void mv(char *name, char *newtype)
     67 {
     68   char old[PATHMAX], new[PATHMAX];
     69 
     70   sprintf(old, "%s%c%s", POOLDIR, DIRSEP, name);
     71 #ifdef SHORTNAMES
     72   assert(strlen(name) > 4);
     73   strcpy(name + strlen(name) - 3, newtype);
     74 #else /* end of SHORTNAMES */
     75   name[0] = newtype[0];
     76 #endif /* else if not SHORTNAMES */
     77   sprintf(new, "%s%c%s", POOLDIR, DIRSEP, name);
     78   rename(old, new);
     79 }
     80 
     81 int latent_read(void)
     82 {
     83   char path[PATHMAX];
     84   DIR *d;
     85   FILE *f;
     86   struct dirent *e;
     87   int size = 0;
     88   long now, then;
     89 
     90   now = time(NULL);
     91   d = opendir(POOLDIR);
     92   if (d != NULL)
     93     for (;;) {
     94       e = readdir(d);
     95       if (e == NULL)
     96 	break;
     97       if (is(e->d_name, "lat")) {
     98 	sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name);
     99 	f = fopen(path, "rb");
    100 	if (f != NULL) {
    101 	  fscanf(f, "%*d %ld\n", &then);
    102 	  fclose(f);
    103 	  if (now > then)
    104 	    mv(e->d_name, "msg");
    105 	}
    106       }
    107     }
    108   closedir(d);
    109   return (size);
    110 }
    111 
    112 int infile_read(void)
    113 {
    114   char path[PATHMAX];
    115   BUFFER *msg;
    116   DIR *d;
    117   FILE *f;
    118   struct dirent *e;
    119   int size = 0;
    120 
    121   msg = buf_new();
    122   d = opendir(POOLDIR);
    123   if (d != NULL)
    124     for (;;) {
    125       e = readdir(d);
    126       if (e == NULL)
    127 	break;
    128       if (is(e->d_name, "inf")) {
    129 	mv(e->d_name, "tmp");
    130 	sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name);
    131 	f = fopen(path, "rb");
    132 	if (f != NULL) {
    133 	  buf_clear(msg);
    134 	  buf_read(msg, f);
    135 	  fclose(f);
    136 	  unlink(path);
    137 	  mix_decrypt(msg);
    138 	}
    139       }
    140     }
    141   closedir(d);
    142   buf_free(msg);
    143   return (size);
    144 }
    145 
    146 int mailin_maildir_one(char *dir)
    147 /** Read mails from one directory
    148     This function reads all files from the directory passed and passes
    149     them on to mix_decrypt(). Each file is unlinked when its is read.
    150 
    151     @param dir	The directory in which files are to be read. No path finding
    152     		voodoo is done to the path; It's passed it opendir() as is.
    153     @author	PP
    154     @return	Number of files read
    155  */
    156 {
    157   BUFFER *msg;
    158   DIR *d;
    159   FILE *f;
    160   struct dirent *e;
    161   int size = 0;
    162   char path[PATHMAX];
    163 
    164   msg = buf_new();
    165   d = opendir(dir);
    166   if (d != NULL)
    167     for (;;) {
    168       e = readdir(d);
    169       if (e == NULL)
    170 	break;
    171       if (e->d_name[0] != '.') {
    172 	sprintf(path, "%s%c%s", dir, DIRSEP, e->d_name);
    173 	path[PATHMAX-1]='\0';
    174 	f = fopen(path, "rb");
    175 	if (f != NULL) {
    176 	  buf_clear(msg);
    177 	  buf_read(msg, f);
    178 	  fclose(f);
    179 	  unlink(path);
    180 	  mix_decrypt(msg);
    181 	  size++;
    182 	}
    183       }
    184     }
    185   closedir(d);
    186   buf_free(msg);
    187   return (size);
    188 }
    189 
    190 int mailin_maildir(char *maildir)
    191 /** Read mails from a mail folder in Maildir format
    192     Reads all files from the Maildir using mailin_maildir_one().
    193     All mails are removed after this function returns.
    194 
    195     @param maildir	The Maildir to open. mixfile() is called to normalize the path.
    196     @author	PP
    197     @return	0
    198  */
    199 {
    200   char normalized[PATHMAX];
    201   char path[PATHMAX];
    202 
    203   mixfile(normalized, maildir);
    204   sprintf(path, "%s%c%s", normalized, DIRSEP, "new");
    205   path[PATHMAX-1]='\0';
    206   mailin_maildir_one(path);
    207   sprintf(path, "%s%c%s", normalized, DIRSEP, "cur");
    208   path[PATHMAX-1]='\0';
    209   mailin_maildir_one(path);
    210   return (0);
    211 }
    212 
    213 int mailin_mbox(char *path)
    214 /** Read mails from a mail folder in mbox format
    215     Reads all messages from the mbox filder passes as an argument. Mails are
    216     handed over to mix_decrypt. After all mails have been read the mailbox
    217     is truncated to zero size i.e. all mails are deleted. The mbox is
    218     locked using lock() and unlock() during this operation.
    219 
    220     @param maildir	Path to the mbox mail folder.
    221     @author	PP
    222     @return	0 on sucess, other on error
    223  */
    224 {
    225   char line[LINELEN];
    226   FILE *f;
    227   int state, eof;
    228   BUFFER *msg;
    229   int err=0;
    230 
    231   msg = buf_new();
    232 
    233   f = mix_openfile(path, "r+");
    234   if (f != NULL) {
    235     if (lock(f) != 0) {
    236       /* Locking failed */
    237       err = 1;
    238       goto end;
    239     }
    240     /* State machine
    241      * 1 - Look for the first ^From_ line
    242      * 2 - add messages as they come
    243      */
    244     state = 1;
    245     eof = 0;
    246     for(;;) {
    247       if (fgets(line, sizeof(line), f) == NULL)
    248 	eof = 1;
    249 
    250       switch (state) {
    251 	case 1:
    252 	  /* Initial state - Looking for first appearance of From_ */
    253 	  if (eof)
    254 	    goto end_state;
    255 	  if (strleft(line, "From ")) {
    256 #if 0
    257 	    buf_appends(msg, line);
    258 #endif /* 0 */
    259 	    state = 2;
    260 	    break;
    261 	  };
    262 	  break;
    263 	case 2:
    264 	  /* Within one mail - Adding lines to mail until we encounter another From_ or eof */
    265 	  if (eof || strleft(line, "From ")) {
    266 	    mix_decrypt(msg);
    267 	    buf_clear(msg);
    268 	  }
    269 	  if (eof)
    270 	    goto end_state;
    271 	  if (!strleft(line, "From "))
    272 	    buf_appends(msg, line);
    273 	  break;
    274 	default:
    275 	  assert(0);
    276 	  err=1;
    277 	  goto end_state;
    278       }
    279     }
    280 end_state:
    281 #ifndef WIN32
    282     rewind(f);
    283     ftruncate(fileno(f), 0);
    284 #else /* end of not WIN32 */
    285     chsize(fileno(f), 0);
    286 #endif /* else if WIN32 */
    287     unlock(f);
    288     fclose(f);
    289   }
    290 end:
    291   buf_free(msg);
    292   return (err);
    293 }
    294 
    295 /** Process MAILIN if applicable
    296     If MAILIN is defined this function calls either mailin_maildir() or
    297     mailin_mbox() depending on whether the last character of MAILIN
    298     is DIRSEP.
    299 
    300     @param mailbox	Path to the mbox or Maildir mail folder.
    301     @author	PP
    302     @return	0 on sucess, other on error
    303  */
    304 int mailin(char *mailbox)
    305 {
    306   if (mailbox != NULL && (strcmp(mailbox, "") != 0))
    307     if (mailbox[strlen(mailbox)-1] == DIRSEP)
    308       return mailin_maildir(mailbox);
    309     else
    310       return mailin_mbox(mailbox);
    311   else
    312     return 0;
    313 };
    314 
    315 int pool_add(BUFFER *msg, char *type)
    316 {
    317   char path[PATHMAX], pathtmp[PATHMAX];
    318   FILE *f;
    319   int err = -1;
    320 
    321   f = pool_new(type, pathtmp, path);
    322   if (f != NULL) {
    323     err = buf_write(msg, f);
    324     fclose(f);
    325   }
    326   if (err == 0) {
    327     rename(pathtmp, path);
    328     errlog(DEBUGINFO, "Added %s file to pool.\n", type);
    329   }
    330   return (err);
    331 
    332 }
    333 
    334 FILE *pool_new(char *type, char *tmpname, char *path)
    335 {
    336   FILE *f;
    337   struct stat buf;
    338   int err;
    339 
    340   assert(strlen(type) == 3);
    341 #ifdef SHORTNAMES
    342   sprintf(tmpname, "%s%c%02x%02x%02x%02x.tmp", POOLDIR, DIRSEP, rnd_byte(), rnd_byte(),
    343 	  rnd_byte(), rnd_byte());
    344   strcpy(path, tmpname);
    345   memcpy(path + strlen(path) - 3, type, 3);
    346 #else /* end of SHORTNAMES */
    347   sprintf(tmpname, "%s%ct%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP, rnd_byte(),
    348 	  rnd_byte(), rnd_byte(), rnd_byte(), rnd_byte(),
    349 	  rnd_byte(), rnd_byte() & 15);
    350   strcpy(path, tmpname);
    351   strrchr(path, DIRSEP)[1] = type[0];
    352 #endif /* else if not SHORTNAMES */
    353   err = stat(tmpname, &buf);
    354   if (err == 0)
    355     errlog(WARNING, "Overwriting file %s\n", tmpname);
    356   f = fopen(tmpname, "wb");
    357   if (f == NULL)
    358     errlog(ERRORMSG, "Error creating temporary file %s\n", tmpname);
    359   return (f);
    360 }
    361 
    362 int pool_read(BUFFER *pool)
    363 {
    364   DIR *d;
    365   struct dirent *e;
    366   int size = 0;
    367 
    368   d = opendir(POOLDIR);
    369   if (d != NULL) {
    370     for (;;) {
    371       e = readdir(d);
    372       if (e == NULL)
    373 	break;
    374       if (is(e->d_name, "msg")) {
    375 	if (pool != NULL) {
    376 	  buf_appends(pool, e->d_name);
    377 	  buf_appendc(pool, 0);
    378 	}
    379 	size++;
    380       }
    381     }
    382     closedir(d);
    383   } else
    384     errlog(WARNING, "Error reading pool dir %s\n", POOLDIR);
    385   return (size);
    386 }
    387 
    388 void pool_dosend(void)
    389 {
    390   DIR *d;
    391   struct dirent *e;
    392   char path[PATHMAX];
    393 
    394   d = opendir(POOLDIR);
    395   if (d != NULL) {
    396     for (;;) {
    397       e = readdir(d);
    398       if (e == NULL)
    399 	break;
    400       if (is(e->d_name, "snd")) {
    401 	sendmail_begin();
    402 	mv(e->d_name, "tmp");
    403 	sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name);
    404 	if (msg_send(path) == 1)
    405 	  mv(e->d_name, "err");
    406       }
    407     }
    408     closedir(d);
    409   } else
    410     errlog(WARNING, "Error reading pool dir %s\n", POOLDIR);
    411   sendmail_end();
    412 }
    413 
    414 int process_mailin()
    415 {
    416   mailin(MAILIN);
    417   infile_read();
    418   return(0);
    419 }
    420 
    421 int create_dummy_mailout()
    422 {
    423   while (rnd_number(100) < OUTDUMMYP) {
    424     errlog(DEBUGINFO, "Generating dummy message with outgoing mail.\n");
    425     if (mix_encrypt(MSG_NULL, NULL, NULL, 1, NULL) == -1)
    426       return -1;
    427   }
    428   return 0;
    429 }
    430 
    431 int pool_send(void)
    432 {
    433   int size, max, i, r;
    434   BUFFER *pool;
    435   long int *ptr;
    436 
    437   create_dummy_mailout();
    438 
    439   latent_read();
    440   pool = buf_new();
    441   size = pool_read(pool);
    442   if (size <= POOLSIZE)
    443     goto end;
    444 
    445   ptr = malloc(size * sizeof(long int));
    446 
    447   if (ptr == NULL)
    448     goto end;
    449   for (i = 0; i < size; i++) {
    450     ptr[i] = pool->ptr;
    451     buf_getline(pool, NULL);
    452   }
    453 
    454   max = size * RATE / 100;	/* send no more than RATE % of the messages */
    455   if (max < 0)
    456     max = 1;
    457 
    458   for (i = 0; i < size - POOLSIZE && i < max; i++) {
    459     do
    460       r = rnd_number(size);	/* chose a new random message */
    461     while (is(pool->data + ptr[r], "snd"));
    462     mv(pool->data + ptr[r], "snd");
    463   }
    464   stats_out(size - --i);
    465   pool_dosend();
    466   free(ptr);
    467 
    468 end:
    469   buf_free(pool);
    470   return (size);
    471 }
    472 
    473 int msg_send(char *name)
    474 {
    475   FILE *f;
    476   int type = -1;
    477   BUFFER *m, *addr;
    478   int err = 0;
    479   char line[LINELEN];
    480   int userfrom = 0;
    481 
    482   m = buf_new();
    483   addr = buf_new();
    484   if ((f = fopen(name, "rb")) == NULL) {
    485     err = -1;
    486     goto end;
    487   }
    488   fscanf(f, "%d %*d\n", &type);
    489   if (type == INTERMEDIATE) {
    490     fgets(line, sizeof(line), f);
    491     buf_sets(addr, line);
    492     buf_chop(addr);
    493     err = buf_read(m, f);
    494     if (err == -1)
    495       goto end;
    496     err = mix_armor(m);
    497     if (err == -1)
    498       goto end;
    499     err = sendmail(m, REMAILERADDR, addr);
    500     stats_log(3);
    501   } else if (type == MSG_MAIL || type == MSG_POST) {
    502     err = buf_read(m, f);
    503     if (err == -1)
    504       goto end;
    505     if (MIDDLEMAN && ! allowmessage(m)) {
    506       mix2_encrypt(type, m, FORWARDTO, 1, 1, NULL);
    507       stats_log(6);
    508     } else {
    509       err = filtermsg(m);
    510       if (err == 1)
    511 	userfrom = 1, err = 0;
    512       if (err != -1) {
    513 	/* message has recipients */
    514 	errlog(DEBUGINFO, "Sending message (%ld bytes)\n", m->length);
    515 
    516 	if (type == MSG_MAIL) {
    517 	  err = sendmail(m, userfrom ? NULL : ANONNAME, NULL);
    518 	  stats_log(4);
    519 	} else if (type == MSG_POST) {
    520 	  if (strchr(NEWS, '@') && !strchr(NEWS, ' ')) {
    521 	    errlog(LOG, "Mailing article to %s.\n", NEWS);
    522 	    buf_sets(addr, NEWS);
    523 	    err = sendmail(m, userfrom ? NULL : ANONNAME, addr);
    524 	  } else if (NEWS[0] != '\0') {
    525 	    FILE *f;
    526 
    527 	    f = openpipe(NEWS);
    528 	    if (f == NULL)
    529 	      goto end;
    530 	    errlog(LOG, "Posting article.\n");
    531 	    if (!userfrom)
    532 	      fprintf(f, "From: %s\n", ANONNAME);
    533 	    if (ORGANIZATION[0] != '\0')
    534 	      fprintf(f, "Organization: %s\n", ORGANIZATION);
    535 	    buf_write(m, f);
    536 	    closepipe(f);
    537 	  } else
    538 	    errlog(NOTICE, "Rejecting news article.\n");
    539 	  stats_log(5);
    540 	}
    541       } else
    542 	errlog(ERRORMSG, "Bad message file.\n");
    543     }
    544   }
    545 end:
    546   if (f != NULL)
    547     fclose(f);
    548   if (err != 1)			/* problem sending mail */
    549     unlink(name);
    550   buf_free(m);
    551   buf_free(addr);
    552   return (err);
    553 }
    554 
    555 int allowmessage(BUFFER *in)
    556 /* Only called if remailer is middleman. Checks whether all Recipient
    557  * addresses are in dest.allow. If yes return 1; 0 otherwhise
    558  */
    559 {
    560   BUFFER *out, *allow, *allow2, *line, *line2;
    561   int err=1;
    562   FILE *f;
    563 
    564   allow = buf_new();
    565   allow2 = buf_new();
    566   out = buf_new();
    567   line = buf_new();
    568   line2 = buf_new();
    569 
    570   f = mix_openfile(DESTALLOW, "r");
    571   if (f != NULL) {
    572     buf_read(allow, f);
    573     fclose(f);
    574   }
    575   f = mix_openfile(DESTALLOW2, "r");
    576   if (f != NULL) {
    577     buf_read(allow2, f);
    578     fclose(f);
    579     buf_cat(allow, allow2);
    580   }
    581 
    582   /* Do header lines */
    583   while (buf_getline(in, line) == 0) {
    584     for (;;) {
    585       buf_lookahead(in, line2);
    586       if (!bufleft(line2, " ") && !bufleft(line2, "\t"))
    587 	break;
    588       buf_getline(in, line2);
    589       buf_cat(line, line2);
    590     }
    591 
    592     if (bufileft(line, "to:") || bufileft(line, "cc:") ||
    593 	bufileft(line, "bcc:") || bufileft(line, "newsgroups:"))
    594       if (! doallow(line, allow))
    595       	err = 0;
    596 
    597     if (line->length > 0) {
    598       if (!buffind(line, ":"))
    599 	 buf_appends(out, "X-Invalid: ");
    600       buf_cat(out, line);
    601       buf_nl(out);
    602     }
    603   }
    604   buf_nl(out);
    605 
    606   /* Rest of the message */
    607   buf_append(out, in->data + in->ptr, in->length - in->ptr);
    608 
    609   buf_move(in, out);
    610   buf_free(out);
    611   buf_free(allow);
    612   buf_free(allow2);
    613   buf_free(line);
    614   buf_free(line2);
    615   return (err);
    616 }
    617 
    618 int doallow(BUFFER *line, BUFFER *filter)
    619 /* line is a To, CC or BCC line.
    620  * problem is: there may be multiple addresses in one header
    621  * line but we only want to allow if _all_ are allowed
    622  *
    623  * So to not send direct if we do not want, we _never_ send
    624  * direct if there is more than one address: This is
    625  * assumed to be the case when there is a
    626  * comma in the header line.
    627  *
    628  * this should probably be rewritten somehwhen. therefore: FIXME
    629  *
    630  * returns: 1 if allowed
    631  *          0 if message should be send indirectly
    632  */
    633 {
    634   if (strchr( line->data, ',')) return 0;
    635   return doblock(line, filter, 0);
    636 }
    637 
    638 int filtermsg(BUFFER *in)
    639 {
    640   BUFFER *out, *line, *line2, *mboundary, *block, *filter, *mid;
    641   FILE *f;
    642   int from = 0, dest = 0;
    643   int inbinary = 0, inpgp = 0, l = 80;
    644   int err = -1;
    645 
    646   line = buf_new();
    647   line2 = buf_new();
    648   filter = buf_new();
    649   mid = buf_new();
    650   mboundary = buf_new();
    651   out = buf_new();
    652   block = NULL;
    653 
    654   if (SIZELIMIT > 0 && in->length > SIZELIMIT * 1024) {
    655     errlog(NOTICE, "Message rejected: %ld bytes\n", in->length);
    656     goto end;
    657   }
    658 
    659   block = readdestblk( );
    660   if ( !block ) block = buf_new( );
    661 
    662   f = mix_openfile(HDRFILTER, "r");
    663   if (f != NULL) {
    664     buf_read(filter, f);
    665     fclose(f);
    666   }
    667 
    668   f = mix_openfile(DISCLAIMFILE, "r");
    669   if (f != NULL) {
    670     buf_read(out, f);
    671     fclose(f);
    672   } else {
    673     if (strfind(DISCLAIMER, "%s"))
    674       buf_appendf(out, DISCLAIMER, COMPLAINTS);
    675     else
    676       buf_appends(out, DISCLAIMER);
    677   }
    678 
    679   while (buf_getline(in, line) == 0) {
    680     for (;;) {
    681       buf_lookahead(in, line2);
    682       if (!bufleft(line2, " ") && !bufleft(line2, "\t"))
    683 	break;
    684       buf_getline(in, line2);
    685       buf_cat(line, line2);
    686     }
    687 
    688     if (bufileft(line, "to:") || bufileft(line, "cc:") ||
    689 	bufileft(line, "bcc:") || bufileft(line, "newsgroups:"))
    690       if (doblock(line, block, 1) == 0)
    691 	dest++;
    692     if (doblock(line, filter, 1) == -1)
    693       goto end;
    694     if (bufileft(line, "from:"))
    695       from = 1;
    696 
    697     if (bufileft(line, "content-type:") && bufileft(line, "multipart"))
    698       get_parameter(line, "boundary", mboundary);
    699 
    700     if (line->length > 0) {
    701       if (!buffind(line, ":"))
    702 	 buf_appends(out, "X-Invalid: ");
    703        buf_cat(out, line);
    704       buf_nl(out);
    705     }
    706   }
    707 
    708   if (MID[0] != '\0' && tolower(MID[0]) != 'n') {
    709     char txt[LINELEN];
    710 
    711     digestmem_md5(in->data + in->ptr, in->length - in->ptr, mid);
    712     id_encode(mid->data, txt);
    713 
    714     if (MID[0] == '@')
    715       strcatn(txt, MID, sizeof(txt));
    716     else {
    717       if (strchr(REMAILERADDR, '@'))
    718 	strcatn(txt, strchr(REMAILERADDR, '@'), sizeof(txt));
    719       else if (strchr(COMPLAINTS, '@'))
    720 	strcatn(txt, strchr(COMPLAINTS, '@'), sizeof(txt));
    721     }
    722     buf_appendf(out, "Message-ID: <%s>\n", txt);
    723   }
    724   buf_nl(out);
    725 
    726   if (from) {
    727     /* prepend Sender line to message header */
    728     buf_setf(line, "Sender: %s\n", ANONNAME);
    729     buf_cat(line, out);
    730     buf_move(out, line);
    731 
    732     f = mix_openfile(FROMDSCLFILE, "r");
    733     if (f != NULL) {
    734       buf_read(out, f);
    735       fclose(f);
    736     } else
    737       buf_appends(out, FROMDISCLAIMER);
    738   }
    739 
    740 #if 0
    741   buf_append(out, in->data + in->ptr, in->length - in->ptr);
    742 #endif /* 0 */
    743   while (buf_getline(in, line) != -1) {
    744       if (boundary(line, mboundary)) {
    745       buf_cat(out, line);
    746       buf_nl(out);
    747       while (buf_getline(in, line) == 0) {	/* MIME body part header */
    748 	err = doblock(line, filter, 1);
    749 	if (err == -1)
    750 	  goto end;
    751 	buf_cat(out, line);
    752 	buf_nl(out);
    753       }
    754     }
    755     if (BINFILTER && l > 20 && line->length == l &&
    756 	(bufleft(line, "M") || !buffind(line, " ")))
    757       inbinary++;
    758     else
    759       inbinary = 0, l = line->length;
    760     if (bufileft(line, begin_pgp) || bufileft(line, begin_key))
    761       inpgp = 1;
    762     if (bufileft(line, end_pgp) || bufileft(line, end_key))
    763       inpgp = 0;
    764     if (inbinary < 10 || inpgp) {
    765       buf_cat(out, line);
    766       buf_nl(out);
    767     } else if (inbinary == 10) {
    768       errlog(NOTICE, "Binary message detected.\n");
    769       if (BINFILTER > 1) {
    770 	err = -1;
    771 	goto end;
    772       }
    773       buf_appends(out, BINDISCLAIMER);
    774       buf_nl(out);
    775     }
    776   }
    777 
    778   f = mix_openfile(MSGFOOTERFILE, "r");
    779   if (f != NULL) {
    780     buf_read(out, f);
    781     fclose(f);
    782   } else
    783     buf_appends(out, MSGFOOTER);
    784 
    785   /* return 1 for user supplied From line */
    786   err = from;
    787   if (dest == 0)
    788     err = -1;
    789 
    790 end:
    791   buf_move(in, out);
    792   buf_free(out);
    793   buf_free(line);
    794   buf_free(line2);
    795   if (block) buf_free(block);
    796   buf_free(filter);
    797   buf_free(mid);
    798   buf_free(mboundary);
    799   return (err);
    800 }
    801 
    802 BUFFER *readdestblk( )
    803 {
    804        char *destblklst = (char *)malloc( strlen( DESTBLOCK )+1 );
    805        char *destblk = NULL;
    806        FILE *f;
    807        BUFFER *addresses;
    808        BUFFER *temp;
    809        int err = 1;
    810 
    811        addresses = buf_new( );
    812        temp = buf_new( );
    813 
    814        strcpy( destblklst, DESTBLOCK );
    815 
    816        while ( (destblk = strtok( destblk ? NULL : destblklst, " " )) )
    817        {
    818 	       if ( (f = mix_openfile( destblk, "r" )) )
    819 	       {
    820 	               if ( !buf_read( temp, f ) )
    821 	               {
    822 	                       buf_cat( addresses, temp );
    823 	                       err = 0;
    824 	               }
    825 	               fclose( f );
    826 	       }
    827        }
    828 
    829        free( destblklst );
    830        buf_free( temp );
    831 
    832        if ( err ) { buf_free( addresses ); return NULL; }
    833        else return addresses;
    834 }
    835 
    836 int doblock(BUFFER *line, BUFFER *filter, int logandreset)
    837 /* logandreset is usually 0
    838  * it is only set to 1 when called from doallow
    839  *  which only checks whether messages are allowed to
    840  *  be sent directly
    841  */
    842 {
    843   int block = 0;
    844   BUFFER *pattern, *result;
    845   char *t;
    846 #ifdef USE_PCRE
    847   int errptr, match;
    848   const char *error;
    849   pcre *compiled;
    850   int ovector[21];
    851   char *newstr;
    852 #endif /* USE_PCRE */
    853 
    854   pattern = buf_new();
    855   result = buf_new();
    856   assert(filter != NULL);
    857 
    858   buf_rewind(filter);
    859   while (buf_getline(filter, pattern) != -1)
    860     if (pattern->length > 0 && !bufleft(pattern, "#")) {
    861       if (bufleft(pattern, "/") && (t = strchr(pattern->data + 1, '/'))
    862 	  != NULL) {
    863 #ifdef USE_PCRE
    864 	*t = '\0';
    865 	compiled = pcre_compile(pattern->data + 1, PCRE_CASELESS,
    866 				&error, &errptr
    867 #ifndef USE_PCRE_OLD
    868 				,NULL
    869 #endif /* not USE_PCRE_OLD */
    870 	  );
    871 	if (compiled) {
    872 	  match = pcre_exec(compiled, NULL, line->data,
    873 			    line->length,
    874 #if (PCRE_MAJOR == 2 && PCRE_MINOR >= 06)
    875 			    0,
    876 #endif /* (PCRE_MAJOR == 2 && PCRE_MINOR >= 06) */
    877 #if (PCRE_MAJOR >= 3)
    878 			    0,
    879 #endif /* (PCRE_MAJOR >= 3) */
    880 			    0, ovector, sizeof(ovector) / sizeof(int));
    881 	  free(compiled);
    882 
    883 	  if (match < -1) {
    884 	    *t = '/';
    885 	    errlog(ERRORMSG, "Bad regexp %b\n", pattern);
    886 	  }
    887 	  else if (match >= 0) {
    888 	    /* "/pattern/q" kills the entire message */
    889 	    if (logandreset
    890 	        && strlen(pattern->data + 1) + 1 < pattern->length
    891 		&& pattern->data[pattern->length - 1] == 'q') {
    892 	      *t = '/';
    893 	      errlog(NOTICE,
    894 		     "Message rejected: %b matches %b.\n", line, pattern);
    895 	      block = -1;
    896 	      break;
    897 	    }
    898 	    if (strlen(pattern->data + 1) + 1 < pattern->length
    899 		&& pattern->data[pattern->length - 1] == '/') {
    900 	      pattern->data[pattern->length - 1] = '\0';
    901 	      newstr = pattern->data + strlen(pattern->data) + 1;
    902 	      buf_reset(result);
    903 	      buf_append(result, line->data, ovector[0]);
    904 	      while (strchr(newstr, '$')) {
    905 		strchr(newstr, '$')[0] = '\0';
    906 		buf_appends(result, newstr);
    907 		newstr += strlen(newstr) + 1;
    908 		if (*newstr >= '1' && *newstr <= '9')
    909 		  buf_append(result, line->data +
    910 			     ovector[2 * (*newstr - '0')],
    911 			     ovector[2 * (*newstr - '0') + 1] -
    912 			     ovector[2 * (*newstr - '0')]);
    913 		newstr++;
    914 	      }
    915 	      buf_appends(result, newstr);
    916 	      buf_appends(result, line->data + ovector[1]);
    917 	      buf_clear(line);
    918 	      buf_appends(line, result->data);
    919 	    } else {
    920 	      block = 1;
    921 	      *t = '/';
    922 	      if (logandreset)
    923 	        errlog(NOTICE, "Blocked header line: %b matches %b.\n",
    924 		       line, pattern);
    925 	    }
    926 	  }
    927 	} else {
    928 	  *t = '/';
    929 	  errlog(ERRORMSG, "Bad regexp %b\n", pattern);
    930 	}
    931 #else /* end of USE_PCRE */
    932 	errlog(ERRORMSG, "No regexp support! Ignoring %b\n", pattern);
    933 #endif /* else if not USE_PCRE */
    934       } else if (bufifind(line, pattern->data)) {
    935 	if (logandreset )
    936 	  errlog(NOTICE, "Blocked header line: %b matches %b.\n",
    937 	         line, pattern);
    938 	block = 1;
    939       }
    940     }
    941 
    942   if (logandreset && (block == 1))
    943     buf_reset(line);
    944 
    945   buf_free(pattern);
    946   buf_free(result);
    947   return (block);
    948 }
    949 
    950 int mix_armor(BUFFER *in)
    951 {
    952   BUFFER *out, *md;
    953 
    954   md = buf_new();
    955   out = buf_new();
    956 
    957   if (in->length != 20480)
    958     return (-1);
    959 
    960   buf_sets(out, "\n::\n");
    961   buf_appends(out, remailer_type);
    962   buf_appends(out, VERSION);
    963   buf_nl(out);
    964   buf_nl(out);
    965   buf_appends(out, begin_remailer);
    966   buf_nl(out);
    967   buf_appends(out, "20480\n");
    968   digest_md5(in, md);
    969   encode(md, 0);
    970   buf_cat(out, md);
    971   buf_nl(out);
    972   encode(in, 40);
    973   buf_cat(out, in);
    974   buf_appends(out, end_remailer);
    975   buf_nl(out);
    976 
    977   buf_move(in, out);
    978   buf_free(out);
    979   buf_free(md);
    980   return (0);
    981 }