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 }